From eec068253f8cfd2f0b5a95b19dd9d20630c43947 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 19 Feb 2012 14:31:41 +0000 Subject: [PATCH 001/221] [rng] Add ANS X9.82 Approved Hash_df derivation function ANS X9.82 specifies several Approved derivation functions for use in distributing entropy throughout a buffer. One such derivation function is Hash_df, which can be implemented using the existing iPXE SHA-1 functionality. Signed-off-by: Michael Brown --- src/crypto/hash_df.c | 134 +++++++++++++++++++++++++++++++++++++ src/include/ipxe/hash_df.h | 30 +++++++++ 2 files changed, 164 insertions(+) create mode 100644 src/crypto/hash_df.c create mode 100644 src/include/ipxe/hash_df.h diff --git a/src/crypto/hash_df.c b/src/crypto/hash_df.c new file mode 100644 index 00000000..4c2d28a9 --- /dev/null +++ b/src/crypto/hash_df.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Hash-based derivation function (Hash_df) + * + * This algorithm is designed to comply with ANS X9.82 Part 3-2007 + * Section 10.5.2. This standard is not freely available, but most of + * the text appears to be shared with NIST SP 800-90, which can be + * downloaded from + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + * + * Where possible, references are given to both documents. In the + * case of any disagreement, ANS X9.82 takes priority over NIST SP + * 800-90. (In particular, note that some algorithms that are + * Approved by NIST SP 800-90 are not Approved by ANS X9.82.) + */ + +#include +#include +#include +#include + +/** + * Distribute entropy throughout a buffer + * + * @v input Input data + * @v input_len Length of input data, in bytes + * @v output Output buffer + * @v output_len Length of output buffer, in bytes + * + * This is the Hash_df function defined in ANS X9.82 Part 3-2007 + * Section 10.5.2 (NIST SP 800-90 Section 10.4.1). + * + * The number of bits requested is implicit in the length of the + * output buffer. Requests must be for an integral number of bytes. + * + * The output buffer is filled incrementally with each iteration of + * the central loop, rather than constructing an overall "temp" and + * then taking the leftmost(no_of_bits_to_return) bits. + * + * There is no way for the Hash_df function to fail. The returned + * status SUCCESS is implicit. + */ +void hash_df ( const void *input, size_t input_len, void *output, + size_t output_len ) { + uint8_t context[HASH_DF_CTX_SIZE]; + uint8_t digest[HASH_DF_OUTLEN_BYTES]; + size_t frag_len; + struct { + uint8_t pad[3]; + uint8_t counter; + uint32_t no_of_bits_to_return; + } __attribute__ (( packed )) prefix; + void *temp; + size_t remaining; + + DBGC ( &hash_df, "HASH_DF input:\n" ); + DBGC_HDA ( &hash_df, 0, input, input_len ); + + /* Sanity checks */ + assert ( input != NULL ); + assert ( output != NULL ); + + /* 1. temp = the Null string + * 2. len = ceil ( no_of_bits_to_return / outlen ) + * + * (Nothing to do. We fill the output buffer incrementally, + * rather than constructing the complete "temp" in-memory. + * "len" is implicit in the number of iterations required to + * fill the output buffer, and so is not calculated + * explicitly.) + */ + + /* 3. counter = an 8-bit binary value representing the integer "1" */ + prefix.counter = 1; + + /* 4. For i = 1 to len do */ + for ( temp = output, remaining = output_len ; remaining > 0 ; ) { + + /* Comment: in step 5.1 (sic), no_of_bits_to_return is + * used as a 32-bit string. + * + * 4.1 temp = temp || Hash ( counter || no_of_bits_to_return + * || input_string ) + */ + prefix.no_of_bits_to_return = htonl ( output_len * 8 ); + digest_init ( &hash_df_algorithm, context ); + digest_update ( &hash_df_algorithm, context, &prefix.counter, + ( sizeof ( prefix ) - + offsetof ( typeof ( prefix ), counter ) ) ); + digest_update ( &hash_df_algorithm, context, input, input_len ); + digest_final ( &hash_df_algorithm, context, digest ); + + /* 4.2 counter = counter + 1 */ + prefix.counter++; + + /* 5. requested_bits = Leftmost ( no_of_bits_to_return ) + * of temp + * + * (We fill the output buffer incrementally.) + */ + frag_len = sizeof ( digest ); + if ( frag_len > remaining ) + frag_len = remaining; + memcpy ( temp, digest, frag_len ); + temp += frag_len; + remaining -= frag_len; + } + + /* 6. Return SUCCESS and requested_bits */ + DBGC ( &hash_df, "HASH_DF output:\n" ); + DBGC_HDA ( &hash_df, 0, output, output_len ); + return; +} diff --git a/src/include/ipxe/hash_df.h b/src/include/ipxe/hash_df.h new file mode 100644 index 00000000..003e5cef --- /dev/null +++ b/src/include/ipxe/hash_df.h @@ -0,0 +1,30 @@ +#ifndef _IPXE_HASH_DF_H +#define _IPXE_HASH_DF_H + +/** @file + * + * Hash-based derivation function (Hash_df) + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** Use SHA-1 as the underlying hash algorithm + * + * Hash_df using SHA-1 is an Approved algorithm in ANS X9.82. + */ +#define hash_df_algorithm sha1_algorithm + +/** Underlying hash algorithm output length (in bytes) */ +#define HASH_DF_OUTLEN_BYTES SHA1_DIGEST_SIZE + +/** Underlying hash algorithm context size (in bytes) */ +#define HASH_DF_CTX_SIZE SHA1_CTX_SIZE + +extern void hash_df ( const void *input, size_t input_len, void *output, + size_t output_len ); + +#endif /* _IPXE_HASH_DF_H */ From 71804f890da621f7ea24f3d013479f8559239f25 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 19 Feb 2012 14:34:46 +0000 Subject: [PATCH 002/221] [rng] Add NIST self-tests for Hash_df NIST provides a set of known-answer tests for the Hash_DRBG algorithm, which includes known answers for the derivation function Hash_df used as part of Hash_DRBG. Hash_DRBG is not an Approved algorithm for ANS X9.82, but the known answers for Hash_df (which is part of ANS X9.82) can still be used as part of the conformance testing for ANS X9.82. Signed-off-by: Michael Brown --- src/tests/hash_df_test.c | 494 +++++++++++++++++++++++++++++++++++++++ src/tests/test.c | 1 + 2 files changed, 495 insertions(+) create mode 100644 src/tests/hash_df_test.c diff --git a/src/tests/hash_df_test.c b/src/tests/hash_df_test.c new file mode 100644 index 00000000..563704f4 --- /dev/null +++ b/src/tests/hash_df_test.c @@ -0,0 +1,494 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Hash-based derivation function (Hash_df) tests + * + * These test vectors are provided by NIST as part of the + * Cryptographic Toolkit Examples, downloadable from: + * + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/Hash_DRBG.pdf + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include + +/** Define inline input data */ +#define INPUT(...) { __VA_ARGS__ } + +/** Define inline expected data */ +#define EXPECT(...) { __VA_ARGS__ } + +/** A Hash_df test */ +struct hash_df_test { + /** Input data */ + const void *input; + /** Length of input data */ + size_t input_len; + /** Expected output data */ + const void *expected; + /** Length of expected output data */ + size_t expected_len; +}; + +/** + * Define a Hash_df test + * + * @v name Test name + * @v input_array Input data + * @v expected_array Expected output data + * @ret test Hash_df test + */ +#define HASH_DF_TEST( name, input_array, expected_array ) \ + static const uint8_t name ## _input [] = input_array; \ + static const uint8_t name ## _expected [] = expected_array; \ + static const struct hash_df_test name = { \ + .input = name ## _input, \ + .input_len = sizeof ( name ## _input ), \ + .expected = name ## _expected, \ + .expected_len = sizeof ( name ## _expected ), \ + } + +/** Test 1 */ +HASH_DF_TEST ( test_1, + INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24 ), + EXPECT ( 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, 0x6c, + 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, 0xfd, + 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, 0x28, + 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97, 0xab, + 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d, 0x94, + 0xbe, 0xe3, 0x3c, 0xbb, 0x89 ) ); + +/** Test 2 */ +HASH_DF_TEST ( test_2, + INPUT ( 0x00, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, + 0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, + 0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, + 0x28, 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97, + 0xab, 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d, + 0x94, 0xbe, 0xe3, 0x3c, 0xbb, 0x89 ), + EXPECT ( 0x54, 0xc5, 0x21, 0x7b, 0x51, 0x02, 0xd8, 0xda, 0x8b, 0xf1, + 0x68, 0x6e, 0xdb, 0xab, 0x2b, 0xbc, 0x0c, 0x11, 0xb0, 0xcc, + 0xb0, 0xf0, 0xaf, 0x23, 0x4c, 0x24, 0xcf, 0x15, 0xec, 0xc8, + 0xcb, 0x39, 0xc2, 0x33, 0xaa, 0xca, 0x48, 0xfc, 0xce, 0xee, + 0x86, 0x3d, 0xa8, 0x81, 0xff, 0xcb, 0xb4, 0x34, 0xa6, 0xcc, + 0xb7, 0xda, 0x2f, 0xb2, 0x10 ) ); + +/** Test 3 */ +HASH_DF_TEST ( test_3, + INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, + 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, + 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, + 0x72, 0x73, 0x74, 0x75, 0x76 ), + EXPECT ( 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, 0x21, + 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, 0x03, + 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, 0xd0, + 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d, 0x58, + 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a, 0x93, + 0x32, 0x4b, 0x27, 0xbd, 0xe8 ) ); + +/** Test 4 */ +HASH_DF_TEST ( test_4, + INPUT ( 0x00, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, + 0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, + 0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, + 0xd0, 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d, + 0x58, 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a, + 0x93, 0x32, 0x4b, 0x27, 0xbd, 0xe8 ), + EXPECT ( 0xa7, 0x02, 0x66, 0xf7, 0xf9, 0x1e, 0xc4, 0xd2, 0x88, 0x73, + 0x14, 0x79, 0x34, 0xce, 0xaf, 0x2a, 0x2c, 0xc3, 0x5a, 0x0f, + 0xd5, 0xe0, 0x0a, 0xba, 0xe7, 0x9d, 0xc6, 0x60, 0x5f, 0xab, + 0xd6, 0xf5, 0xf9, 0x28, 0xe1, 0x8c, 0x63, 0x26, 0x8e, 0x1a, + 0xf4, 0x85, 0xda, 0x6c, 0xbf, 0x04, 0x16, 0xdc, 0xdc, 0x5f, + 0xb8, 0xbc, 0x9c, 0x94, 0xb6 ) ); + +/** Test 5 */ +HASH_DF_TEST ( test_5, + INPUT ( 0x01, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, + 0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, + 0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, + 0x28, 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97, + 0xab, 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d, + 0x94, 0xbe, 0xe3, 0x3c, 0xbb, 0x89, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6 ), + EXPECT ( 0x0a, 0x04, 0x41, 0xa5, 0x2b, 0xed, 0xf7, 0x94, 0xf5, 0xaa, + 0x62, 0x7b, 0xcb, 0xd8, 0x1f, 0x93, 0xe0, 0x11, 0xd5, 0x1f, + 0x34, 0x74, 0x80, 0x2c, 0x37, 0x50, 0x76, 0x75, 0x51, 0xb4, + 0x5b, 0x69, 0xf3, 0xd3, 0x59, 0x39, 0xc9, 0x32, 0xae, 0x1c, + 0xb7, 0xc9, 0x89, 0x4f, 0xb8, 0x84, 0x65, 0xe0, 0xcf, 0xd1, + 0xcc, 0x26, 0x1e, 0x22, 0xc5 ) ); + +/** Test 6 */ +HASH_DF_TEST ( test_6, + INPUT ( 0x00, 0x0a, 0x04, 0x41, 0xa5, 0x2b, 0xed, 0xf7, 0x94, 0xf5, + 0xaa, 0x62, 0x7b, 0xcb, 0xd8, 0x1f, 0x93, 0xe0, 0x11, 0xd5, + 0x1f, 0x34, 0x74, 0x80, 0x2c, 0x37, 0x50, 0x76, 0x75, 0x51, + 0xb4, 0x5b, 0x69, 0xf3, 0xd3, 0x59, 0x39, 0xc9, 0x32, 0xae, + 0x1c, 0xb7, 0xc9, 0x89, 0x4f, 0xb8, 0x84, 0x65, 0xe0, 0xcf, + 0xd1, 0xcc, 0x26, 0x1e, 0x22, 0xc5 ), + EXPECT ( 0x04, 0x11, 0xc8, 0xb0, 0xdb, 0xa7, 0x56, 0xe8, 0x84, 0x2b, + 0x3f, 0xb0, 0x2d, 0x2f, 0xeb, 0x7c, 0xee, 0xa5, 0x67, 0x42, + 0xee, 0x93, 0x79, 0xc9, 0x0e, 0x6d, 0x3b, 0x2f, 0x10, 0x10, + 0xd4, 0x0f, 0x4f, 0x4d, 0xca, 0xda, 0x61, 0xcf, 0xdf, 0xb4, + 0x8a, 0xf8, 0x47, 0xca, 0xcc, 0x4c, 0x92, 0xc6, 0x14, 0x44, + 0x85, 0xc2, 0x27, 0xca, 0x05 ) ); + +/** Test 7 */ +HASH_DF_TEST ( test_7, + INPUT ( 0x01, 0x0e, 0x16, 0x0a, 0x56, 0x07, 0x95, 0x4e, 0x7d, 0x79, + 0xd5, 0xa2, 0x2b, 0xf9, 0x08, 0x0b, 0x10, 0xce, 0xb7, 0x3c, + 0x62, 0x23, 0x07, 0xf9, 0xf5, 0x45, 0xbd, 0xb1, 0xa4, 0x61, + 0xc5, 0x2f, 0x79, 0x43, 0x21, 0x24, 0x3a, 0xac, 0xe2, 0x3f, + 0x36, 0x3f, 0xef, 0xb3, 0x5d, 0xc5, 0xbe, 0xa7, 0xe7, 0x31, + 0x44, 0x14, 0xcf, 0x78, 0xb3, 0xf9, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6 ), + EXPECT ( 0xdc, 0x24, 0xdf, 0x10, 0x2f, 0xa9, 0xf9, 0x6c, 0xc1, 0xcf, + 0xf8, 0xc1, 0x16, 0xc7, 0x9d, 0x14, 0x97, 0xd7, 0xc2, 0x7b, + 0xba, 0x5b, 0xa8, 0x01, 0xe1, 0x56, 0x21, 0x93, 0x35, 0x3f, + 0x31, 0xe3, 0x22, 0x39, 0x57, 0x84, 0x69, 0xb8, 0x0f, 0x2f, + 0x51, 0x64, 0x54, 0x37, 0x28, 0x71, 0x7f, 0x17, 0x1f, 0xdb, + 0x02, 0xb2, 0xad, 0x57, 0x95 ) ); + +/** Test 8 */ +HASH_DF_TEST ( test_8, + INPUT ( 0x00, 0xdc, 0x24, 0xdf, 0x10, 0x2f, 0xa9, 0xf9, 0x6c, 0xc1, + 0xcf, 0xf8, 0xc1, 0x16, 0xc7, 0x9d, 0x14, 0x97, 0xd7, 0xc2, + 0x7b, 0xba, 0x5b, 0xa8, 0x01, 0xe1, 0x56, 0x21, 0x93, 0x35, + 0x3f, 0x31, 0xe3, 0x22, 0x39, 0x57, 0x84, 0x69, 0xb8, 0x0f, + 0x2f, 0x51, 0x64, 0x54, 0x37, 0x28, 0x71, 0x7f, 0x17, 0x1f, + 0xdb, 0x02, 0xb2, 0xad, 0x57, 0x95 ), + EXPECT ( 0xff, 0xaf, 0x45, 0x66, 0x5b, 0x11, 0x0c, 0xa1, 0x33, 0x5a, + 0x3f, 0xce, 0x73, 0xa7, 0x98, 0x1d, 0x0f, 0xd5, 0xc8, 0xd9, + 0x03, 0xf6, 0x5f, 0xaa, 0x46, 0xa3, 0xd5, 0x97, 0xbf, 0x34, + 0xc4, 0xe0, 0xcc, 0x16, 0x75, 0x60, 0xab, 0x94, 0xec, 0x10, + 0xd6, 0x41, 0x5f, 0x37, 0x83, 0xb0, 0x15, 0x67, 0x89, 0x1b, + 0x57, 0x66, 0x2a, 0xbb, 0x39 ) ); + +/** Test 9 */ +HASH_DF_TEST ( test_9, + INPUT ( 0x01, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, + 0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, + 0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, + 0x28, 0x39, 0x36, 0x6d, 0x96, 0x34, 0x8c, 0xfe, 0x8c, 0x97, + 0xab, 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d, + 0x94, 0xbe, 0xe3, 0x3c, 0xbb, 0x89, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, + 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ), + EXPECT ( 0x8f, 0xde, 0xc9, 0xe6, 0x18, 0x96, 0x36, 0xf0, 0xa5, 0xce, + 0x53, 0xe8, 0x1c, 0x13, 0xac, 0x93, 0x84, 0xfa, 0xfb, 0xa0, + 0xee, 0x50, 0xc1, 0xe2, 0xc8, 0xa0, 0x99, 0xde, 0x41, 0xd8, + 0xcc, 0x7a, 0x31, 0x42, 0x9e, 0x8c, 0x8c, 0x88, 0x80, 0xe3, + 0xb4, 0x5d, 0x89, 0xdb, 0x61, 0x2c, 0xd9, 0xd2, 0x8a, 0x55, + 0xc0, 0xf0, 0xd1, 0xf8, 0xf9 ) ); + +/** Test 10 */ +HASH_DF_TEST ( test_10, + INPUT ( 0x00, 0x8f, 0xde, 0xc9, 0xe6, 0x18, 0x96, 0x36, 0xf0, 0xa5, + 0xce, 0x53, 0xe8, 0x1c, 0x13, 0xac, 0x93, 0x84, 0xfa, 0xfb, + 0xa0, 0xee, 0x50, 0xc1, 0xe2, 0xc8, 0xa0, 0x99, 0xde, 0x41, + 0xd8, 0xcc, 0x7a, 0x31, 0x42, 0x9e, 0x8c, 0x8c, 0x88, 0x80, + 0xe3, 0xb4, 0x5d, 0x89, 0xdb, 0x61, 0x2c, 0xd9, 0xd2, 0x8a, + 0x55, 0xc0, 0xf0, 0xd1, 0xf8, 0xf9 ), + EXPECT ( 0x97, 0xd0, 0x76, 0x31, 0xb2, 0x2f, 0x7c, 0x95, 0x7f, 0x19, + 0xf8, 0x44, 0xf4, 0xdc, 0x2a, 0xfa, 0x6f, 0xf9, 0x7c, 0x35, + 0x66, 0x18, 0x98, 0x21, 0x69, 0x91, 0xd1, 0x5b, 0xda, 0x75, + 0xbb, 0xd0, 0x5e, 0xdf, 0x8a, 0x0f, 0xa8, 0x0c, 0xca, 0xb9, + 0x51, 0x95, 0xf4, 0x79, 0xcd, 0x76, 0x20, 0x22, 0x35, 0x10, + 0x2e, 0xf6, 0x27, 0x29, 0x19 ) ); + +/** Test 11 */ +HASH_DF_TEST ( test_11, + INPUT ( 0x01, 0x27, 0xaf, 0x40, 0x17, 0xca, 0xc5, 0xb3, 0x86, 0x24, + 0xe8, 0x4c, 0x2d, 0x10, 0xef, 0xd7, 0x8d, 0xf4, 0xf4, 0x77, + 0xd6, 0x54, 0x69, 0x5a, 0x04, 0x32, 0x32, 0x6b, 0x3a, 0x1c, + 0x4e, 0x88, 0x4a, 0x90, 0x22, 0x28, 0xe8, 0x9e, 0xaa, 0x90, + 0x36, 0xcd, 0x2a, 0xf7, 0x05, 0x66, 0x81, 0x26, 0x23, 0x72, + 0xc7, 0x13, 0x71, 0xd4, 0x53, 0x3d, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ), + EXPECT ( 0x2c, 0x9c, 0x0d, 0x80, 0x03, 0xe3, 0x40, 0x23, 0xbe, 0x5b, + 0x63, 0xfd, 0xb9, 0xd2, 0x24, 0xb4, 0x25, 0x0c, 0xc8, 0x15, + 0x5b, 0xd1, 0xee, 0xd8, 0xe5, 0x5d, 0x91, 0x06, 0x2f, 0xdd, + 0x27, 0x64, 0xb8, 0xae, 0xa9, 0xc8, 0x2f, 0x84, 0x7e, 0x09, + 0xa3, 0xfe, 0xa1, 0xc7, 0x11, 0x7d, 0x6f, 0x7d, 0xd2, 0xef, + 0x77, 0x7d, 0x7c, 0xf3, 0xeb ) ); + +/** Test 12 */ +HASH_DF_TEST ( test_12, + INPUT ( 0x00, 0x2c, 0x9c, 0x0d, 0x80, 0x03, 0xe3, 0x40, 0x23, 0xbe, + 0x5b, 0x63, 0xfd, 0xb9, 0xd2, 0x24, 0xb4, 0x25, 0x0c, 0xc8, + 0x15, 0x5b, 0xd1, 0xee, 0xd8, 0xe5, 0x5d, 0x91, 0x06, 0x2f, + 0xdd, 0x27, 0x64, 0xb8, 0xae, 0xa9, 0xc8, 0x2f, 0x84, 0x7e, + 0x09, 0xa3, 0xfe, 0xa1, 0xc7, 0x11, 0x7d, 0x6f, 0x7d, 0xd2, + 0xef, 0x77, 0x7d, 0x7c, 0xf3, 0xeb ), + EXPECT ( 0x7e, 0x8a, 0xa4, 0x93, 0x42, 0x72, 0xf2, 0xa2, 0x8b, 0xbf, + 0xd7, 0xaf, 0xcc, 0x88, 0xce, 0x1c, 0x80, 0x6a, 0x38, 0xea, + 0x7b, 0x89, 0x45, 0xc8, 0xd1, 0xb6, 0xf1, 0x75, 0x03, 0x78, + 0x54, 0x6a, 0xb1, 0xa2, 0x96, 0x00, 0xd6, 0x44, 0xec, 0x52, + 0x0e, 0x8b, 0xff, 0xf6, 0x0c, 0xb7, 0x7f, 0xa5, 0x4b, 0xb1, + 0x1a, 0x83, 0x31, 0xcb, 0x24 ) ); + +/** Test 13 */ +HASH_DF_TEST ( test_13, + INPUT ( 0x01, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, + 0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, + 0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, + 0xd0, 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d, + 0x58, 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a, + 0x93, 0x32, 0x4b, 0x27, 0xbd, 0xe8, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6 ), + EXPECT ( 0xe5, 0x04, 0x3d, 0x1b, 0x95, 0x4b, 0x34, 0xba, 0x60, 0xd2, + 0x48, 0xe8, 0x83, 0xef, 0x49, 0x8c, 0x5c, 0x52, 0x36, 0xb8, + 0x26, 0x0e, 0x23, 0x8e, 0x02, 0xc8, 0xd4, 0xfc, 0x5f, 0xfe, + 0x90, 0xfa, 0x40, 0x13, 0x44, 0x70, 0x75, 0xbb, 0x54, 0x3e, + 0xf0, 0x0c, 0x3b, 0xda, 0x59, 0x6b, 0x10, 0x88, 0x61, 0xf0, + 0x6b, 0xf9, 0x1b, 0x45, 0xd6 ) ); + +/** Test 14 */ +HASH_DF_TEST ( test_14, + INPUT ( 0x00, 0xe5, 0x04, 0x3d, 0x1b, 0x95, 0x4b, 0x34, 0xba, 0x60, + 0xd2, 0x48, 0xe8, 0x83, 0xef, 0x49, 0x8c, 0x5c, 0x52, 0x36, + 0xb8, 0x26, 0x0e, 0x23, 0x8e, 0x02, 0xc8, 0xd4, 0xfc, 0x5f, + 0xfe, 0x90, 0xfa, 0x40, 0x13, 0x44, 0x70, 0x75, 0xbb, 0x54, + 0x3e, 0xf0, 0x0c, 0x3b, 0xda, 0x59, 0x6b, 0x10, 0x88, 0x61, + 0xf0, 0x6b, 0xf9, 0x1b, 0x45, 0xd6 ), + EXPECT ( 0x1f, 0x3f, 0x63, 0x10, 0xed, 0x10, 0xfc, 0x9f, 0x93, 0x8c, + 0x43, 0x22, 0x61, 0xaf, 0x42, 0xe9, 0xe9, 0x17, 0x5f, 0x08, + 0x0f, 0x32, 0x22, 0xdc, 0x11, 0x8b, 0xa7, 0xcf, 0x88, 0x8c, + 0xdc, 0x3f, 0x36, 0x0d, 0xd2, 0x8f, 0x5e, 0xcb, 0x7c, 0x80, + 0xa6, 0xbc, 0xfc, 0xfc, 0x0f, 0x51, 0xfe, 0x2f, 0x77, 0xc1, + 0xc9, 0x9d, 0xf0, 0xa2, 0x09 ) ); + +/** Test 15 */ +HASH_DF_TEST ( test_15, + INPUT ( 0x01, 0x04, 0x43, 0xa0, 0x2c, 0x82, 0x5c, 0x31, 0x59, 0xf4, + 0x5e, 0x8c, 0x0a, 0xe5, 0x9e, 0x8c, 0x76, 0x45, 0x69, 0x95, + 0xc0, 0x35, 0x40, 0x46, 0x6a, 0x14, 0x54, 0x7c, 0xcb, 0xe8, + 0x8b, 0x6d, 0x39, 0x76, 0x21, 0x17, 0x32, 0x84, 0x72, 0xf5, + 0x2b, 0x84, 0x57, 0x5a, 0xaf, 0xe8, 0x8b, 0x2d, 0x1e, 0x50, + 0x4f, 0x21, 0xec, 0x4e, 0x31, 0x35, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6 ), + EXPECT ( 0x9d, 0xc3, 0x52, 0x08, 0xee, 0x2b, 0x8c, 0x58, 0x1e, 0xa3, + 0x0b, 0xaa, 0xcb, 0x5d, 0x74, 0x31, 0x7a, 0x87, 0x94, 0x54, + 0x10, 0x71, 0x7e, 0x58, 0xd3, 0x70, 0x5f, 0xbd, 0xc7, 0x60, + 0xbe, 0x0c, 0xc9, 0x0e, 0xd1, 0xcc, 0xbb, 0x89, 0x7d, 0x47, + 0xd2, 0x7e, 0x2b, 0x2e, 0x42, 0x2b, 0x32, 0xb9, 0x7f, 0x05, + 0x0d, 0x1b, 0xd2, 0xb4, 0x90 ) ); + +/** Test 16 */ +HASH_DF_TEST ( test_16, + INPUT ( 0x00, 0x9d, 0xc3, 0x52, 0x08, 0xee, 0x2b, 0x8c, 0x58, 0x1e, + 0xa3, 0x0b, 0xaa, 0xcb, 0x5d, 0x74, 0x31, 0x7a, 0x87, 0x94, + 0x54, 0x10, 0x71, 0x7e, 0x58, 0xd3, 0x70, 0x5f, 0xbd, 0xc7, + 0x60, 0xbe, 0x0c, 0xc9, 0x0e, 0xd1, 0xcc, 0xbb, 0x89, 0x7d, + 0x47, 0xd2, 0x7e, 0x2b, 0x2e, 0x42, 0x2b, 0x32, 0xb9, 0x7f, + 0x05, 0x0d, 0x1b, 0xd2, 0xb4, 0x90 ), + EXPECT ( 0x1a, 0x5a, 0xd6, 0xce, 0xa3, 0xd1, 0x5d, 0xa5, 0xfb, 0x47, + 0x42, 0x13, 0x13, 0x09, 0xf0, 0xed, 0x88, 0xcf, 0x4c, 0x90, + 0xa6, 0xc1, 0xcc, 0xee, 0x35, 0xa8, 0x76, 0xeb, 0xfc, 0xcc, + 0x82, 0x67, 0x29, 0xb6, 0x63, 0x9f, 0x81, 0x19, 0x65, 0xb0, + 0xef, 0x85, 0x76, 0xe7, 0x5c, 0xb3, 0xcf, 0xe8, 0x22, 0x07, + 0x68, 0xb2, 0x6c, 0xe7, 0x7a ) ); + +/** Test 17 */ +HASH_DF_TEST ( test_17, + INPUT ( 0x01, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, + 0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, + 0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, + 0xd0, 0x85, 0x8e, 0x9e, 0x3b, 0x90, 0x26, 0xd4, 0xe7, 0x7d, + 0x58, 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a, + 0x93, 0x32, 0x4b, 0x27, 0xbd, 0xe8, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, + 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ), + EXPECT ( 0x56, 0x3a, 0x5d, 0x20, 0x7d, 0x37, 0x70, 0x7b, 0xf5, 0xf2, + 0x4d, 0x0b, 0xd4, 0x93, 0x5d, 0xc3, 0x8d, 0xbe, 0x04, 0x36, + 0x37, 0xb3, 0xff, 0x8a, 0xb6, 0x8c, 0xfc, 0xe2, 0xf2, 0x90, + 0xd1, 0x69, 0x95, 0x20, 0x55, 0x24, 0x19, 0x0f, 0xd2, 0x91, + 0xaa, 0x8a, 0x6e, 0x6b, 0x8e, 0x6d, 0x56, 0xa4, 0x31, 0x33, + 0x3b, 0x40, 0x8e, 0x6f, 0xa8 ) ); + +/** Test 18 */ +HASH_DF_TEST ( test_18, + INPUT ( 0x00, 0x56, 0x3a, 0x5d, 0x20, 0x7d, 0x37, 0x70, 0x7b, 0xf5, + 0xf2, 0x4d, 0x0b, 0xd4, 0x93, 0x5d, 0xc3, 0x8d, 0xbe, 0x04, + 0x36, 0x37, 0xb3, 0xff, 0x8a, 0xb6, 0x8c, 0xfc, 0xe2, 0xf2, + 0x90, 0xd1, 0x69, 0x95, 0x20, 0x55, 0x24, 0x19, 0x0f, 0xd2, + 0x91, 0xaa, 0x8a, 0x6e, 0x6b, 0x8e, 0x6d, 0x56, 0xa4, 0x31, + 0x33, 0x3b, 0x40, 0x8e, 0x6f, 0xa8 ), + EXPECT ( 0xc5, 0xd3, 0xe9, 0x55, 0x1e, 0x00, 0xe4, 0xee, 0x32, 0xb2, + 0x11, 0x6f, 0xaf, 0x4d, 0xef, 0xf4, 0xd4, 0xcf, 0xad, 0x2b, + 0xdc, 0x2d, 0xba, 0xa2, 0xe0, 0xe7, 0xf9, 0xdd, 0xb9, 0xd8, + 0x1e, 0xed, 0x45, 0xe0, 0xa5, 0x0d, 0xa5, 0xaf, 0xd5, 0xc1, + 0xf6, 0xbc, 0xda, 0xf8, 0x1d, 0x28, 0x9c, 0xf4, 0xbd, 0x3c, + 0x91, 0xb7, 0x00, 0x5c, 0x18 ) ); + +/** Test 19 */ +HASH_DF_TEST ( test_19, + INPUT ( 0x01, 0x1c, 0x0e, 0x46, 0x75, 0x9b, 0x38, 0x55, 0x6a, 0x28, + 0xa4, 0x5e, 0x7b, 0x83, 0xe1, 0x4d, 0xb8, 0x62, 0x8d, 0xb1, + 0x62, 0x13, 0xe1, 0xba, 0x2d, 0x97, 0x74, 0xf6, 0xc0, 0xac, + 0x68, 0xf0, 0x56, 0xdb, 0x00, 0xfb, 0x12, 0xe1, 0x5b, 0xf4, + 0xde, 0x95, 0x50, 0xb7, 0x33, 0x1e, 0x2d, 0xbd, 0x66, 0x4c, + 0x3a, 0xb7, 0x76, 0xe8, 0x25, 0x51, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ), + EXPECT ( 0x60, 0x01, 0x93, 0xc8, 0xf6, 0x03, 0x1a, 0x2d, 0x49, 0x37, + 0x2a, 0x8b, 0x0f, 0x60, 0xf6, 0x8c, 0x1d, 0xfd, 0xac, 0xd4, + 0xf8, 0xea, 0x01, 0x37, 0x47, 0xd7, 0x14, 0x82, 0x33, 0x3d, + 0xf5, 0x25, 0x2e, 0x95, 0xb8, 0x22, 0x57, 0x39, 0x1b, 0xf1, + 0x0a, 0xb0, 0x7d, 0x12, 0x08, 0xb6, 0xbd, 0x66, 0x5b, 0x30, + 0x0a, 0xa4, 0xdb, 0x9c, 0x3e ) ); + +/** Test 20 */ +HASH_DF_TEST ( test_20, + INPUT ( 0x00, 0x60, 0x01, 0x93, 0xc8, 0xf6, 0x03, 0x1a, 0x2d, 0x49, + 0x37, 0x2a, 0x8b, 0x0f, 0x60, 0xf6, 0x8c, 0x1d, 0xfd, 0xac, + 0xd4, 0xf8, 0xea, 0x01, 0x37, 0x47, 0xd7, 0x14, 0x82, 0x33, + 0x3d, 0xf5, 0x25, 0x2e, 0x95, 0xb8, 0x22, 0x57, 0x39, 0x1b, + 0xf1, 0x0a, 0xb0, 0x7d, 0x12, 0x08, 0xb6, 0xbd, 0x66, 0x5b, + 0x30, 0x0a, 0xa4, 0xdb, 0x9c, 0x3e ), + EXPECT ( 0x6b, 0x71, 0x82, 0x3b, 0x18, 0x20, 0x07, 0x71, 0xca, 0xae, + 0x5d, 0x12, 0x55, 0xc1, 0x40, 0x3e, 0xdf, 0xe3, 0x8b, 0x4d, + 0x18, 0xc7, 0x87, 0xbb, 0x44, 0xcd, 0x17, 0x18, 0x61, 0x52, + 0xef, 0xea, 0xd6, 0xfd, 0xc4, 0xb8, 0x94, 0xf9, 0x20, 0x02, + 0xc0, 0x72, 0x09, 0x55, 0x5d, 0x7e, 0x35, 0x54, 0xf9, 0xd1, + 0x2f, 0xc5, 0x59, 0x7f, 0x22 ) ); + +/** + * Report Hash_df test result + * + * @v test Hash_df test + */ +#define hash_df_ok( test ) do { \ + uint8_t output[ (test)->expected_len ]; \ + hash_df ( (test)->input, (test)->input_len, output, \ + sizeof ( output ) ); \ + ok ( memcmp ( (test)->expected, output, \ + sizeof ( output ) ) == 0 ); \ + } while ( 0 ) + +/** + * Perform Hash_df self-test + * + */ +static void hash_df_test_exec ( void ) { + + hash_df_ok ( &test_1 ); + hash_df_ok ( &test_2 ); + hash_df_ok ( &test_3 ); + hash_df_ok ( &test_4 ); + hash_df_ok ( &test_5 ); + hash_df_ok ( &test_6 ); + hash_df_ok ( &test_7 ); + hash_df_ok ( &test_8 ); + hash_df_ok ( &test_9 ); + hash_df_ok ( &test_10 ); + hash_df_ok ( &test_11 ); + hash_df_ok ( &test_12 ); + hash_df_ok ( &test_13 ); + hash_df_ok ( &test_14 ); + hash_df_ok ( &test_15 ); + hash_df_ok ( &test_16 ); + hash_df_ok ( &test_17 ); + hash_df_ok ( &test_18 ); + hash_df_ok ( &test_19 ); + hash_df_ok ( &test_20 ); +} + +/** Hash_df self-test */ +struct self_test hash_df_test __self_test = { + .name = "hash_df", + .exec = hash_df_test_exec, +}; diff --git a/src/tests/test.c b/src/tests/test.c index b5cc8506..7e869053 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -142,3 +142,4 @@ struct init_fn test_init_fn __init_fn ( INIT_NORMAL ) = { REQUIRE_OBJECT ( list_test ); REQUIRE_OBJECT ( sha1_test ); REQUIRE_OBJECT ( hmac_drbg_test ); +REQUIRE_OBJECT ( hash_df_test ); From 464ca5dbc0905afc969557396422af0d1c3d31d0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 19 Feb 2012 22:08:51 +0000 Subject: [PATCH 003/221] [i386] Add missing #include in pic8259.h Signed-off-by: Michael Brown --- src/arch/i386/include/pic8259.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/arch/i386/include/pic8259.h b/src/arch/i386/include/pic8259.h index f8e20c4c..a07e97d3 100644 --- a/src/arch/i386/include/pic8259.h +++ b/src/arch/i386/include/pic8259.h @@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #ifndef PIC8259_H #define PIC8259_H +#include + /* For segoff_t */ #include "realmode.h" From bb36f3d7dc5bab4ddf7d31f2a72ff175584cb2ed Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 20 Feb 2012 19:29:49 +0000 Subject: [PATCH 004/221] [udp] Propagate transmission errors to UDP interface users Suggested-by: Simon Rowe Signed-off-by: Michael Brown --- src/net/udp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/net/udp.c b/src/net/udp.c index 5f452535..20badb7f 100644 --- a/src/net/udp.c +++ b/src/net/udp.c @@ -386,10 +386,9 @@ static int udp_xfer_deliver ( struct udp_connection *udp, struct xfer_metadata *meta ) { /* Transmit data, if possible */ - udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ), - ( ( struct sockaddr_tcpip * ) meta->dest ), meta->netdev ); - - return 0; + return udp_tx ( udp, iobuf, ( ( struct sockaddr_tcpip * ) meta->src ), + ( ( struct sockaddr_tcpip * ) meta->dest ), + meta->netdev ); } /** UDP data transfer interface operations */ From a8756182c362866e88fedca812500c24420115f8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 21 Feb 2012 12:25:06 +0000 Subject: [PATCH 005/221] [802.11] Add missing #include Signed-off-by: Michael Brown --- src/crypto/sha1extra.c | 1 + src/net/80211/wpa_ccmp.c | 1 + src/net/80211/wpa_psk.c | 1 + src/net/80211/wpa_tkip.c | 1 + 4 files changed, 4 insertions(+) diff --git a/src/crypto/sha1extra.c b/src/crypto/sha1extra.c index 74445e9d..12b29a6a 100644 --- a/src/crypto/sha1extra.c +++ b/src/crypto/sha1extra.c @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include diff --git a/src/net/80211/wpa_ccmp.c b/src/net/80211/wpa_ccmp.c index 89bb36fd..38fd199f 100644 --- a/src/net/80211/wpa_ccmp.c +++ b/src/net/80211/wpa_ccmp.c @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include diff --git a/src/net/80211/wpa_psk.c b/src/net/80211/wpa_psk.c index 780738e7..c88f556e 100644 --- a/src/net/80211/wpa_psk.c +++ b/src/net/80211/wpa_psk.c @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include diff --git a/src/net/80211/wpa_tkip.c b/src/net/80211/wpa_tkip.c index 0a94df07..8bb3e5aa 100644 --- a/src/net/80211/wpa_tkip.c +++ b/src/net/80211/wpa_tkip.c @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include From a99d5d5aca298c0618919d9be33ac5e73cb838e7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 21 Feb 2012 12:39:20 +0000 Subject: [PATCH 006/221] [rng] Add missing #include Signed-off-by: Michael Brown --- src/crypto/drbg.c | 1 + src/crypto/hash_df.c | 1 + src/crypto/hmac_drbg.c | 1 + src/tests/hash_df_test.c | 1 + src/tests/hmac_drbg_test.c | 1 + 5 files changed, 5 insertions(+) diff --git a/src/crypto/drbg.c b/src/crypto/drbg.c index 68aa7857..58e8fa7b 100644 --- a/src/crypto/drbg.c +++ b/src/crypto/drbg.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #include +#include #include #include #include diff --git a/src/crypto/hash_df.c b/src/crypto/hash_df.c index 4c2d28a9..9e3da181 100644 --- a/src/crypto/hash_df.c +++ b/src/crypto/hash_df.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #include +#include #include #include #include diff --git a/src/crypto/hmac_drbg.c b/src/crypto/hmac_drbg.c index 64613d01..efbd67dc 100644 --- a/src/crypto/hmac_drbg.c +++ b/src/crypto/hmac_drbg.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #include +#include #include #include #include diff --git a/src/tests/hash_df_test.c b/src/tests/hash_df_test.c index 563704f4..201b4a18 100644 --- a/src/tests/hash_df_test.c +++ b/src/tests/hash_df_test.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #undef NDEBUG #include +#include #include #include diff --git a/src/tests/hmac_drbg_test.c b/src/tests/hmac_drbg_test.c index cf066620..ad5584f1 100644 --- a/src/tests/hmac_drbg_test.c +++ b/src/tests/hmac_drbg_test.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #undef NDEBUG #include +#include #include #include From c2668b61ea5ac01279929be6be86cc04fd342ab5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 20 Feb 2012 21:24:30 +0000 Subject: [PATCH 007/221] [rng] Record validity within DRBG state Treat an empty (zeroed) DRBG as invalid. This ensures that a DRBG that has not yet been instantiated (or that has been uninstantiated) will refuse to attempt to generate random bits. Signed-off-by: Michael Brown --- src/crypto/drbg.c | 17 +++++++++++++---- src/include/ipxe/drbg.h | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/crypto/drbg.c b/src/crypto/drbg.c index 58e8fa7b..88cf3acd 100644 --- a/src/crypto/drbg.c +++ b/src/crypto/drbg.c @@ -151,6 +151,7 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal, * in-situ.) */ state->reseed_required = 0; + state->valid = 1; /* 12. Return SUCCESS and state_handle. */ return 0; @@ -187,9 +188,13 @@ int drbg_reseed ( struct drbg_state *state, const void *additional, * If state_handle indicates an invalid or empty internal * state, return an ERROR_FLAG. * - * (Nothing to do since the memory holding the internal state - * was passed in by the caller.) + * (Almost nothing to do since the memory holding the internal + * state was passed in by the caller.) */ + if ( ! state->valid ) { + DBGC ( state, "DRBG %p not valid\n", state ); + return -EINVAL; + } /* 2. If prediction_resistance_request is set, and * prediction_resistance_flag is not set, then return an @@ -273,9 +278,13 @@ int drbg_generate ( struct drbg_state *state, const void *additional, * for the instantiation. If state_handle indicates an * invalid or empty internal state, then return an ERROR_FLAG. * - * (Nothing to do since the memory holding the internal state - * was passed in by the caller.) + * (Almost nothing to do since the memory holding the internal + * state was passed in by the caller.) */ + if ( ! state->valid ) { + DBGC ( state, "DRBG %p not valid\n", state ); + return -EINVAL; + } /* 2. If requested_number_of_bits > * max_number_of_bits_per_request, then return an diff --git a/src/include/ipxe/drbg.h b/src/include/ipxe/drbg.h index a09d136d..3cf4584a 100644 --- a/src/include/ipxe/drbg.h +++ b/src/include/ipxe/drbg.h @@ -39,6 +39,8 @@ struct drbg_state { struct hmac_drbg_state internal; /** Reseed required flag */ int reseed_required; + /** State is valid */ + int valid; }; /** From 073f41085f0791593d96233ef617fcefe3cdacb9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 19 Feb 2012 22:14:06 +0000 Subject: [PATCH 008/221] [rng] Add ANS X9.82 Approved Source of Entropy Input ANS X9.82 specifies several Approved Sources of Entropy Input (SEI). One such SEI uses an entropy source as the Source of Entropy Input, condensing each entropy source output after each GetEntropy call. This can be implemented relatively cheaply in iPXE and avoids the need to allocate potentially very large buffers. (Note that the terms "entropy source" and "Source of Entropy Input" are not synonyms within the context of ANS X9.82.) Use the iPXE API mechanism to allow entropy sources to be selected at compilation time. Signed-off-by: Michael Brown --- src/arch/i386/include/bits/entropy.h | 12 ++ src/arch/x86_64/include/bits/entropy.h | 12 ++ src/config/defaults/efi.h | 1 + src/config/defaults/linux.h | 1 + src/config/defaults/pcbios.h | 1 + src/config/entropy.h | 16 ++ src/crypto/drbg.c | 4 +- src/crypto/entropy.c | 128 +++++++++++++-- src/crypto/null_entropy.c | 35 +++++ src/include/ipxe/entropy.h | 210 +++++++++++++++++++------ src/include/ipxe/hmac_drbg.h | 4 +- src/include/ipxe/null_entropy.h | 51 ++++++ 12 files changed, 410 insertions(+), 65 deletions(-) create mode 100644 src/arch/i386/include/bits/entropy.h create mode 100644 src/arch/x86_64/include/bits/entropy.h create mode 100644 src/config/entropy.h create mode 100644 src/crypto/null_entropy.c create mode 100644 src/include/ipxe/null_entropy.h diff --git a/src/arch/i386/include/bits/entropy.h b/src/arch/i386/include/bits/entropy.h new file mode 100644 index 00000000..db8ba18e --- /dev/null +++ b/src/arch/i386/include/bits/entropy.h @@ -0,0 +1,12 @@ +#ifndef _BITS_ENTROPY_H +#define _BITS_ENTROPY_H + +/** @file + * + * i386-specific entropy API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#endif /* _BITS_ENTROPY_H */ diff --git a/src/arch/x86_64/include/bits/entropy.h b/src/arch/x86_64/include/bits/entropy.h new file mode 100644 index 00000000..9c64c833 --- /dev/null +++ b/src/arch/x86_64/include/bits/entropy.h @@ -0,0 +1,12 @@ +#ifndef _BITS_ENTROPY_H +#define _BITS_ENTROPY_H + +/** @file + * + * x86_64-specific entropy API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#endif /* _BITS_ENTROPY_H */ diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 693f55ad..c0bb78da 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -17,6 +17,7 @@ #define SMBIOS_EFI #define SANBOOT_NULL #define BOFM_EFI +#define ENTROPY_NULL #define IMAGE_EFI /* EFI image support */ #define IMAGE_SCRIPT /* iPXE script image support */ diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 647dc0a5..6b24da48 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -14,6 +14,7 @@ #define NAP_LINUX #define SMBIOS_LINUX #define SANBOOT_NULL +#define ENTROPY_NULL #define DRIVERS_LINUX diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 59adbf78..fb44d0e1 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define UMALLOC_MEMTOP #define SMBIOS_PCBIOS #define SANBOOT_PCBIOS +#define ENTROPY_NULL #define IMAGE_ELF /* ELF image support */ #define IMAGE_MULTIBOOT /* MultiBoot image support */ diff --git a/src/config/entropy.h b/src/config/entropy.h new file mode 100644 index 00000000..7de2f673 --- /dev/null +++ b/src/config/entropy.h @@ -0,0 +1,16 @@ +#ifndef CONFIG_ENTROPY_H +#define CONFIG_ENTROPY_H + +/** @file + * + * Entropy API configuration + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +#include + +#endif /* CONFIG_ENTROPY_H */ diff --git a/src/crypto/drbg.c b/src/crypto/drbg.c index 88cf3acd..afd75da3 100644 --- a/src/crypto/drbg.c +++ b/src/crypto/drbg.c @@ -63,7 +63,7 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal, unsigned int entropy_bits = ( ( 3 * DRBG_SECURITY_STRENGTH + 1 ) / 2 ); size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES; size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES; - uint8_t data[ entropy_bufsize ( entropy_bits, min_len, max_len ) ]; + uint8_t data[max_len]; int len; int rc; @@ -175,7 +175,7 @@ int drbg_reseed ( struct drbg_state *state, const void *additional, unsigned int entropy_bits = DRBG_SECURITY_STRENGTH; size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES; size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES; - uint8_t data[ entropy_bufsize ( entropy_bits, min_len, max_len ) ]; + uint8_t data[max_len]; int len; int rc; diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c index 86fa8978..d5d06e57 100644 --- a/src/crypto/entropy.c +++ b/src/crypto/entropy.c @@ -22,27 +22,129 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * Entropy source * + * This algorithm is designed to comply with ANS X9.82 Part 4 (April + * 2011 Draft) Section 13.3. This standard is unfortunately not + * freely available. */ +#include +#include #include +#include +#include #include /** - * Obtain entropy input + * Get entropy sample * - * @v entropy_bits Minimum amount of entropy, in bits - * @v data Data buffer - * @v min_len Minimum length of entropy input, in bytes - * @v max_len Maximum length of entropy input, in bytes - * @ret len Length of entropy input, in bytes + * @ret entropy Entropy sample + * @ret rc Return status code + * + * This is the GetEntropy function defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 6.5.1. */ -int get_entropy_input ( unsigned int entropy_bits, void *data, size_t min_len, - size_t max_len ) { +static int get_entropy ( entropy_sample_t *entropy ) { + noise_sample_t noise; + int rc; - /* Placeholder to allow remainder of RBG code to be tested */ - ( void ) entropy_bits; - ( void ) min_len; - memset ( data, 0x01, max_len ); + /* Get noise sample */ + if ( ( rc = get_noise ( &noise ) ) != 0 ) + return rc; - return max_len; + /* We do not use any optional conditioning component */ + *entropy = noise; + + return 0; +} + +/** + * Create next nonce value + * + * @ret nonce Nonce + * + * This is the MakeNextNonce function defined in ANS X9.82 Part 4 + * (April 2011 Draft) Section 13.3.4.2. + */ +static uint32_t make_next_nonce ( void ) { + static uint32_t nonce; + + /* The simplest implementation of a nonce uses a large counter */ + nonce++; + + return nonce; +} + +/** + * Obtain entropy input temporary buffer + * + * @v num_samples Number of entropy samples + * @v tmp Temporary buffer + * @v tmp_len Length of temporary buffer + * @ret rc Return status code + * + * This is (part of) the implementation of the Get_entropy_input + * function (using an entropy source as the source of entropy input + * and condensing each entropy source output after each GetEntropy + * call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section + * 13.3.4.2. + * + * To minimise code size, the number of samples required is calculated + * at compilation time. + */ +int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, + size_t tmp_len ) { + struct { + uint32_t nonce; + entropy_sample_t sample; + } __attribute__ (( packed )) data;; + uint8_t df_buf[tmp_len]; + unsigned int i; + int rc; + + /* Enable entropy gathering */ + entropy_enable(); + + /* 3. entropy_total = 0 + * + * (Nothing to do; the number of entropy samples required has + * already been precalculated.) + */ + + /* 4. tmp = a fixed n-bit value, such as 0^n */ + memset ( tmp, 0, tmp_len ); + + /* 5. While ( entropy_total < min_entropy ) */ + while ( num_samples-- ) { + /* 5.1. ( status, entropy_bitstring, assessed_entropy ) + * = GetEntropy() + * 5.2. If status indicates an error, return ( status, Null ) + */ + if ( ( rc = get_entropy ( &data.sample ) ) != 0 ) + goto err_get_entropy; + + /* 5.3. nonce = MakeNextNonce() */ + data.nonce = make_next_nonce(); + + /* 5.4. tmp = tmp XOR + * df ( ( nonce || entropy_bitstring ), n ) + */ + hash_df ( &data, sizeof ( data ), df_buf, sizeof ( df_buf ) ); + for ( i = 0 ; i < tmp_len ; i++ ) + tmp[i] ^= df_buf[i]; + + /* 5.5. entropy_total = entropy_total + assessed_entropy + * + * (Nothing to do; the number of entropy samples + * required has already been precalculated.) + */ + } + + /* Disable entropy gathering */ + entropy_disable(); + + return 0; + + err_get_entropy: + entropy_disable(); + return rc; } diff --git a/src/crypto/null_entropy.c b/src/crypto/null_entropy.c new file mode 100644 index 00000000..be2acae3 --- /dev/null +++ b/src/crypto/null_entropy.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Nonexistent entropy source + * + * + * This source provides no entropy and must NOT be used in a + * security-sensitive environment. + */ + +#include + +PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample ); +PROVIDE_ENTROPY_INLINE ( null, entropy_enable ); +PROVIDE_ENTROPY_INLINE ( null, entropy_disable ); +PROVIDE_ENTROPY_INLINE ( null, get_noise ); diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index d9b70848..8a1974a1 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -10,9 +10,69 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include +#include +#include +#include -/** min-entropy per entropy sample +/** + * Calculate static inline entropy API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define ENTROPY_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide a entropy API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_ENTROPY( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( ENTROPY_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline entropy API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_ENTROPY_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func ) + +/** A noise sample */ +typedef uint8_t noise_sample_t; + +/** An entropy sample */ +typedef uint8_t entropy_sample_t; + +/* Include all architecture-independent entropy API headers */ +#include + +/* Include all architecture-dependent entropy API headers */ +#include + +/** + * Enable entropy gathering + * + */ +void entropy_enable ( void ); + +/** + * Disable entropy gathering + * + */ +void entropy_disable ( void ); + +/** + * min-entropy per sample + * + * @ret min_entropy min-entropy of each sample * * min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in * NIST SP 800-90 Appendix C.3 as @@ -20,71 +80,125 @@ FILE_LICENCE ( GPL2_OR_LATER ); * H_min = -log2 ( p_max ) * * where p_max is the probability of the most likely sample value. + * + * This must be a compile-time constant. */ -#define MIN_ENTROPY_PER_SAMPLE 0.16 - -/** Length of each entropy sample (in bits) */ -#define ENTROPY_SAMPLE_LEN_BITS 12 +double min_entropy_per_sample ( void ); /** - * Calculate entropy buffer size + * Get noise sample * - * @v entropy_bits Amount of entropy required, in bits - * @v min_len Minimum buffer size, in bytes - * @v max_len Maximum buffer size, in bytes - * @ret len Buffer size, in bytes + * @ret noise Noise sample + * @ret rc Return status code + * + * This is the GetNoise function defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 6.5.2. */ -static inline __attribute__ (( const, always_inline )) size_t -entropy_bufsize ( unsigned int entropy_bits, size_t min_len, size_t max_len ) { - unsigned int min_len_bits; - double min_samples; - double samples; - unsigned int samples_int; - unsigned int len_bits; - size_t len; +int get_noise ( noise_sample_t *noise ); - /* Sanity check */ - linker_assert ( MIN_ENTROPY_PER_SAMPLE <= ENTROPY_SAMPLE_LEN_BITS, +extern int get_entropy_input_tmp ( unsigned int num_samples, + uint8_t *tmp, size_t tmp_len ); + +/** + * Obtain entropy input + * + * @v min_entropy_bits Minimum amount of entropy, in bits + * @v data Data buffer + * @v min_len Minimum length of entropy input, in bytes + * @v max_len Maximum length of entropy input, in bytes + * @ret len Length of entropy input, in bytes, or negative error + * + * This is the implementation of the Get_entropy_input function (using + * an entropy source as the source of entropy input and condensing + * each entropy source output after each GetEntropy call) as defined + * in ANS X9.82 Part 4 (April 2011 Draft) Section 13.3.4.2. + * + * To minimise code size, the number of samples required is calculated + * at compilation time. + */ +static inline __attribute__ (( always_inline )) int +get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, + size_t max_len ) { + size_t tmp_len = ( ( ( min_entropy_bits * 2 ) + 7 ) / 8 ); + uint8_t tmp_buf[ tmp_len ]; + uint8_t *tmp = ( ( tmp_len > max_len ) ? tmp_buf : data ); + double min_samples; + unsigned int num_samples; + unsigned int n; + int rc; + + /* Sanity checks */ + linker_assert ( ( min_entropy_per_sample() <= + ( 8 * sizeof ( noise_sample_t ) ) ), min_entropy_per_sample_is_impossibly_high ); + linker_assert ( ( min_entropy_bits <= ( 8 * max_len ) ), + entropy_buffer_too_small ); + + /* Round up minimum entropy to an integral number of bytes */ + min_entropy_bits = ( ( min_entropy_bits + 7 ) & ~7 ); /* Calculate number of samples required to contain sufficient entropy */ - samples = ( ( entropy_bits * 1.0 ) / MIN_ENTROPY_PER_SAMPLE ); - - /* Increase to minimum length if necessary */ - min_len_bits = ( min_len * 8 ); - min_samples = ( ( min_len_bits * 1.0 ) / ENTROPY_SAMPLE_LEN_BITS ); - if ( samples < min_samples ) - samples = min_samples; + min_samples = ( ( min_entropy_bits * 1.0 ) / min_entropy_per_sample() ); /* Round up to a whole number of samples. We don't have the * ceil() function available, so do the rounding by hand. */ - samples_int = samples; - if ( samples_int < samples ) - samples_int++; - assert ( samples_int >= samples ); - - /* Calculate buffer length in bits */ - len_bits = ( samples_int * ENTROPY_SAMPLE_LEN_BITS ); - - /* Calculate buffer length in bytes (rounding up) */ - len = ( ( len_bits + 7 ) / 8 ); - - /* Check that buffer is within allowed lengths */ - linker_assert ( len >= min_len, entropy_bufsize_too_short ); - linker_assert ( len <= max_len, entropy_bufsize_too_long ); + num_samples = min_samples; + if ( num_samples < min_samples ) + num_samples++; + linker_assert ( ( num_samples >= min_samples ), rounding_error ); /* Floating-point operations are not allowed in iPXE since we * never set up a suitable environment. Abort the build - * unless the calculated length is a compile-time constant. + * unless the calculated number of samples is a compile-time + * constant. */ - linker_assert ( __builtin_constant_p ( len ), - entropy_bufsize_not_constant ); + linker_assert ( __builtin_constant_p ( num_samples ), + num_samples_not_constant ); - return len; + /* 1. If ( min_length > max_length ), then return ( FAILURE, Null ) */ + linker_assert ( ( min_len <= max_len ), min_len_greater_than_max_len ); + + /* 2. n = 2 * min_entropy */ + n = ( 2 * min_entropy_bits ); + + /* 3. entropy_total = 0 + * 4. tmp = a fixed n-bit value, such as 0^n + * 5. While ( entropy_total < min_entropy ) + * 5.1. ( status, entropy_bitstring, assessed_entropy ) + * = GetEntropy() + * 5.2. If status indicates an error, return ( status, Null ) + * 5.3. nonce = MakeNextNonce() + * 5.4. tmp = tmp XOR df ( ( nonce || entropy_bitstring ), n ) + * 5.5. entropy_total = entropy_total + assessed_entropy + * + * (The implementation of these steps is inside the function + * get_entropy_input_tmp().) + */ + linker_assert ( __builtin_constant_p ( tmp_len ), + tmp_len_not_constant ); + linker_assert ( ( n == ( 8 * tmp_len ) ), tmp_len_mismatch ); + if ( ( rc = get_entropy_input_tmp ( num_samples, tmp, tmp_len ) ) != 0 ) + return rc; + + /* 6. If ( n < min_length ), then tmp = tmp || 0^(min_length-n) + * 7. If ( n > max_length ), then tmp = df ( tmp, max_length ) + * 8. Return ( SUCCESS, tmp ) + */ + if ( tmp_len < min_len ) { + /* (Data is already in-place.) */ + linker_assert ( ( data == tmp ), data_not_inplace ); + memset ( ( data + tmp_len ), 0, ( min_len - tmp_len ) ); + return min_len; + } else if ( tmp_len > max_len ) { + linker_assert ( ( tmp == tmp_buf ), data_inplace ); + hash_df ( tmp, tmp_len, data, max_len ); + return max_len; + } else { + /* (Data is already in-place.) */ + linker_assert ( ( data == tmp ), data_not_inplace ); + return tmp_len; + } } -extern int get_entropy_input ( unsigned int entropy_bits, void *data, - size_t min_len, size_t max_len ); - #endif /* _IPXE_ENTROPY_H */ diff --git a/src/include/ipxe/hmac_drbg.h b/src/include/ipxe/hmac_drbg.h index c751cbcb..b3dfe368 100644 --- a/src/include/ipxe/hmac_drbg.h +++ b/src/include/ipxe/hmac_drbg.h @@ -59,9 +59,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP * 800-90 Section 10.1 Table 2). * - * We choose to allow up to 2^32-1 bytes (i.e. 2^35-8 bits). + * We choose to allow up to 32 bytes. */ -#define HMAC_DRBG_MAX_ENTROPY_LEN_BYTES 0xffffffffUL +#define HMAC_DRBG_MAX_ENTROPY_LEN_BYTES 32 /** Maximum personalisation string length * diff --git a/src/include/ipxe/null_entropy.h b/src/include/ipxe/null_entropy.h new file mode 100644 index 00000000..0bfec802 --- /dev/null +++ b/src/include/ipxe/null_entropy.h @@ -0,0 +1,51 @@ +#ifndef _IPXE_NULL_ENTROPY_H +#define _IPXE_NULL_ENTROPY_H + +/** @file + * + * Nonexistent entropy source + * + * This source provides no entropy and must NOT be used in a + * security-sensitive environment. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +#ifdef ENTROPY_NULL +#define ENTROPY_PREFIX_null +#else +#define ENTROPY_PREFIX_null __null_ +#endif + +static inline __always_inline void +ENTROPY_INLINE ( null, entropy_enable ) ( void ) { + /* Do nothing */ +} + +static inline __always_inline void +ENTROPY_INLINE ( null, entropy_disable ) ( void ) { + /* Do nothing */ +} + +static inline __always_inline double +ENTROPY_INLINE ( null, min_entropy_per_sample ) ( void ) { + /* Actual amount of min-entropy is zero. To avoid + * division-by-zero errors and to allow compilation of + * entropy-consuming code, pretend to have 1 bit of entropy in + * each sample. + */ + return 1.0; +} + +static inline __always_inline int +ENTROPY_INLINE ( null, get_noise ) ( noise_sample_t *noise ) { + + /* All sample values are constant */ + *noise = 0x01; + + return 0; +} + +#endif /* _IPXE_NULL_ENTROPY_H */ From a3b116cea19bb57d9b292185f275e9995edc6acb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 20 Feb 2012 14:02:25 +0000 Subject: [PATCH 009/221] [rng] Add ANS X9.82 mandatory continuous tests ANS X9.82 specifies two mandatory continuous tests to be performed upon the noise source. Signed-off-by: Michael Brown --- src/crypto/entropy.c | 296 ++++++++++++++++++++++++++++++++++++- src/include/ipxe/errfile.h | 1 + 2 files changed, 296 insertions(+), 1 deletion(-) diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c index d5d06e57..47848368 100644 --- a/src/crypto/entropy.c +++ b/src/crypto/entropy.c @@ -30,10 +30,291 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include +/* Disambiguate the various error causes */ +#define EPIPE_REPETITION_COUNT_TEST \ + __einfo_error ( EINFO_EPIPE_REPETITION_COUNT_TEST ) +#define EINFO_EPIPE_REPETITION_COUNT_TEST \ + __einfo_uniqify ( EINFO_EPIPE, 0x01, "Repetition count test failed" ) +#define EPIPE_ADAPTIVE_PROPORTION_TEST \ + __einfo_error ( EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST ) +#define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \ + __einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" ) + +/** + * Calculate cutoff value for the repetition count test + * + * @ret cutoff Cutoff value + * + * This is the cutoff value for the Repetition Count Test defined in + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +repetition_count_cutoff ( void ) { + double max_repetitions; + unsigned int cutoff; + + /* The cutoff formula for the repetition test is: + * + * C = ( 1 + ( -log2(W) / H_min ) ) + * + * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October + * 2011 Draft) Section 8.5.2.1.3.1). + */ + max_repetitions = ( 1 + ( 30 / min_entropy_per_sample() ) ); + + /* Round up to a whole number of repetitions. We don't have + * the ceil() function available, so do the rounding by hand. + */ + cutoff = max_repetitions; + if ( cutoff < max_repetitions ) + cutoff++; + linker_assert ( ( cutoff >= max_repetitions ), rounding_error ); + + /* Floating-point operations are not allowed in iPXE since we + * never set up a suitable environment. Abort the build + * unless the calculated number of repetitions is a + * compile-time constant. + */ + linker_assert ( __builtin_constant_p ( cutoff ), + repetition_count_cutoff_not_constant ); + + return cutoff; +} + +/** + * Perform repetition count test + * + * @v sample Noise sample + * @ret rc Return status code + * + * This is the Repetition Count Test defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 8.5.2.1.2. + */ +static int repetition_count_test ( noise_sample_t sample ) { + static noise_sample_t most_recent_sample; + static unsigned int repetition_count = 0; + + /* A = the most recently seen sample value + * B = the number of times that value A has been seen in a row + * C = the cutoff value above which the repetition test should fail + */ + + /* 1. For each new sample processed: + * + * (Note that the test for "repetition_count > 0" ensures that + * the initial value of most_recent_sample is treated as being + * undefined.) + */ + if ( ( sample == most_recent_sample ) && ( repetition_count > 0 ) ) { + + /* a) If the new sample = A, then B is incremented by one. */ + repetition_count++; + + /* i. If B >= C, then an error condition is raised + * due to a failure of the test + */ + if ( repetition_count >= repetition_count_cutoff() ) + return -EPIPE_REPETITION_COUNT_TEST; + + } else { + + /* b) Else: + * i. A = new sample + */ + most_recent_sample = sample; + + /* ii. B = 1 */ + repetition_count = 1; + } + + return 0; +} + +/** + * Window size for the adaptive proportion test + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows + * five possible window sizes: 16, 64, 256, 4096 and 65536. + * + * We expect to generate relatively few (<256) entropy samples during + * a typical iPXE run; the use of a large window size would mean that + * the test would never complete a single cycle. We use a window size + * of 64, which is the smallest window size that permits values of + * H_min down to one bit per sample. + */ +#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64 + +/** + * Combine adaptive proportion test window size and min-entropy + * + * @v n N (window size) + * @v h H (min-entropy) + * @ret n_h (N,H) combined value + */ +#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) ) + +/** + * Define a row of the adaptive proportion cutoff table + * + * @v h H (min-entropy) + * @v c16 Cutoff for N=16 + * @v c64 Cutoff for N=64 + * @v c256 Cutoff for N=256 + * @v c4096 Cutoff for N=4096 + * @v c65536 Cutoff for N=65536 + */ +#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \ + case APC_N_H ( 16, h ) : return c16; \ + case APC_N_H ( 64, h ) : return c64; \ + case APC_N_H ( 256, h ) : return c256; \ + case APC_N_H ( 4096, h ) : return c4096; \ + case APC_N_H ( 65536, h ) : return c65536; + +/** Value used to represent "N/A" in adaptive proportion cutoff table */ +#define APC_NA 0 + +/** + * Look up value in adaptive proportion test cutoff table + * + * @v n N (window size) + * @v h H (min-entropy) + * @ret cutoff Cutoff + * + * This is the table of cutoff values defined in ANS X9.82 Part 2 + * (October 2011 Draft) Section 8.5.2.1.3.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) { + switch ( APC_N_H ( n, h ) ) { + APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 ); + APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 ); + APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 ); + APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 ); + APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 ); + APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 ); + APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 ); + APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 ); + APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 ); + APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 ); + APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 ); + APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 ); + APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 ); + APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 ); + APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 ); + APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 ); + APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 ); + APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 ); + APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 ); + APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 ); + default: + return APC_NA; + } +} + +/** + * Calculate cutoff value for the adaptive proportion test + * + * @ret cutoff Cutoff value + * + * This is the cutoff value for the Adaptive Proportion Test defined + * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2. + */ +static inline __attribute__ (( always_inline )) unsigned int +adaptive_proportion_cutoff ( void ) { + unsigned int h; + unsigned int n; + unsigned int cutoff; + + /* Look up cutoff value in cutoff table */ + n = ADAPTIVE_PROPORTION_WINDOW_SIZE; + h = min_entropy_per_sample(); + cutoff = adaptive_proportion_cutoff_lookup ( n, h ); + + /* Fail unless cutoff value is a build-time constant */ + linker_assert ( __builtin_constant_p ( cutoff ), + adaptive_proportion_cutoff_not_constant ); + + /* Fail if cutoff value is N/A */ + linker_assert ( ( cutoff != APC_NA ), + adaptive_proportion_cutoff_not_applicable ); + + return cutoff; +} + +/** + * Perform adaptive proportion test + * + * @v sample Noise sample + * @ret rc Return status code + * + * This is the Adaptive Proportion Test for the Most Common Value + * defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3. + */ +static int adaptive_proportion_test ( noise_sample_t sample ) { + static noise_sample_t current_counted_sample; + static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE; + static unsigned int repetition_count; + + /* A = the sample value currently being counted + * B = the number of samples examined in this run of the test so far + * N = the total number of samples that must be observed in + * one run of the test, also known as the "window size" of + * the test + * B = the current number of times that S (sic) has been seen + * in the W (sic) samples examined so far + * C = the cutoff value above which the repetition test should fail + * W = the probability of a false positive: 2^-30 + */ + + /* 1. The entropy source draws the current sample from the + * noise source. + * + * (Nothing to do; we already have the current sample.) + */ + + /* 2. If S = N, then a new run of the test begins: */ + if ( sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) { + + /* a. A = the current sample */ + current_counted_sample = sample; + + /* b. S = 0 */ + sample_count = 0; + + /* c. B = 0 */ + repetition_count = 0; + + } else { + + /* Else: (the test is already running) + * a. S = S + 1 + */ + sample_count++; + + /* b. If A = the current sample, then: */ + if ( sample == current_counted_sample ) { + + /* i. B = B + 1 */ + repetition_count++; + + /* ii. If S (sic) > C then raise an error + * condition, because the test has + * detected a failure + */ + if ( repetition_count > adaptive_proportion_cutoff() ) + return -EPIPE_ADAPTIVE_PROPORTION_TEST; + + } + } + + return 0; +} + /** * Get entropy sample * @@ -44,13 +325,26 @@ FILE_LICENCE ( GPL2_OR_LATER ); * (October 2011 Draft) Section 6.5.1. */ static int get_entropy ( entropy_sample_t *entropy ) { + static int rc = 0; noise_sample_t noise; - int rc; + + /* Any failure is permanent */ + if ( rc != 0 ) + return rc; /* Get noise sample */ if ( ( rc = get_noise ( &noise ) ) != 0 ) return rc; + /* Perform Repetition Count Test and Adaptive Proportion Test + * as mandated by ANS X9.82 Part 2 (October 2011 Draft) + * Section 8.5.2.1.1. + */ + if ( ( rc = repetition_count_test ( noise ) ) != 0 ) + return rc; + if ( ( rc = adaptive_proportion_test ( noise ) ) != 0 ) + return rc; + /* We do not use any optional conditioning component */ *entropy = noise; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 8f6c3641..03d1c7b9 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -244,6 +244,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_nvo_cmd ( ERRFILE_OTHER | 0x00230000 ) #define ERRFILE_hmac_drbg ( ERRFILE_OTHER | 0x00240000 ) #define ERRFILE_drbg ( ERRFILE_OTHER | 0x00250000 ) +#define ERRFILE_entropy ( ERRFILE_OTHER | 0x00260000 ) /** @} */ From c6b0b3424bd703aa0c15ae5397d3da0234b61c41 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 20 Feb 2012 19:26:04 +0000 Subject: [PATCH 010/221] [rng] Add ANS X9.82 mandatory start-up tests ANS X9.82 specifies that the start-up tests shall consist of at least one full cycle of the continuous tests. Signed-off-by: Michael Brown --- src/crypto/entropy.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c index 47848368..ab574a94 100644 --- a/src/crypto/entropy.c +++ b/src/crypto/entropy.c @@ -351,6 +351,31 @@ static int get_entropy ( entropy_sample_t *entropy ) { return 0; } +/** + * Calculate number of samples required for startup tests + * + * @ret num_samples Number of samples required + * + * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires + * that at least one full cycle of the continuous tests must be + * performed at start-up. + */ +static inline __attribute__ (( always_inline )) unsigned int +startup_test_count ( void ) { + unsigned int num_samples; + + /* At least max(N,C) samples shall be generated by the noise + * source for start-up testing. + */ + num_samples = repetition_count_cutoff(); + if ( num_samples < adaptive_proportion_cutoff() ) + num_samples = adaptive_proportion_cutoff(); + linker_assert ( __builtin_constant_p ( num_samples ), + startup_test_count_not_constant ); + + return num_samples; +} + /** * Create next nonce value * @@ -387,6 +412,7 @@ static uint32_t make_next_nonce ( void ) { */ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, size_t tmp_len ) { + static unsigned int startup_tested = 0; struct { uint32_t nonce; entropy_sample_t sample; @@ -398,6 +424,12 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, /* Enable entropy gathering */ entropy_enable(); + /* Perform mandatory startup tests, if not yet performed */ + for ( ; startup_tested < startup_test_count() ; startup_tested++ ) { + if ( ( rc = get_entropy ( &data.sample ) ) != 0 ) + goto err_get_entropy; + } + /* 3. entropy_total = 0 * * (Nothing to do; the number of entropy samples required has From 4e0effc6ad3b9f39859e259dd8f1f8af91c5b480 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 20 Feb 2012 21:26:23 +0000 Subject: [PATCH 011/221] [rng] Add ANS X9.82 RBG wrapper functions Signed-off-by: Michael Brown --- src/crypto/rbg.c | 114 +++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/rbg.h | 43 ++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 src/crypto/rbg.c create mode 100644 src/include/ipxe/rbg.h diff --git a/src/crypto/rbg.c b/src/crypto/rbg.c new file mode 100644 index 00000000..da0ad5df --- /dev/null +++ b/src/crypto/rbg.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * RBG mechanism + * + * This mechanism is designed to comply with ANS X9.82 Part 4 (April + * 2011 Draft) Section 10. This standard is unfortunately not freely + * available. + * + * The chosen RBG design is that of a DRBG with a live entropy source + * with no conditioning function. Only a single security strength is + * supported. No seedfile is used since there may be no non-volatile + * storage available. The system UUID is used as the personalisation + * string. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** The RBG */ +struct random_bit_generator rbg; + +/** + * Start up RBG + * + * @ret rc Return status code + * + * This is the RBG_Startup function defined in ANS X9.82 Part 4 (April + * 2011 Draft) Section 9.1.2.2. + */ +static int rbg_startup ( void ) { + union uuid uuid; + int len; + int rc; + + /* Try to obtain system UUID for use as personalisation + * string, in accordance with ANS X9.82 Part 3-2007 Section + * 8.5.2. If no UUID is available, proceed without a + * personalisation string. + */ + if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) { + rc = len; + DBGC ( &rbg, "RBG could not fetch personalisation string: " + "%s\n", strerror ( rc ) ); + len = 0; + } + + /* Instantiate DRBG */ + if ( ( rc = drbg_instantiate ( &rbg.state, &uuid, len ) ) != 0 ) { + DBGC ( &rbg, "RBG could not instantiate DRBG: %s\n", + strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Shut down RBG + * + */ +static void rbg_shutdown ( void ) { + + /* Uninstantiate DRBG */ + drbg_uninstantiate ( &rbg.state ); +} + +/** RBG startup function */ +static void rbg_startup_fn ( void ) { + + /* Start up RBG. There is no way to report an error at this + * stage, but a failed startup will result in an invalid DRBG + * that refuses to generate bits. + */ + rbg_startup(); +} + +/** RBG shutdown function */ +static void rbg_shutdown_fn ( int booting __unused ) { + + /* Shut down RBG */ + rbg_shutdown(); +} + +/** RBG startup table entry */ +struct startup_fn startup_rbg __startup_fn ( STARTUP_NORMAL ) = { + .startup = rbg_startup_fn, + .shutdown = rbg_shutdown_fn, +}; diff --git a/src/include/ipxe/rbg.h b/src/include/ipxe/rbg.h new file mode 100644 index 00000000..9689142f --- /dev/null +++ b/src/include/ipxe/rbg.h @@ -0,0 +1,43 @@ +#ifndef _IPXE_RBG_H +#define _IPXE_RBG_H + +/** @file + * + * RBG mechanism + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** An RBG */ +struct random_bit_generator { + /** DRBG state */ + struct drbg_state state; +}; + +extern struct random_bit_generator rbg; + +/** + * Generate bits using RBG + * + * @v additional Additional input + * @v additional_len Length of additional input + * @v prediction_resist Prediction resistance is required + * @v data Output buffer + * @v len Length of output buffer + * @ret rc Return status code + * + * This is the RBG_Generate function defined in ANS X9.82 Part 4 + * (April 2011 Draft) Section 9.1.2.2. + */ +static inline int rbg_generate ( const void *additional, size_t additional_len, + int prediction_resist, void *data, + size_t len ) { + return drbg_generate ( &rbg.state, additional, additional_len, + prediction_resist, data, len ); +} + +#endif /* _IPXE_RBG_H */ From 4fb60435c9a4bad8a84d1176b8eac7aa3670c43a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 21 Feb 2012 12:09:15 +0000 Subject: [PATCH 012/221] [rng] Add get_random_nz() function required by RSA algorithm RSA requires the generation of random non-zero bytes (i.e. a sequence of random numbers in the range [0x01,0xff]). ANS X9.82 provides various Approved methods for converting random bits into random numbers. The simplest such method is the Simple Discard Method. Signed-off-by: Michael Brown --- src/crypto/random_nz.c | 75 ++++++++++++++++++++++++++++++++++++ src/include/ipxe/random_nz.h | 16 ++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/crypto/random_nz.c create mode 100644 src/include/ipxe/random_nz.h diff --git a/src/crypto/random_nz.c b/src/crypto/random_nz.c new file mode 100644 index 00000000..7b54aad7 --- /dev/null +++ b/src/crypto/random_nz.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Random non-zero bytes + * + * The RSA algorithm requires the generation of random non-zero bytes, + * i.e. bytes in the range [0x01,0xff]. + * + * This algorithm is designed to comply with ANS X9.82 Part 1-2006 + * Section 9.2.1. This standard is not freely available, but most of + * the text appears to be shared with NIST SP 800-90, which can be + * downloaded from + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + * + * Where possible, references are given to both documents. In the + * case of any disagreement, ANS X9.82 takes priority over NIST SP + * 800-90. (In particular, note that some algorithms that are + * Approved by NIST SP 800-90 are not Approved by ANS X9.82.) + */ + +#include +#include +#include +#include + +/** + * Get random non-zero bytes + * + * @v data Output buffer + * @v len Length of output buffer + * @ret rc Return status code + * + * This algorithm is designed to be isomorphic to the Simple Discard + * Method described in ANS X9.82 Part 1-2006 Section 9.2.1 (NIST SP + * 800-90 Section B.5.1.1). + */ +int get_random_nz ( void *data, size_t len ) { + uint8_t *bytes = data; + int rc; + + while ( len ) { + + /* Generate random byte */ + if ( ( rc = rbg_generate ( NULL, 0, 0, bytes, 1 ) ) != 0 ) + return rc; + + /* Move to next byte if this byte is acceptable */ + if ( *bytes != 0 ) { + bytes++; + len--; + } + } + + return 0; +} diff --git a/src/include/ipxe/random_nz.h b/src/include/ipxe/random_nz.h new file mode 100644 index 00000000..6bb80d2a --- /dev/null +++ b/src/include/ipxe/random_nz.h @@ -0,0 +1,16 @@ +#ifndef _IPXE_RANDOM_NZ_H +#define _IPXE_RANDOM_NZ_H + +/** @file + * + * HMAC_DRBG algorithm + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +extern int get_random_nz ( void *data, size_t len ); + +#endif /* _IPXE_RANDOM_NZ_H */ From 75090f2abf2528b73a05b299bd4cc64c7b31ed92 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 21 Feb 2012 11:46:48 +0000 Subject: [PATCH 013/221] [tls] Use ANS X9.82 Approved RBG as source of random data for TLS Signed-off-by: Michael Brown --- src/net/tls.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index ace719c1..9acc5c3d 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, @@ -121,12 +122,25 @@ static void tls_close ( struct tls_session *tls, int rc ) { /** * Generate random data * + * @v tls TLS session * @v data Buffer to fill * @v len Length of buffer + * @ret rc Return status code */ -static void tls_generate_random ( void *data, size_t len ) { - /* FIXME: Some real random data source would be nice... */ - memset ( data, 0x01, len ); +static int tls_generate_random ( struct tls_session *tls, + void *data, size_t len ) { + int rc; + + /* Generate random bits with no additional input and without + * prediction resistance + */ + if ( ( rc = rbg_generate ( NULL, 0, 0, data, len ) ) != 0 ) { + DBGC ( tls, "TLS %p could not generate random data: %s\n", + tls, strerror ( rc ) ); + return rc; + } + + return 0; } /** @@ -1782,11 +1796,14 @@ static struct process_descriptor tls_process_desc = int add_tls ( struct interface *xfer, struct interface **next ) { struct tls_session *tls; + int rc; /* Allocate and initialise TLS structure */ tls = malloc ( sizeof ( *tls ) ); - if ( ! tls ) - return -ENOMEM; + if ( ! tls ) { + rc = -ENOMEM; + goto err_alloc; + } memset ( tls, 0, sizeof ( *tls ) ); ref_init ( &tls->refcnt, free_tls ); intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt ); @@ -1796,11 +1813,15 @@ int add_tls ( struct interface *xfer, struct interface **next ) { tls_clear_cipher ( tls, &tls->rx_cipherspec ); tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); tls->client_random.gmt_unix_time = 0; - tls_generate_random ( &tls->client_random.random, - ( sizeof ( tls->client_random.random ) ) ); + if ( ( rc = tls_generate_random ( tls, &tls->client_random.random, + ( sizeof ( tls->client_random.random ) ) ) ) != 0 ) { + goto err_random; + } tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 ); - tls_generate_random ( &tls->pre_master_secret.random, - ( sizeof ( tls->pre_master_secret.random ) ) ); + if ( ( rc = tls_generate_random ( tls, &tls->pre_master_secret.random, + ( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) { + goto err_random; + } digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); @@ -1811,4 +1832,9 @@ int add_tls ( struct interface *xfer, struct interface **next ) { *next = &tls->cipherstream; ref_put ( &tls->refcnt ); return 0; + + err_random: + ref_put ( &tls->refcnt ); + err_alloc: + return rc; } From 5a80c1106230f4308fe330eb9b881a349a3f9278 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 21 Feb 2012 12:40:27 +0000 Subject: [PATCH 014/221] [crypto] Use ANS X9.82 Approved get_random_nz() for RSA Signed-off-by: Michael Brown --- src/crypto/axtls/crypto.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/crypto/axtls/crypto.h b/src/crypto/axtls/crypto.h index a9893cf3..b7af7c41 100644 --- a/src/crypto/axtls/crypto.h +++ b/src/crypto/axtls/crypto.h @@ -130,9 +130,16 @@ void RNG_terminate(void); void get_random(int num_rand_bytes, uint8_t *rand_data); //void get_random_NZ(int num_rand_bytes, uint8_t *rand_data); -#include +#include static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) { - memset ( rand_data, 0x01, num_rand_bytes ); + /* AXTLS does not check for failures when generating random + * data. Rely on the fact that get_random_nz() does not + * request prediction resistance (and so cannot introduce new + * failures) and therefore any potential failure must already + * have been encountered by e.g. tls_generate_random(), which + * does check for failures. + */ + get_random_nz ( rand_data, num_rand_bytes ); } /************************************************************************** From c0340d9762e0ba05f4b46d7b8264a3f1c070cefd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 27 Feb 2012 14:18:59 +0000 Subject: [PATCH 015/221] [test] Allow self-tests to be run individually Separate out the list of self-tests from the self-test infrastructure. This allows tests to be run individually. For example: make bin/sha1_test.iso Signed-off-by: Michael Brown --- src/tests/test.c | 6 ------ src/tests/tests.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 src/tests/tests.c diff --git a/src/tests/test.c b/src/tests/test.c index 7e869053..fa9f5797 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -137,9 +137,3 @@ static void test_init ( void ) { struct init_fn test_init_fn __init_fn ( INIT_NORMAL ) = { .initialise = test_init, }; - -/* Drag in all applicable self-tests */ -REQUIRE_OBJECT ( list_test ); -REQUIRE_OBJECT ( sha1_test ); -REQUIRE_OBJECT ( hmac_drbg_test ); -REQUIRE_OBJECT ( hash_df_test ); diff --git a/src/tests/tests.c b/src/tests/tests.c new file mode 100644 index 00000000..870d467e --- /dev/null +++ b/src/tests/tests.c @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Self-test collection + * + */ + +/* Drag in all applicable self-tests */ +REQUIRE_OBJECT ( list_test ); +REQUIRE_OBJECT ( sha1_test ); +REQUIRE_OBJECT ( hmac_drbg_test ); +REQUIRE_OBJECT ( hash_df_test ); From 5d2e65c60f03f0e3c6333bec1a86a24d4daee86d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 27 Feb 2012 23:43:30 +0000 Subject: [PATCH 016/221] [rng] Add entropy sample generator Allow a list of raw noise samples to be generated for offline analysis. Signed-off-by: Michael Brown --- src/tests/entropy_sample.c | 70 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/tests/entropy_sample.c diff --git a/src/tests/entropy_sample.c b/src/tests/entropy_sample.c new file mode 100644 index 00000000..e00bb484 --- /dev/null +++ b/src/tests/entropy_sample.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Entropy sampling + * + */ + +#include +#include +#include + +/** Total number of test samples */ +#define SAMPLE_COUNT 65536 + +/** Number of samples per block */ +#define SAMPLE_BLOCKSIZE 256 + +/** + * Generate entropy samples for external testing + * + */ +static void entropy_sample_test_exec ( void ) { + static noise_sample_t samples[SAMPLE_BLOCKSIZE]; + unsigned int i; + unsigned int j; + int rc; + + /* Collect and print blocks of samples */ + for ( i = 0 ; i < ( SAMPLE_COUNT / SAMPLE_BLOCKSIZE ) ; i++ ) { + + /* Collect one block of samples */ + entropy_enable(); + for ( j = 0 ; j < SAMPLE_BLOCKSIZE ; j++ ) { + rc = get_noise ( &samples[j] ); + ok ( rc == 0 ); + } + entropy_disable(); + + /* Print out sample values */ + for ( j = 0 ; j < SAMPLE_BLOCKSIZE ; j++ ) { + printf ( "SAMPLE %d %d\n", ( i * SAMPLE_BLOCKSIZE + j ), + samples[j] ); + } + } +} + +/** Entropy sampling self-test */ +struct self_test entropy_sample_test __self_test = { + .name = "entropy_sample", + .exec = entropy_sample_test_exec, +}; From 05719804b9e06eabf152ccf59059fc39fd1cc08c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 19 Feb 2012 22:24:42 +0000 Subject: [PATCH 017/221] [rng] Add RTC-based entropy source The RTC-based entropy source uses the nanosecond-scale CPU TSC to measure the time between two 1kHz interrupts generated by the CMOS RTC. In a physical machine these clocks are driven from independent crystals, resulting in some observable clock drift. In a virtual machine, the CMOS RTC is typically emulated using host-OS constructions such as SIGALRM. Signed-off-by: Michael Brown --- src/arch/i386/include/bits/entropy.h | 2 + src/arch/i386/include/ipxe/rtc_entropy.h | 62 +++++ src/arch/i386/interface/pcbios/rtc_entropy.c | 233 +++++++++++++++++++ src/config/defaults/pcbios.h | 2 +- 4 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 src/arch/i386/include/ipxe/rtc_entropy.h create mode 100644 src/arch/i386/interface/pcbios/rtc_entropy.c diff --git a/src/arch/i386/include/bits/entropy.h b/src/arch/i386/include/bits/entropy.h index db8ba18e..6dcceec6 100644 --- a/src/arch/i386/include/bits/entropy.h +++ b/src/arch/i386/include/bits/entropy.h @@ -9,4 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include + #endif /* _BITS_ENTROPY_H */ diff --git a/src/arch/i386/include/ipxe/rtc_entropy.h b/src/arch/i386/include/ipxe/rtc_entropy.h new file mode 100644 index 00000000..6c3cf210 --- /dev/null +++ b/src/arch/i386/include/ipxe/rtc_entropy.h @@ -0,0 +1,62 @@ +#ifndef _IPXE_RTC_ENTROPY_H +#define _IPXE_RTC_ENTROPY_H + +/** @file + * + * RTC-based entropy source + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +#ifdef ENTROPY_RTC +#define ENTROPY_PREFIX_rtc +#else +#define ENTROPY_PREFIX_rtc __rtc_ +#endif + +/** + * min-entropy per sample + * + * @ret min_entropy min-entropy of each sample + */ +static inline __always_inline double +ENTROPY_INLINE ( rtc, min_entropy_per_sample ) ( void ) { + + /* The min-entropy has been measured on several platforms + * using the entropy_sample test code. Modelling the samples + * as independent, and using a confidence level of 99.99%, the + * measurements were as follows: + * + * qemu-kvm : 7.38 bits + * VMware : 7.46 bits + * Physical hardware : 2.67 bits + * + * We choose the lowest of these (2.67 bits) and apply a 50% + * safety margin to allow for some potential non-independence + * of samples. + */ + return 1.3; +} + +extern uint8_t rtc_sample ( void ); + +/** + * Get noise sample + * + * @ret noise Noise sample + * @ret rc Return status code + */ +static inline __always_inline int +ENTROPY_INLINE ( rtc, get_noise ) ( noise_sample_t *noise ) { + + /* Get sample */ + *noise = rtc_sample(); + + /* Always successful */ + return 0; +} + +#endif /* _IPXE_RTC_ENTROPY_H */ diff --git a/src/arch/i386/interface/pcbios/rtc_entropy.c b/src/arch/i386/interface/pcbios/rtc_entropy.c new file mode 100644 index 00000000..03189659 --- /dev/null +++ b/src/arch/i386/interface/pcbios/rtc_entropy.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * RTC-based entropy source + * + * The CMOS/RTC registers are documented (with varying degrees of + * accuracy and consistency) at + * + * http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt + * http://wiki.osdev.org/RTC + * http://wiki.osdev.org/CMOS + */ + +#include +#include +#include +#include +#include + +/** RTC IRQ */ +#define RTC_IRQ 8 + +/** RTC interrupt vector */ +#define RTC_INT IRQ_INT ( RTC_IRQ ) + +/** CMOS/RTC address (and NMI) register */ +#define CMOS_ADDRESS 0x70 + +/** NMI disable bit */ +#define CMOS_DISABLE_NMI 0x80 + +/** CMOS/RTC data register */ +#define CMOS_DATA 0x71 + +/** RTC status register A */ +#define RTC_STATUS_A 0x0a + +/** RTC status register B */ +#define RTC_STATUS_B 0x0b + +/** RTC Periodic Interrupt Enabled bit */ +#define RTC_STATUS_B_PIE 0x40 + +/** RTC status register C */ +#define RTC_STATUS_C 0x0c + +/** RTC status register D */ +#define RTC_STATUS_D 0x0d + +/** CMOS default address */ +#define CMOS_DEFAULT_ADDRESS RTC_STATUS_D + +/** RTC "interrupt triggered" flag */ +static uint8_t __text16 ( rtc_flag ); +#define rtc_flag __use_text16 ( rtc_flag ) + +/** RTC interrupt handler */ +extern void rtc_isr ( void ); + +/** Previous RTC interrupt handler */ +static struct segoff rtc_old_handler; + +/** + * Hook RTC interrupt handler + * + */ +static void rtc_hook_isr ( void ) { + + /* RTC interrupt handler */ + __asm__ __volatile__ ( + TEXT16_CODE ( "\nrtc_isr:\n\t" + /* Preserve registers */ + "pushw %%ax\n\t" + /* Set "interrupt triggered" flag */ + "cs movb $0x01, %c0\n\t" + /* Read RTC status register C to + * acknowledge interrupt + */ + "movb %3, %%al\n\t" + "outb %%al, %1\n\t" + "inb %2\n\t" + /* Send EOI */ + "movb $0x20, %%al\n\t" + "outb %%al, $0xa0\n\t" + "outb %%al, $0x20\n\t" + /* Restore registers and return */ + "popw %%ax\n\t" + "iret\n\t" ) + : + : "p" ( __from_text16 ( &rtc_flag ) ), + "i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ), + "i" ( RTC_STATUS_C ) ); + + hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr, + &rtc_old_handler ); +} + +/** + * Unhook RTC interrupt handler + * + */ +static void rtc_unhook_isr ( void ) { + int rc; + + rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr, + &rtc_old_handler ); + assert ( rc == 0 ); /* Should always be able to unhook */ +} + +/** + * Enable RTC interrupts + * + */ +static void rtc_enable_int ( void ) { + uint8_t status_b; + + /* Set Periodic Interrupt Enable bit in status register B */ + outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS ); + status_b = inb ( CMOS_DATA ); + outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS ); + outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA ); + + /* Re-enable NMI and reset to default address */ + outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS ); + inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */ +} + +/** + * Disable RTC interrupts + * + */ +static void rtc_disable_int ( void ) { + uint8_t status_b; + + /* Clear Periodic Interrupt Enable bit in status register B */ + outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS ); + status_b = inb ( CMOS_DATA ); + outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS ); + outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA ); + + /* Re-enable NMI and reset to default address */ + outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS ); + inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */ +} + +/** + * Enable entropy gathering + * + */ +static void rtc_entropy_enable ( void ) { + + rtc_hook_isr(); + enable_irq ( RTC_IRQ ); + rtc_enable_int(); +} + +/** + * Disable entropy gathering + * + */ +static void rtc_entropy_disable ( void ) { + + rtc_disable_int(); + disable_irq ( RTC_IRQ ); + rtc_unhook_isr(); +} + +/** + * Measure a single RTC tick + * + * @ret delta Length of RTC tick (in TSC units) + */ +uint8_t rtc_sample ( void ) { + uint32_t before; + uint32_t after; + uint32_t temp; + + __asm__ __volatile__ ( + REAL_CODE ( /* Enable interrupts */ + "sti\n\t" + /* Wait for RTC interrupt */ + "cs movb %b2, %c4\n\t" + "\n1:\n\t" + "cs xchgb %b2, %c4\n\t" /* Serialize */ + "testb %b2, %b2\n\t" + "jz 1b\n\t" + /* Read "before" TSC */ + "rdtsc\n\t" + /* Store "before" TSC on stack */ + "pushl %0\n\t" + /* Wait for another RTC interrupt */ + "xorb %b2, %b2\n\t" + "cs movb %b2, %c4\n\t" + "\n1:\n\t" + "cs xchgb %b2, %c4\n\t" /* Serialize */ + "testb %b2, %b2\n\t" + "jz 1b\n\t" + /* Read "after" TSC */ + "rdtsc\n\t" + /* Retrieve "before" TSC on stack */ + "popl %1\n\t" + /* Disable interrupts */ + "cli\n\t" + ) + : "=a" ( after ), "=d" ( before ), "=q" ( temp ) + : "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) ); + + return ( after - before ); +} + +PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample ); +PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable ); +PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable ); +PROVIDE_ENTROPY_INLINE ( rtc, get_noise ); diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index fb44d0e1..17e6ef63 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -18,7 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define UMALLOC_MEMTOP #define SMBIOS_PCBIOS #define SANBOOT_PCBIOS -#define ENTROPY_NULL +#define ENTROPY_RTC #define IMAGE_ELF /* ELF image support */ #define IMAGE_MULTIBOOT /* MultiBoot image support */ From 99de2398676d5fd9706c837c37e698a71fd31f17 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 28 Feb 2012 14:53:28 +0000 Subject: [PATCH 018/221] [http] Allow for HTTPS-only builds Separate out the core HTTP functionality (which is shared by both HTTP and HTTPS) from the provision of the "http://" URI opener. This allows for builds that support only "https://" URIs. Signed-off-by: Michael Brown --- src/include/ipxe/errfile.h | 2 +- src/net/tcp/http.c | 860 +---------------------------------- src/net/tcp/httpcore.c | 886 +++++++++++++++++++++++++++++++++++++ 3 files changed, 889 insertions(+), 859 deletions(-) create mode 100644 src/net/tcp/httpcore.c diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 03d1c7b9..7c86fdbb 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -161,7 +161,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_nullnet ( ERRFILE_NET | 0x00090000 ) #define ERRFILE_tcp ( ERRFILE_NET | 0x000a0000 ) #define ERRFILE_ftp ( ERRFILE_NET | 0x000b0000 ) -#define ERRFILE_http ( ERRFILE_NET | 0x000c0000 ) +#define ERRFILE_httpcore ( ERRFILE_NET | 0x000c0000 ) #define ERRFILE_iscsi ( ERRFILE_NET | 0x000d0000 ) #define ERRFILE_tcpip ( ERRFILE_NET | 0x000e0000 ) #define ERRFILE_udp ( ERRFILE_NET | 0x000f0000 ) diff --git a/src/net/tcp/http.c b/src/net/tcp/http.c index cee75133..0c038885 100644 --- a/src/net/tcp/http.c +++ b/src/net/tcp/http.c @@ -25,869 +25,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 ); -/** Block size used for HTTP block device request */ -#define HTTP_BLKSIZE 512 - -/** HTTP flags */ -enum http_flags { - /** Request is waiting to be transmitted */ - HTTP_TX_PENDING = 0x0001, - /** Fetch header only */ - HTTP_HEAD_ONLY = 0x0002, - /** Keep connection alive */ - HTTP_KEEPALIVE = 0x0004, -}; - -/** HTTP receive state */ -enum http_rx_state { - HTTP_RX_RESPONSE = 0, - HTTP_RX_HEADER, - HTTP_RX_CHUNK_LEN, - HTTP_RX_DATA, - HTTP_RX_TRAILER, - HTTP_RX_IDLE, - HTTP_RX_DEAD, -}; - -/** - * An HTTP request - * - */ -struct http_request { - /** Reference count */ - struct refcnt refcnt; - /** Data transfer interface */ - struct interface xfer; - /** Partial transfer interface */ - struct interface partial; - - /** URI being fetched */ - struct uri *uri; - /** Transport layer interface */ - struct interface socket; - - /** Flags */ - unsigned int flags; - /** Starting offset of partial transfer (if applicable) */ - size_t partial_start; - /** Length of partial transfer (if applicable) */ - size_t partial_len; - - /** TX process */ - struct process process; - - /** RX state */ - enum http_rx_state rx_state; - /** Received length */ - size_t rx_len; - /** Length remaining (or 0 if unknown) */ - size_t remaining; - /** HTTP is using Transfer-Encoding: chunked */ - int chunked; - /** Current chunk length remaining (if applicable) */ - size_t chunk_remaining; - /** Line buffer for received header lines */ - struct line_buffer linebuf; - /** Receive data buffer (if applicable) */ - userptr_t rx_buffer; -}; - -/** - * Free HTTP request - * - * @v refcnt Reference counter - */ -static void http_free ( struct refcnt *refcnt ) { - struct http_request *http = - container_of ( refcnt, struct http_request, refcnt ); - - uri_put ( http->uri ); - empty_line_buffer ( &http->linebuf ); - free ( http ); -}; - -/** - * Close HTTP request - * - * @v http HTTP request - * @v rc Return status code - */ -static void http_close ( struct http_request *http, int rc ) { - - /* Prevent further processing of any current packet */ - http->rx_state = HTTP_RX_DEAD; - - /* If we had a Content-Length, and the received content length - * isn't correct, flag an error - */ - if ( http->remaining != 0 ) { - DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n", - http, http->rx_len, ( http->rx_len + http->remaining ) ); - if ( rc == 0 ) - rc = -EIO; - } - - /* Remove process */ - process_del ( &http->process ); - - /* Close all data transfer interfaces */ - intf_shutdown ( &http->socket, rc ); - intf_shutdown ( &http->partial, rc ); - intf_shutdown ( &http->xfer, rc ); -} - -/** - * Mark HTTP request as completed successfully - * - * @v http HTTP request - */ -static void http_done ( struct http_request *http ) { - - /* If we had a Content-Length, and the received content length - * isn't correct, force an error - */ - if ( http->remaining != 0 ) { - http_close ( http, -EIO ); - return; - } - - /* Enter idle state */ - http->rx_state = HTTP_RX_IDLE; - http->rx_len = 0; - assert ( http->remaining == 0 ); - assert ( http->chunked == 0 ); - assert ( http->chunk_remaining == 0 ); - - /* Close partial transfer interface */ - intf_restart ( &http->partial, 0 ); - - /* Close everything unless we are keeping the connection alive */ - if ( ! ( http->flags & HTTP_KEEPALIVE ) ) - http_close ( http, 0 ); -} - -/** - * Convert HTTP response code to return status code - * - * @v response HTTP response code - * @ret rc Return status code - */ -static int http_response_to_rc ( unsigned int response ) { - switch ( response ) { - case 200: - case 206: - case 301: - case 302: - return 0; - case 404: - return -ENOENT; - case 403: - return -EPERM; - case 401: - return -EACCES; - default: - return -EIO; - } -} - -/** - * Handle HTTP response - * - * @v http HTTP request - * @v response HTTP response - * @ret rc Return status code - */ -static int http_rx_response ( struct http_request *http, char *response ) { - char *spc; - unsigned int code; - int rc; - - DBGC ( http, "HTTP %p response \"%s\"\n", http, response ); - - /* Check response starts with "HTTP/" */ - if ( strncmp ( response, "HTTP/", 5 ) != 0 ) - return -EIO; - - /* Locate and check response code */ - spc = strchr ( response, ' ' ); - if ( ! spc ) - return -EIO; - code = strtoul ( spc, NULL, 10 ); - if ( ( rc = http_response_to_rc ( code ) ) != 0 ) - return rc; - - /* Move to received headers */ - http->rx_state = HTTP_RX_HEADER; - return 0; -} - -/** - * Handle HTTP Location header - * - * @v http HTTP request - * @v value HTTP header value - * @ret rc Return status code - */ -static int http_rx_location ( struct http_request *http, const char *value ) { - int rc; - - /* Redirect to new location */ - DBGC ( http, "HTTP %p redirecting to %s\n", http, value ); - if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING, - value ) ) != 0 ) { - DBGC ( http, "HTTP %p could not redirect: %s\n", - http, strerror ( rc ) ); - return rc; - } - - return 0; -} - -/** - * Handle HTTP Content-Length header - * - * @v http HTTP request - * @v value HTTP header value - * @ret rc Return status code - */ -static int http_rx_content_length ( struct http_request *http, - const char *value ) { - struct block_device_capacity capacity; - size_t content_len; - char *endp; - - /* Parse content length */ - content_len = strtoul ( value, &endp, 10 ); - if ( *endp != '\0' ) { - DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n", - http, value ); - return -EIO; - } - - /* If we already have an expected content length, and this - * isn't it, then complain - */ - if ( http->remaining && ( http->remaining != content_len ) ) { - DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected " - "%zd)\n", http, content_len, http->remaining ); - return -EIO; - } - if ( ! ( http->flags & HTTP_HEAD_ONLY ) ) - http->remaining = content_len; - - /* Use seek() to notify recipient of filesize */ - xfer_seek ( &http->xfer, http->remaining ); - xfer_seek ( &http->xfer, 0 ); - - /* Report block device capacity if applicable */ - if ( http->flags & HTTP_HEAD_ONLY ) { - capacity.blocks = ( content_len / HTTP_BLKSIZE ); - capacity.blksize = HTTP_BLKSIZE; - capacity.max_count = -1U; - block_capacity ( &http->partial, &capacity ); - } - return 0; -} - -/** - * Handle HTTP Transfer-Encoding header - * - * @v http HTTP request - * @v value HTTP header value - * @ret rc Return status code - */ -static int http_rx_transfer_encoding ( struct http_request *http, - const char *value ) { - - if ( strcmp ( value, "chunked" ) == 0 ) { - /* Mark connection as using chunked transfer encoding */ - http->chunked = 1; - } - - return 0; -} - -/** An HTTP header handler */ -struct http_header_handler { - /** Name (e.g. "Content-Length") */ - const char *header; - /** Handle received header - * - * @v http HTTP request - * @v value HTTP header value - * @ret rc Return status code - * - * If an error is returned, the download will be aborted. - */ - int ( * rx ) ( struct http_request *http, const char *value ); -}; - -/** List of HTTP header handlers */ -static struct http_header_handler http_header_handlers[] = { - { - .header = "Location", - .rx = http_rx_location, - }, - { - .header = "Content-Length", - .rx = http_rx_content_length, - }, - { - .header = "Transfer-Encoding", - .rx = http_rx_transfer_encoding, - }, - { NULL, NULL } -}; - -/** - * Handle HTTP header - * - * @v http HTTP request - * @v header HTTP header - * @ret rc Return status code - */ -static int http_rx_header ( struct http_request *http, char *header ) { - struct http_header_handler *handler; - char *separator; - char *value; - int rc; - - /* An empty header line marks the end of this phase */ - if ( ! header[0] ) { - empty_line_buffer ( &http->linebuf ); - if ( ( http->rx_state == HTTP_RX_HEADER ) && - ( ! ( http->flags & HTTP_HEAD_ONLY ) ) ) { - DBGC ( http, "HTTP %p start of data\n", http ); - http->rx_state = ( http->chunked ? - HTTP_RX_CHUNK_LEN : HTTP_RX_DATA ); - return 0; - } else { - DBGC ( http, "HTTP %p end of trailer\n", http ); - http_done ( http ); - return 0; - } - } - - DBGC ( http, "HTTP %p header \"%s\"\n", http, header ); - - /* Split header at the ": " */ - separator = strstr ( header, ": " ); - if ( ! separator ) { - DBGC ( http, "HTTP %p malformed header\n", http ); - return -EIO; - } - *separator = '\0'; - value = ( separator + 2 ); - - /* Hand off to header handler, if one exists */ - for ( handler = http_header_handlers ; handler->header ; handler++ ) { - if ( strcasecmp ( header, handler->header ) == 0 ) { - if ( ( rc = handler->rx ( http, value ) ) != 0 ) - return rc; - break; - } - } - return 0; -} - -/** - * Handle HTTP chunk length - * - * @v http HTTP request - * @v length HTTP chunk length - * @ret rc Return status code - */ -static int http_rx_chunk_len ( struct http_request *http, char *length ) { - char *endp; - - /* Skip blank lines between chunks */ - if ( length[0] == '\0' ) - return 0; - - /* Parse chunk length */ - http->chunk_remaining = strtoul ( length, &endp, 16 ); - if ( *endp != '\0' ) { - DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n", - http, length ); - return -EIO; - } - - /* Terminate chunked encoding if applicable */ - if ( http->chunk_remaining == 0 ) { - DBGC ( http, "HTTP %p end of chunks\n", http ); - http->chunked = 0; - http->rx_state = HTTP_RX_TRAILER; - return 0; - } - - /* Use seek() to notify recipient of new filesize */ - DBGC ( http, "HTTP %p start of chunk of length %zd\n", - http, http->chunk_remaining ); - xfer_seek ( &http->xfer, ( http->rx_len + http->chunk_remaining ) ); - xfer_seek ( &http->xfer, http->rx_len ); - - /* Start receiving data */ - http->rx_state = HTTP_RX_DATA; - - return 0; -} - -/** An HTTP line-based data handler */ -struct http_line_handler { - /** Handle line - * - * @v http HTTP request - * @v line Line to handle - * @ret rc Return status code - */ - int ( * rx ) ( struct http_request *http, char *line ); -}; - -/** List of HTTP line-based data handlers */ -static struct http_line_handler http_line_handlers[] = { - [HTTP_RX_RESPONSE] = { .rx = http_rx_response }, - [HTTP_RX_HEADER] = { .rx = http_rx_header }, - [HTTP_RX_CHUNK_LEN] = { .rx = http_rx_chunk_len }, - [HTTP_RX_TRAILER] = { .rx = http_rx_header }, -}; - -/** - * Handle new data arriving via HTTP connection - * - * @v http HTTP request - * @v iobuf I/O buffer - * @v meta Data transfer metadata - * @ret rc Return status code - */ -static int http_socket_deliver ( struct http_request *http, - struct io_buffer *iobuf, - struct xfer_metadata *meta __unused ) { - struct http_line_handler *lh; - char *line; - size_t data_len; - ssize_t line_len; - int rc = 0; - - while ( iobuf && iob_len ( iobuf ) ) { - - switch ( http->rx_state ) { - case HTTP_RX_IDLE: - /* Receiving any data in this state is an error */ - DBGC ( http, "HTTP %p received %zd bytes while %s\n", - http, iob_len ( iobuf ), - ( ( http->rx_state == HTTP_RX_IDLE ) ? - "idle" : "dead" ) ); - rc = -EPROTO; - goto done; - case HTTP_RX_DEAD: - /* Do no further processing */ - goto done; - case HTTP_RX_DATA: - /* Pass received data to caller */ - data_len = iob_len ( iobuf ); - if ( http->chunk_remaining && - ( http->chunk_remaining < data_len ) ) { - data_len = http->chunk_remaining; - } - if ( http->remaining && - ( http->remaining < data_len ) ) { - data_len = http->remaining; - } - if ( http->rx_buffer != UNULL ) { - /* Copy to partial transfer buffer */ - copy_to_user ( http->rx_buffer, http->rx_len, - iobuf->data, data_len ); - iob_pull ( iobuf, data_len ); - } else if ( data_len < iob_len ( iobuf ) ) { - /* Deliver partial buffer as raw data */ - rc = xfer_deliver_raw ( &http->xfer, - iobuf->data, data_len ); - iob_pull ( iobuf, data_len ); - if ( rc != 0 ) - goto done; - } else { - /* Deliver whole I/O buffer */ - if ( ( rc = xfer_deliver_iob ( &http->xfer, - iob_disown ( iobuf ) ) ) != 0 ) - goto done; - } - http->rx_len += data_len; - if ( http->chunk_remaining ) { - http->chunk_remaining -= data_len; - if ( http->chunk_remaining == 0 ) - http->rx_state = HTTP_RX_CHUNK_LEN; - } - if ( http->remaining ) { - http->remaining -= data_len; - if ( ( http->remaining == 0 ) && - ( http->rx_state == HTTP_RX_DATA ) ) { - http_done ( http ); - } - } - break; - case HTTP_RX_RESPONSE: - case HTTP_RX_HEADER: - case HTTP_RX_CHUNK_LEN: - case HTTP_RX_TRAILER: - /* In the other phases, buffer and process a - * line at a time - */ - line_len = line_buffer ( &http->linebuf, iobuf->data, - iob_len ( iobuf ) ); - if ( line_len < 0 ) { - rc = line_len; - DBGC ( http, "HTTP %p could not buffer line: " - "%s\n", http, strerror ( rc ) ); - goto done; - } - iob_pull ( iobuf, line_len ); - line = buffered_line ( &http->linebuf ); - if ( line ) { - lh = &http_line_handlers[http->rx_state]; - if ( ( rc = lh->rx ( http, line ) ) != 0 ) - goto done; - } - break; - default: - assert ( 0 ); - break; - } - } - - done: - if ( rc ) - http_close ( http, rc ); - free_iob ( iobuf ); - return rc; -} - -/** - * Check HTTP socket flow control window - * - * @v http HTTP request - * @ret len Length of window - */ -static size_t http_socket_window ( struct http_request *http __unused ) { - - /* Window is always open. This is to prevent TCP from - * stalling if our parent window is not currently open. - */ - return ( ~( ( size_t ) 0 ) ); -} - -/** - * HTTP process - * - * @v http HTTP request - */ -static void http_step ( struct http_request *http ) { - const char *host = http->uri->host; - const char *user = http->uri->user; - const char *password = - ( http->uri->password ? http->uri->password : "" ); - size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ + - strlen ( password ) ) : 0 ); - size_t user_pw_base64_len = base64_encoded_len ( user_pw_len ); - uint8_t user_pw[ user_pw_len + 1 /* NUL */ ]; - char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ]; - int rc; - int request_len = unparse_uri ( NULL, 0, http->uri, - URI_PATH_BIT | URI_QUERY_BIT ); - char request[ request_len + 1 /* NUL */ ]; - char range[48]; /* Enough for two 64-bit integers in decimal */ - int partial; - - /* Do nothing if we have already transmitted the request */ - if ( ! ( http->flags & HTTP_TX_PENDING ) ) - return; - - /* Do nothing until socket is ready */ - if ( ! xfer_window ( &http->socket ) ) - return; - - /* Construct path?query request */ - unparse_uri ( request, sizeof ( request ), http->uri, - URI_PATH_BIT | URI_QUERY_BIT ); - - /* Construct authorisation, if applicable */ - if ( user ) { - /* Make "user:password" string from decoded fields */ - snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ), - "%s:%s", user, password ); - - /* Base64-encode the "user:password" string */ - base64_encode ( user_pw, user_pw_len, user_pw_base64 ); - } - - /* Force a HEAD request if we have nowhere to send any received data */ - if ( ( xfer_window ( &http->xfer ) == 0 ) && - ( http->rx_buffer == UNULL ) ) { - http->flags |= ( HTTP_HEAD_ONLY | HTTP_KEEPALIVE ); - } - - /* Determine type of request */ - partial = ( http->partial_len != 0 ); - snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start, - ( http->partial_start + http->partial_len - 1 ) ); - - /* Mark request as transmitted */ - http->flags &= ~HTTP_TX_PENDING; - - /* Send GET request */ - if ( ( rc = xfer_printf ( &http->socket, - "%s %s%s HTTP/1.1\r\n" - "User-Agent: iPXE/" VERSION "\r\n" - "Host: %s%s%s\r\n" - "%s%s%s%s%s%s%s" - "\r\n", - ( ( http->flags & HTTP_HEAD_ONLY ) ? - "HEAD" : "GET" ), - ( http->uri->path ? "" : "/" ), - request, host, - ( http->uri->port ? - ":" : "" ), - ( http->uri->port ? - http->uri->port : "" ), - ( ( http->flags & HTTP_KEEPALIVE ) ? - "Connection: Keep-Alive\r\n" : "" ), - ( partial ? "Range: bytes=" : "" ), - ( partial ? range : "" ), - ( partial ? "\r\n" : "" ), - ( user ? - "Authorization: Basic " : "" ), - ( user ? user_pw_base64 : "" ), - ( user ? "\r\n" : "" ) ) ) != 0 ) { - http_close ( http, rc ); - } -} - -/** - * Check HTTP data transfer flow control window - * - * @v http HTTP request - * @ret len Length of window - */ -static size_t http_xfer_window ( struct http_request *http ) { - - /* New block commands may be issued only when we are idle */ - return ( ( http->rx_state == HTTP_RX_IDLE ) ? 1 : 0 ); -} - -/** - * Initiate HTTP partial read - * - * @v http HTTP request - * @v partial Partial transfer interface - * @v offset Starting offset - * @v buffer Data buffer - * @v len Length - * @ret rc Return status code - */ -static int http_partial_read ( struct http_request *http, - struct interface *partial, - size_t offset, userptr_t buffer, size_t len ) { - - /* Sanity check */ - if ( http_xfer_window ( http ) == 0 ) - return -EBUSY; - - /* Initialise partial transfer parameters */ - http->rx_buffer = buffer; - http->partial_start = offset; - http->partial_len = len; - http->remaining = len; - - /* Schedule request */ - http->rx_state = HTTP_RX_RESPONSE; - http->flags = ( HTTP_TX_PENDING | HTTP_KEEPALIVE ); - if ( ! len ) - http->flags |= HTTP_HEAD_ONLY; - process_add ( &http->process ); - - /* Attach to parent interface and return */ - intf_plug_plug ( &http->partial, partial ); - - return 0; -} - -/** - * Issue HTTP block device read - * - * @v http HTTP request - * @v block Block data interface - * @v lba Starting logical block address - * @v count Number of blocks to transfer - * @v buffer Data buffer - * @v len Length of data buffer - * @ret rc Return status code - */ -static int http_block_read ( struct http_request *http, - struct interface *block, - uint64_t lba, unsigned int count, - userptr_t buffer, size_t len __unused ) { - - return http_partial_read ( http, block, ( lba * HTTP_BLKSIZE ), - buffer, ( count * HTTP_BLKSIZE ) ); -} - -/** - * Read HTTP block device capacity - * - * @v http HTTP request - * @v block Block data interface - * @ret rc Return status code - */ -static int http_block_read_capacity ( struct http_request *http, - struct interface *block ) { - - return http_partial_read ( http, block, 0, 0, 0 ); -} - -/** - * Describe HTTP device in an ACPI table - * - * @v http HTTP request - * @v acpi ACPI table - * @v len Length of ACPI table - * @ret rc Return status code - */ -static int http_acpi_describe ( struct http_request *http, - struct acpi_description_header *acpi, - size_t len ) { - - DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n", - http ); - ( void ) acpi; - ( void ) len; - return 0; -} - -/** HTTP socket interface operations */ -static struct interface_operation http_socket_operations[] = { - INTF_OP ( xfer_window, struct http_request *, http_socket_window ), - INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ), - INTF_OP ( xfer_window_changed, struct http_request *, http_step ), - INTF_OP ( intf_close, struct http_request *, http_close ), -}; - -/** HTTP socket interface descriptor */ -static struct interface_descriptor http_socket_desc = - INTF_DESC_PASSTHRU ( struct http_request, socket, - http_socket_operations, xfer ); - -/** HTTP partial transfer interface operations */ -static struct interface_operation http_partial_operations[] = { - INTF_OP ( intf_close, struct http_request *, http_close ), -}; - -/** HTTP partial transfer interface descriptor */ -static struct interface_descriptor http_partial_desc = - INTF_DESC ( struct http_request, partial, http_partial_operations ); - -/** HTTP data transfer interface operations */ -static struct interface_operation http_xfer_operations[] = { - INTF_OP ( xfer_window, struct http_request *, http_xfer_window ), - INTF_OP ( block_read, struct http_request *, http_block_read ), - INTF_OP ( block_read_capacity, struct http_request *, - http_block_read_capacity ), - INTF_OP ( intf_close, struct http_request *, http_close ), - INTF_OP ( acpi_describe, struct http_request *, http_acpi_describe ), -}; - -/** HTTP data transfer interface descriptor */ -static struct interface_descriptor http_xfer_desc = - INTF_DESC_PASSTHRU ( struct http_request, xfer, - http_xfer_operations, socket ); - -/** HTTP process descriptor */ -static struct process_descriptor http_process_desc = - PROC_DESC_ONCE ( struct http_request, process, http_step ); - -/** - * Initiate an HTTP connection, with optional filter - * - * @v xfer Data transfer interface - * @v uri Uniform Resource Identifier - * @v default_port Default port number - * @v filter Filter to apply to socket, or NULL - * @ret rc Return status code - */ -int http_open_filter ( struct interface *xfer, struct uri *uri, - unsigned int default_port, - int ( * filter ) ( struct interface *xfer, - struct interface **next ) ) { - struct http_request *http; - struct sockaddr_tcpip server; - struct interface *socket; - int rc; - - /* Sanity checks */ - if ( ! uri->host ) - return -EINVAL; - - /* Allocate and populate HTTP structure */ - http = zalloc ( sizeof ( *http ) ); - if ( ! http ) - return -ENOMEM; - ref_init ( &http->refcnt, http_free ); - intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt ); - intf_init ( &http->partial, &http_partial_desc, &http->refcnt ); - http->uri = uri_get ( uri ); - intf_init ( &http->socket, &http_socket_desc, &http->refcnt ); - process_init ( &http->process, &http_process_desc, &http->refcnt ); - http->flags = HTTP_TX_PENDING; - - /* Open socket */ - memset ( &server, 0, sizeof ( server ) ); - server.st_port = htons ( uri_port ( http->uri, default_port ) ); - socket = &http->socket; - if ( filter ) { - if ( ( rc = filter ( socket, &socket ) ) != 0 ) - goto err; - } - if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, - ( struct sockaddr * ) &server, - uri->host, NULL ) ) != 0 ) - goto err; - - /* Attach to parent interface, mortalise self, and return */ - intf_plug_plug ( &http->xfer, xfer ); - ref_put ( &http->refcnt ); - return 0; - - err: - DBGC ( http, "HTTP %p could not create request: %s\n", - http, strerror ( rc ) ); - http_close ( http, rc ); - ref_put ( &http->refcnt ); - return rc; -} - /** * Initiate an HTTP connection * diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c new file mode 100644 index 00000000..3c36b8e0 --- /dev/null +++ b/src/net/tcp/httpcore.c @@ -0,0 +1,886 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * @file + * + * Hyper Text Transfer Protocol (HTTP) core functionality + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** Block size used for HTTP block device request */ +#define HTTP_BLKSIZE 512 + +/** HTTP flags */ +enum http_flags { + /** Request is waiting to be transmitted */ + HTTP_TX_PENDING = 0x0001, + /** Fetch header only */ + HTTP_HEAD_ONLY = 0x0002, + /** Keep connection alive */ + HTTP_KEEPALIVE = 0x0004, +}; + +/** HTTP receive state */ +enum http_rx_state { + HTTP_RX_RESPONSE = 0, + HTTP_RX_HEADER, + HTTP_RX_CHUNK_LEN, + HTTP_RX_DATA, + HTTP_RX_TRAILER, + HTTP_RX_IDLE, + HTTP_RX_DEAD, +}; + +/** + * An HTTP request + * + */ +struct http_request { + /** Reference count */ + struct refcnt refcnt; + /** Data transfer interface */ + struct interface xfer; + /** Partial transfer interface */ + struct interface partial; + + /** URI being fetched */ + struct uri *uri; + /** Transport layer interface */ + struct interface socket; + + /** Flags */ + unsigned int flags; + /** Starting offset of partial transfer (if applicable) */ + size_t partial_start; + /** Length of partial transfer (if applicable) */ + size_t partial_len; + + /** TX process */ + struct process process; + + /** RX state */ + enum http_rx_state rx_state; + /** Received length */ + size_t rx_len; + /** Length remaining (or 0 if unknown) */ + size_t remaining; + /** HTTP is using Transfer-Encoding: chunked */ + int chunked; + /** Current chunk length remaining (if applicable) */ + size_t chunk_remaining; + /** Line buffer for received header lines */ + struct line_buffer linebuf; + /** Receive data buffer (if applicable) */ + userptr_t rx_buffer; +}; + +/** + * Free HTTP request + * + * @v refcnt Reference counter + */ +static void http_free ( struct refcnt *refcnt ) { + struct http_request *http = + container_of ( refcnt, struct http_request, refcnt ); + + uri_put ( http->uri ); + empty_line_buffer ( &http->linebuf ); + free ( http ); +}; + +/** + * Close HTTP request + * + * @v http HTTP request + * @v rc Return status code + */ +static void http_close ( struct http_request *http, int rc ) { + + /* Prevent further processing of any current packet */ + http->rx_state = HTTP_RX_DEAD; + + /* If we had a Content-Length, and the received content length + * isn't correct, flag an error + */ + if ( http->remaining != 0 ) { + DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n", + http, http->rx_len, ( http->rx_len + http->remaining ) ); + if ( rc == 0 ) + rc = -EIO; + } + + /* Remove process */ + process_del ( &http->process ); + + /* Close all data transfer interfaces */ + intf_shutdown ( &http->socket, rc ); + intf_shutdown ( &http->partial, rc ); + intf_shutdown ( &http->xfer, rc ); +} + +/** + * Mark HTTP request as completed successfully + * + * @v http HTTP request + */ +static void http_done ( struct http_request *http ) { + + /* If we had a Content-Length, and the received content length + * isn't correct, force an error + */ + if ( http->remaining != 0 ) { + http_close ( http, -EIO ); + return; + } + + /* Enter idle state */ + http->rx_state = HTTP_RX_IDLE; + http->rx_len = 0; + assert ( http->remaining == 0 ); + assert ( http->chunked == 0 ); + assert ( http->chunk_remaining == 0 ); + + /* Close partial transfer interface */ + intf_restart ( &http->partial, 0 ); + + /* Close everything unless we are keeping the connection alive */ + if ( ! ( http->flags & HTTP_KEEPALIVE ) ) + http_close ( http, 0 ); +} + +/** + * Convert HTTP response code to return status code + * + * @v response HTTP response code + * @ret rc Return status code + */ +static int http_response_to_rc ( unsigned int response ) { + switch ( response ) { + case 200: + case 206: + case 301: + case 302: + return 0; + case 404: + return -ENOENT; + case 403: + return -EPERM; + case 401: + return -EACCES; + default: + return -EIO; + } +} + +/** + * Handle HTTP response + * + * @v http HTTP request + * @v response HTTP response + * @ret rc Return status code + */ +static int http_rx_response ( struct http_request *http, char *response ) { + char *spc; + unsigned int code; + int rc; + + DBGC ( http, "HTTP %p response \"%s\"\n", http, response ); + + /* Check response starts with "HTTP/" */ + if ( strncmp ( response, "HTTP/", 5 ) != 0 ) + return -EIO; + + /* Locate and check response code */ + spc = strchr ( response, ' ' ); + if ( ! spc ) + return -EIO; + code = strtoul ( spc, NULL, 10 ); + if ( ( rc = http_response_to_rc ( code ) ) != 0 ) + return rc; + + /* Move to received headers */ + http->rx_state = HTTP_RX_HEADER; + return 0; +} + +/** + * Handle HTTP Location header + * + * @v http HTTP request + * @v value HTTP header value + * @ret rc Return status code + */ +static int http_rx_location ( struct http_request *http, const char *value ) { + int rc; + + /* Redirect to new location */ + DBGC ( http, "HTTP %p redirecting to %s\n", http, value ); + if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING, + value ) ) != 0 ) { + DBGC ( http, "HTTP %p could not redirect: %s\n", + http, strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** + * Handle HTTP Content-Length header + * + * @v http HTTP request + * @v value HTTP header value + * @ret rc Return status code + */ +static int http_rx_content_length ( struct http_request *http, + const char *value ) { + struct block_device_capacity capacity; + size_t content_len; + char *endp; + + /* Parse content length */ + content_len = strtoul ( value, &endp, 10 ); + if ( *endp != '\0' ) { + DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n", + http, value ); + return -EIO; + } + + /* If we already have an expected content length, and this + * isn't it, then complain + */ + if ( http->remaining && ( http->remaining != content_len ) ) { + DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected " + "%zd)\n", http, content_len, http->remaining ); + return -EIO; + } + if ( ! ( http->flags & HTTP_HEAD_ONLY ) ) + http->remaining = content_len; + + /* Use seek() to notify recipient of filesize */ + xfer_seek ( &http->xfer, http->remaining ); + xfer_seek ( &http->xfer, 0 ); + + /* Report block device capacity if applicable */ + if ( http->flags & HTTP_HEAD_ONLY ) { + capacity.blocks = ( content_len / HTTP_BLKSIZE ); + capacity.blksize = HTTP_BLKSIZE; + capacity.max_count = -1U; + block_capacity ( &http->partial, &capacity ); + } + return 0; +} + +/** + * Handle HTTP Transfer-Encoding header + * + * @v http HTTP request + * @v value HTTP header value + * @ret rc Return status code + */ +static int http_rx_transfer_encoding ( struct http_request *http, + const char *value ) { + + if ( strcmp ( value, "chunked" ) == 0 ) { + /* Mark connection as using chunked transfer encoding */ + http->chunked = 1; + } + + return 0; +} + +/** An HTTP header handler */ +struct http_header_handler { + /** Name (e.g. "Content-Length") */ + const char *header; + /** Handle received header + * + * @v http HTTP request + * @v value HTTP header value + * @ret rc Return status code + * + * If an error is returned, the download will be aborted. + */ + int ( * rx ) ( struct http_request *http, const char *value ); +}; + +/** List of HTTP header handlers */ +static struct http_header_handler http_header_handlers[] = { + { + .header = "Location", + .rx = http_rx_location, + }, + { + .header = "Content-Length", + .rx = http_rx_content_length, + }, + { + .header = "Transfer-Encoding", + .rx = http_rx_transfer_encoding, + }, + { NULL, NULL } +}; + +/** + * Handle HTTP header + * + * @v http HTTP request + * @v header HTTP header + * @ret rc Return status code + */ +static int http_rx_header ( struct http_request *http, char *header ) { + struct http_header_handler *handler; + char *separator; + char *value; + int rc; + + /* An empty header line marks the end of this phase */ + if ( ! header[0] ) { + empty_line_buffer ( &http->linebuf ); + if ( ( http->rx_state == HTTP_RX_HEADER ) && + ( ! ( http->flags & HTTP_HEAD_ONLY ) ) ) { + DBGC ( http, "HTTP %p start of data\n", http ); + http->rx_state = ( http->chunked ? + HTTP_RX_CHUNK_LEN : HTTP_RX_DATA ); + return 0; + } else { + DBGC ( http, "HTTP %p end of trailer\n", http ); + http_done ( http ); + return 0; + } + } + + DBGC ( http, "HTTP %p header \"%s\"\n", http, header ); + + /* Split header at the ": " */ + separator = strstr ( header, ": " ); + if ( ! separator ) { + DBGC ( http, "HTTP %p malformed header\n", http ); + return -EIO; + } + *separator = '\0'; + value = ( separator + 2 ); + + /* Hand off to header handler, if one exists */ + for ( handler = http_header_handlers ; handler->header ; handler++ ) { + if ( strcasecmp ( header, handler->header ) == 0 ) { + if ( ( rc = handler->rx ( http, value ) ) != 0 ) + return rc; + break; + } + } + return 0; +} + +/** + * Handle HTTP chunk length + * + * @v http HTTP request + * @v length HTTP chunk length + * @ret rc Return status code + */ +static int http_rx_chunk_len ( struct http_request *http, char *length ) { + char *endp; + + /* Skip blank lines between chunks */ + if ( length[0] == '\0' ) + return 0; + + /* Parse chunk length */ + http->chunk_remaining = strtoul ( length, &endp, 16 ); + if ( *endp != '\0' ) { + DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n", + http, length ); + return -EIO; + } + + /* Terminate chunked encoding if applicable */ + if ( http->chunk_remaining == 0 ) { + DBGC ( http, "HTTP %p end of chunks\n", http ); + http->chunked = 0; + http->rx_state = HTTP_RX_TRAILER; + return 0; + } + + /* Use seek() to notify recipient of new filesize */ + DBGC ( http, "HTTP %p start of chunk of length %zd\n", + http, http->chunk_remaining ); + xfer_seek ( &http->xfer, ( http->rx_len + http->chunk_remaining ) ); + xfer_seek ( &http->xfer, http->rx_len ); + + /* Start receiving data */ + http->rx_state = HTTP_RX_DATA; + + return 0; +} + +/** An HTTP line-based data handler */ +struct http_line_handler { + /** Handle line + * + * @v http HTTP request + * @v line Line to handle + * @ret rc Return status code + */ + int ( * rx ) ( struct http_request *http, char *line ); +}; + +/** List of HTTP line-based data handlers */ +static struct http_line_handler http_line_handlers[] = { + [HTTP_RX_RESPONSE] = { .rx = http_rx_response }, + [HTTP_RX_HEADER] = { .rx = http_rx_header }, + [HTTP_RX_CHUNK_LEN] = { .rx = http_rx_chunk_len }, + [HTTP_RX_TRAILER] = { .rx = http_rx_header }, +}; + +/** + * Handle new data arriving via HTTP connection + * + * @v http HTTP request + * @v iobuf I/O buffer + * @v meta Data transfer metadata + * @ret rc Return status code + */ +static int http_socket_deliver ( struct http_request *http, + struct io_buffer *iobuf, + struct xfer_metadata *meta __unused ) { + struct http_line_handler *lh; + char *line; + size_t data_len; + ssize_t line_len; + int rc = 0; + + while ( iobuf && iob_len ( iobuf ) ) { + + switch ( http->rx_state ) { + case HTTP_RX_IDLE: + /* Receiving any data in this state is an error */ + DBGC ( http, "HTTP %p received %zd bytes while %s\n", + http, iob_len ( iobuf ), + ( ( http->rx_state == HTTP_RX_IDLE ) ? + "idle" : "dead" ) ); + rc = -EPROTO; + goto done; + case HTTP_RX_DEAD: + /* Do no further processing */ + goto done; + case HTTP_RX_DATA: + /* Pass received data to caller */ + data_len = iob_len ( iobuf ); + if ( http->chunk_remaining && + ( http->chunk_remaining < data_len ) ) { + data_len = http->chunk_remaining; + } + if ( http->remaining && + ( http->remaining < data_len ) ) { + data_len = http->remaining; + } + if ( http->rx_buffer != UNULL ) { + /* Copy to partial transfer buffer */ + copy_to_user ( http->rx_buffer, http->rx_len, + iobuf->data, data_len ); + iob_pull ( iobuf, data_len ); + } else if ( data_len < iob_len ( iobuf ) ) { + /* Deliver partial buffer as raw data */ + rc = xfer_deliver_raw ( &http->xfer, + iobuf->data, data_len ); + iob_pull ( iobuf, data_len ); + if ( rc != 0 ) + goto done; + } else { + /* Deliver whole I/O buffer */ + if ( ( rc = xfer_deliver_iob ( &http->xfer, + iob_disown ( iobuf ) ) ) != 0 ) + goto done; + } + http->rx_len += data_len; + if ( http->chunk_remaining ) { + http->chunk_remaining -= data_len; + if ( http->chunk_remaining == 0 ) + http->rx_state = HTTP_RX_CHUNK_LEN; + } + if ( http->remaining ) { + http->remaining -= data_len; + if ( ( http->remaining == 0 ) && + ( http->rx_state == HTTP_RX_DATA ) ) { + http_done ( http ); + } + } + break; + case HTTP_RX_RESPONSE: + case HTTP_RX_HEADER: + case HTTP_RX_CHUNK_LEN: + case HTTP_RX_TRAILER: + /* In the other phases, buffer and process a + * line at a time + */ + line_len = line_buffer ( &http->linebuf, iobuf->data, + iob_len ( iobuf ) ); + if ( line_len < 0 ) { + rc = line_len; + DBGC ( http, "HTTP %p could not buffer line: " + "%s\n", http, strerror ( rc ) ); + goto done; + } + iob_pull ( iobuf, line_len ); + line = buffered_line ( &http->linebuf ); + if ( line ) { + lh = &http_line_handlers[http->rx_state]; + if ( ( rc = lh->rx ( http, line ) ) != 0 ) + goto done; + } + break; + default: + assert ( 0 ); + break; + } + } + + done: + if ( rc ) + http_close ( http, rc ); + free_iob ( iobuf ); + return rc; +} + +/** + * Check HTTP socket flow control window + * + * @v http HTTP request + * @ret len Length of window + */ +static size_t http_socket_window ( struct http_request *http __unused ) { + + /* Window is always open. This is to prevent TCP from + * stalling if our parent window is not currently open. + */ + return ( ~( ( size_t ) 0 ) ); +} + +/** + * HTTP process + * + * @v http HTTP request + */ +static void http_step ( struct http_request *http ) { + const char *host = http->uri->host; + const char *user = http->uri->user; + const char *password = + ( http->uri->password ? http->uri->password : "" ); + size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ + + strlen ( password ) ) : 0 ); + size_t user_pw_base64_len = base64_encoded_len ( user_pw_len ); + uint8_t user_pw[ user_pw_len + 1 /* NUL */ ]; + char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ]; + int rc; + int request_len = unparse_uri ( NULL, 0, http->uri, + URI_PATH_BIT | URI_QUERY_BIT ); + char request[ request_len + 1 /* NUL */ ]; + char range[48]; /* Enough for two 64-bit integers in decimal */ + int partial; + + /* Do nothing if we have already transmitted the request */ + if ( ! ( http->flags & HTTP_TX_PENDING ) ) + return; + + /* Do nothing until socket is ready */ + if ( ! xfer_window ( &http->socket ) ) + return; + + /* Construct path?query request */ + unparse_uri ( request, sizeof ( request ), http->uri, + URI_PATH_BIT | URI_QUERY_BIT ); + + /* Construct authorisation, if applicable */ + if ( user ) { + /* Make "user:password" string from decoded fields */ + snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ), + "%s:%s", user, password ); + + /* Base64-encode the "user:password" string */ + base64_encode ( user_pw, user_pw_len, user_pw_base64 ); + } + + /* Force a HEAD request if we have nowhere to send any received data */ + if ( ( xfer_window ( &http->xfer ) == 0 ) && + ( http->rx_buffer == UNULL ) ) { + http->flags |= ( HTTP_HEAD_ONLY | HTTP_KEEPALIVE ); + } + + /* Determine type of request */ + partial = ( http->partial_len != 0 ); + snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start, + ( http->partial_start + http->partial_len - 1 ) ); + + /* Mark request as transmitted */ + http->flags &= ~HTTP_TX_PENDING; + + /* Send GET request */ + if ( ( rc = xfer_printf ( &http->socket, + "%s %s%s HTTP/1.1\r\n" + "User-Agent: iPXE/" VERSION "\r\n" + "Host: %s%s%s\r\n" + "%s%s%s%s%s%s%s" + "\r\n", + ( ( http->flags & HTTP_HEAD_ONLY ) ? + "HEAD" : "GET" ), + ( http->uri->path ? "" : "/" ), + request, host, + ( http->uri->port ? + ":" : "" ), + ( http->uri->port ? + http->uri->port : "" ), + ( ( http->flags & HTTP_KEEPALIVE ) ? + "Connection: Keep-Alive\r\n" : "" ), + ( partial ? "Range: bytes=" : "" ), + ( partial ? range : "" ), + ( partial ? "\r\n" : "" ), + ( user ? + "Authorization: Basic " : "" ), + ( user ? user_pw_base64 : "" ), + ( user ? "\r\n" : "" ) ) ) != 0 ) { + http_close ( http, rc ); + } +} + +/** + * Check HTTP data transfer flow control window + * + * @v http HTTP request + * @ret len Length of window + */ +static size_t http_xfer_window ( struct http_request *http ) { + + /* New block commands may be issued only when we are idle */ + return ( ( http->rx_state == HTTP_RX_IDLE ) ? 1 : 0 ); +} + +/** + * Initiate HTTP partial read + * + * @v http HTTP request + * @v partial Partial transfer interface + * @v offset Starting offset + * @v buffer Data buffer + * @v len Length + * @ret rc Return status code + */ +static int http_partial_read ( struct http_request *http, + struct interface *partial, + size_t offset, userptr_t buffer, size_t len ) { + + /* Sanity check */ + if ( http_xfer_window ( http ) == 0 ) + return -EBUSY; + + /* Initialise partial transfer parameters */ + http->rx_buffer = buffer; + http->partial_start = offset; + http->partial_len = len; + http->remaining = len; + + /* Schedule request */ + http->rx_state = HTTP_RX_RESPONSE; + http->flags = ( HTTP_TX_PENDING | HTTP_KEEPALIVE ); + if ( ! len ) + http->flags |= HTTP_HEAD_ONLY; + process_add ( &http->process ); + + /* Attach to parent interface and return */ + intf_plug_plug ( &http->partial, partial ); + + return 0; +} + +/** + * Issue HTTP block device read + * + * @v http HTTP request + * @v block Block data interface + * @v lba Starting logical block address + * @v count Number of blocks to transfer + * @v buffer Data buffer + * @v len Length of data buffer + * @ret rc Return status code + */ +static int http_block_read ( struct http_request *http, + struct interface *block, + uint64_t lba, unsigned int count, + userptr_t buffer, size_t len __unused ) { + + return http_partial_read ( http, block, ( lba * HTTP_BLKSIZE ), + buffer, ( count * HTTP_BLKSIZE ) ); +} + +/** + * Read HTTP block device capacity + * + * @v http HTTP request + * @v block Block data interface + * @ret rc Return status code + */ +static int http_block_read_capacity ( struct http_request *http, + struct interface *block ) { + + return http_partial_read ( http, block, 0, 0, 0 ); +} + +/** + * Describe HTTP device in an ACPI table + * + * @v http HTTP request + * @v acpi ACPI table + * @v len Length of ACPI table + * @ret rc Return status code + */ +static int http_acpi_describe ( struct http_request *http, + struct acpi_description_header *acpi, + size_t len ) { + + DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n", + http ); + ( void ) acpi; + ( void ) len; + return 0; +} + +/** HTTP socket interface operations */ +static struct interface_operation http_socket_operations[] = { + INTF_OP ( xfer_window, struct http_request *, http_socket_window ), + INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ), + INTF_OP ( xfer_window_changed, struct http_request *, http_step ), + INTF_OP ( intf_close, struct http_request *, http_close ), +}; + +/** HTTP socket interface descriptor */ +static struct interface_descriptor http_socket_desc = + INTF_DESC_PASSTHRU ( struct http_request, socket, + http_socket_operations, xfer ); + +/** HTTP partial transfer interface operations */ +static struct interface_operation http_partial_operations[] = { + INTF_OP ( intf_close, struct http_request *, http_close ), +}; + +/** HTTP partial transfer interface descriptor */ +static struct interface_descriptor http_partial_desc = + INTF_DESC ( struct http_request, partial, http_partial_operations ); + +/** HTTP data transfer interface operations */ +static struct interface_operation http_xfer_operations[] = { + INTF_OP ( xfer_window, struct http_request *, http_xfer_window ), + INTF_OP ( block_read, struct http_request *, http_block_read ), + INTF_OP ( block_read_capacity, struct http_request *, + http_block_read_capacity ), + INTF_OP ( intf_close, struct http_request *, http_close ), + INTF_OP ( acpi_describe, struct http_request *, http_acpi_describe ), +}; + +/** HTTP data transfer interface descriptor */ +static struct interface_descriptor http_xfer_desc = + INTF_DESC_PASSTHRU ( struct http_request, xfer, + http_xfer_operations, socket ); + +/** HTTP process descriptor */ +static struct process_descriptor http_process_desc = + PROC_DESC_ONCE ( struct http_request, process, http_step ); + +/** + * Initiate an HTTP connection, with optional filter + * + * @v xfer Data transfer interface + * @v uri Uniform Resource Identifier + * @v default_port Default port number + * @v filter Filter to apply to socket, or NULL + * @ret rc Return status code + */ +int http_open_filter ( struct interface *xfer, struct uri *uri, + unsigned int default_port, + int ( * filter ) ( struct interface *xfer, + struct interface **next ) ) { + struct http_request *http; + struct sockaddr_tcpip server; + struct interface *socket; + int rc; + + /* Sanity checks */ + if ( ! uri->host ) + return -EINVAL; + + /* Allocate and populate HTTP structure */ + http = zalloc ( sizeof ( *http ) ); + if ( ! http ) + return -ENOMEM; + ref_init ( &http->refcnt, http_free ); + intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt ); + intf_init ( &http->partial, &http_partial_desc, &http->refcnt ); + http->uri = uri_get ( uri ); + intf_init ( &http->socket, &http_socket_desc, &http->refcnt ); + process_init ( &http->process, &http_process_desc, &http->refcnt ); + http->flags = HTTP_TX_PENDING; + + /* Open socket */ + memset ( &server, 0, sizeof ( server ) ); + server.st_port = htons ( uri_port ( http->uri, default_port ) ); + socket = &http->socket; + if ( filter ) { + if ( ( rc = filter ( socket, &socket ) ) != 0 ) + goto err; + } + if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, + ( struct sockaddr * ) &server, + uri->host, NULL ) ) != 0 ) + goto err; + + /* Attach to parent interface, mortalise self, and return */ + intf_plug_plug ( &http->xfer, xfer ); + ref_put ( &http->refcnt ); + return 0; + + err: + DBGC ( http, "HTTP %p could not create request: %s\n", + http, strerror ( rc ) ); + http_close ( http, rc ); + ref_put ( &http->refcnt ); + return rc; +} From c72b8969e2fed31c7be6f70fdec107f92c1c03e8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 28 Feb 2012 22:27:48 +0000 Subject: [PATCH 019/221] [syslog] Disable console when no syslog server is defined Explicitly disable the syslog console when no syslog server is defined, rather than (ab)using the socket family address as an equivalent console-enabled flag. Signed-off-by: Michael Brown --- src/net/udp/syslog.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/net/udp/syslog.c b/src/net/udp/syslog.c index 6d9fc216..775e3f4a 100644 --- a/src/net/udp/syslog.c +++ b/src/net/udp/syslog.c @@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** The syslog server */ static struct sockaddr_tcpip logserver = { + .st_family = AF_INET, .st_port = htons ( SYSLOG_PORT ), }; @@ -84,10 +85,6 @@ static struct ansiesc_context syslog_ansiesc_ctx = { static void syslog_putchar ( int character ) { int rc; - /* Do nothing if we have no log server */ - if ( ! logserver.st_family ) - return; - /* Ignore if we are already mid-logging */ if ( syslog_entered ) return; @@ -136,6 +133,7 @@ static void syslog_putchar ( int character ) { /** Syslog console driver */ struct console_driver syslog_console __console_driver = { .putchar = syslog_putchar, + .disabled = 1, }; /****************************************************************************** @@ -166,11 +164,11 @@ static int apply_syslog_settings ( void ) { int rc; /* Fetch log server */ + syslog_console.disabled = 1; old_addr.s_addr = sin_logserver->sin_addr.s_addr; - logserver.st_family = 0; if ( ( len = fetch_ipv4_setting ( NULL, &syslog_setting, &sin_logserver->sin_addr ) ) >= 0 ) { - sin_logserver->sin_family = AF_INET; + syslog_console.disabled = 0; } /* Do nothing unless log server has changed */ @@ -181,7 +179,7 @@ static int apply_syslog_settings ( void ) { intf_restart ( &syslogger, 0 ); /* Do nothing unless we have a log server */ - if ( ! logserver.st_family ) { + if ( syslog_console.disabled ) { DBG ( "SYSLOG has no log server\n" ); return 0; } From 851b93fbc3d5d28851963bd412eb321742c5437f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 28 Feb 2012 22:45:32 +0000 Subject: [PATCH 020/221] [syslog] Separate out generic line-based console functionality Abstract out the generic line-handling portions of the syslog putchar() routine, to allow use by other console types. Signed-off-by: Michael Brown --- src/core/lineconsole.c | 76 ++++++++++++++++++++++++++++++++++ src/include/ipxe/lineconsole.h | 33 +++++++++++++++ src/net/udp/syslog.c | 44 ++++---------------- 3 files changed, 117 insertions(+), 36 deletions(-) create mode 100644 src/core/lineconsole.c create mode 100644 src/include/ipxe/lineconsole.h diff --git a/src/core/lineconsole.c b/src/core/lineconsole.c new file mode 100644 index 00000000..c43a2875 --- /dev/null +++ b/src/core/lineconsole.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Line-based console + * + */ + +#include +#include +#include +#include + +/** Line-based console ANSI escape sequence handlers */ +static struct ansiesc_handler line_ansiesc_handlers[] = { + { 0, NULL } +}; + +/** Line-based console ANSI escape sequence context */ +static struct ansiesc_context line_ansiesc_ctx = { + .handlers = line_ansiesc_handlers, +}; + +/** + * Print a character to a line-based console + * + * @v character Character to be printed + * @ret print Print line + */ +size_t line_putchar ( struct line_console *line, int character ) { + + /* Strip ANSI escape sequences */ + character = ansiesc_process ( &line_ansiesc_ctx, character ); + if ( character < 0 ) + return 0; + + /* Ignore carriage return */ + if ( character == '\r' ) + return 0; + + /* Treat newline as a terminator */ + if ( character == '\n' ) + character = 0; + + /* Add character to buffer */ + line->buffer[line->index++] = character; + + /* Do nothing more unless we reach end-of-line (or end-of-buffer) */ + if ( ( character != 0 ) && + ( line->index < ( line->len - 1 /* NUL */ ) ) ) { + return 0; + } + + /* Reset to start of buffer */ + line->index = 0; + + return 1; +} diff --git a/src/include/ipxe/lineconsole.h b/src/include/ipxe/lineconsole.h new file mode 100644 index 00000000..d53a0e9f --- /dev/null +++ b/src/include/ipxe/lineconsole.h @@ -0,0 +1,33 @@ +#ifndef _IPXE_LINECONSOLE_H +#define _IPXE_LINECONSOLE_H + +/** @file + * + * Line-based console + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +/** A line-based console */ +struct line_console { + /** Data buffer + * + * Must initially be filled with NULs + */ + char *buffer; + /** Current index within buffer */ + size_t index; + /** Length of buffer + * + * The final character of the buffer will only ever be used as + * a potential terminating NUL. + */ + size_t len; +}; + +extern size_t line_putchar ( struct line_console *line, int character ); + +#endif /* _IPXE_LINECONSOLE_H */ diff --git a/src/net/udp/syslog.c b/src/net/udp/syslog.c index 775e3f4a..5a8a865a 100644 --- a/src/net/udp/syslog.c +++ b/src/net/udp/syslog.c @@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include /** The syslog server */ @@ -61,22 +61,15 @@ static struct interface syslogger = INTF_INIT ( syslogger_desc ); /** Syslog line buffer */ static char syslog_buffer[SYSLOG_BUFSIZE]; -/** Index into syslog line buffer */ -static unsigned int syslog_idx; +/** Syslog line console */ +static struct line_console syslog_line = { + .buffer = syslog_buffer, + .len = sizeof ( syslog_buffer ), +}; /** Syslog recursion marker */ static int syslog_entered; -/** Syslog ANSI escape sequence handlers */ -static struct ansiesc_handler syslog_ansiesc_handlers[] = { - { 0, NULL } -}; - -/** Syslog ANSI escape sequence context */ -static struct ansiesc_context syslog_ansiesc_ctx = { - .handlers = syslog_ansiesc_handlers, -}; - /** * Print a character to syslog console * @@ -89,31 +82,10 @@ static void syslog_putchar ( int character ) { if ( syslog_entered ) return; - /* Strip ANSI escape sequences */ - character = ansiesc_process ( &syslog_ansiesc_ctx, character ); - if ( character < 0 ) + /* Fill line buffer */ + if ( line_putchar ( &syslog_line, character ) == 0 ) return; - /* Ignore carriage return */ - if ( character == '\r' ) - return; - - /* Treat newline as a terminator */ - if ( character == '\n' ) - character = 0; - - /* Add character to buffer */ - syslog_buffer[syslog_idx++] = character; - - /* Do nothing more unless we reach end-of-line (or end-of-buffer) */ - if ( ( character != 0 ) && - ( syslog_idx < ( sizeof ( syslog_buffer ) - 1 /* NUL */ ) ) ) { - return; - } - - /* Reset to start of buffer */ - syslog_idx = 0; - /* Guard against re-entry */ syslog_entered = 1; From 3a5823a12684a537b2804e37f86cac0cad1436b4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 28 Feb 2012 17:48:46 +0000 Subject: [PATCH 021/221] [vmware] Add GuestRPC mechanism Use the VMware backdoor I/O port to access the GuestRPC mechanism. Signed-off-by: Michael Brown --- src/arch/i386/Makefile | 1 + src/arch/i386/include/bits/errfile.h | 2 + src/arch/i386/include/ipxe/guestrpc.h | 68 +++++ src/arch/i386/include/ipxe/vmware.h | 81 ++++++ src/arch/i386/interface/vmware/guestrpc.c | 326 ++++++++++++++++++++++ src/arch/i386/interface/vmware/vmware.c | 57 ++++ 6 files changed, 535 insertions(+) create mode 100644 src/arch/i386/include/ipxe/guestrpc.h create mode 100644 src/arch/i386/include/ipxe/vmware.h create mode 100644 src/arch/i386/interface/vmware/guestrpc.c create mode 100644 src/arch/i386/interface/vmware/vmware.c diff --git a/src/arch/i386/Makefile b/src/arch/i386/Makefile index 3261fff3..068fbd67 100644 --- a/src/arch/i386/Makefile +++ b/src/arch/i386/Makefile @@ -85,6 +85,7 @@ SRCDIRS += arch/i386/interface/pcbios SRCDIRS += arch/i386/interface/pxe SRCDIRS += arch/i386/interface/pxeparent SRCDIRS += arch/i386/interface/syslinux +SRCDIRS += arch/i386/interface/vmware SRCDIRS += arch/i386/hci/commands # The various xxx_loader.c files are #included into core/loader.c and diff --git a/src/arch/i386/include/bits/errfile.h b/src/arch/i386/include/bits/errfile.h index 93f34f8d..1077bae8 100644 --- a/src/arch/i386/include/bits/errfile.h +++ b/src/arch/i386/include/bits/errfile.h @@ -16,6 +16,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_int13 ( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 ) #define ERRFILE_pxeparent ( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 ) #define ERRFILE_runtime ( ERRFILE_ARCH | ERRFILE_CORE | 0x00070000 ) +#define ERRFILE_vmware ( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 ) +#define ERRFILE_guestrpc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/arch/i386/include/ipxe/guestrpc.h b/src/arch/i386/include/ipxe/guestrpc.h new file mode 100644 index 00000000..72a0f714 --- /dev/null +++ b/src/arch/i386/include/ipxe/guestrpc.h @@ -0,0 +1,68 @@ +#ifndef _IPXE_GUESTRPC_H +#define _IPXE_GUESTRPC_H + +/** @file + * + * VMware GuestRPC mechanism + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** GuestRPC magic number */ +#define GUESTRPC_MAGIC 0x49435052 /* "RPCI" */ + +/** Open RPC channel */ +#define GUESTRPC_OPEN 0x00 + +/** Open RPC channel success status */ +#define GUESTRPC_OPEN_SUCCESS 0x00010000 + +/** Send RPC command length */ +#define GUESTRPC_COMMAND_LEN 0x01 + +/** Send RPC command length success status */ +#define GUESTRPC_COMMAND_LEN_SUCCESS 0x00810000 + +/** Send RPC command data */ +#define GUESTRPC_COMMAND_DATA 0x02 + +/** Send RPC command data success status */ +#define GUESTRPC_COMMAND_DATA_SUCCESS 0x00010000 + +/** Receive RPC reply length */ +#define GUESTRPC_REPLY_LEN 0x03 + +/** Receive RPC reply length success status */ +#define GUESTRPC_REPLY_LEN_SUCCESS 0x00830000 + +/** Receive RPC reply data */ +#define GUESTRPC_REPLY_DATA 0x04 + +/** Receive RPC reply data success status */ +#define GUESTRPC_REPLY_DATA_SUCCESS 0x00010000 + +/** Finish receiving RPC reply */ +#define GUESTRPC_REPLY_FINISH 0x05 + +/** Finish receiving RPC reply success status */ +#define GUESTRPC_REPLY_FINISH_SUCCESS 0x00010000 + +/** Close RPC channel */ +#define GUESTRPC_CLOSE 0x06 + +/** Close RPC channel success status */ +#define GUESTRPC_CLOSE_SUCCESS 0x00010000 + +/** RPC command success status */ +#define GUESTRPC_SUCCESS 0x2031 /* "1 " */ + +extern int guestrpc_open ( void ); +extern void guestrpc_close ( int channel ); +extern int guestrpc_command ( int channel, const char *command, char *reply, + size_t reply_len ); + +#endif /* _IPXE_GUESTRPC_H */ diff --git a/src/arch/i386/include/ipxe/vmware.h b/src/arch/i386/include/ipxe/vmware.h new file mode 100644 index 00000000..2ac65f43 --- /dev/null +++ b/src/arch/i386/include/ipxe/vmware.h @@ -0,0 +1,81 @@ +#ifndef _IPXE_VMWARE_H +#define _IPXE_VMWARE_H + +/** @file + * + * VMware backdoor mechanism + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +/** VMware backdoor I/O port */ +#define VMW_PORT 0x5658 + +/** VMware backdoor magic value */ +#define VMW_MAGIC 0x564d5868 /* "VMXh" */ + +/** VMware backdoor magic instruction */ +#define VMW_BACKDOOR "inl %%dx, %%eax" + +/** Get VMware version */ +#define VMW_CMD_GET_VERSION 0x0a + +/** Issue GuestRPC command */ +#define VMW_CMD_GUESTRPC 0x1e + +/** + * Get VMware version + * + * @ret version VMware version(?) + * @ret magic VMware magic number, if present + * @ret product_type VMware product type + */ +static inline __attribute__ (( always_inline )) void +vmware_cmd_get_version ( uint32_t *version, uint32_t *magic, + uint32_t *product_type ) { + uint32_t discard_d; + + /* Perform backdoor call */ + __asm__ __volatile__ ( VMW_BACKDOOR + : "=a" ( *version ), "=b" ( *magic ), + "=c" ( *product_type ), "=d" ( discard_d ) + : "0" ( VMW_MAGIC ), "1" ( 0 ), + "2" ( VMW_CMD_GET_VERSION ), + "3" ( VMW_PORT ) ); +} + +/** + * Issue GuestRPC command + * + * @v channel Channel number + * @v subcommand GuestRPC subcommand + * @v parameter Subcommand-specific parameter + * @ret edxhi Subcommand-specific result + * @ret ebx Subcommand-specific result + * @ret status Command status + */ +static inline __attribute__ (( always_inline )) uint32_t +vmware_cmd_guestrpc ( int channel, uint16_t subcommand, uint32_t parameter, + uint16_t *edxhi, uint32_t *ebx ) { + uint32_t discard_a; + uint32_t status; + uint32_t edx; + + /* Perform backdoor call */ + __asm__ __volatile__ ( VMW_BACKDOOR + : "=a" ( discard_a ), "=b" ( *ebx ), + "=c" ( status ), "=d" ( edx ) + : "0" ( VMW_MAGIC ), "1" ( parameter ), + "2" ( VMW_CMD_GUESTRPC | ( subcommand << 16 )), + "3" ( VMW_PORT | ( channel << 16 ) ) ); + *edxhi = ( edx >> 16 ); + + return status; +} + +extern int vmware_present ( void ); + +#endif /* _IPXE_VMWARE_H */ diff --git a/src/arch/i386/interface/vmware/guestrpc.c b/src/arch/i386/interface/vmware/guestrpc.c new file mode 100644 index 00000000..72860e74 --- /dev/null +++ b/src/arch/i386/interface/vmware/guestrpc.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * VMware GuestRPC mechanism + * + */ + +#include +#include +#include +#include +#include +#include + +/* Disambiguate the various error causes */ +#define EPROTO_OPEN __einfo_error ( EINFO_EPROTO_OPEN ) +#define EINFO_EPROTO_OPEN \ + __einfo_uniqify ( EINFO_EPROTO, 0x00, "GuestRPC open failed" ) +#define EPROTO_COMMAND_LEN __einfo_error ( EINFO_EPROTO_COMMAND_LEN ) +#define EINFO_EPROTO_COMMAND_LEN \ + __einfo_uniqify ( EINFO_EPROTO, 0x01, "GuestRPC command length failed" ) +#define EPROTO_COMMAND_DATA __einfo_error ( EINFO_EPROTO_COMMAND_DATA ) +#define EINFO_EPROTO_COMMAND_DATA \ + __einfo_uniqify ( EINFO_EPROTO, 0x02, "GuestRPC command data failed" ) +#define EPROTO_REPLY_LEN __einfo_error ( EINFO_EPROTO_REPLY_LEN ) +#define EINFO_EPROTO_REPLY_LEN \ + __einfo_uniqify ( EINFO_EPROTO, 0x03, "GuestRPC reply length failed" ) +#define EPROTO_REPLY_DATA __einfo_error ( EINFO_EPROTO_REPLY_DATA ) +#define EINFO_EPROTO_REPLY_DATA \ + __einfo_uniqify ( EINFO_EPROTO, 0x04, "GuestRPC reply data failed" ) +#define EPROTO_REPLY_FINISH __einfo_error ( EINFO_EPROTO_REPLY_FINISH ) +#define EINFO_EPROTO_REPLY_FINISH \ + __einfo_uniqify ( EINFO_EPROTO, 0x05, "GuestRPC reply finish failed" ) +#define EPROTO_CLOSE __einfo_error ( EINFO_EPROTO_CLOSE ) +#define EINFO_EPROTO_CLOSE \ + __einfo_uniqify ( EINFO_EPROTO, 0x06, "GuestRPC close failed" ) + +/** + * Open GuestRPC channel + * + * @ret channel Channel number, or negative error + */ +int guestrpc_open ( void ) { + uint16_t channel; + uint32_t discard_b; + uint32_t status; + + /* Issue GuestRPC command */ + status = vmware_cmd_guestrpc ( 0, GUESTRPC_OPEN, GUESTRPC_MAGIC, + &channel, &discard_b ); + if ( status != GUESTRPC_OPEN_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC open failed: status %08x\n", + status ); + return -EPROTO_OPEN; + } + + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d opened\n", channel ); + return channel; +} + +/** + * Send GuestRPC command length + * + * @v channel Channel number + * @v len Command length + * @ret rc Return status code + */ +static int guestrpc_command_len ( int channel, size_t len ) { + uint16_t discard_d; + uint32_t discard_b; + uint32_t status; + + /* Issue GuestRPC command */ + status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_LEN, len, + &discard_d, &discard_b ); + if ( status != GUESTRPC_COMMAND_LEN_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command " + "length %zd failed: status %08x\n", + channel, len, status ); + return -EPROTO_COMMAND_LEN; + } + + return 0; +} + +/** + * Send GuestRPC command data + * + * @v channel Channel number + * @v data Command data + * @ret rc Return status code + */ +static int guestrpc_command_data ( int channel, uint32_t data ) { + uint16_t discard_d; + uint32_t discard_b; + uint32_t status; + + /* Issue GuestRPC command */ + status = vmware_cmd_guestrpc ( channel, GUESTRPC_COMMAND_DATA, data, + &discard_d, &discard_b ); + if ( status != GUESTRPC_COMMAND_DATA_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d send command " + "data %08x failed: status %08x\n", + channel, data, status ); + return -EPROTO_COMMAND_DATA; + } + + return 0; +} + +/** + * Receive GuestRPC reply length + * + * @v channel Channel number + * @ret reply_id Reply ID + * @ret len Reply length, or negative error + */ +static int guestrpc_reply_len ( int channel, uint16_t *reply_id ) { + uint32_t len; + uint32_t status; + + /* Issue GuestRPC command */ + status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_LEN, 0, + reply_id, &len ); + if ( status != GUESTRPC_REPLY_LEN_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply " + "length failed: status %08x\n", channel, status ); + return -EPROTO_REPLY_LEN; + } + + return len; +} + +/** + * Receive GuestRPC reply data + * + * @v channel Channel number + * @v reply_id Reply ID + * @ret data Reply data + * @ret rc Return status code + */ +static int guestrpc_reply_data ( int channel, uint16_t reply_id, + uint32_t *data ) { + uint16_t discard_d; + uint32_t status; + + /* Issue GuestRPC command */ + status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_DATA, reply_id, + &discard_d, data ); + if ( status != GUESTRPC_REPLY_DATA_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d receive reply " + "%d data failed: status %08x\n", + channel, reply_id, status ); + return -EPROTO_REPLY_DATA; + } + + return 0; +} + +/** + * Finish receiving GuestRPC reply + * + * @v channel Channel number + * @v reply_id Reply ID + * @ret rc Return status code + */ +static int guestrpc_reply_finish ( int channel, uint16_t reply_id ) { + uint16_t discard_d; + uint32_t discard_b; + uint32_t status; + + /* Issue GuestRPC command */ + status = vmware_cmd_guestrpc ( channel, GUESTRPC_REPLY_FINISH, reply_id, + &discard_d, &discard_b ); + if ( status != GUESTRPC_REPLY_FINISH_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d finish reply %d " + "failed: status %08x\n", channel, reply_id, status ); + return -EPROTO_REPLY_FINISH; + } + + return 0; +} + +/** + * Close GuestRPC channel + * + * @v channel Channel number + */ +void guestrpc_close ( int channel ) { + uint16_t discard_d; + uint32_t discard_b; + uint32_t status; + + /* Issue GuestRPC command */ + status = vmware_cmd_guestrpc ( channel, GUESTRPC_CLOSE, 0, + &discard_d, &discard_b ); + if ( status != GUESTRPC_CLOSE_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d close failed: " + "status %08x\n", channel, status ); + return; + } + + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d closed\n", channel ); +} + +/** + * Issue GuestRPC command + * + * @v channel Channel number + * @v command Command + * @v reply Reply buffer + * @v reply_len Length of reply buffer + * @ret len Length of reply, or negative error + * + * The actual length of the reply will be returned even if the buffer + * was too small. + */ +int guestrpc_command ( int channel, const char *command, char *reply, + size_t reply_len ) { + const uint8_t *command_bytes = ( ( const void * ) command ); + uint8_t *reply_bytes = ( ( void * ) reply ); + size_t command_len = strlen ( command ); + int orig_reply_len = reply_len; + uint16_t status; + uint8_t *status_bytes = ( ( void * ) &status ); + size_t status_len = sizeof ( status ); + uint32_t data; + uint16_t reply_id; + int len; + int remaining; + unsigned int i; + int rc; + + DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d issuing command:\n", + channel ); + DBGC2_HDA ( GUESTRPC_MAGIC, 0, command, command_len ); + + /* Sanity check */ + assert ( ( reply != NULL ) || ( reply_len == 0 ) ); + + /* Send command length */ + if ( ( rc = guestrpc_command_len ( channel, command_len ) ) < 0 ) + return rc; + + /* Send command data */ + while ( command_len ) { + data = 0; + for ( i = sizeof ( data ) ; i ; i-- ) { + if ( command_len ) { + data = ( ( data & ~0xff ) | + *(command_bytes++) ); + command_len--; + } + data = ( ( data << 24 ) | ( data >> 8 ) ); + } + if ( ( rc = guestrpc_command_data ( channel, data ) ) < 0 ) + return rc; + } + + /* Receive reply length */ + if ( ( len = guestrpc_reply_len ( channel, &reply_id ) ) < 0 ) { + rc = len; + return rc; + } + + /* Receive reply */ + for ( remaining = len ; remaining > 0 ; remaining -= sizeof ( data ) ) { + if ( ( rc = guestrpc_reply_data ( channel, reply_id, + &data ) ) < 0 ) { + return rc; + } + for ( i = sizeof ( data ) ; i ; i-- ) { + if ( status_len ) { + *(status_bytes++) = ( data & 0xff ); + status_len--; + } else if ( reply_len ) { + *(reply_bytes++) = ( data & 0xff ); + reply_len--; + } + data = ( ( data << 24 ) | ( data >> 8 ) ); + } + } + + /* Finish receiving RPC reply */ + if ( ( rc = guestrpc_reply_finish ( channel, reply_id ) ) < 0 ) + return rc; + + DBGC2 ( GUESTRPC_MAGIC, "GuestRPC channel %d received reply (id %d, " + "length %d):\n", channel, reply_id, len ); + DBGC2_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) ); + DBGC2_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply, + ( ( len < orig_reply_len ) ? len : orig_reply_len ) ); + + /* Check reply status */ + if ( status != GUESTRPC_SUCCESS ) { + DBGC ( GUESTRPC_MAGIC, "GuestRPC channel %d command failed " + "(status %04x, reply id %d, reply length %d):\n", + channel, status, reply_id, len ); + DBGC_HDA ( GUESTRPC_MAGIC, 0, command, command_len ); + DBGC_HDA ( GUESTRPC_MAGIC, 0, &status, sizeof ( status ) ); + DBGC_HDA ( GUESTRPC_MAGIC, sizeof ( status ), reply, + ( ( len < orig_reply_len ) ? len : orig_reply_len )); + return -EIO; + } + + return len; +} diff --git a/src/arch/i386/interface/vmware/vmware.c b/src/arch/i386/interface/vmware/vmware.c new file mode 100644 index 00000000..8cc26c94 --- /dev/null +++ b/src/arch/i386/interface/vmware/vmware.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * VMware backdoor mechanism + * + * Based on the unofficial documentation at + * + * http://sites.google.com/site/chitchatvmback/backdoor + * + */ + +#include +#include +#include + +/** + * Detect VMware presence + * + * @ret rc Return status code + */ +int vmware_present ( void ) { + uint32_t version; + uint32_t magic; + uint32_t product_type; + + /* Perform backdoor call */ + vmware_cmd_get_version ( &version, &magic, &product_type ); + + /* Check for VMware presence */ + if ( magic != VMW_MAGIC ) { + DBGC ( VMW_MAGIC, "VMware not present\n" ); + return -ENOENT; + } + + DBGC ( VMW_MAGIC, "VMware product type %04x version %08x detected\n", + product_type, version ); + return 0; +} From fa538bdbc631681c0234a607b43543efd1f56a57 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 28 Feb 2012 23:09:06 +0000 Subject: [PATCH 022/221] [vmware] Add VMware logfile console (CONSOLE_VMWARE) Allow iPXE console output to be sent to the VMware logfile via the GuestRPC mechanism. Signed-off-by: Michael Brown --- src/arch/i386/interface/vmware/vmconsole.c | 117 +++++++++++++++++++++ src/config/config.c | 3 + src/config/console.h | 1 + 3 files changed, 121 insertions(+) create mode 100644 src/arch/i386/interface/vmware/vmconsole.c diff --git a/src/arch/i386/interface/vmware/vmconsole.c b/src/arch/i386/interface/vmware/vmconsole.c new file mode 100644 index 00000000..930c088d --- /dev/null +++ b/src/arch/i386/interface/vmware/vmconsole.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * VMware logfile console + * + */ + +#include +#include +#include +#include +#include + +/** VMware logfile console buffer size */ +#define VMCONSOLE_BUFSIZE 128 + +/** VMware logfile console GuestRPC channel */ +static int vmconsole_channel; + +/** VMware logfile console line buffer */ +static struct { + char prefix[4]; + char message[VMCONSOLE_BUFSIZE]; +} vmconsole_buffer = { + .prefix = "log ", +}; + +/** VMware logfile line console */ +static struct line_console vmconsole_line = { + .buffer = vmconsole_buffer.message, + .len = sizeof ( vmconsole_buffer.message ), +}; + +/** VMware logfile console recursion marker */ +static int vmconsole_entered; + +/** + * Print a character to VMware logfile console + * + * @v character Character to be printed + */ +static void vmconsole_putchar ( int character ) { + int rc; + + /* Ignore if we are already mid-logging */ + if ( vmconsole_entered ) + return; + + /* Fill line buffer */ + if ( line_putchar ( &vmconsole_line, character ) == 0 ) + return; + + /* Guard against re-entry */ + vmconsole_entered = 1; + + /* Send log message */ + if ( ( rc = guestrpc_command ( vmconsole_channel, + vmconsole_buffer.prefix, NULL, 0 ) ) <0){ + DBG ( "VMware console could not send log message: %s\n", + strerror ( rc ) ); + } + + /* Clear re-entry flag */ + vmconsole_entered = 0; +} + +/** VMware logfile console driver */ +struct console_driver vmconsole __console_driver = { + .putchar = vmconsole_putchar, + .disabled = 1, +}; + +/** + * Initialise VMware logfile console + * + */ +static void vmconsole_init ( void ) { + int rc; + + /* Attempt to open console */ + vmconsole_channel = guestrpc_open(); + if ( vmconsole_channel < 0 ) { + rc = vmconsole_channel; + DBG ( "VMware console could not be initialised: %s\n", + strerror ( rc ) ); + return; + } + + /* Mark console as available */ + vmconsole.disabled = 0; +} + +/** + * VMware logfile console initialisation function + */ +struct init_fn vmconsole_init_fn __init_fn ( INIT_CONSOLE ) = { + .initialise = vmconsole_init, +}; diff --git a/src/config/config.c b/src/config/config.c index 2c3555ea..bdf6b5ce 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -86,6 +86,9 @@ REQUIRE_OBJECT ( efi_console ); #ifdef CONSOLE_LINUX REQUIRE_OBJECT ( linux_console ); #endif +#ifdef CONSOLE_VMWARE +REQUIRE_OBJECT ( vmconsole ); +#endif /* * Drag in all requested network protocols diff --git a/src/config/console.h b/src/config/console.h index afc89569..bf7ea050 100644 --- a/src/config/console.h +++ b/src/config/console.h @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONSOLE_BTEXT /* Who knows what this does? */ //#define CONSOLE_PC_KBD /* Direct access to PC keyboard */ //#define CONSOLE_SYSLOG /* Syslog console */ +//#define CONSOLE_VMWARE /* VMware logfile console */ #define KEYBOARD_MAP us From cd29df5c0829e6f1a6a72e3bd69b459abe9835fa Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 1 Mar 2012 14:20:32 +0000 Subject: [PATCH 023/221] [vmware] Fix length returned by guestrpc_command() Signed-off-by: Michael Brown --- src/arch/i386/interface/vmware/guestrpc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/arch/i386/interface/vmware/guestrpc.c b/src/arch/i386/interface/vmware/guestrpc.c index 72860e74..a19e5bff 100644 --- a/src/arch/i386/interface/vmware/guestrpc.c +++ b/src/arch/i386/interface/vmware/guestrpc.c @@ -292,6 +292,7 @@ int guestrpc_command ( int channel, const char *command, char *reply, if ( status_len ) { *(status_bytes++) = ( data & 0xff ); status_len--; + len--; } else if ( reply_len ) { *(reply_bytes++) = ( data & 0xff ); reply_len--; From cb10137e1992ba8fcd035b228a6a58ba3b40c3a2 Mon Sep 17 00:00:00 2001 From: Jason Lunz Date: Fri, 24 Feb 2012 20:30:48 -0800 Subject: [PATCH 024/221] [http] Recognise status code 303 as valid As RFC 2616 10.3.4 explains, a 303 status is the proper HTTP 1.1 behavior for what most HTTP 1.0 clients did with code 302. Signed-off-by: Jason Lunz Signed-off-by: Michael Brown --- src/net/tcp/httpcore.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 3c36b8e0..69d27389 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -200,6 +200,7 @@ static int http_response_to_rc ( unsigned int response ) { case 206: case 301: case 302: + case 303: return 0; case 404: return -ENOENT; From 1d293776ea290ae1f4d1228f3278030facf97a4b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 1 Mar 2012 16:26:38 +0000 Subject: [PATCH 025/221] [iscsi] Send any padding inline with the data segment Some iSCSI targets respond to a PDU before receiving the padding bytes. If the target responds quickly enough, this can cause iPXE to start processing a new TX PDU before the padding bytes have been sent, which results in a protocol violation. Fix by always transmitting the padding bytes along with the data segment. Originally-fixed-by: Shyam Iyer Signed-off-by: Michael Brown --- src/include/ipxe/iscsi.h | 2 -- src/net/tcp/iscsi.c | 37 +++++++++---------------------------- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/src/include/ipxe/iscsi.h b/src/include/ipxe/iscsi.h index 5d3d73b0..b4de793a 100644 --- a/src/include/ipxe/iscsi.h +++ b/src/include/ipxe/iscsi.h @@ -515,8 +515,6 @@ enum iscsi_tx_state { ISCSI_TX_AHS, /** Sending the data segment */ ISCSI_TX_DATA, - /** Sending the data segment padding */ - ISCSI_TX_DATA_PADDING, }; /** State of an iSCSI RX engine */ diff --git a/src/net/tcp/iscsi.c b/src/net/tcp/iscsi.c index fa1bb398..9eaf3cc5 100644 --- a/src/net/tcp/iscsi.c +++ b/src/net/tcp/iscsi.c @@ -570,20 +570,23 @@ static int iscsi_tx_data_out ( struct iscsi_session *iscsi ) { struct io_buffer *iobuf; unsigned long offset; size_t len; + size_t pad_len; offset = ntohl ( data_out->offset ); len = ISCSI_DATA_LEN ( data_out->lengths ); + pad_len = ISCSI_DATA_PAD_LEN ( data_out->lengths ); assert ( iscsi->command != NULL ); assert ( iscsi->command->data_out ); assert ( ( offset + len ) <= iscsi->command->data_out_len ); - iobuf = xfer_alloc_iob ( &iscsi->socket, len ); + iobuf = xfer_alloc_iob ( &iscsi->socket, ( len + pad_len ) ); if ( ! iobuf ) return -ENOMEM; copy_from_user ( iob_put ( iobuf, len ), iscsi->command->data_out, offset, len ); + memset ( iob_put ( iobuf, pad_len ), 0, pad_len ); return xfer_deliver_iob ( &iscsi->socket, iobuf ); } @@ -801,13 +804,17 @@ static int iscsi_tx_login_request ( struct iscsi_session *iscsi ) { struct iscsi_bhs_login_request *request = &iscsi->tx_bhs.login_request; struct io_buffer *iobuf; size_t len; + size_t pad_len; len = ISCSI_DATA_LEN ( request->lengths ); - iobuf = xfer_alloc_iob ( &iscsi->socket, len ); + pad_len = ISCSI_DATA_PAD_LEN ( request->lengths ); + iobuf = xfer_alloc_iob ( &iscsi->socket, ( len + pad_len ) ); if ( ! iobuf ) return -ENOMEM; iob_put ( iobuf, len ); iscsi_build_login_request_strings ( iscsi, iobuf->data, len ); + memset ( iob_put ( iobuf, pad_len ), 0, pad_len ); + return xfer_deliver_iob ( &iscsi->socket, iobuf ); } @@ -1415,27 +1422,6 @@ static int iscsi_tx_data ( struct iscsi_session *iscsi ) { } } -/** - * Transmit data padding of an iSCSI PDU - * - * @v iscsi iSCSI session - * @ret rc Return status code - * - * Handle transmission of any data padding in a PDU data segment. - * iscsi::tx_bhs will be valid when this is called. - */ -static int iscsi_tx_data_padding ( struct iscsi_session *iscsi ) { - static const char pad[] = { '\0', '\0', '\0' }; - struct iscsi_bhs_common *common = &iscsi->tx_bhs.common; - size_t pad_len; - - pad_len = ISCSI_DATA_PAD_LEN ( common->lengths ); - if ( ! pad_len ) - return 0; - - return xfer_deliver_raw ( &iscsi->socket, pad, pad_len ); -} - /** * Complete iSCSI PDU transmission * @@ -1494,11 +1480,6 @@ static void iscsi_tx_step ( struct iscsi_session *iscsi ) { case ISCSI_TX_DATA: tx = iscsi_tx_data; tx_len = ISCSI_DATA_LEN ( common->lengths ); - next_state = ISCSI_TX_DATA_PADDING; - break; - case ISCSI_TX_DATA_PADDING: - tx = iscsi_tx_data_padding; - tx_len = ISCSI_DATA_PAD_LEN ( common->lengths ); next_state = ISCSI_TX_IDLE; break; case ISCSI_TX_IDLE: From 6324bd9389521c7e86384591f41eb78a81e9af47 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 2 Mar 2012 18:02:03 +0000 Subject: [PATCH 026/221] [undi] Allow underlying PXE stack to construct link-layer header Some PXE stacks (observed with a QLogic 8242) will always try to prepend a link-layer header, even if the caller uses P_UNKNOWN to indicate that the link-layer header has already been filled in. This results in an invalid packet being transmitted. Work around these faulty PXE stacks where possible by stripping the existing link-layer header and allowing the PXE stack to (re)construct the link-layer header itself. Originally-fixed-by: Buck Huppmann Signed-off-by: Michael Brown --- src/arch/i386/drivers/net/undinet.c | 49 +++++++++++++++++++++++++++-- src/include/ipxe/ethernet.h | 8 +++++ src/net/ethernet.c | 13 ++++---- 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c index 63b37389..19014415 100644 --- a/src/arch/i386/drivers/net/undinet.c +++ b/src/arch/i386/drivers/net/undinet.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include #include @@ -166,6 +167,10 @@ static int undinet_isr_triggered ( void ) { static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd ); #define undinet_tbd __use_data16 ( undinet_tbd ) +/** UNDI transmit destination address */ +static uint8_t __data16_array ( undinet_destaddr, [ETH_ALEN] ); +#define undinet_destaddr __use_data16 ( undinet_destaddr ) + /** * Transmit packet * @@ -175,8 +180,14 @@ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd ); */ static int undinet_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) { + struct undi_nic *undinic = netdev->priv; struct s_PXENV_UNDI_TRANSMIT undi_transmit; - size_t len = iob_len ( iobuf ); + const void *ll_dest; + const void *ll_source; + uint16_t net_proto; + unsigned int flags; + uint8_t protocol; + size_t len; int rc; /* Technically, we ought to make sure that the previous @@ -189,15 +200,49 @@ static int undinet_transmit ( struct net_device *netdev, * transmit the next packet. */ + /* Some PXE stacks are unable to cope with P_UNKNOWN, and will + * always try to prepend a link-layer header. Work around + * these stacks by stripping the existing link-layer header + * and allowing the PXE stack to (re)construct the link-layer + * header itself. + */ + if ( ( rc = eth_pull ( netdev, iobuf, &ll_dest, &ll_source, + &net_proto, &flags ) ) != 0 ) { + DBGC ( undinic, "UNDINIC %p could not strip Ethernet header: " + "%s\n", undinic, strerror ( rc ) ); + return rc; + } + memcpy ( undinet_destaddr, ll_dest, sizeof ( undinet_destaddr ) ); + switch ( net_proto ) { + case htons ( ETH_P_IP ) : + protocol = P_IP; + break; + case htons ( ETH_P_ARP ) : + protocol = P_ARP; + break; + case htons ( ETH_P_RARP ) : + protocol = P_RARP; + break; + default: + /* Unknown protocol; restore the original link-layer header */ + iob_push ( iobuf, sizeof ( struct ethhdr ) ); + protocol = P_UNKNOWN; + break; + } + /* Copy packet to UNDI I/O buffer */ + len = iob_len ( iobuf ); if ( len > sizeof ( basemem_packet ) ) len = sizeof ( basemem_packet ); memcpy ( &basemem_packet, iobuf->data, len ); /* Create PXENV_UNDI_TRANSMIT data structure */ memset ( &undi_transmit, 0, sizeof ( undi_transmit ) ); + undi_transmit.Protocol = protocol; + undi_transmit.XmitFlag = ( ( flags & LL_BROADCAST ) ? + XMT_BROADCAST : XMT_DESTADDR ); undi_transmit.DestAddr.segment = rm_ds; - undi_transmit.DestAddr.offset = __from_data16 ( &undinet_tbd ); + undi_transmit.DestAddr.offset = __from_data16 ( &undinet_destaddr ); undi_transmit.TBD.segment = rm_ds; undi_transmit.TBD.offset = __from_data16 ( &undinet_tbd ); diff --git a/src/include/ipxe/ethernet.h b/src/include/ipxe/ethernet.h index 7e49655a..3d2d462e 100644 --- a/src/include/ipxe/ethernet.h +++ b/src/include/ipxe/ethernet.h @@ -10,6 +10,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include +#include /** * Check if Ethernet address is all zeroes @@ -77,6 +79,12 @@ static inline int is_valid_ether_addr ( const void *addr ) { ( ! is_zero_ether_addr ( addr ) ) ); } +extern int eth_push ( struct net_device *netdev, struct io_buffer *iobuf, + const void *ll_dest, const void *ll_source, + uint16_t net_proto ); +extern int eth_pull ( struct net_device *netdev, struct io_buffer *iobuf, + const void **ll_dest, const void **ll_source, + uint16_t *net_proto, unsigned int *flags ); extern void eth_init_addr ( const void *hw_addr, void *ll_addr ); extern const char * eth_ntoa ( const void *ll_addr ); extern int eth_mc_hash ( unsigned int af, const void *net_addr, diff --git a/src/net/ethernet.c b/src/net/ethernet.c index c63fd9bc..a842bc11 100644 --- a/src/net/ethernet.c +++ b/src/net/ethernet.c @@ -50,9 +50,9 @@ static uint8_t eth_broadcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; * @v net_proto Network-layer protocol, in network-byte order * @ret rc Return status code */ -static int eth_push ( struct net_device *netdev __unused, - struct io_buffer *iobuf, const void *ll_dest, - const void *ll_source, uint16_t net_proto ) { +int eth_push ( struct net_device *netdev __unused, struct io_buffer *iobuf, + const void *ll_dest, const void *ll_source, + uint16_t net_proto ) { struct ethhdr *ethhdr = iob_push ( iobuf, sizeof ( *ethhdr ) ); /* Build Ethernet header */ @@ -74,10 +74,9 @@ static int eth_push ( struct net_device *netdev __unused, * @ret flags Packet flags * @ret rc Return status code */ -static int eth_pull ( struct net_device *netdev __unused, - struct io_buffer *iobuf, const void **ll_dest, - const void **ll_source, uint16_t *net_proto, - unsigned int *flags ) { +int eth_pull ( struct net_device *netdev __unused, struct io_buffer *iobuf, + const void **ll_dest, const void **ll_source, + uint16_t *net_proto, unsigned int *flags ) { struct ethhdr *ethhdr = iobuf->data; /* Sanity check */ From d620606d3e8c913876a671990600c226788b71da Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 2 Mar 2012 20:12:10 +0000 Subject: [PATCH 027/221] [arp] Maintain an ARP transmission queue Allow packet transmission to be deferred pending successful ARP resolution. This avoids the time spent waiting for a higher-level protocol (e.g. TCP or TFTP) to attempt retransmission. Signed-off-by: Michael Brown --- src/include/ipxe/arp.h | 8 +- src/net/arp.c | 428 ++++++++++++++++++++++++++++++----------- src/net/ipv4.c | 84 ++++---- 3 files changed, 361 insertions(+), 159 deletions(-) diff --git a/src/include/ipxe/arp.h b/src/include/ipxe/arp.h index f7b99c68..00396d82 100644 --- a/src/include/ipxe/arp.h +++ b/src/include/ipxe/arp.h @@ -35,10 +35,8 @@ struct arp_net_protocol { extern struct net_protocol arp_protocol __net_protocol; -extern int arp_resolve ( struct net_device *netdev, - struct net_protocol *net_protocol, - const void *dest_net_addr, - const void *source_net_addr, - void *dest_ll_addr ); +extern int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev, + struct net_protocol *net_protocol, const void *net_dest, + const void *net_source, const void *ll_source ); #endif /* _IPXE_ARP_H */ diff --git a/src/net/arp.c b/src/net/arp.c index ef30d5ec..4283b669 100644 --- a/src/net/arp.c +++ b/src/net/arp.c @@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include #include #include @@ -26,6 +27,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include +#include +#include +#include #include /** @file @@ -38,104 +43,263 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** ARP minimum timeout */ +#define ARP_MIN_TIMEOUT ( TICKS_PER_SEC / 8 ) + +/** ARP maximum timeout */ +#define ARP_MAX_TIMEOUT ( TICKS_PER_SEC * 3 ) + /** An ARP cache entry */ struct arp_entry { + /** List of ARP cache entries */ + struct list_head list; + /** Network device */ + struct net_device *netdev; /** Network-layer protocol */ struct net_protocol *net_protocol; - /** Link-layer protocol */ - struct ll_protocol *ll_protocol; - /** Network-layer address */ - uint8_t net_addr[MAX_NET_ADDR_LEN]; - /** Link-layer address */ - uint8_t ll_addr[MAX_LL_ADDR_LEN]; + /** Network-layer destination address */ + uint8_t net_dest[MAX_NET_ADDR_LEN]; + /** Network-layer source address */ + uint8_t net_source[MAX_NET_ADDR_LEN]; + /** Link-layer destination address */ + uint8_t ll_dest[MAX_LL_ADDR_LEN]; + /** Retransmission timer */ + struct retry_timer timer; + /** Pending I/O buffers */ + struct list_head tx_queue; }; -/** Number of entries in the ARP cache - * - * This is a global cache, covering all network interfaces, - * network-layer protocols and link-layer protocols. - */ -#define NUM_ARP_ENTRIES 4 - /** The ARP cache */ -static struct arp_entry arp_table[NUM_ARP_ENTRIES]; -#define arp_table_end &arp_table[NUM_ARP_ENTRIES] - -static unsigned int next_new_arp_entry = 0; +static LIST_HEAD ( arp_entries ); struct net_protocol arp_protocol __net_protocol; +static void arp_expired ( struct retry_timer *timer, int over ); + +/** + * Create ARP cache entry + * + * @v netdev Network device + * @v net_protocol Network-layer protocol + * @v net_dest Destination network-layer address + * @v net_source Source network-layer address + * @ret arp ARP cache entry, or NULL if allocation failed + */ +static struct arp_entry * arp_create ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest, + const void *net_source ) { + struct arp_entry *arp; + + /* Allocate entry and add to cache */ + arp = zalloc ( sizeof ( *arp ) ); + if ( ! arp ) + return NULL; + + /* Initialise entry and add to cache */ + arp->netdev = netdev_get ( netdev ); + arp->net_protocol = net_protocol; + memcpy ( arp->net_dest, net_dest, + net_protocol->net_addr_len ); + memcpy ( arp->net_source, net_source, + net_protocol->net_addr_len ); + timer_init ( &arp->timer, arp_expired, NULL ); + arp->timer.min_timeout = ARP_MIN_TIMEOUT; + arp->timer.max_timeout = ARP_MAX_TIMEOUT; + INIT_LIST_HEAD ( &arp->tx_queue ); + list_add ( &arp->list, &arp_entries ); + + /* Start timer running to trigger initial transmission */ + start_timer_nodelay ( &arp->timer ); + + DBGC ( arp, "ARP %p %s %s %s created\n", arp, netdev->name, + net_protocol->name, net_protocol->ntoa ( net_dest ) ); + return arp; +} + /** * Find entry in the ARP cache * - * @v ll_protocol Link-layer protocol + * @v netdev Network device * @v net_protocol Network-layer protocol - * @v net_addr Network-layer address + * @v net_dest Destination network-layer address * @ret arp ARP cache entry, or NULL if not found - * */ -static struct arp_entry * -arp_find_entry ( struct ll_protocol *ll_protocol, - struct net_protocol *net_protocol, - const void *net_addr ) { +static struct arp_entry * arp_find ( struct net_device *netdev, + struct net_protocol *net_protocol, + const void *net_dest ) { struct arp_entry *arp; - for ( arp = arp_table ; arp < arp_table_end ; arp++ ) { - if ( ( arp->ll_protocol == ll_protocol ) && + list_for_each_entry ( arp, &arp_entries, list ) { + if ( ( arp->netdev == netdev ) && ( arp->net_protocol == net_protocol ) && - ( memcmp ( arp->net_addr, net_addr, - net_protocol->net_addr_len ) == 0 ) ) + ( memcmp ( arp->net_dest, net_dest, + net_protocol->net_addr_len ) == 0 ) ) { + + /* Move to start of cache */ + list_del ( &arp->list ); + list_add ( &arp->list, &arp_entries ); + return arp; + } } return NULL; } /** - * Look up media-specific link-layer address in the ARP cache + * Destroy ARP cache entry * + * @v arp ARP cache entry + * @v rc Reason for destruction + */ +static void arp_destroy ( struct arp_entry *arp, int rc ) { + struct net_device *netdev = arp->netdev; + struct net_protocol *net_protocol = arp->net_protocol; + struct io_buffer *iobuf; + struct io_buffer *tmp; + + /* Stop timer */ + stop_timer ( &arp->timer ); + + /* Discard any outstanding I/O buffers */ + list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) { + DBGC2 ( arp, "ARP %p %s %s %s discarding deferred packet: " + "%s\n", arp, netdev->name, net_protocol->name, + net_protocol->ntoa ( arp->net_dest ), strerror ( rc ) ); + list_del ( &iobuf->list ); + netdev_tx_err ( arp->netdev, iobuf, rc ); + } + + DBGC ( arp, "ARP %p %s %s %s destroyed: %s\n", arp, netdev->name, + net_protocol->name, net_protocol->ntoa ( arp->net_dest ), + strerror ( rc ) ); + + /* Drop reference to network device, remove from cache and free */ + netdev_put ( arp->netdev ); + list_del ( &arp->list ); + free ( arp ); +} + +/** + * Test if ARP cache entry has a valid link-layer address + * + * @v arp ARP cache entry + * @ret resolved ARP cache entry is resolved + */ +static inline int arp_resolved ( struct arp_entry *arp ) { + return ( ! timer_running ( &arp->timer ) ); +} + +/** + * Transmit packet, determining link-layer address via ARP + * + * @v iobuf I/O buffer * @v netdev Network device * @v net_protocol Network-layer protocol - * @v dest_net_addr Destination network-layer address - * @v source_net_addr Source network-layer address - * @ret dest_ll_addr Destination link layer address + * @v net_dest Destination network-layer address + * @v net_source Source network-layer address + * @v ll_source Source link-layer address * @ret rc Return status code - * - * This function will use the ARP cache to look up the link-layer - * address for the link-layer protocol associated with the network - * device and the given network-layer protocol and addresses. If - * found, the destination link-layer address will be filled in in @c - * dest_ll_addr. - * - * If no address is found in the ARP cache, an ARP request will be - * transmitted on the specified network device and -ENOENT will be - * returned. */ -int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol, - const void *dest_net_addr, const void *source_net_addr, - void *dest_ll_addr ) { +int arp_tx ( struct io_buffer *iobuf, struct net_device *netdev, + struct net_protocol *net_protocol, const void *net_dest, + const void *net_source, const void *ll_source ) { + struct arp_entry *arp; + + /* Find or create ARP cache entry */ + arp = arp_find ( netdev, net_protocol, net_dest ); + if ( ! arp ) { + arp = arp_create ( netdev, net_protocol, net_dest, + net_source ); + if ( ! arp ) + return -ENOMEM; + } + + /* If a link-layer address is available then transmit + * immediately, otherwise queue for later transmission. + */ + if ( arp_resolved ( arp ) ) { + return net_tx ( iobuf, netdev, net_protocol, arp->ll_dest, + ll_source ); + } else { + DBGC2 ( arp, "ARP %p %s %s %s deferring packet\n", + arp, netdev->name, net_protocol->name, + net_protocol->ntoa ( net_dest ) ); + list_add_tail ( &iobuf->list, &arp->tx_queue ); + return -EAGAIN; + } +} + +/** + * Update ARP cache entry + * + * @v arp ARP cache entry + * @v ll_dest Destination link-layer address + */ +static void arp_update ( struct arp_entry *arp, const void *ll_dest ) { + struct net_device *netdev = arp->netdev; struct ll_protocol *ll_protocol = netdev->ll_protocol; - const struct arp_entry *arp; + struct net_protocol *net_protocol = arp->net_protocol; + struct io_buffer *iobuf; + struct io_buffer *tmp; + int rc; + + DBGC ( arp, "ARP %p %s %s %s updated => %s\n", arp, netdev->name, + net_protocol->name, net_protocol->ntoa ( arp->net_dest ), + ll_protocol->ntoa ( ll_dest ) ); + + /* Fill in link-layer address */ + memcpy ( arp->ll_dest, ll_dest, ll_protocol->ll_addr_len ); + + /* Stop retransmission timer */ + stop_timer ( &arp->timer ); + + /* Transmit any packets in queue */ + list_for_each_entry_safe ( iobuf, tmp, &arp->tx_queue, list ) { + DBGC2 ( arp, "ARP %p %s %s %s transmitting deferred packet\n", + arp, netdev->name, net_protocol->name, + net_protocol->ntoa ( arp->net_dest ) ); + list_del ( &iobuf->list ); + if ( ( rc = net_tx ( iobuf, netdev, net_protocol, ll_dest, + netdev->ll_addr ) ) != 0 ) { + DBGC ( arp, "ARP %p could not transmit deferred " + "packet: %s\n", arp, strerror ( rc ) ); + /* Ignore error and continue */ + } + } +} + +/** + * Handle ARP timer expiry + * + * @v timer Retry timer + * @v fail Failure indicator + */ +static void arp_expired ( struct retry_timer *timer, int fail ) { + struct arp_entry *arp = container_of ( timer, struct arp_entry, timer ); + struct net_device *netdev = arp->netdev; + struct ll_protocol *ll_protocol = netdev->ll_protocol; + struct net_protocol *net_protocol = arp->net_protocol; struct io_buffer *iobuf; struct arphdr *arphdr; int rc; - /* Look for existing entry in ARP table */ - arp = arp_find_entry ( ll_protocol, net_protocol, dest_net_addr ); - if ( arp ) { - DBG ( "ARP cache hit: %s %s => %s %s\n", - net_protocol->name, net_protocol->ntoa ( arp->net_addr ), - ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) ); - memcpy ( dest_ll_addr, arp->ll_addr, ll_protocol->ll_addr_len); - return 0; + /* If we have failed, destroy the cache entry */ + if ( fail ) { + arp_destroy ( arp, -ETIMEDOUT ); + return; } - DBG ( "ARP cache miss: %s %s\n", net_protocol->name, - net_protocol->ntoa ( dest_net_addr ) ); + + /* Restart the timer */ + start_timer ( &arp->timer ); /* Allocate ARP packet */ iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *arphdr ) + - 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ); - if ( ! iobuf ) - return -ENOMEM; + ( 2 * ( MAX_LL_ADDR_LEN + MAX_NET_ADDR_LEN ) ) ); + if ( ! iobuf ) { + /* Leave timer running and try again later */ + return; + } iob_reserve ( iobuf, MAX_LL_HEADER_LEN ); /* Build up ARP request */ @@ -148,18 +312,19 @@ int arp_resolve ( struct net_device *netdev, struct net_protocol *net_protocol, memcpy ( iob_put ( iobuf, ll_protocol->ll_addr_len ), netdev->ll_addr, ll_protocol->ll_addr_len ); memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), - source_net_addr, net_protocol->net_addr_len ); + arp->net_source, net_protocol->net_addr_len ); memset ( iob_put ( iobuf, ll_protocol->ll_addr_len ), 0, ll_protocol->ll_addr_len ); memcpy ( iob_put ( iobuf, net_protocol->net_addr_len ), - dest_net_addr, net_protocol->net_addr_len ); + arp->net_dest, net_protocol->net_addr_len ); /* Transmit ARP request */ if ( ( rc = net_tx ( iobuf, netdev, &arp_protocol, - netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) - return rc; - - return -ENOENT; + netdev->ll_broadcast, netdev->ll_addr ) ) != 0 ) { + DBGC ( arp, "ARP %p could not transmit request: %s\n", + arp, strerror ( rc ) ); + return; + } } /** @@ -188,12 +353,6 @@ static struct arp_net_protocol * arp_find_protocol ( uint16_t net_proto ) { * @v ll_source Link-layer source address * @v flags Packet flags * @ret rc Return status code - * - * This handles ARP requests and responses as detailed in RFC826. The - * method detailed within the RFC is pretty optimised, handling - * requests and responses with basically a single code path and - * avoiding the need for extraneous ARP requests; read the RFC for - * details. */ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, @@ -204,71 +363,68 @@ static int arp_rx ( struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol; struct ll_protocol *ll_protocol; struct arp_entry *arp; - int merge = 0; + int rc; /* Identify network-layer and link-layer protocols */ arp_net_protocol = arp_find_protocol ( arphdr->ar_pro ); - if ( ! arp_net_protocol ) + if ( ! arp_net_protocol ) { + rc = -EPROTONOSUPPORT; goto done; + } net_protocol = arp_net_protocol->net_protocol; ll_protocol = netdev->ll_protocol; /* Sanity checks */ if ( ( arphdr->ar_hrd != ll_protocol->ll_proto ) || ( arphdr->ar_hln != ll_protocol->ll_addr_len ) || - ( arphdr->ar_pln != net_protocol->net_addr_len ) ) + ( arphdr->ar_pln != net_protocol->net_addr_len ) ) { + rc = -EINVAL; goto done; - - /* See if we have an entry for this sender, and update it if so */ - arp = arp_find_entry ( ll_protocol, net_protocol, - arp_sender_pa ( arphdr ) ); - if ( arp ) { - memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ), - arphdr->ar_hln ); - merge = 1; - DBG ( "ARP cache update: %s %s => %s %s\n", - net_protocol->name, net_protocol->ntoa ( arp->net_addr ), - ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) ); } - /* See if we own the target protocol address */ - if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0) - goto done; - - /* Create new ARP table entry if necessary */ - if ( ! merge ) { - arp = &arp_table[next_new_arp_entry++ % NUM_ARP_ENTRIES]; - arp->ll_protocol = ll_protocol; - arp->net_protocol = net_protocol; - memcpy ( arp->ll_addr, arp_sender_ha ( arphdr ), - arphdr->ar_hln ); - memcpy ( arp->net_addr, arp_sender_pa ( arphdr ), - arphdr->ar_pln); - DBG ( "ARP cache add: %s %s => %s %s\n", - net_protocol->name, net_protocol->ntoa ( arp->net_addr ), - ll_protocol->name, ll_protocol->ntoa ( arp->ll_addr ) ); + /* See if we have an entry for this sender, and update it if so */ + arp = arp_find ( netdev, net_protocol, arp_sender_pa ( arphdr ) ); + if ( arp ) { + arp_update ( arp, arp_sender_ha ( arphdr ) ); } /* If it's not a request, there's nothing more to do */ - if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) + if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) ) { + rc = 0; goto done; + } + + /* See if we own the target protocol address */ + if ( arp_net_protocol->check ( netdev, arp_target_pa ( arphdr ) ) != 0){ + rc = 0; + goto done; + } /* Change request to a reply */ - DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name, - net_protocol->ntoa ( arp_target_pa ( arphdr ) ), - ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) ); + DBGC ( netdev, "ARP reply %s %s %s => %s %s\n", + netdev->name, net_protocol->name, + net_protocol->ntoa ( arp_target_pa ( arphdr ) ), + ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) ); arphdr->ar_op = htons ( ARPOP_REPLY ); memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ), arphdr->ar_hln + arphdr->ar_pln ); memcpy ( arp_sender_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln ); /* Send reply */ - net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol, - arp_target_ha ( arphdr ), netdev->ll_addr ); + if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &arp_protocol, + arp_target_ha ( arphdr ), + netdev->ll_addr ) ) != 0 ) { + DBGC ( netdev, "ARP could not transmit reply via %s: %s\n", + netdev->name, strerror ( rc ) ); + goto done; + } + + /* Success */ + rc = 0; done: free_iob ( iobuf ); - return 0; + return rc; } /** @@ -290,3 +446,59 @@ struct net_protocol arp_protocol __net_protocol = { .rx = arp_rx, .ntoa = arp_ntoa, }; + +/** + * Update ARP cache on network device creation + * + * @v netdev Network device + */ +static int arp_probe ( struct net_device *netdev __unused ) { + /* Nothing to do */ + return 0; +} + +/** + * Update ARP cache on network device state change or removal + * + * @v netdev Network device + */ +static void arp_flush ( struct net_device *netdev ) { + struct arp_entry *arp; + struct arp_entry *tmp; + + /* Remove all ARP cache entries when a network device is closed */ + if ( ! netdev_is_open ( netdev ) ) { + list_for_each_entry_safe ( arp, tmp, &arp_entries, list ) + arp_destroy ( arp, -ENODEV ); + } +} + +/** ARP driver (for net device notifications) */ +struct net_driver arp_net_driver __net_driver = { + .name = "ARP", + .probe = arp_probe, + .notify = arp_flush, + .remove = arp_flush, +}; + +/** + * Discard some cached ARP entries + * + * @ret discarded Number of cached items discarded + */ +static unsigned int arp_discard ( void ) { + struct arp_entry *arp; + + /* Drop oldest cache entry, if any */ + list_for_each_entry_reverse ( arp, &arp_entries, list ) { + arp_destroy ( arp, -ENOBUFS ); + return 1; + } + + return 0; +} + +/** ARP cache discarder */ +struct cache_discarder arp_cache_discarder __cache_discarder = { + .discard = arp_discard, +}; diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 99c2580e..08249d41 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -281,35 +281,6 @@ static uint16_t ipv4_pshdr_chksum ( struct io_buffer *iobuf, uint16_t csum ) { return tcpip_continue_chksum ( csum, &pshdr, sizeof ( pshdr ) ); } -/** - * Determine link-layer address - * - * @v dest IPv4 destination address - * @v src IPv4 source address - * @v netmask IPv4 subnet mask - * @v netdev Network device - * @v ll_dest Link-layer destination address buffer - * @ret rc Return status code - */ -static int ipv4_ll_addr ( struct in_addr dest, struct in_addr src, - struct in_addr netmask, struct net_device *netdev, - uint8_t *ll_dest ) { - struct ll_protocol *ll_protocol = netdev->ll_protocol; - - if ( ( ( dest.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0 ) { - /* Broadcast address */ - memcpy ( ll_dest, netdev->ll_broadcast, - ll_protocol->ll_addr_len ); - return 0; - } else if ( IN_MULTICAST ( ntohl ( dest.s_addr ) ) ) { - return ll_protocol->mc_hash ( AF_INET, &dest, ll_dest ); - } else { - /* Unicast address: resolve via ARP */ - return arp_resolve ( netdev, &ipv4_protocol, &dest, - &src, ll_dest ); - } -} - /** * Transmit IP packet * @@ -335,7 +306,8 @@ static int ipv4_tx ( struct io_buffer *iobuf, struct ipv4_miniroute *miniroute; struct in_addr next_hop; struct in_addr netmask = { .s_addr = 0 }; - uint8_t ll_dest[MAX_LL_ADDR_LEN]; + uint8_t ll_dest_buf[MAX_LL_ADDR_LEN]; + const void *ll_dest; int rc; /* Fill up the IP header, except source address */ @@ -373,16 +345,6 @@ static int ipv4_tx ( struct io_buffer *iobuf, ( ( netdev->rx_stats.bad & 0xf ) << 4 ) | ( ( netdev->rx_stats.good & 0xf ) << 0 ) ); - /* Determine link-layer destination address */ - if ( ( rc = ipv4_ll_addr ( next_hop, iphdr->src, netmask, netdev, - ll_dest ) ) != 0 ) { - DBGC ( sin_dest->sin_addr, "IPv4 has no link-layer address for " - "%s: %s\n", inet_ntoa ( next_hop ), strerror ( rc ) ); - /* Record error for diagnosis */ - netdev_tx_err ( netdev, iob_disown ( iobuf ), rc ); - goto err; - } - /* Fix up checksums */ if ( trans_csum ) *trans_csum = ipv4_pshdr_chksum ( iobuf, *trans_csum ); @@ -395,12 +357,42 @@ static int ipv4_tx ( struct io_buffer *iobuf, iphdr->protocol, ntohs ( iphdr->ident ), ntohs ( iphdr->chksum ) ); - /* Hand off to link layer */ - if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest, - netdev->ll_addr ) ) != 0 ) { - DBGC ( sin_dest->sin_addr, "IPv4 could not transmit packet " - "via %s: %s\n", netdev->name, strerror ( rc ) ); - return rc; + /* Calculate link-layer destination address, if possible */ + if ( ( ( next_hop.s_addr ^ INADDR_BROADCAST ) & ~netmask.s_addr ) == 0){ + /* Broadcast address */ + ll_dest = netdev->ll_broadcast; + } else if ( IN_MULTICAST ( ntohl ( next_hop.s_addr ) ) ) { + /* Multicast address */ + if ( ( rc = netdev->ll_protocol->mc_hash ( AF_INET, &next_hop, + ll_dest_buf ) ) !=0){ + DBGC ( sin_dest->sin_addr, "IPv4 could not hash " + "multicast %s: %s\n", + inet_ntoa ( next_hop ), strerror ( rc ) ); + return rc; + } + ll_dest = ll_dest_buf; + } else { + /* Unicast address */ + ll_dest = NULL; + } + + /* Hand off to link layer (via ARP if applicable) */ + if ( ll_dest ) { + if ( ( rc = net_tx ( iobuf, netdev, &ipv4_protocol, ll_dest, + netdev->ll_addr ) ) != 0 ) { + DBGC ( sin_dest->sin_addr, "IPv4 could not transmit " + "packet via %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } + } else { + if ( ( rc = arp_tx ( iobuf, netdev, &ipv4_protocol, &next_hop, + &iphdr->src, netdev->ll_addr ) ) != 0 ) { + DBGC ( sin_dest->sin_addr, "IPv4 could not transmit " + "packet via %s: %s\n", + netdev->name, strerror ( rc ) ); + return rc; + } } return 0; From d9ce3bfe4c574934234a07cab1b7c6af917645c5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 3 Mar 2012 14:11:46 +0000 Subject: [PATCH 028/221] [tls] Support TLS version 1.1 Advertise support for TLS version 1.1, and be prepared to downgrade to TLS version 1.0. Tested against Apache with mod_gnutls, using the GnuTLSPriorities directive to force specific protocol versions. Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 2 ++ src/net/tls.c | 44 +++++++++++++++++++++++++++--------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 94cd322c..c14e9210 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -138,6 +138,8 @@ struct tls_session { /** Ciphertext stream */ struct interface cipherstream; + /** Protocol version */ + uint16_t version; /** Current TX cipher specification */ struct tls_cipherspec tx_cipherspec; /** Next TX cipher specification */ diff --git a/src/net/tls.c b/src/net/tls.c index 9acc5c3d..cbba0003 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -697,7 +697,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) { hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) | htonl ( sizeof ( hello ) - sizeof ( hello.type_length ) ) ); - hello.version = htons ( TLS_VERSION_TLS_1_0 ); + hello.version = htons ( tls->version ); memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) ); hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) ); hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ); @@ -877,6 +877,7 @@ static int tls_new_server_hello ( struct tls_session *tls, char next[0]; } __attribute__ (( packed )) *hello_b = ( void * ) &hello_a->next; void *end = hello_b->next; + uint16_t version; int rc; /* Sanity check */ @@ -886,13 +887,22 @@ static int tls_new_server_hello ( struct tls_session *tls, return -EINVAL; } - /* Check protocol version */ - if ( ntohs ( hello_a->version ) < TLS_VERSION_TLS_1_0 ) { + /* Check and store protocol version */ + version = ntohs ( hello_a->version ); + if ( version < TLS_VERSION_TLS_1_0 ) { DBGC ( tls, "TLS %p does not support protocol version %d.%d\n", - tls, ( ntohs ( hello_a->version ) >> 8 ), - ( ntohs ( hello_a->version ) & 0xff ) ); + tls, ( version >> 8 ), ( version & 0xff ) ); return -ENOTSUP; } + if ( version > tls->version ) { + DBGC ( tls, "TLS %p server attempted to illegally upgrade to " + "protocol version %d.%d\n", + tls, ( version >> 8 ), ( version & 0xff ) ); + return -EPROTO; + } + tls->version = version; + DBGC ( tls, "TLS %p using protocol version %d.%d\n", + tls, ( version >> 8 ), ( version & 0xff ) ); /* Copy out server random bytes */ memcpy ( &tls->server_random, &hello_a->random, @@ -1208,8 +1218,8 @@ static void * tls_assemble_block ( struct tls_session *tls, const void *data, size_t len, void *digest, size_t *plaintext_len ) { size_t blocksize = tls->tx_cipherspec.cipher->blocksize; - size_t iv_len = blocksize; size_t mac_len = tls->tx_cipherspec.digest->digestsize; + size_t iv_len; size_t padding_len; void *plaintext; void *iv; @@ -1217,8 +1227,8 @@ static void * tls_assemble_block ( struct tls_session *tls, void *mac; void *padding; - /* FIXME: TLSv1.1 has an explicit IV */ - iv_len = 0; + /* TLSv1.1 and later use an explicit IV */ + iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ? blocksize : 0 ); /* Calculate block-ciphered struct length */ padding_len = ( ( blocksize - 1 ) & -( iv_len + len + mac_len + 1 ) ); @@ -1234,7 +1244,7 @@ static void * tls_assemble_block ( struct tls_session *tls, padding = ( mac + mac_len ); /* Fill in block-ciphered struct */ - memset ( iv, 0, iv_len ); + tls_generate_random ( tls, iv, iv_len ); memcpy ( content, data, len ); memcpy ( mac, digest, mac_len ); memset ( padding, padding_len, ( padding_len + 1 ) ); @@ -1266,7 +1276,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, /* Construct header */ plaintext_tlshdr.type = type; - plaintext_tlshdr.version = htons ( TLS_VERSION_TLS_1_0 ); + plaintext_tlshdr.version = htons ( tls->version ); plaintext_tlshdr.length = htons ( len ); /* Calculate MAC */ @@ -1304,7 +1314,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, /* Assemble ciphertext */ tlshdr = iob_put ( ciphertext, sizeof ( *tlshdr ) ); tlshdr->type = type; - tlshdr->version = htons ( TLS_VERSION_TLS_1_0 ); + tlshdr->version = htons ( tls->version ); tlshdr->length = htons ( plaintext_len ); memcpy ( cipherspec->cipher_next_ctx, cipherspec->cipher_ctx, cipherspec->cipher->ctxsize ); @@ -1399,17 +1409,18 @@ static int tls_split_block ( struct tls_session *tls, size_t padding_len; unsigned int i; - /* Decompose block-ciphered data */ + /* Sanity check */ if ( plaintext_len < 1 ) { DBGC ( tls, "TLS %p received underlength record\n", tls ); DBGC_HD ( tls, plaintext, plaintext_len ); return -EINVAL; } - iv_len = tls->rx_cipherspec.cipher->blocksize; - /* FIXME: TLSv1.1 uses an explicit IV */ - iv_len = 0; + /* TLSv1.1 and later use an explicit IV */ + iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ? + tls->rx_cipherspec.cipher->blocksize : 0 ); + /* Decompose block-ciphered data */ mac_len = tls->rx_cipherspec.digest->digestsize; padding_len = *( ( uint8_t * ) ( plaintext + plaintext_len - 1 ) ); if ( plaintext_len < ( iv_len + mac_len + padding_len + 1 ) ) { @@ -1808,6 +1819,7 @@ int add_tls ( struct interface *xfer, struct interface **next ) { ref_init ( &tls->refcnt, free_tls ); intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt ); intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt ); + tls->version = TLS_VERSION_TLS_1_1; tls_clear_cipher ( tls, &tls->tx_cipherspec ); tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); tls_clear_cipher ( tls, &tls->rx_cipherspec ); @@ -1817,7 +1829,7 @@ int add_tls ( struct interface *xfer, struct interface **next ) { ( sizeof ( tls->client_random.random ) ) ) ) != 0 ) { goto err_random; } - tls->pre_master_secret.version = htons ( TLS_VERSION_TLS_1_0 ); + tls->pre_master_secret.version = htons ( tls->version ); if ( ( rc = tls_generate_random ( tls, &tls->pre_master_secret.random, ( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) { goto err_random; From b7f8d1bbfd657ecfcae6e74a62766e2e15abaa11 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 3 Mar 2012 20:15:21 +0000 Subject: [PATCH 029/221] [tls] Add support for Server Name Indication (SNI) Signed-off-by: Michael Brown --- src/include/ipxe/http.h | 1 + src/include/ipxe/tls.h | 8 +++++++- src/net/tcp/httpcore.c | 3 ++- src/net/tls.c | 32 +++++++++++++++++++++++++++++--- 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/include/ipxe/http.h b/src/include/ipxe/http.h index d8f4ca5a..cf8c0c7f 100644 --- a/src/include/ipxe/http.h +++ b/src/include/ipxe/http.h @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); extern int http_open_filter ( struct interface *xfer, struct uri *uri, unsigned int default_port, int ( * filter ) ( struct interface *, + const char *, struct interface ** ) ); #endif /* _IPXE_HTTP_H */ diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index c14e9210..90833781 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -74,6 +74,10 @@ struct tls_header { #define TLS_RSA_WITH_AES_128_CBC_SHA 0x002f #define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 +/* TLS extension types */ +#define TLS_SERVER_NAME 0 +#define TLS_SERVER_NAME_HOST_NAME 0 + /** TLS RX state machine state */ enum tls_rx_state { TLS_RX_HEADER = 0, @@ -133,6 +137,8 @@ struct tls_session { /** Reference counter */ struct refcnt refcnt; + /** Server name */ + const char *name; /** Plaintext stream */ struct interface plainstream; /** Ciphertext stream */ @@ -183,7 +189,7 @@ struct tls_session { void *rx_data; }; -extern int add_tls ( struct interface *xfer, +extern int add_tls ( struct interface *xfer, const char *name, struct interface **next ); #endif /* _IPXE_TLS_H */ diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 69d27389..617f49b0 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -838,6 +838,7 @@ static struct process_descriptor http_process_desc = int http_open_filter ( struct interface *xfer, struct uri *uri, unsigned int default_port, int ( * filter ) ( struct interface *xfer, + const char *name, struct interface **next ) ) { struct http_request *http; struct sockaddr_tcpip server; @@ -865,7 +866,7 @@ int http_open_filter ( struct interface *xfer, struct uri *uri, server.st_port = htons ( uri_port ( http->uri, default_port ) ); socket = &http->socket; if ( filter ) { - if ( ( rc = filter ( socket, &socket ) ) != 0 ) + if ( ( rc = filter ( socket, uri->host, &socket ) ) != 0 ) goto err; } if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, diff --git a/src/net/tls.c b/src/net/tls.c index cbba0003..919025e7 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -691,6 +691,19 @@ static int tls_send_client_hello ( struct tls_session *tls ) { uint16_t cipher_suites[2]; uint8_t compression_methods_len; uint8_t compression_methods[1]; + uint16_t extensions_len; + struct { + uint16_t server_name_type; + uint16_t server_name_len; + struct { + uint16_t len; + struct { + uint8_t type; + uint16_t len; + uint8_t name[ strlen ( tls->name ) ]; + } __attribute__ (( packed )) list[1]; + } __attribute__ (( packed )) server_name; + } __attribute__ (( packed )) extensions; } __attribute__ (( packed )) hello; memset ( &hello, 0, sizeof ( hello ) ); @@ -703,6 +716,17 @@ static int tls_send_client_hello ( struct tls_session *tls ) { hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ); hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ); hello.compression_methods_len = sizeof ( hello.compression_methods ); + hello.extensions_len = htons ( sizeof ( hello.extensions ) ); + hello.extensions.server_name_type = htons ( TLS_SERVER_NAME ); + hello.extensions.server_name_len + = htons ( sizeof ( hello.extensions.server_name ) ); + hello.extensions.server_name.len + = htons ( sizeof ( hello.extensions.server_name.list ) ); + hello.extensions.server_name.list[0].type = TLS_SERVER_NAME_HOST_NAME; + hello.extensions.server_name.list[0].len + = htons ( sizeof ( hello.extensions.server_name.list[0].name )); + memcpy ( hello.extensions.server_name.list[0].name, tls->name, + sizeof ( hello.extensions.server_name.list[0].name ) ); return tls_send_handshake ( tls, &hello, sizeof ( hello ) ); } @@ -881,8 +905,8 @@ static int tls_new_server_hello ( struct tls_session *tls, int rc; /* Sanity check */ - if ( end != ( data + len ) ) { - DBGC ( tls, "TLS %p received overlength Server Hello\n", tls ); + if ( end > ( data + len ) ) { + DBGC ( tls, "TLS %p received underlength Server Hello\n", tls ); DBGC_HD ( tls, data, len ); return -EINVAL; } @@ -1805,7 +1829,8 @@ static struct process_descriptor tls_process_desc = ****************************************************************************** */ -int add_tls ( struct interface *xfer, struct interface **next ) { +int add_tls ( struct interface *xfer, const char *name, + struct interface **next ) { struct tls_session *tls; int rc; @@ -1817,6 +1842,7 @@ int add_tls ( struct interface *xfer, struct interface **next ) { } memset ( tls, 0, sizeof ( *tls ) ); ref_init ( &tls->refcnt, free_tls ); + tls->name = name; intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt ); intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt ); tls->version = TLS_VERSION_TLS_1_1; From 56a7981d5889c91fb333c6b98daf7b9a9d1ec0ee Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 3 Mar 2012 22:15:25 +0000 Subject: [PATCH 030/221] [tls] Allow transmitted records to be scheduled independently Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 20 ++++---- src/net/tls.c | 112 +++++++++++------------------------------ 2 files changed, 39 insertions(+), 93 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 90833781..2aa2b06d 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -84,14 +84,12 @@ enum tls_rx_state { TLS_RX_DATA, }; -/** TLS TX state machine state */ -enum tls_tx_state { - TLS_TX_NONE = 0, - TLS_TX_CLIENT_HELLO, - TLS_TX_CLIENT_KEY_EXCHANGE, - TLS_TX_CHANGE_CIPHER, - TLS_TX_FINISHED, - TLS_TX_DATA +/** TLS TX pending flags */ +enum tls_tx_pending { + TLS_TX_CLIENT_HELLO = 0x0001, + TLS_TX_CLIENT_KEY_EXCHANGE = 0x0002, + TLS_TX_CHANGE_CIPHER = 0x0004, + TLS_TX_FINISHED = 0x0008, }; /** A TLS cipher specification */ @@ -172,10 +170,12 @@ struct tls_session { /** TX sequence number */ uint64_t tx_seq; - /** TX state */ - enum tls_tx_state tx_state; + /** TX pending transmissions */ + unsigned int tx_pending; /** TX process */ struct process process; + /** TX ready for plaintext data */ + int tx_ready; /** RX sequence number */ uint64_t rx_seq; diff --git a/src/net/tls.c b/src/net/tls.c index 919025e7..edf8d9fb 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -596,7 +596,7 @@ static void tls_verify_handshake ( struct tls_session *tls, void *out ) { /****************************************************************************** * - * TX state machine transitions + * Record handling * ****************************************************************************** */ @@ -610,53 +610,6 @@ static void tls_tx_resume ( struct tls_session *tls ) { process_add ( &tls->process ); } -/** - * Enter TX state machine active state - * - * @v tls TLS session - * @v state TX state - */ -static void tls_tx_start ( struct tls_session *tls, enum tls_tx_state state ) { - - /* Enter specified state */ - tls->tx_state = state; - - /* Resume state machine */ - tls_tx_resume ( tls ); -} - -/** - * Enter TX state machine idle state - * - * @v tls TLS session - */ -static void tls_tx_none ( struct tls_session *tls ) { - - /* Enter idle state */ - tls->tx_state = TLS_TX_NONE; -} - -/** - * Enter TX state machine data state - * - * @v tls TLS session - */ -static void tls_tx_data ( struct tls_session *tls ) { - - /* Enter data state */ - tls->tx_state = TLS_TX_DATA; - - /* Send notification of a window change */ - xfer_window_changed ( &tls->plainstream ); -} - -/****************************************************************************** - * - * Record handling - * - ****************************************************************************** - */ - /** * Transmit Handshake record * @@ -1025,15 +978,11 @@ static int tls_new_server_hello_done ( struct tls_session *tls, return -EINVAL; } - /* Check that we are ready to send the Client Key Exchange */ - if ( tls->tx_state != TLS_TX_NONE ) { - DBGC ( tls, "TLS %p received Server Hello Done while in " - "TX state %d\n", tls, tls->tx_state ); - return -EIO; - } - - /* Start sending the Client Key Exchange */ - tls_tx_start ( tls, TLS_TX_CLIENT_KEY_EXCHANGE ); + /* Schedule Client Key Exchange, Change Cipher, and Finished */ + tls->tx_pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | + TLS_TX_CHANGE_CIPHER | + TLS_TX_FINISHED ); + tls_tx_resume ( tls ); return 0; } @@ -1050,10 +999,15 @@ static int tls_new_finished ( struct tls_session *tls, void *data, size_t len ) { /* FIXME: Handle this properly */ - tls_tx_data ( tls ); ( void ) data; ( void ) len; + /* Mark session as ready to transmit plaintext data */ + tls->tx_ready = 1; + + /* Send notification of a window change */ + xfer_window_changed ( &tls->plainstream ); + return 0; } @@ -1561,7 +1515,7 @@ static int tls_new_ciphertext ( struct tls_session *tls, static size_t tls_plainstream_window ( struct tls_session *tls ) { /* Block window unless we are ready to accept data */ - if ( tls->tx_state != TLS_TX_DATA ) + if ( ! tls->tx_ready ) return 0; return xfer_window ( &tls->cipherstream ); @@ -1581,7 +1535,7 @@ static int tls_plainstream_deliver ( struct tls_session *tls, int rc; /* Refuse unless we are ready to accept data */ - if ( tls->tx_state != TLS_TX_DATA ) { + if ( ! tls->tx_ready ) { rc = -ENOTCONN; goto done; } @@ -1757,29 +1711,24 @@ static void tls_tx_step ( struct tls_session *tls ) { if ( ! xfer_window ( &tls->cipherstream ) ) return; - switch ( tls->tx_state ) { - case TLS_TX_NONE: - /* Nothing to do */ - break; - case TLS_TX_CLIENT_HELLO: + /* Send first pending transmission */ + if ( tls->tx_pending & TLS_TX_CLIENT_HELLO ) { /* Send Client Hello */ if ( ( rc = tls_send_client_hello ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Client Hello: %s\n", tls, strerror ( rc ) ); goto err; } - tls_tx_none ( tls ); - break; - case TLS_TX_CLIENT_KEY_EXCHANGE: + tls->tx_pending &= ~TLS_TX_CLIENT_HELLO; + } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) { /* Send Client Key Exchange */ if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could send Client Key Exchange: " "%s\n", tls, strerror ( rc ) ); goto err; } - tls_tx_start ( tls, TLS_TX_CHANGE_CIPHER ); - break; - case TLS_TX_CHANGE_CIPHER: + tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE; + } else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) { /* Send Change Cipher, and then change the cipher in use */ if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Change Cipher: " @@ -1794,24 +1743,21 @@ static void tls_tx_step ( struct tls_session *tls ) { goto err; } tls->tx_seq = 0; - tls_tx_start ( tls, TLS_TX_FINISHED ); - break; - case TLS_TX_FINISHED: + tls->tx_pending &= ~TLS_TX_CHANGE_CIPHER; + } else if ( tls->tx_pending & TLS_TX_FINISHED ) { /* Send Finished */ if ( ( rc = tls_send_finished ( tls ) ) != 0 ) { DBGC ( tls, "TLS %p could not send Finished: %s\n", tls, strerror ( rc ) ); goto err; } - tls_tx_none ( tls ); - break; - case TLS_TX_DATA: - /* Nothing to do */ - break; - default: - assert ( 0 ); + tls->tx_pending &= ~TLS_TX_FINISHED; } + /* Reschedule process if pending transmissions remain */ + if ( tls->tx_pending ) + tls_tx_resume ( tls ); + return; err: @@ -1862,8 +1808,8 @@ int add_tls ( struct interface *xfer, const char *name, } digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); - process_init_stopped ( &tls->process, &tls_process_desc, &tls->refcnt ); - tls_tx_start ( tls, TLS_TX_CLIENT_HELLO ); + tls->tx_pending = TLS_TX_CLIENT_HELLO; + process_init ( &tls->process, &tls_process_desc, &tls->refcnt ); /* Attach to parent interface, mortalise self, and return */ intf_plug_plug ( &tls->plainstream, xfer ); From a42f6cab144f1f65295dc194e70b3f05ffa1c560 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 3 Mar 2012 22:29:20 +0000 Subject: [PATCH 031/221] [tls] Verify the contents of the Finished record Signed-off-by: Michael Brown --- src/net/tls.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index edf8d9fb..28a4ba4e 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -997,10 +997,31 @@ static int tls_new_server_hello_done ( struct tls_session *tls, */ static int tls_new_finished ( struct tls_session *tls, void *data, size_t len ) { + struct { + uint8_t verify_data[12]; + char next[0]; + } __attribute__ (( packed )) *finished = data; + void *end = finished->next; + uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE]; + uint8_t verify_data[ sizeof ( finished->verify_data ) ]; - /* FIXME: Handle this properly */ - ( void ) data; - ( void ) len; + /* Sanity check */ + if ( end != ( data + len ) ) { + DBGC ( tls, "TLS %p received overlength Finished\n", tls ); + DBGC_HD ( tls, data, len ); + return -EINVAL; + } + + /* Verify data */ + tls_verify_handshake ( tls, digest ); + tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), + verify_data, sizeof ( verify_data ), "server finished", + digest, sizeof ( digest ) ); + if ( memcmp ( verify_data, finished->verify_data, + sizeof ( verify_data ) ) != 0 ) { + DBGC ( tls, "TLS %p verification failed\n", tls ); + return -EPERM; + } /* Mark session as ready to transmit plaintext data */ tls->tx_ready = 1; From 281f9aa7a6775e60c78469228fe3d1a3a1355db9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 3 Mar 2012 22:47:16 +0000 Subject: [PATCH 032/221] [tls] Send empty Certificate record if requested by server Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 7 +++--- src/net/tls.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 2aa2b06d..49401e6b 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -87,9 +87,10 @@ enum tls_rx_state { /** TLS TX pending flags */ enum tls_tx_pending { TLS_TX_CLIENT_HELLO = 0x0001, - TLS_TX_CLIENT_KEY_EXCHANGE = 0x0002, - TLS_TX_CHANGE_CIPHER = 0x0004, - TLS_TX_FINISHED = 0x0008, + TLS_TX_CERTIFICATE = 0x0002, + TLS_TX_CLIENT_KEY_EXCHANGE = 0x0004, + TLS_TX_CHANGE_CIPHER = 0x0008, + TLS_TX_FINISHED = 0x0010, }; /** A TLS cipher specification */ diff --git a/src/net/tls.c b/src/net/tls.c index 28a4ba4e..0249ed7c 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -684,6 +684,27 @@ static int tls_send_client_hello ( struct tls_session *tls ) { return tls_send_handshake ( tls, &hello, sizeof ( hello ) ); } +/** + * Transmit Certificate record + * + * @v tls TLS session + * @ret rc Return status code + */ +static int tls_send_certificate ( struct tls_session *tls ) { + struct { + uint32_t type_length; + uint8_t length[3]; + } __attribute__ (( packed )) certificate; + + memset ( &certificate, 0, sizeof ( certificate ) ); + certificate.type_length = ( cpu_to_le32 ( TLS_CERTIFICATE ) | + htonl ( sizeof ( certificate ) - + sizeof ( certificate.type_length))); + + return tls_send_handshake ( tls, &certificate, sizeof ( certificate ) ); +} + + /** * Transmit Client Key Exchange record * @@ -955,6 +976,30 @@ static int tls_new_certificate ( struct tls_session *tls, return -EINVAL; } +/** + * Receive new Certificate Request handshake record + * + * @v tls TLS session + * @v data Plaintext handshake record + * @v len Length of plaintext handshake record + * @ret rc Return status code + */ +static int tls_new_certificate_request ( struct tls_session *tls, + void *data __unused, + size_t len __unused ) { + + /* We can only send an empty certificate (as mandated by + * TLSv1.2), so there is no point in parsing the Certificate + * Request. + */ + + /* Schedule Certificate transmission */ + tls->tx_pending |= TLS_TX_CERTIFICATE; + tls_tx_resume ( tls ); + + return 0; +} + /** * Receive new Server Hello Done handshake record * @@ -1070,6 +1115,10 @@ static int tls_new_handshake ( struct tls_session *tls, case TLS_CERTIFICATE: rc = tls_new_certificate ( tls, payload, payload_len ); break; + case TLS_CERTIFICATE_REQUEST: + rc = tls_new_certificate_request ( tls, payload, + payload_len ); + break; case TLS_SERVER_HELLO_DONE: rc = tls_new_server_hello_done ( tls, payload, payload_len ); @@ -1741,6 +1790,14 @@ static void tls_tx_step ( struct tls_session *tls ) { goto err; } tls->tx_pending &= ~TLS_TX_CLIENT_HELLO; + } else if ( tls->tx_pending & TLS_TX_CERTIFICATE ) { + /* Send Certificate */ + if ( ( rc = tls_send_certificate ( tls ) ) != 0 ) { + DBGC ( tls, "TLS %p cold not send Certificate: %s\n", + tls, strerror ( rc ) ); + goto err; + } + tls->tx_pending &= ~TLS_TX_CERTIFICATE; } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) { /* Send Client Key Exchange */ if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) { From 4fde501e39fa637798867576bf80abf2a4faf401 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 14:58:22 +0000 Subject: [PATCH 033/221] [802.11] Add missing #include Signed-off-by: Michael Brown --- src/net/80211/wpa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/net/80211/wpa.c b/src/net/80211/wpa.c index 38ddb911..90929ea3 100644 --- a/src/net/80211/wpa.c +++ b/src/net/80211/wpa.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include /** @file * From c5c1ae42e67254f5c4667c037ee92806d4703e64 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 14:59:32 +0000 Subject: [PATCH 034/221] [rng] Add missing #include Signed-off-by: Michael Brown --- src/crypto/hash_df.c | 1 + src/crypto/hmac_drbg.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/crypto/hash_df.c b/src/crypto/hash_df.c index 9e3da181..1074f8ca 100644 --- a/src/crypto/hash_df.c +++ b/src/crypto/hash_df.c @@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include #include diff --git a/src/crypto/hmac_drbg.c b/src/crypto/hmac_drbg.c index efbd67dc..9e70e4e6 100644 --- a/src/crypto/hmac_drbg.c +++ b/src/crypto/hmac_drbg.c @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include From 4a32308b400fadf0bdbb0a15c74d2440ee6482ee Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 15:01:13 +0000 Subject: [PATCH 035/221] [tls] Add missing #include Signed-off-by: Michael Brown --- src/include/ipxe/x509.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 37c5a4ee..2ea21aa9 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include struct asn1_cursor; From af96c4151ce96d04f960a79e5cf317353410bb1e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 15:06:45 +0000 Subject: [PATCH 036/221] [i386] Optimise byte-swapping functions and provide __bswap_{16,32,64}s() Use the "bswap" instruction to shrink the size of byte-swapping code, and provide the in-place variants __bswap_{16,32,64}s. "bswap" is available only on 486 and later processors. (We already assume the presence of "cpuid" and "rdtsc", which are available only on Pentium and later processors.) Signed-off-by: Michael Brown --- src/arch/i386/include/bits/byteswap.h | 88 +++++++++++++++++---------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/src/arch/i386/include/bits/byteswap.h b/src/arch/i386/include/bits/byteswap.h index ddbd40ed..381e695f 100644 --- a/src/arch/i386/include/bits/byteswap.h +++ b/src/arch/i386/include/bits/byteswap.h @@ -1,43 +1,67 @@ -#ifndef ETHERBOOT_BITS_BYTESWAP_H -#define ETHERBOOT_BITS_BYTESWAP_H +#ifndef _BITS_BYTESWAP_H +#define _BITS_BYTESWAP_H + +/** @file + * + * Byte-order swapping functions + * + */ + +#include FILE_LICENCE ( GPL2_OR_LATER ); -static inline __attribute__ ((always_inline, const)) uint16_t -__bswap_variable_16(uint16_t x) -{ - __asm__("xchgb %b0,%h0\n\t" - : "=q" (x) - : "0" (x)); +static inline __attribute__ (( always_inline, const )) uint16_t +__bswap_variable_16 ( uint16_t x ) { + __asm__ ( "xchgb %b0,%h0" : "=q" ( x ) : "0" ( x ) ); return x; } -static inline __attribute__ ((always_inline, const)) uint32_t -__bswap_variable_32(uint32_t x) -{ - __asm__("xchgb %b0,%h0\n\t" - "rorl $16,%0\n\t" - "xchgb %b0,%h0" - : "=q" (x) - : "0" (x)); +static inline __attribute__ (( always_inline )) void +__bswap_16s ( uint16_t *x ) { + __asm__ ( "rorw $8, %0" : "=g" ( *x ) : "0" ( *x ) ); +} + +static inline __attribute__ (( always_inline, const )) uint32_t +__bswap_variable_32 ( uint32_t x ) { + __asm__ ( "bswapl %0" : "=r" ( x ) : "0" ( x ) ); return x; } -static inline __attribute__ ((always_inline, const)) uint64_t -__bswap_variable_64(uint64_t x) -{ - union { - uint64_t qword; - uint32_t dword[2]; - } u; - - u.qword = x; - u.dword[0] = __bswap_variable_32(u.dword[0]); - u.dword[1] = __bswap_variable_32(u.dword[1]); - __asm__("xchgl %0,%1" - : "=r" ( u.dword[0] ), "=r" ( u.dword[1] ) - : "0" ( u.dword[0] ), "1" ( u.dword[1] ) ); - return u.qword; +static inline __attribute__ (( always_inline )) void +__bswap_32s ( uint32_t *x ) { + __asm__ ( "bswapl %0" : "=r" ( *x ) : "0" ( *x ) ); } -#endif /* ETHERBOOT_BITS_BYTESWAP_H */ +static inline __attribute__ (( always_inline, const )) uint64_t +__bswap_variable_64 ( uint64_t x ) { + uint32_t in_high = ( x >> 32 ); + uint32_t in_low = ( x & 0xffffffffUL ); + uint32_t out_high; + uint32_t out_low; + + __asm__ ( "bswapl %0\n\t" + "bswapl %1\n\t" + "xchgl %0,%1\n\t" + : "=r" ( out_high ), "=r" ( out_low ) + : "0" ( in_high ), "1" ( in_low ) ); + + return ( ( ( ( uint64_t ) out_high ) << 32 ) | + ( ( uint64_t ) out_low ) ); +} + +static inline __attribute__ (( always_inline )) void +__bswap_64s ( uint64_t *x ) { + uint32_t __attribute__ (( may_alias )) *dwords = ( ( void * ) x ); + uint32_t discard; + + __asm__ ( "movl %0,%2\n\t" + "bswapl %2\n\t" + "xchgl %2,%1\n\t" + "bswapl %2\n\t" + "movl %2,%0\n\t" + : "=g" ( dwords[0] ), "=g" ( dwords[1] ), "=r" ( discard ) + : "0" ( dwords[0] ), "1" ( dwords[1] ) ); +} + +#endif /* _BITS_BYTESWAP_H */ From 249a833ed4cc481b5feb2c148ea4412835a71471 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 15:28:44 +0000 Subject: [PATCH 037/221] [x86_64] Provide __bswap_{16,32,64}s() Signed-off-by: Michael Brown --- src/arch/x86_64/include/bits/byteswap.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/arch/x86_64/include/bits/byteswap.h b/src/arch/x86_64/include/bits/byteswap.h index 9ed85e8f..113b3278 100644 --- a/src/arch/x86_64/include/bits/byteswap.h +++ b/src/arch/x86_64/include/bits/byteswap.h @@ -1,22 +1,47 @@ #ifndef _BITS_BYTESWAP_H #define _BITS_BYTESWAP_H +/** @file + * + * Byte-order swapping functions + * + */ + +#include + +FILE_LICENCE ( GPL2_OR_LATER ); + static inline __attribute__ (( always_inline, const )) uint16_t __bswap_variable_16 ( uint16_t x ) { __asm__ ( "xchgb %b0,%h0" : "=Q" ( x ) : "0" ( x ) ); return x; } +static inline __attribute__ (( always_inline )) void +__bswap_16s ( uint16_t *x ) { + __asm__ ( "rorw $8, %0" : "=g" ( *x ) : "0" ( *x ) ); +} + static inline __attribute__ (( always_inline, const )) uint32_t __bswap_variable_32 ( uint32_t x ) { __asm__ ( "bswapl %k0" : "=r" ( x ) : "0" ( x ) ); return x; } +static inline __attribute__ (( always_inline )) void +__bswap_32s ( uint32_t *x ) { + __asm__ ( "bswapl %k0" : "=r" ( *x ) : "0" ( *x ) ); +} + static inline __attribute__ (( always_inline, const )) uint64_t __bswap_variable_64 ( uint64_t x ) { __asm__ ( "bswapq %q0" : "=r" ( x ) : "0" ( x ) ); return x; } +static inline __attribute__ (( always_inline )) void +__bswap_64s ( uint64_t *x ) { + __asm__ ( "bswapq %q0" : "=r" ( *x ) : "0" ( *x ) ); +} + #endif /* _BITS_BYTESWAP_H */ From c94a4a8d126d6d876ed3106ccff8b929346284c6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 15:12:38 +0000 Subject: [PATCH 038/221] [test] Add self-tests for byte-order swapping functions Signed-off-by: Michael Brown --- src/tests/byteswap_test.c | 91 +++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 2 files changed, 92 insertions(+) create mode 100644 src/tests/byteswap_test.c diff --git a/src/tests/byteswap_test.c b/src/tests/byteswap_test.c new file mode 100644 index 00000000..9bfe2659 --- /dev/null +++ b/src/tests/byteswap_test.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Byte-order swapping test functions + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include + +/* Provide global functions to allow inspection of generated assembly code */ + +uint16_t test_bswap16 ( uint16_t x ) { + return __bswap_16 ( x ); +} + +uint32_t test_bswap32 ( uint32_t x ) { + return __bswap_32 ( x ); +} + +uint64_t test_bswap64 ( uint64_t x ) { + return __bswap_64 ( x ); +} + +void test_bswap16s ( uint16_t *x ) { + __bswap_16s ( x ); +} + +void test_bswap32s ( uint32_t *x ) { + __bswap_32s ( x ); +} + +void test_bswap64s ( uint64_t *x ) { + __bswap_64s ( x ); +} + +/** + * Perform byte-order swapping + * + */ +static void byteswap_test_exec ( void ) { + uint16_t test16; + uint32_t test32; + uint64_t test64; + + ok ( test_bswap16 ( 0x1234 ) == 0x3412 ); + ok ( test_bswap32 ( 0x12345678UL ) == 0x78563412UL ); + ok ( test_bswap64 ( 0x123456789abcdef0ULL ) == 0xf0debc9a78563412ULL ); + + test16 = 0xabcd; + test_bswap16s ( &test16 ); + ok ( test16 == 0xcdab ); + + test32 = 0xabcdef01UL; + test_bswap32s ( &test32 ); + ok ( test32 == 0x01efcdabUL ); + + test64 = 0xabcdef0123456789ULL; + test_bswap64s ( &test64 ); + ok ( test64 == 0x8967452301efcdabULL ); +} + +/** Byte-order swapping self-test */ +struct self_test byteswap_test __self_test = { + .name = "byteswap", + .exec = byteswap_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 870d467e..1e5b217a 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Drag in all applicable self-tests */ REQUIRE_OBJECT ( list_test ); +REQUIRE_OBJECT ( byteswap_test ); REQUIRE_OBJECT ( sha1_test ); REQUIRE_OBJECT ( hmac_drbg_test ); REQUIRE_OBJECT ( hash_df_test ); From 4100edf9d756681b807045230def53bb10feb278 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 15:00:29 +0000 Subject: [PATCH 039/221] [802.11] Eliminate use of AXTLS-specific SHA1_SIZE constant Signed-off-by: Michael Brown --- src/crypto/sha1extra.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/crypto/sha1extra.c b/src/crypto/sha1extra.c index 12b29a6a..01d5f89c 100644 --- a/src/crypto/sha1extra.c +++ b/src/crypto/sha1extra.c @@ -47,7 +47,7 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label, u8 keym[key_len]; /* modifiable copy of key */ u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */ u8 *in_blknr; /* pointer to last byte of in, block number */ - u8 out[SHA1_SIZE]; /* HMAC-SHA1 result */ + u8 out[SHA1_DIGEST_SIZE]; /* HMAC-SHA1 result */ u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */ const size_t label_len = strlen ( label ); @@ -68,14 +68,14 @@ void prf_sha1 ( const void *key, size_t key_len, const char *label, hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) ); hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out ); - if ( prf_len <= SHA1_SIZE ) { + if ( prf_len <= sizeof ( out ) ) { memcpy ( prf, out, prf_len ); break; } - memcpy ( prf, out, SHA1_SIZE ); - prf_len -= SHA1_SIZE; - prf += SHA1_SIZE; + memcpy ( prf, out, sizeof ( out ) ); + prf_len -= sizeof ( out ); + prf += sizeof ( out ); } } @@ -98,30 +98,31 @@ static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len, { u8 pass[pass_len]; /* modifiable passphrase */ u8 in[salt_len + 4]; /* input buffer to first round */ - u8 last[SHA1_SIZE]; /* output of round N, input of N+1 */ + u8 last[SHA1_DIGEST_SIZE]; /* output of round N, input of N+1 */ u8 sha1_ctx[SHA1_CTX_SIZE]; u8 *next_in = in; /* changed to `last' after first round */ int next_size = sizeof ( in ); - int i, j; + int i; + unsigned int j; blocknr = htonl ( blocknr ); memcpy ( pass, passphrase, pass_len ); memcpy ( in, salt, salt_len ); memcpy ( in + salt_len, &blocknr, 4 ); - memset ( block, 0, SHA1_SIZE ); + memset ( block, 0, sizeof ( last ) ); for ( i = 0; i < iterations; i++ ) { hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len ); hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size ); hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last ); - for ( j = 0; j < SHA1_SIZE; j++ ) { + for ( j = 0; j < sizeof ( last ); j++ ) { block[j] ^= last[j]; } next_in = last; - next_size = SHA1_SIZE; + next_size = sizeof ( last ); } } @@ -147,20 +148,20 @@ void pbkdf2_sha1 ( const void *passphrase, size_t pass_len, const void *salt, size_t salt_len, int iterations, void *key, size_t key_len ) { - u32 blocks = ( key_len + SHA1_SIZE - 1 ) / SHA1_SIZE; + u32 blocks = ( key_len + SHA1_DIGEST_SIZE - 1 ) / SHA1_DIGEST_SIZE; u32 blk; - u8 buf[SHA1_SIZE]; + u8 buf[SHA1_DIGEST_SIZE]; for ( blk = 1; blk <= blocks; blk++ ) { pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len, iterations, blk, buf ); - if ( key_len <= SHA1_SIZE ) { + if ( key_len <= sizeof ( buf ) ) { memcpy ( key, buf, key_len ); break; } - memcpy ( key, buf, SHA1_SIZE ); - key_len -= SHA1_SIZE; - key += SHA1_SIZE; + memcpy ( key, buf, sizeof ( buf ) ); + key_len -= sizeof ( buf ); + key += sizeof ( buf ); } } From 76f59397369571093eab3d810f1a004d35f6195d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 15:13:54 +0000 Subject: [PATCH 040/221] [crypto] Replace SHA-1 implementation Replace SHA-1 implementation from AXTLS with a dedicated iPXE implementation which is around 40% smaller. This implementation has been verified using the existing SHA-1 self-tests (including the NIST SHA-1 test vectors). Signed-off-by: Michael Brown --- src/crypto/axtls/sha1.c | 240 ----------------------------------- src/crypto/axtls_sha1.c | 25 ---- src/crypto/sha1.c | 270 ++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/sha1.h | 80 ++++++++++-- 4 files changed, 338 insertions(+), 277 deletions(-) delete mode 100644 src/crypto/axtls/sha1.c delete mode 100644 src/crypto/axtls_sha1.c create mode 100644 src/crypto/sha1.c diff --git a/src/crypto/axtls/sha1.c b/src/crypto/axtls/sha1.c deleted file mode 100644 index 9a42801f..00000000 --- a/src/crypto/axtls/sha1.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright(C) 2006 Cameron Rich - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/** - * SHA1 implementation - as defined in FIPS PUB 180-1 published April 17, 1995. - * This code was originally taken from RFC3174 - */ - -#include -#include "crypto.h" - -/* - * Define the SHA1 circular left shift macro - */ -#define SHA1CircularShift(bits,word) \ - (((word) << (bits)) | ((word) >> (32-(bits)))) - -/* ----- static functions ----- */ -static void SHA1PadMessage(SHA1_CTX *ctx); -static void SHA1ProcessMessageBlock(SHA1_CTX *ctx); - -/** - * Initialize the SHA1 context - */ -void SHA1Init(SHA1_CTX *ctx) -{ - ctx->Length_Low = 0; - ctx->Length_High = 0; - ctx->Message_Block_Index = 0; - ctx->Intermediate_Hash[0] = 0x67452301; - ctx->Intermediate_Hash[1] = 0xEFCDAB89; - ctx->Intermediate_Hash[2] = 0x98BADCFE; - ctx->Intermediate_Hash[3] = 0x10325476; - ctx->Intermediate_Hash[4] = 0xC3D2E1F0; -} - -/** - * Accepts an array of octets as the next portion of the message. - */ -void SHA1Update(SHA1_CTX *ctx, const uint8_t *msg, int len) -{ - while (len--) - { - ctx->Message_Block[ctx->Message_Block_Index++] = (*msg & 0xFF); - - ctx->Length_Low += 8; - if (ctx->Length_Low == 0) - { - ctx->Length_High++; - } - - if (ctx->Message_Block_Index == 64) - { - SHA1ProcessMessageBlock(ctx); - } - - msg++; - } -} - -/** - * Return the 160-bit message digest into the user's array - */ -void SHA1Final(SHA1_CTX *ctx, uint8_t *digest) -{ - int i; - - SHA1PadMessage(ctx); - memset(ctx->Message_Block, 0, 64); - ctx->Length_Low = 0; /* and clear length */ - ctx->Length_High = 0; - - for (i = 0; i < SHA1_SIZE; i++) - { - digest[i] = ctx->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ); - } -} - -/** - * Process the next 512 bits of the message stored in the array. - */ -static void SHA1ProcessMessageBlock(SHA1_CTX *ctx) -{ - const uint32_t K[] = { /* Constants defined in SHA-1 */ - 0x5A827999, - 0x6ED9EBA1, - 0x8F1BBCDC, - 0xCA62C1D6 - }; - int t; /* Loop counter */ - uint32_t temp; /* Temporary word value */ - uint32_t W[80]; /* Word sequence */ - uint32_t A, B, C, D, E; /* Word buffers */ - - /* - * Initialize the first 16 words in the array W - */ - for (t = 0; t < 16; t++) - { - W[t] = ctx->Message_Block[t * 4] << 24; - W[t] |= ctx->Message_Block[t * 4 + 1] << 16; - W[t] |= ctx->Message_Block[t * 4 + 2] << 8; - W[t] |= ctx->Message_Block[t * 4 + 3]; - } - - for (t = 16; t < 80; t++) - { - W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); - } - - A = ctx->Intermediate_Hash[0]; - B = ctx->Intermediate_Hash[1]; - C = ctx->Intermediate_Hash[2]; - D = ctx->Intermediate_Hash[3]; - E = ctx->Intermediate_Hash[4]; - - for (t = 0; t < 20; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | ((~B) & D)) + E + W[t] + K[0]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - - B = A; - A = temp; - } - - for (t = 20; t < 40; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for (t = 40; t < 60; t++) - { - temp = SHA1CircularShift(5,A) + - ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - for (t = 60; t < 80; t++) - { - temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; - E = D; - D = C; - C = SHA1CircularShift(30,B); - B = A; - A = temp; - } - - ctx->Intermediate_Hash[0] += A; - ctx->Intermediate_Hash[1] += B; - ctx->Intermediate_Hash[2] += C; - ctx->Intermediate_Hash[3] += D; - ctx->Intermediate_Hash[4] += E; - ctx->Message_Block_Index = 0; -} - -/* - * According to the standard, the message must be padded to an even - * 512 bits. The first padding bit must be a '1'. The last 64 - * bits represent the length of the original message. All bits in - * between should be 0. This function will pad the message - * according to those rules by filling the Message_Block array - * accordingly. It will also call the ProcessMessageBlock function - * provided appropriately. When it returns, it can be assumed that - * the message digest has been computed. - * - * @param ctx [in, out] The SHA1 context - */ -static void SHA1PadMessage(SHA1_CTX *ctx) -{ - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second - * block. - */ - if (ctx->Message_Block_Index > 55) - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; - while(ctx->Message_Block_Index < 64) - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0; - } - - SHA1ProcessMessageBlock(ctx); - - while (ctx->Message_Block_Index < 56) - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0; - } - } - else - { - ctx->Message_Block[ctx->Message_Block_Index++] = 0x80; - while(ctx->Message_Block_Index < 56) - { - - ctx->Message_Block[ctx->Message_Block_Index++] = 0; - } - } - - /* - * Store the message length as the last 8 octets - */ - ctx->Message_Block[56] = ctx->Length_High >> 24; - ctx->Message_Block[57] = ctx->Length_High >> 16; - ctx->Message_Block[58] = ctx->Length_High >> 8; - ctx->Message_Block[59] = ctx->Length_High; - ctx->Message_Block[60] = ctx->Length_Low >> 24; - ctx->Message_Block[61] = ctx->Length_Low >> 16; - ctx->Message_Block[62] = ctx->Length_Low >> 8; - ctx->Message_Block[63] = ctx->Length_Low; - SHA1ProcessMessageBlock(ctx); -} diff --git a/src/crypto/axtls_sha1.c b/src/crypto/axtls_sha1.c deleted file mode 100644 index 3eb8912d..00000000 --- a/src/crypto/axtls_sha1.c +++ /dev/null @@ -1,25 +0,0 @@ -#include "crypto/axtls/crypto.h" -#include -#include - -static void sha1_init ( void *ctx ) { - SHA1Init ( ctx ); -} - -static void sha1_update ( void *ctx, const void *data, size_t len ) { - SHA1Update ( ctx, data, len ); -} - -static void sha1_final ( void *ctx, void *out ) { - SHA1Final ( ctx, out ); -} - -struct digest_algorithm sha1_algorithm = { - .name = "sha1", - .ctxsize = SHA1_CTX_SIZE, - .blocksize = 64, - .digestsize = SHA1_DIGEST_SIZE, - .init = sha1_init, - .update = sha1_update, - .final = sha1_final, -}; diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c new file mode 100644 index 00000000..834d9a21 --- /dev/null +++ b/src/crypto/sha1.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * SHA-1 algorithm + * + */ + +#include +#include +#include +#include +#include +#include + +/** + * Rotate dword left + * + * @v dword Dword + * @v rotate Amount of rotation + */ +static inline __attribute__ (( always_inline )) uint32_t +rol32 ( uint32_t dword, unsigned int rotate ) { + return ( ( dword << rotate ) | ( dword >> ( 32 - rotate ) ) ); +} + +/** SHA-1 variables */ +struct sha1_variables { + /* This layout matches that of struct sha1_digest_data, + * allowing for efficient endianness-conversion, + */ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + uint32_t e; + uint32_t w[80]; +} __attribute__ (( packed )); + +/** + * f(a,b,c,d) for steps 0 to 19 + * + * @v v SHA-1 variables + * @ret f f(a,b,c,d) + */ +static uint32_t sha1_f_0_19 ( struct sha1_variables *v ) { + return ( ( v->b & v->c ) | ( (~v->b) & v->d ) ); +} + +/** + * f(a,b,c,d) for steps 20 to 39 and 60 to 79 + * + * @v v SHA-1 variables + * @ret f f(a,b,c,d) + */ +static uint32_t sha1_f_20_39_60_79 ( struct sha1_variables *v ) { + return ( v->b ^ v->c ^ v->d ); +} + +/** + * f(a,b,c,d) for steps 40 to 59 + * + * @v v SHA-1 variables + * @ret f f(a,b,c,d) + */ +static uint32_t sha1_f_40_59 ( struct sha1_variables *v ) { + return ( ( v->b & v->c ) | ( v->b & v->d ) | ( v->c & v->d ) ); +} + +/** An SHA-1 step function */ +struct sha1_step { + /** + * Calculate f(a,b,c,d) + * + * @v v SHA-1 variables + * @ret f f(a,b,c,d) + */ + uint32_t ( * f ) ( struct sha1_variables *v ); + /** Constant k */ + uint32_t k; +}; + +/** SHA-1 steps */ +static struct sha1_step sha1_steps[4] = { + /** 0 to 19 */ + { .f = sha1_f_0_19, .k = 0x5a827999 }, + /** 20 to 39 */ + { .f = sha1_f_20_39_60_79, .k = 0x6ed9eba1 }, + /** 40 to 59 */ + { .f = sha1_f_40_59, .k = 0x8f1bbcdc }, + /** 60 to 79 */ + { .f = sha1_f_20_39_60_79, .k = 0xca62c1d6 }, +}; + +/** + * Initialise SHA-1 algorithm + * + * @v ctx SHA-1 context + */ +static void sha1_init ( void *ctx ) { + struct sha1_context *context = ctx; + + context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x67452301 ); + context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xefcdab89 ); + context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x98badcfe ); + context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0x10325476 ); + context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0xc3d2e1f0 ); + context->len = 0; +} + +/** + * Calculate SHA-1 digest of accumulated data + * + * @v context SHA-1 context + */ +static void sha1_digest ( struct sha1_context *context ) { + union { + union sha1_digest_data_dwords ddd; + struct sha1_variables v; + } u; + uint32_t *a = &u.v.a; + uint32_t *b = &u.v.b; + uint32_t *c = &u.v.c; + uint32_t *d = &u.v.d; + uint32_t *e = &u.v.e; + uint32_t *w = u.v.w; + uint32_t f; + uint32_t k; + uint32_t temp; + struct sha1_step *step; + unsigned int i; + + /* Sanity checks */ + assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); + linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout ); + linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout ); + + DBGC ( context, "SHA1 digesting:\n" ); + DBGC_HDA ( context, 0, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); + DBGC_HDA ( context, context->len, &context->ddd.dd.data, + sizeof ( context->ddd.dd.data ) ); + + /* Convert h[0..4] to host-endian, and initialise a, b, c, d, + * e, and w[0..15] + */ + for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) / + sizeof ( u.ddd.dword[0] ) ) ; i++ ) { + be32_to_cpus ( &context->ddd.dword[i] ); + u.ddd.dword[i] = context->ddd.dword[i]; + } + + /* Initialise w[16..79] */ + for ( i = 16 ; i < 80 ; i++ ) + w[i] = rol32 ( ( w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] ), 1 ); + + /* Main loop */ + for ( i = 0 ; i < 80 ; i++ ) { + step = &sha1_steps[ i / 20 ]; + f = step->f ( &u.v ); + k = step->k; + temp = ( rol32 ( *a, 5 ) + f + *e + k + w[i] ); + *e = *d; + *d = *c; + *c = rol32 ( *b, 30 ); + *b = *a; + *a = temp; + DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x\n", + i, *a, *b, *c, *d, *e ); + } + + /* Add chunk to hash and convert back to big-endian */ + for ( i = 0 ; i < 5 ; i++ ) { + context->ddd.dd.digest.h[i] = + cpu_to_be32 ( context->ddd.dd.digest.h[i] + + u.ddd.dd.digest.h[i] ); + } + + DBGC ( context, "SHA1 digested:\n" ); + DBGC_HDA ( context, 0, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); +} + +/** + * Accumulate data with SHA-1 algorithm + * + * @v ctx SHA-1 context + * @v data Data + * @v len Length of data + */ +static void sha1_update ( void *ctx, const void *data, size_t len ) { + struct sha1_context *context = ctx; + const uint8_t *byte = data; + size_t offset; + + /* Accumulate data a byte at a time, performing the digest + * whenever we fill the data buffer + */ + while ( len-- ) { + offset = ( context->len % sizeof ( context->ddd.dd.data ) ); + context->ddd.dd.data.byte[offset] = *(byte++); + context->len++; + if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ) + sha1_digest ( context ); + } +} + +/** + * Generate SHA-1 digest + * + * @v ctx SHA-1 context + * @v out Output buffer + */ +static void sha1_final ( void *ctx, void *out ) { + struct sha1_context *context = ctx; + uint64_t len_bits; + uint8_t pad; + + /* Record length before pre-processing */ + len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 ); + + /* Pad with a single "1" bit followed by as many "0" bits as required */ + pad = 0x80; + do { + sha1_update ( ctx, &pad, sizeof ( pad ) ); + pad = 0x00; + } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) != + offsetof ( typeof ( context->ddd.dd.data ), final.len ) ); + + /* Append length (in bits) */ + sha1_update ( ctx, &len_bits, sizeof ( len_bits ) ); + assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); + + /* Copy out final digest */ + memcpy ( out, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); +} + +/** SHA-1 algorithm */ +struct digest_algorithm sha1_algorithm = { + .name = "sha1", + .ctxsize = sizeof ( struct sha1_context ), + .blocksize = sizeof ( union sha1_block ), + .digestsize = sizeof ( struct sha1_digest ), + .init = sha1_init, + .update = sha1_update, + .final = sha1_final, +}; diff --git a/src/include/ipxe/sha1.h b/src/include/ipxe/sha1.h index 9b6f5514..a97035ec 100644 --- a/src/include/ipxe/sha1.h +++ b/src/include/ipxe/sha1.h @@ -1,24 +1,80 @@ #ifndef _IPXE_SHA1_H #define _IPXE_SHA1_H +/** @file + * + * SHA-1 algorithm + * + */ + FILE_LICENCE ( GPL2_OR_LATER ); -#include "crypto/axtls/crypto.h" +#include +#include -struct digest_algorithm; +/** An SHA-1 digest */ +struct sha1_digest { + /** Hash output */ + uint32_t h[5]; +}; -#define SHA1_CTX_SIZE sizeof ( SHA1_CTX ) -#define SHA1_DIGEST_SIZE SHA1_SIZE +/** An SHA-1 data block */ +union sha1_block { + /** Raw bytes */ + uint8_t byte[64]; + /** Raw dwords */ + uint32_t dword[16]; + /** Final block structure */ + struct { + /** Padding */ + uint8_t pad[56]; + /** Length in bits */ + uint64_t len; + } final; +}; + +/** SHA-1 digest and data block + * + * The order of fields within this structure is designed to minimise + * code size. + */ +struct sha1_digest_data { + /** Digest of data already processed */ + struct sha1_digest digest; + /** Accumulated data */ + union sha1_block data; +} __attribute__ (( packed )); + +/** SHA-1 digest and data block */ +union sha1_digest_data_dwords { + /** Digest and data block */ + struct sha1_digest_data dd; + /** Raw dwords */ + uint32_t dword[ sizeof ( struct sha1_digest_data ) / + sizeof ( uint32_t ) ]; +}; + +/** An SHA-1 context */ +struct sha1_context { + /** Amount of accumulated data */ + size_t len; + /** Digest and accumulated data */ + union sha1_digest_data_dwords ddd; +} __attribute__ (( packed )); + +/** SHA-1 context size */ +#define SHA1_CTX_SIZE sizeof ( struct sha1_context ) + +/** SHA-1 digest size */ +#define SHA1_DIGEST_SIZE sizeof ( struct sha1_digest ) extern struct digest_algorithm sha1_algorithm; -/* SHA1-wrapping functions defined in sha1extra.c: */ - -void prf_sha1 ( const void *key, size_t key_len, const char *label, - const void *data, size_t data_len, void *prf, size_t prf_len ); - -void pbkdf2_sha1 ( const void *passphrase, size_t pass_len, - const void *salt, size_t salt_len, - int iterations, void *key, size_t key_len ); +extern void prf_sha1 ( const void *key, size_t key_len, const char *label, + const void *data, size_t data_len, void *prf, + size_t prf_len ); +extern void pbkdf2_sha1 ( const void *passphrase, size_t pass_len, + const void *salt, size_t salt_len, + int iterations, void *key, size_t key_len ); #endif /* _IPXE_SHA1_H */ From e187de72398a995658d22b583c278532c3f99aa7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 21:09:40 +0000 Subject: [PATCH 041/221] [i386] Fix building on older versions of gcc Fix a strict-aliasing error on certain versions of gcc. Reported-by: Marko Myllynen Signed-off-by: Michael Brown --- src/arch/i386/include/bits/byteswap.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/arch/i386/include/bits/byteswap.h b/src/arch/i386/include/bits/byteswap.h index 381e695f..d4077135 100644 --- a/src/arch/i386/include/bits/byteswap.h +++ b/src/arch/i386/include/bits/byteswap.h @@ -52,7 +52,10 @@ __bswap_variable_64 ( uint64_t x ) { static inline __attribute__ (( always_inline )) void __bswap_64s ( uint64_t *x ) { - uint32_t __attribute__ (( may_alias )) *dwords = ( ( void * ) x ); + struct { + uint32_t low; + uint32_t high; + } __attribute__ (( may_alias )) *dwords = ( ( void * ) x ); uint32_t discard; __asm__ ( "movl %0,%2\n\t" @@ -60,8 +63,9 @@ __bswap_64s ( uint64_t *x ) { "xchgl %2,%1\n\t" "bswapl %2\n\t" "movl %2,%0\n\t" - : "=g" ( dwords[0] ), "=g" ( dwords[1] ), "=r" ( discard ) - : "0" ( dwords[0] ), "1" ( dwords[1] ) ); + : "=g" ( dwords->low ), "=g" ( dwords->high ), + "=r" ( discard ) + : "0" ( dwords->low ), "1" ( dwords->high ) ); } #endif /* _BITS_BYTESWAP_H */ From 732bea2f88d0d471e396831b19d2d5d40833c41c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 21:41:24 +0000 Subject: [PATCH 042/221] [i386] Use memory address constraints in __bswap_16s() and __bswap_64s() Minimise code size by forcing the use of memory addresses for __bswap_16s() and __bswap_64s(). (__bswap_32s() cannot avoid loading the value into a register.) Signed-off-by: Michael Brown --- src/arch/i386/include/bits/byteswap.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/arch/i386/include/bits/byteswap.h b/src/arch/i386/include/bits/byteswap.h index d4077135..f3d30a25 100644 --- a/src/arch/i386/include/bits/byteswap.h +++ b/src/arch/i386/include/bits/byteswap.h @@ -19,7 +19,7 @@ __bswap_variable_16 ( uint16_t x ) { static inline __attribute__ (( always_inline )) void __bswap_16s ( uint16_t *x ) { - __asm__ ( "rorw $8, %0" : "=g" ( *x ) : "0" ( *x ) ); + __asm__ ( "rorw $8, %0" : "+m" ( *x ) ); } static inline __attribute__ (( always_inline, const )) uint32_t @@ -63,9 +63,8 @@ __bswap_64s ( uint64_t *x ) { "xchgl %2,%1\n\t" "bswapl %2\n\t" "movl %2,%0\n\t" - : "=g" ( dwords->low ), "=g" ( dwords->high ), - "=r" ( discard ) - : "0" ( dwords->low ), "1" ( dwords->high ) ); + : "+m" ( dwords->low ), "+m" ( dwords->high ), + "=r" ( discard ) ); } #endif /* _BITS_BYTESWAP_H */ From 3b689e531dfc23e52c142f23cb8c83efeef9708f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 4 Mar 2012 21:46:45 +0000 Subject: [PATCH 043/221] [x86_64] Use memory address constraint in __bswap_16s() Signed-off-by: Michael Brown --- src/arch/x86_64/include/bits/byteswap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/x86_64/include/bits/byteswap.h b/src/arch/x86_64/include/bits/byteswap.h index 113b3278..2e472d98 100644 --- a/src/arch/x86_64/include/bits/byteswap.h +++ b/src/arch/x86_64/include/bits/byteswap.h @@ -19,7 +19,7 @@ __bswap_variable_16 ( uint16_t x ) { static inline __attribute__ (( always_inline )) void __bswap_16s ( uint16_t *x ) { - __asm__ ( "rorw $8, %0" : "=g" ( *x ) : "0" ( *x ) ); + __asm__ ( "rorw $8, %0" : "+m" ( *x ) ); } static inline __attribute__ (( always_inline, const )) uint32_t From 657ab17338c28046f9cb085cbd93ed3818408c14 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 00:18:49 +0000 Subject: [PATCH 044/221] [crypto] Add SHA-256 algorithm This implementation has been verified using the NIST SHA-256 test vectors. Signed-off-by: Michael Brown --- src/crypto/sha256.c | 254 ++++++++++++++++++++++++++++++++++++++ src/include/ipxe/sha256.h | 73 +++++++++++ 2 files changed, 327 insertions(+) create mode 100644 src/crypto/sha256.c create mode 100644 src/include/ipxe/sha256.h diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c new file mode 100644 index 00000000..71683901 --- /dev/null +++ b/src/crypto/sha256.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * SHA-256 algorithm + * + */ + +#include +#include +#include +#include +#include +#include + +/** + * Rotate dword right + * + * @v dword Dword + * @v rotate Amount of rotation + */ +static inline __attribute__ (( always_inline )) uint32_t +ror32 ( uint32_t dword, unsigned int rotate ) { + return ( ( dword >> rotate ) | ( dword << ( 32 - rotate ) ) ); +} + +/** SHA-256 variables */ +struct sha256_variables { + /* This layout matches that of struct sha256_digest_data, + * allowing for efficient endianness-conversion, + */ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + uint32_t e; + uint32_t f; + uint32_t g; + uint32_t h; + uint32_t w[64]; +} __attribute__ (( packed )); + +/** SHA-256 constants */ +static const uint32_t k[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +/** + * Initialise SHA-256 algorithm + * + * @v ctx SHA-256 context + */ +static void sha256_init ( void *ctx ) { + struct sha256_context *context = ctx; + + context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x6a09e667 ); + context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xbb67ae85 ); + context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x3c6ef372 ); + context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0xa54ff53a ); + context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0x510e527f ); + context->ddd.dd.digest.h[5] = cpu_to_be32 ( 0x9b05688c ); + context->ddd.dd.digest.h[6] = cpu_to_be32 ( 0x1f83d9ab ); + context->ddd.dd.digest.h[7] = cpu_to_be32 ( 0x5be0cd19 ); + context->len = 0; +} + +/** + * Calculate SHA-256 digest of accumulated data + * + * @v context SHA-256 context + */ +static void sha256_digest ( struct sha256_context *context ) { + union { + union sha256_digest_data_dwords ddd; + struct sha256_variables v; + } u; + uint32_t *a = &u.v.a; + uint32_t *b = &u.v.b; + uint32_t *c = &u.v.c; + uint32_t *d = &u.v.d; + uint32_t *e = &u.v.e; + uint32_t *f = &u.v.f; + uint32_t *g = &u.v.g; + uint32_t *h = &u.v.h; + uint32_t *w = u.v.w; + uint32_t s0; + uint32_t s1; + uint32_t maj; + uint32_t t1; + uint32_t t2; + uint32_t ch; + unsigned int i; + + /* Sanity checks */ + assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); + linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout ); + linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout ); + + DBGC ( context, "SHA256 digesting:\n" ); + DBGC_HDA ( context, 0, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); + DBGC_HDA ( context, context->len, &context->ddd.dd.data, + sizeof ( context->ddd.dd.data ) ); + + /* Convert h[0..7] to host-endian, and initialise a, b, c, d, + * e, f, g, h, and w[0..15] + */ + for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) / + sizeof ( u.ddd.dword[0] ) ) ; i++ ) { + be32_to_cpus ( &context->ddd.dword[i] ); + u.ddd.dword[i] = context->ddd.dword[i]; + } + + /* Initialise w[16..63] */ + for ( i = 16 ; i < 64 ; i++ ) { + s0 = ( ror32 ( w[i-15], 7 ) ^ ror32 ( w[i-15], 18 ) ^ + ( w[i-15] >> 3 ) ); + s1 = ( ror32 ( w[i-2], 17 ) ^ ror32 ( w[i-2], 19 ) ^ + ( w[i-2] >> 10 ) ); + w[i] = ( w[i-16] + s0 + w[i-7] + s1 ); + } + + /* Main loop */ + for ( i = 0 ; i < 64 ; i++ ) { + s0 = ( ror32 ( *a, 2 ) ^ ror32 ( *a, 13 ) ^ ror32 ( *a, 22 ) ); + maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) ); + t2 = ( s0 + maj ); + s1 = ( ror32 ( *e, 6 ) ^ ror32 ( *e, 11 ) ^ ror32 ( *e, 25 ) ); + ch = ( ( *e & *f ) ^ ( (~*e) & *g ) ); + t1 = ( *h + s1 + ch + k[i] + w[i] ); + *h = *g; + *g = *f; + *f = *e; + *e = ( *d + t1 ); + *d = *c; + *c = *b; + *b = *a; + *a = ( t1 + t2 ); + DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x %08x %08x " + "%08x\n", i, *a, *b, *c, *d, *e, *f, *g, *h ); + } + + /* Add chunk to hash and convert back to big-endian */ + for ( i = 0 ; i < 8 ; i++ ) { + context->ddd.dd.digest.h[i] = + cpu_to_be32 ( context->ddd.dd.digest.h[i] + + u.ddd.dd.digest.h[i] ); + } + + DBGC ( context, "SHA256 digested:\n" ); + DBGC_HDA ( context, 0, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); +} + +/** + * Accumulate data with SHA-256 algorithm + * + * @v ctx SHA-256 context + * @v data Data + * @v len Length of data + */ +static void sha256_update ( void *ctx, const void *data, size_t len ) { + struct sha256_context *context = ctx; + const uint8_t *byte = data; + size_t offset; + + /* Accumulate data a byte at a time, performing the digest + * whenever we fill the data buffer + */ + while ( len-- ) { + offset = ( context->len % sizeof ( context->ddd.dd.data ) ); + context->ddd.dd.data.byte[offset] = *(byte++); + context->len++; + if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ) + sha256_digest ( context ); + } +} + +/** + * Generate SHA-256 digest + * + * @v ctx SHA-256 context + * @v out Output buffer + */ +static void sha256_final ( void *ctx, void *out ) { + struct sha256_context *context = ctx; + uint64_t len_bits; + uint8_t pad; + + /* Record length before pre-processing */ + len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 ); + + /* Pad with a single "1" bit followed by as many "0" bits as required */ + pad = 0x80; + do { + sha256_update ( ctx, &pad, sizeof ( pad ) ); + pad = 0x00; + } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) != + offsetof ( typeof ( context->ddd.dd.data ), final.len ) ); + + /* Append length (in bits) */ + sha256_update ( ctx, &len_bits, sizeof ( len_bits ) ); + assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); + + /* Copy out final digest */ + memcpy ( out, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); +} + +/** SHA-256 algorithm */ +struct digest_algorithm sha256_algorithm = { + .name = "sha256", + .ctxsize = sizeof ( struct sha256_context ), + .blocksize = sizeof ( union sha256_block ), + .digestsize = sizeof ( struct sha256_digest ), + .init = sha256_init, + .update = sha256_update, + .final = sha256_final, +}; diff --git a/src/include/ipxe/sha256.h b/src/include/ipxe/sha256.h new file mode 100644 index 00000000..9aa9f3e5 --- /dev/null +++ b/src/include/ipxe/sha256.h @@ -0,0 +1,73 @@ +#ifndef _IPXE_SHA256_H +#define _IPXE_SHA256_H + +/** @file + * + * SHA-256 algorithm + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** An SHA-256 digest */ +struct sha256_digest { + /** Hash output */ + uint32_t h[8]; +}; + +/** An SHA-256 data block */ +union sha256_block { + /** Raw bytes */ + uint8_t byte[64]; + /** Raw dwords */ + uint32_t dword[16]; + /** Final block structure */ + struct { + /** Padding */ + uint8_t pad[56]; + /** Length in bits */ + uint64_t len; + } final; +}; + +/** SHA-256 digest and data block + * + * The order of fields within this structure is designed to minimise + * code size. + */ +struct sha256_digest_data { + /** Digest of data already processed */ + struct sha256_digest digest; + /** Accumulated data */ + union sha256_block data; +} __attribute__ (( packed )); + +/** SHA-256 digest and data block */ +union sha256_digest_data_dwords { + /** Digest and data block */ + struct sha256_digest_data dd; + /** Raw dwords */ + uint32_t dword[ sizeof ( struct sha256_digest_data ) / + sizeof ( uint32_t ) ]; +}; + +/** An SHA-256 context */ +struct sha256_context { + /** Amount of accumulated data */ + size_t len; + /** Digest and accumulated data */ + union sha256_digest_data_dwords ddd; +} __attribute__ (( packed )); + +/** SHA-256 context size */ +#define SHA256_CTX_SIZE sizeof ( struct sha256_context ) + +/** SHA-256 digest size */ +#define SHA256_DIGEST_SIZE sizeof ( struct sha256_digest ) + +extern struct digest_algorithm sha256_algorithm; + +#endif /* _IPXE_SHA256_H */ From bbdf17c3e8cea54a63f417cee14b11648fe90131 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 00:20:30 +0000 Subject: [PATCH 045/221] [test] Add self-tests for SHA-256 algorithm Signed-off-by: Michael Brown --- src/tests/sha256_test.c | 101 ++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 2 files changed, 102 insertions(+) create mode 100644 src/tests/sha256_test.c diff --git a/src/tests/sha256_test.c b/src/tests/sha256_test.c new file mode 100644 index 00000000..7599ba5d --- /dev/null +++ b/src/tests/sha256_test.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * SHA-256 tests + * + */ + +#include +#include +#include +#include "digest_test.h" + +/** An SHA-256 test vector */ +struct sha256_test_vector { + /** Test data */ + void *data; + /** Test data length */ + size_t len; + /** Expected digest */ + uint8_t digest[SHA256_DIGEST_SIZE]; +}; + +/** SHA-256 test vectors */ +static struct sha256_test_vector sha256_test_vectors[] = { + /* Empty test data + * + * Expected digest value obtained from "sha256sum /dev/null" + */ + { NULL, 0, + { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, + 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, + 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 } }, + /* Test data and expected digests taken from the NIST + * Cryptographic Toolkit Algorithm Examples at + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf + */ + { "abc", 3, + { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, + 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, + 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad } }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, + { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, + 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, + 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 } }, +}; + +/** SHA-256 test fragment lists */ +static struct digest_test_fragments sha256_test_fragments[] = { + { { 0, -1UL, } }, + { { 1, 1, 1, 1, 1, 1, 1, 1 } }, + { { 2, 0, 23, 4, 6, 1, 0 } }, +}; + +/** + * Perform SHA-256 self-test + * + */ +static void sha256_test_exec ( void ) { + struct digest_algorithm *digest = &sha256_algorithm; + struct sha256_test_vector *test; + unsigned int i; + unsigned int j; + + for ( i = 0 ; i < ( sizeof ( sha256_test_vectors ) / + sizeof ( sha256_test_vectors[0] ) ) ; i++ ) { + test = &sha256_test_vectors[i]; + /* Test with a single pass */ + digest_ok ( digest, NULL, test->data, test->len, test->digest ); + /* Test with fragment lists */ + for ( j = 0 ; j < ( sizeof ( sha256_test_fragments ) / + sizeof ( sha256_test_fragments[0] )); j++ ){ + digest_ok ( digest, &sha256_test_fragments[j], + test->data, test->len, test->digest ); + } + } +} + +/** SHA-256 self-test */ +struct self_test sha256_test __self_test = { + .name = "sha256", + .exec = sha256_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 1e5b217a..7c364b25 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -28,5 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); REQUIRE_OBJECT ( list_test ); REQUIRE_OBJECT ( byteswap_test ); REQUIRE_OBJECT ( sha1_test ); +REQUIRE_OBJECT ( sha256_test ); REQUIRE_OBJECT ( hmac_drbg_test ); REQUIRE_OBJECT ( hash_df_test ); From c15e73f28361a9c6d435b6f64bc1791f4fab8345 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 00:31:07 +0000 Subject: [PATCH 046/221] [test] Add self-tests for MD5 algorithm Signed-off-by: Michael Brown --- src/tests/md5_test.c | 93 ++++++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 2 files changed, 94 insertions(+) create mode 100644 src/tests/md5_test.c diff --git a/src/tests/md5_test.c b/src/tests/md5_test.c new file mode 100644 index 00000000..17972daa --- /dev/null +++ b/src/tests/md5_test.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * MD5 tests + * + */ + +#include +#include +#include +#include "digest_test.h" + +/** An MD5 test vector */ +struct md5_test_vector { + /** Test data */ + void *data; + /** Test data length */ + size_t len; + /** Expected digest */ + uint8_t digest[MD5_DIGEST_SIZE]; +}; + +/** MD5 test vectors */ +static struct md5_test_vector md5_test_vectors[] = { + /* Test inputs borrowed from SHA-1 tests, with results + * calculated using md5sum. + */ + { NULL, 0, + { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, + 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } }, + { "abc", 3, + { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, + 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", 56, + { 0x82, 0x15, 0xef, 0x07, 0x96, 0xa2, 0x0b, 0xca, + 0xaa, 0xe1, 0x16, 0xd3, 0x87, 0x6c, 0x66, 0x4a } }, +}; + +/** MD5 test fragment lists */ +static struct digest_test_fragments md5_test_fragments[] = { + { { 0, -1UL, } }, + { { 1, 1, 1, 1, 1, 1, 1, 1 } }, + { { 2, 0, 23, 4, 6, 1, 0 } }, +}; + +/** + * Perform MD5 self-test + * + */ +static void md5_test_exec ( void ) { + struct digest_algorithm *digest = &md5_algorithm; + struct md5_test_vector *test; + unsigned int i; + unsigned int j; + + for ( i = 0 ; i < ( sizeof ( md5_test_vectors ) / + sizeof ( md5_test_vectors[0] ) ) ; i++ ) { + test = &md5_test_vectors[i]; + /* Test with a single pass */ + digest_ok ( digest, NULL, test->data, test->len, test->digest ); + /* Test with fragment lists */ + for ( j = 0 ; j < ( sizeof ( md5_test_fragments ) / + sizeof ( md5_test_fragments[0] ) ) ; j++ ){ + digest_ok ( digest, &md5_test_fragments[j], + test->data, test->len, test->digest ); + } + } +} + +/** MD5 self-test */ +struct self_test md5_test __self_test = { + .name = "md5", + .exec = md5_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 7c364b25..8e034afb 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Drag in all applicable self-tests */ REQUIRE_OBJECT ( list_test ); REQUIRE_OBJECT ( byteswap_test ); +REQUIRE_OBJECT ( md5_test ); REQUIRE_OBJECT ( sha1_test ); REQUIRE_OBJECT ( sha256_test ); REQUIRE_OBJECT ( hmac_drbg_test ); From cdb4802ff1fbd03622bba0cb26b57d116fa6b97e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 10:18:16 +0000 Subject: [PATCH 047/221] [802.11] Avoid using struct md5_ctx directly Signed-off-by: Michael Brown --- src/net/80211/wpa_tkip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/net/80211/wpa_tkip.c b/src/net/80211/wpa_tkip.c index 8bb3e5aa..871666ee 100644 --- a/src/net/80211/wpa_tkip.c +++ b/src/net/80211/wpa_tkip.c @@ -544,15 +544,15 @@ struct net80211_crypto tkip_crypto __net80211_crypto = { static void tkip_kie_mic ( const void *kck, const void *msg, size_t len, void *mic ) { - struct md5_ctx md5; + uint8_t ctx[MD5_CTX_SIZE]; u8 kckb[16]; size_t kck_len = 16; memcpy ( kckb, kck, kck_len ); - hmac_init ( &md5_algorithm, &md5, kckb, &kck_len ); - hmac_update ( &md5_algorithm, &md5, msg, len ); - hmac_final ( &md5_algorithm, &md5, kckb, &kck_len, mic ); + hmac_init ( &md5_algorithm, ctx, kckb, &kck_len ); + hmac_update ( &md5_algorithm, ctx, msg, len ); + hmac_final ( &md5_algorithm, ctx, kckb, &kck_len, mic ); } /** From fba2310562214eecd5c1fcdba86fccd95e292fa7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 10:19:40 +0000 Subject: [PATCH 048/221] [crypto] Replace MD5 implementation Replace MD5 implementation with one which is around 20% smaller. This implementation has been verified using the existing MD5 self-tests. Signed-off-by: Michael Brown --- src/crypto/md5.c | 450 +++++++++++++++++++++++------------------ src/include/ipxe/md5.h | 71 ++++++- 2 files changed, 316 insertions(+), 205 deletions(-) diff --git a/src/crypto/md5.c b/src/crypto/md5.c index ef322ad2..e6c68821 100644 --- a/src/crypto/md5.c +++ b/src/crypto/md5.c @@ -1,233 +1,295 @@ -/* - * Cryptographic API. +/* + * Copyright (C) 2012 Michael Brown . * - * MD5 Message Digest Algorithm (RFC1321). + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. * - * Derived from cryptoapi implementation, originally based on the - * public domain implementation written by Colin Plumb in 1993. - * - * Reduced object size by around 50% compared to the original Linux - * version for use in Etherboot by Michael Brown. - * - * Copyright (c) Cryptoapi developers. - * Copyright (c) 2002 James Morris - * Copyright (c) 2006 Michael Brown - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ FILE_LICENCE ( GPL2_OR_LATER ); +/** @file + * + * MD5 algorithm + * + */ + #include #include #include +#include #include #include +/** + * Rotate dword left + * + * @v dword Dword + * @v rotate Amount of rotation + */ +static inline __attribute__ (( always_inline )) uint32_t +rol32 ( uint32_t dword, unsigned int rotate ) { + return ( ( dword << rotate ) | ( dword >> ( 32 - rotate ) ) ); +} + +/** MD5 variables */ +struct md5_variables { + /* This layout matches that of struct md5_digest_data, + * allowing for efficient endianness-conversion, + */ + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; + uint32_t w[16]; +} __attribute__ (( packed )); + +/** MD5 constants */ +static const uint32_t k[64] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, + 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340, + 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, + 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, + 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, + 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 +}; + +/** MD5 shift amounts */ +static const uint8_t r[64] = { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 +}; + +/** + * f(b,c,d) for steps 0 to 15 + * + * @v v MD5 variables + * @ret f f(b,c,d) + */ +static uint32_t md5_f_0_15 ( struct md5_variables *v ) { + return ( v->d ^ ( v->b & ( v->c ^ v->d ) ) ); +} + +/** + * f(b,c,d) for steps 16 to 31 + * + * @v v MD5 variables + * @ret f f(b,c,d) + */ +static uint32_t md5_f_16_31 ( struct md5_variables *v ) { + return ( v->c ^ ( v->d & ( v->b ^ v->c ) ) ); +} + +/** + * f(b,c,d) for steps 32 to 47 + * + * @v v MD5 variables + * @ret f f(b,c,d) + */ +static uint32_t md5_f_32_47 ( struct md5_variables *v ) { + return ( v->b ^ v->c ^ v->d ); +} + +/** + * f(b,c,d) for steps 48 to 63 + * + * @v v MD5 variables + * @ret f f(b,c,d) + */ +static uint32_t md5_f_48_63 ( struct md5_variables *v ) { + return ( v->c ^ ( v->b | (~v->d) ) ); +} + +/** An MD5 step function */ struct md5_step { - u32 ( * f ) ( u32 b, u32 c, u32 d ); - u8 coefficient; - u8 constant; + /** + * Calculate f(b,c,d) + * + * @v v MD5 variables + * @ret f f(b,c,d) + */ + uint32_t ( * f ) ( struct md5_variables *v ); + /** Coefficient of i in g=ni+m */ + uint8_t coefficient; + /** Constant term in g=ni+m */ + uint8_t constant; }; -static u32 f1(u32 b, u32 c, u32 d) -{ - return ( d ^ ( b & ( c ^ d ) ) ); -} - -static u32 f2(u32 b, u32 c, u32 d) -{ - return ( c ^ ( d & ( b ^ c ) ) ); -} - -static u32 f3(u32 b, u32 c, u32 d) -{ - return ( b ^ c ^ d ); -} - -static u32 f4(u32 b, u32 c, u32 d) -{ - return ( c ^ ( b | ~d ) ); -} - +/** MD5 steps */ static struct md5_step md5_steps[4] = { - { - .f = f1, - .coefficient = 1, - .constant = 0, - }, - { - .f = f2, - .coefficient = 5, - .constant = 1, - }, - { - .f = f3, - .coefficient = 3, - .constant = 5, - }, - { - .f = f4, - .coefficient = 7, - .constant = 0, - } + /** 0 to 15 */ + { .f = md5_f_0_15, .coefficient = 1, .constant = 0 }, + /** 16 to 31 */ + { .f = md5_f_16_31, .coefficient = 5, .constant = 1 }, + /** 32 to 47 */ + { .f = md5_f_32_47, .coefficient = 3, .constant = 5 }, + /** 48 to 63 */ + { .f = md5_f_48_63, .coefficient = 7, .constant = 0 }, }; -static const u8 r[64] = { - 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22, - 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, - 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, - 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21 -}; +/** + * Initialise MD5 algorithm + * + * @v ctx MD5 context + */ +static void md5_init ( void *ctx ) { + struct md5_context *context = ctx; -static const u32 k[64] = { - 0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, - 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL, - 0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, - 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL, - 0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, - 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL, - 0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, - 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL, - 0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, - 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL, - 0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, - 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL, - 0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, - 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL, - 0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, - 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL, -}; + context->ddd.dd.digest.h[0] = cpu_to_le32 ( 0x67452301 ); + context->ddd.dd.digest.h[1] = cpu_to_le32 ( 0xefcdab89 ); + context->ddd.dd.digest.h[2] = cpu_to_le32 ( 0x98badcfe ); + context->ddd.dd.digest.h[3] = cpu_to_le32 ( 0x10325476 ); + context->len = 0; +} -static void md5_transform(u32 *hash, const u32 *in) -{ - u32 a, b, c, d, f, g, temp; - int i; +/** + * Calculate MD5 digest of accumulated data + * + * @v context MD5 context + */ +static void md5_digest ( struct md5_context *context ) { + union { + union md5_digest_data_dwords ddd; + struct md5_variables v; + } u; + uint32_t *a = &u.v.a; + uint32_t *b = &u.v.b; + uint32_t *c = &u.v.c; + uint32_t *d = &u.v.d; + uint32_t *w = u.v.w; + uint32_t f; + uint32_t g; + uint32_t temp; struct md5_step *step; + unsigned int i; - a = hash[0]; - b = hash[1]; - c = hash[2]; - d = hash[3]; + /* Sanity checks */ + assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); + linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout ); + linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout ); + linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout ); + DBGC ( context, "MD5 digesting:\n" ); + DBGC_HDA ( context, 0, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); + DBGC_HDA ( context, context->len, &context->ddd.dd.data, + sizeof ( context->ddd.dd.data ) ); + + /* Convert h[0..3] to host-endian, and initialise a, b, c, d, + * and w[0..15] + */ + for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) / + sizeof ( u.ddd.dword[0] ) ) ; i++ ) { + le32_to_cpus ( &context->ddd.dword[i] ); + u.ddd.dword[i] = context->ddd.dword[i]; + } + + /* Main loop */ for ( i = 0 ; i < 64 ; i++ ) { - step = &md5_steps[i >> 4]; - f = step->f ( b, c, d ); - g = ( ( i * step->coefficient + step->constant ) & 0xf ); - temp = d; - d = c; - c = b; - a += ( f + k[i] + in[g] ); - a = ( ( a << r[i] ) | ( a >> ( 32-r[i] ) ) ); - b += a; - a = temp; + step = &md5_steps[ i / 16 ]; + f = step->f ( &u.v ); + g = ( ( ( step->coefficient * i ) + step->constant ) % 16 ); + temp = *d; + *d = *c; + *c = *b; + *b = ( *b + rol32 ( ( *a + f + k[i] + w[g] ), r[i] ) ); + *a = temp; + DBGC2 ( context, "%2d : %08x %08x %08x %08x\n", + i, *a, *b, *c, *d ); } - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; + /* Add chunk to hash and convert back to big-endian */ + for ( i = 0 ; i < 4 ; i++ ) { + context->ddd.dd.digest.h[i] = + cpu_to_le32 ( context->ddd.dd.digest.h[i] + + u.ddd.dd.digest.h[i] ); + } + + DBGC ( context, "MD5 digested:\n" ); + DBGC_HDA ( context, 0, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); } -/* XXX: this stuff can be optimized */ -static inline void le32_to_cpu_array(u32 *buf, unsigned int words) -{ - while (words--) { - le32_to_cpus(buf); - buf++; +/** + * Accumulate data with MD5 algorithm + * + * @v ctx MD5 context + * @v data Data + * @v len Length of data + */ +static void md5_update ( void *ctx, const void *data, size_t len ) { + struct md5_context *context = ctx; + const uint8_t *byte = data; + size_t offset; + + /* Accumulate data a byte at a time, performing the digest + * whenever we fill the data buffer + */ + while ( len-- ) { + offset = ( context->len % sizeof ( context->ddd.dd.data ) ); + context->ddd.dd.data.byte[offset] = *(byte++); + context->len++; + if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ) + md5_digest ( context ); } } -static inline void cpu_to_le32_array(u32 *buf, unsigned int words) -{ - while (words--) { - cpu_to_le32s(buf); - buf++; - } -} - -static inline void md5_transform_helper(struct md5_ctx *ctx) -{ - le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(u32)); - md5_transform(ctx->hash, ctx->block); -} - -static void md5_init(void *context) -{ - struct md5_ctx *mctx = context; - - mctx->hash[0] = 0x67452301; - mctx->hash[1] = 0xefcdab89; - mctx->hash[2] = 0x98badcfe; - mctx->hash[3] = 0x10325476; - mctx->byte_count = 0; -} - -static void md5_update(void *context, const void *data, size_t len) -{ - struct md5_ctx *mctx = context; - const u32 avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); - - mctx->byte_count += len; - - if (avail > len) { - memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), - data, len); - return; - } - - memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), - data, avail); - - md5_transform_helper(mctx); - data += avail; - len -= avail; - - while (len >= sizeof(mctx->block)) { - memcpy(mctx->block, data, sizeof(mctx->block)); - md5_transform_helper(mctx); - data += sizeof(mctx->block); - len -= sizeof(mctx->block); - } - - memcpy(mctx->block, data, len); -} - -static void md5_final(void *context, void *out) -{ - struct md5_ctx *mctx = context; - const unsigned int offset = mctx->byte_count & 0x3f; - char *p = (char *)mctx->block + offset; - int padding = 56 - (offset + 1); - - *p++ = 0x80; - if (padding < 0) { - memset(p, 0x00, padding + sizeof (u64)); - md5_transform_helper(mctx); - p = (char *)mctx->block; - padding = 56; - } - - memset(p, 0, padding); - mctx->block[14] = mctx->byte_count << 3; - mctx->block[15] = mctx->byte_count >> 29; - le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - - sizeof(u64)) / sizeof(u32)); - md5_transform(mctx->hash, mctx->block); - cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32)); - memcpy(out, mctx->hash, sizeof(mctx->hash)); - memset(mctx, 0, sizeof(*mctx)); +/** + * Generate MD5 digest + * + * @v ctx MD5 context + * @v out Output buffer + */ +static void md5_final ( void *ctx, void *out ) { + struct md5_context *context = ctx; + uint64_t len_bits; + uint8_t pad; + + /* Record length before pre-processing */ + len_bits = cpu_to_le64 ( ( ( uint64_t ) context->len ) * 8 ); + + /* Pad with a single "1" bit followed by as many "0" bits as required */ + pad = 0x80; + do { + md5_update ( ctx, &pad, sizeof ( pad ) ); + pad = 0x00; + } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) != + offsetof ( typeof ( context->ddd.dd.data ), final.len ) ); + + /* Append length (in bits) */ + md5_update ( ctx, &len_bits, sizeof ( len_bits ) ); + assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 ); + + /* Copy out final digest */ + memcpy ( out, &context->ddd.dd.digest, + sizeof ( context->ddd.dd.digest ) ); } +/** MD5 algorithm */ struct digest_algorithm md5_algorithm = { .name = "md5", - .ctxsize = MD5_CTX_SIZE, - .blocksize = ( MD5_BLOCK_WORDS * 4 ), - .digestsize = MD5_DIGEST_SIZE, + .ctxsize = sizeof ( struct md5_context ), + .blocksize = sizeof ( union md5_block ), + .digestsize = sizeof ( struct md5_digest ), .init = md5_init, .update = md5_update, .final = md5_final, diff --git a/src/include/ipxe/md5.h b/src/include/ipxe/md5.h index c3dfeb7e..860bc476 100644 --- a/src/include/ipxe/md5.h +++ b/src/include/ipxe/md5.h @@ -1,23 +1,72 @@ #ifndef _IPXE_MD5_H #define _IPXE_MD5_H +/** @file + * + * MD5 algorithm + * + */ + FILE_LICENCE ( GPL2_OR_LATER ); -struct digest_algorithm; - #include +#include -#define MD5_DIGEST_SIZE 16 -#define MD5_BLOCK_WORDS 16 -#define MD5_HASH_WORDS 4 - -struct md5_ctx { - u32 hash[MD5_HASH_WORDS]; - u32 block[MD5_BLOCK_WORDS]; - u64 byte_count; +/** An MD5 digest */ +struct md5_digest { + /** Hash output */ + uint32_t h[4]; }; -#define MD5_CTX_SIZE sizeof ( struct md5_ctx ) +/** An MD5 data block */ +union md5_block { + /** Raw bytes */ + uint8_t byte[64]; + /** Raw dwords */ + uint32_t dword[16]; + /** Final block structure */ + struct { + /** Padding */ + uint8_t pad[56]; + /** Length in bits */ + uint64_t len; + } final; +}; + +/** MD5 digest and data block + * + * The order of fields within this structure is designed to minimise + * code size. + */ +struct md5_digest_data { + /** Digest of data already processed */ + struct md5_digest digest; + /** Accumulated data */ + union md5_block data; +} __attribute__ (( packed )); + +/** MD5 digest and data block */ +union md5_digest_data_dwords { + /** Digest and data block */ + struct md5_digest_data dd; + /** Raw dwords */ + uint32_t dword[ sizeof ( struct md5_digest_data ) / + sizeof ( uint32_t ) ]; +}; + +/** An MD5 context */ +struct md5_context { + /** Amount of accumulated data */ + size_t len; + /** Digest and accumulated data */ + union md5_digest_data_dwords ddd; +} __attribute__ (( packed )); + +/** MD5 context size */ +#define MD5_CTX_SIZE sizeof ( struct md5_context ) + +/** MD5 digest size */ +#define MD5_DIGEST_SIZE sizeof ( struct md5_digest ) extern struct digest_algorithm md5_algorithm; From 015c9367918b37539fabad32af532d1bd94c2378 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 15:28:39 +0000 Subject: [PATCH 049/221] [tls] Support TLS version 1.2 Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 6 +++ src/net/tls.c | 105 ++++++++++++++++++++++++++++------------- 2 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 49401e6b..aa4bfc64 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -16,6 +16,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** A TLS header */ @@ -40,6 +41,9 @@ struct tls_header { /** TLS version 1.1 */ #define TLS_VERSION_TLS_1_1 0x0302 +/** TLS version 1.2 */ +#define TLS_VERSION_TLS_1_2 0x0303 + /** Change cipher content type */ #define TLS_TYPE_CHANGE_CIPHER 20 @@ -165,6 +169,8 @@ struct tls_session { uint8_t handshake_md5_ctx[MD5_CTX_SIZE]; /** SHA1 context for handshake verification */ uint8_t handshake_sha1_ctx[SHA1_CTX_SIZE]; + /** SHA256 context for handshake verification */ + uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE]; /** Hack: server RSA public key */ struct x509_rsa_public_key rsa; diff --git a/src/net/tls.c b/src/net/tls.c index 0249ed7c..517a13e1 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -247,32 +248,40 @@ static void tls_prf ( struct tls_session *tls, void *secret, size_t secret_len, size_t subsecret_len; void *md5_secret; void *sha1_secret; - uint8_t out_md5[out_len]; - uint8_t out_sha1[out_len]; + uint8_t buf[out_len]; unsigned int i; va_start ( seeds, out_len ); - /* Split secret into two, with an overlap of up to one byte */ - subsecret_len = ( ( secret_len + 1 ) / 2 ); - md5_secret = secret; - sha1_secret = ( secret + secret_len - subsecret_len ); + if ( tls->version >= TLS_VERSION_TLS_1_2 ) { + /* Use P_SHA256 for TLSv1.2 and later */ + tls_p_hash_va ( tls, &sha256_algorithm, secret, secret_len, + out, out_len, seeds ); + } else { + /* Use combination of P_MD5 and P_SHA-1 for TLSv1.1 + * and earlier + */ - /* Calculate MD5 portion */ - va_copy ( tmp, seeds ); - tls_p_hash_va ( tls, &md5_algorithm, md5_secret, subsecret_len, - out_md5, out_len, seeds ); - va_end ( tmp ); + /* Split secret into two, with an overlap of up to one byte */ + subsecret_len = ( ( secret_len + 1 ) / 2 ); + md5_secret = secret; + sha1_secret = ( secret + secret_len - subsecret_len ); - /* Calculate SHA1 portion */ - va_copy ( tmp, seeds ); - tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret, subsecret_len, - out_sha1, out_len, seeds ); - va_end ( tmp ); + /* Calculate MD5 portion */ + va_copy ( tmp, seeds ); + tls_p_hash_va ( tls, &md5_algorithm, md5_secret, + subsecret_len, out, out_len, seeds ); + va_end ( tmp ); - /* XOR the two portions together into the final output buffer */ - for ( i = 0 ; i < out_len ; i++ ) { - *( ( uint8_t * ) out + i ) = ( out_md5[i] ^ out_sha1[i] ); + /* Calculate SHA1 portion */ + va_copy ( tmp, seeds ); + tls_p_hash_va ( tls, &sha1_algorithm, sha1_secret, + subsecret_len, buf, out_len, seeds ); + va_end ( tmp ); + + /* XOR the two portions together into the final output buffer */ + for ( i = 0 ; i < out_len ; i++ ) + *( ( uint8_t * ) out + i ) ^= buf[i]; } va_end ( seeds ); @@ -569,6 +578,24 @@ static void tls_add_handshake ( struct tls_session *tls, digest_update ( &md5_algorithm, tls->handshake_md5_ctx, data, len ); digest_update ( &sha1_algorithm, tls->handshake_sha1_ctx, data, len ); + digest_update ( &sha256_algorithm, tls->handshake_sha256_ctx, + data, len ); +} + +/** + * Size of handshake output buffer + * + * @v tls TLS session + */ +static size_t tls_verify_handshake_len ( struct tls_session *tls ) { + + if ( tls->version >= TLS_VERSION_TLS_1_2 ) { + /* Use SHA-256 for TLSv1.2 and later */ + return SHA256_DIGEST_SIZE; + } else { + /* Use MD5+SHA1 for TLSv1.1 and earlier */ + return ( MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE ); + } } /** @@ -577,21 +604,30 @@ static void tls_add_handshake ( struct tls_session *tls, * @v tls TLS session * @v out Output buffer * - * Calculates the MD5+SHA1 digest over all handshake messages seen so - * far. + * Calculates the MD5+SHA1 or SHA256 digest over all handshake + * messages seen so far. */ static void tls_verify_handshake ( struct tls_session *tls, void *out ) { - struct digest_algorithm *md5 = &md5_algorithm; - struct digest_algorithm *sha1 = &sha1_algorithm; - uint8_t md5_ctx[md5->ctxsize]; - uint8_t sha1_ctx[sha1->ctxsize]; - void *md5_digest = out; - void *sha1_digest = ( out + md5->digestsize ); + union { + uint8_t md5[MD5_CTX_SIZE]; + uint8_t sha1[SHA1_CTX_SIZE]; + uint8_t sha256[SHA256_CTX_SIZE]; + } ctx; - memcpy ( md5_ctx, tls->handshake_md5_ctx, sizeof ( md5_ctx ) ); - memcpy ( sha1_ctx, tls->handshake_sha1_ctx, sizeof ( sha1_ctx ) ); - digest_final ( md5, md5_ctx, md5_digest ); - digest_final ( sha1, sha1_ctx, sha1_digest ); + if ( tls->version >= TLS_VERSION_TLS_1_2 ) { + /* Use SHA-256 for TLSv1.2 and later */ + memcpy ( ctx.sha256, tls->handshake_sha256_ctx, + sizeof ( ctx.sha256 ) ); + digest_final ( &sha256_algorithm, ctx.sha256, out ); + } else { + /* Use MD5+SHA1 for TLSv1.1 and earlier */ + memcpy ( ctx.md5, tls->handshake_md5_ctx, sizeof ( ctx.md5 ) ); + digest_final ( &md5_algorithm, ctx.md5, out ); + memcpy ( ctx.sha1, tls->handshake_sha1_ctx, + sizeof ( ctx.sha1 ) ); + digest_final ( &sha1_algorithm, ctx.sha1, + ( out + MD5_DIGEST_SIZE ) ); + } } /****************************************************************************** @@ -770,7 +806,7 @@ static int tls_send_finished ( struct tls_session *tls ) { uint32_t type_length; uint8_t verify_data[12]; } __attribute__ (( packed )) finished; - uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE]; + uint8_t digest[ tls_verify_handshake_len ( tls ) ]; memset ( &finished, 0, sizeof ( finished ) ); finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) | @@ -1047,7 +1083,7 @@ static int tls_new_finished ( struct tls_session *tls, char next[0]; } __attribute__ (( packed )) *finished = data; void *end = finished->next; - uint8_t digest[MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE]; + uint8_t digest[ tls_verify_handshake_len ( tls ) ]; uint8_t verify_data[ sizeof ( finished->verify_data ) ]; /* Sanity check */ @@ -1869,7 +1905,7 @@ int add_tls ( struct interface *xfer, const char *name, tls->name = name; intf_init ( &tls->plainstream, &tls_plainstream_desc, &tls->refcnt ); intf_init ( &tls->cipherstream, &tls_cipherstream_desc, &tls->refcnt ); - tls->version = TLS_VERSION_TLS_1_1; + tls->version = TLS_VERSION_TLS_1_2; tls_clear_cipher ( tls, &tls->tx_cipherspec ); tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); tls_clear_cipher ( tls, &tls->rx_cipherspec ); @@ -1886,6 +1922,7 @@ int add_tls ( struct interface *xfer, const char *name, } digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); + digest_init ( &sha256_algorithm, tls->handshake_sha256_ctx ); tls->tx_pending = TLS_TX_CLIENT_HELLO; process_init ( &tls->process, &tls_process_desc, &tls->refcnt ); From 6069b09bfc01107eb53f3e4ca792ab69dae601b1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 15:36:38 +0000 Subject: [PATCH 050/221] [tls] Support (and prefer) SHA-256 variants of existing cipher suites Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 2 ++ src/net/tls.c | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index aa4bfc64..8d4e709d 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -77,6 +77,8 @@ struct tls_header { #define TLS_RSA_WITH_NULL_SHA 0x0002 #define TLS_RSA_WITH_AES_128_CBC_SHA 0x002f #define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 +#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003c +#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003d /* TLS extension types */ #define TLS_SERVER_NAME 0 diff --git a/src/net/tls.c b/src/net/tls.c index 517a13e1..4195e5c7 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -513,6 +513,16 @@ static int tls_select_cipher ( struct tls_session *tls, cipher = &aes_cbc_algorithm; digest = &sha1_algorithm; break; + case htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ): + key_len = ( 128 / 8 ); + cipher = &aes_cbc_algorithm; + digest = &sha256_algorithm; + break; + case htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ): + key_len = ( 256 / 8 ); + cipher = &aes_cbc_algorithm; + digest = &sha256_algorithm; + break; default: DBGC ( tls, "TLS %p does not support cipher %04x\n", tls, ntohs ( cipher_suite ) ); @@ -677,7 +687,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) { uint8_t random[32]; uint8_t session_id_len; uint16_t cipher_suite_len; - uint16_t cipher_suites[2]; + uint16_t cipher_suites[4]; uint8_t compression_methods_len; uint8_t compression_methods[1]; uint16_t extensions_len; @@ -702,8 +712,10 @@ static int tls_send_client_hello ( struct tls_session *tls ) { hello.version = htons ( tls->version ); memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) ); hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) ); - hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ); - hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ); + hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ); + hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ); + hello.cipher_suites[2] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ); + hello.cipher_suites[3] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ); hello.compression_methods_len = sizeof ( hello.compression_methods ); hello.extensions_len = htons ( sizeof ( hello.extensions ) ); hello.extensions.server_name_type = htons ( TLS_SERVER_NAME ); From c8f52cccfbd54e764cafee627cb72059fbe93f79 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 23:12:47 +0000 Subject: [PATCH 051/221] [tls] Formalise the definition of a TLS cipher suite Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 14 ++- src/net/tls.c | 195 ++++++++++++++++++++++++----------------- 2 files changed, 125 insertions(+), 84 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 8d4e709d..804e1a1f 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -99,8 +99,8 @@ enum tls_tx_pending { TLS_TX_FINISHED = 0x0010, }; -/** A TLS cipher specification */ -struct tls_cipherspec { +/** A TLS cipher suite */ +struct tls_cipher_suite { /** Public-key encryption algorithm */ struct pubkey_algorithm *pubkey; /** Bulk encryption cipher algorithm */ @@ -108,7 +108,15 @@ struct tls_cipherspec { /** MAC digest algorithm */ struct digest_algorithm *digest; /** Key length */ - size_t key_len; + uint16_t key_len; + /** Numeric code (in network-endian order) */ + uint16_t code; +}; + +/** A TLS cipher specification */ +struct tls_cipherspec { + /** Cipher suite */ + struct tls_cipher_suite *suite; /** Dynamically-allocated storage */ void *dynamic; /** Public key encryption context */ diff --git a/src/net/tls.c b/src/net/tls.c index 4195e5c7..8940613c 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -346,9 +346,9 @@ static void tls_generate_master_secret ( struct tls_session *tls ) { static int tls_generate_keys ( struct tls_session *tls ) { struct tls_cipherspec *tx_cipherspec = &tls->tx_cipherspec_pending; struct tls_cipherspec *rx_cipherspec = &tls->rx_cipherspec_pending; - size_t hash_size = tx_cipherspec->digest->digestsize; - size_t key_size = tx_cipherspec->key_len; - size_t iv_size = tx_cipherspec->cipher->blocksize; + size_t hash_size = tx_cipherspec->suite->digest->digestsize; + size_t key_size = tx_cipherspec->suite->key_len; + size_t iv_size = tx_cipherspec->suite->cipher->blocksize; size_t total = ( 2 * ( hash_size + key_size + iv_size ) ); uint8_t key_block[total]; uint8_t *key; @@ -376,7 +376,7 @@ static int tls_generate_keys ( struct tls_session *tls ) { key += hash_size; /* TX key */ - if ( ( rc = cipher_setkey ( tx_cipherspec->cipher, + if ( ( rc = cipher_setkey ( tx_cipherspec->suite->cipher, tx_cipherspec->cipher_ctx, key, key_size ) ) != 0 ) { DBGC ( tls, "TLS %p could not set TX key: %s\n", @@ -388,7 +388,7 @@ static int tls_generate_keys ( struct tls_session *tls ) { key += key_size; /* RX key */ - if ( ( rc = cipher_setkey ( rx_cipherspec->cipher, + if ( ( rc = cipher_setkey ( rx_cipherspec->suite->cipher, rx_cipherspec->cipher_ctx, key, key_size ) ) != 0 ) { DBGC ( tls, "TLS %p could not set TX key: %s\n", @@ -400,13 +400,15 @@ static int tls_generate_keys ( struct tls_session *tls ) { key += key_size; /* TX initialisation vector */ - cipher_setiv ( tx_cipherspec->cipher, tx_cipherspec->cipher_ctx, key ); + cipher_setiv ( tx_cipherspec->suite->cipher, + tx_cipherspec->cipher_ctx, key ); DBGC ( tls, "TLS %p TX IV:\n", tls ); DBGC_HD ( tls, key, iv_size ); key += iv_size; /* RX initialisation vector */ - cipher_setiv ( rx_cipherspec->cipher, rx_cipherspec->cipher_ctx, key ); + cipher_setiv ( rx_cipherspec->suite->cipher, + rx_cipherspec->cipher_ctx, key ); DBGC ( tls, "TLS %p RX IV:\n", tls ); DBGC_HD ( tls, key, iv_size ); key += iv_size; @@ -423,6 +425,70 @@ static int tls_generate_keys ( struct tls_session *tls ) { ****************************************************************************** */ +/** Null cipher suite */ +struct tls_cipher_suite tls_cipher_suite_null = { + .pubkey = &pubkey_null, + .cipher = &cipher_null, + .digest = &digest_null, +}; + +/** Supported cipher suites, in order of preference */ +struct tls_cipher_suite tls_cipher_suites[] = { + { + .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ), + .key_len = ( 256 / 8 ), + .pubkey = &pubkey_null, /* FIXME */ + .cipher = &aes_cbc_algorithm, + .digest = &sha256_algorithm, + }, + { + .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ), + .key_len = ( 128 / 8 ), + .pubkey = &pubkey_null, /* FIXME */ + .cipher = &aes_cbc_algorithm, + .digest = &sha256_algorithm, + }, + { + .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ), + .key_len = ( 256 / 8 ), + .pubkey = &pubkey_null, /* FIXME */ + .cipher = &aes_cbc_algorithm, + .digest = &sha1_algorithm, + }, + { + .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ), + .key_len = ( 128 / 8 ), + .pubkey = &pubkey_null, /* FIXME */ + .cipher = &aes_cbc_algorithm, + .digest = &sha1_algorithm, + }, +}; + +/** Number of supported cipher suites */ +#define TLS_NUM_CIPHER_SUITES \ + ( sizeof ( tls_cipher_suites ) / sizeof ( tls_cipher_suites[0] ) ) + +/** + * Identify cipher suite + * + * @v cipher_suite Cipher suite specification + * @ret suite Cipher suite, or NULL + */ +static struct tls_cipher_suite * +tls_find_cipher_suite ( unsigned int cipher_suite ) { + struct tls_cipher_suite *suite; + unsigned int i; + + /* Identify cipher suite */ + for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ ) { + suite = &tls_cipher_suites[i]; + if ( suite->code == cipher_suite ) + return suite; + } + + return NULL; +} + /** * Clear cipher suite * @@ -432,9 +498,7 @@ static void tls_clear_cipher ( struct tls_session *tls __unused, struct tls_cipherspec *cipherspec ) { free ( cipherspec->dynamic ); memset ( cipherspec, 0, sizeof ( cipherspec ) ); - cipherspec->pubkey = &pubkey_null; - cipherspec->cipher = &cipher_null; - cipherspec->digest = &digest_null; + cipherspec->suite = &tls_cipher_suite_null; } /** @@ -442,18 +506,15 @@ static void tls_clear_cipher ( struct tls_session *tls __unused, * * @v tls TLS session * @v cipherspec TLS cipher specification - * @v pubkey Public-key encryption elgorithm - * @v cipher Bulk encryption cipher algorithm - * @v digest MAC digest algorithm - * @v key_len Key length + * @v suite Cipher suite * @ret rc Return status code */ static int tls_set_cipher ( struct tls_session *tls, struct tls_cipherspec *cipherspec, - struct pubkey_algorithm *pubkey, - struct cipher_algorithm *cipher, - struct digest_algorithm *digest, - size_t key_len ) { + struct tls_cipher_suite *suite ) { + struct pubkey_algorithm *pubkey = suite->pubkey; + struct cipher_algorithm *cipher = suite->cipher; + struct digest_algorithm *digest = suite->digest; size_t total; void *dynamic; @@ -479,10 +540,7 @@ static int tls_set_cipher ( struct tls_session *tls, assert ( ( cipherspec->dynamic + total ) == dynamic ); /* Store parameters */ - cipherspec->pubkey = pubkey; - cipherspec->cipher = cipher; - cipherspec->digest = digest; - cipherspec->key_len = key_len; + cipherspec->suite = suite; return 0; } @@ -496,49 +554,28 @@ static int tls_set_cipher ( struct tls_session *tls, */ static int tls_select_cipher ( struct tls_session *tls, unsigned int cipher_suite ) { - struct pubkey_algorithm *pubkey = &pubkey_null; - struct cipher_algorithm *cipher = &cipher_null; - struct digest_algorithm *digest = &digest_null; - unsigned int key_len = 0; + struct tls_cipher_suite *suite; int rc; - switch ( cipher_suite ) { - case htons ( TLS_RSA_WITH_AES_128_CBC_SHA ): - key_len = ( 128 / 8 ); - cipher = &aes_cbc_algorithm; - digest = &sha1_algorithm; - break; - case htons ( TLS_RSA_WITH_AES_256_CBC_SHA ): - key_len = ( 256 / 8 ); - cipher = &aes_cbc_algorithm; - digest = &sha1_algorithm; - break; - case htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ): - key_len = ( 128 / 8 ); - cipher = &aes_cbc_algorithm; - digest = &sha256_algorithm; - break; - case htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ): - key_len = ( 256 / 8 ); - cipher = &aes_cbc_algorithm; - digest = &sha256_algorithm; - break; - default: + /* Identify cipher suite */ + suite = tls_find_cipher_suite ( cipher_suite ); + if ( ! suite ) { DBGC ( tls, "TLS %p does not support cipher %04x\n", tls, ntohs ( cipher_suite ) ); return -ENOTSUP; } /* Set ciphers */ - if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending, pubkey, - cipher, digest, key_len ) ) != 0 ) + if ( ( rc = tls_set_cipher ( tls, &tls->tx_cipherspec_pending, + suite ) ) != 0 ) return rc; - if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending, pubkey, - cipher, digest, key_len ) ) != 0 ) + if ( ( rc = tls_set_cipher ( tls, &tls->rx_cipherspec_pending, + suite ) ) != 0 ) return rc; - DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls, - pubkey->name, cipher->name, ( key_len * 8 ), digest->name ); + DBGC ( tls, "TLS %p selected %s-%s-%d-%s\n", tls, suite->pubkey->name, + suite->cipher->name, ( suite->key_len * 8 ), + suite->digest->name ); return 0; } @@ -556,10 +593,7 @@ static int tls_change_cipher ( struct tls_session *tls, struct tls_cipherspec *active ) { /* Sanity check */ - if ( /* FIXME (when pubkey is not hard-coded to RSA): - * ( pending->pubkey == &pubkey_null ) || */ - ( pending->cipher == &cipher_null ) || - ( pending->digest == &digest_null ) ) { + if ( pending->suite == &tls_cipher_suite_null ) { DBGC ( tls, "TLS %p refusing to use null cipher\n", tls ); return -ENOTSUP; } @@ -687,7 +721,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) { uint8_t random[32]; uint8_t session_id_len; uint16_t cipher_suite_len; - uint16_t cipher_suites[4]; + uint16_t cipher_suites[TLS_NUM_CIPHER_SUITES]; uint8_t compression_methods_len; uint8_t compression_methods[1]; uint16_t extensions_len; @@ -704,6 +738,7 @@ static int tls_send_client_hello ( struct tls_session *tls ) { } __attribute__ (( packed )) server_name; } __attribute__ (( packed )) extensions; } __attribute__ (( packed )) hello; + unsigned int i; memset ( &hello, 0, sizeof ( hello ) ); hello.type_length = ( cpu_to_le32 ( TLS_CLIENT_HELLO ) | @@ -712,10 +747,8 @@ static int tls_send_client_hello ( struct tls_session *tls ) { hello.version = htons ( tls->version ); memcpy ( &hello.random, &tls->client_random, sizeof ( hello.random ) ); hello.cipher_suite_len = htons ( sizeof ( hello.cipher_suites ) ); - hello.cipher_suites[0] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ); - hello.cipher_suites[1] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ); - hello.cipher_suites[2] = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ); - hello.cipher_suites[3] = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ); + for ( i = 0 ; i < TLS_NUM_CIPHER_SUITES ; i++ ) + hello.cipher_suites[i] = tls_cipher_suites[i].code; hello.compression_methods_len = sizeof ( hello.compression_methods ); hello.extensions_len = htons ( sizeof ( hello.extensions ) ); hello.extensions.server_name_type = htons ( TLS_SERVER_NAME ); @@ -1252,7 +1285,7 @@ static void tls_hmac ( struct tls_session *tls __unused, struct tls_cipherspec *cipherspec, uint64_t seq, struct tls_header *tlshdr, const void *data, size_t len, void *hmac ) { - struct digest_algorithm *digest = cipherspec->digest; + struct digest_algorithm *digest = cipherspec->suite->digest; uint8_t digest_ctx[digest->ctxsize]; hmac_init ( digest, digest_ctx, cipherspec->mac_secret, @@ -1278,7 +1311,7 @@ static void tls_hmac ( struct tls_session *tls __unused, static void * __malloc tls_assemble_stream ( struct tls_session *tls, const void *data, size_t len, void *digest, size_t *plaintext_len ) { - size_t mac_len = tls->tx_cipherspec.digest->digestsize; + size_t mac_len = tls->tx_cipherspec.suite->digest->digestsize; void *plaintext; void *content; void *mac; @@ -1313,8 +1346,8 @@ static void * __malloc tls_assemble_stream ( struct tls_session *tls, static void * tls_assemble_block ( struct tls_session *tls, const void *data, size_t len, void *digest, size_t *plaintext_len ) { - size_t blocksize = tls->tx_cipherspec.cipher->blocksize; - size_t mac_len = tls->tx_cipherspec.digest->digestsize; + size_t blocksize = tls->tx_cipherspec.suite->cipher->blocksize; + size_t mac_len = tls->tx_cipherspec.suite->digest->digestsize; size_t iv_len; size_t padding_len; void *plaintext; @@ -1362,11 +1395,12 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, struct tls_header plaintext_tlshdr; struct tls_header *tlshdr; struct tls_cipherspec *cipherspec = &tls->tx_cipherspec; + struct cipher_algorithm *cipher = cipherspec->suite->cipher; void *plaintext = NULL; size_t plaintext_len; struct io_buffer *ciphertext = NULL; size_t ciphertext_len; - size_t mac_len = cipherspec->digest->digestsize; + size_t mac_len = cipherspec->suite->digest->digestsize; uint8_t mac[mac_len]; int rc; @@ -1380,7 +1414,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, data, len, mac ); /* Allocate and assemble plaintext struct */ - if ( is_stream_cipher ( cipherspec->cipher ) ) { + if ( is_stream_cipher ( cipher ) ) { plaintext = tls_assemble_stream ( tls, data, len, mac, &plaintext_len ); } else { @@ -1413,10 +1447,9 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, tlshdr->version = htons ( tls->version ); tlshdr->length = htons ( plaintext_len ); memcpy ( cipherspec->cipher_next_ctx, cipherspec->cipher_ctx, - cipherspec->cipher->ctxsize ); - cipher_encrypt ( cipherspec->cipher, cipherspec->cipher_next_ctx, - plaintext, iob_put ( ciphertext, plaintext_len ), - plaintext_len ); + cipher->ctxsize ); + cipher_encrypt ( cipher, cipherspec->cipher_next_ctx, plaintext, + iob_put ( ciphertext, plaintext_len ), plaintext_len ); /* Free plaintext as soon as possible to conserve memory */ free ( plaintext ); @@ -1433,8 +1466,7 @@ static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, /* Update TX state machine to next record */ tls->tx_seq += 1; memcpy ( tls->tx_cipherspec.cipher_ctx, - tls->tx_cipherspec.cipher_next_ctx, - tls->tx_cipherspec.cipher->ctxsize ); + tls->tx_cipherspec.cipher_next_ctx, cipher->ctxsize ); done: free ( plaintext ); @@ -1462,7 +1494,7 @@ static int tls_split_stream ( struct tls_session *tls, size_t mac_len; /* Decompose stream-ciphered data */ - mac_len = tls->rx_cipherspec.digest->digestsize; + mac_len = tls->rx_cipherspec.suite->digest->digestsize; if ( plaintext_len < mac_len ) { DBGC ( tls, "TLS %p received underlength record\n", tls ); DBGC_HD ( tls, plaintext, plaintext_len ); @@ -1514,10 +1546,10 @@ static int tls_split_block ( struct tls_session *tls, /* TLSv1.1 and later use an explicit IV */ iv_len = ( ( tls->version >= TLS_VERSION_TLS_1_1 ) ? - tls->rx_cipherspec.cipher->blocksize : 0 ); + tls->rx_cipherspec.suite->cipher->blocksize : 0 ); /* Decompose block-ciphered data */ - mac_len = tls->rx_cipherspec.digest->digestsize; + mac_len = tls->rx_cipherspec.suite->digest->digestsize; padding_len = *( ( uint8_t * ) ( plaintext + plaintext_len - 1 ) ); if ( plaintext_len < ( iv_len + mac_len + padding_len + 1 ) ) { DBGC ( tls, "TLS %p received underlength record\n", tls ); @@ -1559,12 +1591,13 @@ static int tls_new_ciphertext ( struct tls_session *tls, struct tls_header *tlshdr, void *ciphertext ) { struct tls_header plaintext_tlshdr; struct tls_cipherspec *cipherspec = &tls->rx_cipherspec; + struct cipher_algorithm *cipher = cipherspec->suite->cipher; size_t record_len = ntohs ( tlshdr->length ); void *plaintext = NULL; void *data; size_t len; void *mac; - size_t mac_len = cipherspec->digest->digestsize; + size_t mac_len = cipherspec->suite->digest->digestsize; uint8_t verify_mac[mac_len]; int rc; @@ -1578,11 +1611,11 @@ static int tls_new_ciphertext ( struct tls_session *tls, } /* Decrypt the record */ - cipher_decrypt ( cipherspec->cipher, cipherspec->cipher_ctx, + cipher_decrypt ( cipher, cipherspec->cipher_ctx, ciphertext, plaintext, record_len ); /* Split record into content and MAC */ - if ( is_stream_cipher ( cipherspec->cipher ) ) { + if ( is_stream_cipher ( cipher ) ) { if ( ( rc = tls_split_stream ( tls, plaintext, record_len, &data, &len, &mac ) ) != 0 ) goto done; From fb6a33360fd99b19f557a1721475da9d4dd6b05c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 16:13:07 +0000 Subject: [PATCH 052/221] [rng] Allow hash_df() to accept multiple underlying hash algorithms Signed-off-by: Michael Brown --- src/crypto/entropy.c | 3 +- src/crypto/hash_df.c | 17 +++-- src/include/ipxe/entropy.h | 13 +++- src/include/ipxe/hash_df.h | 18 +---- src/tests/hash_df_test.c | 145 +++++++++++++++++++------------------ 5 files changed, 101 insertions(+), 95 deletions(-) diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c index ab574a94..cb3d54d8 100644 --- a/src/crypto/entropy.c +++ b/src/crypto/entropy.c @@ -454,7 +454,8 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, /* 5.4. tmp = tmp XOR * df ( ( nonce || entropy_bitstring ), n ) */ - hash_df ( &data, sizeof ( data ), df_buf, sizeof ( df_buf ) ); + hash_df ( &entropy_hash_df_algorithm, &data, sizeof ( data ), + df_buf, sizeof ( df_buf ) ); for ( i = 0 ; i < tmp_len ; i++ ) tmp[i] ^= df_buf[i]; diff --git a/src/crypto/hash_df.c b/src/crypto/hash_df.c index 1074f8ca..250c2ffc 100644 --- a/src/crypto/hash_df.c +++ b/src/crypto/hash_df.c @@ -45,6 +45,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** * Distribute entropy throughout a buffer * + * @v hash Underlying hash algorithm * @v input Input data * @v input_len Length of input data, in bytes * @v output Output buffer @@ -63,10 +64,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); * There is no way for the Hash_df function to fail. The returned * status SUCCESS is implicit. */ -void hash_df ( const void *input, size_t input_len, void *output, - size_t output_len ) { - uint8_t context[HASH_DF_CTX_SIZE]; - uint8_t digest[HASH_DF_OUTLEN_BYTES]; +void hash_df ( struct digest_algorithm *hash, const void *input, + size_t input_len, void *output, size_t output_len ) { + uint8_t context[hash->ctxsize]; + uint8_t digest[hash->digestsize]; size_t frag_len; struct { uint8_t pad[3]; @@ -106,12 +107,12 @@ void hash_df ( const void *input, size_t input_len, void *output, * || input_string ) */ prefix.no_of_bits_to_return = htonl ( output_len * 8 ); - digest_init ( &hash_df_algorithm, context ); - digest_update ( &hash_df_algorithm, context, &prefix.counter, + digest_init ( hash, context ); + digest_update ( hash, context, &prefix.counter, ( sizeof ( prefix ) - offsetof ( typeof ( prefix ), counter ) ) ); - digest_update ( &hash_df_algorithm, context, input, input_len ); - digest_final ( &hash_df_algorithm, context, digest ); + digest_update ( hash, context, input, input_len ); + digest_final ( hash, context, digest ); /* 4.2 counter = counter + 1 */ prefix.counter++; diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index 8a1974a1..7208ac87 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -14,6 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** @@ -99,6 +100,15 @@ int get_noise ( noise_sample_t *noise ); extern int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, size_t tmp_len ); +/** Use SHA-1 as the underlying hash algorithm for Hash_df + * + * Hash_df using SHA-1 is an Approved algorithm in ANS X9.82. + */ +#define entropy_hash_df_algorithm sha1_algorithm + +/** Underlying hash algorithm output length (in bytes) */ +#define ENTROPY_HASH_DF_OUTLEN_BYTES SHA1_DIGEST_SIZE + /** * Obtain entropy input * @@ -192,7 +202,8 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, return min_len; } else if ( tmp_len > max_len ) { linker_assert ( ( tmp == tmp_buf ), data_inplace ); - hash_df ( tmp, tmp_len, data, max_len ); + hash_df ( &entropy_hash_df_algorithm, tmp, tmp_len, + data, max_len ); return max_len; } else { /* (Data is already in-place.) */ diff --git a/src/include/ipxe/hash_df.h b/src/include/ipxe/hash_df.h index 003e5cef..607a4a61 100644 --- a/src/include/ipxe/hash_df.h +++ b/src/include/ipxe/hash_df.h @@ -10,21 +10,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include +#include -/** Use SHA-1 as the underlying hash algorithm - * - * Hash_df using SHA-1 is an Approved algorithm in ANS X9.82. - */ -#define hash_df_algorithm sha1_algorithm - -/** Underlying hash algorithm output length (in bytes) */ -#define HASH_DF_OUTLEN_BYTES SHA1_DIGEST_SIZE - -/** Underlying hash algorithm context size (in bytes) */ -#define HASH_DF_CTX_SIZE SHA1_CTX_SIZE - -extern void hash_df ( const void *input, size_t input_len, void *output, - size_t output_len ); +extern void hash_df ( struct digest_algorithm *hash, const void *input, + size_t input_len, void *output, size_t output_len ); #endif /* _IPXE_HASH_DF_H */ diff --git a/src/tests/hash_df_test.c b/src/tests/hash_df_test.c index 201b4a18..55de8cff 100644 --- a/src/tests/hash_df_test.c +++ b/src/tests/hash_df_test.c @@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** Define inline input data */ @@ -45,6 +46,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** A Hash_df test */ struct hash_df_test { + /** Underlying hash algorithm */ + struct digest_algorithm *hash; /** Input data */ const void *input; /** Length of input data */ @@ -59,22 +62,24 @@ struct hash_df_test { * Define a Hash_df test * * @v name Test name + * @v hash_algorithm Underlying hash algorithm * @v input_array Input data * @v expected_array Expected output data * @ret test Hash_df test */ -#define HASH_DF_TEST( name, input_array, expected_array ) \ - static const uint8_t name ## _input [] = input_array; \ - static const uint8_t name ## _expected [] = expected_array; \ - static const struct hash_df_test name = { \ - .input = name ## _input, \ - .input_len = sizeof ( name ## _input ), \ - .expected = name ## _expected, \ - .expected_len = sizeof ( name ## _expected ), \ +#define HASH_DF_TEST( name, hash_algorithm, input_array, expected_array ) \ + static const uint8_t name ## _input [] = input_array; \ + static const uint8_t name ## _expected [] = expected_array; \ + static const struct hash_df_test name = { \ + .hash = &(hash_algorithm), \ + .input = name ## _input, \ + .input_len = sizeof ( name ## _input ), \ + .expected = name ## _expected, \ + .expected_len = sizeof ( name ## _expected ), \ } -/** Test 1 */ -HASH_DF_TEST ( test_1, +/** SHA-1 Test 1 */ +HASH_DF_TEST ( test_sha1_1, sha1_algorithm, INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, @@ -88,8 +93,8 @@ HASH_DF_TEST ( test_1, 0x67, 0x67, 0xb0, 0x5e, 0x83, 0xa9, 0x80, 0x40, 0x6d, 0x94, 0xbe, 0xe3, 0x3c, 0xbb, 0x89 ) ); -/** Test 2 */ -HASH_DF_TEST ( test_2, +/** SHA-1 Test 2 */ +HASH_DF_TEST ( test_sha1_2, sha1_algorithm, INPUT ( 0x00, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, 0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, 0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, @@ -103,8 +108,8 @@ HASH_DF_TEST ( test_2, 0x86, 0x3d, 0xa8, 0x81, 0xff, 0xcb, 0xb4, 0x34, 0xa6, 0xcc, 0xb7, 0xda, 0x2f, 0xb2, 0x10 ) ); -/** Test 3 */ -HASH_DF_TEST ( test_3, +/** SHA-1 Test 3 */ +HASH_DF_TEST ( test_sha1_3, sha1_algorithm, INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, @@ -124,8 +129,8 @@ HASH_DF_TEST ( test_3, 0xe0, 0x2e, 0x85, 0xa2, 0x31, 0x4c, 0xe3, 0xd7, 0x4a, 0x93, 0x32, 0x4b, 0x27, 0xbd, 0xe8 ) ); -/** Test 4 */ -HASH_DF_TEST ( test_4, +/** SHA-1 Test 4 */ +HASH_DF_TEST ( test_sha1_4, sha1_algorithm, INPUT ( 0x00, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, 0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, 0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, @@ -139,8 +144,8 @@ HASH_DF_TEST ( test_4, 0xf4, 0x85, 0xda, 0x6c, 0xbf, 0x04, 0x16, 0xdc, 0xdc, 0x5f, 0xb8, 0xbc, 0x9c, 0x94, 0xb6 ) ); -/** Test 5 */ -HASH_DF_TEST ( test_5, +/** SHA-1 Test 5 */ +HASH_DF_TEST ( test_sha1_5, sha1_algorithm, INPUT ( 0x01, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, 0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, 0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, @@ -160,8 +165,8 @@ HASH_DF_TEST ( test_5, 0xb7, 0xc9, 0x89, 0x4f, 0xb8, 0x84, 0x65, 0xe0, 0xcf, 0xd1, 0xcc, 0x26, 0x1e, 0x22, 0xc5 ) ); -/** Test 6 */ -HASH_DF_TEST ( test_6, +/** SHA-1 Test 6 */ +HASH_DF_TEST ( test_sha1_6, sha1_algorithm, INPUT ( 0x00, 0x0a, 0x04, 0x41, 0xa5, 0x2b, 0xed, 0xf7, 0x94, 0xf5, 0xaa, 0x62, 0x7b, 0xcb, 0xd8, 0x1f, 0x93, 0xe0, 0x11, 0xd5, 0x1f, 0x34, 0x74, 0x80, 0x2c, 0x37, 0x50, 0x76, 0x75, 0x51, @@ -175,8 +180,8 @@ HASH_DF_TEST ( test_6, 0x8a, 0xf8, 0x47, 0xca, 0xcc, 0x4c, 0x92, 0xc6, 0x14, 0x44, 0x85, 0xc2, 0x27, 0xca, 0x05 ) ); -/** Test 7 */ -HASH_DF_TEST ( test_7, +/** SHA-1 Test 7 */ +HASH_DF_TEST ( test_sha1_7, sha1_algorithm, INPUT ( 0x01, 0x0e, 0x16, 0x0a, 0x56, 0x07, 0x95, 0x4e, 0x7d, 0x79, 0xd5, 0xa2, 0x2b, 0xf9, 0x08, 0x0b, 0x10, 0xce, 0xb7, 0x3c, 0x62, 0x23, 0x07, 0xf9, 0xf5, 0x45, 0xbd, 0xb1, 0xa4, 0x61, @@ -196,8 +201,8 @@ HASH_DF_TEST ( test_7, 0x51, 0x64, 0x54, 0x37, 0x28, 0x71, 0x7f, 0x17, 0x1f, 0xdb, 0x02, 0xb2, 0xad, 0x57, 0x95 ) ); -/** Test 8 */ -HASH_DF_TEST ( test_8, +/** SHA-1 Test 8 */ +HASH_DF_TEST ( test_sha1_8, sha1_algorithm, INPUT ( 0x00, 0xdc, 0x24, 0xdf, 0x10, 0x2f, 0xa9, 0xf9, 0x6c, 0xc1, 0xcf, 0xf8, 0xc1, 0x16, 0xc7, 0x9d, 0x14, 0x97, 0xd7, 0xc2, 0x7b, 0xba, 0x5b, 0xa8, 0x01, 0xe1, 0x56, 0x21, 0x93, 0x35, @@ -211,8 +216,8 @@ HASH_DF_TEST ( test_8, 0xd6, 0x41, 0x5f, 0x37, 0x83, 0xb0, 0x15, 0x67, 0x89, 0x1b, 0x57, 0x66, 0x2a, 0xbb, 0x39 ) ); -/** Test 9 */ -HASH_DF_TEST ( test_9, +/** SHA-1 Test 9 */ +HASH_DF_TEST ( test_sha1_9, sha1_algorithm, INPUT ( 0x01, 0xd0, 0x8f, 0xb4, 0x41, 0xf2, 0xf4, 0xcb, 0x37, 0xcf, 0x6c, 0x24, 0x20, 0xa8, 0x2c, 0x74, 0x27, 0xac, 0xf7, 0xfc, 0xfd, 0x79, 0x90, 0x14, 0x38, 0x34, 0xa5, 0xc2, 0x56, 0xab, @@ -237,8 +242,8 @@ HASH_DF_TEST ( test_9, 0xb4, 0x5d, 0x89, 0xdb, 0x61, 0x2c, 0xd9, 0xd2, 0x8a, 0x55, 0xc0, 0xf0, 0xd1, 0xf8, 0xf9 ) ); -/** Test 10 */ -HASH_DF_TEST ( test_10, +/** SHA-1 Test 10 */ +HASH_DF_TEST ( test_sha1_10, sha1_algorithm, INPUT ( 0x00, 0x8f, 0xde, 0xc9, 0xe6, 0x18, 0x96, 0x36, 0xf0, 0xa5, 0xce, 0x53, 0xe8, 0x1c, 0x13, 0xac, 0x93, 0x84, 0xfa, 0xfb, 0xa0, 0xee, 0x50, 0xc1, 0xe2, 0xc8, 0xa0, 0x99, 0xde, 0x41, @@ -252,8 +257,8 @@ HASH_DF_TEST ( test_10, 0x51, 0x95, 0xf4, 0x79, 0xcd, 0x76, 0x20, 0x22, 0x35, 0x10, 0x2e, 0xf6, 0x27, 0x29, 0x19 ) ); -/** Test 11 */ -HASH_DF_TEST ( test_11, +/** SHA-1 Test 11 */ +HASH_DF_TEST ( test_sha1_11, sha1_algorithm, INPUT ( 0x01, 0x27, 0xaf, 0x40, 0x17, 0xca, 0xc5, 0xb3, 0x86, 0x24, 0xe8, 0x4c, 0x2d, 0x10, 0xef, 0xd7, 0x8d, 0xf4, 0xf4, 0x77, 0xd6, 0x54, 0x69, 0x5a, 0x04, 0x32, 0x32, 0x6b, 0x3a, 0x1c, @@ -278,8 +283,8 @@ HASH_DF_TEST ( test_11, 0xa3, 0xfe, 0xa1, 0xc7, 0x11, 0x7d, 0x6f, 0x7d, 0xd2, 0xef, 0x77, 0x7d, 0x7c, 0xf3, 0xeb ) ); -/** Test 12 */ -HASH_DF_TEST ( test_12, +/** SHA-1 Test 12 */ +HASH_DF_TEST ( test_sha1_12, sha1_algorithm, INPUT ( 0x00, 0x2c, 0x9c, 0x0d, 0x80, 0x03, 0xe3, 0x40, 0x23, 0xbe, 0x5b, 0x63, 0xfd, 0xb9, 0xd2, 0x24, 0xb4, 0x25, 0x0c, 0xc8, 0x15, 0x5b, 0xd1, 0xee, 0xd8, 0xe5, 0x5d, 0x91, 0x06, 0x2f, @@ -293,8 +298,8 @@ HASH_DF_TEST ( test_12, 0x0e, 0x8b, 0xff, 0xf6, 0x0c, 0xb7, 0x7f, 0xa5, 0x4b, 0xb1, 0x1a, 0x83, 0x31, 0xcb, 0x24 ) ); -/** Test 13 */ -HASH_DF_TEST ( test_13, +/** SHA-1 Test 13 */ +HASH_DF_TEST ( test_sha1_13, sha1_algorithm, INPUT ( 0x01, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, 0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, 0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, @@ -314,8 +319,8 @@ HASH_DF_TEST ( test_13, 0xf0, 0x0c, 0x3b, 0xda, 0x59, 0x6b, 0x10, 0x88, 0x61, 0xf0, 0x6b, 0xf9, 0x1b, 0x45, 0xd6 ) ); -/** Test 14 */ -HASH_DF_TEST ( test_14, +/** SHA-1 Test 14 */ +HASH_DF_TEST ( test_sha1_14, sha1_algorithm, INPUT ( 0x00, 0xe5, 0x04, 0x3d, 0x1b, 0x95, 0x4b, 0x34, 0xba, 0x60, 0xd2, 0x48, 0xe8, 0x83, 0xef, 0x49, 0x8c, 0x5c, 0x52, 0x36, 0xb8, 0x26, 0x0e, 0x23, 0x8e, 0x02, 0xc8, 0xd4, 0xfc, 0x5f, @@ -329,8 +334,8 @@ HASH_DF_TEST ( test_14, 0xa6, 0xbc, 0xfc, 0xfc, 0x0f, 0x51, 0xfe, 0x2f, 0x77, 0xc1, 0xc9, 0x9d, 0xf0, 0xa2, 0x09 ) ); -/** Test 15 */ -HASH_DF_TEST ( test_15, +/** SHA-1 Test 15 */ +HASH_DF_TEST ( test_sha1_15, sha1_algorithm, INPUT ( 0x01, 0x04, 0x43, 0xa0, 0x2c, 0x82, 0x5c, 0x31, 0x59, 0xf4, 0x5e, 0x8c, 0x0a, 0xe5, 0x9e, 0x8c, 0x76, 0x45, 0x69, 0x95, 0xc0, 0x35, 0x40, 0x46, 0x6a, 0x14, 0x54, 0x7c, 0xcb, 0xe8, @@ -350,8 +355,8 @@ HASH_DF_TEST ( test_15, 0xd2, 0x7e, 0x2b, 0x2e, 0x42, 0x2b, 0x32, 0xb9, 0x7f, 0x05, 0x0d, 0x1b, 0xd2, 0xb4, 0x90 ) ); -/** Test 16 */ -HASH_DF_TEST ( test_16, +/** SHA-1 Test 16 */ +HASH_DF_TEST ( test_sha1_16, sha1_algorithm, INPUT ( 0x00, 0x9d, 0xc3, 0x52, 0x08, 0xee, 0x2b, 0x8c, 0x58, 0x1e, 0xa3, 0x0b, 0xaa, 0xcb, 0x5d, 0x74, 0x31, 0x7a, 0x87, 0x94, 0x54, 0x10, 0x71, 0x7e, 0x58, 0xd3, 0x70, 0x5f, 0xbd, 0xc7, @@ -365,8 +370,8 @@ HASH_DF_TEST ( test_16, 0xef, 0x85, 0x76, 0xe7, 0x5c, 0xb3, 0xcf, 0xe8, 0x22, 0x07, 0x68, 0xb2, 0x6c, 0xe7, 0x7a ) ); -/** Test 17 */ -HASH_DF_TEST ( test_17, +/** SHA-1 Test 17 */ +HASH_DF_TEST ( test_sha1_17, sha1_algorithm, INPUT ( 0x01, 0x99, 0xb9, 0x53, 0x7b, 0x84, 0x27, 0xb8, 0xce, 0x23, 0x21, 0x9a, 0x61, 0x1c, 0xbe, 0x61, 0x06, 0x44, 0xcf, 0x85, 0x03, 0xee, 0xc5, 0xba, 0x22, 0xde, 0x1a, 0xb2, 0x12, 0xc3, @@ -391,8 +396,8 @@ HASH_DF_TEST ( test_17, 0xaa, 0x8a, 0x6e, 0x6b, 0x8e, 0x6d, 0x56, 0xa4, 0x31, 0x33, 0x3b, 0x40, 0x8e, 0x6f, 0xa8 ) ); -/** Test 18 */ -HASH_DF_TEST ( test_18, +/** SHA-1 Test 18 */ +HASH_DF_TEST ( test_sha1_18, sha1_algorithm, INPUT ( 0x00, 0x56, 0x3a, 0x5d, 0x20, 0x7d, 0x37, 0x70, 0x7b, 0xf5, 0xf2, 0x4d, 0x0b, 0xd4, 0x93, 0x5d, 0xc3, 0x8d, 0xbe, 0x04, 0x36, 0x37, 0xb3, 0xff, 0x8a, 0xb6, 0x8c, 0xfc, 0xe2, 0xf2, @@ -406,8 +411,8 @@ HASH_DF_TEST ( test_18, 0xf6, 0xbc, 0xda, 0xf8, 0x1d, 0x28, 0x9c, 0xf4, 0xbd, 0x3c, 0x91, 0xb7, 0x00, 0x5c, 0x18 ) ); -/** Test 19 */ -HASH_DF_TEST ( test_19, +/** SHA-1 Test 19 */ +HASH_DF_TEST ( test_sha1_19, sha1_algorithm, INPUT ( 0x01, 0x1c, 0x0e, 0x46, 0x75, 0x9b, 0x38, 0x55, 0x6a, 0x28, 0xa4, 0x5e, 0x7b, 0x83, 0xe1, 0x4d, 0xb8, 0x62, 0x8d, 0xb1, 0x62, 0x13, 0xe1, 0xba, 0x2d, 0x97, 0x74, 0xf6, 0xc0, 0xac, @@ -432,8 +437,8 @@ HASH_DF_TEST ( test_19, 0x0a, 0xb0, 0x7d, 0x12, 0x08, 0xb6, 0xbd, 0x66, 0x5b, 0x30, 0x0a, 0xa4, 0xdb, 0x9c, 0x3e ) ); -/** Test 20 */ -HASH_DF_TEST ( test_20, +/** SHA-1 Test 20 */ +HASH_DF_TEST ( test_sha1_20, sha1_algorithm, INPUT ( 0x00, 0x60, 0x01, 0x93, 0xc8, 0xf6, 0x03, 0x1a, 0x2d, 0x49, 0x37, 0x2a, 0x8b, 0x0f, 0x60, 0xf6, 0x8c, 0x1d, 0xfd, 0xac, 0xd4, 0xf8, 0xea, 0x01, 0x37, 0x47, 0xd7, 0x14, 0x82, 0x33, @@ -454,8 +459,8 @@ HASH_DF_TEST ( test_20, */ #define hash_df_ok( test ) do { \ uint8_t output[ (test)->expected_len ]; \ - hash_df ( (test)->input, (test)->input_len, output, \ - sizeof ( output ) ); \ + hash_df ( (test)->hash, (test)->input, (test)->input_len, \ + output, sizeof ( output ) ); \ ok ( memcmp ( (test)->expected, output, \ sizeof ( output ) ) == 0 ); \ } while ( 0 ) @@ -466,26 +471,26 @@ HASH_DF_TEST ( test_20, */ static void hash_df_test_exec ( void ) { - hash_df_ok ( &test_1 ); - hash_df_ok ( &test_2 ); - hash_df_ok ( &test_3 ); - hash_df_ok ( &test_4 ); - hash_df_ok ( &test_5 ); - hash_df_ok ( &test_6 ); - hash_df_ok ( &test_7 ); - hash_df_ok ( &test_8 ); - hash_df_ok ( &test_9 ); - hash_df_ok ( &test_10 ); - hash_df_ok ( &test_11 ); - hash_df_ok ( &test_12 ); - hash_df_ok ( &test_13 ); - hash_df_ok ( &test_14 ); - hash_df_ok ( &test_15 ); - hash_df_ok ( &test_16 ); - hash_df_ok ( &test_17 ); - hash_df_ok ( &test_18 ); - hash_df_ok ( &test_19 ); - hash_df_ok ( &test_20 ); + hash_df_ok ( &test_sha1_1 ); + hash_df_ok ( &test_sha1_2 ); + hash_df_ok ( &test_sha1_3 ); + hash_df_ok ( &test_sha1_4 ); + hash_df_ok ( &test_sha1_5 ); + hash_df_ok ( &test_sha1_6 ); + hash_df_ok ( &test_sha1_7 ); + hash_df_ok ( &test_sha1_8 ); + hash_df_ok ( &test_sha1_9 ); + hash_df_ok ( &test_sha1_10 ); + hash_df_ok ( &test_sha1_11 ); + hash_df_ok ( &test_sha1_12 ); + hash_df_ok ( &test_sha1_13 ); + hash_df_ok ( &test_sha1_14 ); + hash_df_ok ( &test_sha1_15 ); + hash_df_ok ( &test_sha1_16 ); + hash_df_ok ( &test_sha1_17 ); + hash_df_ok ( &test_sha1_18 ); + hash_df_ok ( &test_sha1_19 ); + hash_df_ok ( &test_sha1_20 ); } /** Hash_df self-test */ From 0978251a66342334c792c9a390e7d6d229ac39d5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 23:51:35 +0000 Subject: [PATCH 053/221] [rng] Add NIST self-tests for Hash_df using SHA-256 Signed-off-by: Michael Brown --- src/tests/hash_df_test.c | 397 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 397 insertions(+) diff --git a/src/tests/hash_df_test.c b/src/tests/hash_df_test.c index 55de8cff..0fb28492 100644 --- a/src/tests/hash_df_test.c +++ b/src/tests/hash_df_test.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** Define inline input data */ @@ -452,6 +453,381 @@ HASH_DF_TEST ( test_sha1_20, sha1_algorithm, 0xc0, 0x72, 0x09, 0x55, 0x5d, 0x7e, 0x35, 0x54, 0xf9, 0xd1, 0x2f, 0xc5, 0x59, 0x7f, 0x22 ) ); +/** SHA-256 Test 1 */ +HASH_DF_TEST ( test_sha256_1, sha256_algorithm, + INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27 ), + EXPECT ( 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c, 0xa7, + 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd, 0x46, + 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b, 0xcd, + 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c, 0x0d, + 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d, 0xf4, + 0x04, 0x48, 0xd2, 0xd8, 0xe1 ) ); + +/** SHA-256 Test 2 */ +HASH_DF_TEST ( test_sha256_2, sha256_algorithm, + INPUT ( 0x00, 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c, + 0xa7, 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd, + 0x46, 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b, + 0xcd, 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c, + 0x0d, 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d, + 0xf4, 0x04, 0x48, 0xd2, 0xd8, 0xe1 ), + EXPECT ( 0xe1, 0x5d, 0xe4, 0xa8, 0xe3, 0xb1, 0x41, 0x9b, 0x61, 0xd5, + 0x34, 0xf1, 0x5d, 0xbd, 0x31, 0xee, 0x19, 0xec, 0x59, 0x5f, + 0x8b, 0x98, 0x11, 0x1a, 0x94, 0xf5, 0x22, 0x37, 0xad, 0x5d, + 0x66, 0xf0, 0xcf, 0xaa, 0xfd, 0xdc, 0x90, 0x19, 0x59, 0x02, + 0xe9, 0x79, 0xf7, 0x9b, 0x65, 0x35, 0x7f, 0xea, 0x85, 0x99, + 0x8e, 0x4e, 0x37, 0xd2, 0xc1 ) ); + +/** SHA-256 Test 3 */ +HASH_DF_TEST ( test_sha256_3, sha256_algorithm, + INPUT ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, + 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, + 0x32, 0x33, 0x34, 0x35, 0x36, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, + 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, + 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76 ), + EXPECT ( 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3, 0x03, + 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62, 0xd1, + 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32, 0xf7, + 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee, 0xc8, + 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7, 0x99, + 0x29, 0x90, 0x94, 0xa1, 0xca ) ); + +/** SHA-256 Test 4 */ +HASH_DF_TEST ( test_sha256_4, sha256_algorithm, + INPUT ( 0x00, 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3, + 0x03, 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62, + 0xd1, 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32, + 0xf7, 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee, + 0xc8, 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7, + 0x99, 0x29, 0x90, 0x94, 0xa1, 0xca ), + EXPECT ( 0x44, 0x74, 0x8a, 0x78, 0xb1, 0x6e, 0x75, 0x55, 0x9f, 0x88, + 0x1d, 0x51, 0xc1, 0x5d, 0xfe, 0x6c, 0x52, 0xcf, 0xb0, 0xbb, + 0x71, 0x62, 0x01, 0x69, 0xc7, 0x93, 0x34, 0x27, 0x67, 0xe7, + 0xf8, 0x87, 0x5f, 0x42, 0xcb, 0x6a, 0x20, 0xc8, 0x9d, 0x7c, + 0x6e, 0xf3, 0xdc, 0x61, 0x0d, 0x8f, 0xf2, 0x03, 0xd6, 0x76, + 0x6c, 0xed, 0x19, 0x19, 0xd0 ) ); + +/** SHA-256 Test 5 */ +HASH_DF_TEST ( test_sha256_5, sha256_algorithm, + INPUT ( 0x01, 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c, + 0xa7, 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd, + 0x46, 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b, + 0xcd, 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c, + 0x0d, 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d, + 0xf4, 0x04, 0x48, 0xd2, 0xd8, 0xe1, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6 ), + EXPECT ( 0x3c, 0x40, 0xe8, 0xdc, 0x71, 0x72, 0xfd, 0xa2, 0x32, 0x55, + 0x0a, 0x1d, 0x8e, 0x14, 0x47, 0xc1, 0x1f, 0x47, 0x48, 0x88, + 0xf9, 0x6c, 0xd8, 0x5c, 0x38, 0x63, 0xd5, 0xe4, 0x84, 0x26, + 0x67, 0x56, 0x28, 0xd0, 0x88, 0x85, 0x34, 0x7c, 0x3e, 0xfd, + 0x62, 0x92, 0xfd, 0xdc, 0xd1, 0xa1, 0x42, 0x1e, 0xed, 0x51, + 0xb7, 0x13, 0xab, 0x09, 0x0f ) ); + +/** SHA-256 Test 6 */ +HASH_DF_TEST ( test_sha256_6, sha256_algorithm, + INPUT ( 0x00, 0x3c, 0x40, 0xe8, 0xdc, 0x71, 0x72, 0xfd, 0xa2, 0x32, + 0x55, 0x0a, 0x1d, 0x8e, 0x14, 0x47, 0xc1, 0x1f, 0x47, 0x48, + 0x88, 0xf9, 0x6c, 0xd8, 0x5c, 0x38, 0x63, 0xd5, 0xe4, 0x84, + 0x26, 0x67, 0x56, 0x28, 0xd0, 0x88, 0x85, 0x34, 0x7c, 0x3e, + 0xfd, 0x62, 0x92, 0xfd, 0xdc, 0xd1, 0xa1, 0x42, 0x1e, 0xed, + 0x51, 0xb7, 0x13, 0xab, 0x09, 0x0f ), + EXPECT ( 0xe7, 0x56, 0x83, 0x84, 0xf2, 0x64, 0xe4, 0xa7, 0xe7, 0xae, + 0x85, 0x0d, 0x9d, 0x50, 0x1f, 0xd6, 0x31, 0x83, 0x56, 0x4f, + 0xd7, 0xd3, 0x90, 0x44, 0x6f, 0x5b, 0xe5, 0xf6, 0x7b, 0x50, + 0x19, 0x5b, 0x52, 0x84, 0x69, 0x2a, 0xd4, 0xb7, 0x6d, 0xfd, + 0x4f, 0x52, 0x4b, 0xcf, 0xcc, 0xab, 0x62, 0xc1, 0x30, 0x9f, + 0x25, 0x15, 0x17, 0xdf, 0xfd ) ); + +/** SHA-256 Test 7 */ +HASH_DF_TEST ( test_sha256_7, sha256_algorithm, + INPUT ( 0x01, 0x23, 0x97, 0x6c, 0x61, 0x63, 0xd7, 0xe2, 0x4a, 0x1a, + 0x03, 0x8f, 0x2b, 0x2b, 0x64, 0x67, 0x97, 0x50, 0xca, 0x9e, + 0xd8, 0xd1, 0x40, 0x69, 0x8d, 0x64, 0x22, 0x39, 0x7b, 0x02, + 0x96, 0x9e, 0x6e, 0xcd, 0xd2, 0x9d, 0xac, 0xc5, 0x76, 0x7e, + 0x2c, 0xc2, 0xd0, 0xa1, 0x56, 0xc8, 0x7a, 0xd0, 0xb3, 0x57, + 0x89, 0x05, 0x07, 0xe0, 0x37, 0x77, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6 ), + EXPECT ( 0xe9, 0x83, 0xb1, 0x66, 0xa9, 0x2a, 0x99, 0x7e, 0xab, 0xcc, + 0x96, 0x6c, 0x6a, 0xa3, 0xd3, 0xb3, 0xa1, 0x68, 0x1f, 0xc5, + 0x8f, 0x58, 0x29, 0x40, 0x3b, 0x48, 0x60, 0x1e, 0xc1, 0x77, + 0x54, 0x94, 0x2e, 0x11, 0xc1, 0xcd, 0x46, 0x5b, 0x7d, 0xbe, + 0x2a, 0x78, 0xca, 0x04, 0x2c, 0xf9, 0xb3, 0x05, 0x71, 0xff, + 0x12, 0xe3, 0xb9, 0xf6, 0xc9 ) ); + +/** SHA-256 Test 8 */ +HASH_DF_TEST ( test_sha256_8, sha256_algorithm, + INPUT ( 0x00, 0xe9, 0x83, 0xb1, 0x66, 0xa9, 0x2a, 0x99, 0x7e, 0xab, + 0xcc, 0x96, 0x6c, 0x6a, 0xa3, 0xd3, 0xb3, 0xa1, 0x68, 0x1f, + 0xc5, 0x8f, 0x58, 0x29, 0x40, 0x3b, 0x48, 0x60, 0x1e, 0xc1, + 0x77, 0x54, 0x94, 0x2e, 0x11, 0xc1, 0xcd, 0x46, 0x5b, 0x7d, + 0xbe, 0x2a, 0x78, 0xca, 0x04, 0x2c, 0xf9, 0xb3, 0x05, 0x71, + 0xff, 0x12, 0xe3, 0xb9, 0xf6, 0xc9 ), + EXPECT ( 0xa9, 0x77, 0x5c, 0xe1, 0x65, 0x5b, 0xff, 0x95, 0x1b, 0xe0, + 0xaf, 0x5b, 0x79, 0x59, 0x72, 0x5c, 0x76, 0x7d, 0x86, 0xf1, + 0xe1, 0x9b, 0x11, 0xb8, 0x90, 0x04, 0xf6, 0x97, 0x4d, 0xbf, + 0xa0, 0x46, 0x04, 0x45, 0x8e, 0x5c, 0x52, 0x8e, 0x7e, 0x1d, + 0xfa, 0xb3, 0x88, 0x7b, 0xa4, 0xaa, 0xdb, 0xd6, 0xfb, 0xde, + 0x0b, 0x31, 0x6f, 0x1d, 0x91 ) ); + +/** SHA-256 Test 9 */ +HASH_DF_TEST ( test_sha256_9, sha256_algorithm, + INPUT ( 0x01, 0xab, 0x41, 0xcd, 0xe4, 0x37, 0xab, 0x8b, 0x09, 0x1c, + 0xa7, 0xc5, 0x75, 0x5d, 0x10, 0xf0, 0x11, 0x0c, 0x1d, 0xbd, + 0x46, 0x2f, 0x22, 0x6c, 0xfd, 0xab, 0xfb, 0xb0, 0x4a, 0x8b, + 0xcd, 0xef, 0x95, 0x16, 0x7d, 0x84, 0xaf, 0x64, 0x12, 0x8c, + 0x0d, 0x71, 0xf4, 0xd5, 0xb8, 0xc0, 0xed, 0xfb, 0xbe, 0x3d, + 0xf4, 0x04, 0x48, 0xd2, 0xd8, 0xe1, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, + 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ), + EXPECT ( 0x57, 0xb2, 0xcf, 0x00, 0xb5, 0x42, 0x97, 0x46, 0x0b, 0x08, + 0x7e, 0x52, 0x75, 0xd7, 0xdd, 0x74, 0x23, 0xb6, 0xe3, 0xb6, + 0x5e, 0x35, 0x16, 0xd2, 0x48, 0x11, 0x99, 0xa0, 0x17, 0xb5, + 0x3a, 0x22, 0x20, 0x33, 0xfe, 0x68, 0xa6, 0x0b, 0xd0, 0xbd, + 0x70, 0x40, 0x26, 0xcd, 0x5a, 0x3e, 0x79, 0x55, 0xdb, 0x01, + 0xdc, 0xb2, 0x84, 0x48, 0xd1 ) ); + +/** SHA-256 Test 10 */ +HASH_DF_TEST ( test_sha256_10, sha256_algorithm, + INPUT ( 0x00, 0x57, 0xb2, 0xcf, 0x00, 0xb5, 0x42, 0x97, 0x46, 0x0b, + 0x08, 0x7e, 0x52, 0x75, 0xd7, 0xdd, 0x74, 0x23, 0xb6, 0xe3, + 0xb6, 0x5e, 0x35, 0x16, 0xd2, 0x48, 0x11, 0x99, 0xa0, 0x17, + 0xb5, 0x3a, 0x22, 0x20, 0x33, 0xfe, 0x68, 0xa6, 0x0b, 0xd0, + 0xbd, 0x70, 0x40, 0x26, 0xcd, 0x5a, 0x3e, 0x79, 0x55, 0xdb, + 0x01, 0xdc, 0xb2, 0x84, 0x48, 0xd1 ), + EXPECT ( 0x5b, 0xc1, 0xc6, 0x45, 0xcc, 0x8d, 0x32, 0x15, 0x82, 0xaf, + 0xbb, 0x00, 0x16, 0x99, 0x2b, 0x0f, 0x3a, 0xfe, 0x0f, 0x54, + 0x7a, 0xe7, 0xa7, 0x4c, 0x9c, 0x05, 0xa1, 0x44, 0x02, 0xfb, + 0xb1, 0xd5, 0x40, 0xe6, 0x80, 0x9d, 0x8b, 0xee, 0xf5, 0x99, + 0xed, 0x4c, 0x39, 0x16, 0x47, 0x40, 0xed, 0xa0, 0xd9, 0xc3, + 0x79, 0x5d, 0xe5, 0x52, 0xc5 ) ); + +/** SHA-256 Test 11 */ +HASH_DF_TEST ( test_sha256_11, sha256_algorithm, + INPUT ( 0x01, 0xb3, 0x74, 0x95, 0x46, 0x81, 0xcf, 0xc9, 0x5b, 0x8d, + 0xb8, 0x39, 0x52, 0x8c, 0x71, 0x08, 0x83, 0x5e, 0xb4, 0xf3, + 0x0a, 0xd9, 0x1c, 0xbe, 0x9e, 0xa0, 0xd5, 0x45, 0xcc, 0xfd, + 0x18, 0x13, 0x2a, 0xf1, 0xd3, 0x76, 0x8f, 0x47, 0x02, 0x77, + 0x2b, 0x69, 0x15, 0x9f, 0x2c, 0xc0, 0x7f, 0x48, 0x74, 0x1e, + 0xb5, 0xb2, 0xb1, 0x22, 0x11, 0x25, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ), + EXPECT ( 0x5d, 0xc1, 0xc5, 0xf4, 0xb4, 0x11, 0x50, 0xce, 0xe0, 0xef, + 0xc1, 0x29, 0xb8, 0x37, 0xb3, 0x1c, 0x84, 0xd7, 0x91, 0xff, + 0x2e, 0x7e, 0xda, 0xc2, 0x9c, 0x2c, 0x50, 0xcf, 0x8a, 0x40, + 0x70, 0x9b, 0x98, 0x64, 0x0f, 0x7b, 0xbd, 0x32, 0xbc, 0xf0, + 0xfc, 0xb6, 0x13, 0xf9, 0x6d, 0x55, 0xd1, 0x60, 0x56, 0xbb, + 0x3c, 0xa6, 0xa7, 0x74, 0x05 ) ); + +/** SHA-256 Test 12 */ +HASH_DF_TEST ( test_sha256_12, sha256_algorithm, + INPUT ( 0x00, 0x5d, 0xc1, 0xc5, 0xf4, 0xb4, 0x11, 0x50, 0xce, 0xe0, + 0xef, 0xc1, 0x29, 0xb8, 0x37, 0xb3, 0x1c, 0x84, 0xd7, 0x91, + 0xff, 0x2e, 0x7e, 0xda, 0xc2, 0x9c, 0x2c, 0x50, 0xcf, 0x8a, + 0x40, 0x70, 0x9b, 0x98, 0x64, 0x0f, 0x7b, 0xbd, 0x32, 0xbc, + 0xf0, 0xfc, 0xb6, 0x13, 0xf9, 0x6d, 0x55, 0xd1, 0x60, 0x56, + 0xbb, 0x3c, 0xa6, 0xa7, 0x74, 0x05 ), + EXPECT ( 0x62, 0x22, 0x10, 0x8c, 0xed, 0xfe, 0x6d, 0x6a, 0x22, 0x9f, + 0x8c, 0x3c, 0xbf, 0x44, 0x68, 0xc8, 0xf5, 0x17, 0x22, 0x86, + 0x4c, 0xc4, 0x16, 0xa4, 0x29, 0x26, 0xd9, 0x9b, 0xa6, 0xf0, + 0x45, 0xc1, 0xf6, 0x21, 0x11, 0x56, 0x94, 0x6c, 0x6e, 0x79, + 0x37, 0x29, 0x97, 0x4e, 0xb4, 0xc5, 0xa6, 0x07, 0x8f, 0x9a, + 0x1d, 0x4d, 0x1c, 0xd7, 0x49 ) ); + +/** SHA-256 Test 13 */ +HASH_DF_TEST ( test_sha256_13, sha256_algorithm, + INPUT ( 0x01, 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3, + 0x03, 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62, + 0xd1, 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32, + 0xf7, 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee, + 0xc8, 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7, + 0x99, 0x29, 0x90, 0x94, 0xa1, 0xca, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6 ), + EXPECT ( 0xe0, 0x26, 0xa5, 0xc2, 0xe7, 0x62, 0x3e, 0x62, 0xb7, 0x1a, + 0x2e, 0x04, 0xc2, 0x5f, 0x0b, 0x08, 0x58, 0x2b, 0xe2, 0x16, + 0x36, 0x34, 0xc0, 0x49, 0x6d, 0x2b, 0x65, 0xda, 0x7e, 0xaa, + 0x03, 0xb5, 0xc3, 0xb6, 0xb5, 0x10, 0xbb, 0x3f, 0xe4, 0x74, + 0x34, 0x07, 0x1f, 0x70, 0x7a, 0xc7, 0xfe, 0x4c, 0x39, 0x6a, + 0xaa, 0xee, 0x76, 0x4c, 0x90 ) ); + +/** SHA-256 Test 14 */ +HASH_DF_TEST ( test_sha256_14, sha256_algorithm, + INPUT ( 0x00, 0xe0, 0x26, 0xa5, 0xc2, 0xe7, 0x62, 0x3e, 0x62, 0xb7, + 0x1a, 0x2e, 0x04, 0xc2, 0x5f, 0x0b, 0x08, 0x58, 0x2b, 0xe2, + 0x16, 0x36, 0x34, 0xc0, 0x49, 0x6d, 0x2b, 0x65, 0xda, 0x7e, + 0xaa, 0x03, 0xb5, 0xc3, 0xb6, 0xb5, 0x10, 0xbb, 0x3f, 0xe4, + 0x74, 0x34, 0x07, 0x1f, 0x70, 0x7a, 0xc7, 0xfe, 0x4c, 0x39, + 0x6a, 0xaa, 0xee, 0x76, 0x4c, 0x90 ), + EXPECT ( 0xc9, 0xea, 0x75, 0x4b, 0xee, 0x0a, 0xb6, 0x44, 0x15, 0xca, + 0x7f, 0xe3, 0x2e, 0xbb, 0xfb, 0x07, 0xed, 0x93, 0x2e, 0x7c, + 0x95, 0x7e, 0xce, 0xae, 0xf0, 0xcd, 0x2f, 0xa7, 0x7a, 0x46, + 0xf9, 0xe8, 0x59, 0x62, 0x78, 0x97, 0x54, 0xc6, 0xd2, 0x98, + 0xf9, 0xb5, 0xe4, 0x59, 0x6b, 0x4e, 0x0e, 0x6d, 0xf4, 0xf4, + 0xb8, 0x23, 0x60, 0xda, 0x33 ) ); + +/** SHA-256 Test 15 */ +HASH_DF_TEST ( test_sha256_15, sha256_algorithm, + INPUT ( 0x01, 0xaa, 0x11, 0x1b, 0x0e, 0xd5, 0x6c, 0xf4, 0xa6, 0xcc, + 0xe4, 0xad, 0xe7, 0xf1, 0x1b, 0x06, 0x10, 0x45, 0xbf, 0x10, + 0x92, 0xcb, 0xb3, 0x8f, 0xf3, 0x23, 0x95, 0xea, 0x62, 0xd2, + 0x6b, 0x27, 0xc8, 0x86, 0x89, 0x45, 0xc5, 0x93, 0xba, 0x70, + 0xc3, 0x84, 0xad, 0xad, 0x45, 0x77, 0x1c, 0x93, 0xb0, 0x9c, + 0x27, 0x69, 0x07, 0x52, 0xd1, 0xd8, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6 ), + EXPECT ( 0xfc, 0x5f, 0x56, 0x48, 0xed, 0xc4, 0xfc, 0x30, 0x7b, 0x5c, + 0x5a, 0x53, 0xd5, 0x12, 0x89, 0xb5, 0x0e, 0x73, 0xdc, 0xec, + 0x4a, 0xa1, 0xcb, 0x47, 0xa3, 0xba, 0xd8, 0x46, 0xbb, 0x57, + 0xc3, 0xc4, 0x80, 0x49, 0x1d, 0xf5, 0x21, 0xc4, 0x66, 0x9b, + 0xff, 0xf3, 0x7a, 0x41, 0x8b, 0xaf, 0x6e, 0x9b, 0xea, 0xec, + 0x34, 0x96, 0xd0, 0xf1, 0xa6 ) ); + +/** SHA-256 Test 16 */ +HASH_DF_TEST ( test_sha256_16, sha256_algorithm, + INPUT ( 0x00, 0xfc, 0x5f, 0x56, 0x48, 0xed, 0xc4, 0xfc, 0x30, 0x7b, + 0x5c, 0x5a, 0x53, 0xd5, 0x12, 0x89, 0xb5, 0x0e, 0x73, 0xdc, + 0xec, 0x4a, 0xa1, 0xcb, 0x47, 0xa3, 0xba, 0xd8, 0x46, 0xbb, + 0x57, 0xc3, 0xc4, 0x80, 0x49, 0x1d, 0xf5, 0x21, 0xc4, 0x66, + 0x9b, 0xff, 0xf3, 0x7a, 0x41, 0x8b, 0xaf, 0x6e, 0x9b, 0xea, + 0xec, 0x34, 0x96, 0xd0, 0xf1, 0xa6 ), + EXPECT ( 0x62, 0xb0, 0x7d, 0xc3, 0x9e, 0xbd, 0xf3, 0x10, 0x87, 0xb8, + 0x5d, 0xdc, 0xec, 0xfd, 0x43, 0x35, 0x62, 0xe5, 0x3b, 0xae, + 0x9f, 0x72, 0x1c, 0x5a, 0xfa, 0xb8, 0xf1, 0xcf, 0x01, 0x61, + 0xc8, 0x8e, 0x45, 0x50, 0x3e, 0x15, 0xb2, 0x6e, 0x7b, 0x80, + 0xd5, 0x1d, 0xb0, 0xb9, 0x24, 0x52, 0x36, 0x2d, 0xc3, 0xdc, + 0x57, 0x0d, 0xfe, 0x6e, 0x17 ) ); + +/** SHA-256 Test 17 */ +HASH_DF_TEST ( test_sha256_17, sha256_algorithm, + INPUT ( 0x01, 0xa3, 0xe9, 0x4e, 0x39, 0x26, 0xfd, 0xa1, 0x69, 0xc3, + 0x03, 0xd6, 0x64, 0x38, 0x39, 0x05, 0xe0, 0xd7, 0x99, 0x62, + 0xd1, 0x65, 0x44, 0x6d, 0x63, 0xbd, 0xa6, 0x54, 0xd1, 0x32, + 0xf7, 0x2d, 0xb4, 0x71, 0x56, 0x4b, 0x45, 0x6f, 0xf2, 0xee, + 0xc8, 0x36, 0x42, 0x2a, 0xcc, 0x5a, 0x02, 0x99, 0x35, 0xa7, + 0x99, 0x29, 0x90, 0x94, 0xa1, 0xca, 0x80, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, + 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, + 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, + 0xb6, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, + 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, + 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, + 0x91, 0x92, 0x93, 0x94, 0x95, 0x96 ), + EXPECT ( 0x98, 0x75, 0xbb, 0x7c, 0x7a, 0x0b, 0x23, 0x6b, 0xf4, 0x6f, + 0x4e, 0xa6, 0x6f, 0x67, 0xc7, 0xb4, 0x4f, 0x80, 0xef, 0x70, + 0x61, 0x4b, 0xef, 0xe8, 0xb0, 0x85, 0xcc, 0xaf, 0x55, 0x89, + 0xa7, 0x6f, 0x85, 0xfd, 0x96, 0x69, 0x53, 0xe2, 0x0a, 0x55, + 0xd2, 0xf3, 0x5b, 0xa5, 0x81, 0xef, 0x51, 0x11, 0xbf, 0xbf, + 0x05, 0x65, 0x3a, 0xf7, 0xe7 ) ); + +/** SHA-256 Test 18 */ +HASH_DF_TEST ( test_sha256_18, sha256_algorithm, + INPUT ( 0x00, 0x98, 0x75, 0xbb, 0x7c, 0x7a, 0x0b, 0x23, 0x6b, 0xf4, + 0x6f, 0x4e, 0xa6, 0x6f, 0x67, 0xc7, 0xb4, 0x4f, 0x80, 0xef, + 0x70, 0x61, 0x4b, 0xef, 0xe8, 0xb0, 0x85, 0xcc, 0xaf, 0x55, + 0x89, 0xa7, 0x6f, 0x85, 0xfd, 0x96, 0x69, 0x53, 0xe2, 0x0a, + 0x55, 0xd2, 0xf3, 0x5b, 0xa5, 0x81, 0xef, 0x51, 0x11, 0xbf, + 0xbf, 0x05, 0x65, 0x3a, 0xf7, 0xe7 ), + EXPECT ( 0x12, 0x80, 0xfe, 0x1f, 0x05, 0x79, 0x8c, 0xca, 0xed, 0x5d, + 0x6d, 0xf6, 0xe7, 0xd2, 0x6f, 0x04, 0x6e, 0x53, 0x8c, 0xc5, + 0x2a, 0x6a, 0x03, 0x0d, 0xa8, 0x26, 0xb2, 0xb4, 0x79, 0x82, + 0xd6, 0xee, 0x8a, 0x68, 0x67, 0x58, 0x07, 0x06, 0x93, 0x9e, + 0xcc, 0x03, 0xfc, 0x11, 0xb0, 0x05, 0x9f, 0xe2, 0xae, 0xad, + 0xea, 0x0a, 0x46, 0x98, 0x5c ) ); + +/** SHA-256 Test 19 */ +HASH_DF_TEST ( test_sha256_19, sha256_algorithm, + INPUT ( 0x01, 0xaa, 0xf6, 0xb9, 0x9b, 0x7f, 0x84, 0xb0, 0x36, 0xe1, + 0xcc, 0xbc, 0x9d, 0x57, 0x3a, 0x36, 0xb8, 0xbd, 0xd4, 0x7c, + 0x35, 0x8b, 0xb5, 0xf3, 0xc1, 0xd6, 0xe7, 0x90, 0x3a, 0xaa, + 0x29, 0xf1, 0xc8, 0x7a, 0xe6, 0x66, 0xb8, 0x86, 0x93, 0xbe, + 0xf4, 0x6c, 0x51, 0xc2, 0x4c, 0x47, 0xbe, 0xfe, 0x4b, 0x35, + 0x75, 0x4d, 0xcb, 0xfa, 0x1e, 0x7d, 0xc0, 0xc1, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, + 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, + 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, + 0xf6, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, + 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, + 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 ), + EXPECT ( 0xb0, 0x6d, 0xbf, 0xb1, 0x4e, 0x7f, 0x4e, 0x01, 0x25, 0x62, + 0x94, 0x2f, 0xe4, 0xf2, 0xa9, 0x60, 0x17, 0x07, 0x55, 0x9d, + 0x7d, 0xd1, 0x90, 0x89, 0x8b, 0xc8, 0x06, 0x24, 0xe5, 0xc8, + 0xc1, 0xbb, 0x9b, 0x90, 0xfb, 0x2e, 0xef, 0x12, 0xed, 0x24, + 0xbe, 0xbd, 0x8d, 0xf7, 0x1e, 0xf6, 0x5c, 0x70, 0xfa, 0x4e, + 0x91, 0x86, 0x3a, 0x31, 0xbe ) ); + +/** SHA-256 Test 20 */ +HASH_DF_TEST ( test_sha256_20, sha256_algorithm, + INPUT ( 0x00, 0xb0, 0x6d, 0xbf, 0xb1, 0x4e, 0x7f, 0x4e, 0x01, 0x25, + 0x62, 0x94, 0x2f, 0xe4, 0xf2, 0xa9, 0x60, 0x17, 0x07, 0x55, + 0x9d, 0x7d, 0xd1, 0x90, 0x89, 0x8b, 0xc8, 0x06, 0x24, 0xe5, + 0xc8, 0xc1, 0xbb, 0x9b, 0x90, 0xfb, 0x2e, 0xef, 0x12, 0xed, + 0x24, 0xbe, 0xbd, 0x8d, 0xf7, 0x1e, 0xf6, 0x5c, 0x70, 0xfa, + 0x4e, 0x91, 0x86, 0x3a, 0x31, 0xbe ), + EXPECT ( 0x5c, 0x07, 0xb7, 0x9c, 0x12, 0x83, 0x1b, 0xac, 0x36, 0x52, + 0x17, 0x8b, 0x2f, 0x90, 0x7a, 0x69, 0x61, 0x98, 0x39, 0xd8, + 0xa7, 0xfa, 0xa2, 0xb6, 0x95, 0xef, 0xb3, 0x10, 0x82, 0x38, + 0x01, 0x35, 0x85, 0x19, 0x1f, 0x59, 0x9c, 0x99, 0x07, 0xc7, + 0x21, 0x92, 0xed, 0x25, 0x7e, 0x9f, 0x6c, 0xd3, 0x77, 0xdd, + 0x6b, 0xac, 0x33, 0x7c, 0x19 ) ); + /** * Report Hash_df test result * @@ -491,6 +867,27 @@ static void hash_df_test_exec ( void ) { hash_df_ok ( &test_sha1_18 ); hash_df_ok ( &test_sha1_19 ); hash_df_ok ( &test_sha1_20 ); + + hash_df_ok ( &test_sha256_1 ); + hash_df_ok ( &test_sha256_2 ); + hash_df_ok ( &test_sha256_3 ); + hash_df_ok ( &test_sha256_4 ); + hash_df_ok ( &test_sha256_5 ); + hash_df_ok ( &test_sha256_6 ); + hash_df_ok ( &test_sha256_7 ); + hash_df_ok ( &test_sha256_8 ); + hash_df_ok ( &test_sha256_9 ); + hash_df_ok ( &test_sha256_10 ); + hash_df_ok ( &test_sha256_11 ); + hash_df_ok ( &test_sha256_12 ); + hash_df_ok ( &test_sha256_13 ); + hash_df_ok ( &test_sha256_14 ); + hash_df_ok ( &test_sha256_15 ); + hash_df_ok ( &test_sha256_16 ); + hash_df_ok ( &test_sha256_17 ); + hash_df_ok ( &test_sha256_18 ); + hash_df_ok ( &test_sha256_19 ); + hash_df_ok ( &test_sha256_20 ); } /** Hash_df self-test */ From 742e43be05d7525135b81a8bcde44083aa1a0ecd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 5 Mar 2012 16:21:49 +0000 Subject: [PATCH 054/221] [rng] Use SHA-256 for Hash_df, and validate the hash function strength ANS X9.82 Part 4 (April 2011 Draft) Section 13.3.4.2 states that "When using the derivation function based on a hash function, the output length of the hash function shall meet or exceed the security strength indicated by the min_entropy parameter in the Get_entropy_input call", although this criteria is missing from the pseudocode provided in the same section. Add a test for this condition, and upgrade from SHA-1 to SHA-256 since SHA-1 has an output length of 160 bits, which is insufficient for generating the (128 * 3/2 = 192) bits required when instantiating the 128-bit strength DRBG. Signed-off-by: Michael Brown --- src/include/ipxe/entropy.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index 7208ac87..02dde2f1 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -14,7 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include #include /** @@ -100,14 +100,14 @@ int get_noise ( noise_sample_t *noise ); extern int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, size_t tmp_len ); -/** Use SHA-1 as the underlying hash algorithm for Hash_df +/** Use SHA-256 as the underlying hash algorithm for Hash_df * - * Hash_df using SHA-1 is an Approved algorithm in ANS X9.82. + * Hash_df using SHA-256 is an Approved algorithm in ANS X9.82. */ -#define entropy_hash_df_algorithm sha1_algorithm +#define entropy_hash_df_algorithm sha256_algorithm /** Underlying hash algorithm output length (in bytes) */ -#define ENTROPY_HASH_DF_OUTLEN_BYTES SHA1_DIGEST_SIZE +#define ENTROPY_HASH_DF_OUTLEN_BYTES SHA256_DIGEST_SIZE /** * Obtain entropy input @@ -166,6 +166,13 @@ get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len, linker_assert ( __builtin_constant_p ( num_samples ), num_samples_not_constant ); + /* (Unnumbered). The output length of the hash function shall + * meet or exceed the security strength indicated by the + * min_entropy parameter. + */ + linker_assert ( ( ( 8 * ENTROPY_HASH_DF_OUTLEN_BYTES ) >= + min_entropy_bits ), hash_df_algorithm_too_weak ); + /* 1. If ( min_length > max_length ), then return ( FAILURE, Null ) */ linker_assert ( ( min_len <= max_len ), min_len_greater_than_max_len ); From b9d9c3f1d5b0a92cd7c07df1c180f915ad2e6018 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 6 Mar 2012 12:58:56 +0000 Subject: [PATCH 055/221] [rng] Allow HMAC_DRBG to use multiple underlying hash algorithms Signed-off-by: Michael Brown --- src/crypto/hmac_drbg.c | 128 ++++++------ src/include/ipxe/drbg.h | 32 ++- src/include/ipxe/hmac_drbg.h | 160 ++++++++++++--- src/tests/hmac_drbg_test.c | 387 +++++++++++++++++++---------------- 4 files changed, 441 insertions(+), 266 deletions(-) diff --git a/src/crypto/hmac_drbg.c b/src/crypto/hmac_drbg.c index 9e70e4e6..3f56e1b7 100644 --- a/src/crypto/hmac_drbg.c +++ b/src/crypto/hmac_drbg.c @@ -46,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** * Update the HMAC_DRBG key * + * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v data Provided data * @v len Length of provided data @@ -57,40 +58,40 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * as used by hmac_drbg_update() */ -static void hmac_drbg_update_key ( struct hmac_drbg_state *state, +static void hmac_drbg_update_key ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *data, size_t len, const uint8_t single ) { - uint8_t context[HMAC_DRBG_CTX_SIZE]; - size_t key_len = sizeof ( state->key ); + uint8_t context[ hash->ctxsize ]; + size_t out_len = hash->digestsize; - DBGC ( state, "HMAC_DRBG %p provided data :\n", state ); + DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state ); DBGC_HDA ( state, 0, data, len ); /* Sanity checks */ + assert ( hash != NULL ); assert ( state != NULL ); assert ( ( data != NULL ) || ( len == 0 ) ); assert ( ( single == 0x00 ) || ( single == 0x01 ) ); /* K = HMAC ( K, V || single || provided_data ) */ - hmac_init ( &hmac_drbg_algorithm, context, state->key, &key_len ); - assert ( key_len == sizeof ( state->key ) ); - hmac_update ( &hmac_drbg_algorithm, context, - state->value, sizeof ( state->value ) ); - hmac_update ( &hmac_drbg_algorithm, context, - &single, sizeof ( single ) ); - hmac_update ( &hmac_drbg_algorithm, context, data, len ); - hmac_final ( &hmac_drbg_algorithm, context, state->key, &key_len, - state->key ); - assert ( key_len == sizeof ( state->key ) ); + hmac_init ( hash, context, state->key, &out_len ); + assert ( out_len == hash->digestsize ); + hmac_update ( hash, context, state->value, out_len ); + hmac_update ( hash, context, &single, sizeof ( single ) ); + hmac_update ( hash, context, data, len ); + hmac_final ( hash, context, state->key, &out_len, state->key ); + assert ( out_len == hash->digestsize ); - DBGC ( state, "HMAC_DRBG %p K = HMAC ( K, V || %#02x || " - "provided_data ) :\n", state, single ); - DBGC_HDA ( state, 0, state->key, sizeof ( state->key ) ); + DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || " + "provided_data ) :\n", hash->name, state, single ); + DBGC_HDA ( state, 0, state->key, out_len ); } /** * Update the HMAC_DRBG value * + * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v data Provided data * @v len Length of provided data @@ -102,29 +103,31 @@ static void hmac_drbg_update_key ( struct hmac_drbg_state *state, * * as used by hmac_drbg_update() and hmac_drbg_generate() */ -static void hmac_drbg_update_value ( struct hmac_drbg_state *state ) { - uint8_t context[HMAC_DRBG_CTX_SIZE]; - size_t key_len = sizeof ( state->key ); +static void hmac_drbg_update_value ( struct digest_algorithm *hash, + struct hmac_drbg_state *state ) { + uint8_t context[ hash->ctxsize ]; + size_t out_len = hash->digestsize; /* Sanity checks */ + assert ( hash != NULL ); assert ( state != NULL ); /* V = HMAC ( K, V ) */ - hmac_init ( &hmac_drbg_algorithm, context, state->key, &key_len ); - assert ( key_len == sizeof ( state->key ) ); - hmac_update ( &hmac_drbg_algorithm, context, - state->value, sizeof ( state->value ) ); - hmac_final ( &hmac_drbg_algorithm, context, state->key, &key_len, - state->value ); - assert ( key_len == sizeof ( state->key ) ); + hmac_init ( hash, context, state->key, &out_len ); + assert ( out_len == hash->digestsize ); + hmac_update ( hash, context, state->value, out_len ); + hmac_final ( hash, context, state->key, &out_len, state->value ); + assert ( out_len == hash->digestsize ); - DBGC ( state, "HMAC_DRBG %p V = HMAC ( K, V ) :\n", state ); - DBGC_HDA ( state, 0, state->value, sizeof ( state->value ) ); + DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n", + hash->name, state ); + DBGC_HDA ( state, 0, state->value, out_len ); } /** * Update HMAC_DRBG internal state * + * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v data Provided data * @v len Length of provided data @@ -135,30 +138,32 @@ static void hmac_drbg_update_value ( struct hmac_drbg_state *state ) { * The key and value are updated in-place within the HMAC_DRBG * internal state. */ -static void hmac_drbg_update ( struct hmac_drbg_state *state, +static void hmac_drbg_update ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *data, size_t len ) { - DBGC ( state, "HMAC_DRBG %p update\n", state ); + DBGC ( state, "HMAC_DRBG_%s %p update\n", hash->name, state ); /* Sanity checks */ + assert ( hash != NULL ); assert ( state != NULL ); assert ( ( data != NULL ) || ( len == 0 ) ); /* 1. K = HMAC ( K, V || 0x00 || provided_data ) */ - hmac_drbg_update_key ( state, data, len, 0x00 ); + hmac_drbg_update_key ( hash, state, data, len, 0x00 ); /* 2. V = HMAC ( K, V ) */ - hmac_drbg_update_value ( state ); + hmac_drbg_update_value ( hash, state ); /* 3. If ( provided_data = Null ), then return K and V */ if ( ! len ) return; /* 4. K = HMAC ( K, V || 0x01 || provided_data ) */ - hmac_drbg_update_key ( state, data, len, 0x01 ); + hmac_drbg_update_key ( hash, state, data, len, 0x01 ); /* 5. V = HMAC ( K, V ) */ - hmac_drbg_update_value ( state ); + hmac_drbg_update_value ( hash, state ); /* 6. Return K and V */ } @@ -166,6 +171,7 @@ static void hmac_drbg_update ( struct hmac_drbg_state *state, /** * Instantiate HMAC_DRBG * + * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state to be initialised * @v entropy Entropy input * @v entropy_len Length of entropy input @@ -184,17 +190,18 @@ static void hmac_drbg_update ( struct hmac_drbg_state *state, * The key, value and reseed counter are updated in-place within the * HMAC_DRBG internal state. */ -void hmac_drbg_instantiate ( struct hmac_drbg_state *state, +void hmac_drbg_instantiate ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *entropy, size_t entropy_len, const void *personal, size_t personal_len ){ + size_t out_len = hash->digestsize; - DBGC ( state, "HMAC_DRBG %p instantiate\n", state ); + DBGC ( state, "HMAC_DRBG_%s %p instantiate\n", hash->name, state ); /* Sanity checks */ + assert ( hash != NULL ); assert ( state != NULL ); assert ( entropy != NULL ); - assert ( ( 8 * entropy_len ) >= - ( 3 * HMAC_DRBG_SECURITY_STRENGTH / 2 ) ); assert ( ( personal != NULL ) || ( personal_len == 0 ) ); /* 1. seed_material = entropy_input || nonce || @@ -202,23 +209,24 @@ void hmac_drbg_instantiate ( struct hmac_drbg_state *state, */ /* 2. Key = 0x00 00..00 */ - memset ( state->key, 0x00, sizeof ( state->key ) ); + memset ( state->key, 0x00, out_len ); /* 3. V = 0x01 01...01 */ - memset ( state->value, 0x01, sizeof ( state->value ) ); + memset ( state->value, 0x01, out_len ); /* 4. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) * 5. reseed_counter = 1 * 6. Return V, Key and reseed_counter as the * initial_working_state */ - hmac_drbg_reseed ( state, entropy, entropy_len, + hmac_drbg_reseed ( hash, state, entropy, entropy_len, personal, personal_len ); } /** * Reseed HMAC_DRBG * + * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v entropy Entropy input * @v entropy_len Length of entropy input @@ -231,27 +239,29 @@ void hmac_drbg_instantiate ( struct hmac_drbg_state *state, * The key, value and reseed counter are updated in-place within the * HMAC_DRBG internal state. */ -void hmac_drbg_reseed ( struct hmac_drbg_state *state, +void hmac_drbg_reseed ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *entropy, size_t entropy_len, const void *additional, size_t additional_len ) { uint8_t seed_material[ entropy_len + additional_len ]; - DBGC ( state, "HMAC_DRBG %p (re)seed\n", state ); + DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state ); /* Sanity checks */ + assert ( hash != NULL ); assert ( state != NULL ); assert ( entropy != NULL ); - assert ( ( 8 * entropy_len ) >= HMAC_DRBG_SECURITY_STRENGTH ); assert ( ( additional != NULL ) || ( additional_len == 0 ) ); /* 1. seed_material = entropy_input || additional_input */ memcpy ( seed_material, entropy, entropy_len ); memcpy ( ( seed_material + entropy_len ), additional, additional_len ); - DBGC ( state, "HMAC_DRBG %p seed material :\n", state ); + DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state ); DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) ); /* 2. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */ - hmac_drbg_update ( state, seed_material, sizeof ( seed_material ) ); + hmac_drbg_update ( hash, state, seed_material, + sizeof ( seed_material ) ); /* 3. reseed_counter = 1 */ state->reseed_counter = 1; @@ -262,6 +272,7 @@ void hmac_drbg_reseed ( struct hmac_drbg_state *state, /** * Generate pseudorandom bits using HMAC_DRBG * + * @v hash Underlying hash algorithm * @v state HMAC_DRBG internal state * @v additional Additional input * @v additional_len Length of additional input @@ -279,16 +290,19 @@ void hmac_drbg_reseed ( struct hmac_drbg_state *state, * * Note that the only permitted error is "reseed required". */ -int hmac_drbg_generate ( struct hmac_drbg_state *state, +int hmac_drbg_generate ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *additional, size_t additional_len, void *data, size_t len ) { + size_t out_len = hash->digestsize; void *orig_data = data; size_t orig_len = len; size_t frag_len; - DBGC ( state, "HMAC_DRBG %p generate\n", state ); + DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state ); /* Sanity checks */ + assert ( hash != NULL ); assert ( state != NULL ); assert ( data != NULL ); assert ( ( additional != NULL ) || ( additional_len == 0 ) ); @@ -297,8 +311,8 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state, * indication that a reseed is required */ if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) { - DBGC ( state, "HMAC_DRBG %p reseed interval exceeded\n", - state ); + DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n", + hash->name, state ); return -ESTALE; } @@ -306,7 +320,7 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state, * ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */ if ( additional_len ) - hmac_drbg_update ( state, additional, additional_len ); + hmac_drbg_update ( hash, state, additional, additional_len ); /* 3. temp = Null * 4. While ( len ( temp ) < requested_number_of_bits ) do: @@ -314,27 +328,27 @@ int hmac_drbg_generate ( struct hmac_drbg_state *state, while ( len ) { /* 4.1 V = HMAC ( Key, V ) */ - hmac_drbg_update_value ( state ); + hmac_drbg_update_value ( hash, state ); /* 4.2. temp = temp || V * 5. returned_bits = Leftmost requested_number_of_bits * of temp */ frag_len = len; - if ( frag_len > sizeof ( state->value ) ) - frag_len = sizeof ( state->value ); + if ( frag_len > out_len ) + frag_len = out_len; memcpy ( data, state->value, frag_len ); data += frag_len; len -= frag_len; } /* 6. ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */ - hmac_drbg_update ( state, additional, additional_len ); + hmac_drbg_update ( hash, state, additional, additional_len ); /* 7. reseed_counter = reseed_counter + 1 */ state->reseed_counter++; - DBGC ( state, "HMAC_DRBG %p generated :\n", state ); + DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state ); DBGC_HDA ( state, 0, orig_data, orig_len ); /* 8. Return SUCCESS, returned_bits, and the new values of diff --git a/src/include/ipxe/drbg.h b/src/include/ipxe/drbg.h index 3cf4584a..139f03c5 100644 --- a/src/include/ipxe/drbg.h +++ b/src/include/ipxe/drbg.h @@ -10,16 +10,29 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include -/** Maximum security strength */ -#define DRBG_MAX_SECURITY_STRENGTH HMAC_DRBG_MAX_SECURITY_STRENGTH +/** Choose HMAC_DRBG using SHA-1 + * + * HMAC_DRBG using SHA-1 is an Approved algorithm in ANS X9.82. + */ +#define HMAC_DRBG_ALGORITHM HMAC_DRBG_SHA1 -/** Security strength */ -#define DRBG_SECURITY_STRENGTH HMAC_DRBG_SECURITY_STRENGTH +/** Maximum security strength */ +#define DRBG_MAX_SECURITY_STRENGTH \ + HMAC_DRBG_MAX_SECURITY_STRENGTH ( HMAC_DRBG_ALGORITHM ) + +/** Security strength + * + * We choose to operate at the maximum security strength supported by + * the algorithm. + */ +#define DRBG_SECURITY_STRENGTH DRBG_MAX_SECURITY_STRENGTH /** Minimum entropy input length */ -#define DRBG_MIN_ENTROPY_LEN_BYTES HMAC_DRBG_MIN_ENTROPY_LEN_BYTES +#define DRBG_MIN_ENTROPY_LEN_BYTES \ + HMAC_DRBG_MIN_ENTROPY_LEN_BYTES ( DRBG_SECURITY_STRENGTH ) /** Maximum entropy input length */ #define DRBG_MAX_ENTROPY_LEN_BYTES HMAC_DRBG_MAX_ENTROPY_LEN_BYTES @@ -60,7 +73,8 @@ static inline void drbg_instantiate_algorithm ( struct drbg_state *state, size_t entropy_len, const void *personal, size_t personal_len ) { - hmac_drbg_instantiate ( &state->internal, entropy, entropy_len, + hmac_drbg_instantiate ( HMAC_DRBG_HASH ( HMAC_DRBG_ALGORITHM ), + &state->internal, entropy, entropy_len, personal, personal_len ); } @@ -81,7 +95,8 @@ static inline void drbg_reseed_algorithm ( struct drbg_state *state, size_t entropy_len, const void *additional, size_t additional_len ) { - hmac_drbg_reseed ( &state->internal, entropy, entropy_len, + hmac_drbg_reseed ( HMAC_DRBG_HASH ( HMAC_DRBG_ALGORITHM ), + &state->internal, entropy, entropy_len, additional, additional_len ); } @@ -104,7 +119,8 @@ static inline int drbg_generate_algorithm ( struct drbg_state *state, const void *additional, size_t additional_len, void *data, size_t len ) { - return hmac_drbg_generate ( &state->internal, additional, + return hmac_drbg_generate ( HMAC_DRBG_HASH ( HMAC_DRBG_ALGORITHM ), + &state->internal, additional, additional_len, data, len ); } diff --git a/src/include/ipxe/hmac_drbg.h b/src/include/ipxe/hmac_drbg.h index b3dfe368..8dfd2924 100644 --- a/src/include/ipxe/hmac_drbg.h +++ b/src/include/ipxe/hmac_drbg.h @@ -10,48 +10,148 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include +#include -/** Use SHA-1 as the underlying hash algorithm +/** Declare an HMAC_DRBG algorithm * - * HMAC_DRBG using SHA-1 is an Approved algorithm in ANS X9.82. + * @v hash Underlying hash algorithm + * @v max_security_strength Maxmimum security strength + * @v out_len_bits Output block length, in bits + * @ret hmac_drbg HMAC_DRBG algorithm */ -#define hmac_drbg_algorithm sha1_algorithm +#define HMAC_DRBG( hash, max_security_strength, out_len_bits ) \ + ( hash, max_security_strength, out_len_bits ) + +/** HMAC_DRBG using SHA-1 + * + * The maximum security strength of HMAC_DRBG using SHA-1 is 128 bits + * according to the list of maximum security strengths documented in + * NIST SP 800-57 Part 1 Section 5.6.1 Table 3. + * + * The output block length of HMAC_DRBG using SHA-1 is 160 bits + * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP + * 800-90 Section 10.1 Table 2). + */ +#define HMAC_DRBG_SHA1 HMAC_DRBG ( &sha1_algorithm, 128, 160 ) + +/** HMAC_DRBG using SHA-224 + * + * The maximum security strength of HMAC_DRBG using SHA-224 is 192 + * bits according to the list of maximum security strengths documented + * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3. + * + * The output block length of HMAC_DRBG using SHA-224 is 224 bits + * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP + * 800-90 Section 10.1 Table 2). + */ +#define HMAC_DRBG_SHA224 HMAC_DRBG ( &sha224_algorithm, 192, 224 ) + +/** HMAC_DRBG using SHA-256 + * + * The maximum security strength of HMAC_DRBG using SHA-256 is 256 + * bits according to the list of maximum security strengths documented + * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3. + * + * The output block length of HMAC_DRBG using SHA-256 is 256 bits + * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP + * 800-90 Section 10.1 Table 2). + */ +#define HMAC_DRBG_SHA256 HMAC_DRBG ( &sha256_algorithm, 256, 256 ) + +/** HMAC_DRBG using SHA-384 + * + * The maximum security strength of HMAC_DRBG using SHA-384 is 256 + * bits according to the list of maximum security strengths documented + * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3. + * + * The output block length of HMAC_DRBG using SHA-384 is 384 bits + * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP + * 800-90 Section 10.1 Table 2). + */ +#define HMAC_DRBG_SHA384 HMAC_DRBG ( &sha384_algorithm, 256, 384 ) + +/** HMAC_DRBG using SHA-512 + * + * The maximum security strength of HMAC_DRBG using SHA-512 is 256 + * bits according to the list of maximum security strengths documented + * in NIST SP 800-57 Part 1 Section 5.6.1 Table 3. + * + * The output block length of HMAC_DRBG using SHA-512 is 512 bits + * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP + * 800-90 Section 10.1 Table 2). + */ +#define HMAC_DRBG_SHA512 HMAC_DRBG ( &sha512_algorithm, 256, 512 ) + +/** Underlying hash algorithm + * + * @v hmac_drbg HMAC_DRBG algorithm + * @ret hash Underlying hash algorithm + */ +#define HMAC_DRBG_HASH( hmac_drbg ) \ + HMAC_DRBG_EXTRACT_HASH hmac_drbg +#define HMAC_DRBG_EXTRACT_HASH( hash, max_security_strength, out_len_bits ) \ + hash /** Maximum security strength * - * The maximum security strength of HMAC_DRBG using SHA-1 is 128 bits - * (according to the list of maximum security strengths documented in - * NIST SP 800-57 Part 1 Section 5.6.1 Table 3). + * @v hmac_drbg HMAC_DRBG algorithm + * @ret max_security_strength Maxmimum security strength */ -#define HMAC_DRBG_MAX_SECURITY_STRENGTH 128 +#define HMAC_DRBG_MAX_SECURITY_STRENGTH( hmac_drbg ) \ + HMAC_DRBG_EXTRACT_MAX_SECURITY_STRENGTH hmac_drbg +#define HMAC_DRBG_EXTRACT_MAX_SECURITY_STRENGTH( hash, max_security_strength, \ + out_len_bits ) \ + max_security_strength -/** Security strength +/** Output block length, in bits * - * For the sake of implementation simplicity, only a single security - * strength is supported, which is the maximum security strength - * supported by the algorithm. + * @v hmac_drbg HMAC_DRBG algorithm + * @ret out_len_bits Output block length, in bits */ -#define HMAC_DRBG_SECURITY_STRENGTH HMAC_DRBG_MAX_SECURITY_STRENGTH +#define HMAC_DRBG_OUTLEN_BITS( hmac_drbg ) \ + HMAC_DRBG_EXTRACT_OUTLEN_BITS hmac_drbg +#define HMAC_DRBG_EXTRACT_OUTLEN_BITS( hash, max_security_strength, \ + out_len_bits ) \ + out_len_bits -/** Underlying hash algorithm output length (in bytes) */ -#define HMAC_DRBG_OUTLEN_BYTES SHA1_DIGEST_SIZE +/** Output block length, in bytes + * + * @v hmac_drbg HMAC_DRBG algorithm + * @ret out_len_bytes Output block length, in bytes + */ +#define HMAC_DRBG_OUTLEN_BYTES( hmac_drbg ) \ + ( HMAC_DRBG_OUTLEN_BITS ( hmac_drbg ) / 8 ) + +/** Maximum output block length, in bytes + * + * The maximum output block length for HMAC_DRBG is 512 bits for + * SHA-512 according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 + * (NIST SP 800-90 Section 10.1 Table 2). + */ +#define HMAC_DRBG_MAX_OUTLEN_BYTES HMAC_DRBG_OUTLEN_BYTES ( HMAC_DRBG_SHA512 ) /** Required minimum entropy for instantiate and reseed + * + * @v security_strength Security strength + * @ret min_entropy Required minimum entropy * * The minimum required entropy for HMAC_DRBG is equal to the security * strength according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 * (NIST SP 800-90 Section 10.1 Table 2). */ -#define HMAC_DRBG_MIN_ENTROPY_BYTES ( HMAC_DRBG_SECURITY_STRENGTH / 8 ) +#define HMAC_DRBG_MIN_ENTROPY( security_strength ) (security_strength) /** Minimum entropy input length + * + * @v security_strength Security strength + * @ret min_entropy_len_bytes Required minimum entropy length (in bytes) * * The minimum entropy input length for HMAC_DRBG is equal to the * security strength according to ANS X9.82 Part 3-2007 Section 10.2.1 * Table 2 (NIST SP 800-90 Section 10.1 Table 2). */ -#define HMAC_DRBG_MIN_ENTROPY_LEN_BYTES ( HMAC_DRBG_SECURITY_STRENGTH / 8 ) +#define HMAC_DRBG_MIN_ENTROPY_LEN_BYTES( security_strength ) \ + ( (security_strength) / 8 ) /** Maximum entropy input length * @@ -95,19 +195,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Reseed interval * - * The maximum permitted reseed interval for HMAC_DRBG using SHA-1 is - * 2^48 according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 - * (NIST SP 800-90 Section 10.1 Table 2). However, the sample - * implementation given in ANS X9.82 Part 3-2007 Annex E.2.1 (NIST SP - * 800-90 Appendix F.2) shows a reseed interval of 10000. + * The maximum permitted reseed interval for HMAC_DRBG is 2^48 + * according to ANS X9.82 Part 3-2007 Section 10.2.1 Table 2 (NIST SP + * 800-90 Section 10.1 Table 2). However, the sample implementation + * given in ANS X9.82 Part 3-2007 Annex E.2.1 (NIST SP 800-90 Appendix + * F.2) shows a reseed interval of 10000. * * We choose a very conservative reseed interval. */ #define HMAC_DRBG_RESEED_INTERVAL 1024 -/** Underlying hash algorithm context size (in bytes) */ -#define HMAC_DRBG_CTX_SIZE SHA1_CTX_SIZE - /** * HMAC_DRBG internal state * @@ -124,13 +221,13 @@ struct hmac_drbg_state { * "The value V of outlen bits, which is updated each time * another outlen bits of output are produced" */ - uint8_t value[HMAC_DRBG_OUTLEN_BYTES]; + uint8_t value[HMAC_DRBG_MAX_OUTLEN_BYTES]; /** Current key * * "The outlen-bit Key, which is updated at least once each * time that the DRBG mechanism generates pseudorandom bits." */ - uint8_t key[HMAC_DRBG_OUTLEN_BYTES]; + uint8_t key[HMAC_DRBG_MAX_OUTLEN_BYTES]; /** Reseed counter * * "A counter (reseed_counter) that indicates the number of @@ -140,13 +237,16 @@ struct hmac_drbg_state { unsigned int reseed_counter; }; -extern void hmac_drbg_instantiate ( struct hmac_drbg_state *state, +extern void hmac_drbg_instantiate ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *entropy, size_t entropy_len, const void *personal, size_t personal_len ); -extern void hmac_drbg_reseed ( struct hmac_drbg_state *state, +extern void hmac_drbg_reseed ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *entropy, size_t entropy_len, const void *additional, size_t additional_len ); -extern int hmac_drbg_generate ( struct hmac_drbg_state *state, +extern int hmac_drbg_generate ( struct digest_algorithm *hash, + struct hmac_drbg_state *state, const void *additional, size_t additional_len, void *data, size_t len ); diff --git a/src/tests/hmac_drbg_test.c b/src/tests/hmac_drbg_test.c index ad5584f1..2e93e5e8 100644 --- a/src/tests/hmac_drbg_test.c +++ b/src/tests/hmac_drbg_test.c @@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** Define inline expected data */ @@ -42,10 +43,18 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** An HMAC_DRBG instantiation test */ struct hmac_drbg_test_instantiate { - /** Entropy (including nonce) */ + /** Underlying hash algorithm */ + struct digest_algorithm *hash; + /** Output block length */ + size_t out_len; + /** Entropy */ const void *entropy; - /** Length of entropy (including nonce) */ + /** Length of entropy */ size_t entropy_len; + /** Nonce */ + const void *nonce; + /** Length of nonce */ + size_t nonce_len; /** Personalisation string */ const void *personal; /** Length of personalisation string */ @@ -64,19 +73,26 @@ struct hmac_drbg_test_instantiate { * Define an HMAC_DRBG instantiation test * * @v name Test name - * @v entropy_array Entropy input (including nonce) + * @v hmac_drbg HMAC_DRBG algorithm + * @v entropy_array Entropy input + * @v nonce_array Nonce * @v personal_array Personalisation string * @v key Expected key * @v value Expected value * @ret test Instantiation test */ -#define HMAC_DRBG_TEST_INSTANTIATE( name, entropy_array, \ - personal_array, key, value ) \ +#define HMAC_DRBG_TEST_INSTANTIATE( name, hmac_drbg, entropy_array, \ + nonce_array, personal_array, \ + key, value ) \ static const uint8_t name ## _key [] = key; \ static const uint8_t name ## _value [] = value; \ static const struct hmac_drbg_test_instantiate name = { \ + .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ + .out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ), \ .entropy = entropy_array, \ .entropy_len = sizeof ( entropy_array ), \ + .nonce = nonce_array, \ + .nonce_len = sizeof ( nonce_array ), \ .personal = personal_array, \ .personal_len = sizeof ( personal_array ), \ .expected_key = name ## _key, \ @@ -92,19 +108,33 @@ struct hmac_drbg_test_instantiate { * @v test Instantiation test */ #define instantiate_ok( state, test ) do { \ - assert ( (test)->expected_key_len == HMAC_DRBG_OUTLEN_BYTES ); \ - assert ( (test)->expected_value_len == HMAC_DRBG_OUTLEN_BYTES ); \ - hmac_drbg_instantiate ( (state), (test)->entropy, \ - (test)->entropy_len, (test)->personal, \ + struct { \ + uint8_t entropy[(test)->entropy_len]; \ + uint8_t nonce[(test)->nonce_len]; \ + } __attribute__ (( packed )) entropy_nonce; \ + \ + assert ( (test)->expected_key_len == (test)->out_len ); \ + assert ( (test)->expected_value_len == (test)->out_len ); \ + memcpy ( entropy_nonce.entropy, (test)->entropy, \ + sizeof ( entropy_nonce.entropy ) ); \ + memcpy ( entropy_nonce.nonce, (test)->nonce, \ + sizeof ( entropy_nonce.nonce ) ); \ + hmac_drbg_instantiate ( (test)->hash, (state), &entropy_nonce, \ + sizeof ( entropy_nonce ), \ + (test)->personal, \ (test)->personal_len ); \ ok ( memcmp ( (state)->key, (test)->expected_key, \ - sizeof ( (state)->key ) ) == 0 ); \ + (test)->expected_key_len ) == 0 ); \ ok ( memcmp ( (state)->value, (test)->expected_value, \ - sizeof ( (state)->value ) ) == 0 ); \ + (test)->expected_value_len ) == 0 ); \ } while ( 0 ) /** An HMAC_DRBG reseed test */ struct hmac_drbg_test_reseed { + /** Underlying hash algorithm */ + struct digest_algorithm *hash; + /** Output block length */ + size_t out_len; /** Entropy */ const void *entropy; /** Length of entropy */ @@ -127,17 +157,20 @@ struct hmac_drbg_test_reseed { * Define an HMAC_DRBG reseed test * * @v name Test name + * @v hmac_drbg HMAC_DRBG algorithm * @v entropy_array Entropy input * @v additional_array Additional input * @v key Expected key * @v value Expected value * @ret test Reseed test */ -#define HMAC_DRBG_TEST_RESEED( name, entropy_array, additional_array, \ - key, value ) \ +#define HMAC_DRBG_TEST_RESEED( name, hmac_drbg, entropy_array, \ + additional_array, key, value ) \ static const uint8_t name ## _key [] = key; \ static const uint8_t name ## _value [] = value; \ static const struct hmac_drbg_test_reseed name = { \ + .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ + .out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ), \ .entropy = entropy_array, \ .entropy_len = sizeof ( entropy_array ), \ .additional = additional_array, \ @@ -155,19 +188,23 @@ struct hmac_drbg_test_reseed { * @v test Reseed test */ #define reseed_ok( state, test ) do { \ - assert ( (test)->expected_key_len == HMAC_DRBG_OUTLEN_BYTES ); \ - assert ( (test)->expected_value_len == HMAC_DRBG_OUTLEN_BYTES ); \ - hmac_drbg_reseed ( (state), (test)->entropy, \ + assert ( (test)->expected_key_len == (test)->out_len ); \ + assert ( (test)->expected_value_len == (test)->out_len ); \ + hmac_drbg_reseed ( (test)->hash, (state), (test)->entropy, \ (test)->entropy_len, (test)->additional, \ (test)->additional_len ); \ ok ( memcmp ( (state)->key, (test)->expected_key, \ - sizeof ( (state)->key ) ) == 0 ); \ + (test)->expected_key_len ) == 0 ); \ ok ( memcmp ( (state)->value, (test)->expected_value, \ - sizeof ( (state)->value ) ) == 0 ); \ + (test)->expected_value_len ) == 0 ); \ } while ( 0 ) /** An HMAC_DRBG generation test */ struct hmac_drbg_test_generate { + /** Underlying hash algorithm */ + struct digest_algorithm *hash; + /** Output block length */ + size_t out_len; /** Additional input */ const void *additional; /** Length of additional_input */ @@ -183,25 +220,28 @@ struct hmac_drbg_test_generate { /** Expected pseudorandom data */ const void *expected_data; /** Length of data */ - size_t len; + size_t expected_data_len; }; /** * Define an HMAC_DRBG generation test * * @v name Test name + * @v hmac_drbg HMAC_DRBG algorithm * @v additional_array Additional input * @v key Expected key * @v value Expected value * @v data Expected pseudorandom data * @ret test Generation test */ -#define HMAC_DRBG_TEST_GENERATE( name, additional_array, key, value, \ - data ) \ +#define HMAC_DRBG_TEST_GENERATE( name, hmac_drbg, additional_array, \ + key, value, data ) \ static const uint8_t name ## _key [] = key; \ static const uint8_t name ## _value [] = value; \ static const uint8_t name ## _data [] = data; \ static const struct hmac_drbg_test_generate name = { \ + .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ + .out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ), \ .additional = additional_array, \ .additional_len = sizeof ( additional_array ), \ .expected_key = name ## _key, \ @@ -209,7 +249,7 @@ struct hmac_drbg_test_generate { .expected_value = name ## _value, \ .expected_value_len = sizeof ( name ## _value ), \ .expected_data = name ## _data, \ - .len = sizeof ( name ## _data ), \ + .expected_data_len = sizeof ( name ## _data ), \ } /** @@ -219,25 +259,28 @@ struct hmac_drbg_test_generate { * @v test Generation test */ #define generate_ok( state, test ) do { \ - uint8_t data[ (test)->len ]; \ + uint8_t data[ (test)->expected_data_len ]; \ int rc; \ \ - assert ( (test)->expected_key_len == HMAC_DRBG_OUTLEN_BYTES ); \ - assert ( (test)->expected_value_len == HMAC_DRBG_OUTLEN_BYTES );\ - rc = hmac_drbg_generate ( (state), (test)->additional, \ - (test)->additional_len, data, \ - sizeof ( data ) ); \ + assert ( (test)->expected_key_len == (test)->out_len ); \ + assert ( (test)->expected_value_len == (test)->out_len ); \ + rc = hmac_drbg_generate ( (test)->hash, (state), \ + (test)->additional, \ + (test)->additional_len, \ + data, sizeof ( data ) ); \ ok ( rc == 0 ); \ ok ( memcmp ( (state)->key, (test)->expected_key, \ - sizeof ( (state)->key ) ) == 0 ); \ + (test)->expected_key_len ) == 0 ); \ ok ( memcmp ( (state)->value, (test)->expected_value, \ - sizeof ( (state)->value ) ) == 0 ); \ + (test)->expected_value_len ) == 0 ); \ ok ( memcmp ( data, (test)->expected_data, \ - sizeof ( data ) ) == 0 ); \ + (test)->expected_data_len ) == 0 ); \ } while ( 0 ) /** An HMAC_DRBG generation failure test */ struct hmac_drbg_test_generate_fail { + /** Underlying hash algorithm */ + struct digest_algorithm *hash; /** Additional input */ const void *additional; /** Length of additional_input */ @@ -250,11 +293,14 @@ struct hmac_drbg_test_generate_fail { * Define an HMAC_DRBG generation failure test * * @v name Test name + * @v hmac_drbg HMAC_DRBG algorithm * @v additional_array Additional input * @ret test Generation failure test */ -#define HMAC_DRBG_TEST_GENERATE_FAIL( name, additional_array, len ) \ +#define HMAC_DRBG_TEST_GENERATE_FAIL( name, hmac_drbg, \ + additional_array, len ) \ static const struct hmac_drbg_test_generate_fail name = { \ + .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ .additional = additional_array, \ .additional_len = sizeof ( additional_array ), \ .requested_len = len, \ @@ -270,25 +316,24 @@ struct hmac_drbg_test_generate_fail { uint8_t data[ (test)->requested_len ]; \ int rc; \ \ - rc = hmac_drbg_generate ( (state), (test)->additional, \ + rc = hmac_drbg_generate ( (test)->hash, (state), \ + (test)->additional, \ (test)->additional_len, data, \ sizeof ( data ) ); \ ok ( rc != 0 ); \ } while ( 0 ) -/** "EntropyInput" and "Nonce" - * - * These are pre-concatenated since our implementation expects to - * receive the nonce in the form of additional entropy. - */ +/** "EntropyInput" */ static const uint8_t entropy_input[] = { - /* "EntropyInput" */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - /* "Nonce" */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36 +}; + +/** "Nonce" for SHA-1 */ +static const uint8_t nonce_sha1[] = { 0x20, 0x21, 0x22, 0x23, 0x24 }; @@ -343,16 +388,16 @@ static const uint8_t additional_input_2[] = { 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6 }; -/** Test 1 : Instantiation */ -HMAC_DRBG_TEST_INSTANTIATE ( instantiate_1, - entropy_input, personalisation_string_empty, +/** SHA-1 Test 1 : Instantiation */ +HMAC_DRBG_TEST_INSTANTIATE ( sha1_instantiate_1, HMAC_DRBG_SHA1, + entropy_input, nonce_sha1, personalisation_string_empty, EXPECT ( 0xab, 0x16, 0x0d, 0xd2, 0x1c, 0x30, 0x98, 0x0c, 0xa3, 0xca, 0x5a, 0x9c, 0x77, 0xb7, 0xbd, 0xf0, 0x50, 0xe6, 0x4e, 0xe9 ), EXPECT ( 0x61, 0x44, 0x99, 0xea, 0x98, 0x0c, 0xfb, 0x3d, 0xaa, 0x2c, 0xa8, 0x6d, 0x65, 0xa4, 0x6b, 0xf4, 0x48, 0x8d, 0x8c, 0xc5 ) ); -/** Test 1.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_1_1, +/** SHA-1 Test 1.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_1_1, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x7b, 0xb1, 0x80, 0x28, 0xe0, 0x1d, 0x03, 0x42, 0xdf, 0x4f, 0x54, 0xda, 0x51, 0x22, 0xfa, 0x5f, 0x2c, 0x3a, 0x05, 0xe4 ), @@ -363,8 +408,8 @@ HMAC_DRBG_TEST_GENERATE ( generate_1_1, 0x8c, 0x0b, 0x22, 0xcd, 0x06, 0x30, 0xbf, 0xb0, 0x12, 0x7f, 0xb5, 0x40, 0x8c, 0x8e, 0xfc, 0x17, 0xa9, 0x29, 0x89, 0x6e ) ); -/** Test 1.2 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_1_2, +/** SHA-1 Test 1.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_1_2, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x3d, 0x4d, 0x73, 0x77, 0xe9, 0x17, 0x2a, 0xaf, 0xa7, 0x76, 0xb0, 0xdd, 0xcb, 0x89, 0x42, 0x00, 0x4a, 0x44, 0xb7, 0xfd ), @@ -375,11 +420,11 @@ HMAC_DRBG_TEST_GENERATE ( generate_1_2, 0x9c, 0xe3, 0x67, 0xd0, 0x3a, 0xea, 0xde, 0x37, 0x82, 0x7f, 0xa8, 0xe9, 0xcb, 0x6a, 0x08, 0x19, 0x61, 0x15, 0xd9, 0x48 ) ); -/** Test 2 : Instantiation */ -#define instantiate_2 instantiate_1 +/** SHA-1 Test 2 : Instantiation */ +#define sha1_instantiate_2 sha1_instantiate_1 -/** Test 2.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_2_1, +/** SHA-1 Test 2.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_2_1, HMAC_DRBG_SHA1, additional_input_1, EXPECT ( 0x3a, 0x06, 0x2e, 0x6b, 0x79, 0xfe, 0x70, 0xdb, 0xff, 0xeb, 0x3a, 0x2b, 0x6b, 0xe8, 0x03, 0x23, 0xf7, 0xd6, 0x74, 0xc5 ), @@ -390,8 +435,8 @@ HMAC_DRBG_TEST_GENERATE ( generate_2_1, 0x9a, 0xd0, 0xbb, 0x26, 0xfa, 0xc0, 0x49, 0x7b, 0x5c, 0x57, 0xe1, 0x61, 0xe3, 0x66, 0x81, 0xbc, 0xc9, 0x30, 0xce, 0x80 ) ); -/** Test 2.2 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_2_2, +/** SHA-1 Test 2.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_2_2, HMAC_DRBG_SHA1, additional_input_2, EXPECT ( 0x8a, 0xd7, 0xe3, 0x47, 0x72, 0xb5, 0xfc, 0x7c, 0x3b, 0x3b, 0x27, 0x62, 0x4f, 0x0b, 0x91, 0x77, 0x6a, 0x8a, 0x71, 0x12 ), @@ -402,16 +447,16 @@ HMAC_DRBG_TEST_GENERATE ( generate_2_2, 0xb9, 0xc3, 0x7b, 0x7f, 0xe8, 0x1b, 0xa9, 0x40, 0x45, 0xa1, 0x4a, 0x7c, 0xb5, 0x14, 0xb4, 0x46, 0x66, 0x6e, 0xa5, 0xa7 ) ); -/** Test 3 : Instantiation */ -HMAC_DRBG_TEST_INSTANTIATE ( instantiate_3, - entropy_input, personalisation_string, +/** SHA-1 Test 3 : Instantiation */ +HMAC_DRBG_TEST_INSTANTIATE ( sha1_instantiate_3, HMAC_DRBG_SHA1, + entropy_input, nonce_sha1, personalisation_string, EXPECT ( 0xb7, 0xd9, 0x66, 0xd7, 0x0d, 0x4e, 0x27, 0xa7, 0xfa, 0x83, 0x8f, 0x7d, 0x61, 0x12, 0x6c, 0x0e, 0xdc, 0x84, 0x76, 0x1c ), EXPECT ( 0xda, 0xb2, 0xa7, 0x18, 0x83, 0xf1, 0x00, 0x5c, 0x5d, 0xd0, 0x39, 0x32, 0x4d, 0x3c, 0x36, 0x4d, 0x6e, 0x18, 0xf9, 0x54 ) ); -/** Test 3.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_3_1, +/** SHA-1 Test 3.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_3_1, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x87, 0xd3, 0x82, 0x8b, 0xe0, 0x3a, 0x80, 0x7d, 0xd3, 0x40, 0x29, 0x41, 0xbe, 0xd6, 0xde, 0x98, 0x6e, 0xe7, 0xa2, 0x86 ), @@ -422,8 +467,8 @@ HMAC_DRBG_TEST_GENERATE ( generate_3_1, 0x9b, 0xd0, 0x60, 0x20, 0x8e, 0xea, 0x7d, 0x71, 0xf9, 0xd1, 0x23, 0xdf, 0x47, 0xb3, 0xce, 0x06, 0x9d, 0x98, 0xed, 0xe6 ) ); -/** Test 3.2 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_3_2, +/** SHA-1 Test 3.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_3_2, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x26, 0xab, 0xbf, 0x54, 0xb2, 0x8b, 0x93, 0xff, 0x90, 0x08, 0x67, 0x0e, 0xbf, 0xee, 0x86, 0xcd, 0xd7, 0x22, 0x8e, 0xd5 ), @@ -434,11 +479,11 @@ HMAC_DRBG_TEST_GENERATE ( generate_3_2, 0x63, 0x97, 0x65, 0x47, 0x2b, 0x71, 0xac, 0xeb, 0xe2, 0xea, 0x8b, 0x1b, 0x6b, 0x49, 0x62, 0x9c, 0xb6, 0x73, 0x17, 0xe0 ) ); -/** Test 4 : Instantiation */ -#define instantiate_4 instantiate_3 +/** SHA-1 Test 4 : Instantiation */ +#define sha1_instantiate_4 sha1_instantiate_3 -/** Test 4.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_4_1, +/** SHA-1 Test 4.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_4_1, HMAC_DRBG_SHA1, additional_input_1, EXPECT ( 0x17, 0xa5, 0xd7, 0x9f, 0x07, 0x67, 0x87, 0x6f, 0x3a, 0x45, 0xe0, 0xc9, 0xc3, 0x3e, 0xc8, 0x8b, 0x03, 0xce, 0xea, 0x13 ), @@ -449,8 +494,8 @@ HMAC_DRBG_TEST_GENERATE ( generate_4_1, 0x6d, 0xfc, 0x30, 0x2e, 0xad, 0x4c, 0xe3, 0xf5, 0x54, 0xc7, 0x9b, 0x0d, 0x44, 0x23, 0x9e, 0xba, 0x56, 0xa7, 0xea, 0x2d ) ); -/** Test 4.2 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_4_2, +/** SHA-1 Test 4.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_4_2, HMAC_DRBG_SHA1, additional_input_2, EXPECT ( 0x07, 0x9b, 0x57, 0xd9, 0x40, 0x6e, 0x11, 0xc2, 0xf8, 0x7c, 0x8c, 0x82, 0x8c, 0x8c, 0x6f, 0xa7, 0x6e, 0x40, 0xea, 0x01 ), @@ -461,23 +506,23 @@ HMAC_DRBG_TEST_GENERATE ( generate_4_2, 0xdc, 0x91, 0x21, 0x5d, 0x44, 0xb1, 0x07, 0xb4, 0xd5, 0xa7, 0x79, 0x01, 0x59, 0x25, 0x09, 0x76, 0x52, 0x80, 0xf9, 0x69 ) ); -/** Test 5 : Instantiation */ -#define instantiate_5 instantiate_1 +/** SHA-1 Test 5 : Instantiation */ +#define sha1_instantiate_5 sha1_instantiate_1 -/** Test 5.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_5_1, +/** SHA-1 Test 5.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_5_1, HMAC_DRBG_SHA1, additional_input_empty, ( 320 / 8 ) ); -/** Test 5.2 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_5_2, +/** SHA-1 Test 5.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_5_2, HMAC_DRBG_SHA1, entropy_input_1, additional_input_empty, EXPECT ( 0xcd, 0x4c, 0xab, 0x38, 0xc8, 0xad, 0x65, 0x71, 0x22, 0xbf, 0x5d, 0x3d, 0x00, 0xd0, 0xac, 0x9b, 0x13, 0xd6, 0x29, 0xbb ), EXPECT ( 0xf6, 0x60, 0xe2, 0x3e, 0x91, 0x00, 0x6b, 0x62, 0xc6, 0x54, 0x3a, 0xb1, 0x34, 0x4d, 0x23, 0xa3, 0x1a, 0xb4, 0xcf, 0x2c ) ); -/** Test 5.3 : Retried first call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_5_3, +/** SHA-1 Test 5.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_5_3, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x58, 0x7f, 0xd8, 0x21, 0xef, 0x6c, 0x9d, 0xa4, 0xa8, 0x3c, 0x19, 0x21, 0x1f, 0x10, 0x56, 0xca, 0xcd, 0x23, 0xfc, 0x1a ), @@ -488,20 +533,20 @@ HMAC_DRBG_TEST_GENERATE ( generate_5_3, 0xbc, 0x0e, 0xfc, 0x28, 0x2a, 0xbd, 0x87, 0x60, 0x5c, 0xc9, 0x0c, 0xba, 0x9b, 0x86, 0x33, 0xdc, 0xb1, 0xda, 0xe0, 0x2e ) ); -/** Test 5.4 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_5_4, +/** SHA-1 Test 5.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_5_4, HMAC_DRBG_SHA1, additional_input_empty, ( 320 / 8 ) ); -/** Test 5.5 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_5_5, +/** SHA-1 Test 5.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_5_5, HMAC_DRBG_SHA1, entropy_input_2, additional_input_empty, EXPECT ( 0xdb, 0xa1, 0xcf, 0xf4, 0x87, 0x95, 0x46, 0xa0, 0x38, 0xa5, 0x59, 0xb2, 0xa2, 0x4d, 0xf2, 0xc0, 0x30, 0x08, 0x9a, 0x41 ), EXPECT ( 0x2f, 0x88, 0x3c, 0x46, 0x48, 0xe1, 0x31, 0xe8, 0x6d, 0xdf, 0x9d, 0xca, 0x0d, 0x74, 0xf3, 0x0c, 0xa1, 0xce, 0x6e, 0xfb ) ); -/** Test 5.6 : Retried second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_5_6, +/** SHA-1 Test 5.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_5_6, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0xf9, 0x39, 0xa5, 0xab, 0x08, 0xa3, 0x9f, 0x23, 0x10, 0x70, 0xb0, 0xd4, 0xc9, 0x6d, 0xc2, 0x37, 0x90, 0xba, 0x01, 0x53 ), @@ -512,23 +557,23 @@ HMAC_DRBG_TEST_GENERATE ( generate_5_6, 0x1a, 0x0a, 0xd3, 0x9b, 0xd1, 0x5e, 0x86, 0x2e, 0x64, 0x4f, 0x31, 0xe4, 0xa2, 0xd7, 0xd8, 0x43, 0xe5, 0x7c, 0x59, 0x68 ) ); -/** Test 6 : Instantiate */ -#define instantiate_6 instantiate_1 +/** SHA-1 Test 6 : Instantiate */ +#define sha1_instantiate_6 sha1_instantiate_1 -/** Test 6.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_6_1, +/** SHA-1 Test 6.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_6_1, HMAC_DRBG_SHA1, additional_input_1, ( 320 / 8 ) ); -/** Test 6.2 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_6_2, +/** SHA-1 Test 6.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_6_2, HMAC_DRBG_SHA1, entropy_input_1, additional_input_1, EXPECT ( 0x52, 0x28, 0xa4, 0xb6, 0xa4, 0x46, 0x92, 0x90, 0x5e, 0xc0, 0x44, 0xbf, 0xf0, 0xbb, 0x4e, 0x25, 0xa3, 0x87, 0xca, 0xc1 ), EXPECT ( 0x24, 0x77, 0x32, 0xd0, 0x4c, 0xb8, 0x4e, 0xd4, 0x1a, 0xdd, 0x95, 0xa4, 0xb7, 0x8b, 0x50, 0xcd, 0x9b, 0x3d, 0x3f, 0x32 ) ); -/** Test 6.3 : Retried first call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_6_3, +/** SHA-1 Test 6.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_6_3, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0xab, 0x3d, 0xd4, 0x89, 0x5b, 0xc8, 0xcd, 0x22, 0x71, 0xde, 0xba, 0x5f, 0x3c, 0x13, 0x63, 0x52, 0x6b, 0x8b, 0x74, 0x52 ), @@ -539,20 +584,20 @@ HMAC_DRBG_TEST_GENERATE ( generate_6_3, 0x57, 0xae, 0xe8, 0x15, 0xb9, 0xc0, 0x70, 0x04, 0xc7, 0xe9, 0x92, 0xeb, 0x8c, 0x7e, 0x59, 0x19, 0x64, 0xaf, 0xee, 0xa2 ) ); -/** Test 6.4 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_6_4, +/** SHA-1 Test 6.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_6_4, HMAC_DRBG_SHA1, additional_input_2, ( 320 / 8 ) ); -/** Test 6.5 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_6_5, +/** SHA-1 Test 6.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_6_5, HMAC_DRBG_SHA1, entropy_input_2, additional_input_2, EXPECT ( 0xe5, 0x73, 0x9f, 0x9c, 0xf7, 0xff, 0x43, 0x84, 0xd1, 0x27, 0x3e, 0x02, 0x6b, 0x45, 0x31, 0x21, 0x36, 0x49, 0x4f, 0x41 ), EXPECT ( 0x30, 0xc3, 0x43, 0x05, 0xc2, 0xc6, 0x48, 0xb0, 0x57, 0xa6, 0x40, 0x22, 0x1b, 0x5c, 0x56, 0x57, 0x26, 0xcd, 0x32, 0xb2 ) ); -/** Test 6.6 : Retried second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_6_6, +/** SHA-1 Test 6.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_6_6, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x61, 0x91, 0xca, 0x9b, 0xf0, 0x00, 0xd1, 0x0a, 0x71, 0x69, 0x0a, 0xc1, 0x0e, 0x09, 0xff, 0xc8, 0x92, 0xab, 0xde, 0x9a ), @@ -563,23 +608,23 @@ HMAC_DRBG_TEST_GENERATE ( generate_6_6, 0x2d, 0xc6, 0x4a, 0x16, 0x42, 0x11, 0x88, 0x9a, 0x01, 0x0f, 0x24, 0x71, 0xa0, 0x91, 0x2f, 0xfe, 0xa1, 0xbf, 0x01, 0x95 ) ); -/** Test 7 : Instantiation */ -#define instantiate_7 instantiate_3 +/** SHA-1 Test 7 : Instantiation */ +#define sha1_instantiate_7 sha1_instantiate_3 -/** Test 7.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_7_1, +/** SHA-1 Test 7.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_7_1, HMAC_DRBG_SHA1, additional_input_empty, ( 320 / 8 ) ); -/** Test 7.2 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_7_2, +/** SHA-1 Test 7.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_7_2, HMAC_DRBG_SHA1, entropy_input_1, additional_input_empty, EXPECT ( 0xb9, 0x25, 0x4d, 0x8a, 0xac, 0xba, 0x43, 0xfb, 0xda, 0xe6, 0x39, 0x4f, 0x2b, 0x3a, 0xfc, 0x5d, 0x58, 0x08, 0x00, 0xbf ), EXPECT ( 0x28, 0x40, 0x3b, 0x60, 0x36, 0x38, 0xd0, 0x7d, 0x79, 0x66, 0x66, 0x1e, 0xf6, 0x7b, 0x9d, 0x39, 0x05, 0xf4, 0x6d, 0xb9 ) ); -/** Test 7.3 : Retried first call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_7_3, +/** SHA-1 Test 7.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_7_3, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x64, 0xfe, 0x07, 0x4a, 0x6e, 0x77, 0x97, 0xd1, 0xa4, 0x35, 0xda, 0x89, 0x64, 0x48, 0x4d, 0x6c, 0xf8, 0xbd, 0xc0, 0x1b ), @@ -590,20 +635,20 @@ HMAC_DRBG_TEST_GENERATE ( generate_7_3, 0xb5, 0x70, 0x81, 0xe4, 0x22, 0x0f, 0x22, 0xc5, 0xc2, 0x83, 0xe2, 0xc9, 0x1b, 0x8e, 0x30, 0x5a, 0xb8, 0x69, 0xc6, 0x25 ) ); -/** Test 7.4 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_7_4, +/** SHA-1 Test 7.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_7_4, HMAC_DRBG_SHA1, additional_input_empty, ( 320 / 8 ) ); -/** Test 7.5 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_7_5, +/** SHA-1 Test 7.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_7_5, HMAC_DRBG_SHA1, entropy_input_2, additional_input_empty, EXPECT ( 0x02, 0xbc, 0x57, 0x7f, 0xd1, 0x0e, 0xf7, 0x19, 0x3c, 0x1d, 0xb0, 0x98, 0xbd, 0x5b, 0x75, 0xc7, 0xc4, 0xb6, 0x79, 0x59 ), EXPECT ( 0xbc, 0xbd, 0xf0, 0x52, 0xe0, 0xe0, 0x2a, 0xe8, 0x9a, 0x77, 0x67, 0x94, 0x3f, 0x98, 0x65, 0xb8, 0xb7, 0x22, 0x90, 0x2d ) ); -/** Test 7.6 : Retried second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_7_6, +/** SHA-1 Test 7.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_7_6, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x1a, 0xa4, 0x24, 0x1c, 0x69, 0x5e, 0x29, 0xc0, 0xa5, 0x9a, 0xd1, 0x8a, 0x60, 0x70, 0xe3, 0x38, 0xa5, 0x48, 0xbe, 0x92 ), @@ -614,23 +659,23 @@ HMAC_DRBG_TEST_GENERATE ( generate_7_6, 0x61, 0x48, 0x2c, 0xa5, 0x4d, 0x5f, 0xa7, 0x23, 0xf4, 0xc8, 0x8b, 0x4f, 0xa5, 0x04, 0xbf, 0x03, 0x27, 0x7f, 0xa7, 0x83 ) ); -/** Test 8 : Instantiate */ -#define instantiate_8 instantiate_3 +/** SHA-1 Test 8 : Instantiate */ +#define sha1_instantiate_8 sha1_instantiate_3 -/** Test 8.1 : First call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_8_1, +/** SHA-1 Test 8.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_8_1, HMAC_DRBG_SHA1, additional_input_1, ( 320 / 8 ) ); -/** Test 8.2 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_8_2, +/** SHA-1 Test 8.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_8_2, HMAC_DRBG_SHA1, entropy_input_1, additional_input_1, EXPECT ( 0xc0, 0x95, 0x48, 0xc0, 0xd3, 0xc8, 0x61, 0xd7, 0x40, 0xf2, 0x83, 0x7d, 0x72, 0xb5, 0x07, 0x23, 0x5c, 0x26, 0xdb, 0x82 ), EXPECT ( 0x17, 0x4b, 0x3f, 0x84, 0xc3, 0x53, 0x1f, 0x7c, 0x0a, 0x2e, 0x54, 0x21, 0x23, 0x4e, 0xa1, 0x6b, 0x70, 0x8d, 0xdf, 0x0d ) ); -/** Test 8.3 : Retried first call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_8_3, +/** SHA-1 Test 8.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_8_3, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0x60, 0x3f, 0x09, 0x49, 0x27, 0x9c, 0x70, 0xe8, 0xc6, 0x6c, 0x0f, 0x56, 0x37, 0xc0, 0xf3, 0x75, 0x60, 0x07, 0xe5, 0xac ), @@ -641,20 +686,20 @@ HMAC_DRBG_TEST_GENERATE ( generate_8_3, 0x34, 0x71, 0xfd, 0xa5, 0x5c, 0x6d, 0xdd, 0x2c, 0x03, 0xef, 0xa3, 0xb9, 0x64, 0x3a, 0xb3, 0xbb, 0x22, 0xf6, 0xc9, 0xf2 ) ); -/** Test 8.4 : Second call to Generate */ -HMAC_DRBG_TEST_GENERATE_FAIL ( generate_fail_8_4, +/** SHA-1 Test 8.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha1_generate_fail_8_4, HMAC_DRBG_SHA1, additional_input_2, ( 320 / 8 ) ); -/** Test 8.5 : Reseed */ -HMAC_DRBG_TEST_RESEED ( reseed_8_5, +/** SHA-1 Test 8.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha1_reseed_8_5, HMAC_DRBG_SHA1, entropy_input_2, additional_input_2, EXPECT ( 0x89, 0x42, 0xa5, 0x4f, 0x34, 0x9e, 0x28, 0x1b, 0x84, 0xaa, 0x46, 0x95, 0x87, 0xfb, 0xdd, 0xaf, 0x9d, 0x11, 0x40, 0x82 ), EXPECT ( 0x07, 0x73, 0x0e, 0x3c, 0xbf, 0xfd, 0x3c, 0xaf, 0xd7, 0xa8, 0xaa, 0xe2, 0xbf, 0x01, 0xd6, 0x01, 0x43, 0x01, 0xe2, 0x4d ) ); -/** Test 8.6 : Retried second call to Generate */ -HMAC_DRBG_TEST_GENERATE ( generate_8_6, +/** SHA-1 Test 8.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha1_generate_8_6, HMAC_DRBG_SHA1, additional_input_empty, EXPECT ( 0xbd, 0xe1, 0xb4, 0x6c, 0xdc, 0x54, 0x13, 0xb3, 0xd9, 0xf7, 0x35, 0xac, 0xdb, 0x80, 0xb1, 0x3c, 0x57, 0xbf, 0xe4, 0x73 ), @@ -724,69 +769,69 @@ static void hmac_drbg_test_exec ( void ) { * greater than the reseed_interval. */ - /* Test 1 */ - instantiate_ok ( &state, &instantiate_1 ); - generate_ok ( &state, &generate_1_1 ); - generate_ok ( &state, &generate_1_2 ); + /* SHA-1 Test 1 */ + instantiate_ok ( &state, &sha1_instantiate_1 ); + generate_ok ( &state, &sha1_generate_1_1 ); + generate_ok ( &state, &sha1_generate_1_2 ); - /* Test 2 */ - instantiate_ok ( &state, &instantiate_2 ); - generate_ok ( &state, &generate_2_1 ); - generate_ok ( &state, &generate_2_2 ); + /* SHA-1 Test 2 */ + instantiate_ok ( &state, &sha1_instantiate_2 ); + generate_ok ( &state, &sha1_generate_2_1 ); + generate_ok ( &state, &sha1_generate_2_2 ); - /* Test 3 */ - instantiate_ok ( &state, &instantiate_3 ); - generate_ok ( &state, &generate_3_1 ); - generate_ok ( &state, &generate_3_2 ); + /* SHA-1 Test 3 */ + instantiate_ok ( &state, &sha1_instantiate_3 ); + generate_ok ( &state, &sha1_generate_3_1 ); + generate_ok ( &state, &sha1_generate_3_2 ); - /* Test 4 */ - instantiate_ok ( &state, &instantiate_4 ); - generate_ok ( &state, &generate_4_1 ); - generate_ok ( &state, &generate_4_2 ); + /* SHA-1 Test 4 */ + instantiate_ok ( &state, &sha1_instantiate_4 ); + generate_ok ( &state, &sha1_generate_4_1 ); + generate_ok ( &state, &sha1_generate_4_2 ); - /* Test 5 */ - instantiate_ok ( &state, &instantiate_5 ); + /* SHA-1 Test 5 */ + instantiate_ok ( &state, &sha1_instantiate_5 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_5_1 ); - reseed_ok ( &state, &reseed_5_2 ); - generate_ok ( &state, &generate_5_3 ); + generate_fail_ok ( &state, &sha1_generate_fail_5_1 ); + reseed_ok ( &state, &sha1_reseed_5_2 ); + generate_ok ( &state, &sha1_generate_5_3 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_5_4 ); - reseed_ok ( &state, &reseed_5_5 ); - generate_ok ( &state, &generate_5_6 ); + generate_fail_ok ( &state, &sha1_generate_fail_5_4 ); + reseed_ok ( &state, &sha1_reseed_5_5 ); + generate_ok ( &state, &sha1_generate_5_6 ); - /* Test 6 */ - instantiate_ok ( &state, &instantiate_6 ); + /* SHA-1 Test 6 */ + instantiate_ok ( &state, &sha1_instantiate_6 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_6_1 ); - reseed_ok ( &state, &reseed_6_2 ); - generate_ok ( &state, &generate_6_3 ); + generate_fail_ok ( &state, &sha1_generate_fail_6_1 ); + reseed_ok ( &state, &sha1_reseed_6_2 ); + generate_ok ( &state, &sha1_generate_6_3 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_6_4 ); - reseed_ok ( &state, &reseed_6_5 ); - generate_ok ( &state, &generate_6_6 ); + generate_fail_ok ( &state, &sha1_generate_fail_6_4 ); + reseed_ok ( &state, &sha1_reseed_6_5 ); + generate_ok ( &state, &sha1_generate_6_6 ); - /* Test 7 */ - instantiate_ok ( &state, &instantiate_7 ); + /* SHA-1 Test 7 */ + instantiate_ok ( &state, &sha1_instantiate_7 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_7_1 ); - reseed_ok ( &state, &reseed_7_2 ); - generate_ok ( &state, &generate_7_3 ); + generate_fail_ok ( &state, &sha1_generate_fail_7_1 ); + reseed_ok ( &state, &sha1_reseed_7_2 ); + generate_ok ( &state, &sha1_generate_7_3 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_7_4 ); - reseed_ok ( &state, &reseed_7_5 ); - generate_ok ( &state, &generate_7_6 ); + generate_fail_ok ( &state, &sha1_generate_fail_7_4 ); + reseed_ok ( &state, &sha1_reseed_7_5 ); + generate_ok ( &state, &sha1_generate_7_6 ); - /* Test 8 */ - instantiate_ok ( &state, &instantiate_8 ); + /* SHA-1 Test 8 */ + instantiate_ok ( &state, &sha1_instantiate_8 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_8_1 ); - reseed_ok ( &state, &reseed_8_2 ); - generate_ok ( &state, &generate_8_3 ); + generate_fail_ok ( &state, &sha1_generate_fail_8_1 ); + reseed_ok ( &state, &sha1_reseed_8_2 ); + generate_ok ( &state, &sha1_generate_8_3 ); force_reseed_required ( &state ); /* See above comments */ - generate_fail_ok ( &state, &generate_fail_8_4 ); - reseed_ok ( &state, &reseed_8_5 ); - generate_ok ( &state, &generate_8_6 ); + generate_fail_ok ( &state, &sha1_generate_fail_8_4 ); + reseed_ok ( &state, &sha1_reseed_8_5 ); + generate_ok ( &state, &sha1_generate_8_6 ); } /** HMAC_DRBG self-test */ From a810258b429f846fbf4ff51c37847dcf66b87e4f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 6 Mar 2012 13:34:22 +0000 Subject: [PATCH 056/221] [rng] Add NIST self-tests for HMAC_DRBG using SHA-256 Signed-off-by: Michael Brown --- src/tests/hmac_drbg_test.c | 544 +++++++++++++++++++++++++++++++++++++ 1 file changed, 544 insertions(+) diff --git a/src/tests/hmac_drbg_test.c b/src/tests/hmac_drbg_test.c index 2e93e5e8..299d8949 100644 --- a/src/tests/hmac_drbg_test.c +++ b/src/tests/hmac_drbg_test.c @@ -36,6 +36,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** Define inline expected data */ @@ -337,6 +338,11 @@ static const uint8_t nonce_sha1[] = { 0x20, 0x21, 0x22, 0x23, 0x24 }; +/** "Nonce" for SHA-256 */ +static const uint8_t nonce_sha256[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 +}; + /** "EntropyInput1 (for Reseed1) */ static const uint8_t entropy_input_1[] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, @@ -710,6 +716,480 @@ HMAC_DRBG_TEST_GENERATE ( sha1_generate_8_6, HMAC_DRBG_SHA1, 0xa1, 0xdb, 0x09, 0x80, 0x9f, 0x57, 0xbf, 0xea, 0xe5, 0xb3, 0xe5, 0xf1, 0x46, 0xc7, 0x5f, 0x2d, 0x8d, 0xbb, 0x5e, 0x4a ) ); +/** SHA-256 Test 1 : Instantiation */ +HMAC_DRBG_TEST_INSTANTIATE ( sha256_instantiate_1, HMAC_DRBG_SHA256, + entropy_input, nonce_sha256, personalisation_string_empty, + EXPECT ( 0x3d, 0xda, 0x54, 0x3e, 0x7e, 0xef, 0x14, 0xf9, 0x36, 0x23, + 0x7b, 0xe6, 0x5d, 0x09, 0x4b, 0x4d, 0xdc, 0x96, 0x9c, 0x0b, + 0x2b, 0x5e, 0xaf, 0xb5, 0xd8, 0x05, 0xe8, 0x6c, 0xfa, 0x64, + 0xd7, 0x41 ), + EXPECT ( 0x2d, 0x02, 0xc2, 0xf8, 0x22, 0x51, 0x7d, 0x54, 0xb8, 0x17, + 0x27, 0x9a, 0x59, 0x49, 0x1c, 0x41, 0xa1, 0x98, 0x9b, 0x3e, + 0x38, 0x2d, 0xeb, 0xe8, 0x0d, 0x2c, 0x7f, 0x66, 0x0f, 0x44, + 0x76, 0xc4 ) ); + +/** SHA-256 Test 1.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_1_1, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0xdd, 0x30, 0x95, 0x79, 0x35, 0x38, 0x02, 0xcc, 0xdd, 0x43, + 0x99, 0xc3, 0x69, 0x1c, 0x9d, 0xd9, 0x09, 0xdd, 0x3b, 0x2d, + 0xd0, 0x03, 0xcc, 0xd5, 0x9d, 0x6f, 0x08, 0xd8, 0x5f, 0x2e, + 0x35, 0x09 ), + EXPECT ( 0xa1, 0xc2, 0x0f, 0xf2, 0x70, 0xa3, 0x9d, 0x2b, 0x8d, 0x03, + 0xd6, 0x59, 0xb9, 0xdd, 0xd0, 0x11, 0xc2, 0xcc, 0xdf, 0x24, + 0x48, 0x55, 0x7e, 0xf6, 0xa1, 0xa9, 0x15, 0xd1, 0x89, 0x40, + 0xa6, 0x88 ), + EXPECT ( 0xd6, 0x7b, 0x8c, 0x17, 0x34, 0xf4, 0x6f, 0xa3, 0xf7, 0x63, + 0xcf, 0x57, 0xc6, 0xf9, 0xf4, 0xf2, 0xdc, 0x10, 0x89, 0xbd, + 0x8b, 0xc1, 0xf6, 0xf0, 0x23, 0x95, 0x0b, 0xfc, 0x56, 0x17, + 0x63, 0x52, 0x08, 0xc8, 0x50, 0x12, 0x38, 0xad, 0x7a, 0x44, + 0x00, 0xde, 0xfe, 0xe4, 0x6c, 0x64, 0x0b, 0x61, 0xaf, 0x77, + 0xc2, 0xd1, 0xa3, 0xbf, 0xaa, 0x90, 0xed, 0xe5, 0xd2, 0x07, + 0x40, 0x6e, 0x54, 0x03 ) ); + +/** SHA-256 Test 1.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_1_2, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0x5c, 0xd5, 0xe5, 0x0a, 0x3e, 0x44, 0x8a, 0x07, 0xc3, 0xd2, + 0xf2, 0xa3, 0xf9, 0xde, 0xbc, 0xc0, 0x46, 0x5f, 0x9c, 0xf1, + 0x1c, 0xa1, 0x36, 0xe9, 0xb5, 0x04, 0xb4, 0xd3, 0x1c, 0x7f, + 0xf1, 0xb8 ), + EXPECT ( 0x33, 0xb3, 0x09, 0xf2, 0xff, 0x01, 0xce, 0x10, 0x4b, 0x44, + 0x29, 0xb6, 0x75, 0xfa, 0xfa, 0x19, 0x01, 0x1e, 0x34, 0x8b, + 0x28, 0x12, 0x71, 0x5a, 0x76, 0x37, 0xf6, 0xa6, 0xe6, 0x3b, + 0x5d, 0x57 ), + EXPECT ( 0x8f, 0xda, 0xec, 0x20, 0xf8, 0xb4, 0x21, 0x40, 0x70, 0x59, + 0xe3, 0x58, 0x89, 0x20, 0xda, 0x7e, 0xda, 0x9d, 0xce, 0x3c, + 0xf8, 0x27, 0x4d, 0xfa, 0x1c, 0x59, 0xc1, 0x08, 0xc1, 0xd0, + 0xaa, 0x9b, 0x0f, 0xa3, 0x8d, 0xa5, 0xc7, 0x92, 0x03, 0x7c, + 0x4d, 0x33, 0xcd, 0x07, 0x0c, 0xa7, 0xcd, 0x0c, 0x56, 0x08, + 0xdb, 0xa8, 0xb8, 0x85, 0x65, 0x46, 0x39, 0xde, 0x21, 0x87, + 0xb7, 0x4c, 0xb2, 0x63 ) ); + +/** SHA-256 Test 2 : Instantiation */ +#define sha256_instantiate_2 sha256_instantiate_1 + +/** SHA-256 Test 2.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_2_1, HMAC_DRBG_SHA256, + additional_input_1, + EXPECT ( 0x79, 0x1d, 0x31, 0x44, 0xb3, 0x02, 0xad, 0x6c, 0xe4, 0x32, + 0x41, 0x34, 0x42, 0x10, 0xaa, 0xd0, 0xd3, 0x99, 0xed, 0xb7, + 0xb5, 0x90, 0x6f, 0xb2, 0x51, 0xdb, 0x1c, 0xb6, 0x00, 0x04, + 0xea, 0x51 ), + EXPECT ( 0x58, 0xfd, 0x96, 0x5f, 0x4f, 0x99, 0x89, 0x3c, 0x17, 0xe6, + 0xa3, 0x3c, 0xb8, 0xe9, 0x04, 0x15, 0xb5, 0x16, 0xd0, 0x06, + 0x14, 0xa4, 0x49, 0xd4, 0x06, 0xe0, 0x3c, 0x68, 0x5b, 0xd8, + 0x59, 0xbd ), + EXPECT ( 0x41, 0x87, 0x87, 0x35, 0x81, 0x35, 0x41, 0x9b, 0x93, 0x81, + 0x33, 0x53, 0x53, 0x06, 0x17, 0x6a, 0xfb, 0x25, 0x1c, 0xdd, + 0x2b, 0xa3, 0x79, 0x88, 0x59, 0xb5, 0x66, 0xa0, 0x5c, 0xfb, + 0x1d, 0x68, 0x0e, 0xa9, 0x25, 0x85, 0x6d, 0x5b, 0x84, 0xd5, + 0x6a, 0xda, 0xe8, 0x70, 0x45, 0xa6, 0xba, 0x28, 0xd2, 0xc9, + 0x08, 0xab, 0x75, 0xb7, 0xcc, 0x41, 0x43, 0x1f, 0xac, 0x59, + 0xf3, 0x89, 0x18, 0xa3 ) ); + +/** SHA-256 Test 2.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_2_2, HMAC_DRBG_SHA256, + additional_input_2, + EXPECT ( 0xe7, 0x45, 0x8f, 0xb4, 0x4a, 0x36, 0x9a, 0x65, 0x3f, 0x2f, + 0x8f, 0x57, 0x7b, 0xf9, 0x75, 0xc4, 0xb3, 0x62, 0xc4, 0xfe, + 0x61, 0x8b, 0x2f, 0x1f, 0xf6, 0x76, 0x9b, 0x13, 0xc9, 0x4d, + 0xec, 0xf4 ), + EXPECT ( 0x19, 0x33, 0x4b, 0x8c, 0x31, 0xb7, 0x49, 0x32, 0xdd, 0xd7, + 0xb2, 0xa4, 0x68, 0xf6, 0x43, 0x6d, 0xf9, 0x2e, 0x10, 0x0d, + 0x39, 0xd3, 0xac, 0xb3, 0x68, 0xc7, 0x02, 0x9c, 0xb8, 0x83, + 0xec, 0x89 ), + EXPECT ( 0x7c, 0x06, 0x7b, 0xdd, 0xca, 0x81, 0x72, 0x48, 0x23, 0xd6, + 0x4c, 0x69, 0x82, 0x92, 0x85, 0xbd, 0xbf, 0xf5, 0x37, 0x71, + 0x61, 0x02, 0xc1, 0x88, 0x2e, 0x20, 0x22, 0x50, 0xe0, 0xfa, + 0x5e, 0xf3, 0xa3, 0x84, 0xcd, 0x34, 0xa2, 0x0f, 0xfd, 0x1f, + 0xbc, 0x91, 0xe0, 0xc5, 0x32, 0xa8, 0xa4, 0x21, 0xbc, 0x4a, + 0xfe, 0x3c, 0xd4, 0x7f, 0x22, 0x32, 0x3e, 0xb4, 0xba, 0xe1, + 0xa0, 0x07, 0x89, 0x81 ) ); + +/** SHA-256 Test 3 : Instantiation */ +HMAC_DRBG_TEST_INSTANTIATE ( sha256_instantiate_3, HMAC_DRBG_SHA256, + entropy_input, nonce_sha256, personalisation_string, + EXPECT ( 0x65, 0x67, 0x3c, 0x34, 0x8e, 0x51, 0xcf, 0xac, 0xc4, 0x10, + 0xbd, 0x20, 0x02, 0x49, 0xa5, 0x9a, 0x9d, 0x6b, 0xae, 0x77, + 0x69, 0x04, 0x27, 0x1b, 0xb1, 0xf7, 0x18, 0xda, 0x1d, 0x18, + 0x20, 0x42 ), + EXPECT ( 0xe0, 0xf9, 0x1a, 0xc9, 0x96, 0x30, 0xee, 0xe6, 0x7c, 0xf8, + 0x30, 0xcf, 0xd5, 0x04, 0x4f, 0xeb, 0xf5, 0x5c, 0x0c, 0x11, + 0x50, 0x07, 0x99, 0x7a, 0xda, 0x11, 0x29, 0x6f, 0xc4, 0x16, + 0x4a, 0x9a ) ); + +/** SHA-256 Test 3.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_3_1, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0xf0, 0xb2, 0xf2, 0x42, 0xca, 0xd9, 0x92, 0xa7, 0x24, 0xf7, + 0xe5, 0x59, 0x1d, 0x2f, 0x3b, 0x0c, 0x21, 0x57, 0xae, 0x70, + 0xd5, 0x32, 0x78, 0x99, 0x40, 0xf1, 0x64, 0x45, 0x9b, 0x00, + 0xc7, 0x49 ), + EXPECT ( 0x1a, 0x03, 0xf9, 0x1c, 0x51, 0x20, 0xba, 0xca, 0x2b, 0xf6, + 0xc6, 0x4d, 0xd7, 0x3a, 0xb1, 0x1d, 0xf6, 0xfd, 0x3f, 0xf1, + 0xac, 0x3b, 0x57, 0x20, 0xa3, 0xf7, 0xfb, 0xe3, 0x9e, 0x7e, + 0x7f, 0xe9 ), + EXPECT ( 0x0d, 0xd9, 0xc8, 0x55, 0x89, 0xf3, 0x57, 0xc3, 0x89, 0xd6, + 0xaf, 0x8d, 0xe9, 0xd7, 0x34, 0xa9, 0x17, 0xc7, 0x71, 0xef, + 0x2d, 0x88, 0x16, 0xb9, 0x82, 0x59, 0x6e, 0xd1, 0x2d, 0xb4, + 0x5d, 0x73, 0x4a, 0x62, 0x68, 0x08, 0x35, 0xc0, 0x2f, 0xda, + 0x66, 0xb0, 0x8e, 0x1a, 0x36, 0x9a, 0xe2, 0x18, 0xf2, 0x6d, + 0x52, 0x10, 0xad, 0x56, 0x42, 0x48, 0x87, 0x2d, 0x7a, 0x28, + 0x78, 0x41, 0x59, 0xc3 ) ); + +/** SHA-256 Test 3.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_3_2, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0x5c, 0x0d, 0xec, 0x09, 0x37, 0x08, 0xc1, 0x7c, 0xa7, 0x6b, + 0x57, 0xc0, 0xcb, 0x60, 0xcf, 0x88, 0x9d, 0xcc, 0x47, 0xad, + 0x10, 0xbd, 0x64, 0xbc, 0x6a, 0x14, 0xb2, 0x3f, 0x20, 0x26, + 0x07, 0x8a ), + EXPECT ( 0x45, 0x67, 0x52, 0xa5, 0x11, 0xb8, 0x48, 0xbd, 0x05, 0xf1, + 0x81, 0x9b, 0x9f, 0x6b, 0x15, 0x42, 0xc7, 0xd5, 0xec, 0xf9, + 0x32, 0x73, 0x39, 0x26, 0x7a, 0x0c, 0x77, 0x23, 0x5b, 0x87, + 0xdc, 0x5a ), + EXPECT ( 0x46, 0xb4, 0xf4, 0x75, 0x6a, 0xe7, 0x15, 0xe0, 0xe5, 0x16, + 0x81, 0xab, 0x29, 0x32, 0xde, 0x15, 0x23, 0xbe, 0x5d, 0x13, + 0xba, 0xf0, 0xf4, 0x58, 0x8b, 0x11, 0xfe, 0x37, 0x2f, 0xda, + 0x37, 0xab, 0xe3, 0x68, 0x31, 0x73, 0x41, 0xbc, 0x8b, 0xa9, + 0x1f, 0xc5, 0xd8, 0x5b, 0x7f, 0xb8, 0xca, 0x8f, 0xbc, 0x30, + 0x9a, 0x75, 0x8f, 0xd6, 0xfc, 0xa9, 0xdf, 0x43, 0xc7, 0x66, + 0x0b, 0x22, 0x13, 0x22 ) ); + +/** SHA-256 Test 4 : Instantiation */ +#define sha256_instantiate_4 sha256_instantiate_3 + +/** SHA-256 Test 4.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_4_1, HMAC_DRBG_SHA256, + additional_input_1, + EXPECT ( 0x57, 0x2c, 0x03, 0x74, 0xc1, 0xa1, 0x01, 0x25, 0xbf, 0xa6, + 0xae, 0xcd, 0x7c, 0xeb, 0xfe, 0x32, 0xf7, 0x52, 0xc3, 0xfb, + 0x31, 0x67, 0x31, 0xb7, 0xcf, 0xdb, 0xde, 0xc2, 0x63, 0x56, + 0x93, 0x2b ), + EXPECT ( 0xd6, 0x8b, 0xf0, 0x41, 0xf3, 0xeb, 0x50, 0x88, 0x08, 0x8d, + 0x8b, 0x8e, 0x71, 0x2c, 0x36, 0xae, 0x95, 0x83, 0xbb, 0x08, + 0xfd, 0x1f, 0x90, 0x34, 0xa4, 0xe9, 0x42, 0xe9, 0xa6, 0x74, + 0x7c, 0xe7 ), + EXPECT ( 0x14, 0x78, 0xf2, 0x9e, 0x94, 0xb0, 0x2c, 0xb4, 0x0d, 0x3a, + 0xab, 0x86, 0x24, 0x55, 0x57, 0xce, 0x13, 0xa8, 0xca, 0x2f, + 0xdb, 0x65, 0x7d, 0x98, 0xef, 0xc1, 0x92, 0x34, 0x6b, 0x9f, + 0xac, 0x33, 0xea, 0x58, 0xad, 0xa2, 0xcc, 0xa4, 0x32, 0xcc, + 0xde, 0xfb, 0xcd, 0xaa, 0x8b, 0x82, 0xf5, 0x53, 0xef, 0x96, + 0x61, 0x34, 0xe2, 0xcd, 0x13, 0x9f, 0x15, 0xf0, 0x1c, 0xad, + 0x56, 0x85, 0x65, 0xa8 ) ); + +/** SHA-256 Test 4.2 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_4_2, HMAC_DRBG_SHA256, + additional_input_2, + EXPECT ( 0x28, 0x2e, 0x07, 0x34, 0x80, 0x80, 0x93, 0x75, 0x58, 0xb1, + 0x39, 0x2e, 0x95, 0xab, 0x91, 0xe7, 0xc1, 0xf6, 0x22, 0xb2, + 0x4f, 0xfb, 0x87, 0x20, 0xa5, 0xf0, 0xa5, 0xe0, 0x75, 0x50, + 0xc7, 0xc2 ), + EXPECT ( 0xdf, 0xc3, 0xbd, 0xb5, 0xf3, 0xbc, 0xf1, 0xaa, 0x68, 0x29, + 0x8e, 0x79, 0x0d, 0x72, 0x0a, 0x67, 0xa7, 0x6e, 0x31, 0xb9, + 0x2b, 0x9b, 0x35, 0xa8, 0xe5, 0x47, 0x1b, 0xb1, 0x7e, 0x30, + 0x3c, 0x6b ), + EXPECT ( 0x49, 0x7c, 0x7a, 0x16, 0xe8, 0x8a, 0x64, 0x11, 0xf8, 0xfc, + 0xe1, 0x0e, 0xf5, 0x67, 0x63, 0xc6, 0x10, 0x25, 0x80, 0x1d, + 0x8f, 0x51, 0xa7, 0x43, 0x52, 0xd6, 0x82, 0xcc, 0x23, 0xa0, + 0xa8, 0xe6, 0x73, 0xca, 0xe0, 0x32, 0x28, 0x93, 0x90, 0x64, + 0x7d, 0xc6, 0x83, 0xb7, 0x34, 0x28, 0x85, 0xd6, 0xb7, 0x6a, + 0xb1, 0xda, 0x69, 0x6d, 0x3e, 0x97, 0xe2, 0x2d, 0xff, 0xdd, + 0xff, 0xfd, 0x8d, 0xf0 ) ); + +/** SHA-256 Test 5 : Instantiation */ +#define sha256_instantiate_5 sha256_instantiate_1 + +/** SHA-256 Test 5.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_5_1, HMAC_DRBG_SHA256, + additional_input_empty, ( 512 / 8 ) ); + +/** SHA-256 Test 5.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_5_2, HMAC_DRBG_SHA256, + entropy_input_1, additional_input_empty, + EXPECT ( 0xb8, 0x40, 0x07, 0xe3, 0xe2, 0x7f, 0x34, 0xf9, 0xa7, 0x82, + 0x0b, 0x7a, 0xb5, 0x9b, 0xbe, 0xfc, 0xd0, 0xc4, 0xac, 0xae, + 0xde, 0x4b, 0x0b, 0x36, 0xb1, 0x47, 0xb8, 0x97, 0x79, 0xfd, + 0x74, 0x9d ), + EXPECT ( 0xa7, 0x2b, 0x8f, 0xee, 0x92, 0x39, 0x2f, 0x0a, 0x9d, 0x2d, + 0x61, 0xbf, 0x09, 0xa4, 0xdf, 0xcc, 0x9d, 0xe6, 0x9a, 0x16, + 0xa5, 0xf1, 0x50, 0x22, 0x4c, 0x3e, 0xf6, 0x04, 0x2d, 0x15, + 0x21, 0xfc ) ); + +/** SHA-256 Test 5.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_5_3, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0x43, 0x48, 0xaf, 0x84, 0x20, 0x84, 0x2f, 0xa0, 0x77, 0xb9, + 0xd3, 0xdb, 0xa8, 0xdc, 0xe9, 0xb3, 0xe1, 0xdf, 0x73, 0x4f, + 0xfc, 0xe1, 0xbe, 0xa5, 0xb9, 0xe2, 0xb1, 0x54, 0xdc, 0x5e, + 0xc6, 0x15 ), + EXPECT ( 0xd2, 0xc1, 0xac, 0x27, 0x88, 0x5d, 0x43, 0x32, 0x76, 0x71, + 0x31, 0x46, 0x32, 0xea, 0x60, 0x43, 0x3c, 0xca, 0x72, 0x73, + 0x04, 0x56, 0x9e, 0xa7, 0xd4, 0x71, 0xfe, 0xa7, 0xdb, 0x7d, + 0x31, 0x5d ), + EXPECT ( 0xfa, 0xbd, 0x0a, 0xe2, 0x5c, 0x69, 0xdc, 0x2e, 0xfd, 0xef, + 0xb7, 0xf2, 0x0c, 0x5a, 0x31, 0xb5, 0x7a, 0xc9, 0x38, 0xab, + 0x77, 0x1a, 0xa1, 0x9b, 0xf8, 0xf5, 0xf1, 0x46, 0x8f, 0x66, + 0x5c, 0x93, 0x8c, 0x9a, 0x1a, 0x5d, 0xf0, 0x62, 0x8a, 0x56, + 0x90, 0xf1, 0x5a, 0x1a, 0xd8, 0xa6, 0x13, 0xf3, 0x1b, 0xbd, + 0x65, 0xee, 0xad, 0x54, 0x57, 0xd5, 0xd2, 0x69, 0x47, 0xf2, + 0x9f, 0xe9, 0x1a, 0xa7 ) ); + +/** SHA-256 Test 5.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_5_4, HMAC_DRBG_SHA256, + additional_input_empty, ( 512 / 8 ) ); + +/** SHA-256 Test 5.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_5_5, HMAC_DRBG_SHA256, + entropy_input_2, additional_input_empty, + EXPECT ( 0xbf, 0xa0, 0x2c, 0xe7, 0xe9, 0x2d, 0xe9, 0x2b, 0x18, 0x24, + 0x28, 0x86, 0x89, 0x0e, 0x58, 0x6f, 0x83, 0x69, 0x06, 0xac, + 0xe9, 0xe5, 0x54, 0xf1, 0xb0, 0xed, 0x63, 0x57, 0x3c, 0xb8, + 0xb5, 0x03 ), + EXPECT ( 0xd3, 0x24, 0x03, 0xee, 0xa9, 0xdc, 0xe1, 0x61, 0x6e, 0x4e, + 0x11, 0x55, 0xb9, 0x23, 0xd8, 0x84, 0x2c, 0xc6, 0xe7, 0x84, + 0xc6, 0x7a, 0x93, 0x85, 0xb2, 0xa6, 0x37, 0xf1, 0x02, 0xfa, + 0x45, 0xd5 ) ); + +/** SHA-256 Test 5.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_5_6, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0x81, 0x21, 0xf7, 0x76, 0x4c, 0x08, 0x1e, 0xe9, 0xd1, 0x17, + 0x1e, 0xd1, 0x87, 0xba, 0xe0, 0x88, 0x95, 0xca, 0xe2, 0x30, + 0xd0, 0xa2, 0x5e, 0x37, 0x39, 0xc5, 0x7d, 0x54, 0x16, 0x10, + 0x9b, 0x82 ), + EXPECT ( 0x37, 0x84, 0x97, 0x7c, 0xc0, 0xe5, 0x9f, 0xbc, 0x9c, 0xda, + 0x4e, 0x11, 0x92, 0x47, 0x5c, 0x6e, 0xfa, 0xf8, 0x07, 0x20, + 0x19, 0x86, 0x21, 0x22, 0xcb, 0x6b, 0xce, 0xaa, 0xcc, 0x4a, + 0x17, 0x5e ), + EXPECT ( 0x6b, 0xd9, 0x25, 0xb0, 0xe1, 0xc2, 0x32, 0xef, 0xd6, 0x7c, + 0xcd, 0x84, 0xf7, 0x22, 0xe9, 0x27, 0xec, 0xb4, 0x6a, 0xb2, + 0xb7, 0x40, 0x01, 0x47, 0x77, 0xaf, 0x14, 0xba, 0x0b, 0xbf, + 0x53, 0xa4, 0x5b, 0xdb, 0xb6, 0x2b, 0x3f, 0x7d, 0x0b, 0x9c, + 0x8e, 0xea, 0xd0, 0x57, 0xc0, 0xec, 0x75, 0x4e, 0xf8, 0xb5, + 0x3e, 0x60, 0xa1, 0xf4, 0x34, 0xf0, 0x59, 0x46, 0xa8, 0xb6, + 0x86, 0xaf, 0xbc, 0x7a ) ); + +/** SHA-256 Test 6 : Instantiate */ +#define sha256_instantiate_6 sha256_instantiate_1 + +/** SHA-256 Test 6.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_6_1, HMAC_DRBG_SHA256, + additional_input_1, ( 512 / 8 ) ); + +/** SHA-256 Test 6.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_6_2, HMAC_DRBG_SHA256, + entropy_input_1, additional_input_1, + EXPECT ( 0xc1, 0x25, 0xea, 0x99, 0x75, 0x8e, 0xbb, 0x9a, 0x6f, 0x69, + 0xae, 0x31, 0x2a, 0xc2, 0x04, 0xb5, 0x94, 0xc0, 0x0a, 0xb6, + 0x8b, 0x81, 0x6e, 0x3a, 0x52, 0x12, 0x8e, 0x02, 0x78, 0xa5, + 0x84, 0xac ), + EXPECT ( 0xb2, 0xcb, 0x2b, 0x89, 0x12, 0x3f, 0x5b, 0x4a, 0xf5, 0x87, + 0xb8, 0xf6, 0xbd, 0xc5, 0x42, 0x7a, 0x99, 0x14, 0x19, 0xd3, + 0x53, 0x07, 0x7c, 0x68, 0x5e, 0x70, 0x7a, 0xcd, 0xf8, 0xe9, + 0xfd, 0xa9 ) ); + +/** SHA-256 Test 6.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_6_3, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0xc6, 0xed, 0x8f, 0xed, 0x71, 0x57, 0xa4, 0xd0, 0x9e, 0xa1, + 0xdd, 0xe8, 0x94, 0x6b, 0x54, 0x43, 0x3e, 0xcc, 0x54, 0x49, + 0xa4, 0xa3, 0x52, 0xaf, 0x45, 0x76, 0x4e, 0xe6, 0x73, 0x4b, + 0xbb, 0x04 ), + EXPECT ( 0xeb, 0xc7, 0x75, 0x25, 0x6b, 0xb7, 0x81, 0x24, 0x1e, 0x9c, + 0x70, 0xbb, 0xcf, 0x73, 0x2b, 0xdc, 0x90, 0xad, 0x10, 0xd9, + 0xdd, 0x3a, 0x89, 0x6e, 0xcc, 0x12, 0xb9, 0x2f, 0xfb, 0x63, + 0x45, 0xab ), + EXPECT ( 0x08, 0x5d, 0x57, 0xaf, 0x6b, 0xab, 0xcf, 0x2b, 0x9a, 0xee, + 0xf3, 0x87, 0xd5, 0x31, 0x65, 0x0e, 0x6a, 0x50, 0x5c, 0x54, + 0x40, 0x6a, 0xb3, 0x7a, 0x52, 0x89, 0x9e, 0x0e, 0xca, 0xb3, + 0x63, 0x2b, 0x7a, 0x06, 0x8a, 0x28, 0x14, 0xc6, 0xdf, 0x6a, + 0xe5, 0x32, 0xb6, 0x58, 0xd0, 0xd9, 0x74, 0x1c, 0x84, 0x77, + 0x5f, 0xee, 0x45, 0xb6, 0x84, 0xcd, 0xbd, 0xc2, 0x5f, 0xbc, + 0xb4, 0xd8, 0xf3, 0x10 ) ); + +/** SHA-256 Test 6.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_6_4, HMAC_DRBG_SHA256, + additional_input_2, ( 512 / 8 ) ); + +/** SHA-256 Test 6.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_6_5, HMAC_DRBG_SHA256, + entropy_input_2, additional_input_2, + EXPECT ( 0xfc, 0x51, 0xda, 0x84, 0xf9, 0x69, 0x6b, 0xcc, 0x84, 0xc8, + 0xf2, 0xac, 0xb9, 0x24, 0xbc, 0xdf, 0x72, 0xf8, 0x2e, 0xa2, + 0xca, 0x64, 0x3f, 0x08, 0x3b, 0x0c, 0x16, 0xc3, 0x63, 0x4e, + 0xfc, 0x62 ), + EXPECT ( 0xb9, 0x74, 0xe4, 0x37, 0x0a, 0xd5, 0x76, 0xbb, 0x99, 0xc4, + 0xe4, 0x9e, 0xa6, 0x80, 0xbf, 0xf9, 0x8d, 0xe9, 0xe1, 0x2f, + 0xec, 0xd0, 0x13, 0xde, 0xd4, 0x3c, 0x80, 0xf6, 0x9a, 0x7a, + 0xde, 0x8a ) ); + +/** SHA-256 Test 6.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_6_6, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0x56, 0xa2, 0xb4, 0x46, 0x32, 0xcb, 0x8f, 0xc3, 0xa6, 0x40, + 0x09, 0xbf, 0xd6, 0xec, 0x95, 0xe5, 0x6c, 0xef, 0x8e, 0x7c, + 0x91, 0x2a, 0xa8, 0x2b, 0x16, 0xf6, 0x14, 0x91, 0x5d, 0x9c, + 0xd6, 0xe3 ), + EXPECT ( 0xb5, 0xb3, 0x96, 0xa0, 0x15, 0x76, 0xb0, 0xfe, 0x42, 0xf4, + 0x08, 0x44, 0x55, 0x6c, 0x4c, 0xf4, 0xb6, 0x80, 0x4c, 0x94, + 0xde, 0x9d, 0x62, 0x38, 0xf1, 0xf7, 0xe7, 0xaf, 0x5c, 0x72, + 0x57, 0xf3 ), + EXPECT ( 0x9b, 0x21, 0x9f, 0xd9, 0x0d, 0xe2, 0xa0, 0x8e, 0x49, 0x34, + 0x05, 0xcf, 0x87, 0x44, 0x17, 0xb5, 0x82, 0x67, 0x70, 0xf3, + 0x94, 0x48, 0x15, 0x55, 0xdc, 0x66, 0x8a, 0xcd, 0x96, 0xb9, + 0xa3, 0xe5, 0x6f, 0x9d, 0x2c, 0x32, 0x5e, 0x26, 0xd4, 0x7c, + 0x1d, 0xfc, 0xfc, 0x8f, 0xbf, 0x86, 0x12, 0x6f, 0x40, 0xa1, + 0xe6, 0x39, 0x60, 0xf6, 0x27, 0x49, 0x34, 0x2e, 0xcd, 0xb7, + 0x1b, 0x24, 0x0d, 0xc6 ) ); + +/** SHA-256 Test 7 : Instantiation */ +#define sha256_instantiate_7 sha256_instantiate_3 + +/** SHA-256 Test 7.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_7_1, HMAC_DRBG_SHA256, + additional_input_empty, ( 512 / 8 ) ); + +/** SHA-256 Test 7.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_7_2, HMAC_DRBG_SHA256, + entropy_input_1, additional_input_empty, + EXPECT ( 0x44, 0x76, 0xc6, 0xd1, 0x1f, 0xc3, 0x5d, 0x44, 0x09, 0xd9, + 0x03, 0x2e, 0x45, 0x3b, 0x0f, 0x0d, 0xc3, 0x31, 0x4d, 0xb8, + 0x62, 0xcb, 0xdb, 0x60, 0x9c, 0x56, 0x02, 0x20, 0x8d, 0x4c, + 0x88, 0xd8 ), + EXPECT ( 0x95, 0xef, 0x78, 0x5a, 0x61, 0xc2, 0xf7, 0xb3, 0x6b, 0xc5, + 0x96, 0xba, 0x4b, 0xa2, 0x08, 0xa5, 0x2c, 0x6d, 0xc2, 0x03, + 0x63, 0x6d, 0x8f, 0x17, 0x87, 0x45, 0x3b, 0x85, 0x2b, 0x7e, + 0x49, 0xec ) ); + +/** SHA-256 Test 7.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_7_3, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0x0d, 0xf9, 0x11, 0x0e, 0x2f, 0x22, 0x58, 0x98, 0x24, 0xa9, + 0x47, 0x6c, 0x8e, 0x32, 0x08, 0x8e, 0x51, 0xa0, 0xda, 0x36, + 0x63, 0x3f, 0x8c, 0xd1, 0xf7, 0x54, 0x7d, 0xff, 0x69, 0x6e, + 0x4b, 0x29 ), + EXPECT ( 0xc0, 0xe3, 0xc8, 0xed, 0x5a, 0x8b, 0x57, 0x9e, 0x3f, 0xef, + 0x9d, 0xf3, 0xb7, 0xc2, 0xc2, 0x12, 0x98, 0x07, 0x17, 0xcc, + 0x91, 0xae, 0x18, 0x66, 0x45, 0xfa, 0xbb, 0x2c, 0xc7, 0x84, + 0xd5, 0xd7 ), + EXPECT ( 0xd8, 0xb6, 0x71, 0x30, 0x71, 0x41, 0x94, 0xff, 0xe5, 0xb2, + 0xa3, 0x5d, 0xbc, 0xd5, 0xe1, 0xa2, 0x99, 0x42, 0xad, 0x5c, + 0x68, 0xf3, 0xde, 0xb9, 0x4a, 0xdd, 0x9e, 0x9e, 0xba, 0xd8, + 0x60, 0x67, 0xed, 0xf0, 0x49, 0x15, 0xfb, 0x40, 0xc3, 0x91, + 0xea, 0xe7, 0x0c, 0x65, 0x9e, 0xaa, 0xe7, 0xef, 0x11, 0xa3, + 0xd4, 0x6a, 0x5b, 0x08, 0x5e, 0xdd, 0x90, 0xcc, 0x72, 0xce, + 0xa9, 0x89, 0x21, 0x0b ) ); + +/** SHA-256 Test 7.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_7_4, HMAC_DRBG_SHA256, + additional_input_empty, ( 512 / 8 ) ); + +/** SHA-256 Test 7.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_7_5, HMAC_DRBG_SHA256, + entropy_input_2, additional_input_empty, + EXPECT ( 0x3d, 0x77, 0x63, 0xe5, 0x30, 0x3d, 0xb5, 0x4b, 0xe2, 0x05, + 0x44, 0xa8, 0x1e, 0x9f, 0x00, 0xca, 0xdc, 0xfc, 0x1c, 0xb2, + 0x8d, 0xec, 0xb9, 0xcf, 0xc6, 0x99, 0xf6, 0x1d, 0xba, 0xf8, + 0x80, 0x21 ), + EXPECT ( 0xfe, 0xbc, 0x02, 0x79, 0xb7, 0x71, 0x0d, 0xec, 0x5c, 0x06, + 0x7e, 0xbe, 0xfa, 0x06, 0x8e, 0x4b, 0x59, 0x67, 0x49, 0x1b, + 0x7e, 0xef, 0x94, 0x75, 0x83, 0x50, 0x6d, 0x04, 0x97, 0xce, + 0x67, 0xba ) ); + +/** SHA-256 Test 7.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_7_6, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0x2d, 0x21, 0xac, 0x94, 0x99, 0x2f, 0xd8, 0x2b, 0x09, 0x80, + 0xd3, 0xd5, 0x95, 0x51, 0xb9, 0xd0, 0x7c, 0x8d, 0x54, 0xb2, + 0x52, 0xb6, 0x16, 0x28, 0x93, 0x44, 0xf8, 0xac, 0x86, 0x9e, + 0xd3, 0x5b ), + EXPECT ( 0x61, 0x0c, 0x34, 0xcd, 0xbf, 0x6f, 0x75, 0x33, 0x54, 0x7f, + 0x23, 0x32, 0xea, 0xc5, 0x7e, 0xe3, 0x1e, 0x72, 0x4f, 0xb2, + 0x92, 0x55, 0x56, 0x6b, 0x59, 0x78, 0x33, 0x16, 0x6c, 0xd0, + 0x39, 0x9f ), + EXPECT ( 0x8b, 0xba, 0x71, 0xc2, 0x58, 0x3f, 0x25, 0x30, 0xc2, 0x59, + 0xc9, 0x07, 0x84, 0xa5, 0x9a, 0xc4, 0x4d, 0x1c, 0x80, 0x56, + 0x91, 0x7c, 0xcf, 0x38, 0x87, 0x88, 0x10, 0x2d, 0x73, 0x82, + 0x4c, 0x6c, 0x11, 0xd5, 0xd6, 0x3b, 0xe1, 0xf0, 0x10, 0x17, + 0xd8, 0x84, 0xcd, 0x69, 0xd9, 0x33, 0x4b, 0x9e, 0xbc, 0x01, + 0xe7, 0xbd, 0x8f, 0xdf, 0x2a, 0x8e, 0x52, 0x57, 0x22, 0x93, + 0xdc, 0x21, 0xc0, 0xe1 ) ); + +/** SHA-256 Test 8 : Instantiate */ +#define sha256_instantiate_8 sha256_instantiate_3 + +/** SHA-256 Test 8.1 : First call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_8_1, HMAC_DRBG_SHA256, + additional_input_1, ( 512 / 8 ) ); + +/** SHA-256 Test 8.2 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_8_2, HMAC_DRBG_SHA256, + entropy_input_1, additional_input_1, + EXPECT ( 0xb3, 0x81, 0x38, 0x8c, 0x1d, 0x7c, 0xfd, 0x56, 0x59, 0x30, + 0x99, 0x3b, 0xd9, 0x26, 0x90, 0x66, 0x50, 0x88, 0xd9, 0xb8, + 0x39, 0x96, 0x9b, 0x87, 0xf1, 0x6d, 0xb6, 0xdf, 0x4e, 0x43, + 0x00, 0xd7 ), + EXPECT ( 0xfa, 0x04, 0x25, 0x64, 0x00, 0xe3, 0x42, 0xe6, 0x55, 0xf4, + 0x33, 0x26, 0x94, 0xe3, 0xb2, 0x4c, 0x04, 0xfb, 0x85, 0xbf, + 0x87, 0x80, 0x21, 0xe4, 0x52, 0xe7, 0x3b, 0x8f, 0x46, 0xd4, + 0xbd, 0xc6 ) ); + +/** SHA-256 Test 8.3 : Retried first call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_8_3, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0xd4, 0x1f, 0x6f, 0x33, 0x65, 0x82, 0x21, 0x70, 0x50, 0xb1, + 0xf6, 0x59, 0x28, 0xfd, 0x6e, 0x94, 0xcb, 0xc9, 0x45, 0x68, + 0xfe, 0x3b, 0x6b, 0x53, 0x38, 0x9e, 0x1e, 0x3a, 0x5b, 0x49, + 0xe1, 0x01 ), + EXPECT ( 0xa6, 0x55, 0xc9, 0xe7, 0xd1, 0x33, 0xf1, 0xcd, 0x8b, 0x11, + 0x61, 0xf2, 0x7d, 0x54, 0xe7, 0x5a, 0x7e, 0x7c, 0x80, 0x42, + 0xbf, 0x74, 0xd4, 0x7f, 0x9f, 0xfd, 0x60, 0xe2, 0x45, 0xeb, + 0xa5, 0x7e ), + EXPECT ( 0x44, 0xd7, 0x8b, 0xbc, 0x3e, 0xb6, 0x7c, 0x59, 0xc2, 0x2f, + 0x6c, 0x31, 0x00, 0x3d, 0x21, 0x2a, 0x78, 0x37, 0xcc, 0xd8, + 0x4c, 0x43, 0x8b, 0x55, 0x15, 0x0f, 0xd0, 0x13, 0xa8, 0xa7, + 0x8f, 0xe8, 0xed, 0xea, 0x81, 0xc6, 0x72, 0xe4, 0xb8, 0xdd, + 0xc8, 0x18, 0x38, 0x86, 0xe6, 0x9c, 0x2e, 0x17, 0x7d, 0xf5, + 0x74, 0xc1, 0xf1, 0x90, 0xdf, 0x27, 0x18, 0x50, 0xf8, 0xce, + 0x55, 0xef, 0x20, 0xb8 ) ); + +/** SHA-256 Test 8.4 : Second call to Generate */ +HMAC_DRBG_TEST_GENERATE_FAIL ( sha256_generate_fail_8_4, HMAC_DRBG_SHA256, + additional_input_2, ( 512 / 8 ) ); + +/** SHA-256 Test 8.5 : Reseed */ +HMAC_DRBG_TEST_RESEED ( sha256_reseed_8_5, HMAC_DRBG_SHA256, + entropy_input_2, additional_input_2, + EXPECT ( 0xfb, 0xa8, 0x05, 0x45, 0x3e, 0x3c, 0x9a, 0x73, 0x64, 0x58, + 0x5c, 0xed, 0xbc, 0xd2, 0x92, 0x30, 0xfb, 0xc9, 0x3d, 0x6f, + 0x12, 0x9d, 0x21, 0xed, 0xdd, 0xf6, 0x61, 0x3b, 0x3a, 0x8f, + 0xf2, 0x83 ), + EXPECT ( 0x83, 0x64, 0x7a, 0x33, 0x8c, 0x15, 0x3c, 0xba, 0xf0, 0xe4, + 0x9a, 0x54, 0xa4, 0x4f, 0xea, 0x66, 0x70, 0xcf, 0xd7, 0xc1, + 0x71, 0x4d, 0x4a, 0xb3, 0x5f, 0x11, 0x12, 0x3d, 0xf2, 0x7b, + 0x69, 0xcf ) ); + +/** SHA-256 Test 8.6 : Retried second call to Generate */ +HMAC_DRBG_TEST_GENERATE ( sha256_generate_8_6, HMAC_DRBG_SHA256, + additional_input_empty, + EXPECT ( 0xae, 0x59, 0xc7, 0x0a, 0x7c, 0x60, 0xed, 0x49, 0x83, 0x78, + 0xea, 0x84, 0x5b, 0xe9, 0x7d, 0x8f, 0xf8, 0x81, 0xe0, 0xea, + 0x37, 0x2e, 0x26, 0x5f, 0xa6, 0x72, 0x84, 0x29, 0x3e, 0x1a, + 0x46, 0xac ), + EXPECT ( 0xe2, 0xf0, 0x4d, 0xe3, 0xce, 0x21, 0x79, 0x61, 0xae, 0x2b, + 0x2d, 0x20, 0xa7, 0xba, 0x7c, 0x6c, 0x82, 0x0b, 0x5b, 0x14, + 0x92, 0x6e, 0x59, 0x56, 0xae, 0x6d, 0xfa, 0x2e, 0xd1, 0xd6, + 0x39, 0x93 ), + EXPECT ( 0x91, 0x77, 0x80, 0xdc, 0x0c, 0xe9, 0x98, 0x9f, 0xee, 0x6c, + 0x08, 0x06, 0xd6, 0xda, 0x12, 0x3a, 0x18, 0x25, 0x29, 0x47, + 0x58, 0xd4, 0xe1, 0xb5, 0x82, 0x68, 0x72, 0x31, 0x78, 0x0a, + 0x2a, 0x9c, 0x33, 0xf1, 0xd1, 0x56, 0xcc, 0xad, 0x32, 0x77, + 0x64, 0xb2, 0x9a, 0x4c, 0xb2, 0x69, 0x01, 0x77, 0xae, 0x96, + 0xef, 0x9e, 0xe9, 0x2a, 0xd0, 0xc3, 0x40, 0xba, 0x0f, 0xd1, + 0x20, 0x3c, 0x02, 0xc6 ) ); + /** * Force a "reseed required" state * @@ -832,6 +1312,70 @@ static void hmac_drbg_test_exec ( void ) { generate_fail_ok ( &state, &sha1_generate_fail_8_4 ); reseed_ok ( &state, &sha1_reseed_8_5 ); generate_ok ( &state, &sha1_generate_8_6 ); + + /* SHA-256 Test 1 */ + instantiate_ok ( &state, &sha256_instantiate_1 ); + generate_ok ( &state, &sha256_generate_1_1 ); + generate_ok ( &state, &sha256_generate_1_2 ); + + /* SHA-256 Test 2 */ + instantiate_ok ( &state, &sha256_instantiate_2 ); + generate_ok ( &state, &sha256_generate_2_1 ); + generate_ok ( &state, &sha256_generate_2_2 ); + + /* SHA-256 Test 3 */ + instantiate_ok ( &state, &sha256_instantiate_3 ); + generate_ok ( &state, &sha256_generate_3_1 ); + generate_ok ( &state, &sha256_generate_3_2 ); + + /* SHA-256 Test 4 */ + instantiate_ok ( &state, &sha256_instantiate_4 ); + generate_ok ( &state, &sha256_generate_4_1 ); + generate_ok ( &state, &sha256_generate_4_2 ); + + /* SHA-256 Test 5 */ + instantiate_ok ( &state, &sha256_instantiate_5 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_5_1 ); + reseed_ok ( &state, &sha256_reseed_5_2 ); + generate_ok ( &state, &sha256_generate_5_3 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_5_4 ); + reseed_ok ( &state, &sha256_reseed_5_5 ); + generate_ok ( &state, &sha256_generate_5_6 ); + + /* SHA-256 Test 6 */ + instantiate_ok ( &state, &sha256_instantiate_6 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_6_1 ); + reseed_ok ( &state, &sha256_reseed_6_2 ); + generate_ok ( &state, &sha256_generate_6_3 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_6_4 ); + reseed_ok ( &state, &sha256_reseed_6_5 ); + generate_ok ( &state, &sha256_generate_6_6 ); + + /* SHA-256 Test 7 */ + instantiate_ok ( &state, &sha256_instantiate_7 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_7_1 ); + reseed_ok ( &state, &sha256_reseed_7_2 ); + generate_ok ( &state, &sha256_generate_7_3 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_7_4 ); + reseed_ok ( &state, &sha256_reseed_7_5 ); + generate_ok ( &state, &sha256_generate_7_6 ); + + /* SHA-256 Test 8 */ + instantiate_ok ( &state, &sha256_instantiate_8 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_8_1 ); + reseed_ok ( &state, &sha256_reseed_8_2 ); + generate_ok ( &state, &sha256_generate_8_3 ); + force_reseed_required ( &state ); /* See above comments */ + generate_fail_ok ( &state, &sha256_generate_fail_8_4 ); + reseed_ok ( &state, &sha256_reseed_8_5 ); + generate_ok ( &state, &sha256_generate_8_6 ); } /** HMAC_DRBG self-test */ From 8d038040eaac85bbe08f0b5ba507ff0167b3a2f3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 6 Mar 2012 13:42:06 +0000 Subject: [PATCH 057/221] [rng] Choose HMAC_DRBG using SHA-256 as the DRBG algorithm Both HMAC_DRBG using SHA-1 and HMAC_DRBG using SHA-256 are Approved algorithms in ANS X9.82 for our chosen security strength of 128 bits. However, general recommendations (see e.g. NIST SP800-57) are to use a larger hash function in preference to SHA-1. Since SHA-256 is required anyway for TLSv1.2 support, there is no code size penalty for switching HMAC_DRBG to also use SHA-256. Signed-off-by: Michael Brown --- src/include/ipxe/drbg.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/include/ipxe/drbg.h b/src/include/ipxe/drbg.h index 139f03c5..6374e778 100644 --- a/src/include/ipxe/drbg.h +++ b/src/include/ipxe/drbg.h @@ -10,14 +10,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include +#include #include -/** Choose HMAC_DRBG using SHA-1 +/** Choose HMAC_DRBG using SHA-256 * - * HMAC_DRBG using SHA-1 is an Approved algorithm in ANS X9.82. + * HMAC_DRBG using SHA-256 is an Approved algorithm in ANS X9.82. */ -#define HMAC_DRBG_ALGORITHM HMAC_DRBG_SHA1 +#define HMAC_DRBG_ALGORITHM HMAC_DRBG_SHA256 /** Maximum security strength */ #define DRBG_MAX_SECURITY_STRENGTH \ @@ -25,10 +25,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Security strength * - * We choose to operate at the maximum security strength supported by - * the algorithm. + * We choose to operate at a strength of 128 bits. */ -#define DRBG_SECURITY_STRENGTH DRBG_MAX_SECURITY_STRENGTH +#define DRBG_SECURITY_STRENGTH 128 /** Minimum entropy input length */ #define DRBG_MIN_ENTROPY_LEN_BYTES \ From 1f238bc69e1aa56f79e163e60fd7c733ef7e0eb8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 6 Mar 2012 21:01:30 +0000 Subject: [PATCH 058/221] [test] Add NIST self-tests for AES128 and AES256 in CBC mode Signed-off-by: Michael Brown --- src/tests/aes_cbc_test.c | 180 +++++++++++++++++++++++++++++++++++++++ src/tests/cbc_test.c | 96 +++++++++++++++++++++ src/tests/cbc_test.h | 53 ++++++++++++ src/tests/tests.c | 1 + 4 files changed, 330 insertions(+) create mode 100644 src/tests/aes_cbc_test.c create mode 100644 src/tests/cbc_test.c create mode 100644 src/tests/cbc_test.h diff --git a/src/tests/aes_cbc_test.c b/src/tests/aes_cbc_test.c new file mode 100644 index 00000000..77622b25 --- /dev/null +++ b/src/tests/aes_cbc_test.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * AES-in-CBC-mode tests + * + * These test vectors are provided by NIST as part of the + * Cryptographic Toolkit Examples, downloadable from: + * + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CBC.pdf + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include "cbc_test.h" + +/** Define inline key */ +#define KEY(...) { __VA_ARGS__ } + +/** Define inline initialisation vector */ +#define IV(...) { __VA_ARGS__ } + +/** Define inline plaintext data */ +#define PLAINTEXT(...) { __VA_ARGS__ } + +/** Define inline ciphertext data */ +#define CIPHERTEXT(...) { __VA_ARGS__ } + +/** An AES-in-CBC-mode test */ +struct aes_cbc_test { + /** Key */ + const void *key; + /** Length of key */ + size_t key_len; + /** Initialisation vector */ + const void *iv; + /** Length of initialisation vector */ + size_t iv_len; + /** Plaintext */ + const void *plaintext; + /** Length of plaintext */ + size_t plaintext_len; + /** Ciphertext */ + const void *ciphertext; + /** Length of ciphertext */ + size_t ciphertext_len; +}; + +/** + * Define an AES-in-CBC-mode test + * + * @v name Test name + * @v key_array Key + * @v iv_array Initialisation vector + * @v plaintext_array Plaintext + * @v ciphertext_array Ciphertext + * @ret test AES-in-CBC-mode test + */ +#define AES_CBC_TEST( name, key_array, iv_array, plaintext_array, \ + ciphertext_array ) \ + static const uint8_t name ## _key [] = key_array; \ + static const uint8_t name ## _iv [] = iv_array; \ + static const uint8_t name ## _plaintext [] = plaintext_array; \ + static const uint8_t name ## _ciphertext [] = ciphertext_array; \ + static const struct aes_cbc_test name = { \ + .key = name ## _key, \ + .key_len = sizeof ( name ## _key ), \ + .iv = name ## _iv, \ + .iv_len = sizeof ( name ## _iv ), \ + .plaintext = name ## _plaintext, \ + .plaintext_len = sizeof ( name ## _plaintext ), \ + .ciphertext = name ## _ciphertext, \ + .ciphertext_len = sizeof ( name ## _ciphertext ), \ + } + +/** + * Report AES-in-CBC-mode + * + * @v state HMAC_DRBG internal state + * @v test Instantiation test + */ +#define aes_cbc_ok( test ) do { \ + struct cipher_algorithm *cipher = &aes_cbc_algorithm; \ + \ + assert ( (test)->iv_len == cipher->blocksize ); \ + assert ( (test)->plaintext_len == (test)->ciphertext_len ); \ + cbc_encrypt_ok ( cipher, (test)->key, (test)->key_len, \ + (test)->iv, (test)->plaintext, \ + (test)->ciphertext, (test)->plaintext_len ); \ + cbc_decrypt_ok ( cipher, (test)->key, (test)->key_len, \ + (test)->iv, (test)->ciphertext, \ + (test)->plaintext, (test)->ciphertext_len ); \ + } while ( 0 ) + +/** CBC_AES128 */ +AES_CBC_TEST ( test_128, + KEY ( 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, + 0x88, 0x09, 0xcf, 0x4f, 0x3c ), + IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ), + PLAINTEXT ( 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ), + CIPHERTEXT ( 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, + 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d, + 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, + 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2, + 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, + 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16, + 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, + 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7 ) ); + +/** CBC_AES256 */ +AES_CBC_TEST ( test_256, + KEY ( 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, + 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, + 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 ), + IV ( 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f ), + PLAINTEXT ( 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 ), + CIPHERTEXT ( 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, + 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6, + 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, + 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d, + 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, + 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61, + 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, + 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b ) ); + +/** + * Perform AES-in-CBC-mode self-test + * + */ +static void aes_cbc_test_exec ( void ) { + + aes_cbc_ok ( &test_128 ); + aes_cbc_ok ( &test_256 ); +} + +/** AES-in-CBC-mode self-test */ +struct self_test aes_cbc_test __self_test = { + .name = "aes_cbc", + .exec = aes_cbc_test_exec, +}; diff --git a/src/tests/cbc_test.c b/src/tests/cbc_test.c new file mode 100644 index 00000000..ebff3268 --- /dev/null +++ b/src/tests/cbc_test.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * CBC self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include "cbc_test.h" + +/** + * Test CBC encryption + * + * @v cipher Cipher algorithm + * @v key Key + * @v key_len Length of key + * @v iv Initialisation vector + * @v plaintext Plaintext data + * @v expected_ciphertext Expected ciphertext data + * @v len Length of data + * @ret ok Ciphertext is as expected + */ +int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key, + size_t key_len, const void *iv, const void *plaintext, + const void *expected_ciphertext, size_t len ) { + uint8_t ctx[ cipher->ctxsize ]; + uint8_t ciphertext[ len ]; + int rc; + + /* Initialise cipher */ + rc = cipher_setkey ( cipher, ctx, key, key_len ); + assert ( rc == 0 ); + cipher_setiv ( cipher, ctx, iv ); + + /* Perform encryption */ + cipher_encrypt ( cipher, ctx, plaintext, ciphertext, len ); + + /* Verify result */ + return ( memcmp ( ciphertext, expected_ciphertext, len ) == 0 ); +} + +/** + * Test CBC decryption + * + * @v cipher Cipher algorithm + * @v key Key + * @v key_len Length of key + * @v iv Initialisation vector + * @v ciphertext Ciphertext data + * @v expected_plaintext Expected plaintext data + * @v len Length of data + * @ret ok Plaintext is as expected + */ +int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key, + size_t key_len, const void *iv, const void *ciphertext, + const void *expected_plaintext, size_t len ) { + uint8_t ctx[ cipher->ctxsize ]; + uint8_t plaintext[ len ]; + int rc; + + /* Initialise cipher */ + rc = cipher_setkey ( cipher, ctx, key, key_len ); + assert ( rc == 0 ); + cipher_setiv ( cipher, ctx, iv ); + + /* Perform encryption */ + cipher_decrypt ( cipher, ctx, ciphertext, plaintext, len ); + + /* Verify result */ + return ( memcmp ( plaintext, expected_plaintext, len ) == 0 ); +} diff --git a/src/tests/cbc_test.h b/src/tests/cbc_test.h new file mode 100644 index 00000000..40356cc3 --- /dev/null +++ b/src/tests/cbc_test.h @@ -0,0 +1,53 @@ +#ifndef _CBC_TEST_H +#define _CBC_TEST_H + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include + +extern int cbc_test_encrypt ( struct cipher_algorithm *cipher, const void *key, + size_t key_len, const void *iv, + const void *plaintext, + const void *expected_ciphertext, size_t len ); +extern int cbc_test_decrypt ( struct cipher_algorithm *cipher, const void *key, + size_t key_len, const void *iv, + const void *ciphertext, + const void *expected_plaintext, size_t len ); + +/** + * Report CBC encryption test result + * + * @v cipher Cipher algorithm + * @v key Key + * @v key_len Length of key + * @v iv Initialisation vector + * @v plaintext Plaintext data + * @v expected_ciphertext Expected ciphertext data + * @v len Length of data + */ +#define cbc_encrypt_ok( cipher, key, key_len, iv, plaintext, \ + expected_ciphertext, len ) do { \ + ok ( cbc_test_encrypt ( cipher, key, key_len, iv, plaintext, \ + expected_ciphertext, len ) ); \ + } while ( 0 ) + +/** + * Report CBC decryption test result + * + * @v cipher Cipher algorithm + * @v key Key + * @v key_len Length of key + * @v iv Initialisation vector + * @v ciphertext Ciphertext data + * @v expected_plaintext Expected plaintext data + * @v len Length of data + */ +#define cbc_decrypt_ok( cipher, key, key_len, iv, ciphertext, \ + expected_plaintext, len ) do { \ + ok ( cbc_test_decrypt ( cipher, key, key_len, iv, ciphertext, \ + expected_plaintext, len ) ); \ + } while ( 0 ) + +#endif /* _CBC_TEST_H */ diff --git a/src/tests/tests.c b/src/tests/tests.c index 8e034afb..c759de7f 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -30,5 +30,6 @@ REQUIRE_OBJECT ( byteswap_test ); REQUIRE_OBJECT ( md5_test ); REQUIRE_OBJECT ( sha1_test ); REQUIRE_OBJECT ( sha256_test ); +REQUIRE_OBJECT ( aes_cbc_test ); REQUIRE_OBJECT ( hmac_drbg_test ); REQUIRE_OBJECT ( hash_df_test ); From 18ff2ad53e2e6fdaca071f0b5b02b8f9666024c1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 6 Mar 2012 22:02:15 +0000 Subject: [PATCH 059/221] [debug] Ensure debug address and colourisation fields are fully initialised Signed-off-by: Michael Brown --- src/include/compiler.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/compiler.h b/src/include/compiler.h index feea5167..9a751d3b 100644 --- a/src/include/compiler.h +++ b/src/include/compiler.h @@ -339,6 +339,7 @@ int __debug_disable; unsigned long ul; \ typeof ( dispaddr ) raw; \ } da; \ + da.ul = 0; \ da.raw = dispaddr; \ dbg_hex_dump_da ( da.ul, data, len ); \ } \ @@ -370,6 +371,7 @@ int __debug_disable; unsigned long ul; \ typeof ( dispaddr ) raw; \ } da; \ + da.ul = 0; \ da.raw = dispaddr; \ dbg_md5_da ( da.ul, data, len ); \ } \ @@ -421,6 +423,7 @@ int __debug_disable; unsigned long ul; \ typeof ( id ) raw; \ } dbg_stream; \ + dbg_stream.ul = 0; \ dbg_stream.raw = id; \ dbg_autocolourise ( dbg_stream.ul ); \ } \ From 8ad1e7ac128e0eb2f53943288e08ed23694ddfa9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 7 Mar 2012 00:33:19 +0000 Subject: [PATCH 060/221] [test] Avoid using "static const" for test declarations gcc will not warn about unused constant static variables. An unused test declaration is almost certainly a bug, so ensure that warnings are generated. Signed-off-by: Michael Brown --- src/tests/aes_cbc_test.c | 2 +- src/tests/hash_df_test.c | 2 +- src/tests/hmac_drbg_test.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tests/aes_cbc_test.c b/src/tests/aes_cbc_test.c index 77622b25..371ec81b 100644 --- a/src/tests/aes_cbc_test.c +++ b/src/tests/aes_cbc_test.c @@ -86,7 +86,7 @@ struct aes_cbc_test { static const uint8_t name ## _iv [] = iv_array; \ static const uint8_t name ## _plaintext [] = plaintext_array; \ static const uint8_t name ## _ciphertext [] = ciphertext_array; \ - static const struct aes_cbc_test name = { \ + static struct aes_cbc_test name = { \ .key = name ## _key, \ .key_len = sizeof ( name ## _key ), \ .iv = name ## _iv, \ diff --git a/src/tests/hash_df_test.c b/src/tests/hash_df_test.c index 0fb28492..ccbc86ea 100644 --- a/src/tests/hash_df_test.c +++ b/src/tests/hash_df_test.c @@ -71,7 +71,7 @@ struct hash_df_test { #define HASH_DF_TEST( name, hash_algorithm, input_array, expected_array ) \ static const uint8_t name ## _input [] = input_array; \ static const uint8_t name ## _expected [] = expected_array; \ - static const struct hash_df_test name = { \ + static struct hash_df_test name = { \ .hash = &(hash_algorithm), \ .input = name ## _input, \ .input_len = sizeof ( name ## _input ), \ diff --git a/src/tests/hmac_drbg_test.c b/src/tests/hmac_drbg_test.c index 299d8949..d03efef0 100644 --- a/src/tests/hmac_drbg_test.c +++ b/src/tests/hmac_drbg_test.c @@ -87,7 +87,7 @@ struct hmac_drbg_test_instantiate { key, value ) \ static const uint8_t name ## _key [] = key; \ static const uint8_t name ## _value [] = value; \ - static const struct hmac_drbg_test_instantiate name = { \ + static struct hmac_drbg_test_instantiate name = { \ .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ .out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ), \ .entropy = entropy_array, \ @@ -169,7 +169,7 @@ struct hmac_drbg_test_reseed { additional_array, key, value ) \ static const uint8_t name ## _key [] = key; \ static const uint8_t name ## _value [] = value; \ - static const struct hmac_drbg_test_reseed name = { \ + static struct hmac_drbg_test_reseed name = { \ .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ .out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ), \ .entropy = entropy_array, \ @@ -240,7 +240,7 @@ struct hmac_drbg_test_generate { static const uint8_t name ## _key [] = key; \ static const uint8_t name ## _value [] = value; \ static const uint8_t name ## _data [] = data; \ - static const struct hmac_drbg_test_generate name = { \ + static struct hmac_drbg_test_generate name = { \ .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ .out_len = HMAC_DRBG_OUTLEN_BYTES ( hmac_drbg ), \ .additional = additional_array, \ @@ -300,7 +300,7 @@ struct hmac_drbg_test_generate_fail { */ #define HMAC_DRBG_TEST_GENERATE_FAIL( name, hmac_drbg, \ additional_array, len ) \ - static const struct hmac_drbg_test_generate_fail name = { \ + static struct hmac_drbg_test_generate_fail name = { \ .hash = HMAC_DRBG_HASH ( hmac_drbg ), \ .additional = additional_array, \ .additional_len = sizeof ( additional_array ), \ From b4bb39909eac7f1bf0fc59c5397e9caaa16a1a59 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 9 Mar 2012 17:07:53 +0000 Subject: [PATCH 061/221] [prefix] Eliminate uninitialised variable Signed-off-by: Michael Brown --- src/arch/i386/core/runtime.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/arch/i386/core/runtime.c b/src/arch/i386/core/runtime.c index 2053bf21..7d410c99 100644 --- a/src/arch/i386/core/runtime.c +++ b/src/arch/i386/core/runtime.c @@ -193,6 +193,7 @@ static int initrd_init ( void ) { if ( ! image ) { DBGC ( colour, "RUNTIME could not allocate image for " "initrd\n" ); + rc = -ENOMEM; goto err_alloc_image; } image_set_name ( image, "" ); @@ -202,6 +203,7 @@ static int initrd_init ( void ) { if ( ! image->data ) { DBGC ( colour, "RUNTIME could not allocate %zd bytes for " "initrd\n", initrd_len ); + rc = -ENOMEM; goto err_umalloc; } image->len = initrd_len; From 74b1e706a8cc4a85b82ec6afb8389c9af4eb87b7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 9 Mar 2012 17:08:53 +0000 Subject: [PATCH 062/221] [ath9k] Fix compilation on older gcc versions Signed-off-by: Michael Brown --- src/drivers/net/ath/ath9k/ath9k_mac.c | 2 +- src/drivers/net/ath/ath9k/mac.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/drivers/net/ath/ath9k/ath9k_mac.c b/src/drivers/net/ath/ath9k/ath9k_mac.c index fbb3c334..c2f6d630 100644 --- a/src/drivers/net/ath/ath9k/ath9k_mac.c +++ b/src/drivers/net/ath/ath9k/ath9k_mac.c @@ -638,7 +638,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER)); } -void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints) +void ath9k_hw_set_interrupts(struct ath_hw *ah, unsigned int ints) { enum ath9k_int omask = ah->imask; u32 mask, mask2; diff --git a/src/drivers/net/ath/ath9k/mac.h b/src/drivers/net/ath/ath9k/mac.h index c11fe4a5..5899230e 100644 --- a/src/drivers/net/ath/ath9k/mac.h +++ b/src/drivers/net/ath/ath9k/mac.h @@ -668,7 +668,6 @@ enum ath9k_key_type { struct ath_hw; struct ath9k_channel; -enum ath9k_int; u32 ath9k_hw_gettxbuf(struct ath_hw *ah, u32 q); void ath9k_hw_puttxbuf(struct ath_hw *ah, u32 q, u32 txdp); @@ -699,7 +698,7 @@ int ath9k_hw_stopdmarecv(struct ath_hw *ah, int *reset); /* Interrupt Handling */ int ath9k_hw_intrpend(struct ath_hw *ah); -void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints); +void ath9k_hw_set_interrupts(struct ath_hw *ah, unsigned int ints); void ath9k_hw_enable_interrupts(struct ath_hw *ah); void ath9k_hw_disable_interrupts(struct ath_hw *ah); From 1c29b4d979a9ea9be49bb942a2c41b7b6dc0dc9e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 9 Mar 2012 15:45:56 +0000 Subject: [PATCH 063/221] [crypto] Upgrade AES and RSA code to upstream axTLS version 1.4.5 All axTLS files are now vanilla versions of the upstream axTLS files, with one minor exception: the unused "ctx" parameter of bi_int_divide() has been marked with "__unused" to avoid a compilation error. Signed-off-by: Michael Brown --- src/crypto/axtls/aes.c | 191 +++++++++------------ src/crypto/axtls/bigint.c | 303 +++++++++++++++++---------------- src/crypto/axtls/bigint.h | 60 ++++--- src/crypto/axtls/bigint_impl.h | 66 ++++--- src/crypto/axtls/config.h | 13 ++ src/crypto/axtls/crypto.h | 242 +++++++++----------------- src/crypto/axtls/os_port.h | 71 ++++---- src/crypto/axtls/rsa.c | 143 +++++----------- src/crypto/axtls_aes.c | 5 +- src/crypto/x509.c | 10 ++ src/include/ipxe/aes.h | 4 + src/net/tls.c | 2 +- 12 files changed, 508 insertions(+), 602 deletions(-) create mode 100644 src/crypto/axtls/config.h diff --git a/src/crypto/axtls/aes.c b/src/crypto/axtls/aes.c index 87faaa1d..bd99a709 100644 --- a/src/crypto/axtls/aes.c +++ b/src/crypto/axtls/aes.c @@ -1,23 +1,33 @@ /* - * Copyright(C) 2006 Cameron Rich + * Copyright (c) 2007, Cameron Rich * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * All rights reserved. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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 OWNER 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. */ -FILE_LICENCE ( GPL2_OR_LATER ); - /** * AES implementation - this is a small code version. There are much faster * versions around but they are much larger in size (i.e. they use large @@ -25,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #include +#include "os_port.h" #include "crypto.h" /* all commented out in skeleton mode */ @@ -64,10 +75,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); (f8)^=rot2(f4), \ (f8)^rot1(f9)) -/* some macros to do endian independent byte extraction */ -#define n2l(c,l) l=ntohl(*c); c++ -#define l2n(l,c) *c++=htonl(l) - /* * AES S-box */ @@ -154,11 +161,15 @@ static const unsigned char Rcon[30]= 0xb3,0x7d,0xfa,0xef,0xc5,0x91, }; +/* ----- static functions ----- */ +static void AES_encrypt(const AES_CTX *ctx, uint32_t *data); +static void AES_decrypt(const AES_CTX *ctx, uint32_t *data); + /* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial x^8+x^4+x^3+x+1 */ static unsigned char AES_xtime(uint32_t x) { - return x = (x&0x80) ? (x<<1)^0x1b : x<<1; + return (x&0x80) ? (x<<1)^0x1b : x<<1; } /** @@ -247,7 +258,7 @@ void AES_convert_key(AES_CTX *ctx) k = ctx->ks; k += 4; - for (i=ctx->rounds*4; i>4; i--) + for (i= ctx->rounds*4; i > 4; i--) { w= *k; w = inv_mix_col(w,t1,t2,t3,t4); @@ -255,52 +266,43 @@ void AES_convert_key(AES_CTX *ctx) } } -#if 0 /** * Encrypt a byte sequence (with a block size 16) using the AES cipher. */ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) { - uint32_t tin0, tin1, tin2, tin3; - uint32_t tout0, tout1, tout2, tout3; - uint32_t tin[4]; - uint32_t *iv = (uint32_t *)ctx->iv; - uint32_t *msg_32 = (uint32_t *)msg; - uint32_t *out_32 = (uint32_t *)out; + int i; + uint32_t tin[4], tout[4], iv[4]; - n2l(iv, tout0); - n2l(iv, tout1); - n2l(iv, tout2); - n2l(iv, tout3); - iv -= 4; + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + tout[i] = ntohl(iv[i]); - for (length -= 16; length >= 0; length -= 16) + for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE) { - n2l(msg_32, tin0); - n2l(msg_32, tin1); - n2l(msg_32, tin2); - n2l(msg_32, tin3); - tin[0] = tin0^tout0; - tin[1] = tin1^tout1; - tin[2] = tin2^tout2; - tin[3] = tin3^tout3; + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; + + for (i = 0; i < 4; i++) + tin[i] = ntohl(msg_32[i])^tout[i]; AES_encrypt(ctx, tin); - tout0 = tin[0]; - l2n(tout0, out_32); - tout1 = tin[1]; - l2n(tout1, out_32); - tout2 = tin[2]; - l2n(tout2, out_32); - tout3 = tin[3]; - l2n(tout3, out_32); + for (i = 0; i < 4; i++) + { + tout[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } + + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; } - l2n(tout0, iv); - l2n(tout1, iv); - l2n(tout2, iv); - l2n(tout3, iv); + for (i = 0; i < 4; i++) + iv[i] = htonl(tout[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); } /** @@ -308,61 +310,48 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) */ void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length) { - uint32_t tin0, tin1, tin2, tin3; - uint32_t xor0,xor1,xor2,xor3; - uint32_t tout0,tout1,tout2,tout3; - uint32_t data[4]; - uint32_t *iv = (uint32_t *)ctx->iv; - uint32_t *msg_32 = (uint32_t *)msg; - uint32_t *out_32 = (uint32_t *)out; + int i; + uint32_t tin[4], xor[4], tout[4], data[4], iv[4]; - n2l(iv ,xor0); - n2l(iv, xor1); - n2l(iv, xor2); - n2l(iv, xor3); - iv -= 4; + memcpy(iv, ctx->iv, AES_IV_SIZE); + for (i = 0; i < 4; i++) + xor[i] = ntohl(iv[i]); - for (length-=16; length >= 0; length -= 16) + for (length -= 16; length >= 0; length -= 16) { - n2l(msg_32, tin0); - n2l(msg_32, tin1); - n2l(msg_32, tin2); - n2l(msg_32, tin3); + uint32_t msg_32[4]; + uint32_t out_32[4]; + memcpy(msg_32, msg, AES_BLOCKSIZE); + msg += AES_BLOCKSIZE; - data[0] = tin0; - data[1] = tin1; - data[2] = tin2; - data[3] = tin3; + for (i = 0; i < 4; i++) + { + tin[i] = ntohl(msg_32[i]); + data[i] = tin[i]; + } AES_decrypt(ctx, data); - tout0 = data[0]^xor0; - tout1 = data[1]^xor1; - tout2 = data[2]^xor2; - tout3 = data[3]^xor3; + for (i = 0; i < 4; i++) + { + tout[i] = data[i]^xor[i]; + xor[i] = tin[i]; + out_32[i] = htonl(tout[i]); + } - xor0 = tin0; - xor1 = tin1; - xor2 = tin2; - xor3 = tin3; - - l2n(tout0, out_32); - l2n(tout1, out_32); - l2n(tout2, out_32); - l2n(tout3, out_32); + memcpy(out, out_32, AES_BLOCKSIZE); + out += AES_BLOCKSIZE; } - l2n(xor0, iv); - l2n(xor1, iv); - l2n(xor2, iv); - l2n(xor3, iv); + for (i = 0; i < 4; i++) + iv[i] = htonl(xor[i]); + memcpy(ctx->iv, iv, AES_IV_SIZE); } -#endif /** * Encrypt a single block (16 bytes) of data */ -void AES_encrypt(const AES_CTX *ctx, uint32_t *data) +static void AES_encrypt(const AES_CTX *ctx, uint32_t *data) { /* To make this code smaller, generate the sbox entries on the fly. * This will have a really heavy effect upon performance. @@ -375,9 +364,7 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data) /* Pre-round key addition */ for (row = 0; row < 4; row++) - { data[row] ^= *(k++); - } /* Encrypt one block. */ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++) @@ -395,12 +382,10 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data) { tmp1 = a0 ^ a1 ^ a2 ^ a3; old_a0 = a0; - a0 ^= tmp1 ^ AES_xtime(a0 ^ a1); a1 ^= tmp1 ^ AES_xtime(a1 ^ a2); a2 ^= tmp1 ^ AES_xtime(a2 ^ a3); a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0); - } tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3); @@ -409,32 +394,28 @@ void AES_encrypt(const AES_CTX *ctx, uint32_t *data) /* KeyAddition - note that it is vital that this loop is separate from the MixColumn operation, which must be atomic...*/ for (row = 0; row < 4; row++) - { data[row] = tmp[row] ^ *(k++); - } } } /** * Decrypt a single block (16 bytes) of data */ -void AES_decrypt(const AES_CTX *ctx, uint32_t *data) +static void AES_decrypt(const AES_CTX *ctx, uint32_t *data) { uint32_t tmp[4]; uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6; uint32_t a0, a1, a2, a3, row; int curr_rnd; int rounds = ctx->rounds; - uint32_t *k = (uint32_t*)ctx->ks + ((rounds+1)*4); + const uint32_t *k = ctx->ks + ((rounds+1)*4); /* pre-round key addition */ for (row=4; row > 0;row--) - { data[row-1] ^= *(--k); - } /* Decrypt one block */ - for (curr_rnd=0; curr_rnd < rounds; curr_rnd++) + for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++) { /* Perform ByteSub and ShiftRow operations together */ for (row = 4; row > 0; row--) @@ -469,9 +450,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data) } for (row = 4; row > 0; row--) - { data[row-1] = tmp[row-1] ^ *(--k); - } } } diff --git a/src/crypto/axtls/bigint.c b/src/crypto/axtls/bigint.c index 49cad971..e228a218 100644 --- a/src/crypto/axtls/bigint.c +++ b/src/crypto/axtls/bigint.c @@ -1,19 +1,31 @@ /* - * Copyright(C) 2006 Cameron Rich + * Copyright (c) 2007, Cameron Rich * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * All rights reserved. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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 OWNER 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. */ /** @@ -53,12 +65,17 @@ #include #include #include +#include "os_port.h" #include "bigint.h" -#include "crypto.h" + +#define V1 v->comps[v->size-1] /**< v1 for division */ +#define V2 v->comps[v->size-2] /**< v2 for division */ +#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */ +#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */ static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); -static bigint __malloc *alloc(BI_CTX *ctx, int size); +static bigint *alloc(BI_CTX *ctx, int size); static bigint *trim(bigint *bi); static void more_comps(bigint *bi, int n); #if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ @@ -69,8 +86,11 @@ static bigint *comp_left_shift(bigint *biR, int num_shifts); #ifdef CONFIG_BIGINT_CHECK_ON static void check(const bigint *bi); +#else +#define check(A) /**< disappears in normal production mode */ #endif + /** * @brief Start a new bigint context. * @return A bigint context. @@ -97,8 +117,6 @@ BI_CTX *bi_initialize(void) */ void bi_terminate(BI_CTX *ctx) { - bigint *p, *pn; - bi_depermanent(ctx->bi_radix); bi_free(ctx, ctx->bi_radix); @@ -111,6 +129,20 @@ void bi_terminate(BI_CTX *ctx) abort(); } + bi_clear_cache(ctx); + free(ctx); +} + +/** + *@brief Clear the memory cache. + */ +void bi_clear_cache(BI_CTX *ctx) +{ + bigint *p, *pn; + + if (ctx->free_list == NULL) + return; + for (p = ctx->free_list; p != NULL; p = pn) { pn = p->next; @@ -118,7 +150,8 @@ void bi_terminate(BI_CTX *ctx) free(p); } - free(ctx); + ctx->free_count = 0; + ctx->free_list = NULL; } /** @@ -410,18 +443,18 @@ bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) else { q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1); - } - if (v->size > 1 && V2) - { - /* we are implementing the following: - if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - - q_dash*V1)*COMP_RADIX) + U(2))) ... */ - comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - - (long_comp)q_dash*V1); - if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2)) + if (v->size > 1 && V2) { - q_dash--; + /* we are implementing the following: + if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - + q_dash*V1)*COMP_RADIX) + U(2))) ... */ + comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - + (long_comp)q_dash*V1); + if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2)) + { + q_dash--; + } } } @@ -473,6 +506,7 @@ bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) /* * Perform an integer divide on a bigint. */ +// mcb30 - mark ctx with __unused to avoid a compilation error static bigint *bi_int_divide(BI_CTX *ctx __unused, bigint *biR, comp denom) { int i = biR->size - 1; @@ -485,7 +519,7 @@ static bigint *bi_int_divide(BI_CTX *ctx __unused, bigint *biR, comp denom) r = (r<comps[i]; biR->comps[i] = (comp)(r / denom); r %= denom; - } while (--i != 0); + } while (--i >= 0); return trim(biR); } @@ -690,10 +724,11 @@ void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) if (k < 0) { - break; + goto buf_done; } } } +buf_done: bi_free(ctx, x); } @@ -769,11 +804,16 @@ void bi_free_mod(BI_CTX *ctx, int mod_offset) /** * Perform a standard multiplication between two bigints. + * + * Barrett reduction has no need for some parts of the product, so ignore bits + * of the multiply. This routine gives Barrett its big performance + * improvements over Classical/Montgomery reduction methods. */ -static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) +static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, + int inner_partial, int outer_partial) { - int i, j, i_plus_j; - int n = bia->size; + int i = 0, j; + int n = bia->size; int t = bib->size; bigint *biR = alloc(ctx, n + t); comp *sr = biR->comps; @@ -785,23 +825,33 @@ static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) /* clear things to start with */ memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE)); - i = 0; do { + long_comp tmp; comp carry = 0; - comp b = *sb++; - i_plus_j = i; + int r_index = i; j = 0; + if (outer_partial && outer_partial-i > 0 && outer_partial < n) + { + r_index = outer_partial-1; + j = outer_partial-i-1; + } + do { - long_comp tmp = sr[i_plus_j] + (long_comp)sa[j]*b + carry; - sr[i_plus_j++] = (comp)tmp; /* downsize */ - carry = (comp)(tmp >> COMP_BIT_SIZE); + if (inner_partial && r_index >= inner_partial) + { + break; + } + + tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry; + sr[r_index++] = (comp)tmp; /* downsize */ + carry = tmp >> COMP_BIT_SIZE; } while (++j < n); - sr[i_plus_j] = carry; + sr[r_index] = carry; } while (++i < t); bi_free(ctx, bia); @@ -881,12 +931,12 @@ bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) #ifdef CONFIG_BIGINT_KARATSUBA if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH) { - return regular_multiply(ctx, bia, bib); + return regular_multiply(ctx, bia, bib, 0, 0); } return karatsuba(ctx, bia, bib, 0); #else - return regular_multiply(ctx, bia, bib); + return regular_multiply(ctx, bia, bib, 0, 0); #endif } @@ -898,47 +948,46 @@ static bigint *regular_square(BI_CTX *ctx, bigint *bi) { int t = bi->size; int i = 0, j; - bigint *biR = alloc(ctx, t*2); + bigint *biR = alloc(ctx, t*2+1); comp *w = biR->comps; comp *x = bi->comps; - comp carry; - + long_comp carry; memset(w, 0, biR->size*COMP_BYTE_SIZE); do { long_comp tmp = w[2*i] + (long_comp)x[i]*x[i]; - comp u = 0; w[2*i] = (comp)tmp; - carry = (comp)(tmp >> COMP_BIT_SIZE); + carry = tmp >> COMP_BIT_SIZE; for (j = i+1; j < t; j++) { + uint8_t c = 0; long_comp xx = (long_comp)x[i]*x[j]; - long_comp blob = (long_comp)w[i+j]+carry; + if ((COMP_MAX-xx) < xx) + c = 1; - if (u) /* previous overflow */ - { - blob += COMP_RADIX; - } + tmp = (xx<<1); - u = 0; - if (xx & COMP_BIG_MSB) /* check for overflow */ - { - u = 1; - } + if ((COMP_MAX-tmp) < w[i+j]) + c = 1; - tmp = 2*xx + blob; + tmp += w[i+j]; + + if ((COMP_MAX-tmp) < carry) + c = 1; + + tmp += carry; w[i+j] = (comp)tmp; - carry = (comp)(tmp >> COMP_BIT_SIZE); + carry = tmp >> COMP_BIT_SIZE; + + if (c) + carry += COMP_RADIX; } - w[i+t] += carry; - - if (u) - { - w[i+t+1] = 1; /* add carry */ - } + tmp = w[i+t] + carry; + w[i+t] = (comp)tmp; + w[i+t+1] = tmp >> COMP_BIT_SIZE; } while (++i < t); bi_free(ctx, bi); @@ -1092,7 +1141,7 @@ static int find_max_exp_index(bigint *biexp) } shift >>= 1; - } while (--i != 0); + } while (i-- != 0); return -1; /* error - must have been a leading 0 */ } @@ -1115,7 +1164,7 @@ static int exp_bit_is_one(bigint *biexp, int offset) shift <<= 1; } - return test & shift; + return (test & shift) != 0; } #ifdef CONFIG_BIGINT_CHECK_ON @@ -1210,81 +1259,6 @@ static bigint *comp_mod(bigint *bi, int mod) return bi; } -/* - * Barrett reduction has no need for some parts of the product, so ignore bits - * of the multiply. This routine gives Barrett its big performance - * improvements over Classical/Montgomery reduction methods. - */ -static bigint *partial_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, - int inner_partial, int outer_partial) -{ - int i = 0, j, n = bia->size, t = bib->size; - bigint *biR; - comp carry; - comp *sr, *sa, *sb; - - check(bia); - check(bib); - - biR = alloc(ctx, n + t); - sa = bia->comps; - sb = bib->comps; - sr = biR->comps; - - if (inner_partial) - { - memset(sr, 0, inner_partial*COMP_BYTE_SIZE); - } - else /* outer partial */ - { - if (n < outer_partial || t < outer_partial) /* should we bother? */ - { - bi_free(ctx, bia); - bi_free(ctx, bib); - biR->comps[0] = 0; /* return 0 */ - biR->size = 1; - return biR; - } - - memset(&sr[outer_partial], 0, (n+t-outer_partial)*COMP_BYTE_SIZE); - } - - do - { - comp *a = sa; - comp b = *sb++; - long_comp tmp; - int i_plus_j = i; - carry = 0; - j = n; - - if (outer_partial && i_plus_j < outer_partial) - { - i_plus_j = outer_partial; - a = &sa[outer_partial-i]; - j = n-(outer_partial-i); - } - - do - { - if (inner_partial && i_plus_j >= inner_partial) - { - break; - } - - tmp = sr[i_plus_j] + ((long_comp)*a++)*b + carry; - sr[i_plus_j++] = (comp)tmp; /* downsize */ - carry = (comp)(tmp >> COMP_BIT_SIZE); - } while (--j != 0); - - sr[i_plus_j] = carry; - } while (++i < t); - - bi_free(ctx, bia); - bi_free(ctx, bib); - return trim(biR); -} - /** * @brief Perform a single Barrett reduction. * @param ctx [in] The bigint session context. @@ -1310,12 +1284,12 @@ bigint *bi_barrett(BI_CTX *ctx, bigint *bi) q1 = comp_right_shift(bi_clone(ctx, bi), k-1); /* do outer partial multiply */ - q2 = partial_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); + q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); q3 = comp_right_shift(q2, k+1); r1 = comp_mod(bi, k+1); /* do inner partial multiply */ - r2 = comp_mod(partial_multiply(ctx, q3, bim, k+1, 0), k+1); + r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1); r = bi_subtract(ctx, r1, r2, NULL); /* if (r >= m) r = r - m; */ @@ -1366,6 +1340,7 @@ static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) * @param ctx [in] The bigint session context. * @param bi [in] The bigint on which to perform the mod power operation. * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation * @see bi_set_mod(). */ bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) @@ -1467,6 +1442,7 @@ bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) * @param bi [in] The bigint to perform the exp/mod. * @param bim [in] The temporary modulus. * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation * @see bi_set_mod(). */ bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp) @@ -1493,4 +1469,45 @@ bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp) return biR; } #endif + +#ifdef CONFIG_BIGINT_CRT +/** + * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. + * + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param dP [in] CRT's dP bigint + * @param dQ [in] CRT's dQ bigint + * @param p [in] CRT's p bigint + * @param q [in] CRT's q bigint + * @param qInv [in] CRT's qInv bigint + * @return The result of the CRT operation + */ +bigint *bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, bigint *qInv) +{ + bigint *m1, *m2, *h; + + /* Montgomery has a condition the 0 < x, y < m and these products violate + * that condition. So disable Montgomery when using CRT */ +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 1; +#endif + ctx->mod_offset = BIGINT_P_OFFSET; + m1 = bi_mod_power(ctx, bi_copy(bi), dP); + + ctx->mod_offset = BIGINT_Q_OFFSET; + m2 = bi_mod_power(ctx, bi, dQ); + + h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); + h = bi_multiply(ctx, h, qInv); + ctx->mod_offset = BIGINT_P_OFFSET; + h = bi_residue(ctx, h); +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 0; /* reset for any further operation */ +#endif + return bi_add(ctx, m2, bi_multiply(ctx, q, h)); +} +#endif /** @} */ diff --git a/src/crypto/axtls/bigint.h b/src/crypto/axtls/bigint.h index f5f33531..1f38c53d 100644 --- a/src/crypto/axtls/bigint.h +++ b/src/crypto/axtls/bigint.h @@ -1,44 +1,43 @@ /* - * Copyright(C) 2006 Cameron Rich + * Copyright (c) 2007, Cameron Rich * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * All rights reserved. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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 OWNER 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. */ -FILE_LICENCE ( GPL2_OR_LATER ); - #ifndef BIGINT_HEADER #define BIGINT_HEADER -/* enable features based on a 'super-set' capbaility. */ -#if defined(CONFIG_SSL_FULL_MODE) -#define CONFIG_SSL_ENABLE_CLIENT -#define CONFIG_SSL_CERT_VERIFICATION -#elif defined(CONFIG_SSL_ENABLE_CLIENT) -#define CONFIG_SSL_CERT_VERIFICATION -#endif +#include "crypto.h" -#include "os_port.h" -#include "bigint_impl.h" - -#ifndef CONFIG_BIGINT_CHECK_ON -#define check(A) /**< disappears in normal production mode */ -#endif BI_CTX *bi_initialize(void); void bi_terminate(BI_CTX *ctx); void bi_permanent(bigint *bi); void bi_depermanent(bigint *bi); +void bi_clear_cache(BI_CTX *ctx); void bi_free(BI_CTX *ctx, bigint *bi); bigint *bi_copy(bigint *bi); bigint *bi_clone(BI_CTX *ctx, const bigint *bi); @@ -90,4 +89,11 @@ bigint *bi_square(BI_CTX *ctx, bigint *bi); #define bi_square(A, B) bi_multiply(A, bi_copy(B), B) #endif +#ifdef CONFIG_BIGINT_CRT +bigint *bi_crt(BI_CTX *ctx, bigint *bi, + bigint *dP, bigint *dQ, + bigint *p, bigint *q, + bigint *qInv); +#endif + #endif diff --git a/src/crypto/axtls/bigint_impl.h b/src/crypto/axtls/bigint_impl.h index 762a7ccb..09d8550e 100644 --- a/src/crypto/axtls/bigint_impl.h +++ b/src/crypto/axtls/bigint_impl.h @@ -1,19 +1,31 @@ /* - * Copyright(C) 2006 Cameron Rich + * Copyright (c) 2007, Cameron Rich * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * All rights reserved. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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 OWNER 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. */ #ifndef BIGINT_IMPL_HEADER @@ -30,20 +42,39 @@ #endif /* Architecture specific functions for big ints */ +#if defined(CONFIG_INTEGER_8BIT) +#define COMP_RADIX 256U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */ +typedef uint8_t comp; /**< A single precision component. */ +typedef uint16_t long_comp; /**< A double precision component. */ +typedef int16_t slong_comp; /**< A signed double precision component. */ +#elif defined(CONFIG_INTEGER_16BIT) +#define COMP_RADIX 65536U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */ +typedef uint16_t comp; /**< A single precision component. */ +typedef uint32_t long_comp; /**< A double precision component. */ +typedef int32_t slong_comp; /**< A signed double precision component. */ +#else /* regular 32 bit */ #ifdef WIN32 #define COMP_RADIX 4294967296i64 -#define COMP_BIG_MSB 0x8000000000000000i64 +#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 #else #define COMP_RADIX 4294967296ULL /**< Max component + 1 */ -#define COMP_BIG_MSB 0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */ +#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */ #endif #define COMP_BIT_SIZE 32 /**< Number of bits in a component. */ #define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */ #define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */ - typedef uint32_t comp; /**< A single precision component. */ typedef uint64_t long_comp; /**< A double precision component. */ typedef int64_t slong_comp; /**< A signed double precision component. */ +#endif /** * @struct _bigint @@ -97,9 +128,4 @@ typedef struct /**< A big integer "session" context. */ #define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ -#define V1 v->comps[v->size-1] /**< v1 for division */ -#define V2 v->comps[v->size-2] /**< v2 for division */ -#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */ -#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */ - #endif diff --git a/src/crypto/axtls/config.h b/src/crypto/axtls/config.h new file mode 100644 index 00000000..32fa3bf0 --- /dev/null +++ b/src/crypto/axtls/config.h @@ -0,0 +1,13 @@ +#ifndef AXTLS_CONFIG_H +#define AXTLS_CONFIG_H + +/** + * @file config.h + * + * Trick the axtls code into building within our build environment. + */ + +#define CONFIG_SSL_ENABLE_CLIENT 1 +#define CONFIG_BIGINT_CLASSICAL 1 + +#endif diff --git a/src/crypto/axtls/crypto.h b/src/crypto/axtls/crypto.h index b7af7c41..2c4cda4d 100644 --- a/src/crypto/axtls/crypto.h +++ b/src/crypto/axtls/crypto.h @@ -1,23 +1,33 @@ /* - * Copyright(C) 2006 Cameron Rich + * Copyright (c) 2007, Cameron Rich * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * All rights reserved. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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 OWNER 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. */ -FILE_LICENCE ( GPL2_OR_LATER ); - /** * @file crypto.h */ @@ -29,20 +39,40 @@ FILE_LICENCE ( GPL2_OR_LATER ); extern "C" { #endif +#include "config.h" +#include "bigint_impl.h" #include "bigint.h" +#ifndef STDCALL +#define STDCALL +#endif +#ifndef EXP_FUNC +#define EXP_FUNC +#endif + + +/* enable features based on a 'super-set' capbaility. */ +#if defined(CONFIG_SSL_FULL_MODE) +#define CONFIG_SSL_ENABLE_CLIENT +#define CONFIG_SSL_CERT_VERIFICATION +#elif defined(CONFIG_SSL_ENABLE_CLIENT) +#define CONFIG_SSL_CERT_VERIFICATION +#endif + /************************************************************************** * AES declarations **************************************************************************/ #define AES_MAXROUNDS 14 +#define AES_BLOCKSIZE 16 +#define AES_IV_SIZE 16 typedef struct aes_key_st { uint16_t rounds; uint16_t key_size; uint32_t ks[(AES_MAXROUNDS+1)*8]; - uint8_t iv[16]; + uint8_t iv[AES_IV_SIZE]; } AES_CTX; typedef enum @@ -57,8 +87,6 @@ void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length); void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length); void AES_convert_key(AES_CTX *ctx); -void AES_encrypt(const AES_CTX *ctx, uint32_t *data); -void AES_decrypt(const AES_CTX *ctx, uint32_t *data); /************************************************************************** * RC4 declarations @@ -66,7 +94,7 @@ void AES_decrypt(const AES_CTX *ctx, uint32_t *data); typedef struct { - int x, y, m[256]; + uint8_t x, y, m[256]; } RC4_CTX; void RC4_setup(RC4_CTX *s, const uint8_t *key, int length); @@ -84,22 +112,38 @@ void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length); */ typedef struct { - uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */ - uint32_t Length_Low; /* Message length in bits */ - uint32_t Length_High; /* Message length in bits */ + uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */ + uint32_t Length_Low; /* Message length in bits */ + uint32_t Length_High; /* Message length in bits */ uint16_t Message_Block_Index; /* Index into message block array */ - uint8_t Message_Block[64]; /* 512-bit message blocks */ + uint8_t Message_Block[64]; /* 512-bit message blocks */ } SHA1_CTX; -void SHA1Init(SHA1_CTX *); -void SHA1Update(SHA1_CTX *, const uint8_t * msg, int len); -void SHA1Final(SHA1_CTX *, uint8_t *digest); +void SHA1_Init(SHA1_CTX *); +void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len); +void SHA1_Final(uint8_t *digest, SHA1_CTX *); /************************************************************************** - * MD5 declarations + * MD2 declarations **************************************************************************/ -/* MD5 context. */ +#define MD2_SIZE 16 + +typedef struct +{ + unsigned char cksum[16]; /* checksum of the data block */ + unsigned char state[48]; /* intermediate digest state */ + unsigned char buffer[16]; /* data block being processed */ + int left; /* amount of data in buffer */ +} MD2_CTX; + +EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx); +EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen); +EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx); + +/************************************************************************** + * MD5 declarations + **************************************************************************/ #define MD5_SIZE 16 @@ -110,9 +154,9 @@ typedef struct uint8_t buffer[64]; /* input buffer */ } MD5_CTX; -void MD5Init(MD5_CTX *); -void MD5Update(MD5_CTX *, const uint8_t *msg, int len); -void MD5Final(MD5_CTX *, uint8_t *digest); +EXP_FUNC void STDCALL MD5_Init(MD5_CTX *); +EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len); +EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *); /************************************************************************** * HMAC declarations @@ -122,26 +166,6 @@ void hmac_md5(const uint8_t *msg, int length, const uint8_t *key, void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key, int key_len, uint8_t *digest); -/************************************************************************** - * RNG declarations - **************************************************************************/ -void RNG_initialize(const uint8_t *seed_buf, int size); -void RNG_terminate(void); -void get_random(int num_rand_bytes, uint8_t *rand_data); -//void get_random_NZ(int num_rand_bytes, uint8_t *rand_data); - -#include -static inline void get_random_NZ(int num_rand_bytes, uint8_t *rand_data) { - /* AXTLS does not check for failures when generating random - * data. Rely on the fact that get_random_nz() does not - * request prediction resistance (and so cannot introduce new - * failures) and therefore any potential failure must already - * have been encountered by e.g. tls_generate_random(), which - * does check for failures. - */ - get_random_nz ( rand_data, num_rand_bytes ); -} - /************************************************************************** * RSA declarations **************************************************************************/ @@ -159,7 +183,6 @@ typedef struct bigint *qInv; /* q^-1 mod p */ #endif int num_octets; - bigint *sig_m; /* signature modulus */ BI_CTX *bi_ctx; } RSA_CTX; @@ -182,125 +205,22 @@ void RSA_free(RSA_CTX *ctx); int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, int is_decryption); bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg); -#ifdef CONFIG_SSL_CERT_VERIFICATION -bigint *RSA_raw_sign_verify(RSA_CTX *c, bigint *bi_msg); +#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, bigint *modulus, bigint *pub_exp); -bigint *RSA_public(const RSA_CTX *c, bigint *bi_msg); +bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg); int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, uint8_t *out_data, int is_signing); void RSA_print(const RSA_CTX *ctx); #endif /************************************************************************** - * ASN1 declarations + * RNG declarations **************************************************************************/ -#define X509_OK 0 -#define X509_NOT_OK -1 -#define X509_VFY_ERROR_NO_TRUSTED_CERT -2 -#define X509_VFY_ERROR_BAD_SIGNATURE -3 -#define X509_VFY_ERROR_NOT_YET_VALID -4 -#define X509_VFY_ERROR_EXPIRED -5 -#define X509_VFY_ERROR_SELF_SIGNED -6 -#define X509_VFY_ERROR_INVALID_CHAIN -7 -#define X509_VFY_ERROR_UNSUPPORTED_DIGEST -8 -#define X509_INVALID_PRIV_KEY -9 - -/* - * The Distinguished Name - */ -#define X509_NUM_DN_TYPES 3 -#define X509_COMMON_NAME 0 -#define X509_ORGANIZATION 1 -#define X509_ORGANIZATIONAL_TYPE 2 - -#define ASN1_INTEGER 0x02 -#define ASN1_BIT_STRING 0x03 -#define ASN1_OCTET_STRING 0x04 -#define ASN1_NULL 0x05 -#define ASN1_OID 0x06 -#define ASN1_PRINTABLE_STR 0x13 -#define ASN1_TELETEX_STR 0x14 -#define ASN1_IA5_STR 0x16 -#define ASN1_UTC_TIME 0x17 -#define ASN1_SEQUENCE 0x30 -#define ASN1_SET 0x31 -#define ASN1_IMPLICIT_TAG 0x80 -#define ASN1_EXPLICIT_TAG 0xa0 - -#define SALT_SIZE 8 - -struct _x509_ctx -{ - char *ca_cert_dn[X509_NUM_DN_TYPES]; - char *cert_dn[X509_NUM_DN_TYPES]; -#if defined(_WIN32_WCE) - long not_before; - long not_after; -#else - time_t not_before; - time_t not_after; -#endif - uint8_t *signature; - uint16_t sig_len; - uint8_t sig_type; - RSA_CTX *rsa_ctx; - bigint *digest; - struct _x509_ctx *next; -}; - -typedef struct _x509_ctx X509_CTX; - -#ifdef CONFIG_SSL_CERT_VERIFICATION -typedef struct -{ - X509_CTX *cert[CONFIG_X509_MAX_CA_CERTS]; -} CA_CERT_CTX; -#endif - -int asn1_get_private_key(const uint8_t *buf, int len, RSA_CTX **rsa_ctx); -int asn1_next_obj(const uint8_t *buf, int *offset, int obj_type); -int asn1_skip_obj(const uint8_t *buf, int *offset, int obj_type); -int asn1_get_int(const uint8_t *buf, int *offset, uint8_t **object); -int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx); -void x509_free(X509_CTX *x509_ctx); -#ifdef CONFIG_SSL_CERT_VERIFICATION -int x509_verify(const CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert); -const uint8_t *x509_get_signature(const uint8_t *asn1_signature, int *len); -#endif -#ifdef CONFIG_SSL_FULL_MODE -void x509_print(CA_CERT_CTX *ca_cert_ctx, const X509_CTX *cert); -void x509_display_error(int error); -#endif - -/************************************************************************** - * MISC declarations - **************************************************************************/ - -extern const char * const unsupported_str; - -typedef void (*crypt_func)(void *, const uint8_t *, uint8_t *, int); -typedef void (*hmac_func)(const uint8_t *msg, int length, const uint8_t *key, - int key_len, uint8_t *digest); - -typedef struct -{ - uint8_t *pre_data; /* include the ssl record bytes */ - uint8_t *data; /* the regular ssl data */ - int max_len; - int index; -} BUF_MEM; - -BUF_MEM buf_new(void); -void buf_grow(BUF_MEM *bm, int len); -void buf_free(BUF_MEM *bm); -int get_file(const char *filename, uint8_t **buf); - -#if defined(CONFIG_SSL_FULL_MODE) || defined(WIN32) || defined(CONFIG_DEBUG) -void print_blob(const char *format, const uint8_t *data, int size, ...); -#else - #define print_blob(...) -#endif +EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size); +EXP_FUNC void STDCALL RNG_terminate(void); +EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data); +void get_random_NZ(int num_rand_bytes, uint8_t *rand_data); #ifdef __cplusplus } diff --git a/src/crypto/axtls/os_port.h b/src/crypto/axtls/os_port.h index babdbfad..0a6ef54a 100644 --- a/src/crypto/axtls/os_port.h +++ b/src/crypto/axtls/os_port.h @@ -1,61 +1,54 @@ +#ifndef AXTLS_OS_PORT_H +#define AXTLS_OS_PORT_H + /** * @file os_port.h * * Trick the axtls code into building within our build environment. */ -#ifndef HEADER_OS_PORT_H -#define HEADER_OS_PORT_H - #include -#include -#include -#include -#include #include -#define STDCALL -#define EXP_FUNC -#define TTY_FLUSH() +/** All imported axTLS files are licensed using the three-clause BSD licence */ +FILE_LICENCE ( BSD3 ); /** We can't actually abort, since we are effectively a kernel... */ #define abort() assert ( 0 ) -/** crypto_misc.c has a bad #ifdef */ -static inline void close ( int fd __unused ) { - /* Do nothing */ +/** rsa.c uses alloca() */ +#define alloca( size ) __builtin_alloca ( size ) + +#include +static inline void get_random_NZ ( int num_rand_bytes, uint8_t *rand_data ) { + /* AXTLS does not check for failures when generating random + * data. Rely on the fact that get_random_nz() does not + * request prediction resistance (and so cannot introduce new + * failures) and therefore any potential failure must already + * have been encountered by e.g. tls_generate_random(), which + * does check for failures. + */ + get_random_nz ( rand_data, num_rand_bytes ); } -typedef void FILE; +/* Expose AES_encrypt() and AES_decrypt() in aes.o */ +#define aes 1 +#if OBJECT -static inline FILE * fopen ( const char *filename __unused, - const char *mode __unused ) { - return NULL; +/* AES_CTX is not defined at this point, so omit prototypes */ + +static void AES_encrypt(); +static void AES_decrypt(); + +void axtls_aes_encrypt ( void *ctx, uint32_t *data ) { + AES_encrypt ( ctx, data ); } -static inline int fseek ( FILE *stream __unused, long offset __unused, - int whence __unused ) { - return -1; +void axtls_aes_decrypt ( void *ctx, uint32_t *data ) { + AES_decrypt ( ctx, data ); } -static inline long ftell ( FILE *stream __unused ) { - return -1; -} - -static inline size_t fread ( void *ptr __unused, size_t size __unused, - size_t nmemb __unused, FILE *stream __unused ) { - return -1; -} - -static inline int fclose ( FILE *stream __unused ) { - return -1; -} - -#define CONFIG_SSL_CERT_VERIFICATION 1 -#define CONFIG_SSL_MAX_CERTS 1 -#define CONFIG_X509_MAX_CA_CERTS 1 -#define CONFIG_SSL_EXPIRY_TIME 24 -#define CONFIG_SSL_ENABLE_CLIENT 1 -#define CONFIG_BIGINT_CLASSICAL 1 +#endif +#undef aes #endif diff --git a/src/crypto/axtls/rsa.c b/src/crypto/axtls/rsa.c index 389eda57..f17500c3 100644 --- a/src/crypto/axtls/rsa.c +++ b/src/crypto/axtls/rsa.c @@ -1,19 +1,31 @@ /* - * Copyright(C) 2006 Cameron Rich + * Copyright (c) 2007, Cameron Rich * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. + * All rights reserved. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of the axTLS project 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 OWNER 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. */ /** @@ -25,12 +37,9 @@ #include #include #include +#include "os_port.h" #include "crypto.h" -#ifdef CONFIG_BIGINT_CRT -static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi); -#endif - void RSA_priv_key_new(RSA_CTX **ctx, const uint8_t *modulus, int mod_len, const uint8_t *pub_exp, int pub_len, @@ -71,11 +80,16 @@ void RSA_pub_key_new(RSA_CTX **ctx, const uint8_t *pub_exp, int pub_len) { RSA_CTX *rsa_ctx; - BI_CTX *bi_ctx = bi_initialize(); + BI_CTX *bi_ctx; + + if (*ctx) /* if we load multiple certs, dump the old one */ + RSA_free(*ctx); + + bi_ctx = bi_initialize(); *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX)); rsa_ctx = *ctx; rsa_ctx->bi_ctx = bi_ctx; - rsa_ctx->num_octets = (mod_len & 0xFFF0); + rsa_ctx->num_octets = mod_len; rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len); bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET); rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len); @@ -129,10 +143,10 @@ void RSA_free(RSA_CTX *rsa_ctx) int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data, int is_decryption) { - int byte_size = ctx->num_octets; - uint8_t *block; + const int byte_size = ctx->num_octets; int i, size; bigint *decrypted_bi, *dat_bi; + uint8_t *block = (uint8_t *)alloca(byte_size); memset(out_data, 0, byte_size); /* initialise */ @@ -146,7 +160,6 @@ int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, #endif /* convert to a normal block */ - block = (uint8_t *)malloc(byte_size); bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size); i = 10; /* start at the first possible non-padded byte */ @@ -170,7 +183,6 @@ int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, if (size > 0) memcpy(out_data, &block[i], size); - free(block); return size ? size : -1; } @@ -180,7 +192,7 @@ int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg) { #ifdef CONFIG_BIGINT_CRT - return bi_crt(c, bi_msg); + return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv); #else BI_CTX *ctx = c->bi_ctx; ctx->mod_offset = BIGINT_M_OFFSET; @@ -188,39 +200,6 @@ bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg) #endif } -#ifdef CONFIG_BIGINT_CRT -/** - * Use the Chinese Remainder Theorem to quickly perform RSA decrypts. - * This should really be in bigint.c (and was at one stage), but needs - * access to the RSA_CTX context... - */ -static bigint *bi_crt(const RSA_CTX *rsa, bigint *bi) -{ - BI_CTX *ctx = rsa->bi_ctx; - bigint *m1, *m2, *h; - - /* Montgomery has a condition the 0 < x, y < m and these products violate - * that condition. So disable Montgomery when using CRT */ -#if defined(CONFIG_BIGINT_MONTGOMERY) - ctx->use_classical = 1; -#endif - ctx->mod_offset = BIGINT_P_OFFSET; - m1 = bi_mod_power(ctx, bi_copy(bi), rsa->dP); - - ctx->mod_offset = BIGINT_Q_OFFSET; - m2 = bi_mod_power(ctx, bi, rsa->dQ); - - h = bi_subtract(ctx, bi_add(ctx, m1, rsa->p), bi_copy(m2), NULL); - h = bi_multiply(ctx, h, rsa->qInv); - ctx->mod_offset = BIGINT_P_OFFSET; - h = bi_residue(ctx, h); -#if defined(CONFIG_BIGINT_MONTGOMERY) - ctx->use_classical = 0; /* reset for any further operation */ -#endif - return bi_add(ctx, m2, bi_multiply(ctx, rsa->q, h)); -} -#endif - #ifdef CONFIG_SSL_FULL_MODE /** * Used for diagnostics. @@ -238,7 +217,7 @@ void RSA_print(const RSA_CTX *rsa_ctx) } #endif -#ifdef CONFIG_SSL_CERT_VERIFICATION +#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) /** * Performs c = m^e mod n */ @@ -279,54 +258,12 @@ int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, /* now encrypt it */ dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size); encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : - RSA_public(ctx, dat_bi); + RSA_public(ctx, dat_bi); bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size); + + /* save a few bytes of memory */ + bi_clear_cache(ctx->bi_ctx); return byte_size; } -#if 0 -/** - * Take a signature and decrypt it. - */ -bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len, - bigint *modulus, bigint *pub_exp) -{ - uint8_t *block; - int i, size; - bigint *decrypted_bi, *dat_bi; - bigint *bir = NULL; - - block = (uint8_t *)malloc(sig_len); - - /* decrypt */ - dat_bi = bi_import(ctx, sig, sig_len); - ctx->mod_offset = BIGINT_M_OFFSET; - - /* convert to a normal block */ - decrypted_bi = bi_mod_power2(ctx, dat_bi, modulus, pub_exp); - - bi_export(ctx, decrypted_bi, block, sig_len); - ctx->mod_offset = BIGINT_M_OFFSET; - - i = 10; /* start at the first possible non-padded byte */ - while (block[i++] && i < sig_len); - size = sig_len - i; - - /* get only the bit we want */ - if (size > 0) - { - int len; - const uint8_t *sig_ptr = x509_get_signature(&block[i], &len); - - if (sig_ptr) - { - bir = bi_import(ctx, sig_ptr, len); - } - } - - free(block); - return bir; -} -#endif - #endif /* CONFIG_SSL_CERT_VERIFICATION */ diff --git a/src/crypto/axtls_aes.c b/src/crypto/axtls_aes.c index b73a5725..3f1d668a 100644 --- a/src/crypto/axtls_aes.c +++ b/src/crypto/axtls_aes.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include #include @@ -119,7 +120,7 @@ static void aes_encrypt ( void *ctx, const void *src, void *dst, assert ( len == AES_BLOCKSIZE ); if ( aes_ctx->decrypting ) assert ( 0 ); - aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_encrypt ); + aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_encrypt ); } /** @@ -139,7 +140,7 @@ static void aes_decrypt ( void *ctx, const void *src, void *dst, AES_convert_key ( &aes_ctx->axtls_ctx ); aes_ctx->decrypting = 1; } - aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, AES_decrypt ); + aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_decrypt ); } /** Basic AES algorithm */ diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 28d28fc1..50593bc6 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -155,6 +155,11 @@ int x509_rsa_public_key ( const struct asn1_cursor *certificate, DBG_HDA ( 0, certificate->data, certificate->len ); return -ENOTSUP; } + if ( modulus.len && ( ! *( ( uint8_t * ) modulus.data ) ) ) { + /* Skip positive sign byte */ + modulus.data++; + modulus.len--; + } memcpy ( &exponent, &pubkey, sizeof ( exponent ) ); rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */ asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ ); @@ -163,6 +168,11 @@ int x509_rsa_public_key ( const struct asn1_cursor *certificate, DBG_HDA ( 0, certificate->data, certificate->len ); return -ENOTSUP; } + if ( exponent.len && ( ! *( ( uint8_t * ) exponent.data ) ) ) { + /* Skip positive sign byte */ + exponent.data++; + exponent.len--; + } /* Allocate space and copy out modulus and exponent */ rsa_pubkey->modulus = malloc ( modulus.len + exponent.len ); diff --git a/src/include/ipxe/aes.h b/src/include/ipxe/aes.h index 5d645b20..4e44f985 100644 --- a/src/include/ipxe/aes.h +++ b/src/include/ipxe/aes.h @@ -21,6 +21,10 @@ struct aes_context { /** AES context size */ #define AES_CTX_SIZE sizeof ( struct aes_context ) +/* AXTLS functions */ +extern void axtls_aes_encrypt ( const AES_CTX *ctx, uint32_t *data ); +extern void axtls_aes_decrypt ( const AES_CTX *ctx, uint32_t *data ); + extern struct cipher_algorithm aes_algorithm; extern struct cipher_algorithm aes_cbc_algorithm; diff --git a/src/net/tls.c b/src/net/tls.c index 8940613c..90af1676 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -794,7 +794,7 @@ static int tls_send_certificate ( struct tls_session *tls ) { */ static int tls_send_client_key_exchange ( struct tls_session *tls ) { /* FIXME: Hack alert */ - RSA_CTX *rsa_ctx; + RSA_CTX *rsa_ctx = NULL; RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len, tls->rsa.exponent, tls->rsa.exponent_len ); struct { From b63bcd73a0e83fe74d530d100248c87579956985 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 10 Mar 2012 00:25:03 +0000 Subject: [PATCH 064/221] [tls] Use const to mark incoming data being processed Signed-off-by: Michael Brown --- src/include/ipxe/asn1.h | 2 +- src/net/tls.c | 54 +++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 7ac10862..b51267ba 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -23,7 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ struct asn1_cursor { /** Start of data */ - void *data; + const void *data; /** Length of data */ size_t len; }; diff --git a/src/net/tls.c b/src/net/tls.c index 90af1676..dfd19a0a 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -65,7 +65,7 @@ static void tls_clear_cipher ( struct tls_session *tls, * TLS uses 24-bit integers in several places, which are awkward to * parse in C. */ -static unsigned long tls_uint24 ( uint8_t field24[3] ) { +static unsigned long tls_uint24 ( const uint8_t field24[3] ) { return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] ); } @@ -874,7 +874,7 @@ static int tls_send_finished ( struct tls_session *tls ) { * @ret rc Return status code */ static int tls_new_change_cipher ( struct tls_session *tls, - void *data, size_t len ) { + const void *data, size_t len ) { int rc; if ( ( len != 1 ) || ( *( ( uint8_t * ) data ) != 1 ) ) { @@ -902,13 +902,14 @@ static int tls_new_change_cipher ( struct tls_session *tls, * @v len Length of plaintext record * @ret rc Return status code */ -static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) { - struct { +static int tls_new_alert ( struct tls_session *tls, const void *data, + size_t len ) { + const struct { uint8_t level; uint8_t description; char next[0]; } __attribute__ (( packed )) *alert = data; - void *end = alert->next; + const void *end = alert->next; /* Sanity check */ if ( end != ( data + len ) ) { @@ -942,20 +943,20 @@ static int tls_new_alert ( struct tls_session *tls, void *data, size_t len ) { * @ret rc Return status code */ static int tls_new_server_hello ( struct tls_session *tls, - void *data, size_t len ) { - struct { + const void *data, size_t len ) { + const struct { uint16_t version; uint8_t random[32]; uint8_t session_id_len; char next[0]; } __attribute__ (( packed )) *hello_a = data; - struct { + const struct { uint8_t session_id[hello_a->session_id_len]; uint16_t cipher_suite; uint8_t compression_method; char next[0]; } __attribute__ (( packed )) *hello_b = ( void * ) &hello_a->next; - void *end = hello_b->next; + const void *end = hello_b->next; uint16_t version; int rc; @@ -1008,18 +1009,18 @@ static int tls_new_server_hello ( struct tls_session *tls, * @ret rc Return status code */ static int tls_new_certificate ( struct tls_session *tls, - void *data, size_t len ) { - struct { + const void *data, size_t len ) { + const struct { uint8_t length[3]; uint8_t certificates[0]; } __attribute__ (( packed )) *certificate = data; - struct { + const struct { uint8_t length[3]; uint8_t certificate[0]; } __attribute__ (( packed )) *element = ( ( void * ) certificate->certificates ); size_t elements_len = tls_uint24 ( certificate->length ); - void *end = ( certificate->certificates + elements_len ); + const void *end = ( certificate->certificates + elements_len ); struct asn1_cursor cursor; int rc; @@ -1066,7 +1067,7 @@ static int tls_new_certificate ( struct tls_session *tls, * @ret rc Return status code */ static int tls_new_certificate_request ( struct tls_session *tls, - void *data __unused, + const void *data __unused, size_t len __unused ) { /* We can only send an empty certificate (as mandated by @@ -1090,11 +1091,11 @@ static int tls_new_certificate_request ( struct tls_session *tls, * @ret rc Return status code */ static int tls_new_server_hello_done ( struct tls_session *tls, - void *data, size_t len ) { - struct { + const void *data, size_t len ) { + const struct { char next[0]; } __attribute__ (( packed )) *hello_done = data; - void *end = hello_done->next; + const void *end = hello_done->next; /* Sanity check */ if ( end != ( data + len ) ) { @@ -1122,12 +1123,12 @@ static int tls_new_server_hello_done ( struct tls_session *tls, * @ret rc Return status code */ static int tls_new_finished ( struct tls_session *tls, - void *data, size_t len ) { - struct { + const void *data, size_t len ) { + const struct { uint8_t verify_data[12]; char next[0]; } __attribute__ (( packed )) *finished = data; - void *end = finished->next; + const void *end = finished->next; uint8_t digest[ tls_verify_handshake_len ( tls ) ]; uint8_t verify_data[ sizeof ( finished->verify_data ) ]; @@ -1167,12 +1168,12 @@ static int tls_new_finished ( struct tls_session *tls, * @ret rc Return status code */ static int tls_new_handshake ( struct tls_session *tls, - void *data, size_t len ) { - void *end = ( data + len ); + const void *data, size_t len ) { + const void *end = ( data + len ); int rc; while ( data != end ) { - struct { + const struct { uint8_t type; uint8_t length[3]; uint8_t payload[0]; @@ -1242,8 +1243,8 @@ static int tls_new_handshake ( struct tls_session *tls, * @v len Length of plaintext record * @ret rc Return status code */ -static int tls_new_record ( struct tls_session *tls, - unsigned int type, void *data, size_t len ) { +static int tls_new_record ( struct tls_session *tls, unsigned int type, + const void *data, size_t len ) { switch ( type ) { case TLS_TYPE_CHANGE_CIPHER: @@ -1588,7 +1589,8 @@ static int tls_split_block ( struct tls_session *tls, * @ret rc Return status code */ static int tls_new_ciphertext ( struct tls_session *tls, - struct tls_header *tlshdr, void *ciphertext ) { + struct tls_header *tlshdr, + const void *ciphertext ) { struct tls_header plaintext_tlshdr; struct tls_cipherspec *cipherspec = &tls->rx_cipherspec; struct cipher_algorithm *cipher = cipherspec->suite->cipher; From a0e559d1f32e7d35cccaf0c4a7816bd5ddaf4a66 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 04:37:48 +0000 Subject: [PATCH 065/221] [forcedeth] Use standard random() function It seems unlikely that a network card driver requires cryptographically secure random numbers. Signed-off-by: Michael Brown --- src/drivers/net/forcedeth.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/drivers/net/forcedeth.c b/src/drivers/net/forcedeth.c index 5d0137e1..34c59223 100644 --- a/src/drivers/net/forcedeth.c +++ b/src/drivers/net/forcedeth.c @@ -740,8 +740,7 @@ forcedeth_open ( struct net_device *netdev ) ioaddr + NvRegReceiverStatus ); /* Set up slot time */ - get_random_bytes ( &low, sizeof(low) ); - low &= NVREG_SLOTTIME_MASK; + low = ( random() & NVREG_SLOTTIME_MASK ); writel ( low | NVREG_SLOTTIME_DEFAULT, ioaddr + NvRegSlotTime ); writel ( NVREG_TX_DEFERRAL_DEFAULT , ioaddr + NvRegTxDeferral ); From 554627c960def1adbf909e40126aefc0eed49529 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 04:40:19 +0000 Subject: [PATCH 066/221] [802.11] Use rbg_generate() for secure random numbers Signed-off-by: Michael Brown --- src/net/80211/wpa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/net/80211/wpa.c b/src/net/80211/wpa.c index 90929ea3..45def8c1 100644 --- a/src/net/80211/wpa.c +++ b/src/net/80211/wpa.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -515,7 +516,8 @@ static int wpa_handle_1_of_4 ( struct wpa_common_ctx *ctx, ctx->state = WPA_WORKING; memcpy ( ctx->Anonce, pkt->nonce, sizeof ( ctx->Anonce ) ); if ( ! ctx->have_Snonce ) { - get_random_bytes ( ctx->Snonce, sizeof ( ctx->Snonce ) ); + rbg_generate ( NULL, 0, 0, ctx->Snonce, + sizeof ( ctx->Snonce ) ); ctx->have_Snonce = 1; } From ffb6d6be6dc8b0b7f144ed7f6d40b537b4480295 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 04:41:49 +0000 Subject: [PATCH 067/221] [rng] Remove obsolete (and unfinished) get_random_bytes() function Signed-off-by: Michael Brown --- src/crypto/crandom.c | 55 --------------------------------------- src/include/ipxe/crypto.h | 2 -- 2 files changed, 57 deletions(-) delete mode 100644 src/crypto/crandom.c diff --git a/src/crypto/crandom.c b/src/crypto/crandom.c deleted file mode 100644 index 1886f9b7..00000000 --- a/src/crypto/crandom.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2009 Joshua Oreman . - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/** @file - * - * Cryptographically strong random number generator - * - * Currently the cryptographic part is not implemented, and this just - * uses random(). - */ - -#include -#include - -/** - * Get cryptographically strong random bytes - * - * @v buf Buffer in which to store random bytes - * @v len Number of random bytes to generate - * - * @b WARNING: This function is currently underimplemented, and does - * not give numbers any stronger than random()! - */ -void get_random_bytes ( void *buf, size_t len ) -{ - u8 *bufp = buf; - - /* - * Somewhat arbitrarily, choose the 0x00FF0000-masked byte - * returned by random() as having good entropy. PRNGs often - * don't provide good entropy in lower bits, and the top byte - * might show a pattern because of sign issues. - */ - - while ( len-- ) { - *bufp++ = ( random() >> 16 ) & 0xFF; - } -} diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 9383c076..7c21e96e 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -151,6 +151,4 @@ extern struct digest_algorithm digest_null; extern struct cipher_algorithm cipher_null; extern struct pubkey_algorithm pubkey_null; -void get_random_bytes ( void *buf, size_t len ); - #endif /* _IPXE_CRYPTO_H */ From f229162749d3105c732046774867a6a6698f97b9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 16:30:17 +0000 Subject: [PATCH 068/221] [crypto] Add ASN.1 functions for X.509 certificate parsing Signed-off-by: Michael Brown --- src/crypto/asn1.c | 62 ++++++++++++++++++++-- src/include/ipxe/asn1.h | 113 ++++++++++++++++++++++++++++++++++------ 2 files changed, 154 insertions(+), 21 deletions(-) diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index 40b87533..d988aab4 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include @@ -43,11 +44,23 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define EINFO_EINVAL_ASN1_LEN \ __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" ) +/** + * Invalidate ASN.1 object cursor + * + * @v cursor ASN.1 object cursor + */ +void asn1_invalidate_cursor ( struct asn1_cursor *cursor ) { + static uint8_t asn1_invalid_object[] = { ASN1_END, 0 }; + + cursor->data = asn1_invalid_object; + cursor->len = 0; +} + /** * Start parsing ASN.1 object * * @v cursor ASN.1 object cursor - * @v type Expected type + * @v type Expected type, or ASN1_ANY * @ret len Length of object body, or negative error * * The object cursor will be updated to point to the start of the @@ -67,7 +80,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) { } /* Check the tag byte */ - if ( *( ( uint8_t * ) cursor->data ) != type ) { + if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) { DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n", cursor, type, *( ( uint8_t * ) cursor->data ) ); return -ENXIO; @@ -110,7 +123,7 @@ static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) { * Enter ASN.1 object * * @v cursor ASN.1 object cursor - * @v type Expected type + * @v type Expected type, or ASN1_ANY * @ret rc Return status code * * The object cursor will be updated to point to the body of the @@ -137,7 +150,7 @@ int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) { * Skip ASN.1 object if present * * @v cursor ASN.1 object cursor - * @v type Expected type + * @v type Expected type, or ASN1_ANY * @ret rc Return status code * * The object cursor will be updated to point to the next ASN.1 @@ -168,7 +181,7 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) { * Skip ASN.1 object * * @v cursor ASN.1 object cursor - * @v type Expected type + * @v type Expected type, or ASN1_ANY * @ret rc Return status code * * The object cursor will be updated to point to the next ASN.1 @@ -185,3 +198,42 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) { return 0; } + +/** + * Enter ASN.1 object of any type + * + * @v cursor ASN.1 object cursor + * @ret rc Return status code + */ +int asn1_enter_any ( struct asn1_cursor *cursor ) { + return asn1_enter ( cursor, ASN1_ANY ); +} + +/** + * Skip ASN.1 object of any type + * + * @v cursor ASN.1 object cursor + * @ret rc Return status code + */ +int asn1_skip_any ( struct asn1_cursor *cursor ) { + return asn1_skip ( cursor, ASN1_ANY ); +} + +/** + * Compare two ASN.1 objects + * + * @v cursor1 ASN.1 object cursor + * @v cursor2 ASN.1 object cursor + * @ret difference Difference as returned by memcmp() + * + * Note that invalid and empty cursors will compare as equal with each + * other. + */ +int asn1_compare ( const struct asn1_cursor *cursor1, + const struct asn1_cursor *cursor2 ) { + int difference; + + difference = ( cursor2->len - cursor1->len ); + return ( difference ? difference : + memcmp ( cursor1->data, cursor2->data, cursor1->len ) ); +} diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index b51267ba..7d8f6670 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -9,18 +9,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#define ASN1_INTEGER 0x02 -#define ASN1_BIT_STRING 0x03 -#define ASN1_OCTET_STRING 0x04 -#define ASN1_NULL 0x05 -#define ASN1_OID 0x06 -#define ASN1_SEQUENCE 0x30 -#define ASN1_IP_ADDRESS 0x40 -#define ASN1_EXPLICIT_TAG 0xa0 - -/** - * A DER-encoded ASN.1 object cursor - */ +/** An ASN.1 object cursor */ struct asn1_cursor { /** Start of data */ const void *data; @@ -28,19 +17,111 @@ struct asn1_cursor { size_t len; }; +/** ASN.1 end */ +#define ASN1_END 0x00 + +/** ASN.1 integer */ +#define ASN1_INTEGER 0x02 + +/** ASN.1 bit string */ +#define ASN1_BIT_STRING 0x03 + +/** ASN.1 octet string */ +#define ASN1_OCTET_STRING 0x04 + +/** ASN.1 null */ +#define ASN1_NULL 0x05 + +/** ASN.1 object identifier */ +#define ASN1_OID 0x06 + +/** ASN.1 UTC time */ +#define ASN1_UTC_TIME 0x17 + +/** ASN.1 generalized time */ +#define ASN1_GENERALIZED_TIME 0x18 + +/** ASN.1 sequence */ +#define ASN1_SEQUENCE 0x30 + +/** ASN.1 set */ +#define ASN1_SET 0x31 + +/** ASN.1 explicit tag */ +#define ASN1_EXPLICIT_TAG 0xa0 + +/** ASN.1 "any tag" magic value */ +#define ASN1_ANY -1U + +/** Initial OID byte */ +#define ASN1_OID_INITIAL( first, second ) ( ( (first) * 40 ) + (second) ) + +/** Single-byte OID value + * + * Valid for values up to 127 + */ +#define ASN1_OID_SINGLE( value ) ( (value) & 0x7f ) + +/** Double-byte OID value + * + * Valid for values up to 16383 + */ +#define ASN1_OID_DOUBLE( value ) \ + ( 0x80 | ( ( (value) >> 7 ) & 0x7f ) ), ASN1_OID_SINGLE ( (value) ) + +/** Double-byte OID value + * + * Valid for values up to 2097151 + */ +#define ASN1_OID_TRIPLE( value ) \ + ( 0x80 | ( ( (value) >> 14 ) & 0x7f ) ), ASN1_OID_DOUBLE ( (value) ) + +/** ASN.1 OID for iso(1) member-body(2) */ +#define ASN1_OID_ISO_MEMBERBODY ASN1_OID_INITIAL ( 1, 2 ) + +/** ASN.1 OID for joint-iso-itu-t(2) ds(5) */ +#define ASN1_OID_DIRECTORY_SERVICES ASN1_OID_INITIAL ( 2, 5 ) + +/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */ +#define ASN1_OID_ATTRIBUTE_TYPE \ + ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */ +#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 ) + +/** Define an ASN.1 cursor containing an OID */ +#define ASN1_OID_CURSOR( oid_value ) { \ + .data = oid_value, \ + .len = sizeof ( oid_value ), \ + } + +/** An ASN.1 bit string */ +struct asn1_bit_string { + /** Number of unused bits */ + uint8_t unused; + /** Data */ + uint8_t data[0]; +} __attribute__ (( packed )); + /** - * Invalidate ASN.1 object cursor + * Extract ASN.1 type * * @v cursor ASN.1 object cursor + * @ret type Type */ -static inline __attribute__ (( always_inline )) void -asn1_invalidate_cursor ( struct asn1_cursor *cursor ) { - cursor->len = 0; +static inline __attribute__ (( always_inline )) unsigned int +asn1_type ( const struct asn1_cursor *cursor ) { + return ( *( ( const uint8_t * ) cursor->data ) ); } +extern void asn1_invalidate_cursor ( struct asn1_cursor *cursor ); extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ); extern int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ); extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ); +extern int asn1_enter_any ( struct asn1_cursor *cursor ); +extern int asn1_skip_any ( struct asn1_cursor *cursor ); +extern int asn1_compare ( const struct asn1_cursor *cursor1, + const struct asn1_cursor *cursor2 ); #endif /* _IPXE_ASN1_H */ From 071184a6e488f68b2b3149b801ab56e2b02cec3e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 16:35:21 +0000 Subject: [PATCH 069/221] [crypto] Add big-integer library for RSA calculations RSA requires modular exponentiation using arbitrarily large integers. Given the sizes of the modulus and exponent, all required calculations can be done without any further dynamic storage allocation. The x86 architecture allows for efficient large integer support via inline assembly using the instructions that take advantage of the carry flag (e.g. "adcl", "rcrl"). This implemention is approximately 80% smaller than the (more generic) AXTLS implementation. Signed-off-by: Michael Brown --- src/arch/x86/core/x86_bigint.c | 90 +++++ src/arch/x86/include/bits/bigint.h | 318 ++++++++++++++++++ src/crypto/axtls/{bigint.c => axtls_bigint.c} | 0 src/crypto/bigint.c | 122 +++++++ src/include/ipxe/bigint.h | 268 +++++++++++++++ 5 files changed, 798 insertions(+) create mode 100644 src/arch/x86/core/x86_bigint.c create mode 100644 src/arch/x86/include/bits/bigint.h rename src/crypto/axtls/{bigint.c => axtls_bigint.c} (100%) create mode 100644 src/crypto/bigint.c create mode 100644 src/include/ipxe/bigint.h diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c new file mode 100644 index 00000000..cb6c67b1 --- /dev/null +++ b/src/arch/x86/core/x86_bigint.c @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include + +/** @file + * + * Big integer support + */ + +/** + * Multiply big integers + * + * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplier0 Element 0 of big integer to be multiplied + * @v result0 Element 0 of big integer to hold result + * @v size Number of elements + */ +void bigint_multiply_raw ( const uint32_t *multiplicand0, + const uint32_t *multiplier0, + uint32_t *result0, unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = + ( ( const void * ) multiplicand0 ); + const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = + ( ( const void * ) multiplier0 ); + bigint_t ( size * 2 ) __attribute__ (( may_alias )) *result = + ( ( void * ) result0 ); + unsigned int i; + unsigned int j; + uint32_t multiplicand_element; + uint32_t multiplier_element; + uint32_t *result_elements; + uint32_t discard_a; + uint32_t discard_d; + long index; + + /* Zero result */ + memset ( result, 0, sizeof ( *result ) ); + + /* Multiply integers one element at a time */ + for ( i = 0 ; i < size ; i++ ) { + multiplicand_element = multiplicand->element[i]; + for ( j = 0 ; j < size ; j++ ) { + multiplier_element = multiplier->element[j]; + result_elements = &result->element[ i + j ]; + /* Perform a single multiply, and add the + * resulting double-element into the result, + * carrying as necessary. The carry can + * never overflow beyond the end of the + * result, since: + * + * a < 2^{n}, b < 2^{n} => ab < 2^{2n} + */ + __asm__ __volatile__ ( "mull %4\n\t" + "addl %%eax, (%5,%2,4)\n\t" + "adcl %%edx, 4(%5,%2,4)\n\t" + "\n1:\n\t" + "adcl $0, 8(%5,%2,4)\n\t" + "inc %2\n\t" + /* Does not affect CF */ + "jc 1b\n\t" + : "=&a" ( discard_a ), + "=&d" ( discard_d ), + "=&r" ( index ) + : "0" ( multiplicand_element ), + "g" ( multiplier_element ), + "r" ( result_elements ), + "2" ( 0 ) ); + } + } +} diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h new file mode 100644 index 00000000..4c9aed62 --- /dev/null +++ b/src/arch/x86/include/bits/bigint.h @@ -0,0 +1,318 @@ +#ifndef _BITS_BIGINT_H +#define _BITS_BIGINT_H + +/** @file + * + * Big integer support + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** Element of a big integer */ +typedef uint32_t bigint_element_t; + +/** + * Initialise big integer + * + * @v value0 Element 0 of big integer to initialise + * @v size Number of elements + * @v data Raw data + * @v len Length of raw data + */ +static inline __attribute__ (( always_inline )) void +bigint_init_raw ( uint32_t *value0, unsigned int size, + const void *data, size_t len ) { + long pad_len = ( sizeof ( bigint_t ( size ) ) - len ); + void *discard_D; + long discard_c; + + /* Copy raw data in reverse order, padding with zeros */ + __asm__ __volatile__ ( "\n1:\n\t" + "movb -1(%2,%1), %%al\n\t" + "stosb\n\t" + "loop 1b\n\t" + "xorl %%eax, %%eax\n\t" + "mov %3, %1\n\t" + "rep stosb\n\t" + : "=&D" ( discard_D ), "=&c" ( discard_c ) + : "r" ( data ), "g" ( pad_len ), "0" ( value0 ), + "1" ( len ) + : "eax" ); +} + +/** + * Add big integers + * + * @v addend0 Element 0 of big integer to add + * @v value0 Element 0 of big integer to be added to + * @v size Number of elements + */ +static inline __attribute__ (( always_inline )) void +bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, + unsigned int size ) { + long index; + void *discard_S; + long discard_c; + + __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */ + "\n1:\n\t" + "lodsl\n\t" + "adcl %%eax, (%3,%0,4)\n\t" + "inc %0\n\t" /* Does not affect CF */ + "loop 1b\n\t" + : "=&r" ( index ), "=&S" ( discard_S ), + "=&c" ( discard_c ) + : "r" ( value0 ), "1" ( addend0 ), "2" ( size ) + : "eax" ); +} + +/** + * Subtract big integers + * + * @v subtrahend0 Element 0 of big integer to subtract + * @v value0 Element 0 of big integer to be subtracted from + * @v size Number of elements + */ +static inline __attribute__ (( always_inline )) void +bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, + unsigned int size ) { + long index; + void *discard_S; + long discard_c; + + __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */ + "\n1:\n\t" + "lodsl\n\t" + "sbbl %%eax, (%3,%0,4)\n\t" + "inc %0\n\t" /* Does not affect CF */ + "loop 1b\n\t" + : "=&r" ( index ), "=&S" ( discard_S ), + "=&c" ( discard_c ) + : "r" ( value0 ), "1" ( subtrahend0 ), + "2" ( size ) + : "eax" ); +} + +/** + * Rotate big integer left + * + * @v value0 Element 0 of big integer + * @v size Number of elements + */ +static inline __attribute__ (( always_inline )) void +bigint_rol_raw ( uint32_t *value0, unsigned int size ) { + long index; + long discard_c; + + __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */ + "\n1:\n\t" + "rcll $1, (%2,%0,4)\n\t" + "inc %0\n\t" /* Does not affect CF */ + "loop 1b\n\t" + : "=&r" ( index ), "=&c" ( discard_c ) + : "r" ( value0 ), "1" ( size ) ); +} + +/** + * Rotate big integer right + * + * @v value0 Element 0 of big integer + * @v size Number of elements + */ +static inline __attribute__ (( always_inline )) void +bigint_ror_raw ( uint32_t *value0, unsigned int size ) { + long discard_c; + + __asm__ __volatile__ ( "clc\n\t" + "\n1:\n\t" + "rcrl $1, -4(%1,%0,4)\n\t" + "loop 1b\n\t" + : "=&c" ( discard_c ) + : "r" ( value0 ), "0" ( size ) ); +} + +/** + * Test if big integer is equal to zero + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @ret is_zero Big integer is equal to zero + */ +static inline __attribute__ (( always_inline, pure )) int +bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) { + void *discard_D; + long discard_c; + int result; + + __asm__ __volatile__ ( "xor %0, %0\n\t" /* Set ZF */ + "repe scasl\n\t" + "sete %b0\n\t" + : "=&a" ( result ), "=&D" ( discard_D ), + "=&c" ( discard_c ) + : "1" ( value0 ), "2" ( size ) ); + return result; +} + +/** + * Compare big integers + * + * @v value0 Element 0 of big integer + * @v reference0 Element 0 of reference big integer + * @v size Number of elements + * @ret geq Big integer is greater than or equal to the reference + */ +static inline __attribute__ (( always_inline, pure )) int +bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0, + unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( const void * ) value0 ); + const bigint_t ( size ) __attribute__ (( may_alias )) *reference = + ( ( const void * ) reference0 ); + void *discard_S; + void *discard_D; + long discard_c; + int result; + + __asm__ __volatile__ ( "std\n\t" + "\n1:\n\t" + "lodsl\n\t" + "scasl\n\t" + "loope 1b\n\t" + "setae %b0\n\t" + "cld\n\t" + : "=r" ( result ), "=&S" ( discard_S ), + "=&D" ( discard_D ), "=&c" ( discard_c ) + : "0" ( 0 ), "1" ( &value->element[ size - 1 ] ), + "2" ( &reference->element[ size - 1 ] ), + "3" ( size ) + : "eax" ); + return result; +} + +/** + * Test if bit is set in big integer + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @v bit Bit to test + * @ret is_set Bit is set + */ +static inline __attribute__ (( always_inline )) int +bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size, + unsigned int bit ) { + const bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( const void * ) value0 ); + unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) ); + unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) ); + + return ( value->element[index] & ( 1 << subindex ) ); +} + +/** + * Find highest bit set in big integer + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @ret max_bit Highest bit set + 1 (or 0 if no bits set) + */ +static inline __attribute__ (( always_inline )) int +bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) { + long discard_c; + int result; + + __asm__ __volatile__ ( "\n1:\n\t" + "bsrl -4(%2,%1,4), %0\n\t" + "loopz 1b\n\t" + "rol %1\n\t" /* Does not affect ZF */ + "rol %1\n\t" + "leal 1(%k0,%k1,8), %k0\n\t" + "jnz 2f\n\t" + "xor %0, %0\n\t" + "\n2:\n\t" + : "=&r" ( result ), "=&c" ( discard_c ) + : "r" ( value0 ), "1" ( size ) ); + return result; +} + +/** + * Grow big integer + * + * @v source0 Element 0 of source big integer + * @v source_size Number of elements in source big integer + * @v dest0 Element 0 of destination big integer + * @v dest_size Number of elements in destination big integer + */ +static inline __attribute__ (( always_inline )) void +bigint_grow_raw ( const uint32_t *source0, unsigned int source_size, + uint32_t *dest0, unsigned int dest_size ) { + long pad_size = ( dest_size - source_size ); + void *discard_D; + void *discard_S; + long discard_c; + + __asm__ __volatile__ ( "rep movsl\n\t" + "xorl %%eax, %%eax\n\t" + "mov %3, %2\n\t" + "rep stosl\n\t" + : "=&D" ( discard_D ), "=&S" ( discard_S ), + "=&c" ( discard_c ) + : "g" ( pad_size ), "0" ( dest0 ), + "1" ( source0 ), "2" ( source_size ) + : "eax" ); +} + +/** + * Shrink big integer + * + * @v source0 Element 0 of source big integer + * @v source_size Number of elements in source big integer + * @v dest0 Element 0 of destination big integer + * @v dest_size Number of elements in destination big integer + */ +static inline __attribute__ (( always_inline )) void +bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused, + uint32_t *dest0, unsigned int dest_size ) { + void *discard_D; + void *discard_S; + long discard_c; + + __asm__ __volatile__ ( "rep movsl\n\t" + : "=&D" ( discard_D ), "=&S" ( discard_S ), + "=&c" ( discard_c ) + : "0" ( dest0 ), "1" ( source0 ), + "2" ( dest_size ) + : "eax" ); +} + +/** + * Finalise big integer + * + * @v value0 Element 0 of big integer to finalise + * @v size Number of elements + * @v out Output buffer + * @v len Length of output buffer + */ +static inline __attribute__ (( always_inline )) void +bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, + void *out, size_t len ) { + void *discard_D; + long discard_c; + + /* Copy raw data in reverse order */ + __asm__ __volatile__ ( "\n1:\n\t" + "movb -1(%2,%1), %%al\n\t" + "stosb\n\t" + "loop 1b\n\t" + : "=&D" ( discard_D ), "=&c" ( discard_c ) + : "r" ( value0 ), "0" ( out ), "1" ( len ) + : "eax" ); +} + +extern void bigint_multiply_raw ( const uint32_t *multiplicand0, + const uint32_t *multiplier0, + uint32_t *value0, unsigned int size ); + +#endif /* _BITS_BIGINT_H */ diff --git a/src/crypto/axtls/bigint.c b/src/crypto/axtls/axtls_bigint.c similarity index 100% rename from src/crypto/axtls/bigint.c rename to src/crypto/axtls/axtls_bigint.c diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c new file mode 100644 index 00000000..c3edec9d --- /dev/null +++ b/src/crypto/bigint.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include + +/** @file + * + * Big integer support + */ + +/** + * Perform modular multiplication of big integers + * + * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplier0 Element 0 of big integer to be multiplied + * @v modulus0 Element 0 of big integer modulus + * @v result0 Element 0 of big integer to hold result + */ +void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, + const bigint_element_t *multiplier0, + const bigint_element_t *modulus0, + bigint_element_t *result0, + unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = + ( ( const void * ) multiplicand0 ); + const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = + ( ( const void * ) multiplier0 ); + const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = + ( ( const void * ) modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *result = + ( ( void * ) result0 ); + bigint_t ( size * 2 ) temp_result; + bigint_t ( size * 2 ) temp_modulus; + int rotation; + int i; + + /* Perform multiplication */ + bigint_multiply ( multiplicand, multiplier, &temp_result ); + + /* Rescale modulus to match result */ + bigint_grow ( modulus, &temp_modulus ); + rotation = ( bigint_max_set_bit ( &temp_result ) - + bigint_max_set_bit ( &temp_modulus ) ); + for ( i = 0 ; i < rotation ; i++ ) + bigint_rol ( &temp_modulus ); + + /* Subtract multiples of modulus */ + for ( i = 0 ; i <= rotation ; i++ ) { + if ( bigint_is_geq ( &temp_result, &temp_modulus ) ) + bigint_subtract ( &temp_modulus, &temp_result ); + bigint_ror ( &temp_modulus ); + } + + /* Resize result */ + bigint_shrink ( &temp_result, result ); + + /* Sanity check */ + assert ( bigint_is_geq ( modulus, result ) ); +} + +/** + * Perform modular exponentiation of big integers + * + * @v base0 Element 0 of big integer base + * @v modulus0 Element 0 of big integer modulus + * @v exponent0 Element 0 of big integer exponent + * @v result0 Element 0 of big integer to hold result + * @v size Number of elements in base, modulus, and result + * @v exponent_size Number of elements in exponent + */ +void bigint_mod_exp_raw ( const bigint_element_t *base0, + const bigint_element_t *modulus0, + const bigint_element_t *exponent0, + bigint_element_t *result0, + unsigned int size, + unsigned int exponent_size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) *base = + ( ( const void * ) base0 ); + const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = + ( ( const void * ) modulus0 ); + const bigint_t ( exponent_size ) __attribute__ (( may_alias )) + *exponent = ( ( const void * ) exponent0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *result = + ( ( void * ) result0 ); + bigint_t ( size ) temp_base; + bigint_t ( exponent_size ) temp_exponent; + static const uint8_t start[1] = { 0x01 }; + + memcpy ( &temp_base, base, sizeof ( temp_base ) ); + memcpy ( &temp_exponent, exponent, sizeof ( temp_exponent ) ); + bigint_init ( result, start, sizeof ( start ) ); + + while ( ! bigint_is_zero ( &temp_exponent ) ) { + if ( bigint_bit_is_set ( &temp_exponent, 0 ) ) { + bigint_mod_multiply ( result, &temp_base, + modulus, result ); + } + bigint_ror ( &temp_exponent ); + bigint_mod_multiply ( &temp_base, &temp_base, modulus, + &temp_base ); + } +} diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h new file mode 100644 index 00000000..a21b3e5d --- /dev/null +++ b/src/include/ipxe/bigint.h @@ -0,0 +1,268 @@ +#ifndef _IPXE_BIGINT_H +#define _IPXE_BIGINT_H + +/** @file + * + * Big integer support + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** + * Define a big-integer type + * + * @v size Number of elements + * @ret bigint_t Big integer type + */ +#define bigint_t( size ) \ + struct { \ + bigint_element_t element[ (size) ]; \ + } + +/** + * Determine number of elements required for a big-integer type + * + * @v len Maximum length of big integer, in bytes + * @ret size Number of elements + */ +#define bigint_required_size( len ) \ + ( ( (len) + sizeof ( bigint_element_t ) - 1 ) / \ + sizeof ( bigint_element_t ) ) + +/** + * Determine number of elements in big-integer type + * + * @v bigint Big integer + * @ret size Number of elements + */ +#define bigint_size( bigint ) \ + ( sizeof ( *(bigint) ) / sizeof ( (bigint)->element[0] ) ) + +/** + * Initialise big integer + * + * @v value Big integer to initialise + * @v data Raw data + * @v len Length of raw data + */ +#define bigint_init( value, data, len ) do { \ + unsigned int size = bigint_size (value); \ + assert ( (len) <= ( size * sizeof ( (value)->element[0] ) ) ); \ + bigint_init_raw ( (value)->element, size, (data), (len) ); \ + } while ( 0 ) + +/** + * Finalise big integer + * + * @v value Big integer to finalise + * @v out Output buffer + * @v len Length of output buffer + */ +#define bigint_done( value, out, len ) do { \ + unsigned int size = bigint_size (value); \ + bigint_done_raw ( (value)->element, size, (out), (len) ); \ + } while ( 0 ) + +/** + * Add big integers + * + * @v addend Big integer to add + * @v value Big integer to be added to + */ +#define bigint_add( addend, value ) do { \ + unsigned int size = bigint_size (addend); \ + bigint_add_raw ( (addend)->element, (value)->element, size ); \ + } while ( 0 ) + +/** + * Subtract big integers + * + * @v subtrahend Big integer to subtract + * @v value Big integer to be subtracted from + */ +#define bigint_subtract( subtrahend, value ) do { \ + unsigned int size = bigint_size (subtrahend); \ + bigint_subtract_raw ( (subtrahend)->element, (value)->element, \ + size ); \ + } while ( 0 ) + +/** + * Rotate big integer left + * + * @v value Big integer + */ +#define bigint_rol( value ) do { \ + unsigned int size = bigint_size (value); \ + bigint_rol_raw ( (value)->element, size ); \ + } while ( 0 ) + +/** + * Rotate big integer right + * + * @v value Big integer + */ +#define bigint_ror( value ) do { \ + unsigned int size = bigint_size (value); \ + bigint_ror_raw ( (value)->element, size ); \ + } while ( 0 ) + +/** + * Test if big integer is equal to zero + * + * @v value Big integer + * @v size Number of elements + * @ret is_zero Big integer is equal to zero + */ +#define bigint_is_zero( value ) ( { \ + unsigned int size = bigint_size (value); \ + bigint_is_zero_raw ( (value)->element, size ); } ) + +/** + * Compare big integers + * + * @v value Big integer + * @v reference Reference big integer + * @ret geq Big integer is greater than or equal to the reference + */ +#define bigint_is_geq( value, reference ) ( { \ + unsigned int size = bigint_size (value); \ + bigint_is_geq_raw ( (value)->element, (reference)->element, \ + size ); } ) + +/** + * Test if bit is set in big integer + * + * @v value Big integer + * @v bit Bit to test + * @ret is_set Bit is set + */ +#define bigint_bit_is_set( value, bit ) ( { \ + unsigned int size = bigint_size (value); \ + bigint_bit_is_set_raw ( (value)->element, size, bit ); } ) + +/** + * Find highest bit set in big integer + * + * @v value Big integer + * @ret max_bit Highest bit set + 1 (or 0 if no bits set) + */ +#define bigint_max_set_bit( value ) ( { \ + unsigned int size = bigint_size (value); \ + bigint_max_set_bit_raw ( (value)->element, size ); } ) + +/** + * Grow big integer + * + * @v source Source big integer + * @v dest Destination big integer + */ +#define bigint_grow( source, dest ) do { \ + unsigned int source_size = bigint_size (source); \ + unsigned int dest_size = bigint_size (dest); \ + bigint_grow_raw ( (source)->element, source_size, \ + (dest)->element, dest_size ); \ + } while ( 0 ) + +/** + * Shrink big integer + * + * @v source Source big integer + * @v dest Destination big integer + */ +#define bigint_shrink( source, dest ) do { \ + unsigned int source_size = bigint_size (source); \ + unsigned int dest_size = bigint_size (dest); \ + bigint_shrink_raw ( (source)->element, source_size, \ + (dest)->element, dest_size ); \ + } while ( 0 ) + +/** + * Multiply big integers + * + * @v multiplicand Big integer to be multiplied + * @v multiplier Big integer to be multiplied + * @v result Big integer to hold result + */ +#define bigint_multiply( multiplicand, multiplier, result ) do { \ + unsigned int size = bigint_size (multiplicand); \ + bigint_multiply_raw ( (multiplicand)->element, \ + (multiplier)->element, (result)->element, \ + size ); \ + } while ( 0 ) + +/** + * Perform modular multiplication of big integers + * + * @v multiplicand Big integer to be multiplied + * @v multiplier Big integer to be multiplied + * @v modulus Big integer modulus + * @v result Big integer to hold result + */ +#define bigint_mod_multiply( multiplicand, multiplier, modulus, \ + result ) do { \ + unsigned int size = bigint_size (multiplicand); \ + bigint_mod_multiply_raw ( (multiplicand)->element, \ + (multiplier)->element, \ + (modulus)->element, \ + (result)->element, size ); \ + } while ( 0 ) + +/** + * Perform modular exponentiation of big integers + * + * @v base Big integer base + * @v modulus Big integer modulus + * @v exponent Big integer exponent + * @v result Big integer to hold result + */ +#define bigint_mod_exp( base, modulus, exponent, result ) do { \ + unsigned int size = bigint_size (base); \ + unsigned int exponent_size = bigint_size (exponent); \ + bigint_mod_exp_raw ( (base)->element, (modulus)->element, \ + (exponent)->element, (result)->element, \ + size, exponent_size ); \ + } while ( 0 ) + +#include + +void bigint_init_raw ( bigint_element_t *value0, unsigned int size, + const void *data, size_t len ); +void bigint_done_raw ( const bigint_element_t *value0, unsigned int size, + void *out, size_t len ); +void bigint_add_raw ( const bigint_element_t *addend0, + bigint_element_t *value0, unsigned int size ); +void bigint_subtract_raw ( const bigint_element_t *subtrahend0, + bigint_element_t *value0, unsigned int size ); +void bigint_rol_raw ( bigint_element_t *value0, unsigned int size ); +void bigint_ror_raw ( bigint_element_t *value0, unsigned int size ); +int bigint_is_zero_raw ( const bigint_element_t *value0, unsigned int size ); +int bigint_is_geq_raw ( const bigint_element_t *value0, + const bigint_element_t *reference0, + unsigned int size ); +int bigint_bit_is_set_raw ( const bigint_element_t *value0, unsigned int size, + unsigned int bit ); +int bigint_max_set_bit_raw ( const bigint_element_t *value0, + unsigned int size ); +void bigint_grow_raw ( const bigint_element_t *source0, + unsigned int source_size, bigint_element_t *dest0, + unsigned int dest_size ); +void bigint_shrink_raw ( const bigint_element_t *source0, + unsigned int source_size, bigint_element_t *dest0, + unsigned int dest_size ); +void bigint_multiply_raw ( const bigint_element_t *multiplicand0, + const bigint_element_t *multiplier0, + bigint_element_t *result0, + unsigned int size ); +void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, + const bigint_element_t *multiplier0, + const bigint_element_t *modulus0, + bigint_element_t *result0, + unsigned int size ); +void bigint_mod_exp_raw ( const bigint_element_t *base0, + const bigint_element_t *modulus0, + const bigint_element_t *exponent0, + bigint_element_t *result0, + unsigned int size, + unsigned int exponent_size ); + +#endif /* _IPXE_BIGINT_H */ From 4e53303c03a9b24e192811716fa62ce7444c5df2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 16:44:59 +0000 Subject: [PATCH 070/221] [test] Add big integer self-tests These test vectors are generated using Perl's Math::BigInt. Signed-off-by: Michael Brown --- src/tests/bigint_test.c | 2429 +++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 2 files changed, 2430 insertions(+) create mode 100644 src/tests/bigint_test.c diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c new file mode 100644 index 00000000..8c9f188e --- /dev/null +++ b/src/tests/bigint_test.c @@ -0,0 +1,2429 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Big integer self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include + +/** Define inline big integer */ +#define BIGINT(...) { __VA_ARGS__ } + +/* Provide global functions to allow inspection of generated assembly code */ + +void bigint_init_sample ( bigint_element_t *value0, unsigned int size, + const void *data, size_t len ) { + bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( void * ) value0 ); + + bigint_init ( value, data, len ); +} + +void bigint_done_sample ( const bigint_element_t *value0, unsigned int size, + void *out, size_t len ) { + const bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( const void * ) value0 ); + + bigint_done ( value, out, len ); +} + +void bigint_add_sample ( const bigint_element_t *addend0, + bigint_element_t *value0, unsigned int size ) { + const bigint_t ( size ) *addend __attribute__ (( may_alias )) + = ( ( const void * ) addend0 ); + bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( void * ) value0 ); + + bigint_add ( addend, value ); +} + +void bigint_subtract_sample ( const bigint_element_t *subtrahend0, + bigint_element_t *value0, unsigned int size ) { + const bigint_t ( size ) *subtrahend __attribute__ (( may_alias )) + = ( ( const void * ) subtrahend0 ); + bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( void * ) value0 ); + + bigint_subtract ( subtrahend, value ); +} + +void bigint_rol_sample ( bigint_element_t *value0, unsigned int size ) { + bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( void * ) value0 ); + + bigint_rol ( value ); +} + +void bigint_ror_sample ( bigint_element_t *value0, unsigned int size ) { + bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( void * ) value0 ); + + bigint_ror ( value ); +} + +int bigint_is_zero_sample ( const bigint_element_t *value0, + unsigned int size ) { + const bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( const void * ) value0 ); + + return bigint_is_zero ( value ); +} + +int bigint_is_geq_sample ( const bigint_element_t *value0, + const bigint_element_t *reference0, + unsigned int size ) { + const bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( const void * ) value0 ); + const bigint_t ( size ) *reference __attribute__ (( may_alias )) + = ( ( const void * ) reference0 ); + + return bigint_is_geq ( value, reference ); +} + +int bigint_bit_is_set_sample ( const bigint_element_t *value0, + unsigned int size, unsigned int bit ) { + const bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( const void * ) value0 ); + + return bigint_bit_is_set ( value, bit ); +} + +int bigint_max_set_bit_sample ( const bigint_element_t *value0, + unsigned int size ) { + const bigint_t ( size ) *value __attribute__ (( may_alias )) + = ( ( const void * ) value0 ); + + return bigint_max_set_bit ( value ); +} + +void bigint_grow_sample ( const bigint_element_t *source0, + unsigned int source_size, bigint_element_t *dest0, + unsigned int dest_size ) { + const bigint_t ( source_size ) *source __attribute__ (( may_alias )) + = ( ( const void * ) source0 ); + bigint_t ( dest_size ) *dest __attribute__ (( may_alias )) + = ( ( void * ) dest0 ); + + bigint_grow ( source, dest ); +} + +void bigint_shrink_sample ( const bigint_element_t *source0, + unsigned int source_size, bigint_element_t *dest0, + unsigned int dest_size ) { + const bigint_t ( source_size ) *source __attribute__ (( may_alias )) + = ( ( const void * ) source0 ); + bigint_t ( dest_size ) *dest __attribute__ (( may_alias )) + = ( ( void * ) dest0 ); + + bigint_shrink ( source, dest ); +} + +void bigint_multiply_sample ( const bigint_element_t *multiplicand0, + const bigint_element_t *multiplier0, + bigint_element_t *result0, + unsigned int size ) { + const bigint_t ( size ) *multiplicand __attribute__ (( may_alias )) + = ( ( const void * ) multiplicand0 ); + const bigint_t ( size ) *multiplier __attribute__ (( may_alias )) + = ( ( const void * ) multiplier0 ); + bigint_t ( size * 2 ) *result __attribute__ (( may_alias )) + = ( ( void * ) result0 ); + + bigint_multiply ( multiplicand, multiplier, result ); +} + +void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, + const bigint_element_t *multiplier0, + const bigint_element_t *modulus0, + bigint_element_t *result0, + unsigned int size ) { + const bigint_t ( size ) *multiplicand __attribute__ (( may_alias )) + = ( ( const void * ) multiplicand0 ); + const bigint_t ( size ) *multiplier __attribute__ (( may_alias )) + = ( ( const void * ) multiplier0 ); + const bigint_t ( size ) *modulus __attribute__ (( may_alias )) + = ( ( const void * ) modulus0 ); + bigint_t ( size ) *result __attribute__ (( may_alias )) + = ( ( void * ) result0 ); + + bigint_mod_multiply ( multiplicand, multiplier, modulus, result ); +} + +void bigint_mod_exp_sample ( const bigint_element_t *base0, + const bigint_element_t *modulus0, + const bigint_element_t *exponent0, + bigint_element_t *result0, + unsigned int size, unsigned int exponent_size ) { + const bigint_t ( size ) *base __attribute__ (( may_alias )) + = ( ( const void * ) base0 ); + const bigint_t ( size ) *modulus __attribute__ (( may_alias )) + = ( ( const void * ) modulus0 ); + const bigint_t ( exponent_size ) *exponent __attribute__ (( may_alias )) + = ( ( const void * ) exponent0 ); + bigint_t ( size ) *result __attribute__ (( may_alias )) + = ( ( void * ) result0 ); + + bigint_mod_exp ( base, modulus, exponent, result ); +} + +/** + * Report result of big integer addition test + * + * @v addend Big integer to add + * @v value Big integer to be added to + * @v expected Big integer expected result + */ +#define bigint_add_ok( addend, value, expected ) do { \ + static const uint8_t addend_raw[] = addend; \ + static const uint8_t value_raw[] = value; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) addend_temp; \ + bigint_t ( size ) value_temp; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &addend_temp ) == \ + bigint_size ( &value_temp ) ); \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + bigint_init ( &addend_temp, addend_raw, \ + sizeof ( addend_raw ) ); \ + DBG ( "Add:\n" ); \ + DBG_HDA ( 0, &addend_temp, sizeof ( addend_temp ) ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_add ( &addend_temp, &value_temp ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report result of big integer subtraction test + * + * @v subtrahend Big integer to subtract + * @v value Big integer to be subtracted from + * @v expected Big integer expected result + */ +#define bigint_subtract_ok( subtrahend, value, expected ) do { \ + static const uint8_t subtrahend_raw[] = subtrahend; \ + static const uint8_t value_raw[] = value; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) subtrahend_temp; \ + bigint_t ( size ) value_temp; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &subtrahend_temp ) == \ + bigint_size ( &value_temp ) ); \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + bigint_init ( &subtrahend_temp, subtrahend_raw, \ + sizeof ( subtrahend_raw ) ); \ + DBG ( "Subtract:\n" ); \ + DBG_HDA ( 0, &subtrahend_temp, sizeof ( subtrahend_temp ) ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_subtract ( &subtrahend_temp, &value_temp ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report result of big integer left rotation test + * + * @v value Big integer + * @v expected Big integer expected result + */ +#define bigint_rol_ok( value, expected ) do { \ + static const uint8_t value_raw[] = value; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) value_temp; \ + {} /* Fix emacs alignment */ \ + \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + DBG ( "Rotate left:\n" ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_rol ( &value_temp ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report result of big integer right rotation test + * + * @v value Big integer + * @v expected Big integer expected result + */ +#define bigint_ror_ok( value, expected ) do { \ + static const uint8_t value_raw[] = value; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) value_temp; \ + {} /* Fix emacs alignment */ \ + \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + DBG ( "Rotate right:\n" ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_ror ( &value_temp ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report result of big integer zero comparison test + * + * @v value Big integer + * @v expected Expected result + */ +#define bigint_is_zero_ok( value, expected ) do { \ + static const uint8_t value_raw[] = value; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) value_temp; \ + int is_zero; \ + {} /* Fix emacs alignment */ \ + \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + DBG ( "Zero comparison:\n" ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + is_zero = bigint_is_zero ( &value_temp ); \ + DBG ( "...is %szero\n", ( is_zero ? "" : "not " ) ); \ + ok ( ( !! is_zero ) == ( !! (expected) ) ); \ + } while ( 0 ) + +/** + * Report result of big integer greater-than-or-equal comparison test + * + * @v value Big integer + * @v reference Reference big integer + * @v expected Expected result + */ +#define bigint_is_geq_ok( value, reference, expected ) do { \ + static const uint8_t value_raw[] = value; \ + static const uint8_t reference_raw[] = reference; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) value_temp; \ + bigint_t ( size ) reference_temp; \ + int is_geq; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &reference_temp ) == \ + bigint_size ( &value_temp ) ); \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + bigint_init ( &reference_temp, reference_raw, \ + sizeof ( reference_raw ) ); \ + DBG ( "Greater-than-or-equal comparison:\n" ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + DBG_HDA ( 0, &reference_temp, sizeof ( reference_temp ) ); \ + is_geq = bigint_is_geq ( &value_temp, &reference_temp ); \ + DBG ( "...is %sgreater than or equal\n", \ + ( is_geq ? "" : "not " ) ); \ + ok ( ( !! is_geq ) == ( !! (expected) ) ); \ + } while ( 0 ) + +/** + * Report result of big integer bit-set test + * + * @v value Big integer + * @v bit Bit to test + * @v expected Expected result + */ +#define bigint_bit_is_set_ok( value, bit, expected ) do { \ + static const uint8_t value_raw[] = value; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) value_temp; \ + int bit_is_set; \ + {} /* Fix emacs alignment */ \ + \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + DBG ( "Bit set:\n" ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bit_is_set = bigint_bit_is_set ( &value_temp, bit ); \ + DBG ( "...bit %d is %sset\n", bit, \ + ( bit_is_set ? "" : "not " ) ); \ + ok ( ( !! bit_is_set ) == ( !! (expected) ) ); \ + } while ( 0 ) + +/** + * Report result of big integer maximum set bit test + * + * @v value Big integer + * @v expected Expected result + */ +#define bigint_max_set_bit_ok( value, expected ) do { \ + static const uint8_t value_raw[] = value; \ + unsigned int size = \ + bigint_required_size ( sizeof ( value_raw ) ); \ + bigint_t ( size ) value_temp; \ + int max_set_bit; \ + {} /* Fix emacs alignment */ \ + \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ + DBG ( "Maximum set bit:\n" ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + max_set_bit = bigint_max_set_bit ( &value_temp ); \ + DBG ( "...maximum set bit is bit %d\n", ( max_set_bit - 1 ) ); \ + ok ( max_set_bit == (expected) ); \ + } while ( 0 ) + +/** + * Report result of big integer multiplication test + * + * @v multiplicand Big integer to be multiplied + * @v multiplier Big integer to be multiplied + * @v expected Big integer expected result + */ +#define bigint_multiply_ok( multiplicand, multiplier, expected ) do { \ + static const uint8_t multiplicand_raw[] = multiplicand; \ + static const uint8_t multiplier_raw[] = multiplier; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( multiplicand_raw ) ); \ + bigint_t ( size ) multiplicand_temp; \ + bigint_t ( size ) multiplier_temp; \ + bigint_t ( size * 2 ) result_temp; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &multiplier_temp ) == \ + bigint_size ( &multiplicand_temp ) ); \ + assert ( bigint_size ( &result_temp ) == \ + ( 2 * bigint_size ( &multiplicand_temp ) ) ); \ + bigint_init ( &multiplicand_temp, multiplicand_raw, \ + sizeof ( multiplicand_raw ) ); \ + bigint_init ( &multiplier_temp, multiplier_raw, \ + sizeof ( multiplier_raw ) ); \ + DBG ( "Multiply:\n" ); \ + DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\ + DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \ + bigint_multiply ( &multiplicand_temp, &multiplier_temp, \ + &result_temp ); \ + DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ + bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report result of big integer modular multiplication test + * + * @v multiplicand Big integer to be multiplied + * @v multiplier Big integer to be multiplied + * @v modulus Big integer modulus + * @v expected Big integer expected result + */ +#define bigint_mod_multiply_ok( multiplicand, multiplier, modulus, \ + expected ) do { \ + static const uint8_t multiplicand_raw[] = multiplicand; \ + static const uint8_t multiplier_raw[] = multiplier; \ + static const uint8_t modulus_raw[] = modulus; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( multiplicand_raw ) ); \ + bigint_t ( size ) multiplicand_temp; \ + bigint_t ( size ) multiplier_temp; \ + bigint_t ( size ) modulus_temp; \ + bigint_t ( size ) result_temp; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &multiplier_temp ) == \ + bigint_size ( &multiplicand_temp ) ); \ + assert ( bigint_size ( &multiplier_temp ) == \ + bigint_size ( &modulus_temp ) ); \ + assert ( bigint_size ( &multiplier_temp ) == \ + bigint_size ( &result_temp ) ); \ + bigint_init ( &multiplicand_temp, multiplicand_raw, \ + sizeof ( multiplicand_raw ) ); \ + bigint_init ( &multiplier_temp, multiplier_raw, \ + sizeof ( multiplier_raw ) ); \ + bigint_init ( &modulus_temp, modulus_raw, \ + sizeof ( modulus_raw ) ); \ + DBG ( "Modular multiply:\n" ); \ + DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\ + DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \ + DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ + bigint_mod_multiply ( &multiplicand_temp, &multiplier_temp, \ + &modulus_temp, &result_temp ); \ + DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ + bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report result of big integer modular exponentiation test + * + * @v base Big integer base + * @v modulus Big integer modulus + * @v exponent Big integer exponent + * @v expected Big integer expected result + */ +#define bigint_mod_exp_ok( base, modulus, exponent, expected ) do { \ + static const uint8_t base_raw[] = base; \ + static const uint8_t modulus_raw[] = modulus; \ + static const uint8_t exponent_raw[] = exponent; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( base_raw ) ); \ + unsigned int exponent_size = \ + bigint_required_size ( sizeof ( exponent_raw ) ); \ + bigint_t ( size ) base_temp; \ + bigint_t ( size ) modulus_temp; \ + bigint_t ( exponent_size ) exponent_temp; \ + bigint_t ( size ) result_temp; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &modulus_temp ) == \ + bigint_size ( &base_temp ) ); \ + assert ( bigint_size ( &modulus_temp ) == \ + bigint_size ( &result_temp ) ); \ + bigint_init ( &base_temp, base_raw, sizeof ( base_raw ) ); \ + bigint_init ( &modulus_temp, modulus_raw, \ + sizeof ( modulus_raw ) ); \ + bigint_init ( &exponent_temp, exponent_raw, \ + sizeof ( exponent_raw ) ); \ + DBG ( "Modular exponentiation:\n" ); \ + DBG_HDA ( 0, &base_temp, sizeof ( base_temp ) ); \ + DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ + DBG_HDA ( 0, &exponent_temp, sizeof ( exponent_temp ) ); \ + bigint_mod_exp ( &base_temp, &modulus_temp, &exponent_temp, \ + &result_temp ); \ + DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ + bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + +/** + * Perform big integer self-tests + * + */ +static void bigint_test_exec ( void ) { + + bigint_add_ok ( BIGINT ( 0x8a ), + BIGINT ( 0x43 ), + BIGINT ( 0xcd ) ); + bigint_add_ok ( BIGINT ( 0xc5, 0x7b ), + BIGINT ( 0xd6, 0xb1 ), + BIGINT ( 0x9c, 0x2c ) ); + bigint_add_ok ( BIGINT ( 0xf9, 0xd9, 0xdc ), + BIGINT ( 0x6d, 0x4b, 0xca ), + BIGINT ( 0x67, 0x25, 0xa6 ) ); + bigint_add_ok ( BIGINT ( 0xdd, 0xc2, 0x20, 0x5f ), + BIGINT ( 0x80, 0x32, 0xc4, 0xb0 ), + BIGINT ( 0x5d, 0xf4, 0xe5, 0x0f ) ); + bigint_add_ok ( BIGINT ( 0x01, 0xed, 0x45, 0x4b, 0x41, 0xeb, 0x4c, + 0x2e, 0x53, 0x07, 0x15, 0x51, 0x56, 0x47, + 0x29, 0xfc, 0x9c, 0xbd, 0xbd, 0xfb, 0x1b, + 0xd1, 0x1d ), + BIGINT ( 0x73, 0xed, 0xfc, 0x35, 0x31, 0x22, 0xd7, + 0xb1, 0xea, 0x91, 0x5a, 0xe4, 0xba, 0xbc, + 0xa1, 0x38, 0x72, 0xae, 0x4b, 0x1c, 0xc1, + 0x05, 0xb3 ), + BIGINT ( 0x75, 0xdb, 0x41, 0x80, 0x73, 0x0e, 0x23, + 0xe0, 0x3d, 0x98, 0x70, 0x36, 0x11, 0x03, + 0xcb, 0x35, 0x0f, 0x6c, 0x09, 0x17, 0xdc, + 0xd6, 0xd0 ) ); + bigint_add_ok ( BIGINT ( 0x06, 0x8e, 0xd6, 0x18, 0xbb, 0x4b, 0x0c, + 0xc5, 0x85, 0xde, 0xee, 0x9b, 0x3f, 0x65, + 0x63, 0x86, 0xf5, 0x5a, 0x9f, 0xa2, 0xd7, + 0xb2, 0xc7, 0xb6, 0x1d, 0x28, 0x6c, 0x50, + 0x47, 0x10, 0x0a, 0x0e, 0x86, 0xcd, 0x2a, + 0x64, 0xdc, 0xe6, 0x9d, 0x96, 0xd8, 0xf4, + 0x56, 0x46, 0x6f, 0xbb, 0x7b, 0x64, 0x6f, + 0xdc, 0x2a, 0xd1, 0x3b, 0xcc, 0x03, 0x85, + 0x95, 0xf4, 0xe9, 0x68, 0x1f, 0x5c, 0xc5, + 0xbf, 0x97, 0x19, 0x12, 0x88, 0x2e, 0x88, + 0xb9, 0x34, 0xac, 0x74, 0x83, 0x2d, 0x8f, + 0xb3, 0x97, 0x53, 0x99, 0xf3, 0xb4, 0x8b, + 0x2d, 0x98, 0x69, 0x8d, 0x19, 0xf0, 0x40, + 0x66, 0x3f, 0x60, 0x78, 0x34, 0x7f, 0x9b, + 0xf7, 0x01, 0x74, 0x55, 0xca, 0x63, 0x25, + 0x7b, 0x86, 0xe9, 0x73, 0xfd, 0x5d, 0x77, + 0x32, 0x5e, 0x9e, 0x42, 0x53, 0xb6, 0x35, + 0x92, 0xb9, 0xd7, 0x1b, 0xf7, 0x16, 0x55, + 0xf6, 0xe2 ), + BIGINT ( 0x3f, 0x8f, 0x62, 0x21, 0x4a, 0x7a, 0xa2, + 0xef, 0xa8, 0x79, 0x9b, 0x73, 0xac, 0xde, + 0x72, 0xe4, 0xfc, 0x3c, 0xd3, 0xa9, 0x44, + 0x1a, 0x6a, 0x02, 0x76, 0xe3, 0x78, 0x4d, + 0x2e, 0x07, 0x9b, 0xb6, 0x3d, 0x5d, 0xc5, + 0xcd, 0x68, 0x23, 0x4b, 0x5f, 0x89, 0x0e, + 0xd7, 0xa7, 0xff, 0x18, 0x80, 0xdc, 0xfb, + 0x34, 0x45, 0xca, 0x4b, 0xdb, 0x8a, 0x19, + 0xcb, 0xc9, 0xe5, 0xa1, 0x63, 0xa2, 0x0d, + 0x56, 0xc4, 0xf9, 0x51, 0x1b, 0x88, 0x4e, + 0x36, 0xab, 0x15, 0x4d, 0x8f, 0xdc, 0x08, + 0xc4, 0x4d, 0x43, 0xc7, 0x2b, 0xc9, 0x5c, + 0x05, 0x26, 0xe3, 0x46, 0xf0, 0x64, 0xaa, + 0x02, 0xa4, 0xbe, 0x3a, 0xd1, 0xca, 0x07, + 0x6a, 0x6e, 0x62, 0xf4, 0x57, 0x71, 0x96, + 0xec, 0xf0, 0x0b, 0xac, 0xa4, 0x4a, 0xa3, + 0x6d, 0x01, 0xba, 0xbd, 0x62, 0xc0, 0x10, + 0x54, 0x33, 0x8a, 0x71, 0xef, 0xaa, 0x1c, + 0x25, 0x25 ), + BIGINT ( 0x46, 0x1e, 0x38, 0x3a, 0x05, 0xc5, 0xaf, + 0xb5, 0x2e, 0x58, 0x8a, 0x0e, 0xec, 0x43, + 0xd6, 0x6b, 0xf1, 0x97, 0x73, 0x4c, 0x1b, + 0xcd, 0x31, 0xb8, 0x94, 0x0b, 0xe4, 0x9d, + 0x75, 0x17, 0xa5, 0xc4, 0xc4, 0x2a, 0xf0, + 0x32, 0x45, 0x09, 0xe8, 0xf6, 0x62, 0x03, + 0x2d, 0xee, 0x6e, 0xd3, 0xfc, 0x41, 0x6b, + 0x10, 0x70, 0x9b, 0x87, 0xa7, 0x8d, 0x9f, + 0x61, 0xbe, 0xcf, 0x09, 0x82, 0xfe, 0xd3, + 0x16, 0x5c, 0x12, 0x63, 0xa3, 0xb6, 0xd6, + 0xef, 0xdf, 0xc1, 0xc2, 0x13, 0x09, 0x98, + 0x77, 0xe4, 0x97, 0x61, 0x1f, 0x7d, 0xe7, + 0x32, 0xbf, 0x4c, 0xd4, 0x0a, 0x54, 0xea, + 0x68, 0xe4, 0x1e, 0xb3, 0x06, 0x49, 0xa3, + 0x61, 0x6f, 0xd7, 0x4a, 0x21, 0xd4, 0xbc, + 0x68, 0x76, 0xf5, 0x20, 0xa1, 0xa8, 0x1a, + 0x9f, 0x60, 0x58, 0xff, 0xb6, 0x76, 0x45, + 0xe6, 0xed, 0x61, 0x8d, 0xe6, 0xc0, 0x72, + 0x1c, 0x07 ) ); + bigint_subtract_ok ( BIGINT ( 0x83 ), + BIGINT ( 0x50 ), + BIGINT ( 0xcd ) ); + bigint_subtract_ok ( BIGINT ( 0x2c, 0x7c ), + BIGINT ( 0x49, 0x0e ), + BIGINT ( 0x1c, 0x92 ) ); + bigint_subtract_ok ( BIGINT ( 0x9c, 0x30, 0xbf ), + BIGINT ( 0xde, 0x4e, 0x07 ), + BIGINT ( 0x42, 0x1d, 0x48 ) ); + bigint_subtract_ok ( BIGINT ( 0xbb, 0x77, 0x32, 0x5a ), + BIGINT ( 0x5a, 0xd5, 0xfe, 0x28 ), + BIGINT ( 0x9f, 0x5e, 0xcb, 0xce ) ); + bigint_subtract_ok ( BIGINT ( 0x7b, 0xaa, 0x16, 0xcf, 0x15, 0x87, + 0xe0, 0x4f, 0x2c, 0xa3, 0xec, 0x2f, + 0x46, 0xfb, 0x83, 0xc6, 0xe0, 0xee, + 0x57, 0xfa, 0x04, 0xce, 0xa6 ), + BIGINT ( 0x46, 0x55, 0xb6, 0x23, 0x63, 0xd0, + 0x55, 0xdb, 0x8f, 0xcc, 0x55, 0xa8, + 0x2f, 0x85, 0xc1, 0x9f, 0x2c, 0x13, + 0x10, 0x9e, 0x76, 0x3c, 0x11 ), + BIGINT ( 0xca, 0xab, 0x9f, 0x54, 0x4e, 0x48, + 0x75, 0x8c, 0x63, 0x28, 0x69, 0x78, + 0xe8, 0x8a, 0x3d, 0xd8, 0x4b, 0x24, + 0xb8, 0xa4, 0x71, 0x6d, 0x6b ) ); + bigint_subtract_ok ( BIGINT ( 0x5b, 0x06, 0x77, 0x7b, 0xfd, 0x34, + 0x5f, 0x0f, 0xd9, 0xbd, 0x8e, 0x5d, + 0xc8, 0x4a, 0x70, 0x95, 0x1b, 0xb6, + 0x48, 0xfb, 0x0e, 0x40, 0xce, 0x06, + 0x66, 0xcc, 0x29, 0xe9, 0x51, 0x59, + 0x59, 0xc9, 0x65, 0x07, 0x75, 0xb8, + 0xd4, 0xcb, 0x07, 0x68, 0x14, 0x48, + 0xc7, 0x1e, 0xfe, 0xb3, 0x4c, 0xf1, + 0x10, 0xf0, 0xc7, 0x82, 0x38, 0x4c, + 0xaf, 0x05, 0x6d, 0x91, 0xc5, 0x18, + 0xfd, 0x1e, 0x26, 0x1b, 0xef, 0x71, + 0x70, 0x2e, 0x06, 0x70, 0x8e, 0x54, + 0xfa, 0x2b, 0x4d, 0x96, 0x85, 0x10, + 0x03, 0x76, 0xe7, 0x17, 0x59, 0x86, + 0x6c, 0x8b, 0x24, 0x6e, 0xd9, 0x30, + 0xf3, 0xd2, 0x9b, 0x62, 0xdc, 0x23, + 0x54, 0x06, 0x51, 0xb1, 0x95, 0x58, + 0xec, 0x27, 0xf6, 0x19, 0xae, 0xf4, + 0x31, 0xec, 0x72, 0x53, 0xcd, 0x32, + 0xed, 0xf4, 0x25, 0x4a, 0x5b, 0x36, + 0xa2, 0xb4, 0xa0, 0x29, 0x0c, 0x6b, + 0x3f, 0xc2 ), + BIGINT ( 0x7a, 0xd4, 0x25, 0xf1, 0xb5, 0xf5, + 0x00, 0x96, 0x47, 0x5b, 0x4f, 0x9f, + 0x1f, 0x61, 0x69, 0xd9, 0x72, 0x47, + 0xde, 0xbd, 0x87, 0x5d, 0x50, 0x91, + 0x69, 0xd8, 0x35, 0xe0, 0x43, 0xd8, + 0xd5, 0x15, 0xf2, 0xcd, 0x01, 0x73, + 0x0d, 0x34, 0xf0, 0x34, 0x46, 0x76, + 0xc0, 0x55, 0x7b, 0x27, 0xf5, 0x7b, + 0x55, 0xe9, 0xd0, 0x29, 0x0b, 0x4b, + 0x9f, 0x07, 0xbf, 0x2c, 0x3f, 0xef, + 0x36, 0x34, 0xde, 0x29, 0x1d, 0x5d, + 0x84, 0x5a, 0x5d, 0xc1, 0x02, 0x4d, + 0x56, 0xf1, 0x47, 0x39, 0x37, 0xc9, + 0xb5, 0x5f, 0x73, 0xec, 0x7c, 0x3d, + 0xbd, 0xc0, 0xfd, 0x38, 0x6c, 0x91, + 0x88, 0x4a, 0x0f, 0xee, 0xa1, 0x80, + 0xf5, 0x6a, 0x7c, 0x8c, 0x02, 0xc3, + 0x5a, 0xb2, 0x15, 0xa6, 0x2f, 0x6b, + 0x5b, 0x78, 0xb5, 0xf3, 0xbd, 0xd0, + 0xc8, 0xbc, 0xb1, 0xbb, 0xe1, 0xce, + 0x22, 0x80, 0x34, 0x5a, 0x2a, 0x27, + 0x83, 0xdc ), + BIGINT ( 0x1f, 0xcd, 0xae, 0x75, 0xb8, 0xc0, + 0xa1, 0x86, 0x6d, 0x9d, 0xc1, 0x41, + 0x57, 0x16, 0xf9, 0x44, 0x56, 0x91, + 0x95, 0xc2, 0x79, 0x1c, 0x82, 0x8b, + 0x03, 0x0c, 0x0b, 0xf6, 0xf2, 0x7f, + 0x7b, 0x4c, 0x8d, 0xc5, 0x8b, 0xba, + 0x38, 0x69, 0xe8, 0xcc, 0x32, 0x2d, + 0xf9, 0x36, 0x7c, 0x74, 0xa8, 0x8a, + 0x44, 0xf9, 0x08, 0xa6, 0xd2, 0xfe, + 0xf0, 0x02, 0x51, 0x9a, 0x7a, 0xd6, + 0x39, 0x16, 0xb8, 0x0d, 0x2d, 0xec, + 0x14, 0x2c, 0x57, 0x50, 0x73, 0xf8, + 0x5c, 0xc5, 0xf9, 0xa2, 0xb2, 0xb9, + 0xb1, 0xe8, 0x8c, 0xd5, 0x22, 0xb7, + 0x51, 0x35, 0xd8, 0xc9, 0x93, 0x60, + 0x94, 0x77, 0x74, 0x8b, 0xc5, 0x5d, + 0xa1, 0x64, 0x2a, 0xda, 0x6d, 0x6a, + 0x6e, 0x8a, 0x1f, 0x8c, 0x80, 0x77, + 0x29, 0x8c, 0x43, 0x9f, 0xf0, 0x9d, + 0xda, 0xc8, 0x8c, 0x71, 0x86, 0x97, + 0x7f, 0xcb, 0x94, 0x31, 0x1d, 0xbc, + 0x44, 0x1a ) ); + bigint_rol_ok ( BIGINT ( 0xe0 ), + BIGINT ( 0xc0 ) ); + bigint_rol_ok ( BIGINT ( 0x43, 0x1d ), + BIGINT ( 0x86, 0x3a ) ); + bigint_rol_ok ( BIGINT ( 0xac, 0xed, 0x9b ), + BIGINT ( 0x59, 0xdb, 0x36 ) ); + bigint_rol_ok ( BIGINT ( 0x2c, 0xe8, 0x3a, 0x22 ), + BIGINT ( 0x59, 0xd0, 0x74, 0x44 ) ); + bigint_rol_ok ( BIGINT ( 0x4e, 0x88, 0x4a, 0x05, 0x5e, 0x10, 0xee, + 0x5b, 0xc6, 0x40, 0x0e, 0x03, 0xd7, 0x0d, + 0x28, 0xa5, 0x55, 0xb2, 0x50, 0xef, 0x69, + 0xd1, 0x1d ), + BIGINT ( 0x9d, 0x10, 0x94, 0x0a, 0xbc, 0x21, 0xdc, + 0xb7, 0x8c, 0x80, 0x1c, 0x07, 0xae, 0x1a, + 0x51, 0x4a, 0xab, 0x64, 0xa1, 0xde, 0xd3, + 0xa2, 0x3a ) ); + bigint_rol_ok ( BIGINT ( 0x07, 0x62, 0x78, 0x70, 0x2e, 0xd4, 0x41, + 0xaa, 0x9b, 0x50, 0xb1, 0x9a, 0x71, 0xf5, + 0x1c, 0x2f, 0xe7, 0x0d, 0xf1, 0x46, 0x57, + 0x04, 0x99, 0x78, 0x4e, 0x84, 0x78, 0xba, + 0x57, 0xea, 0xa5, 0x43, 0xf7, 0x02, 0xf0, + 0x7a, 0x22, 0x60, 0x65, 0x42, 0xf2, 0x33, + 0x7d, 0xe3, 0xa8, 0x1b, 0xc4, 0x14, 0xdb, + 0xee, 0x4a, 0xf1, 0xe1, 0x52, 0xd4, 0xda, + 0x23, 0xed, 0x13, 0x5d, 0xea, 0xcf, 0xf6, + 0x5e, 0x39, 0x84, 0xe2, 0xb3, 0xa2, 0x05, + 0xba, 0xd9, 0x49, 0x8e, 0x75, 0x1d, 0xdb, + 0xe6, 0xb1, 0x6e, 0xda, 0x0a, 0x83, 0xd0, + 0x6e, 0xcf, 0x7a, 0x66, 0xb7, 0x64, 0x84, + 0xf5, 0x09, 0x5a, 0xa8, 0x11, 0x93, 0xf3, + 0x4f, 0x02, 0x28, 0x00, 0x3a, 0xf0, 0xa9, + 0x08, 0x77, 0x04, 0xf5, 0x04, 0xcd, 0x6b, + 0x24, 0xbe, 0x0f, 0x6d, 0xe3, 0xb2, 0xd3, + 0x07, 0x68, 0xe9, 0x00, 0x59, 0xa0, 0xe4, + 0x9e, 0x5e ), + BIGINT ( 0x0e, 0xc4, 0xf0, 0xe0, 0x5d, 0xa8, 0x83, + 0x55, 0x36, 0xa1, 0x63, 0x34, 0xe3, 0xea, + 0x38, 0x5f, 0xce, 0x1b, 0xe2, 0x8c, 0xae, + 0x09, 0x32, 0xf0, 0x9d, 0x08, 0xf1, 0x74, + 0xaf, 0xd5, 0x4a, 0x87, 0xee, 0x05, 0xe0, + 0xf4, 0x44, 0xc0, 0xca, 0x85, 0xe4, 0x66, + 0xfb, 0xc7, 0x50, 0x37, 0x88, 0x29, 0xb7, + 0xdc, 0x95, 0xe3, 0xc2, 0xa5, 0xa9, 0xb4, + 0x47, 0xda, 0x26, 0xbb, 0xd5, 0x9f, 0xec, + 0xbc, 0x73, 0x09, 0xc5, 0x67, 0x44, 0x0b, + 0x75, 0xb2, 0x93, 0x1c, 0xea, 0x3b, 0xb7, + 0xcd, 0x62, 0xdd, 0xb4, 0x15, 0x07, 0xa0, + 0xdd, 0x9e, 0xf4, 0xcd, 0x6e, 0xc9, 0x09, + 0xea, 0x12, 0xb5, 0x50, 0x23, 0x27, 0xe6, + 0x9e, 0x04, 0x50, 0x00, 0x75, 0xe1, 0x52, + 0x10, 0xee, 0x09, 0xea, 0x09, 0x9a, 0xd6, + 0x49, 0x7c, 0x1e, 0xdb, 0xc7, 0x65, 0xa6, + 0x0e, 0xd1, 0xd2, 0x00, 0xb3, 0x41, 0xc9, + 0x3c, 0xbc ) ); + bigint_ror_ok ( BIGINT ( 0x8f ), + BIGINT ( 0x47 ) ); + bigint_ror_ok ( BIGINT ( 0xaa, 0x1d ), + BIGINT ( 0x55, 0x0e ) ); + bigint_ror_ok ( BIGINT ( 0xf0, 0xbd, 0x68 ), + BIGINT ( 0x78, 0x5e, 0xb4 ) ); + bigint_ror_ok ( BIGINT ( 0x33, 0xa0, 0x3d, 0x95 ), + BIGINT ( 0x19, 0xd0, 0x1e, 0xca ) ); + bigint_ror_ok ( BIGINT ( 0xa1, 0xf4, 0xb9, 0x64, 0x91, 0x99, 0xa1, + 0xf4, 0xae, 0xeb, 0x71, 0x97, 0x1b, 0x71, + 0x09, 0x38, 0x3f, 0x8f, 0xc5, 0x3a, 0xb9, + 0x75, 0x94 ), + BIGINT ( 0x50, 0xfa, 0x5c, 0xb2, 0x48, 0xcc, 0xd0, + 0xfa, 0x57, 0x75, 0xb8, 0xcb, 0x8d, 0xb8, + 0x84, 0x9c, 0x1f, 0xc7, 0xe2, 0x9d, 0x5c, + 0xba, 0xca ) ); + bigint_ror_ok ( BIGINT ( 0xc0, 0xb3, 0x78, 0x46, 0x69, 0x6e, 0x35, + 0x94, 0xed, 0x28, 0xdc, 0xfd, 0xf6, 0xdb, + 0x2d, 0x24, 0xcb, 0xa4, 0x6f, 0x0e, 0x58, + 0x89, 0x04, 0xec, 0xc8, 0x0c, 0x2d, 0xb3, + 0x58, 0xa7, 0x22, 0x6d, 0x93, 0xe0, 0xb8, + 0x48, 0x6a, 0x3f, 0x04, 0x7e, 0xbe, 0xb8, + 0xa7, 0x84, 0xf5, 0xc9, 0x2f, 0x60, 0x9e, + 0x7c, 0xbc, 0xaf, 0x28, 0x89, 0x2f, 0xaa, + 0xd1, 0x82, 0x77, 0xa4, 0xdf, 0xf3, 0x4a, + 0xc6, 0xed, 0xa3, 0x07, 0xb4, 0xa9, 0xfd, + 0xef, 0xf8, 0x20, 0xb9, 0xb3, 0xff, 0x35, + 0x27, 0xed, 0x02, 0xea, 0xec, 0x63, 0xc0, + 0x46, 0x97, 0xc0, 0x4c, 0xca, 0x89, 0xca, + 0x14, 0xe8, 0xe0, 0x02, 0x14, 0x44, 0x46, + 0xf3, 0x2f, 0xbc, 0x6a, 0x28, 0xa2, 0xbe, + 0x20, 0xc8, 0xaa, 0x0f, 0xd9, 0x51, 0x8e, + 0x8d, 0x51, 0x29, 0x61, 0xef, 0x48, 0xae, + 0x3e, 0xe5, 0x10, 0xbf, 0xda, 0x9b, 0x92, + 0xb3, 0x77 ), + BIGINT ( 0x60, 0x59, 0xbc, 0x23, 0x34, 0xb7, 0x1a, + 0xca, 0x76, 0x94, 0x6e, 0x7e, 0xfb, 0x6d, + 0x96, 0x92, 0x65, 0xd2, 0x37, 0x87, 0x2c, + 0x44, 0x82, 0x76, 0x64, 0x06, 0x16, 0xd9, + 0xac, 0x53, 0x91, 0x36, 0xc9, 0xf0, 0x5c, + 0x24, 0x35, 0x1f, 0x82, 0x3f, 0x5f, 0x5c, + 0x53, 0xc2, 0x7a, 0xe4, 0x97, 0xb0, 0x4f, + 0x3e, 0x5e, 0x57, 0x94, 0x44, 0x97, 0xd5, + 0x68, 0xc1, 0x3b, 0xd2, 0x6f, 0xf9, 0xa5, + 0x63, 0x76, 0xd1, 0x83, 0xda, 0x54, 0xfe, + 0xf7, 0xfc, 0x10, 0x5c, 0xd9, 0xff, 0x9a, + 0x93, 0xf6, 0x81, 0x75, 0x76, 0x31, 0xe0, + 0x23, 0x4b, 0xe0, 0x26, 0x65, 0x44, 0xe5, + 0x0a, 0x74, 0x70, 0x01, 0x0a, 0x22, 0x23, + 0x79, 0x97, 0xde, 0x35, 0x14, 0x51, 0x5f, + 0x10, 0x64, 0x55, 0x07, 0xec, 0xa8, 0xc7, + 0x46, 0xa8, 0x94, 0xb0, 0xf7, 0xa4, 0x57, + 0x1f, 0x72, 0x88, 0x5f, 0xed, 0x4d, 0xc9, + 0x59, 0xbb ) ); + bigint_is_zero_ok ( BIGINT ( 0x9b ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0x5a, 0x9d ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0x5f, 0x80, 0x78 ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0xa0, 0x52, 0x47, 0x2e ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0x18, 0x08, 0x49, 0xdb, 0x7b, 0x5c, + 0xe7, 0x41, 0x07, 0xdf, 0xed, 0xf9, + 0xd3, 0x92, 0x0d, 0x75, 0xa6, 0xb0, + 0x14, 0xfa, 0xdd, 0xfd, 0x82 ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0x04, 0x04, 0xb5, 0xf5, 0x01, 0xae, + 0x2b, 0x91, 0xa7, 0xc1, 0x49, 0x97, + 0x3f, 0x45, 0x53, 0x52, 0xb8, 0x52, + 0xf1, 0x62, 0xa5, 0x21, 0x18, 0xd4, + 0xb0, 0xb4, 0x8a, 0x17, 0x0e, 0xe8, + 0xeb, 0xaa, 0x28, 0xae, 0x3d, 0x8e, + 0xe3, 0x6c, 0xd0, 0x01, 0x0c, 0x54, + 0xca, 0x23, 0xbb, 0x06, 0xcd, 0x7a, + 0x61, 0x89, 0x38, 0x34, 0x6e, 0xc7, + 0xc2, 0xee, 0xb1, 0x80, 0x61, 0x0e, + 0xc6, 0x8d, 0x65, 0xa0, 0xeb, 0x34, + 0xe9, 0x63, 0x09, 0x4c, 0x20, 0xac, + 0x42, 0xe3, 0x35, 0xa2, 0x3e, 0x3b, + 0x2e, 0x18, 0x70, 0x45, 0x7c, 0xab, + 0x42, 0xcc, 0xe0, 0x9e, 0x7c, 0x42, + 0xd1, 0xda, 0x6c, 0x51, 0x10, 0x1e, + 0x0e, 0x3f, 0xe5, 0xd6, 0xd8, 0x56, + 0x08, 0xb2, 0x3b, 0x15, 0xc4, 0x7c, + 0x0c, 0x7e, 0xaf, 0x7b, 0x9d, 0xd6, + 0x2b, 0xc0, 0x2f, 0xa2, 0xa3, 0xa3, + 0x77, 0x58, 0x1b, 0xe9, 0xa8, 0x9a, + 0x23, 0x7f ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0x00 ), + 1 ); + bigint_is_zero_ok ( BIGINT ( 0x00, 0x00 ), + 1 ); + bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00 ), + 1 ); + bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00 ), + 1 ); + bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 ), + 1 ); + bigint_is_zero_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ), + 1 ); + bigint_is_zero_ok ( BIGINT ( 0xff ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0xff, 0xff ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff ), + 0 ); + bigint_is_zero_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff ), + 0 ); + bigint_is_geq_ok ( BIGINT ( 0xa2 ), + BIGINT ( 0x58 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0x58 ), + BIGINT ( 0xa2 ), + 0 ); + bigint_is_geq_ok ( BIGINT ( 0xa2 ), + BIGINT ( 0xa2 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0x61, 0x29 ), + BIGINT ( 0x87, 0xac ), + 0 ); + bigint_is_geq_ok ( BIGINT ( 0x87, 0xac ), + BIGINT ( 0x61, 0x29 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0x61, 0x29 ), + BIGINT ( 0x61, 0x29 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0xe6, 0x63, 0x14 ), + BIGINT ( 0xb7, 0x2b, 0x76 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0xb7, 0x2b, 0x76 ), + BIGINT ( 0xe6, 0x63, 0x14 ), + 0 ); + bigint_is_geq_ok ( BIGINT ( 0xe6, 0x63, 0x14 ), + BIGINT ( 0xe6, 0x63, 0x14 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ), + BIGINT ( 0xb5, 0xf9, 0x9b, 0x90 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0xb5, 0xf9, 0x9b, 0x90 ), + BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ), + 0 ); + bigint_is_geq_ok ( BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ), + BIGINT ( 0xe7, 0x4f, 0xd4, 0x80 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12, + 0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d, + 0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b, + 0x60, 0x98 ), + BIGINT ( 0x77, 0xbc, 0x3b, 0x1b, 0x57, 0x43, 0x3b, + 0x8c, 0x82, 0xda, 0xb5, 0xc7, 0x18, 0x09, + 0xb3, 0x59, 0x0e, 0x53, 0x2a, 0xb9, 0xd8, + 0xa2, 0xb4 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0x77, 0xbc, 0x3b, 0x1b, 0x57, 0x43, 0x3b, + 0x8c, 0x82, 0xda, 0xb5, 0xc7, 0x18, 0x09, + 0xb3, 0x59, 0x0e, 0x53, 0x2a, 0xb9, 0xd8, + 0xa2, 0xb4 ), + BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12, + 0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d, + 0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b, + 0x60, 0x98 ), + 0 ); + bigint_is_geq_ok ( BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12, + 0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d, + 0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b, + 0x60, 0x98 ), + BIGINT ( 0xe6, 0x2c, 0x7c, 0x24, 0x78, 0x8f, 0x12, + 0x20, 0xde, 0xd3, 0x6b, 0xc9, 0x97, 0x2d, + 0x66, 0x74, 0xe5, 0xb6, 0xf7, 0x8f, 0x2b, + 0x60, 0x98 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4, + 0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3, + 0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40, + 0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63, + 0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f, + 0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85, + 0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce, + 0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b, + 0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73, + 0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3, + 0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76, + 0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0, + 0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1, + 0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa, + 0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13, + 0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83, + 0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3, + 0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a, + 0x27, 0x96 ), + BIGINT ( 0xd4, 0x6b, 0x0a, 0x2e, 0x9f, 0xde, 0x4b, + 0x64, 0xfa, 0x6b, 0x37, 0x73, 0x66, 0x06, + 0xee, 0x04, 0xef, 0xe6, 0x3c, 0x7d, 0x57, + 0x22, 0x7f, 0x1f, 0x62, 0x1c, 0x7e, 0x20, + 0xda, 0x97, 0xd0, 0x27, 0x23, 0xf6, 0x77, + 0x5b, 0x49, 0x97, 0xe1, 0x65, 0x91, 0x13, + 0x93, 0xd6, 0x12, 0xc3, 0x66, 0x91, 0x76, + 0xe8, 0x47, 0x4c, 0x6a, 0x1b, 0xa2, 0x02, + 0xf8, 0x94, 0xaa, 0xe0, 0x1b, 0x0b, 0x17, + 0x86, 0x5e, 0xf5, 0x17, 0x23, 0xf5, 0x17, + 0x91, 0x6b, 0xd7, 0x2f, 0x5a, 0xfe, 0x8a, + 0x63, 0x28, 0x31, 0x1e, 0x09, 0x60, 0x29, + 0x5d, 0x55, 0xd8, 0x79, 0xeb, 0x78, 0x36, + 0x44, 0x69, 0xa4, 0x76, 0xa5, 0x35, 0x30, + 0xca, 0xc9, 0xf9, 0x62, 0xd7, 0x82, 0x13, + 0x56, 0xd0, 0x58, 0xfe, 0x16, 0x4b, 0xfb, + 0xa8, 0x4c, 0xb3, 0xd7, 0xcf, 0x5f, 0x93, + 0x9d, 0xc4, 0x11, 0xb4, 0xdd, 0xf8, 0x8f, + 0xe1, 0x11 ), + 0 ); + bigint_is_geq_ok ( BIGINT ( 0xd4, 0x6b, 0x0a, 0x2e, 0x9f, 0xde, 0x4b, + 0x64, 0xfa, 0x6b, 0x37, 0x73, 0x66, 0x06, + 0xee, 0x04, 0xef, 0xe6, 0x3c, 0x7d, 0x57, + 0x22, 0x7f, 0x1f, 0x62, 0x1c, 0x7e, 0x20, + 0xda, 0x97, 0xd0, 0x27, 0x23, 0xf6, 0x77, + 0x5b, 0x49, 0x97, 0xe1, 0x65, 0x91, 0x13, + 0x93, 0xd6, 0x12, 0xc3, 0x66, 0x91, 0x76, + 0xe8, 0x47, 0x4c, 0x6a, 0x1b, 0xa2, 0x02, + 0xf8, 0x94, 0xaa, 0xe0, 0x1b, 0x0b, 0x17, + 0x86, 0x5e, 0xf5, 0x17, 0x23, 0xf5, 0x17, + 0x91, 0x6b, 0xd7, 0x2f, 0x5a, 0xfe, 0x8a, + 0x63, 0x28, 0x31, 0x1e, 0x09, 0x60, 0x29, + 0x5d, 0x55, 0xd8, 0x79, 0xeb, 0x78, 0x36, + 0x44, 0x69, 0xa4, 0x76, 0xa5, 0x35, 0x30, + 0xca, 0xc9, 0xf9, 0x62, 0xd7, 0x82, 0x13, + 0x56, 0xd0, 0x58, 0xfe, 0x16, 0x4b, 0xfb, + 0xa8, 0x4c, 0xb3, 0xd7, 0xcf, 0x5f, 0x93, + 0x9d, 0xc4, 0x11, 0xb4, 0xdd, 0xf8, 0x8f, + 0xe1, 0x11 ), + BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4, + 0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3, + 0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40, + 0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63, + 0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f, + 0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85, + 0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce, + 0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b, + 0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73, + 0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3, + 0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76, + 0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0, + 0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1, + 0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa, + 0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13, + 0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83, + 0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3, + 0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a, + 0x27, 0x96 ), + 1 ); + bigint_is_geq_ok ( BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4, + 0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3, + 0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40, + 0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63, + 0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f, + 0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85, + 0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce, + 0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b, + 0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73, + 0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3, + 0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76, + 0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0, + 0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1, + 0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa, + 0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13, + 0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83, + 0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3, + 0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a, + 0x27, 0x96 ), + BIGINT ( 0x2a, 0x98, 0xfd, 0x87, 0x5d, 0x9f, 0xb4, + 0x8b, 0x5c, 0xcd, 0x5f, 0xcd, 0x53, 0xb3, + 0xd1, 0x81, 0x6a, 0x9c, 0x93, 0x66, 0x40, + 0xa7, 0x64, 0xe0, 0x8c, 0xec, 0x96, 0x63, + 0x4d, 0x29, 0xfa, 0xb1, 0x5d, 0x93, 0x2f, + 0xf9, 0x36, 0xea, 0x3b, 0xc1, 0xaf, 0x85, + 0xcb, 0xde, 0x2d, 0xc8, 0x48, 0x33, 0xce, + 0x7b, 0xa4, 0xa4, 0xda, 0x0f, 0xaa, 0x1b, + 0xcb, 0xed, 0xbe, 0x3a, 0xa5, 0xbb, 0x73, + 0x28, 0x04, 0xc6, 0x2a, 0xfb, 0x3a, 0xc3, + 0xae, 0x42, 0x1f, 0x53, 0x6c, 0xb2, 0x76, + 0xb7, 0xe2, 0x88, 0xcb, 0x88, 0xcf, 0xf0, + 0x52, 0x81, 0xd3, 0xb2, 0x1f, 0x56, 0xe1, + 0xe1, 0x47, 0x93, 0x6f, 0x2b, 0x49, 0xaa, + 0x50, 0x99, 0x7a, 0xc4, 0x56, 0xb7, 0x13, + 0x80, 0xf4, 0x73, 0x88, 0xc7, 0x39, 0x83, + 0x67, 0xc7, 0xcc, 0xb2, 0x28, 0x7a, 0xd3, + 0xdc, 0x48, 0xea, 0x62, 0x0d, 0xf5, 0x5a, + 0x27, 0x96 ), + 1 ); + bigint_bit_is_set_ok ( BIGINT ( 0x37 ), + 0, 1 ); + bigint_bit_is_set_ok ( BIGINT ( 0xe6, 0xcb ), + 0, 1 ); + bigint_bit_is_set_ok ( BIGINT ( 0xd9, 0x0c, 0x5b ), + 0, 1 ); + bigint_bit_is_set_ok ( BIGINT ( 0x8b, 0x56, 0x89, 0xaf ), + 0, 1 ); + bigint_bit_is_set_ok ( BIGINT ( 0x25, 0xfc, 0xaf, 0xeb, 0x81, 0xc3, + 0xb8, 0x2f, 0xbb, 0xe3, 0x07, 0xb2, + 0xe2, 0x2a, 0xe2, 0x2d, 0xb4, 0x4d, + 0x6d, 0xec, 0x51, 0xa0, 0x2f ), + 0, 1 ); + bigint_bit_is_set_ok ( BIGINT ( 0x25, 0xfc, 0xaf, 0xeb, 0x81, 0xc3, + 0xb8, 0x2f, 0xbb, 0xe3, 0x07, 0xb2, + 0xe2, 0x2a, 0xe2, 0x2d, 0xb4, 0x4d, + 0x6d, 0xec, 0x51, 0xa0, 0x2f ), + 45, 0 ); + bigint_bit_is_set_ok ( BIGINT ( 0x88, 0x04, 0xec, 0xe6, 0xfb, 0x31, + 0x87, 0x43, 0xb2, 0x04, 0x9e, 0x09, + 0xba, 0x3e, 0x6d, 0x64, 0x1a, 0x85, + 0xb6, 0x46, 0x7d, 0x71, 0x3c, 0x06, + 0xd6, 0x40, 0x52, 0x39, 0x95, 0xa1, + 0x06, 0xff, 0x6a, 0x5c, 0xa3, 0x6d, + 0x4a, 0xc9, 0x77, 0x87, 0x75, 0x25, + 0x57, 0x65, 0x72, 0x73, 0x64, 0x7e, + 0xe9, 0x16, 0x17, 0xf3, 0x65, 0x3f, + 0xd5, 0xcc, 0xd7, 0xa2, 0xee, 0xe7, + 0x8d, 0x48, 0xd5, 0x7e, 0xdd, 0x59, + 0x4b, 0xf0, 0x96, 0x8b, 0x21, 0x65, + 0x04, 0x66, 0xc5, 0xff, 0x3e, 0x60, + 0xba, 0x28, 0x38, 0x7d, 0x9c, 0x09, + 0xd1, 0x8e, 0xac, 0x73, 0x8e, 0xf2, + 0x1e, 0xdf, 0x83, 0x6e, 0x54, 0xd5, + 0x34, 0xc1, 0xc6, 0xf9, 0x62, 0x2a, + 0x7d, 0xec, 0x47, 0xf2, 0xfc, 0xa2, + 0x10, 0x0a, 0x67, 0x1b, 0xc6, 0x11, + 0x9d, 0x68, 0x25, 0x8b, 0xb5, 0x9b, + 0x83, 0xf8, 0xa2, 0x11, 0xf5, 0xd4, + 0xcb, 0xe0 ), + 0, 0 ); + bigint_bit_is_set_ok ( BIGINT ( 0x88, 0x04, 0xec, 0xe6, 0xfb, 0x31, + 0x87, 0x43, 0xb2, 0x04, 0x9e, 0x09, + 0xba, 0x3e, 0x6d, 0x64, 0x1a, 0x85, + 0xb6, 0x46, 0x7d, 0x71, 0x3c, 0x06, + 0xd6, 0x40, 0x52, 0x39, 0x95, 0xa1, + 0x06, 0xff, 0x6a, 0x5c, 0xa3, 0x6d, + 0x4a, 0xc9, 0x77, 0x87, 0x75, 0x25, + 0x57, 0x65, 0x72, 0x73, 0x64, 0x7e, + 0xe9, 0x16, 0x17, 0xf3, 0x65, 0x3f, + 0xd5, 0xcc, 0xd7, 0xa2, 0xee, 0xe7, + 0x8d, 0x48, 0xd5, 0x7e, 0xdd, 0x59, + 0x4b, 0xf0, 0x96, 0x8b, 0x21, 0x65, + 0x04, 0x66, 0xc5, 0xff, 0x3e, 0x60, + 0xba, 0x28, 0x38, 0x7d, 0x9c, 0x09, + 0xd1, 0x8e, 0xac, 0x73, 0x8e, 0xf2, + 0x1e, 0xdf, 0x83, 0x6e, 0x54, 0xd5, + 0x34, 0xc1, 0xc6, 0xf9, 0x62, 0x2a, + 0x7d, 0xec, 0x47, 0xf2, 0xfc, 0xa2, + 0x10, 0x0a, 0x67, 0x1b, 0xc6, 0x11, + 0x9d, 0x68, 0x25, 0x8b, 0xb5, 0x9b, + 0x83, 0xf8, 0xa2, 0x11, 0xf5, 0xd4, + 0xcb, 0xe0 ), + 45, 1 ); + bigint_bit_is_set_ok ( BIGINT ( 0x88, 0x04, 0xec, 0xe6, 0xfb, 0x31, + 0x87, 0x43, 0xb2, 0x04, 0x9e, 0x09, + 0xba, 0x3e, 0x6d, 0x64, 0x1a, 0x85, + 0xb6, 0x46, 0x7d, 0x71, 0x3c, 0x06, + 0xd6, 0x40, 0x52, 0x39, 0x95, 0xa1, + 0x06, 0xff, 0x6a, 0x5c, 0xa3, 0x6d, + 0x4a, 0xc9, 0x77, 0x87, 0x75, 0x25, + 0x57, 0x65, 0x72, 0x73, 0x64, 0x7e, + 0xe9, 0x16, 0x17, 0xf3, 0x65, 0x3f, + 0xd5, 0xcc, 0xd7, 0xa2, 0xee, 0xe7, + 0x8d, 0x48, 0xd5, 0x7e, 0xdd, 0x59, + 0x4b, 0xf0, 0x96, 0x8b, 0x21, 0x65, + 0x04, 0x66, 0xc5, 0xff, 0x3e, 0x60, + 0xba, 0x28, 0x38, 0x7d, 0x9c, 0x09, + 0xd1, 0x8e, 0xac, 0x73, 0x8e, 0xf2, + 0x1e, 0xdf, 0x83, 0x6e, 0x54, 0xd5, + 0x34, 0xc1, 0xc6, 0xf9, 0x62, 0x2a, + 0x7d, 0xec, 0x47, 0xf2, 0xfc, 0xa2, + 0x10, 0x0a, 0x67, 0x1b, 0xc6, 0x11, + 0x9d, 0x68, 0x25, 0x8b, 0xb5, 0x9b, + 0x83, 0xf8, 0xa2, 0x11, 0xf5, 0xd4, + 0xcb, 0xe0 ), + 1013, 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0x3a ), + 6 ); + bigint_max_set_bit_ok ( BIGINT ( 0x03 ), + 2 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00 ), + 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0xff ), + 8 ); + bigint_max_set_bit_ok ( BIGINT ( 0x20, 0x30 ), + 14 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x10 ), + 5 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00 ), + 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff ), + 16 ); + bigint_max_set_bit_ok ( BIGINT ( 0x06, 0xdb, 0x7a ), + 19 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00 ), + 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00 ), + 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff ), + 24 ); + bigint_max_set_bit_ok ( BIGINT ( 0xee, 0xcb, 0x7b, 0xfd ), + 32 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x01, 0xdd ), + 9 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00 ), + 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff ), + 32 ); + bigint_max_set_bit_ok ( BIGINT ( 0x32, 0x39, 0x96, 0x52, 0x10, 0x67, + 0x7e, 0x32, 0xfc, 0x4e, 0x56, 0xc3, + 0x68, 0x18, 0x76, 0x1a, 0xac, 0x0e, + 0x93, 0xee, 0x55, 0xc5, 0x6e ), + 182 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xc8, 0xe6, 0x59 ), + 24 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 ), + 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff ), + 184 ); + bigint_max_set_bit_ok ( BIGINT ( 0xcd, 0xb3, 0x22, 0x30, 0xdd, 0xa7, + 0xff, 0x37, 0xbf, 0xe3, 0x38, 0xf7, + 0xe1, 0x41, 0x73, 0xea, 0x3a, 0xfc, + 0x78, 0x9e, 0xfb, 0x4f, 0x85, 0xdc, + 0x1c, 0x40, 0x89, 0x6e, 0xda, 0xf9, + 0x9d, 0x6d, 0x12, 0x97, 0xb1, 0x80, + 0x2a, 0xeb, 0x91, 0xce, 0x3b, 0x83, + 0xb8, 0xa5, 0x3d, 0xce, 0x46, 0x56, + 0xb7, 0xd1, 0x28, 0xbc, 0x93, 0x4e, + 0x8c, 0x29, 0x6d, 0x2c, 0xcc, 0x58, + 0x49, 0x2f, 0x37, 0xa0, 0x08, 0x37, + 0x86, 0xdd, 0x38, 0x21, 0xa7, 0x57, + 0x37, 0xe3, 0xc5, 0xcc, 0x50, 0x11, + 0x1a, 0xe4, 0xea, 0xe7, 0x4d, 0x3c, + 0x37, 0x65, 0x78, 0xd1, 0xf6, 0xc3, + 0x94, 0x46, 0xd4, 0x0e, 0xd3, 0x9a, + 0x21, 0x8b, 0xa6, 0x54, 0xc0, 0xd2, + 0x88, 0x07, 0x24, 0xbf, 0x7d, 0x31, + 0xfd, 0x15, 0xa8, 0x92, 0x65, 0xe1, + 0x8d, 0xed, 0x70, 0x7b, 0x68, 0x0f, + 0xcc, 0x13, 0xb9, 0xb2, 0xdd, 0x3c, + 0x6a, 0x52 ), + 1024 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0xd9, + 0x91, 0x18, 0x6e, 0xd3, 0xff, 0x9b, + 0xdf, 0xf1, 0x9c, 0x7b, 0xf0, 0xa0, + 0xb9, 0xf5 ), + 127 ); + bigint_max_set_bit_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ), + 0 ); + bigint_max_set_bit_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff ), + 1024 ); + bigint_multiply_ok ( BIGINT ( 0xf0 ), + BIGINT ( 0xeb ), + BIGINT ( 0xdc, 0x50 ) ); + bigint_multiply_ok ( BIGINT ( 0xd7, 0x16 ), + BIGINT ( 0x88, 0xfb ), + BIGINT ( 0x73, 0x16, 0x92, 0x92 ) ); + bigint_multiply_ok ( BIGINT ( 0xfe, 0xed, 0x1d ), + BIGINT ( 0x69, 0x9c, 0x03 ), + BIGINT ( 0x69, 0x2a, 0x9c, 0x5f, 0x73, 0x57 ) ); + bigint_multiply_ok ( BIGINT ( 0x96, 0xe9, 0x6f, 0x81 ), + BIGINT ( 0x67, 0x3c, 0x5a, 0x16 ), + BIGINT ( 0x3c, 0xdb, 0x7f, 0xae, 0x12, 0x7e, + 0xef, 0x16 ) ); + bigint_multiply_ok ( BIGINT ( 0xe8, 0x08, 0x0b, 0xe9, 0x29, 0x36, + 0xea, 0x51, 0x1d, 0x75, 0x1a, 0xd5, + 0xba, 0xc6, 0xa0, 0xf3, 0x48, 0x5c, + 0xdf, 0x42, 0xdf, 0x28, 0x38 ), + BIGINT ( 0x22, 0x07, 0x41, 0x54, 0x4e, 0xf9, + 0x90, 0xa8, 0xaf, 0xba, 0xf6, 0xb0, + 0x35, 0x7e, 0x98, 0xef, 0x2c, 0x31, + 0xc9, 0xa7, 0x25, 0x74, 0x8d ), + BIGINT ( 0x1e, 0xd7, 0xa5, 0x03, 0xc0, 0x18, + 0x2e, 0x29, 0xb1, 0x3e, 0x96, 0x71, + 0x90, 0xa5, 0x6d, 0x43, 0x58, 0xf7, + 0x22, 0x80, 0x0b, 0x21, 0xc6, 0x70, + 0x90, 0x1c, 0xa8, 0x85, 0x87, 0xaf, + 0xd7, 0xdd, 0x27, 0x69, 0xaf, 0x20, + 0xa0, 0x2d, 0x43, 0x5d, 0xda, 0xba, + 0x4b, 0x3a, 0x86, 0xd8 ) ); + bigint_multiply_ok ( BIGINT ( 0xa2, 0x0f, 0xc6, 0x08, 0x0a, 0x01, + 0x19, 0x42, 0x0e, 0xaa, 0x5c, 0xae, + 0x4f, 0x4e, 0xb0, 0xad, 0xb2, 0xe8, + 0xee, 0xd5, 0x65, 0xec, 0x5a, 0xda, + 0xc0, 0xba, 0x78, 0xa8, 0x0f, 0x15, + 0x39, 0xd7, 0x7a, 0x10, 0xc2, 0xa7, + 0xec, 0x44, 0xac, 0xad, 0x39, 0x04, + 0x2e, 0x66, 0x54, 0x70, 0x57, 0xee, + 0xf6, 0x97, 0x19, 0x71, 0x16, 0xf9, + 0xbb, 0x2e, 0x84, 0x09, 0x6e, 0x9a, + 0x3b, 0x16, 0xb2, 0x65, 0x74, 0x50, + 0x19, 0xd1, 0xe9, 0x95, 0xa0, 0x7b, + 0x33, 0xb5, 0xac, 0x7c, 0x9e, 0xd4, + 0x68, 0x0d, 0xc9, 0xe4, 0x03, 0x86, + 0x1a, 0xa3, 0x42, 0x33, 0x28, 0x14, + 0x12, 0x7d, 0x5a, 0xd9, 0x30, 0x18, + 0x0a, 0xf4, 0x0c, 0x96, 0x58, 0xc9, + 0xb5, 0x37, 0xdb, 0x49, 0xdc, 0x01, + 0x4a, 0xcb, 0x6d, 0x87, 0x52, 0xf6, + 0xae, 0xa7, 0x71, 0x31, 0x9a, 0x1a, + 0xe2, 0x1c, 0x87, 0x51, 0xc9, 0xeb, + 0x70, 0x71 ), + BIGINT ( 0x7c, 0xdd, 0x2f, 0x5d, 0x27, 0xfe, + 0xca, 0x70, 0x96, 0xc3, 0xb1, 0x1f, + 0xac, 0xa9, 0x3a, 0xdc, 0xcd, 0xbc, + 0x58, 0xb4, 0xde, 0xe7, 0xe5, 0x34, + 0x1a, 0xc0, 0xb9, 0x46, 0xf7, 0x52, + 0x76, 0x23, 0xe8, 0xe9, 0x92, 0xa1, + 0x86, 0x3c, 0x6f, 0xf1, 0x22, 0xf4, + 0x72, 0xb1, 0xde, 0xd3, 0x8f, 0x11, + 0x9e, 0x52, 0xe5, 0x81, 0x54, 0xe9, + 0xa7, 0x72, 0x3f, 0x3e, 0xa0, 0x80, + 0xbb, 0xae, 0x0e, 0x30, 0x6a, 0x11, + 0x91, 0x11, 0x3b, 0x3f, 0x44, 0x1f, + 0x8d, 0x4d, 0xea, 0xdd, 0x09, 0x95, + 0x9d, 0x02, 0xa6, 0x6d, 0x3b, 0x08, + 0x40, 0x8d, 0xb4, 0x4b, 0x05, 0x74, + 0x8c, 0x1f, 0xaa, 0x61, 0x6f, 0x0e, + 0xcc, 0xcf, 0xe0, 0x81, 0x03, 0xe4, + 0x9b, 0x11, 0xd9, 0xab, 0xf3, 0x24, + 0xe2, 0x3b, 0xe0, 0x05, 0x60, 0x65, + 0x16, 0xc6, 0x2e, 0x83, 0xa0, 0x98, + 0x8e, 0x11, 0x05, 0x00, 0xe4, 0x3f, + 0x7e, 0x65 ), + BIGINT ( 0x4f, 0x0b, 0xa9, 0x85, 0xb8, 0x31, + 0x48, 0xea, 0x11, 0x44, 0xaf, 0x2d, + 0xed, 0x1a, 0x76, 0x45, 0xac, 0x87, + 0x0c, 0xf3, 0xd7, 0xc4, 0x8e, 0x5c, + 0xd7, 0xdf, 0x28, 0x74, 0xa6, 0x40, + 0xe4, 0x6b, 0x5b, 0x19, 0x36, 0x37, + 0x9c, 0xcd, 0x43, 0x76, 0x15, 0x00, + 0x5d, 0x23, 0xa2, 0x8a, 0x53, 0x25, + 0xbf, 0x18, 0xda, 0xe6, 0x09, 0xdf, + 0xaa, 0xeb, 0x9a, 0x82, 0x01, 0x14, + 0x2b, 0x20, 0x2b, 0xb6, 0x22, 0x62, + 0x6b, 0xcc, 0xd4, 0xc9, 0x02, 0x67, + 0x95, 0x43, 0x75, 0x4e, 0x97, 0x4e, + 0xec, 0x04, 0xde, 0x29, 0x0a, 0xef, + 0xf7, 0xc1, 0x72, 0x8c, 0x64, 0x38, + 0x16, 0x47, 0x9f, 0x16, 0x0c, 0xa5, + 0x79, 0x6b, 0xea, 0x2e, 0x4c, 0x3d, + 0x0c, 0xe6, 0x57, 0x51, 0x65, 0xa5, + 0x3b, 0xca, 0xae, 0x54, 0x0c, 0x67, + 0xf8, 0x23, 0x00, 0xc9, 0x8d, 0xe6, + 0x16, 0x91, 0x19, 0xb3, 0x5b, 0x68, + 0x7b, 0xf2, 0xe2, 0x5d, 0x69, 0x48, + 0x3f, 0x2b, 0xa0, 0x4f, 0x7c, 0x3c, + 0x26, 0xf9, 0xd9, 0xfd, 0x3d, 0x5d, + 0xd6, 0x05, 0x00, 0xd8, 0xdf, 0x5a, + 0x56, 0x8f, 0x16, 0x68, 0x4f, 0x15, + 0x19, 0x9d, 0xd7, 0x11, 0x51, 0x7d, + 0x73, 0x5c, 0xd4, 0xd5, 0xb4, 0xc7, + 0x42, 0xe3, 0xee, 0xf1, 0x67, 0xd6, + 0x69, 0x72, 0x04, 0x4b, 0x88, 0x3d, + 0x05, 0xd8, 0x1e, 0x50, 0xcb, 0xce, + 0x39, 0x19, 0x42, 0xb6, 0xa7, 0xf3, + 0xba, 0x78, 0x90, 0xd2, 0x09, 0x05, + 0x87, 0xf8, 0xc0, 0x9c, 0x47, 0xff, + 0xbf, 0xaa, 0x21, 0x8d, 0x81, 0x86, + 0xcd, 0x58, 0xdf, 0x30, 0xf1, 0xd1, + 0x60, 0x53, 0x85, 0x40, 0xbf, 0x14, + 0x3e, 0xdc, 0x9e, 0x9e, 0xc4, 0xc7, + 0x48, 0xa0, 0x83, 0xe0, 0x99, 0x8b, + 0x43, 0xf8, 0x52, 0x8a, 0x15, 0x88, + 0x89, 0x83, 0x7d, 0x71, 0xbb, 0x62, + 0x12, 0x7a, 0x23, 0x85, 0x3a, 0xbb, + 0xdb, 0x09, 0xfa, 0x95 ) ); + bigint_multiply_ok ( BIGINT ( 0xff ), + BIGINT ( 0xff ), + BIGINT ( 0xfe, 0x01 ) ); + bigint_multiply_ok ( BIGINT ( 0xff, 0xff ), + BIGINT ( 0xff, 0xff ), + BIGINT ( 0xff, 0xfe, 0x00, 0x01 ) ); + bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01 ) ); + bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x00, 0x01 ) ); + bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01 ) ); + bigint_multiply_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01 ) ); + bigint_mod_multiply_ok ( BIGINT ( 0x37 ), + BIGINT ( 0x67 ), + BIGINT ( 0x3f ), + BIGINT ( 0x3a ) ); + bigint_mod_multiply_ok ( BIGINT ( 0x45, 0x94 ), + BIGINT ( 0xbd, 0xd2 ), + BIGINT ( 0xca, 0xc7 ), + BIGINT ( 0xac, 0xc1 ) ); + bigint_mod_multiply_ok ( BIGINT ( 0x8e, 0xcd, 0x74 ), + BIGINT ( 0xe2, 0xf1, 0xea ), + BIGINT ( 0x59, 0x51, 0x53 ), + BIGINT ( 0x22, 0xdd, 0x1c ) ); + bigint_mod_multiply_ok ( BIGINT ( 0xc2, 0xa8, 0x40, 0x6f ), + BIGINT ( 0x29, 0xd7, 0xf4, 0x77 ), + BIGINT ( 0xbb, 0xbd, 0xdb, 0x3d ), + BIGINT ( 0x8f, 0x39, 0xd0, 0x47 ) ); + bigint_mod_multiply_ok ( BIGINT ( 0x2e, 0xcb, 0x74, 0x7c, 0x64, 0x60, + 0xb3, 0x44, 0xf3, 0x23, 0x49, 0x4a, + 0xc6, 0xb6, 0xbf, 0xea, 0x80, 0xd8, + 0x34, 0xc5, 0x54, 0x22, 0x09 ), + BIGINT ( 0x61, 0x2c, 0x5a, 0xc5, 0xde, 0x07, + 0x65, 0x8e, 0xab, 0x88, 0x1a, 0x2e, + 0x7a, 0x95, 0x17, 0xe3, 0x3b, 0x17, + 0xe4, 0x21, 0xb0, 0xb4, 0x57 ), + BIGINT ( 0x8e, 0x46, 0xa5, 0x87, 0x7b, 0x7f, + 0xc4, 0xd7, 0x31, 0xb1, 0x94, 0xe7, + 0xe7, 0x1c, 0x7e, 0x7a, 0xc2, 0x6c, + 0xce, 0xcb, 0xc8, 0x5d, 0x70 ), + BIGINT ( 0x1e, 0xd1, 0x5b, 0x3d, 0x1d, 0x17, + 0x7c, 0x31, 0x95, 0x13, 0x1b, 0xd8, + 0xee, 0x0a, 0xb0, 0xe1, 0x5b, 0x13, + 0xad, 0x83, 0xe9, 0xf8, 0x7f ) ); + bigint_mod_multiply_ok ( BIGINT ( 0x56, 0x37, 0xab, 0x07, 0x8b, 0x25, + 0xa7, 0xc2, 0x50, 0x30, 0x43, 0xfc, + 0x63, 0x8b, 0xdf, 0x84, 0x68, 0x85, + 0xca, 0xce, 0x44, 0x5c, 0xb1, 0x14, + 0xa4, 0xb5, 0xba, 0x43, 0xe0, 0x31, + 0x45, 0x6b, 0x82, 0xa9, 0x0b, 0x9e, + 0x3a, 0xb0, 0x39, 0x09, 0x2a, 0x68, + 0x2e, 0x0f, 0x09, 0x54, 0x47, 0x04, + 0xdb, 0xcf, 0x4a, 0x3a, 0x2d, 0x7b, + 0x7d, 0x50, 0xa4, 0xc5, 0xeb, 0x13, + 0xdd, 0x49, 0x61, 0x7d, 0x18, 0xa1, + 0x0d, 0x6b, 0x58, 0xba, 0x9f, 0x7c, + 0x81, 0x34, 0x9e, 0xf9, 0x9c, 0x9e, + 0x28, 0xa8, 0x1c, 0x15, 0x16, 0x20, + 0x3c, 0x0a, 0xb1, 0x11, 0x06, 0x93, + 0xbc, 0xd8, 0x4e, 0x49, 0xae, 0x7b, + 0xb4, 0x02, 0x8b, 0x1c, 0x5b, 0x18, + 0xb4, 0xac, 0x7f, 0xdd, 0x70, 0xef, + 0x87, 0xac, 0x1b, 0xac, 0x25, 0xa3, + 0xc9, 0xa7, 0x3a, 0xc5, 0x76, 0x68, + 0x09, 0x1f, 0xa1, 0x48, 0x53, 0xb6, + 0x13, 0xac ), + BIGINT ( 0xef, 0x5c, 0x1f, 0x1a, 0x44, 0x64, + 0x66, 0xcf, 0xdd, 0x3f, 0x0b, 0x27, + 0x81, 0xa7, 0x91, 0x7a, 0x35, 0x7b, + 0x0f, 0x46, 0x5e, 0xca, 0xbf, 0xf8, + 0x50, 0x5e, 0x99, 0x7c, 0xc6, 0x64, + 0x43, 0x00, 0x9f, 0xb2, 0xda, 0xfa, + 0x42, 0x15, 0x9c, 0xa3, 0xd6, 0xc8, + 0x64, 0xa7, 0x65, 0x4a, 0x98, 0xf7, + 0xb3, 0x96, 0x5f, 0x42, 0xf9, 0x73, + 0xe1, 0x75, 0xc3, 0xc4, 0x0b, 0x5d, + 0x5f, 0xf3, 0x04, 0x8a, 0xee, 0x59, + 0xa6, 0x1b, 0x06, 0x38, 0x0b, 0xa2, + 0x9f, 0xb4, 0x4f, 0x6d, 0x50, 0x5e, + 0x37, 0x37, 0x21, 0x83, 0x9d, 0xa3, + 0x12, 0x16, 0x4d, 0xab, 0x36, 0x51, + 0x21, 0xb1, 0x74, 0x66, 0x40, 0x9a, + 0xd3, 0x72, 0xcc, 0x18, 0x40, 0x53, + 0x89, 0xff, 0xd7, 0x00, 0x8d, 0x7e, + 0x93, 0x81, 0xdb, 0x29, 0xb6, 0xd7, + 0x23, 0x2b, 0x67, 0x2f, 0x11, 0x98, + 0x49, 0x87, 0x2f, 0x46, 0xb7, 0x33, + 0x6d, 0x12 ), + BIGINT ( 0x67, 0x7a, 0x17, 0x6a, 0xd2, 0xf8, + 0x49, 0xfb, 0x7c, 0x95, 0x25, 0x54, + 0xf0, 0xab, 0x5b, 0xb3, 0x0e, 0x01, + 0xab, 0xd3, 0x65, 0x6f, 0x7e, 0x18, + 0x05, 0xed, 0x9b, 0xc4, 0x90, 0x6c, + 0xd0, 0x6d, 0x94, 0x79, 0x28, 0xd6, + 0x24, 0x77, 0x9a, 0x08, 0xd2, 0x2f, + 0x7c, 0x2d, 0xa0, 0x0c, 0x14, 0xbe, + 0x7b, 0xee, 0x9e, 0x48, 0x88, 0x3c, + 0x8f, 0x9f, 0xb9, 0x7a, 0xcb, 0x98, + 0x76, 0x61, 0x0d, 0xee, 0xa2, 0x42, + 0x67, 0x1b, 0x2c, 0x42, 0x8f, 0x41, + 0xcc, 0x78, 0xba, 0xba, 0xaa, 0xa2, + 0x92, 0xb0, 0x6e, 0x0c, 0x4e, 0xe1, + 0xa5, 0x13, 0x7d, 0x8a, 0x8f, 0x81, + 0x95, 0x8a, 0xdf, 0x57, 0x93, 0x88, + 0x27, 0x4f, 0x1a, 0x59, 0xa4, 0x74, + 0x22, 0xa9, 0x78, 0xe5, 0xed, 0xb1, + 0x09, 0x26, 0x59, 0xde, 0x88, 0x21, + 0x8d, 0xa2, 0xa8, 0x58, 0x10, 0x7b, + 0x65, 0x96, 0xbf, 0x69, 0x3b, 0xc5, + 0x55, 0xf8 ), + BIGINT ( 0x15, 0xf7, 0x00, 0xeb, 0xc7, 0x5a, + 0x6f, 0xf0, 0x50, 0xf3, 0x21, 0x8a, + 0x8e, 0xa6, 0xf6, 0x67, 0x56, 0x7d, + 0x07, 0x45, 0x89, 0xdb, 0xd7, 0x7e, + 0x9e, 0x28, 0x7f, 0xfb, 0xed, 0xca, + 0x2c, 0xbf, 0x47, 0x77, 0x99, 0x95, + 0xf3, 0xd6, 0x9d, 0xc5, 0x57, 0x81, + 0x7f, 0x97, 0xf2, 0x6b, 0x24, 0xee, + 0xce, 0xc5, 0x9b, 0xe6, 0x42, 0x2d, + 0x37, 0xb7, 0xeb, 0x3d, 0xb5, 0xf7, + 0x1e, 0x86, 0xc2, 0x40, 0x44, 0xc9, + 0x85, 0x5a, 0x1a, 0xc0, 0xac, 0x9e, + 0x78, 0x69, 0x00, 0x7b, 0x93, 0x65, + 0xd7, 0x7f, 0x0c, 0xd6, 0xba, 0x4f, + 0x06, 0x00, 0x61, 0x05, 0xb2, 0x44, + 0xb4, 0xe7, 0xbb, 0x3b, 0x96, 0xb0, + 0x6d, 0xe8, 0x43, 0xd2, 0x03, 0xb7, + 0x0a, 0xc4, 0x6d, 0x30, 0xd8, 0xd5, + 0xe6, 0x54, 0x65, 0xdd, 0xa9, 0x1b, + 0x50, 0xc0, 0xb9, 0x95, 0xb0, 0x7d, + 0x7c, 0xca, 0x63, 0xf8, 0x72, 0xbe, + 0x3b, 0x00 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xcd ), + BIGINT ( 0xbb ), + BIGINT ( 0x25 ), + BIGINT ( 0xab ) ); + bigint_mod_exp_ok ( BIGINT ( 0xc4 ), + BIGINT ( 0xe9 ), + BIGINT ( 0x02, 0x4c ), + BIGINT ( 0x7e ) ); + bigint_mod_exp_ok ( BIGINT ( 0xcb ), + BIGINT ( 0xde ), + BIGINT ( 0xbd, 0x73, 0xbf ), + BIGINT ( 0x17 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x17 ), + BIGINT ( 0xb9 ), + BIGINT ( 0x39, 0x68, 0xba, 0x7d ), + BIGINT ( 0x17 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x2e ), + BIGINT ( 0xb7 ), + BIGINT ( 0x39, 0x07, 0x1b, 0x49, 0x5b, 0xea, + 0xf2, 0x61, 0x75, 0x94, 0x60, 0x86, + 0x73, 0xd0, 0xeb, 0x11, 0x08, 0x19, + 0x90, 0x19, 0xe0, 0xed, 0x2a ), + BIGINT ( 0x19 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x59 ), + BIGINT ( 0xce ), + BIGINT ( 0xdf, 0xbc, 0x0d, 0x0c, 0x09, 0xeb, + 0xf8, 0xcf, 0xdb, 0xb6, 0x00, 0xa3, + 0x9e, 0xc3, 0x6c, 0x8d, 0xf1, 0xc3, + 0x03, 0x36, 0xaa, 0xd4, 0x22, 0x7c, + 0x20, 0x7b, 0xa9, 0x9a, 0x01, 0xe4, + 0xf2, 0x50, 0x42, 0x29, 0x68, 0x7a, + 0xa6, 0x2c, 0xdf, 0xb6, 0x51, 0xa9, + 0x73, 0x10, 0x98, 0x37, 0x69, 0xb3, + 0x21, 0x49, 0x6d, 0xcc, 0x80, 0xfa, + 0x7e, 0x12, 0xe4, 0x9c, 0xc2, 0xbb, + 0xe3, 0xa3, 0x10, 0x3f, 0xba, 0x99, + 0x22, 0x79, 0x71, 0x39, 0x96, 0x7b, + 0x1a, 0x89, 0xdc, 0xda, 0x43, 0x52, + 0x50, 0x7b, 0xe3, 0x8c, 0xd3, 0xc0, + 0xf5, 0x7d, 0xfc, 0x80, 0x71, 0x6e, + 0xaf, 0x5c, 0xd0, 0x14, 0xc0, 0x60, + 0x24, 0xa8, 0x9a, 0x8a, 0x54, 0x4a, + 0x6f, 0x42, 0x7a, 0x14, 0x14, 0x25, + 0xd5, 0x22, 0x08, 0x8f, 0xd9, 0xdb, + 0xd4, 0x0f, 0x14, 0xf4, 0x3b, 0x26, + 0x0e, 0xb6, 0x72, 0xd7, 0x03, 0xd5, + 0xf0, 0x0e ), + BIGINT ( 0xa9 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x7f, 0x30 ), + BIGINT ( 0x73, 0x74 ), + BIGINT ( 0x75 ), + BIGINT ( 0x4b, 0xe8 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x04, 0x6c ), + BIGINT ( 0x99, 0x04 ), + BIGINT ( 0x33, 0xd2 ), + BIGINT ( 0x86, 0x74 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xca, 0x88 ), + BIGINT ( 0xdc, 0x60 ), + BIGINT ( 0x7e, 0x76, 0x79 ), + BIGINT ( 0x42, 0x40 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x68, 0x97 ), + BIGINT ( 0x52, 0x8b ), + BIGINT ( 0x4f, 0x7f, 0xe7, 0xda ), + BIGINT ( 0x22, 0x77 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xbd, 0x14 ), + BIGINT ( 0x9e, 0xfc ), + BIGINT ( 0x23, 0xf7, 0xd0, 0xa1, 0x9e, 0x9b, + 0x05, 0xd2, 0x44, 0x24, 0x4f, 0x3f, + 0x83, 0xcc, 0x49, 0x70, 0xa5, 0x0d, + 0xfc, 0xa7, 0x43, 0xf3, 0x3e ), + BIGINT ( 0x1a, 0xc8 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x46, 0x3e ), + BIGINT ( 0xb8, 0xde ), + BIGINT ( 0xa9, 0xc0, 0xdc, 0x45, 0x65, 0x0d, + 0xa5, 0x56, 0x70, 0x4c, 0xf1, 0xda, + 0xab, 0x64, 0xc2, 0x04, 0xf6, 0x32, + 0x20, 0x68, 0x31, 0x5f, 0x9a, 0x00, + 0x0f, 0x7b, 0x24, 0x33, 0xdf, 0xaf, + 0xfe, 0x03, 0x1e, 0x4a, 0xa1, 0xf8, + 0x45, 0x8d, 0x5a, 0x7d, 0x12, 0x58, + 0x00, 0x6d, 0xba, 0x79, 0x9f, 0xe1, + 0xa1, 0xfc, 0x1f, 0xb9, 0xf3, 0xa7, + 0x07, 0xf5, 0xfe, 0xd6, 0xa1, 0xba, + 0xda, 0x63, 0xef, 0x39, 0x8e, 0xb7, + 0x48, 0xa8, 0x81, 0x86, 0xb1, 0x22, + 0x14, 0x9f, 0x9e, 0xac, 0x69, 0xf7, + 0xae, 0x1f, 0xf2, 0x99, 0x41, 0xb7, + 0x37, 0xa7, 0xbc, 0x42, 0xf2, 0x45, + 0x43, 0xf2, 0x2a, 0xef, 0xc2, 0x83, + 0xd5, 0x32, 0x6e, 0xfa, 0x49, 0x1c, + 0x94, 0x9c, 0xc2, 0xc5, 0xad, 0x28, + 0x53, 0x1c, 0x11, 0xc4, 0x1c, 0x78, + 0x8f, 0x13, 0xdc, 0xb3, 0x2a, 0x63, + 0xfd, 0x1f, 0x89, 0x9b, 0x0c, 0x31, + 0x92, 0x73 ), + BIGINT ( 0x7b, 0x8a ) ); + bigint_mod_exp_ok ( BIGINT ( 0xf3, 0xc3, 0xab ), + BIGINT ( 0xd0, 0x7e, 0xd0 ), + BIGINT ( 0xf6 ), + BIGINT ( 0x1f, 0xb3, 0x09 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x13, 0xec, 0xf6 ), + BIGINT ( 0x87, 0x1a, 0x9a ), + BIGINT ( 0x03, 0xf3 ), + BIGINT ( 0x15, 0xe9, 0x8e ) ); + bigint_mod_exp_ok ( BIGINT ( 0x5a, 0x96, 0xe5 ), + BIGINT ( 0x56, 0x4a, 0xd1 ), + BIGINT ( 0x89, 0x62, 0x8e ), + BIGINT ( 0x34, 0xb8, 0xaa ) ); + bigint_mod_exp_ok ( BIGINT ( 0x84, 0x7c, 0xbd ), + BIGINT ( 0x3c, 0x80, 0x0a ), + BIGINT ( 0x5e, 0x52, 0x9d, 0xba ), + BIGINT ( 0x04, 0xcb, 0x4f ) ); + bigint_mod_exp_ok ( BIGINT ( 0x50, 0x01, 0x51 ), + BIGINT ( 0x02, 0xe6, 0x96 ), + BIGINT ( 0x34, 0x0c, 0x7e, 0xbf, 0x27, 0x23, + 0x46, 0x92, 0x1c, 0xca, 0x91, 0xab, + 0x50, 0x2c, 0x3a, 0x64, 0xc8, 0x4a, + 0x75, 0xd6, 0xe2, 0xde, 0x31 ), + BIGINT ( 0x02, 0x16, 0x05 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x5e, 0x47, 0xd8 ), + BIGINT ( 0x26, 0xd1, 0xb6 ), + BIGINT ( 0x49, 0x61, 0x84, 0x7a, 0xa9, 0xfb, + 0x93, 0x45, 0xe4, 0xfa, 0x53, 0x60, + 0x73, 0x98, 0x5a, 0x17, 0xe7, 0x77, + 0x2d, 0xcd, 0x97, 0xf4, 0xc0, 0x34, + 0x46, 0xfa, 0xbd, 0x21, 0xdf, 0xa5, + 0xa0, 0x12, 0x38, 0x7c, 0xbd, 0xd9, + 0xcd, 0xbc, 0xde, 0x29, 0xa5, 0x13, + 0xa8, 0xf0, 0xf6, 0x88, 0xc6, 0x31, + 0xed, 0x90, 0x19, 0x11, 0x7d, 0xe1, + 0x0e, 0x81, 0x98, 0x8e, 0x98, 0x86, + 0xde, 0x2a, 0x4c, 0xad, 0xff, 0x57, + 0x12, 0xbc, 0x4b, 0xaf, 0x21, 0xde, + 0xca, 0x3a, 0x25, 0xd7, 0x98, 0xe3, + 0x25, 0xbc, 0x17, 0x74, 0x0b, 0x9c, + 0x53, 0xe1, 0x1a, 0xec, 0x9a, 0x5a, + 0xdc, 0x68, 0xdf, 0xad, 0xd6, 0x71, + 0x6b, 0x5b, 0x8b, 0x85, 0xbb, 0xe5, + 0xd5, 0x14, 0x4c, 0x30, 0x27, 0x68, + 0xd1, 0xf7, 0x58, 0x34, 0x4c, 0xe1, + 0x71, 0xde, 0x7b, 0x8d, 0xa2, 0xe6, + 0x0a, 0x44, 0x22, 0x26, 0x5a, 0x70, + 0xbb, 0x68 ), + BIGINT ( 0x18, 0x36, 0x96 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xc7, 0x4a, 0xf0, 0x48 ), + BIGINT ( 0x5d, 0x27, 0x07, 0x54 ), + BIGINT ( 0x4a ), + BIGINT ( 0x48, 0x68, 0x7b, 0xe0 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xb4, 0x89, 0xc9, 0x5b ), + BIGINT ( 0x7c, 0xd7, 0xc7, 0xff ), + BIGINT ( 0xc6, 0x9c ), + BIGINT ( 0x0b, 0x2d, 0xf8, 0xf7 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xea, 0x72, 0x43, 0xfe ), + BIGINT ( 0xfc, 0x57, 0x2d, 0x47 ), + BIGINT ( 0x60, 0x01, 0x2c ), + BIGINT ( 0x12, 0x01, 0xe3, 0xf5 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x81, 0x7f, 0x27, 0x94 ), + BIGINT ( 0x17, 0x21, 0x67, 0xab ), + BIGINT ( 0x50, 0x19, 0x12, 0x52 ), + BIGINT ( 0x05, 0x17, 0x6b, 0x13 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x38, 0xab, 0xd4, 0xec ), + BIGINT ( 0x0c, 0x2a, 0x56, 0x38 ), + BIGINT ( 0x2f, 0x85, 0x85, 0x57, 0xf6, 0xde, + 0x24, 0xb4, 0x28, 0x3c, 0x5a, 0x3c, + 0x0b, 0x12, 0x85, 0x85, 0x85, 0x98, + 0x46, 0x5b, 0x9c, 0x52, 0x3a ), + BIGINT ( 0x02, 0xe6, 0x6a, 0x70 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xa6, 0x35, 0xc0, 0x6f ), + BIGINT ( 0x23, 0xac, 0x78, 0x72 ), + BIGINT ( 0x6a, 0x07, 0x80, 0xbf, 0x1b, 0xa5, + 0xf8, 0x0b, 0x90, 0x06, 0xa4, 0xa5, + 0x44, 0x13, 0xba, 0x4b, 0xb3, 0xce, + 0x9f, 0x55, 0x42, 0x56, 0xc3, 0x30, + 0x82, 0x85, 0x5a, 0x3b, 0xae, 0x88, + 0x92, 0x4e, 0x3c, 0x37, 0xf6, 0x80, + 0x4c, 0x03, 0x3c, 0x1e, 0x2c, 0x17, + 0xef, 0x9d, 0xd7, 0x6f, 0xdc, 0xbb, + 0x42, 0x42, 0xa1, 0x7f, 0x97, 0x66, + 0xcd, 0xc8, 0x8a, 0x7c, 0xc6, 0x70, + 0x61, 0x54, 0x82, 0xd0, 0xd0, 0x8b, + 0xd5, 0x4f, 0x57, 0x7b, 0x8e, 0xab, + 0xdc, 0xbf, 0x8e, 0x85, 0x94, 0x83, + 0x8a, 0xb3, 0x72, 0x69, 0x2d, 0x51, + 0xdd, 0x86, 0x1e, 0x58, 0xb8, 0x00, + 0xe2, 0x5e, 0xa7, 0xef, 0x6a, 0x6a, + 0xb0, 0x10, 0x3d, 0x53, 0xfe, 0x23, + 0x51, 0xc0, 0x51, 0xed, 0x1f, 0x02, + 0x4b, 0x73, 0x17, 0x59, 0xfa, 0xb9, + 0xa8, 0x05, 0xa7, 0x79, 0xc3, 0xc9, + 0x4c, 0x2d, 0x58, 0x59, 0x10, 0x99, + 0x71, 0xe6 ), + BIGINT ( 0x01, 0x63, 0xd0, 0x07 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xff, 0x2a, 0x37, 0x04, 0xd4, 0x08, + 0x9f, 0xf5, 0xac, 0x29, 0x7f, 0x4b, + 0x93, 0x86, 0x02, 0x26, 0xac, 0x29, + 0xa8, 0xf9, 0x77, 0x91, 0x20 ), + BIGINT ( 0x2c, 0xb2, 0xe2, 0x1f, 0x4b, 0x97, + 0xaa, 0x3b, 0xd1, 0x36, 0xb0, 0x40, + 0x8b, 0x1c, 0x19, 0xa2, 0xea, 0xc8, + 0xc6, 0x4e, 0x2a, 0x66, 0x50 ), + BIGINT ( 0x97 ), + BIGINT ( 0x04, 0x22, 0x44, 0xe2, 0x14, 0x54, + 0x6c, 0x5a, 0xba, 0x1b, 0x39, 0xb7, + 0xaa, 0x06, 0xcf, 0x2b, 0xc8, 0x7e, + 0xc0, 0xe0, 0x70, 0xf2, 0x90 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xcd, 0xf3, 0xf7, 0x50, 0x13, 0x39, + 0x13, 0x4a, 0x56, 0xc5, 0xb8, 0xa6, + 0x42, 0x2d, 0x40, 0x5e, 0x07, 0xf2, + 0x92, 0x2a, 0x51, 0x87, 0x20 ), + BIGINT ( 0x93, 0x1a, 0x28, 0xbb, 0x69, 0x4f, + 0x31, 0x01, 0xe0, 0x88, 0x8a, 0x4c, + 0x4f, 0x9b, 0xda, 0xf6, 0x4e, 0xf3, + 0x11, 0xe7, 0x35, 0xa1, 0xfb ), + BIGINT ( 0x66, 0x69 ), + BIGINT ( 0x7a, 0x5a, 0x9b, 0x84, 0x72, 0x8f, + 0x57, 0x31, 0xb4, 0x34, 0x70, 0x18, + 0x77, 0xa6, 0x43, 0xa9, 0x51, 0x69, + 0x07, 0x3e, 0xf6, 0x68, 0x82 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xdd, 0x4c, 0x85, 0xcb, 0x3f, 0x45, + 0x61, 0xe0, 0x58, 0x1e, 0xad, 0xd3, + 0x6b, 0xef, 0x82, 0x53, 0x4a, 0x16, + 0x1a, 0xf0, 0x09, 0x82, 0x74 ), + BIGINT ( 0xd2, 0xa2, 0x73, 0x89, 0x0c, 0x56, + 0xe4, 0x31, 0xdf, 0x70, 0x3c, 0x40, + 0x0d, 0x36, 0xfc, 0x4a, 0xf3, 0xa2, + 0x8f, 0x9a, 0x9d, 0xaa, 0xb0 ), + BIGINT ( 0xbc, 0xca, 0x45 ), + BIGINT ( 0x9f, 0x5f, 0x7c, 0xac, 0x5e, 0xc7, + 0xf2, 0xc5, 0x72, 0x3d, 0xff, 0x29, + 0xd2, 0x25, 0xa9, 0x64, 0x5b, 0xbe, + 0x63, 0x63, 0xc6, 0x84, 0x20 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xf8, 0xc9, 0xb9, 0x3d, 0xe1, 0xff, + 0xa6, 0x8e, 0xb0, 0xd2, 0xa9, 0xa9, + 0xc1, 0x5c, 0xc5, 0x94, 0x90, 0xb9, + 0xca, 0x2f, 0x1a, 0xbd, 0x21 ), + BIGINT ( 0xa7, 0xf4, 0xb0, 0x3c, 0xf4, 0x2b, + 0x9d, 0x40, 0x5f, 0xfd, 0x2e, 0x28, + 0xa9, 0x23, 0x01, 0xaf, 0x0b, 0x73, + 0xaa, 0xcf, 0x14, 0xdc, 0xd8 ), + BIGINT ( 0x31, 0xe2, 0xe8, 0xf0 ), + BIGINT ( 0x53, 0x30, 0xc6, 0x10, 0x12, 0x7c, + 0xb3, 0x91, 0x15, 0x5f, 0x01, 0x62, + 0xec, 0x1f, 0x15, 0x61, 0x3b, 0x9a, + 0x76, 0x22, 0xf8, 0x31, 0xb1 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xff, 0x8c, 0x04, 0x74, 0x3e, 0x93, + 0xfd, 0xce, 0xd5, 0x7f, 0xc5, 0x58, + 0xce, 0x00, 0x53, 0x44, 0x02, 0xf4, + 0xfd, 0x01, 0xc3, 0xb0, 0x3c ), + BIGINT ( 0x2f, 0xbe, 0xb3, 0x2d, 0xd6, 0x59, + 0x69, 0x44, 0xc0, 0xd4, 0x27, 0x9c, + 0xff, 0x53, 0x9e, 0x66, 0x2c, 0x01, + 0x3a, 0x96, 0x5d, 0x75, 0xc1 ), + BIGINT ( 0x47, 0x3e, 0xb2, 0x81, 0x51, 0x9a, + 0xdf, 0x75, 0xba, 0xa5, 0x19, 0xc1, + 0xc7, 0xcc, 0xae, 0x82, 0x9c, 0x3e, + 0xfd, 0x7f, 0xb0, 0xd7, 0x00 ), + BIGINT ( 0x09, 0x9c, 0xd0, 0x49, 0x1d, 0x88, + 0xd8, 0x08, 0x45, 0x61, 0x71, 0xa1, + 0xb5, 0xab, 0xa9, 0x5b, 0xa8, 0xf1, + 0xc6, 0x53, 0x68, 0x8f, 0x3e ) ); + bigint_mod_exp_ok ( BIGINT ( 0xd8, 0x78, 0xad, 0x80, 0x81, 0xf1, + 0x84, 0x23, 0x82, 0x5d, 0x49, 0x46, + 0x75, 0xfd, 0xd1, 0x49, 0x53, 0x10, + 0x4d, 0x10, 0xab, 0x0f, 0xf0 ), + BIGINT ( 0x78, 0x3d, 0x09, 0x1b, 0xea, 0xa4, + 0xb9, 0x13, 0xf8, 0xb5, 0xb5, 0x5e, + 0x69, 0xa4, 0xe1, 0xfd, 0x88, 0x58, + 0x26, 0xb3, 0x76, 0xa2, 0x38 ), + BIGINT ( 0x3b, 0x12, 0xe0, 0x8e, 0xa2, 0x2f, + 0x2a, 0x2b, 0xb1, 0x78, 0xf9, 0xf6, + 0x93, 0x4d, 0x52, 0x82, 0x29, 0x2d, + 0xe4, 0x36, 0x92, 0x49, 0xc1, 0x25, + 0x6e, 0x26, 0xe6, 0x6e, 0xc2, 0x4d, + 0xea, 0x13, 0x86, 0x85, 0x71, 0x4d, + 0x85, 0x70, 0xf9, 0x2b, 0xa0, 0x0f, + 0x96, 0xe5, 0x63, 0x7a, 0xb4, 0x25, + 0x53, 0x1a, 0xd8, 0x30, 0x36, 0xba, + 0x6e, 0x2e, 0xce, 0x2d, 0x8f, 0x32, + 0xe9, 0xdc, 0x91, 0x9e, 0xd4, 0xf1, + 0x3b, 0x40, 0xc9, 0xf4, 0x97, 0x74, + 0x5e, 0x69, 0xcd, 0x34, 0x4a, 0x18, + 0x65, 0xe5, 0x07, 0xb5, 0x9e, 0x2a, + 0xc4, 0xeb, 0xb6, 0x96, 0x7b, 0x99, + 0x0c, 0xe4, 0xb3, 0x85, 0xff, 0x17, + 0x72, 0x5d, 0xf6, 0x30, 0xb4, 0xff, + 0x98, 0xe6, 0xf6, 0x31, 0x24, 0x82, + 0x91, 0xa6, 0x18, 0x6d, 0x0b, 0x84, + 0x6f, 0x5f, 0x64, 0xa3, 0xdf, 0x92, + 0x06, 0x16, 0xe3, 0x7c, 0x08, 0x61, + 0x77, 0xce ), + BIGINT ( 0x17, 0xc9, 0xc5, 0x38, 0x4c, 0x15, + 0x0f, 0x4e, 0xc2, 0x90, 0x3b, 0x46, + 0x7b, 0x2f, 0x95, 0x82, 0xfe, 0x51, + 0x95, 0x2b, 0xff, 0xd5, 0x28 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x69, 0xa3, 0x7e, 0x24, 0xdf, 0x9e, + 0x0b, 0x3e, 0x3f, 0x43, 0x06, 0x0e, + 0x1d, 0x57, 0x74, 0xe0, 0xa0, 0x5b, + 0x82, 0xca, 0xb0, 0x33, 0x8b, 0xe4, + 0x39, 0x27, 0x41, 0xd4, 0x2e, 0x30, + 0x3a, 0x0e, 0x62, 0x6f, 0xfa, 0xb4, + 0x02, 0x88, 0x70, 0x35, 0xa6, 0xea, + 0x7d, 0xb2, 0x87, 0xc3, 0xa5, 0x50, + 0x49, 0x38, 0xa4, 0x68, 0xa9, 0xe4, + 0xa6, 0xcc, 0xd7, 0x13, 0xb1, 0xd9, + 0x1c, 0x6a, 0x9a, 0xb8, 0x6c, 0x9b, + 0xff, 0xcd, 0x2c, 0xb3, 0xbd, 0xe2, + 0xfd, 0x1f, 0x08, 0xdd, 0xc6, 0xee, + 0x18, 0x0c, 0xa5, 0xcd, 0x09, 0x19, + 0x51, 0x51, 0xa5, 0x6f, 0x93, 0x1b, + 0x34, 0xfd, 0x8f, 0xd9, 0x87, 0xed, + 0x15, 0x7e, 0x36, 0x60, 0xdd, 0x1b, + 0xf4, 0xcc, 0xc4, 0x4c, 0x19, 0x2b, + 0xd6, 0x1e, 0xec, 0x51, 0xe9, 0x27, + 0xe9, 0xbd, 0x6a, 0x3f, 0x91, 0x45, + 0xc3, 0x6d, 0x40, 0x7e, 0x6c, 0x56, + 0x05, 0x5a ), + BIGINT ( 0x5c, 0x96, 0x05, 0x81, 0x94, 0x45, + 0xcf, 0x47, 0x5f, 0x1b, 0xb0, 0xf9, + 0xef, 0x13, 0x8f, 0xcc, 0x71, 0xfd, + 0x50, 0xf1, 0xe7, 0x62, 0x6e, 0xfa, + 0x48, 0x66, 0x1c, 0xf7, 0xef, 0x09, + 0x12, 0xa2, 0xfd, 0x17, 0xb7, 0x6a, + 0x3b, 0xed, 0xf7, 0x86, 0xd2, 0xbe, + 0x95, 0x90, 0xc6, 0x00, 0x14, 0x8d, + 0xe3, 0x27, 0xbe, 0x03, 0x7c, 0x9e, + 0x6b, 0x51, 0x31, 0x8d, 0x18, 0xc4, + 0x16, 0xd2, 0x84, 0x63, 0x9b, 0xe9, + 0xa4, 0xf8, 0xff, 0x70, 0x4d, 0xeb, + 0x6f, 0x4a, 0xb7, 0x5b, 0x54, 0xf1, + 0xb5, 0xbe, 0x78, 0xb6, 0xfd, 0x8b, + 0xe1, 0x39, 0x62, 0x85, 0x9b, 0xde, + 0x30, 0xa8, 0xe4, 0x37, 0x52, 0x57, + 0x39, 0x79, 0xdb, 0x0b, 0x19, 0x6b, + 0xc9, 0x17, 0xfd, 0x8c, 0x2c, 0xaa, + 0xa4, 0xf1, 0x04, 0xd1, 0xd3, 0x2f, + 0xbb, 0x3a, 0x36, 0x82, 0x31, 0xa4, + 0x40, 0xd4, 0x87, 0x46, 0xe3, 0x6e, + 0xd0, 0x17 ), + BIGINT ( 0x93 ), + BIGINT ( 0x0d, 0x39, 0x92, 0x57, 0xaa, 0x6d, + 0xfc, 0x3b, 0x10, 0x18, 0x6d, 0x59, + 0xbe, 0x31, 0x8f, 0xee, 0xf9, 0x82, + 0x84, 0xe0, 0xdf, 0xa5, 0x00, 0x28, + 0xd1, 0x64, 0x6b, 0x4b, 0x43, 0x3b, + 0x76, 0x3e, 0x6b, 0xc4, 0xe4, 0xf5, + 0x0b, 0x59, 0x5a, 0xe4, 0x53, 0x5e, + 0x02, 0xd4, 0xde, 0x72, 0xd3, 0xa3, + 0x58, 0x66, 0xa7, 0xdd, 0x2b, 0x0b, + 0xa4, 0x83, 0xd0, 0xd9, 0xef, 0x29, + 0x3d, 0x2f, 0x97, 0xff, 0x9a, 0xc7, + 0xf6, 0x8a, 0x8d, 0x59, 0xef, 0x87, + 0xd1, 0xe6, 0xba, 0x4d, 0x99, 0xd9, + 0x5f, 0x5e, 0x7a, 0x7e, 0x67, 0x22, + 0x5b, 0x77, 0x83, 0xa2, 0x02, 0xfd, + 0xb2, 0xe4, 0xf6, 0x20, 0x4c, 0x12, + 0x20, 0xa7, 0xda, 0x5b, 0x3b, 0x8c, + 0xa2, 0xca, 0xda, 0x20, 0xaa, 0x27, + 0xe6, 0x54, 0x3e, 0xa8, 0x6f, 0x64, + 0x9d, 0xa7, 0x0d, 0x57, 0x1b, 0x21, + 0xff, 0xd2, 0xe2, 0xb2, 0x0a, 0x4f, + 0xb7, 0x0e ) ); + bigint_mod_exp_ok ( BIGINT ( 0x06, 0xcf, 0x54, 0xf2, 0x0d, 0x62, + 0x33, 0xdd, 0xe7, 0x4d, 0x7f, 0x2f, + 0x8e, 0x52, 0x73, 0xf4, 0x73, 0x68, + 0x4b, 0x13, 0x6e, 0x58, 0x6b, 0x4a, + 0xb8, 0x4c, 0xef, 0x73, 0xfe, 0x5f, + 0xf6, 0xd0, 0xbb, 0x82, 0x17, 0x3f, + 0x9d, 0x91, 0xf8, 0xa3, 0xb8, 0x79, + 0xef, 0x41, 0x38, 0xc1, 0xef, 0xc9, + 0xc6, 0xcf, 0x2a, 0xc3, 0xaa, 0x75, + 0x17, 0xda, 0xbc, 0x76, 0x29, 0x61, + 0x6d, 0x05, 0x79, 0x0b, 0x44, 0xb1, + 0x54, 0x75, 0xb7, 0xd9, 0xf6, 0xa8, + 0xbd, 0xf7, 0x85, 0xe0, 0xe7, 0x90, + 0x62, 0xce, 0x79, 0xfb, 0xc5, 0x23, + 0xa5, 0x09, 0xc0, 0xc4, 0x4d, 0xe7, + 0x9c, 0x49, 0x8f, 0x82, 0xf1, 0x31, + 0x34, 0x85, 0xdd, 0x3b, 0xbe, 0xe9, + 0x93, 0x19, 0x03, 0x75, 0x3f, 0xc4, + 0xa4, 0x0f, 0x52, 0x53, 0xc1, 0xcd, + 0x08, 0xb0, 0x05, 0x0c, 0xa2, 0x0c, + 0x3a, 0x72, 0xb2, 0x3c, 0xdb, 0x4f, + 0xac, 0xc6 ), + BIGINT ( 0xe4, 0x40, 0xd8, 0x30, 0x00, 0xcf, + 0x4c, 0xfd, 0xda, 0xae, 0x90, 0xd3, + 0x5b, 0xc7, 0x20, 0xcc, 0x2b, 0xe2, + 0x0a, 0x39, 0x1e, 0xde, 0xef, 0x98, + 0x16, 0x3b, 0x9d, 0x36, 0x63, 0x0d, + 0x46, 0xed, 0x23, 0x6e, 0x38, 0xa8, + 0x15, 0xb5, 0xb1, 0xaf, 0x47, 0xb1, + 0xec, 0xaa, 0x8b, 0x57, 0xd6, 0xca, + 0x39, 0x2f, 0x62, 0xbd, 0xd5, 0xf8, + 0x98, 0x98, 0x5d, 0xfe, 0x14, 0xd6, + 0xdc, 0xe5, 0x98, 0x60, 0x5b, 0x16, + 0x92, 0xcb, 0xed, 0xb6, 0x9c, 0x5c, + 0x82, 0x40, 0x6b, 0xaa, 0x48, 0x7a, + 0xd4, 0xfe, 0xa3, 0xe7, 0x30, 0xf1, + 0x7c, 0xfb, 0x94, 0x2e, 0xeb, 0xb6, + 0x71, 0xe4, 0x33, 0x63, 0xc3, 0xb0, + 0x94, 0x6d, 0xee, 0xa5, 0x15, 0x3f, + 0x28, 0xf1, 0xfa, 0xdc, 0xf2, 0x13, + 0x0f, 0xc7, 0xd9, 0xe0, 0xbf, 0x1b, + 0x49, 0xee, 0x21, 0x8e, 0x26, 0xc9, + 0x28, 0x21, 0x86, 0x1d, 0x46, 0x33, + 0xd4, 0x69 ), + BIGINT ( 0xd9, 0x87 ), + BIGINT ( 0xdf, 0xff, 0xcc, 0xb7, 0xfe, 0x19, + 0x02, 0x92, 0x9d, 0xab, 0x33, 0xd2, + 0x21, 0xbc, 0xd3, 0xc4, 0x31, 0xad, + 0x4b, 0xb3, 0x16, 0x50, 0x96, 0xd9, + 0xdc, 0x88, 0x74, 0x60, 0xde, 0xdf, + 0xb7, 0x83, 0xdb, 0x22, 0xef, 0xcb, + 0xcb, 0xdb, 0x4c, 0xfb, 0x94, 0x4c, + 0x3f, 0xf5, 0xf5, 0x99, 0x85, 0x21, + 0x1a, 0x2b, 0xec, 0x90, 0x2d, 0xb4, + 0x20, 0x3c, 0x27, 0x9f, 0xe5, 0xb1, + 0x5c, 0x92, 0xfa, 0xb0, 0xa9, 0x8e, + 0x2c, 0x21, 0x8e, 0x8d, 0xe5, 0x55, + 0x84, 0x02, 0xa5, 0x15, 0x5c, 0x53, + 0x1f, 0x40, 0x81, 0x0a, 0x10, 0xde, + 0x21, 0x41, 0xa9, 0x97, 0xf8, 0x6f, + 0xbf, 0x42, 0x58, 0x9e, 0xc6, 0xdd, + 0x10, 0x33, 0x3f, 0xad, 0xe6, 0x8e, + 0x57, 0x27, 0x37, 0x20, 0xa4, 0x86, + 0xef, 0x39, 0x7b, 0x6f, 0x78, 0x77, + 0xab, 0xa0, 0x62, 0xe1, 0xfd, 0x9c, + 0xbe, 0xfa, 0x98, 0x2e, 0x29, 0xe3, + 0xeb, 0x52 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x00, 0x91, 0xb3, 0x87, 0xe6, 0x01, + 0x57, 0xe9, 0x68, 0xa4, 0xf4, 0x9b, + 0xea, 0x6a, 0x8a, 0x9e, 0x1a, 0x8b, + 0xd3, 0x85, 0x9d, 0xba, 0x85, 0xab, + 0xd8, 0xcd, 0x25, 0x56, 0x8e, 0x85, + 0x8a, 0x8e, 0x48, 0x9e, 0xb4, 0x90, + 0xc8, 0x2e, 0x07, 0x78, 0x80, 0x49, + 0xa0, 0xb7, 0x95, 0x6a, 0xd8, 0xad, + 0xb5, 0xda, 0x5d, 0xe6, 0x11, 0x87, + 0xb8, 0x33, 0x8f, 0xa8, 0x6f, 0x4e, + 0xc6, 0xc3, 0x0d, 0xf5, 0xa9, 0x4e, + 0xb2, 0x42, 0x53, 0x81, 0xcd, 0x33, + 0x83, 0x49, 0xab, 0x0d, 0x0e, 0xf5, + 0x2c, 0xcd, 0x84, 0x58, 0xf3, 0x30, + 0xa3, 0x6e, 0x3c, 0x3a, 0xc6, 0x77, + 0x43, 0xb0, 0xe7, 0x4b, 0x66, 0x30, + 0xe9, 0x48, 0x0b, 0x0d, 0x86, 0x3f, + 0xd8, 0xe2, 0xb5, 0x88, 0xc1, 0x44, + 0xb2, 0x6b, 0xb0, 0x7a, 0x35, 0x3b, + 0x56, 0x83, 0xb1, 0xac, 0x9e, 0xeb, + 0x9b, 0x08, 0x43, 0xac, 0x0a, 0x3a, + 0x31, 0x69 ), + BIGINT ( 0x96, 0x6f, 0xb0, 0xa7, 0x02, 0xb5, + 0xd9, 0x19, 0xbe, 0x4b, 0x27, 0x65, + 0x5b, 0x96, 0xd4, 0x0b, 0x49, 0x70, + 0xf0, 0x09, 0x8e, 0xf2, 0x04, 0x85, + 0x93, 0xe9, 0x2e, 0x09, 0x31, 0x76, + 0x8b, 0xbb, 0xe9, 0xe1, 0x2b, 0x4f, + 0xed, 0x83, 0xa6, 0x87, 0xa3, 0x07, + 0x0a, 0x3d, 0x1c, 0x65, 0x14, 0x5a, + 0xd5, 0xc0, 0x5d, 0x3c, 0x31, 0x9a, + 0x83, 0xad, 0xca, 0x6a, 0x93, 0x0d, + 0x1a, 0x67, 0x4e, 0x68, 0x06, 0x64, + 0x53, 0x2e, 0x15, 0xd9, 0xdd, 0x5e, + 0xcb, 0xb7, 0x2e, 0xef, 0xd3, 0xbb, + 0x5f, 0xaf, 0xef, 0x9e, 0xf2, 0x7b, + 0x69, 0x15, 0xb0, 0x18, 0x6c, 0x67, + 0x10, 0xda, 0x33, 0x07, 0x48, 0x97, + 0x31, 0xb3, 0x3d, 0x3d, 0xc9, 0x2e, + 0x0b, 0x68, 0x91, 0x3f, 0x6a, 0x3b, + 0x1a, 0xdf, 0xa8, 0x69, 0x46, 0x1c, + 0xb2, 0x69, 0x08, 0x0b, 0x02, 0x1b, + 0x03, 0x64, 0xae, 0xb6, 0x2d, 0xc6, + 0xc4, 0x0a ), + BIGINT ( 0x6d, 0x3f, 0xdd ), + BIGINT ( 0x40, 0x6e, 0x9d, 0x3e, 0xeb, 0xa4, + 0xb1, 0x8d, 0xb7, 0xb4, 0x0f, 0x5b, + 0x12, 0xad, 0x27, 0x9e, 0xbd, 0xe7, + 0xe5, 0x9d, 0xec, 0xb4, 0xac, 0x23, + 0x5f, 0xa9, 0xec, 0x9c, 0xd1, 0x6a, + 0xbe, 0x99, 0xba, 0xb3, 0x66, 0x0e, + 0x17, 0xaa, 0x13, 0xa2, 0x2e, 0x01, + 0x28, 0xb1, 0x6c, 0xba, 0xad, 0x68, + 0x48, 0xf0, 0xf3, 0x4c, 0x08, 0x9f, + 0xd1, 0x9c, 0xb7, 0x75, 0xc5, 0xb6, + 0x5a, 0x05, 0xb0, 0x14, 0xd4, 0x61, + 0xea, 0x18, 0x9f, 0xe6, 0xe5, 0xe3, + 0xd4, 0xff, 0x35, 0x43, 0x0b, 0xb8, + 0xf6, 0xe9, 0x19, 0x7a, 0x88, 0xa7, + 0x4d, 0x01, 0x92, 0x05, 0xd2, 0x6e, + 0xa3, 0xc1, 0xb6, 0x66, 0x75, 0xb1, + 0x00, 0x0d, 0x42, 0x37, 0xcc, 0xca, + 0xc0, 0x8d, 0xc8, 0x7e, 0x5c, 0xc9, + 0x53, 0x81, 0x2f, 0xc4, 0x61, 0xb6, + 0x96, 0x3b, 0xa5, 0x04, 0x14, 0x1b, + 0xa7, 0x77, 0xa1, 0xbc, 0x73, 0x1d, + 0xad, 0xed ) ); + bigint_mod_exp_ok ( BIGINT ( 0x45, 0xfb, 0xf3, 0xdc, 0x31, 0xe5, + 0x56, 0x7a, 0xee, 0x15, 0xfb, 0x16, + 0xee, 0x6e, 0x90, 0x3e, 0xa3, 0x89, + 0xc2, 0x6d, 0x9b, 0x06, 0x65, 0xd0, + 0xcd, 0xa2, 0xcc, 0x01, 0x60, 0x0d, + 0xd1, 0xdd, 0x68, 0x14, 0xc2, 0xcd, + 0xd8, 0x79, 0x75, 0xad, 0x0a, 0x9f, + 0x39, 0x5f, 0x52, 0x4b, 0x58, 0x31, + 0x48, 0xbb, 0x2a, 0xcc, 0xe0, 0x42, + 0x18, 0x32, 0xdc, 0x63, 0x14, 0x11, + 0x4e, 0xab, 0x96, 0x29, 0xc5, 0x06, + 0x79, 0xe5, 0x06, 0xf7, 0x59, 0xdb, + 0x1e, 0x51, 0xfd, 0xc4, 0x48, 0x3a, + 0x4c, 0x7f, 0xd0, 0xe2, 0x36, 0x86, + 0xc1, 0x8b, 0xc5, 0x86, 0x52, 0xe0, + 0xdb, 0x92, 0x5f, 0x0e, 0x19, 0xb1, + 0xa3, 0x23, 0xdd, 0xf0, 0x78, 0xcc, + 0x81, 0x3f, 0x4a, 0xe6, 0xb0, 0x32, + 0xd1, 0x5c, 0x5e, 0x3a, 0xb0, 0xd8, + 0xe2, 0x04, 0xc0, 0x30, 0x85, 0x1d, + 0x5e, 0x28, 0xee, 0xd9, 0xb3, 0x83, + 0x9f, 0xe2 ), + BIGINT ( 0xb3, 0x2c, 0x2e, 0xc5, 0xba, 0xf8, + 0x41, 0x98, 0x79, 0x7e, 0xaa, 0x0c, + 0x2a, 0x8f, 0xd9, 0x56, 0x55, 0xaa, + 0x74, 0x60, 0x74, 0xd1, 0x49, 0x2c, + 0x6f, 0x0a, 0x4e, 0xf8, 0x3f, 0x1b, + 0x73, 0x4c, 0xe0, 0x17, 0x37, 0x06, + 0x76, 0x73, 0xd5, 0x2d, 0x4d, 0x3f, + 0xb0, 0x15, 0x7e, 0x98, 0xd0, 0xdf, + 0xf0, 0x33, 0x78, 0xe2, 0xe6, 0xec, + 0x21, 0x22, 0xad, 0xd5, 0xab, 0x2d, + 0x0d, 0x59, 0x95, 0x05, 0x34, 0x1f, + 0x51, 0xf5, 0xec, 0x93, 0x05, 0x15, + 0x37, 0xcf, 0x93, 0x03, 0xd7, 0xf6, + 0x35, 0x23, 0x8f, 0x33, 0xf6, 0xba, + 0x42, 0xc8, 0x52, 0x94, 0xd3, 0x33, + 0x3e, 0x39, 0x01, 0xd1, 0x55, 0x3f, + 0x48, 0x84, 0xe9, 0xbc, 0x0b, 0x0f, + 0xc9, 0x69, 0x41, 0x2c, 0x5f, 0x34, + 0xd0, 0xe6, 0x15, 0x50, 0x06, 0x64, + 0x5b, 0x8b, 0x71, 0x22, 0xb3, 0x3e, + 0x09, 0x9c, 0x76, 0x13, 0x9b, 0x29, + 0x57, 0x94 ), + BIGINT ( 0xca, 0x94, 0xf7, 0xca ), + BIGINT ( 0x83, 0x68, 0xb9, 0xe7, 0x91, 0xf3, + 0x3b, 0x5a, 0x0b, 0xb6, 0x1e, 0x2f, + 0x3f, 0x5f, 0xdc, 0x96, 0x5b, 0x7f, + 0x8d, 0xc5, 0x8e, 0xda, 0x6e, 0x21, + 0xe3, 0x20, 0xea, 0x37, 0x39, 0x3b, + 0xb4, 0xd7, 0xf6, 0xba, 0x61, 0xfe, + 0xdc, 0x7e, 0x82, 0x9a, 0x38, 0x7b, + 0xd5, 0xb1, 0x11, 0x98, 0xc4, 0x88, + 0x0b, 0x01, 0x7d, 0x81, 0xc9, 0x64, + 0x23, 0xc3, 0x3e, 0xf3, 0x67, 0x95, + 0x78, 0xca, 0xda, 0x52, 0xaf, 0x72, + 0x25, 0xd9, 0xf0, 0x27, 0xd3, 0x1c, + 0xfb, 0xad, 0xa1, 0xa7, 0x06, 0x2f, + 0xaa, 0x2f, 0x86, 0x5c, 0x8b, 0x30, + 0xe1, 0xda, 0x5a, 0x36, 0xf9, 0xfd, + 0xbf, 0xfe, 0x0d, 0x03, 0xf8, 0x9c, + 0x6b, 0x9b, 0xe5, 0x70, 0x6d, 0x75, + 0xd7, 0x54, 0x28, 0x43, 0x34, 0x69, + 0x98, 0x11, 0x29, 0xee, 0x50, 0x06, + 0xa4, 0xc4, 0x11, 0x6d, 0x60, 0x8c, + 0xcd, 0xd1, 0x88, 0xe9, 0x6b, 0xbb, + 0xc1, 0xd4 ) ); + bigint_mod_exp_ok ( BIGINT ( 0xa1, 0x01, 0x7e, 0xb4, 0x0e, 0x66, + 0xa5, 0x07, 0x8b, 0x10, 0x84, 0x0d, + 0x30, 0x0a, 0xa4, 0x2d, 0x10, 0x2c, + 0xd4, 0x9a, 0x27, 0xf1, 0x02, 0x8c, + 0x38, 0x18, 0x7f, 0x7f, 0x95, 0x65, + 0xf1, 0xa9, 0x3b, 0x7d, 0x1f, 0x4f, + 0x88, 0xb0, 0x65, 0x62, 0x63, 0x63, + 0xaa, 0x82, 0xfc, 0x83, 0x3a, 0x3a, + 0x46, 0x59, 0x6a, 0x89, 0xec, 0xa9, + 0xb0, 0x4c, 0x5e, 0xbe, 0x46, 0x98, + 0xd0, 0xd4, 0xb7, 0xe3, 0x1b, 0x30, + 0x0b, 0xfb, 0xbb, 0x4f, 0x0b, 0xd3, + 0xe4, 0xa0, 0x80, 0x54, 0xcb, 0x52, + 0x0a, 0xe8, 0x03, 0x75, 0x8e, 0x96, + 0xa4, 0x21, 0xaa, 0xbd, 0x7a, 0xfd, + 0xfa, 0xf8, 0xaf, 0x42, 0xf6, 0x61, + 0xd2, 0x93, 0xce, 0x66, 0x67, 0xe9, + 0x02, 0xda, 0x81, 0x0b, 0xb0, 0x1e, + 0x9e, 0x27, 0x57, 0x98, 0x18, 0x88, + 0x35, 0x49, 0xc0, 0x88, 0x88, 0x59, + 0xae, 0x2f, 0x66, 0x59, 0x31, 0x87, + 0x88, 0xda ), + BIGINT ( 0xfe, 0x21, 0x7c, 0xf4, 0xbe, 0xae, + 0x65, 0xda, 0x89, 0xd2, 0x26, 0xd6, + 0x9c, 0x65, 0xc6, 0xb6, 0xb4, 0x0a, + 0x84, 0x11, 0xe1, 0xe8, 0xba, 0xd8, + 0x16, 0xcf, 0x60, 0x6c, 0x83, 0xa5, + 0x4a, 0xbf, 0xa2, 0x24, 0x0b, 0x66, + 0xda, 0xe2, 0x4e, 0x2d, 0xe5, 0x9e, + 0xbf, 0xad, 0x5c, 0xa3, 0x1e, 0x5c, + 0xbd, 0xe2, 0x5b, 0x46, 0xcf, 0xcc, + 0xd5, 0xc9, 0x13, 0x95, 0xc3, 0xdb, + 0x64, 0xbf, 0xeb, 0x31, 0xa9, 0x8a, + 0x3b, 0xd2, 0x5d, 0x3b, 0x2e, 0xdc, + 0x0c, 0xca, 0xab, 0xde, 0x92, 0xae, + 0x45, 0x35, 0x96, 0xb0, 0xb7, 0xb9, + 0xe6, 0xfe, 0x28, 0x0d, 0x10, 0x72, + 0x53, 0x8e, 0x21, 0xc0, 0x33, 0x79, + 0x01, 0x43, 0x8d, 0x77, 0xc4, 0xaa, + 0xcf, 0x7f, 0xc3, 0xd1, 0xf5, 0xfd, + 0x79, 0x81, 0xf6, 0x2e, 0xb7, 0xeb, + 0x55, 0x5f, 0x74, 0xf0, 0x3a, 0xb9, + 0x57, 0x07, 0x09, 0x97, 0xa5, 0x4c, + 0x4a, 0x85 ), + BIGINT ( 0xd9, 0xb7, 0xb2, 0xd6, 0xeb, 0xf3, + 0x66, 0xbe, 0x15, 0x64, 0xad, 0x2e, + 0x9e, 0xc6, 0xaf, 0x5e, 0xaf, 0x40, + 0x1e, 0x90, 0x82, 0x2f, 0x98 ), + BIGINT ( 0x12, 0x48, 0x31, 0x7f, 0x09, 0xbb, + 0x8f, 0xd9, 0x02, 0x7e, 0x4a, 0xd0, + 0x2f, 0x42, 0x7c, 0x17, 0x6e, 0x83, + 0x74, 0x21, 0x95, 0x47, 0x7d, 0x93, + 0x4a, 0xce, 0x34, 0x7c, 0xde, 0xc7, + 0x8f, 0xf6, 0x28, 0x97, 0xba, 0x81, + 0x9b, 0xcc, 0x54, 0x14, 0x7f, 0xd3, + 0x93, 0x66, 0x41, 0x8c, 0x0e, 0x47, + 0xee, 0xc5, 0x5e, 0xd6, 0x5f, 0x01, + 0x62, 0x97, 0xf1, 0x2b, 0xee, 0x60, + 0x5e, 0x82, 0x2c, 0x7b, 0x0a, 0xf2, + 0xc3, 0x23, 0xbf, 0xb9, 0x83, 0xf7, + 0x97, 0xf5, 0xca, 0x58, 0xd7, 0xf0, + 0x87, 0x7b, 0xcb, 0x87, 0x69, 0x42, + 0xbc, 0x05, 0xc4, 0xad, 0xbd, 0x82, + 0xcf, 0x44, 0x16, 0x4f, 0x46, 0xe0, + 0xde, 0x2f, 0xfa, 0x77, 0xec, 0xa4, + 0x23, 0x7d, 0x47, 0x3e, 0x94, 0x19, + 0x8b, 0xb8, 0x84, 0x81, 0x80, 0x6c, + 0x1e, 0x31, 0xa3, 0x6d, 0x14, 0x94, + 0x57, 0x28, 0x99, 0x08, 0x0a, 0xa7, + 0x98, 0x4b ) ); + bigint_mod_exp_ok ( BIGINT ( 0xda, 0x52, 0xfd, 0x44, 0x5d, 0x11, + 0x60, 0x6c, 0xec, 0x87, 0xbf, 0x19, + 0xb8, 0x46, 0xaa, 0x41, 0xfc, 0x10, + 0xae, 0x47, 0xd6, 0x72, 0x42, 0x57, + 0xc3, 0x05, 0xca, 0xe3, 0x59, 0x94, + 0x82, 0x7c, 0xa1, 0xe0, 0xd2, 0x6b, + 0x77, 0x71, 0x42, 0xa1, 0xf7, 0x84, + 0xae, 0xf4, 0x6f, 0x44, 0x0d, 0x88, + 0xa2, 0xc5, 0x45, 0x9b, 0x49, 0x36, + 0xd4, 0x20, 0x3a, 0x7c, 0x92, 0xdb, + 0x65, 0xd9, 0x20, 0xd6, 0x71, 0x22, + 0x90, 0x70, 0xbf, 0xf3, 0x17, 0xe8, + 0x2c, 0x10, 0xe9, 0x4c, 0x02, 0x69, + 0x37, 0xa2, 0x91, 0x04, 0x46, 0x11, + 0xdc, 0xab, 0x5b, 0x1e, 0x3e, 0x31, + 0xd8, 0x69, 0xf8, 0x48, 0x84, 0x1f, + 0x56, 0x46, 0xf1, 0xc0, 0x14, 0x3f, + 0xcc, 0x5d, 0xe2, 0xf7, 0x8b, 0xa4, + 0x9e, 0x94, 0x32, 0xaa, 0x3c, 0x5e, + 0x21, 0x70, 0x00, 0x24, 0x2a, 0x1b, + 0xec, 0x25, 0xb1, 0xb6, 0x83, 0x36, + 0x5a, 0x95 ), + BIGINT ( 0x5e, 0xdc, 0x71, 0x1f, 0x5b, 0x55, + 0xaa, 0xda, 0x56, 0xf5, 0x93, 0x9b, + 0xe8, 0xfc, 0x6a, 0x80, 0xe1, 0xe3, + 0x93, 0xe4, 0xc0, 0x58, 0x6f, 0x22, + 0xce, 0x9d, 0x6f, 0x84, 0x4c, 0xd4, + 0x12, 0x44, 0x57, 0x25, 0xca, 0xe5, + 0x2b, 0x7c, 0x35, 0x88, 0xc7, 0x38, + 0x25, 0x20, 0x9b, 0x57, 0xf2, 0xf2, + 0x6c, 0x28, 0x47, 0x9c, 0x3f, 0x91, + 0x1e, 0x3f, 0xe9, 0xeb, 0x50, 0xd6, + 0xa7, 0x22, 0x88, 0x6c, 0x71, 0xe5, + 0x62, 0x2a, 0xb7, 0xce, 0xbe, 0xf7, + 0x1a, 0x8c, 0x52, 0xa6, 0xff, 0xb8, + 0x34, 0x83, 0x7e, 0x04, 0xa8, 0x9c, + 0xa8, 0xa7, 0xd1, 0x05, 0x8e, 0x13, + 0x03, 0xe0, 0x49, 0xd8, 0x4a, 0xc4, + 0x4d, 0x38, 0x21, 0x5b, 0x62, 0xc2, + 0x38, 0x23, 0x7c, 0x9e, 0xf1, 0xe9, + 0xb6, 0x9a, 0x75, 0x42, 0x14, 0x99, + 0x63, 0x36, 0x13, 0x4c, 0x2d, 0x3a, + 0x77, 0xd4, 0x74, 0xb7, 0x30, 0xb2, + 0x00, 0x0f ), + BIGINT ( 0xe3, 0xe5, 0x3b, 0xb5, 0x92, 0x5a, + 0xc6, 0xfa, 0x8f, 0xe8, 0x00, 0xb9, + 0x5c, 0xa0, 0xb6, 0x3e, 0x5e, 0x14, + 0x12, 0xa9, 0xdd, 0x2a, 0x3d, 0x4d, + 0xa3, 0x91, 0x6a, 0x56, 0x99, 0xc2, + 0x6c, 0x8e, 0xda, 0xb0, 0x5a, 0x2a, + 0x37, 0x55, 0x8b, 0xd3, 0x9b, 0xb6, + 0x1d, 0x49, 0x7d, 0x81, 0x76, 0x1c, + 0x2e, 0xb9, 0x92, 0x6d, 0xfa, 0x54, + 0x53, 0xfc, 0x74, 0x9b, 0x6b, 0x63, + 0x95, 0x1a, 0x89, 0xcc, 0xbd, 0x36, + 0xc5, 0x31, 0x7f, 0xf5, 0x31, 0x69, + 0x40, 0xd5, 0x7b, 0x94, 0x5d, 0xa9, + 0xd1, 0x34, 0x95, 0xa1, 0x8b, 0xa5, + 0xb5, 0x83, 0xda, 0xb5, 0x9d, 0x5b, + 0x74, 0x41, 0xad, 0x81, 0x45, 0x40, + 0x9b, 0xc3, 0xe8, 0xfe, 0x47, 0xdc, + 0xb0, 0xc3, 0x34, 0x5d, 0xf6, 0x3c, + 0x1d, 0x07, 0x76, 0xd9, 0x25, 0xca, + 0xa2, 0x39, 0x6c, 0xa8, 0xae, 0x30, + 0x4a, 0xde, 0xfb, 0xeb, 0x19, 0x80, + 0x5e, 0x49 ), + BIGINT ( 0x4b, 0x0e, 0x74, 0xb8, 0xa7, 0x92, + 0x74, 0xd9, 0x50, 0xf6, 0x1b, 0x67, + 0x76, 0x76, 0x56, 0x6c, 0x09, 0x9c, + 0x01, 0xda, 0xaf, 0xa3, 0xca, 0xb2, + 0x12, 0x85, 0x52, 0x24, 0xe9, 0x7e, + 0x2b, 0xf2, 0x6e, 0xe9, 0x1a, 0x10, + 0x5d, 0xa0, 0x25, 0x46, 0x8f, 0x2a, + 0x95, 0x62, 0x50, 0xb6, 0x66, 0x43, + 0x37, 0x8b, 0xcb, 0x05, 0xf8, 0x61, + 0x59, 0xf9, 0xdd, 0xd2, 0x68, 0x72, + 0xfa, 0x88, 0x13, 0x36, 0xd8, 0x24, + 0x73, 0xec, 0x47, 0x44, 0xdd, 0x45, + 0x8a, 0x59, 0xd2, 0xbd, 0x43, 0xe3, + 0x05, 0x16, 0xd5, 0x9b, 0x1c, 0x8a, + 0x4b, 0x07, 0xda, 0x58, 0x0d, 0x4a, + 0x4e, 0xe7, 0x15, 0xfc, 0xbd, 0x95, + 0xf7, 0x18, 0xa5, 0xa7, 0x93, 0xff, + 0xf8, 0x1f, 0xd4, 0x6b, 0x07, 0xc6, + 0x5d, 0x90, 0x73, 0x57, 0x57, 0x37, + 0xfa, 0x83, 0xd4, 0x7c, 0xe9, 0x77, + 0x46, 0x91, 0x3a, 0x50, 0x0d, 0x6a, + 0x25, 0xd0 ) ); +} + +/** Big integer self-test */ +struct self_test bigint_test __self_test = { + .name = "bigint", + .exec = bigint_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index c759de7f..278addee 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -33,3 +33,4 @@ REQUIRE_OBJECT ( sha256_test ); REQUIRE_OBJECT ( aes_cbc_test ); REQUIRE_OBJECT ( hmac_drbg_test ); REQUIRE_OBJECT ( hash_df_test ); +REQUIRE_OBJECT ( bigint_test ); From 321883014b7d9d70326dd891fa133ff7675466f4 Mon Sep 17 00:00:00 2001 From: 1d 2k Date: Wed, 14 Mar 2012 00:03:19 +0000 Subject: [PATCH 071/221] [eepro100] Add PCI ID 8086:10fe Signed-off-by: Michael Brown --- src/drivers/net/eepro100.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index 85840cdf..99dfb180 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -1141,6 +1141,7 @@ PCI_ROM(0x8086, 0x5200, "eepro100-5200", "Intel EtherExpress PRO/100 Intelligent PCI_ROM(0x8086, 0x5201, "eepro100-5201", "Intel EtherExpress PRO/100 Intelligent Server", 0), PCI_ROM(0x8086, 0x1092, "82562-3", "Intel Pro/100 VE Network", 0), PCI_ROM(0x8086, 0x27dc, "eepro100-27dc", "Intel 82801G (ICH7) Chipset Ethernet Controller", 0), +PCI_ROM(0x8086, 0x10fe, "82552", "Intel 82552 10/100 Network Connection", 0), }; /* Cards with device ids 0x1030 to 0x103F, 0x2449, 0x2459 or 0x245D might need From 37cb7c74987e2f74294a3e6bc65e205f813d3569 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 14 Mar 2012 00:10:31 +0000 Subject: [PATCH 072/221] [crypto] Use real prototypes for AXTLS' AES_encrypt() and AES_decrypt() Avoid a compiler warning on some versions of gcc by using real function prototypes. Reported-by: Rob Shelley Signed-off-by: Michael Brown --- src/crypto/axtls/os_port.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crypto/axtls/os_port.h b/src/crypto/axtls/os_port.h index 0a6ef54a..76313e20 100644 --- a/src/crypto/axtls/os_port.h +++ b/src/crypto/axtls/os_port.h @@ -35,10 +35,10 @@ static inline void get_random_NZ ( int num_rand_bytes, uint8_t *rand_data ) { #define aes 1 #if OBJECT -/* AES_CTX is not defined at this point, so omit prototypes */ +struct aes_key_st; -static void AES_encrypt(); -static void AES_decrypt(); +static void AES_encrypt ( const struct aes_key_st *ctx, uint32_t *data ); +static void AES_decrypt ( const struct aes_key_st *ctx, uint32_t *data ); void axtls_aes_encrypt ( void *ctx, uint32_t *data ) { AES_encrypt ( ctx, data ); From 0e81ff22974a3cecc1ffa86973fb59f1e9f90af2 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Fri, 16 Mar 2012 14:46:51 +0100 Subject: [PATCH 073/221] [myri10ge] Fix compilation error in myri10ge_command() with gcc 4.7 Signed-off-by: Michael Brown --- src/drivers/net/myri10ge.c | 6 +++--- src/drivers/net/myri10ge_mcp.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/drivers/net/myri10ge.c b/src/drivers/net/myri10ge.c index 5bb555d8..2c9bf960 100644 --- a/src/drivers/net/myri10ge.c +++ b/src/drivers/net/myri10ge.c @@ -304,10 +304,10 @@ static int myri10ge_command ( struct myri10ge_private *priv, command->response_addr.high = 0; command->response_addr.low = htonl ( virt_to_bus ( &priv->dma->command_response ) ); - for ( i=0; i<36; i+=4 ) - * ( uint32 * ) &command->pad[i] = 0; + for ( i=0; i<9; i++ ) + command->pad[i] = 0; wmb(); - * ( uint32 * ) &command->pad[36] = 0; + command->pad[9] = 0; /* Wait up to 2 seconds for a response. */ diff --git a/src/drivers/net/myri10ge_mcp.h b/src/drivers/net/myri10ge_mcp.h index 397f8b0d..391dab37 100644 --- a/src/drivers/net/myri10ge_mcp.h +++ b/src/drivers/net/myri10ge_mcp.h @@ -80,7 +80,7 @@ struct mcp_cmd { /* 16 */ struct mcp_dma_addr response_addr; /* 24 */ - uint8_t pad[40]; + uint32_t pad[10]; }; typedef struct mcp_cmd mcp_cmd_t; From a0082b1308e009526c5b74aa1579f25c46969221 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Mar 2012 11:57:15 +0000 Subject: [PATCH 074/221] [libc] Move VA_ARG_COUNT() macro to stdarg.h Make the non-standard but extremely useful macro VA_ARG_COUNT() available outside of dhcp.h. Signed-off-by: Michael Brown --- src/include/ipxe/dhcp.h | 27 +-------------------------- src/include/stdarg.h | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index 06fb33bc..28772302 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include #include #include @@ -458,32 +459,6 @@ struct dhcp_netdev_desc { /** @} */ -/** - * Count number of arguments to a variadic macro - * - * This rather neat, non-iterative solution is courtesy of Laurent - * Deniau. - * - */ -#define _VA_ARG_COUNT( _1, _2, _3, _4, _5, _6, _7, _8, \ - _9, _10, _11, _12, _13, _14, _15, _16, \ - _17, _18, _19, _20, _21, _22, _23, _24, \ - _25, _26, _27, _28, _29, _30, _31, _32, \ - _33, _34, _35, _36, _37, _38, _39, _40, \ - _41, _42, _43, _44, _45, _46, _47, _48, \ - _49, _50, _51, _52, _53, _54, _55, _56, \ - _57, _58, _59, _60, _61, _62, _63, N, ... ) N -#define VA_ARG_COUNT( ... ) \ - _VA_ARG_COUNT ( __VA_ARGS__, \ - 63, 62, 61, 60, 59, 58, 57, 56, \ - 55, 54, 53, 52, 51, 50, 49, 48, \ - 47, 46, 45, 44, 43, 42, 41, 40, \ - 39, 38, 37, 36, 35, 34, 33, 32, \ - 31, 30, 29, 28, 27, 26, 25, 24, \ - 23, 22, 21, 20, 19, 18, 17, 16, \ - 15, 14, 13, 12, 11, 10, 9, 8, \ - 7, 6, 5, 4, 3, 2, 1, 0 ) - /** Construct a DHCP option from a list of bytes */ #define DHCP_OPTION( ... ) VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__ diff --git a/src/include/stdarg.h b/src/include/stdarg.h index 78b261ae..f317238a 100644 --- a/src/include/stdarg.h +++ b/src/include/stdarg.h @@ -9,4 +9,30 @@ typedef __builtin_va_list va_list; #define va_end( ap ) __builtin_va_end ( ap ) #define va_copy( dest, src ) __builtin_va_copy ( dest, src ) +/** + * Count number of arguments to a variadic macro + * + * This rather neat, non-iterative solution is courtesy of Laurent + * Deniau. + * + */ +#define _VA_ARG_COUNT( _1, _2, _3, _4, _5, _6, _7, _8, \ + _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, \ + _25, _26, _27, _28, _29, _30, _31, _32, \ + _33, _34, _35, _36, _37, _38, _39, _40, \ + _41, _42, _43, _44, _45, _46, _47, _48, \ + _49, _50, _51, _52, _53, _54, _55, _56, \ + _57, _58, _59, _60, _61, _62, _63, N, ... ) N +#define VA_ARG_COUNT( ... ) \ + _VA_ARG_COUNT ( __VA_ARGS__, \ + 63, 62, 61, 60, 59, 58, 57, 56, \ + 55, 54, 53, 52, 51, 50, 49, 48, \ + 47, 46, 45, 44, 43, 42, 41, 40, \ + 39, 38, 37, 36, 35, 34, 33, 32, \ + 31, 30, 29, 28, 27, 26, 25, 24, \ + 23, 22, 21, 20, 19, 18, 17, 16, \ + 15, 14, 13, 12, 11, 10, 9, 8, \ + 7, 6, 5, 4, 3, 2, 1, 0 ) + #endif /* _STDARG_H */ From b0a1ad9242645af9f74e9eb65ffba37f322b64f9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 16 Mar 2012 19:52:39 +0000 Subject: [PATCH 075/221] [rng] Fix build error when assertions are enabled Signed-off-by: Michael Brown --- src/crypto/drbg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/crypto/drbg.c b/src/crypto/drbg.c index afd75da3..809de372 100644 --- a/src/crypto/drbg.c +++ b/src/crypto/drbg.c @@ -128,8 +128,8 @@ int drbg_instantiate ( struct drbg_state *state, const void *personal, state, strerror ( rc ) ); return rc; } - assert ( len >= min_len ); - assert ( len <= sizeof ( data ) ); + assert ( len >= ( int ) min_len ); + assert ( len <= ( int ) sizeof ( data ) ); /* 9. initial_working_state = Instantiate_algorithm ( * entropy_input, nonce, personalization_string ). From da76a489d692786c4febf33d77eec29b3ebc2692 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 02:42:00 +0000 Subject: [PATCH 076/221] [test] Run self-tests as an embedded image Allow iPXE to exit after running self-tests, rather than locking the machine. Signed-off-by: Michael Brown --- src/include/ipxe/errfile.h | 1 + src/tests/test.c | 46 ++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 7c86fdbb..35a0bb7f 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -60,6 +60,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_null_sanboot ( ERRFILE_CORE | 0x00140000 ) #define ERRFILE_edd ( ERRFILE_CORE | 0x00150000 ) #define ERRFILE_parseopt ( ERRFILE_CORE | 0x00160000 ) +#define ERRFILE_test ( ERRFILE_CORE | 0x00170000 ) #define ERRFILE_eisa ( ERRFILE_DRIVER | 0x00000000 ) #define ERRFILE_isa ( ERRFILE_DRIVER | 0x00010000 ) diff --git a/src/tests/test.c b/src/tests/test.c index fa9f5797..b0a24c08 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -29,9 +29,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include #include +#include /** Current self-test set */ static struct self_test *current_tests; @@ -100,8 +102,9 @@ static void run_tests ( struct self_test *tests ) { /** * Run all self-tests * + * @ret rc Return status code */ -static void test_init ( void ) { +static int run_all_tests ( void ) { struct self_test *tests; unsigned int failures = 0; unsigned int assertions = 0; @@ -125,15 +128,50 @@ static void test_init ( void ) { printf ( " with %d assertion failures", assertions ); } printf ( "\n" ); + return -EINPROGRESS; } else { printf ( "OK: all %d tests passed\n", total ); + return 0; } +} - /* Lock system */ - while ( 1 ) {} +static int test_image_probe ( struct image *image __unused ) { + return -ENOTTY; +} + +static int test_image_exec ( struct image *image __unused ) { + return run_all_tests(); +} + +static struct image_type test_image_type = { + .name = "self-tests", + .probe = test_image_probe, + .exec = test_image_exec, +}; + +static void test_image_free ( struct refcnt *refcnt __unused ) { + /* Do nothing */ +} + +static struct image test_image = { + .refcnt = REF_INIT ( test_image_free ), + .name = "", + .type = &test_image_type, +}; + +static void test_init ( void ) { + int rc; + + /* Register self-tests image */ + if ( ( rc = register_image ( &test_image ) ) != 0 ) { + DBG ( "Could not register self-test image: %s\n", + strerror ( rc ) ); + /* No way to report failure */ + return; + } } /** Self-test initialisation function */ -struct init_fn test_init_fn __init_fn ( INIT_NORMAL ) = { +struct init_fn test_init_fn __init_fn ( INIT_EARLY ) = { .initialise = test_init, }; From e20550fddf295607fbc26ba34e9998acd30c875e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 13:24:20 +0000 Subject: [PATCH 077/221] [crypto] Add more ASN.1 functions for X.509 certificate parsing Signed-off-by: Michael Brown --- src/crypto/asn1.c | 106 +++++++++++++++++++++++++++++++++++++++- src/crypto/x509.c | 2 +- src/include/ipxe/asn1.h | 26 +++++++--- 3 files changed, 125 insertions(+), 9 deletions(-) diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index d988aab4..f075b66d 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -43,6 +43,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EINVAL_ASN1_LEN ) #define EINFO_EINVAL_ASN1_LEN \ __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" ) +#define EINVAL_ASN1_BOOLEAN \ + __einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN ) +#define EINFO_EINVAL_ASN1_BOOLEAN \ + __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" ) +#define EINVAL_ASN1_INTEGER \ + __einfo_error ( EINFO_EINVAL_ASN1_INTEGER ) +#define EINFO_EINVAL_ASN1_INTEGER \ + __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" ) /** * Invalidate ASN.1 object cursor @@ -191,7 +199,7 @@ int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) { int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) { int rc; - if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) < 0 ) { + if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) { asn1_invalidate_cursor ( cursor ); return rc; } @@ -199,6 +207,32 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) { return 0; } +/** + * Shrink ASN.1 cursor to fit object + * + * @v cursor ASN.1 object cursor + * @v type Expected type, or ASN1_ANY + * @ret rc Return status code + * + * The object cursor will be shrunk to contain only the current ASN.1 + * object. If any error occurs, the object cursor will be + * invalidated. + */ +int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) { + struct asn1_cursor next; + int rc; + + /* Skip to next object */ + memcpy ( &next, cursor, sizeof ( next ) ); + if ( ( rc = asn1_skip ( &next, type ) ) != 0 ) + return rc; + + /* Shrink original cursor to contain only its first object */ + cursor->len = ( next.data - cursor->data ); + + return 0; +} + /** * Enter ASN.1 object of any type * @@ -219,6 +253,76 @@ int asn1_skip_any ( struct asn1_cursor *cursor ) { return asn1_skip ( cursor, ASN1_ANY ); } +/** + * Shrink ASN.1 object of any type + * + * @v cursor ASN.1 object cursor + * @ret rc Return status code + */ +int asn1_shrink_any ( struct asn1_cursor *cursor ) { + return asn1_shrink ( cursor, ASN1_ANY ); +} + +/** + * Parse value of ASN.1 boolean + * + * @v cursor ASN.1 object cursor + * @ret value Value, or negative error + */ +int asn1_boolean ( const struct asn1_cursor *cursor ) { + struct asn1_cursor contents; + const struct asn1_boolean *boolean; + + /* Enter boolean */ + memcpy ( &contents, cursor, sizeof ( contents ) ); + asn1_enter ( &contents, ASN1_BOOLEAN ); + if ( contents.len != sizeof ( *boolean ) ) + return -EINVAL_ASN1_BOOLEAN; + + /* Extract value */ + boolean = contents.data; + return boolean->value; +} + +/** + * Parse value of ASN.1 integer + * + * @v cursor ASN.1 object cursor + * @v value Value to fill in + * @ret rc Return status code + */ +int asn1_integer ( const struct asn1_cursor *cursor, int *value ) { + struct asn1_cursor contents; + uint8_t high_byte; + int rc; + + /* Enter integer */ + memcpy ( &contents, cursor, sizeof ( contents ) ); + if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 ) + return rc; + if ( contents.len < 1 ) + return -EINVAL_ASN1_INTEGER; + + /* Initialise value according to sign byte */ + *value = *( ( int8_t * ) contents.data ); + contents.data++; + contents.len--; + + /* Process value */ + while ( contents.len ) { + high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) ); + if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) { + DBGC ( cursor, "ASN1 %p integer overflow\n", cursor ); + return -EINVAL_ASN1_INTEGER; + } + *value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) ); + contents.data++; + contents.len--; + } + + return 0; +} + /** * Compare two ASN.1 objects * diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 50593bc6..c09c5ebd 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -55,7 +55,7 @@ static int x509_public_key ( const struct asn1_cursor *certificate, memcpy ( &cursor, certificate, sizeof ( cursor ) ); rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */ asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */ - asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ), /* version */ + asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/ asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */ asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */ diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 7d8f6670..be344c9c 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -20,6 +20,9 @@ struct asn1_cursor { /** ASN.1 end */ #define ASN1_END 0x00 +/** ASN.1 boolean */ +#define ASN1_BOOLEAN 0x01 + /** ASN.1 integer */ #define ASN1_INTEGER 0x02 @@ -48,7 +51,7 @@ struct asn1_cursor { #define ASN1_SET 0x31 /** ASN.1 explicit tag */ -#define ASN1_EXPLICIT_TAG 0xa0 +#define ASN1_EXPLICIT_TAG( number) ( 0xa0 | (number) ) /** ASN.1 "any tag" magic value */ #define ASN1_ANY -1U @@ -79,15 +82,14 @@ struct asn1_cursor { /** ASN.1 OID for iso(1) member-body(2) */ #define ASN1_OID_ISO_MEMBERBODY ASN1_OID_INITIAL ( 1, 2 ) +/** ASN.1 OID for iso(1) identified-organization(3) */ +#define ASN1_OID_IDENTIFIED_ORGANIZATION ASN1_OID_INITIAL ( 1, 3 ) + /** ASN.1 OID for joint-iso-itu-t(2) ds(5) */ #define ASN1_OID_DIRECTORY_SERVICES ASN1_OID_INITIAL ( 2, 5 ) -/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */ -#define ASN1_OID_ATTRIBUTE_TYPE \ - ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 ) - -/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */ -#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 ) +/** ASN.1 OID for joint-iso-itu-t(2) country(16) */ +#define ASN1_OID_COUNTRY ASN1_OID_INITIAL ( 2, 16 ) /** Define an ASN.1 cursor containing an OID */ #define ASN1_OID_CURSOR( oid_value ) { \ @@ -95,6 +97,12 @@ struct asn1_cursor { .len = sizeof ( oid_value ), \ } +/** An ASN.1 boolean */ +struct asn1_boolean { + /** Value */ + uint8_t value; +} __attribute__ (( packed )); + /** An ASN.1 bit string */ struct asn1_bit_string { /** Number of unused bits */ @@ -119,8 +127,12 @@ extern int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ); extern int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ); extern int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ); +extern int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ); extern int asn1_enter_any ( struct asn1_cursor *cursor ); extern int asn1_skip_any ( struct asn1_cursor *cursor ); +extern int asn1_shrink_any ( struct asn1_cursor *cursor ); +extern int asn1_boolean ( const struct asn1_cursor *cursor ); +extern int asn1_integer ( const struct asn1_cursor *cursor, int *value ); extern int asn1_compare ( const struct asn1_cursor *cursor1, const struct asn1_cursor *cursor2 ); From c00eb6e190d4957c0e7c5f1e18e4ea1fbaa5a6d0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 13:25:10 +0000 Subject: [PATCH 078/221] [crypto] Add abstraction for a public-key algorithm Signed-off-by: Michael Brown --- src/crypto/crypto_null.c | 49 ++++++++++++++++++++ src/include/ipxe/crypto.h | 98 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index c9c32ae9..590ac560 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -81,7 +81,56 @@ struct cipher_algorithm cipher_null = { .decrypt = cipher_null_decrypt, }; +static int pubkey_null_init ( void *ctx __unused, const void *key __unused, + size_t key_len __unused ) { + return 0; +} + +static size_t pubkey_null_max_len ( void *ctx __unused ) { + return 0; +} + +static int pubkey_null_encrypt ( void *ctx __unused, + const void *plaintext __unused, + size_t plaintext_len __unused, + void *ciphertext __unused ) { + return 0; +} + +static int pubkey_null_decrypt ( void *ctx __unused, + const void *ciphertext __unused, + size_t ciphertext_len __unused, + void *plaintext __unused ) { + return 0; +} + +static int pubkey_null_sign ( void *ctx __unused, + struct digest_algorithm *digest __unused, + const void *value __unused, + void *signature __unused ) { + return 0; +} + +static int pubkey_null_verify ( void *ctx __unused, + struct digest_algorithm *digest __unused, + const void *value __unused, + const void *signature __unused , + size_t signature_len __unused ) { + return 0; +} + +static void pubkey_null_final ( void *ctx __unused ) { + /* Do nothing */ +} + struct pubkey_algorithm pubkey_null = { .name = "null", .ctxsize = 0, + .init = pubkey_null_init, + .max_len = pubkey_null_max_len, + .encrypt = pubkey_null_encrypt, + .decrypt = pubkey_null_decrypt, + .sign = pubkey_null_sign, + .verify = pubkey_null_verify, + .final = pubkey_null_final, }; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 7c21e96e..d7d42b66 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -96,6 +96,67 @@ struct pubkey_algorithm { const char *name; /** Context size */ size_t ctxsize; + /** Initialise algorithm + * + * @v ctx Context + * @v key Key + * @v key_len Length of key + * @ret rc Return status code + */ + int ( * init ) ( void *ctx, const void *key, size_t key_len ); + /** Calculate maximum output length + * + * @v ctx Context + * @ret max_len Maximum output length + */ + size_t ( * max_len ) ( void *ctx ); + /** Encrypt + * + * @v ctx Context + * @v plaintext Plaintext + * @v plaintext_len Length of plaintext + * @v ciphertext Ciphertext + * @ret ciphertext_len Length of ciphertext, or negative error + */ + int ( * encrypt ) ( void *ctx, const void *data, size_t len, + void *out ); + /** Decrypt + * + * @v ctx Context + * @v ciphertext Ciphertext + * @v ciphertext_len Ciphertext length + * @v plaintext Plaintext + * @ret plaintext_len Plaintext length, or negative error + */ + int ( * decrypt ) ( void *ctx, const void *data, size_t len, + void *out ); + /** Sign digest value + * + * @v ctx Context + * @v digest Digest algorithm + * @v value Digest value + * @v signature Signature + * @ret signature_len Signature length, or negative error + */ + int ( * sign ) ( void *ctx, struct digest_algorithm *digest, + const void *value, void *signature ); + /** Verify signed digest value + * + * @v ctx Context + * @v digest Digest algorithm + * @v value Digest value + * @v signature Signature + * @v signature_len Signature length + * @ret rc Return status code + */ + int ( * verify ) ( void *ctx, struct digest_algorithm *digest, + const void *value, const void *signature, + size_t signature_len ); + /** Finalise algorithm + * + * @v ctx Context + */ + void ( * final ) ( void *ctx ); }; static inline void digest_init ( struct digest_algorithm *digest, @@ -147,6 +208,43 @@ static inline int is_stream_cipher ( struct cipher_algorithm *cipher ) { return ( cipher->blocksize == 1 ); } +static inline int pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx, + const void *key, size_t key_len ) { + return pubkey->init ( ctx, key, key_len ); +} + +static inline size_t pubkey_max_len ( struct pubkey_algorithm *pubkey, + void *ctx ) { + return pubkey->max_len ( ctx ); +} + +static inline int pubkey_encrypt ( struct pubkey_algorithm *pubkey, void *ctx, + const void *data, size_t len, void *out ) { + return pubkey->encrypt ( ctx, data, len, out ); +} + +static inline int pubkey_decrypt ( struct pubkey_algorithm *pubkey, void *ctx, + const void *data, size_t len, void *out ) { + return pubkey->decrypt ( ctx, data, len, out ); +} + +static inline int pubkey_sign ( struct pubkey_algorithm *pubkey, void *ctx, + struct digest_algorithm *digest, + const void *value, void *signature ) { + return pubkey->sign ( ctx, digest, value, signature ); +} + +static inline int pubkey_verify ( struct pubkey_algorithm *pubkey, void *ctx, + struct digest_algorithm *digest, + const void *value, const void *signature, + size_t signature_len ) { + return pubkey->verify ( ctx, digest, value, signature, signature_len ); +} + +static inline void pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) { + pubkey->final ( ctx ); +} + extern struct digest_algorithm digest_null; extern struct cipher_algorithm cipher_null; extern struct pubkey_algorithm pubkey_null; From 299dedcff06770282c5aae5ce9558fe016750e5d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 16:47:29 +0000 Subject: [PATCH 079/221] [crypto] Add native RSA algorithm Add an implementation of RSA that uses the iPXE big-integer support. Signed-off-by: Michael Brown --- src/crypto/axtls/{rsa.c => axtls_rsa.c} | 0 src/crypto/rsa.c | 600 ++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/rsa.h | 130 ++++- 4 files changed, 728 insertions(+), 3 deletions(-) rename src/crypto/axtls/{rsa.c => axtls_rsa.c} (100%) create mode 100644 src/crypto/rsa.c diff --git a/src/crypto/axtls/rsa.c b/src/crypto/axtls/axtls_rsa.c similarity index 100% rename from src/crypto/axtls/rsa.c rename to src/crypto/axtls/axtls_rsa.c diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c new file mode 100644 index 00000000..4aba5cc3 --- /dev/null +++ b/src/crypto/rsa.c @@ -0,0 +1,600 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * RSA public-key cryptography + * + * RSA is documented in RFC 3447. + */ + +/** An RSA digestInfo prefix */ +struct rsa_digestinfo_prefix { + /** Digest algorithm */ + struct digest_algorithm *digest; + /** Prefix */ + const void *data; + /** Length of prefix */ + size_t len; +}; + +/** "id-md5" object identifier */ +static const uint8_t rsa_md5_prefix[] = + { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) }; + +/** "id-sha1" object identifier */ +static const uint8_t rsa_sha1_prefix[] = + { RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) }; + +/** "id-sha256" object identifier */ +static const uint8_t rsa_sha256_prefix[] = + { RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) }; + +/** RSA digestInfo prefixes */ +static struct rsa_digestinfo_prefix rsa_digestinfo_prefixes[] = { + { + .digest = &md5_algorithm, + .data = rsa_md5_prefix, + .len = sizeof ( rsa_md5_prefix ), + }, + { + .digest = &sha1_algorithm, + .data = rsa_sha1_prefix, + .len = sizeof ( rsa_sha1_prefix ), + }, + { + .digest = &sha256_algorithm, + .data = rsa_sha256_prefix, + .len = sizeof ( rsa_sha256_prefix ), + }, +}; + +/** + * Identify RSA prefix + * + * @v digest Digest algorithm + * @ret prefix RSA prefix, or NULL + */ +static struct rsa_digestinfo_prefix * +rsa_find_prefix ( struct digest_algorithm *digest ) { + struct rsa_digestinfo_prefix *prefix; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( rsa_digestinfo_prefixes ) / + sizeof ( rsa_digestinfo_prefixes[0] ) ) ; i++ ) { + prefix = &rsa_digestinfo_prefixes[i]; + if ( prefix->digest == digest ) + return prefix; + } + return NULL; +} + +/** + * Free RSA dynamic storage + * + * @v context RSA context + */ +static void rsa_free ( struct rsa_context *context ) { + + free ( context->dynamic ); + context->dynamic = NULL; +} + +/** + * Allocate RSA dynamic storage + * + * @v context RSA context + * @v modulus_len Modulus length + * @v exponent_len Exponent length + * @ret rc Return status code + */ +static int rsa_alloc ( struct rsa_context *context, size_t modulus_len, + size_t exponent_len ) { + unsigned int size = bigint_required_size ( modulus_len ); + unsigned int exponent_size = bigint_required_size ( exponent_len ); + struct { + bigint_t ( size ) modulus; + bigint_t ( exponent_size ) exponent; + bigint_t ( size ) input; + bigint_t ( size ) output; + } __attribute__ (( packed )) *dynamic; + + /* Free any existing dynamic storage */ + rsa_free ( context ); + + /* Allocate dynamic storage */ + dynamic = malloc ( sizeof ( *dynamic ) ); + if ( ! dynamic ) + return -ENOMEM; + + /* Assign dynamic storage */ + context->dynamic = dynamic; + context->modulus0 = &dynamic->modulus.element[0]; + context->size = size; + context->max_len = modulus_len; + context->exponent0 = &dynamic->exponent.element[0]; + context->exponent_size = exponent_size; + context->input0 = &dynamic->input.element[0]; + context->output0 = &dynamic->output.element[0]; + + return 0; +} + +/** + * Parse RSA integer + * + * @v context RSA context + * @v integer Integer to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int rsa_parse_integer ( struct rsa_context *context, + struct asn1_cursor *integer, + const struct asn1_cursor *raw ) { + + /* Enter integer */ + memcpy ( integer, raw, sizeof ( *integer ) ); + asn1_enter ( integer, ASN1_INTEGER ); + + /* Skip initial sign byte if applicable */ + if ( ( integer->len > 1 ) && + ( *( ( uint8_t * ) integer->data ) == 0x00 ) ) { + integer->data++; + integer->len--; + } + + /* Fail if cursor or integer are invalid */ + if ( ! integer->len ) { + DBGC ( context, "RSA %p invalid integer:\n", context ); + DBGC_HDA ( context, 0, raw->data, raw->len ); + return -EINVAL; + } + + return 0; +} + +/** + * Initialise RSA cipher + * + * @v ctx RSA context + * @v key Key + * @v key_len Length of key + * @ret rc Return status code + */ +static int rsa_init ( void *ctx, const void *key, size_t key_len ) { + struct rsa_context *context = ctx; + const struct asn1_bit_string *bit_string; + struct asn1_cursor modulus; + struct asn1_cursor exponent; + struct asn1_cursor cursor; + int is_private; + int rc; + + /* Initialise context */ + memset ( context, 0, sizeof ( *context ) ); + + /* Initialise cursor */ + cursor.data = key; + cursor.len = key_len; + + /* Enter subjectPublicKeyInfo/RSAPrivateKey */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Determine key format */ + if ( asn1_type ( &cursor ) == ASN1_INTEGER ) { + /* Private key */ + is_private = 1; + + /* Skip version */ + asn1_skip_any ( &cursor ); + + } else { + /* Public key */ + is_private = 0; + + /* Skip algorithm */ + asn1_skip ( &cursor, ASN1_SEQUENCE ); + + /* Enter subjectPublicKey */ + asn1_enter ( &cursor, ASN1_BIT_STRING ); + + /* Check and skip unused-bits byte of bit string */ + bit_string = cursor.data; + if ( cursor.len < 1 ) { + rc = -EINVAL; + goto err_parse; + } + cursor.data++; + cursor.len--; + + /* Enter RSAPublicKey */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + } + + /* Extract modulus */ + if ( ( rc = rsa_parse_integer ( context, &modulus, &cursor ) ) != 0 ) + goto err_parse; + asn1_skip_any ( &cursor ); + + /* Skip public exponent, if applicable */ + if ( is_private ) + asn1_skip ( &cursor, ASN1_INTEGER ); + + /* Extract publicExponent/privateExponent */ + if ( ( rc = rsa_parse_integer ( context, &exponent, &cursor ) ) != 0 ) + goto err_parse; + + DBGC ( context, "RSA %p modulus:\n", context ); + DBGC_HDA ( context, 0, modulus.data, modulus.len ); + DBGC ( context, "RSA %p exponent:\n", context ); + DBGC_HDA ( context, 0, exponent.data, exponent.len ); + + /* Allocate dynamic storage */ + if ( ( rc = rsa_alloc ( context, modulus.len, exponent.len ) ) != 0 ) + goto err_alloc; + + /* Construct big integers */ + bigint_init ( ( ( bigint_t ( context->size ) * ) context->modulus0 ), + modulus.data, modulus.len ); + bigint_init ( ( ( bigint_t ( context->exponent_size ) * ) + context->exponent0 ), exponent.data, exponent.len ); + + return 0; + + rsa_free ( context ); + err_alloc: + err_parse: + return rc; +} + +/** + * Calculate RSA maximum output length + * + * @v ctx RSA context + * @ret max_len Maximum output length + */ +static size_t rsa_max_len ( void *ctx ) { + struct rsa_context *context = ctx; + + return context->max_len; +} + +/** + * Perform RSA cipher operation + * + * @v context RSA context + * @v in Input buffer + * @v out Output buffer + */ +static void rsa_cipher ( struct rsa_context *context, + const void *in, void *out ) { + bigint_t ( context->size ) *input = ( ( void * ) context->input0 ); + bigint_t ( context->size ) *output = ( ( void * ) context->output0 ); + bigint_t ( context->size ) *modulus = ( ( void * ) context->modulus0 ); + bigint_t ( context->exponent_size ) *exponent = + ( ( void * ) context->exponent0 ); + + /* Initialise big integer */ + bigint_init ( input, in, context->max_len ); + + /* Perform modular exponentiation */ + bigint_mod_exp ( input, modulus, exponent, output ); + + /* Copy out result */ + bigint_done ( output, out, context->max_len ); +} + +/** + * Encrypt using RSA + * + * @v ctx RSA context + * @v plaintext Plaintext + * @v plaintext_len Length of plaintext + * @v ciphertext Ciphertext + * @ret ciphertext_len Length of ciphertext, or negative error + */ +static int rsa_encrypt ( void *ctx, const void *plaintext, + size_t plaintext_len, void *ciphertext ) { + struct rsa_context *context = ctx; + void *temp; + uint8_t *encoded; + size_t max_len = ( context->max_len - 11 ); + size_t random_nz_len = ( max_len - plaintext_len + 8 ); + int rc; + + /* Sanity check */ + if ( plaintext_len > max_len ) { + DBGC ( context, "RSA %p plaintext too long (%zd bytes, max " + "%zd)\n", context, plaintext_len, max_len ); + return -ERANGE; + } + DBGC ( context, "RSA %p encrypting:\n", context ); + DBGC_HDA ( context, 0, plaintext, plaintext_len ); + + /* Construct encoded message (using the big integer output + * buffer as temporary storage) + */ + temp = context->output0; + encoded = temp; + encoded[0] = 0x00; + encoded[1] = 0x02; + if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) { + DBGC ( context, "RSA %p could not generate random data: %s\n", + context, strerror ( rc ) ); + return rc; + } + encoded[ 2 + random_nz_len ] = 0x00; + memcpy ( &encoded[ context->max_len - plaintext_len ], + plaintext, plaintext_len ); + + /* Encipher the encoded message */ + rsa_cipher ( context, encoded, ciphertext ); + DBGC ( context, "RSA %p encrypted:\n", context ); + DBGC_HDA ( context, 0, ciphertext, context->max_len ); + + return context->max_len; +} + +/** + * Decrypt using RSA + * + * @v ctx RSA context + * @v ciphertext Ciphertext + * @v ciphertext_len Ciphertext length + * @v plaintext Plaintext + * @ret plaintext_len Plaintext length, or negative error + */ +static int rsa_decrypt ( void *ctx, const void *ciphertext, + size_t ciphertext_len, void *plaintext ) { + struct rsa_context *context = ctx; + void *temp; + uint8_t *encoded; + uint8_t *end; + uint8_t *zero; + uint8_t *start; + size_t plaintext_len; + + /* Sanity check */ + if ( ciphertext_len != context->max_len ) { + DBGC ( context, "RSA %p ciphertext incorrect length (%zd " + "bytes, should be %zd)\n", + context, ciphertext_len, context->max_len ); + return -ERANGE; + } + DBGC ( context, "RSA %p decrypting:\n", context ); + DBGC_HDA ( context, 0, ciphertext, ciphertext_len ); + + /* Decipher the message (using the big integer input buffer as + * temporary storage) + */ + temp = context->input0; + encoded = temp; + rsa_cipher ( context, ciphertext, encoded ); + + /* Parse the message */ + end = ( encoded + context->max_len ); + if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) ) + goto invalid; + zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) ); + if ( ! zero ) + goto invalid; + start = ( zero + 1 ); + plaintext_len = ( end - start ); + + /* Copy out message */ + memcpy ( plaintext, start, plaintext_len ); + DBGC ( context, "RSA %p decrypted:\n", context ); + DBGC_HDA ( context, 0, plaintext, plaintext_len ); + + return plaintext_len; + + invalid: + DBGC ( context, "RSA %p invalid decrypted message:\n", context ); + DBGC_HDA ( context, 0, encoded, context->max_len ); + return -EINVAL; +} + +/** + * Encode RSA digest + * + * @v context RSA context + * @v digest Digest algorithm + * @v value Digest value + * @v encoded Encoded digest + * @ret rc Return status code + */ +static int rsa_encode_digest ( struct rsa_context *context, + struct digest_algorithm *digest, + const void *value, void *encoded ) { + struct rsa_digestinfo_prefix *prefix; + size_t digest_len = digest->digestsize; + uint8_t *temp = encoded; + size_t digestinfo_len; + size_t max_len; + size_t pad_len; + + /* Identify prefix */ + prefix = rsa_find_prefix ( digest ); + if ( ! prefix ) { + DBGC ( context, "RSA %p has no prefix for %s\n", + context, digest->name ); + return -ENOTSUP; + } + digestinfo_len = ( prefix->len + digest_len ); + + /* Sanity check */ + max_len = ( context->max_len - 11 ); + if ( digestinfo_len > max_len ) { + DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max" + "%zd)\n", + context, digest->name, digestinfo_len, max_len ); + return -ERANGE; + } + DBGC ( context, "RSA %p encoding %s digest:\n", + context, digest->name ); + DBGC_HDA ( context, 0, value, digest_len ); + + /* Construct encoded message */ + *(temp++) = 0x00; + *(temp++) = 0x01; + pad_len = ( max_len - digestinfo_len + 8 ); + memset ( temp, 0xff, pad_len ); + temp += pad_len; + *(temp++) = 0x00; + memcpy ( temp, prefix->data, prefix->len ); + temp += prefix->len; + memcpy ( temp, value, digest_len ); + temp += digest_len; + assert ( temp == ( encoded + context->max_len ) ); + DBGC ( context, "RSA %p encoded %s digest:\n", context, digest->name ); + DBGC_HDA ( context, 0, encoded, context->max_len ); + + return 0; +} + +/** + * Sign digest value using RSA + * + * @v ctx RSA context + * @v digest Digest algorithm + * @v value Digest value + * @v signature Signature + * @ret signature_len Signature length, or negative error + */ +static int rsa_sign ( void *ctx, struct digest_algorithm *digest, + const void *value, void *signature ) { + struct rsa_context *context = ctx; + void *temp; + int rc; + + DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name ); + DBGC_HDA ( context, 0, value, digest->digestsize ); + + /* Encode digest (using the big integer output buffer as + * temporary storage) + */ + temp = context->output0; + if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 ) + return rc; + + /* Encipher the encoded digest */ + rsa_cipher ( context, temp, signature ); + DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name ); + DBGC_HDA ( context, 0, signature, context->max_len ); + + return context->max_len; +} + +/** + * Verify signed digest value using RSA + * + * @v ctx RSA context + * @v digest Digest algorithm + * @v value Digest value + * @v signature Signature + * @v signature_len Signature length + * @ret rc Return status code + */ +static int rsa_verify ( void *ctx, struct digest_algorithm *digest, + const void *value, const void *signature, + size_t signature_len ) { + struct rsa_context *context = ctx; + void *temp; + void *expected; + void *actual; + int rc; + + /* Sanity check */ + if ( signature_len != context->max_len ) { + DBGC ( context, "RSA %p signature incorrect length (%zd " + "bytes, should be %zd)\n", + context, signature_len, context->max_len ); + return -ERANGE; + } + DBGC ( context, "RSA %p verifying %s digest:\n", + context, digest->name ); + DBGC_HDA ( context, 0, value, digest->digestsize ); + DBGC_HDA ( context, 0, signature, signature_len ); + + /* Decipher the signature (using the big integer input buffer + * as temporary storage) + */ + temp = context->input0; + expected = temp; + rsa_cipher ( context, signature, expected ); + DBGC ( context, "RSA %p deciphered signature:\n", context ); + DBGC_HDA ( context, 0, expected, context->max_len ); + + /* Encode digest (using the big integer output buffer as + * temporary storage) + */ + temp = context->output0; + actual = temp; + if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 ) + return rc; + + /* Verify the signature */ + if ( memcmp ( actual, expected, context->max_len ) != 0 ) { + DBGC ( context, "RSA %p signature verification failed\n", + context ); + return -EACCES; + } + + DBGC ( context, "RSA %p signature verified successfully\n", context ); + return 0; +} + +/** + * Finalise RSA cipher + * + * @v ctx RSA context + */ +static void rsa_final ( void *ctx ) { + struct rsa_context *context = ctx; + + rsa_free ( context ); +} + +/** RSA public-key algorithm */ +struct pubkey_algorithm rsa_algorithm = { + .name = "rsa", + .ctxsize = sizeof ( struct rsa_context ), + .init = rsa_init, + .max_len = rsa_max_len, + .encrypt = rsa_encrypt, + .decrypt = rsa_decrypt, + .sign = rsa_sign, + .verify = rsa_verify, + .final = rsa_final, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 35a0bb7f..050bf3fe 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -246,6 +246,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_hmac_drbg ( ERRFILE_OTHER | 0x00240000 ) #define ERRFILE_drbg ( ERRFILE_OTHER | 0x00250000 ) #define ERRFILE_entropy ( ERRFILE_OTHER | 0x00260000 ) +#define ERRFILE_rsa ( ERRFILE_OTHER | 0x00270000 ) /** @} */ diff --git a/src/include/ipxe/rsa.h b/src/include/ipxe/rsa.h index a080f9f0..e70362ce 100644 --- a/src/include/ipxe/rsa.h +++ b/src/include/ipxe/rsa.h @@ -1,12 +1,136 @@ #ifndef _IPXE_RSA_H #define _IPXE_RSA_H +/** @file + * + * RSA public-key cryptography + */ + FILE_LICENCE ( GPL2_OR_LATER ); -struct pubkey_algorithm; +#include +#include +#include + +/** ASN.1 OID for iso(1) member-body(2) us(840) */ +#define ASN1_OID_ISO_US ASN1_OID_ISO_MEMBERBODY, ASN1_OID_DOUBLE ( 840 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) */ +#define ASN1_OID_RSADSI ASN1_OID_ISO_US, ASN1_OID_TRIPLE ( 113549 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) */ +#define ASN1_OID_PKCS ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) + * digestAlgorithm(2) + */ +#define ASN1_OID_DIGESTALGORITHM ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) */ +#define ASN1_OID_OIW ASN1_OID_IDENTIFIED_ORGANIZATION, ASN1_OID_SINGLE ( 14 ) + +/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) secsig(3) */ +#define ASN1_OID_SECSIG ASN1_OID_OIW, ASN1_OID_SINGLE ( 3 ) + +/** ASN1. OID for iso(1) identified-organization(3) oiw(14) secsig(3) + * algorithms(2) + */ +#define ASN1_OID_SECSIG_ALGORITHMS ASN1_OID_SECSIG, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) */ +#define ASN1_OID_COUNTRY_US ASN1_OID_COUNTRY, ASN1_OID_DOUBLE ( 840 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) organization(1) */ +#define ASN1_OID_US_ORGANIZATION ASN1_OID_COUNTRY_US, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) + */ +#define ASN1_OID_US_GOV ASN1_OID_US_ORGANIZATION, ASN1_OID_SINGLE ( 101 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) + */ +#define ASN1_OID_CSOR ASN1_OID_US_GOV, ASN1_OID_SINGLE ( 3 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistalgorithm(4) + */ +#define ASN1_OID_NISTALGORITHM ASN1_OID_CSOR, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) + */ +#define ASN1_OID_HASHALGS ASN1_OID_NISTALGORITHM, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for pkcs-1 */ +#define ASN1_OID_PKCS_1 ASN1_OID_PKCS, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for rsaEncryption */ +#define ASN1_OID_RSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for md5WithRSAEncryption */ +#define ASN1_OID_MD5WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for sha1WithRSAEncryption */ +#define ASN1_OID_SHA1WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 5 ) + +/** ASN.1 OID for sha256WithRSAEncryption */ +#define ASN1_OID_SHA256WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 11 ) + +/** ASN.1 OID for id-md5 */ +#define ASN1_OID_MD5 ASN1_OID_DIGESTALGORITHM, ASN1_OID_SINGLE ( 5 ) + +/** ASN.1 OID for id-sha1 */ +#define ASN1_OID_SHA1 ASN1_OID_SECSIG_ALGORITHMS, ASN1_OID_SINGLE ( 26 ) + +/** ASN.1 OID for id-sha256 */ +#define ASN1_OID_SHA256 ASN1_OID_HASHALGS, ASN1_OID_SINGLE ( 1 ) + +/** RSA digestAlgorithm sequence contents */ +#define RSA_DIGESTALGORITHM_CONTENTS( ... ) \ + ASN1_OID, VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__, \ + ASN1_NULL, 0x00 + +/** RSA digestAlgorithm sequence */ +#define RSA_DIGESTALGORITHM( ... ) \ + ASN1_SEQUENCE, \ + VA_ARG_COUNT ( RSA_DIGESTALGORITHM_CONTENTS ( __VA_ARGS__ ) ), \ + RSA_DIGESTALGORITHM_CONTENTS ( __VA_ARGS__ ) + +/** RSA digest prefix */ +#define RSA_DIGEST_PREFIX( digest_size ) \ + ASN1_OCTET_STRING, digest_size + +/** RSA digestInfo prefix */ +#define RSA_DIGESTINFO_PREFIX( digest_size, ... ) \ + ASN1_SEQUENCE, \ + ( VA_ARG_COUNT ( RSA_DIGESTALGORITHM ( __VA_ARGS__ ) ) + \ + VA_ARG_COUNT ( RSA_DIGEST_PREFIX ( digest_size ) ) + \ + digest_size ), \ + RSA_DIGESTALGORITHM ( __VA_ARGS__ ), \ + RSA_DIGEST_PREFIX ( digest_size ) + +/** An RSA context */ +struct rsa_context { + /** Allocated memory */ + void *dynamic; + /** Modulus */ + bigint_element_t *modulus0; + /** Modulus size */ + unsigned int size; + /** Modulus length */ + size_t max_len; + /** Exponent */ + bigint_element_t *exponent0; + /** Exponent size */ + unsigned int exponent_size; + /** Input buffer */ + bigint_element_t *input0; + /** Output buffer */ + bigint_element_t *output0; +}; extern struct pubkey_algorithm rsa_algorithm; -#include "crypto/axtls/crypto.h" - #endif /* _IPXE_RSA_H */ From 7fb064470f8a7128daab3ed52e954f4269214f75 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 13:28:36 +0000 Subject: [PATCH 080/221] [test] Add self-tests for RSA Add self-tests for the RSA algorithm using test vectors generated with the openssl tools. Signed-off-by: Michael Brown --- src/tests/pubkey_test.h | 175 ++++++++++++++ src/tests/rsa_test.c | 491 ++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 3 files changed, 667 insertions(+) create mode 100644 src/tests/pubkey_test.h create mode 100644 src/tests/rsa_test.c diff --git a/src/tests/pubkey_test.h b/src/tests/pubkey_test.h new file mode 100644 index 00000000..7678453a --- /dev/null +++ b/src/tests/pubkey_test.h @@ -0,0 +1,175 @@ +#ifndef _PUBKEY_TEST_H +#define _PUBKEY_TEST_H + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include + +/** + * Report public key decryption test result + * + * @v pubkey Public key algorithm + * @v key Key + * @v key_len Key length + * @v ciphertext Ciphertext + * @v ciphertext_len Ciphertext length + * @v expected Expected plaintext + * @v expected_len Expected plaintext length + */ +#define pubkey_decrypt_ok( pubkey, key, key_len, ciphertext, \ + ciphertext_len, expected, expected_len ) do {\ + uint8_t ctx[ (pubkey)->ctxsize ]; \ + \ + ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + { \ + size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ + uint8_t decrypted[ max_len ]; \ + int decrypted_len; \ + \ + decrypted_len = pubkey_decrypt ( (pubkey), ctx, \ + (ciphertext), \ + (ciphertext_len), \ + decrypted ); \ + ok ( decrypted_len == ( ( int ) (expected_len) ) ); \ + ok ( memcmp ( decrypted, (expected), \ + (expected_len) ) == 0 ); \ + } \ + pubkey_final ( (pubkey), ctx ); \ + } while ( 0 ) + +/** + * Report public key encryption and decryption test result + * + * @v pubkey Public key algorithm + * @v encrypt_key Encryption key + * @v encrypt_key_len Encryption key length + * @v decrypt_key Decryption key + * @v decrypt_key_len Decryption key length + * @v plaintext Plaintext + * @v plaintext_len Plaintext length + */ +#define pubkey_encrypt_ok( pubkey, encrypt_key, encrypt_key_len, \ + decrypt_key, decrypt_key_len, plaintext, \ + plaintext_len ) do { \ + uint8_t ctx[ (pubkey)->ctxsize ]; \ + \ + ok ( pubkey_init ( (pubkey), ctx, (encrypt_key), \ + (encrypt_key_len) ) == 0 ); \ + { \ + size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ + uint8_t encrypted[ max_len ]; \ + int encrypted_len; \ + \ + encrypted_len = pubkey_encrypt ( (pubkey), ctx, \ + (plaintext), \ + (plaintext_len), \ + encrypted ); \ + ok ( encrypted_len >= 0 ); \ + pubkey_decrypt_ok ( (pubkey), (decrypt_key), \ + (decrypt_key_len), encrypted, \ + encrypted_len, (plaintext), \ + (plaintext_len) ); \ + } \ + pubkey_final ( (pubkey), ctx ); \ + } while ( 0 ) + +/** + * Report public key signature test result + * + * @v pubkey Public key algorithm + * @v key Key + * @v key_len Key length + * @v digest Digest algorithm + * @v plaintext Plaintext + * @v plaintext_len Plaintext length + * @v expected Expected signature + * @v expected_len Expected signature length + */ +#define pubkey_sign_ok( pubkey, key, key_len, digest, plaintext, \ + plaintext_len, expected, expected_len ) do { \ + uint8_t ctx[ (pubkey)->ctxsize ]; \ + uint8_t digestctx[ (digest)->ctxsize ]; \ + uint8_t digestout[ (digest)->digestsize ]; \ + \ + digest_init ( (digest), digestctx ); \ + digest_update ( (digest), digestctx, (plaintext), \ + (plaintext_len) ); \ + digest_final ( (digest), digestctx, digestout ); \ + \ + ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + { \ + size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ + uint8_t signature[ max_len ]; \ + int signature_len; \ + \ + signature_len = pubkey_sign ( (pubkey), ctx, (digest), \ + digestout, signature ); \ + ok ( signature_len == ( ( int ) (expected_len) ) ); \ + ok ( memcmp ( signature, (expected), \ + (expected_len) ) == 0 ); \ + } \ + pubkey_final ( (pubkey), ctx ); \ + } while ( 0 ) + +/** + * Report public key verification test result + * + * @v pubkey Public key algorithm + * @v key Key + * @v key_len Key length + * @v digest Digest algorithm + * @v plaintext Plaintext + * @v plaintext_len Plaintext length + * @v signature Signature + * @v signature_len Signature length + */ +#define pubkey_verify_ok( pubkey, key, key_len, digest, plaintext, \ + plaintext_len, signature, signature_len ) do {\ + uint8_t ctx[ (pubkey)->ctxsize ]; \ + uint8_t digestctx[ (digest)->ctxsize ]; \ + uint8_t digestout[ (digest)->digestsize ]; \ + \ + digest_init ( (digest), digestctx ); \ + digest_update ( (digest), digestctx, (plaintext), \ + (plaintext_len) ); \ + digest_final ( (digest), digestctx, digestout ); \ + \ + ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ + (signature), (signature_len) ) == 0 ); \ + pubkey_final ( (pubkey), ctx ); \ + } while ( 0 ) + +/** + * Report public key verification test result + * + * @v pubkey Public key algorithm + * @v key Key + * @v key_len Key length + * @v digest Digest algorithm + * @v plaintext Plaintext + * @v plaintext_len Plaintext length + * @v signature Signature + * @v signature_len Signature length + */ +#define pubkey_verify_fail_ok( pubkey, key, key_len, digest, plaintext, \ + plaintext_len, signature, \ + signature_len ) do { \ + uint8_t ctx[ (pubkey)->ctxsize ]; \ + uint8_t digestctx[ (digest)->ctxsize ]; \ + uint8_t digestout[ (digest)->digestsize ]; \ + \ + digest_init ( (digest), digestctx ); \ + digest_update ( (digest), digestctx, (plaintext), \ + (plaintext_len) ); \ + digest_final ( (digest), digestctx, digestout ); \ + \ + ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ + (signature), (signature_len) ) != 0 ); \ + pubkey_final ( (pubkey), ctx ); \ + } while ( 0 ) + +#endif /* _PUBKEY_TEST_H */ diff --git a/src/tests/rsa_test.c b/src/tests/rsa_test.c new file mode 100644 index 00000000..a451e38c --- /dev/null +++ b/src/tests/rsa_test.c @@ -0,0 +1,491 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * RSA self-tests + * + * These test vectors are generated using openssl's genrsa, rsa, + * rsautl, and dgst tools. + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include "pubkey_test.h" + +/** Define inline private key data */ +#define PRIVATE(...) { __VA_ARGS__ } + +/** Define inline public key data */ +#define PUBLIC(...) { __VA_ARGS__ } + +/** Define inline plaintext data */ +#define PLAINTEXT(...) { __VA_ARGS__ } + +/** Define inline ciphertext data */ +#define CIPHERTEXT(...) { __VA_ARGS__ } + +/** Define inline signature data */ +#define SIGNATURE(...) { __VA_ARGS__ } + +/** An RSA encryption and decryption self-test */ +struct rsa_encrypt_decrypt_test { + /** Private key */ + const void *private; + /** Private key length */ + size_t private_len; + /** Public key */ + const void *public; + /** Public key length */ + size_t public_len; + /** Plaintext */ + const void *plaintext; + /** Plaintext length */ + size_t plaintext_len; + /** Ciphertext + * + * Note that the encryption process includes some random + * padding, so a given plaintext will encrypt to multiple + * different ciphertexts. + */ + const void *ciphertext; + /** Ciphertext length */ + size_t ciphertext_len; +}; + +/** + * Define an RSA encryption and decryption test + * + * @v name Test name + * @v PRIVATE Private key + * @v PUBLIC Public key + * @v PLAINTEXT Plaintext + * @v CIPHERTEXT Ciphertext + * @ret test Encryption and decryption test + */ +#define RSA_ENCRYPT_DECRYPT_TEST( name, PRIVATE, PUBLIC, PLAINTEXT, \ + CIPHERTEXT ) \ + static const uint8_t name ## _private[] = PRIVATE; \ + static const uint8_t name ## _public[] = PUBLIC; \ + static const uint8_t name ## _plaintext[] = PLAINTEXT; \ + static const uint8_t name ## _ciphertext[] = CIPHERTEXT; \ + static struct rsa_encrypt_decrypt_test name = { \ + .private = name ## _private, \ + .private_len = sizeof ( name ## _private ), \ + .public = name ## _public, \ + .public_len = sizeof ( name ## _public ), \ + .plaintext = name ## _plaintext, \ + .plaintext_len = sizeof ( name ## _plaintext ), \ + .ciphertext = name ## _ciphertext, \ + .ciphertext_len = sizeof ( name ## _ciphertext ), \ + } + +/** An RSA signature self-test */ +struct rsa_signature_test { + /** Private key */ + const void *private; + /** Private key length */ + size_t private_len; + /** Public key */ + const void *public; + /** Public key length */ + size_t public_len; + /** Plaintext */ + const void *plaintext; + /** Plaintext length */ + size_t plaintext_len; + /** Digest algorithm */ + struct digest_algorithm *digest; + /** Signature */ + const void *signature; + /** Signature length */ + size_t signature_len; +}; + +/** + * Define an RSA signature test + * + * @v name Test name + * @v PRIVATE Private key + * @v PUBLIC Public key + * @v PLAINTEXT Plaintext + * @v DIGEST Digest algorithm + * @v SIGNATURE Signature + * @ret test Signature test + */ +#define RSA_SIGNATURE_TEST( name, PRIVATE, PUBLIC, PLAINTEXT, DIGEST, \ + SIGNATURE ) \ + static const uint8_t name ## _private[] = PRIVATE; \ + static const uint8_t name ## _public[] = PUBLIC; \ + static const uint8_t name ## _plaintext[] = PLAINTEXT; \ + static const uint8_t name ## _signature[] = SIGNATURE; \ + static struct rsa_signature_test name = { \ + .private = name ## _private, \ + .private_len = sizeof ( name ## _private ), \ + .public = name ## _public, \ + .public_len = sizeof ( name ## _public ), \ + .plaintext = name ## _plaintext, \ + .plaintext_len = sizeof ( name ## _plaintext ), \ + .digest = DIGEST, \ + .signature = name ## _signature, \ + .signature_len = sizeof ( name ## _signature ), \ + } + +/** + * Report RSA encryption and decryption test result + * + * @v test RSA encryption and decryption test + */ +#define rsa_encrypt_decrypt_ok( test ) do { \ + pubkey_decrypt_ok ( &rsa_algorithm, (test)->private, \ + (test)->private_len, (test)->ciphertext, \ + (test)->ciphertext_len, (test)->plaintext, \ + (test)->plaintext_len ); \ + pubkey_encrypt_ok ( &rsa_algorithm, (test)->private, \ + (test)->private_len, (test)->public, \ + (test)->public_len, (test)->plaintext, \ + (test)->plaintext_len ); \ + pubkey_encrypt_ok ( &rsa_algorithm, (test)->public, \ + (test)->public_len, (test)->private, \ + (test)->private_len, (test)->plaintext, \ + (test)->plaintext_len ); \ + } while ( 0 ) + + +/** + * Report RSA signature test result + * + * @v test RSA signature test + */ +#define rsa_signature_ok( test ) do { \ + uint8_t bad_signature[ (test)->signature_len ]; \ + pubkey_sign_ok ( &rsa_algorithm, (test)->private, \ + (test)->private_len, (test)->digest, \ + (test)->plaintext, (test)->plaintext_len, \ + (test)->signature, (test)->signature_len ); \ + pubkey_verify_ok ( &rsa_algorithm, (test)->public, \ + (test)->public_len, (test)->digest, \ + (test)->plaintext, (test)->plaintext_len, \ + (test)->signature, (test)->signature_len ); \ + memset ( bad_signature, 0, sizeof ( bad_signature ) ); \ + pubkey_verify_fail_ok ( &rsa_algorithm, (test)->public, \ + (test)->public_len, (test)->digest, \ + (test)->plaintext, \ + (test)->plaintext_len, bad_signature, \ + sizeof ( bad_signature ) ); \ + } while ( 0 ) + +/** "Hello world" encryption and decryption test */ +RSA_ENCRYPT_DECRYPT_TEST ( hw_test, + PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, + 0xd2, 0xf1, 0x04, 0x67, 0xf6, 0x2c, 0x96, 0x07, 0xa6, 0xbd, + 0x85, 0xac, 0xc1, 0x17, 0x5d, 0xe8, 0xf0, 0x93, 0x94, 0x0c, + 0x45, 0x67, 0x26, 0x67, 0xde, 0x7e, 0xfb, 0xa8, 0xda, 0xbd, + 0x07, 0xdf, 0xcf, 0x45, 0x04, 0x6d, 0xbd, 0x69, 0x8b, 0xfb, + 0xc1, 0x72, 0xc0, 0xfc, 0x03, 0x04, 0xf2, 0x82, 0xc4, 0x7b, + 0x6a, 0x3e, 0xec, 0x53, 0x7a, 0xe3, 0x4e, 0xa8, 0xc9, 0xf9, + 0x1f, 0x2a, 0x13, 0x0d, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x40, 0x49, 0xb8, 0x61, 0xc9, 0xd3, 0x87, 0x11, 0x87, 0xeb, + 0x06, 0x21, 0x49, 0x96, 0xd2, 0x0b, 0xc7, 0xf5, 0x0c, 0x1e, + 0x99, 0x8b, 0x47, 0xd9, 0x6c, 0x43, 0x9e, 0x2d, 0x65, 0x7d, + 0xcc, 0xc2, 0x8b, 0x1a, 0x6f, 0x2b, 0x55, 0xbe, 0xb3, 0x9f, + 0xd1, 0xe2, 0x9a, 0xde, 0x1d, 0xac, 0xec, 0x67, 0xec, 0xa5, + 0xbf, 0x9c, 0x30, 0xd6, 0xf9, 0x0a, 0x1a, 0x48, 0xf3, 0xc2, + 0x93, 0x3a, 0x17, 0x27, 0x21, 0x02, 0x21, 0x00, 0xfc, 0x8d, + 0xfb, 0xee, 0x8a, 0xaa, 0x45, 0x19, 0x4b, 0xf0, 0x68, 0xb0, + 0x02, 0x38, 0x3e, 0x03, 0x6b, 0x24, 0x77, 0x20, 0xbd, 0x5e, + 0x6c, 0x76, 0xdb, 0xc9, 0xe1, 0x43, 0xa3, 0x40, 0x62, 0x6f, + 0x02, 0x21, 0x00, 0xd5, 0xd1, 0xb4, 0x4d, 0x03, 0x40, 0x69, + 0x3f, 0x9a, 0xa7, 0x44, 0x15, 0x28, 0x1e, 0xa5, 0x5f, 0xcf, + 0x97, 0x21, 0x12, 0xb3, 0xe6, 0x1c, 0x9a, 0x8d, 0xb7, 0xb4, + 0x80, 0x3a, 0x9c, 0xb0, 0x43, 0x02, 0x20, 0x71, 0xf0, 0xa0, + 0xab, 0x82, 0xf5, 0xc4, 0x8c, 0xe0, 0x1c, 0xcb, 0x2e, 0x35, + 0x22, 0x28, 0xa0, 0x24, 0x33, 0x64, 0x67, 0x69, 0xe7, 0xf2, + 0xa9, 0x41, 0x09, 0x78, 0x4e, 0xaa, 0x95, 0x3e, 0x93, 0x02, + 0x21, 0x00, 0x85, 0xcc, 0x4d, 0xd9, 0x0b, 0x39, 0xd9, 0x22, + 0x75, 0xf2, 0x49, 0x46, 0x3b, 0xee, 0xc1, 0x69, 0x6d, 0x0b, + 0x93, 0x24, 0x92, 0xf2, 0x61, 0xdf, 0xcc, 0xe2, 0xb1, 0xce, + 0xb3, 0xde, 0xac, 0xe5, 0x02, 0x21, 0x00, 0x9c, 0x23, 0x6a, + 0x95, 0xa6, 0xfe, 0x1e, 0xd8, 0x0c, 0x3f, 0x6e, 0xe6, 0x0a, + 0xeb, 0x97, 0xd6, 0x36, 0x1c, 0x80, 0xc1, 0x02, 0x87, 0x0d, + 0x4d, 0xfe, 0x28, 0x02, 0x1e, 0xde, 0xe1, 0xcc, 0x72 ), + PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, + 0x30, 0x48, 0x02, 0x41, 0x00, 0xd2, 0xf1, 0x04, 0x67, 0xf6, + 0x2c, 0x96, 0x07, 0xa6, 0xbd, 0x85, 0xac, 0xc1, 0x17, 0x5d, + 0xe8, 0xf0, 0x93, 0x94, 0x0c, 0x45, 0x67, 0x26, 0x67, 0xde, + 0x7e, 0xfb, 0xa8, 0xda, 0xbd, 0x07, 0xdf, 0xcf, 0x45, 0x04, + 0x6d, 0xbd, 0x69, 0x8b, 0xfb, 0xc1, 0x72, 0xc0, 0xfc, 0x03, + 0x04, 0xf2, 0x82, 0xc4, 0x7b, 0x6a, 0x3e, 0xec, 0x53, 0x7a, + 0xe3, 0x4e, 0xa8, 0xc9, 0xf9, 0x1f, 0x2a, 0x13, 0x0d, 0x02, + 0x03, 0x01, 0x00, 0x01 ), + PLAINTEXT ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x0a ), + CIPHERTEXT ( 0x39, 0xff, 0x5c, 0x54, 0x65, 0x3e, 0x6a, 0xab, 0xc0, 0x62, + 0x91, 0xb2, 0xbf, 0x1d, 0x73, 0x5b, 0xd5, 0x4c, 0xbd, 0x16, + 0x0f, 0x24, 0xc9, 0xf5, 0xa7, 0xdd, 0x94, 0xd6, 0xf8, 0xae, + 0xd3, 0xa0, 0x9f, 0x4d, 0xff, 0x8d, 0x81, 0x34, 0x47, 0xff, + 0x2a, 0x87, 0x96, 0xd3, 0x17, 0x5d, 0x93, 0x4d, 0x7b, 0x27, + 0x88, 0x4f, 0xec, 0x43, 0x9c, 0xed, 0xb3, 0xf2, 0x19, 0x89, + 0x38, 0x43, 0xf9, 0x41 ) ); + +/** Random message MD5 signature test */ +RSA_SIGNATURE_TEST ( md5_test, + PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, + 0xf9, 0x3f, 0x78, 0x44, 0xe2, 0x0e, 0x25, 0xf1, 0x0e, 0x94, + 0xcd, 0xca, 0x6f, 0x9e, 0xea, 0x6d, 0xdf, 0xcd, 0xa0, 0x7c, + 0xe2, 0x21, 0xeb, 0xde, 0xa6, 0x01, 0x4b, 0xb0, 0x76, 0x4b, + 0xd8, 0x8b, 0x19, 0x83, 0xb4, 0xbe, 0x45, 0xde, 0x3d, 0x46, + 0x61, 0x0f, 0x11, 0xe2, 0x2c, 0xf5, 0xb0, 0x63, 0xa0, 0x84, + 0xc0, 0xaf, 0x4e, 0xbe, 0x6a, 0xd3, 0x84, 0x3f, 0xec, 0x42, + 0x17, 0xe9, 0x25, 0xe1, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x40, 0x62, 0x7d, 0x93, 0x1f, 0xdd, 0x17, 0xec, 0x24, 0x42, + 0x37, 0xc8, 0xce, 0x0a, 0xa7, 0x88, 0x49, 0x5c, 0x9b, 0x9b, + 0xa4, 0x5d, 0x93, 0x3b, 0xea, 0x62, 0x3c, 0xb6, 0xd5, 0x07, + 0x19, 0xd7, 0x79, 0xf0, 0x3b, 0xab, 0xa3, 0xa5, 0x43, 0x35, + 0x8d, 0x58, 0x40, 0xa0, 0x95, 0xc5, 0x63, 0x28, 0x28, 0xda, + 0x13, 0x28, 0xdf, 0xc9, 0x05, 0xdc, 0x69, 0x46, 0xff, 0x2a, + 0xfb, 0xe4, 0xd1, 0x23, 0xa5, 0x02, 0x21, 0x00, 0xfc, 0xef, + 0x3b, 0x9d, 0x9d, 0x69, 0xf3, 0x66, 0x0a, 0x2b, 0x52, 0xd6, + 0x61, 0x14, 0x90, 0x6e, 0x7d, 0x3c, 0x08, 0x4b, 0x98, 0x44, + 0x00, 0xf2, 0xa4, 0x16, 0x2d, 0xd1, 0xf9, 0xa0, 0x1e, 0x37, + 0x02, 0x21, 0x00, 0xfc, 0x44, 0xcc, 0x7c, 0xc0, 0x26, 0x9a, + 0x0a, 0x6e, 0xda, 0x17, 0x05, 0x7d, 0x66, 0x8d, 0x29, 0x1a, + 0x44, 0xbf, 0x33, 0x76, 0xae, 0x8d, 0xe8, 0xb5, 0xed, 0xb8, + 0x6f, 0xdc, 0xfe, 0x10, 0xa7, 0x02, 0x20, 0x76, 0x48, 0x8a, + 0x60, 0x93, 0x14, 0xd1, 0x36, 0x8e, 0xda, 0xe3, 0xca, 0x4d, + 0x6c, 0x08, 0x7f, 0x23, 0x21, 0xc7, 0xdf, 0x52, 0x3d, 0xbb, + 0x13, 0xbd, 0x98, 0x81, 0xa5, 0x08, 0x4f, 0xd0, 0xd1, 0x02, + 0x21, 0x00, 0xd9, 0xa3, 0x11, 0x37, 0xdf, 0x1e, 0x6e, 0x6e, + 0xe9, 0xcb, 0xc5, 0x68, 0xbb, 0x13, 0x2a, 0x5d, 0x77, 0x88, + 0x2f, 0xdc, 0x5a, 0x5b, 0xa5, 0x9a, 0x4a, 0xba, 0x58, 0x10, + 0x49, 0xfb, 0xf6, 0xa9, 0x02, 0x21, 0x00, 0x89, 0xe8, 0x47, + 0x5b, 0x20, 0x04, 0x3b, 0x0f, 0xb9, 0xe0, 0x1d, 0xab, 0xcf, + 0xe8, 0x72, 0xfd, 0x7d, 0x17, 0x85, 0xc8, 0xd8, 0xbd, 0x1a, + 0x92, 0xe0, 0xbc, 0x7a, 0xc7, 0x31, 0xbe, 0xef, 0xf4 ), + PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, + 0x30, 0x48, 0x02, 0x41, 0x00, 0xf9, 0x3f, 0x78, 0x44, 0xe2, + 0x0e, 0x25, 0xf1, 0x0e, 0x94, 0xcd, 0xca, 0x6f, 0x9e, 0xea, + 0x6d, 0xdf, 0xcd, 0xa0, 0x7c, 0xe2, 0x21, 0xeb, 0xde, 0xa6, + 0x01, 0x4b, 0xb0, 0x76, 0x4b, 0xd8, 0x8b, 0x19, 0x83, 0xb4, + 0xbe, 0x45, 0xde, 0x3d, 0x46, 0x61, 0x0f, 0x11, 0xe2, 0x2c, + 0xf5, 0xb0, 0x63, 0xa0, 0x84, 0xc0, 0xaf, 0x4e, 0xbe, 0x6a, + 0xd3, 0x84, 0x3f, 0xec, 0x42, 0x17, 0xe9, 0x25, 0xe1, 0x02, + 0x03, 0x01, 0x00, 0x01 ), + PLAINTEXT ( 0x9d, 0x5b, 0x46, 0x42, 0x27, 0xc0, 0xf1, 0x4b, 0xe5, 0x9e, + 0xd3, 0x10, 0xa1, 0xeb, 0x16, 0xc3, 0xc6, 0x8f, 0x1a, 0x18, + 0x86, 0xc3, 0x92, 0x15, 0x2d, 0x65, 0xa0, 0x40, 0xe1, 0x3e, + 0x29, 0x79, 0x7c, 0xd4, 0x08, 0xef, 0x53, 0xeb, 0x08, 0x07, + 0x39, 0x21, 0xb3, 0x40, 0xff, 0x4b, 0xc7, 0x76, 0xb9, 0x12, + 0x32, 0x41, 0xcc, 0x5a, 0x86, 0x5c, 0x2e, 0x0b, 0x05, 0xd8, + 0x56, 0xd4, 0xdf, 0x6f, 0x2c, 0xf0, 0xbf, 0x4b, 0x6f, 0x68, + 0xde, 0x39, 0x4a, 0x3e, 0xae, 0x44, 0xb9, 0xc6, 0x24, 0xb3, + 0x83, 0x2e, 0x9f, 0xf5, 0x6d, 0x61, 0xc3, 0x8e, 0xe8, 0x8f, + 0xa6, 0x87, 0x58, 0x3f, 0x36, 0x13, 0xf4, 0x7e, 0xf0, 0x20, + 0x47, 0x87, 0x3f, 0x21, 0x6e, 0x51, 0x3c, 0xf1, 0xef, 0xca, + 0x9f, 0x77, 0x9c, 0x91, 0x4f, 0xd4, 0x56, 0xc0, 0x39, 0x11, + 0xab, 0x15, 0x2c, 0x5e, 0xad, 0x40, 0x09, 0xe6, 0xde, 0xe5, + 0x77, 0x60, 0x19, 0xd4, 0x0d, 0x77, 0x76, 0x24, 0x8b, 0xe6, + 0xdd, 0xa5, 0x8d, 0x4a, 0x55, 0x3a, 0xdf, 0xf8, 0x29, 0xfb, + 0x47, 0x8a, 0xfe, 0x98, 0x34, 0xf6, 0x30, 0x7f, 0x09, 0x03, + 0x26, 0x05, 0xd5, 0x46, 0x18, 0x96, 0xca, 0x96, 0x5b, 0x66, + 0xf2, 0x8d, 0xfc, 0xfc, 0x37, 0xf7, 0xc7, 0x6d, 0x6c, 0xd8, + 0x24, 0x0c, 0x6a, 0xec, 0x82, 0x5c, 0x72, 0xf1, 0xfc, 0x05, + 0xed, 0x8e, 0xe8, 0xd9, 0x8b, 0x8b, 0x67, 0x02, 0x95 ), + &md5_algorithm, + SIGNATURE ( 0xdb, 0x56, 0x3d, 0xea, 0xae, 0x81, 0x4b, 0x3b, 0x2e, 0x8e, + 0xb8, 0xee, 0x13, 0x61, 0xc6, 0xe7, 0xd7, 0x50, 0xcd, 0x0d, + 0x34, 0x3a, 0xfe, 0x9a, 0x8d, 0xf8, 0xfb, 0xd6, 0x7e, 0xbd, + 0xdd, 0xb3, 0xf9, 0xfb, 0xe0, 0xf8, 0xe7, 0x71, 0x03, 0xe6, + 0x55, 0xd5, 0xf4, 0x02, 0x3c, 0xb5, 0xbc, 0x95, 0x2b, 0x66, + 0x56, 0xec, 0x2f, 0x8e, 0xa7, 0xae, 0xd9, 0x80, 0xb3, 0xaa, + 0xac, 0x45, 0x00, 0xa8 ) ); + +/** Random message SHA-1 signature test */ +RSA_SIGNATURE_TEST ( sha1_test, + PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, + 0xe0, 0x3a, 0x8d, 0x35, 0xe1, 0x92, 0x2f, 0xea, 0x0d, 0x82, + 0x60, 0x2e, 0xb6, 0x0b, 0x02, 0xd3, 0xf4, 0x39, 0xfb, 0x06, + 0x43, 0x8e, 0xa1, 0x7c, 0xc5, 0xae, 0x0d, 0xc7, 0xee, 0x83, + 0xb3, 0x63, 0x20, 0x92, 0x34, 0xe2, 0x94, 0x3d, 0xdd, 0xbb, + 0x6c, 0x64, 0x69, 0x68, 0x25, 0x24, 0x81, 0x4b, 0x4d, 0x48, + 0x5a, 0xd2, 0x29, 0x14, 0xeb, 0x38, 0xdd, 0x3e, 0xb5, 0x57, + 0x45, 0x9b, 0xed, 0x33, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x40, 0x3d, 0xa9, 0x1c, 0x47, 0xe2, 0xdd, 0xf6, 0x7b, 0x20, + 0x77, 0xe7, 0xc7, 0x30, 0x9c, 0x5a, 0x8c, 0xba, 0xae, 0x6f, + 0x0f, 0x4b, 0xe8, 0x9f, 0x13, 0xd6, 0xb0, 0x84, 0x6d, 0xa4, + 0x73, 0x67, 0x12, 0xa9, 0x7c, 0x75, 0xaf, 0x62, 0x92, 0x7b, + 0x80, 0xaf, 0x39, 0x7d, 0x01, 0xb3, 0x43, 0xc8, 0x0d, 0x17, + 0x7f, 0x82, 0x59, 0x46, 0xb8, 0xe5, 0x4e, 0xba, 0x5e, 0x71, + 0x5c, 0xba, 0x62, 0x06, 0x91, 0x02, 0x21, 0x00, 0xf7, 0xaa, + 0xb6, 0x9c, 0xc8, 0xad, 0x68, 0xa8, 0xd7, 0x25, 0xb1, 0xb5, + 0x91, 0xd4, 0xc7, 0xd6, 0x69, 0x51, 0x5d, 0x04, 0xed, 0xd8, + 0xc6, 0xea, 0x69, 0xd2, 0x24, 0xbe, 0x5e, 0x7c, 0x89, 0xa5, + 0x02, 0x21, 0x00, 0xe7, 0xc5, 0xf4, 0x01, 0x35, 0xe0, 0x16, + 0xb5, 0x13, 0x86, 0x14, 0x5a, 0x6a, 0x8d, 0x03, 0x90, 0xae, + 0x7d, 0x3a, 0xc1, 0xfe, 0x8c, 0xa0, 0x4a, 0xb4, 0x94, 0x50, + 0x58, 0xa4, 0xc6, 0x73, 0xf7, 0x02, 0x21, 0x00, 0xe2, 0xda, + 0x16, 0x6c, 0x63, 0x90, 0x1a, 0xc6, 0x54, 0x53, 0x2d, 0x84, + 0x8f, 0x70, 0x24, 0x1f, 0x6b, 0xd6, 0x5f, 0xea, 0x8c, 0xe5, + 0xbb, 0xc5, 0xa9, 0x6a, 0x17, 0xc7, 0xdb, 0x8a, 0x1d, 0x15, + 0x02, 0x21, 0x00, 0xe4, 0x2a, 0x7e, 0xe4, 0x76, 0x2a, 0x2d, + 0x90, 0x83, 0x30, 0xda, 0x76, 0x8c, 0x30, 0x58, 0x13, 0x25, + 0x83, 0x88, 0xc5, 0x93, 0x96, 0xd2, 0xf1, 0xd8, 0x45, 0xad, + 0xb7, 0x26, 0x37, 0x6b, 0xcf, 0x02, 0x20, 0x73, 0x58, 0x1f, + 0x0a, 0xcd, 0x0c, 0x83, 0x27, 0xcc, 0x15, 0xa2, 0x1e, 0x07, + 0x32, 0x1b, 0xa3, 0xc6, 0xa6, 0xb8, 0x83, 0x97, 0x48, 0x45, + 0x50, 0x6c, 0x37, 0x45, 0xa5, 0x54, 0x2a, 0x59, 0x3c ), + PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, + 0x30, 0x48, 0x02, 0x41, 0x00, 0xe0, 0x3a, 0x8d, 0x35, 0xe1, + 0x92, 0x2f, 0xea, 0x0d, 0x82, 0x60, 0x2e, 0xb6, 0x0b, 0x02, + 0xd3, 0xf4, 0x39, 0xfb, 0x06, 0x43, 0x8e, 0xa1, 0x7c, 0xc5, + 0xae, 0x0d, 0xc7, 0xee, 0x83, 0xb3, 0x63, 0x20, 0x92, 0x34, + 0xe2, 0x94, 0x3d, 0xdd, 0xbb, 0x6c, 0x64, 0x69, 0x68, 0x25, + 0x24, 0x81, 0x4b, 0x4d, 0x48, 0x5a, 0xd2, 0x29, 0x14, 0xeb, + 0x38, 0xdd, 0x3e, 0xb5, 0x57, 0x45, 0x9b, 0xed, 0x33, 0x02, + 0x03, 0x01, 0x00, 0x01 ), + PLAINTEXT ( 0xf7, 0x42, 0x01, 0x57, 0x6b, 0x70, 0xcc, 0x4a, 0xdc, 0xed, + 0x12, 0x83, 0x3f, 0xef, 0x27, 0xc1, 0x3c, 0x85, 0xdd, 0x5e, + 0x0a, 0x34, 0x98, 0xf9, 0x21, 0xd3, 0x24, 0x2a, 0x5a, 0xb2, + 0xdf, 0x60, 0x21, 0x28, 0x7c, 0x5b, 0x7a, 0xbe, 0xcb, 0xea, + 0xbc, 0xd6, 0x0e, 0xae, 0x94, 0x64, 0x21, 0xda, 0x28, 0x66, + 0x2f, 0x71, 0x48, 0xe5, 0xea, 0x59, 0x38, 0x28, 0x3e, 0xed, + 0x3b, 0x95, 0x4f, 0x3d, 0x72, 0x2a, 0x00, 0xf3, 0x95, 0x4d, + 0xf0, 0x02, 0x71, 0x63, 0x5a, 0xbc, 0x84, 0xd1, 0x81, 0x3f, + 0x16, 0xcd, 0x28, 0x3d, 0x47, 0xa2, 0xee, 0xa1, 0x2f, 0x84, + 0x8a, 0x22, 0x02, 0x88, 0xd7, 0x83, 0x06, 0x4a, 0x9f, 0xea, + 0x0f, 0x15, 0x48, 0x43, 0x58, 0x6d, 0x39, 0x78, 0x5a, 0x43, + 0x3f, 0xed, 0x6f, 0x68, 0xde, 0x9c, 0xfe, 0xd3, 0x67, 0x74, + 0x08, 0x46, 0x7d, 0x20, 0x22, 0x60, 0x8c, 0x37, 0x35, 0x46, + 0x56, 0x19, 0x3c, 0xfa, 0xa5, 0x40, 0xac, 0x44, 0x90, 0x8a, + 0xa5, 0x80, 0xb2, 0x32, 0xbc, 0xb4, 0x3f, 0x3e, 0x5e, 0xd4, + 0x51, 0xa9, 0x2e, 0xd9, 0x7f, 0x5e, 0x32, 0xb1, 0x24, 0x35, + 0x88, 0x71, 0x3a, 0x01, 0x86, 0x5c, 0xa2, 0xe2, 0x2d, 0x02, + 0x30, 0x91, 0x1c, 0xaa, 0x6c, 0x24, 0x42, 0x1b, 0x1a, 0xba, + 0x30, 0x40, 0x49, 0x83, 0xd9, 0xd7, 0x66, 0x7e, 0x5c, 0x1a, + 0x4b, 0x7f, 0xa6, 0x8e, 0x8a, 0xd6, 0x0c, 0x65, 0x75 ), + &sha1_algorithm, + SIGNATURE ( 0xa5, 0x5a, 0x8a, 0x67, 0x81, 0x76, 0x7e, 0xad, 0x99, 0x22, + 0xf1, 0x47, 0x64, 0xd2, 0xfb, 0x81, 0x45, 0xeb, 0x85, 0x56, + 0xf8, 0x7d, 0xb8, 0xec, 0x41, 0x17, 0x84, 0xf7, 0x2b, 0xbb, + 0x2b, 0x8f, 0xb6, 0xb8, 0x8f, 0xc6, 0xab, 0x39, 0xbc, 0xa3, + 0x72, 0xb3, 0x63, 0x45, 0x5a, 0xe0, 0xac, 0xf8, 0x1c, 0x83, + 0x48, 0x84, 0x89, 0x8a, 0x6b, 0xdf, 0x93, 0xa0, 0xc3, 0x0b, + 0x0e, 0x3d, 0x80, 0x80 ) ); + +/** Random message SHA-256 signature test */ +RSA_SIGNATURE_TEST ( sha256_test, + PRIVATE ( 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, + 0xa5, 0xe9, 0xdb, 0xa9, 0x1a, 0x6e, 0xd6, 0x4c, 0x25, 0x50, + 0xfe, 0x61, 0x77, 0x08, 0x7a, 0x80, 0x36, 0xcb, 0x88, 0x49, + 0x5c, 0xe8, 0xaa, 0x15, 0xf8, 0xb3, 0xd6, 0x78, 0x51, 0x46, + 0x86, 0x3a, 0x5f, 0xd5, 0x9f, 0xab, 0xfe, 0x74, 0x8c, 0x53, + 0x0d, 0xb5, 0x3c, 0x7d, 0x2c, 0x35, 0x88, 0x3f, 0xde, 0xa2, + 0xce, 0x46, 0x94, 0x30, 0xa9, 0x76, 0xee, 0x25, 0xc5, 0x5d, + 0xa6, 0xa6, 0x3a, 0xa5, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x40, 0x14, 0x4b, 0xbc, 0x4c, 0x3e, 0x68, 0x8a, 0x9c, 0x7c, + 0x00, 0x21, 0x6e, 0x28, 0xd2, 0x87, 0xb1, 0xc1, 0x82, 0x3a, + 0x64, 0xc7, 0x11, 0xcb, 0x24, 0xae, 0xec, 0xc8, 0xf2, 0xa4, + 0xf6, 0x9c, 0x9a, 0xbb, 0x05, 0x94, 0x80, 0x9b, 0xc1, 0x21, + 0x83, 0x36, 0x23, 0xba, 0x04, 0x20, 0x23, 0x06, 0x48, 0xa7, + 0xa4, 0xe6, 0x31, 0x8e, 0xa1, 0x73, 0xe5, 0x6b, 0x83, 0x4c, + 0x3a, 0xb8, 0xd8, 0x22, 0x61, 0x02, 0x21, 0x00, 0xd4, 0xdf, + 0xcb, 0x21, 0x4a, 0x9a, 0x35, 0x52, 0x02, 0x99, 0xcc, 0x40, + 0x83, 0x65, 0x30, 0x1f, 0x9d, 0x13, 0xd6, 0xd1, 0x79, 0x10, + 0xce, 0x5b, 0xeb, 0x25, 0xa2, 0x39, 0x4e, 0xdf, 0x1c, 0x29, + 0x02, 0x21, 0x00, 0xc7, 0x86, 0x8f, 0xd9, 0x88, 0xe9, 0x98, + 0x4b, 0x5c, 0x50, 0x06, 0x94, 0x05, 0x59, 0x31, 0x25, 0xa7, + 0xa8, 0xe6, 0x95, 0x2b, 0xe3, 0x74, 0x93, 0x51, 0xa8, 0x8e, + 0x3d, 0xe2, 0xe0, 0xfa, 0x1d, 0x02, 0x20, 0x6e, 0xe3, 0x81, + 0x31, 0xff, 0x65, 0xa3, 0x1e, 0xec, 0x61, 0xe7, 0x67, 0x37, + 0xcb, 0x0f, 0x2d, 0x78, 0xaa, 0xab, 0xfd, 0x84, 0x5e, 0x3f, + 0xd0, 0xdc, 0x06, 0x47, 0xa2, 0x28, 0xb6, 0xca, 0x39, 0x02, + 0x20, 0x13, 0x7d, 0x9f, 0x9b, 0xbe, 0x76, 0x23, 0x3c, 0x69, + 0x5e, 0x1f, 0xe6, 0x61, 0xc7, 0x5e, 0xb7, 0xb0, 0xf3, 0x1c, + 0xe3, 0x41, 0x90, 0x4c, 0x98, 0xff, 0x87, 0x19, 0xae, 0x0d, + 0xf5, 0xb0, 0x39, 0x02, 0x21, 0x00, 0xb7, 0xeb, 0xcd, 0x01, + 0x2e, 0x23, 0x42, 0x4f, 0x0c, 0x6f, 0xde, 0xc8, 0x4f, 0xa7, + 0x69, 0x09, 0x12, 0x34, 0xb6, 0x95, 0x4d, 0xb8, 0x7f, 0x16, + 0xd0, 0x48, 0x17, 0x4a, 0x9e, 0x6e, 0x5e, 0xe2 ), + PUBLIC ( 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, + 0x30, 0x48, 0x02, 0x41, 0x00, 0xa5, 0xe9, 0xdb, 0xa9, 0x1a, + 0x6e, 0xd6, 0x4c, 0x25, 0x50, 0xfe, 0x61, 0x77, 0x08, 0x7a, + 0x80, 0x36, 0xcb, 0x88, 0x49, 0x5c, 0xe8, 0xaa, 0x15, 0xf8, + 0xb3, 0xd6, 0x78, 0x51, 0x46, 0x86, 0x3a, 0x5f, 0xd5, 0x9f, + 0xab, 0xfe, 0x74, 0x8c, 0x53, 0x0d, 0xb5, 0x3c, 0x7d, 0x2c, + 0x35, 0x88, 0x3f, 0xde, 0xa2, 0xce, 0x46, 0x94, 0x30, 0xa9, + 0x76, 0xee, 0x25, 0xc5, 0x5d, 0xa6, 0xa6, 0x3a, 0xa5, 0x02, + 0x03, 0x01, 0x00, 0x01 ), + PLAINTEXT ( 0x60, 0xe7, 0xba, 0x9d, 0x5a, 0xe3, 0x2d, 0xfa, 0x5f, 0x47, + 0xdb, 0x93, 0x24, 0x2c, 0xc4, 0xe2, 0x61, 0xf3, 0x89, 0x4d, + 0x67, 0xad, 0xc8, 0xae, 0xf8, 0xe2, 0xfb, 0x52, 0x0f, 0x8d, + 0x18, 0x7e, 0x30, 0xd8, 0x8d, 0x94, 0x07, 0x92, 0x70, 0x91, + 0xaf, 0x3b, 0x92, 0xa6, 0x0f, 0x7a, 0x9b, 0x46, 0x85, 0x8c, + 0x2a, 0x5a, 0x78, 0x5d, 0x1e, 0x13, 0xbf, 0xe6, 0x12, 0xbd, + 0xb1, 0xbb, 0x92, 0x6d, 0x11, 0xed, 0xe1, 0xe4, 0x6e, 0x88, + 0x4d, 0x0b, 0x51, 0xd6, 0xfd, 0x6a, 0xb2, 0x9b, 0xd3, 0xfd, + 0x56, 0xec, 0xd9, 0xd6, 0xb8, 0xc5, 0xfd, 0x0c, 0xf7, 0x55, + 0x5f, 0xc5, 0x6f, 0xbc, 0xbb, 0x78, 0x2f, 0x50, 0x08, 0x65, + 0x0f, 0x12, 0xca, 0x5a, 0xea, 0x52, 0xd0, 0x94, 0x76, 0x17, + 0xe4, 0xba, 0x97, 0xba, 0x11, 0xbf, 0x05, 0x7e, 0xa1, 0xfd, + 0x7d, 0xb5, 0xf1, 0x3a, 0x7e, 0x6f, 0xa1, 0xaa, 0x97, 0x66, + 0x5d, 0x72, 0x76, 0x45, 0x40, 0xb5, 0x22, 0x71, 0x43, 0xe8, + 0x77, 0x76, 0xc8, 0x1b, 0xd2, 0xd1, 0x33, 0x05, 0x64, 0xa9, + 0xc2, 0xa8, 0x40, 0x40, 0x21, 0xdd, 0xcf, 0x07, 0x7e, 0xf2, + 0x4b, 0x80, 0x3d, 0x0f, 0x67, 0xf6, 0xbd, 0xc2, 0xc7, 0xe3, + 0x91, 0x71, 0xd6, 0x2d, 0xa1, 0xae, 0x81, 0x0c, 0xed, 0x54, + 0x48, 0x79, 0x8a, 0x78, 0x05, 0x74, 0x4d, 0x4f, 0xf0, 0xe0, + 0x3c, 0x41, 0x5c, 0x04, 0x0b, 0x68, 0x57, 0xc5, 0xd6 ), + &sha256_algorithm, + SIGNATURE ( 0x02, 0x2e, 0xc5, 0x2a, 0x2b, 0x7f, 0xb4, 0x80, 0xca, 0x9d, + 0x96, 0x5b, 0xaf, 0x1f, 0x72, 0x5b, 0x6e, 0xf1, 0x69, 0x7f, + 0x4d, 0x41, 0xd5, 0x9f, 0x00, 0xdc, 0x47, 0xf4, 0x68, 0x8f, + 0xda, 0xfc, 0xd1, 0x23, 0x96, 0x11, 0x1d, 0xc0, 0x1b, 0x1d, + 0x36, 0x66, 0x2a, 0xf9, 0x21, 0x51, 0xcb, 0xb9, 0x7d, 0x24, + 0x7d, 0x38, 0x37, 0xc4, 0xea, 0xdd, 0x3a, 0x6f, 0xa8, 0x65, + 0x60, 0x73, 0x77, 0x3c ) ); + +/** + * Perform RSA self-tests + * + */ +static void rsa_test_exec ( void ) { + + rsa_encrypt_decrypt_ok ( &hw_test ); + rsa_signature_ok ( &md5_test ); + rsa_signature_ok ( &sha1_test ); + rsa_signature_ok ( &sha256_test ); +} + +/** RSA self-test */ +struct self_test rsa_test __self_test = { + .name = "rsa", + .exec = rsa_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 278addee..cccb29a9 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -34,3 +34,4 @@ REQUIRE_OBJECT ( aes_cbc_test ); REQUIRE_OBJECT ( hmac_drbg_test ); REQUIRE_OBJECT ( hash_df_test ); REQUIRE_OBJECT ( bigint_test ); +REQUIRE_OBJECT ( rsa_test ); From dc87161c300e01fa5a6cca11af7fad22ea6cded9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 14:44:53 +0000 Subject: [PATCH 081/221] [tls] Use iPXE native RSA algorithm Signed-off-by: Michael Brown --- src/crypto/x509.c | 156 ++++------------------------------------ src/include/ipxe/tls.h | 3 - src/include/ipxe/x509.h | 23 +----- src/net/tls.c | 88 +++++++++++++---------- 4 files changed, 68 insertions(+), 202 deletions(-) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index c09c5ebd..a13b671a 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -33,161 +33,33 @@ FILE_LICENCE ( GPL2_OR_LATER ); * documented in RFC2313. */ -/** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */ -static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01 }; - /** - * Identify X.509 certificate public key + * Identify X.509 certificate RSA public key * * @v certificate Certificate - * @v algorithm Public key algorithm to fill in - * @v pubkey Public key value to fill in + * @v rsa RSA public key to fill in * @ret rc Return status code */ -static int x509_public_key ( const struct asn1_cursor *certificate, - struct asn1_cursor *algorithm, - struct asn1_cursor *pubkey ) { - struct asn1_cursor cursor; +int x509_rsa_public_key ( const struct asn1_cursor *certificate, + struct x509_rsa_public_key *key ) { + struct asn1_cursor *cursor = &key->raw; int rc; /* Locate subjectPublicKeyInfo */ - memcpy ( &cursor, certificate, sizeof ( cursor ) ); - rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */ - asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */ - asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/ - asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */ - asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */ - asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */ - asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */ - asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */ - asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/); + memcpy ( cursor, certificate, sizeof ( *cursor ) ); + rc = ( asn1_enter ( cursor, ASN1_SEQUENCE ), /* Certificate */ + asn1_enter ( cursor, ASN1_SEQUENCE ), /* tbsCertificate */ + asn1_skip_if_exists ( cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/ + asn1_skip ( cursor, ASN1_INTEGER ), /* serialNumber */ + asn1_skip ( cursor, ASN1_SEQUENCE ), /* signature */ + asn1_skip ( cursor, ASN1_SEQUENCE ), /* issuer */ + asn1_skip ( cursor, ASN1_SEQUENCE ), /* validity */ + asn1_skip ( cursor, ASN1_SEQUENCE ) /* name */ ); if ( rc != 0 ) { DBG ( "Cannot locate subjectPublicKeyInfo in:\n" ); DBG_HDA ( 0, certificate->data, certificate->len ); return rc; } - /* Locate algorithm */ - memcpy ( algorithm, &cursor, sizeof ( *algorithm ) ); - rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ ); - if ( rc != 0 ) { - DBG ( "Cannot locate algorithm in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return rc; - } - - /* Locate subjectPublicKey */ - memcpy ( pubkey, &cursor, sizeof ( *pubkey ) ); - rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */ - asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ ); - if ( rc != 0 ) { - DBG ( "Cannot locate subjectPublicKey in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return rc; - } - - return 0; -} - -/** - * Identify X.509 certificate RSA modulus and public exponent - * - * @v certificate Certificate - * @v rsa RSA public key to fill in - * @ret rc Return status code - * - * The caller is responsible for eventually calling - * x509_free_rsa_public_key() to free the storage allocated to hold - * the RSA modulus and exponent. - */ -int x509_rsa_public_key ( const struct asn1_cursor *certificate, - struct x509_rsa_public_key *rsa_pubkey ) { - struct asn1_cursor algorithm; - struct asn1_cursor pubkey; - struct asn1_cursor modulus; - struct asn1_cursor exponent; - int rc; - - /* First, extract the public key algorithm and key data */ - if ( ( rc = x509_public_key ( certificate, &algorithm, - &pubkey ) ) != 0 ) - return rc; - - /* Check that algorithm is RSA */ - rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ ); - if ( rc != 0 ) { - DBG ( "Cannot locate algorithm:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return rc; - } - if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) || - ( memcmp ( algorithm.data, &oid_rsa_encryption, - sizeof ( oid_rsa_encryption ) ) != 0 ) ) { - DBG ( "algorithm is not rsaEncryption in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return -ENOTSUP; - } - - /* Check that public key is a byte string, i.e. that the - * "unused bits" byte contains zero. - */ - if ( ( pubkey.len < 1 ) || - ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) { - DBG ( "subjectPublicKey is not a byte string in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return -ENOTSUP; - } - pubkey.data++; - pubkey.len--; - - /* Pick out the modulus and exponent */ - rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ ); - if ( rc != 0 ) { - DBG ( "Cannot locate RSAPublicKey in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return -ENOTSUP; - } - memcpy ( &modulus, &pubkey, sizeof ( modulus ) ); - rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ ); - if ( rc != 0 ) { - DBG ( "Cannot locate modulus in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return -ENOTSUP; - } - if ( modulus.len && ( ! *( ( uint8_t * ) modulus.data ) ) ) { - /* Skip positive sign byte */ - modulus.data++; - modulus.len--; - } - memcpy ( &exponent, &pubkey, sizeof ( exponent ) ); - rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */ - asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ ); - if ( rc != 0 ) { - DBG ( "Cannot locate publicExponent in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); - return -ENOTSUP; - } - if ( exponent.len && ( ! *( ( uint8_t * ) exponent.data ) ) ) { - /* Skip positive sign byte */ - exponent.data++; - exponent.len--; - } - - /* Allocate space and copy out modulus and exponent */ - rsa_pubkey->modulus = malloc ( modulus.len + exponent.len ); - if ( ! rsa_pubkey->modulus ) - return -ENOMEM; - rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len ); - memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len ); - rsa_pubkey->modulus_len = modulus.len; - memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len ); - rsa_pubkey->exponent_len = exponent.len; - - DBG2 ( "RSA modulus:\n" ); - DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len ); - DBG2 ( "RSA exponent:\n" ); - DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len ); - return 0; } diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 804e1a1f..a2504f19 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -182,9 +182,6 @@ struct tls_session { /** SHA256 context for handshake verification */ uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE]; - /** Hack: server RSA public key */ - struct x509_rsa_public_key rsa; - /** TX sequence number */ uint64_t tx_seq; /** TX pending transmissions */ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 2ea21aa9..f8cffabd 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -11,31 +11,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include - -struct asn1_cursor; +#include /** An X.509 RSA public key */ struct x509_rsa_public_key { - /** Modulus */ - uint8_t *modulus; - /** Modulus length */ - size_t modulus_len; - /** Exponent */ - uint8_t *exponent; - /** Exponent length */ - size_t exponent_len; + /** Raw public key */ + struct asn1_cursor raw; }; -/** - * Free X.509 RSA public key - * - * @v rsa_pubkey RSA public key - */ -static inline void -x509_free_rsa_public_key ( struct x509_rsa_public_key *rsa_pubkey ) { - free ( rsa_pubkey->modulus ); -} - extern int x509_rsa_public_key ( const struct asn1_cursor *certificate, struct x509_rsa_public_key *rsa_pubkey ); diff --git a/src/net/tls.c b/src/net/tls.c index dfd19a0a..7ec5745f 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -39,7 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include #include #include #include @@ -90,7 +89,6 @@ static void free_tls ( struct refcnt *refcnt ) { tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); tls_clear_cipher ( tls, &tls->rx_cipherspec ); tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); - x509_free_rsa_public_key ( &tls->rsa ); free ( tls->rx_data ); /* Free TLS structure itself */ @@ -437,28 +435,28 @@ struct tls_cipher_suite tls_cipher_suites[] = { { .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ), .key_len = ( 256 / 8 ), - .pubkey = &pubkey_null, /* FIXME */ + .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha256_algorithm, }, { .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ), .key_len = ( 128 / 8 ), - .pubkey = &pubkey_null, /* FIXME */ + .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha256_algorithm, }, { .code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ), .key_len = ( 256 / 8 ), - .pubkey = &pubkey_null, /* FIXME */ + .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha1_algorithm, }, { .code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ), .key_len = ( 128 / 8 ), - .pubkey = &pubkey_null, /* FIXME */ + .pubkey = &rsa_algorithm, .cipher = &aes_cbc_algorithm, .digest = &sha1_algorithm, }, @@ -496,6 +494,11 @@ tls_find_cipher_suite ( unsigned int cipher_suite ) { */ static void tls_clear_cipher ( struct tls_session *tls __unused, struct tls_cipherspec *cipherspec ) { + + if ( cipherspec->suite ) { + pubkey_final ( cipherspec->suite->pubkey, + cipherspec->pubkey_ctx ); + } free ( cipherspec->dynamic ); memset ( cipherspec, 0, sizeof ( cipherspec ) ); cipherspec->suite = &tls_cipher_suite_null; @@ -523,13 +526,12 @@ static int tls_set_cipher ( struct tls_session *tls, /* Allocate dynamic storage */ total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize ); - dynamic = malloc ( total ); + dynamic = zalloc ( total ); if ( ! dynamic ) { DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto " "context\n", tls, total ); return -ENOMEM; } - memset ( dynamic, 0, total ); /* Assign storage */ cipherspec->dynamic = dynamic; @@ -793,37 +795,38 @@ static int tls_send_certificate ( struct tls_session *tls ) { * @ret rc Return status code */ static int tls_send_client_key_exchange ( struct tls_session *tls ) { - /* FIXME: Hack alert */ - RSA_CTX *rsa_ctx = NULL; - RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len, - tls->rsa.exponent, tls->rsa.exponent_len ); + struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; + struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; + size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx ); struct { uint32_t type_length; uint16_t encrypted_pre_master_secret_len; - uint8_t encrypted_pre_master_secret[rsa_ctx->num_octets]; + uint8_t encrypted_pre_master_secret[max_len]; } __attribute__ (( packed )) key_xchg; + size_t unused; + int len; + int rc; + /* Encrypt pre-master secret using server's public key */ memset ( &key_xchg, 0, sizeof ( key_xchg ) ); - key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) | - htonl ( sizeof ( key_xchg ) - - sizeof ( key_xchg.type_length ) ) ); - key_xchg.encrypted_pre_master_secret_len - = htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) ); - - /* FIXME: Hack alert */ - DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" ); - DBGC_HD ( tls, &tls->pre_master_secret, - sizeof ( tls->pre_master_secret ) ); - DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len ); - DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len ); - RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret, - sizeof ( tls->pre_master_secret ), - key_xchg.encrypted_pre_master_secret, 0 ); - DBGC ( tls, "RSA encrypt done. Ciphertext:\n" ); - DBGC_HD ( tls, &key_xchg.encrypted_pre_master_secret, - sizeof ( key_xchg.encrypted_pre_master_secret ) ); - RSA_free ( rsa_ctx ); - + len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx, + &tls->pre_master_secret, + sizeof ( tls->pre_master_secret ), + key_xchg.encrypted_pre_master_secret ); + if ( len < 0 ) { + rc = len; + DBGC ( tls, "TLS %p could not encrypt pre-master secret: %s\n", + tls, strerror ( rc ) ); + return rc; + } + unused = ( max_len - len ); + key_xchg.type_length = + ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) | + htonl ( sizeof ( key_xchg ) - + sizeof ( key_xchg.type_length ) - unused ) ); + key_xchg.encrypted_pre_master_secret_len = + htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) - + unused ); return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) ); } @@ -1021,7 +1024,10 @@ static int tls_new_certificate ( struct tls_session *tls, ( ( void * ) certificate->certificates ); size_t elements_len = tls_uint24 ( certificate->length ); const void *end = ( certificate->certificates + elements_len ); + struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; + struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; struct asn1_cursor cursor; + struct x509_rsa_public_key key; int rc; /* Sanity check */ @@ -1044,12 +1050,20 @@ static int tls_new_certificate ( struct tls_session *tls, } // HACK - if ( ( rc = x509_rsa_public_key ( &cursor, - &tls->rsa ) ) != 0 ) { - DBGC ( tls, "TLS %p cannot determine RSA public key: " - "%s\n", tls, strerror ( rc ) ); + if ( ( rc = x509_rsa_public_key ( &cursor, &key ) ) != 0 ) { + DBGC ( tls, "TLS %p cannot parse public key: %s\n", + tls, strerror ( rc ) ); return rc; } + + /* Initialise public key algorithm */ + if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx, + key.raw.data, key.raw.len ) ) != 0){ + DBGC ( tls, "TLS %p cannot initialise public key: %s\n", + tls, strerror ( rc ) ); + return rc; + } + return 0; element = ( cursor.data + cursor.len ); From 66f200bdacc80cacc46c59ed0f49b3ddf0e357f1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 13 Mar 2012 16:49:42 +0000 Subject: [PATCH 082/221] [crypto] Remove obsolete AXTLS RSA algorithm Signed-off-by: Michael Brown --- src/crypto/axtls/axtls_bigint.c | 1513 ------------------------------- src/crypto/axtls/axtls_rsa.c | 269 ------ 2 files changed, 1782 deletions(-) delete mode 100644 src/crypto/axtls/axtls_bigint.c delete mode 100644 src/crypto/axtls/axtls_rsa.c diff --git a/src/crypto/axtls/axtls_bigint.c b/src/crypto/axtls/axtls_bigint.c deleted file mode 100644 index e228a218..00000000 --- a/src/crypto/axtls/axtls_bigint.c +++ /dev/null @@ -1,1513 +0,0 @@ -/* - * Copyright (c) 2007, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of the axTLS project 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 OWNER 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. - */ - -/** - * @defgroup bigint_api Big Integer API - * @brief The bigint implementation as used by the axTLS project. - * - * The bigint library is for RSA encryption/decryption as well as signing. - * This code tries to minimise use of malloc/free by maintaining a small - * cache. A bigint context may maintain state by being made "permanent". - * It be be later released with a bi_depermanent() and bi_free() call. - * - * It supports the following reduction techniques: - * - Classical - * - Barrett - * - Montgomery - * - * It also implements the following: - * - Karatsuba multiplication - * - Squaring - * - Sliding window exponentiation - * - Chinese Remainder Theorem (implemented in rsa.c). - * - * All the algorithms used are pretty standard, and designed for different - * data bus sizes. Negative numbers are not dealt with at all, so a subtraction - * may need to be tested for negativity. - * - * This library steals some ideas from Jef Poskanzer - * - * and GMP . It gets most of its implementation - * detail from "The Handbook of Applied Cryptography" - * - * @{ - */ - -#include -#include -#include -#include -#include -#include "os_port.h" -#include "bigint.h" - -#define V1 v->comps[v->size-1] /**< v1 for division */ -#define V2 v->comps[v->size-2] /**< v2 for division */ -#define U(j) tmp_u->comps[tmp_u->size-j-1] /**< uj for division */ -#define Q(j) quotient->comps[quotient->size-j-1] /**< qj for division */ - -static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); -static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); -static bigint *alloc(BI_CTX *ctx, int size); -static bigint *trim(bigint *bi); -static void more_comps(bigint *bi, int n); -#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ - defined(CONFIG_BIGINT_MONTGOMERY) -static bigint *comp_right_shift(bigint *biR, int num_shifts); -static bigint *comp_left_shift(bigint *biR, int num_shifts); -#endif - -#ifdef CONFIG_BIGINT_CHECK_ON -static void check(const bigint *bi); -#else -#define check(A) /**< disappears in normal production mode */ -#endif - - -/** - * @brief Start a new bigint context. - * @return A bigint context. - */ -BI_CTX *bi_initialize(void) -{ - /* calloc() sets everything to zero */ - BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX)); - - /* the radix */ - ctx->bi_radix = alloc(ctx, 2); - ctx->bi_radix->comps[0] = 0; - ctx->bi_radix->comps[1] = 1; - bi_permanent(ctx->bi_radix); - return ctx; -} - -/** - * @brief Close the bigint context and free any resources. - * - * Free up any used memory - a check is done if all objects were not - * properly freed. - * @param ctx [in] The bigint session context. - */ -void bi_terminate(BI_CTX *ctx) -{ - bi_depermanent(ctx->bi_radix); - bi_free(ctx, ctx->bi_radix); - - if (ctx->active_count != 0) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("bi_terminate: there were %d un-freed bigints\n", - ctx->active_count); -#endif - abort(); - } - - bi_clear_cache(ctx); - free(ctx); -} - -/** - *@brief Clear the memory cache. - */ -void bi_clear_cache(BI_CTX *ctx) -{ - bigint *p, *pn; - - if (ctx->free_list == NULL) - return; - - for (p = ctx->free_list; p != NULL; p = pn) - { - pn = p->next; - free(p->comps); - free(p); - } - - ctx->free_count = 0; - ctx->free_list = NULL; -} - -/** - * @brief Increment the number of references to this object. - * It does not do a full copy. - * @param bi [in] The bigint to copy. - * @return A reference to the same bigint. - */ -bigint *bi_copy(bigint *bi) -{ - check(bi); - if (bi->refs != PERMANENT) - bi->refs++; - return bi; -} - -/** - * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it. - * - * For this object to be freed, bi_depermanent() must be called. - * @param bi [in] The bigint to be made permanent. - */ -void bi_permanent(bigint *bi) -{ - check(bi); - if (bi->refs != 1) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("bi_permanent: refs was not 1\n"); -#endif - abort(); - } - - bi->refs = PERMANENT; -} - -/** - * @brief Take a permanent object and make it eligible for freedom. - * @param bi [in] The bigint to be made back to temporary. - */ -void bi_depermanent(bigint *bi) -{ - check(bi); - if (bi->refs != PERMANENT) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("bi_depermanent: bigint was not permanent\n"); -#endif - abort(); - } - - bi->refs = 1; -} - -/** - * @brief Free a bigint object so it can be used again. - * - * The memory itself it not actually freed, just tagged as being available - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to be freed. - */ -void bi_free(BI_CTX *ctx, bigint *bi) -{ - check(bi); - if (bi->refs == PERMANENT) - { - return; - } - - if (--bi->refs > 0) - { - return; - } - - bi->next = ctx->free_list; - ctx->free_list = bi; - ctx->free_count++; - - if (--ctx->active_count < 0) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("bi_free: active_count went negative " - "- double-freed bigint?\n"); -#endif - abort(); - } -} - -/** - * @brief Convert an (unsigned) integer into a bigint. - * @param ctx [in] The bigint session context. - * @param i [in] The (unsigned) integer to be converted. - * - */ -bigint *int_to_bi(BI_CTX *ctx, comp i) -{ - bigint *biR = alloc(ctx, 1); - biR->comps[0] = i; - return biR; -} - -/** - * @brief Do a full copy of the bigint object. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint object to be copied. - */ -bigint *bi_clone(BI_CTX *ctx, const bigint *bi) -{ - bigint *biR = alloc(ctx, bi->size); - check(bi); - memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE); - return biR; -} - -/** - * @brief Perform an addition operation between two bigints. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return The result of the addition. - */ -bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib) -{ - int n; - comp carry = 0; - comp *pa, *pb; - - check(bia); - check(bib); - - n = max(bia->size, bib->size); - more_comps(bia, n+1); - more_comps(bib, n); - pa = bia->comps; - pb = bib->comps; - - do - { - comp sl, rl, cy1; - sl = *pa + *pb++; - rl = sl + carry; - cy1 = sl < *pa; - carry = cy1 | (rl < sl); - *pa++ = rl; - } while (--n != 0); - - *pa = carry; /* do overflow */ - bi_free(ctx, bib); - return trim(bia); -} - -/** - * @brief Perform a subtraction operation between two bigints. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @param is_negative [out] If defined, indicates that the result was negative. - * is_negative may be null. - * @return The result of the subtraction. The result is always positive. - */ -bigint *bi_subtract(BI_CTX *ctx, - bigint *bia, bigint *bib, int *is_negative) -{ - int n = bia->size; - comp *pa, *pb, carry = 0; - - check(bia); - check(bib); - - more_comps(bib, n); - pa = bia->comps; - pb = bib->comps; - - do - { - comp sl, rl, cy1; - sl = *pa - *pb++; - rl = sl - carry; - cy1 = sl > *pa; - carry = cy1 | (rl > sl); - *pa++ = rl; - } while (--n != 0); - - if (is_negative) /* indicate a negative result */ - { - *is_negative = carry; - } - - bi_free(ctx, trim(bib)); /* put bib back to the way it was */ - return trim(bia); -} - -/** - * Perform a multiply between a bigint an an (unsigned) integer - */ -static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b) -{ - int j = 0, n = bia->size; - bigint *biR = alloc(ctx, n + 1); - comp carry = 0; - comp *r = biR->comps; - comp *a = bia->comps; - - check(bia); - - /* clear things to start with */ - memset(r, 0, ((n+1)*COMP_BYTE_SIZE)); - - do - { - long_comp tmp = *r + (long_comp)a[j]*b + carry; - *r++ = (comp)tmp; /* downsize */ - carry = (comp)(tmp >> COMP_BIT_SIZE); - } while (++j < n); - - *r = carry; - bi_free(ctx, bia); - return trim(biR); -} - -/** - * @brief Does both division and modulo calculations. - * - * Used extensively when doing classical reduction. - * @param ctx [in] The bigint session context. - * @param u [in] A bigint which is the numerator. - * @param v [in] Either the denominator or the modulus depending on the mode. - * @param is_mod [n] Determines if this is a normal division (0) or a reduction - * (1). - * @return The result of the division/reduction. - */ -bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) -{ - int n = v->size, m = u->size-n; - int j = 0, orig_u_size = u->size; - uint8_t mod_offset = ctx->mod_offset; - comp d; - bigint *quotient, *tmp_u; - comp q_dash; - - check(u); - check(v); - - /* if doing reduction and we are < mod, then return mod */ - if (is_mod && bi_compare(v, u) > 0) - { - bi_free(ctx, v); - return u; - } - - quotient = alloc(ctx, m+1); - tmp_u = alloc(ctx, n+1); - v = trim(v); /* make sure we have no leading 0's */ - d = (comp)((long_comp)COMP_RADIX/(V1+1)); - - /* clear things to start with */ - memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE)); - - /* normalise */ - if (d > 1) - { - u = bi_int_multiply(ctx, u, d); - - if (is_mod) - { - v = ctx->bi_normalised_mod[mod_offset]; - } - else - { - v = bi_int_multiply(ctx, v, d); - } - } - - if (orig_u_size == u->size) /* new digit position u0 */ - { - more_comps(u, orig_u_size + 1); - } - - do - { - /* get a temporary short version of u */ - memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE); - - /* calculate q' */ - if (U(0) == V1) - { - q_dash = COMP_RADIX-1; - } - else - { - q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1); - - if (v->size > 1 && V2) - { - /* we are implementing the following: - if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - - q_dash*V1)*COMP_RADIX) + U(2))) ... */ - comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - - (long_comp)q_dash*V1); - if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2)) - { - q_dash--; - } - } - } - - /* multiply and subtract */ - if (q_dash) - { - int is_negative; - tmp_u = bi_subtract(ctx, tmp_u, - bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative); - more_comps(tmp_u, n+1); - - Q(j) = q_dash; - - /* add back */ - if (is_negative) - { - Q(j)--; - tmp_u = bi_add(ctx, tmp_u, bi_copy(v)); - - /* lop off the carry */ - tmp_u->size--; - v->size--; - } - } - else - { - Q(j) = 0; - } - - /* copy back to u */ - memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE); - } while (++j <= m); - - bi_free(ctx, tmp_u); - bi_free(ctx, v); - - if (is_mod) /* get the remainder */ - { - bi_free(ctx, quotient); - return bi_int_divide(ctx, trim(u), d); - } - else /* get the quotient */ - { - bi_free(ctx, u); - return trim(quotient); - } -} - -/* - * Perform an integer divide on a bigint. - */ -// mcb30 - mark ctx with __unused to avoid a compilation error -static bigint *bi_int_divide(BI_CTX *ctx __unused, bigint *biR, comp denom) -{ - int i = biR->size - 1; - long_comp r = 0; - - check(biR); - - do - { - r = (r<comps[i]; - biR->comps[i] = (comp)(r / denom); - r %= denom; - } while (--i >= 0); - - return trim(biR); -} - -#ifdef CONFIG_BIGINT_MONTGOMERY -/** - * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, - * where B^-1(B-1) mod N=1. Actually, only the least significant part of - * N' is needed, hence the definition N0'=N' mod b. We reproduce below the - * simple algorithm from an article by Dusse and Kaliski to efficiently - * find N0' from N0 and b */ -static comp modular_inverse(bigint *bim) -{ - int i; - comp t = 1; - comp two_2_i_minus_1 = 2; /* 2^(i-1) */ - long_comp two_2_i = 4; /* 2^i */ - comp N = bim->comps[0]; - - for (i = 2; i <= COMP_BIT_SIZE; i++) - { - if ((long_comp)N*t%two_2_i >= two_2_i_minus_1) - { - t += two_2_i_minus_1; - } - - two_2_i_minus_1 <<= 1; - two_2_i <<= 1; - } - - return (comp)(COMP_RADIX-t); -} -#endif - -#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ - defined(CONFIG_BIGINT_MONTGOMERY) -/** - * Take each component and shift down (in terms of components) - */ -static bigint *comp_right_shift(bigint *biR, int num_shifts) -{ - int i = biR->size-num_shifts; - comp *x = biR->comps; - comp *y = &biR->comps[num_shifts]; - - check(biR); - - if (i <= 0) /* have we completely right shifted? */ - { - biR->comps[0] = 0; /* return 0 */ - biR->size = 1; - return biR; - } - - do - { - *x++ = *y++; - } while (--i > 0); - - biR->size -= num_shifts; - return biR; -} - -/** - * Take each component and shift it up (in terms of components) - */ -static bigint *comp_left_shift(bigint *biR, int num_shifts) -{ - int i = biR->size-1; - comp *x, *y; - - check(biR); - - if (num_shifts <= 0) - { - return biR; - } - - more_comps(biR, biR->size + num_shifts); - - x = &biR->comps[i+num_shifts]; - y = &biR->comps[i]; - - do - { - *x-- = *y--; - } while (i--); - - memset(biR->comps, 0, num_shifts*COMP_BYTE_SIZE); /* zero LS comps */ - return biR; -} -#endif - -/** - * @brief Allow a binary sequence to be imported as a bigint. - * @param ctx [in] The bigint session context. - * @param data [in] The data to be converted. - * @param size [in] The number of bytes of data. - * @return A bigint representing this data. - */ -bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size) -{ - bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE); - int i, j = 0, offset = 0; - - memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); - - for (i = size-1; i >= 0; i--) - { - biR->comps[offset] += data[i] << (j*8); - - if (++j == COMP_BYTE_SIZE) - { - j = 0; - offset ++; - } - } - - return trim(biR); -} - -#ifdef CONFIG_SSL_FULL_MODE -/** - * @brief The testharness uses this code to import text hex-streams and - * convert them into bigints. - * @param ctx [in] The bigint session context. - * @param data [in] A string consisting of hex characters. The characters must - * be in upper case. - * @return A bigint representing this data. - */ -bigint *bi_str_import(BI_CTX *ctx, const char *data) -{ - int size = strlen(data); - bigint *biR = alloc(ctx, (size+COMP_NUM_NIBBLES-1)/COMP_NUM_NIBBLES); - int i, j = 0, offset = 0; - memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE); - - for (i = size-1; i >= 0; i--) - { - int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10); - biR->comps[offset] += num << (j*4); - - if (++j == COMP_NUM_NIBBLES) - { - j = 0; - offset ++; - } - } - - return biR; -} - -void bi_print(const char *label, bigint *x) -{ - int i, j; - - if (x == NULL) - { - printf("%s: (null)\n", label); - return; - } - - printf("%s: (size %d)\n", label, x->size); - for (i = x->size-1; i >= 0; i--) - { - for (j = COMP_NUM_NIBBLES-1; j >= 0; j--) - { - comp mask = 0x0f << (j*4); - comp num = (x->comps[i] & mask) >> (j*4); - putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout); - } - } - - printf("\n"); -} -#endif - -/** - * @brief Take a bigint and convert it into a byte sequence. - * - * This is useful after a decrypt operation. - * @param ctx [in] The bigint session context. - * @param x [in] The bigint to be converted. - * @param data [out] The converted data as a byte stream. - * @param size [in] The maximum size of the byte stream. Unused bytes will be - * zeroed. - */ -void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) -{ - int i, j, k = size-1; - - check(x); - memset(data, 0, size); /* ensure all leading 0's are cleared */ - - for (i = 0; i < x->size; i++) - { - for (j = 0; j < COMP_BYTE_SIZE; j++) - { - comp mask = 0xff << (j*8); - int num = (x->comps[i] & mask) >> (j*8); - data[k--] = num; - - if (k < 0) - { - goto buf_done; - } - } - } -buf_done: - - bi_free(ctx, x); -} - -/** - * @brief Pre-calculate some of the expensive steps in reduction. - * - * This function should only be called once (normally when a session starts). - * When the session is over, bi_free_mod() should be called. bi_mod_power() - * relies on this function being called. - * @param ctx [in] The bigint session context. - * @param bim [in] The bigint modulus that will be used. - * @param mod_offset [in] There are three moduluii that can be stored - the - * standard modulus, and its two primes p and q. This offset refers to which - * modulus we are referring to. - * @see bi_free_mod(), bi_mod_power(). - */ -void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) -{ - int k = bim->size; - comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1)); -#ifdef CONFIG_BIGINT_MONTGOMERY - bigint *R, *R2; -#endif - - ctx->bi_mod[mod_offset] = bim; - bi_permanent(ctx->bi_mod[mod_offset]); - ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); - bi_permanent(ctx->bi_normalised_mod[mod_offset]); - -#if defined(CONFIG_BIGINT_MONTGOMERY) - /* set montgomery variables */ - R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k-1); /* R */ - R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k*2-1); /* R^2 */ - ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */ - ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */ - - bi_permanent(ctx->bi_RR_mod_m[mod_offset]); - bi_permanent(ctx->bi_R_mod_m[mod_offset]); - - ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]); - -#elif defined (CONFIG_BIGINT_BARRETT) - ctx->bi_mu[mod_offset] = - bi_divide(ctx, comp_left_shift( - bi_clone(ctx, ctx->bi_radix), k*2-1), ctx->bi_mod[mod_offset], 0); - bi_permanent(ctx->bi_mu[mod_offset]); -#endif -} - -/** - * @brief Used when cleaning various bigints at the end of a session. - * @param ctx [in] The bigint session context. - * @param mod_offset [in] The offset to use. - * @see bi_set_mod(). - */ -void bi_free_mod(BI_CTX *ctx, int mod_offset) -{ - bi_depermanent(ctx->bi_mod[mod_offset]); - bi_free(ctx, ctx->bi_mod[mod_offset]); -#if defined (CONFIG_BIGINT_MONTGOMERY) - bi_depermanent(ctx->bi_RR_mod_m[mod_offset]); - bi_depermanent(ctx->bi_R_mod_m[mod_offset]); - bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]); - bi_free(ctx, ctx->bi_R_mod_m[mod_offset]); -#elif defined(CONFIG_BIGINT_BARRETT) - bi_depermanent(ctx->bi_mu[mod_offset]); - bi_free(ctx, ctx->bi_mu[mod_offset]); -#endif - bi_depermanent(ctx->bi_normalised_mod[mod_offset]); - bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); -} - -/** - * Perform a standard multiplication between two bigints. - * - * Barrett reduction has no need for some parts of the product, so ignore bits - * of the multiply. This routine gives Barrett its big performance - * improvements over Classical/Montgomery reduction methods. - */ -static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, - int inner_partial, int outer_partial) -{ - int i = 0, j; - int n = bia->size; - int t = bib->size; - bigint *biR = alloc(ctx, n + t); - comp *sr = biR->comps; - comp *sa = bia->comps; - comp *sb = bib->comps; - - check(bia); - check(bib); - - /* clear things to start with */ - memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE)); - - do - { - long_comp tmp; - comp carry = 0; - int r_index = i; - j = 0; - - if (outer_partial && outer_partial-i > 0 && outer_partial < n) - { - r_index = outer_partial-1; - j = outer_partial-i-1; - } - - do - { - if (inner_partial && r_index >= inner_partial) - { - break; - } - - tmp = sr[r_index] + ((long_comp)sa[j])*sb[i] + carry; - sr[r_index++] = (comp)tmp; /* downsize */ - carry = tmp >> COMP_BIT_SIZE; - } while (++j < n); - - sr[r_index] = carry; - } while (++i < t); - - bi_free(ctx, bia); - bi_free(ctx, bib); - return trim(biR); -} - -#ifdef CONFIG_BIGINT_KARATSUBA -/* - * Karatsuba improves on regular multiplication due to only 3 multiplications - * being done instead of 4. The additional additions/subtractions are O(N) - * rather than O(N^2) and so for big numbers it saves on a few operations - */ -static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square) -{ - bigint *x0, *x1; - bigint *p0, *p1, *p2; - int m; - - if (is_square) - { - m = (bia->size + 1)/2; - } - else - { - m = (max(bia->size, bib->size) + 1)/2; - } - - x0 = bi_clone(ctx, bia); - x0->size = m; - x1 = bi_clone(ctx, bia); - comp_right_shift(x1, m); - bi_free(ctx, bia); - - /* work out the 3 partial products */ - if (is_square) - { - p0 = bi_square(ctx, bi_copy(x0)); - p2 = bi_square(ctx, bi_copy(x1)); - p1 = bi_square(ctx, bi_add(ctx, x0, x1)); - } - else /* normal multiply */ - { - bigint *y0, *y1; - y0 = bi_clone(ctx, bib); - y0->size = m; - y1 = bi_clone(ctx, bib); - comp_right_shift(y1, m); - bi_free(ctx, bib); - - p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0)); - p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1)); - p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1)); - } - - p1 = bi_subtract(ctx, - bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), NULL); - - comp_left_shift(p1, m); - comp_left_shift(p2, 2*m); - return bi_add(ctx, p1, bi_add(ctx, p0, p2)); -} -#endif - -/** - * @brief Perform a multiplication operation between two bigints. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return The result of the multiplication. - */ -bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) -{ - check(bia); - check(bib); - -#ifdef CONFIG_BIGINT_KARATSUBA - if (min(bia->size, bib->size) < MUL_KARATSUBA_THRESH) - { - return regular_multiply(ctx, bia, bib, 0, 0); - } - - return karatsuba(ctx, bia, bib, 0); -#else - return regular_multiply(ctx, bia, bib, 0, 0); -#endif -} - -#ifdef CONFIG_BIGINT_SQUARE -/* - * Perform the actual square operion. It takes into account overflow. - */ -static bigint *regular_square(BI_CTX *ctx, bigint *bi) -{ - int t = bi->size; - int i = 0, j; - bigint *biR = alloc(ctx, t*2+1); - comp *w = biR->comps; - comp *x = bi->comps; - long_comp carry; - memset(w, 0, biR->size*COMP_BYTE_SIZE); - - do - { - long_comp tmp = w[2*i] + (long_comp)x[i]*x[i]; - w[2*i] = (comp)tmp; - carry = tmp >> COMP_BIT_SIZE; - - for (j = i+1; j < t; j++) - { - uint8_t c = 0; - long_comp xx = (long_comp)x[i]*x[j]; - if ((COMP_MAX-xx) < xx) - c = 1; - - tmp = (xx<<1); - - if ((COMP_MAX-tmp) < w[i+j]) - c = 1; - - tmp += w[i+j]; - - if ((COMP_MAX-tmp) < carry) - c = 1; - - tmp += carry; - w[i+j] = (comp)tmp; - carry = tmp >> COMP_BIT_SIZE; - - if (c) - carry += COMP_RADIX; - } - - tmp = w[i+t] + carry; - w[i+t] = (comp)tmp; - w[i+t+1] = tmp >> COMP_BIT_SIZE; - } while (++i < t); - - bi_free(ctx, bi); - return trim(biR); -} - -/** - * @brief Perform a square operation on a bigint. - * @param ctx [in] The bigint session context. - * @param bia [in] A bigint. - * @return The result of the multiplication. - */ -bigint *bi_square(BI_CTX *ctx, bigint *bia) -{ - check(bia); - -#ifdef CONFIG_BIGINT_KARATSUBA - if (bia->size < SQU_KARATSUBA_THRESH) - { - return regular_square(ctx, bia); - } - - return karatsuba(ctx, bia, NULL, 1); -#else - return regular_square(ctx, bia); -#endif -} -#endif - -/** - * @brief Compare two bigints. - * @param bia [in] A bigint. - * @param bib [in] Another bigint. - * @return -1 if smaller, 1 if larger and 0 if equal. - */ -int bi_compare(bigint *bia, bigint *bib) -{ - int r, i; - - check(bia); - check(bib); - - if (bia->size > bib->size) - r = 1; - else if (bia->size < bib->size) - r = -1; - else - { - comp *a = bia->comps; - comp *b = bib->comps; - - /* Same number of components. Compare starting from the high end - * and working down. */ - r = 0; - i = bia->size - 1; - - do - { - if (a[i] > b[i]) - { - r = 1; - break; - } - else if (a[i] < b[i]) - { - r = -1; - break; - } - } while (--i >= 0); - } - - return r; -} - -/* - * Allocate and zero more components. Does not consume bi. - */ -static void more_comps(bigint *bi, int n) -{ - if (n > bi->max_comps) - { - bi->max_comps = max(bi->max_comps * 2, n); - bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE); - } - - if (n > bi->size) - { - memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE); - } - - bi->size = n; -} - -/* - * Make a new empty bigint. It may just use an old one if one is available. - * Otherwise get one off the heap. - */ -static bigint *alloc(BI_CTX *ctx, int size) -{ - bigint *biR; - - /* Can we recycle an old bigint? */ - if (ctx->free_list != NULL) - { - biR = ctx->free_list; - ctx->free_list = biR->next; - ctx->free_count--; - - if (biR->refs != 0) - { -#ifdef CONFIG_SSL_FULL_MODE - printf("alloc: refs was not 0\n"); -#endif - abort(); /* create a stack trace from a core dump */ - } - - more_comps(biR, size); - } - else - { - /* No free bigints available - create a new one. */ - biR = (bigint *)malloc(sizeof(bigint)); - biR->comps = (comp*)malloc(size * COMP_BYTE_SIZE); - biR->max_comps = size; /* give some space to spare */ - } - - biR->size = size; - biR->refs = 1; - biR->next = NULL; - ctx->active_count++; - return biR; -} - -/* - * Work out the highest '1' bit in an exponent. Used when doing sliding-window - * exponentiation. - */ -static int find_max_exp_index(bigint *biexp) -{ - int i = COMP_BIT_SIZE-1; - comp shift = COMP_RADIX/2; - comp test = biexp->comps[biexp->size-1]; /* assume no leading zeroes */ - - check(biexp); - - do - { - if (test & shift) - { - return i+(biexp->size-1)*COMP_BIT_SIZE; - } - - shift >>= 1; - } while (i-- != 0); - - return -1; /* error - must have been a leading 0 */ -} - -/* - * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window - * exponentiation. - */ -static int exp_bit_is_one(bigint *biexp, int offset) -{ - comp test = biexp->comps[offset / COMP_BIT_SIZE]; - int num_shifts = offset % COMP_BIT_SIZE; - comp shift = 1; - int i; - - check(biexp); - - for (i = 0; i < num_shifts; i++) - { - shift <<= 1; - } - - return (test & shift) != 0; -} - -#ifdef CONFIG_BIGINT_CHECK_ON -/* - * Perform a sanity check on bi. - */ -static void check(const bigint *bi) -{ - if (bi->refs <= 0) - { - printf("check: zero or negative refs in bigint\n"); - abort(); - } - - if (bi->next != NULL) - { - printf("check: attempt to use a bigint from " - "the free list\n"); - abort(); - } -} -#endif - -/* - * Delete any leading 0's (and allow for 0). - */ -static bigint *trim(bigint *bi) -{ - check(bi); - - while (bi->comps[bi->size-1] == 0 && bi->size > 1) - { - bi->size--; - } - - return bi; -} - -#if defined(CONFIG_BIGINT_MONTGOMERY) -/** - * @brief Perform a single montgomery reduction. - * @param ctx [in] The bigint session context. - * @param bixy [in] A bigint. - * @return The result of the montgomery reduction. - */ -bigint *bi_mont(BI_CTX *ctx, bigint *bixy) -{ - int i = 0, n; - uint8_t mod_offset = ctx->mod_offset; - bigint *bim = ctx->bi_mod[mod_offset]; - comp mod_inv = ctx->N0_dash[mod_offset]; - - check(bixy); - - if (ctx->use_classical) /* just use classical instead */ - { - return bi_mod(ctx, bixy); - } - - n = bim->size; - - do - { - bixy = bi_add(ctx, bixy, comp_left_shift( - bi_int_multiply(ctx, bim, bixy->comps[i]*mod_inv), i)); - } while (++i < n); - - comp_right_shift(bixy, n); - - if (bi_compare(bixy, bim) >= 0) - { - bixy = bi_subtract(ctx, bixy, bim, NULL); - } - - return bixy; -} - -#elif defined(CONFIG_BIGINT_BARRETT) -/* - * Stomp on the most significant components to give the illusion of a "mod base - * radix" operation - */ -static bigint *comp_mod(bigint *bi, int mod) -{ - check(bi); - - if (bi->size > mod) - { - bi->size = mod; - } - - return bi; -} - -/** - * @brief Perform a single Barrett reduction. - * @param ctx [in] The bigint session context. - * @param bi [in] A bigint. - * @return The result of the Barrett reduction. - */ -bigint *bi_barrett(BI_CTX *ctx, bigint *bi) -{ - bigint *q1, *q2, *q3, *r1, *r2, *r; - uint8_t mod_offset = ctx->mod_offset; - bigint *bim = ctx->bi_mod[mod_offset]; - int k = bim->size; - - check(bi); - check(bim); - - /* use Classical method instead - Barrett cannot help here */ - if (bi->size > k*2) - { - return bi_mod(ctx, bi); - } - - q1 = comp_right_shift(bi_clone(ctx, bi), k-1); - - /* do outer partial multiply */ - q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k-1); - q3 = comp_right_shift(q2, k+1); - r1 = comp_mod(bi, k+1); - - /* do inner partial multiply */ - r2 = comp_mod(regular_multiply(ctx, q3, bim, k+1, 0), k+1); - r = bi_subtract(ctx, r1, r2, NULL); - - /* if (r >= m) r = r - m; */ - if (bi_compare(r, bim) >= 0) - { - r = bi_subtract(ctx, r, bim, NULL); - } - - return r; -} -#endif /* CONFIG_BIGINT_BARRETT */ - -#ifdef CONFIG_BIGINT_SLIDING_WINDOW -/* - * Work out g1, g3, g5, g7... etc for the sliding-window algorithm - */ -static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) -{ - int k = 1, i; - bigint *g2; - - for (i = 0; i < window-1; i++) /* compute 2^(window-1) */ - { - k <<= 1; - } - - ctx->g = (bigint **)malloc(k*sizeof(bigint *)); - ctx->g[0] = bi_clone(ctx, g1); - bi_permanent(ctx->g[0]); - g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ - - for (i = 1; i < k; i++) - { - ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i-1], bi_copy(g2))); - bi_permanent(ctx->g[i]); - } - - bi_free(ctx, g2); - ctx->window = k; -} -#endif - -/** - * @brief Perform a modular exponentiation. - * - * This function requires bi_set_mod() to have been called previously. This is - * one of the optimisations used for performance. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint on which to perform the mod power operation. - * @param biexp [in] The bigint exponent. - * @return The result of the mod exponentiation operation - * @see bi_set_mod(). - */ -bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) -{ - int i = find_max_exp_index(biexp), j, window_size = 1; - bigint *biR = int_to_bi(ctx, 1); - -#if defined(CONFIG_BIGINT_MONTGOMERY) - uint8_t mod_offset = ctx->mod_offset; - if (!ctx->use_classical) - { - /* preconvert */ - bi = bi_mont(ctx, - bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ - bi_free(ctx, biR); - biR = ctx->bi_R_mod_m[mod_offset]; /* A */ - } -#endif - - check(bi); - check(biexp); - -#ifdef CONFIG_BIGINT_SLIDING_WINDOW - for (j = i; j > 32; j /= 5) /* work out an optimum size */ - window_size++; - - /* work out the slide constants */ - precompute_slide_window(ctx, window_size, bi); -#else /* just one constant */ - ctx->g = (bigint **)malloc(sizeof(bigint *)); - ctx->g[0] = bi_clone(ctx, bi); - ctx->window = 1; - bi_permanent(ctx->g[0]); -#endif - - /* if sliding-window is off, then only one bit will be done at a time and - * will reduce to standard left-to-right exponentiation */ - do - { - if (exp_bit_is_one(biexp, i)) - { - int l = i-window_size+1; - int part_exp = 0; - - if (l < 0) /* LSB of exponent will always be 1 */ - l = 0; - else - { - while (exp_bit_is_one(biexp, l) == 0) - l++; /* go back up */ - } - - /* build up the section of the exponent */ - for (j = i; j >= l; j--) - { - biR = bi_residue(ctx, bi_square(ctx, biR)); - if (exp_bit_is_one(biexp, j)) - part_exp++; - - if (j != l) - part_exp <<= 1; - } - - part_exp = (part_exp-1)/2; /* adjust for array */ - biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); - i = l-1; - } - else /* square it */ - { - biR = bi_residue(ctx, bi_square(ctx, biR)); - i--; - } - } while (i >= 0); - - /* cleanup */ - for (i = 0; i < ctx->window; i++) - { - bi_depermanent(ctx->g[i]); - bi_free(ctx, ctx->g[i]); - } - - free(ctx->g); - bi_free(ctx, bi); - bi_free(ctx, biexp); -#if defined CONFIG_BIGINT_MONTGOMERY - return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ -#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ - return biR; -#endif -} - -#ifdef CONFIG_SSL_CERT_VERIFICATION -/** - * @brief Perform a modular exponentiation using a temporary modulus. - * - * We need this function to check the signatures of certificates. The modulus - * of this function is temporary as it's just used for authentication. - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to perform the exp/mod. - * @param bim [in] The temporary modulus. - * @param biexp [in] The bigint exponent. - * @return The result of the mod exponentiation operation - * @see bi_set_mod(). - */ -bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp) -{ - bigint *biR, *tmp_biR; - - /* Set up a temporary bigint context and transfer what we need between - * them. We need to do this since we want to keep the original modulus - * which is already in this context. This operation is only called when - * doing peer verification, and so is not expensive :-) */ - BI_CTX *tmp_ctx = bi_initialize(); - bi_set_mod(tmp_ctx, bi_clone(tmp_ctx, bim), BIGINT_M_OFFSET); - tmp_biR = bi_mod_power(tmp_ctx, - bi_clone(tmp_ctx, bi), - bi_clone(tmp_ctx, biexp)); - biR = bi_clone(ctx, tmp_biR); - bi_free(tmp_ctx, tmp_biR); - bi_free_mod(tmp_ctx, BIGINT_M_OFFSET); - bi_terminate(tmp_ctx); - - bi_free(ctx, bi); - bi_free(ctx, bim); - bi_free(ctx, biexp); - return biR; -} -#endif - -#ifdef CONFIG_BIGINT_CRT -/** - * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. - * - * @param ctx [in] The bigint session context. - * @param bi [in] The bigint to perform the exp/mod. - * @param dP [in] CRT's dP bigint - * @param dQ [in] CRT's dQ bigint - * @param p [in] CRT's p bigint - * @param q [in] CRT's q bigint - * @param qInv [in] CRT's qInv bigint - * @return The result of the CRT operation - */ -bigint *bi_crt(BI_CTX *ctx, bigint *bi, - bigint *dP, bigint *dQ, - bigint *p, bigint *q, bigint *qInv) -{ - bigint *m1, *m2, *h; - - /* Montgomery has a condition the 0 < x, y < m and these products violate - * that condition. So disable Montgomery when using CRT */ -#if defined(CONFIG_BIGINT_MONTGOMERY) - ctx->use_classical = 1; -#endif - ctx->mod_offset = BIGINT_P_OFFSET; - m1 = bi_mod_power(ctx, bi_copy(bi), dP); - - ctx->mod_offset = BIGINT_Q_OFFSET; - m2 = bi_mod_power(ctx, bi, dQ); - - h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); - h = bi_multiply(ctx, h, qInv); - ctx->mod_offset = BIGINT_P_OFFSET; - h = bi_residue(ctx, h); -#if defined(CONFIG_BIGINT_MONTGOMERY) - ctx->use_classical = 0; /* reset for any further operation */ -#endif - return bi_add(ctx, m2, bi_multiply(ctx, q, h)); -} -#endif -/** @} */ diff --git a/src/crypto/axtls/axtls_rsa.c b/src/crypto/axtls/axtls_rsa.c deleted file mode 100644 index f17500c3..00000000 --- a/src/crypto/axtls/axtls_rsa.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2007, Cameron Rich - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * 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. - * * Neither the name of the axTLS project 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 OWNER 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. - */ - -/** - * Implements the RSA public encryption algorithm. Uses the bigint library to - * perform its calculations. - */ - -#include -#include -#include -#include -#include "os_port.h" -#include "crypto.h" - -void RSA_priv_key_new(RSA_CTX **ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len, - const uint8_t *priv_exp, int priv_len -#if CONFIG_BIGINT_CRT - , const uint8_t *p, int p_len, - const uint8_t *q, int q_len, - const uint8_t *dP, int dP_len, - const uint8_t *dQ, int dQ_len, - const uint8_t *qInv, int qInv_len -#endif - ) -{ - RSA_CTX *rsa_ctx; - BI_CTX *bi_ctx; - RSA_pub_key_new(ctx, modulus, mod_len, pub_exp, pub_len); - rsa_ctx = *ctx; - bi_ctx = rsa_ctx->bi_ctx; - rsa_ctx->d = bi_import(bi_ctx, priv_exp, priv_len); - bi_permanent(rsa_ctx->d); - -#ifdef CONFIG_BIGINT_CRT - rsa_ctx->p = bi_import(bi_ctx, p, p_len); - rsa_ctx->q = bi_import(bi_ctx, q, q_len); - rsa_ctx->dP = bi_import(bi_ctx, dP, dP_len); - rsa_ctx->dQ = bi_import(bi_ctx, dQ, dQ_len); - rsa_ctx->qInv = bi_import(bi_ctx, qInv, qInv_len); - bi_permanent(rsa_ctx->dP); - bi_permanent(rsa_ctx->dQ); - bi_permanent(rsa_ctx->qInv); - bi_set_mod(bi_ctx, rsa_ctx->p, BIGINT_P_OFFSET); - bi_set_mod(bi_ctx, rsa_ctx->q, BIGINT_Q_OFFSET); -#endif -} - -void RSA_pub_key_new(RSA_CTX **ctx, - const uint8_t *modulus, int mod_len, - const uint8_t *pub_exp, int pub_len) -{ - RSA_CTX *rsa_ctx; - BI_CTX *bi_ctx; - - if (*ctx) /* if we load multiple certs, dump the old one */ - RSA_free(*ctx); - - bi_ctx = bi_initialize(); - *ctx = (RSA_CTX *)calloc(1, sizeof(RSA_CTX)); - rsa_ctx = *ctx; - rsa_ctx->bi_ctx = bi_ctx; - rsa_ctx->num_octets = mod_len; - rsa_ctx->m = bi_import(bi_ctx, modulus, mod_len); - bi_set_mod(bi_ctx, rsa_ctx->m, BIGINT_M_OFFSET); - rsa_ctx->e = bi_import(bi_ctx, pub_exp, pub_len); - bi_permanent(rsa_ctx->e); -} - -/** - * Free up any RSA context resources. - */ -void RSA_free(RSA_CTX *rsa_ctx) -{ - BI_CTX *bi_ctx; - if (rsa_ctx == NULL) /* deal with ptrs that are null */ - return; - - bi_ctx = rsa_ctx->bi_ctx; - - bi_depermanent(rsa_ctx->e); - bi_free(bi_ctx, rsa_ctx->e); - bi_free_mod(rsa_ctx->bi_ctx, BIGINT_M_OFFSET); - - if (rsa_ctx->d) - { - bi_depermanent(rsa_ctx->d); - bi_free(bi_ctx, rsa_ctx->d); -#ifdef CONFIG_BIGINT_CRT - bi_depermanent(rsa_ctx->dP); - bi_depermanent(rsa_ctx->dQ); - bi_depermanent(rsa_ctx->qInv); - bi_free(bi_ctx, rsa_ctx->dP); - bi_free(bi_ctx, rsa_ctx->dQ); - bi_free(bi_ctx, rsa_ctx->qInv); - bi_free_mod(rsa_ctx->bi_ctx, BIGINT_P_OFFSET); - bi_free_mod(rsa_ctx->bi_ctx, BIGINT_Q_OFFSET); -#endif - } - - bi_terminate(bi_ctx); - free(rsa_ctx); -} - -/** - * @brief Use PKCS1.5 for decryption/verification. - * @param ctx [in] The context - * @param in_data [in] The data to encrypt (must be < modulus size-11) - * @param out_data [out] The encrypted data. - * @param is_decryption [in] Decryption or verify operation. - * @return The number of bytes that were originally encrypted. -1 on error. - * @see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 - */ -int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, - uint8_t *out_data, int is_decryption) -{ - const int byte_size = ctx->num_octets; - int i, size; - bigint *decrypted_bi, *dat_bi; - uint8_t *block = (uint8_t *)alloca(byte_size); - - memset(out_data, 0, byte_size); /* initialise */ - - /* decrypt */ - dat_bi = bi_import(ctx->bi_ctx, in_data, byte_size); -#ifdef CONFIG_SSL_CERT_VERIFICATION - decrypted_bi = is_decryption ? /* decrypt or verify? */ - RSA_private(ctx, dat_bi) : RSA_public(ctx, dat_bi); -#else /* always a decryption */ - decrypted_bi = RSA_private(ctx, dat_bi); -#endif - - /* convert to a normal block */ - bi_export(ctx->bi_ctx, decrypted_bi, block, byte_size); - - i = 10; /* start at the first possible non-padded byte */ - -#ifdef CONFIG_SSL_CERT_VERIFICATION - if (is_decryption == 0) /* PKCS1.5 signing pads with "0xff"s */ - { - while (block[i++] == 0xff && i < byte_size); - - if (block[i-2] != 0xff) - i = byte_size; /*ensure size is 0 */ - } - else /* PKCS1.5 encryption padding is random */ -#endif - { - while (block[i++] && i < byte_size); - } - size = byte_size - i; - - /* get only the bit we want */ - if (size > 0) - memcpy(out_data, &block[i], size); - - return size ? size : -1; -} - -/** - * Performs m = c^d mod n - */ -bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg) -{ -#ifdef CONFIG_BIGINT_CRT - return bi_crt(c->bi_ctx, bi_msg, c->dP, c->dQ, c->p, c->q, c->qInv); -#else - BI_CTX *ctx = c->bi_ctx; - ctx->mod_offset = BIGINT_M_OFFSET; - return bi_mod_power(ctx, bi_msg, c->d); -#endif -} - -#ifdef CONFIG_SSL_FULL_MODE -/** - * Used for diagnostics. - */ -void RSA_print(const RSA_CTX *rsa_ctx) -{ - if (rsa_ctx == NULL) - return; - - printf("----------------- RSA DEBUG ----------------\n"); - printf("Size:\t%d\n", rsa_ctx->num_octets); - bi_print("Modulus", rsa_ctx->m); - bi_print("Public Key", rsa_ctx->e); - bi_print("Private Key", rsa_ctx->d); -} -#endif - -#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT) -/** - * Performs c = m^e mod n - */ -bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg) -{ - c->bi_ctx->mod_offset = BIGINT_M_OFFSET; - return bi_mod_power(c->bi_ctx, bi_msg, c->e); -} - -/** - * Use PKCS1.5 for encryption/signing. - * see http://www.rsasecurity.com/rsalabs/node.asp?id=2125 - */ -int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len, - uint8_t *out_data, int is_signing) -{ - int byte_size = ctx->num_octets; - int num_pads_needed = byte_size-in_len-3; - bigint *dat_bi, *encrypt_bi; - - /* note: in_len+11 must be > byte_size */ - out_data[0] = 0; /* ensure encryption block is < modulus */ - - if (is_signing) - { - out_data[1] = 1; /* PKCS1.5 signing pads with "0xff"'s */ - memset(&out_data[2], 0xff, num_pads_needed); - } - else /* randomize the encryption padding with non-zero bytes */ - { - out_data[1] = 2; - get_random_NZ(num_pads_needed, &out_data[2]); - } - - out_data[2+num_pads_needed] = 0; - memcpy(&out_data[3+num_pads_needed], in_data, in_len); - - /* now encrypt it */ - dat_bi = bi_import(ctx->bi_ctx, out_data, byte_size); - encrypt_bi = is_signing ? RSA_private(ctx, dat_bi) : - RSA_public(ctx, dat_bi); - bi_export(ctx->bi_ctx, encrypt_bi, out_data, byte_size); - - /* save a few bytes of memory */ - bi_clear_cache(ctx->bi_ctx); - return byte_size; -} - -#endif /* CONFIG_SSL_CERT_VERIFICATION */ From 196f0bb081db462bc0f9a9462f47c9639101204b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 16:45:04 +0000 Subject: [PATCH 083/221] [rng] Allow entropy_enable() to return an error Signed-off-by: Michael Brown --- src/arch/i386/interface/pcbios/rtc_entropy.c | 5 ++++- src/crypto/entropy.c | 3 ++- src/include/ipxe/entropy.h | 3 ++- src/include/ipxe/null_entropy.h | 3 ++- src/tests/entropy_sample.c | 3 ++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/arch/i386/interface/pcbios/rtc_entropy.c b/src/arch/i386/interface/pcbios/rtc_entropy.c index 03189659..257cf08a 100644 --- a/src/arch/i386/interface/pcbios/rtc_entropy.c +++ b/src/arch/i386/interface/pcbios/rtc_entropy.c @@ -165,12 +165,15 @@ static void rtc_disable_int ( void ) { /** * Enable entropy gathering * + * @ret rc Return status code */ -static void rtc_entropy_enable ( void ) { +static int rtc_entropy_enable ( void ) { rtc_hook_isr(); enable_irq ( RTC_IRQ ); rtc_enable_int(); + + return 0; } /** diff --git a/src/crypto/entropy.c b/src/crypto/entropy.c index cb3d54d8..03e7290a 100644 --- a/src/crypto/entropy.c +++ b/src/crypto/entropy.c @@ -422,7 +422,8 @@ int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp, int rc; /* Enable entropy gathering */ - entropy_enable(); + if ( ( rc = entropy_enable() ) != 0 ) + return rc; /* Perform mandatory startup tests, if not yet performed */ for ( ; startup_tested < startup_test_count() ; startup_tested++ ) { diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index 02dde2f1..50ba4fc6 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -61,8 +61,9 @@ typedef uint8_t entropy_sample_t; /** * Enable entropy gathering * + * @ret rc Return status code */ -void entropy_enable ( void ); +int entropy_enable ( void ); /** * Disable entropy gathering diff --git a/src/include/ipxe/null_entropy.h b/src/include/ipxe/null_entropy.h index 0bfec802..646d1a17 100644 --- a/src/include/ipxe/null_entropy.h +++ b/src/include/ipxe/null_entropy.h @@ -19,9 +19,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ENTROPY_PREFIX_null __null_ #endif -static inline __always_inline void +static inline __always_inline int ENTROPY_INLINE ( null, entropy_enable ) ( void ) { /* Do nothing */ + return 0; } static inline __always_inline void diff --git a/src/tests/entropy_sample.c b/src/tests/entropy_sample.c index e00bb484..9e75b4e9 100644 --- a/src/tests/entropy_sample.c +++ b/src/tests/entropy_sample.c @@ -48,7 +48,8 @@ static void entropy_sample_test_exec ( void ) { for ( i = 0 ; i < ( SAMPLE_COUNT / SAMPLE_BLOCKSIZE ) ; i++ ) { /* Collect one block of samples */ - entropy_enable(); + rc = entropy_enable(); + ok ( rc == 0 ); for ( j = 0 ; j < SAMPLE_BLOCKSIZE ; j++ ) { rc = get_noise ( &samples[j] ); ok ( rc == 0 ); From 5af9e6219646ace094cfe35caa0125cbff8f38f8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 17:03:58 +0000 Subject: [PATCH 084/221] [rng] Add Linux entropy source using /dev/random Signed-off-by: Michael Brown --- src/config/defaults/linux.h | 2 +- src/include/ipxe/entropy.h | 1 + src/include/ipxe/errfile.h | 1 + src/include/ipxe/linux/linux_entropy.h | 32 +++++++++ src/interface/linux/linux_entropy.c | 96 ++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/include/ipxe/linux/linux_entropy.h create mode 100644 src/interface/linux/linux_entropy.c diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index 6b24da48..fcdf9040 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -14,7 +14,7 @@ #define NAP_LINUX #define SMBIOS_LINUX #define SANBOOT_NULL -#define ENTROPY_NULL +#define ENTROPY_LINUX #define DRIVERS_LINUX diff --git a/src/include/ipxe/entropy.h b/src/include/ipxe/entropy.h index 50ba4fc6..adf325e7 100644 --- a/src/include/ipxe/entropy.h +++ b/src/include/ipxe/entropy.h @@ -54,6 +54,7 @@ typedef uint8_t entropy_sample_t; /* Include all architecture-independent entropy API headers */ #include +#include /* Include all architecture-dependent entropy API headers */ #include diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 050bf3fe..bfb738a4 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -247,6 +247,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_drbg ( ERRFILE_OTHER | 0x00250000 ) #define ERRFILE_entropy ( ERRFILE_OTHER | 0x00260000 ) #define ERRFILE_rsa ( ERRFILE_OTHER | 0x00270000 ) +#define ERRFILE_linux_entropy ( ERRFILE_OTHER | 0x00280000 ) /** @} */ diff --git a/src/include/ipxe/linux/linux_entropy.h b/src/include/ipxe/linux/linux_entropy.h new file mode 100644 index 00000000..bd89bd52 --- /dev/null +++ b/src/include/ipxe/linux/linux_entropy.h @@ -0,0 +1,32 @@ +#ifndef _IPXE_LINUX_ENTROPY_H +#define _IPXE_LINUX_ENTROPY_H + +/** @file + * + * iPXE entropy API for linux + * + */ + +FILE_LICENCE(GPL2_OR_LATER); + +#ifdef ENTROPY_LINUX +#define ENTROPY_PREFIX_linux +#else +#define ENTROPY_PREFIX_linux __linux_ +#endif + +/** + * min-entropy per sample + * + * @ret min_entropy min-entropy of each sample + */ +static inline __always_inline double +ENTROPY_INLINE ( linux, min_entropy_per_sample ) ( void ) { + + /* We read single bytes from /dev/random and assume that each + * contains full entropy. + */ + return 8; +} + +#endif /* _IPXE_LINUX_ENTROPY_H */ diff --git a/src/interface/linux/linux_entropy.c b/src/interface/linux/linux_entropy.c new file mode 100644 index 00000000..d82aabaa --- /dev/null +++ b/src/interface/linux/linux_entropy.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Linux entropy source + * + */ + +#include +#include +#include +#include + +/** Entropy source filename */ +static const char entropy_filename[] = "/dev/random"; + +/** Entropy source file handle */ +static int entropy_fd; + +/** + * Enable entropy gathering + * + * @ret rc Return status code + */ +static int linux_entropy_enable ( void ) { + + /* Open entropy source */ + entropy_fd = linux_open ( entropy_filename, O_RDONLY ); + if ( entropy_fd < 0 ) { + DBGC ( &entropy_fd, "ENTROPY could not open %s: %s\n", + entropy_filename, linux_strerror ( linux_errno ) ); + return entropy_fd; + } + + return 0; +} + +/** + * Disable entropy gathering + * + */ +static void linux_entropy_disable ( void ) { + + /* Close entropy source */ + linux_close ( entropy_fd ); +} + +/** + * Get noise sample + * + * @ret noise Noise sample + * @ret rc Return status code + */ +static int linux_get_noise ( noise_sample_t *noise ) { + uint8_t byte; + ssize_t len; + + /* Read a single byte from entropy source */ + len = linux_read ( entropy_fd, &byte, sizeof ( byte ) ); + if ( len < 0 ) { + DBGC ( &entropy_fd, "ENTROPY could not read from %s: %s\n", + entropy_filename, linux_strerror ( linux_errno ) ); + return len; + } + if ( len == 0 ) { + DBGC ( &entropy_fd, "ENTROPY EOF on reading from %s: %s\n", + entropy_filename, linux_strerror ( linux_errno ) ); + return -EPIPE; + } + *noise = byte; + + return 0; +} + +PROVIDE_ENTROPY_INLINE ( linux, min_entropy_per_sample ); +PROVIDE_ENTROPY ( linux, entropy_enable, linux_entropy_enable ); +PROVIDE_ENTROPY ( linux, entropy_disable, linux_entropy_disable ); +PROVIDE_ENTROPY ( linux, get_noise, linux_get_noise ); From 3ec773cd2b9d32c5a4bb3a7a6ae86e49fd278c8f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 20:02:25 +0000 Subject: [PATCH 085/221] [crypto] Force caller to provide temporary storage for modular calculations bigint_mod_multiply() and bigint_mod_exp() require a fixed amount of temporary storage for intermediate results. (The amount of temporary storage required depends upon the size of the integers involved.) When performing calculations for 4096-bit RSA the amount of temporary storage space required will exceed 2.5kB, which is too much to allocate on the stack. Avoid this problem by forcing the caller to allocate temporary storage. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 62 +++++++++++++++++++++++---------------- src/crypto/rsa.c | 7 ++++- src/include/ipxe/bigint.h | 49 ++++++++++++++++++++++++++----- src/include/ipxe/rsa.h | 2 ++ src/tests/bigint_test.c | 19 ++++++++---- 5 files changed, 99 insertions(+), 40 deletions(-) diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index c3edec9d..b13b0ac6 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -35,12 +35,14 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v multiplier0 Element 0 of big integer to be multiplied * @v modulus0 Element 0 of big integer modulus * @v result0 Element 0 of big integer to hold result + * @v size Number of elements in base, modulus, and result + * @v tmp Temporary working space */ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, bigint_element_t *result0, - unsigned int size ) { + unsigned int size, void *tmp ) { const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = ( ( const void * ) multiplicand0 ); const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = @@ -49,30 +51,35 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, ( ( const void * ) modulus0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - bigint_t ( size * 2 ) temp_result; - bigint_t ( size * 2 ) temp_modulus; + struct { + bigint_t ( size * 2 ) result; + bigint_t ( size * 2 ) modulus; + } *temp = tmp; int rotation; int i; + /* Sanity check */ + assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) ); + /* Perform multiplication */ - bigint_multiply ( multiplicand, multiplier, &temp_result ); + bigint_multiply ( multiplicand, multiplier, &temp->result ); /* Rescale modulus to match result */ - bigint_grow ( modulus, &temp_modulus ); - rotation = ( bigint_max_set_bit ( &temp_result ) - - bigint_max_set_bit ( &temp_modulus ) ); + bigint_grow ( modulus, &temp->modulus ); + rotation = ( bigint_max_set_bit ( &temp->result ) - + bigint_max_set_bit ( &temp->modulus ) ); for ( i = 0 ; i < rotation ; i++ ) - bigint_rol ( &temp_modulus ); + bigint_rol ( &temp->modulus ); /* Subtract multiples of modulus */ for ( i = 0 ; i <= rotation ; i++ ) { - if ( bigint_is_geq ( &temp_result, &temp_modulus ) ) - bigint_subtract ( &temp_modulus, &temp_result ); - bigint_ror ( &temp_modulus ); + if ( bigint_is_geq ( &temp->result, &temp->modulus ) ) + bigint_subtract ( &temp->modulus, &temp->result ); + bigint_ror ( &temp->modulus ); } /* Resize result */ - bigint_shrink ( &temp_result, result ); + bigint_shrink ( &temp->result, result ); /* Sanity check */ assert ( bigint_is_geq ( modulus, result ) ); @@ -87,13 +94,14 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, * @v result0 Element 0 of big integer to hold result * @v size Number of elements in base, modulus, and result * @v exponent_size Number of elements in exponent + * @v tmp Temporary working space */ void bigint_mod_exp_raw ( const bigint_element_t *base0, const bigint_element_t *modulus0, const bigint_element_t *exponent0, bigint_element_t *result0, - unsigned int size, - unsigned int exponent_size ) { + unsigned int size, unsigned int exponent_size, + void *tmp ) { const bigint_t ( size ) __attribute__ (( may_alias )) *base = ( ( const void * ) base0 ); const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = @@ -102,21 +110,25 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, *exponent = ( ( const void * ) exponent0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - bigint_t ( size ) temp_base; - bigint_t ( exponent_size ) temp_exponent; + size_t mod_multiply_len = bigint_mod_multiply_tmp_len ( modulus ); + struct { + bigint_t ( size ) base; + bigint_t ( exponent_size ) exponent; + uint8_t mod_multiply[mod_multiply_len]; + } *temp = tmp; static const uint8_t start[1] = { 0x01 }; - memcpy ( &temp_base, base, sizeof ( temp_base ) ); - memcpy ( &temp_exponent, exponent, sizeof ( temp_exponent ) ); + memcpy ( &temp->base, base, sizeof ( temp->base ) ); + memcpy ( &temp->exponent, exponent, sizeof ( temp->exponent ) ); bigint_init ( result, start, sizeof ( start ) ); - while ( ! bigint_is_zero ( &temp_exponent ) ) { - if ( bigint_bit_is_set ( &temp_exponent, 0 ) ) { - bigint_mod_multiply ( result, &temp_base, - modulus, result ); + while ( ! bigint_is_zero ( &temp->exponent ) ) { + if ( bigint_bit_is_set ( &temp->exponent, 0 ) ) { + bigint_mod_multiply ( result, &temp->base, modulus, + result, temp->mod_multiply ); } - bigint_ror ( &temp_exponent ); - bigint_mod_multiply ( &temp_base, &temp_base, modulus, - &temp_base ); + bigint_ror ( &temp->exponent ); + bigint_mod_multiply ( &temp->base, &temp->base, modulus, + &temp->base, temp->mod_multiply ); } } diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 4aba5cc3..a0bf39eb 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -123,11 +123,15 @@ static int rsa_alloc ( struct rsa_context *context, size_t modulus_len, size_t exponent_len ) { unsigned int size = bigint_required_size ( modulus_len ); unsigned int exponent_size = bigint_required_size ( exponent_len ); + bigint_t ( size ) *modulus; + bigint_t ( exponent_size ) *exponent; + size_t tmp_len = bigint_mod_exp_tmp_len ( modulus, exponent ); struct { bigint_t ( size ) modulus; bigint_t ( exponent_size ) exponent; bigint_t ( size ) input; bigint_t ( size ) output; + uint8_t tmp[tmp_len]; } __attribute__ (( packed )) *dynamic; /* Free any existing dynamic storage */ @@ -147,6 +151,7 @@ static int rsa_alloc ( struct rsa_context *context, size_t modulus_len, context->exponent_size = exponent_size; context->input0 = &dynamic->input.element[0]; context->output0 = &dynamic->output.element[0]; + context->tmp = &dynamic->tmp; return 0; } @@ -309,7 +314,7 @@ static void rsa_cipher ( struct rsa_context *context, bigint_init ( input, in, context->max_len ); /* Perform modular exponentiation */ - bigint_mod_exp ( input, modulus, exponent, output ); + bigint_mod_exp ( input, modulus, exponent, output, context->tmp ); /* Copy out result */ bigint_done ( output, out, context->max_len ); diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index a21b3e5d..97fbce24 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -197,16 +197,30 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v multiplier Big integer to be multiplied * @v modulus Big integer modulus * @v result Big integer to hold result + * @v tmp Temporary working space */ #define bigint_mod_multiply( multiplicand, multiplier, modulus, \ - result ) do { \ + result, tmp ) do { \ unsigned int size = bigint_size (multiplicand); \ bigint_mod_multiply_raw ( (multiplicand)->element, \ (multiplier)->element, \ (modulus)->element, \ - (result)->element, size ); \ + (result)->element, size, tmp ); \ } while ( 0 ) +/** + * Calculate temporary working space required for moduluar multiplication + * + * @v modulus Big integer modulus + * @ret len Length of temporary working space + */ +#define bigint_mod_multiply_tmp_len( modulus ) ( { \ + unsigned int size = bigint_size (modulus); \ + sizeof ( struct { \ + bigint_t ( size * 2 ) temp_result; \ + bigint_t ( size * 2 ) temp_modulus; \ + } ); } ) + /** * Perform modular exponentiation of big integers * @@ -214,15 +228,34 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v modulus Big integer modulus * @v exponent Big integer exponent * @v result Big integer to hold result + * @v tmp Temporary working space */ -#define bigint_mod_exp( base, modulus, exponent, result ) do { \ +#define bigint_mod_exp( base, modulus, exponent, result, tmp ) do { \ unsigned int size = bigint_size (base); \ unsigned int exponent_size = bigint_size (exponent); \ bigint_mod_exp_raw ( (base)->element, (modulus)->element, \ - (exponent)->element, (result)->element, \ - size, exponent_size ); \ + (exponent)->element, (result)->element, \ + size, exponent_size, tmp ); \ } while ( 0 ) +/** + * Calculate temporary working space required for moduluar exponentiation + * + * @v modulus Big integer modulus + * @v exponent Big integer exponent + * @ret len Length of temporary working space + */ +#define bigint_mod_exp_tmp_len( modulus, exponent ) ( { \ + unsigned int size = bigint_size (modulus); \ + unsigned int exponent_size = bigint_size (exponent); \ + size_t mod_multiply_len = \ + bigint_mod_multiply_tmp_len (modulus); \ + sizeof ( struct { \ + bigint_t ( size ) temp_base; \ + bigint_t ( exponent_size ) temp_exponent; \ + uint8_t mod_multiply[mod_multiply_len]; \ + } ); } ) + #include void bigint_init_raw ( bigint_element_t *value0, unsigned int size, @@ -257,12 +290,12 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, bigint_element_t *result0, - unsigned int size ); + unsigned int size, void *tmp ); void bigint_mod_exp_raw ( const bigint_element_t *base0, const bigint_element_t *modulus0, const bigint_element_t *exponent0, bigint_element_t *result0, - unsigned int size, - unsigned int exponent_size ); + unsigned int size, unsigned int exponent_size, + void *tmp ); #endif /* _IPXE_BIGINT_H */ diff --git a/src/include/ipxe/rsa.h b/src/include/ipxe/rsa.h index e70362ce..87e75a82 100644 --- a/src/include/ipxe/rsa.h +++ b/src/include/ipxe/rsa.h @@ -129,6 +129,8 @@ struct rsa_context { bigint_element_t *input0; /** Output buffer */ bigint_element_t *output0; + /** Temporary working space for modular exponentiation */ + void *tmp; }; extern struct pubkey_algorithm rsa_algorithm; diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 8c9f188e..4052131f 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -162,7 +162,8 @@ void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, bigint_element_t *result0, - unsigned int size ) { + unsigned int size, + void *tmp ) { const bigint_t ( size ) *multiplicand __attribute__ (( may_alias )) = ( ( const void * ) multiplicand0 ); const bigint_t ( size ) *multiplier __attribute__ (( may_alias )) @@ -172,14 +173,15 @@ void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, bigint_t ( size ) *result __attribute__ (( may_alias )) = ( ( void * ) result0 ); - bigint_mod_multiply ( multiplicand, multiplier, modulus, result ); + bigint_mod_multiply ( multiplicand, multiplier, modulus, result, tmp ); } void bigint_mod_exp_sample ( const bigint_element_t *base0, const bigint_element_t *modulus0, const bigint_element_t *exponent0, bigint_element_t *result0, - unsigned int size, unsigned int exponent_size ) { + unsigned int size, unsigned int exponent_size, + void *tmp ) { const bigint_t ( size ) *base __attribute__ (( may_alias )) = ( ( const void * ) base0 ); const bigint_t ( size ) *modulus __attribute__ (( may_alias )) @@ -189,7 +191,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_t ( size ) *result __attribute__ (( may_alias )) = ( ( void * ) result0 ); - bigint_mod_exp ( base, modulus, exponent, result ); + bigint_mod_exp ( base, modulus, exponent, result, tmp ); } /** @@ -471,6 +473,8 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_t ( size ) multiplier_temp; \ bigint_t ( size ) modulus_temp; \ bigint_t ( size ) result_temp; \ + size_t tmp_len = bigint_mod_multiply_tmp_len ( &modulus_temp ); \ + uint8_t tmp[tmp_len]; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &multiplier_temp ) == \ @@ -490,7 +494,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \ DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ bigint_mod_multiply ( &multiplicand_temp, &multiplier_temp, \ - &modulus_temp, &result_temp ); \ + &modulus_temp, &result_temp, tmp ); \ DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ \ @@ -520,6 +524,9 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_t ( size ) modulus_temp; \ bigint_t ( exponent_size ) exponent_temp; \ bigint_t ( size ) result_temp; \ + size_t tmp_len = bigint_mod_exp_tmp_len ( &modulus_temp, \ + &exponent_temp ); \ + uint8_t tmp[tmp_len]; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &modulus_temp ) == \ @@ -536,7 +543,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ DBG_HDA ( 0, &exponent_temp, sizeof ( exponent_temp ) ); \ bigint_mod_exp ( &base_temp, &modulus_temp, &exponent_temp, \ - &result_temp ); \ + &result_temp, tmp ); \ DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ \ From d6979e0d55c9a796fdf947909be37e2bcdca918d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 20:42:03 +0000 Subject: [PATCH 086/221] [rsa] Actually check the unused-bits byte in the public key bit string Signed-off-by: Michael Brown --- src/crypto/rsa.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index a0bf39eb..6aa6e897 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -236,12 +236,13 @@ static int rsa_init ( void *ctx, const void *key, size_t key_len ) { /* Check and skip unused-bits byte of bit string */ bit_string = cursor.data; - if ( cursor.len < 1 ) { + if ( ( cursor.len < sizeof ( *bit_string ) ) || + ( bit_string->unused != 0 ) ) { rc = -EINVAL; goto err_parse; } - cursor.data++; - cursor.len--; + cursor.data = &bit_string->data; + cursor.len -= offsetof ( typeof ( *bit_string ), data ); /* Enter RSAPublicKey */ asn1_enter ( &cursor, ASN1_SEQUENCE ); From 4d3b5473f850f9c0ba7107cff397cfca4972d679 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 17:25:55 +0000 Subject: [PATCH 087/221] [tls] Add full X.509 certificate parsing Signed-off-by: Michael Brown --- src/crypto/rootcert.c | 50 ++ src/crypto/x509.c | 1179 ++++++++++++++++++++++++++++++++++- src/include/ipxe/rootcert.h | 16 + src/include/ipxe/x509.h | 216 ++++++- src/net/tls.c | 22 +- 5 files changed, 1444 insertions(+), 39 deletions(-) create mode 100644 src/crypto/rootcert.c create mode 100644 src/include/ipxe/rootcert.h diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c new file mode 100644 index 00000000..99ee9c87 --- /dev/null +++ b/src/crypto/rootcert.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2007 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include + +/** @file + * + * Root certificate store + * + */ + +/* Use iPXE root CA if no trusted certificates are explicitly specified */ +#ifndef TRUSTED +#define TRUSTED \ + /* iPXE root CA */ \ + 0x9f, 0xaf, 0x71, 0x7b, 0x7f, 0x8c, 0xa2, 0xf9, 0x3c, 0x25, \ + 0x6c, 0x79, 0xf8, 0xac, 0x55, 0x91, 0x89, 0x5d, 0x66, 0xd1, \ + 0xff, 0x3b, 0xee, 0x63, 0x97, 0xa7, 0x0d, 0x29, 0xc6, 0x5e, \ + 0xed, 0x1a, +#endif + +/** Root certificate fingerprints */ +static const uint8_t fingerprints[] = { TRUSTED }; + +/** Root certificates */ +struct x509_root root_certificates = { + .digest = &sha256_algorithm, + .count = ( sizeof ( fingerprints ) / SHA256_DIGEST_SIZE ), + .fingerprints = fingerprints, +}; diff --git a/src/crypto/x509.c b/src/crypto/x509.c index a13b671a..2a5e72ba 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -18,48 +18,1181 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#include #include +#include #include +#include #include +#include +#include +#include +#include +#include +#include #include /** @file * * X.509 certificates * - * The structure of X.509v3 certificates is concisely documented in - * RFC5280 section 4.1. The structure of RSA public keys is - * documented in RFC2313. + * The structure of X.509v3 certificates is documented in RFC 5280 + * section 4.1. */ +/* Disambiguate the various error causes */ +#define ENOTSUP_ALGORITHM \ + __einfo_error ( EINFO_ENOTSUP_ALGORITHM ) +#define EINFO_ENOTSUP_ALGORITHM \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" ) +#define ENOTSUP_EXTENSION \ + __einfo_error ( EINFO_ENOTSUP_EXTENSION ) +#define EINFO_ENOTSUP_EXTENSION \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported extension" ) +#define EINVAL_NON_SIGNATURE \ + __einfo_error ( EINFO_EINVAL_NON_SIGNATURE ) +#define EINFO_EINVAL_NON_SIGNATURE \ + __einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a signature algorithm" ) +#define EINVAL_BIT_STRING \ + __einfo_error ( EINFO_EINVAL_BIT_STRING ) +#define EINFO_EINVAL_BIT_STRING \ + __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid bit string" ) +#define EINVAL_TIME \ + __einfo_error ( EINFO_EINVAL_TIME ) +#define EINFO_EINVAL_TIME \ + __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid time" ) +#define EINVAL_ALGORITHM_MISMATCH \ + __einfo_error ( EINFO_EINVAL_ALGORITHM_MISMATCH ) +#define EINFO_EINVAL_ALGORITHM_MISMATCH \ + __einfo_uniqify ( EINFO_EINVAL, 0x04, "Signature algorithm mismatch" ) +#define EINVAL_PATH_LEN \ + __einfo_error ( EINFO_EINVAL_PATH_LEN ) +#define EINFO_EINVAL_PATH_LEN \ + __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid pathLenConstraint" ) +#define EINVAL_VERSION \ + __einfo_error ( EINFO_EINVAL_VERSION ) +#define EINFO_EINVAL_VERSION \ + __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid version" ) +#define EACCES_WRONG_ISSUER \ + __einfo_error ( EINFO_EACCES_WRONG_ISSUER ) +#define EINFO_EACCES_WRONG_ISSUER \ + __einfo_uniqify ( EINFO_EACCES, 0x01, "Wrong issuer" ) +#define EACCES_NOT_CA \ + __einfo_error ( EINFO_EACCES_NOT_CA ) +#define EINFO_EACCES_NOT_CA \ + __einfo_uniqify ( EINFO_EACCES, 0x02, "Not a CA certificate" ) +#define EACCES_KEY_USAGE \ + __einfo_error ( EINFO_EACCES_KEY_USAGE ) +#define EINFO_EACCES_KEY_USAGE \ + __einfo_uniqify ( EINFO_EACCES, 0x03, "Incorrect key usage" ) + +/** "commonName" object identifier */ +static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; + +/** "commonName" object identifier cursor */ +static struct asn1_cursor oid_common_name_cursor = + ASN1_OID_CURSOR ( oid_common_name ); + +/** "rsaEncryption" object identifier */ +static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION }; + +/** "md5WithRSAEncryption" object identifier */ +static uint8_t oid_md5_with_rsa_encryption[] = + { ASN1_OID_MD5WITHRSAENCRYPTION }; + +/** "sha1WithRSAEncryption" object identifier */ +static uint8_t oid_sha1_with_rsa_encryption[] = + { ASN1_OID_SHA1WITHRSAENCRYPTION }; + +/** "sha256WithRSAEncryption" object identifier */ +static uint8_t oid_sha256_with_rsa_encryption[] = + { ASN1_OID_SHA256WITHRSAENCRYPTION }; + +/** Supported algorithms */ +static struct x509_algorithm x509_algorithms[] = { + { + .name = "rsaEncryption", + .pubkey = &rsa_algorithm, + .digest = NULL, + .oid = ASN1_OID_CURSOR ( oid_rsa_encryption ), + }, + { + .name = "md5WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &md5_algorithm, + .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ), + }, + { + .name = "sha1WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &sha1_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ), + }, + { + .name = "sha256WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &sha256_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ), + }, +}; + /** - * Identify X.509 certificate RSA public key + * Identify X.509 algorithm by OID * - * @v certificate Certificate - * @v rsa RSA public key to fill in + * @v oid OID + * @ret algorithm Algorithm, or NULL + */ +static struct x509_algorithm * +x509_find_algorithm ( const struct asn1_cursor *oid ) { + struct x509_algorithm *algorithm; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( x509_algorithms ) / + sizeof ( x509_algorithms[0] ) ) ; i++ ) { + algorithm = &x509_algorithms[i]; + if ( asn1_compare ( &algorithm->oid, oid ) == 0 ) + return algorithm; + } + + return NULL; +} + +/** + * Parse X.509 certificate algorithm + * + * @v cert X.509 certificate + * @v algorithm Algorithm to fill in + * @v raw ASN.1 cursor * @ret rc Return status code */ -int x509_rsa_public_key ( const struct asn1_cursor *certificate, - struct x509_rsa_public_key *key ) { - struct asn1_cursor *cursor = &key->raw; +static int x509_parse_algorithm ( struct x509_certificate *cert, + struct x509_algorithm **algorithm, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; int rc; - /* Locate subjectPublicKeyInfo */ - memcpy ( cursor, certificate, sizeof ( *cursor ) ); - rc = ( asn1_enter ( cursor, ASN1_SEQUENCE ), /* Certificate */ - asn1_enter ( cursor, ASN1_SEQUENCE ), /* tbsCertificate */ - asn1_skip_if_exists ( cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/ - asn1_skip ( cursor, ASN1_INTEGER ), /* serialNumber */ - asn1_skip ( cursor, ASN1_SEQUENCE ), /* signature */ - asn1_skip ( cursor, ASN1_SEQUENCE ), /* issuer */ - asn1_skip ( cursor, ASN1_SEQUENCE ), /* validity */ - asn1_skip ( cursor, ASN1_SEQUENCE ) /* name */ ); - if ( rc != 0 ) { - DBG ( "Cannot locate subjectPublicKeyInfo in:\n" ); - DBG_HDA ( 0, certificate->data, certificate->len ); + /* Enter signatureAlgorithm */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Enter algorithm */ + if ( ( rc = asn1_enter ( &cursor, ASN1_OID ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot locate algorithm:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); return rc; } + /* Identify algorithm */ + *algorithm = x509_find_algorithm ( &cursor ); + if ( ! *algorithm ) { + DBGC ( cert, "X509 %p unsupported algorithm:\n", cert ); + DBGC_HDA ( cert, 0, cursor.data, cursor.len ); + return -ENOTSUP_ALGORITHM; + } + return 0; } + +/** + * Parse X.509 certificate signature algorithm + * + * @v cert X.509 certificate + * @v algorithm Algorithm to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_signature_algorithm ( struct x509_certificate *cert, + struct x509_algorithm **algorithm, + const struct asn1_cursor *raw ) { + int rc; + + /* Parse algorithm */ + if ( ( rc = x509_parse_algorithm ( cert, algorithm, raw ) ) != 0 ) + return rc; + + /* Check algorithm is a signature algorithm */ + if ( ! x509_is_signature_algorithm ( *algorithm ) ) { + DBGC ( cert, "X509 %p algorithm %s is not a signature " + "algorithm:\n", cert, (*algorithm)->name ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_NON_SIGNATURE; + } + + return 0; +} + +/** + * Parse X.509 certificate bit string + * + * @v cert X.509 certificate + * @v bits Bit string to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_bit_string ( struct x509_certificate *cert, + struct x509_bit_string *bits, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + const struct asn1_bit_string *bit_string; + size_t len; + unsigned int unused; + uint8_t unused_mask; + const uint8_t *last; + int rc; + + /* Enter bit string */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + if ( ( rc = asn1_enter ( &cursor, ASN1_BIT_STRING ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot locate bit string:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + + /* Validity checks */ + if ( cursor.len < sizeof ( *bit_string ) ) { + DBGC ( cert, "X509 %p invalid bit string:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_BIT_STRING; + } + bit_string = cursor.data; + len = ( cursor.len - offsetof ( typeof ( *bit_string ), data ) ); + unused = bit_string->unused; + unused_mask = ( 0xff >> ( 8 - unused ) ); + last = ( bit_string->data + len - 1 ); + if ( ( unused >= 8 ) || + ( ( unused > 0 ) && ( len == 0 ) ) || + ( ( *last & unused_mask ) != 0 ) ) { + DBGC ( cert, "X509 %p invalid bit string:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_BIT_STRING; + } + + /* Populate bit string */ + bits->data = &bit_string->data; + bits->len = len; + bits->unused = unused; + + return 0; +} + +/** + * Parse X.509 certificate bit string that must be an integral number of bytes + * + * @v cert X.509 certificate + * @v bits Bit string to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_integral_bit_string ( struct x509_certificate *cert, + struct x509_bit_string *bits, + const struct asn1_cursor *raw ) { + int rc; + + /* Parse bit string */ + if ( ( rc = x509_parse_bit_string ( cert, bits, raw ) ) != 0 ) + return rc; + + /* Check that there are no unused bits at end of string */ + if ( bits->unused ) { + DBGC ( cert, "X509 %p invalid integral bit string:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_BIT_STRING; + } + + return 0; +} + +/** + * Parse X.509 certificate time + * + * @v cert X.509 certificate + * @v time Time to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + * + * RFC 5280 section 4.1.2.5 places several restrictions on the allowed + * formats for UTCTime and GeneralizedTime, and mandates the + * interpretation of centuryless year values. + */ +static int x509_parse_time ( struct x509_certificate *cert, + struct x509_time *time, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + unsigned int have_century; + unsigned int type; + union { + struct { + uint8_t century; + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + } __attribute__ (( packed )) named; + uint8_t raw[7]; + } pairs; + const uint8_t *data; + size_t remaining; + unsigned int tens; + unsigned int units; + unsigned int i; + int rc; + + /* Determine time format utcTime/generalizedTime */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + type = asn1_type ( &cursor ); + switch ( type ) { + case ASN1_UTC_TIME: + have_century = 0; + break; + case ASN1_GENERALIZED_TIME: + have_century = 1; + break; + default: + DBGC ( cert, "X509 %p invalid time type %02x\n", cert, type ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_TIME; + } + + /* Enter utcTime/generalizedTime */ + if ( ( rc = asn1_enter ( &cursor, type ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot locate %s time:\n", cert, + ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + + /* Parse digit string a pair at a time */ + data = cursor.data; + remaining = cursor.len; + for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) { + if ( remaining < 2 ) { + DBGC ( cert, "X509 %p invalid time:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_TIME; + } + tens = data[0]; + units = data[1]; + if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) { + DBGC ( cert, "X509 %p invalid time:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_TIME; + } + pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) ); + data += 2; + remaining -= 2; + } + + /* Determine century if applicable */ + if ( ! have_century ) + pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 ); + + /* Check for trailing "Z" */ + if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) { + DBGC ( cert, "X509 %p invalid time:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_TIME; + } + + /* Fill in time */ + time->year = ( ( pairs.named.century * 100 ) + pairs.named.year ); + time->month = pairs.named.month; + time->day = pairs.named.day; + time->hour = pairs.named.hour; + time->minute = pairs.named.minute; + time->second = pairs.named.second; + + return 0; +} + +/** + * Parse X.509 certificate version + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_version ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int version; + int rc; + + /* Enter version */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + + /* Parse integer */ + if ( ( rc = asn1_integer ( &cursor, &version ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot parse version: %s\n", + cert, strerror ( rc ) ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + + /* Sanity check */ + if ( version < 0 ) { + DBGC ( cert, "X509 %p invalid version %d\n", cert, version ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_VERSION; + } + + /* Record version */ + cert->version = version; + DBGC ( cert, "X509 %p is a version %d certificate\n", + cert, ( cert->version + 1 ) ); + + return 0; +} + +/** + * Parse X.509 certificate issuer + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_issuer ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_issuer *issuer = &cert->issuer; + int rc; + + /* Record raw issuer */ + memcpy ( &issuer->raw, raw, sizeof ( issuer->raw ) ); + if ( ( rc = asn1_shrink ( &issuer->raw, ASN1_SEQUENCE ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot shrink issuer: %s\n", + cert, strerror ( rc ) ); + return rc; + } + DBGC ( cert, "X509 %p issuer is:\n", cert ); + DBGC_HDA ( cert, 0, issuer->raw.data, issuer->raw.len ); + + return 0; +} + +/** + * Parse X.509 certificate validity + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_validity ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_validity *validity = &cert->validity; + struct x509_time *not_before = &validity->not_before; + struct x509_time *not_after = &validity->not_after; + struct asn1_cursor cursor; + int rc; + + /* Enter validity */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse notBefore */ + if ( ( rc = x509_parse_time ( cert, not_before, &cursor ) ) != 0 ) + return rc; + DBGC ( cert, "X509 %p valid from %04d-%02d-%02d %02d:%02d:%02d\n", + cert, not_before->year, not_before->month, not_before->day, + not_before->hour, not_before->minute, not_before->second ); + asn1_skip_any ( &cursor ); + + /* Parse notAfter */ + if ( ( rc = x509_parse_time ( cert, not_after, &cursor ) ) != 0 ) + return rc; + DBGC ( cert, "X509 %p valid until %04d-%02d-%02d %02d:%02d:%02d\n", + cert, not_after->year, not_after->month, not_after->day, + not_after->hour, not_after->minute, not_after->second ); + + return 0; +} + +/** + * Parse X.509 certificate common name + * + * @v cert X.509 certificate + * @v name Common name to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_common_name ( struct x509_certificate *cert, + struct x509_name *name, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + struct asn1_cursor oid_cursor; + struct asn1_cursor name_cursor; + int rc; + + /* Enter name */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Scan through name list */ + for ( ; cursor.len ; asn1_skip_any ( &cursor ) ) { + memcpy ( &oid_cursor, &cursor, sizeof ( oid_cursor ) ); + asn1_enter ( &oid_cursor, ASN1_SET ); + asn1_enter ( &oid_cursor, ASN1_SEQUENCE ); + memcpy ( &name_cursor, &oid_cursor, sizeof ( name_cursor ) ); + asn1_enter ( &oid_cursor, ASN1_OID ); + if ( asn1_compare ( &oid_common_name_cursor, &oid_cursor ) != 0) + continue; + asn1_skip_any ( &name_cursor ); + if ( ( rc = asn1_enter_any ( &name_cursor ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot locate name:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + name->data = name_cursor.data; + name->len = name_cursor.len; + return 0; + } + + DBGC ( cert, "X509 %p no commonName found:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -ENOENT; +} + +/** + * Parse X.509 certificate subject + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_subject ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_subject *subject = &cert->subject; + struct x509_name *name = &subject->name; + int rc; + + /* Record raw subject */ + memcpy ( &subject->raw, raw, sizeof ( subject->raw ) ); + asn1_shrink_any ( &subject->raw ); + DBGC ( cert, "X509 %p subject is:\n", cert ); + DBGC_HDA ( cert, 0, subject->raw.data, subject->raw.len ); + + /* Parse common name */ + if ( ( rc = x509_parse_common_name ( cert, name, raw ) ) != 0 ) + return rc; + DBGC ( cert, "X509 %p common name is:\n", cert ); + DBGC_HDA ( cert, 0, name->data, name->len ); + + return 0; +} + +/** + * Parse X.509 certificate public key information + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_public_key ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_public_key *public_key = &cert->subject.public_key; + struct x509_algorithm **algorithm = &public_key->algorithm; + struct asn1_cursor cursor; + int rc; + + /* Record raw subjectPublicKeyInfo */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_shrink_any ( &cursor ); + memcpy ( &public_key->raw, &cursor, sizeof ( public_key->raw ) ); + + /* Enter subjectPublicKeyInfo */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse algorithm */ + if ( ( rc = x509_parse_algorithm ( cert, algorithm, &cursor ) ) != 0 ) + return rc; + DBGC ( cert, "X509 %p public key algorithm is %s\n", + cert, (*algorithm)->name ); + DBGC ( cert, "X509 %p public key is:\n", cert ); + DBGC_HDA ( cert, 0, public_key->raw.data, public_key->raw.len ); + + return 0; +} + +/** + * Parse X.509 certificate basic constraints + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_basic_constraints ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_basic_constraints *basic = &cert->extensions.basic; + struct asn1_cursor cursor; + int ca = 0; + int path_len; + int rc; + + /* Enter basicConstraints */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse "cA", if present */ + if ( asn1_type ( &cursor ) == ASN1_BOOLEAN ) { + ca = asn1_boolean ( &cursor ); + if ( ca < 0 ) { + rc = ca; + DBGC ( cert, "X509 %p cannot parse cA: %s\n", + cert, strerror ( rc ) ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + asn1_skip_any ( &cursor ); + } + basic->ca = ca; + DBGC ( cert, "X509 %p is %sa CA certificate\n", + cert, ( basic->ca ? "" : "not " ) ); + + /* Ignore everything else unless "cA" is true */ + if ( ! ca ) + return 0; + + /* Parse "pathLenConstraint", if present and applicable */ + basic->path_len = -1U; /* Default is unlimited */ + if ( asn1_type ( &cursor ) == ASN1_INTEGER ) { + if ( ( rc = asn1_integer ( &cursor, &path_len ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot parse pathLenConstraint: " + "%s\n", cert, strerror ( rc ) ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + if ( path_len < 0 ) { + DBGC ( cert, "X509 %p invalid pathLenConstraint %d\n", + cert, path_len ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL; + } + basic->path_len = path_len; + DBGC ( cert, "X509 %p path length constraint is %u\n", + cert, basic->path_len ); + } + + return 0; +} + +/** + * Parse X.509 certificate key usage + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_key_usage ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_key_usage *usage = &cert->extensions.usage; + struct x509_bit_string bit_string; + const uint8_t *bytes; + size_t len; + unsigned int i; + int rc; + + /* Mark extension as present */ + usage->present = 1; + + /* Parse bit string */ + if ( ( rc = x509_parse_bit_string ( cert, &bit_string, raw ) ) != 0 ) + return rc; + + /* Parse key usage bits */ + bytes = bit_string.data; + len = bit_string.len; + if ( len > sizeof ( usage->bits ) ) + len = sizeof ( usage->bits ); + for ( i = 0 ; i < len ; i++ ) { + usage->bits |= ( *(bytes++) << ( 8 * i ) ); + } + DBGC ( cert, "X509 %p key usage is %08x\n", cert, usage->bits ); + + return 0; +} + +/** "id-ce-basicConstraints" object identifier */ +static uint8_t oid_ce_basic_constraints[] = { ASN1_OID_BASICCONSTRAINTS }; + +/** "id-ce-keyUsage" object identifier */ +static uint8_t oid_ce_key_usage[] = { ASN1_OID_KEYUSAGE }; + +/** Supported certificate extensions */ +static struct x509_extension x509_extensions[] = { + { + .name = "basicConstraints", + .oid = ASN1_OID_CURSOR ( oid_ce_basic_constraints ), + .parse = x509_parse_basic_constraints, + }, + { + .name = "keyUsage", + .oid = ASN1_OID_CURSOR ( oid_ce_key_usage ), + .parse = x509_parse_key_usage, + }, +}; + +/** + * Identify X.509 extension by OID + * + * @v oid OID + * @ret extension Extension, or NULL + */ +static struct x509_extension * +x509_find_extension ( const struct asn1_cursor *oid ) { + struct x509_extension *extension; + unsigned int i; + + for ( i = 0 ; i < ( sizeof ( x509_extensions ) / + sizeof ( x509_extensions[0] ) ) ; i++ ) { + extension = &x509_extensions[i]; + if ( asn1_compare ( &extension->oid, oid ) == 0 ) + return extension; + } + + return NULL; +} + +/** + * Parse X.509 certificate extension + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_extension ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + struct asn1_cursor subcursor; + struct x509_extension *extension; + int is_critical = 0; + int rc; + + /* Enter extension */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Try to identify extension */ + memcpy ( &subcursor, &cursor, sizeof ( subcursor ) ); + asn1_enter ( &subcursor, ASN1_OID ); + extension = x509_find_extension ( &subcursor ); + asn1_skip_any ( &cursor ); + DBGC ( cert, "X509 %p found extension %s\n", + cert, ( extension ? extension->name : "" ) ); + + /* Identify criticality */ + if ( asn1_type ( &cursor ) == ASN1_BOOLEAN ) { + is_critical = asn1_boolean ( &cursor ); + if ( is_critical < 0 ) { + rc = is_critical; + DBGC ( cert, "X509 %p cannot parse extension " + "criticality: %s\n", cert, strerror ( rc ) ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + asn1_skip_any ( &cursor ); + } + + /* Handle unknown extensions */ + if ( ! extension ) { + if ( is_critical ) { + /* Fail if we cannot handle a critical extension */ + DBGC ( cert, "X509 %p cannot handle critical " + "extension:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -ENOTSUP_EXTENSION; + } else { + /* Ignore unknown non-critical extensions */ + return 0; + } + }; + + /* Extract extnValue */ + if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) { + DBGC ( cert, "X509 %p extension missing extnValue:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + + /* Parse extension */ + if ( ( rc = extension->parse ( cert, &cursor ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Parse X.509 certificate extensions, if present + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_extensions ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter extensions, if present */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 3 ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse each extension in turn */ + while ( cursor.len ) { + if ( ( rc = x509_parse_extension ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + } + + return 0; +} + +/** + * Parse X.509 certificate tbsCertificate + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_tbscertificate ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_algorithm **algorithm = &cert->signature_algorithm; + struct asn1_cursor cursor; + int rc; + + /* Record raw tbsCertificate */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_shrink_any ( &cursor ); + memcpy ( &cert->tbs, &cursor, sizeof ( cert->tbs ) ); + + /* Enter tbsCertificate */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse version, if present */ + if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) { + if ( ( rc = x509_parse_version ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + } + + /* Skip serialNumber */ + asn1_skip ( &cursor, ASN1_INTEGER ); + + /* Parse signature */ + if ( ( rc = x509_parse_signature_algorithm ( cert, algorithm, + &cursor ) ) != 0 ) + return rc; + DBGC ( cert, "X509 %p tbsCertificate signature algorithm is %s\n", + cert, (*algorithm)->name ); + asn1_skip_any ( &cursor ); + + /* Parse issuer */ + if ( ( rc = x509_parse_issuer ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse validity */ + if ( ( rc = x509_parse_validity ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse subject */ + if ( ( rc = x509_parse_subject ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse subjectPublicKeyInfo */ + if ( ( rc = x509_parse_public_key ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse extensions, if present */ + if ( ( rc = x509_parse_extensions ( cert, &cursor ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Parse X.509 certificate from ASN.1 data + * + * @v cert X.509 certificate + * @v data Raw certificate data + * @v len Length of raw data + * @ret rc Return status code + */ +int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ) { + struct x509_signature *signature = &cert->signature; + struct x509_algorithm **signature_algorithm = &signature->algorithm; + struct x509_bit_string *signature_value = &signature->value; + struct asn1_cursor cursor; + int rc; + + /* Initialise certificate */ + memset ( cert, 0, sizeof ( *cert ) ); + cert->raw.data = data; + cert->raw.len = len; + + /* Enter certificate */ + memcpy ( &cursor, &cert->raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse tbsCertificate */ + if ( ( rc = x509_parse_tbscertificate ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse signatureAlgorithm */ + if ( ( rc = x509_parse_signature_algorithm ( cert, signature_algorithm, + &cursor ) ) != 0 ) + return rc; + DBGC ( cert, "X509 %p signatureAlgorithm is %s\n", + cert, (*signature_algorithm)->name ); + asn1_skip_any ( &cursor ); + + /* Parse signatureValue */ + if ( ( rc = x509_parse_integral_bit_string ( cert, signature_value, + &cursor ) ) != 0 ) + return rc; + DBGC ( cert, "X509 %p signatureValue is:\n", cert ); + DBGC_HDA ( cert, 0, signature_value->data, signature_value->len ); + + /* Check that algorithm in tbsCertificate matches algorithm in + * signature + */ + if ( signature->algorithm != (*signature_algorithm) ) { + DBGC ( cert, "X509 %p signature algorithm %s does not match " + "signatureAlgorithm %s\n", + cert, signature->algorithm->name, + (*signature_algorithm)->name ); + return -EINVAL_ALGORITHM_MISMATCH; + } + + return 0; +} + +/** + * Verify X.509 certificate signature + * + * @v cert X.509 certificate + * @v public_key X.509 public key + * @ret rc Return status code + */ +static int x509_check_signature ( struct x509_certificate *cert, + struct x509_public_key *public_key ) { + struct x509_signature *signature = &cert->signature; + struct x509_algorithm *algorithm = signature->algorithm; + struct digest_algorithm *digest = algorithm->digest; + struct pubkey_algorithm *pubkey = algorithm->pubkey; + uint8_t digest_ctx[ digest->ctxsize ]; + uint8_t digest_out[ digest->digestsize ]; + uint8_t pubkey_ctx[ pubkey->ctxsize ]; + int rc; + + /* Sanity check */ + assert ( cert->signature_algorithm == cert->signature.algorithm ); + + /* Calculate certificate digest */ + digest_init ( digest, digest_ctx ); + digest_update ( digest, digest_ctx, cert->tbs.data, cert->tbs.len ); + digest_final ( digest, digest_ctx, digest_out ); + DBGC ( cert, "X509 %p digest:\n", cert ); + DBGC_HDA ( cert, 0, digest_out, sizeof ( digest_out ) ); + + /* Check that signature public key algorithm matches signer */ + if ( public_key->algorithm->pubkey != pubkey ) { + DBGC ( cert, "X509 %p signature algorithm %s does not match " + "signer's algorithm %s\n", + cert, algorithm->name, public_key->algorithm->name ); + rc = -EINVAL_ALGORITHM_MISMATCH; + goto err_mismatch; + } + + /* Verify signature using signer's public key */ + if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, + public_key->raw.len ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot initialise public key: %s\n", + cert, strerror ( rc ) ); + goto err_pubkey_init; + } + if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, + signature->value.data, + signature->value.len ) ) != 0 ) { + DBGC ( cert, "X509 %p signature verification failed: %s\n", + cert, strerror ( rc ) ); + goto err_pubkey_verify; + } + + /* Success */ + rc = 0; + + err_pubkey_verify: + pubkey_final ( pubkey, pubkey_ctx ); + err_pubkey_init: + err_mismatch: + return rc; +} + +/** + * Validate X.509 certificate against signing certificate + * + * @v cert X.509 certificate + * @v issuer X.509 issuer certificate + * @ret rc Return status code + */ +int x509_validate ( struct x509_certificate *cert, + struct x509_certificate *issuer ) { + struct x509_public_key *public_key = &issuer->subject.public_key; + int rc; + + /* Check issuer. In theory, this should be a full X.500 DN + * comparison, which would require support for a plethora of + * abominations such as TeletexString (which allows the + * character set to be changed mid-string using escape codes). + * In practice, we assume that anyone who deliberately changes + * the encoding of the issuer DN is probably a masochist who + * will rather enjoy the process of figuring out exactly why + * their certificate doesn't work. + * + * See http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt + * for some enjoyable ranting on this subject. + */ + if ( asn1_compare ( &cert->issuer.raw, &issuer->subject.raw ) != 0 ) { + DBGC ( cert, "X509 %p issuer does not match X509 %p subject\n", + cert, issuer ); + DBGC_HDA ( cert, 0, cert->issuer.raw.data, + cert->issuer.raw.len ); + DBGC_HDA ( issuer, 0, issuer->subject.raw.data, + issuer->subject.raw.len ); + return -EACCES_WRONG_ISSUER; + } + + /* Check that issuer is allowed to sign certificates */ + if ( ! issuer->extensions.basic.ca ) { + DBGC ( issuer, "X509 %p cannot sign X509 %p: not a CA " + "certificate\n", issuer, cert ); + return -EACCES_NOT_CA; + } + if ( issuer->extensions.usage.present && + ( ! ( issuer->extensions.usage.bits & X509_KEY_CERT_SIGN ) ) ) { + DBGC ( issuer, "X509 %p cannot sign X509 %p: no keyCertSign " + "usage\n", issuer, cert ); + return -EACCES_KEY_USAGE; + } + + /* Check signature */ + if ( ( rc = x509_check_signature ( cert, public_key ) ) != 0 ) + return rc; + + DBGC ( cert, "X509 %p successfully validated using X509 %p\n", + cert, issuer ); + return 0; +} + +/** + * Calculate X.509 certificate fingerprint + * + * @v cert X.509 certificate + * @v digest Digest algorithm + * @v fingerprint Fingerprint buffer + */ +void x509_fingerprint ( struct x509_certificate *cert, + struct digest_algorithm *digest, void *fingerprint ) { + uint8_t ctx[ digest->ctxsize ]; + + /* Calculate fingerprint */ + digest_init ( digest, ctx ); + digest_update ( digest, ctx, cert->raw.data, cert->raw.len ); + digest_final ( digest, ctx, fingerprint ); +} + +/** + * Validate X.509 root certificate + * + * @v cert X.509 certificate + * @v root X.509 root certificate store + * @ret rc Return status code + */ +int x509_validate_root ( struct x509_certificate *cert, + struct x509_root *root ) { + struct digest_algorithm *digest = root->digest; + uint8_t fingerprint[ digest->digestsize ]; + const uint8_t *root_fingerprint = root->fingerprints; + unsigned int i; + + /* Calculate certificate fingerprint */ + x509_fingerprint ( cert, digest, fingerprint ); + + /* Check fingerprint against all root certificates */ + for ( i = 0 ; i < root->count ; i++ ) { + if ( memcmp ( fingerprint, root_fingerprint, + sizeof ( fingerprint ) ) == 0 ) { + DBGC ( cert, "X509 %p is a root certificate\n", cert ); + return 0; + } + root_fingerprint += sizeof ( fingerprint ); + } + + DBGC ( cert, "X509 %p is not a root certificate\n", cert ); + return -ENOENT; +} + +/** + * Validate X.509 certificate chain + * + * @v parse_next Parse next X.509 certificate in chain + * @v context Context for parse_next() + * @v root Root certificate store, or NULL to use default + * @v first Initial X.509 certificate to fill in, or NULL + * @ret rc Return status code + */ +int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, + void *context ), + void *context, + struct x509_root *root, + struct x509_certificate *first ) { + struct x509_certificate temp[2]; + struct x509_certificate *current = &temp[0]; + struct x509_certificate *next = &temp[1]; + struct x509_certificate *swap; + int rc; + + /* Use default root certificate store if none specified */ + if ( ! root ) + root = &root_certificates; + + /* Get first certificate in chain */ + if ( ( rc = parse_next ( current, context ) ) != 0 ) { + DBGC ( context, "X509 chain %p could not get first " + "certificate: %s\n", context, strerror ( rc ) ); + return rc; + } + + /* Record first certificate, if applicable */ + if ( first ) + memcpy ( first, current, sizeof ( *first ) ); + + /* Process chain */ + while ( 1 ) { + + /* Succeed if we have reached a root certificate */ + if ( x509_validate_root ( current, root ) == 0 ) + return 0; + + /* Get next certificate in chain */ + if ( ( rc = parse_next ( next, context ) ) != 0 ) { + DBGC ( context, "X509 chain %p could not get next " + "certificate: %s\n", context, strerror ( rc ) ); + return rc; + } + + /* Validate current certificate */ + if ( ( rc = x509_validate ( current, next ) ) != 0 ) + return rc; + + /* Move to next certificate in chain */ + swap = current; + current = next; + next = swap; + } +} diff --git a/src/include/ipxe/rootcert.h b/src/include/ipxe/rootcert.h new file mode 100644 index 00000000..6525df87 --- /dev/null +++ b/src/include/ipxe/rootcert.h @@ -0,0 +1,16 @@ +#ifndef _IPXE_ROOTCERT_H +#define _IPXE_ROOTCERT_H + +/** @file + * + * Root certificate store + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +extern struct x509_root root_certificates; + +#endif /* _IPXE_ROOTCERT_H */ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index f8cffabd..4da4539f 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -10,16 +10,220 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include +#include #include -/** An X.509 RSA public key */ -struct x509_rsa_public_key { - /** Raw public key */ +/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */ +#define ASN1_OID_ATTRIBUTE_TYPE \ + ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */ +#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 ) + +/** ASN.1 OID for id-ce */ +#define ASN1_OID_CE ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 29 ) + +/** ASN.1 OID for id-ce-keyUsage */ +#define ASN1_OID_KEYUSAGE ASN1_OID_CE, ASN1_OID_SINGLE ( 15 ) + +/** ASN.1 OID for id-ce-basicConstraints */ +#define ASN1_OID_BASICCONSTRAINTS ASN1_OID_CE, ASN1_OID_SINGLE ( 19 ) + +/** An X.509 algorithm */ +struct x509_algorithm { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Public-key algorithm */ + struct pubkey_algorithm *pubkey; + /** Digest algorithm (if applicable) */ + struct digest_algorithm *digest; +}; + +/** + * Test if X.509 algorithm is a signature algorithm + * + * @v algorithm Algorithm + * @ret is_signature Algorithm is a signature algorithm + */ +static inline __attribute__ (( always_inline )) int +x509_is_signature_algorithm ( struct x509_algorithm *algorithm ) { + return ( algorithm->digest != NULL ); +} + +/** An X.509 bit string */ +struct x509_bit_string { + /** Data */ + const void *data; + /** Length */ + size_t len; + /** Unused bits at end of data */ + unsigned int unused; +}; + +/** An X.509 issuer */ +struct x509_issuer { + /** Raw issuer */ struct asn1_cursor raw; }; -extern int x509_rsa_public_key ( const struct asn1_cursor *certificate, - struct x509_rsa_public_key *rsa_pubkey ); +/** An X.509 time */ +struct x509_time { + /** Year */ + uint16_t year; + /** Month */ + uint8_t month; + /** Day */ + uint8_t day; + /** Hour */ + uint8_t hour; + /** Minute */ + uint8_t minute; + /** Second */ + uint8_t second; +}; + +/** An X.509 certificate validity period */ +struct x509_validity { + /** Not valid before */ + struct x509_time not_before; + /** Not valid after */ + struct x509_time not_after; +}; + +/** An X.509 name */ +struct x509_name { + /** Name (not NUL-terminated) */ + const void *data; + /** Length of name */ + size_t len; +}; + +/** An X.509 certificate public key */ +struct x509_public_key { + /** Raw public key */ + struct asn1_cursor raw; + /** Public key algorithm */ + struct x509_algorithm *algorithm; +}; + +/** An X.509 certificate subject */ +struct x509_subject { + /** Raw subject */ + struct asn1_cursor raw; + /** Common name */ + struct x509_name name; + /** Public key information */ + struct x509_public_key public_key; +}; + +/** An X.509 certificate signature */ +struct x509_signature { + /** Signature algorithm */ + struct x509_algorithm *algorithm; + /** Signature value */ + struct x509_bit_string value; +}; + +/** An X.509 certificate basic constraints set */ +struct x509_basic_constraints { + /** Subject is a CA */ + int ca; + /** Path length */ + unsigned int path_len; +}; + +/** An X.509 certificate key usage */ +struct x509_key_usage { + /** Key usage extension is present */ + int present; + /** Usage bits */ + unsigned int bits; +}; + +/** X.509 certificate key usage bits */ +enum x509_key_usage_bits { + X509_DIGITAL_SIGNATURE = 0x0080, + X509_NON_REPUDIATION = 0x0040, + X509_KEY_ENCIPHERMENT = 0x0020, + X509_DATA_ENCIPHERMENT = 0x0010, + X509_KEY_AGREEMENT = 0x0008, + X509_KEY_CERT_SIGN = 0x0004, + X509_CRL_SIGN = 0x0002, + X509_ENCIPHER_ONLY = 0x0001, + X509_DECIPHER_ONLY = 0x8000, +}; + +/** An X.509 certificate extensions set */ +struct x509_extensions { + /** Basic constraints */ + struct x509_basic_constraints basic; + /** Key usage */ + struct x509_key_usage usage; +}; + +/** An X.509 certificate */ +struct x509_certificate { + /** Raw certificate */ + struct asn1_cursor raw; + /** Version */ + unsigned int version; + /** Raw tbsCertificate */ + struct asn1_cursor tbs; + /** Signature algorithm */ + struct x509_algorithm *signature_algorithm; + /** Issuer */ + struct x509_issuer issuer; + /** Validity */ + struct x509_validity validity; + /** Subject */ + struct x509_subject subject; + /** Signature */ + struct x509_signature signature; + /** Extensions */ + struct x509_extensions extensions; +}; + +/** An X.509 extension */ +struct x509_extension { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Parse extension + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ + int ( * parse ) ( struct x509_certificate *cert, + const struct asn1_cursor *raw ); +}; + +/** An X.509 root certificate store */ +struct x509_root { + /** Fingerprint digest algorithm */ + struct digest_algorithm *digest; + /** Number of certificates */ + unsigned int count; + /** Certificate fingerprints */ + const void *fingerprints; +}; + +extern int x509_parse ( struct x509_certificate *cert, + const void *data, size_t len ); +extern int x509_validate ( struct x509_certificate *cert, + struct x509_certificate *issuer ); +extern void x509_fingerprint ( struct x509_certificate *cert, + struct digest_algorithm *digest, + void *fingerprint ); +extern int x509_validate_root ( struct x509_certificate *cert, + struct x509_root *root ); +extern int x509_validate_chain ( int ( * parse_next ) + ( struct x509_certificate *cert, + void *context ), + void *context, struct x509_root *root, + struct x509_certificate *first ); #endif /* _IPXE_X509_H */ diff --git a/src/net/tls.c b/src/net/tls.c index 7ec5745f..5e2bbdc4 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1026,8 +1026,10 @@ static int tls_new_certificate ( struct tls_session *tls, const void *end = ( certificate->certificates + elements_len ); struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; - struct asn1_cursor cursor; - struct x509_rsa_public_key key; + struct x509_certificate cert; + struct x509_public_key *key = &cert.subject.public_key; + const void *cert_data; + size_t cert_len; int rc; /* Sanity check */ @@ -1040,9 +1042,9 @@ static int tls_new_certificate ( struct tls_session *tls, /* Traverse certificate chain */ do { - cursor.data = element->certificate; - cursor.len = tls_uint24 ( element->length ); - if ( ( cursor.data + cursor.len ) > end ) { + cert_data = element->certificate; + cert_len = tls_uint24 ( element->length ); + if ( ( cert_data + cert_len ) > end ) { DBGC ( tls, "TLS %p received corrupt Server " "Certificate\n", tls ); DBGC_HD ( tls, data, len ); @@ -1050,23 +1052,23 @@ static int tls_new_certificate ( struct tls_session *tls, } // HACK - if ( ( rc = x509_rsa_public_key ( &cursor, &key ) ) != 0 ) { - DBGC ( tls, "TLS %p cannot parse public key: %s\n", + + /* Parse certificate */ + if ( ( rc = x509_parse ( &cert, cert_data, cert_len ) ) != 0 ) { + DBGC ( tls, "TLS %p cannot parse certificate: %s\n", tls, strerror ( rc ) ); return rc; } /* Initialise public key algorithm */ if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx, - key.raw.data, key.raw.len ) ) != 0){ + key->raw.data, key->raw.len ) ) != 0){ DBGC ( tls, "TLS %p cannot initialise public key: %s\n", tls, strerror ( rc ) ); return rc; } return 0; - - element = ( cursor.data + cursor.len ); } while ( element != end ); return -EINVAL; From aee3a064f22f994a930990c1bb0d339412e65d76 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 22:55:29 +0000 Subject: [PATCH 088/221] [build] Allow trusted root certificates to be specified at build time Allow trusted root certificates to be specified at build time using the syntax make TRUST=/path/to/certificate1,/path/to/certificate2,... The build process uses openssl to calculate the SHA-256 fingerprints of the specified certificates, and adds them to the root certificate store in rootcert.c. The certificates can be in any format understood by openssl. The certificates may be server certificates or (more usefully) CA certificates. If no trusted certificates are specified, then the default "iPXE root CA" certificate will be used. Signed-off-by: Michael Brown --- src/Makefile | 1 + src/Makefile.housekeeping | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Makefile b/src/Makefile index c30dc5c9..0189a469 100644 --- a/src/Makefile +++ b/src/Makefile @@ -32,6 +32,7 @@ RANLIB := $(CROSS_COMPILE)ranlib OBJCOPY := $(CROSS_COMPILE)objcopy NM := $(CROSS_COMPILE)nm OBJDUMP := $(CROSS_COMPILE)objdump +OPENSSL := openssl PARSEROM := ./util/parserom.pl FIXROM := ./util/fixrom.pl SYMCHECK := ./util/symcheck.pl diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index 41c59562..daac97b9 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -637,6 +637,34 @@ $(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC) CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)" +# List of trusted root certificates +# +TRUSTED_LIST := $(BIN)/.trusted.list +ifeq ($(wildcard $(TRUSTED_LIST)),) +TRUST_OLD := +else +TRUST_OLD := $(shell cat $(TRUSTED_LIST)) +endif +ifneq ($(TRUST_OLD),$(TRUST)) +$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST)) +endif + +$(TRUSTED_LIST) : + +VERYCLEANUP += $(TRUSTED_LIST) + +# Trusted root certificate fingerprints +# +TRUSTED_CERTS := $(subst $(COMMA), ,$(TRUST)) +TRUSTED_FPS := $(foreach CERT,$(TRUSTED_CERTS),\ + 0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\ + $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \ + -fingerprint))))$(COMMA)) + +$(BIN)/rootcert.o : $(TRUSTED_FILES) $(TRUSTED_LIST) + +CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)") + # Generate error usage information # $(BIN)/%.einfo : $(BIN)/%.o From f3a791c6dec83c506476b4d80f497142c7753e48 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 20:17:41 +0000 Subject: [PATCH 089/221] [tls] Validate server certificate Validate the server certificate against the trusted root certificate store. The server must provide a complete certificate chain, up to and including the trusted root certificate that is embedded into iPXE. Note that the date and time are not yet validated. Signed-off-by: Michael Brown --- src/net/tls.c | 129 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 36 deletions(-) diff --git a/src/net/tls.c b/src/net/tls.c index 5e2bbdc4..1688dfc3 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -43,6 +43,16 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +/* Disambiguate the various error causes */ +#define EACCES_UNTRUSTED \ + __einfo_error ( EINFO_EACCES_UNTRUSTED ) +#define EINFO_EACCES_UNTRUSTED \ + __einfo_uniqify ( EINFO_EACCES, 0x01, "Untrusted certificate chain" ) +#define EACCES_WRONG_NAME \ + __einfo_error ( EINFO_EACCES_WRONG_NAME ) +#define EINFO_EACCES_WRONG_NAME \ + __einfo_uniqify ( EINFO_EACCES, 0x02, "Incorrect server name" ) + static int tls_send_plaintext ( struct tls_session *tls, unsigned int type, const void *data, size_t len ); static void tls_clear_cipher ( struct tls_session *tls, @@ -1003,6 +1013,63 @@ static int tls_new_server_hello ( struct tls_session *tls, return 0; } +/** TLS certificate chain context */ +struct tls_certificate_context { + /** TLS session */ + struct tls_session *tls; + /** Current certificate */ + const void *current; + /** End of certificates */ + const void *end; +}; + +/** + * Parse next certificate in TLS certificate list + * + * @v cert X.509 certificate to fill in + * @v ctx Context + * @ret rc Return status code + */ +static int tls_parse_next ( struct x509_certificate *cert, void *ctx ) { + struct tls_certificate_context *context = ctx; + struct tls_session *tls = context->tls; + const struct { + uint8_t length[3]; + uint8_t certificate[0]; + } __attribute__ (( packed )) *current = context->current; + const void *data; + const void *next; + size_t len; + int rc; + + /* Return error at end of chain */ + if ( context->current >= context->end ) { + DBGC ( tls, "TLS %p reached end of certificate chain\n", tls ); + return -EACCES_UNTRUSTED; + } + + /* Extract current certificate and update context */ + data = current->certificate; + len = tls_uint24 ( current->length ); + next = ( data + len ); + if ( next > context->end ) { + DBGC ( tls, "TLS %p overlength certificate\n", tls ); + DBGC_HDA ( tls, 0, context->current, + ( context->end - context->current ) ); + return -EINVAL; + } + context->current = next; + + /* Parse current certificate */ + if ( ( rc = x509_parse ( cert, data, len ) ) != 0 ) { + DBGC ( tls, "TLS %p could not parse certificate: %s\n", + tls, strerror ( rc ) ); + return rc; + } + + return 0; +} + /** * Receive new Certificate handshake record * @@ -1017,19 +1084,14 @@ static int tls_new_certificate ( struct tls_session *tls, uint8_t length[3]; uint8_t certificates[0]; } __attribute__ (( packed )) *certificate = data; - const struct { - uint8_t length[3]; - uint8_t certificate[0]; - } __attribute__ (( packed )) *element = - ( ( void * ) certificate->certificates ); size_t elements_len = tls_uint24 ( certificate->length ); const void *end = ( certificate->certificates + elements_len ); struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending; struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; + struct tls_certificate_context context; struct x509_certificate cert; + struct x509_name *name = &cert.subject.name; struct x509_public_key *key = &cert.subject.public_key; - const void *cert_data; - size_t cert_len; int rc; /* Sanity check */ @@ -1040,38 +1102,33 @@ static int tls_new_certificate ( struct tls_session *tls, return -EINVAL; } - /* Traverse certificate chain */ - do { - cert_data = element->certificate; - cert_len = tls_uint24 ( element->length ); - if ( ( cert_data + cert_len ) > end ) { - DBGC ( tls, "TLS %p received corrupt Server " - "Certificate\n", tls ); - DBGC_HD ( tls, data, len ); - return -EINVAL; - } + /* Parse first certificate and validate certificate chain */ + context.tls = tls; + context.current = certificate->certificates; + context.end = end; + if ( ( rc = x509_validate_chain ( tls_parse_next, &context, + NULL, &cert ) ) != 0 ) { + DBGC ( tls, "TLS %p could not validate certificate chain: %s\n", + tls, strerror ( rc ) ); + return rc; + } - // HACK + /* Verify server name */ + if ( ( name->len != strlen ( tls->name ) ) || + ( memcmp ( name->data, tls->name, name->len ) != 0 ) ) { + DBGC ( tls, "TLS %p server name incorrect\n", tls ); + return -EACCES_WRONG_NAME; + } - /* Parse certificate */ - if ( ( rc = x509_parse ( &cert, cert_data, cert_len ) ) != 0 ) { - DBGC ( tls, "TLS %p cannot parse certificate: %s\n", - tls, strerror ( rc ) ); - return rc; - } + /* Initialise public key algorithm */ + if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx, + key->raw.data, key->raw.len ) ) != 0 ) { + DBGC ( tls, "TLS %p cannot initialise public key: %s\n", + tls, strerror ( rc ) ); + return rc; + } - /* Initialise public key algorithm */ - if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx, - key->raw.data, key->raw.len ) ) != 0){ - DBGC ( tls, "TLS %p cannot initialise public key: %s\n", - tls, strerror ( rc ) ); - return rc; - } - - return 0; - } while ( element != end ); - - return -EINVAL; + return 0; } /** From 0b2c7885c74ae680509e07c552e594f3787900f8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 17:22:52 +0000 Subject: [PATCH 090/221] [crypto] Use correct constraint for byte-addressable register Reported-by: Daniel P. Berrange Signed-off-by: Michael Brown --- src/arch/x86/include/bits/bigint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index 4c9aed62..d3449af5 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -183,7 +183,7 @@ bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0, "loope 1b\n\t" "setae %b0\n\t" "cld\n\t" - : "=r" ( result ), "=&S" ( discard_S ), + : "=q" ( result ), "=&S" ( discard_S ), "=&D" ( discard_D ), "=&c" ( discard_c ) : "0" ( 0 ), "1" ( &value->element[ size - 1 ] ), "2" ( &reference->element[ size - 1 ] ), From bd6805a8c18f859a8f467965f2ee780817d8a81e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 16:09:41 +0000 Subject: [PATCH 091/221] [libc] Add mktime() function Signed-off-by: Michael Brown --- src/core/time.c | 137 +++++++++++++++++++++++++++++++++++++++++ src/include/sys/time.h | 24 ++++---- src/include/time.h | 37 +++++++---- 3 files changed, 173 insertions(+), 25 deletions(-) create mode 100644 src/core/time.c diff --git a/src/core/time.c b/src/core/time.c new file mode 100644 index 00000000..52ae3ee9 --- /dev/null +++ b/src/core/time.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +/** @file + * + * Date and time + * + * POSIX:2008 section 4.15 defines "seconds since the Epoch" as an + * abstract measure approximating the number of seconds that have + * elapsed since the Epoch, excluding leap seconds. The formula given + * is + * + * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + + * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - + * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400 + * + * This calculation assumes that leap years occur in each year that is + * either divisible by 4 but not divisible by 100, or is divisible by + * 400. + */ + +/** Days of week (for debugging) */ +static const char *weekdays[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +/** + * Determine whether or not year is a leap year + * + * @v tm_year Years since 1900 + * @v is_leap_year Year is a leap year + */ +static int is_leap_year ( int tm_year ) { + int leap_year = 0; + + if ( ( tm_year % 4 ) == 0 ) + leap_year = 1; + if ( ( tm_year % 100 ) == 0 ) + leap_year = 0; + if ( ( tm_year % 400 ) == 100 ) + leap_year = 1; + + return leap_year; +} + +/** + * Calculate number of leap years since 1900 + * + * @v tm_year Years since 1900 + * @v num_leap_years Number of leap years + */ +static int leap_years_to_end ( int tm_year ) { + int leap_years = 0; + + leap_years += ( tm_year / 4 ); + leap_years -= ( tm_year / 100 ); + leap_years += ( ( tm_year + 300 ) / 400 ); + + return leap_years; +} + +/** + * Calculate day of week + * + * @v tm_year Years since 1900 + * @v tm_mon Month of year [0,11] + * @v tm_day Day of month [1,31] + */ +static int day_of_week ( int tm_year, int tm_mon, int tm_mday ) { + static const uint8_t offset[12] = + { 1, 4, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5 }; + int pseudo_year = tm_year; + + if ( tm_mon < 2 ) + pseudo_year--; + return ( ( pseudo_year + leap_years_to_end ( pseudo_year ) + + offset[tm_mon] + tm_mday ) % 7 ); +} + +/** Days from start of year until start of months (in non-leap years) */ +static const uint16_t days_to_month_start[] = + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + +/** + * Calculate seconds since the Epoch + * + * @v tm Broken-down time + * @ret time Seconds since the Epoch + */ +time_t mktime ( struct tm *tm ) { + int days_since_epoch; + int seconds_since_day; + time_t seconds; + + /* Calculate day of year */ + tm->tm_yday = ( ( tm->tm_mday - 1 ) + + days_to_month_start[ tm->tm_mon ] ); + if ( ( tm->tm_mon >= 2 ) && is_leap_year ( tm->tm_year ) ) + tm->tm_yday++; + + /* Calculate day of week */ + tm->tm_wday = day_of_week ( tm->tm_year, tm->tm_mon, tm->tm_mday ); + + /* Calculate seconds since the Epoch */ + days_since_epoch = ( tm->tm_yday + ( 365 * tm->tm_year ) - 25567 + + leap_years_to_end ( tm->tm_year - 1 ) ); + seconds_since_day = + ( ( ( ( tm->tm_hour * 60 ) + tm->tm_min ) * 60 ) + tm->tm_sec ); + seconds = ( ( ( ( time_t ) days_since_epoch ) * ( ( time_t ) 86400 ) ) + + seconds_since_day ); + + DBGC ( &weekdays, "TIME %04d-%02d-%02d %02d:%02d:%02d => %lld (%s, " + "day %d)\n", ( tm->tm_year + 1900 ), ( tm->tm_mon + 1 ), + tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, seconds, + weekdays[ tm->tm_wday ], tm->tm_yday ); + + return seconds; +} diff --git a/src/include/sys/time.h b/src/include/sys/time.h index 21fb7e99..6c9b7421 100644 --- a/src/include/sys/time.h +++ b/src/include/sys/time.h @@ -1,20 +1,18 @@ #ifndef _SYS_TIME_H #define _SYS_TIME_H -#include +/** @file + * + * Date and time + */ -typedef unsigned long suseconds_t; +#include -struct timeval { - time_t tv_sec; /* seconds */ - suseconds_t tv_usec; /* microseconds */ -}; - -struct timezone { - int tz_minuteswest; /* minutes W of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - -extern int gettimeofday ( struct timeval *tv, struct timezone *tz ); +/** Seconds since the Epoch + * + * We use a 64-bit type to avoid Y2K38 issues, since we may have to + * handle distant future dates (e.g. X.509 certificate expiry dates). + */ +typedef int64_t time_t; #endif /* _SYS_TIME_H */ diff --git a/src/include/time.h b/src/include/time.h index 6ea927c3..f33300ab 100644 --- a/src/include/time.h +++ b/src/include/time.h @@ -1,22 +1,35 @@ #ifndef _TIME_H #define _TIME_H -typedef unsigned long time_t; +/** @file + * + * Date and time + */ +#include + +/** Broken-down time */ struct tm { - int tm_sec; /* seconds */ - int tm_min; /* minutes */ - int tm_hour; /* hours */ - int tm_mday; /* day of the month */ - int tm_mon; /* month */ - int tm_year; /* year */ - int tm_wday; /* day of the week */ - int tm_yday; /* day in the year */ - int tm_isdst; /* daylight saving time */ + /** Seconds [0,60] */ + int tm_sec; + /** Minutes [0,59] */ + int tm_min; + /** Hour [0,23] */ + int tm_hour; + /** Day of month [1,31] */ + int tm_mday; + /** Month of year [0,11] */ + int tm_mon; + /** Years since 1900 */ + int tm_year; + /** Day of week [0,6] (Sunday=0) */ + int tm_wday; + /** Day of year [0,365] */ + int tm_yday; + /** Daylight savings flag */ + int tm_isdst; }; -extern time_t time ( time_t *t ); - extern time_t mktime ( struct tm *tm ); #endif /* _TIME_H */ From c130001bdfb2fa4c880b59f76340a91703ffcfc9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 16:10:23 +0000 Subject: [PATCH 092/221] [test] Add self-tests for mktime() Signed-off-by: Michael Brown --- src/tests/tests.c | 1 + src/tests/time_test.c | 182 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/tests/time_test.c diff --git a/src/tests/tests.c b/src/tests/tests.c index cccb29a9..3f4d5b4b 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Drag in all applicable self-tests */ REQUIRE_OBJECT ( list_test ); REQUIRE_OBJECT ( byteswap_test ); +REQUIRE_OBJECT ( time_test ); REQUIRE_OBJECT ( md5_test ); REQUIRE_OBJECT ( sha1_test ); REQUIRE_OBJECT ( sha256_test ); diff --git a/src/tests/time_test.c b/src/tests/time_test.c new file mode 100644 index 00000000..d12d3acf --- /dev/null +++ b/src/tests/time_test.c @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Date and time self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include + +/** A mktime() test */ +struct mktime_test { + /** Broken-down time */ + struct tm tm; + /** Day of the week */ + int wday; + /** Day of the year */ + int yday; + /** Seconds since the Epoch */ + time_t time; +}; + +/** + * Define a mktime() test + * + * @v name Test name + * @v SEC Seconds [0,60] + * @v MIN Minutes [0,59] + * @v HOUR Hour [0,23] + * @v MDAY Day of month [1,31] + * @v MON Month of year [0,11] + * @v YEAR Years since 1900 + * @v WDAY Day of week [0,6] (Sunday=0) + * @v YDAY Day of year [0,365] + * @v ISDST Daylight savings flag (ignored) + * @v TIME Seconds since the Epoch + * @ret test mktime() test + * + * This macro is designed to make it easy to generate test vectors in + * Perl using + * + * print join ", ", gmtime ( $time ), $time."ULL"; + * + */ +#define MKTIME_TEST( name, SEC, MIN, HOUR, MDAY, MON, YEAR, WDAY, \ + YDAY, ISDST, TIME ) \ + static struct mktime_test name = { \ + .tm = { \ + .tm_sec = SEC, \ + .tm_min = MIN, \ + .tm_hour = HOUR, \ + .tm_mday = MDAY, \ + .tm_mon = MON, \ + .tm_year = YEAR, \ + .tm_isdst = ISDST, \ + }, \ + .wday = WDAY, \ + .yday = YDAY, \ + .time = TIME, \ + } + +/** + * Report mktime() test result + * + * @v test mktime() test + */ +#define mktime_ok( test ) do { \ + time_t time = mktime ( &(test)->tm ); \ + ok ( time == (test)->time ); \ + ok ( (test)->tm.tm_wday == (test)->wday ); \ + ok ( (test)->tm.tm_yday == (test)->yday ); \ + } while ( 0 ) + +/* Start of the Epoch */ +MKTIME_TEST ( mktime_epoch, 00, 00, 00, 01, 00, 70, 4, 0, 0, 0 ); + +/* Birth of iPXE as a new project */ +MKTIME_TEST ( mktime_ipxe, 01, 15, 20, 19, 03, 110, 1, 108, 0, 1271708101ULL ); + +/* Random test vectors generated using Perl's gmtime() */ +MKTIME_TEST ( mktime_0, 4, 17, 20, 1, 0, 150, 6, 0, 0, 2524681024ULL ); +MKTIME_TEST ( mktime_1, 22, 47, 21, 27, 11, 77, 2, 360, 0, 252107242ULL ); +MKTIME_TEST ( mktime_2, 26, 10, 0, 7, 2, 196, 3, 66, 0, 3981917426ULL ); +MKTIME_TEST ( mktime_3, 44, 44, 23, 15, 9, 261, 4, 287, 0, 6052319084ULL ); +MKTIME_TEST ( mktime_4, 3, 22, 18, 8, 9, 296, 6, 281, 0, 7156232523ULL ); +MKTIME_TEST ( mktime_5, 27, 26, 16, 18, 11, 338, 2, 351, 0, 8487649587ULL ); +MKTIME_TEST ( mktime_6, 31, 36, 22, 3, 3, 293, 3, 92, 0, 7045310191ULL ); +MKTIME_TEST ( mktime_7, 2, 0, 6, 25, 5, 289, 4, 175, 0, 6926191202ULL ); +MKTIME_TEST ( mktime_8, 43, 50, 1, 8, 0, 210, 3, 7, 0, 4418589043ULL ); +MKTIME_TEST ( mktime_9, 48, 14, 20, 23, 3, 86, 3, 112, 0, 514671288ULL ); +MKTIME_TEST ( mktime_10, 4, 43, 5, 29, 11, 173, 5, 362, 0, 3281751784ULL ); +MKTIME_TEST ( mktime_11, 47, 26, 21, 12, 7, 177, 4, 223, 0, 3396029207ULL ); +MKTIME_TEST ( mktime_12, 18, 55, 20, 26, 11, 88, 1, 360, 0, 599172918ULL ); +MKTIME_TEST ( mktime_13, 8, 32, 13, 15, 7, 314, 1, 226, 0, 7719456728ULL ); +MKTIME_TEST ( mktime_14, 0, 16, 11, 20, 6, 138, 2, 200, 0, 2163237360ULL ); +MKTIME_TEST ( mktime_15, 48, 0, 9, 31, 2, 202, 5, 89, 0, 4173238848ULL ); +MKTIME_TEST ( mktime_16, 51, 55, 0, 15, 1, 323, 6, 45, 0, 7987769751ULL ); +MKTIME_TEST ( mktime_17, 36, 10, 7, 11, 5, 301, 4, 161, 0, 7303590636ULL ); +MKTIME_TEST ( mktime_18, 22, 39, 11, 21, 9, 233, 3, 293, 0, 5169181162ULL ); +MKTIME_TEST ( mktime_19, 48, 29, 8, 31, 7, 207, 3, 242, 0, 4344222588ULL ); +MKTIME_TEST ( mktime_20, 4, 53, 22, 8, 8, 165, 2, 250, 0, 3019675984ULL ); +MKTIME_TEST ( mktime_21, 14, 16, 8, 10, 5, 298, 0, 160, 0, 7208900174ULL ); +MKTIME_TEST ( mktime_22, 10, 35, 3, 12, 3, 188, 1, 102, 0, 3732579310ULL ); +MKTIME_TEST ( mktime_23, 47, 12, 18, 22, 2, 103, 6, 80, 0, 1048356767ULL ); +MKTIME_TEST ( mktime_24, 23, 29, 17, 23, 10, 201, 3, 326, 0, 4162210163ULL ); +MKTIME_TEST ( mktime_25, 58, 35, 23, 24, 3, 111, 0, 113, 0, 1303688158ULL ); +MKTIME_TEST ( mktime_26, 34, 56, 15, 24, 11, 154, 4, 357, 0, 2681740594ULL ); +MKTIME_TEST ( mktime_27, 7, 11, 22, 28, 1, 243, 4, 58, 0, 5464447867ULL ); +MKTIME_TEST ( mktime_28, 25, 45, 23, 29, 11, 90, 6, 362, 0, 662514325ULL ); +MKTIME_TEST ( mktime_29, 31, 20, 12, 24, 1, 146, 6, 54, 0, 2403087631ULL ); +MKTIME_TEST ( mktime_30, 49, 7, 18, 16, 10, 271, 6, 319, 0, 6370596469ULL ); +MKTIME_TEST ( mktime_31, 31, 55, 2, 25, 5, 141, 2, 175, 0, 2255741731ULL ); + +/** + * Perform date and time self-tests + * + */ +static void time_test_exec ( void ) { + + mktime_ok ( &mktime_epoch ); + mktime_ok ( &mktime_ipxe ); + mktime_ok ( &mktime_0 ); + mktime_ok ( &mktime_1 ); + mktime_ok ( &mktime_2 ); + mktime_ok ( &mktime_3 ); + mktime_ok ( &mktime_4 ); + mktime_ok ( &mktime_5 ); + mktime_ok ( &mktime_6 ); + mktime_ok ( &mktime_7 ); + mktime_ok ( &mktime_8 ); + mktime_ok ( &mktime_9 ); + mktime_ok ( &mktime_10 ); + mktime_ok ( &mktime_11 ); + mktime_ok ( &mktime_12 ); + mktime_ok ( &mktime_13 ); + mktime_ok ( &mktime_14 ); + mktime_ok ( &mktime_15 ); + mktime_ok ( &mktime_16 ); + mktime_ok ( &mktime_17 ); + mktime_ok ( &mktime_18 ); + mktime_ok ( &mktime_19 ); + mktime_ok ( &mktime_20 ); + mktime_ok ( &mktime_21 ); + mktime_ok ( &mktime_22 ); + mktime_ok ( &mktime_23 ); + mktime_ok ( &mktime_24 ); + mktime_ok ( &mktime_25 ); + mktime_ok ( &mktime_26 ); + mktime_ok ( &mktime_27 ); + mktime_ok ( &mktime_28 ); + mktime_ok ( &mktime_29 ); + mktime_ok ( &mktime_30 ); + mktime_ok ( &mktime_31 ); +} + +/** Date and time self-test */ +struct self_test time_test __self_test = { + .name = "time", + .exec = time_test_exec, +}; From 846bde90e6b1001480016fa46a957a9e726af68a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 16:59:53 +0000 Subject: [PATCH 093/221] [time] Define an API for getting the current time Signed-off-by: Michael Brown --- src/arch/i386/include/bits/time.h | 12 ++++++ src/arch/x86_64/include/bits/time.h | 12 ++++++ src/config/defaults/efi.h | 1 + src/config/defaults/linux.h | 1 + src/config/defaults/pcbios.h | 1 + src/config/time.h | 16 ++++++++ src/core/null_time.c | 29 +++++++++++++++ src/include/ipxe/null_time.h | 23 ++++++++++++ src/include/ipxe/time.h | 58 +++++++++++++++++++++++++++++ src/include/time.h | 16 ++++++++ 10 files changed, 169 insertions(+) create mode 100644 src/arch/i386/include/bits/time.h create mode 100644 src/arch/x86_64/include/bits/time.h create mode 100644 src/config/time.h create mode 100644 src/core/null_time.c create mode 100644 src/include/ipxe/null_time.h create mode 100644 src/include/ipxe/time.h diff --git a/src/arch/i386/include/bits/time.h b/src/arch/i386/include/bits/time.h new file mode 100644 index 00000000..d2baacd8 --- /dev/null +++ b/src/arch/i386/include/bits/time.h @@ -0,0 +1,12 @@ +#ifndef _BITS_TIME_H +#define _BITS_TIME_H + +/** @file + * + * i386-specific time API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#endif /* _BITS_TIME_H */ diff --git a/src/arch/x86_64/include/bits/time.h b/src/arch/x86_64/include/bits/time.h new file mode 100644 index 00000000..59b35535 --- /dev/null +++ b/src/arch/x86_64/include/bits/time.h @@ -0,0 +1,12 @@ +#ifndef _BITS_TIME_H +#define _BITS_TIME_H + +/** @file + * + * x86_64-specific time API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#endif /* _BITS_TIME_H */ diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index c0bb78da..16a44dd5 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -18,6 +18,7 @@ #define SANBOOT_NULL #define BOFM_EFI #define ENTROPY_NULL +#define TIME_NULL #define IMAGE_EFI /* EFI image support */ #define IMAGE_SCRIPT /* iPXE script image support */ diff --git a/src/config/defaults/linux.h b/src/config/defaults/linux.h index fcdf9040..58c73c38 100644 --- a/src/config/defaults/linux.h +++ b/src/config/defaults/linux.h @@ -15,6 +15,7 @@ #define SMBIOS_LINUX #define SANBOOT_NULL #define ENTROPY_LINUX +#define TIME_NULL #define DRIVERS_LINUX diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 17e6ef63..2bb82cf0 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define SMBIOS_PCBIOS #define SANBOOT_PCBIOS #define ENTROPY_RTC +#define TIME_NULL #define IMAGE_ELF /* ELF image support */ #define IMAGE_MULTIBOOT /* MultiBoot image support */ diff --git a/src/config/time.h b/src/config/time.h new file mode 100644 index 00000000..0576211f --- /dev/null +++ b/src/config/time.h @@ -0,0 +1,16 @@ +#ifndef CONFIG_TIME_H +#define CONFIG_TIME_H + +/** @file + * + * Time API configuration + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +#include + +#endif /* CONFIG_TIME_H */ diff --git a/src/core/null_time.c b/src/core/null_time.c new file mode 100644 index 00000000..f9c48a95 --- /dev/null +++ b/src/core/null_time.c @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Nonexistent time source + * + */ + +#include + +PROVIDE_TIME_INLINE ( null, time_now ); diff --git a/src/include/ipxe/null_time.h b/src/include/ipxe/null_time.h new file mode 100644 index 00000000..2b72cdf5 --- /dev/null +++ b/src/include/ipxe/null_time.h @@ -0,0 +1,23 @@ +#ifndef _IPXE_NULL_TIME_H +#define _IPXE_NULL_TIME_H + +/** @file + * + * Nonexistent time source + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#ifdef TIME_NULL +#define TIME_PREFIX_null +#else +#define TIME_PREFIX_null __null_ +#endif + +static inline __always_inline time_t +TIME_INLINE ( null, time_now ) ( void ) { + return 0; +} + +#endif /* _IPXE_NULL_TIME_H */ diff --git a/src/include/ipxe/time.h b/src/include/ipxe/time.h new file mode 100644 index 00000000..c74959f8 --- /dev/null +++ b/src/include/ipxe/time.h @@ -0,0 +1,58 @@ +#ifndef _IPXE_TIME_H +#define _IPXE_TIME_H + +/** @file + * + * Time source + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include + +/** + * Calculate static inline time API function name + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @ret _subsys_func Subsystem API function + */ +#define TIME_INLINE( _subsys, _api_func ) \ + SINGLE_API_INLINE ( TIME_PREFIX_ ## _subsys, _api_func ) + +/** + * Provide a time API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + * @v _func Implementing function + */ +#define PROVIDE_TIME( _subsys, _api_func, _func ) \ + PROVIDE_SINGLE_API ( TIME_PREFIX_ ## _subsys, _api_func, _func ) + +/** + * Provide a static inline time API implementation + * + * @v _prefix Subsystem prefix + * @v _api_func API function + */ +#define PROVIDE_TIME_INLINE( _subsys, _api_func ) \ + PROVIDE_SINGLE_API_INLINE ( TIME_PREFIX_ ## _subsys, _api_func ) + +/* Include all architecture-independent time API headers */ +#include + +/* Include all architecture-dependent time API headers */ +#include + +/** + * Get current time in seconds + * + * @ret time Time, in seconds + */ +time_t time_now ( void ); + +#endif /* _IPXE_TIME_H */ diff --git a/src/include/time.h b/src/include/time.h index f33300ab..bc73af4c 100644 --- a/src/include/time.h +++ b/src/include/time.h @@ -7,6 +7,7 @@ */ #include +#include /** Broken-down time */ struct tm { @@ -30,6 +31,21 @@ struct tm { int tm_isdst; }; +/** + * Get current time in seconds since the Epoch + * + * @v t Time to fill in, or NULL + * @ret time Current time + */ +static inline time_t time ( time_t *t ) { + time_t now; + + now = time_now(); + if ( t ) + *t = now; + return now; +} + extern time_t mktime ( struct tm *tm ); #endif /* _TIME_H */ From 12002d6955f7423ef02cd6a68946240f6dd592b2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 17:08:51 +0000 Subject: [PATCH 094/221] [time] Add RTC-based time source Add a time source using the CMOS RTC to obtain the current time. Signed-off-by: Michael Brown --- src/arch/i386/include/bits/time.h | 2 + src/arch/i386/include/ipxe/rtc_time.h | 18 +++ src/arch/i386/include/rtc.h | 83 +++++++++++ src/arch/i386/interface/pcbios/rtc_entropy.c | 40 +----- src/arch/i386/interface/pcbios/rtc_time.c | 137 +++++++++++++++++++ src/config/defaults/pcbios.h | 2 +- 6 files changed, 242 insertions(+), 40 deletions(-) create mode 100644 src/arch/i386/include/ipxe/rtc_time.h create mode 100644 src/arch/i386/include/rtc.h create mode 100644 src/arch/i386/interface/pcbios/rtc_time.c diff --git a/src/arch/i386/include/bits/time.h b/src/arch/i386/include/bits/time.h index d2baacd8..24dd020e 100644 --- a/src/arch/i386/include/bits/time.h +++ b/src/arch/i386/include/bits/time.h @@ -9,4 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include + #endif /* _BITS_TIME_H */ diff --git a/src/arch/i386/include/ipxe/rtc_time.h b/src/arch/i386/include/ipxe/rtc_time.h new file mode 100644 index 00000000..c0dfe3f8 --- /dev/null +++ b/src/arch/i386/include/ipxe/rtc_time.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_RTC_TIME_H +#define _IPXE_RTC_TIME_H + +/** @file + * + * RTC-based time source + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#ifdef TIME_RTC +#define TIME_PREFIX_rtc +#else +#define TIME_PREFIX_rtc __rtc_ +#endif + +#endif /* _IPXE_RTC_TIME_H */ diff --git a/src/arch/i386/include/rtc.h b/src/arch/i386/include/rtc.h new file mode 100644 index 00000000..2a6abbae --- /dev/null +++ b/src/arch/i386/include/rtc.h @@ -0,0 +1,83 @@ +#ifndef _RTC_H +#define _RTC_H + +/** @file + * + * CMOS Real-Time Clock (RTC) + * + * The CMOS/RTC registers are documented (with varying degrees of + * accuracy and consistency) at + * + * http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt + * http://wiki.osdev.org/RTC + * http://wiki.osdev.org/CMOS + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +/** RTC IRQ */ +#define RTC_IRQ 8 + +/** RTC interrupt vector */ +#define RTC_INT IRQ_INT ( RTC_IRQ ) + +/** CMOS/RTC address (and NMI) register */ +#define CMOS_ADDRESS 0x70 + +/** NMI disable bit */ +#define CMOS_DISABLE_NMI 0x80 + +/** CMOS/RTC data register */ +#define CMOS_DATA 0x71 + +/** RTC seconds */ +#define RTC_SEC 0x00 + +/** RTC minutes */ +#define RTC_MIN 0x02 + +/** RTC hours */ +#define RTC_HOUR 0x04 + +/** RTC weekday */ +#define RTC_WDAY 0x06 + +/** RTC day of month */ +#define RTC_MDAY 0x07 + +/** RTC month */ +#define RTC_MON 0x08 + +/** RTC year */ +#define RTC_YEAR 0x09 + +/** RTC status register A */ +#define RTC_STATUS_A 0x0a + +/** RTC update in progress bit */ +#define RTC_STATUS_A_UPDATE_IN_PROGRESS 0x80 + +/** RTC status register B */ +#define RTC_STATUS_B 0x0b + +/** RTC 24 hour format bit */ +#define RTC_STATUS_B_24_HOUR 0x02 + +/** RTC binary mode bit */ +#define RTC_STATUS_B_BINARY 0x04 + +/** RTC Periodic Interrupt Enabled bit */ +#define RTC_STATUS_B_PIE 0x40 + +/** RTC status register C */ +#define RTC_STATUS_C 0x0c + +/** RTC status register D */ +#define RTC_STATUS_D 0x0d + +/** CMOS default address */ +#define CMOS_DEFAULT_ADDRESS RTC_STATUS_D + +#endif /* _RTC_H */ diff --git a/src/arch/i386/interface/pcbios/rtc_entropy.c b/src/arch/i386/interface/pcbios/rtc_entropy.c index 257cf08a..3f2a7c78 100644 --- a/src/arch/i386/interface/pcbios/rtc_entropy.c +++ b/src/arch/i386/interface/pcbios/rtc_entropy.c @@ -22,53 +22,15 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * RTC-based entropy source * - * The CMOS/RTC registers are documented (with varying degrees of - * accuracy and consistency) at - * - * http://www.nondot.org/sabre/os/files/MiscHW/RealtimeClockFAQ.txt - * http://wiki.osdev.org/RTC - * http://wiki.osdev.org/CMOS */ #include #include #include #include +#include #include -/** RTC IRQ */ -#define RTC_IRQ 8 - -/** RTC interrupt vector */ -#define RTC_INT IRQ_INT ( RTC_IRQ ) - -/** CMOS/RTC address (and NMI) register */ -#define CMOS_ADDRESS 0x70 - -/** NMI disable bit */ -#define CMOS_DISABLE_NMI 0x80 - -/** CMOS/RTC data register */ -#define CMOS_DATA 0x71 - -/** RTC status register A */ -#define RTC_STATUS_A 0x0a - -/** RTC status register B */ -#define RTC_STATUS_B 0x0b - -/** RTC Periodic Interrupt Enabled bit */ -#define RTC_STATUS_B_PIE 0x40 - -/** RTC status register C */ -#define RTC_STATUS_C 0x0c - -/** RTC status register D */ -#define RTC_STATUS_D 0x0d - -/** CMOS default address */ -#define CMOS_DEFAULT_ADDRESS RTC_STATUS_D - /** RTC "interrupt triggered" flag */ static uint8_t __text16 ( rtc_flag ); #define rtc_flag __use_text16 ( rtc_flag ) diff --git a/src/arch/i386/interface/pcbios/rtc_time.c b/src/arch/i386/interface/pcbios/rtc_time.c new file mode 100644 index 00000000..b5b46ff4 --- /dev/null +++ b/src/arch/i386/interface/pcbios/rtc_time.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * RTC-based time source + * + */ + +#include +#include +#include +#include + +/** + * Read RTC register + * + * @v address Register address + * @ret data Data + */ +static unsigned int rtc_readb ( int address ) { + outb ( address, CMOS_ADDRESS ); + return inb ( CMOS_DATA ); +} + +/** + * Check if RTC update is in progress + * + * @ret is_busy RTC update is in progress + */ +static int rtc_is_busy ( void ) { + return ( rtc_readb ( RTC_STATUS_A ) & RTC_STATUS_A_UPDATE_IN_PROGRESS ); +} + +/** + * Read RTC BCD register + * + * @v address Register address + * @ret value Value + */ +static unsigned int rtc_readb_bcd ( int address ) { + unsigned int bcd; + + bcd = rtc_readb ( address ); + return ( bcd - ( 6 * ( bcd >> 4 ) ) ); +} + +/** + * Read RTC time + * + * @ret time Time, in seconds + */ +static time_t rtc_read_time ( void ) { + unsigned int status_b; + int is_binary; + int is_24hour; + unsigned int ( * read_component ) ( int address ); + struct tm tm; + int is_pm; + unsigned int hour; + time_t time; + + /* Wait for any in-progress update to complete */ + while ( rtc_is_busy() ) {} + + /* Determine RTC mode */ + status_b = rtc_readb ( RTC_STATUS_B ); + is_binary = ( status_b & RTC_STATUS_B_BINARY ); + is_24hour = ( status_b & RTC_STATUS_B_24_HOUR ); + read_component = ( is_binary ? rtc_readb : rtc_readb_bcd ); + + /* Read time values */ + tm.tm_sec = read_component ( RTC_SEC ); + tm.tm_min = read_component ( RTC_MIN ); + hour = read_component ( RTC_HOUR ); + if ( ! is_24hour ) { + is_pm = ( hour >= 80 ); + hour = ( ( ( ( hour & 0x7f ) % 80 ) % 12 ) + + ( is_pm ? 12 : 0 ) ); + } + tm.tm_hour = hour; + tm.tm_mday = read_component ( RTC_MDAY ); + tm.tm_mon = ( read_component ( RTC_MON ) - 1 ); + tm.tm_year = ( read_component ( RTC_YEAR ) + + 100 /* Assume we are in the 21st century, since + * this code was written in 2012 */ ); + + DBGC ( RTC_STATUS_A, "RTCTIME is %04d-%02d-%02d %02d:%02d:%02d " + "(%s,%d-hour)\n", ( tm.tm_year + 1900 ), ( tm.tm_mon + 1 ), + tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, + ( is_binary ? "binary" : "BCD" ), ( is_24hour ? 24 : 12 ) ); + + /* Convert to seconds since the Epoch */ + time = mktime ( &tm ); + + return time; +} + +/** + * Get current time in seconds + * + * @ret time Time, in seconds + */ +static time_t rtc_now ( void ) { + time_t time = 0; + time_t last_time; + + /* Read time until we get two matching values in a row, in + * case we end up reading a corrupted value in the middle of + * an update. + */ + do { + last_time = time; + time = rtc_read_time(); + } while ( time != last_time ); + + return time; +} + +PROVIDE_TIME ( rtc, time_now, rtc_now ); diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 2bb82cf0..9092d675 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -19,7 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define SMBIOS_PCBIOS #define SANBOOT_PCBIOS #define ENTROPY_RTC -#define TIME_NULL +#define TIME_RTC #define IMAGE_ELF /* ELF image support */ #define IMAGE_MULTIBOOT /* MultiBoot image support */ From 5da712385e07f0965a3f7548933c2bd3c4f254f6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 23:05:26 +0000 Subject: [PATCH 095/221] [tls] Include current time within the client random bytes Signed-off-by: Michael Brown --- src/net/tls.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/net/tls.c b/src/net/tls.c index 1688dfc3..276b2357 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -2030,7 +2031,7 @@ int add_tls ( struct interface *xfer, const char *name, tls_clear_cipher ( tls, &tls->tx_cipherspec_pending ); tls_clear_cipher ( tls, &tls->rx_cipherspec ); tls_clear_cipher ( tls, &tls->rx_cipherspec_pending ); - tls->client_random.gmt_unix_time = 0; + tls->client_random.gmt_unix_time = time ( NULL ); if ( ( rc = tls_generate_random ( tls, &tls->client_random.random, ( sizeof ( tls->client_random.random ) ) ) ) != 0 ) { goto err_random; From 0610bcb1d2876d9e71ced51ed44c4e8854eefb33 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 22:49:09 +0000 Subject: [PATCH 096/221] [tls] Parse X.509 validity times into seconds since the Epoch Signed-off-by: Michael Brown --- src/crypto/x509.c | 26 ++++++++++++++------------ src/include/ipxe/x509.h | 15 +++------------ 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 2a5e72ba..3303ae22 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include #include @@ -331,6 +332,7 @@ static int x509_parse_time ( struct x509_certificate *cert, } __attribute__ (( packed )) named; uint8_t raw[7]; } pairs; + struct tm tm; const uint8_t *data; size_t remaining; unsigned int tens; @@ -395,12 +397,16 @@ static int x509_parse_time ( struct x509_certificate *cert, } /* Fill in time */ - time->year = ( ( pairs.named.century * 100 ) + pairs.named.year ); - time->month = pairs.named.month; - time->day = pairs.named.day; - time->hour = pairs.named.hour; - time->minute = pairs.named.minute; - time->second = pairs.named.second; + tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) + + pairs.named.year ); + tm.tm_mon = ( pairs.named.month - 1 ); + tm.tm_mday = pairs.named.day; + tm.tm_hour = pairs.named.hour; + tm.tm_min = pairs.named.minute; + tm.tm_sec = pairs.named.second; + + /* Convert to seconds since the Epoch */ + time->time = mktime ( &tm ); return 0; } @@ -492,17 +498,13 @@ static int x509_parse_validity ( struct x509_certificate *cert, /* Parse notBefore */ if ( ( rc = x509_parse_time ( cert, not_before, &cursor ) ) != 0 ) return rc; - DBGC ( cert, "X509 %p valid from %04d-%02d-%02d %02d:%02d:%02d\n", - cert, not_before->year, not_before->month, not_before->day, - not_before->hour, not_before->minute, not_before->second ); + DBGC ( cert, "X509 %p valid from time %lld\n", cert, not_before->time ); asn1_skip_any ( &cursor ); /* Parse notAfter */ if ( ( rc = x509_parse_time ( cert, not_after, &cursor ) ) != 0 ) return rc; - DBGC ( cert, "X509 %p valid until %04d-%02d-%02d %02d:%02d:%02d\n", - cert, not_after->year, not_after->month, not_after->day, - not_after->hour, not_after->minute, not_after->second ); + DBGC ( cert, "X509 %p valid until time %lld\n", cert, not_after->time ); return 0; } diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 4da4539f..f290a76e 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include /** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */ @@ -70,18 +71,8 @@ struct x509_issuer { /** An X.509 time */ struct x509_time { - /** Year */ - uint16_t year; - /** Month */ - uint8_t month; - /** Day */ - uint8_t day; - /** Hour */ - uint8_t hour; - /** Minute */ - uint8_t minute; - /** Second */ - uint8_t second; + /** Seconds since the Epoch */ + time_t time; }; /** An X.509 certificate validity period */ From 8583c323a25fd65fb6e7fe47e3e8b69d23acb2d3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 19 Mar 2012 23:04:05 +0000 Subject: [PATCH 097/221] [tls] Check certificate validity period against current date and time Signed-off-by: Michael Brown --- src/crypto/x509.c | 48 +++++++++++++++++++++++++++++++++++------ src/include/ipxe/x509.h | 8 ++++--- src/net/tls.c | 4 +++- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 3303ae22..a11eee6f 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -85,6 +85,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EACCES_KEY_USAGE ) #define EINFO_EACCES_KEY_USAGE \ __einfo_uniqify ( EINFO_EACCES, 0x03, "Incorrect key usage" ) +#define EACCES_EXPIRED \ + __einfo_error ( EINFO_EACCES_EXPIRED ) +#define EINFO_EACCES_EXPIRED \ + __einfo_uniqify ( EINFO_EACCES, 0x04, "Expired (or not yet valid)" ) /** "commonName" object identifier */ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; @@ -1036,14 +1040,14 @@ static int x509_check_signature ( struct x509_certificate *cert, } /** - * Validate X.509 certificate against signing certificate + * Validate X.509 certificate against issuer certificate * * @v cert X.509 certificate * @v issuer X.509 issuer certificate * @ret rc Return status code */ -int x509_validate ( struct x509_certificate *cert, - struct x509_certificate *issuer ) { +int x509_validate_issuer ( struct x509_certificate *cert, + struct x509_certificate *issuer ) { struct x509_public_key *public_key = &issuer->subject.public_key; int rc; @@ -1139,19 +1143,45 @@ int x509_validate_root ( struct x509_certificate *cert, return -ENOENT; } +/** + * Validate X.509 certificate validity period + * + * @v cert X.509 certificate + * @v time Time at which to validate certificate + * @ret rc Return status code + */ +int x509_validate_time ( struct x509_certificate *cert, time_t time ) { + struct x509_validity *validity = &cert->validity; + + /* Check validity period */ + if ( time < validity->not_before.time ) { + DBGC ( cert, "X509 %p is not yet valid (at time %lld)\n", + cert, time ); + return -EACCES_EXPIRED; + } + if ( time > validity->not_after.time ) { + DBGC ( cert, "X509 %p has expired (at time %lld)\n", + cert, time ); + return -EACCES_EXPIRED; + } + + DBGC ( cert, "X509 %p is valid (at time %lld)\n", cert, time ); + return 0; +} + /** * Validate X.509 certificate chain * * @v parse_next Parse next X.509 certificate in chain * @v context Context for parse_next() + * @v time Time at which to validate certificates * @v root Root certificate store, or NULL to use default * @v first Initial X.509 certificate to fill in, or NULL * @ret rc Return status code */ int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, void *context ), - void *context, - struct x509_root *root, + void *context, time_t time, struct x509_root *root, struct x509_certificate *first ) { struct x509_certificate temp[2]; struct x509_certificate *current = &temp[0]; @@ -1177,6 +1207,10 @@ int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, /* Process chain */ while ( 1 ) { + /* Check that certificate is valid at specified time */ + if ( ( rc = x509_validate_time ( current, time ) ) != 0 ) + return rc; + /* Succeed if we have reached a root certificate */ if ( x509_validate_root ( current, root ) == 0 ) return 0; @@ -1188,8 +1222,8 @@ int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, return rc; } - /* Validate current certificate */ - if ( ( rc = x509_validate ( current, next ) ) != 0 ) + /* Validate current certificate against next certificate */ + if ( ( rc = x509_validate_issuer ( current, next ) ) != 0 ) return rc; /* Move to next certificate in chain */ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index f290a76e..925e23f7 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -204,17 +204,19 @@ struct x509_root { extern int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ); -extern int x509_validate ( struct x509_certificate *cert, - struct x509_certificate *issuer ); +extern int x509_validate_issuer ( struct x509_certificate *cert, + struct x509_certificate *issuer ); extern void x509_fingerprint ( struct x509_certificate *cert, struct digest_algorithm *digest, void *fingerprint ); extern int x509_validate_root ( struct x509_certificate *cert, struct x509_root *root ); +extern int x509_validate_time ( struct x509_certificate *cert, time_t time ); extern int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, void *context ), - void *context, struct x509_root *root, + void *context, time_t time, + struct x509_root *root, struct x509_certificate *first ); #endif /* _IPXE_X509_H */ diff --git a/src/net/tls.c b/src/net/tls.c index 276b2357..3aefb19d 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1093,6 +1093,7 @@ static int tls_new_certificate ( struct tls_session *tls, struct x509_certificate cert; struct x509_name *name = &cert.subject.name; struct x509_public_key *key = &cert.subject.public_key; + time_t now; int rc; /* Sanity check */ @@ -1107,8 +1108,9 @@ static int tls_new_certificate ( struct tls_session *tls, context.tls = tls; context.current = certificate->certificates; context.end = end; + now = time ( NULL ); if ( ( rc = x509_validate_chain ( tls_parse_next, &context, - NULL, &cert ) ) != 0 ) { + now, NULL, &cert ) ) != 0 ) { DBGC ( tls, "TLS %p could not validate certificate chain: %s\n", tls, strerror ( rc ) ); return rc; From a156c157465dde3e4a07034a3201a4ec19cdf750 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Mar 2012 04:07:53 +0000 Subject: [PATCH 098/221] [tls] Use hybrid MD5+SHA1 algorithm TLSv1.1 and earlier use a hybrid of MD5 and SHA-1 to generate digests over the handshake messages. Formalise this as a separate digest algorithm "md5+sha1". Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 28 ++++++++++++--- src/net/tls.c | 79 +++++++++++++++++++++++++++++++++++------- 2 files changed, 90 insertions(+), 17 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index a2504f19..a491b795 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -145,6 +145,28 @@ struct tls_client_random { uint8_t random[28]; } __attribute__ (( packed )); +/** An MD5+SHA1 context */ +struct md5_sha1_context { + /** MD5 context */ + uint8_t md5[MD5_CTX_SIZE]; + /** SHA-1 context */ + uint8_t sha1[SHA1_CTX_SIZE]; +} __attribute__ (( packed )); + +/** MD5+SHA1 context size */ +#define MD5_SHA1_CTX_SIZE sizeof ( struct md5_sha1_context ) + +/** An MD5+SHA1 digest */ +struct md5_sha1_digest { + /** MD5 digest */ + uint8_t md5[MD5_DIGEST_SIZE]; + /** SHA-1 digest */ + uint8_t sha1[SHA1_DIGEST_SIZE]; +} __attribute__ (( packed )); + +/** MD5+SHA1 digest size */ +#define MD5_SHA1_DIGEST_SIZE sizeof ( struct md5_sha1_digest ) + /** A TLS session */ struct tls_session { /** Reference counter */ @@ -175,10 +197,8 @@ struct tls_session { uint8_t server_random[32]; /** Client random bytes */ struct tls_client_random client_random; - /** MD5 context for handshake verification */ - uint8_t handshake_md5_ctx[MD5_CTX_SIZE]; - /** SHA1 context for handshake verification */ - uint8_t handshake_sha1_ctx[SHA1_CTX_SIZE]; + /** MD5+SHA1 context for handshake verification */ + uint8_t handshake_md5_sha1_ctx[MD5_SHA1_CTX_SIZE]; /** SHA256 context for handshake verification */ uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE]; diff --git a/src/net/tls.c b/src/net/tls.c index 3aefb19d..2580008d 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -79,6 +79,64 @@ static unsigned long tls_uint24 ( const uint8_t field24[3] ) { return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] ); } +/****************************************************************************** + * + * Hybrid MD5+SHA1 hash as used by TLSv1.1 and earlier + * + ****************************************************************************** + */ + +/** + * Initialise MD5+SHA1 algorithm + * + * @v ctx MD5+SHA1 context + */ +static void md5_sha1_init ( void *ctx ) { + struct md5_sha1_context *context = ctx; + + digest_init ( &md5_algorithm, context->md5 ); + digest_init ( &sha1_algorithm, context->sha1 ); +} + +/** + * Accumulate data with MD5+SHA1 algorithm + * + * @v ctx MD5+SHA1 context + * @v data Data + * @v len Length of data + */ +static void md5_sha1_update ( void *ctx, const void *data, size_t len ) { + struct md5_sha1_context *context = ctx; + + digest_update ( &md5_algorithm, context->md5, data, len ); + digest_update ( &sha1_algorithm, context->sha1, data, len ); +} + +/** + * Generate MD5+SHA1 digest + * + * @v ctx MD5+SHA1 context + * @v out Output buffer + */ +static void md5_sha1_final ( void *ctx, void *out ) { + struct md5_sha1_context *context = ctx; + struct md5_sha1_digest *digest = out; + + digest_final ( &md5_algorithm, context->md5, digest->md5 ); + digest_final ( &sha1_algorithm, context->sha1, digest->sha1 ); +} + +/** Hybrid MD5+SHA1 digest algorithm */ +static struct digest_algorithm md5_sha1_algorithm = { + .name = "md5+sha1", + .ctxsize = sizeof ( struct md5_sha1_context ), + .blocksize = 0, /* Not applicable */ + .digestsize = sizeof ( struct md5_sha1_digest ), + .init = md5_sha1_init, + .update = md5_sha1_update, + .final = md5_sha1_final, +}; + /****************************************************************************** * * Cleanup functions @@ -633,8 +691,8 @@ static int tls_change_cipher ( struct tls_session *tls, static void tls_add_handshake ( struct tls_session *tls, const void *data, size_t len ) { - digest_update ( &md5_algorithm, tls->handshake_md5_ctx, data, len ); - digest_update ( &sha1_algorithm, tls->handshake_sha1_ctx, data, len ); + digest_update ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx, + data, len ); digest_update ( &sha256_algorithm, tls->handshake_sha256_ctx, data, len ); } @@ -651,7 +709,7 @@ static size_t tls_verify_handshake_len ( struct tls_session *tls ) { return SHA256_DIGEST_SIZE; } else { /* Use MD5+SHA1 for TLSv1.1 and earlier */ - return ( MD5_DIGEST_SIZE + SHA1_DIGEST_SIZE ); + return MD5_SHA1_DIGEST_SIZE; } } @@ -666,8 +724,7 @@ static size_t tls_verify_handshake_len ( struct tls_session *tls ) { */ static void tls_verify_handshake ( struct tls_session *tls, void *out ) { union { - uint8_t md5[MD5_CTX_SIZE]; - uint8_t sha1[SHA1_CTX_SIZE]; + uint8_t md5_sha1[MD5_SHA1_CTX_SIZE]; uint8_t sha256[SHA256_CTX_SIZE]; } ctx; @@ -678,12 +735,9 @@ static void tls_verify_handshake ( struct tls_session *tls, void *out ) { digest_final ( &sha256_algorithm, ctx.sha256, out ); } else { /* Use MD5+SHA1 for TLSv1.1 and earlier */ - memcpy ( ctx.md5, tls->handshake_md5_ctx, sizeof ( ctx.md5 ) ); - digest_final ( &md5_algorithm, ctx.md5, out ); - memcpy ( ctx.sha1, tls->handshake_sha1_ctx, - sizeof ( ctx.sha1 ) ); - digest_final ( &sha1_algorithm, ctx.sha1, - ( out + MD5_DIGEST_SIZE ) ); + memcpy ( ctx.md5_sha1, tls->handshake_md5_sha1_ctx, + sizeof ( ctx.md5_sha1 ) ); + digest_final ( &md5_sha1_algorithm, ctx.md5_sha1, out ); } } @@ -2043,8 +2097,7 @@ int add_tls ( struct interface *xfer, const char *name, ( sizeof ( tls->pre_master_secret.random ) ) ) ) != 0 ) { goto err_random; } - digest_init ( &md5_algorithm, tls->handshake_md5_ctx ); - digest_init ( &sha1_algorithm, tls->handshake_sha1_ctx ); + digest_init ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx ); digest_init ( &sha256_algorithm, tls->handshake_sha256_ctx ); tls->tx_pending = TLS_TX_CLIENT_HELLO; process_init ( &tls->process, &tls_process_desc, &tls->refcnt ); From 7869f71ae79392aed3fbeb76f449ee2132769d4b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Mar 2012 17:05:37 +0000 Subject: [PATCH 099/221] [tls] Treat handshake digest algorithm as a session parameter Simplify code by recording the active handshake digest algorithm as a session parameter. (Note that we must still accumulate digests for all supported algorithms, since we don't know which digest will eventually be used until we receive the Server Hello.) Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 4 +++ src/net/tls.c | 63 ++++++++++++++++-------------------------- 2 files changed, 28 insertions(+), 39 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index a491b795..0d1f2d85 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -201,6 +201,10 @@ struct tls_session { uint8_t handshake_md5_sha1_ctx[MD5_SHA1_CTX_SIZE]; /** SHA256 context for handshake verification */ uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE]; + /** Digest algorithm used for handshake verification */ + struct digest_algorithm *handshake_digest; + /** Digest algorithm context used for handshake verification */ + uint8_t *handshake_ctx; /** TX sequence number */ uint64_t tx_seq; diff --git a/src/net/tls.c b/src/net/tls.c index 2580008d..56b01f23 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -697,22 +697,6 @@ static void tls_add_handshake ( struct tls_session *tls, data, len ); } -/** - * Size of handshake output buffer - * - * @v tls TLS session - */ -static size_t tls_verify_handshake_len ( struct tls_session *tls ) { - - if ( tls->version >= TLS_VERSION_TLS_1_2 ) { - /* Use SHA-256 for TLSv1.2 and later */ - return SHA256_DIGEST_SIZE; - } else { - /* Use MD5+SHA1 for TLSv1.1 and earlier */ - return MD5_SHA1_DIGEST_SIZE; - } -} - /** * Calculate handshake verification hash * @@ -723,22 +707,11 @@ static size_t tls_verify_handshake_len ( struct tls_session *tls ) { * messages seen so far. */ static void tls_verify_handshake ( struct tls_session *tls, void *out ) { - union { - uint8_t md5_sha1[MD5_SHA1_CTX_SIZE]; - uint8_t sha256[SHA256_CTX_SIZE]; - } ctx; + struct digest_algorithm *digest = tls->handshake_digest; + uint8_t ctx[ digest->ctxsize ]; - if ( tls->version >= TLS_VERSION_TLS_1_2 ) { - /* Use SHA-256 for TLSv1.2 and later */ - memcpy ( ctx.sha256, tls->handshake_sha256_ctx, - sizeof ( ctx.sha256 ) ); - digest_final ( &sha256_algorithm, ctx.sha256, out ); - } else { - /* Use MD5+SHA1 for TLSv1.1 and earlier */ - memcpy ( ctx.md5_sha1, tls->handshake_md5_sha1_ctx, - sizeof ( ctx.md5_sha1 ) ); - digest_final ( &md5_sha1_algorithm, ctx.md5_sha1, out ); - } + memcpy ( ctx, tls->handshake_ctx, sizeof ( ctx ) ); + digest_final ( digest, ctx, out ); } /****************************************************************************** @@ -915,20 +888,21 @@ static int tls_send_change_cipher ( struct tls_session *tls ) { * @ret rc Return status code */ static int tls_send_finished ( struct tls_session *tls ) { + struct digest_algorithm *digest = tls->handshake_digest; struct { uint32_t type_length; uint8_t verify_data[12]; } __attribute__ (( packed )) finished; - uint8_t digest[ tls_verify_handshake_len ( tls ) ]; + uint8_t digest_out[ digest->digestsize ]; memset ( &finished, 0, sizeof ( finished ) ); finished.type_length = ( cpu_to_le32 ( TLS_FINISHED ) | htonl ( sizeof ( finished ) - sizeof ( finished.type_length ) ) ); - tls_verify_handshake ( tls, digest ); + tls_verify_handshake ( tls, digest_out ); tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), finished.verify_data, sizeof ( finished.verify_data ), - "client finished", digest, sizeof ( digest ) ); + "client finished", digest_out, sizeof ( digest_out ) ); return tls_send_handshake ( tls, &finished, sizeof ( finished ) ); } @@ -1052,6 +1026,14 @@ static int tls_new_server_hello ( struct tls_session *tls, DBGC ( tls, "TLS %p using protocol version %d.%d\n", tls, ( version >> 8 ), ( version & 0xff ) ); + /* Use MD5+SHA1 digest algorithm for handshake verification + * for versions earlier than TLSv1.2. + */ + if ( tls->version < TLS_VERSION_TLS_1_2 ) { + tls->handshake_digest = &md5_sha1_algorithm; + tls->handshake_ctx = tls->handshake_md5_sha1_ctx; + } + /* Copy out server random bytes */ memcpy ( &tls->server_random, &hello_a->random, sizeof ( tls->server_random ) ); @@ -1254,12 +1236,13 @@ static int tls_new_server_hello_done ( struct tls_session *tls, */ static int tls_new_finished ( struct tls_session *tls, const void *data, size_t len ) { + struct digest_algorithm *digest = tls->handshake_digest; const struct { uint8_t verify_data[12]; char next[0]; } __attribute__ (( packed )) *finished = data; const void *end = finished->next; - uint8_t digest[ tls_verify_handshake_len ( tls ) ]; + uint8_t digest_out[ digest->digestsize ]; uint8_t verify_data[ sizeof ( finished->verify_data ) ]; /* Sanity check */ @@ -1270,10 +1253,10 @@ static int tls_new_finished ( struct tls_session *tls, } /* Verify data */ - tls_verify_handshake ( tls, digest ); + tls_verify_handshake ( tls, digest_out ); tls_prf_label ( tls, &tls->master_secret, sizeof ( tls->master_secret ), verify_data, sizeof ( verify_data ), "server finished", - digest, sizeof ( digest ) ); + digest_out, sizeof ( digest_out ) ); if ( memcmp ( verify_data, finished->verify_data, sizeof ( verify_data ) ) != 0 ) { DBGC ( tls, "TLS %p verification failed\n", tls ); @@ -2014,8 +1997,8 @@ static void tls_tx_step ( struct tls_session *tls ) { } else if ( tls->tx_pending & TLS_TX_CLIENT_KEY_EXCHANGE ) { /* Send Client Key Exchange */ if ( ( rc = tls_send_client_key_exchange ( tls ) ) != 0 ) { - DBGC ( tls, "TLS %p could send Client Key Exchange: " - "%s\n", tls, strerror ( rc ) ); + DBGC ( tls, "TLS %p could not send Client Key " + "Exchange: %s\n", tls, strerror ( rc ) ); goto err; } tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE; @@ -2099,6 +2082,8 @@ int add_tls ( struct interface *xfer, const char *name, } digest_init ( &md5_sha1_algorithm, tls->handshake_md5_sha1_ctx ); digest_init ( &sha256_algorithm, tls->handshake_sha256_ctx ); + tls->handshake_digest = &sha256_algorithm; + tls->handshake_ctx = tls->handshake_sha256_ctx; tls->tx_pending = TLS_TX_CLIENT_HELLO; process_init ( &tls->process, &tls_process_desc, &tls->refcnt ); From 05c13716f9a6323d8c8b4006f11dc2fc86493371 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Mar 2012 04:20:06 +0000 Subject: [PATCH 100/221] [crypto] Use linker tables for RSA digestInfo prefixes Allow external code to specify RSA digestInfo prefixes for additional digest algorithms. Signed-off-by: Michael Brown --- src/crypto/rsa.c | 63 +++++++++++++++++------------------------- src/include/ipxe/rsa.h | 18 ++++++++++++ 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 6aa6e897..9b98b179 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -39,45 +39,37 @@ FILE_LICENCE ( GPL2_OR_LATER ); * RSA is documented in RFC 3447. */ -/** An RSA digestInfo prefix */ -struct rsa_digestinfo_prefix { - /** Digest algorithm */ - struct digest_algorithm *digest; - /** Prefix */ - const void *data; - /** Length of prefix */ - size_t len; -}; - -/** "id-md5" object identifier */ -static const uint8_t rsa_md5_prefix[] = +/** MD5 digestInfo prefix */ +static const uint8_t rsa_md5_prefix_data[] = { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) }; -/** "id-sha1" object identifier */ -static const uint8_t rsa_sha1_prefix[] = +/** SHA-1 digestInfo prefix */ +static const uint8_t rsa_sha1_prefix_data[] = { RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) }; -/** "id-sha256" object identifier */ -static const uint8_t rsa_sha256_prefix[] = +/** SHA-256 digestInfo prefix */ +static const uint8_t rsa_sha256_prefix_data[] = { RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) }; -/** RSA digestInfo prefixes */ -static struct rsa_digestinfo_prefix rsa_digestinfo_prefixes[] = { - { - .digest = &md5_algorithm, - .data = rsa_md5_prefix, - .len = sizeof ( rsa_md5_prefix ), - }, - { - .digest = &sha1_algorithm, - .data = rsa_sha1_prefix, - .len = sizeof ( rsa_sha1_prefix ), - }, - { - .digest = &sha256_algorithm, - .data = rsa_sha256_prefix, - .len = sizeof ( rsa_sha256_prefix ), - }, +/** MD5 digestInfo prefix */ +struct rsa_digestinfo_prefix rsa_md5_prefix __rsa_digestinfo_prefix = { + .digest = &md5_algorithm, + .data = rsa_md5_prefix_data, + .len = sizeof ( rsa_md5_prefix_data ), +}; + +/** SHA-1 digestInfo prefix */ +struct rsa_digestinfo_prefix rsa_sha1_prefix __rsa_digestinfo_prefix = { + .digest = &sha1_algorithm, + .data = rsa_sha1_prefix_data, + .len = sizeof ( rsa_sha1_prefix_data ), +}; + +/** SHA-256 digestInfo prefix */ +struct rsa_digestinfo_prefix rsa_sha256_prefix __rsa_digestinfo_prefix = { + .digest = &sha256_algorithm, + .data = rsa_sha256_prefix_data, + .len = sizeof ( rsa_sha256_prefix_data ), }; /** @@ -89,11 +81,8 @@ static struct rsa_digestinfo_prefix rsa_digestinfo_prefixes[] = { static struct rsa_digestinfo_prefix * rsa_find_prefix ( struct digest_algorithm *digest ) { struct rsa_digestinfo_prefix *prefix; - unsigned int i; - for ( i = 0 ; i < ( sizeof ( rsa_digestinfo_prefixes ) / - sizeof ( rsa_digestinfo_prefixes[0] ) ) ; i++ ) { - prefix = &rsa_digestinfo_prefixes[i]; + for_each_table_entry ( prefix, RSA_DIGESTINFO_PREFIXES ) { if ( prefix->digest == digest ) return prefix; } diff --git a/src/include/ipxe/rsa.h b/src/include/ipxe/rsa.h index 87e75a82..d43d336a 100644 --- a/src/include/ipxe/rsa.h +++ b/src/include/ipxe/rsa.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include /** ASN.1 OID for iso(1) member-body(2) us(840) */ #define ASN1_OID_ISO_US ASN1_OID_ISO_MEMBERBODY, ASN1_OID_DOUBLE ( 840 ) @@ -111,6 +112,23 @@ FILE_LICENCE ( GPL2_OR_LATER ); RSA_DIGESTALGORITHM ( __VA_ARGS__ ), \ RSA_DIGEST_PREFIX ( digest_size ) +/** An RSA digestInfo prefix */ +struct rsa_digestinfo_prefix { + /** Digest algorithm */ + struct digest_algorithm *digest; + /** Prefix */ + const void *data; + /** Length of prefix */ + size_t len; +}; + +/** RSA digestInfo prefix table */ +#define RSA_DIGESTINFO_PREFIXES \ + __table ( struct rsa_digestinfo_prefix, "rsa_digestinfo_prefixes" ) + +/** Declare an RSA digestInfo prefix */ +#define __rsa_digestinfo_prefix __table_entry ( RSA_DIGESTINFO_PREFIXES, 01 ) + /** An RSA context */ struct rsa_context { /** Allocated memory */ From 8685280cbddc6e2d050d5e94719cab5d4ba866fc Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Mar 2012 13:32:20 +0000 Subject: [PATCH 101/221] [build] Allow a client certificate to be specified at build time Allow a client certificate and corresponding private key to be specified at build time using the syntax make CERT=/path/to/certificate KEY=/path/to/key The build process uses openssl to convert the files into DER format, and includes them within the client certificate store in clientcert.c. The build process will prompt for the private key password if applicable. Note that the private key is stored unencrypted, and so the resulting iPXE binary (and the temporary files created during the build process) should be treated as being equivalent to an unencrypted private key file. Signed-off-by: Michael Brown --- src/Makefile.housekeeping | 80 ++++++++++++++++++++++++++++++++--- src/crypto/clientcert.c | 80 +++++++++++++++++++++++++++++++++++ src/include/ipxe/clientcert.h | 43 +++++++++++++++++++ 3 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 src/crypto/clientcert.c create mode 100644 src/include/ipxe/clientcert.h diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index daac97b9..0fab407c 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -629,12 +629,6 @@ EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\ $(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST) -# This file uses .incbin inline assembly to include a binary file. -# Unfortunately ccache does not detect this dependency and caches builds even -# when the binary file has changed. -# -$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC) - CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)" # List of trusted root certificates @@ -665,6 +659,80 @@ $(BIN)/rootcert.o : $(TRUSTED_FILES) $(TRUSTED_LIST) CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)") +# (Single-element) list of client certificates +# +CERT_LIST := $(BIN)/.certificate.list +ifeq ($(wildcard $(CERT_LIST)),) +CERT_OLD := +else +CERT_OLD := $(shell cat $(CERT_LIST)) +endif +ifneq ($(CERT_OLD),$(CERT)) +$(shell $(ECHO) "$(CERT)" > $(CERT_LIST)) +endif + +$(CERT_LIST) : + +VERYCLEANUP += $(CERT_LIST) + +# Embedded client certificate +# +CERT_INC := $(BIN)/.certificate.der + +ifdef CERT +$(CERT_INC) : $(CERT) $(CERT_LIST) + $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@ + +$(BIN)/clientcert.o : $(CERT_INC) +endif + +CLEANUP += $(CERT_INC) + +$(BIN)/clientcert.o : $(CERT_LIST) + +CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"") + +# (Single-element) list of client private keys +# +KEY_LIST := $(BIN)/.private_key.list +ifeq ($(wildcard $(KEY_LIST)),) +KEY_OLD := +else +KEY_OLD := $(shell cat $(KEY_LIST)) +endif +ifneq ($(KEY_OLD),$(KEY)) +$(shell $(ECHO) "$(KEY)" > $(KEY_LIST)) +endif + +$(KEY_LIST) : + +VERYCLEANUP += $(KEY_LIST) + +# Embedded client private key +# +KEY_INC := $(BIN)/.private_key.der + +ifdef KEY +$(KEY_INC) : $(KEY) $(KEY_LIST) + $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@ + +$(BIN)/clientcert.o : $(KEY_INC) +endif + +CLEANUP += $(KEY_INC) + +$(BIN)/clientcert.o : $(KEY_LIST) + +CFLAGS_clientcert += $(if $(KEY),-DPRIVATE_KEY="\"$(KEY_INC)\"") + +# These files use .incbin inline assembly to include a binary file. +# Unfortunately ccache does not detect this dependency and caches +# builds even when the binary file has changed. +# +$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC) + +$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC) + # Generate error usage information # $(BIN)/%.einfo : $(BIN)/%.o diff --git a/src/crypto/clientcert.c b/src/crypto/clientcert.c new file mode 100644 index 00000000..03c75284 --- /dev/null +++ b/src/crypto/clientcert.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** @file + * + * Client certificate store + * + * Life would in theory be easier if we could use a single file to + * hold both the certificate and corresponding private key. + * Unfortunately, the only common format which supports this is + * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my + * codebase. See, for reference and amusement: + * + * http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html + * + */ + +/* Sanity checks */ +#if defined(CERTIFICATE) && ! defined(PRIVATE_KEY) +#warning "Attempting to embed certificate with no corresponding private key" +#endif +#if defined(PRIVATE_KEY) && ! defined(CERTIFICATE) +#warning "Attempting to embed private key with no corresponding certificate" +#endif + +/* Raw client certificate data */ +extern char client_certificate_data[]; +extern char client_certificate_len[]; +__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" + "\nclient_certificate_data:\n\t" +#ifdef CERTIFICATE + ".incbin \"" CERTIFICATE "\"\n\t" +#endif /* CERTIFICATE */ + ".size client_certificate_data, ( . - client_certificate_data )\n\t" + ".equ client_certificate_len, ( . - client_certificate_data )\n\t" + ".previous\n\t" ); + +/** Client certificate */ +struct client_certificate client_certificate = { + .data = client_certificate_data, + .len = ( ( size_t ) client_certificate_len ), +}; + +/* Raw client private key data */ +extern char client_private_key_data[]; +extern char client_private_key_len[]; +__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" + "\nclient_private_key_data:\n\t" +#ifdef PRIVATE_KEY + ".incbin \"" PRIVATE_KEY "\"\n\t" +#endif /* PRIVATE_KEY */ + ".size client_private_key_data, ( . - client_private_key_data )\n\t" + ".equ client_private_key_len, ( . - client_private_key_data )\n\t" + ".previous\n\t" ); + +/** Client private key */ +struct client_private_key client_private_key = { + .data = client_private_key_data, + .len = ( ( size_t ) client_private_key_len ), +}; diff --git a/src/include/ipxe/clientcert.h b/src/include/ipxe/clientcert.h new file mode 100644 index 00000000..08f62eb7 --- /dev/null +++ b/src/include/ipxe/clientcert.h @@ -0,0 +1,43 @@ +#ifndef _IPXE_CLIENTCERT_H +#define _IPXE_CLIENTCERT_H + +/** @file + * + * Client certificate store + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +/** A client certificate */ +struct client_certificate { + /** Data */ + const void *data; + /** Length */ + size_t len; +}; + +/** A client private key */ +struct client_private_key { + /** Data */ + const void *data; + /** Length */ + size_t len; +}; + +extern struct client_certificate client_certificate; +extern struct client_private_key client_private_key; + +/** + * Check for presence of a client certificate + * + * @ret have_cert We have a client certificate and private key + */ +static inline int have_client_certificate ( void ) { + return ( ( client_certificate.len > 0 ) && + ( client_private_key.len > 0 ) ); +} + +#endif /* _IPXE_CLIENTCERT_H */ From cf78afa5c541ce322aed17c6b6c5b492ed40b2e1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Mar 2012 17:09:22 +0000 Subject: [PATCH 102/221] [tls] Support sending a client certificate Signed-off-by: Michael Brown --- src/include/ipxe/tls.h | 33 +++++- src/net/tls.c | 250 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 268 insertions(+), 15 deletions(-) diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 0d1f2d85..77223336 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -80,6 +80,14 @@ struct tls_header { #define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003c #define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003d +/* TLS hash algorithm identifiers */ +#define TLS_MD5_ALGORITHM 1 +#define TLS_SHA1_ALGORITHM 2 +#define TLS_SHA256_ALGORITHM 4 + +/* TLS signature algorithm identifiers */ +#define TLS_RSA_ALGORITHM 1 + /* TLS extension types */ #define TLS_SERVER_NAME 0 #define TLS_SERVER_NAME_HOST_NAME 0 @@ -95,8 +103,9 @@ enum tls_tx_pending { TLS_TX_CLIENT_HELLO = 0x0001, TLS_TX_CERTIFICATE = 0x0002, TLS_TX_CLIENT_KEY_EXCHANGE = 0x0004, - TLS_TX_CHANGE_CIPHER = 0x0008, - TLS_TX_FINISHED = 0x0010, + TLS_TX_CERTIFICATE_VERIFY = 0x0008, + TLS_TX_CHANGE_CIPHER = 0x0010, + TLS_TX_FINISHED = 0x0020, }; /** A TLS cipher suite */ @@ -129,6 +138,24 @@ struct tls_cipherspec { void *mac_secret; }; +/** A TLS signature and hash algorithm identifier */ +struct tls_signature_hash_id { + /** Hash algorithm */ + uint8_t hash; + /** Signature algorithm */ + uint8_t signature; +} __attribute__ (( packed )); + +/** A TLS signature algorithm */ +struct tls_signature_hash_algorithm { + /** Digest algorithm */ + struct digest_algorithm *digest; + /** Public-key algorithm */ + struct pubkey_algorithm *pubkey; + /** Numeric code */ + struct tls_signature_hash_id code; +}; + /** TLS pre-master secret */ struct tls_pre_master_secret { /** TLS version */ @@ -205,6 +232,8 @@ struct tls_session { struct digest_algorithm *handshake_digest; /** Digest algorithm context used for handshake verification */ uint8_t *handshake_ctx; + /** Public-key algorithm used for Certificate Verify (if sent) */ + struct pubkey_algorithm *verify_pubkey; /** TX sequence number */ uint64_t tx_seq; diff --git a/src/net/tls.c b/src/net/tls.c index 56b01f23..4b5891e4 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include @@ -75,8 +76,25 @@ static void tls_clear_cipher ( struct tls_session *tls, * TLS uses 24-bit integers in several places, which are awkward to * parse in C. */ -static unsigned long tls_uint24 ( const uint8_t field24[3] ) { - return ( ( field24[0] << 16 ) + ( field24[1] << 8 ) + field24[2] ); +static inline __attribute__ (( always_inline )) unsigned long +tls_uint24 ( const uint8_t field24[3] ) { + const uint32_t *field32 __attribute__ (( may_alias )) = + ( ( const void * ) field24 ); + return ( be32_to_cpu ( *field32 ) >> 8 ); +} + +/** + * Set 24-bit field value + * + * @v field24 24-bit field + * @v value Field value + * + * The field must be pre-zeroed. + */ +static void tls_set_uint24 ( uint8_t field24[3], unsigned long value ) { + uint32_t *field32 __attribute__ (( may_alias )) = + ( ( void * ) field24 ); + *field32 |= cpu_to_be32 ( value << 8 ); } /****************************************************************************** @@ -137,6 +155,13 @@ static struct digest_algorithm md5_sha1_algorithm = { .final = md5_sha1_final, }; +/** RSA digestInfo prefix for MD5+SHA1 algorithm */ +struct rsa_digestinfo_prefix rsa_md5_sha1_prefix __rsa_digestinfo_prefix = { + .digest = &md5_sha1_algorithm, + .data = NULL, /* MD5+SHA1 signatures have no digestInfo */ + .len = 0, +}; + /****************************************************************************** * * Cleanup functions @@ -674,6 +699,59 @@ static int tls_change_cipher ( struct tls_session *tls, return 0; } +/****************************************************************************** + * + * Signature and hash algorithms + * + ****************************************************************************** + */ + +/** Supported signature and hash algorithms + * + * Note that the default (TLSv1.1 and earlier) algorithm using + * MD5+SHA1 is never explicitly specified. + */ +struct tls_signature_hash_algorithm tls_signature_hash_algorithms[] = { + { + .code = { + .signature = TLS_RSA_ALGORITHM, + .hash = TLS_SHA256_ALGORITHM, + }, + .pubkey = &rsa_algorithm, + .digest = &sha256_algorithm, + }, +}; + +/** Number of supported signature and hash algorithms */ +#define TLS_NUM_SIG_HASH_ALGORITHMS \ + ( sizeof ( tls_signature_hash_algorithms ) / \ + sizeof ( tls_signature_hash_algorithms[0] ) ) + +/** + * Find TLS signature and hash algorithm + * + * @v pubkey Public-key algorithm + * @v digest Digest algorithm + * @ret sig_hash Signature and hash algorithm, or NULL + */ +static struct tls_signature_hash_algorithm * +tls_signature_hash_algorithm ( struct pubkey_algorithm *pubkey, + struct digest_algorithm *digest ) { + struct tls_signature_hash_algorithm *sig_hash; + unsigned int i; + + /* Identify signature and hash algorithm */ + for ( i = 0 ; i < TLS_NUM_SIG_HASH_ALGORITHMS ; i++ ) { + sig_hash = &tls_signature_hash_algorithms[i]; + if ( ( sig_hash->pubkey == pubkey ) && + ( sig_hash->digest == digest ) ) { + return sig_hash; + } + } + + return NULL; +} + /****************************************************************************** * * Handshake verification @@ -812,20 +890,69 @@ static int tls_send_client_hello ( struct tls_session *tls ) { * @ret rc Return status code */ static int tls_send_certificate ( struct tls_session *tls ) { + int num_certificates = ( have_client_certificate() ? 1 : 0 ); struct { uint32_t type_length; uint8_t length[3]; - } __attribute__ (( packed )) certificate; + struct { + uint8_t length[3]; + uint8_t data[ client_certificate.len ]; + } __attribute__ (( packed )) certificates[num_certificates]; + } __attribute__ (( packed )) *certificate; + struct x509_certificate cert; + int rc; - memset ( &certificate, 0, sizeof ( certificate ) ); - certificate.type_length = ( cpu_to_le32 ( TLS_CERTIFICATE ) | - htonl ( sizeof ( certificate ) - - sizeof ( certificate.type_length))); + /* If we have a certificate to send, determine the applicable + * public-key algorithm and schedule transmission of + * CertificateVerify. + */ + if ( num_certificates ) { - return tls_send_handshake ( tls, &certificate, sizeof ( certificate ) ); + /* Parse certificate to determine public-key algorithm */ + if ( ( rc = x509_parse ( &cert, client_certificate.data, + client_certificate.len ) ) != 0 ) { + DBGC ( tls, "TLS %p could not parse client " + "certificate: %s\n", tls, strerror ( rc ) ); + return rc; + } + tls->verify_pubkey = cert.signature_algorithm->pubkey; + + /* Schedule CertificateVerify transmission */ + tls->tx_pending |= TLS_TX_CERTIFICATE_VERIFY; + tls_tx_resume ( tls ); + } + + /* Allocate storage for Certificate record (which may be too + * large for the stack). + */ + certificate = zalloc ( sizeof ( *certificate ) ); + if ( ! certificate ) + return -ENOMEM; + + /* Populate record */ + certificate->type_length = + ( cpu_to_le32 ( TLS_CERTIFICATE ) | + htonl ( sizeof ( *certificate ) - + sizeof ( certificate->type_length ) ) ); + tls_set_uint24 ( certificate->length, + sizeof ( certificate->certificates ) ); + if ( num_certificates ) { + tls_set_uint24 ( certificate->certificates[0].length, + sizeof ( certificate->certificates[0].data ) ); + memcpy ( certificate->certificates[0].data, + client_certificate.data, + sizeof ( certificate->certificates[0].data ) ); + } + + /* Transmit record */ + rc = tls_send_handshake ( tls, certificate, sizeof ( *certificate ) ); + + /* Free record */ + free ( certificate ); + + return rc; } - /** * Transmit Client Key Exchange record * @@ -866,7 +993,97 @@ static int tls_send_client_key_exchange ( struct tls_session *tls ) { htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) - unused ); - return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) ); + return tls_send_handshake ( tls, &key_xchg, + ( sizeof ( key_xchg ) - unused ) ); +} + +/** + * Transmit Certificate Verify record + * + * @v tls TLS session + * @ret rc Return status code + */ +static int tls_send_certificate_verify ( struct tls_session *tls ) { + struct digest_algorithm *digest = tls->handshake_digest; + struct pubkey_algorithm *pubkey = tls->verify_pubkey; + uint8_t digest_out[ digest->digestsize ]; + uint8_t ctx[ pubkey->ctxsize ]; + struct tls_signature_hash_algorithm *sig_hash = NULL; + int rc; + + /* Generate digest to be signed */ + tls_verify_handshake ( tls, digest_out ); + + /* Initialise public-key algorithm */ + if ( ( rc = pubkey_init ( pubkey, ctx, client_private_key.data, + client_private_key.len ) ) != 0 ) { + DBGC ( tls, "TLS %p could not initialise %s client private " + "key: %s\n", tls, pubkey->name, strerror ( rc ) ); + goto err_pubkey_init; + } + + /* TLSv1.2 and later use explicit algorithm identifiers */ + if ( tls->version >= TLS_VERSION_TLS_1_2 ) { + sig_hash = tls_signature_hash_algorithm ( pubkey, digest ); + if ( ! sig_hash ) { + DBGC ( tls, "TLS %p could not identify (%s,%s) " + "signature and hash algorithm\n", tls, + pubkey->name, digest->name ); + rc = -ENOTSUP; + goto err_sig_hash; + } + } + + /* Generate and transmit record */ + { + size_t max_len = pubkey_max_len ( pubkey, ctx ); + int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 ); + struct { + uint32_t type_length; + struct tls_signature_hash_id sig_hash[use_sig_hash]; + uint16_t signature_len; + uint8_t signature[max_len]; + } __attribute__ (( packed )) certificate_verify; + size_t unused; + int len; + + /* Sign digest */ + len = pubkey_sign ( pubkey, ctx, digest, digest_out, + certificate_verify.signature ); + if ( len < 0 ) { + rc = len; + DBGC ( tls, "TLS %p could not sign %s digest using %s " + "client private key: %s\n", tls, digest->name, + pubkey->name, strerror ( rc ) ); + goto err_pubkey_sign; + } + unused = ( max_len - len ); + + /* Construct Certificate Verify record */ + certificate_verify.type_length = + ( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) | + htonl ( sizeof ( certificate_verify ) - + sizeof ( certificate_verify.type_length ) - + unused ) ); + if ( use_sig_hash ) { + memcpy ( &certificate_verify.sig_hash[0], + &sig_hash->code, + sizeof ( certificate_verify.sig_hash[0] ) ); + } + certificate_verify.signature_len = + htons ( sizeof ( certificate_verify.signature ) - + unused ); + + /* Transmit record */ + rc = tls_send_handshake ( tls, &certificate_verify, + ( sizeof ( certificate_verify ) - unused ) ); + } + + err_pubkey_sign: + err_sig_hash: + pubkey_final ( pubkey, ctx ); + err_pubkey_init: + return rc; } /** @@ -1182,9 +1399,8 @@ static int tls_new_certificate_request ( struct tls_session *tls, const void *data __unused, size_t len __unused ) { - /* We can only send an empty certificate (as mandated by - * TLSv1.2), so there is no point in parsing the Certificate - * Request. + /* We can only send a single certificate, so there is no point + * in parsing the Certificate Request. */ /* Schedule Certificate transmission */ @@ -2002,6 +2218,14 @@ static void tls_tx_step ( struct tls_session *tls ) { goto err; } tls->tx_pending &= ~TLS_TX_CLIENT_KEY_EXCHANGE; + } else if ( tls->tx_pending & TLS_TX_CERTIFICATE_VERIFY ) { + /* Send Certificate Verify */ + if ( ( rc = tls_send_certificate_verify ( tls ) ) != 0 ) { + DBGC ( tls, "TLS %p could not send Certificate " + "Verify: %s\n", tls, strerror ( rc ) ); + goto err; + } + tls->tx_pending &= ~TLS_TX_CERTIFICATE_VERIFY; } else if ( tls->tx_pending & TLS_TX_CHANGE_CIPHER ) { /* Send Change Cipher, and then change the cipher in use */ if ( ( rc = tls_send_change_cipher ( tls ) ) != 0 ) { From c76afb36054669759dd7a876e80b9779dbc79120 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 14:13:15 +0000 Subject: [PATCH 103/221] [crypto] Use standard bit-rotation functions Signed-off-by: Michael Brown --- src/crypto/md5.c | 12 +----------- src/crypto/sha1.c | 12 +----------- src/crypto/sha256.c | 12 +----------- src/include/ipxe/rotate.h | 12 ++++++++---- 4 files changed, 11 insertions(+), 37 deletions(-) diff --git a/src/crypto/md5.c b/src/crypto/md5.c index e6c68821..2d0d03d1 100644 --- a/src/crypto/md5.c +++ b/src/crypto/md5.c @@ -28,20 +28,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include -/** - * Rotate dword left - * - * @v dword Dword - * @v rotate Amount of rotation - */ -static inline __attribute__ (( always_inline )) uint32_t -rol32 ( uint32_t dword, unsigned int rotate ) { - return ( ( dword << rotate ) | ( dword >> ( 32 - rotate ) ) ); -} - /** MD5 variables */ struct md5_variables { /* This layout matches that of struct md5_digest_data, diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c index 834d9a21..fd271a63 100644 --- a/src/crypto/sha1.c +++ b/src/crypto/sha1.c @@ -28,20 +28,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include -/** - * Rotate dword left - * - * @v dword Dword - * @v rotate Amount of rotation - */ -static inline __attribute__ (( always_inline )) uint32_t -rol32 ( uint32_t dword, unsigned int rotate ) { - return ( ( dword << rotate ) | ( dword >> ( 32 - rotate ) ) ); -} - /** SHA-1 variables */ struct sha1_variables { /* This layout matches that of struct sha1_digest_data, diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c index 71683901..6736a577 100644 --- a/src/crypto/sha256.c +++ b/src/crypto/sha256.c @@ -28,20 +28,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include -/** - * Rotate dword right - * - * @v dword Dword - * @v rotate Amount of rotation - */ -static inline __attribute__ (( always_inline )) uint32_t -ror32 ( uint32_t dword, unsigned int rotate ) { - return ( ( dword >> rotate ) | ( dword << ( 32 - rotate ) ) ); -} - /** SHA-256 variables */ struct sha256_variables { /* This layout matches that of struct sha256_digest_data, diff --git a/src/include/ipxe/rotate.h b/src/include/ipxe/rotate.h index 745d84e6..ba271ca7 100644 --- a/src/include/ipxe/rotate.h +++ b/src/include/ipxe/rotate.h @@ -10,19 +10,23 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -static inline uint32_t rol32 ( uint32_t data, unsigned int rotation ) { +static inline __attribute__ (( always_inline )) uint32_t +rol32 ( uint32_t data, unsigned int rotation ) { return ( ( data << rotation ) | ( data >> ( 32 - rotation ) ) ); } -static inline uint32_t ror32 ( uint32_t data, unsigned int rotation ) { +static inline __attribute__ (( always_inline )) uint32_t +ror32 ( uint32_t data, unsigned int rotation ) { return ( ( data >> rotation ) | ( data << ( 32 - rotation ) ) ); } -static inline uint64_t rol64 ( uint64_t data, unsigned int rotation ) { +static inline __attribute__ (( always_inline )) uint64_t +rol64 ( uint64_t data, unsigned int rotation ) { return ( ( data << rotation ) | ( data >> ( 64 - rotation ) ) ); } -static inline uint64_t ror64 ( uint64_t data, unsigned int rotation ) { +static inline __attribute__ (( always_inline )) uint64_t +ror64 ( uint64_t data, unsigned int rotation ) { return ( ( data >> rotation ) | ( data << ( 64 - rotation ) ) ); } From 225be9d5988543d38069b357003e39a3b5a05e8d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Mar 2012 23:31:01 +0000 Subject: [PATCH 104/221] [crypto] Move all ASN.1 OIDs to asn1.h Signed-off-by: Michael Brown --- src/include/ipxe/asn1.h | 91 +++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/rsa.h | 75 --------------------------------- src/include/ipxe/x509.h | 16 -------- 3 files changed, 91 insertions(+), 91 deletions(-) diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index be344c9c..064f2a99 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -91,6 +91,97 @@ struct asn1_cursor { /** ASN.1 OID for joint-iso-itu-t(2) country(16) */ #define ASN1_OID_COUNTRY ASN1_OID_INITIAL ( 2, 16 ) +/** ASN.1 OID for iso(1) member-body(2) us(840) */ +#define ASN1_OID_ISO_US ASN1_OID_ISO_MEMBERBODY, ASN1_OID_DOUBLE ( 840 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) */ +#define ASN1_OID_RSADSI ASN1_OID_ISO_US, ASN1_OID_TRIPLE ( 113549 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) */ +#define ASN1_OID_PKCS ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) + * digestAlgorithm(2) + */ +#define ASN1_OID_DIGESTALGORITHM ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) */ +#define ASN1_OID_OIW ASN1_OID_IDENTIFIED_ORGANIZATION, ASN1_OID_SINGLE ( 14 ) + +/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) secsig(3) */ +#define ASN1_OID_SECSIG ASN1_OID_OIW, ASN1_OID_SINGLE ( 3 ) + +/** ASN1. OID for iso(1) identified-organization(3) oiw(14) secsig(3) + * algorithms(2) + */ +#define ASN1_OID_SECSIG_ALGORITHMS ASN1_OID_SECSIG, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) */ +#define ASN1_OID_COUNTRY_US ASN1_OID_COUNTRY, ASN1_OID_DOUBLE ( 840 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) organization(1) */ +#define ASN1_OID_US_ORGANIZATION ASN1_OID_COUNTRY_US, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) + */ +#define ASN1_OID_US_GOV ASN1_OID_US_ORGANIZATION, ASN1_OID_SINGLE ( 101 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) + */ +#define ASN1_OID_CSOR ASN1_OID_US_GOV, ASN1_OID_SINGLE ( 3 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistalgorithm(4) + */ +#define ASN1_OID_NISTALGORITHM ASN1_OID_CSOR, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) + * organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) + */ +#define ASN1_OID_HASHALGS ASN1_OID_NISTALGORITHM, ASN1_OID_SINGLE ( 2 ) + +/** ASN.1 OID for pkcs-1 */ +#define ASN1_OID_PKCS_1 ASN1_OID_PKCS, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for rsaEncryption */ +#define ASN1_OID_RSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for md5WithRSAEncryption */ +#define ASN1_OID_MD5WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for sha1WithRSAEncryption */ +#define ASN1_OID_SHA1WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 5 ) + +/** ASN.1 OID for sha256WithRSAEncryption */ +#define ASN1_OID_SHA256WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 11 ) + +/** ASN.1 OID for id-md5 */ +#define ASN1_OID_MD5 ASN1_OID_DIGESTALGORITHM, ASN1_OID_SINGLE ( 5 ) + +/** ASN.1 OID for id-sha1 */ +#define ASN1_OID_SHA1 ASN1_OID_SECSIG_ALGORITHMS, ASN1_OID_SINGLE ( 26 ) + +/** ASN.1 OID for id-sha256 */ +#define ASN1_OID_SHA256 ASN1_OID_HASHALGS, ASN1_OID_SINGLE ( 1 ) + +/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */ +#define ASN1_OID_ATTRIBUTE_TYPE \ + ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 ) + +/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */ +#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 ) + +/** ASN.1 OID for id-ce */ +#define ASN1_OID_CE ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 29 ) + +/** ASN.1 OID for id-ce-keyUsage */ +#define ASN1_OID_KEYUSAGE ASN1_OID_CE, ASN1_OID_SINGLE ( 15 ) + +/** ASN.1 OID for id-ce-basicConstraints */ +#define ASN1_OID_BASICCONSTRAINTS ASN1_OID_CE, ASN1_OID_SINGLE ( 19 ) + /** Define an ASN.1 cursor containing an OID */ #define ASN1_OID_CURSOR( oid_value ) { \ .data = oid_value, \ diff --git a/src/include/ipxe/rsa.h b/src/include/ipxe/rsa.h index d43d336a..1a5ad8ba 100644 --- a/src/include/ipxe/rsa.h +++ b/src/include/ipxe/rsa.h @@ -13,81 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include -/** ASN.1 OID for iso(1) member-body(2) us(840) */ -#define ASN1_OID_ISO_US ASN1_OID_ISO_MEMBERBODY, ASN1_OID_DOUBLE ( 840 ) - -/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) */ -#define ASN1_OID_RSADSI ASN1_OID_ISO_US, ASN1_OID_TRIPLE ( 113549 ) - -/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) */ -#define ASN1_OID_PKCS ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) - * digestAlgorithm(2) - */ -#define ASN1_OID_DIGESTALGORITHM ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 2 ) - -/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) */ -#define ASN1_OID_OIW ASN1_OID_IDENTIFIED_ORGANIZATION, ASN1_OID_SINGLE ( 14 ) - -/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) secsig(3) */ -#define ASN1_OID_SECSIG ASN1_OID_OIW, ASN1_OID_SINGLE ( 3 ) - -/** ASN1. OID for iso(1) identified-organization(3) oiw(14) secsig(3) - * algorithms(2) - */ -#define ASN1_OID_SECSIG_ALGORITHMS ASN1_OID_SECSIG, ASN1_OID_SINGLE ( 2 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) */ -#define ASN1_OID_COUNTRY_US ASN1_OID_COUNTRY, ASN1_OID_DOUBLE ( 840 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) organization(1) */ -#define ASN1_OID_US_ORGANIZATION ASN1_OID_COUNTRY_US, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) - */ -#define ASN1_OID_US_GOV ASN1_OID_US_ORGANIZATION, ASN1_OID_SINGLE ( 101 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) csor(3) - */ -#define ASN1_OID_CSOR ASN1_OID_US_GOV, ASN1_OID_SINGLE ( 3 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) csor(3) nistalgorithm(4) - */ -#define ASN1_OID_NISTALGORITHM ASN1_OID_CSOR, ASN1_OID_SINGLE ( 4 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) - */ -#define ASN1_OID_HASHALGS ASN1_OID_NISTALGORITHM, ASN1_OID_SINGLE ( 2 ) - -/** ASN.1 OID for pkcs-1 */ -#define ASN1_OID_PKCS_1 ASN1_OID_PKCS, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for rsaEncryption */ -#define ASN1_OID_RSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for md5WithRSAEncryption */ -#define ASN1_OID_MD5WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 4 ) - -/** ASN.1 OID for sha1WithRSAEncryption */ -#define ASN1_OID_SHA1WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 5 ) - -/** ASN.1 OID for sha256WithRSAEncryption */ -#define ASN1_OID_SHA256WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 11 ) - -/** ASN.1 OID for id-md5 */ -#define ASN1_OID_MD5 ASN1_OID_DIGESTALGORITHM, ASN1_OID_SINGLE ( 5 ) - -/** ASN.1 OID for id-sha1 */ -#define ASN1_OID_SHA1 ASN1_OID_SECSIG_ALGORITHMS, ASN1_OID_SINGLE ( 26 ) - -/** ASN.1 OID for id-sha256 */ -#define ASN1_OID_SHA256 ASN1_OID_HASHALGS, ASN1_OID_SINGLE ( 1 ) - /** RSA digestAlgorithm sequence contents */ #define RSA_DIGESTALGORITHM_CONTENTS( ... ) \ ASN1_OID, VA_ARG_COUNT ( __VA_ARGS__ ), __VA_ARGS__, \ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 925e23f7..89f90b84 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -14,22 +14,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include -/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */ -#define ASN1_OID_ATTRIBUTE_TYPE \ - ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 ) - -/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */ -#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 ) - -/** ASN.1 OID for id-ce */ -#define ASN1_OID_CE ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 29 ) - -/** ASN.1 OID for id-ce-keyUsage */ -#define ASN1_OID_KEYUSAGE ASN1_OID_CE, ASN1_OID_SINGLE ( 15 ) - -/** ASN.1 OID for id-ce-basicConstraints */ -#define ASN1_OID_BASICCONSTRAINTS ASN1_OID_CE, ASN1_OID_SINGLE ( 19 ) - /** An X.509 algorithm */ struct x509_algorithm { /** Name */ From 94cdbd76d684d37e1956a91f5a340e623bea4666 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 16:09:58 +0000 Subject: [PATCH 105/221] [crypto] Treat ASN.1 OIDs as opaque OIDs are theoretically part of a global hierarchy. However, the hierarchy is sufficiently disorganised as to be essentially meaningless for all purposes other than guaranteeing uniqueness. Ignore the hierarchical nature of OIDs and treat them as opaque. Signed-off-by: Michael Brown --- src/include/ipxe/asn1.h | 147 ++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 96 deletions(-) diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 064f2a99..f912f5f5 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -79,113 +79,68 @@ struct asn1_cursor { #define ASN1_OID_TRIPLE( value ) \ ( 0x80 | ( ( (value) >> 14 ) & 0x7f ) ), ASN1_OID_DOUBLE ( (value) ) -/** ASN.1 OID for iso(1) member-body(2) */ -#define ASN1_OID_ISO_MEMBERBODY ASN1_OID_INITIAL ( 1, 2 ) +/** ASN.1 OID for rsaEncryption (1.2.840.113549.1.1.1) */ +#define ASN1_OID_RSAENCRYPTION \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 1 ) -/** ASN.1 OID for iso(1) identified-organization(3) */ -#define ASN1_OID_IDENTIFIED_ORGANIZATION ASN1_OID_INITIAL ( 1, 3 ) +/** ASN.1 OID for md5WithRSAEncryption (1.2.840.113549.1.1.4) */ +#define ASN1_OID_MD5WITHRSAENCRYPTION \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 4 ) -/** ASN.1 OID for joint-iso-itu-t(2) ds(5) */ -#define ASN1_OID_DIRECTORY_SERVICES ASN1_OID_INITIAL ( 2, 5 ) +/** ASN.1 OID for sha1WithRSAEncryption (1.2.840.113549.1.1.5) */ +#define ASN1_OID_SHA1WITHRSAENCRYPTION \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ) -/** ASN.1 OID for joint-iso-itu-t(2) country(16) */ -#define ASN1_OID_COUNTRY ASN1_OID_INITIAL ( 2, 16 ) +/** ASN.1 OID for sha256WithRSAEncryption (1.2.840.113549.1.1.11) */ +#define ASN1_OID_SHA256WITHRSAENCRYPTION \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 11 ) -/** ASN.1 OID for iso(1) member-body(2) us(840) */ -#define ASN1_OID_ISO_US ASN1_OID_ISO_MEMBERBODY, ASN1_OID_DOUBLE ( 840 ) +/** ASN.1 OID for id-md5 (1.2.840.113549.2.5) */ +#define ASN1_OID_MD5 \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 2 ), \ + ASN1_OID_SINGLE ( 5 ) -/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) */ -#define ASN1_OID_RSADSI ASN1_OID_ISO_US, ASN1_OID_TRIPLE ( 113549 ) +/** ASN.1 OID for id-sha1 (1.3.14.3.2.26) */ +#define ASN1_OID_SHA1 \ + ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 14 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 2 ), \ + ASN1_OID_SINGLE ( 26 ) -/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) */ -#define ASN1_OID_PKCS ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 1 ) +/** ASN.1 OID for id-sha256 (2.16.840.1.101.3.4.2.1) */ +#define ASN1_OID_SHA256 \ + ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 101 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 2 ), ASN1_OID_SINGLE ( 1 ) -/** ASN.1 OID for iso(1) member-body(2) us(840) rsadsi(113549) - * digestAlgorithm(2) - */ -#define ASN1_OID_DIGESTALGORITHM ASN1_OID_RSADSI, ASN1_OID_SINGLE ( 2 ) +/** ASN.1 OID for commonName (2.5.4.3) */ +#define ASN1_OID_COMMON_NAME \ + ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 4 ), \ + ASN1_OID_SINGLE ( 3 ) -/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) */ -#define ASN1_OID_OIW ASN1_OID_IDENTIFIED_ORGANIZATION, ASN1_OID_SINGLE ( 14 ) +/** ASN.1 OID for id-ce-keyUsage (2.5.29.15) */ +#define ASN1_OID_KEYUSAGE \ + ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ + ASN1_OID_SINGLE ( 15 ) -/** ASN.1 OID for iso(1) identified-organization(3) oiw(14) secsig(3) */ -#define ASN1_OID_SECSIG ASN1_OID_OIW, ASN1_OID_SINGLE ( 3 ) - -/** ASN1. OID for iso(1) identified-organization(3) oiw(14) secsig(3) - * algorithms(2) - */ -#define ASN1_OID_SECSIG_ALGORITHMS ASN1_OID_SECSIG, ASN1_OID_SINGLE ( 2 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) */ -#define ASN1_OID_COUNTRY_US ASN1_OID_COUNTRY, ASN1_OID_DOUBLE ( 840 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) organization(1) */ -#define ASN1_OID_US_ORGANIZATION ASN1_OID_COUNTRY_US, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) - */ -#define ASN1_OID_US_GOV ASN1_OID_US_ORGANIZATION, ASN1_OID_SINGLE ( 101 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) csor(3) - */ -#define ASN1_OID_CSOR ASN1_OID_US_GOV, ASN1_OID_SINGLE ( 3 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) csor(3) nistalgorithm(4) - */ -#define ASN1_OID_NISTALGORITHM ASN1_OID_CSOR, ASN1_OID_SINGLE ( 4 ) - -/** ASN.1 OID for joint-iso-itu-t(2) country(16) us(840) - * organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) - */ -#define ASN1_OID_HASHALGS ASN1_OID_NISTALGORITHM, ASN1_OID_SINGLE ( 2 ) - -/** ASN.1 OID for pkcs-1 */ -#define ASN1_OID_PKCS_1 ASN1_OID_PKCS, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for rsaEncryption */ -#define ASN1_OID_RSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for md5WithRSAEncryption */ -#define ASN1_OID_MD5WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 4 ) - -/** ASN.1 OID for sha1WithRSAEncryption */ -#define ASN1_OID_SHA1WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 5 ) - -/** ASN.1 OID for sha256WithRSAEncryption */ -#define ASN1_OID_SHA256WITHRSAENCRYPTION ASN1_OID_PKCS_1, ASN1_OID_SINGLE ( 11 ) - -/** ASN.1 OID for id-md5 */ -#define ASN1_OID_MD5 ASN1_OID_DIGESTALGORITHM, ASN1_OID_SINGLE ( 5 ) - -/** ASN.1 OID for id-sha1 */ -#define ASN1_OID_SHA1 ASN1_OID_SECSIG_ALGORITHMS, ASN1_OID_SINGLE ( 26 ) - -/** ASN.1 OID for id-sha256 */ -#define ASN1_OID_SHA256 ASN1_OID_HASHALGS, ASN1_OID_SINGLE ( 1 ) - -/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) */ -#define ASN1_OID_ATTRIBUTE_TYPE \ - ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 4 ) - -/** ASN.1 OID for joint-iso-itu-t(2) ds(5) attributeType(4) commonName(3) */ -#define ASN1_OID_COMMON_NAME ASN1_OID_ATTRIBUTE_TYPE, ASN1_OID_SINGLE ( 3 ) - -/** ASN.1 OID for id-ce */ -#define ASN1_OID_CE ASN1_OID_DIRECTORY_SERVICES, ASN1_OID_SINGLE ( 29 ) - -/** ASN.1 OID for id-ce-keyUsage */ -#define ASN1_OID_KEYUSAGE ASN1_OID_CE, ASN1_OID_SINGLE ( 15 ) - -/** ASN.1 OID for id-ce-basicConstraints */ -#define ASN1_OID_BASICCONSTRAINTS ASN1_OID_CE, ASN1_OID_SINGLE ( 19 ) +/** ASN.1 OID for id-ce-basicConstraints (2.5.29.19) */ +#define ASN1_OID_BASICCONSTRAINTS \ + ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ + ASN1_OID_SINGLE ( 19 ) /** Define an ASN.1 cursor containing an OID */ -#define ASN1_OID_CURSOR( oid_value ) { \ - .data = oid_value, \ - .len = sizeof ( oid_value ), \ +#define ASN1_OID_CURSOR( oid_value ) { \ + .data = oid_value, \ + .len = sizeof ( oid_value ), \ } /** An ASN.1 boolean */ From b1316ef27670d3dba06c61487fbe91222b5d050b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 19:18:38 +0000 Subject: [PATCH 106/221] [crypto] Validate path length constraint in certificate chain Signed-off-by: Michael Brown --- src/crypto/x509.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index a11eee6f..449d07e2 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -89,6 +89,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EACCES_EXPIRED ) #define EINFO_EACCES_EXPIRED \ __einfo_uniqify ( EINFO_EACCES, 0x04, "Expired (or not yet valid)" ) +#define EACCES_PATH_LEN \ + __einfo_error ( EINFO_EACCES_PATH_LEN ) +#define EINFO_EACCES_PATH_LEN \ + __einfo_uniqify ( EINFO_EACCES, 0x05, "Maximum path length exceeded" ) /** "commonName" object identifier */ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; @@ -1187,6 +1191,7 @@ int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, struct x509_certificate *current = &temp[0]; struct x509_certificate *next = &temp[1]; struct x509_certificate *swap; + unsigned int path_len = 0; int rc; /* Use default root certificate store if none specified */ @@ -1226,6 +1231,15 @@ int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, if ( ( rc = x509_validate_issuer ( current, next ) ) != 0 ) return rc; + /* Validate path length constraint */ + if ( path_len > next->extensions.basic.path_len ) { + DBGC ( context, "X509 chain %p path length %d exceeds " + "maximum %d\n", context, path_len, + next->extensions.basic.path_len ); + return -EACCES_PATH_LEN; + } + path_len++; + /* Move to next certificate in chain */ swap = current; current = next; From 9a03a8e3d23b993d4f4a475a9334cf29d8ce182b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Mar 2012 17:27:07 +0000 Subject: [PATCH 107/221] [test] Add X.509 self-tests Signed-off-by: Michael Brown --- src/include/ipxe/errfile.h | 1 + src/tests/tests.c | 1 + src/tests/x509_test.c | 918 +++++++++++++++++++++++++++++++++++++ 3 files changed, 920 insertions(+) create mode 100644 src/tests/x509_test.c diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index bfb738a4..4b568840 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -248,6 +248,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_entropy ( ERRFILE_OTHER | 0x00260000 ) #define ERRFILE_rsa ( ERRFILE_OTHER | 0x00270000 ) #define ERRFILE_linux_entropy ( ERRFILE_OTHER | 0x00280000 ) +#define ERRFILE_x509_test ( ERRFILE_OTHER | 0x00290000 ) /** @} */ diff --git a/src/tests/tests.c b/src/tests/tests.c index 3f4d5b4b..78a18a6c 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -36,3 +36,4 @@ REQUIRE_OBJECT ( hmac_drbg_test ); REQUIRE_OBJECT ( hash_df_test ); REQUIRE_OBJECT ( bigint_test ); REQUIRE_OBJECT ( rsa_test ); +REQUIRE_OBJECT ( x509_test ); diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c new file mode 100644 index 00000000..6076d9aa --- /dev/null +++ b/src/tests/x509_test.c @@ -0,0 +1,918 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * X.509 self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include + +/** Fingerprint algorithm used for X.509 test certificates */ +#define x509_test_algorithm sha256_algorithm + +/** An X.509 test certificate */ +struct x509_test_certificate { + /** Data */ + const void *data; + /** Length of data */ + size_t len; + /** Fingerprint */ + const void *fingerprint; +}; + +/** An X.509 test certificate chain */ +struct x509_test_chain { + /** Test certificates */ + struct x509_test_certificate **certs; + /** Number of certificates */ + unsigned int count; +}; + +/** Define inline certificate data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define inline fingerprint data */ +#define FINGERPRINT(...) { __VA_ARGS__ } + +/** Define a test certificate */ +#define CERTIFICATE( name, DATA, FINGERPRINT ) \ + static const uint8_t name ## _data[] = DATA; \ + static const uint8_t name ## _fingerprint[] = FINGERPRINT; \ + static struct x509_test_certificate name = { \ + .data = name ## _data, \ + .len = sizeof ( name ## _data ), \ + .fingerprint = name ## _fingerprint, \ + } + +/** Define a test certificate chain */ +#define CHAIN( name, ... ) \ + static struct x509_test_certificate * name ## _certs[] = \ + { __VA_ARGS__ }; \ + static struct x509_test_chain name = { \ + .certs = name ## _certs, \ + .count = ( sizeof ( name ## _certs ) / \ + sizeof ( name ## _certs[0] ) ), \ + } + +/* + * subject iPXE self-test root CA + * issuer iPXE self-test root CA + */ +CERTIFICATE ( root_crt, + DATA ( 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58, + 0xd2, 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, + 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, + 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, + 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, + 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30, + 0x38, 0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, + 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, + 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, + 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, + 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72, + 0xb5, 0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e, + 0xeb, 0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa, + 0x75, 0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd, + 0x8f, 0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3, + 0x72, 0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47, + 0x61, 0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec, + 0x2b, 0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97, + 0xd5, 0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e, + 0xda, 0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b, + 0x5d, 0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7, + 0x6c, 0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24, + 0x16, 0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9, + 0x44, 0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea, + 0x17, 0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82, + 0x36, 0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c, + 0x05, 0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75, + 0x29, 0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1, + 0xc8, 0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4, + 0xdb, 0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1, + 0x3d, 0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04, + 0xf8, 0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6, + 0xc0, 0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77, + 0xc9, 0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34, + 0x6f, 0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5, + 0x63, 0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94, + 0x10, 0xd4, 0x72, 0xd2, 0xb8 ), + FINGERPRINT ( 0x71, 0x5d, 0x51, 0x37, 0x5e, 0x18, 0xb3, 0xbc, + 0xbb, 0x30, 0x0e, 0x8f, 0x50, 0xc7, 0x55, 0xf5, + 0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38, + 0xaf, 0x00, 0xc4, 0x1a, 0xfc, 0xd8, 0xac, 0xc3 ) ); + +/* + * subject iPXE self-test intermediate CA + * issuer iPXE self-test root CA + */ +CERTIFICATE ( intermediate_crt, + DATA ( 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, + 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, + 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x31, + 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x33, 0x5a, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x27, + 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x69, + 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, + 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, + 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, + 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc9, 0x3a, + 0xee, 0xc6, 0x3c, 0xac, 0x4d, 0x81, 0xc6, 0x98, 0x5e, 0xe1, + 0x48, 0x66, 0x1a, 0x1e, 0x60, 0x19, 0x41, 0xae, 0xca, 0x14, + 0x97, 0xc8, 0x3a, 0x50, 0xb6, 0x48, 0xf5, 0x42, 0xac, 0x0f, + 0xe1, 0xe3, 0x47, 0xf0, 0xbf, 0x7c, 0xd0, 0xee, 0x8f, 0xb7, + 0xa6, 0x19, 0xad, 0xbb, 0xc5, 0x1b, 0x34, 0x38, 0xc8, 0xbd, + 0x55, 0x84, 0x93, 0x72, 0xaf, 0x84, 0xfc, 0x9b, 0x97, 0x1d, + 0xb5, 0x54, 0x24, 0xd6, 0x5d, 0xb7, 0x31, 0xf4, 0xbd, 0x3b, + 0x40, 0x97, 0xc0, 0xa9, 0x5a, 0x2a, 0xcb, 0x6b, 0x98, 0x07, + 0xdb, 0xb5, 0x9f, 0xe8, 0x31, 0x3f, 0x01, 0x46, 0x46, 0x70, + 0x05, 0xa2, 0x0f, 0x8c, 0x7a, 0x61, 0xf3, 0xdf, 0xdb, 0xa1, + 0x37, 0x2c, 0x88, 0x6a, 0x81, 0x21, 0x12, 0x4c, 0xf5, 0xcd, + 0xaf, 0xc9, 0xd2, 0x36, 0x3d, 0x82, 0xd1, 0xca, 0x19, 0xaf, + 0x4e, 0xae, 0x50, 0x71, 0x44, 0xbf, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x5d, 0x3c, 0xb3, + 0x52, 0x19, 0xa6, 0x9e, 0x4a, 0x44, 0x98, 0xbf, 0x51, 0x20, + 0x47, 0x0a, 0xf3, 0x26, 0x1a, 0xcc, 0x35, 0x2f, 0xc9, 0xed, + 0xe0, 0x9d, 0x46, 0xeb, 0xbc, 0x7e, 0xc9, 0xb9, 0x1d, 0x76, + 0xa4, 0x1d, 0xc2, 0xd9, 0x16, 0x29, 0x77, 0x01, 0x40, 0xdd, + 0xe5, 0xcb, 0x28, 0x91, 0x3a, 0x0c, 0x13, 0x01, 0x1b, 0x72, + 0x62, 0x45, 0x27, 0xfd, 0xd7, 0x00, 0x47, 0x36, 0x09, 0x1e, + 0x7b, 0xd2, 0xcb, 0x95, 0x3d, 0x28, 0x82, 0xce, 0x83, 0x59, + 0x32, 0xf9, 0xe6, 0xec, 0x89, 0xac, 0x88, 0x45, 0x22, 0x88, + 0x6f, 0x5e, 0xa2, 0x79, 0x95, 0xba, 0xb9, 0xc9, 0xb6, 0x4c, + 0x7c, 0xb4, 0x29, 0xa1, 0x02, 0xf5, 0xac, 0x5d, 0x8e, 0x52, + 0xeb, 0xe8, 0xb1, 0x56, 0x49, 0xb3, 0x77, 0x62, 0x7d, 0x87, + 0x4d, 0x17, 0xf2, 0x62, 0x83, 0x08, 0x59, 0x21, 0x60, 0x0d, + 0x84, 0x8e, 0x5a, 0x84, 0xf6 ), + FINGERPRINT ( 0x88, 0x70, 0xbf, 0xf0, 0xd6, 0x09, 0x03, 0x3a, + 0xe1, 0x80, 0xa7, 0xa5, 0x5c, 0x3e, 0xe1, 0x05, + 0x38, 0x97, 0xde, 0xe1, 0xe9, 0x74, 0x55, 0xb1, + 0x1e, 0x59, 0x69, 0x44, 0x42, 0x1b, 0xc8, 0xff ) ); + +/* + * subject iPXE self-test leaf CA + * issuer iPXE self-test intermediate CA + */ +CERTIFICATE ( leaf_crt, + DATA ( 0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, + 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x27, 0x30, + 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x69, 0x50, + 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, + 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31, + 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, + 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, + 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, + 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, + 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x55, + 0xad, 0xdf, 0x7b, 0xd1, 0x48, 0xc3, 0xd3, 0x02, 0x54, 0x6c, + 0x92, 0x45, 0x22, 0x3d, 0x90, 0xd8, 0xc7, 0x13, 0xcd, 0xc1, + 0x59, 0xc6, 0xe0, 0xad, 0x0e, 0xe6, 0xdb, 0x3b, 0xe8, 0x63, + 0xea, 0x4e, 0xb6, 0xea, 0x50, 0xea, 0x6e, 0x33, 0x9d, 0x28, + 0x25, 0x42, 0x49, 0xd0, 0xf0, 0xed, 0xc5, 0x5b, 0x6b, 0x4a, + 0xe7, 0x45, 0xfa, 0xd3, 0x3f, 0xae, 0xde, 0x5a, 0x90, 0xab, + 0xf1, 0x61, 0x2f, 0x40, 0x5e, 0xcf, 0x8b, 0x0b, 0x10, 0x59, + 0xa9, 0xd0, 0x1e, 0x0f, 0x18, 0x6b, 0x92, 0xd8, 0x9f, 0x58, + 0x10, 0x84, 0xb6, 0x15, 0xe8, 0x5b, 0xc4, 0xa0, 0x3e, 0x49, + 0x8b, 0xea, 0xdd, 0xa9, 0x7e, 0x32, 0x26, 0x9a, 0x68, 0x44, + 0xf0, 0x30, 0xca, 0x2a, 0xd6, 0x19, 0x7a, 0x80, 0xfd, 0xd7, + 0xfc, 0xc7, 0x5d, 0xe7, 0x61, 0xd2, 0x3f, 0x1f, 0x2c, 0x40, + 0x70, 0x7b, 0x34, 0xcb, 0x08, 0xa9, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x26, 0x30, 0x24, 0x30, 0x12, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, + 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, + 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, + 0x40, 0xd2, 0x70, 0x02, 0x08, 0x19, 0xa0, 0xb8, 0x8d, 0x9d, + 0x3d, 0x62, 0x41, 0x90, 0x2a, 0x36, 0x4a, 0x8b, 0x21, 0x42, + 0x9a, 0xb4, 0xc5, 0xf8, 0x79, 0x17, 0xd7, 0x64, 0x4d, 0xbf, + 0x8f, 0x6a, 0x04, 0x54, 0x7a, 0x0b, 0xd4, 0xb5, 0x0e, 0xab, + 0xf7, 0xb7, 0x06, 0x2b, 0xf8, 0xde, 0x87, 0xb2, 0x37, 0x3b, + 0x95, 0x01, 0xba, 0x9f, 0x8f, 0xec, 0x0a, 0x86, 0xca, 0x51, + 0xb6, 0x25, 0x73, 0x2f, 0xa1, 0x66, 0xc8, 0x7a, 0x5e, 0x51, + 0xbd, 0x49, 0xb5, 0x75, 0xda, 0xea, 0xe5, 0xeb, 0x5d, 0xe3, + 0xb0, 0xad, 0x49, 0x9f, 0x8b, 0xfd, 0x89, 0xb3, 0xb7, 0xb2, + 0x4c, 0x7d, 0x8a, 0x29, 0xb2, 0xbe, 0x04, 0xef, 0x9c, 0x73, + 0x3c, 0xea, 0xa3, 0x9f, 0x07, 0x66, 0x5a, 0x2f, 0x38, 0xad, + 0x1a, 0xeb, 0xe1, 0xb0, 0x62, 0x14, 0x55, 0xdc, 0x8c, 0x83, + 0xbb, 0xc7, 0x13, 0x04, 0x41, 0x54, 0xf1, 0x45 ), + FINGERPRINT ( 0xca, 0xcf, 0xea, 0x98, 0x3d, 0x71, 0xb6, 0x9d, + 0x4f, 0x5b, 0x84, 0x5e, 0xaa, 0x8e, 0xae, 0x63, + 0x0e, 0xad, 0x52, 0xe8, 0xc7, 0x51, 0x81, 0x07, + 0xd1, 0xa1, 0x66, 0xdb, 0xd5, 0x62, 0xe1, 0xe6 ) ); + +/* + * subject iPXE self-test useless CA + * issuer iPXE self-test leaf CA + */ +CERTIFICATE ( useless_crt, + DATA ( 0x30, 0x82, 0x02, 0xae, 0x30, 0x82, 0x02, 0x17, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, + 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, + 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x31, + 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x34, 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, + 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x69, + 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x75, 0x73, 0x65, 0x6c, 0x65, 0x73, + 0x73, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, + 0x81, 0x81, 0x00, 0xbe, 0x7f, 0x5a, 0x07, 0x7c, 0x61, 0xc2, + 0x3a, 0x7e, 0xe3, 0x94, 0xcb, 0xe9, 0xc3, 0x4c, 0x6f, 0x8d, + 0x5c, 0x4a, 0xf0, 0xc2, 0x13, 0x54, 0x09, 0x39, 0xa8, 0xf9, + 0xc2, 0xc3, 0xdd, 0xbe, 0x42, 0x99, 0xa6, 0xe1, 0x58, 0x0a, + 0xd5, 0x89, 0x12, 0xa6, 0xd6, 0x4e, 0xfb, 0x6c, 0xe5, 0xab, + 0xff, 0x40, 0x52, 0xcc, 0x1e, 0x63, 0x10, 0xd7, 0xfe, 0x49, + 0xf3, 0x86, 0x29, 0x58, 0x6a, 0x90, 0xe4, 0xe2, 0x56, 0x85, + 0x14, 0x7d, 0xa5, 0xf8, 0xe0, 0x7e, 0x96, 0x88, 0xd9, 0x23, + 0xe5, 0x44, 0x72, 0xa9, 0x5a, 0xbb, 0x76, 0x6b, 0x59, 0x3e, + 0x85, 0xd4, 0xe7, 0xb2, 0x31, 0x32, 0xea, 0x40, 0x1f, 0xce, + 0xfb, 0xb1, 0x91, 0xee, 0x86, 0x91, 0x3e, 0xa4, 0x86, 0xa4, + 0xe9, 0x74, 0xd7, 0x14, 0x8c, 0xb6, 0xb4, 0xc0, 0x08, 0xbb, + 0xc8, 0x38, 0xc3, 0x96, 0x3d, 0x85, 0xcf, 0xef, 0x94, 0x52, + 0x29, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, + 0x81, 0x00, 0x50, 0x59, 0xfb, 0x9d, 0x4d, 0xfe, 0x0e, 0x5b, + 0xc4, 0x51, 0xe9, 0xe8, 0xa4, 0xf5, 0x2f, 0x32, 0x8b, 0x06, + 0x78, 0xbe, 0xf1, 0x18, 0xc5, 0x6f, 0xd9, 0x20, 0xee, 0xb7, + 0x51, 0x40, 0xaf, 0xf3, 0x3c, 0xe4, 0x74, 0x00, 0xa4, 0x63, + 0x3b, 0x37, 0xe1, 0xef, 0x80, 0xdc, 0xd5, 0x90, 0xed, 0xba, + 0x91, 0x86, 0x7f, 0x97, 0x5d, 0x3e, 0x8f, 0x29, 0xcc, 0x57, + 0xee, 0x79, 0x15, 0x6b, 0xe3, 0xd1, 0x25, 0x14, 0x24, 0xdf, + 0xbf, 0x38, 0xee, 0xe3, 0x8a, 0x88, 0x19, 0x0f, 0xc8, 0x10, + 0xae, 0x27, 0x99, 0xa8, 0x35, 0x47, 0xc9, 0xfb, 0x92, 0x47, + 0xa2, 0x36, 0x2a, 0x8c, 0x26, 0x12, 0xb1, 0x0d, 0x46, 0xe2, + 0xdc, 0x33, 0x29, 0x0c, 0x32, 0xcf, 0x22, 0x49, 0xde, 0xc3, + 0x55, 0x2a, 0xba, 0xdd, 0xe3, 0x98, 0xc0, 0xe4, 0x9a, 0xa2, + 0xe5, 0x43, 0x04, 0x32, 0xd3, 0x50, 0x7d, 0x9c, 0x71, 0x23 ), + FINGERPRINT ( 0xda, 0xbf, 0xd3, 0x5e, 0x2e, 0x29, 0xa9, 0xfd, + 0x4d, 0x40, 0xba, 0xb8, 0xdd, 0x66, 0x93, 0x4c, + 0x10, 0xea, 0x5b, 0x07, 0xa6, 0xe2, 0x27, 0x63, + 0x2e, 0xfe, 0x01, 0x63, 0x7c, 0xea, 0xc6, 0xd0 ) ); + +/* + * subject boot.test.ipxe.org + * issuer iPXE self-test leaf CA + */ +CERTIFICATE ( server_crt, + DATA ( 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82, 0x01, 0xe6, 0x02, 0x01, + 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, + 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, 0x84, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, + 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x12, 0x62, 0x6f, 0x6f, 0x74, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, + 0x00, 0xbd, 0x43, 0x97, 0x45, 0xa2, 0xe0, 0x1d, 0x38, 0x41, + 0xb0, 0xd9, 0x91, 0xf9, 0x77, 0xa9, 0xcb, 0x9c, 0x9c, 0x93, + 0xfe, 0x5a, 0xee, 0xbc, 0xd9, 0x0f, 0x39, 0xf6, 0x42, 0xe4, + 0x55, 0x21, 0xbb, 0x11, 0xfd, 0xfd, 0xba, 0x25, 0x58, 0xc8, + 0xc6, 0xa5, 0x3b, 0x6f, 0x80, 0xba, 0x5b, 0xbc, 0x89, 0xca, + 0x7a, 0xdf, 0x6e, 0xb9, 0x81, 0xb6, 0x25, 0x67, 0x0a, 0x38, + 0x10, 0xf8, 0x26, 0x43, 0x0c, 0x51, 0x02, 0x14, 0xd6, 0xf2, + 0x9d, 0x7c, 0xf5, 0x25, 0x1c, 0x78, 0x4d, 0x47, 0xaf, 0x87, + 0x2e, 0x38, 0x49, 0x87, 0xb5, 0x8a, 0xf3, 0xb5, 0xd4, 0x15, + 0x69, 0x2a, 0x52, 0xc9, 0x46, 0x97, 0x34, 0x8e, 0x50, 0x4b, + 0xc4, 0xf2, 0xfb, 0x39, 0xfd, 0x16, 0x68, 0xdb, 0xa8, 0x17, + 0xe2, 0x71, 0x4b, 0xe0, 0xdf, 0x3d, 0xfc, 0xc3, 0x9b, 0x9d, + 0x22, 0xc9, 0xd3, 0xf6, 0x02, 0xa6, 0x60, 0xef, 0xf7, 0x02, + 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x7d, 0xff, 0x73, 0xf3, 0x68, 0xe3, 0x75, + 0xf1, 0xcf, 0xac, 0x2e, 0x23, 0x73, 0xea, 0xd1, 0x26, 0x33, + 0xbf, 0xf9, 0x56, 0xdf, 0xbf, 0x98, 0x20, 0x84, 0x08, 0x78, + 0x6b, 0xe6, 0x71, 0x7e, 0x22, 0x68, 0x4d, 0x6c, 0xbb, 0xd5, + 0xcc, 0xb4, 0x28, 0x33, 0x5e, 0xbe, 0x4d, 0x10, 0x16, 0x9f, + 0x65, 0x3b, 0x68, 0x90, 0xa7, 0xf7, 0x9d, 0x57, 0x71, 0x45, + 0x39, 0x86, 0x4c, 0xc0, 0x97, 0x34, 0x03, 0x9c, 0x2b, 0x25, + 0x05, 0xb1, 0x5c, 0x0c, 0x4e, 0xf2, 0x14, 0xbf, 0xcf, 0xf0, + 0x9a, 0x2d, 0xcf, 0x02, 0x47, 0x60, 0xd2, 0xe9, 0xed, 0xbf, + 0x71, 0x5d, 0x07, 0x09, 0x01, 0x87, 0xeb, 0xf7, 0xa8, 0x26, + 0x86, 0x24, 0x59, 0xf0, 0x31, 0x3b, 0x42, 0xd1, 0xf1, 0xfd, + 0x7c, 0x49, 0x5f, 0x1a, 0xf0, 0x41, 0x67, 0xf0, 0x16, 0x3a, + 0xfd, 0xb6, 0xb5, 0xf6, 0x2e, 0x0c, 0x18, 0x1f, 0x09, 0x8e, + 0x4d ), + FINGERPRINT ( 0xe0, 0xdb, 0x60, 0x53, 0x7c, 0xf6, 0x25, 0x8f, + 0xa7, 0xba, 0xdf, 0xe2, 0x1a, 0xfc, 0x27, 0x49, + 0xf6, 0x83, 0x15, 0xbd, 0x1b, 0x4c, 0x3f, 0x36, + 0x6f, 0x33, 0xf2, 0x47, 0x8e, 0x8b, 0x38, 0xa8 ) ); + +/* + * subject not.a.ca.test.ipxe.org + * issuer boot.test.ipxe.org + */ +CERTIFICATE ( not_ca_crt, + DATA ( 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82, 0x01, 0xe6, 0x02, 0x01, + 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x12, 0x62, 0x6f, 0x6f, 0x74, 0x2e, 0x74, 0x65, + 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, + 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, + 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, + 0x33, 0x34, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, + 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, + 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, + 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, + 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, + 0x6e, 0x6f, 0x74, 0x2e, 0x61, 0x2e, 0x63, 0x61, 0x2e, 0x74, + 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, + 0x00, 0xc3, 0x5b, 0x6d, 0xb3, 0x8d, 0x74, 0x9c, 0x1d, 0xbd, + 0x94, 0x41, 0xa2, 0x42, 0x96, 0x3c, 0x41, 0x82, 0xc0, 0xf1, + 0x95, 0xbf, 0xc5, 0x34, 0x92, 0x92, 0xa3, 0xed, 0xed, 0x5c, + 0x07, 0xaa, 0xb4, 0xc1, 0x66, 0xbb, 0xa6, 0xd1, 0xd9, 0x78, + 0x93, 0xf1, 0x9c, 0x3e, 0x13, 0x3a, 0xee, 0x74, 0x31, 0xeb, + 0x55, 0x86, 0xa5, 0x43, 0x8a, 0x5d, 0x0c, 0x2c, 0x0d, 0xfb, + 0x91, 0x9e, 0x31, 0x22, 0xbe, 0x96, 0xb5, 0x0e, 0x44, 0xc8, + 0x5b, 0x65, 0xb2, 0xf5, 0xec, 0x2a, 0x51, 0xed, 0x8f, 0x28, + 0xd8, 0xb2, 0x4b, 0x45, 0x39, 0x31, 0x1f, 0x11, 0xb7, 0x12, + 0xe3, 0xc6, 0xb2, 0xd2, 0x8d, 0x50, 0xd5, 0xf4, 0xd2, 0x71, + 0x77, 0xc9, 0x4c, 0x67, 0xee, 0xf7, 0xdc, 0xdb, 0x68, 0xa6, + 0xac, 0x33, 0xd4, 0xb2, 0x12, 0x61, 0x5c, 0xae, 0x4c, 0x2e, + 0x26, 0xe8, 0xdf, 0x46, 0x3a, 0x05, 0xaf, 0xeb, 0x0d, 0x02, + 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x90, 0x3e, 0x16, 0x27, 0x2f, 0x4e, 0x4b, + 0x31, 0x0e, 0xae, 0x31, 0x9d, 0x64, 0x88, 0x9f, 0xce, 0xd8, + 0x22, 0x51, 0x9d, 0xd9, 0x2b, 0xfe, 0xed, 0x75, 0xbe, 0xec, + 0x5a, 0x73, 0xaf, 0x6c, 0xa5, 0x5e, 0xd1, 0x15, 0x9a, 0x08, + 0xcf, 0x4d, 0x41, 0x78, 0x48, 0xb4, 0x29, 0xf1, 0xf7, 0x63, + 0x9b, 0x11, 0x91, 0x16, 0x94, 0x55, 0xff, 0xeb, 0xe9, 0x6f, + 0x0a, 0x34, 0x89, 0xed, 0xf2, 0xd1, 0x79, 0x91, 0x9d, 0xe5, + 0x73, 0x48, 0x68, 0x7f, 0x9b, 0xf4, 0x94, 0x80, 0x29, 0xbb, + 0x2f, 0xac, 0x6c, 0xf7, 0x6a, 0x43, 0xcc, 0x40, 0x34, 0x85, + 0xc8, 0xa1, 0x6d, 0x16, 0x36, 0x65, 0x3f, 0x93, 0x60, 0xc1, + 0x64, 0x33, 0x91, 0xa1, 0x8f, 0x86, 0x8c, 0xce, 0x14, 0x19, + 0x72, 0x28, 0xef, 0x94, 0x3d, 0x09, 0xb8, 0x3b, 0x39, 0xe8, + 0xd1, 0x66, 0x2b, 0x38, 0xb4, 0x46, 0x50, 0xf4, 0xcd, 0xc4, + 0x9a ), + FINGERPRINT ( 0x37, 0x6b, 0xc2, 0x20, 0xa9, 0xbc, 0xe2, 0x83, + 0x99, 0x60, 0x06, 0x2e, 0xaf, 0x94, 0xfe, 0xb0, + 0x1a, 0x2c, 0x17, 0x47, 0x1e, 0xc0, 0xd1, 0x66, + 0xb6, 0x76, 0xeb, 0x1c, 0x07, 0xae, 0x72, 0xf2 ) ); + +/* + * subject bad.path.len.test.ipxe.org + * issuer iPXE self-test useless CA + */ +CERTIFICATE ( bad_path_len_crt, + DATA ( 0x30, 0x82, 0x02, 0x88, 0x30, 0x82, 0x01, 0xf1, 0x02, 0x01, + 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x8b, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x19, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, 0x73, + 0x65, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, + 0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, + 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, + 0x30, 0x81, 0x8c, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x23, 0x30, 0x21, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x62, 0x61, 0x64, + 0x2e, 0x70, 0x61, 0x74, 0x68, 0x2e, 0x6c, 0x65, 0x6e, 0x2e, + 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, + 0x81, 0x00, 0xed, 0xf1, 0xe3, 0xb2, 0x61, 0x68, 0xa0, 0xd5, + 0x43, 0xfe, 0xad, 0xee, 0xfb, 0x8e, 0x2c, 0xf0, 0x44, 0xaf, + 0x0a, 0x3c, 0x87, 0xc2, 0x56, 0x9b, 0x66, 0x15, 0xc6, 0xbc, + 0x5b, 0x96, 0xef, 0xa1, 0x49, 0xd6, 0xe7, 0xeb, 0xb8, 0xf6, + 0x3d, 0x62, 0xf5, 0x51, 0xfd, 0xb1, 0xa5, 0x4e, 0x92, 0x7c, + 0x7a, 0x31, 0x1b, 0xb8, 0x21, 0x5c, 0xfe, 0x0b, 0x4e, 0x58, + 0xd6, 0xd0, 0x8b, 0x81, 0x00, 0x4a, 0xf8, 0xf7, 0x2a, 0xc9, + 0xea, 0xfa, 0x9c, 0xc9, 0x33, 0x0b, 0xc4, 0xce, 0x96, 0x4c, + 0x30, 0x6e, 0xf0, 0x07, 0xfa, 0x1b, 0x94, 0x1f, 0xe3, 0x3b, + 0xb2, 0x7d, 0x31, 0x1a, 0x37, 0x64, 0xe2, 0xc3, 0xf1, 0xe5, + 0xb9, 0xcc, 0xd1, 0x02, 0xae, 0x16, 0x39, 0x9b, 0xfc, 0x55, + 0xca, 0xdd, 0x33, 0x92, 0xe3, 0x12, 0x40, 0xc5, 0x32, 0x51, + 0x62, 0xac, 0x3a, 0xc0, 0x17, 0x36, 0xd0, 0x27, 0x3d, 0xbb, + 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x07, 0x53, 0x2a, 0x80, 0xd6, 0x25, + 0x10, 0x37, 0xce, 0x3b, 0x87, 0x87, 0xfc, 0xae, 0xe2, 0x2a, + 0x28, 0x3f, 0xf7, 0xa6, 0x32, 0x5b, 0x06, 0xbd, 0x4f, 0x34, + 0x6b, 0x47, 0x8a, 0x4b, 0x47, 0x51, 0xe8, 0x45, 0x69, 0xe3, + 0xf3, 0xdf, 0xa4, 0x25, 0x8f, 0x34, 0xbe, 0xe5, 0x2c, 0xa4, + 0x6c, 0x8c, 0x6e, 0x02, 0x74, 0x23, 0x43, 0x21, 0x4d, 0xe3, + 0x75, 0x93, 0x8e, 0xa8, 0x2c, 0x54, 0xba, 0x35, 0xe7, 0xab, + 0x44, 0xfa, 0x07, 0x7a, 0x18, 0xb4, 0xa7, 0xce, 0xfa, 0xa6, + 0x74, 0x5a, 0x45, 0x2c, 0x6f, 0x86, 0x34, 0x8f, 0x4a, 0x09, + 0xe0, 0xf3, 0x4f, 0x37, 0xbb, 0xa3, 0xa0, 0xcb, 0xad, 0x6b, + 0xc1, 0x16, 0x06, 0xdf, 0x83, 0x98, 0xaf, 0xa8, 0xc3, 0xa0, + 0x5f, 0x33, 0x09, 0x01, 0x12, 0xbd, 0xd3, 0x45, 0x9f, 0x5f, + 0x96, 0x93, 0xe9, 0x69, 0xe9, 0xb1, 0x8a, 0xe4, 0x94, 0xce, + 0xe4, 0x8d ), + FINGERPRINT ( 0xb6, 0x80, 0x84, 0xf1, 0x45, 0x55, 0x1f, 0xbc, + 0x15, 0xa6, 0xd8, 0x4b, 0xf3, 0x19, 0x65, 0xef, + 0x53, 0x5a, 0xc8, 0x99, 0xe5, 0xdf, 0x79, 0x07, + 0x00, 0x2c, 0x9f, 0x49, 0x91, 0x21, 0xeb, 0xfc ) ); + +/** Valid certificate chain up to boot.test.ipxe.org */ +CHAIN ( server_chain, &server_crt, &leaf_crt, &intermediate_crt, &root_crt ); + +/** Broken certificate chain up to boot.test.ipxe.org */ +CHAIN ( broken_server_chain, &server_crt, &leaf_crt, &root_crt ); + +/** Incomplete certificate chain up to boot.test.ipxe.org */ +CHAIN ( incomplete_server_chain, &server_crt, &leaf_crt, &intermediate_crt ); + +/** Non-functional certificate chain up to not_ca.test.ipxe.org */ +CHAIN ( not_ca_chain, + ¬_ca_crt, &server_crt, &leaf_crt, &intermediate_crt, &root_crt ); + +/** Valid certificate chain up to iPXE self-test useless CA */ +CHAIN ( useless_chain, &useless_crt, &leaf_crt, &intermediate_crt, &root_crt ); + +/** Non-functional certificate chain up to bad.path.len.test.ipxe.org */ +CHAIN ( bad_path_len_chain, &bad_path_len_crt, &useless_crt, &leaf_crt, + &intermediate_crt, &root_crt ); + +/** Certificate store containing the iPXE self-test root CA */ +static struct x509_root test_root = { + .digest = &x509_test_algorithm, + .count = 1, + .fingerprints = root_crt_fingerprint, +}; + +/** Certificate store containing the iPXE self-test intermediate CA */ +static struct x509_root intermediate_root = { + .digest = &x509_test_algorithm, + .count = 1, + .fingerprints = intermediate_crt_fingerprint, +}; + +/** Dummy fingerprint (not matching any certificates) */ +static uint8_t dummy_fingerprint[] = + FINGERPRINT ( 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff ); + +/** Certificate store containing a dummy fingerprint */ +static struct x509_root dummy_root = { + .digest = &x509_test_algorithm, + .count = 1, + .fingerprints = dummy_fingerprint, +}; + +/** Time at which all test certificates are valid */ +static time_t test_time = 1332374737ULL; /* Thu Mar 22 00:05:37 2012 */ + +/** Time at which end-entity test certificates are invalid */ +static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ + +/** Time at which CA test certificates are invalid */ +static time_t test_ca_expired = 2205014905ULL; /* Wed Nov 16 00:08:25 2039 */ + +/** An X.509 test certificate chain context */ +struct x509_test_chain_context { + /** Test certificate chain */ + struct x509_test_chain *chain; + /** Index within chain */ + unsigned int index; +}; + +/** + * Parse next certificate in chain + * + * @v cert X.509 certificate to parse + * @v ctx Chain context + * @ret rc Return status code + */ +static int x509_test_parse_next ( struct x509_certificate *cert, void *ctx ) { + struct x509_test_chain_context *context = ctx; + struct x509_test_certificate *test_cert; + + /* Return error at end of chain */ + if ( context->index >= context->chain->count ) + return -ENOENT; + + /* Get next test certificate */ + test_cert = context->chain->certs[ context->index++ ]; + + /* Parse certificate */ + return x509_parse ( cert, test_cert->data, test_cert->len ); +} + +/** + * Report certificate parsing test result + * + * @v cert Test certificate + */ +#define x509_parse_ok( cert ) do { \ + struct x509_certificate temp; \ + ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 ); \ + } while ( 0 ) + +/** + * Report certificate fingerprint test result + * + * @v cert Test certificate + */ +#define x509_fingerprint_ok( cert ) do { \ + struct x509_certificate temp; \ + uint8_t fingerprint[ x509_test_algorithm.digestsize ]; \ + ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 ); \ + x509_fingerprint ( &temp, &x509_test_algorithm, fingerprint ); \ + ok ( memcmp ( fingerprint, (cert)->fingerprint, \ + sizeof ( fingerprint ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report certificate issuer validation test result + * + * @v cert Test certificate + * @v issuer Test issuer + */ +#define x509_validate_issuer_ok( cert, issuer ) do { \ + struct x509_certificate cert_temp; \ + struct x509_certificate issuer_temp; \ + ok ( x509_parse ( &cert_temp, (cert)->data, \ + (cert)->len ) == 0 ); \ + ok ( x509_parse ( &issuer_temp, (issuer)->data, \ + (issuer)->len ) == 0 ); \ + ok ( x509_validate_issuer ( &cert_temp, &issuer_temp ) == 0 ); \ + } while ( 0 ) + +/** + * Report certificate issuer validation failure test result + * + * @v cert Test certificate + * @v issuer Test issuer + */ +#define x509_validate_issuer_fail_ok( cert, issuer ) do { \ + struct x509_certificate cert_temp; \ + struct x509_certificate issuer_temp; \ + ok ( x509_parse ( &cert_temp, (cert)->data, \ + (cert)->len ) == 0 ); \ + ok ( x509_parse ( &issuer_temp, (issuer)->data, \ + (issuer)->len ) == 0 ); \ + ok ( x509_validate_issuer ( &cert_temp, &issuer_temp ) != 0 ); \ + } while ( 0 ) + +/** + * Report certificate root validation test result + * + * @v cert Test certificate + * @v root Test root certificate store + */ +#define x509_validate_root_ok( cert, root ) do { \ + struct x509_certificate temp; \ + ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 ); \ + ok ( x509_validate_root ( &temp, root ) == 0 ); \ + } while ( 0 ) + +/** + * Report certificate root validation failure test result + * + * @v cert Test certificate + * @v root Test root certificate store + */ +#define x509_validate_root_fail_ok( cert, root ) do { \ + struct x509_certificate temp; \ + ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 ); \ + ok ( x509_validate_root ( &temp, root ) != 0 ); \ + } while ( 0 ) + +/** + * Report certificate time validation test result + * + * @v cert Test certificate + * @v time Test time + */ +#define x509_validate_time_ok( cert, time ) do { \ + struct x509_certificate temp; \ + ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 ); \ + ok ( x509_validate_time ( &temp, time ) == 0 ); \ + } while ( 0 ) + +/** + * Report certificate time validation failure test result + * + * @v cert Test certificate + * @v time Test time + */ +#define x509_validate_time_fail_ok( cert, time ) do { \ + struct x509_certificate temp; \ + ok ( x509_parse ( &temp, (cert)->data, (cert)->len ) == 0 ); \ + ok ( x509_validate_time ( &temp, time ) != 0 ); \ + } while ( 0 ) + +/** + * Report certificate chain validation test result + * + * @v chain Test certificate chain + * @v time Test certificate validation time + * @v root Test root certificate store + */ +#define x509_validate_chain_ok( chain, time, root ) do { \ + struct x509_test_chain_context context = { (chain), 0 }; \ + struct x509_certificate temp; \ + ok ( x509_validate_chain ( x509_test_parse_next, &context, \ + (time), (root), &temp ) == 0 ); \ + ok ( temp.raw.data == (chain)->certs[0]->data ); \ + ok ( temp.raw.len == (chain)->certs[0]->len ); \ + } while ( 0 ) + +/** + * Report certificate chain validation failure test result + * + * @v chain Test certificate chain + * @v time Test certificate validation time + * @v root Test root certificate store + */ +#define x509_validate_chain_fail_ok( chain, time, root ) do { \ + struct x509_test_chain_context context = { (chain), 0 }; \ + struct x509_certificate temp; \ + ok ( x509_validate_chain ( x509_test_parse_next, &context, \ + (time), (root), &temp ) != 0 ); \ + } while ( 0 ) + +/** + * Perform X.509 self-tests + * + */ +static void x509_test_exec ( void ) { + + /* Check all certificate fingerprints */ + x509_fingerprint_ok ( &root_crt ); + x509_fingerprint_ok ( &intermediate_crt ); + x509_fingerprint_ok ( &leaf_crt ); + x509_fingerprint_ok ( &useless_crt ); + x509_fingerprint_ok ( &server_crt ); + x509_fingerprint_ok ( ¬_ca_crt ); + x509_fingerprint_ok ( &bad_path_len_crt ); + + /* Check pairwise issuing */ + x509_validate_issuer_ok ( &intermediate_crt, &root_crt ); + x509_validate_issuer_ok ( &leaf_crt, &intermediate_crt ); + x509_validate_issuer_ok ( &useless_crt, &leaf_crt ); + x509_validate_issuer_ok ( &server_crt, &leaf_crt ); + x509_validate_issuer_fail_ok ( ¬_ca_crt, &server_crt ); + x509_validate_issuer_ok ( &bad_path_len_crt, &useless_crt ); + + /* Check root certificate stores */ + x509_validate_root_ok ( &root_crt, &test_root ); + x509_validate_root_fail_ok ( &intermediate_crt, &test_root ); + x509_validate_root_ok ( &intermediate_crt, &intermediate_root ); + x509_validate_root_fail_ok ( &root_crt, &intermediate_root ); + x509_validate_root_fail_ok ( &root_crt, &dummy_root ); + + /* Check certificate validity periods */ + x509_validate_time_ok ( &server_crt, test_time ); + x509_validate_time_fail_ok ( &server_crt, test_expired ); + x509_validate_time_ok ( &root_crt, test_time ); + x509_validate_time_ok ( &root_crt, test_expired ); + x509_validate_time_fail_ok ( &root_crt, test_ca_expired ); + + /* Check certificate chains */ + x509_validate_chain_ok ( &server_chain, test_time, &test_root ); + x509_validate_chain_ok ( &server_chain, test_time, &intermediate_root ); + x509_validate_chain_fail_ok ( &server_chain, test_time, &dummy_root ); + x509_validate_chain_fail_ok ( &broken_server_chain, test_time, + &test_root ); + x509_validate_chain_fail_ok ( &incomplete_server_chain, test_time, + &test_root ); + x509_validate_chain_ok ( &incomplete_server_chain, test_time, + &intermediate_root ); + x509_validate_chain_fail_ok ( ¬_ca_chain, test_time, &test_root ); + x509_validate_chain_ok ( &useless_chain, test_time, &test_root ); + x509_validate_chain_fail_ok ( &bad_path_len_chain, test_time, + &test_root ); + + /* Check certificate chain expiry times */ + x509_validate_chain_fail_ok ( &server_chain, test_expired, &test_root ); + x509_validate_chain_ok ( &useless_chain, test_expired, &test_root ); + x509_validate_chain_fail_ok ( &useless_chain, test_ca_expired, + &test_root ); +} + +/** X.509 self-test */ +struct self_test x509_test __self_test = { + .name = "x509", + .exec = x509_test_exec, +}; + +/* Drag in algorithms required for tests */ +REQUIRE_OBJECT ( rsa ); +REQUIRE_OBJECT ( sha1 ); +REQUIRE_OBJECT ( sha256 ); From 38b7e43f7d88a35b23b2d44a72d07d2ee589d31e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 13:57:32 +0000 Subject: [PATCH 108/221] [crypto] Generalise X.509 OID-identified algorithm to asn1.c The concept of an OID-identified algorithm as defined in X.509 is used in some other standards (e.g. PKCS#7). Generalise this functionality and provide it as part of the ASN.1 core. Signed-off-by: Michael Brown --- src/crypto/asn1.c | 54 ++++++++++++++++++ src/crypto/rsa.c | 47 +++++++++++++++ src/crypto/x509.c | 123 +++++++++------------------------------- src/include/ipxe/asn1.h | 23 ++++++++ src/include/ipxe/x509.h | 29 +--------- 5 files changed, 155 insertions(+), 121 deletions(-) diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index f075b66d..cd502502 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** @file @@ -341,3 +342,56 @@ int asn1_compare ( const struct asn1_cursor *cursor1, return ( difference ? difference : memcmp ( cursor1->data, cursor2->data, cursor1->len ) ); } + +/** + * Identify ASN.1 algorithm by OID + * + * @v cursor ASN.1 object cursor + + * @ret algorithm Algorithm, or NULL + */ +static struct asn1_algorithm * +asn1_find_algorithm ( const struct asn1_cursor *cursor ) { + struct asn1_algorithm *algorithm; + + for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) { + if ( asn1_compare ( &algorithm->oid, cursor ) == 0 ) + return algorithm; + } + + return NULL; +} + +/** + * Parse ASN.1 OID-identified algorithm + * + * @v cursor ASN.1 object cursor + * @ret algorithm Algorithm, or NULL + */ +struct asn1_algorithm * asn1_algorithm ( const struct asn1_cursor *cursor ) { + struct asn1_cursor contents; + struct asn1_algorithm *algorithm; + int rc; + + /* Enter signatureAlgorithm */ + memcpy ( &contents, cursor, sizeof ( contents ) ); + asn1_enter ( &contents, ASN1_SEQUENCE ); + + /* Enter algorithm */ + if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) { + DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n", + cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return NULL; + } + + /* Identify algorithm */ + algorithm = asn1_find_algorithm ( &contents ); + if ( ! algorithm ) { + DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor ); + DBGC_HDA ( cursor, 0, cursor->data, cursor->len ); + return NULL; + } + + return algorithm; +} diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 9b98b179..62f52c95 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -39,6 +39,53 @@ FILE_LICENCE ( GPL2_OR_LATER ); * RSA is documented in RFC 3447. */ +/** "rsaEncryption" object identifier */ +static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION }; + +/** "md5WithRSAEncryption" object identifier */ +static uint8_t oid_md5_with_rsa_encryption[] = + { ASN1_OID_MD5WITHRSAENCRYPTION }; + +/** "sha1WithRSAEncryption" object identifier */ +static uint8_t oid_sha1_with_rsa_encryption[] = + { ASN1_OID_SHA1WITHRSAENCRYPTION }; + +/** "sha256WithRSAEncryption" object identifier */ +static uint8_t oid_sha256_with_rsa_encryption[] = + { ASN1_OID_SHA256WITHRSAENCRYPTION }; + +/** "rsaEncryption" OID-identified algorithm */ +struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = { + .name = "rsaEncryption", + .pubkey = &rsa_algorithm, + .digest = NULL, + .oid = ASN1_OID_CURSOR ( oid_rsa_encryption ), +}; + +/** "md5WithRSAEncryption" OID-identified algorithm */ +struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = { + .name = "md5WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &md5_algorithm, + .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ), +}; + +/** "sha1WithRSAEncryption" OID-identified algorithm */ +struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = { + .name = "sha1WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &sha1_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ), +}; + +/** "sha256WithRSAEncryption" OID-identified algorithm */ +struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = { + .name = "sha256WithRSAEncryption", + .pubkey = &rsa_algorithm, + .digest = &sha256_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ), +}; + /** MD5 digestInfo prefix */ static const uint8_t rsa_md5_prefix_data[] = { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) }; diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 449d07e2..5ce42f88 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -49,10 +49,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_ENOTSUP_EXTENSION ) #define EINFO_ENOTSUP_EXTENSION \ __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported extension" ) -#define EINVAL_NON_SIGNATURE \ - __einfo_error ( EINFO_EINVAL_NON_SIGNATURE ) -#define EINFO_EINVAL_NON_SIGNATURE \ - __einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a signature algorithm" ) +#define EINVAL_ALGORITHM \ + __einfo_error ( EINFO_EINVAL_ALGORITHM ) +#define EINFO_EINVAL_ALGORITHM \ + __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid algorithm type" ) #define EINVAL_BIT_STRING \ __einfo_error ( EINFO_EINVAL_BIT_STRING ) #define EINFO_EINVAL_BIT_STRING \ @@ -101,70 +101,6 @@ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; static struct asn1_cursor oid_common_name_cursor = ASN1_OID_CURSOR ( oid_common_name ); -/** "rsaEncryption" object identifier */ -static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION }; - -/** "md5WithRSAEncryption" object identifier */ -static uint8_t oid_md5_with_rsa_encryption[] = - { ASN1_OID_MD5WITHRSAENCRYPTION }; - -/** "sha1WithRSAEncryption" object identifier */ -static uint8_t oid_sha1_with_rsa_encryption[] = - { ASN1_OID_SHA1WITHRSAENCRYPTION }; - -/** "sha256WithRSAEncryption" object identifier */ -static uint8_t oid_sha256_with_rsa_encryption[] = - { ASN1_OID_SHA256WITHRSAENCRYPTION }; - -/** Supported algorithms */ -static struct x509_algorithm x509_algorithms[] = { - { - .name = "rsaEncryption", - .pubkey = &rsa_algorithm, - .digest = NULL, - .oid = ASN1_OID_CURSOR ( oid_rsa_encryption ), - }, - { - .name = "md5WithRSAEncryption", - .pubkey = &rsa_algorithm, - .digest = &md5_algorithm, - .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ), - }, - { - .name = "sha1WithRSAEncryption", - .pubkey = &rsa_algorithm, - .digest = &sha1_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ), - }, - { - .name = "sha256WithRSAEncryption", - .pubkey = &rsa_algorithm, - .digest = &sha256_algorithm, - .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ), - }, -}; - -/** - * Identify X.509 algorithm by OID - * - * @v oid OID - * @ret algorithm Algorithm, or NULL - */ -static struct x509_algorithm * -x509_find_algorithm ( const struct asn1_cursor *oid ) { - struct x509_algorithm *algorithm; - unsigned int i; - - for ( i = 0 ; i < ( sizeof ( x509_algorithms ) / - sizeof ( x509_algorithms[0] ) ) ; i++ ) { - algorithm = &x509_algorithms[i]; - if ( asn1_compare ( &algorithm->oid, oid ) == 0 ) - return algorithm; - } - - return NULL; -} - /** * Parse X.509 certificate algorithm * @@ -173,29 +109,24 @@ x509_find_algorithm ( const struct asn1_cursor *oid ) { * @v raw ASN.1 cursor * @ret rc Return status code */ -static int x509_parse_algorithm ( struct x509_certificate *cert, - struct x509_algorithm **algorithm, +int x509_parse_pubkey_algorithm ( struct x509_certificate *cert, + struct asn1_algorithm **algorithm, const struct asn1_cursor *raw ) { - struct asn1_cursor cursor; - int rc; - /* Enter signatureAlgorithm */ - memcpy ( &cursor, raw, sizeof ( cursor ) ); - asn1_enter ( &cursor, ASN1_SEQUENCE ); - - /* Enter algorithm */ - if ( ( rc = asn1_enter ( &cursor, ASN1_OID ) ) != 0 ) { - DBGC ( cert, "X509 %p cannot locate algorithm:\n", cert ); + /* Parse algorithm */ + *algorithm = asn1_algorithm ( raw ); + if ( ! (*algorithm) ) { + DBGC ( cert, "X509 %p unrecognised algorithm:\n", cert ); DBGC_HDA ( cert, 0, raw->data, raw->len ); - return rc; + return -ENOTSUP_ALGORITHM; } - /* Identify algorithm */ - *algorithm = x509_find_algorithm ( &cursor ); - if ( ! *algorithm ) { - DBGC ( cert, "X509 %p unsupported algorithm:\n", cert ); - DBGC_HDA ( cert, 0, cursor.data, cursor.len ); - return -ENOTSUP_ALGORITHM; + /* Check algorithm has a public key */ + if ( ! (*algorithm)->pubkey ) { + DBGC ( cert, "X509 %p algorithm %s is not a public-key " + "algorithm:\n", cert, (*algorithm)->name ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return -EINVAL_ALGORITHM; } return 0; @@ -210,20 +141,21 @@ static int x509_parse_algorithm ( struct x509_certificate *cert, * @ret rc Return status code */ static int x509_parse_signature_algorithm ( struct x509_certificate *cert, - struct x509_algorithm **algorithm, + struct asn1_algorithm **algorithm, const struct asn1_cursor *raw ) { int rc; /* Parse algorithm */ - if ( ( rc = x509_parse_algorithm ( cert, algorithm, raw ) ) != 0 ) + if ( ( rc = x509_parse_pubkey_algorithm ( cert, algorithm, + raw ) ) != 0 ) return rc; /* Check algorithm is a signature algorithm */ - if ( ! x509_is_signature_algorithm ( *algorithm ) ) { + if ( ! (*algorithm)->digest ) { DBGC ( cert, "X509 %p algorithm %s is not a signature " "algorithm:\n", cert, (*algorithm)->name ); DBGC_HDA ( cert, 0, raw->data, raw->len ); - return -EINVAL_NON_SIGNATURE; + return -EINVAL_ALGORITHM; } return 0; @@ -600,7 +532,7 @@ static int x509_parse_subject ( struct x509_certificate *cert, static int x509_parse_public_key ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { struct x509_public_key *public_key = &cert->subject.public_key; - struct x509_algorithm **algorithm = &public_key->algorithm; + struct asn1_algorithm **algorithm = &public_key->algorithm; struct asn1_cursor cursor; int rc; @@ -613,7 +545,8 @@ static int x509_parse_public_key ( struct x509_certificate *cert, asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Parse algorithm */ - if ( ( rc = x509_parse_algorithm ( cert, algorithm, &cursor ) ) != 0 ) + if ( ( rc = x509_parse_pubkey_algorithm ( cert, algorithm, + &cursor ) ) != 0 ) return rc; DBGC ( cert, "X509 %p public key algorithm is %s\n", cert, (*algorithm)->name ); @@ -866,7 +799,7 @@ static int x509_parse_extensions ( struct x509_certificate *cert, */ static int x509_parse_tbscertificate ( struct x509_certificate *cert, const struct asn1_cursor *raw ) { - struct x509_algorithm **algorithm = &cert->signature_algorithm; + struct asn1_algorithm **algorithm = &cert->signature_algorithm; struct asn1_cursor cursor; int rc; @@ -933,7 +866,7 @@ static int x509_parse_tbscertificate ( struct x509_certificate *cert, */ int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ) { struct x509_signature *signature = &cert->signature; - struct x509_algorithm **signature_algorithm = &signature->algorithm; + struct asn1_algorithm **signature_algorithm = &signature->algorithm; struct x509_bit_string *signature_value = &signature->value; struct asn1_cursor cursor; int rc; @@ -991,7 +924,7 @@ int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ) { static int x509_check_signature ( struct x509_certificate *cert, struct x509_public_key *public_key ) { struct x509_signature *signature = &cert->signature; - struct x509_algorithm *algorithm = signature->algorithm; + struct asn1_algorithm *algorithm = signature->algorithm; struct digest_algorithm *digest = algorithm->digest; struct pubkey_algorithm *pubkey = algorithm->pubkey; uint8_t digest_ctx[ digest->ctxsize ]; diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index f912f5f5..553a8f3c 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -9,6 +9,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include +#include + /** An ASN.1 object cursor */ struct asn1_cursor { /** Start of data */ @@ -143,6 +146,24 @@ struct asn1_cursor { .len = sizeof ( oid_value ), \ } +/** An ASN.1 OID-identified algorithm */ +struct asn1_algorithm { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Public-key algorithm (if applicable) */ + struct pubkey_algorithm *pubkey; + /** Digest algorithm (if applicable) */ + struct digest_algorithm *digest; +}; + +/** ASN.1 OID-identified algorithms */ +#define ASN1_ALGORITHMS __table ( struct asn1_algorithm, "asn1_algorithms" ) + +/** Declare an ASN.1 OID-identified algorithm */ +#define __asn1_algorithm __table_entry ( ASN1_ALGORITHMS, 01 ) + /** An ASN.1 boolean */ struct asn1_boolean { /** Value */ @@ -181,5 +202,7 @@ extern int asn1_boolean ( const struct asn1_cursor *cursor ); extern int asn1_integer ( const struct asn1_cursor *cursor, int *value ); extern int asn1_compare ( const struct asn1_cursor *cursor1, const struct asn1_cursor *cursor2 ); +extern struct asn1_algorithm * +asn1_algorithm ( const struct asn1_cursor *cursor ); #endif /* _IPXE_ASN1_H */ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 89f90b84..45f738cd 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -14,29 +14,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include -/** An X.509 algorithm */ -struct x509_algorithm { - /** Name */ - const char *name; - /** Object identifier */ - struct asn1_cursor oid; - /** Public-key algorithm */ - struct pubkey_algorithm *pubkey; - /** Digest algorithm (if applicable) */ - struct digest_algorithm *digest; -}; - -/** - * Test if X.509 algorithm is a signature algorithm - * - * @v algorithm Algorithm - * @ret is_signature Algorithm is a signature algorithm - */ -static inline __attribute__ (( always_inline )) int -x509_is_signature_algorithm ( struct x509_algorithm *algorithm ) { - return ( algorithm->digest != NULL ); -} - /** An X.509 bit string */ struct x509_bit_string { /** Data */ @@ -80,7 +57,7 @@ struct x509_public_key { /** Raw public key */ struct asn1_cursor raw; /** Public key algorithm */ - struct x509_algorithm *algorithm; + struct asn1_algorithm *algorithm; }; /** An X.509 certificate subject */ @@ -96,7 +73,7 @@ struct x509_subject { /** An X.509 certificate signature */ struct x509_signature { /** Signature algorithm */ - struct x509_algorithm *algorithm; + struct asn1_algorithm *algorithm; /** Signature value */ struct x509_bit_string value; }; @@ -147,7 +124,7 @@ struct x509_certificate { /** Raw tbsCertificate */ struct asn1_cursor tbs; /** Signature algorithm */ - struct x509_algorithm *signature_algorithm; + struct asn1_algorithm *signature_algorithm; /** Issuer */ struct x509_issuer issuer; /** Validity */ From d56499ab1887f6b9e2ec8635c1f5a93af2bb6ea8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 14:18:06 +0000 Subject: [PATCH 109/221] [crypto] Define ASN.1 OID-identified algorithms for all supported digests Signed-off-by: Michael Brown --- src/crypto/md5.c | 11 +++++++++++ src/crypto/sha1.c | 11 +++++++++++ src/crypto/sha256.c | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/crypto/md5.c b/src/crypto/md5.c index 2d0d03d1..b8b7b43d 100644 --- a/src/crypto/md5.c +++ b/src/crypto/md5.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** MD5 variables */ @@ -284,3 +285,13 @@ struct digest_algorithm md5_algorithm = { .update = md5_update, .final = md5_final, }; + +/** "md5" object identifier */ +static uint8_t oid_md5[] = { ASN1_OID_MD5 }; + +/** "md5" OID-identified algorithm */ +struct asn1_algorithm oid_md5_algorithm __asn1_algorithm = { + .name = "md5", + .digest = &md5_algorithm, + .oid = ASN1_OID_CURSOR ( oid_md5 ), +}; diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c index fd271a63..7f287d3c 100644 --- a/src/crypto/sha1.c +++ b/src/crypto/sha1.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** SHA-1 variables */ @@ -258,3 +259,13 @@ struct digest_algorithm sha1_algorithm = { .update = sha1_update, .final = sha1_final, }; + +/** "sha1" object identifier */ +static uint8_t oid_sha1[] = { ASN1_OID_SHA1 }; + +/** "sha1" OID-identified algorithm */ +struct asn1_algorithm oid_sha1_algorithm __asn1_algorithm = { + .name = "sha1", + .digest = &sha1_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha1 ), +}; diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c index 6736a577..e85d2006 100644 --- a/src/crypto/sha256.c +++ b/src/crypto/sha256.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** SHA-256 variables */ @@ -242,3 +243,13 @@ struct digest_algorithm sha256_algorithm = { .update = sha256_update, .final = sha256_final, }; + +/** "sha256" object identifier */ +static uint8_t oid_sha256[] = { ASN1_OID_SHA256 }; + +/** "sha256" OID-identified algorithm */ +struct asn1_algorithm oid_sha256_algorithm __asn1_algorithm = { + .name = "sha256", + .digest = &sha256_algorithm, + .oid = ASN1_OID_CURSOR ( oid_sha256 ), +}; From c28537838858be19a0d9ee903fc3758ec73d756d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 17:14:05 +0000 Subject: [PATCH 110/221] [crypto] Parse X.509 certificate serial number Signed-off-by: Michael Brown --- src/crypto/x509.c | 31 +++++++++++++++++++++++++++++-- src/include/ipxe/x509.h | 8 ++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 5ce42f88..978fbd95 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -391,6 +391,31 @@ static int x509_parse_version ( struct x509_certificate *cert, return 0; } +/** + * Parse X.509 certificate serial number + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_serial ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_serial *serial = &cert->serial; + int rc; + + /* Record raw serial number */ + memcpy ( &serial->raw, raw, sizeof ( serial->raw ) ); + if ( ( rc = asn1_shrink ( &serial->raw, ASN1_INTEGER ) ) != 0 ) { + DBGC ( cert, "X509 %p cannot shrink serialNumber: %s\n", + cert, strerror ( rc ) ); + return rc; + } + DBGC ( cert, "X509 %p issuer is:\n", cert ); + DBGC_HDA ( cert, 0, serial->raw.data, serial->raw.len ); + + return 0; +} + /** * Parse X.509 certificate issuer * @@ -818,8 +843,10 @@ static int x509_parse_tbscertificate ( struct x509_certificate *cert, asn1_skip_any ( &cursor ); } - /* Skip serialNumber */ - asn1_skip ( &cursor, ASN1_INTEGER ); + /* Parse serialNumber */ + if ( ( rc = x509_parse_serial ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); /* Parse signature */ if ( ( rc = x509_parse_signature_algorithm ( cert, algorithm, diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 45f738cd..ca2912fd 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -24,6 +24,12 @@ struct x509_bit_string { unsigned int unused; }; +/** An X.509 serial number */ +struct x509_serial { + /** Raw serial number */ + struct asn1_cursor raw; +}; + /** An X.509 issuer */ struct x509_issuer { /** Raw issuer */ @@ -121,6 +127,8 @@ struct x509_certificate { struct asn1_cursor raw; /** Version */ unsigned int version; + /** Serial number */ + struct x509_serial serial; /** Raw tbsCertificate */ struct asn1_cursor tbs; /** Signature algorithm */ From 2d9d0adc4e7539c45a2a0f387bcf60a1f96ed79c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 16:48:08 +0000 Subject: [PATCH 111/221] [crypto] Add previous certificate in chain as a parameter to parse_next() Signed-off-by: Michael Brown --- src/crypto/x509.c | 10 ++++++---- src/include/ipxe/x509.h | 1 + src/net/tls.c | 5 ++++- src/tests/x509_test.c | 6 +++++- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 978fbd95..eb485522 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1143,8 +1143,10 @@ int x509_validate_time ( struct x509_certificate *cert, time_t time ) { * @v first Initial X.509 certificate to fill in, or NULL * @ret rc Return status code */ -int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, - void *context ), +int x509_validate_chain ( int ( * parse_next ) + ( struct x509_certificate *cert, + const struct x509_certificate *previous, + void *context ), void *context, time_t time, struct x509_root *root, struct x509_certificate *first ) { struct x509_certificate temp[2]; @@ -1159,7 +1161,7 @@ int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, root = &root_certificates; /* Get first certificate in chain */ - if ( ( rc = parse_next ( current, context ) ) != 0 ) { + if ( ( rc = parse_next ( current, NULL, context ) ) != 0 ) { DBGC ( context, "X509 chain %p could not get first " "certificate: %s\n", context, strerror ( rc ) ); return rc; @@ -1181,7 +1183,7 @@ int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, return 0; /* Get next certificate in chain */ - if ( ( rc = parse_next ( next, context ) ) != 0 ) { + if ( ( rc = parse_next ( next, current, context ) ) != 0 ) { DBGC ( context, "X509 chain %p could not get next " "certificate: %s\n", context, strerror ( rc ) ); return rc; diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index ca2912fd..427f7955 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -183,6 +183,7 @@ extern int x509_validate_root ( struct x509_certificate *cert, extern int x509_validate_time ( struct x509_certificate *cert, time_t time ); extern int x509_validate_chain ( int ( * parse_next ) ( struct x509_certificate *cert, + const struct x509_certificate *previous, void *context ), void *context, time_t time, struct x509_root *root, diff --git a/src/net/tls.c b/src/net/tls.c index 4b5891e4..6475f78d 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1281,10 +1281,13 @@ struct tls_certificate_context { * Parse next certificate in TLS certificate list * * @v cert X.509 certificate to fill in + * @v previous Previous X.509 certificate, or NULL * @v ctx Context * @ret rc Return status code */ -static int tls_parse_next ( struct x509_certificate *cert, void *ctx ) { +static int tls_parse_next ( struct x509_certificate *cert, + const struct x509_certificate *previous __unused, + void *ctx ) { struct tls_certificate_context *context = ctx; struct tls_session *tls = context->tls; const struct { diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index 6076d9aa..7803315e 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -695,10 +695,14 @@ struct x509_test_chain_context { * Parse next certificate in chain * * @v cert X.509 certificate to parse + * @v previous Previous X.509 certificate, or NULL * @v ctx Chain context * @ret rc Return status code */ -static int x509_test_parse_next ( struct x509_certificate *cert, void *ctx ) { +static int +x509_test_parse_next ( struct x509_certificate *cert, + const struct x509_certificate *previous __unused, + void *ctx ) { struct x509_test_chain_context *context = ctx; struct x509_test_certificate *test_cert; From 2cd24473b8e41b54f1dafc16c7b5adee8c224446 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Mar 2012 02:10:17 +0000 Subject: [PATCH 112/221] [crypto] Avoid an error when asn1_shrink() is already at end of object asn1_skip() will return an error on reaching the end of an object, and so should not be used as the basis for asn1_shrink(). Signed-off-by: Michael Brown --- src/crypto/asn1.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/crypto/asn1.c b/src/crypto/asn1.c index cd502502..2eab3422 100644 --- a/src/crypto/asn1.c +++ b/src/crypto/asn1.c @@ -220,16 +220,21 @@ int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) { * invalidated. */ int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) { - struct asn1_cursor next; - int rc; + struct asn1_cursor temp; + const void *end; + int len; - /* Skip to next object */ - memcpy ( &next, cursor, sizeof ( next ) ); - if ( ( rc = asn1_skip ( &next, type ) ) != 0 ) - return rc; + /* Find end of object */ + memcpy ( &temp, cursor, sizeof ( temp ) ); + len = asn1_start ( &temp, type ); + if ( len < 0 ) { + asn1_invalidate_cursor ( cursor ); + return len; + } + end = ( temp.data + len ); /* Shrink original cursor to contain only its first object */ - cursor->len = ( next.data - cursor->data ); + cursor->len = ( end - cursor->data ); return 0; } From 5c6639593969e6b7b6b4796cbb833c002819857c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Mar 2012 11:01:13 +0000 Subject: [PATCH 113/221] [crypto] Shrink raw certificate data to fit certificate The certificate may be part of an ASN.1-encoded certificate chain, and so may not be the only object contained within the ASN.1 cursor. Signed-off-by: Michael Brown --- src/crypto/x509.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index eb485522..145c77ee 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -902,6 +902,7 @@ int x509_parse ( struct x509_certificate *cert, const void *data, size_t len ) { memset ( cert, 0, sizeof ( *cert ) ); cert->raw.data = data; cert->raw.len = len; + asn1_shrink_any ( &cert->raw ); /* Enter certificate */ memcpy ( &cursor, &cert->raw, sizeof ( cursor ) ); From f2af64aba55fda84bd4c6dc6d3590049a637c03f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Mar 2012 10:55:13 +0000 Subject: [PATCH 114/221] [crypto] Differentiate "untrusted root" and "incomplete chain" error cases Signed-off-by: Michael Brown --- src/crypto/x509.c | 14 +++++++++++++- src/net/tls.c | 10 +++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 145c77ee..cf82fc03 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -93,6 +93,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EACCES_PATH_LEN ) #define EINFO_EACCES_PATH_LEN \ __einfo_uniqify ( EINFO_EACCES, 0x05, "Maximum path length exceeded" ) +#define EACCES_UNTRUSTED \ + __einfo_error ( EINFO_EACCES_UNTRUSTED ) +#define EINFO_EACCES_UNTRUSTED \ + __einfo_uniqify ( EINFO_EACCES, 0x06, "Untrusted root certificate" ) /** "commonName" object identifier */ static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME }; @@ -1179,10 +1183,18 @@ int x509_validate_chain ( int ( * parse_next ) if ( ( rc = x509_validate_time ( current, time ) ) != 0 ) return rc; - /* Succeed if we have reached a root certificate */ + /* Succeed if we have reached a trusted root certificate */ if ( x509_validate_root ( current, root ) == 0 ) return 0; + /* Fail if we have reached an untrusted root certificate */ + if ( asn1_compare ( ¤t->issuer.raw, + ¤t->subject.raw ) == 0 ) { + DBGC ( context, "X509 chain %p reached untrusted root " + "certificate\n", context ); + return -EACCES_UNTRUSTED; + } + /* Get next certificate in chain */ if ( ( rc = parse_next ( next, current, context ) ) != 0 ) { DBGC ( context, "X509 chain %p could not get next " diff --git a/src/net/tls.c b/src/net/tls.c index 6475f78d..ce39da9a 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -46,10 +46,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include /* Disambiguate the various error causes */ -#define EACCES_UNTRUSTED \ - __einfo_error ( EINFO_EACCES_UNTRUSTED ) -#define EINFO_EACCES_UNTRUSTED \ - __einfo_uniqify ( EINFO_EACCES, 0x01, "Untrusted certificate chain" ) +#define EACCES_INCOMPLETE \ + __einfo_error ( EINFO_EACCES_INCOMPLETE ) +#define EINFO_EACCES_INCOMPLETE \ + __einfo_uniqify ( EINFO_EACCES, 0x01, "Incomplete certificate chain" ) #define EACCES_WRONG_NAME \ __einfo_error ( EINFO_EACCES_WRONG_NAME ) #define EINFO_EACCES_WRONG_NAME \ @@ -1302,7 +1302,7 @@ static int tls_parse_next ( struct x509_certificate *cert, /* Return error at end of chain */ if ( context->current >= context->end ) { DBGC ( tls, "TLS %p reached end of certificate chain\n", tls ); - return -EACCES_UNTRUSTED; + return -EACCES_INCOMPLETE; } /* Extract current certificate and update context */ From fe6e741c62e11655018996b5d281eaeb1af796c1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 16:16:37 +0000 Subject: [PATCH 115/221] [crypto] Parse X.509 extended key usage extension Signed-off-by: Michael Brown --- src/crypto/x509.c | 85 +++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/asn1.h | 12 ++++++ src/include/ipxe/x509.h | 27 +++++++++++++ 3 files changed, 124 insertions(+) diff --git a/src/crypto/x509.c b/src/crypto/x509.c index cf82fc03..7c6aab5c 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -683,12 +683,92 @@ static int x509_parse_key_usage ( struct x509_certificate *cert, return 0; } +/** "id-kp-codeSigning" object identifier */ +static uint8_t oid_code_signing[] = { ASN1_OID_CODESIGNING }; + +/** Supported key purposes */ +static struct x509_key_purpose x509_key_purposes[] = { + { + .name = "codeSigning", + .bits = X509_CODE_SIGNING, + .oid = ASN1_OID_CURSOR ( oid_code_signing ), + }, +}; + +/** + * Parse X.509 certificate key purpose identifier + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_key_purpose ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct x509_extended_key_usage *ext_usage = &cert->extensions.ext_usage; + struct x509_key_purpose *purpose; + struct asn1_cursor cursor; + unsigned int i; + int rc; + + /* Enter keyPurposeId */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + if ( ( rc = asn1_enter ( &cursor, ASN1_OID ) ) != 0 ) { + DBGC ( cert, "X509 %p invalid keyPurposeId:\n", cert ); + DBGC_HDA ( cert, 0, raw->data, raw->len ); + return rc; + } + + /* Identify key purpose */ + for ( i = 0 ; i < ( sizeof ( x509_key_purposes ) / + sizeof ( x509_key_purposes[0] ) ) ; i++ ) { + purpose = &x509_key_purposes[i]; + if ( asn1_compare ( &cursor, &purpose->oid ) == 0 ) { + DBGC ( cert, "X509 %p has key purpose %s\n", + cert, purpose->name ); + ext_usage->bits |= purpose->bits; + return 0; + } + } + + /* Ignore unrecognised key purposes */ + return 0; +} + +/** + * Parse X.509 certificate extended key usage + * + * @v cert X.509 certificate + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int x509_parse_extended_key_usage ( struct x509_certificate *cert, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter extKeyUsage */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse each extension in turn */ + while ( cursor.len ) { + if ( ( rc = x509_parse_key_purpose ( cert, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + } + + return 0; +} + /** "id-ce-basicConstraints" object identifier */ static uint8_t oid_ce_basic_constraints[] = { ASN1_OID_BASICCONSTRAINTS }; /** "id-ce-keyUsage" object identifier */ static uint8_t oid_ce_key_usage[] = { ASN1_OID_KEYUSAGE }; +/** "id-ce-extKeyUsage" object identifier */ +static uint8_t oid_ce_ext_key_usage[] = { ASN1_OID_EXTKEYUSAGE }; + /** Supported certificate extensions */ static struct x509_extension x509_extensions[] = { { @@ -701,6 +781,11 @@ static struct x509_extension x509_extensions[] = { .oid = ASN1_OID_CURSOR ( oid_ce_key_usage ), .parse = x509_parse_key_usage, }, + { + .name = "extKeyUsage", + .oid = ASN1_OID_CURSOR ( oid_ce_ext_key_usage ), + .parse = x509_parse_extended_key_usage, + }, }; /** diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 553a8f3c..393d5dc3 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -140,6 +140,18 @@ struct asn1_cursor { ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ ASN1_OID_SINGLE ( 19 ) +/** ASN.1 OID for id-ce-extKeyUsage (2.5.29.37) */ +#define ASN1_OID_EXTKEYUSAGE \ + ASN1_OID_INITIAL ( 2, 5 ), ASN1_OID_SINGLE ( 29 ), \ + ASN1_OID_SINGLE ( 37 ) + +/** ASN.1 OID for id-kp-codeSigning (1.3.6.1.5.5.7.3.3) */ +#define ASN1_OID_CODESIGNING \ + ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 6 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 5 ), \ + ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \ + ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 3 ) + /** Define an ASN.1 cursor containing an OID */ #define ASN1_OID_CURSOR( oid_value ) { \ .data = oid_value, \ diff --git a/src/include/ipxe/x509.h b/src/include/ipxe/x509.h index 427f7955..09e18007 100644 --- a/src/include/ipxe/x509.h +++ b/src/include/ipxe/x509.h @@ -113,12 +113,29 @@ enum x509_key_usage_bits { X509_DECIPHER_ONLY = 0x8000, }; +/** An X.509 certificate extended key usage */ +struct x509_extended_key_usage { + /** Usage bits */ + unsigned int bits; +}; + +/** X.509 certificate extended key usage bits + * + * Extended key usages are identified by OID; these bits are purely an + * internal definition. + */ +enum x509_extended_key_usage_bits { + X509_CODE_SIGNING = 0x0001, +}; + /** An X.509 certificate extensions set */ struct x509_extensions { /** Basic constraints */ struct x509_basic_constraints basic; /** Key usage */ struct x509_key_usage usage; + /** Extended key usage */ + struct x509_extended_key_usage ext_usage; }; /** An X.509 certificate */ @@ -161,6 +178,16 @@ struct x509_extension { const struct asn1_cursor *raw ); }; +/** An X.509 key purpose */ +struct x509_key_purpose { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Extended key usage bits */ + unsigned int bits; +}; + /** An X.509 root certificate store */ struct x509_root { /** Fingerprint digest algorithm */ From bdb69d587e79219d7dca6f9aa21f8dd3f05adcac Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 20 Mar 2012 23:54:16 +0000 Subject: [PATCH 116/221] [crypto] Add support for Cryptographic Message Syntax (PKCS #7) The Cryptographic Message Syntax (PKCS#7) provides a format for encapsulating digital signatures of arbitrary binary blobs. A signature can be generated using openssl cms -sign -in -binary -noattr \ -signer .crt -inkey .key -certfile .crt \ -outform DER -out Signed-off-by: Michael Brown --- src/crypto/cms.c | 582 +++++++++++++++++++++++++++++++++++++ src/include/ipxe/asn1.h | 6 + src/include/ipxe/cms.h | 50 ++++ src/include/ipxe/errfile.h | 1 + 4 files changed, 639 insertions(+) create mode 100644 src/crypto/cms.c create mode 100644 src/include/ipxe/cms.h diff --git a/src/crypto/cms.c b/src/crypto/cms.c new file mode 100644 index 00000000..1e253afa --- /dev/null +++ b/src/crypto/cms.c @@ -0,0 +1,582 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Cryptographic Message Syntax (PKCS #7) + * + * The format of CMS messages is defined in RFC 5652. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Disambiguate the various error causes */ +#define EACCES_NON_SIGNING \ + __einfo_error ( EINFO_EACCES_NON_SIGNING ) +#define EINFO_EACCES_NON_SIGNING \ + __einfo_uniqify ( EINFO_EACCES, 0x01, "Not a signing certificate" ) +#define EACCES_NON_CODE_SIGNING \ + __einfo_error ( EINFO_EACCES_NON_CODE_SIGNING ) +#define EINFO_EACCES_NON_CODE_SIGNING \ + __einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" ) +#define EACCES_INCOMPLETE \ + __einfo_error ( EINFO_EACCES_INCOMPLETE ) +#define EINFO_EACCES_INCOMPLETE \ + __einfo_uniqify ( EINFO_EACCES, 0x03, "Incomplete certificate chain" ) +#define EACCES_WRONG_NAME \ + __einfo_error ( EINFO_EACCES_WRONG_NAME ) +#define EINFO_EACCES_WRONG_NAME \ + __einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" ) + +/** "pkcs7-signedData" object identifier */ +static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA }; + +/** "pkcs7-signedData" object identifier cursor */ +static struct asn1_cursor oid_signeddata_cursor = + ASN1_OID_CURSOR ( oid_signeddata ); + +/** + * Parse CMS signature content type + * + * @v sig CMS signature + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_content_type ( struct cms_signature *sig, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + + /* Enter contentType */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_OID ); + + /* Check OID is pkcs7-signedData */ + if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) { + DBGC ( sig, "CMS %p does not contain signedData:\n", sig ); + DBGC_HDA ( sig, 0, raw->data, raw->len ); + return -ENOTSUP; + } + + DBGC ( sig, "CMS %p contains signedData\n", sig ); + return 0; +} + +/** + * Parse CMS signature signer identifier + * + * @v sig CMS signature + * @v info Signer information to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_signer_identifier ( struct cms_signature *sig, + struct cms_signer_info *info, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter issuerAndSerialNumber */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Record issuer */ + memcpy ( &info->issuer, &cursor, sizeof ( info->issuer ) ); + if ( ( rc = asn1_shrink ( &info->issuer, ASN1_SEQUENCE ) ) != 0 ) { + DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n", + sig, info, strerror ( rc ) ); + DBGC_HDA ( sig, 0, raw->data, raw->len ); + return rc; + } + DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info ); + DBGC_HDA ( sig, 0, info->issuer.data, info->issuer.len ); + asn1_skip_any ( &cursor ); + + /* Record serialNumber */ + memcpy ( &info->serial, &cursor, sizeof ( info->serial ) ); + if ( ( rc = asn1_shrink ( &info->serial, ASN1_INTEGER ) ) != 0 ) { + DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n", + sig, info, strerror ( rc ) ); + DBGC_HDA ( sig, 0, raw->data, raw->len ); + return rc; + } + DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info ); + DBGC_HDA ( sig, 0, info->serial.data, info->serial.len ); + + return 0; +} + +/** + * Parse CMS signature digest algorithm + * + * @v sig CMS signature + * @v info Signer information to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_digest_algorithm ( struct cms_signature *sig, + struct cms_signer_info *info, + const struct asn1_cursor *raw ) { + struct asn1_algorithm *algorithm; + + /* Identify algorithm */ + algorithm = asn1_algorithm ( raw ); + if ( ! algorithm ) { + DBGC ( sig, "CMS %p/%p could not identify digest algorithm:\n", + sig, info ); + DBGC_HDA ( sig, 0, raw->data, raw->len ); + return -ENOTSUP; + } + + /* Check algorithm is a digest algorithm */ + if ( ! algorithm->digest ) { + DBGC ( sig, "CMS %p/%p algorithm %s is not a digest " + "algorithm\n", sig, info, algorithm->name ); + return -EINVAL; + } + + /* Record digest algorithm */ + info->digest = algorithm->digest; + DBGC ( sig, "CMS %p/%p digest algorithm is %s\n", + sig, info, algorithm->name ); + + return 0; +} + +/** + * Parse CMS signature algorithm + * + * @v sig CMS signature + * @v info Signer information to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_signature_algorithm ( struct cms_signature *sig, + struct cms_signer_info *info, + const struct asn1_cursor *raw ) { + struct asn1_algorithm *algorithm; + + /* Identify algorithm */ + algorithm = asn1_algorithm ( raw ); + if ( ! algorithm ) { + DBGC ( sig, "CMS %p/%p could not identify public-key " + "algorithm:\n", sig, info ); + DBGC_HDA ( sig, 0, raw->data, raw->len ); + return -ENOTSUP; + } + + /* Check algorithm is a signature algorithm */ + if ( ! algorithm->pubkey ) { + DBGC ( sig, "CMS %p/%p algorithm %s is not a public-key " + "algorithm\n", sig, info, algorithm->name ); + return -EINVAL; + } + + /* Record signature algorithm */ + info->pubkey = algorithm->pubkey; + DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n", + sig, info, algorithm->name ); + + return 0; +} + +/** + * Parse CMS signature value + * + * @v sig CMS signature + * @v info Signer information to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_signature_value ( struct cms_signature *sig, + struct cms_signer_info *info, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter signature */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) { + DBGC ( sig, "CMS %p/%p could not locate signature:\n", + sig, info ); + DBGC_HDA ( sig, 0, raw->data, raw->len ); + return rc; + } + + /* Record signature */ + info->signature = cursor.data; + info->signature_len = cursor.len; + DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info ); + DBGC_HDA ( sig, 0, info->signature, info->signature_len ); + + return 0; +} + +/** + * Parse CMS signature signer information + * + * @v sig CMS signature + * @v info Signer information to fill in + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_signer_info ( struct cms_signature *sig, + struct cms_signer_info *info, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Enter signerInfo */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Skip version */ + asn1_skip ( &cursor, ASN1_INTEGER ); + + /* Parse sid */ + if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse digestAlgorithm */ + if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Skip signedAttrs, if present */ + asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + + /* Parse signatureAlgorithm */ + if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0) + return rc; + asn1_skip_any ( &cursor ); + + /* Parse signature */ + if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Parse CMS signature from ASN.1 data + * + * @v sig CMS signature + * @v data Raw signature data + * @v len Length of raw data + * @ret rc Return status code + */ +int cms_parse ( struct cms_signature *sig, const void *data, size_t len ) { + struct asn1_cursor cursor; + int rc; + + /* Initialise signature */ + memset ( sig, 0, sizeof ( *sig ) ); + cursor.data = data; + cursor.len = len; + + /* Enter contentInfo */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Parse contentType */ + if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Enter content */ + asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + + /* Enter signedData */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Skip version */ + asn1_skip ( &cursor, ASN1_INTEGER ); + + /* Skip digestAlgorithms */ + asn1_skip ( &cursor, ASN1_SET ); + + /* Skip encapContentInfo */ + asn1_skip ( &cursor, ASN1_SEQUENCE ); + + /* Record certificates */ + memcpy ( &sig->certificates, &cursor, sizeof ( sig->certificates ) ); + if ( ( rc = asn1_enter ( &sig->certificates, + ASN1_EXPLICIT_TAG ( 0 ) ) ) != 0 ) { + DBGC ( sig, "CMS %p could not locate certificates:\n", sig ); + DBGC_HDA ( sig, 0, data, len ); + return rc; + } + asn1_skip_any ( &cursor ); + + /* Skip crls, if present */ + asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) ); + + /* Enter signerInfos */ + asn1_enter ( &cursor, ASN1_SET ); + + /* Parse first signerInfo */ + if ( ( rc = cms_parse_signer_info ( sig, &sig->info, &cursor ) ) != 0 ) + return rc; + + return 0; +} + +/** CMS certificate chain context */ +struct cms_chain_context { + /** Signature */ + struct cms_signature *sig; + /** Signer information */ + struct cms_signer_info *info; +}; + +/** + * Parse next certificate in chain + * + * @v cert X.509 certificate to parse + * @v previous Previous X.509 certificate, or NULL + * @v ctx Chain context + * @ret rc Return status code + */ +static int cms_parse_next ( struct x509_certificate *cert, + const struct x509_certificate *previous, + void *ctx ) { + struct cms_chain_context *context = ctx; + struct cms_signature *sig = context->sig; + struct cms_signer_info *info = context->info; + struct asn1_cursor cursor; + int rc; + + /* Search for relevant certificate */ + memcpy ( &cursor, &sig->certificates, sizeof ( cursor ) ); + while ( cursor.len ) { + + /* Parse certificate */ + if ( ( rc = x509_parse ( cert, cursor.data, + cursor.len ) ) != 0 ) { + DBGC ( sig, "CMS %p/%p could not parse certificate:\n", + sig, info ); + DBGC_HDA ( sig, 0, cursor.data, cursor.len ); + return rc; + } + + if ( previous == NULL ) { + /* First certificate: check issuer and serial + * number against signer info + */ + if ( ( asn1_compare ( &info->issuer, + &cert->issuer.raw ) == 0 ) && + ( asn1_compare ( &info->serial, + &cert->serial.raw ) == 0 ) ) { + return 0; + } + } else { + /* Subsequent certificates: check subject + * against previous certificate's issuer. + */ + if ( asn1_compare ( &previous->issuer.raw, + &cert->subject.raw ) == 0 ) { + return 0; + } + } + + /* Move to next certificate */ + asn1_skip_any ( &cursor ); + } + + DBGC ( sig, "CMS %p/%p reached end of certificate chain\n", sig, info ); + return -EACCES_INCOMPLETE; +} + +/** + * Calculate digest of CMS-signed data + * + * @v sig CMS signature + * @v info Signer information + * @v data Signed data + * @v len Length of signed data + * @v out Digest output + */ +static void cms_digest ( struct cms_signature *sig, + struct cms_signer_info *info, + userptr_t data, size_t len, void *out ) { + struct digest_algorithm *digest = info->digest; + uint8_t ctx[ digest->ctxsize ]; + uint8_t block[ digest->blocksize ]; + size_t offset = 0; + size_t frag_len; + + /* Initialise digest */ + digest_init ( digest, ctx ); + + /* Process data one block at a time */ + while ( len ) { + frag_len = len; + if ( frag_len > sizeof ( block ) ) + frag_len = sizeof ( block ); + copy_from_user ( block, data, offset, frag_len ); + digest_update ( digest, ctx, block, frag_len ); + offset += frag_len; + len -= frag_len; + } + + /* Finalise digest */ + digest_final ( digest, ctx, out ); + + DBGC ( sig, "CMS %p/%p digest value:\n", sig, info ); + DBGC_HDA ( sig, 0, out, digest->digestsize ); +} + +/** + * Verify digest of CMS-signed data + * + * @v sig CMS signature + * @v info Signer information + * @v cert Corresponding certificate + * @v data Signed data + * @v len Length of signed data + * @ret rc Return status code + */ +static int cms_verify_digest ( struct cms_signature *sig, + struct cms_signer_info *info, + struct x509_certificate *cert, + userptr_t data, size_t len ) { + struct digest_algorithm *digest = info->digest; + struct pubkey_algorithm *pubkey = info->pubkey; + struct x509_public_key *public_key = &cert->subject.public_key; + uint8_t digest_out[ digest->digestsize ]; + uint8_t ctx[ pubkey->ctxsize ]; + int rc; + + /* Generate digest */ + cms_digest ( sig, info, data, len, digest_out ); + + /* Initialise public-key algorithm */ + if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data, + public_key->raw.len ) ) != 0 ) { + DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n", + sig, info, strerror ( rc ) ); + goto err_init; + } + + /* Verify digest */ + if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out, + info->signature, + info->signature_len ) ) != 0 ) { + DBGC ( sig, "CMS %p/%p signature verification failed: %s\n", + sig, info, strerror ( rc ) ); + return rc; + } + + pubkey_final ( pubkey, ctx ); + err_init: + return rc; +} + +/** + * Verify CMS signature signer information + * + * @v sig CMS signature + * @v info Signer information + * @v data Signed data + * @v len Length of signed data + * @v name Required common name, or NULL to allow any name + * @v time Time at which to validate certificates + * @v root Root certificate store, or NULL to use default + * @ret rc Return status code + */ +static int cms_verify_signer_info ( struct cms_signature *sig, + struct cms_signer_info *info, + userptr_t data, size_t len, + const char *name, time_t time, + struct x509_root *root ) { + struct cms_chain_context context; + struct x509_certificate cert; + int rc; + + /* Validate certificate chain */ + context.sig = sig; + context.info = info; + if ( ( rc = x509_validate_chain ( cms_parse_next, &context, time, root, + &cert ) ) != 0 ) { + DBGC ( sig, "CMS %p/%p could not validate chain: %s\n", + sig, info, strerror ( rc ) ); + return rc; + } + + /* Check that certificate can create digital signatures */ + if ( ! ( cert.extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) { + DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n", + sig, info ); + return -EACCES_NON_SIGNING; + } + + /* Check that certificate can sign code */ + if ( ! ( cert.extensions.ext_usage.bits & X509_CODE_SIGNING ) ) { + DBGC ( sig, "CMS %p/%p certificate is not code-signing\n", + sig, info ); + return -EACCES_NON_CODE_SIGNING; + } + + /* Check certificate name, if applicable */ + if ( ( name != NULL ) && + ( ( cert.subject.name.len != strlen ( name ) ) || + ( memcmp ( cert.subject.name.data, name, + cert.subject.name.len ) != 0 ) ) ) { + DBGC ( sig, "CMS %p/%p certificate name incorrect\n", + sig, info ); + return -EACCES_WRONG_NAME; + } + + /* Verify digest */ + if ( ( rc = cms_verify_digest ( sig, info, &cert, data, len ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Verify CMS signature + * + * @v sig CMS signature + * @v data Signed data + * @v len Length of signed data + * @v name Required common name, or NULL to allow any name + * @v time Time at which to validate certificates + * @v root Root certificate store, or NULL to use default + * @ret rc Return status code + */ +int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, + const char *name, time_t time, struct x509_root *root ) { + int rc; + + /* Verify using first signerInfo */ + if ( ( rc = cms_verify_signer_info ( sig, &sig->info, data, len, + name, time, root ) ) != 0 ) + return rc; + + return 0; +} diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 393d5dc3..d83308a2 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -152,6 +152,12 @@ struct asn1_cursor { ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 3 ) +/** ASN.1 OID for pkcs-signedData (1.2.840.113549.1.7.2) */ +#define ASN1_OID_SIGNEDDATA \ + ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ + ASN1_OID_SINGLE ( 7 ), ASN1_OID_SINGLE ( 2 ) + /** Define an ASN.1 cursor containing an OID */ #define ASN1_OID_CURSOR( oid_value ) { \ .data = oid_value, \ diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h new file mode 100644 index 00000000..f355bf1c --- /dev/null +++ b/src/include/ipxe/cms.h @@ -0,0 +1,50 @@ +#ifndef _IPXE_CMS_H +#define _IPXE_CMS_H + +/** @file + * + * Cryptographic Message Syntax (PKCS #7) + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include + +/** CMS signer information */ +struct cms_signer_info { + /** Issuer name */ + struct asn1_cursor issuer; + /** Serial number */ + struct asn1_cursor serial; + /** Digest algorithm */ + struct digest_algorithm *digest; + /** Public-key algorithm */ + struct pubkey_algorithm *pubkey; + /** Signature */ + const void *signature; + /** Length of signature */ + size_t signature_len; +}; + +/** A CMS signature */ +struct cms_signature { + /** Raw certificate list */ + struct asn1_cursor certificates; + /** Signer information + * + * We currently use only the first signer information block. + */ + struct cms_signer_info info; +}; + +extern int cms_parse ( struct cms_signature *sig, const void *data, + size_t len ); +extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, + const char *name, time_t time, struct x509_root *root ); + +#endif /* _IPXE_CMS_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 4b568840..e0473a17 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -249,6 +249,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_rsa ( ERRFILE_OTHER | 0x00270000 ) #define ERRFILE_linux_entropy ( ERRFILE_OTHER | 0x00280000 ) #define ERRFILE_x509_test ( ERRFILE_OTHER | 0x00290000 ) +#define ERRFILE_cms ( ERRFILE_OTHER | 0x002a0000 ) /** @} */ From 7ace2ebe9491606f2ac68a3f91c1f1d49b6ef6b3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Mar 2012 17:31:53 +0000 Subject: [PATCH 117/221] [test] Add CMS self-tests Signed-off-by: Michael Brown --- src/tests/cms_test.c | 1430 ++++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 2 files changed, 1431 insertions(+) create mode 100644 src/tests/cms_test.c diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c new file mode 100644 index 00000000..51796513 --- /dev/null +++ b/src/tests/cms_test.c @@ -0,0 +1,1430 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * CMS self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include + +/** Fingerprint algorithm used for X.509 test certificates */ +#define cms_test_algorithm sha256_algorithm + +/** CMS test code blob */ +struct cms_test_code { + /** Data */ + const void *data; + /** Length of data */ + size_t len; +}; + +/** CMS test signature */ +struct cms_test_signature { + /** Data */ + const void *data; + /** Length of data */ + size_t len; +}; + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define inline fingerprint data */ +#define FINGERPRINT(...) { __VA_ARGS__ } + +/** Define a test code blob */ +#define SIGNED_CODE( name, DATA ) \ + static const uint8_t name ## _data[] = DATA; \ + static struct cms_test_code name = { \ + .data = name ## _data, \ + .len = sizeof ( name ## _data ), \ + } + +/** Define a test signature */ +#define SIGNATURE( name, DATA ) \ + static const uint8_t name ## _data[] = DATA; \ + static struct cms_test_signature name = { \ + .data = name ## _data, \ + .len = sizeof ( name ## _data ), \ + } + +/** Code that has been signed */ +SIGNED_CODE ( test_code, + DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, + 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, + 0x61, 0x6e, 0x64, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, + 0x64, 0x20, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x6f, 0x20, 0x61, + 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x79, 0x6f, + 0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73, 0x68, + 0x65, 0x6c, 0x6c, 0x0a ) ); + +/** Code that has not been signed */ +SIGNED_CODE ( bad_code, + DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, + 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x6d, 0x61, 0x6c, 0x69, 0x63, 0x69, 0x6f, + 0x75, 0x73, 0x20, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x6f, 0x20, + 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73, + 0x68, 0x65, 0x6c, 0x6c, 0x0a ) ); + +/** Valid signature */ +SIGNATURE ( codesigned_sig, + DATA ( 0x30, 0x82, 0x0c, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x32, 0x30, + 0x82, 0x0c, 0x2e, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, + 0xa0, 0x82, 0x0a, 0xd8, 0x30, 0x82, 0x02, 0xac, 0x30, 0x82, + 0x02, 0x15, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, + 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, + 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, + 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, + 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, + 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, + 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, + 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30, + 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, + 0x02, 0x81, 0x81, 0x00, 0xc3, 0x3a, 0xdb, 0x7b, 0x17, 0x24, + 0x47, 0xb9, 0xb9, 0x17, 0x02, 0x17, 0xa8, 0xce, 0x21, 0x97, + 0x92, 0x2f, 0x65, 0x53, 0x3b, 0x7e, 0x5c, 0x7d, 0x13, 0xab, + 0x46, 0xe8, 0x4a, 0x44, 0x6c, 0x5d, 0x8f, 0xa2, 0x0c, 0x1d, + 0x69, 0xc1, 0x66, 0x48, 0xc4, 0x1a, 0xc9, 0x32, 0xe5, 0x97, + 0x92, 0xb7, 0x11, 0xa7, 0x1f, 0x21, 0xac, 0x96, 0xcb, 0x85, + 0x10, 0xcc, 0x23, 0x20, 0x51, 0xdd, 0xaf, 0xbe, 0xf5, 0x23, + 0x12, 0x0b, 0x03, 0xe9, 0xf9, 0x61, 0x86, 0x64, 0x82, 0xa4, + 0xfd, 0x53, 0x24, 0xdf, 0xc2, 0x96, 0x2e, 0x28, 0xbb, 0x94, + 0xfb, 0x2c, 0xaf, 0x9e, 0x07, 0x79, 0x96, 0x48, 0x24, 0xf0, + 0x9d, 0xb3, 0x11, 0x3d, 0x4c, 0x2e, 0xd8, 0xc9, 0xf9, 0x69, + 0xca, 0xdb, 0x16, 0xbd, 0x4c, 0xc5, 0xce, 0x28, 0x18, 0xdc, + 0x88, 0x1b, 0x31, 0x0d, 0x10, 0x6b, 0x5b, 0x10, 0xe9, 0xcc, + 0xfe, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x24, 0x30, + 0x22, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, + 0x03, 0x02, 0x07, 0x80, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x22, 0x20, 0xe4, 0xc5, 0x0a, 0xef, + 0xae, 0xab, 0xbd, 0xab, 0x96, 0x56, 0x2c, 0x30, 0xeb, 0x06, + 0x84, 0xa0, 0x96, 0x37, 0x1a, 0x29, 0x2b, 0xeb, 0x8c, 0xb5, + 0x23, 0x22, 0x10, 0xef, 0x81, 0xe8, 0xdc, 0xa9, 0xdd, 0x8e, + 0x1d, 0x2c, 0xfc, 0xf5, 0x07, 0x19, 0xb7, 0x94, 0x91, 0xf7, + 0x2e, 0x07, 0xa1, 0xbc, 0xc5, 0x17, 0x34, 0xbe, 0x8a, 0x62, + 0x05, 0x5e, 0x9f, 0xe3, 0xce, 0xfd, 0x16, 0x42, 0xca, 0x25, + 0x2e, 0x0a, 0x03, 0x54, 0xd5, 0x3a, 0x52, 0x7f, 0x99, 0x94, + 0x96, 0xc6, 0xf5, 0xf0, 0xe3, 0x09, 0xd6, 0x00, 0x9b, 0x6f, + 0x0b, 0xa4, 0x9a, 0x13, 0x70, 0x9e, 0x67, 0xf9, 0x8c, 0x64, + 0xab, 0x22, 0x5d, 0xb3, 0xba, 0x2d, 0xe2, 0x70, 0xb8, 0x0c, + 0x6d, 0xd3, 0x12, 0x70, 0x5e, 0x04, 0x80, 0xef, 0x5e, 0x42, + 0x0a, 0x77, 0x57, 0x79, 0xa2, 0x1d, 0xe5, 0xbd, 0x20, 0xce, + 0x45, 0xc3, 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, + 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, + 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, + 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, + 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, + 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, + 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, + 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, + 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, + 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, + 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, + 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, + 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, + 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, + 0xc9, 0x3a, 0xee, 0xc6, 0x3c, 0xac, 0x4d, 0x81, 0xc6, 0x98, + 0x5e, 0xe1, 0x48, 0x66, 0x1a, 0x1e, 0x60, 0x19, 0x41, 0xae, + 0xca, 0x14, 0x97, 0xc8, 0x3a, 0x50, 0xb6, 0x48, 0xf5, 0x42, + 0xac, 0x0f, 0xe1, 0xe3, 0x47, 0xf0, 0xbf, 0x7c, 0xd0, 0xee, + 0x8f, 0xb7, 0xa6, 0x19, 0xad, 0xbb, 0xc5, 0x1b, 0x34, 0x38, + 0xc8, 0xbd, 0x55, 0x84, 0x93, 0x72, 0xaf, 0x84, 0xfc, 0x9b, + 0x97, 0x1d, 0xb5, 0x54, 0x24, 0xd6, 0x5d, 0xb7, 0x31, 0xf4, + 0xbd, 0x3b, 0x40, 0x97, 0xc0, 0xa9, 0x5a, 0x2a, 0xcb, 0x6b, + 0x98, 0x07, 0xdb, 0xb5, 0x9f, 0xe8, 0x31, 0x3f, 0x01, 0x46, + 0x46, 0x70, 0x05, 0xa2, 0x0f, 0x8c, 0x7a, 0x61, 0xf3, 0xdf, + 0xdb, 0xa1, 0x37, 0x2c, 0x88, 0x6a, 0x81, 0x21, 0x12, 0x4c, + 0xf5, 0xcd, 0xaf, 0xc9, 0xd2, 0x36, 0x3d, 0x82, 0xd1, 0xca, + 0x19, 0xaf, 0x4e, 0xae, 0x50, 0x71, 0x44, 0xbf, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, + 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x5d, + 0x3c, 0xb3, 0x52, 0x19, 0xa6, 0x9e, 0x4a, 0x44, 0x98, 0xbf, + 0x51, 0x20, 0x47, 0x0a, 0xf3, 0x26, 0x1a, 0xcc, 0x35, 0x2f, + 0xc9, 0xed, 0xe0, 0x9d, 0x46, 0xeb, 0xbc, 0x7e, 0xc9, 0xb9, + 0x1d, 0x76, 0xa4, 0x1d, 0xc2, 0xd9, 0x16, 0x29, 0x77, 0x01, + 0x40, 0xdd, 0xe5, 0xcb, 0x28, 0x91, 0x3a, 0x0c, 0x13, 0x01, + 0x1b, 0x72, 0x62, 0x45, 0x27, 0xfd, 0xd7, 0x00, 0x47, 0x36, + 0x09, 0x1e, 0x7b, 0xd2, 0xcb, 0x95, 0x3d, 0x28, 0x82, 0xce, + 0x83, 0x59, 0x32, 0xf9, 0xe6, 0xec, 0x89, 0xac, 0x88, 0x45, + 0x22, 0x88, 0x6f, 0x5e, 0xa2, 0x79, 0x95, 0xba, 0xb9, 0xc9, + 0xb6, 0x4c, 0x7c, 0xb4, 0x29, 0xa1, 0x02, 0xf5, 0xac, 0x5d, + 0x8e, 0x52, 0xeb, 0xe8, 0xb1, 0x56, 0x49, 0xb3, 0x77, 0x62, + 0x7d, 0x87, 0x4d, 0x17, 0xf2, 0x62, 0x83, 0x08, 0x59, 0x21, + 0x60, 0x0d, 0x84, 0x8e, 0x5a, 0x84, 0xf6, 0x30, 0x82, 0x02, + 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58, 0xd2, 0xdc, 0xc9, + 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30, 0x38, 0x30, 0x38, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, + 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, + 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, + 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72, 0xb5, 0xc1, 0x73, + 0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e, 0xeb, 0x1d, 0x9d, + 0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa, 0x75, 0x84, 0x66, + 0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd, 0x8f, 0x59, 0x64, + 0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3, 0x72, 0x93, 0xf2, + 0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47, 0x61, 0x50, 0xea, + 0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec, 0x2b, 0x75, 0xa6, + 0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97, 0xd5, 0xaf, 0x77, + 0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e, 0xda, 0xee, 0x72, + 0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b, 0x5d, 0x99, 0x4e, + 0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7, 0x6c, 0xe7, 0x5d, + 0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24, 0x16, 0x92, 0x66, + 0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9, 0x44, 0x24, 0x61, + 0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, + 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea, 0x17, 0x8d, 0x27, + 0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82, 0x36, 0xbd, 0xac, + 0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c, 0x05, 0x80, 0x6d, + 0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75, 0x29, 0xa1, 0xc6, + 0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1, 0xc8, 0x94, 0xa9, + 0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4, 0xdb, 0x63, 0x97, + 0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1, 0x3d, 0xed, 0xbb, + 0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04, 0xf8, 0x3c, 0x0e, + 0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6, 0xc0, 0x18, 0x53, + 0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77, 0xc9, 0x8e, 0x90, + 0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34, 0x6f, 0xc9, 0xe8, + 0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5, 0x63, 0x18, 0xc0, + 0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94, 0x10, 0xd4, 0x72, + 0xd2, 0xb8, 0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, 0x02, 0x1f, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x30, 0x81, 0x90, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, + 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, + 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, + 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, + 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1e, + 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x31, + 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, + 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, + 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, + 0xc3, 0x55, 0xad, 0xdf, 0x7b, 0xd1, 0x48, 0xc3, 0xd3, 0x02, + 0x54, 0x6c, 0x92, 0x45, 0x22, 0x3d, 0x90, 0xd8, 0xc7, 0x13, + 0xcd, 0xc1, 0x59, 0xc6, 0xe0, 0xad, 0x0e, 0xe6, 0xdb, 0x3b, + 0xe8, 0x63, 0xea, 0x4e, 0xb6, 0xea, 0x50, 0xea, 0x6e, 0x33, + 0x9d, 0x28, 0x25, 0x42, 0x49, 0xd0, 0xf0, 0xed, 0xc5, 0x5b, + 0x6b, 0x4a, 0xe7, 0x45, 0xfa, 0xd3, 0x3f, 0xae, 0xde, 0x5a, + 0x90, 0xab, 0xf1, 0x61, 0x2f, 0x40, 0x5e, 0xcf, 0x8b, 0x0b, + 0x10, 0x59, 0xa9, 0xd0, 0x1e, 0x0f, 0x18, 0x6b, 0x92, 0xd8, + 0x9f, 0x58, 0x10, 0x84, 0xb6, 0x15, 0xe8, 0x5b, 0xc4, 0xa0, + 0x3e, 0x49, 0x8b, 0xea, 0xdd, 0xa9, 0x7e, 0x32, 0x26, 0x9a, + 0x68, 0x44, 0xf0, 0x30, 0xca, 0x2a, 0xd6, 0x19, 0x7a, 0x80, + 0xfd, 0xd7, 0xfc, 0xc7, 0x5d, 0xe7, 0x61, 0xd2, 0x3f, 0x1f, + 0x2c, 0x40, 0x70, 0x7b, 0x34, 0xcb, 0x08, 0xa9, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x26, 0x30, 0x24, 0x30, 0x12, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, + 0x81, 0x00, 0x40, 0xd2, 0x70, 0x02, 0x08, 0x19, 0xa0, 0xb8, + 0x8d, 0x9d, 0x3d, 0x62, 0x41, 0x90, 0x2a, 0x36, 0x4a, 0x8b, + 0x21, 0x42, 0x9a, 0xb4, 0xc5, 0xf8, 0x79, 0x17, 0xd7, 0x64, + 0x4d, 0xbf, 0x8f, 0x6a, 0x04, 0x54, 0x7a, 0x0b, 0xd4, 0xb5, + 0x0e, 0xab, 0xf7, 0xb7, 0x06, 0x2b, 0xf8, 0xde, 0x87, 0xb2, + 0x37, 0x3b, 0x95, 0x01, 0xba, 0x9f, 0x8f, 0xec, 0x0a, 0x86, + 0xca, 0x51, 0xb6, 0x25, 0x73, 0x2f, 0xa1, 0x66, 0xc8, 0x7a, + 0x5e, 0x51, 0xbd, 0x49, 0xb5, 0x75, 0xda, 0xea, 0xe5, 0xeb, + 0x5d, 0xe3, 0xb0, 0xad, 0x49, 0x9f, 0x8b, 0xfd, 0x89, 0xb3, + 0xb7, 0xb2, 0x4c, 0x7d, 0x8a, 0x29, 0xb2, 0xbe, 0x04, 0xef, + 0x9c, 0x73, 0x3c, 0xea, 0xa3, 0x9f, 0x07, 0x66, 0x5a, 0x2f, + 0x38, 0xad, 0x1a, 0xeb, 0xe1, 0xb0, 0x62, 0x14, 0x55, 0xdc, + 0x8c, 0x83, 0xbb, 0xc7, 0x13, 0x04, 0x41, 0x54, 0xf1, 0x45, + 0x31, 0x82, 0x01, 0x33, 0x30, 0x82, 0x01, 0x2f, 0x02, 0x01, + 0x01, 0x30, 0x81, 0x8e, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, + 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, + 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, + 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, + 0x20, 0x43, 0x41, 0x02, 0x01, 0x04, 0x30, 0x07, 0x06, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x04, 0x81, 0x80, 0x1f, 0x95, 0x53, 0x9c, 0x63, 0xcc, 0x9e, + 0xe3, 0x41, 0x30, 0xaf, 0x66, 0xac, 0x7c, 0x39, 0x69, 0xa0, + 0x02, 0xe3, 0x28, 0xfa, 0xf6, 0x71, 0xf4, 0xcf, 0x97, 0x2a, + 0xbb, 0xe0, 0x1d, 0x71, 0x73, 0x4a, 0xa7, 0xea, 0xb0, 0x72, + 0xc3, 0xd2, 0xba, 0x52, 0x42, 0x06, 0x88, 0x4a, 0xa6, 0x41, + 0x1d, 0x2f, 0x82, 0xb3, 0x7d, 0x32, 0x59, 0x34, 0x4e, 0x47, + 0x1b, 0xaa, 0x5e, 0x90, 0xe2, 0x73, 0x62, 0x2d, 0x6f, 0x6c, + 0x47, 0x52, 0x05, 0x90, 0xcb, 0xac, 0x30, 0xa8, 0x20, 0x71, + 0x14, 0x39, 0x16, 0x85, 0x3d, 0x32, 0x2f, 0x9d, 0x31, 0x97, + 0xa8, 0x96, 0xb9, 0xf2, 0x2b, 0xdc, 0xa6, 0x2f, 0x68, 0xc7, + 0xac, 0x46, 0xa2, 0xc7, 0x26, 0xd0, 0xde, 0xac, 0x1d, 0x5d, + 0x70, 0x65, 0xc6, 0x26, 0xdd, 0x30, 0x3f, 0x3a, 0xbd, 0x5e, + 0x8f, 0x87, 0x64, 0xab, 0xe7, 0xf9, 0x71, 0x64, 0x03, 0x05, + 0xbf ) ); + +/** Signature with a broken certificate chain */ +SIGNATURE ( brokenchain_sig, + DATA ( 0x30, 0x82, 0x09, 0x8a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x7b, 0x30, + 0x82, 0x09, 0x77, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, + 0xa0, 0x82, 0x08, 0x21, 0x30, 0x82, 0x02, 0xac, 0x30, 0x82, + 0x02, 0x15, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, + 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, + 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, + 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, + 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, + 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, + 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, + 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30, + 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x63, 0x6f, 0x64, 0x65, 0x73, 0x69, 0x67, + 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, + 0x02, 0x81, 0x81, 0x00, 0xc3, 0x3a, 0xdb, 0x7b, 0x17, 0x24, + 0x47, 0xb9, 0xb9, 0x17, 0x02, 0x17, 0xa8, 0xce, 0x21, 0x97, + 0x92, 0x2f, 0x65, 0x53, 0x3b, 0x7e, 0x5c, 0x7d, 0x13, 0xab, + 0x46, 0xe8, 0x4a, 0x44, 0x6c, 0x5d, 0x8f, 0xa2, 0x0c, 0x1d, + 0x69, 0xc1, 0x66, 0x48, 0xc4, 0x1a, 0xc9, 0x32, 0xe5, 0x97, + 0x92, 0xb7, 0x11, 0xa7, 0x1f, 0x21, 0xac, 0x96, 0xcb, 0x85, + 0x10, 0xcc, 0x23, 0x20, 0x51, 0xdd, 0xaf, 0xbe, 0xf5, 0x23, + 0x12, 0x0b, 0x03, 0xe9, 0xf9, 0x61, 0x86, 0x64, 0x82, 0xa4, + 0xfd, 0x53, 0x24, 0xdf, 0xc2, 0x96, 0x2e, 0x28, 0xbb, 0x94, + 0xfb, 0x2c, 0xaf, 0x9e, 0x07, 0x79, 0x96, 0x48, 0x24, 0xf0, + 0x9d, 0xb3, 0x11, 0x3d, 0x4c, 0x2e, 0xd8, 0xc9, 0xf9, 0x69, + 0xca, 0xdb, 0x16, 0xbd, 0x4c, 0xc5, 0xce, 0x28, 0x18, 0xdc, + 0x88, 0x1b, 0x31, 0x0d, 0x10, 0x6b, 0x5b, 0x10, 0xe9, 0xcc, + 0xfe, 0xa1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x24, 0x30, + 0x22, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, + 0x03, 0x02, 0x07, 0x80, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, + 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, + 0x05, 0x05, 0x07, 0x03, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x22, 0x20, 0xe4, 0xc5, 0x0a, 0xef, + 0xae, 0xab, 0xbd, 0xab, 0x96, 0x56, 0x2c, 0x30, 0xeb, 0x06, + 0x84, 0xa0, 0x96, 0x37, 0x1a, 0x29, 0x2b, 0xeb, 0x8c, 0xb5, + 0x23, 0x22, 0x10, 0xef, 0x81, 0xe8, 0xdc, 0xa9, 0xdd, 0x8e, + 0x1d, 0x2c, 0xfc, 0xf5, 0x07, 0x19, 0xb7, 0x94, 0x91, 0xf7, + 0x2e, 0x07, 0xa1, 0xbc, 0xc5, 0x17, 0x34, 0xbe, 0x8a, 0x62, + 0x05, 0x5e, 0x9f, 0xe3, 0xce, 0xfd, 0x16, 0x42, 0xca, 0x25, + 0x2e, 0x0a, 0x03, 0x54, 0xd5, 0x3a, 0x52, 0x7f, 0x99, 0x94, + 0x96, 0xc6, 0xf5, 0xf0, 0xe3, 0x09, 0xd6, 0x00, 0x9b, 0x6f, + 0x0b, 0xa4, 0x9a, 0x13, 0x70, 0x9e, 0x67, 0xf9, 0x8c, 0x64, + 0xab, 0x22, 0x5d, 0xb3, 0xba, 0x2d, 0xe2, 0x70, 0xb8, 0x0c, + 0x6d, 0xd3, 0x12, 0x70, 0x5e, 0x04, 0x80, 0xef, 0x5e, 0x42, + 0x0a, 0x77, 0x57, 0x79, 0xa2, 0x1d, 0xe5, 0xbd, 0x20, 0xce, + 0x45, 0xc3, 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, + 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8, + 0x9c, 0x58, 0xd2, 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, + 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, + 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, + 0x39, 0x30, 0x38, 0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, + 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, + 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, + 0xaa, 0x72, 0xb5, 0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27, + 0xab, 0x5e, 0xeb, 0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05, + 0xc7, 0xfa, 0x75, 0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc, + 0x2d, 0xfd, 0x8f, 0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82, + 0x23, 0xc3, 0x72, 0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8, + 0xf1, 0x47, 0x61, 0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74, + 0x7a, 0xec, 0x2b, 0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23, + 0x48, 0x97, 0xd5, 0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38, + 0xb7, 0x9e, 0xda, 0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb, + 0xfd, 0x9b, 0x5d, 0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4, + 0x8d, 0xd7, 0x6c, 0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36, + 0x2c, 0x24, 0x16, 0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d, + 0x18, 0xb9, 0x44, 0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03, + 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, + 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94, + 0x9e, 0xea, 0x17, 0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19, + 0xbe, 0x82, 0x36, 0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71, + 0x30, 0x1c, 0x05, 0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c, + 0x77, 0x75, 0x29, 0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27, + 0xee, 0xb1, 0xc8, 0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d, + 0xbe, 0xf4, 0xdb, 0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a, + 0xa5, 0xd1, 0x3d, 0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15, + 0x0a, 0x04, 0xf8, 0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56, + 0x96, 0xf6, 0xc0, 0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72, + 0x77, 0x77, 0xc9, 0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a, + 0x4c, 0x34, 0x6f, 0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93, + 0xa9, 0xf5, 0x63, 0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36, + 0xc5, 0x94, 0x10, 0xd4, 0x72, 0xd2, 0xb8, 0x30, 0x82, 0x02, + 0xb6, 0x30, 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x01, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0x90, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, + 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, + 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, + 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, + 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x33, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, + 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, + 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, + 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x00, 0xc3, 0x55, 0xad, 0xdf, 0x7b, + 0xd1, 0x48, 0xc3, 0xd3, 0x02, 0x54, 0x6c, 0x92, 0x45, 0x22, + 0x3d, 0x90, 0xd8, 0xc7, 0x13, 0xcd, 0xc1, 0x59, 0xc6, 0xe0, + 0xad, 0x0e, 0xe6, 0xdb, 0x3b, 0xe8, 0x63, 0xea, 0x4e, 0xb6, + 0xea, 0x50, 0xea, 0x6e, 0x33, 0x9d, 0x28, 0x25, 0x42, 0x49, + 0xd0, 0xf0, 0xed, 0xc5, 0x5b, 0x6b, 0x4a, 0xe7, 0x45, 0xfa, + 0xd3, 0x3f, 0xae, 0xde, 0x5a, 0x90, 0xab, 0xf1, 0x61, 0x2f, + 0x40, 0x5e, 0xcf, 0x8b, 0x0b, 0x10, 0x59, 0xa9, 0xd0, 0x1e, + 0x0f, 0x18, 0x6b, 0x92, 0xd8, 0x9f, 0x58, 0x10, 0x84, 0xb6, + 0x15, 0xe8, 0x5b, 0xc4, 0xa0, 0x3e, 0x49, 0x8b, 0xea, 0xdd, + 0xa9, 0x7e, 0x32, 0x26, 0x9a, 0x68, 0x44, 0xf0, 0x30, 0xca, + 0x2a, 0xd6, 0x19, 0x7a, 0x80, 0xfd, 0xd7, 0xfc, 0xc7, 0x5d, + 0xe7, 0x61, 0xd2, 0x3f, 0x1f, 0x2c, 0x40, 0x70, 0x7b, 0x34, + 0xcb, 0x08, 0xa9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x26, + 0x30, 0x24, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, + 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, + 0x01, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x40, 0xd2, 0x70, + 0x02, 0x08, 0x19, 0xa0, 0xb8, 0x8d, 0x9d, 0x3d, 0x62, 0x41, + 0x90, 0x2a, 0x36, 0x4a, 0x8b, 0x21, 0x42, 0x9a, 0xb4, 0xc5, + 0xf8, 0x79, 0x17, 0xd7, 0x64, 0x4d, 0xbf, 0x8f, 0x6a, 0x04, + 0x54, 0x7a, 0x0b, 0xd4, 0xb5, 0x0e, 0xab, 0xf7, 0xb7, 0x06, + 0x2b, 0xf8, 0xde, 0x87, 0xb2, 0x37, 0x3b, 0x95, 0x01, 0xba, + 0x9f, 0x8f, 0xec, 0x0a, 0x86, 0xca, 0x51, 0xb6, 0x25, 0x73, + 0x2f, 0xa1, 0x66, 0xc8, 0x7a, 0x5e, 0x51, 0xbd, 0x49, 0xb5, + 0x75, 0xda, 0xea, 0xe5, 0xeb, 0x5d, 0xe3, 0xb0, 0xad, 0x49, + 0x9f, 0x8b, 0xfd, 0x89, 0xb3, 0xb7, 0xb2, 0x4c, 0x7d, 0x8a, + 0x29, 0xb2, 0xbe, 0x04, 0xef, 0x9c, 0x73, 0x3c, 0xea, 0xa3, + 0x9f, 0x07, 0x66, 0x5a, 0x2f, 0x38, 0xad, 0x1a, 0xeb, 0xe1, + 0xb0, 0x62, 0x14, 0x55, 0xdc, 0x8c, 0x83, 0xbb, 0xc7, 0x13, + 0x04, 0x41, 0x54, 0xf1, 0x45, 0x31, 0x82, 0x01, 0x33, 0x30, + 0x82, 0x01, 0x2f, 0x02, 0x01, 0x01, 0x30, 0x81, 0x8e, 0x30, + 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, + 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, + 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x02, 0x01, + 0x04, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x81, 0x80, 0x1f, 0x95, + 0x53, 0x9c, 0x63, 0xcc, 0x9e, 0xe3, 0x41, 0x30, 0xaf, 0x66, + 0xac, 0x7c, 0x39, 0x69, 0xa0, 0x02, 0xe3, 0x28, 0xfa, 0xf6, + 0x71, 0xf4, 0xcf, 0x97, 0x2a, 0xbb, 0xe0, 0x1d, 0x71, 0x73, + 0x4a, 0xa7, 0xea, 0xb0, 0x72, 0xc3, 0xd2, 0xba, 0x52, 0x42, + 0x06, 0x88, 0x4a, 0xa6, 0x41, 0x1d, 0x2f, 0x82, 0xb3, 0x7d, + 0x32, 0x59, 0x34, 0x4e, 0x47, 0x1b, 0xaa, 0x5e, 0x90, 0xe2, + 0x73, 0x62, 0x2d, 0x6f, 0x6c, 0x47, 0x52, 0x05, 0x90, 0xcb, + 0xac, 0x30, 0xa8, 0x20, 0x71, 0x14, 0x39, 0x16, 0x85, 0x3d, + 0x32, 0x2f, 0x9d, 0x31, 0x97, 0xa8, 0x96, 0xb9, 0xf2, 0x2b, + 0xdc, 0xa6, 0x2f, 0x68, 0xc7, 0xac, 0x46, 0xa2, 0xc7, 0x26, + 0xd0, 0xde, 0xac, 0x1d, 0x5d, 0x70, 0x65, 0xc6, 0x26, 0xdd, + 0x30, 0x3f, 0x3a, 0xbd, 0x5e, 0x8f, 0x87, 0x64, 0xab, 0xe7, + 0xf9, 0x71, 0x64, 0x03, 0x05, 0xbf ) ); + +/** Signature generated with a non-code-signing certificate */ +SIGNATURE ( genericsigned_sig, + DATA ( 0x30, 0x82, 0x0c, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x20, 0x30, + 0x82, 0x0c, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, + 0xa0, 0x82, 0x0a, 0xc6, 0x30, 0x82, 0x02, 0x9a, 0x30, 0x82, + 0x02, 0x03, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x05, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, + 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, + 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, + 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, + 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, + 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, + 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x35, + 0x5a, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x33, 0x32, 0x32, 0x30, + 0x30, 0x30, 0x31, 0x33, 0x35, 0x5a, 0x30, 0x81, 0x8b, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x19, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, + 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, + 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, + 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xc6, 0xfc, 0x96, + 0x1e, 0x90, 0x32, 0xed, 0xb8, 0x54, 0xb2, 0xc2, 0x39, 0x66, + 0x19, 0xca, 0xd8, 0x45, 0x21, 0xb7, 0x5a, 0x8d, 0x8d, 0x71, + 0xef, 0x69, 0x37, 0x40, 0xbb, 0xa4, 0xde, 0x09, 0x1b, 0x17, + 0x83, 0x3a, 0x7a, 0xf1, 0x7b, 0x02, 0x31, 0x5d, 0x1f, 0x3a, + 0xe5, 0x29, 0x28, 0x9b, 0x7e, 0x7b, 0x5a, 0xc4, 0x18, 0x3e, + 0x43, 0xe6, 0xe9, 0x6e, 0xd1, 0x8d, 0x86, 0xcf, 0xb5, 0x9f, + 0x7f, 0x50, 0x4e, 0x06, 0x13, 0xf7, 0xb2, 0xee, 0xef, 0x0e, + 0xab, 0x50, 0x44, 0x42, 0xfd, 0x3a, 0xa9, 0x47, 0x83, 0x34, + 0x17, 0xdf, 0xee, 0x3d, 0x84, 0x1f, 0xed, 0x7e, 0xfa, 0x0f, + 0xa8, 0xfc, 0x07, 0xf8, 0xd1, 0x49, 0x99, 0x1a, 0xad, 0x39, + 0x16, 0xb3, 0x71, 0x15, 0x2e, 0x82, 0x20, 0x7a, 0x92, 0xed, + 0x1e, 0x37, 0xf6, 0x46, 0x5e, 0x7d, 0x9b, 0xa1, 0x53, 0x4d, + 0x13, 0x91, 0xcd, 0x7a, 0x77, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x0f, 0x30, 0x0d, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, + 0x0f, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xb2, 0x39, 0x0b, 0x02, + 0x33, 0xca, 0x48, 0x96, 0x13, 0x53, 0xe9, 0x1b, 0x28, 0xd6, + 0x35, 0x4e, 0x0c, 0x9d, 0xd0, 0xe3, 0x79, 0x65, 0x0a, 0xe7, + 0xa6, 0x22, 0x61, 0x26, 0xbe, 0xb4, 0x05, 0xec, 0x5f, 0x83, + 0xb7, 0x0e, 0xa4, 0xae, 0x50, 0xb1, 0xa9, 0x45, 0x25, 0xf2, + 0x52, 0x1a, 0x63, 0x05, 0x50, 0x75, 0x33, 0xca, 0x8a, 0xb1, + 0xf2, 0x19, 0xd3, 0x93, 0x84, 0x67, 0x42, 0xe3, 0xb7, 0xa6, + 0xf9, 0x4d, 0x90, 0x7e, 0x13, 0x40, 0xd3, 0x22, 0x9f, 0x83, + 0xaf, 0x70, 0xb2, 0x7d, 0x4d, 0xcc, 0xae, 0x18, 0x9e, 0xca, + 0xc8, 0xcb, 0x82, 0x93, 0xcb, 0xce, 0xc6, 0x32, 0xcf, 0x4e, + 0x04, 0x64, 0x18, 0x5b, 0xc2, 0x1a, 0xb6, 0xd1, 0x8a, 0xc4, + 0x99, 0xce, 0xdd, 0xd7, 0x7e, 0xec, 0xf5, 0xa9, 0xa7, 0x00, + 0xc2, 0xd3, 0x6a, 0xb9, 0xcd, 0x25, 0x88, 0x08, 0x71, 0xf5, + 0x6d, 0x44, 0xe7, 0x93, 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, + 0x02, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, + 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, + 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, + 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, + 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, + 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, + 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, + 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, + 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x90, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, + 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, + 0x81, 0x00, 0xc9, 0x3a, 0xee, 0xc6, 0x3c, 0xac, 0x4d, 0x81, + 0xc6, 0x98, 0x5e, 0xe1, 0x48, 0x66, 0x1a, 0x1e, 0x60, 0x19, + 0x41, 0xae, 0xca, 0x14, 0x97, 0xc8, 0x3a, 0x50, 0xb6, 0x48, + 0xf5, 0x42, 0xac, 0x0f, 0xe1, 0xe3, 0x47, 0xf0, 0xbf, 0x7c, + 0xd0, 0xee, 0x8f, 0xb7, 0xa6, 0x19, 0xad, 0xbb, 0xc5, 0x1b, + 0x34, 0x38, 0xc8, 0xbd, 0x55, 0x84, 0x93, 0x72, 0xaf, 0x84, + 0xfc, 0x9b, 0x97, 0x1d, 0xb5, 0x54, 0x24, 0xd6, 0x5d, 0xb7, + 0x31, 0xf4, 0xbd, 0x3b, 0x40, 0x97, 0xc0, 0xa9, 0x5a, 0x2a, + 0xcb, 0x6b, 0x98, 0x07, 0xdb, 0xb5, 0x9f, 0xe8, 0x31, 0x3f, + 0x01, 0x46, 0x46, 0x70, 0x05, 0xa2, 0x0f, 0x8c, 0x7a, 0x61, + 0xf3, 0xdf, 0xdb, 0xa1, 0x37, 0x2c, 0x88, 0x6a, 0x81, 0x21, + 0x12, 0x4c, 0xf5, 0xcd, 0xaf, 0xc9, 0xd2, 0x36, 0x3d, 0x82, + 0xd1, 0xca, 0x19, 0xaf, 0x4e, 0xae, 0x50, 0x71, 0x44, 0xbf, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, + 0x00, 0x5d, 0x3c, 0xb3, 0x52, 0x19, 0xa6, 0x9e, 0x4a, 0x44, + 0x98, 0xbf, 0x51, 0x20, 0x47, 0x0a, 0xf3, 0x26, 0x1a, 0xcc, + 0x35, 0x2f, 0xc9, 0xed, 0xe0, 0x9d, 0x46, 0xeb, 0xbc, 0x7e, + 0xc9, 0xb9, 0x1d, 0x76, 0xa4, 0x1d, 0xc2, 0xd9, 0x16, 0x29, + 0x77, 0x01, 0x40, 0xdd, 0xe5, 0xcb, 0x28, 0x91, 0x3a, 0x0c, + 0x13, 0x01, 0x1b, 0x72, 0x62, 0x45, 0x27, 0xfd, 0xd7, 0x00, + 0x47, 0x36, 0x09, 0x1e, 0x7b, 0xd2, 0xcb, 0x95, 0x3d, 0x28, + 0x82, 0xce, 0x83, 0x59, 0x32, 0xf9, 0xe6, 0xec, 0x89, 0xac, + 0x88, 0x45, 0x22, 0x88, 0x6f, 0x5e, 0xa2, 0x79, 0x95, 0xba, + 0xb9, 0xc9, 0xb6, 0x4c, 0x7c, 0xb4, 0x29, 0xa1, 0x02, 0xf5, + 0xac, 0x5d, 0x8e, 0x52, 0xeb, 0xe8, 0xb1, 0x56, 0x49, 0xb3, + 0x77, 0x62, 0x7d, 0x87, 0x4d, 0x17, 0xf2, 0x62, 0x83, 0x08, + 0x59, 0x21, 0x60, 0x0d, 0x84, 0x8e, 0x5a, 0x84, 0xf6, 0x30, + 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58, 0xd2, + 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, + 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, + 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, + 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, + 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, + 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, + 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30, 0x38, + 0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, + 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, + 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, + 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x81, + 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, + 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72, 0xb5, + 0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e, 0xeb, + 0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa, 0x75, + 0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd, 0x8f, + 0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3, 0x72, + 0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47, 0x61, + 0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec, 0x2b, + 0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97, 0xd5, + 0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e, 0xda, + 0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b, 0x5d, + 0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7, 0x6c, + 0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24, 0x16, + 0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9, 0x44, + 0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00, 0x01, + 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, + 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, + 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, + 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea, 0x17, + 0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82, 0x36, + 0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c, 0x05, + 0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75, 0x29, + 0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1, 0xc8, + 0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4, 0xdb, + 0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1, 0x3d, + 0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04, 0xf8, + 0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6, 0xc0, + 0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77, 0xc9, + 0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34, 0x6f, + 0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5, 0x63, + 0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94, 0x10, + 0xd4, 0x72, 0xd2, 0xb8, 0x30, 0x82, 0x02, 0xb6, 0x30, 0x82, + 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x90, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, + 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, + 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, + 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, + 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, + 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, + 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, + 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, 0x30, + 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, + 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, + 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, + 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, + 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, + 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, + 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, + 0x81, 0x00, 0xc3, 0x55, 0xad, 0xdf, 0x7b, 0xd1, 0x48, 0xc3, + 0xd3, 0x02, 0x54, 0x6c, 0x92, 0x45, 0x22, 0x3d, 0x90, 0xd8, + 0xc7, 0x13, 0xcd, 0xc1, 0x59, 0xc6, 0xe0, 0xad, 0x0e, 0xe6, + 0xdb, 0x3b, 0xe8, 0x63, 0xea, 0x4e, 0xb6, 0xea, 0x50, 0xea, + 0x6e, 0x33, 0x9d, 0x28, 0x25, 0x42, 0x49, 0xd0, 0xf0, 0xed, + 0xc5, 0x5b, 0x6b, 0x4a, 0xe7, 0x45, 0xfa, 0xd3, 0x3f, 0xae, + 0xde, 0x5a, 0x90, 0xab, 0xf1, 0x61, 0x2f, 0x40, 0x5e, 0xcf, + 0x8b, 0x0b, 0x10, 0x59, 0xa9, 0xd0, 0x1e, 0x0f, 0x18, 0x6b, + 0x92, 0xd8, 0x9f, 0x58, 0x10, 0x84, 0xb6, 0x15, 0xe8, 0x5b, + 0xc4, 0xa0, 0x3e, 0x49, 0x8b, 0xea, 0xdd, 0xa9, 0x7e, 0x32, + 0x26, 0x9a, 0x68, 0x44, 0xf0, 0x30, 0xca, 0x2a, 0xd6, 0x19, + 0x7a, 0x80, 0xfd, 0xd7, 0xfc, 0xc7, 0x5d, 0xe7, 0x61, 0xd2, + 0x3f, 0x1f, 0x2c, 0x40, 0x70, 0x7b, 0x34, 0xcb, 0x08, 0xa9, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x26, 0x30, 0x24, 0x30, + 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, + 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, + 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x03, 0x81, 0x81, 0x00, 0x40, 0xd2, 0x70, 0x02, 0x08, 0x19, + 0xa0, 0xb8, 0x8d, 0x9d, 0x3d, 0x62, 0x41, 0x90, 0x2a, 0x36, + 0x4a, 0x8b, 0x21, 0x42, 0x9a, 0xb4, 0xc5, 0xf8, 0x79, 0x17, + 0xd7, 0x64, 0x4d, 0xbf, 0x8f, 0x6a, 0x04, 0x54, 0x7a, 0x0b, + 0xd4, 0xb5, 0x0e, 0xab, 0xf7, 0xb7, 0x06, 0x2b, 0xf8, 0xde, + 0x87, 0xb2, 0x37, 0x3b, 0x95, 0x01, 0xba, 0x9f, 0x8f, 0xec, + 0x0a, 0x86, 0xca, 0x51, 0xb6, 0x25, 0x73, 0x2f, 0xa1, 0x66, + 0xc8, 0x7a, 0x5e, 0x51, 0xbd, 0x49, 0xb5, 0x75, 0xda, 0xea, + 0xe5, 0xeb, 0x5d, 0xe3, 0xb0, 0xad, 0x49, 0x9f, 0x8b, 0xfd, + 0x89, 0xb3, 0xb7, 0xb2, 0x4c, 0x7d, 0x8a, 0x29, 0xb2, 0xbe, + 0x04, 0xef, 0x9c, 0x73, 0x3c, 0xea, 0xa3, 0x9f, 0x07, 0x66, + 0x5a, 0x2f, 0x38, 0xad, 0x1a, 0xeb, 0xe1, 0xb0, 0x62, 0x14, + 0x55, 0xdc, 0x8c, 0x83, 0xbb, 0xc7, 0x13, 0x04, 0x41, 0x54, + 0xf1, 0x45, 0x31, 0x82, 0x01, 0x33, 0x30, 0x82, 0x01, 0x2f, + 0x02, 0x01, 0x01, 0x30, 0x81, 0x8e, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, + 0x61, 0x66, 0x20, 0x43, 0x41, 0x02, 0x01, 0x05, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x04, 0x81, 0x80, 0xc5, 0x08, 0x17, 0x23, 0xb9, + 0x8d, 0x45, 0x0b, 0x1a, 0x9a, 0x10, 0xa7, 0x16, 0x57, 0x05, + 0x86, 0x0c, 0x9a, 0xfd, 0x2d, 0x9c, 0x87, 0x15, 0xb3, 0x0f, + 0xd5, 0x3b, 0x7b, 0xa8, 0xce, 0xa2, 0xcc, 0x2a, 0x2a, 0x6a, + 0xa0, 0xab, 0x2f, 0x57, 0x8c, 0xb7, 0xc7, 0x4e, 0x2a, 0xbd, + 0x72, 0xc5, 0xef, 0x2a, 0xd8, 0xb8, 0xf2, 0x9d, 0xbe, 0xd4, + 0xa7, 0x55, 0x3e, 0x06, 0x3b, 0x3f, 0xfa, 0x92, 0x4f, 0x1f, + 0x84, 0x84, 0x16, 0xcf, 0x9b, 0x26, 0x71, 0xf7, 0x57, 0x6a, + 0x6d, 0xdd, 0x34, 0x6b, 0x12, 0xc4, 0x70, 0x78, 0x59, 0x9b, + 0xf7, 0x45, 0xf4, 0xae, 0x30, 0xb0, 0x8c, 0x21, 0xb7, 0xb1, + 0x96, 0xda, 0x91, 0x0e, 0x57, 0x7e, 0x1b, 0xe2, 0xef, 0x82, + 0xd5, 0xa3, 0xd1, 0xeb, 0x47, 0x5c, 0x33, 0x91, 0xf8, 0x90, + 0xf9, 0x99, 0x0c, 0x69, 0x05, 0xee, 0xa1, 0x1a, 0x2d, 0x44, + 0x7e, 0x7c, 0x99 ) ); + +/** Signature generated with a non-signing certificate */ +SIGNATURE ( nonsigned_sig, + DATA ( 0x30, 0x82, 0x0c, 0x12, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x03, 0x30, + 0x82, 0x0b, 0xff, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0b, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, + 0xa0, 0x82, 0x0a, 0xa9, 0x30, 0x82, 0x02, 0x7d, 0x30, 0x82, + 0x01, 0xe6, 0x02, 0x01, 0x03, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, + 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, + 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, + 0x30, 0x30, 0x31, 0x33, 0x34, 0x5a, 0x17, 0x0d, 0x31, 0x33, + 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x34, + 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, + 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1b, 0x30, + 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x62, 0x6f, + 0x6f, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, + 0x89, 0x02, 0x81, 0x81, 0x00, 0xbd, 0x43, 0x97, 0x45, 0xa2, + 0xe0, 0x1d, 0x38, 0x41, 0xb0, 0xd9, 0x91, 0xf9, 0x77, 0xa9, + 0xcb, 0x9c, 0x9c, 0x93, 0xfe, 0x5a, 0xee, 0xbc, 0xd9, 0x0f, + 0x39, 0xf6, 0x42, 0xe4, 0x55, 0x21, 0xbb, 0x11, 0xfd, 0xfd, + 0xba, 0x25, 0x58, 0xc8, 0xc6, 0xa5, 0x3b, 0x6f, 0x80, 0xba, + 0x5b, 0xbc, 0x89, 0xca, 0x7a, 0xdf, 0x6e, 0xb9, 0x81, 0xb6, + 0x25, 0x67, 0x0a, 0x38, 0x10, 0xf8, 0x26, 0x43, 0x0c, 0x51, + 0x02, 0x14, 0xd6, 0xf2, 0x9d, 0x7c, 0xf5, 0x25, 0x1c, 0x78, + 0x4d, 0x47, 0xaf, 0x87, 0x2e, 0x38, 0x49, 0x87, 0xb5, 0x8a, + 0xf3, 0xb5, 0xd4, 0x15, 0x69, 0x2a, 0x52, 0xc9, 0x46, 0x97, + 0x34, 0x8e, 0x50, 0x4b, 0xc4, 0xf2, 0xfb, 0x39, 0xfd, 0x16, + 0x68, 0xdb, 0xa8, 0x17, 0xe2, 0x71, 0x4b, 0xe0, 0xdf, 0x3d, + 0xfc, 0xc3, 0x9b, 0x9d, 0x22, 0xc9, 0xd3, 0xf6, 0x02, 0xa6, + 0x60, 0xef, 0xf7, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x7d, 0xff, 0x73, + 0xf3, 0x68, 0xe3, 0x75, 0xf1, 0xcf, 0xac, 0x2e, 0x23, 0x73, + 0xea, 0xd1, 0x26, 0x33, 0xbf, 0xf9, 0x56, 0xdf, 0xbf, 0x98, + 0x20, 0x84, 0x08, 0x78, 0x6b, 0xe6, 0x71, 0x7e, 0x22, 0x68, + 0x4d, 0x6c, 0xbb, 0xd5, 0xcc, 0xb4, 0x28, 0x33, 0x5e, 0xbe, + 0x4d, 0x10, 0x16, 0x9f, 0x65, 0x3b, 0x68, 0x90, 0xa7, 0xf7, + 0x9d, 0x57, 0x71, 0x45, 0x39, 0x86, 0x4c, 0xc0, 0x97, 0x34, + 0x03, 0x9c, 0x2b, 0x25, 0x05, 0xb1, 0x5c, 0x0c, 0x4e, 0xf2, + 0x14, 0xbf, 0xcf, 0xf0, 0x9a, 0x2d, 0xcf, 0x02, 0x47, 0x60, + 0xd2, 0xe9, 0xed, 0xbf, 0x71, 0x5d, 0x07, 0x09, 0x01, 0x87, + 0xeb, 0xf7, 0xa8, 0x26, 0x86, 0x24, 0x59, 0xf0, 0x31, 0x3b, + 0x42, 0xd1, 0xf1, 0xfd, 0x7c, 0x49, 0x5f, 0x1a, 0xf0, 0x41, + 0x67, 0xf0, 0x16, 0x3a, 0xfd, 0xb6, 0xb5, 0xf6, 0x2e, 0x0c, + 0x18, 0x1f, 0x09, 0x8e, 0x4d, 0x30, 0x82, 0x02, 0xb3, 0x30, + 0x82, 0x02, 0x1c, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, + 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, + 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, + 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, + 0x33, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, + 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x90, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, + 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, + 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, + 0x65, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, + 0x81, 0x81, 0x00, 0xc9, 0x3a, 0xee, 0xc6, 0x3c, 0xac, 0x4d, + 0x81, 0xc6, 0x98, 0x5e, 0xe1, 0x48, 0x66, 0x1a, 0x1e, 0x60, + 0x19, 0x41, 0xae, 0xca, 0x14, 0x97, 0xc8, 0x3a, 0x50, 0xb6, + 0x48, 0xf5, 0x42, 0xac, 0x0f, 0xe1, 0xe3, 0x47, 0xf0, 0xbf, + 0x7c, 0xd0, 0xee, 0x8f, 0xb7, 0xa6, 0x19, 0xad, 0xbb, 0xc5, + 0x1b, 0x34, 0x38, 0xc8, 0xbd, 0x55, 0x84, 0x93, 0x72, 0xaf, + 0x84, 0xfc, 0x9b, 0x97, 0x1d, 0xb5, 0x54, 0x24, 0xd6, 0x5d, + 0xb7, 0x31, 0xf4, 0xbd, 0x3b, 0x40, 0x97, 0xc0, 0xa9, 0x5a, + 0x2a, 0xcb, 0x6b, 0x98, 0x07, 0xdb, 0xb5, 0x9f, 0xe8, 0x31, + 0x3f, 0x01, 0x46, 0x46, 0x70, 0x05, 0xa2, 0x0f, 0x8c, 0x7a, + 0x61, 0xf3, 0xdf, 0xdb, 0xa1, 0x37, 0x2c, 0x88, 0x6a, 0x81, + 0x21, 0x12, 0x4c, 0xf5, 0xcd, 0xaf, 0xc9, 0xd2, 0x36, 0x3d, + 0x82, 0xd1, 0xca, 0x19, 0xaf, 0x4e, 0xae, 0x50, 0x71, 0x44, + 0xbf, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x23, 0x30, 0x21, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, + 0x81, 0x00, 0x5d, 0x3c, 0xb3, 0x52, 0x19, 0xa6, 0x9e, 0x4a, + 0x44, 0x98, 0xbf, 0x51, 0x20, 0x47, 0x0a, 0xf3, 0x26, 0x1a, + 0xcc, 0x35, 0x2f, 0xc9, 0xed, 0xe0, 0x9d, 0x46, 0xeb, 0xbc, + 0x7e, 0xc9, 0xb9, 0x1d, 0x76, 0xa4, 0x1d, 0xc2, 0xd9, 0x16, + 0x29, 0x77, 0x01, 0x40, 0xdd, 0xe5, 0xcb, 0x28, 0x91, 0x3a, + 0x0c, 0x13, 0x01, 0x1b, 0x72, 0x62, 0x45, 0x27, 0xfd, 0xd7, + 0x00, 0x47, 0x36, 0x09, 0x1e, 0x7b, 0xd2, 0xcb, 0x95, 0x3d, + 0x28, 0x82, 0xce, 0x83, 0x59, 0x32, 0xf9, 0xe6, 0xec, 0x89, + 0xac, 0x88, 0x45, 0x22, 0x88, 0x6f, 0x5e, 0xa2, 0x79, 0x95, + 0xba, 0xb9, 0xc9, 0xb6, 0x4c, 0x7c, 0xb4, 0x29, 0xa1, 0x02, + 0xf5, 0xac, 0x5d, 0x8e, 0x52, 0xeb, 0xe8, 0xb1, 0x56, 0x49, + 0xb3, 0x77, 0x62, 0x7d, 0x87, 0x4d, 0x17, 0xf2, 0x62, 0x83, + 0x08, 0x59, 0x21, 0x60, 0x0d, 0x84, 0x8e, 0x5a, 0x84, 0xf6, + 0x30, 0x82, 0x02, 0xb3, 0x30, 0x82, 0x02, 0x1c, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58, + 0xd2, 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, + 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, + 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, + 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, + 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, + 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, + 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, + 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x31, 0x32, 0x30, 0x33, 0x32, 0x32, 0x30, 0x30, + 0x30, 0x31, 0x33, 0x33, 0x5a, 0x17, 0x0d, 0x33, 0x39, 0x30, + 0x38, 0x30, 0x38, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, + 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, + 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, 0x30, + 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, + 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xaa, 0x72, + 0xb5, 0xc1, 0x73, 0xf4, 0x95, 0x76, 0xa4, 0x27, 0xab, 0x5e, + 0xeb, 0x1d, 0x9d, 0xd0, 0x04, 0xb2, 0x93, 0x05, 0xc7, 0xfa, + 0x75, 0x84, 0x66, 0xe6, 0x3a, 0x26, 0x1f, 0xbc, 0x2d, 0xfd, + 0x8f, 0x59, 0x64, 0xac, 0xcf, 0x65, 0x9d, 0x82, 0x23, 0xc3, + 0x72, 0x93, 0xf2, 0x40, 0x68, 0x32, 0xd1, 0xb8, 0xf1, 0x47, + 0x61, 0x50, 0xea, 0xbc, 0xcc, 0x3c, 0x6b, 0x74, 0x7a, 0xec, + 0x2b, 0x75, 0xa6, 0xc2, 0xa2, 0xb8, 0xbf, 0x23, 0x48, 0x97, + 0xd5, 0xaf, 0x77, 0xc1, 0x92, 0x88, 0xd7, 0x38, 0xb7, 0x9e, + 0xda, 0xee, 0x72, 0x04, 0xcb, 0x96, 0xe5, 0xdb, 0xfd, 0x9b, + 0x5d, 0x99, 0x4e, 0x7a, 0x60, 0x23, 0x34, 0xa4, 0x8d, 0xd7, + 0x6c, 0xe7, 0x5d, 0x93, 0x97, 0xe1, 0xab, 0x36, 0x2c, 0x24, + 0x16, 0x92, 0x66, 0xf6, 0x6a, 0x14, 0x23, 0x1d, 0x18, 0xb9, + 0x44, 0x24, 0x61, 0x6b, 0xd3, 0x75, 0x02, 0x03, 0x01, 0x00, + 0x01, 0xa3, 0x23, 0x30, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, + 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x94, 0x9e, 0xea, + 0x17, 0x8d, 0x27, 0xa9, 0x17, 0xe5, 0xa9, 0x19, 0xbe, 0x82, + 0x36, 0xbd, 0xac, 0x74, 0xf3, 0x6e, 0x75, 0x71, 0x30, 0x1c, + 0x05, 0x80, 0x6d, 0x1a, 0x69, 0x37, 0x86, 0x9c, 0x77, 0x75, + 0x29, 0xa1, 0xc6, 0xb7, 0x11, 0x0a, 0x63, 0x27, 0xee, 0xb1, + 0xc8, 0x94, 0xa9, 0x2e, 0x56, 0x8f, 0xca, 0x9d, 0xbe, 0xf4, + 0xdb, 0x63, 0x97, 0x68, 0x3b, 0x13, 0xf8, 0x6a, 0xa5, 0xd1, + 0x3d, 0xed, 0xbb, 0x86, 0x9d, 0x42, 0xfc, 0x15, 0x0a, 0x04, + 0xf8, 0x3c, 0x0e, 0xc4, 0x86, 0x05, 0x57, 0x56, 0x96, 0xf6, + 0xc0, 0x18, 0x53, 0xb0, 0xc5, 0xf0, 0xca, 0x72, 0x77, 0x77, + 0xc9, 0x8e, 0x90, 0xa5, 0x4b, 0xb6, 0x80, 0x4a, 0x4c, 0x34, + 0x6f, 0xc9, 0xe8, 0x6f, 0xc2, 0x28, 0xdf, 0x93, 0xa9, 0xf5, + 0x63, 0x18, 0xc0, 0xec, 0x9e, 0xd5, 0x19, 0x36, 0xc5, 0x94, + 0x10, 0xd4, 0x72, 0xd2, 0xb8, 0x30, 0x82, 0x02, 0xb6, 0x30, + 0x82, 0x02, 0x1f, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, + 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81, 0x90, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x27, 0x30, 0x25, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x1e, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, + 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x32, 0x30, + 0x33, 0x32, 0x32, 0x30, 0x30, 0x30, 0x31, 0x33, 0x33, 0x5a, + 0x17, 0x0d, 0x31, 0x34, 0x31, 0x32, 0x31, 0x37, 0x30, 0x30, + 0x30, 0x31, 0x33, 0x33, 0x5a, 0x30, 0x81, 0x88, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, + 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, + 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, + 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, + 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, + 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, + 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, + 0x66, 0x20, 0x43, 0x41, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, + 0x81, 0x81, 0x00, 0xc3, 0x55, 0xad, 0xdf, 0x7b, 0xd1, 0x48, + 0xc3, 0xd3, 0x02, 0x54, 0x6c, 0x92, 0x45, 0x22, 0x3d, 0x90, + 0xd8, 0xc7, 0x13, 0xcd, 0xc1, 0x59, 0xc6, 0xe0, 0xad, 0x0e, + 0xe6, 0xdb, 0x3b, 0xe8, 0x63, 0xea, 0x4e, 0xb6, 0xea, 0x50, + 0xea, 0x6e, 0x33, 0x9d, 0x28, 0x25, 0x42, 0x49, 0xd0, 0xf0, + 0xed, 0xc5, 0x5b, 0x6b, 0x4a, 0xe7, 0x45, 0xfa, 0xd3, 0x3f, + 0xae, 0xde, 0x5a, 0x90, 0xab, 0xf1, 0x61, 0x2f, 0x40, 0x5e, + 0xcf, 0x8b, 0x0b, 0x10, 0x59, 0xa9, 0xd0, 0x1e, 0x0f, 0x18, + 0x6b, 0x92, 0xd8, 0x9f, 0x58, 0x10, 0x84, 0xb6, 0x15, 0xe8, + 0x5b, 0xc4, 0xa0, 0x3e, 0x49, 0x8b, 0xea, 0xdd, 0xa9, 0x7e, + 0x32, 0x26, 0x9a, 0x68, 0x44, 0xf0, 0x30, 0xca, 0x2a, 0xd6, + 0x19, 0x7a, 0x80, 0xfd, 0xd7, 0xfc, 0xc7, 0x5d, 0xe7, 0x61, + 0xd2, 0x3f, 0x1f, 0x2c, 0x40, 0x70, 0x7b, 0x34, 0xcb, 0x08, + 0xa9, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x26, 0x30, 0x24, + 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, + 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, + 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, + 0x00, 0x03, 0x81, 0x81, 0x00, 0x40, 0xd2, 0x70, 0x02, 0x08, + 0x19, 0xa0, 0xb8, 0x8d, 0x9d, 0x3d, 0x62, 0x41, 0x90, 0x2a, + 0x36, 0x4a, 0x8b, 0x21, 0x42, 0x9a, 0xb4, 0xc5, 0xf8, 0x79, + 0x17, 0xd7, 0x64, 0x4d, 0xbf, 0x8f, 0x6a, 0x04, 0x54, 0x7a, + 0x0b, 0xd4, 0xb5, 0x0e, 0xab, 0xf7, 0xb7, 0x06, 0x2b, 0xf8, + 0xde, 0x87, 0xb2, 0x37, 0x3b, 0x95, 0x01, 0xba, 0x9f, 0x8f, + 0xec, 0x0a, 0x86, 0xca, 0x51, 0xb6, 0x25, 0x73, 0x2f, 0xa1, + 0x66, 0xc8, 0x7a, 0x5e, 0x51, 0xbd, 0x49, 0xb5, 0x75, 0xda, + 0xea, 0xe5, 0xeb, 0x5d, 0xe3, 0xb0, 0xad, 0x49, 0x9f, 0x8b, + 0xfd, 0x89, 0xb3, 0xb7, 0xb2, 0x4c, 0x7d, 0x8a, 0x29, 0xb2, + 0xbe, 0x04, 0xef, 0x9c, 0x73, 0x3c, 0xea, 0xa3, 0x9f, 0x07, + 0x66, 0x5a, 0x2f, 0x38, 0xad, 0x1a, 0xeb, 0xe1, 0xb0, 0x62, + 0x14, 0x55, 0xdc, 0x8c, 0x83, 0xbb, 0xc7, 0x13, 0x04, 0x41, + 0x54, 0xf1, 0x45, 0x31, 0x82, 0x01, 0x33, 0x30, 0x82, 0x01, + 0x2f, 0x02, 0x01, 0x01, 0x30, 0x81, 0x8e, 0x30, 0x81, 0x88, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, + 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, + 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, + 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x02, 0x01, 0x03, 0x30, + 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00, 0x04, 0x81, 0x80, 0x33, 0x5c, 0xf8, 0xb4, + 0xa5, 0x70, 0xb9, 0x0f, 0x05, 0x50, 0x72, 0xdb, 0xa3, 0xba, + 0x8e, 0x0d, 0x6d, 0x8a, 0x2a, 0x91, 0x65, 0xb8, 0x76, 0xd0, + 0xfc, 0x9e, 0x1a, 0xdb, 0x2b, 0xd2, 0xfc, 0x03, 0xef, 0x8d, + 0xef, 0xfe, 0x32, 0x16, 0xad, 0xf8, 0xcb, 0x28, 0xb0, 0x61, + 0x15, 0xb8, 0x38, 0x72, 0xfc, 0x5d, 0xa1, 0xd2, 0xae, 0x9d, + 0x6a, 0xb0, 0x5e, 0xbb, 0x78, 0xd3, 0x39, 0x24, 0xa3, 0x71, + 0xa6, 0x90, 0x64, 0xa5, 0x82, 0xba, 0x3b, 0x85, 0x2d, 0x16, + 0x78, 0xf4, 0xcc, 0x9f, 0xfa, 0xc5, 0x68, 0x44, 0x2c, 0x22, + 0xb9, 0x4c, 0x07, 0x5c, 0xb4, 0x79, 0x1a, 0x48, 0xc2, 0x66, + 0x71, 0x57, 0x6d, 0xdf, 0x33, 0xa2, 0x26, 0x99, 0xdd, 0xe9, + 0xb9, 0x1b, 0xe1, 0xa6, 0x4d, 0x53, 0x8e, 0x71, 0x81, 0xa9, + 0x5d, 0x70, 0x47, 0x54, 0xbc, 0x15, 0xad, 0x9c, 0xe8, 0x90, + 0x52, 0x3e, 0x49, 0x86 ) ); + +/** iPXE self-test root CA certificate */ +static uint8_t root_crt_fingerprint[] = + FINGERPRINT ( 0x71, 0x5d, 0x51, 0x37, 0x5e, 0x18, 0xb3, 0xbc, + 0xbb, 0x30, 0x0e, 0x8f, 0x50, 0xc7, 0x55, 0xf5, + 0x96, 0xe7, 0xa8, 0x6d, 0x63, 0x2d, 0x32, 0x38, + 0xaf, 0x00, 0xc4, 0x1a, 0xfc, 0xd8, 0xac, 0xc3 ); + +/** Certificate store containing the iPXE self-test root CA */ +static struct x509_root test_root = { + .digest = &cms_test_algorithm, + .count = 1, + .fingerprints = root_crt_fingerprint, +}; + +/** Dummy fingerprint (not matching any certificates) */ +static uint8_t dummy_fingerprint[] = + FINGERPRINT ( 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff ); + +/** Certificate store containing a dummy fingerprint */ +static struct x509_root dummy_root = { + .digest = &cms_test_algorithm, + .count = 1, + .fingerprints = dummy_fingerprint, +}; + +/** Time at which all test certificates are valid */ +static time_t test_time = 1332374737ULL; /* Thu Mar 22 00:05:37 2012 */ + +/** Time at which end-entity test certificates are invalid */ +static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ + +/** + * Report signature parsing test result + * + * @v sig Test signature + */ +#define cms_parse_ok( sig ) do { \ + struct cms_signature temp; \ + ok ( cms_parse ( &temp, (sig)->data, (sig)->len ) == 0 ); \ + } while ( 0 ) + +/** + * Report signature verification test result + * + * @v sig Test signature + * @v code Test signed code + * @v name Test verification name + * @v time Test verification time + * @v root Test root certificate store + */ +#define cms_verify_ok( sig, code, name, time, root ) do { \ + struct cms_signature temp; \ + ok ( cms_parse ( &temp, (sig)->data, (sig)->len ) == 0 ); \ + ok ( cms_verify ( &temp, virt_to_user ( (code)->data ), \ + (code)->len, name, time, root ) == 0 ); \ + } while ( 0 ) + +/** + * Report signature verification failure test result + * + * @v sig Test signature + * @v code Test signed code + * @v name Test verification name + * @v time Test verification time + * @v root Test root certificate store + */ +#define cms_verify_fail_ok( sig, code, name, time, root ) do { \ + struct cms_signature temp; \ + ok ( cms_parse ( &temp, (sig)->data, (sig)->len ) == 0 ); \ + ok ( cms_verify ( &temp, virt_to_user ( (code)->data ), \ + (code)->len, name, time, root ) != 0 ); \ + } while ( 0 ) + +/** + * Perform CMS self-tests + * + */ +static void cms_test_exec ( void ) { + + /* Check that all signatures can be parsed */ + cms_parse_ok ( &codesigned_sig ); + cms_parse_ok ( &brokenchain_sig ); + cms_parse_ok ( &genericsigned_sig ); + cms_parse_ok ( &nonsigned_sig ); + + /* Check good signature */ + cms_verify_ok ( &codesigned_sig, &test_code, + "codesign.test.ipxe.org", test_time, &test_root ); + cms_verify_ok ( &codesigned_sig, &test_code, + NULL, test_time, &test_root ); + + /* Check incorrect signer name */ + cms_verify_fail_ok ( &codesigned_sig, &test_code, + "wrongname.test.ipxe.org", test_time, &test_root ); + + /* Check non-code-signing certificate */ + cms_verify_fail_ok ( &genericsigned_sig, &test_code, + NULL, test_time, &test_root ); + + /* Check non-signing certificate */ + cms_verify_fail_ok ( &nonsigned_sig, &test_code, + NULL, test_time, &test_root ); + + /* Check broken chain */ + cms_verify_fail_ok ( &brokenchain_sig, &test_code, + NULL, test_time, &test_root ); + + /* Check untrusted signature */ + cms_verify_fail_ok ( &codesigned_sig, &test_code, + NULL, test_time, &dummy_root ); + + /* Check incorrect signed content */ + cms_verify_fail_ok ( &codesigned_sig, &bad_code, + NULL, test_time, &test_root ); + + /* Check expired signature */ + cms_verify_fail_ok ( &codesigned_sig, &test_code, + NULL, test_expired, &test_root ); +} + +/** CMS self-test */ +struct self_test cms_test __self_test = { + .name = "cms", + .exec = cms_test_exec, +}; + +/* Drag in algorithms required for tests */ +REQUIRE_OBJECT ( rsa ); +REQUIRE_OBJECT ( md5 ); +REQUIRE_OBJECT ( sha1 ); +REQUIRE_OBJECT ( sha256 ); diff --git a/src/tests/tests.c b/src/tests/tests.c index 78a18a6c..ccbdde27 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -37,3 +37,4 @@ REQUIRE_OBJECT ( hash_df_test ); REQUIRE_OBJECT ( bigint_test ); REQUIRE_OBJECT ( rsa_test ); REQUIRE_OBJECT ( x509_test ); +REQUIRE_OBJECT ( cms_test ); From efb0c7fce4f9dd8e782209a84221088ee39bce67 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Mar 2012 12:22:38 +0000 Subject: [PATCH 118/221] [bios] Set character attributes only when necessary There is no INT 10 call for "display character with attribute, advancing the cursor and scrolling the screen as necessary". We therefore make two INT 10 calls: INT 10,09 to write the character with its attribute at the current cursor position, and then INT 10,0e to (re)write the character (leaving the attribute unchanged), advance the cursor position and scroll as necessary. This confuses the serial-over-LAN console redirection feature provided by some BIOSes. Fix by performing the INT10,09 only when necessary to change the existing attribute. Reported-by: Itay Gazit Tested-by: Itay Gazit Signed-off-by: Michael Brown --- src/arch/i386/firmware/pcbios/bios_console.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/arch/i386/firmware/pcbios/bios_console.c b/src/arch/i386/firmware/pcbios/bios_console.c index 1ecd07dd..e489971f 100644 --- a/src/arch/i386/firmware/pcbios/bios_console.c +++ b/src/arch/i386/firmware/pcbios/bios_console.c @@ -163,6 +163,14 @@ static void bios_putchar ( int character ) { /* Skip non-printable characters */ "cmpb $0x20, %%al\n\t" "jb 1f\n\t" + /* Read attribute */ + "movb %%al, %%cl\n\t" + "movb $0x08, %%ah\n\t" + "int $0x10\n\t" + "xchgb %%al, %%cl\n\t" + /* Skip if attribute matches */ + "cmpb %%ah, %%bl\n\t" + "je 1f\n\t" /* Set attribute */ "movw $0x0001, %%cx\n\t" "movb $0x09, %%ah\n\t" From 97dcc824bf298788e37f6869417662b0b9d16102 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Mar 2012 13:39:45 +0000 Subject: [PATCH 119/221] [image] Add concept of trusted images Trusted images may always be executed. Untrusted images may be executed only if the current image trust requirement allows untrusted images. Images can be marked as trusted using image_trust(), and marked as untrusted using image_untrust(). The current image trust requirement can be changed using image_set_trust(). It is possible to make the change permanent, in which case any future attempts to change the image trust requirement will fail. Signed-off-by: Michael Brown --- src/core/image.c | 46 ++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/image.h | 22 +++++++++++++++++++ src/usr/imgmgmt.c | 2 ++ 3 files changed, 70 insertions(+) diff --git a/src/core/image.c b/src/core/image.c index b1eba4ad..ae09a072 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -36,12 +36,28 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/* Disambiguate the various error causes */ +#define EACCES_UNTRUSTED \ + __einfo_error ( EINFO_EACCES_UNTRUSTED ) +#define EINFO_EACCES_UNTRUSTED \ + __einfo_uniqify ( EINFO_EACCES, 0x01, "Untrusted image" ) +#define EACCES_PERMANENT \ + __einfo_error ( EINFO_EACCES_PERMANENT ) +#define EINFO_EACCES_PERMANENT \ + __einfo_uniqify ( EINFO_EACCES, 0x02, "Trust requirement is permanent" ) + /** List of registered images */ struct list_head images = LIST_HEAD_INIT ( images ); /** Currently-executing image */ struct image *current_image; +/** Current image trust requirement */ +static int require_trusted_images = 0; + +/** Prevent changes to image trust requirement */ +static int require_trusted_images_permanent = 0; + /** * Free executable image * @@ -228,6 +244,12 @@ int image_exec ( struct image *image ) { if ( ( rc = image_select ( image ) ) != 0 ) return rc; + /* Check that image is trusted (if applicable) */ + if ( require_trusted_images && ! ( image->flags & IMAGE_TRUSTED ) ) { + DBGC ( image, "IMAGE %s is not trusted\n", image->name ); + return -EACCES_UNTRUSTED; + } + /* Switch current working directory to be that of the image itself */ old_cwuri = uri_get ( cwuri ); churi ( image->uri ); @@ -355,3 +377,27 @@ struct image * image_find_selected ( void ) { } return NULL; } + +/** + * Change image trust requirement + * + * @v require_trusted Require trusted images + * @v permanent Make trust requirement permanent + * @ret rc Return status code + */ +int image_set_trust ( int require_trusted, int permanent ) { + + /* Update trust requirement, if permitted to do so */ + if ( ! require_trusted_images_permanent ) { + require_trusted_images = require_trusted; + require_trusted_images_permanent = permanent; + } + + /* Fail if we attempted to change the trust requirement but + * were not permitted to do so. + */ + if ( require_trusted_images != require_trusted ) + return -EACCES_PERMANENT; + + return 0; +} diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index dbcd6d64..500b216e 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -64,6 +64,9 @@ struct image { /** Image is selected for execution */ #define IMAGE_SELECTED 0x0002 +/** Image is trusted */ +#define IMAGE_TRUSTED 0x0004 + /** An executable image type */ struct image_type { /** Name of this image type */ @@ -148,6 +151,7 @@ extern int image_exec ( struct image *image ); extern int image_replace ( struct image *replacement ); extern int image_select ( struct image *image ); extern struct image * image_find_selected ( void ); +extern int image_set_trust ( int require_trusted, int permanent ); /** * Increment reference count on an image @@ -181,4 +185,22 @@ static inline int image_set_name ( struct image *image, const char *name ) { return 0; } +/** + * Set image as trusted + * + * @v image Image + */ +static inline void image_trust ( struct image *image ) { + image->flags |= IMAGE_TRUSTED; +} + +/** + * Set image as untrusted + * + * @v image Image + */ +static inline void image_untrust ( struct image *image ) { + image->flags &= ~IMAGE_TRUSTED; +} + #endif /* _IPXE_IMAGE_H */ diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index e323dd0c..59011415 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -140,6 +140,8 @@ void imgstat ( struct image *image ) { printf ( "%s : %zd bytes", image->name, image->len ); if ( image->type ) printf ( " [%s]", image->type->name ); + if ( image->flags & IMAGE_TRUSTED ) + printf ( " [TRUSTED]" ); if ( image->flags & IMAGE_SELECTED ) printf ( " [SELECTED]" ); if ( image->cmdline ) From 4766b1455f590760af778262be1fe2963a1549a1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Mar 2012 23:52:24 +0000 Subject: [PATCH 120/221] [build] Fix compilation under Cygwin Originally-fixed-by: Steve Goodrich Signed-off-by: Michael Brown --- src/arch/i386/core/runtime.c | 2 +- src/arch/i386/interface/pcbios/int13.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch/i386/core/runtime.c b/src/arch/i386/core/runtime.c index 7d410c99..4268457f 100644 --- a/src/arch/i386/core/runtime.c +++ b/src/arch/i386/core/runtime.c @@ -201,7 +201,7 @@ static int initrd_init ( void ) { /* Allocate and copy initrd content */ image->data = umalloc ( initrd_len ); if ( ! image->data ) { - DBGC ( colour, "RUNTIME could not allocate %zd bytes for " + DBGC ( colour, "RUNTIME could not allocate %d bytes for " "initrd\n", initrd_len ); rc = -ENOMEM; goto err_umalloc; diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c index 8ce77ada..4bfc8a3a 100644 --- a/src/arch/i386/interface/pcbios/int13.c +++ b/src/arch/i386/interface/pcbios/int13.c @@ -160,7 +160,7 @@ static uint8_t num_drives; * @v int13 Emulated drive * @ret blksize Sector size */ -static inline unsigned int int13_blksize ( struct int13_drive *int13 ) { +static inline size_t int13_blksize ( struct int13_drive *int13 ) { return ( int13->capacity.blksize << int13->blksize_shift ); } From 1c127a696215bd75917c3ba836c2db11636b3ffb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 24 Mar 2012 01:16:37 +0000 Subject: [PATCH 121/221] [image] Simplify image management commands and internal API Remove the name, cmdline, and action parameters from imgdownload() and imgdownload_string(). These functions now simply download and return an image. Add the function imgacquire(), which will interpret a "name or URI string" parameter and return either an existing image or a newly downloaded image. Use imgacquire() to merge similar image-management commands that currently differ only by whether they take the name of an existing image or the URI of a new image to download. For example, "chain" and "imgexec" can now be merged. Extend imgstat and imgfree commands to take an optional list of images. Remove the arbitrary restriction on the length of image names. Signed-off-by: Michael Brown --- src/arch/i386/core/runtime.c | 9 +- .../i386/interface/syslinux/comboot_call.c | 17 +- src/core/image.c | 61 ++- src/core/parseopt.c | 22 - src/hci/commands/digest_cmd.c | 5 +- src/hci/commands/image_cmd.c | 405 ++++++++---------- src/include/ipxe/image.h | 19 +- src/include/ipxe/parseopt.h | 2 - src/include/usr/imgmgmt.h | 38 +- src/tests/test.c | 6 +- src/usr/autoboot.c | 9 +- src/usr/imgmgmt.c | 79 ++-- 12 files changed, 296 insertions(+), 376 deletions(-) diff --git a/src/arch/i386/core/runtime.c b/src/arch/i386/core/runtime.c index 4268457f..efa501e6 100644 --- a/src/arch/i386/core/runtime.c +++ b/src/arch/i386/core/runtime.c @@ -189,14 +189,18 @@ static int initrd_init ( void ) { initrd_phys, ( initrd_phys + initrd_len ) ); /* Allocate image */ - image = alloc_image(); + image = alloc_image ( NULL ); if ( ! image ) { DBGC ( colour, "RUNTIME could not allocate image for " "initrd\n" ); rc = -ENOMEM; goto err_alloc_image; } - image_set_name ( image, "" ); + if ( ( rc = image_set_name ( image, "" ) ) != 0 ) { + DBGC ( colour, "RUNTIME could not set image name: %s\n", + strerror ( rc ) ); + goto err_set_name; + } /* Allocate and copy initrd content */ image->data = umalloc ( initrd_len ); @@ -227,6 +231,7 @@ static int initrd_init ( void ) { err_register_image: err_umalloc: + err_set_name: image_put ( image ); err_alloc_image: return rc; diff --git a/src/arch/i386/interface/syslinux/comboot_call.c b/src/arch/i386/interface/syslinux/comboot_call.c index 818cae84..7ee5f61b 100644 --- a/src/arch/i386/interface/syslinux/comboot_call.c +++ b/src/arch/i386/interface/syslinux/comboot_call.c @@ -166,6 +166,8 @@ void comboot_force_text_mode ( void ) { * Fetch kernel and optional initrd */ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) { + struct image *kernel; + struct image *initrd; char *initrd_file; int rc; @@ -184,8 +186,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) { DBG ( "COMBOOT: fetching initrd '%s'\n", initrd_file ); /* Fetch initrd */ - if ( ( rc = imgdownload_string ( initrd_file, NULL, NULL, - NULL ) ) != 0 ) { + if ( ( rc = imgdownload_string ( initrd_file, &initrd ) ) != 0){ DBG ( "COMBOOT: could not fetch initrd: %s\n", strerror ( rc ) ); return rc; @@ -198,14 +199,20 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) { DBG ( "COMBOOT: fetching kernel '%s'\n", kernel_file ); - /* Allocate and fetch kernel */ - if ( ( rc = imgdownload_string ( kernel_file, NULL, cmdline, - image_replace ) ) != 0 ) { + /* Fetch kernel */ + if ( ( rc = imgdownload_string ( kernel_file, &kernel ) ) != 0 ) { DBG ( "COMBOOT: could not fetch kernel: %s\n", strerror ( rc ) ); return rc; } + /* Replace comboot image with kernel */ + if ( ( rc = image_replace ( kernel ) ) != 0 ) { + DBG ( "COMBOOT: could not replace with kernel: %s\n", + strerror ( rc ) ); + return rc; + } + return 0; } diff --git a/src/core/image.c b/src/core/image.c index ae09a072..b02b8936 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -66,6 +66,7 @@ static int require_trusted_images_permanent = 0; static void free_image ( struct refcnt *refcnt ) { struct image *image = container_of ( refcnt, struct image, refcnt ); + free ( image->name ); free ( image->cmdline ); uri_put ( image->uri ); ufree ( image->data ); @@ -77,37 +78,56 @@ static void free_image ( struct refcnt *refcnt ) { /** * Allocate executable image * + * @v uri URI, or NULL * @ret image Executable image */ -struct image * alloc_image ( void ) { +struct image * alloc_image ( struct uri *uri ) { + const char *name; struct image *image; + int rc; + /* Allocate image */ image = zalloc ( sizeof ( *image ) ); - if ( image ) { - ref_init ( &image->refcnt, free_image ); + if ( ! image ) + goto err_alloc; + + /* Initialise image */ + ref_init ( &image->refcnt, free_image ); + if ( uri ) { + image->uri = uri_get ( uri ); + name = basename ( ( char * ) uri->path ); + if ( ( rc = image_set_name ( image, name ) ) != 0 ) + goto err_set_name; } + return image; + + err_set_name: + image_put ( image ); + err_alloc: + return NULL; } /** - * Set image URI + * Set image name * * @v image Image - * @v URI New image URI - * - * If no name is set, the name will be updated to the base name of the - * URI path (if any). + * @v name New image name + * @ret rc Return status code */ -void image_set_uri ( struct image *image, struct uri *uri ) { - const char *path = uri->path; +int image_set_name ( struct image *image, const char *name ) { + char *name_copy; - /* Replace URI reference */ - uri_put ( image->uri ); - image->uri = uri_get ( uri ); + /* Duplicate name */ + name_copy = strdup ( name ); + if ( ! name_copy ) + return -ENOMEM; - /* Set name if none already specified */ - if ( path && ( ! image->name[0] ) ) - image_set_name ( image, basename ( ( char * ) path ) ); + /* Replace existing name */ + free ( image->name ); + image->name = name_copy; + + return 0; } /** @@ -137,11 +157,14 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) { */ int register_image ( struct image *image ) { static unsigned int imgindex = 0; + char name[8]; /* "imgXXXX" */ + int rc; /* Create image name if it doesn't already have one */ - if ( ! image->name[0] ) { - snprintf ( image->name, sizeof ( image->name ), "img%d", - imgindex++ ); + if ( ! image->name ) { + snprintf ( name, sizeof ( name ), "img%d", imgindex++ ); + if ( ( rc = image_set_name ( image, name ) ) != 0 ) + return rc; } /* Avoid ending up with multiple "selected" images on diff --git a/src/core/parseopt.c b/src/core/parseopt.c index f953b421..2739bd87 100644 --- a/src/core/parseopt.c +++ b/src/core/parseopt.c @@ -114,28 +114,6 @@ int parse_netdev ( const char *text, struct net_device **netdev ) { return 0; } -/** - * Parse image name - * - * @v text Text - * @ret image Image - * @ret rc Return status code - */ -int parse_image ( const char *text, struct image **image ) { - - /* Sanity check */ - assert ( text != NULL ); - - /* Find network device */ - *image = find_image ( text ); - if ( ! *image ) { - printf ( "\"%s\": no such image\n", text ); - return -ENOENT; - } - - return 0; -} - /** * Parse flag * diff --git a/src/hci/commands/digest_cmd.c b/src/hci/commands/digest_cmd.c index 6ca12eff..fac49765 100644 --- a/src/hci/commands/digest_cmd.c +++ b/src/hci/commands/digest_cmd.c @@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include /** @file * @@ -74,8 +75,8 @@ static int digest_exec ( int argc, char **argv, for ( i = optind ; i < argc ; i++ ) { - /* find image */ - if ( ( rc = parse_image ( argv[i], &image ) ) != 0 ) + /* Acquire image */ + if ( ( rc = imgacquire ( argv[i], &image ) ) != 0 ) continue; offset = 0; len = image->len; diff --git a/src/hci/commands/image_cmd.c b/src/hci/commands/image_cmd.c index 999442ca..1ae33074 100644 --- a/src/hci/commands/image_cmd.c +++ b/src/hci/commands/image_cmd.c @@ -34,123 +34,158 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ -/** "imgfetch" options */ -struct imgfetch_options { +/** "img{single}" options */ +struct imgsingle_options { /** Image name */ const char *name; }; -/** "imgfetch" option list */ -static struct option_descriptor imgfetch_opts[] = { +/** "img{single}" option list */ +static struct option_descriptor imgsingle_opts[] = { OPTION_DESC ( "name", 'n', required_argument, - struct imgfetch_options, name, parse_string ), + struct imgsingle_options, name, parse_string ), }; -/** "imgfetch" command descriptor */ -static struct command_descriptor imgfetch_cmd = - COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS, - "[--name ] [...]" ); +/** "img{single}" command descriptor */ +static struct command_descriptor imgsingle_cmd = + COMMAND_DESC ( struct imgsingle_options, imgsingle_opts, + 1, MAX_ARGUMENTS, + "[--name ] [...]" ); + +/** An "img{single}" family command descriptor */ +struct imgsingle_descriptor { + /** Command descriptor */ + struct command_descriptor *cmd; + /** Function to use to acquire the image */ + int ( * acquire ) ( const char *name, struct image **image ); + /** Pre-action to take upon image, or NULL */ + void ( * preaction ) ( struct image *image ); + /** Action to take upon image, or NULL */ + int ( * action ) ( struct image *image ); + /** Verb to describe action */ + const char *verb; +}; /** - * The "imgfetch" and friends command body + * The "img{single}" family of commands * * @v argc Argument count * @v argv Argument list - * @v cmd Command descriptor + * @v desc "img{single}" command descriptor * @v action_name Action name (for error messages) - * @v action Action to take upon a successful download + * @v action Action to take upon image * @ret rc Return status code */ -static int imgfetch_core_exec ( int argc, char **argv, - const char *action_name, - int ( * action ) ( struct image *image ) ) { - struct imgfetch_options opts; - char *uri_string; +static int imgsingle_exec ( int argc, char **argv, + struct imgsingle_descriptor *desc ) { + struct imgsingle_options opts; + char *name_uri = NULL; char *cmdline = NULL; + struct image *image; int rc; /* Parse options */ - if ( ( rc = parse_options ( argc, argv, &imgfetch_cmd, &opts ) ) != 0 ) + if ( ( rc = parse_options ( argc, argv, desc->cmd, &opts ) ) != 0 ) goto err_parse_options; - /* Parse URI string */ - uri_string = argv[optind]; - - /* Parse command line */ - if ( argv[ optind + 1 ] != NULL ) { - cmdline = concat_args ( &argv[ optind + 1 ] ); - if ( ! cmdline ) { - rc = -ENOMEM; - goto err_cmdline; + /* Parse name/URI string and command line, if present */ + if ( optind < argc ) { + name_uri = argv[optind]; + if ( argv[ optind + 1 ] != NULL ) { + cmdline = concat_args ( &argv[ optind + 1 ] ); + if ( ! cmdline ) { + rc = -ENOMEM; + goto err_parse_cmdline; + } } } - /* Fetch the image */ - if ( ( rc = imgdownload_string ( uri_string, opts.name, cmdline, - action ) ) != 0 ) { - printf ( "Could not %s %s: %s\n", - action_name, uri_string, strerror ( rc ) ); - goto err_imgdownload; + /* Acquire the image */ + if ( name_uri ) { + if ( ( rc = desc->acquire ( name_uri, &image ) ) != 0 ) + goto err_acquire; + } else { + image = image_find_selected(); + if ( ! image ) { + printf ( "No image selected\n" ); + goto err_acquire; + } } - /* Free command line */ - free ( cmdline ); + /* Carry out command pre-action, if applicable */ + if ( desc->preaction ) + desc->preaction ( image ); - return 0; + /* Set the image name, if applicable */ + if ( opts.name ) { + if ( ( rc = image_set_name ( image, opts.name ) ) != 0 ) { + printf ( "Could not name image: %s\n", + strerror ( rc ) ); + goto err_set_name; + } + } - err_imgdownload: + /* Set the command-line arguments, if applicable */ + if ( cmdline ) { + if ( ( rc = image_set_cmdline ( image, cmdline ) ) != 0 ) { + printf ( "Could not set arguments: %s\n", + strerror ( rc ) ); + goto err_set_cmdline; + } + } + + /* Carry out command action, if applicable */ + if ( desc->action ) { + if ( ( rc = desc->action ( image ) ) != 0 ) { + printf ( "Could not %s: %s\n", + desc->verb, strerror ( rc ) ); + goto err_action; + } + } + + /* Success */ + rc = 0; + + err_action: + err_set_cmdline: + err_set_name: + err_acquire: free ( cmdline ); - err_cmdline: + err_parse_cmdline: err_parse_options: return rc; } +/** "imgfetch" command descriptor */ +static struct command_descriptor imgfetch_cmd = + COMMAND_DESC ( struct imgsingle_options, imgsingle_opts, + 1, MAX_ARGUMENTS, + "[--name ] [...]" ); + +/** "imgfetch" family command descriptor */ +struct imgsingle_descriptor imgfetch_desc = { + .cmd = &imgfetch_cmd, + .acquire = imgdownload_string, +}; + /** - * The "imgfetch"/"module" command + * The "imgfetch" command * * @v argc Argument count * @v argv Argument list * @ret rc Return status code */ static int imgfetch_exec ( int argc, char **argv ) { - - return imgfetch_core_exec ( argc, argv, "fetch", NULL ); + return imgsingle_exec ( argc, argv, &imgfetch_desc ); } -/** - * The "kernel" command - * - * @v argc Argument count - * @v argv Argument list - * @ret rc Return status code - */ -static int kernel_exec ( int argc, char **argv ) { - - return imgfetch_core_exec ( argc, argv, "select", image_select ); -} - -/** - * The "chain" command - * - * @v argc Argument count - * @v argv Argument list - * @ret rc Return status code - */ -static int chain_exec ( int argc, char **argv) { - - return imgfetch_core_exec ( argc, argv, "boot", image_exec ); -} - -/** "imgselect" options */ -struct imgselect_options {}; - -/** "imgselect" option list */ -static struct option_descriptor imgselect_opts[] = {}; - -/** "imgselect" command descriptor */ -static struct command_descriptor imgselect_cmd = - COMMAND_DESC ( struct imgselect_options, imgselect_opts, 1, 1, - "" ); +/** "imgselect" family command descriptor */ +struct imgsingle_descriptor imgselect_desc = { + .cmd = &imgsingle_cmd, + .acquire = imgacquire, + .action = image_select, + .verb = "select", +}; /** * The "imgselect" command @@ -160,38 +195,40 @@ static struct command_descriptor imgselect_cmd = * @ret rc Return status code */ static int imgselect_exec ( int argc, char **argv ) { - struct imgselect_options opts; - struct image *image; - int rc; - - /* Parse options */ - if ( ( rc = parse_options ( argc, argv, &imgselect_cmd, &opts ) ) != 0 ) - return rc; - - /* Parse image name */ - if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) - return rc; - - /* Load image */ - if ( ( rc = imgselect ( image ) ) != 0 ) { - printf ( "Could not select %s: %s\n", - image->name, strerror ( rc ) ); - return rc; - } - - return 0; + return imgsingle_exec ( argc, argv, &imgselect_desc ); } -/** "imgargs" options */ -struct imgargs_options {}; +/** "imgexec" command descriptor */ +static struct command_descriptor imgexec_cmd = + COMMAND_DESC ( struct imgsingle_options, imgsingle_opts, + 0, MAX_ARGUMENTS, + "[--name ] [ [...]]" ); -/** "imgargs" option list */ -static struct option_descriptor imgargs_opts[] = {}; +/** "imgexec" family command descriptor */ +struct imgsingle_descriptor imgexec_desc = { + .cmd = &imgexec_cmd, + .acquire = imgacquire, + .action = image_exec, + .verb = "boot", +}; -/** "imgargs" command descriptor */ -static struct command_descriptor imgargs_cmd = - COMMAND_DESC ( struct imgargs_options, imgargs_opts, 1, MAX_ARGUMENTS, - " [...]" ); +/** + * The "imgexec" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int imgexec_exec ( int argc, char **argv) { + return imgsingle_exec ( argc, argv, &imgexec_desc ); +} + +/** "imgargs" family command descriptor */ +struct imgsingle_descriptor imgargs_desc = { + .cmd = &imgsingle_cmd, + .acquire = imgacquire, + .preaction = image_clear_cmdline, +}; /** * The "imgargs" command body @@ -201,105 +238,60 @@ static struct command_descriptor imgargs_cmd = * @ret rc Return status code */ static int imgargs_exec ( int argc, char **argv ) { - struct imgargs_options opts; - struct image *image; - char *cmdline = NULL; - int rc; - - /* Parse options */ - if ( ( rc = parse_options ( argc, argv, &imgargs_cmd, &opts ) ) != 0 ) - goto err_parse_options; - - /* Parse image name */ - if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) - goto err_parse_image; - - /* Parse command line */ - if ( argv[ optind + 1 ] != NULL ) { - cmdline = concat_args ( &argv[ optind + 1 ] ); - if ( ! cmdline ) { - rc = -ENOMEM; - goto err_cmdline; - } - } - - /* Set command line */ - if ( ( rc = image_set_cmdline ( image, cmdline ) ) != 0 ) - goto err_set_cmdline; - - /* Free command line */ - free ( cmdline ); - - return 0; - - err_set_cmdline: - free ( cmdline ); - err_cmdline: - err_parse_image: - err_parse_options: - return rc; + return imgsingle_exec ( argc, argv, &imgargs_desc ); } -/** "imgexec" options */ -struct imgexec_options {}; +/** "img{multi}" options */ +struct imgmulti_options {}; -/** "imgexec" option list */ -static struct option_descriptor imgexec_opts[] = {}; +/** "img{multi}" option list */ +static struct option_descriptor imgmulti_opts[] = {}; -/** "imgexec" command descriptor */ -static struct command_descriptor imgexec_cmd = - COMMAND_DESC ( struct imgexec_options, imgexec_opts, 0, 1, - "[]" ); +/** "img{multi}" command descriptor */ +static struct command_descriptor imgmulti_cmd = + COMMAND_DESC ( struct imgmulti_options, imgmulti_opts, 0, MAX_ARGUMENTS, + "[...]" ); /** - * The "imgexec" command + * The "img{multi}" family of commands * * @v argc Argument count * @v argv Argument list + * @v payload Function to execute on each image * @ret rc Return status code */ -static int imgexec_exec ( int argc, char **argv ) { - struct imgexec_options opts; +static int imgmulti_exec ( int argc, char **argv, + void ( * payload ) ( struct image *image ) ) { + struct imgmulti_options opts; struct image *image; + struct image *tmp; + int i; int rc; /* Parse options */ - if ( ( rc = parse_options ( argc, argv, &imgexec_cmd, &opts ) ) != 0 ) + if ( ( rc = parse_options ( argc, argv, &imgmulti_cmd, &opts ) ) != 0 ) return rc; - /* Parse image name */ - if ( optind < argc ) { - if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) - return rc; - } else { - image = imgautoselect(); - if ( ! image ) { - rc = -ENOTTY; - printf ( "No image selected: %s\n", strerror ( rc ) ); - return rc; - } + /* If no images are explicitly specified, process all images */ + if ( optind == argc ) { + for_each_image_safe ( image, tmp ) + payload ( image ); + return 0; } - /* Execute image */ - if ( ( rc = imgexec ( image ) ) != 0 ) { - printf ( "Could not execute %s: %s\n", - image->name, strerror ( rc ) ); - return rc; + /* Otherwise, process specified images */ + for ( i = optind ; i < argc ; i++ ) { + image = find_image ( argv[i] ); + if ( ! image ) { + printf ( "\"%s\": no such image\n", argv[i] ); + return -ENOENT; + } + payload ( image ); } return 0; } -/** "imgstat" options */ -struct imgstat_options {}; - -/** "imgstat" option list */ -static struct option_descriptor imgstat_opts[] = {}; - -/** "imgstat" command descriptor */ -static struct command_descriptor imgstat_cmd = - COMMAND_DESC ( struct imgstat_options, imgstat_opts, 0, 0, "" ); - /** * The "imgstat" command * @@ -308,33 +300,9 @@ static struct command_descriptor imgstat_cmd = * @ret rc Return status code */ static int imgstat_exec ( int argc, char **argv ) { - struct imgstat_options opts; - struct image *image; - int rc; - - /* Parse options */ - if ( ( rc = parse_options ( argc, argv, &imgstat_cmd, &opts ) ) != 0 ) - return rc; - - /* Show status of all images */ - for_each_image ( image ) { - imgstat ( image ); - } - - return 0; + return imgmulti_exec ( argc, argv, imgstat ); } -/** "imgfree" options */ -struct imgfree_options {}; - -/** "imgfree" option list */ -static struct option_descriptor imgfree_opts[] = {}; - -/** "imgfree" command descriptor */ -static struct command_descriptor imgfree_cmd = - COMMAND_DESC ( struct imgfree_options, imgfree_opts, 0, 1, - "[]" ); - /** * The "imgfree" command * @@ -343,28 +311,7 @@ static struct command_descriptor imgfree_cmd = * @ret rc Return status code */ static int imgfree_exec ( int argc, char **argv ) { - struct imgfree_options opts; - struct image *image; - struct image *tmp; - int rc; - - /* Parse options */ - if ( ( rc = parse_options ( argc, argv, &imgfree_cmd, &opts ) ) != 0 ) - return rc; - - if ( optind < argc ) { - /* Free specified image */ - if ( ( rc = parse_image ( argv[optind], &image ) ) != 0 ) - return rc; - imgfree ( image ); - } else { - /* Free all images */ - list_for_each_entry_safe ( image, tmp, &images, list ) { - imgfree ( image ); - } - } - - return 0; + return imgmulti_exec ( argc, argv, unregister_image ); } /** Image management commands */ @@ -383,19 +330,19 @@ struct command image_commands[] __command = { }, { .name = "kernel", - .exec = kernel_exec, + .exec = imgselect_exec, /* synonym for "imgselect" */ }, { .name = "chain", - .exec = chain_exec, + .exec = imgexec_exec, /* synonym for "imgexec" */ }, { .name = "imgselect", .exec = imgselect_exec, }, { - .name = "imgload", /* synonym for "imgselect" */ - .exec = imgselect_exec, + .name = "imgload", + .exec = imgselect_exec, /* synonym for "imgselect" */ }, { .name = "imgargs", diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 500b216e..ac97137b 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -29,7 +29,7 @@ struct image { /** URI of image */ struct uri *uri; /** Name */ - char name[16]; + char *name; /** Flags */ unsigned int flags; @@ -122,6 +122,10 @@ extern struct image *current_image; #define for_each_image( image ) \ list_for_each_entry ( (image), &images, list ) +/** Iterate over all registered images, safe against deletion */ +#define for_each_image_safe( image, tmp ) \ + list_for_each_entry_safe ( (image), (tmp), &images, list ) + /** * Test for existence of images * @@ -140,8 +144,8 @@ static inline struct image * first_image ( void ) { return list_first_entry ( &images, struct image, list ); } -extern struct image * alloc_image ( void ); -extern void image_set_uri ( struct image *image, struct uri *uri ); +extern struct image * alloc_image ( struct uri *uri ); +extern int image_set_name ( struct image *image, const char *name ); extern int image_set_cmdline ( struct image *image, const char *cmdline ); extern int register_image ( struct image *image ); extern void unregister_image ( struct image *image ); @@ -174,15 +178,12 @@ static inline void image_put ( struct image *image ) { } /** - * Set image name + * Clear image command line * * @v image Image - * @v name New image name - * @ret rc Return status code */ -static inline int image_set_name ( struct image *image, const char *name ) { - strncpy ( image->name, name, ( sizeof ( image->name ) - 1 ) ); - return 0; +static inline void image_clear_cmdline ( struct image *image ) { + image_set_cmdline ( image, NULL ); } /** diff --git a/src/include/ipxe/parseopt.h b/src/include/ipxe/parseopt.h index 8c456a64..e54dac66 100644 --- a/src/include/ipxe/parseopt.h +++ b/src/include/ipxe/parseopt.h @@ -13,7 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include struct net_device; -struct image; /** A command-line option descriptor */ struct option_descriptor { @@ -117,7 +116,6 @@ struct command_descriptor { extern int parse_string ( const char *text, const char **value ); extern int parse_integer ( const char *text, unsigned int *value ); extern int parse_netdev ( const char *text, struct net_device **netdev ); -extern int parse_image ( const char *text, struct image **image ); extern int parse_flag ( const char *text __unused, int *flag ); extern void print_usage ( struct command_descriptor *cmd, char **argv ); extern int reparse_options ( int argc, char **argv, diff --git a/src/include/usr/imgmgmt.h b/src/include/usr/imgmgmt.h index 71d587ba..8db5c978 100644 --- a/src/include/usr/imgmgmt.h +++ b/src/include/usr/imgmgmt.h @@ -11,41 +11,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -extern int imgdownload ( struct uri *uri, const char *name, const char *cmdline, - int ( * action ) ( struct image *image ) ); -extern int imgdownload_string ( const char *uri_string, const char *name, - const char *cmdline, - int ( * action ) ( struct image *image ) ); +extern int imgdownload ( struct uri *uri, struct image **image ); +extern int imgdownload_string ( const char *uri_string, struct image **image ); +extern int imgacquire ( const char *name, struct image **image ); extern void imgstat ( struct image *image ); -extern void imgfree ( struct image *image ); - -/** - * Select an image for execution - * - * @v image Image - * @ret rc Return status code - */ -static inline int imgselect ( struct image *image ) { - return image_select ( image ); -} - -/** - * Find the previously-selected image - * - * @ret image Image, or NULL - */ -static inline struct image * imgautoselect ( void ) { - return image_find_selected(); -} - -/** - * Execute an image - * - * @v image Image - * @ret rc Return status code - */ -static inline int imgexec ( struct image *image ) { - return image_exec ( image ); -} #endif /* _USR_IMGMGMT_H */ diff --git a/src/tests/test.c b/src/tests/test.c index b0a24c08..11dd2f5e 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -149,12 +149,8 @@ static struct image_type test_image_type = { .exec = test_image_exec, }; -static void test_image_free ( struct refcnt *refcnt __unused ) { - /* Do nothing */ -} - static struct image test_image = { - .refcnt = REF_INIT ( test_image_free ), + .refcnt = REF_INIT ( ref_no_free ), .name = "", .type = &test_image_type, }; diff --git a/src/usr/autoboot.c b/src/usr/autoboot.c index 5bfadec0..da82f5e8 100644 --- a/src/usr/autoboot.c +++ b/src/usr/autoboot.c @@ -131,6 +131,7 @@ struct setting skip_san_boot_setting __setting ( SETTING_SANBOOT_EXTRA ) = { */ int uriboot ( struct uri *filename, struct uri *root_path, int drive, unsigned int flags ) { + struct image *image; int rc; /* Hook SAN device, if applicable */ @@ -157,9 +158,10 @@ int uriboot ( struct uri *filename, struct uri *root_path, int drive, /* Attempt filename boot if applicable */ if ( filename ) { - if ( ( rc = imgdownload ( filename, NULL, NULL, - image_exec ) ) != 0 ) { - printf ( "\nCould not chain image: %s\n", + if ( ( rc = imgdownload ( filename, &image ) ) != 0 ) + goto err_download; + if ( ( rc = image_exec ( image ) ) != 0 ) { + printf ( "Could not boot image: %s\n", strerror ( rc ) ); /* Fall through to (possibly) attempt a SAN boot * as a fallback. If no SAN boot is attempted, @@ -190,6 +192,7 @@ int uriboot ( struct uri *filename, struct uri *root_path, int drive, } } + err_download: err_san_describe: /* Unhook SAN device, if applicable */ if ( ( drive >= 0 ) && ! ( flags & URIBOOT_NO_SAN_UNHOOK ) ) { diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index 59011415..2c74f486 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -36,39 +36,25 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ /** - * Download an image + * Download a new image * * @v uri URI - * @v name Image name, or NULL to use default - * @v cmdline Command line, or NULL for no command line - * @v action Action to take upon a successful download, or NULL + * @v image Image to fill in * @ret rc Return status code */ -int imgdownload ( struct uri *uri, const char *name, const char *cmdline, - int ( * action ) ( struct image *image ) ) { - struct image *image; +int imgdownload ( struct uri *uri, struct image **image ) { size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 ); char uri_string_redacted[len]; const char *password; int rc; /* Allocate image */ - image = alloc_image(); - if ( ! image ) { + *image = alloc_image ( uri ); + if ( ! *image ) { rc = -ENOMEM; goto err_alloc_image; } - /* Set image name */ - if ( name ) - image_set_name ( image, name ); - - /* Set image URI */ - image_set_uri ( image, uri ); - - /* Set image command line */ - image_set_cmdline ( image, cmdline ); - /* Redact password portion of URI, if necessary */ password = uri->password; if ( password ) @@ -78,8 +64,9 @@ int imgdownload ( struct uri *uri, const char *name, const char *cmdline, uri->password = password; /* Create downloader */ - if ( ( rc = create_downloader ( &monojob, image, LOCATION_URI, + if ( ( rc = create_downloader ( &monojob, *image, LOCATION_URI, uri ) ) != 0 ) { + printf ( "Could not start download: %s\n", strerror ( rc ) ); goto err_create_downloader; } @@ -88,49 +75,64 @@ int imgdownload ( struct uri *uri, const char *name, const char *cmdline, goto err_monojob_wait; /* Register image */ - if ( ( rc = register_image ( image ) ) != 0 ) + if ( ( rc = register_image ( *image ) ) != 0 ) { + printf ( "Could not register image: %s\n", strerror ( rc ) ); goto err_register_image; + } /* Drop local reference to image. Image is guaranteed to * remain in scope since it is registered. */ - image_put ( image ); + image_put ( *image ); - /* Carry out specified post-download action, if applicable */ - return ( action ? action ( image ) : 0 ); + return 0; err_register_image: err_monojob_wait: err_create_downloader: - image_put ( image ); + image_put ( *image ); err_alloc_image: return rc; } /** - * Download an image + * Download a new image * - * @v uri_string URI as a string (e.g. "http://www.nowhere.com/vmlinuz") - * @v name Image name, or NULL to use default - * @v cmdline Command line, or NULL for no command line - * @v action Action to take upon a successful download + * @v uri_string URI string + * @v image Image to fill in * @ret rc Return status code */ -int imgdownload_string ( const char *uri_string, const char *name, - const char *cmdline, - int ( * action ) ( struct image *image ) ) { +int imgdownload_string ( const char *uri_string, struct image **image ) { struct uri *uri; int rc; if ( ! ( uri = parse_uri ( uri_string ) ) ) return -ENOMEM; - rc = imgdownload ( uri, name, cmdline, action ); + rc = imgdownload ( uri, image ); uri_put ( uri ); return rc; } +/** + * Acquire an image + * + * @v name_uri Name or URI string + * @v image Image to fill in + * @ret rc Return status code + */ +int imgacquire ( const char *name_uri, struct image **image ) { + + /* If we already have an image with the specified name, use it */ + *image = find_image ( name_uri ); + if ( *image ) + return 0; + + /* Otherwise, download a new image */ + return imgdownload_string ( name_uri, image ); +} + /** * Display status of an image * @@ -148,12 +150,3 @@ void imgstat ( struct image *image ) { printf ( " \"%s\"", image->cmdline ); printf ( "\n" ); } - -/** - * Free an image - * - * @v image Executable/loadable image - */ -void imgfree ( struct image *image ) { - unregister_image ( image ); -} From d1465f7b0b4e3df4af1abf65462fe1d89e53a80a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 22 Mar 2012 13:46:38 +0000 Subject: [PATCH 122/221] [image] Add the "imgtrust" and "imgverify" commands Signed-off-by: Michael Brown --- src/config/config.c | 3 + src/config/general.h | 1 + src/hci/commands/image_trust_cmd.c | 172 +++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/usr/imgtrust.h | 17 +++ src/usr/imgtrust.c | 81 ++++++++++++++ 6 files changed, 275 insertions(+) create mode 100644 src/hci/commands/image_trust_cmd.c create mode 100644 src/include/usr/imgtrust.h create mode 100644 src/usr/imgtrust.c diff --git a/src/config/config.c b/src/config/config.c index bdf6b5ce..d6c4d06a 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -217,6 +217,9 @@ REQUIRE_OBJECT ( route_cmd ); #ifdef IMAGE_CMD REQUIRE_OBJECT ( image_cmd ); #endif +#ifdef IMAGE_TRUST_CMD +REQUIRE_OBJECT ( image_trust_cmd ); +#endif #ifdef DHCP_CMD REQUIRE_OBJECT ( dhcp_cmd ); #endif diff --git a/src/config/general.h b/src/config/general.h index 99136c17..a10696ee 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -126,6 +126,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define VLAN_CMD /* VLAN commands */ //#define PXE_CMD /* PXE commands */ //#define REBOOT_CMD /* Reboot command */ +//#define IMAGE_TRUST_CMD /* Image trust management commands */ /* * ROM-specific options diff --git a/src/hci/commands/image_trust_cmd.c b/src/hci/commands/image_trust_cmd.c new file mode 100644 index 00000000..25e77dde --- /dev/null +++ b/src/hci/commands/image_trust_cmd.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Image trust management commands + * + */ + +/** "imgtrust" options */ +struct imgtrust_options { + /** Allow trusted images */ + int allow; + /** Make trust requirement permanent */ + int permanent; +}; + +/** "imgtrust" option list */ +static struct option_descriptor imgtrust_opts[] = { + OPTION_DESC ( "allow", 'a', no_argument, + struct imgtrust_options, allow, parse_flag ), + OPTION_DESC ( "permanent", 'p', no_argument, + struct imgtrust_options, permanent, parse_flag ), +}; + +/** "imgtrust" command descriptor */ +static struct command_descriptor imgtrust_cmd = + COMMAND_DESC ( struct imgtrust_options, imgtrust_opts, 0, 0, + "[--allow] [--permanent]" ); + +/** + * The "imgtrust" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int imgtrust_exec ( int argc, char **argv ) { + struct imgtrust_options opts; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &imgtrust_cmd, &opts ) ) != 0 ) + return rc; + + /* Set trust requirement */ + if ( ( rc = image_set_trust ( ( ! opts.allow ), + opts.permanent ) ) != 0 ) { + printf ( "Could not set image trust requirement: %s\n", + strerror ( rc ) ); + return rc; + } + + return 0; +} + +/** "imgverify" options */ +struct imgverify_options { + /** Required signer common name */ + const char *signer; + /** Keep signature after verification */ + int keep; +}; + +/** "imgverify" option list */ +static struct option_descriptor imgverify_opts[] = { + OPTION_DESC ( "signer", 's', required_argument, + struct imgverify_options, signer, parse_string ), + OPTION_DESC ( "keep", 'k', no_argument, + struct imgverify_options, keep, parse_flag ), +}; + +/** "imgverify" command descriptor */ +static struct command_descriptor imgverify_cmd = + COMMAND_DESC ( struct imgverify_options, imgverify_opts, 2, 2, + "[--signer ] [--keep] " + "" ); + +/** + * The "imgverify" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int imgverify_exec ( int argc, char **argv ) { + struct imgverify_options opts; + const char *image_name_uri; + const char *signature_name_uri; + struct image *image; + struct image *signature; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &imgverify_cmd, &opts ) ) != 0 ) + return rc; + + /* Parse image name/URI string */ + image_name_uri = argv[optind]; + + /* Parse signature name/URI string */ + signature_name_uri = argv[ optind + 1 ]; + + /* Acquire the image */ + if ( ( rc = imgacquire ( image_name_uri, &image ) ) != 0 ) + goto err_acquire_image; + + /* Acquire the signature image */ + if ( ( rc = imgacquire ( signature_name_uri, &signature ) ) != 0 ) + goto err_acquire_signature; + + /* Verify image */ + if ( ( rc = imgverify ( image, signature, opts.signer ) ) != 0 ) { + printf ( "Could not verify: %s\n", strerror ( rc ) ); + goto err_verify; + } + + /* Success */ + rc = 0; + + err_verify: + /* Discard signature unless --keep was specified */ + if ( ! opts.keep ) + unregister_image ( signature ); + err_acquire_signature: + err_acquire_image: + return rc; +} + +/** Image trust management commands */ +struct command image_trust_commands[] __command = { + { + .name = "imgtrust", + .exec = imgtrust_exec, + }, + { + .name = "imgverify", + .exec = imgverify_exec, + }, +}; + +/* Drag in objects typically required for signature verification */ +REQUIRE_OBJECT ( rsa ); +REQUIRE_OBJECT ( md5 ); +REQUIRE_OBJECT ( sha1 ); +REQUIRE_OBJECT ( sha256 ); diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e0473a17..b3fbb391 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -250,6 +250,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_linux_entropy ( ERRFILE_OTHER | 0x00280000 ) #define ERRFILE_x509_test ( ERRFILE_OTHER | 0x00290000 ) #define ERRFILE_cms ( ERRFILE_OTHER | 0x002a0000 ) +#define ERRFILE_imgtrust ( ERRFILE_OTHER | 0x002b0000 ) /** @} */ diff --git a/src/include/usr/imgtrust.h b/src/include/usr/imgtrust.h new file mode 100644 index 00000000..f47105af --- /dev/null +++ b/src/include/usr/imgtrust.h @@ -0,0 +1,17 @@ +#ifndef _USR_IMGTRUST_H +#define _USR_IMGTRUST_H + +/** @file + * + * Image trust management + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +extern int imgverify ( struct image *image, struct image *signature, + const char *name ); + +#endif /* _USR_IMGTRUST_H */ diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c new file mode 100644 index 00000000..5ea20265 --- /dev/null +++ b/src/usr/imgtrust.c @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include + +/** @file + * + * Image trust management + * + */ + +/** + * Verify image using downloaded signature + * + * @v image Image to verify + * @v signature Image containing signature + * @v name Required common name, or NULL to allow any name + * @ret rc Return status code + */ +int imgverify ( struct image *image, struct image *signature, + const char *name ) { + size_t len; + void *data; + struct cms_signature sig; + time_t now; + int rc; + + /* Mark image as untrusted */ + image_untrust ( image ); + + /* Copy signature to internal memory */ + len = signature->len; + data = malloc ( len ); + if ( ! data ) { + rc = -ENOMEM; + goto err_alloc; + } + copy_from_user ( data, signature->data, 0, len ); + + /* Parse signature */ + if ( ( rc = cms_parse ( &sig, data, len ) ) != 0 ) + goto err_parse; + + /* Use signature to verify image */ + now = time ( NULL ); + if ( ( rc = cms_verify ( &sig, image->data, image->len, + name, now, NULL ) ) != 0 ) + goto err_verify; + + /* Mark image as trusted */ + image_trust ( image ); + + err_verify: + err_parse: + free ( data ); + err_alloc: + return rc; +} From a6d49c17c9ef82420138a51b52a9ce57074650db Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 14:43:52 +0100 Subject: [PATCH 123/221] [console] Move putchar() and getchar() declarations to stdio.h Signed-off-by: Michael Brown --- src/core/debug.c | 1 - src/core/pcmcia.c | 1 - src/core/vsprintf.c | 1 - src/drivers/net/3c509-eisa.c | 1 - src/drivers/net/cs89x0.c | 1 - src/drivers/net/depca.c | 1 - src/drivers/net/epic100.c | 1 - src/drivers/net/etherfabric.c | 2 +- src/hci/mucurses/mucurses.c | 1 - src/include/etherboot.h | 1 - src/include/ipxe/console.h | 3 +-- src/include/stdio.h | 4 ++++ src/usr/iwmgmt.c | 1 - 13 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/core/debug.c b/src/core/debug.c index 73e74d9c..8fca8d90 100644 --- a/src/core/debug.c +++ b/src/core/debug.c @@ -22,7 +22,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include /** * Pause until a key is pressed diff --git a/src/core/pcmcia.c b/src/core/pcmcia.c index 2d8ceb6f..5fd21f4a 100644 --- a/src/core/pcmcia.c +++ b/src/core/pcmcia.c @@ -34,7 +34,6 @@ FILE_LICENCE ( GPL2_ONLY ); #define CODE_STATUS "alpha" #define CODE_VERSION "0.1.3" #include -#include #include int sockets; /* AHTODO: Phase this out! */ diff --git a/src/core/vsprintf.c b/src/core/vsprintf.c index b838b89e..b721b024 100644 --- a/src/core/vsprintf.c +++ b/src/core/vsprintf.c @@ -21,7 +21,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include #include #include diff --git a/src/drivers/net/3c509-eisa.c b/src/drivers/net/3c509-eisa.c index 195a844a..81c60ee9 100644 --- a/src/drivers/net/3c509-eisa.c +++ b/src/drivers/net/3c509-eisa.c @@ -6,7 +6,6 @@ #include #include -#include #include "3c509.h" /* diff --git a/src/drivers/net/cs89x0.c b/src/drivers/net/cs89x0.c index ee34d0c5..876b8785 100644 --- a/src/drivers/net/cs89x0.c +++ b/src/drivers/net/cs89x0.c @@ -92,7 +92,6 @@ FILE_LICENCE ( GPL2_ONLY ); #include "etherboot.h" #include "nic.h" #include -#include #include "cs89x0.h" static unsigned short eth_nic_base; diff --git a/src/drivers/net/depca.c b/src/drivers/net/depca.c index 735a52df..016f28bb 100644 --- a/src/drivers/net/depca.c +++ b/src/drivers/net/depca.c @@ -240,7 +240,6 @@ FILE_LICENCE ( GPL_ANY ); #include "etherboot.h" #include "nic.h" #include -#include #include /* diff --git a/src/drivers/net/epic100.c b/src/drivers/net/epic100.c index 5211317f..b478fab5 100644 --- a/src/drivers/net/epic100.c +++ b/src/drivers/net/epic100.c @@ -10,7 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include "nic.h" -#include #include "epic100.h" /* Condensed operations for readability */ diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index 15e7d4c1..e82d6eb8 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -20,11 +20,11 @@ FILE_LICENCE ( GPL_ANY ); #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/src/hci/mucurses/mucurses.c b/src/hci/mucurses/mucurses.c index 7c162021..ab9a6535 100644 --- a/src/hci/mucurses/mucurses.c +++ b/src/hci/mucurses/mucurses.c @@ -1,4 +1,3 @@ -#include #include #include "mucurses.h" diff --git a/src/include/etherboot.h b/src/include/etherboot.h index b2fbe4f6..ba79cb16 100644 --- a/src/include/etherboot.h +++ b/src/include/etherboot.h @@ -14,7 +14,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include #include #include #include diff --git a/src/include/ipxe/console.h b/src/include/ipxe/console.h index 3bfa5033..5188f985 100644 --- a/src/include/ipxe/console.h +++ b/src/include/ipxe/console.h @@ -1,6 +1,7 @@ #ifndef _IPXE_CONSOLE_H #define _IPXE_CONSOLE_H +#include #include /** @file @@ -100,8 +101,6 @@ struct console_driver { /* Function prototypes */ -extern void putchar ( int character ); -extern int getchar ( void ); extern int iskey ( void ); extern int getkey ( unsigned long timeout ); diff --git a/src/include/stdio.h b/src/include/stdio.h index 84181f0a..91840af5 100644 --- a/src/include/stdio.h +++ b/src/include/stdio.h @@ -6,6 +6,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +extern void putchar ( int character ); + +extern int getchar ( void ); + extern int __attribute__ (( format ( printf, 1, 2 ) )) printf ( const char *fmt, ... ); diff --git a/src/usr/iwmgmt.c b/src/usr/iwmgmt.c index 29f623c3..abcd63f4 100644 --- a/src/usr/iwmgmt.c +++ b/src/usr/iwmgmt.c @@ -19,7 +19,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include #include #include #include From b35d454422a97b89a7128be4d4e9ff7a8f176466 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 15:47:34 +0100 Subject: [PATCH 124/221] [console] Remove unused "btext" console The "btext" console has been disabled by a "#if 0" since 2007. Signed-off-by: Michael Brown --- src/config/config.c | 3 - src/config/console.h | 1 - src/core/btext.c | 5039 ------------------------------------------ src/include/btext.h | 62 - 4 files changed, 5105 deletions(-) delete mode 100644 src/core/btext.c delete mode 100644 src/include/btext.h diff --git a/src/config/config.c b/src/config/config.c index d6c4d06a..4b0bc371 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -71,9 +71,6 @@ REQUIRE_OBJECT ( serial_console ); #ifdef CONSOLE_DIRECT_VGA REQUIRE_OBJECT ( video_subr ); #endif -#ifdef CONSOLE_BTEXT -REQUIRE_OBJECT ( btext ); -#endif #ifdef CONSOLE_PC_KBD REQUIRE_OBJECT ( pc_kbd ); #endif diff --git a/src/config/console.h b/src/config/console.h index bf7ea050..0692c2f5 100644 --- a/src/config/console.h +++ b/src/config/console.h @@ -17,7 +17,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONSOLE_PCBIOS /* Default BIOS console */ //#define CONSOLE_SERIAL /* Serial port */ //#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */ -//#define CONSOLE_BTEXT /* Who knows what this does? */ //#define CONSOLE_PC_KBD /* Direct access to PC keyboard */ //#define CONSOLE_SYSLOG /* Syslog console */ //#define CONSOLE_VMWARE /* VMware logfile console */ diff --git a/src/core/btext.c b/src/core/btext.c deleted file mode 100644 index 4fb7378d..00000000 --- a/src/core/btext.c +++ /dev/null @@ -1,5039 +0,0 @@ -#if 0 - -/* - * Procedures for drawing on the screen early on in the boot process. - * - * Benjamin Herrenschmidt - * - * move to LinuxBIOS by LYH yhlu@tyan.com - * move to Etherboot by LYH - */ - -#include -#include -#include - -#undef __BIG_ENDIAN -#if 0 -#define __LITTLE_ENDIAN -#endif - -#include "btext.h" - -//#define NO_SCROLL - -#ifndef NO_SCROLL -static void scrollscreen(void); -#endif - -static void draw_byte(const unsigned char c, u32 locX, u32 locY); -#if 0 -static void draw_byte_32(const unsigned char *bits, u32 *base, u32 rb); -static void draw_byte_16(const unsigned char *bits, u32 *base, u32 rb); -#endif -static void draw_byte_8(const unsigned char *bits, u32 *base, u32 rb); - -static u32 g_loc_X; -static u32 g_loc_Y; -static u32 g_max_loc_X; -static u32 g_max_loc_Y; - -#define CHAR_256 0 - -#if CHAR_256==1 -#define cmapsz (16*256) -#else -#define cmapsz (16*96) -#endif - -static const unsigned char vga_font[cmapsz]; - -u32 boot_text_mapped; - -boot_infos_t disp_bi; - -#define BTEXT -#define BTDATA - - -/* This function will enable the early boot text when doing OF booting. This - * way, xmon output should work too - */ -static void -btext_setup_display(u32 width, u32 height, u32 depth, u32 pitch, - unsigned long address) -{ - boot_infos_t* bi = &disp_bi; - - g_loc_X = 0; - g_loc_Y = 0; - g_max_loc_X = width / 8; - g_max_loc_Y = height / 16; -// bi->logicalDisplayBase = (unsigned char *)address; - bi->dispDeviceBase = address; - bi->dispDeviceRowBytes = pitch; - bi->dispDeviceDepth = depth; - bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0; - bi->dispDeviceRect[2] = width; - bi->dispDeviceRect[3] = height; - boot_text_mapped = 0; -} - -/* Here's a small text engine to use during early boot - * or for debugging purposes - * - * todo: - * - * - build some kind of vgacon with it to enable early printk - * - move to a separate file - * - add a few video driver hooks to keep in sync with display - * changes. - */ - -static void -map_boot_text(void) -{ - boot_infos_t *bi = &disp_bi; - - if (bi->dispDeviceBase == 0) - return; - - boot_text_mapped = 0; - - bi->logicalDisplayBase = phys_to_virt(bi->dispDeviceBase); - - boot_text_mapped = 1; -} - -/* Calc the base address of a given point (x,y) */ -static unsigned char * BTEXT -calc_base(boot_infos_t *bi, u32 x, u32 y) -{ - unsigned char *base; - base = bi->logicalDisplayBase; -#if 0 - /* Ummm... which moron wrote this? */ - if (base == 0) - base = bi->dispDeviceBase; -#endif - base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3); - base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes; - return base; -} - - -static void BTEXT btext_clearscreen(void) -{ - boot_infos_t* bi = &disp_bi; - u32 *base = (u32 *)calc_base(bi, 0, 0); - u32 width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * - (bi->dispDeviceDepth >> 3)) >> 2; - u32 i,j; - - for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) - { - u32 *ptr = base; - for(j=width; j; --j) - *(ptr++) = 0; - base += (bi->dispDeviceRowBytes >> 2); - } -} - -#if 0 -__inline__ void dcbst(const void* addr) -{ - __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr)); -} - -static void BTEXT btext_flushscreen(void) -{ - boot_infos_t* bi = &disp_bi; - u32 *base = (unsigned long *)calc_base(bi, 0, 0); - u32 width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * - (bi->dispDeviceDepth >> 3)) >> 2; - u32 i,j; - - for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++) - { - u32 *ptr = base; - for(j=width; j>0; j-=8) { - dcbst(ptr); - ptr += 8; - } - base += (bi->dispDeviceRowBytes >> 2); - } -} -#endif - - -#ifndef NO_SCROLL -static BTEXT void -scrollscreen(void) -{ - boot_infos_t* bi = &disp_bi; - u32 *src = (u32 *)calc_base(bi,0,16); - u32 *dst = (u32 *)calc_base(bi,0,0); - u32 width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) * - (bi->dispDeviceDepth >> 3)) >> 2; - u32 i,j; - - for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++) - { - u32 *src_ptr = src; - u32 *dst_ptr = dst; - for(j=width; j; --j) - *(dst_ptr++) = *(src_ptr++); - src += (bi->dispDeviceRowBytes >> 2); - dst += (bi->dispDeviceRowBytes >> 2); - } - for (i=0; i<16; i++) - { - u32 *dst_ptr = dst; - for(j=width; j; --j) - *(dst_ptr++) = 0; - dst += (bi->dispDeviceRowBytes >> 2); - } -} -#endif /* ndef NO_SCROLL */ - -static void BTEXT btext_drawchar(char c) -{ - u32 cline = 0; - - if (!boot_text_mapped) - return; - - switch (c) { - case '\b': - if (g_loc_X > 0) - --g_loc_X; - break; - case '\t': - g_loc_X = (g_loc_X & -8) + 8; - break; - case '\r': - g_loc_X = 0; - break; - case '\n': - g_loc_X = 0; - g_loc_Y++; - cline = 1; - break; - default: - draw_byte(c, g_loc_X++, g_loc_Y); - } - if (g_loc_X >= g_max_loc_X) { - g_loc_X = 0; - g_loc_Y++; - cline = 1; - } -#ifndef NO_SCROLL - while (g_loc_Y >= g_max_loc_Y) { - scrollscreen(); - g_loc_Y--; - } -#else - /* wrap around from bottom to top of screen so we don't - waste time scrolling each line. -- paulus. */ - if (g_loc_Y >= g_max_loc_Y) - g_loc_Y = 0; - if (cline) { - for (x = 0; x < g_max_loc_X; ++x) - draw_byte(' ', x, g_loc_Y); - } -#endif -} -#if 0 -static void BTEXT -btext_drawstring(const char *c) -{ - if (!boot_text_mapped) - return; - while (*c) - btext_drawchar(*c++); -} -static void BTEXT -btext_drawhex(u32 v) -{ - static char hex_table[] = "0123456789abcdef"; - - if (!boot_text_mapped) - return; - btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]); - btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]); - btext_drawchar(' '); -} -#endif - -static void BTEXT -draw_byte(const unsigned char c, u32 locX, u32 locY) -{ - boot_infos_t* bi = &disp_bi; - unsigned char *base = calc_base(bi, locX << 3, locY << 4); -#if CHAR_256==1 - unsigned const char *font = &vga_font[(((u32)c)) * 16]; -#else - unsigned const char *font = &vga_font[(((u32)c-0x20)) * 16]; -#endif - - u32 rb = bi->dispDeviceRowBytes; - - switch(bi->dispDeviceDepth) { -#if 0 - case 24: - case 32: - draw_byte_32(font, (u32 *)base, rb); - break; - case 15: - case 16: - draw_byte_16(font, (u32 *)base, rb); - break; -#endif - case 8: - draw_byte_8(font, (u32 *)base, rb); - break; - } -} -static u32 expand_bits_8[16] BTDATA = { -#if defined(__BIG_ENDIAN) - 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, - 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, - 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, - 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -#elif defined(__LITTLE_ENDIAN) - 0x00000000,0xff000000,0x00ff0000,0xffff0000, - 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, - 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, - 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -#else -#error FIXME: No endianness?? -#endif -}; -#if 0 -static const u32 expand_bits_16[4] BTDATA = { -#if defined(__BIG_ENDIAN) - 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -#elif defined(__LITTLE_ENDIAN) - 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -#else -#error FIXME: No endianness?? -#endif -}; -#endif -#if 0 -static void BTEXT -draw_byte_32(const unsigned char *font, u32 *base, u32 rb) -{ - u32 l, bits; - u32 fg = 0xFFFFFFFF; - u32 bg = 0x00000000; - - for (l = 0; l < 16; ++l) - { - bits = *font++; - base[0] = (-(bits >> 7) & fg) ^ bg; - base[1] = (-((bits >> 6) & 1) & fg) ^ bg; - base[2] = (-((bits >> 5) & 1) & fg) ^ bg; - base[3] = (-((bits >> 4) & 1) & fg) ^ bg; - base[4] = (-((bits >> 3) & 1) & fg) ^ bg; - base[5] = (-((bits >> 2) & 1) & fg) ^ bg; - base[6] = (-((bits >> 1) & 1) & fg) ^ bg; - base[7] = (-(bits & 1) & fg) ^ bg; - base = (u32 *) ((char *)base + rb); - } -} - -static void BTEXT -draw_byte_16(const unsigned char *font, u32 *base, u32 rb) -{ - u32 l, bits; - u32 fg = 0xFFFFFFFF; - u32 bg = 0x00000000; - u32 *eb = expand_bits_16; - - for (l = 0; l < 16; ++l) - { - bits = *font++; - base[0] = (eb[bits >> 6] & fg) ^ bg; - base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg; - base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg; - base[3] = (eb[bits & 3] & fg) ^ bg; - base = (u32 *) ((char *)base + rb); - } -} -#endif -static void BTEXT -draw_byte_8(const unsigned char *font, u32 *base, u32 rb) -{ - u32 l, bits; - u32 fg = 0x0F0F0F0F; - u32 bg = 0x00000000; - u32 *eb = expand_bits_8; - - for (l = 0; l < 16; ++l) - { - bits = *font++; - base[0] = (eb[bits >> 4] & fg) ^ bg; - base[1] = (eb[bits & 0xf] & fg) ^ bg; - base = (u32 *) ((char *)base + rb); - } -} - -static void btext_init(void) -{ -#if 0 -// for debug -#define frame_buffer 0xfc000000 -#else - uint32_t frame_buffer;// 0xfc000000 - - struct pci_device dev; - - #warning "pci_find_device_x no longer exists; use find_pci_device instead" - /* pci_find_device_x(0x1002, 0x4752, 0, &dev); */ - if(dev.vendor==0) return; // no fb - - frame_buffer = (uint32_t)dev.membase; -#endif - - btext_setup_display(640, 480, 8, 640,frame_buffer); - btext_clearscreen(); - map_boot_text(); -} -static void btext_putc(int c) -{ - btext_drawchar((unsigned char)c); -} - -struct console_driver btext_console __console_driver = { - .putchar = btext_putc, - .disabled = 1, -}; - -//come from linux/drivers/video/font-8x16.c -/**********************************************/ -/* */ -/* Font file generated by cpi2fnt */ -/* */ -/**********************************************/ - - -static const unsigned char vga_font[cmapsz] BTDATA = { -#if CHAR_256==1 - /* 0 0x00 '^@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 1 0x01 '^A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x81, /* 10000001 */ - 0xa5, /* 10100101 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0x81, /* 10000001 */ - 0x81, /* 10000001 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 2 0x02 '^B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xdb, /* 11011011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 3 0x03 '^C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 4 0x04 '^D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 5 0x05 '^E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0xe7, /* 11100111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 6 0x06 '^F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 7 0x07 '^G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 8 0x08 '^H' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xe7, /* 11100111 */ - 0xc3, /* 11000011 */ - 0xc3, /* 11000011 */ - 0xe7, /* 11100111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 9 0x09 '^I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x42, /* 01000010 */ - 0x42, /* 01000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 10 0x0a '^J' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xc3, /* 11000011 */ - 0x99, /* 10011001 */ - 0xbd, /* 10111101 */ - 0xbd, /* 10111101 */ - 0x99, /* 10011001 */ - 0xc3, /* 11000011 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 11 0x0b '^K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x1a, /* 00011010 */ - 0x32, /* 00110010 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 12 0x0c '^L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 13 0x0d '^M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x33, /* 00110011 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x70, /* 01110000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 14 0x0e '^N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x7f, /* 01111111 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x63, /* 01100011 */ - 0x67, /* 01100111 */ - 0xe7, /* 11100111 */ - 0xe6, /* 11100110 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 15 0x0f '^O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xdb, /* 11011011 */ - 0x3c, /* 00111100 */ - 0xe7, /* 11100111 */ - 0x3c, /* 00111100 */ - 0xdb, /* 11011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 16 0x10 '^P' */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0xf0, /* 11110000 */ - 0xf8, /* 11111000 */ - 0xfe, /* 11111110 */ - 0xf8, /* 11111000 */ - 0xf0, /* 11110000 */ - 0xe0, /* 11100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 17 0x11 '^Q' */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0e, /* 00001110 */ - 0x1e, /* 00011110 */ - 0x3e, /* 00111110 */ - 0xfe, /* 11111110 */ - 0x3e, /* 00111110 */ - 0x1e, /* 00011110 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 18 0x12 '^R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 19 0x13 '^S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 20 0x14 '^T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7f, /* 01111111 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7b, /* 01111011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 21 0x15 '^U' */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 22 0x16 '^V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 23 0x17 '^W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 24 0x18 '^X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 25 0x19 '^Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 26 0x1a '^Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 27 0x1b '^[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xfe, /* 11111110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 28 0x1c '^\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 29 0x1d '^]' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x28, /* 00101000 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x28, /* 00101000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 30 0x1e '^^' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 31 0x1f '^_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0x7c, /* 01111100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ -#endif - /* 32 0x20 ' ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 33 0x21 '!' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 34 0x22 '"' */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x24, /* 00100100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 35 0x23 '#' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 36 0x24 '$' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x86, /* 10000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 37 0x25 '%' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 38 0x26 '&' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 39 0x27 ''' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 40 0x28 '(' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 41 0x29 ')' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 42 0x2a '*' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0xff, /* 11111111 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 43 0x2b '+' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 44 0x2c ',' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 45 0x2d '-' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 46 0x2e '.' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 47 0x2f '/' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x02, /* 00000010 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x80, /* 10000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 48 0x30 '0' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 49 0x31 '1' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x38, /* 00111000 */ - 0x78, /* 01111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 50 0x32 '2' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 51 0x33 '3' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x3c, /* 00111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 52 0x34 '4' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x1c, /* 00011100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 53 0x35 '5' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 54 0x36 '6' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xfc, /* 11111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 55 0x37 '7' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 56 0x38 '8' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 57 0x39 '9' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 58 0x3a ':' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 59 0x3b ';' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 60 0x3c '<' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 61 0x3d '=' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 62 0x3e '>' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 63 0x3f '?' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 64 0x40 '@' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xde, /* 11011110 */ - 0xdc, /* 11011100 */ - 0xc0, /* 11000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 65 0x41 'A' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 66 0x42 'B' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 67 0x43 'C' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 68 0x44 'D' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 69 0x45 'E' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 70 0x46 'F' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 71 0x47 'G' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xde, /* 11011110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x66, /* 01100110 */ - 0x3a, /* 00111010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 72 0x48 'H' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 73 0x49 'I' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 74 0x4a 'J' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 75 0x4b 'K' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe6, /* 11100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 76 0x4c 'L' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 77 0x4d 'M' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xee, /* 11101110 */ - 0xfe, /* 11111110 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 78 0x4e 'N' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 79 0x4f 'O' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 80 0x50 'P' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 81 0x51 'Q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xde, /* 11011110 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 82 0x52 'R' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfc, /* 11111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 83 0x53 'S' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 84 0x54 'T' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x5a, /* 01011010 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 85 0x55 'U' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 86 0x56 'V' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 87 0x57 'W' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0xee, /* 11101110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 88 0x58 'X' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x7c, /* 01111100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x7c, /* 01111100 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 89 0x59 'Y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 90 0x5a 'Z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc2, /* 11000010 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 91 0x5b '[' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 92 0x5c '\' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x80, /* 10000000 */ - 0xc0, /* 11000000 */ - 0xe0, /* 11100000 */ - 0x70, /* 01110000 */ - 0x38, /* 00111000 */ - 0x1c, /* 00011100 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x02, /* 00000010 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 93 0x5d ']' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 94 0x5e '^' */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 95 0x5f '_' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 96 0x60 '`' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 97 0x61 'a' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 98 0x62 'b' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 99 0x63 'c' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 100 0x64 'd' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 101 0x65 'e' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 102 0x66 'f' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x36, /* 00110110 */ - 0x32, /* 00110010 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 103 0x67 'g' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0xcc, /* 11001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 104 0x68 'h' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x6c, /* 01101100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 105 0x69 'i' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 106 0x6a 'j' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - - /* 107 0x6b 'k' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xe0, /* 11100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x78, /* 01111000 */ - 0x78, /* 01111000 */ - 0x6c, /* 01101100 */ - 0x66, /* 01100110 */ - 0xe6, /* 11100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 108 0x6c 'l' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 109 0x6d 'm' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0xfe, /* 11111110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 110 0x6e 'n' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 111 0x6f 'o' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 112 0x70 'p' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - - /* 113 0x71 'q' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x7c, /* 01111100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x1e, /* 00011110 */ - 0x00, /* 00000000 */ - - /* 114 0x72 'r' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x66, /* 01100110 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 115 0x73 's' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x38, /* 00111000 */ - 0x0c, /* 00001100 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 116 0x74 't' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0xfc, /* 11111100 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x36, /* 00110110 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 117 0x75 'u' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 118 0x76 'v' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 119 0x77 'w' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xd6, /* 11010110 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 120 0x78 'x' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 121 0x79 'y' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - - /* 122 0x7a 'z' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 123 0x7b '{' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 124 0x7c '|' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 125 0x7d '}' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x70, /* 01110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x0e, /* 00001110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 126 0x7e '~' */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 127 0x7f '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ -#if CHAR_256256==1 - /* 128 0x80 '€' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0xc2, /* 11000010 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc2, /* 11000010 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 129 0x81 '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 130 0x82 '‚' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 131 0x83 'ƒ' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 132 0x84 '„' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 133 0x85 '…' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 134 0x86 '†' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 135 0x87 '‡' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 136 0x88 'ˆ' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 137 0x89 '‰' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 138 0x8a 'Š' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 139 0x8b '‹' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 140 0x8c 'Œ' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 141 0x8d '' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 142 0x8e 'Ž' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 143 0x8f '' */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 144 0x90 '' */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x66, /* 01100110 */ - 0x62, /* 01100010 */ - 0x68, /* 01101000 */ - 0x78, /* 01111000 */ - 0x68, /* 01101000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 145 0x91 '‘' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xec, /* 11101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x6e, /* 01101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 146 0x92 '’' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3e, /* 00111110 */ - 0x6c, /* 01101100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xfe, /* 11111110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xce, /* 11001110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 147 0x93 '“' */ - 0x00, /* 00000000 */ - 0x10, /* 00010000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 148 0x94 '”' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 149 0x95 '•' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 150 0x96 '–' */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 151 0x97 '—' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 152 0x98 '˜' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7e, /* 01111110 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x78, /* 01111000 */ - 0x00, /* 00000000 */ - - /* 153 0x99 '™' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 154 0x9a 'š' */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 155 0x9b '›' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 156 0x9c 'œ' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x64, /* 01100100 */ - 0x60, /* 01100000 */ - 0xf0, /* 11110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xe6, /* 11100110 */ - 0xfc, /* 11111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 157 0x9d '' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 158 0x9e 'ž' */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xf8, /* 11111000 */ - 0xc4, /* 11000100 */ - 0xcc, /* 11001100 */ - 0xde, /* 11011110 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 159 0x9f 'Ÿ' */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 160 0xa0 ' ' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0x0c, /* 00001100 */ - 0x7c, /* 01111100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 161 0xa1 '¡' */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 162 0xa2 '¢' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 163 0xa3 '£' */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x00, /* 00000000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 164 0xa4 '¤' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xdc, /* 11011100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 165 0xa5 '¥' */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0xc6, /* 11000110 */ - 0xe6, /* 11100110 */ - 0xf6, /* 11110110 */ - 0xfe, /* 11111110 */ - 0xde, /* 11011110 */ - 0xce, /* 11001110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 166 0xa6 '¦' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 167 0xa7 '§' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 168 0xa8 '¨' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x7c, /* 01111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 169 0xa9 '©' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 170 0xaa 'ª' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 171 0xab '«' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xdc, /* 11011100 */ - 0x86, /* 10000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x3e, /* 00111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 172 0xac '¬' */ - 0x00, /* 00000000 */ - 0x60, /* 01100000 */ - 0xe0, /* 11100000 */ - 0x62, /* 01100010 */ - 0x66, /* 01100110 */ - 0x6c, /* 01101100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x66, /* 01100110 */ - 0xce, /* 11001110 */ - 0x9a, /* 10011010 */ - 0x3f, /* 00111111 */ - 0x06, /* 00000110 */ - 0x06, /* 00000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 173 0xad '­' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 174 0xae '®' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 175 0xaf '¯' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xd8, /* 11011000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x6c, /* 01101100 */ - 0xd8, /* 11011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 176 0xb0 '°' */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - 0x11, /* 00010001 */ - 0x44, /* 01000100 */ - - /* 177 0xb1 '±' */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - 0x55, /* 01010101 */ - 0xaa, /* 10101010 */ - - /* 178 0xb2 '²' */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - 0xdd, /* 11011101 */ - 0x77, /* 01110111 */ - - /* 179 0xb3 '³' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 180 0xb4 '´' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 181 0xb5 'µ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 182 0xb6 '¶' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 183 0xb7 '·' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 184 0xb8 '¸' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 185 0xb9 '¹' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 186 0xba 'º' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 187 0xbb '»' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x06, /* 00000110 */ - 0xf6, /* 11110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 188 0xbc '¼' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf6, /* 11110110 */ - 0x06, /* 00000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 189 0xbd '½' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 190 0xbe '¾' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 191 0xbf '¿' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xf8, /* 11111000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 192 0xc0 'À' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 193 0xc1 'Á' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 194 0xc2 'Â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 195 0xc3 'Ã' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 196 0xc4 'Ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 197 0xc5 'Å' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 198 0xc6 'Æ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 199 0xc7 'Ç' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 200 0xc8 'È' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 201 0xc9 'É' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 202 0xca 'Ê' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 203 0xcb 'Ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 204 0xcc 'Ì' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x37, /* 00110111 */ - 0x30, /* 00110000 */ - 0x37, /* 00110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 205 0xcd 'Í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 206 0xce 'Î' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xf7, /* 11110111 */ - 0x00, /* 00000000 */ - 0xf7, /* 11110111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 207 0xcf 'Ï' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 208 0xd0 'Ð' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 209 0xd1 'Ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 210 0xd2 'Ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 211 0xd3 'Ó' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x3f, /* 00111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 212 0xd4 'Ô' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 213 0xd5 'Õ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 214 0xd6 'Ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x3f, /* 00111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 215 0xd7 '×' */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0xff, /* 11111111 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - - /* 216 0xd8 'Ø' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0xff, /* 11111111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 217 0xd9 'Ù' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xf8, /* 11111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 218 0xda 'Ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1f, /* 00011111 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 219 0xdb 'Û' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 220 0xdc 'Ü' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - - /* 221 0xdd 'Ý' */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - 0xf0, /* 11110000 */ - - /* 222 0xde 'Þ' */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - 0x0f, /* 00001111 */ - - /* 223 0xdf 'ß' */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0xff, /* 11111111 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 224 0xe0 'à' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xdc, /* 11011100 */ - 0x76, /* 01110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 225 0xe1 'á' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x78, /* 01111000 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xcc, /* 11001100 */ - 0xd8, /* 11011000 */ - 0xcc, /* 11001100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xcc, /* 11001100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 226 0xe2 'â' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 227 0xe3 'ã' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 228 0xe4 'ä' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 229 0xe5 'å' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 230 0xe6 'æ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - - /* 231 0xe7 'ç' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 232 0xe8 'è' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 233 0xe9 'é' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xfe, /* 11111110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 234 0xea 'ê' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0xee, /* 11101110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 235 0xeb 'ë' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1e, /* 00011110 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x3e, /* 00111110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x66, /* 01100110 */ - 0x3c, /* 00111100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 236 0xec 'ì' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 237 0xed 'í' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x03, /* 00000011 */ - 0x06, /* 00000110 */ - 0x7e, /* 01111110 */ - 0xdb, /* 11011011 */ - 0xdb, /* 11011011 */ - 0xf3, /* 11110011 */ - 0x7e, /* 01111110 */ - 0x60, /* 01100000 */ - 0xc0, /* 11000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 238 0xee 'î' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x1c, /* 00011100 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x7c, /* 01111100 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 239 0xef 'ï' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7c, /* 01111100 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0xc6, /* 11000110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 240 0xf0 'ð' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0xfe, /* 11111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 241 0xf1 'ñ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x7e, /* 01111110 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 242 0xf2 'ò' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x06, /* 00000110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 243 0xf3 'ó' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x30, /* 00110000 */ - 0x60, /* 01100000 */ - 0x30, /* 00110000 */ - 0x18, /* 00011000 */ - 0x0c, /* 00001100 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 244 0xf4 'ô' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x0e, /* 00001110 */ - 0x1b, /* 00011011 */ - 0x1b, /* 00011011 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - - /* 245 0xf5 'õ' */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0xd8, /* 11011000 */ - 0x70, /* 01110000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 246 0xf6 'ö' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 247 0xf7 '÷' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x76, /* 01110110 */ - 0xdc, /* 11011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 248 0xf8 'ø' */ - 0x00, /* 00000000 */ - 0x38, /* 00111000 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x38, /* 00111000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 249 0xf9 'ù' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 250 0xfa 'ú' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x18, /* 00011000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 251 0xfb 'û' */ - 0x00, /* 00000000 */ - 0x0f, /* 00001111 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0x0c, /* 00001100 */ - 0xec, /* 11101100 */ - 0x6c, /* 01101100 */ - 0x6c, /* 01101100 */ - 0x3c, /* 00111100 */ - 0x1c, /* 00011100 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 252 0xfc 'ü' */ - 0x00, /* 00000000 */ - 0x6c, /* 01101100 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x36, /* 00110110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 253 0xfd 'ý' */ - 0x00, /* 00000000 */ - 0x3c, /* 00111100 */ - 0x66, /* 01100110 */ - 0x0c, /* 00001100 */ - 0x18, /* 00011000 */ - 0x32, /* 00110010 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 254 0xfe 'þ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x7e, /* 01111110 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - - /* 255 0xff 'ÿ' */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ - 0x00, /* 00000000 */ -#endif -}; - -#endif diff --git a/src/include/btext.h b/src/include/btext.h deleted file mode 100644 index 1d3f9e59..00000000 --- a/src/include/btext.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file describes the structure passed from the BootX application - * (for MacOS) when it is used to boot Linux. - * - * Written by Benjamin Herrenschmidt. - * - * Move to LinuxBIOS by LYH yhlu@tyan.com - * - */ - - -#ifndef _BTEXT_H__ -#define _BTEXT_H__ - -#if 1 -#define u32 unsigned int -#define u16 unsigned short -#define u8 unsigned char -#endif - -/* Here are the boot informations that are passed to the bootstrap - * Note that the kernel arguments and the device tree are appended - * at the end of this structure. */ -typedef struct boot_infos -{ - - /* NEW (vers. 2) this holds the current _logical_ base addr of - the frame buffer (for use by early boot message) */ - u8* logicalDisplayBase; - - - /* Some infos about the current MacOS display */ - u32 dispDeviceRect[4]; /* left,top,right,bottom */ - u32 dispDeviceDepth; /* (8, 16 or 32) */ - u32 dispDeviceBase; /* base address (physical) */ - u32 dispDeviceRowBytes; /* rowbytes (in bytes) */ - u32 dispDeviceColorsOffset; /* Colormap (8 bits only) or 0 (*) */ - - - /* The framebuffer size (optional, currently 0) */ - u32 frameBufferSize; /* Represents a max size, can be 0. */ - - -} boot_infos_t; - -/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index is represented - * by 3 short words containing a 16 bits (unsigned) color component. - * Later versions may contain the gamma table for direct-color devices here. - */ -#define BOOTX_COLORTABLE_SIZE (256UL*3UL*2UL) - - -/* - * Definitions for using the procedures in btext.c. - * - * Benjamin Herrenschmidt - */ - -extern boot_infos_t disp_bi; -extern u32 boot_text_mapped; - -#endif /* _BTEXT_H */ From e024cd39a877ea1b37b9004dbd8f33448418cb36 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 17:25:08 +0100 Subject: [PATCH 125/221] [console] Allow usage to be defined independently for each console Add the concept of a "console usage", such as "standard output" or "debug messages". Allow usages to be associated with each console independently. For example, to send debugging output via the serial port, while preventing it from appearing on the local console: #define CONSOLE_SERIAL CONSOLE_USAGE_ALL #define CONSOLE_PCBIOS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_DEBUG ) If no usages are explicitly specified, then a default set of usages will be applied. For example: #define CONSOLE_SERIAL will have the same affect as #define CONSOLE_SERIAL CONSOLE_USAGE_ALL Signed-off-by: Michael Brown --- src/arch/i386/core/video_subr.c | 9 ++++ src/arch/i386/firmware/pcbios/bios_console.c | 8 +++ src/arch/i386/interface/vmware/vmconsole.c | 8 +++ src/core/console.c | 7 ++- src/core/debug.c | 54 ++++++++++++++------ src/core/serial_console.c | 8 +++ src/include/compiler.h | 16 ++---- src/include/ipxe/console.h | 51 +++++++++++++++++- src/interface/efi/efi_console.c | 8 +++ src/interface/linux/linux_console.c | 9 ++++ src/net/udp/syslog.c | 8 +++ 11 files changed, 155 insertions(+), 31 deletions(-) diff --git a/src/arch/i386/core/video_subr.c b/src/arch/i386/core/video_subr.c index 6885ad9a..7dd99e71 100644 --- a/src/arch/i386/core/video_subr.c +++ b/src/arch/i386/core/video_subr.c @@ -11,6 +11,14 @@ #include #include #include "vga.h" +#include + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_DIRECT_VGA ) && \ + CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) ) +#undef CONSOLE_DIRECT_VGA +#define CONSOLE_DIRECT_VGA CONSOLE_USAGE_ALL +#endif struct console_driver vga_console __console_driver; @@ -97,6 +105,7 @@ static void vga_putc(int byte) struct console_driver vga_console __console_driver = { .putchar = vga_putc, .disabled = 1, + .usage = CONSOLE_DIRECT_VGA, }; struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = { diff --git a/src/arch/i386/firmware/pcbios/bios_console.c b/src/arch/i386/firmware/pcbios/bios_console.c index e489971f..8a8795d7 100644 --- a/src/arch/i386/firmware/pcbios/bios_console.c +++ b/src/arch/i386/firmware/pcbios/bios_console.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #define ATTR_BOLD 0x08 @@ -48,6 +49,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ATTR_DEFAULT ATTR_FCOL_WHITE +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) ) +#undef CONSOLE_PCBIOS +#define CONSOLE_PCBIOS CONSOLE_USAGE_ALL +#endif + /** Current character attribute */ static unsigned int bios_attr = ATTR_DEFAULT; @@ -319,4 +326,5 @@ struct console_driver bios_console __console_driver = { .putchar = bios_putchar, .getchar = bios_getchar, .iskey = bios_iskey, + .usage = CONSOLE_PCBIOS, }; diff --git a/src/arch/i386/interface/vmware/vmconsole.c b/src/arch/i386/interface/vmware/vmconsole.c index 930c088d..3096e5b5 100644 --- a/src/arch/i386/interface/vmware/vmconsole.c +++ b/src/arch/i386/interface/vmware/vmconsole.c @@ -29,10 +29,17 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include /** VMware logfile console buffer size */ #define VMCONSOLE_BUFSIZE 128 +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_VMWARE ) && CONSOLE_EXPLICIT ( CONSOLE_VMWARE ) ) +#undef CONSOLE_VMWARE +#define CONSOLE_VMWARE CONSOLE_USAGE_ALL +#endif + /** VMware logfile console GuestRPC channel */ static int vmconsole_channel; @@ -87,6 +94,7 @@ static void vmconsole_putchar ( int character ) { struct console_driver vmconsole __console_driver = { .putchar = vmconsole_putchar, .disabled = 1, + .usage = CONSOLE_VMWARE, }; /** diff --git a/src/core/console.c b/src/core/console.c index f27edf46..a26a3ef6 100644 --- a/src/core/console.c +++ b/src/core/console.c @@ -7,6 +7,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); +/** Current console usage */ +int console_usage = CONSOLE_USAGE_STDOUT; + /** * Write a single character to each console device. * @@ -26,7 +29,9 @@ void putchar ( int character ) { putchar ( '\r' ); for_each_table_entry ( console, CONSOLES ) { - if ( ( ! console->disabled ) && console->putchar ) + if ( ( ! console->disabled ) && + ( console_usage & console->usage ) && + console->putchar ) console->putchar ( character ); } } diff --git a/src/core/debug.c b/src/core/debug.c index 8fca8d90..fc90c64a 100644 --- a/src/core/debug.c +++ b/src/core/debug.c @@ -21,16 +21,38 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include +#include + +/** + * Print debug message + * + * @v fmt Format string + * @v ... Arguments + */ +void dbg_printf ( const char *fmt, ... ) { + int saved_usage; + va_list args; + + /* Mark console as in use for debugging messages */ + saved_usage = console_set_usage ( CONSOLE_USAGE_DEBUG ); + + /* Print message */ + va_start ( args, fmt ); + vprintf ( fmt, args ); + va_end ( args ); + + /* Restore console usage */ + console_set_usage ( saved_usage ); +} /** * Pause until a key is pressed * */ void dbg_pause ( void ) { - printf ( "\nPress a key..." ); + dbg_printf ( "\nPress a key..." ); getchar(); - printf ( "\r \r" ); + dbg_printf ( "\r \r" ); } /** @@ -38,9 +60,9 @@ void dbg_pause ( void ) { * */ void dbg_more ( void ) { - printf ( "---more---" ); + dbg_printf ( "---more---" ); getchar(); - printf ( "\r \r" ); + dbg_printf ( "\r \r" ); } /** @@ -57,27 +79,27 @@ static void dbg_hex_dump_da_row ( unsigned long dispaddr, const void *data, unsigned int i; uint8_t byte; - printf ( "%08lx :", ( dispaddr + offset ) ); + dbg_printf ( "%08lx :", ( dispaddr + offset ) ); for ( i = offset ; i < ( offset + 16 ) ; i++ ) { if ( i >= len ) { - printf ( " " ); + dbg_printf ( " " ); continue; } - printf ( "%c%02x", - ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] ); + dbg_printf ( "%c%02x", + ( ( ( i % 16 ) == 8 ) ? '-' : ' ' ), bytes[i] ); } - printf ( " : " ); + dbg_printf ( " : " ); for ( i = offset ; i < ( offset + 16 ) ; i++ ) { if ( i >= len ) { - printf ( " " ); + dbg_printf ( " " ); continue; } byte = bytes[i]; if ( ( byte < 0x20 ) || ( byte >= 0x7f ) ) byte = '.'; - printf ( "%c", byte ); + dbg_printf ( "%c", byte ); } - printf ( "\n" ); + dbg_printf ( "\n" ); } /** @@ -157,8 +179,8 @@ static int dbg_autocolour ( unsigned long stream ) { * @v stream Message stream ID */ void dbg_autocolourise ( unsigned long stream ) { - printf ( "\033[%dm", - ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) ); + dbg_printf ( "\033[%dm", + ( stream ? ( 31 + dbg_autocolour ( stream ) ) : 0 ) ); } /** @@ -166,5 +188,5 @@ void dbg_autocolourise ( unsigned long stream ) { * */ void dbg_decolourise ( void ) { - printf ( "\033[0m" ); + dbg_printf ( "\033[0m" ); } diff --git a/src/core/serial_console.c b/src/core/serial_console.c index b05a06b1..52bd5376 100644 --- a/src/core/serial_console.c +++ b/src/core/serial_console.c @@ -1,6 +1,7 @@ #include #include #include +#include /** @file * @@ -8,6 +9,12 @@ * */ +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) ) +#undef CONSOLE_SERIAL +#define CONSOLE_SERIAL CONSOLE_USAGE_ALL +#endif + struct console_driver serial_console __console_driver; static void serial_console_init ( void ) { @@ -21,6 +28,7 @@ struct console_driver serial_console __console_driver = { .getchar = serial_getc, .iskey = serial_ischar, .disabled = 1, + .usage = CONSOLE_SERIAL, }; /** diff --git a/src/include/compiler.h b/src/include/compiler.h index 9a751d3b..ed9af237 100644 --- a/src/include/compiler.h +++ b/src/include/compiler.h @@ -260,19 +260,9 @@ REQUEST_EXPANDED ( CONFIG_SYMBOL ); #ifndef ASSEMBLY -/** printf() for debugging - * - * This function exists so that the DBG() macros can expand to - * printf() calls without dragging the printf() prototype into scope. - * - * As far as the compiler is concerned, dbg_printf() and printf() are - * completely unrelated calls; it's only at the assembly stage that - * references to the dbg_printf symbol are collapsed into references - * to the printf symbol. - */ -extern int __attribute__ (( format ( printf, 1, 2 ) )) -dbg_printf ( const char *fmt, ... ) asm ( "printf" ); - +/** printf() for debugging */ +extern void __attribute__ (( format ( printf, 1, 2 ) )) +dbg_printf ( const char *fmt, ... ); extern void dbg_autocolourise ( unsigned long id ); extern void dbg_decolourise ( void ); extern void dbg_hex_dump_da ( unsigned long dispaddr, diff --git a/src/include/ipxe/console.h b/src/include/ipxe/console.h index 5188f985..f70dd714 100644 --- a/src/include/ipxe/console.h +++ b/src/include/ipxe/console.h @@ -75,6 +75,13 @@ struct console_driver { * */ int ( *iskey ) ( void ); + + /** Console usage bitmask + * + * This is the bitwise OR of zero or more @c CONSOLE_USAGE_XXX + * values. + */ + int usage; }; /** Console driver table */ @@ -99,7 +106,49 @@ struct console_driver { */ #define __console_driver __table_entry ( CONSOLES, 01 ) -/* Function prototypes */ +/** + * @defgroup consoleusage Console usages + * @{ + */ + +/** Standard output */ +#define CONSOLE_USAGE_STDOUT 0x0001 + +/** Debug messages */ +#define CONSOLE_USAGE_DEBUG 0x0002 + +/** All console usages */ +#define CONSOLE_USAGE_ALL ( CONSOLE_USAGE_STDOUT | CONSOLE_USAGE_DEBUG ) + +/** @} */ + +/** + * Test to see if console has an explicit usage + * + * @v console Console definition (e.g. CONSOLE_PCBIOS) + * @ret explicit Console has an explicit usage + * + * This relies upon the trick that the expression ( 2 * N + 1 ) will + * be valid even if N is defined to be empty, since it will then + * evaluate to give ( 2 * + 1 ) == ( 2 * +1 ) == 2. + */ +#define CONSOLE_EXPLICIT( console ) ( ( 2 * console + 1 ) != 2 ) + +extern int console_usage; + +/** + * Set console usage + * + * @v usage New console usage + * @ret old_usage Previous console usage + */ +static inline __attribute__ (( always_inline )) int +console_set_usage ( int usage ) { + int old_usage = console_usage; + + console_usage = usage; + return old_usage; +} extern int iskey ( void ); extern int getkey ( unsigned long timeout ); diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 1303a427..54b0c080 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #define ATTR_BOLD 0x08 @@ -48,6 +49,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ATTR_DEFAULT ATTR_FCOL_WHITE +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_EFI ) && CONSOLE_EXPLICIT ( CONSOLE_EFI ) ) +#undef CONSOLE_EFI +#define CONSOLE_EFI CONSOLE_USAGE_ALL +#endif + /** Current character attribute */ static unsigned int efi_attr = ATTR_DEFAULT; @@ -273,4 +280,5 @@ struct console_driver efi_console __console_driver = { .putchar = efi_putchar, .getchar = efi_getchar, .iskey = efi_iskey, + .usage = CONSOLE_EFI, }; diff --git a/src/interface/linux/linux_console.c b/src/interface/linux/linux_console.c index aeb7c661..c79e5263 100644 --- a/src/interface/linux/linux_console.c +++ b/src/interface/linux/linux_console.c @@ -33,6 +33,14 @@ FILE_LICENCE(GPL2_OR_LATER); #include #include +#include + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_LINUX ) && CONSOLE_EXPLICIT ( CONSOLE_LINUX ) ) +#undef CONSOLE_LINUX +#define CONSOLE_LINUX CONSOLE_USAGE_ALL +#endif + static void linux_console_putchar(int c) { /* write to stdout */ @@ -79,6 +87,7 @@ struct console_driver linux_console __console_driver = { .putchar = linux_console_putchar, .getchar = linux_console_getchar, .iskey = linux_console_iskey, + .usage = CONSOLE_LINUX, }; static int linux_tcgetattr(int fd, struct termios *termios_p) diff --git a/src/net/udp/syslog.c b/src/net/udp/syslog.c index 5a8a865a..8788e1c4 100644 --- a/src/net/udp/syslog.c +++ b/src/net/udp/syslog.c @@ -34,6 +34,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_SYSLOG ) && CONSOLE_EXPLICIT ( CONSOLE_SYSLOG ) ) +#undef CONSOLE_SYSLOG +#define CONSOLE_SYSLOG CONSOLE_USAGE_ALL +#endif /** The syslog server */ static struct sockaddr_tcpip logserver = { @@ -106,6 +113,7 @@ static void syslog_putchar ( int character ) { struct console_driver syslog_console __console_driver = { .putchar = syslog_putchar, .disabled = 1, + .usage = CONSOLE_SYSLOG, }; /****************************************************************************** From 64d17dbd509d15ddf41bfc5d5b88d53b5af98155 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 19:02:30 +0100 Subject: [PATCH 126/221] [console] Exclude text-based UI output from logfile-based consoles The output from text-based user interfaces such as the "config" command is not generally meaningful for logfile-based consoles such as syslog and vmconsole. Signed-off-by: Michael Brown --- src/arch/i386/interface/vmware/vmconsole.c | 2 +- src/hci/mucurses/ansi_screen.c | 16 ++++++++++++++-- src/include/ipxe/console.h | 6 +++++- src/net/udp/syslog.c | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/arch/i386/interface/vmware/vmconsole.c b/src/arch/i386/interface/vmware/vmconsole.c index 3096e5b5..096b1af1 100644 --- a/src/arch/i386/interface/vmware/vmconsole.c +++ b/src/arch/i386/interface/vmware/vmconsole.c @@ -37,7 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_VMWARE ) && CONSOLE_EXPLICIT ( CONSOLE_VMWARE ) ) #undef CONSOLE_VMWARE -#define CONSOLE_VMWARE CONSOLE_USAGE_ALL +#define CONSOLE_VMWARE ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI ) #endif /** VMware logfile console GuestRPC channel */ diff --git a/src/hci/mucurses/ansi_screen.c b/src/hci/mucurses/ansi_screen.c index cc342f7c..d952e5f2 100644 --- a/src/hci/mucurses/ansi_screen.c +++ b/src/hci/mucurses/ansi_screen.c @@ -12,6 +12,8 @@ static void ansiscr_putc(struct _curses_screen *scr, chtype c) __nonnull; unsigned short _COLS = 80; unsigned short _LINES = 24; +static unsigned int saved_usage; + static void ansiscr_reset ( struct _curses_screen *scr ) { /* Reset terminal attributes and clear screen */ scr->attrs = 0; @@ -20,6 +22,16 @@ static void ansiscr_reset ( struct _curses_screen *scr ) { printf ( "\033[0m" ); } +static void ansiscr_init ( struct _curses_screen *scr ) { + saved_usage = console_set_usage ( CONSOLE_USAGE_TUI ); + ansiscr_reset ( scr ); +} + +static void ansiscr_exit ( struct _curses_screen *scr ) { + ansiscr_reset ( scr ); + console_set_usage ( saved_usage ); +} + static void ansiscr_movetoyx ( struct _curses_screen *scr, unsigned int y, unsigned int x ) { if ( ( x != scr->curs_x ) || ( y != scr->curs_y ) ) { @@ -65,8 +77,8 @@ static bool ansiscr_peek ( struct _curses_screen *scr __unused ) { } SCREEN _ansi_screen = { - .init = ansiscr_reset, - .exit = ansiscr_reset, + .init = ansiscr_init, + .exit = ansiscr_exit, .movetoyx = ansiscr_movetoyx, .putc = ansiscr_putc, .getc = ansiscr_getc, diff --git a/src/include/ipxe/console.h b/src/include/ipxe/console.h index f70dd714..5ff93884 100644 --- a/src/include/ipxe/console.h +++ b/src/include/ipxe/console.h @@ -117,8 +117,12 @@ struct console_driver { /** Debug messages */ #define CONSOLE_USAGE_DEBUG 0x0002 +/** Text-based user interface */ +#define CONSOLE_USAGE_TUI 0x0004 + /** All console usages */ -#define CONSOLE_USAGE_ALL ( CONSOLE_USAGE_STDOUT | CONSOLE_USAGE_DEBUG ) +#define CONSOLE_USAGE_ALL \ + ( CONSOLE_USAGE_STDOUT | CONSOLE_USAGE_DEBUG | CONSOLE_USAGE_TUI ) /** @} */ diff --git a/src/net/udp/syslog.c b/src/net/udp/syslog.c index 8788e1c4..abf51359 100644 --- a/src/net/udp/syslog.c +++ b/src/net/udp/syslog.c @@ -39,7 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_SYSLOG ) && CONSOLE_EXPLICIT ( CONSOLE_SYSLOG ) ) #undef CONSOLE_SYSLOG -#define CONSOLE_SYSLOG CONSOLE_USAGE_ALL +#define CONSOLE_SYSLOG ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI ) #endif /** The syslog server */ From 24b7296319666709ac49bedb47df18d0bc37704e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 19:50:50 +0100 Subject: [PATCH 127/221] [console] Add "log message" console usage and an internal syslog() call Provide an internal syslog() function (unrelated to the syslog console) which can be used to create log messages with specified priorities. The build-time constant LOG_LEVEL can be used to select the minimum required priority for log messages. Any messages that do not have a sufficient priority will be ignored (and will be optimised away at compile-time). The default LOG_LEVEL is LOG_NONE. Signed-off-by: Michael Brown --- src/config/console.h | 2 + src/core/log.c | 62 ++++++++++++++++++++++++++++ src/include/ipxe/console.h | 7 +++- src/include/ipxe/syslog.h | 4 +- src/include/syslog.h | 84 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 src/core/log.c create mode 100644 src/include/syslog.h diff --git a/src/config/console.h b/src/config/console.h index 0692c2f5..e7a190aa 100644 --- a/src/config/console.h +++ b/src/config/console.h @@ -23,6 +23,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define KEYBOARD_MAP us +#define LOG_LEVEL LOG_NONE + #include #endif /* CONFIG_CONSOLE_H */ diff --git a/src/core/log.c b/src/core/log.c new file mode 100644 index 00000000..c0c3656c --- /dev/null +++ b/src/core/log.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * System logger + * + */ + +#include +#include +#include + +/** + * Write message to system log + * + * @v fmt Format string + * @v args Arguments + */ +void log_vprintf ( const char *fmt, va_list args ) { + int saved_usage; + + /* Mark console as in use for log messages */ + saved_usage = console_set_usage ( CONSOLE_USAGE_LOG ); + + /* Print message */ + vprintf ( fmt, args ); + + /* Restore console usage */ + console_set_usage ( saved_usage ); +} + +/** + * Write message to system log + * + * @v fmt Format string + * @v ... Arguments + */ +void log_printf ( const char *fmt, ... ) { + va_list args; + + va_start ( args, fmt ); + log_vprintf ( fmt, args ); + va_end ( args ); +} diff --git a/src/include/ipxe/console.h b/src/include/ipxe/console.h index 5ff93884..e2bf4be9 100644 --- a/src/include/ipxe/console.h +++ b/src/include/ipxe/console.h @@ -120,9 +120,12 @@ struct console_driver { /** Text-based user interface */ #define CONSOLE_USAGE_TUI 0x0004 +/** Log messages */ +#define CONSOLE_USAGE_LOG 0x0008 + /** All console usages */ -#define CONSOLE_USAGE_ALL \ - ( CONSOLE_USAGE_STDOUT | CONSOLE_USAGE_DEBUG | CONSOLE_USAGE_TUI ) +#define CONSOLE_USAGE_ALL ( CONSOLE_USAGE_STDOUT | CONSOLE_USAGE_DEBUG | \ + CONSOLE_USAGE_TUI | CONSOLE_USAGE_LOG ) /** @} */ diff --git a/src/include/ipxe/syslog.h b/src/include/ipxe/syslog.h index 25edc6b0..256ac761 100644 --- a/src/include/ipxe/syslog.h +++ b/src/include/ipxe/syslog.h @@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include + /** Syslog server port */ #define SYSLOG_PORT 514 @@ -28,7 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * * This is a policy decision */ -#define SYSLOG_SEVERITY 6 /* informational */ +#define SYSLOG_SEVERITY LOG_INFO /** Syslog priority */ #define SYSLOG_PRIORITY( facility, severity ) ( 8 * (facility) + (severity) ) diff --git a/src/include/syslog.h b/src/include/syslog.h new file mode 100644 index 00000000..cc7b19fd --- /dev/null +++ b/src/include/syslog.h @@ -0,0 +1,84 @@ +#ifndef _SYSLOG_H +#define _SYSLOG_H + +/** @file + * + * System logger + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** + * @defgroup syslogpri Syslog priorities + * + * These values are chosen to match those used in the syslog network + * protocol (RFC 5424). + * + * @{ + */ + +/** Emergency: system is unusable */ +#define LOG_EMERG 0 + +/** Alert: action must be taken immediately */ +#define LOG_ALERT 1 + +/** Critical: critical conditions */ +#define LOG_CRIT 2 + +/** Error: error conditions */ +#define LOG_ERR 3 + +/** Warning: warning conditions */ +#define LOG_WARNING 4 + +/** Notice: normal but significant conditions */ +#define LOG_NOTICE 5 + +/** Informational: informational messages */ +#define LOG_INFO 6 + +/** Debug: debug-level messages */ +#define LOG_DEBUG 7 + +/** @} */ + +/** Do not log any messages */ +#define LOG_NONE -1 + +extern void log_vprintf ( const char *fmt, va_list args ); + +extern void __attribute__ (( format ( printf, 1, 2 ) )) +log_printf ( const char *fmt, ... ); + +/** + * Write message to system log + * + * @v priority Message priority + * @v fmt Format string + * @v ... Arguments + */ +#define vsyslog( priority, fmt, args ) do { \ + if ( (priority) <= LOG_LEVEL ) { \ + log_vprintf ( fmt, (args) ); \ + } \ + } while ( 0 ) + +/** + * Write message to system log + * + * @v priority Message priority + * @v fmt Format string + * @v ... Arguments + */ +#define syslog( priority, fmt, ... ) do { \ + if ( (priority) <= LOG_LEVEL ) { \ + log_printf ( fmt, ##__VA_ARGS__ ); \ + } \ + } while ( 0 ) + +#endif /* _SYSLOG_H */ From c2875ae32952690e11fc6f654fa48f4f2c9f0567 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 21:03:59 +0100 Subject: [PATCH 128/221] [console] Do not share ANSI escape context between lineconsole users An ANSI escape sequence context cannot be shared between multiple users. Make the ANSI escape sequence context part of the line console definition and provide individual contexts for each user. Signed-off-by: Michael Brown --- src/arch/i386/interface/vmware/vmconsole.c | 8 ++++++++ src/core/lineconsole.c | 12 +----------- src/include/ipxe/lineconsole.h | 3 +++ src/net/udp/syslog.c | 8 ++++++++ 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/arch/i386/interface/vmware/vmconsole.c b/src/arch/i386/interface/vmware/vmconsole.c index 096b1af1..7f02c50e 100644 --- a/src/arch/i386/interface/vmware/vmconsole.c +++ b/src/arch/i386/interface/vmware/vmconsole.c @@ -51,10 +51,18 @@ static struct { .prefix = "log ", }; +/** VMware logfile console ANSI escape sequence handlers */ +static struct ansiesc_handler vmconsole_handlers[] = { + { 0, NULL } +}; + /** VMware logfile line console */ static struct line_console vmconsole_line = { .buffer = vmconsole_buffer.message, .len = sizeof ( vmconsole_buffer.message ), + .ctx = { + .handlers = vmconsole_handlers, + }, }; /** VMware logfile console recursion marker */ diff --git a/src/core/lineconsole.c b/src/core/lineconsole.c index c43a2875..71bc1f8b 100644 --- a/src/core/lineconsole.c +++ b/src/core/lineconsole.c @@ -29,16 +29,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include -/** Line-based console ANSI escape sequence handlers */ -static struct ansiesc_handler line_ansiesc_handlers[] = { - { 0, NULL } -}; - -/** Line-based console ANSI escape sequence context */ -static struct ansiesc_context line_ansiesc_ctx = { - .handlers = line_ansiesc_handlers, -}; - /** * Print a character to a line-based console * @@ -48,7 +38,7 @@ static struct ansiesc_context line_ansiesc_ctx = { size_t line_putchar ( struct line_console *line, int character ) { /* Strip ANSI escape sequences */ - character = ansiesc_process ( &line_ansiesc_ctx, character ); + character = ansiesc_process ( &line->ctx, character ); if ( character < 0 ) return 0; diff --git a/src/include/ipxe/lineconsole.h b/src/include/ipxe/lineconsole.h index d53a0e9f..925c0acc 100644 --- a/src/include/ipxe/lineconsole.h +++ b/src/include/ipxe/lineconsole.h @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include /** A line-based console */ struct line_console { @@ -26,6 +27,8 @@ struct line_console { * a potential terminating NUL. */ size_t len; + /** ANSI escape sequence context */ + struct ansiesc_context ctx; }; extern size_t line_putchar ( struct line_console *line, int character ); diff --git a/src/net/udp/syslog.c b/src/net/udp/syslog.c index abf51359..caa0d0b2 100644 --- a/src/net/udp/syslog.c +++ b/src/net/udp/syslog.c @@ -68,10 +68,18 @@ static struct interface syslogger = INTF_INIT ( syslogger_desc ); /** Syslog line buffer */ static char syslog_buffer[SYSLOG_BUFSIZE]; +/** Syslog ANSI escape sequence handlers */ +static struct ansiesc_handler syslog_handlers[] = { + { 0, NULL } +}; + /** Syslog line console */ static struct line_console syslog_line = { .buffer = syslog_buffer, .len = sizeof ( syslog_buffer ), + .ctx = { + .handlers = syslog_handlers, + }, }; /** Syslog recursion marker */ From 3ff7927d2fd15dd0a524f27d714dff667511718a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 20:23:30 +0100 Subject: [PATCH 129/221] [syslog] Pass internal syslog() priority through to syslog console Use a private ANSI escape sequence to convey the priority of an internal syslog() message through to the syslog server. Signed-off-by: Michael Brown --- src/include/ipxe/ansiesc.h | 7 +++++++ src/include/ipxe/syslog.h | 8 ++++---- src/include/syslog.h | 29 +++++++++++++++++++++-------- src/net/udp/syslog.c | 23 +++++++++++++++++++++-- 4 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/include/ipxe/ansiesc.h b/src/include/ipxe/ansiesc.h index 35438e43..c00af258 100644 --- a/src/include/ipxe/ansiesc.h +++ b/src/include/ipxe/ansiesc.h @@ -113,6 +113,13 @@ struct ansiesc_context { /** Select graphic rendition */ #define ANSIESC_SGR 'm' +/** Explicit log message priority + * + * This is an iPXE private sequence identifier. (The range 'p' to '~' + * is reserved for private sequences.) + */ +#define ANSIESC_LOG_PRIORITY 'p' + /** @} */ extern int ansiesc_process ( struct ansiesc_context *ctx, int c ); diff --git a/src/include/ipxe/syslog.h b/src/include/ipxe/syslog.h index 256ac761..035ca670 100644 --- a/src/include/ipxe/syslog.h +++ b/src/include/ipxe/syslog.h @@ -20,17 +20,17 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #define SYSLOG_BUFSIZE 128 -/** Syslog facility +/** Syslog default facility * * This is a policy decision */ -#define SYSLOG_FACILITY 0 /* kernel */ +#define SYSLOG_DEFAULT_FACILITY 0 /* kernel */ -/** Syslog severity +/** Syslog default severity * * This is a policy decision */ -#define SYSLOG_SEVERITY LOG_INFO +#define SYSLOG_DEFAULT_SEVERITY LOG_INFO /** Syslog priority */ #define SYSLOG_PRIORITY( facility, severity ) ( 8 * (facility) + (severity) ) diff --git a/src/include/syslog.h b/src/include/syslog.h index cc7b19fd..3dfc11b9 100644 --- a/src/include/syslog.h +++ b/src/include/syslog.h @@ -10,6 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include /** @@ -55,6 +56,16 @@ extern void log_vprintf ( const char *fmt, va_list args ); extern void __attribute__ (( format ( printf, 1, 2 ) )) log_printf ( const char *fmt, ... ); +/** ANSI private escape sequence to set syslog priority + * + * @v priority Priority + */ +#define SYSLOG_SET_PRIORITY( priority ) \ + "\033[" #priority "p" + +/** ANSI private escape sequence to clear syslog priority */ +#define SYSLOG_CLEAR_PRIORITY "\033[p" + /** * Write message to system log * @@ -62,10 +73,11 @@ log_printf ( const char *fmt, ... ); * @v fmt Format string * @v ... Arguments */ -#define vsyslog( priority, fmt, args ) do { \ - if ( (priority) <= LOG_LEVEL ) { \ - log_vprintf ( fmt, (args) ); \ - } \ +#define vsyslog( priority, fmt, args ) do { \ + if ( (priority) <= LOG_LEVEL ) { \ + log_vprintf ( SYSLOG_SET_PRIORITY ( priority ) fmt \ + SYSLOG_CLEAR_PRIORITY, (args) ); \ + } \ } while ( 0 ) /** @@ -75,10 +87,11 @@ log_printf ( const char *fmt, ... ); * @v fmt Format string * @v ... Arguments */ -#define syslog( priority, fmt, ... ) do { \ - if ( (priority) <= LOG_LEVEL ) { \ - log_printf ( fmt, ##__VA_ARGS__ ); \ - } \ +#define syslog( priority, fmt, ... ) do { \ + if ( (priority) <= LOG_LEVEL ) { \ + log_printf ( SYSLOG_SET_PRIORITY ( priority ) fmt \ + SYSLOG_CLEAR_PRIORITY, ##__VA_ARGS__ ); \ + } \ } while ( 0 ) #endif /* _SYSLOG_H */ diff --git a/src/net/udp/syslog.c b/src/net/udp/syslog.c index caa0d0b2..4a265314 100644 --- a/src/net/udp/syslog.c +++ b/src/net/udp/syslog.c @@ -68,8 +68,27 @@ static struct interface syslogger = INTF_INIT ( syslogger_desc ); /** Syslog line buffer */ static char syslog_buffer[SYSLOG_BUFSIZE]; +/** Syslog severity */ +static unsigned int syslog_severity = SYSLOG_DEFAULT_SEVERITY; + +/** + * Handle ANSI set syslog priority (private sequence) + * + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void syslog_handle_priority ( unsigned int count __unused, + int params[] ) { + if ( params[0] >= 0 ) { + syslog_severity = params[0]; + } else { + syslog_severity = SYSLOG_DEFAULT_SEVERITY; + } +} + /** Syslog ANSI escape sequence handlers */ static struct ansiesc_handler syslog_handlers[] = { + { ANSIESC_LOG_PRIORITY, syslog_handle_priority }, { 0, NULL } }; @@ -106,8 +125,8 @@ static void syslog_putchar ( int character ) { /* Send log message */ if ( ( rc = xfer_printf ( &syslogger, "<%d>ipxe: %s", - SYSLOG_PRIORITY ( SYSLOG_FACILITY, - SYSLOG_SEVERITY ), + SYSLOG_PRIORITY ( SYSLOG_DEFAULT_FACILITY, + syslog_severity ), syslog_buffer ) ) != 0 ) { DBG ( "SYSLOG could not send log message: %s\n", strerror ( rc ) ); From 5a91f5646aac3456d5be40319129dac5c5f877f0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 22:47:50 +0100 Subject: [PATCH 130/221] [downloader] Log final status of all downloads Signed-off-by: Michael Brown --- src/core/downloader.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/core/downloader.c b/src/core/downloader.c index 4dc0aa02..612a6633 100644 --- a/src/core/downloader.c +++ b/src/core/downloader.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -73,6 +74,15 @@ static void downloader_free ( struct refcnt *refcnt ) { */ static void downloader_finished ( struct downloader *downloader, int rc ) { + /* Log download status */ + if ( rc == 0 ) { + syslog ( LOG_NOTICE, "Downloaded \"%s\"\n", + downloader->image->name ); + } else { + syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n", + downloader->image->name, strerror ( rc ) ); + } + /* Shut down interfaces */ intf_shutdown ( &downloader->xfer, rc ); intf_shutdown ( &downloader->job, rc ); From 2d11a46b716f1d7e3391c82ea7feea39983f81cb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 23:24:27 +0100 Subject: [PATCH 131/221] [image] Log results of image signature checks Signed-off-by: Michael Brown --- src/usr/imgtrust.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index 5ea20265..59660782 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -72,10 +73,18 @@ int imgverify ( struct image *image, struct image *signature, /* Mark image as trusted */ image_trust ( image ); + syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name ); + + /* Free internal copy of signature */ + free ( data ); + + return 0; err_verify: err_parse: free ( data ); err_alloc: + syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n", + image->name, strerror ( rc ) ); return rc; } From 0f0a94f2facd1da6ccde09fb213eb0f35cf02654 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Mar 2012 23:34:49 +0100 Subject: [PATCH 132/221] [crypto] Disambiguate all CMS errors Signed-off-by: Michael Brown --- src/crypto/cms.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 1e253afa..12f17810 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -52,6 +52,27 @@ FILE_LICENCE ( GPL2_OR_LATER ); __einfo_error ( EINFO_EACCES_WRONG_NAME ) #define EINFO_EACCES_WRONG_NAME \ __einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" ) +#define EINVAL_DIGEST \ + __einfo_error ( EINFO_EINVAL_DIGEST ) +#define EINFO_EINVAL_DIGEST \ + __einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" ) +#define EINVAL_PUBKEY \ + __einfo_error ( EINFO_EINVAL_PUBKEY ) +#define EINFO_EINVAL_PUBKEY \ + __einfo_uniqify ( EINFO_EINVAL, 0x02, "Not a public-key algorithm" ) +#define ENOTSUP_SIGNEDDATA \ + __einfo_error ( EINFO_ENOTSUP_SIGNEDDATA ) +#define EINFO_ENOTSUP_SIGNEDDATA \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Not a digital signature" ) +#define ENOTSUP_DIGEST \ + __einfo_error ( EINFO_ENOTSUP_DIGEST ) +#define EINFO_ENOTSUP_DIGEST \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported digest algorithm" ) +#define ENOTSUP_PUBKEY \ + __einfo_error ( EINFO_ENOTSUP_PUBKEY ) +#define EINFO_ENOTSUP_PUBKEY \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x03, \ + "Unsupported public-key algorithm" ) /** "pkcs7-signedData" object identifier */ static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA }; @@ -79,7 +100,7 @@ static int cms_parse_content_type ( struct cms_signature *sig, if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) { DBGC ( sig, "CMS %p does not contain signedData:\n", sig ); DBGC_HDA ( sig, 0, raw->data, raw->len ); - return -ENOTSUP; + return -ENOTSUP_SIGNEDDATA; } DBGC ( sig, "CMS %p contains signedData\n", sig ); @@ -149,14 +170,14 @@ static int cms_parse_digest_algorithm ( struct cms_signature *sig, DBGC ( sig, "CMS %p/%p could not identify digest algorithm:\n", sig, info ); DBGC_HDA ( sig, 0, raw->data, raw->len ); - return -ENOTSUP; + return -ENOTSUP_DIGEST; } /* Check algorithm is a digest algorithm */ if ( ! algorithm->digest ) { DBGC ( sig, "CMS %p/%p algorithm %s is not a digest " "algorithm\n", sig, info, algorithm->name ); - return -EINVAL; + return -EINVAL_DIGEST; } /* Record digest algorithm */ @@ -186,14 +207,14 @@ static int cms_parse_signature_algorithm ( struct cms_signature *sig, DBGC ( sig, "CMS %p/%p could not identify public-key " "algorithm:\n", sig, info ); DBGC_HDA ( sig, 0, raw->data, raw->len ); - return -ENOTSUP; + return -ENOTSUP_PUBKEY; } /* Check algorithm is a signature algorithm */ if ( ! algorithm->pubkey ) { DBGC ( sig, "CMS %p/%p algorithm %s is not a public-key " "algorithm\n", sig, info, algorithm->name ); - return -EINVAL; + return -EINVAL_PUBKEY; } /* Record signature algorithm */ From 920799a0bad73b7cc356a846876efdb72c19a065 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 00:18:12 +0100 Subject: [PATCH 133/221] [umalloc] Fail allocations when we run out of external memory Signed-off-by: Michael Brown --- .../i386/interface/pcbios/memtop_umalloc.c | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/arch/i386/interface/pcbios/memtop_umalloc.c b/src/arch/i386/interface/pcbios/memtop_umalloc.c index 16736e19..6c581fee 100644 --- a/src/arch/i386/interface/pcbios/memtop_umalloc.c +++ b/src/arch/i386/interface/pcbios/memtop_umalloc.c @@ -52,6 +52,9 @@ static userptr_t top = UNULL; /** Bottom of heap (current lowest allocated block) */ static userptr_t bottom = UNULL; +/** Remaining space on heap */ +static size_t heap_size; + /** * Initialise external heap * @@ -59,12 +62,12 @@ static userptr_t bottom = UNULL; */ static int init_eheap ( void ) { struct memory_map memmap; - unsigned long heap_size = 0; unsigned int i; DBG ( "Allocating external heap\n" ); get_memmap ( &memmap ); + heap_size = 0; for ( i = 0 ; i < memmap.count ; i++ ) { struct memory_region *region = &memmap.regions[i]; unsigned long r_start, r_end; @@ -99,8 +102,8 @@ static int init_eheap ( void ) { return -ENOMEM; } - DBG ( "External heap grows downwards from %lx\n", - user_to_phys ( top, 0 ) ); + DBG ( "External heap grows downwards from %lx (size %zx)\n", + user_to_phys ( top, 0 ), heap_size ); return 0; } @@ -110,6 +113,7 @@ static int init_eheap ( void ) { */ static void ecollect_free ( void ) { struct external_memory extmem; + size_t len; /* Walk the free list and collect empty blocks */ while ( bottom != top ) { @@ -119,8 +123,9 @@ static void ecollect_free ( void ) { break; DBG ( "EXTMEM freeing [%lx,%lx)\n", user_to_phys ( bottom, 0 ), user_to_phys ( bottom, extmem.size ) ); - bottom = userptr_add ( bottom, - ( extmem.size + sizeof ( extmem ) ) ); + len = ( extmem.size + sizeof ( extmem ) ); + bottom = userptr_add ( bottom, len ); + heap_size += len; } } @@ -153,7 +158,12 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { sizeof ( extmem ) ); } else { /* Create a zero-length block */ + if ( heap_size < sizeof ( extmem ) ) { + DBG ( "EXTMEM out of space\n" ); + return UNULL; + } ptr = bottom = userptr_add ( bottom, -sizeof ( extmem ) ); + heap_size -= sizeof ( extmem ); DBG ( "EXTMEM allocating [%lx,%lx)\n", user_to_phys ( ptr, 0 ), user_to_phys ( ptr, 0 ) ); extmem.size = 0; @@ -163,6 +173,10 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { /* Expand/shrink block if possible */ if ( ptr == bottom ) { /* Update block */ + if ( new_size > ( heap_size - extmem.size ) ) { + DBG ( "EXTMEM out of space\n" ); + return UNULL; + } new = userptr_add ( ptr, - ( new_size - extmem.size ) ); align = ( user_to_phys ( new, 0 ) & ( EM_ALIGN - 1 ) ); new_size += align; @@ -174,8 +188,9 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { user_to_phys ( new, new_size )); memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ? extmem.size : new_size ) ); - extmem.size = new_size; bottom = new; + heap_size -= ( new_size - extmem.size ); + extmem.size = new_size; } else { /* Cannot expand; can only pretend to shrink */ if ( new_size > extmem.size ) { @@ -193,7 +208,7 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { /* Collect any free blocks and update hidden memory region */ ecollect_free(); - hide_umalloc ( user_to_phys ( bottom, -sizeof ( extmem ) ), + hide_umalloc ( user_to_phys ( bottom, 0 ), user_to_phys ( top, 0 ) ); return ( new_size ? new : UNOWHERE ); From 2834f9f6ded44dbb217e3a8fa02f63b980dcfefb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 00:21:24 +0100 Subject: [PATCH 134/221] [umalloc] Unhide umalloc()ed memory region when there are no allocations At present, we always hide an extra sizeof(struct external_memory), to account for the header on the lowest allocated block. This header ceases to exist when there are no allocated blocks remaining. Signed-off-by: Michael Brown --- src/arch/i386/interface/pcbios/memtop_umalloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/arch/i386/interface/pcbios/memtop_umalloc.c b/src/arch/i386/interface/pcbios/memtop_umalloc.c index 6c581fee..dba4a23a 100644 --- a/src/arch/i386/interface/pcbios/memtop_umalloc.c +++ b/src/arch/i386/interface/pcbios/memtop_umalloc.c @@ -208,7 +208,8 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { /* Collect any free blocks and update hidden memory region */ ecollect_free(); - hide_umalloc ( user_to_phys ( bottom, 0 ), + hide_umalloc ( user_to_phys ( bottom, ( ( bottom == top ) ? + 0 : -sizeof ( extmem ) ) ), user_to_phys ( top, 0 ) ); return ( new_size ? new : UNOWHERE ); From 9445cb9f8b67b8e8dec59f2e868ec0578bb4aef2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 00:38:19 +0100 Subject: [PATCH 135/221] [downloader] Abort download immediately if buffer resizing fails Signed-off-by: Michael Brown --- src/core/downloader.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/downloader.c b/src/core/downloader.c index 612a6633..1a5b2088 100644 --- a/src/core/downloader.c +++ b/src/core/downloader.c @@ -183,6 +183,8 @@ static int downloader_xfer_deliver ( struct downloader *downloader, done: free_iob ( iobuf ); + if ( rc != 0 ) + downloader_finished ( downloader, rc ); return rc; } From cef3beaba466f9342ca41038a5836ae2da0be417 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 00:43:07 +0100 Subject: [PATCH 136/221] [downloader] Use a more meaningful error message when out of memory Signed-off-by: Michael Brown --- src/core/downloader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/downloader.c b/src/core/downloader.c index 1a5b2088..b4c5a5a7 100644 --- a/src/core/downloader.c +++ b/src/core/downloader.c @@ -111,7 +111,7 @@ static int downloader_ensure_size ( struct downloader *downloader, if ( ! new_buffer ) { DBGC ( downloader, "Downloader %p could not extend buffer to " "%zd bytes\n", downloader, len ); - return -ENOBUFS; + return -ENOSPC; } downloader->image->data = new_buffer; downloader->image->len = len; From 82ecaaac9178566533f738d041f5c4fc578d9348 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 00:51:10 +0100 Subject: [PATCH 137/221] [console] Remove "log message" usage from interactive console defaults Signed-off-by: Michael Brown --- src/arch/i386/core/video_subr.c | 2 +- src/arch/i386/firmware/pcbios/bios_console.c | 2 +- src/core/serial_console.c | 2 +- src/interface/efi/efi_console.c | 2 +- src/interface/linux/linux_console.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/arch/i386/core/video_subr.c b/src/arch/i386/core/video_subr.c index 7dd99e71..306c6d56 100644 --- a/src/arch/i386/core/video_subr.c +++ b/src/arch/i386/core/video_subr.c @@ -17,7 +17,7 @@ #if ! ( defined ( CONSOLE_DIRECT_VGA ) && \ CONSOLE_EXPLICIT ( CONSOLE_DIRECT_VGA ) ) #undef CONSOLE_DIRECT_VGA -#define CONSOLE_DIRECT_VGA CONSOLE_USAGE_ALL +#define CONSOLE_DIRECT_VGA ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif struct console_driver vga_console __console_driver; diff --git a/src/arch/i386/firmware/pcbios/bios_console.c b/src/arch/i386/firmware/pcbios/bios_console.c index 8a8795d7..097de2b8 100644 --- a/src/arch/i386/firmware/pcbios/bios_console.c +++ b/src/arch/i386/firmware/pcbios/bios_console.c @@ -52,7 +52,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) ) #undef CONSOLE_PCBIOS -#define CONSOLE_PCBIOS CONSOLE_USAGE_ALL +#define CONSOLE_PCBIOS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif /** Current character attribute */ diff --git a/src/core/serial_console.c b/src/core/serial_console.c index 52bd5376..bbddd6b2 100644 --- a/src/core/serial_console.c +++ b/src/core/serial_console.c @@ -12,7 +12,7 @@ /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_SERIAL ) && CONSOLE_EXPLICIT ( CONSOLE_SERIAL ) ) #undef CONSOLE_SERIAL -#define CONSOLE_SERIAL CONSOLE_USAGE_ALL +#define CONSOLE_SERIAL ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif struct console_driver serial_console __console_driver; diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 54b0c080..6b612438 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -52,7 +52,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_EFI ) && CONSOLE_EXPLICIT ( CONSOLE_EFI ) ) #undef CONSOLE_EFI -#define CONSOLE_EFI CONSOLE_USAGE_ALL +#define CONSOLE_EFI ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif /** Current character attribute */ diff --git a/src/interface/linux/linux_console.c b/src/interface/linux/linux_console.c index c79e5263..5105eaa9 100644 --- a/src/interface/linux/linux_console.c +++ b/src/interface/linux/linux_console.c @@ -38,7 +38,7 @@ FILE_LICENCE(GPL2_OR_LATER); /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_LINUX ) && CONSOLE_EXPLICIT ( CONSOLE_LINUX ) ) #undef CONSOLE_LINUX -#define CONSOLE_LINUX CONSOLE_USAGE_ALL +#define CONSOLE_LINUX ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif static void linux_console_putchar(int c) From 730c97212418e1cf272ed80272f266455e01eb17 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 11:11:28 +0100 Subject: [PATCH 138/221] [image] Log image executions Signed-off-by: Michael Brown --- src/core/image.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/core/image.c b/src/core/image.c index b02b8936..3cb2d62d 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include #include #include @@ -286,6 +287,9 @@ int image_exec ( struct image *image ) { */ current_image = image_get ( image ); + /* Record boot attempt */ + syslog ( LOG_NOTICE, "Executing \"%s\"\n", image->name ); + /* Try executing the image */ if ( ( rc = image->type->exec ( image ) ) != 0 ) { DBGC ( image, "IMAGE %s could not execute: %s\n", @@ -293,6 +297,15 @@ int image_exec ( struct image *image ) { /* Do not return yet; we still have clean-up to do */ } + /* Record result of boot attempt */ + if ( rc == 0 ) { + syslog ( LOG_NOTICE, "Execution of \"%s\" completed\n", + image->name ); + } else { + syslog ( LOG_ERR, "Execution of \"%s\" failed: %s\n", + image->name, strerror ( rc ) ); + } + /* Pick up replacement image before we drop the original * image's temporary reference. The replacement image must * already be registered, so we don't need to hold a temporary From d45392a67f3e18bdee5d02a0450e037e324ab7f6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 11:14:36 +0100 Subject: [PATCH 139/221] [console] Add LOG_ALL as a synonym for LOG_DEBUG Signed-off-by: Michael Brown --- src/include/syslog.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/syslog.h b/src/include/syslog.h index 3dfc11b9..93f32f86 100644 --- a/src/include/syslog.h +++ b/src/include/syslog.h @@ -51,6 +51,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Do not log any messages */ #define LOG_NONE -1 +/** Log all messages */ +#define LOG_ALL LOG_DEBUG + extern void log_vprintf ( const char *fmt, va_list args ); extern void __attribute__ (( format ( printf, 1, 2 ) )) From ed64732b73d604e5209b95d31f2b855b1a4d11f4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 14:58:45 +0100 Subject: [PATCH 140/221] [crypto] Add an explicit "RSA signature incorrect" error message Signed-off-by: Michael Brown --- src/crypto/rsa.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 62f52c95..be2696ba 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -39,6 +39,12 @@ FILE_LICENCE ( GPL2_OR_LATER ); * RSA is documented in RFC 3447. */ +/* Disambiguate the various error causes */ +#define EACCES_VERIFY \ + __einfo_error ( EINFO_EACCES_VERIFY ) +#define EINFO_EACCES_VERIFY \ + __einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" ) + /** "rsaEncryption" object identifier */ static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION }; @@ -610,7 +616,7 @@ static int rsa_verify ( void *ctx, struct digest_algorithm *digest, if ( memcmp ( actual, expected, context->max_len ) != 0 ) { DBGC ( context, "RSA %p signature verification failed\n", context ); - return -EACCES; + return -EACCES_VERIFY; } DBGC ( context, "RSA %p signature verified successfully\n", context ); From 4740703d9dc1dab286eb2d69473dd15da3a79da4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 20:55:19 +0100 Subject: [PATCH 141/221] [console] Ignore unexpected keysyms when generating keyboard maps I am unable to find any definitive documentation on how Linux keyboard symbols work. In the absence of any documentation, I'm going to assume that unexpected keysyms are harmless and should be ignored. Signed-off-by: Michael Brown --- src/util/genkeymap.pl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util/genkeymap.pl b/src/util/genkeymap.pl index d556df27..6487cd79 100755 --- a/src/util/genkeymap.pl +++ b/src/util/genkeymap.pl @@ -124,8 +124,10 @@ sub keysym_to_ascii { return unless $keysym; # Sanity check - die "Unexpected keysym ".sprintf ( "0x%04x\n", $keysym )."\n" - if $keysym & 0xf000; + if ( $keysym & 0xf000 ) { + warn "Unexpected keysym ".sprintf ( "0x%04x", $keysym )."\n"; + return; + } # Extract type and value my $type = ( $keysym >> 8 ); From e7d4d69031b944882fae786f4453e747bd9406c3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 21:04:18 +0100 Subject: [PATCH 142/221] [console] Add "no_latin1" keymap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "no" keymap is for a Dvorak keyboard. Reported-by: Robin Smidsrød Tested-by: Robin Smidsrød Signed-off-by: Michael Brown --- src/hci/keymap/keymap_no-latin1.c | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/hci/keymap/keymap_no-latin1.c diff --git a/src/hci/keymap/keymap_no-latin1.c b/src/hci/keymap/keymap_no-latin1.c new file mode 100644 index 00000000..8c3e81b3 --- /dev/null +++ b/src/hci/keymap/keymap_no-latin1.c @@ -0,0 +1,34 @@ +/** @file + * + * "no-latin1" keyboard mapping + * + * This file is automatically generated; do not edit + * + */ + +FILE_LICENCE ( PUBLIC_DOMAIN ); + +#include + +/** "no-latin1" keyboard mapping */ +struct key_mapping no_latin1_mapping[] __keymap = { + { 0x26, 0x2f }, /* '&' => '/' */ + { 0x28, 0x29 }, /* '(' => ')' */ + { 0x29, 0x3d }, /* ')' => '=' */ + { 0x2a, 0x28 }, /* '*' => '(' */ + { 0x2b, 0x60 }, /* '+' => '`' */ + { 0x2d, 0x2b }, /* '-' => '+' */ + { 0x2f, 0x2d }, /* '/' => '-' */ + { 0x3c, 0x3b }, /* '<' => ';' */ + { 0x3d, 0x5c }, /* '=' => '\\' */ + { 0x3e, 0x3a }, /* '>' => ':' */ + { 0x3f, 0x5f }, /* '?' => '_' */ + { 0x40, 0x22 }, /* '@' => '"' */ + { 0x5c, 0x27 }, /* '\\' => '\'' */ + { 0x5d, 0x7e }, /* ']' => '~' */ + { 0x5e, 0x26 }, /* '^' => '&' */ + { 0x5f, 0x3f }, /* '_' => '?' */ + { 0x60, 0x7c }, /* '`' => '|' */ + { 0x7c, 0x2a }, /* '|' => '*' */ + { 0x7d, 0x5e }, /* '}' => '^' */ +}; From b9720e4ebf44c6d7bf28d6b8309a84f212370562 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 21:40:44 +0100 Subject: [PATCH 143/221] [http] Disambiguate the various error causes Signed-off-by: Michael Brown --- src/net/tcp/httpcore.c | 58 ++++++++++++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 617f49b0..8f5c7bc9 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -47,6 +47,38 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +/* Disambiguate the various error causes */ +#define EACCES_401 __einfo_error ( EINFO_EACCES_401 ) +#define EINFO_EACCES_401 \ + __einfo_uniqify ( EINFO_EACCES, 0x01, "HTTP 401 Unauthorized" ) +#define EIO_OTHER __einfo_error ( EINFO_EIO_OTHER ) +#define EINFO_EIO_OTHER \ + __einfo_uniqify ( EINFO_EIO, 0x01, "Unrecognised HTTP response code" ) +#define EIO_CONTENT_LENGTH __einfo_error ( EINFO_EIO_CONTENT_LENGTH ) +#define EINFO_EIO_CONTENT_LENGTH \ + __einfo_uniqify ( EINFO_EIO, 0x02, "Content length mismatch" ) +#define EINVAL_RESPONSE __einfo_error ( EINFO_EINVAL_RESPONSE ) +#define EINFO_EINVAL_RESPONSE \ + __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid content length" ) +#define EINVAL_HEADER __einfo_error ( EINFO_EINVAL_HEADER ) +#define EINFO_EINVAL_HEADER \ + __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid header" ) +#define EINVAL_CONTENT_LENGTH __einfo_error ( EINFO_EINVAL_CONTENT_LENGTH ) +#define EINFO_EINVAL_CONTENT_LENGTH \ + __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid content length" ) +#define EINVAL_CHUNK_LENGTH __einfo_error ( EINFO_EINVAL_CHUNK_LENGTH ) +#define EINFO_EINVAL_CHUNK_LENGTH \ + __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid chunk length" ) +#define ENOENT_404 __einfo_error ( EINFO_ENOENT_404 ) +#define EINFO_ENOENT_404 \ + __einfo_uniqify ( EINFO_ENOENT, 0x01, "HTTP 404 Not Found" ) +#define EPERM_403 __einfo_error ( EINFO_EPERM_403 ) +#define EINFO_EPERM_403 \ + __einfo_uniqify ( EINFO_EPERM, 0x01, "HTTP 403 Forbidden" ) +#define EPROTO_UNSOLICITED __einfo_error ( EINFO_EPROTO_UNSOLICITED ) +#define EINFO_EPROTO_UNSOLICITED \ + __einfo_uniqify ( EINFO_EPROTO, 0x01, "Unsolicited data" ) + /** Block size used for HTTP block device request */ #define HTTP_BLKSIZE 512 @@ -146,7 +178,7 @@ static void http_close ( struct http_request *http, int rc ) { DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n", http, http->rx_len, ( http->rx_len + http->remaining ) ); if ( rc == 0 ) - rc = -EIO; + rc = -EIO_CONTENT_LENGTH; } /* Remove process */ @@ -169,7 +201,7 @@ static void http_done ( struct http_request *http ) { * isn't correct, force an error */ if ( http->remaining != 0 ) { - http_close ( http, -EIO ); + http_close ( http, -EIO_CONTENT_LENGTH ); return; } @@ -203,13 +235,13 @@ static int http_response_to_rc ( unsigned int response ) { case 303: return 0; case 404: - return -ENOENT; + return -ENOENT_404; case 403: - return -EPERM; + return -EPERM_403; case 401: - return -EACCES; + return -EACCES_401; default: - return -EIO; + return -EIO_OTHER; } } @@ -229,12 +261,12 @@ static int http_rx_response ( struct http_request *http, char *response ) { /* Check response starts with "HTTP/" */ if ( strncmp ( response, "HTTP/", 5 ) != 0 ) - return -EIO; + return -EINVAL_RESPONSE; /* Locate and check response code */ spc = strchr ( response, ' ' ); if ( ! spc ) - return -EIO; + return -EINVAL_RESPONSE; code = strtoul ( spc, NULL, 10 ); if ( ( rc = http_response_to_rc ( code ) ) != 0 ) return rc; @@ -284,7 +316,7 @@ static int http_rx_content_length ( struct http_request *http, if ( *endp != '\0' ) { DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n", http, value ); - return -EIO; + return -EINVAL_CONTENT_LENGTH; } /* If we already have an expected content length, and this @@ -293,7 +325,7 @@ static int http_rx_content_length ( struct http_request *http, if ( http->remaining && ( http->remaining != content_len ) ) { DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected " "%zd)\n", http, content_len, http->remaining ); - return -EIO; + return -EIO_CONTENT_LENGTH; } if ( ! ( http->flags & HTTP_HEAD_ONLY ) ) http->remaining = content_len; @@ -397,7 +429,7 @@ static int http_rx_header ( struct http_request *http, char *header ) { separator = strstr ( header, ": " ); if ( ! separator ) { DBGC ( http, "HTTP %p malformed header\n", http ); - return -EIO; + return -EINVAL_HEADER; } *separator = '\0'; value = ( separator + 2 ); @@ -432,7 +464,7 @@ static int http_rx_chunk_len ( struct http_request *http, char *length ) { if ( *endp != '\0' ) { DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n", http, length ); - return -EIO; + return -EINVAL_CHUNK_LENGTH; } /* Terminate chunked encoding if applicable */ @@ -500,7 +532,7 @@ static int http_socket_deliver ( struct http_request *http, http, iob_len ( iobuf ), ( ( http->rx_state == HTTP_RX_IDLE ) ? "idle" : "dead" ) ); - rc = -EPROTO; + rc = -EPROTO_UNSOLICITED; goto done; case HTTP_RX_DEAD: /* Do no further processing */ From aac9718fd60e5a85579ffc3d63c302615c403b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Smidsr=C3=B8d?= Date: Wed, 28 Mar 2012 11:52:55 +0100 Subject: [PATCH 144/221] [readline] Accept Ctrl-U for "delete to start of line" Signed-off-by: Michael Brown --- src/hci/editstring.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/hci/editstring.c b/src/hci/editstring.c index 996528ff..35a5b2c1 100644 --- a/src/hci/editstring.c +++ b/src/hci/editstring.c @@ -36,6 +36,7 @@ static void insert_character ( struct edit_string *string, unsigned int character ) __nonnull; static void delete_character ( struct edit_string *string ) __nonnull; static void backspace ( struct edit_string *string ) __nonnull; +static void kill_sol ( struct edit_string *string ) __nonnull; static void kill_eol ( struct edit_string *string ) __nonnull; /** @@ -108,6 +109,17 @@ static void backspace ( struct edit_string *string ) { } } +/** + * Delete to start of line + * + * @v string Editable string + */ +static void kill_sol ( struct edit_string *string ) { + size_t old_cursor = string->cursor; + string->cursor = 0; + insert_delete ( string, old_cursor, NULL ); +} + /** * Delete to end of line * @@ -168,6 +180,10 @@ int edit_string ( struct edit_string *string, int key ) { /* Delete character */ delete_character ( string ); break; + case CTRL_U: + /* Delete to start of line */ + kill_sol ( string ); + break; case CTRL_K: /* Delete to end of line */ kill_eol ( string ); From 0b1fe005b36ebc3af8de0d736e4a1227ba4580f8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 19:49:12 +0100 Subject: [PATCH 145/221] [parseopt] Allow "prompt" command to accept character literals for --key Signed-off-by: Michael Brown --- src/core/parseopt.c | 20 +++++++++++++++++++- src/image/script.c | 2 +- src/include/ipxe/parseopt.h | 1 + 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/core/parseopt.c b/src/core/parseopt.c index 2739bd87..57140690 100644 --- a/src/core/parseopt.c +++ b/src/core/parseopt.c @@ -26,7 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include -#include #include /** @file @@ -129,6 +128,25 @@ int parse_flag ( const char *text __unused, int *flag ) { return 0; } +/** + * Parse key + * + * @v text Text + * @ret key Key + * @ret rc Return status code + */ +int parse_key ( const char *text, unsigned int *key ) { + + /* Interpret single characters as being a literal key character */ + if ( text[0] && ! text[1] ) { + *key = text[0]; + return 0; + } + + /* Otherwise, interpret as an integer */ + return parse_integer ( text, key ); +} + /** * Print command usage message * diff --git a/src/image/script.c b/src/image/script.c index fb89e422..460fbf03 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -302,7 +302,7 @@ struct prompt_options { /** "prompt" option list */ static struct option_descriptor prompt_opts[] = { OPTION_DESC ( "key", 'k', required_argument, - struct prompt_options, key, parse_integer ), + struct prompt_options, key, parse_key ), OPTION_DESC ( "timeout", 't', required_argument, struct prompt_options, timeout, parse_integer ), }; diff --git a/src/include/ipxe/parseopt.h b/src/include/ipxe/parseopt.h index e54dac66..b5fd2203 100644 --- a/src/include/ipxe/parseopt.h +++ b/src/include/ipxe/parseopt.h @@ -117,6 +117,7 @@ extern int parse_string ( const char *text, const char **value ); extern int parse_integer ( const char *text, unsigned int *value ); extern int parse_netdev ( const char *text, struct net_device **netdev ); extern int parse_flag ( const char *text __unused, int *flag ); +extern int parse_key ( const char *text, unsigned int *key ); extern void print_usage ( struct command_descriptor *cmd, char **argv ); extern int reparse_options ( int argc, char **argv, struct command_descriptor *cmd, void *opts ); From 0b445275c421f9292adca5b4480dad7a0136f6a0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Mar 2012 12:50:08 +0100 Subject: [PATCH 146/221] [bios] Recognise Page Up and Page Down keys Signed-off-by: Michael Brown --- src/arch/i386/firmware/pcbios/bios_console.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/arch/i386/firmware/pcbios/bios_console.c b/src/arch/i386/firmware/pcbios/bios_console.c index 097de2b8..7f9892fc 100644 --- a/src/arch/i386/firmware/pcbios/bios_console.c +++ b/src/arch/i386/firmware/pcbios/bios_console.c @@ -216,6 +216,8 @@ static const char ansi_sequences[] = { BIOS_KEY ( "\x4d", "[C" ) /* Right arrow */ BIOS_KEY ( "\x47", "[H" ) /* Home */ BIOS_KEY ( "\x4f", "[F" ) /* End */ + BIOS_KEY ( "\x49", "[5~" ) /* Page up */ + BIOS_KEY ( "\x51", "[6~" ) /* Page down */ BIOS_KEY ( "\x3f", "[15~" ) /* F5 */ BIOS_KEY ( "\x40", "[17~" ) /* F6 */ BIOS_KEY ( "\x41", "[18~" ) /* F7 */ From 0d2fba2887a78b8bc4cd0d7fc6946d001075d92f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 27 Mar 2012 17:27:27 +0100 Subject: [PATCH 147/221] [menu] Add the abstract concept of a menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspired-by: Robin Smidsrød Tested-by: Robin Smidsrød Signed-off-by: Michael Brown --- src/core/menu.c | 177 ++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/menu.h | 47 +++++++++++ 2 files changed, 224 insertions(+) create mode 100644 src/core/menu.c create mode 100644 src/include/ipxe/menu.h diff --git a/src/core/menu.c b/src/core/menu.c new file mode 100644 index 00000000..1d1678f3 --- /dev/null +++ b/src/core/menu.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Menu selection + * + */ + +#include +#include +#include +#include +#include + +/** List of all menus */ +static LIST_HEAD ( menus ); + +/** + * Create menu + * + * @v name Menu name, or NULL + * @v title Menu title, or NULL + * @ret menu Menu, or NULL on failure + */ +struct menu * create_menu ( const char *name, const char *title ) { + size_t name_len; + size_t title_len; + size_t len; + struct menu *menu; + char *name_copy; + char *title_copy; + + /* Destroy any existing menu of this name */ + menu = find_menu ( name ); + if ( menu ) + destroy_menu ( menu ); + + /* Use empty title if none given */ + if ( ! title ) + title = ""; + + /* Allocate menu */ + name_len = ( name ? ( strlen ( name ) + 1 /* NUL */ ) : 0 ); + title_len = ( strlen ( title ) + 1 /* NUL */ ); + len = ( sizeof ( *menu ) + name_len + title_len ); + menu = zalloc ( len ); + if ( ! menu ) + return NULL; + name_copy = ( ( void * ) ( menu + 1 ) ); + title_copy = ( name_copy + name_len ); + + /* Initialise menu */ + if ( name ) { + strcpy ( name_copy, name ); + menu->name = name_copy; + } + strcpy ( title_copy, title ); + menu->title = title_copy; + INIT_LIST_HEAD ( &menu->items ); + + /* Add to list of menus */ + list_add_tail ( &menu->list, &menus ); + + DBGC ( menu, "MENU %s created with title \"%s\"\n", + menu->name, menu->title ); + + return menu; +} + +/** + * Add menu item + * + * @v menu Menu + * @v label Label, or NULL + * @v text Text, or NULL + * @v shortcut Shortcut key + * @v is_default Item is the default item + * @ret item Menu item, or NULL on failure + */ +struct menu_item * add_menu_item ( struct menu *menu, const char *label, + const char *text, int shortcut, + int is_default ) { + size_t label_len; + size_t text_len; + size_t len; + struct menu_item *item; + char *label_copy; + char *text_copy; + + /* Use empty text if none given */ + if ( ! text ) + text = ""; + + /* Allocate item */ + label_len = ( label ? ( strlen ( label ) + 1 /* NUL */ ) : 0 ); + text_len = ( strlen ( text ) + 1 /* NUL */ ); + len = ( sizeof ( *item ) + label_len + text_len ); + item = zalloc ( len ); + if ( ! item ) + return NULL; + label_copy = ( ( void * ) ( item + 1 ) ); + text_copy = ( label_copy + label_len ); + + /* Initialise item */ + if ( label ) { + strcpy ( label_copy, label ); + item->label = label_copy; + } + strcpy ( text_copy, text ); + item->text = text_copy; + item->shortcut = shortcut; + item->is_default = is_default; + + /* Add to list of items */ + list_add_tail ( &item->list, &menu->items ); + + return item; +} + +/** + * Destroy menu + * + * @v menu Menu + */ +void destroy_menu ( struct menu *menu ) { + struct menu_item *item; + struct menu_item *tmp; + + /* Remove from list of menus */ + list_del ( &menu->list ); + + /* Free items */ + list_for_each_entry_safe ( item, tmp, &menu->items, list ) { + list_del ( &item->list ); + free ( item ); + } + + /* Free menu */ + free ( menu ); +} + +/** + * Find menu + * + * @v name Menu name, or NULL + * @ret menu Menu, or NULL if not found + */ +struct menu * find_menu ( const char *name ) { + struct menu *menu; + + list_for_each_entry ( menu, &menus, list ) { + if ( ( menu->name == name ) || + ( strcmp ( menu->name, name ) == 0 ) ) { + return menu; + } + } + + return NULL; +} diff --git a/src/include/ipxe/menu.h b/src/include/ipxe/menu.h new file mode 100644 index 00000000..943aa57a --- /dev/null +++ b/src/include/ipxe/menu.h @@ -0,0 +1,47 @@ +#ifndef _IPXE_MENU_H +#define _IPXE_MENU_H + +/** @file + * + * Menu selection + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include + +/** A menu */ +struct menu { + /** List of menus */ + struct list_head list; + /** Name */ + const char *name; + /** Title */ + const char *title; + /** Menu items */ + struct list_head items; +}; + +/** A menu item */ +struct menu_item { + /** List of menu items */ + struct list_head list; + /** Label */ + const char *label; + /** Text */ + const char *text; + /** Shortcut key */ + int shortcut; + /** Is default item */ + int is_default; +}; + +extern struct menu * create_menu ( const char *name, const char *title ); +extern struct menu_item * add_menu_item ( struct menu *menu, const char *label, + const char *text, int shortcut, + int is_default ); +extern void destroy_menu ( struct menu *menu ); +extern struct menu * find_menu ( const char *name ); + +#endif /* _IPXE_MENU_H */ From 493f1945314cf74c10ffb77b96667b9f725bc5c4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Mar 2012 00:03:11 +0100 Subject: [PATCH 148/221] [menu] Add menu user interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inspired-by: Robin Smidsrød Tested-by: Robin Smidsrød Signed-off-by: Michael Brown --- src/hci/tui/menu_ui.c | 359 +++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/menu.h | 2 + 3 files changed, 362 insertions(+) create mode 100644 src/hci/tui/menu_ui.c diff --git a/src/hci/tui/menu_ui.c b/src/hci/tui/menu_ui.c new file mode 100644 index 00000000..6b1b6323 --- /dev/null +++ b/src/hci/tui/menu_ui.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Menu interface + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Colour pairs */ +#define CPAIR_NORMAL 1 +#define CPAIR_SELECT 2 +#define CPAIR_SEPARATOR 3 + +/* Screen layout */ +#define TITLE_ROW 1 +#define MENU_ROW 3 +#define MENU_COL 1 +#define MENU_ROWS 18 +#define MENU_COLS 78 +#define MENU_PAD 2 + +/** A menu user interface */ +struct menu_ui { + /** Menu */ + struct menu *menu; + /** Number of menu items */ + int count; + /** Currently selected item */ + int selected; + /** First visible item */ + int first_visible; + /** Timeout (0=indefinite) */ + unsigned long timeout; +}; + +/** + * Return a numbered menu item + * + * @v menu Menu + * @v index Index + * @ret item Menu item, or NULL + */ +static struct menu_item * menu_item ( struct menu *menu, unsigned int index ) { + struct menu_item *item; + + list_for_each_entry ( item, &menu->items, list ) { + if ( index-- == 0 ) + return item; + } + + return NULL; +} + +/** + * Draw a numbered menu item + * + * @v ui Menu user interface + * @v index Index + */ +static void draw_menu_item ( struct menu_ui *ui, int index ) { + struct menu_item *item; + unsigned int row_offset; + char buf[ MENU_COLS + 1 /* NUL */ ]; + char timeout_buf[6]; /* "(xxx)" + NUL */ + size_t timeout_len; + size_t max_len; + size_t len; + + /* Move to start of row */ + row_offset = ( index - ui->first_visible ); + move ( ( MENU_ROW + row_offset ), MENU_COL ); + + /* Get menu item */ + item = menu_item ( ui->menu, index ); + if ( item ) { + + /* Draw separators in a different colour */ + if ( ! item->label ) + color_set ( CPAIR_SEPARATOR, NULL ); + + /* Highlight if this is the selected item */ + if ( index == ui->selected ) { + color_set ( CPAIR_SELECT, NULL ); + attron ( A_BOLD ); + } + + /* Construct row */ + memset ( buf, ' ', ( sizeof ( buf ) - 1 ) ); + buf[ sizeof ( buf ) -1 ] = '\0'; + len = strlen ( item->text ); + max_len = ( sizeof ( buf ) - 1 /* NUL */ - ( 2 * MENU_PAD ) ); + if ( len > max_len ) + len = max_len; + memcpy ( ( buf + MENU_PAD ), item->text, len ); + + /* Add timeout if applicable */ + timeout_len = + snprintf ( timeout_buf, sizeof ( timeout_buf ), "(%ld)", + ( ( ui->timeout + TICKS_PER_SEC - 1 ) / + TICKS_PER_SEC ) ); + if ( ( index == ui->selected ) && ( ui->timeout != 0 ) ) { + memcpy ( ( buf + MENU_COLS - MENU_PAD - timeout_len ), + timeout_buf, timeout_len ); + } + + /* Print row */ + printw ( "%s", buf ); + + /* Reset attributes */ + color_set ( CPAIR_NORMAL, NULL ); + attroff ( A_BOLD ); + + } else { + /* Clear row if there is no corresponding menu item */ + clrtoeol(); + } + + /* Move cursor back to start of row */ + move ( ( MENU_ROW + row_offset ), MENU_COL ); +} + +/** + * Draw the current block of menu items + * + * @v ui Menu user interface + */ +static void draw_menu_items ( struct menu_ui *ui ) { + unsigned int i; + + /* Jump scroll to correct point in list */ + while ( ui->first_visible < ui->selected ) + ui->first_visible += MENU_ROWS; + while ( ui->first_visible > ui->selected ) + ui->first_visible -= MENU_ROWS; + + /* Draw ellipses before and/or after the list as necessary */ + color_set ( CPAIR_SEPARATOR, NULL ); + mvaddstr ( ( MENU_ROW - 1 ), ( MENU_COL + MENU_PAD ), + ( ( ui->first_visible > 0 ) ? "..." : " " ) ); + mvaddstr ( ( MENU_ROW + MENU_ROWS ), ( MENU_COL + MENU_PAD ), + ( ( ( ui->first_visible + MENU_ROWS ) < ui->count ) ? + "..." : " " ) ); + color_set ( CPAIR_NORMAL, NULL ); + + /* Draw visible items */ + for ( i = 0 ; i < MENU_ROWS ; i++ ) + draw_menu_item ( ui, ( ui->first_visible + i ) ); +} + +/** + * Menu main loop + * + * @v ui Menu user interface + * @ret selected Selected item + * @ret rc Return status code + */ +static int menu_loop ( struct menu_ui *ui, struct menu_item **selected ) { + struct menu_item *item; + unsigned long timeout; + unsigned int delta; + int current; + int key; + int i; + int move; + int chosen = 0; + int rc = 0; + + do { + /* Record current selection */ + current = ui->selected; + + /* Calculate timeout as remainder of current second */ + timeout = ( ui->timeout % TICKS_PER_SEC ); + if ( ( timeout == 0 ) && ( ui->timeout != 0 ) ) + timeout = TICKS_PER_SEC; + ui->timeout -= timeout; + + /* Get key */ + move = 0; + key = getkey ( timeout ); + if ( key < 0 ) { + /* Choose default if we finally time out */ + if ( ui->timeout == 0 ) + chosen = 1; + } else { + /* Cancel any timeout */ + ui->timeout = 0; + + /* Handle key */ + switch ( key ) { + case KEY_UP: + move = -1; + break; + case KEY_DOWN: + move = +1; + break; + case KEY_PPAGE: + move = ( ui->first_visible - ui->selected - 1 ); + break; + case KEY_NPAGE: + move = ( ui->first_visible - ui->selected + + MENU_ROWS ); + break; + case KEY_HOME: + move = -ui->count; + break; + case KEY_END: + move = +ui->count; + break; + case ESC: + case CTRL_C: + rc = -ECANCELED; + break; + case CR: + case LF: + chosen = 1; + break; + default: + i = 0; + list_for_each_entry ( item, &ui->menu->items, + list ) { + if ( item->shortcut == key ) { + ui->selected = i; + chosen = 1; + break; + } + i++; + } + break; + } + } + + /* Move selection, if applicable */ + while ( move ) { + ui->selected += move; + if ( ui->selected < 0 ) { + ui->selected = 0; + move = +1; + } else if ( ui->selected >= ui->count ) { + ui->selected = ( ui->count - 1 ); + move = -1; + } + item = menu_item ( ui->menu, ui->selected ); + if ( item->label ) + break; + move = ( ( move > 0 ) ? +1 : -1 ); + } + + /* Redraw selection if necessary */ + if ( ( ui->selected != current ) || ( timeout != 0 ) ) { + draw_menu_item ( ui, current ); + delta = ( ui->selected - ui->first_visible ); + if ( delta >= MENU_ROWS ) + draw_menu_items ( ui ); + draw_menu_item ( ui, ui->selected ); + } + + /* Refuse to choose unlabelled items (i.e. separators) */ + item = menu_item ( ui->menu, ui->selected ); + if ( ! item->label ) + chosen = 0; + + /* Record selection */ + *selected = item; + + } while ( ( rc == 0 ) && ! chosen ); + + return rc; +} + +/** + * Show menu + * + * @v menu Menu + * @v wait_ms Time to wait, in milliseconds (0=indefinite) + * @ret selected Selected item + * @ret rc Return status code + */ +int show_menu ( struct menu *menu, unsigned int timeout_ms, + struct menu_item **selected ) { + struct menu_item *item; + struct menu_ui ui; + int labelled_count = 0; + int rc; + + /* Initialise UI */ + memset ( &ui, 0, sizeof ( ui ) ); + ui.menu = menu; + ui.timeout = ( ( timeout_ms * TICKS_PER_SEC ) / 1000 ); + list_for_each_entry ( item, &menu->items, list ) { + if ( item->label ) { + labelled_count++; + if ( ! ui.selected ) + ui.selected = ui.count; + if ( item->is_default ) + ui.selected = ui.count; + } + ui.count++; + } + if ( ! labelled_count ) { + /* Menus with no labelled items cannot be selected + * from, and will seriously confuse the navigation + * logic. Refuse to display any such menus. + */ + return -ENOENT; + } + + /* Initialise screen */ + initscr(); + start_color(); + init_pair ( CPAIR_NORMAL, COLOR_WHITE, COLOR_BLUE ); + init_pair ( CPAIR_SELECT, COLOR_WHITE, COLOR_RED ); + init_pair ( CPAIR_SEPARATOR, COLOR_CYAN, COLOR_BLUE ); + color_set ( CPAIR_NORMAL, NULL ); + erase(); + + /* Draw initial content */ + attron ( A_BOLD ); + mvprintw ( TITLE_ROW, ( ( COLS - strlen ( ui.menu->title ) ) / 2 ), + "%s", ui.menu->title ); + attroff ( A_BOLD ); + draw_menu_items ( &ui ); + draw_menu_item ( &ui, ui.selected ); + + /* Enter main loop */ + rc = menu_loop ( &ui, selected ); + assert ( *selected ); + + /* Clear screen */ + endwin(); + + return rc; +} diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index b3fbb391..c72aeb7b 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -251,6 +251,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_x509_test ( ERRFILE_OTHER | 0x00290000 ) #define ERRFILE_cms ( ERRFILE_OTHER | 0x002a0000 ) #define ERRFILE_imgtrust ( ERRFILE_OTHER | 0x002b0000 ) +#define ERRFILE_menu_ui ( ERRFILE_OTHER | 0x002c0000 ) /** @} */ diff --git a/src/include/ipxe/menu.h b/src/include/ipxe/menu.h index 943aa57a..05bc1d45 100644 --- a/src/include/ipxe/menu.h +++ b/src/include/ipxe/menu.h @@ -43,5 +43,7 @@ extern struct menu_item * add_menu_item ( struct menu *menu, const char *label, int is_default ); extern void destroy_menu ( struct menu *menu ); extern struct menu * find_menu ( const char *name ); +extern int show_menu ( struct menu *menu, unsigned int timeout_ms, + struct menu_item **selected ); #endif /* _IPXE_MENU_H */ From 3425726cf33c2af84c9737a2501cd39517e42cdb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Mar 2012 00:05:22 +0100 Subject: [PATCH 149/221] [menu] Add menu commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow iPXE scripts to create menus. For example: #!ipxe menu iSCSI boot demonstration item install Install Fedora to ${root-path} item --default boot Boot from ${root-path} item shell Enter iPXE shell item exit Exit to BIOS choose label && goto ${label} :boot sanboot ${root-path} :install sanhook ${root-path} chain http://${next-server}/fedora.ipxe :shell shell :exit Inspired-by: Robin Smidsrød Tested-by: Robin Smidsrød Signed-off-by: Michael Brown --- src/config/config.c | 3 + src/config/general.h | 1 + src/core/parseopt.c | 24 ++++ src/hci/commands/menu_cmd.c | 280 ++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/features.h | 1 + src/include/ipxe/parseopt.h | 2 + 7 files changed, 312 insertions(+) create mode 100644 src/hci/commands/menu_cmd.c diff --git a/src/config/config.c b/src/config/config.c index 4b0bc371..bc3f7ed5 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -223,6 +223,9 @@ REQUIRE_OBJECT ( dhcp_cmd ); #ifdef SANBOOT_CMD REQUIRE_OBJECT ( sanboot_cmd ); #endif +#ifdef MENU_CMD +REQUIRE_OBJECT ( menu_cmd ); +#endif #ifdef LOGIN_CMD REQUIRE_OBJECT ( login_cmd ); #endif diff --git a/src/config/general.h b/src/config/general.h index a10696ee..70742165 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -119,6 +119,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define IMAGE_CMD /* Image management commands */ #define DHCP_CMD /* DHCP management commands */ #define SANBOOT_CMD /* SAN boot commands */ +#define MENU_CMD /* Menu commands */ #define LOGIN_CMD /* Login command */ //#define TIME_CMD /* Time commands */ //#define DIGEST_CMD /* Image crypto digest commands */ diff --git a/src/core/parseopt.c b/src/core/parseopt.c index 57140690..432e856d 100644 --- a/src/core/parseopt.c +++ b/src/core/parseopt.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include #include /** @file @@ -113,6 +114,29 @@ int parse_netdev ( const char *text, struct net_device **netdev ) { return 0; } +/** + * Parse menu name + * + * @v text Text + * @ret menu Menu + * @ret rc Return status code + */ +int parse_menu ( const char *text, struct menu **menu ) { + + /* Find menu */ + *menu = find_menu ( text ); + if ( ! *menu ) { + if ( text ) { + printf ( "\"%s\": no such menu\n", text ); + } else { + printf ( "No default menu\n" ); + } + return -ENOENT; + } + + return 0; +} + /** * Parse flag * diff --git a/src/hci/commands/menu_cmd.c b/src/hci/commands/menu_cmd.c new file mode 100644 index 00000000..8dac3cb8 --- /dev/null +++ b/src/hci/commands/menu_cmd.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Menu commands + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +FEATURE ( FEATURE_MISC, "Menu", DHCP_EB_FEATURE_MENU, 1 ); + +/** "menu" options */ +struct menu_options { + /** Name */ + const char *name; + /** Delete */ + int delete; +}; + +/** "menu" option list */ +static struct option_descriptor menu_opts[] = { + OPTION_DESC ( "name", 'n', required_argument, + struct menu_options, name, parse_string ), + OPTION_DESC ( "delete", 'd', no_argument, + struct menu_options, delete, parse_flag ), +}; + +/** "menu" command descriptor */ +static struct command_descriptor menu_cmd = + COMMAND_DESC ( struct menu_options, menu_opts, 0, MAX_ARGUMENTS, + "[--name ] [--delete] []" ); + +/** + * The "menu" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int menu_exec ( int argc, char **argv ) { + struct menu_options opts; + struct menu *menu; + char *title; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &menu_cmd, &opts ) ) != 0 ) + goto err_parse_options; + + /* Parse title */ + title = concat_args ( &argv[optind] ); + if ( ! title ) { + rc = -ENOMEM; + goto err_parse_title; + } + + /* Create menu */ + menu = create_menu ( opts.name, title ); + if ( ! menu ) { + rc = -ENOMEM; + goto err_create_menu; + } + + /* Destroy menu, if applicable */ + if ( opts.delete ) + destroy_menu ( menu ); + + /* Success */ + rc = 0; + + err_create_menu: + free ( title ); + err_parse_title: + err_parse_options: + return rc; +} + +/** "item" options */ +struct item_options { + /** Menu name */ + const char *menu; + /** Shortcut key */ + unsigned int key; + /** Use as default */ + int is_default; + /** Use as a separator */ + int is_gap; +}; + +/** "item" option list */ +static struct option_descriptor item_opts[] = { + OPTION_DESC ( "menu", 'm', required_argument, + struct item_options, menu, parse_string ), + OPTION_DESC ( "key", 'k', required_argument, + struct item_options, key, parse_key ), + OPTION_DESC ( "default", 'd', no_argument, + struct item_options, is_default, parse_flag ), + OPTION_DESC ( "gap", 'g', no_argument, + struct item_options, is_gap, parse_flag ), +}; + +/** "item" command descriptor */ +static struct command_descriptor item_cmd = + COMMAND_DESC ( struct item_options, item_opts, 0, MAX_ARGUMENTS, + "[--menu <menu>] [--key <key>] [--default] " + "[<label>|--gap [<text>]]" ); + +/** + * The "item" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int item_exec ( int argc, char **argv ) { + struct item_options opts; + struct menu *menu; + struct menu_item *item; + char *label = NULL; + char *text = NULL; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &item_cmd, &opts ) ) != 0 ) + goto err_parse_options; + + /* Parse label, if present */ + if ( ! opts.is_gap ) + label = argv[optind++]; /* May be NULL */ + + /* Parse text, if present */ + if ( optind < argc ) { + text = concat_args ( &argv[optind] ); + if ( ! text ) { + rc = -ENOMEM; + goto err_parse_text; + } + } + + /* Identify menu */ + if ( ( rc = parse_menu ( opts.menu, &menu ) ) != 0 ) + goto err_parse_menu; + + /* Add menu item */ + item = add_menu_item ( menu, label, ( text ? text : "" ), + opts.key, opts.is_default ); + if ( ! item ) { + rc = -ENOMEM; + goto err_add_menu_item; + } + + /* Success */ + rc = 0; + + err_add_menu_item: + err_parse_menu: + free ( text ); + err_parse_text: + err_parse_options: + return rc; +} + +/** "choose" options */ +struct choose_options { + /** Menu name */ + const char *menu; + /** Timeout */ + unsigned int timeout; + /** Keep menu */ + int keep; +}; + +/** "choose" option list */ +static struct option_descriptor choose_opts[] = { + OPTION_DESC ( "menu", 'm', required_argument, + struct choose_options, menu, parse_string ), + OPTION_DESC ( "timeout", 't', required_argument, + struct choose_options, timeout, parse_integer ), + OPTION_DESC ( "keep", 'k', no_argument, + struct choose_options, keep, parse_flag ), +}; + +/** "choose" command descriptor */ +static struct command_descriptor choose_cmd = + COMMAND_DESC ( struct choose_options, choose_opts, 1, 1, + "[--menu <menu>] [--timeout <timeout>] [--keep] " + "<setting>" ); + +/** + * The "choose" command + * + * @v argc Argument count + * @v argv Argument list + * @ret rc Return status code + */ +static int choose_exec ( int argc, char **argv ) { + struct choose_options opts; + struct menu *menu; + struct menu_item *item; + const char *setting; + int rc; + + /* Parse options */ + if ( ( rc = parse_options ( argc, argv, &choose_cmd, &opts ) ) != 0 ) + goto err_parse_options; + + /* Parse setting name */ + setting = argv[optind]; + + /* Identify menu */ + if ( ( rc = parse_menu ( opts.menu, &menu ) ) != 0 ) + goto err_parse_menu; + + /* Show menu */ + if ( ( rc = show_menu ( menu, opts.timeout, &item ) ) != 0 ) + goto err_show_menu; + + /* Store setting */ + if ( ( rc = storef_named_setting ( setting, item->label ) ) != 0 ) { + printf ( "Could not store \"%s\": %s\n", + setting, strerror ( rc ) ); + goto err_store; + } + + /* Success */ + rc = 0; + + err_store: + err_show_menu: + /* Destroy menu, if applicable */ + if ( ! opts.keep ) + destroy_menu ( menu ); + err_parse_menu: + err_parse_options: + return rc; +} + +/** Menu commands */ +struct command menu_commands[] __command = { + { + .name = "menu", + .exec = menu_exec, + }, + { + .name = "item", + .exec = item_exec, + }, + { + .name = "choose", + .exec = choose_exec, + }, +}; diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index c72aeb7b..77c2f809 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -252,6 +252,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_cms ( ERRFILE_OTHER | 0x002a0000 ) #define ERRFILE_imgtrust ( ERRFILE_OTHER | 0x002b0000 ) #define ERRFILE_menu_ui ( ERRFILE_OTHER | 0x002c0000 ) +#define ERRFILE_menu_cmd ( ERRFILE_OTHER | 0x002d0000 ) /** @} */ diff --git a/src/include/ipxe/features.h b/src/include/ipxe/features.h index 660015cd..498ec944 100644 --- a/src/include/ipxe/features.h +++ b/src/include/ipxe/features.h @@ -52,6 +52,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define DHCP_EB_FEATURE_EFI 0x24 /**< EFI format */ #define DHCP_EB_FEATURE_FCOE 0x25 /**< FCoE protocol */ #define DHCP_EB_FEATURE_VLAN 0x26 /**< VLAN support */ +#define DHCP_EB_FEATURE_MENU 0x27 /**< Menu support */ /** @} */ diff --git a/src/include/ipxe/parseopt.h b/src/include/ipxe/parseopt.h index b5fd2203..b492a51e 100644 --- a/src/include/ipxe/parseopt.h +++ b/src/include/ipxe/parseopt.h @@ -13,6 +13,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> struct net_device; +struct menu; /** A command-line option descriptor */ struct option_descriptor { @@ -116,6 +117,7 @@ struct command_descriptor { extern int parse_string ( const char *text, const char **value ); extern int parse_integer ( const char *text, unsigned int *value ); extern int parse_netdev ( const char *text, struct net_device **netdev ); +extern int parse_menu ( const char *text, struct menu **menu ); extern int parse_flag ( const char *text __unused, int *flag ); extern int parse_key ( const char *text, unsigned int *key ); extern void print_usage ( struct command_descriptor *cmd, char **argv ); From cf0953a1b09d004f5de5fb617f9a16b17adcb0c0 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Thu, 29 Mar 2012 01:24:31 +0100 Subject: [PATCH 150/221] [comboot] Remove COMBOOT image support by default iPXE's support for COMBOOT images is now quite outdated; it has not kept up to date with changes in the COMBOOT API. The primary use for COMBOOT seems to be for menuing support. Now that we have native iPXE script-based menus, COMBOOT support can be gracefully retired (with immense thanks to Daniel Verkamp for having successfully implemented such an ambitious feature many years ago). Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/config/defaults/pcbios.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/config/defaults/pcbios.h b/src/config/defaults/pcbios.h index 9092d675..b68186f1 100644 --- a/src/config/defaults/pcbios.h +++ b/src/config/defaults/pcbios.h @@ -26,7 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define IMAGE_PXE /* PXE image support */ #define IMAGE_SCRIPT /* iPXE script image support */ #define IMAGE_BZIMAGE /* Linux bzImage image support */ -#define IMAGE_COMBOOT /* SYSLINUX COMBOOT image support */ #define PXE_STACK /* PXE stack in iPXE - required for PXELINUX */ #define PXE_MENU /* PXE menu booting */ From 4dbb193c33deda44a966d81b018c73071b4bc9f6 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Fri, 30 Mar 2012 12:05:13 +0100 Subject: [PATCH 151/221] [int13] Add support for emulating floppy disk drives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested-by: Robin Smidsrød <robin@smidsrod.no> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/arch/i386/include/bios.h | 1 + src/arch/i386/include/int13.h | 52 +++++ src/arch/i386/interface/pcbios/int13.c | 300 ++++++++++++++++++++----- 3 files changed, 297 insertions(+), 56 deletions(-) diff --git a/src/arch/i386/include/bios.h b/src/arch/i386/include/bios.h index 70bb73da..fadb9f1b 100644 --- a/src/arch/i386/include/bios.h +++ b/src/arch/i386/include/bios.h @@ -4,6 +4,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define BDA_SEG 0x0040 +#define BDA_EQUIPMENT_WORD 0x0010 #define BDA_FBMS 0x0013 #define BDA_NUM_DRIVES 0x0075 diff --git a/src/arch/i386/include/int13.h b/src/arch/i386/include/int13.h index 0244acaf..5d36b637 100644 --- a/src/arch/i386/include/int13.h +++ b/src/arch/i386/include/int13.h @@ -71,6 +71,19 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Block size for non-extended INT 13 calls */ #define INT13_BLKSIZE 512 +/** @defgroup int13fddtype INT 13 floppy disk drive types + * @{ + */ + +/** 360K */ +#define INT13_FDD_TYPE_360K 0x01 +/** 1.2M */ +#define INT13_FDD_TYPE_1M2 0x02 +/** 720K */ +#define INT13_FDD_TYPE_720K 0x03 +/** 1.44M */ +#define INT13_FDD_TYPE_1M44 0x04 + /** An INT 13 disk address packet */ struct int13_disk_address { /** Size of the packet, in bytes */ @@ -394,4 +407,43 @@ enum eltorito_media_type { ELTORITO_NO_EMULATION = 0, }; +/** A floppy disk geometry */ +struct int13_fdd_geometry { + /** Number of tracks */ + uint8_t tracks; + /** Number of heads and sectors per track */ + uint8_t heads_spt; +}; + +/** Define a floppy disk geometry */ +#define INT13_FDD_GEOMETRY( cylinders, heads, sectors ) \ + { \ + .tracks = (cylinders), \ + .heads_spt = ( ( (heads) << 6 ) | (sectors) ), \ + } + +/** Get floppy disk number of cylinders */ +#define INT13_FDD_CYLINDERS( geometry ) ( (geometry)->tracks ) + +/** Get floppy disk number of heads */ +#define INT13_FDD_HEADS( geometry ) ( (geometry)->heads_spt >> 6 ) + +/** Get floppy disk number of sectors per track */ +#define INT13_FDD_SECTORS( geometry ) ( (geometry)->heads_spt & 0x3f ) + +/** A floppy drive parameter table */ +struct int13_fdd_parameters { + uint8_t step_rate__head_unload; + uint8_t head_load__ndma; + uint8_t motor_off_delay; + uint8_t bytes_per_sector; + uint8_t sectors_per_track; + uint8_t gap_length; + uint8_t data_length; + uint8_t format_gap_length; + uint8_t format_filler; + uint8_t head_settle_time; + uint8_t motor_start_time; +} __attribute__ (( packed )); + #endif /* INT13_H */ diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c index 4bfc8a3a..6d6d7f87 100644 --- a/src/arch/i386/interface/pcbios/int13.c +++ b/src/arch/i386/interface/pcbios/int13.c @@ -75,9 +75,9 @@ struct int13_drive { /** Underlying block device interface */ struct interface block; - /** BIOS in-use drive number (0x80-0xff) */ + /** BIOS in-use drive number (0x00-0xff) */ unsigned int drive; - /** BIOS natural drive number (0x80-0xff) + /** BIOS natural drive number (0x00-0xff) * * This is the drive number that would have been assigned by * 'naturally' appending the drive to the end of the BIOS @@ -142,17 +142,44 @@ static struct segoff __text16 ( int13_vector ); /** Assembly wrapper */ extern void int13_wrapper ( void ); +/** Dummy floppy disk parameter table */ +static struct int13_fdd_parameters __data16 ( int13_fdd_params ) = { + /* 512 bytes per sector */ + .bytes_per_sector = 0x02, + /* Highest sectors per track that we ever return */ + .sectors_per_track = 48, +}; +#define int13_fdd_params __use_data16 ( int13_fdd_params ) + /** List of registered emulated drives */ static LIST_HEAD ( int13s ); /** - * Number of BIOS drives + * Equipment word * - * Note that this is the number of drives in the system as a whole - * (i.e. a mirror of the counter at 40:75), rather than a count of the - * number of emulated drives. + * This is a cached copy of the BIOS Data Area equipment word at + * 40:10. */ -static uint8_t num_drives; +static uint16_t equipment_word; + +/** + * Number of BIOS floppy disk drives + * + * This is derived from the equipment word. It is held in .text16 to + * allow for easy access by the INT 13,08 wrapper. + */ +static uint8_t __text16 ( num_fdds ); +#define num_fdds __use_text16 ( num_fdds ) + +/** + * Number of BIOS hard disk drives + * + * This is a cached copy of the BIOS Data Area number of hard disk + * drives at 40:75. It is held in .text16 to allow for easy access by + * the INT 13,08 wrapper. + */ +static uint8_t __text16 ( num_drives ); +#define num_drives __use_text16 ( num_drives ) /** * Calculate INT 13 drive sector size @@ -185,6 +212,16 @@ static inline uint32_t int13_capacity32 ( struct int13_drive *int13 ) { return ( ( capacity <= 0xffffffffUL ) ? capacity : 0xffffffff ); } +/** + * Test if INT 13 drive is a floppy disk drive + * + * @v int13 Emulated drive + * @ret is_fdd Emulated drive is a floppy disk + */ +static inline int int13_is_fdd ( struct int13_drive *int13 ) { + return ( ! ( int13->drive & 0x80 ) ); +} + /** An INT 13 command */ struct int13_command { /** Status */ @@ -499,33 +536,33 @@ static int int13_parse_iso9660 ( struct int13_drive *int13, void *scratch ) { } /** - * Guess INT 13 drive geometry + * Guess INT 13 hard disk drive geometry * * @v int13 Emulated drive * @v scratch Scratch area for single-sector reads + * @ret heads Guessed number of heads + * @ret sectors Guessed number of sectors per track * @ret rc Return status code * * Guesses the drive geometry by inspecting the partition table. */ -static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) { +static int int13_guess_geometry_hdd ( struct int13_drive *int13, void *scratch, + unsigned int *heads, + unsigned int *sectors ) { struct master_boot_record *mbr = scratch; struct partition_table_entry *partition; - unsigned int guessed_heads = 255; - unsigned int guessed_sectors_per_track = 63; - unsigned int blocks; - unsigned int blocks_per_cyl; unsigned int i; int rc; - /* Don't even try when the blksize is invalid for C/H/S access */ - if ( int13_blksize ( int13 ) != INT13_BLKSIZE ) - return 0; + /* Default guess is xx/255/63 */ + *heads = 255; + *sectors = 63; /* Read partition table */ if ( ( rc = int13_rw ( int13, 0, 1, virt_to_user ( mbr ), block_read ) ) != 0 ) { - DBGC ( int13, "INT13 drive %02x could not read partition " - "table to guess geometry: %s\n", + DBGC ( int13, "INT13 drive %02x could not read " + "partition table to guess geometry: %s\n", int13->drive, strerror ( rc ) ); return rc; } @@ -534,25 +571,126 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) { DBGC ( int13, "INT13 drive %02x has signature %08x\n", int13->drive, mbr->signature ); - /* Scan through partition table and modify guesses for heads - * and sectors_per_track if we find any used partitions. + /* Scan through partition table and modify guesses for + * heads and sectors_per_track if we find any used + * partitions. */ for ( i = 0 ; i < 4 ; i++ ) { partition = &mbr->partitions[i]; if ( ! partition->type ) continue; - guessed_heads = ( PART_HEAD ( partition->chs_end ) + 1 ); - guessed_sectors_per_track = PART_SECTOR ( partition->chs_end ); + *heads = ( PART_HEAD ( partition->chs_end ) + 1 ); + *sectors = PART_SECTOR ( partition->chs_end ); DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based " - "on partition %d\n", int13->drive, guessed_heads, - guessed_sectors_per_track, ( i + 1 ) ); + "on partition %d\n", + int13->drive, *heads, *sectors, ( i + 1 ) ); + } + + return 0; +} + +/** Recognised floppy disk geometries */ +static const struct int13_fdd_geometry int13_fdd_geometries[] = { + INT13_FDD_GEOMETRY ( 40, 1, 8 ), + INT13_FDD_GEOMETRY ( 40, 1, 9 ), + INT13_FDD_GEOMETRY ( 40, 2, 8 ), + INT13_FDD_GEOMETRY ( 40, 1, 9 ), + INT13_FDD_GEOMETRY ( 80, 2, 8 ), + INT13_FDD_GEOMETRY ( 80, 2, 9 ), + INT13_FDD_GEOMETRY ( 80, 2, 15 ), + INT13_FDD_GEOMETRY ( 80, 2, 18 ), + INT13_FDD_GEOMETRY ( 80, 2, 20 ), + INT13_FDD_GEOMETRY ( 80, 2, 21 ), + INT13_FDD_GEOMETRY ( 82, 2, 21 ), + INT13_FDD_GEOMETRY ( 83, 2, 21 ), + INT13_FDD_GEOMETRY ( 80, 2, 22 ), + INT13_FDD_GEOMETRY ( 80, 2, 23 ), + INT13_FDD_GEOMETRY ( 80, 2, 24 ), + INT13_FDD_GEOMETRY ( 80, 2, 36 ), + INT13_FDD_GEOMETRY ( 80, 2, 39 ), + INT13_FDD_GEOMETRY ( 80, 2, 40 ), + INT13_FDD_GEOMETRY ( 80, 2, 44 ), + INT13_FDD_GEOMETRY ( 80, 2, 48 ), +}; + +/** + * Guess INT 13 floppy disk drive geometry + * + * @v int13 Emulated drive + * @ret heads Guessed number of heads + * @ret sectors Guessed number of sectors per track + * @ret rc Return status code + * + * Guesses the drive geometry by inspecting the disk size. + */ +static int int13_guess_geometry_fdd ( struct int13_drive *int13, + unsigned int *heads, + unsigned int *sectors ) { + unsigned int blocks = int13_blksize ( int13 ); + const struct int13_fdd_geometry *geometry; + unsigned int cylinders; + unsigned int i; + + /* Look for a match against a known geometry */ + for ( i = 0 ; i < ( sizeof ( int13_fdd_geometries ) / + sizeof ( int13_fdd_geometries[0] ) ) ; i++ ) { + geometry = &int13_fdd_geometries[i]; + cylinders = INT13_FDD_CYLINDERS ( geometry ); + *heads = INT13_FDD_HEADS ( geometry ); + *sectors = INT13_FDD_SECTORS ( geometry ); + if ( ( cylinders * (*heads) * (*sectors) ) == blocks ) { + DBGC ( int13, "INT13 drive %02x guessing C/H/S " + "%d/%d/%d based on size %dK\n", int13->drive, + cylinders, *heads, *sectors, ( blocks / 2 ) ); + return 0; + } + } + + /* Otherwise, assume a partial disk image in the most common + * format (1440K, 80/2/18). + */ + *heads = 2; + *sectors = 18; + DBGC ( int13, "INT13 drive %02x guessing C/H/S xx/%d/%d based on size " + "%dK\n", int13->drive, *heads, *sectors, ( blocks / 2 ) ); + return 0; +} + +/** + * Guess INT 13 drive geometry + * + * @v int13 Emulated drive + * @v scratch Scratch area for single-sector reads + * @ret rc Return status code + */ +static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) { + unsigned int guessed_heads; + unsigned int guessed_sectors; + unsigned int blocks; + unsigned int blocks_per_cyl; + int rc; + + /* Don't even try when the blksize is invalid for C/H/S access */ + if ( int13_blksize ( int13 ) != INT13_BLKSIZE ) + return 0; + + /* Guess geometry according to drive type */ + if ( int13_is_fdd ( int13 ) ) { + if ( ( rc = int13_guess_geometry_fdd ( int13, &guessed_heads, + &guessed_sectors )) != 0) + return rc; + } else { + if ( ( rc = int13_guess_geometry_hdd ( int13, scratch, + &guessed_heads, + &guessed_sectors )) != 0) + return rc; } /* Apply guesses if no geometry already specified */ if ( ! int13->heads ) int13->heads = guessed_heads; if ( ! int13->sectors_per_track ) - int13->sectors_per_track = guessed_sectors_per_track; + int13->sectors_per_track = guessed_sectors; if ( ! int13->cylinders ) { /* Avoid attempting a 64-bit divide on a 32-bit system */ blocks = int13_capacity32 ( int13 ); @@ -569,19 +707,40 @@ static int int13_guess_geometry ( struct int13_drive *int13, void *scratch ) { /** * Update BIOS drive count */ -static void int13_set_num_drives ( void ) { +static void int13_sync_num_drives ( void ) { struct int13_drive *int13; + uint8_t *counter; + uint8_t max_drive; + uint8_t required; - /* Get current drive count */ + /* Get current drive counts */ + get_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD ); get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); + num_fdds = ( ( equipment_word & 0x0001 ) ? + ( ( ( equipment_word >> 6 ) & 0x3 ) + 1 ) : 0 ); /* Ensure count is large enough to cover all of our emulated drives */ list_for_each_entry ( int13, &int13s, list ) { - if ( num_drives <= ( int13->drive & 0x7f ) ) - num_drives = ( ( int13->drive & 0x7f ) + 1 ); + counter = ( int13_is_fdd ( int13 ) ? &num_fdds : &num_drives ); + max_drive = int13->drive; + if ( max_drive < int13->natural_drive ) + max_drive = int13->natural_drive; + required = ( ( max_drive & 0x7f ) + 1 ); + if ( *counter < required ) { + *counter = required; + DBGC ( int13, "INT13 drive %02x added to drive count: " + "%d HDDs, %d FDDs\n", + int13->drive, num_drives, num_fdds ); + } } /* Update current drive count */ + equipment_word &= ~( ( 0x3 << 6 ) | 0x0001 ); + if ( num_fdds ) { + equipment_word |= ( 0x0001 | + ( ( ( num_fdds - 1 ) & 0x3 ) << 6 ) ); + } + put_real ( equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD ); put_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); } @@ -589,13 +748,14 @@ static void int13_set_num_drives ( void ) { * Check number of drives */ static void int13_check_num_drives ( void ) { + uint16_t check_equipment_word; uint8_t check_num_drives; + get_real ( check_equipment_word, BDA_SEG, BDA_EQUIPMENT_WORD ); get_real ( check_num_drives, BDA_SEG, BDA_NUM_DRIVES ); - if ( check_num_drives != num_drives ) { - int13_set_num_drives(); - DBG ( "INT13 fixing up number of drives from %d to %d\n", - check_num_drives, num_drives ); + if ( ( check_equipment_word != equipment_word ) || + ( check_num_drives != num_drives ) ) { + int13_sync_num_drives(); } } @@ -669,14 +829,19 @@ static int int13_rw_sectors ( struct int13_drive *int13, int13->drive, int13_blksize ( int13 ) ); return -INT13_STATUS_INVALID; } - + /* Calculate parameters */ cylinder = ( ( ( ix86->regs.cl & 0xc0 ) << 2 ) | ix86->regs.ch ); - assert ( cylinder < int13->cylinders ); head = ix86->regs.dh; - assert ( head < int13->heads ); sector = ( ix86->regs.cl & 0x3f ); - assert ( ( sector >= 1 ) && ( sector <= int13->sectors_per_track ) ); + if ( ( cylinder >= int13->cylinders ) || + ( head >= int13->heads ) || + ( sector < 1 ) || ( sector > int13->sectors_per_track ) ) { + DBGC ( int13, "C/H/S %d/%d/%d out of range for geometry " + "%d/%d/%d\n", cylinder, head, sector, int13->cylinders, + int13->heads, int13->sectors_per_track ); + return -INT13_STATUS_INVALID; + } lba = ( ( ( ( cylinder * int13->heads ) + head ) * int13->sectors_per_track ) + sector - 1 ); count = ix86->regs.al; @@ -761,10 +926,19 @@ static int int13_get_parameters ( struct int13_drive *int13, return -INT13_STATUS_INVALID; } + /* Common parameters */ ix86->regs.ch = ( max_cylinder & 0xff ); ix86->regs.cl = ( ( ( max_cylinder >> 8 ) << 6 ) | max_sector ); ix86->regs.dh = max_head; - get_real ( ix86->regs.dl, BDA_SEG, BDA_NUM_DRIVES ); + ix86->regs.dl = ( int13_is_fdd ( int13 ) ? num_fdds : num_drives ); + + /* Floppy-specific parameters */ + if ( int13_is_fdd ( int13 ) ) { + ix86->regs.bl = INT13_FDD_TYPE_1M44; + ix86->segs.es = rm_ds; + ix86->regs.di = __from_data16 ( &int13_fdd_params ); + } + return 0; } @@ -781,10 +955,15 @@ static int int13_get_disk_type ( struct int13_drive *int13, uint32_t blocks; DBGC2 ( int13, "Get disk type\n" ); - blocks = int13_capacity32 ( int13 ); - ix86->regs.cx = ( blocks >> 16 ); - ix86->regs.dx = ( blocks & 0xffff ); - return INT13_DISK_TYPE_HDD; + + if ( int13_is_fdd ( int13 ) ) { + return INT13_DISK_TYPE_FDD; + } else { + blocks = int13_capacity32 ( int13 ); + ix86->regs.cx = ( blocks >> 16 ); + ix86->regs.dx = ( blocks & 0xffff ); + return INT13_DISK_TYPE_HDD; + } } /** @@ -833,6 +1012,13 @@ static int int13_extended_rw ( struct int13_drive *int13, userptr_t buffer; int rc; + /* Extended reads are not allowed on floppy drives. + * ELTORITO.SYS seems to assume that we are really a CD-ROM if + * we support extended reads for a floppy drive. + */ + if ( int13_is_fdd ( int13 ) ) + return -INT13_STATUS_INVALID; + /* Get buffer size */ get_real ( bufsize, ix86->segs.ds, ( ix86->regs.si + offsetof ( typeof ( addr ), bufsize ) ) ); @@ -1300,26 +1486,29 @@ static void int13_hook_vector ( void ) { "popw 6(%%bp)\n\t" /* Fix up %dl: * - * INT 13,15 : do nothing + * INT 13,15 : do nothing if hard disk * INT 13,08 : load with number of drives * all others: restore original value */ "cmpb $0x15, -1(%%bp)\n\t" - "je 2f\n\t" + "jne 2f\n\t" + "testb $0x80, -4(%%bp)\n\t" + "jnz 3f\n\t" + "\n2:\n\t" "movb -4(%%bp), %%dl\n\t" "cmpb $0x08, -1(%%bp)\n\t" - "jne 2f\n\t" - "pushw %%ds\n\t" - "pushw %1\n\t" - "popw %%ds\n\t" - "movb %c2, %%dl\n\t" - "popw %%ds\n\t" + "jne 3f\n\t" + "testb $0x80, %%dl\n\t" + "movb %%cs:%c1, %%dl\n\t" + "jnz 3f\n\t" + "movb %%cs:%c2, %%dl\n\t" /* Return */ - "\n2:\n\t" + "\n3:\n\t" "movw %%bp, %%sp\n\t" "popw %%bp\n\t" "iret\n\t" ) - : : "i" ( int13 ), "i" ( BDA_SEG ), "i" ( BDA_NUM_DRIVES ) ); + : : "i" ( int13 ), "i" ( __from_text16 ( &num_drives ) ), + "i" ( __from_text16 ( &num_fdds ) ) ); hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, &int13_vector ); @@ -1404,14 +1593,13 @@ static void int13_free ( struct refcnt *refcnt ) { */ static int int13_hook ( struct uri *uri, unsigned int drive ) { struct int13_drive *int13; - uint8_t num_drives; unsigned int natural_drive; void *scratch; int rc; /* Calculate natural drive number */ - get_real ( num_drives, BDA_SEG, BDA_NUM_DRIVES ); - natural_drive = ( num_drives | 0x80 ); + int13_sync_num_drives(); + natural_drive = ( ( drive & 0x80 ) ? ( num_drives | 0x80 ) : num_fdds ); /* Check that drive number is not in use */ list_for_each_entry ( int13, &int13s, list ) { @@ -1468,7 +1656,7 @@ static int int13_hook ( struct uri *uri, unsigned int drive ) { list_add ( &int13->list, &int13s ); /* Update BIOS drive count */ - int13_set_num_drives(); + int13_sync_num_drives(); free ( scratch ); return 0; From f5c644cbe156573d23824a5c7046d1dec93eaf58 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Fri, 30 Mar 2012 17:57:52 +0100 Subject: [PATCH 152/221] [menu] Fix default selection when default is item 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Robin Smidsrød <robin@smidsrod.no> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/hci/tui/menu_ui.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hci/tui/menu_ui.c b/src/hci/tui/menu_ui.c index 6b1b6323..2457a825 100644 --- a/src/hci/tui/menu_ui.c +++ b/src/hci/tui/menu_ui.c @@ -315,9 +315,9 @@ int show_menu ( struct menu *menu, unsigned int timeout_ms, ui.timeout = ( ( timeout_ms * TICKS_PER_SEC ) / 1000 ); list_for_each_entry ( item, &menu->items, list ) { if ( item->label ) { - labelled_count++; - if ( ! ui.selected ) + if ( ! labelled_count ) ui.selected = ui.count; + labelled_count++; if ( item->is_default ) ui.selected = ui.count; } From 275fdae9bb3aafa6db1a089821654323f9990042 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Fri, 30 Mar 2012 20:50:25 +0100 Subject: [PATCH 153/221] [image] Fix use-after-free in debug messages Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/core/image.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/image.c b/src/core/image.c index 3cb2d62d..10580925 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -67,13 +67,13 @@ static int require_trusted_images_permanent = 0; static void free_image ( struct refcnt *refcnt ) { struct image *image = container_of ( refcnt, struct image, refcnt ); + DBGC ( image, "IMAGE %s freed\n", image->name ); free ( image->name ); free ( image->cmdline ); uri_put ( image->uri ); ufree ( image->data ); image_put ( image->replacement ); free ( image ); - DBGC ( image, "IMAGE %s freed\n", image->name ); } /** @@ -327,8 +327,8 @@ int image_exec ( struct image *image ) { /* Tail-recurse into replacement image, if one exists */ if ( replacement ) { - DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n", - image->name, replacement->name ); + DBGC ( image, "IMAGE <freed> replacing self with IMAGE %s\n", + replacement->name ); if ( ( rc = image_exec ( replacement ) ) != 0 ) return rc; } From 61851e685de53045065e331830c32ebdef101f74 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Mon, 9 Apr 2012 15:15:05 +0100 Subject: [PATCH 154/221] [elf] Avoid attempting to load 64-bit ELF binaries Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/image/elf.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/image/elf.c b/src/image/elf.c index 406a8d47..f4ea4aab 100644 --- a/src/image/elf.c +++ b/src/image/elf.c @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); typedef Elf32_Ehdr Elf_Ehdr; typedef Elf32_Phdr Elf_Phdr; typedef Elf32_Off Elf_Off; +#define ELFCLASS ELFCLASS32 /** * Load ELF segment into memory @@ -121,6 +122,13 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, * @ret rc Return status code */ int elf_load ( struct image *image, physaddr_t *entry ) { + static const uint8_t e_ident[] = { + [EI_MAG0] = ELFMAG0, + [EI_MAG1] = ELFMAG1, + [EI_MAG2] = ELFMAG2, + [EI_MAG3] = ELFMAG3, + [EI_CLASS] = ELFCLASS, + }; Elf_Ehdr ehdr; Elf_Phdr phdr; Elf_Off phoff; @@ -129,7 +137,8 @@ int elf_load ( struct image *image, physaddr_t *entry ) { /* Read ELF header */ copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) ); - if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) { + if ( memcmp ( &ehdr.e_ident[EI_MAG0], e_ident, + sizeof ( e_ident ) ) != 0 ) { DBGC ( image, "ELF %p has invalid signature\n", image ); return -ENOEXEC; } From 943b3003bd8eea1d925abb57c344bea5347d7938 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Tue, 10 Apr 2012 11:54:31 +0100 Subject: [PATCH 155/221] [syslog] Add basic support for encrypted syslog via TLS Encrypted syslog seems not yet to be standardised, but is supported by some existing syslog servers. Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/config/config.c | 3 + src/config/console.h | 1 + src/include/ipxe/dhcp.h | 3 + src/net/tcp/syslogs.c | 275 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 src/net/tcp/syslogs.c diff --git a/src/config/config.c b/src/config/config.c index bc3f7ed5..c96f9c53 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -77,6 +77,9 @@ REQUIRE_OBJECT ( pc_kbd ); #ifdef CONSOLE_SYSLOG REQUIRE_OBJECT ( syslog ); #endif +#ifdef CONSOLE_SYSLOGS +REQUIRE_OBJECT ( syslogs ); +#endif #ifdef CONSOLE_EFI REQUIRE_OBJECT ( efi_console ); #endif diff --git a/src/config/console.h b/src/config/console.h index e7a190aa..95c32803 100644 --- a/src/config/console.h +++ b/src/config/console.h @@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONSOLE_DIRECT_VGA /* Direct access to VGA card */ //#define CONSOLE_PC_KBD /* Direct access to PC keyboard */ //#define CONSOLE_SYSLOG /* Syslog console */ +//#define CONSOLE_SYSLOGS /* Encrypted syslog console */ //#define CONSOLE_VMWARE /* VMware logfile console */ #define KEYBOARD_MAP us diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index 28772302..f5b3136a 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -352,6 +352,9 @@ struct dhcp_client_uuid { */ #define DHCP_EB_SCRIPTLET DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x51 ) +/** Encrypted syslog server */ +#define DHCP_EB_SYSLOGS_SERVER DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x55 ) + /** Skip PXE DHCP protocol extensions such as ProxyDHCP * * If set to a non-zero value, iPXE will not wait for ProxyDHCP offers diff --git a/src/net/tcp/syslogs.c b/src/net/tcp/syslogs.c new file mode 100644 index 00000000..e7480e56 --- /dev/null +++ b/src/net/tcp/syslogs.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Encrypted syslog protocol + * + */ + +#include <stdint.h> +#include <stdlib.h> +#include <byteswap.h> +#include <ipxe/xfer.h> +#include <ipxe/open.h> +#include <ipxe/tcpip.h> +#include <ipxe/dhcp.h> +#include <ipxe/settings.h> +#include <ipxe/console.h> +#include <ipxe/lineconsole.h> +#include <ipxe/tls.h> +#include <ipxe/syslog.h> +#include <config/console.h> + +/* Set default console usage if applicable */ +#if ! ( defined ( CONSOLE_SYSLOGS ) && CONSOLE_EXPLICIT ( CONSOLE_SYSLOGS ) ) +#undef CONSOLE_SYSLOGS +#define CONSOLE_SYSLOGS ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_TUI ) +#endif + +struct console_driver syslogs_console __console_driver; + +/** The encrypted syslog server */ +static struct sockaddr_tcpip logserver = { + .st_family = AF_INET, + .st_port = htons ( SYSLOG_PORT ), +}; + +/** + * Handle encrypted syslog TLS interface close + * + * @v intf Interface + * @v rc Reason for close + */ +static void syslogs_close ( struct interface *intf __unused, int rc ) { + + DBG ( "SYSLOGS console disconnected: %s\n", strerror ( rc ) ); +} + +/** + * Handle encrypted syslog TLS interface window change + * + * @v intf Interface + */ +static void syslogs_window_changed ( struct interface *intf ) { + + /* Mark console as enabled when window first opens, indicating + * that TLS negotiation is complete. (Do not disable console + * when window closes again, since TCP will close the window + * whenever there is unACKed data.) + */ + if ( xfer_window ( intf ) ) { + if ( syslogs_console.disabled ) + DBG ( "SYSLOGS console connected\n" ); + syslogs_console.disabled = 0; + } +} + +/** Encrypted syslog TLS interface operations */ +static struct interface_operation syslogs_operations[] = { + INTF_OP ( xfer_window_changed, struct interface *, + syslogs_window_changed ), + INTF_OP ( intf_close, struct interface *, syslogs_close ), +}; + +/** Encrypted syslog TLS interface descriptor */ +static struct interface_descriptor syslogs_desc = + INTF_DESC_PURE ( syslogs_operations ); + +/** The encrypted syslog TLS interface */ +static struct interface syslogs = INTF_INIT ( syslogs_desc ); + +/****************************************************************************** + * + * Console driver + * + ****************************************************************************** + */ + +/** Encrypted syslog line buffer */ +static char syslogs_buffer[SYSLOG_BUFSIZE]; + +/** Encrypted syslog severity */ +static unsigned int syslogs_severity = SYSLOG_DEFAULT_SEVERITY; + +/** + * Handle ANSI set encrypted syslog priority (private sequence) + * + * @v count Parameter count + * @v params List of graphic rendition aspects + */ +static void syslogs_handle_priority ( unsigned int count __unused, + int params[] ) { + if ( params[0] >= 0 ) { + syslogs_severity = params[0]; + } else { + syslogs_severity = SYSLOG_DEFAULT_SEVERITY; + } +} + +/** Encrypted syslog ANSI escape sequence handlers */ +static struct ansiesc_handler syslogs_handlers[] = { + { ANSIESC_LOG_PRIORITY, syslogs_handle_priority }, + { 0, NULL } +}; + +/** Encrypted syslog line console */ +static struct line_console syslogs_line = { + .buffer = syslogs_buffer, + .len = sizeof ( syslogs_buffer ), + .ctx = { + .handlers = syslogs_handlers, + }, +}; + +/** Encrypted syslog recursion marker */ +static int syslogs_entered; + +/** + * Print a character to encrypted syslog console + * + * @v character Character to be printed + */ +static void syslogs_putchar ( int character ) { + int rc; + + /* Ignore if we are already mid-logging */ + if ( syslogs_entered ) + return; + + /* Fill line buffer */ + if ( line_putchar ( &syslogs_line, character ) == 0 ) + return; + + /* Guard against re-entry */ + syslogs_entered = 1; + + /* Send log message */ + if ( ( rc = xfer_printf ( &syslogs, "<%d>ipxe: %s\n", + SYSLOG_PRIORITY ( SYSLOG_DEFAULT_FACILITY, + syslogs_severity ), + syslogs_buffer ) ) != 0 ) { + DBG ( "SYSLOGS could not send log message: %s\n", + strerror ( rc ) ); + } + + /* Clear re-entry flag */ + syslogs_entered = 0; +} + +/** Encrypted syslog console driver */ +struct console_driver syslogs_console __console_driver = { + .putchar = syslogs_putchar, + .disabled = 1, + .usage = CONSOLE_SYSLOGS, +}; + +/****************************************************************************** + * + * Settings + * + ****************************************************************************** + */ + +/** Encrypted syslog server setting */ +struct setting syslogs_setting __setting ( SETTING_MISC ) = { + .name = "syslogs", + .description = "Encrypted syslog server", + .tag = DHCP_EB_SYSLOGS_SERVER, + .type = &setting_type_string, +}; + +/** + * Apply encrypted syslog settings + * + * @ret rc Return status code + */ +static int apply_syslogs_settings ( void ) { + static char *old_server; + char *server; + struct interface *socket; + int len; + int rc; + + /* Fetch log server */ + len = fetch_string_setting_copy ( NULL, &syslogs_setting, &server ); + if ( len < 0 ) { + rc = len; + goto err_fetch_server; + } + + /* Do nothing unless log server has changed */ + if ( ( ( server == NULL ) && ( old_server == NULL ) ) || + ( ( server != NULL ) && ( old_server != NULL ) && + ( strcmp ( server, old_server ) == 0 ) ) ) { + rc = 0; + goto out_no_change; + } + free ( old_server ); + old_server = NULL; + + /* Reset encrypted syslog connection */ + syslogs_console.disabled = 1; + intf_restart ( &syslogs, 0 ); + + /* Do nothing unless we have a log server */ + if ( ! server ) { + DBG ( "SYSLOGS has no log server\n" ); + rc = 0; + goto out_no_server; + } + + /* Add TLS filter */ + if ( ( rc = add_tls ( &syslogs, server, &socket ) ) != 0 ) { + DBG ( "SYSLOGS cannot create TLS filter: %s\n", + strerror ( rc ) ); + goto err_add_tls; + } + + /* Connect to log server */ + if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM, + (( struct sockaddr *) &logserver ), + server, NULL ) ) != 0 ) { + DBG ( "SYSLOGS cannot connect to log server: %s\n", + strerror ( rc ) ); + goto err_open_named_socket; + } + DBG ( "SYSLOGS using log server %s\n", server ); + + /* Record log server */ + old_server = server; + server = NULL; + + /* Success */ + rc = 0; + + err_open_named_socket: + err_add_tls: + out_no_server: + out_no_change: + free ( server ); + err_fetch_server: + return rc; +} + +/** Encrypted syslog settings applicator */ +struct settings_applicator syslogs_applicator __settings_applicator = { + .apply = apply_syslogs_settings, +}; From 3c13d68f50d556141fb42e58ea2358a54f40f33a Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Tue, 10 Apr 2012 12:55:54 +0100 Subject: [PATCH 156/221] [int13] Fix compilation on some versions of gcc Using __from_text16() and __from_data16() in inline asm constraints sometimes defeats gcc's ability to simplify expressions down to compile-time constants. Reported-by: Jason Kohles <jkohles@palantir.com> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/arch/i386/interface/pcbios/int13.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/arch/i386/interface/pcbios/int13.c b/src/arch/i386/interface/pcbios/int13.c index 6d6d7f87..0a1e7748 100644 --- a/src/arch/i386/interface/pcbios/int13.c +++ b/src/arch/i386/interface/pcbios/int13.c @@ -1499,16 +1499,15 @@ static void int13_hook_vector ( void ) { "cmpb $0x08, -1(%%bp)\n\t" "jne 3f\n\t" "testb $0x80, %%dl\n\t" - "movb %%cs:%c1, %%dl\n\t" + "movb %%cs:num_drives, %%dl\n\t" "jnz 3f\n\t" - "movb %%cs:%c2, %%dl\n\t" + "movb %%cs:num_fdds, %%dl\n\t" /* Return */ "\n3:\n\t" "movw %%bp, %%sp\n\t" "popw %%bp\n\t" "iret\n\t" ) - : : "i" ( int13 ), "i" ( __from_text16 ( &num_drives ) ), - "i" ( __from_text16 ( &num_fdds ) ) ); + : : "i" ( int13 ) ); hook_bios_interrupt ( 0x13, ( unsigned int ) int13_wrapper, &int13_vector ); From ede37e493d61c0cfbe04ab38bcc9819216756abf Mon Sep 17 00:00:00 2001 From: Stefan Weil <sw@weilnetz.de> Date: Wed, 4 Apr 2012 18:16:00 +0200 Subject: [PATCH 157/221] [crypto] Fix wrong setup in function aes_wrap Use explicit size in memset because 8 bytes must be set always. This problem was reported by cppcheck. Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/crypto/aes_wrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/aes_wrap.c b/src/crypto/aes_wrap.c index 46ef016f..f59fbf91 100644 --- a/src/crypto/aes_wrap.c +++ b/src/crypto/aes_wrap.c @@ -48,7 +48,7 @@ int aes_wrap ( const void *kek, const void *src, void *dest, int nblk ) cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 ); /* Set up */ - memset ( A, 0xA6, sizeof ( A ) ); + memset ( A, 0xA6, 8 ); memmove ( dest + 8, src, nblk * 8 ); /* Wrap */ From dcccb1fb7bb79bdd018b23ca203d26cca98a1d3f Mon Sep 17 00:00:00 2001 From: Stefan Weil <sw@weilnetz.de> Date: Wed, 4 Apr 2012 18:16:01 +0200 Subject: [PATCH 158/221] [tls] Fix wrong memset in function tls_clear_cipher sizeof(cipherspec) is obviously wrong in this context, because it will only zero the first 4 or 8 bytes (cipherspec is a pointer). This problem was reported by cppcheck. Signed-off-by: Stefan Weil <sw@weilnetz.de> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/net/tls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/tls.c b/src/net/tls.c index ce39da9a..0f11fbe2 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -594,7 +594,7 @@ static void tls_clear_cipher ( struct tls_session *tls __unused, cipherspec->pubkey_ctx ); } free ( cipherspec->dynamic ); - memset ( cipherspec, 0, sizeof ( cipherspec ) ); + memset ( cipherspec, 0, sizeof ( *cipherspec ) ); cipherspec->suite = &tls_cipher_suite_null; } From 0e4a5ca4c73bc7f264616a0032d60e40c99e6710 Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson <daniel@hozac.com> Date: Fri, 6 Apr 2012 10:13:04 +0200 Subject: [PATCH 159/221] [e1000e] Basic 82579 support Add support for 82579-based chips such as those found on Sandy Bridge motherboards. Based on d3738bb8203acf8552c3ec8b3447133fc0938ddd in Linux. Signed-off-by: Daniel Hokka Zakrisson <daniel@hozac.com> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/drivers/net/e1000e/e1000e.h | 2 + src/drivers/net/e1000e/e1000e_defines.h | 2 + src/drivers/net/e1000e/e1000e_hw.h | 4 ++ src/drivers/net/e1000e/e1000e_ich8lan.c | 51 +++++++++++++++++-------- src/drivers/net/e1000e/e1000e_ich8lan.h | 3 ++ src/drivers/net/e1000e/e1000e_main.c | 17 +++++++++ src/drivers/net/e1000e/e1000e_phy.c | 3 ++ 7 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/drivers/net/e1000e/e1000e.h b/src/drivers/net/e1000e/e1000e.h index bc8e7b08..0e537932 100644 --- a/src/drivers/net/e1000e/e1000e.h +++ b/src/drivers/net/e1000e/e1000e.h @@ -143,6 +143,7 @@ enum e1000_boards { board_ich9lan, board_ich10lan, board_pchlan, + board_pch2lan, board_82583, }; @@ -300,6 +301,7 @@ extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); +extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw); extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); diff --git a/src/drivers/net/e1000e/e1000e_defines.h b/src/drivers/net/e1000e/e1000e_defines.h index da135d91..8cfc6ed8 100644 --- a/src/drivers/net/e1000e/e1000e_defines.h +++ b/src/drivers/net/e1000e/e1000e_defines.h @@ -675,6 +675,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 #define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008 #define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 +#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 #define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 @@ -1261,6 +1262,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define BME1000_E_PHY_ID_R2 0x01410CB1 #define I82577_E_PHY_ID 0x01540050 #define I82578_E_PHY_ID 0x004DD040 +#define I82579_E_PHY_ID 0x01540090 #define M88_VENDOR 0x0141 /* M88E1000 Specific Registers */ diff --git a/src/drivers/net/e1000e/e1000e_hw.h b/src/drivers/net/e1000e/e1000e_hw.h index 03ed35c9..336af30d 100644 --- a/src/drivers/net/e1000e/e1000e_hw.h +++ b/src/drivers/net/e1000e/e1000e_hw.h @@ -85,6 +85,8 @@ struct e1000_hw; #define E1000_DEV_ID_PCH_M_HV_LC 0x10EB #define E1000_DEV_ID_PCH_D_HV_DM 0x10EF #define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 +#define E1000_DEV_ID_PCH2_LV_LM 0x1502 +#define E1000_DEV_ID_PCH2_LV_V 0x1503 #define E1000_REVISION_0 0 #define E1000_REVISION_1 1 #define E1000_REVISION_2 2 @@ -109,6 +111,7 @@ enum e1000_mac_type { e1000_ich9lan, e1000_ich10lan, e1000_pchlan, + e1000_pch2lan, e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ }; @@ -146,6 +149,7 @@ enum e1000_phy_type { e1000_phy_bm, e1000_phy_82578, e1000_phy_82577, + e1000_phy_82579, }; enum e1000_bus_type { diff --git a/src/drivers/net/e1000e/e1000e_ich8lan.c b/src/drivers/net/e1000e/e1000e_ich8lan.c index 7b9a49b9..d438ff1e 100644 --- a/src/drivers/net/e1000e/e1000e_ich8lan.c +++ b/src/drivers/net/e1000e/e1000e_ich8lan.c @@ -206,7 +206,7 @@ static s32 e1000e_init_phy_params_pchlan(struct e1000_hw *hw) e1000e_get_phy_id(hw); phy->type = e1000e_get_phy_type_from_id(phy->id); - if (phy->type == e1000_phy_82577) { + if (phy->type == e1000_phy_82577 || phy->type == e1000_phy_82579) { phy->ops.check_polarity = e1000e_check_polarity_82577; #if 0 phy->ops.force_speed_duplex = @@ -449,6 +449,7 @@ static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw) mac->ops.led_off = e1000e_led_off_ich8lan; break; case e1000_pchlan: + case e1000_pch2lan: /* ID LED init */ mac->ops.id_led_init = e1000e_id_led_init_pchlan; /* setup LED */ @@ -467,6 +468,14 @@ static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw) if (mac->type == e1000_ich8lan) e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true); + /* Disable PHY configuration by hardware, config by software */ + if (mac->type == e1000_pch2lan) { + u32 extcnf_ctrl = er32(EXTCNF_CTRL); + + extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; + ew32(EXTCNF_CTRL, extcnf_ctrl); + } + return E1000_SUCCESS; } @@ -577,6 +586,7 @@ void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw) hw->phy.ops.init_params = e1000e_init_phy_params_ich8lan; break; case e1000_pchlan: + case e1000_pch2lan: hw->phy.ops.init_params = e1000e_init_phy_params_pchlan; break; default: @@ -765,7 +775,8 @@ static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw) /* Check if SW needs to configure the PHY */ if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) || - (hw->mac.type == e1000_pchlan)) + (hw->mac.type == e1000_pchlan) || + (hw->mac.type == e1000_pch2lan)) sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; else sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; @@ -777,13 +788,15 @@ static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw) /* Wait for basic configuration completes before proceeding */ e1000e_lan_init_done_ich8lan(hw); - /* - * Make sure HW does not configure LCD from PHY - * extended configuration before SW configuration - */ - data = er32(EXTCNF_CTRL); - if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) - goto out; + if (hw->mac.type != e1000_pch2lan) { + /* + * Make sure HW does not configure LCD from PHY + * extended configuration before SW configuration + */ + data = er32(EXTCNF_CTRL); + if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) + goto out; + } cnf_size = er32(EXTCNF_SIZE); cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; @@ -795,7 +808,8 @@ static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw) cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && - (hw->mac.type == e1000_pchlan)) { + (hw->mac.type == e1000_pchlan || + hw->mac.type == e1000_pch2lan)) { /* * HW configures the SMBus address and LEDs when the * OEM and LCD Write Enable bits are set in the NVM. @@ -1006,16 +1020,18 @@ s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) u32 mac_reg; u16 oem_reg; - if (hw->mac.type != e1000_pchlan) + if (hw->mac.type != e1000_pchlan && hw->mac.type != e1000_pch2lan) return ret_val; ret_val = hw->phy.ops.acquire(hw); if (ret_val) return ret_val; - mac_reg = er32(EXTCNF_CTRL); - if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) - goto out; + if (hw->mac.type != e1000_pch2lan) { + mac_reg = er32(EXTCNF_CTRL); + if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) + goto out; + } mac_reg = er32(FEXTNVM); if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) @@ -2573,7 +2589,7 @@ static s32 e1000e_reset_hw_ich8lan(struct e1000_hw *hw) } } /* Dummy read to clear the phy wakeup bit after lcd reset */ - if (hw->mac.type == e1000_pchlan) + if (hw->mac.type == e1000_pchlan || hw->mac.type == e1000_pch2lan) e1e_rphy(hw, BM_WUC, ®); ret_val = e1000e_sw_lcd_config_ich8lan(hw); @@ -2791,6 +2807,7 @@ static s32 e1000e_setup_link_ich8lan(struct e1000_hw *hw) ew32(FCTTV, hw->fc.pause_time); if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82579) || (hw->phy.type == e1000_phy_82577)) { ret_val = e1e_wphy(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27), @@ -2859,6 +2876,7 @@ static s32 e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw) goto out; break; case e1000_phy_82577: + case e1000_phy_82579: ret_val = e1000e_copper_link_setup_82577(hw); if (ret_val) goto out; @@ -3388,6 +3406,7 @@ static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw __unused) /* Clear PHY statistics registers */ if ((hw->phy.type == e1000_phy_82578) || + (hw->phy.type == e1000_phy_82579) || (hw->phy.type == e1000_phy_82577)) { e1e_rphy(hw, HV_SCC_UPPER, &phy_data); e1e_rphy(hw, HV_SCC_LOWER, &phy_data); @@ -3434,6 +3453,8 @@ static struct pci_device_id e1000e_ich8lan_nics[] = { PCI_ROM(0x8086, 0x10EB, "E1000_DEV_ID_PCH_M_HV_LC", "E1000_DEV_ID_PCH_M_HV_LC", board_pchlan), PCI_ROM(0x8086, 0x10EF, "E1000_DEV_ID_PCH_D_HV_DM", "E1000_DEV_ID_PCH_D_HV_DM", board_pchlan), PCI_ROM(0x8086, 0x10F0, "E1000_DEV_ID_PCH_D_HV_DC", "E1000_DEV_ID_PCH_D_HV_DC", board_pchlan), + PCI_ROM(0x8086, 0x1502, "E1000_DEV_ID_PCH2_LV_LM", "E1000_DEV_ID_PCH2_LV_LM", board_pch2lan), + PCI_ROM(0x8086, 0x1503, "E1000_DEV_ID_PCH2_LV_V", "E1000_DEV_ID_PCH2_LV_V", board_pch2lan), }; struct pci_driver e1000e_ich8lan_driver __pci_driver = { diff --git a/src/drivers/net/e1000e/e1000e_ich8lan.h b/src/drivers/net/e1000e/e1000e_ich8lan.h index af344782..8b145d92 100644 --- a/src/drivers/net/e1000e/e1000e_ich8lan.h +++ b/src/drivers/net/e1000e/e1000e_ich8lan.h @@ -146,6 +146,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define HV_SMB_ADDR_PEC_EN 0x0200 #define HV_SMB_ADDR_VALID 0x0080 +/* PHY Power Management Control */ +#define HV_PM_CTRL PHY_REG(770, 17) + /* Strapping Option Register - RO */ #define E1000_STRAP 0x0000C #define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000 diff --git a/src/drivers/net/e1000e/e1000e_main.c b/src/drivers/net/e1000e/e1000e_main.c index 352e3c45..69a5bc20 100644 --- a/src/drivers/net/e1000e/e1000e_main.c +++ b/src/drivers/net/e1000e/e1000e_main.c @@ -279,6 +279,22 @@ static struct e1000_info e1000_pch_info = { .get_variants = e1000e_get_variants_ich8lan, }; +static struct e1000_info e1000_pch2_info = { + .mac = e1000_pch2lan, + .flags = FLAG_IS_ICH + | FLAG_HAS_WOL + | FLAG_RX_CSUM_ENABLED + | FLAG_HAS_CTRLEXT_ON_LOAD + | FLAG_HAS_AMT + | FLAG_HAS_FLASH + | FLAG_HAS_JUMBO_FRAMES + | FLAG_APME_IN_WUC, + .pba = 26, + .max_hw_frame_size = DEFAULT_JUMBO, + .init_ops = e1000e_init_function_pointers_ich8lan, + .get_variants = e1000e_get_variants_ich8lan, +}; + static const struct e1000_info *e1000_info_tbl[] = { [board_82571] = &e1000_82571_info, [board_82572] = &e1000_82572_info, @@ -290,6 +306,7 @@ static const struct e1000_info *e1000_info_tbl[] = { [board_ich9lan] = &e1000_ich9_info, [board_ich10lan] = &e1000_ich10_info, [board_pchlan] = &e1000_pch_info, + [board_pch2lan] = &e1000_pch2_info, }; /* Low-level support routines */ diff --git a/src/drivers/net/e1000e/e1000e_phy.c b/src/drivers/net/e1000e/e1000e_phy.c index 337be737..133109dc 100644 --- a/src/drivers/net/e1000e/e1000e_phy.c +++ b/src/drivers/net/e1000e/e1000e_phy.c @@ -2332,6 +2332,9 @@ enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) case I82577_E_PHY_ID: phy_type = e1000_phy_82577; break; + case I82579_E_PHY_ID: + phy_type = e1000_phy_82579; + break; default: phy_type = e1000_phy_unknown; break; From 96a8c70a0cf4eadad8e306618f76177d0e8ea52d Mon Sep 17 00:00:00 2001 From: Erik Jacobson <ejacobson@ddn.com> Date: Thu, 5 Apr 2012 11:31:57 -0500 Subject: [PATCH 160/221] [igbvf] Add i350 virtual function support Modified-by: Michael Brown <mcb30@ipxe.org> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/drivers/net/igbvf/igbvf_main.c | 3 ++- src/drivers/net/igbvf/igbvf_vf.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/drivers/net/igbvf/igbvf_main.c b/src/drivers/net/igbvf/igbvf_main.c index 1f7e1dfd..cd189ecb 100644 --- a/src/drivers/net/igbvf/igbvf_main.c +++ b/src/drivers/net/igbvf/igbvf_main.c @@ -942,7 +942,8 @@ void igbvf_remove ( struct pci_device *pdev ) } static struct pci_device_id igbvf_pci_tbl[] = { - PCI_ROM(0x8086, 0x10CA, "igbvf", "E1000_DEV_ID_82576_VF", 0) + PCI_ROM(0x8086, 0x10CA, "igbvf", "E1000_DEV_ID_82576_VF", 0), + PCI_ROM(0x8086, 0x1520, "i350vf", "E1000_DEV_ID_I350_VF", 0), }; diff --git a/src/drivers/net/igbvf/igbvf_vf.h b/src/drivers/net/igbvf/igbvf_vf.h index ce8ad796..8d8963fe 100644 --- a/src/drivers/net/igbvf/igbvf_vf.h +++ b/src/drivers/net/igbvf/igbvf_vf.h @@ -54,6 +54,7 @@ FILE_LICENCE ( GPL2_ONLY ); struct e1000_hw; #define E1000_DEV_ID_82576_VF 0x10CA +#define E1000_DEV_ID_I350_VF 0x1520 #define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */ From 196751ce95fa6b6566a5b336193681fad3581fd1 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Tue, 10 Apr 2012 19:38:54 +0100 Subject: [PATCH 161/221] [build] Enable warnings when building utilities Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/Makefile | 1 + src/Makefile.housekeeping | 25 +++++++++++++++---------- src/util/efirom.c | 18 +++--------------- src/util/einfo.c | 13 +++++++------ src/util/elf2efi.c | 7 ++++--- src/util/iccfix.c | 3 ++- src/util/nrv2b.c | 5 ++--- src/util/zbin.c | 7 +++++-- 8 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/Makefile b/src/Makefile index 0189a469..6537ecb4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -7,6 +7,7 @@ CLEANUP := CFLAGS := ASFLAGS := LDFLAGS := +HOST_CFLAGS := MAKEDEPS := Makefile ############################################################################### diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index 0fab407c..bf4b93c5 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -381,6 +381,7 @@ CFLAGS += -g ifeq ($(CCTYPE),gcc) CFLAGS += -ffreestanding CFLAGS += -Wall -W -Wformat-nonliteral +HOST_CFLAGS += -Wall -W -Wformat-nonliteral endif ifeq ($(CCTYPE),icc) CFLAGS += -fno-builtin @@ -411,12 +412,14 @@ endif CFLAGS += $(WORKAROUND_CFLAGS) $(EXTRA_CFLAGS) ASFLAGS += $(WORKAROUND_ASFLAGS) $(EXTRA_ASFLAGS) LDFLAGS += $(WORKAROUND_LDFLAGS) $(EXTRA_LDFLAGS) +HOST_CFLAGS += -O2 -g # Inhibit -Werror if NO_WERROR is specified on make command line # ifneq ($(NO_WERROR),1) CFLAGS += -Werror ASFLAGS += --fatal-warnings +HOST_CFLAGS += -Werror endif # Function trace recorder state in the last build. This is needed @@ -1057,13 +1060,13 @@ endif # defined(BIN) # $(NRV2B) : util/nrv2b.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) -O2 -DENCODE -DDECODE -DMAIN -DVERBOSE -DNDEBUG \ - -DBITSIZE=32 -DENDIAN=0 -o $@ $< + $(Q)$(HOST_CC) $(HOST_CFLAGS) -DENCODE -DDECODE -DMAIN -DVERBOSE \ + -DNDEBUG -DBITSIZE=32 -DENDIAN=0 -o $@ $< CLEANUP += $(NRV2B) $(ZBIN) : util/zbin.c util/nrv2b.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) -O2 -o $@ $< + $(Q)$(HOST_CC) $(HOST_CFLAGS) -o $@ $< CLEANUP += $(ZBIN) ############################################################################### @@ -1071,23 +1074,25 @@ CLEANUP += $(ZBIN) # The EFI image converter # ELF2EFI_CFLAGS := -I$(BINUTILS_DIR)/include -I$(BFD_DIR)/include \ - -I$(ZLIB_DIR)/include -idirafter include \ - -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \ + -I$(ZLIB_DIR)/include -idirafter include +ELF2EFI_LDFLAGS := -L$(BINUTILS_DIR)/lib -L$(BFD_DIR)/lib -L$(ZLIB_DIR)/lib \ -lbfd -ldl -liberty -lz -Wl,--no-warn-search-mismatch $(ELF2EFI32) : util/elf2efi.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 -O2 -o $@ + $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_IA32 $< \ + $(ELF2EFI_LDFLAGS) -o $@ CLEANUP += $(ELF2EFI32) $(ELF2EFI64) : util/elf2efi.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) $< $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 -O2 -o $@ + $(Q)$(HOST_CC) $(HOST_CFLAGS) $(ELF2EFI_CFLAGS) -DEFI_TARGET_X64 $< \ + $(ELF2EFI_LDFLAGS) -o $@ CLEANUP += $(ELF2EFI64) $(EFIROM) : util/efirom.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) -idirafter include -O2 -o $@ $< + $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(EFIROM) ############################################################################### @@ -1096,7 +1101,7 @@ CLEANUP += $(EFIROM) # $(ICCFIX) : util/iccfix.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) -idirafter include -O2 -o $@ $< + $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(ICCFIX) ############################################################################### @@ -1105,7 +1110,7 @@ CLEANUP += $(ICCFIX) # $(EINFO) : util/einfo.c $(MAKEDEPS) $(QM)$(ECHO) " [HOSTCC] $@" - $(Q)$(HOST_CC) -idirafter include -O2 -o $@ $< + $(Q)$(HOST_CC) $(HOST_CFLAGS) -idirafter include -o $@ $< CLEANUP += $(EINFO) ############################################################################### diff --git a/src/util/efirom.c b/src/util/efirom.c index d0bdace6..a65abfee 100644 --- a/src/util/efirom.c +++ b/src/util/efirom.c @@ -56,18 +56,6 @@ static void * xmalloc ( size_t len ) { return ptr; } -/** - * Get file size - * - * @v file File - * @v len File size - */ -static size_t file_size ( FILE *file ) { - ssize_t len; - - return len; -} - /** * Read information from PE headers * @@ -239,15 +227,15 @@ static int parse_options ( const int argc, char **argv, } int main ( int argc, char **argv ) { - struct options opts = { - }; - unsigned int infile_index; + struct options opts; + int infile_index; const char *infile_name; const char *outfile_name; FILE *infile; FILE *outfile; /* Parse command-line arguments */ + memset ( &opts, 0, sizeof ( opts ) ); infile_index = parse_options ( argc, argv, &opts ); if ( argc != ( infile_index + 2 ) ) { print_help ( argv[0] ); diff --git a/src/util/einfo.c b/src/util/einfo.c index 06736f21..15f920d0 100644 --- a/src/util/einfo.c +++ b/src/util/einfo.c @@ -20,6 +20,7 @@ #include <stdint.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> @@ -49,7 +50,8 @@ struct einfo { * @v infile Filename * @v opts Command-line options */ -static void einfo ( const char *infile, struct options *opts ) { +static void einfo ( const char *infile, + struct options *opts __attribute__ (( unused )) ) { int fd; struct stat stat; size_t len; @@ -85,9 +87,9 @@ static void einfo ( const char *infile, struct options *opts ) { for ( einfo = start ; ( ( void * ) einfo ) < ( start + len ) ; einfo = ( ( ( void * ) einfo ) + einfo->size ) ) { printf ( "%08x\t%s\t%d\t%s\n", einfo->error, - ( ( ( void * ) einfo ) + einfo->file ), + ( ( ( char * ) einfo ) + einfo->file ), einfo->line, - ( ( ( void * ) einfo ) + einfo->desc ) ); + ( ( ( char * ) einfo ) + einfo->desc ) ); } } @@ -115,8 +117,7 @@ static void print_help ( const char *program_name ) { * @v opts Options structure to populate */ static int parse_options ( const int argc, char **argv, - struct options *opts ) { - char *end; + struct options *opts __attribute__ (( unused )) ) { int c; while (1) { @@ -147,7 +148,7 @@ static int parse_options ( const int argc, char **argv, int main ( int argc, char **argv ) { struct options opts = { }; - unsigned int infile_index; + int infile_index; const char *infile; /* Parse command-line arguments */ diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index e6629296..c8df22e1 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -459,7 +459,8 @@ static struct pe_section * process_section ( bfd *bfd, * @v rel Relocation entry * @v pe_reltab PE relocation table to fill in */ -static void process_reloc ( bfd *bfd, asection *section, arelent *rel, +static void process_reloc ( bfd *bfd __attribute__ (( unused )), + asection *section, arelent *rel, struct pe_relocs **pe_reltab ) { reloc_howto_type *howto = rel->howto; asymbol *sym = *(rel->sym_ptr_ptr); @@ -637,7 +638,7 @@ static void write_pe_file ( struct pe_header *pe_header, for ( section = pe_sections ; section ; section = section->next ) { if ( fseek ( pe, section->hdr.PointerToRawData, SEEK_SET ) != 0 ) { - eprintf ( "Could not seek to %lx: %s\n", + eprintf ( "Could not seek to %x: %s\n", section->hdr.PointerToRawData, strerror ( errno ) ); exit ( 1 ); @@ -786,7 +787,7 @@ int main ( int argc, char **argv ) { struct options opts = { .subsystem = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, }; - unsigned int infile_index; + int infile_index; const char *infile; const char *outfile; diff --git a/src/util/iccfix.c b/src/util/iccfix.c index 8b555c54..528bf4b2 100644 --- a/src/util/iccfix.c +++ b/src/util/iccfix.c @@ -2,6 +2,7 @@ #include <stddef.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> @@ -49,7 +50,7 @@ static int ICCFIX ( void *elf ) { ( align >= ICC_ALIGN_HACK_FACTOR ) ) { new_align = ( align / ICC_ALIGN_HACK_FACTOR ); shdr->sh_addralign = new_align; - dprintf ( "Section \"%s\": alignment %d->%d\n", + dprintf ( "Section \"%s\": alignment %ld->%ld\n", name, align, new_align ); } } diff --git a/src/util/nrv2b.c b/src/util/nrv2b.c index 6bac4cdd..cbb94c0e 100644 --- a/src/util/nrv2b.c +++ b/src/util/nrv2b.c @@ -77,7 +77,7 @@ static __inline__ void Error(char *message) /* These will be a complete waste of time on a lo-endian */ /* system, but it only gets done once so WTF. */ -static unsigned long i86ul_to_host(unsigned long ul) +static unsigned long __attribute__ (( unused )) i86ul_to_host(unsigned long ul) { unsigned long res = 0; int i; @@ -375,7 +375,6 @@ static int swd_init(struct ucl_swd *s, const uint8_t *dict, unsigned int dict_len) { unsigned int i = 0; - int c = 0; if (s->n == 0) s->n = N; @@ -439,7 +438,7 @@ static void swd_exit(struct ucl_swd *s) { /* unused s */ - + ( void ) s; } #define swd_pos2off(s,pos) \ diff --git a/src/util/zbin.c b/src/util/zbin.c index f0df5ea0..a9195164 100644 --- a/src/util/zbin.c +++ b/src/util/zbin.c @@ -218,7 +218,8 @@ static int process_zinfo_pack ( struct input_file *input, return 0; } -static int process_zinfo_payl ( struct input_file *input, +static int process_zinfo_payl ( struct input_file *input + __attribute__ (( unused )), struct output_file *output, union zinfo_record *zinfo ) { struct zinfo_payload *payload = &zinfo->payload; @@ -229,9 +230,11 @@ static int process_zinfo_payl ( struct input_file *input, if ( DEBUG ) { fprintf ( stderr, "PAYL at %#zx\n", output->hdr_len ); } + return 0; } -static int process_zinfo_add ( struct input_file *input, +static int process_zinfo_add ( struct input_file *input + __attribute__ (( unused )), struct output_file *output, size_t len, struct zinfo_add *add, From 6ab98fa9f74f774ce445c827ae144d7b93ac9716 Mon Sep 17 00:00:00 2001 From: Marin Mareo Hannache <mareo@mareo.fr> Date: Sun, 1 Apr 2012 17:30:43 +0200 Subject: [PATCH 162/221] [tftp] Remove configuration option for tftm DOWNLOAD_PROTO_TFTM is now useless as tftm support has been merged into tftp.c. DOWNLOAD_PROTO_TFTP should be used instead. Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/config/config.c | 3 --- src/config/general.h | 1 - 2 files changed, 4 deletions(-) diff --git a/src/config/config.c b/src/config/config.c index c96f9c53..513f054f 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -125,9 +125,6 @@ REQUIRE_OBJECT ( https ); #ifdef DOWNLOAD_PROTO_FTP REQUIRE_OBJECT ( ftp ); #endif -#ifdef DOWNLOAD_PROTO_TFTM -REQUIRE_OBJECT ( tftm ); -#endif #ifdef DOWNLOAD_PROTO_SLAM REQUIRE_OBJECT ( slam ); #endif diff --git a/src/config/general.h b/src/config/general.h index 70742165..ec095028 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -58,7 +58,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define DOWNLOAD_PROTO_HTTP /* Hypertext Transfer Protocol */ #undef DOWNLOAD_PROTO_HTTPS /* Secure Hypertext Transfer Protocol */ #undef DOWNLOAD_PROTO_FTP /* File Transfer Protocol */ -#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */ #undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */ /* From cc288dc0f88e6b3aa578073ffb7566db50920f08 Mon Sep 17 00:00:00 2001 From: Marin Mareo Hannache <mareo@mareo.fr> Date: Sun, 1 Apr 2012 19:25:56 +0200 Subject: [PATCH 163/221] [linux] Fix a build error on some platforms Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/arch/x86_64/core/linux/linuxprefix.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/arch/x86_64/core/linux/linuxprefix.S b/src/arch/x86_64/core/linux/linuxprefix.S index 713b9e38..ec8a9dec 100644 --- a/src/arch/x86_64/core/linux/linuxprefix.S +++ b/src/arch/x86_64/core/linux/linuxprefix.S @@ -22,4 +22,4 @@ _linux_start: movq $__NR_exit, %rax syscall - .size _start, . - _start + .size _linux_start, . - _linux_start From d11b82f0e401ca6499e590fa348c8dbd67bc1d40 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Sun, 15 Apr 2012 00:15:41 +0100 Subject: [PATCH 164/221] [multiboot] Include full image URI in command line Solaris kernels seem to rely on having the full kernel path present in the multiboot command line; if only the kernel name is present then the boot fails with the error message krtld: failed to open 'unix' Debugged-by: Michael Brown <mcb30@ipxe.org> Debugged-by: Scott McWhirter <scottm@joyent.com> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/arch/i386/image/multiboot.c | 47 ++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/arch/i386/image/multiboot.c b/src/arch/i386/image/multiboot.c index 15e8fd52..0336581f 100644 --- a/src/arch/i386/image/multiboot.c +++ b/src/arch/i386/image/multiboot.c @@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <ipxe/elf.h> #include <ipxe/init.h> #include <ipxe/features.h> +#include <ipxe/uri.h> FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 ); @@ -139,26 +140,35 @@ static void multiboot_build_memmap ( struct image *image, /** * Add command line in base memory * - * @v imgname Image name - * @v cmdline Command line + * @v image Image * @ret physaddr Physical address of command line */ -physaddr_t multiboot_add_cmdline ( const char *imgname, const char *cmdline ) { - char *mb_cmdline; +physaddr_t multiboot_add_cmdline ( struct image *image ) { + char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset ); + size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ); + char *buf = mb_cmdline; + size_t len; - if ( ! cmdline ) - cmdline = ""; + /* Copy image URI to base memory buffer as start of command line */ + len = ( unparse_uri ( buf, remaining, image->uri, + URI_ALL ) + 1 /* NUL */ ); + if ( len > remaining ) + len = remaining; + mb_cmdline_offset += len; + buf += len; + remaining -= len; - /* Copy command line to base memory buffer */ - mb_cmdline = ( mb_cmdlines + mb_cmdline_offset ); - mb_cmdline_offset += - ( snprintf ( mb_cmdline, - ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ), - "%s %s", imgname, cmdline ) + 1 ); - - /* Truncate to terminating NUL in buffer if necessary */ - if ( mb_cmdline_offset > sizeof ( mb_cmdlines ) ) - mb_cmdline_offset = ( sizeof ( mb_cmdlines ) - 1 ); + /* Copy command line to base memory buffer, if present */ + if ( image->cmdline ) { + mb_cmdline_offset--; /* Strip NUL */ + buf--; + remaining++; + len = ( snprintf ( buf, remaining, " %s", + image->cmdline ) + 1 /* NUL */ ); + if ( len > remaining ) + len = remaining; + mb_cmdline_offset += len; + } return virt_to_phys ( mb_cmdline ); } @@ -209,8 +219,7 @@ multiboot_build_module_list ( struct image *image, ( ( count - insert ) * sizeof ( *module ) ) ); module->mod_start = start; module->mod_end = end; - module->string = multiboot_add_cmdline ( module_image->name, - module_image->cmdline ); + module->string = multiboot_add_cmdline ( module_image ); module->reserved = 0; /* We promise to page-align modules */ @@ -405,7 +414,7 @@ static int multiboot_exec ( struct image *image ) { mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP | MBI_FLAG_CMDLINE | MBI_FLAG_MODS ); mb_cmdline_offset = 0; - mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline ); + mbinfo.cmdline = multiboot_add_cmdline ( image ); mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules, ( sizeof(mbmodules) / sizeof(mbmodules[0]) ) ); mbinfo.mods_addr = virt_to_phys ( mbmodules ); From 1d33649516f2046e9fe692d42fffeeec96a2b858 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Tue, 17 Apr 2012 10:15:29 +0100 Subject: [PATCH 165/221] [libc] Allow strtoul() to interpret negative numbers Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/arch/i386/core/runtime.c | 1 + src/core/misc.c | 12 ++++++++++++ src/core/strtoull.c | 12 ++++++++++++ src/include/stdlib.h | 4 ---- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/arch/i386/core/runtime.c b/src/arch/i386/core/runtime.c index efa501e6..fcfec060 100644 --- a/src/arch/i386/core/runtime.c +++ b/src/arch/i386/core/runtime.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stddef.h> #include <stdint.h> #include <stdlib.h> +#include <ctype.h> #include <errno.h> #include <assert.h> #include <ipxe/init.h> diff --git a/src/core/misc.c b/src/core/misc.c index 8f56e1fb..11342481 100644 --- a/src/core/misc.c +++ b/src/core/misc.c @@ -35,8 +35,17 @@ int inet_aton ( const char *cp, struct in_addr *inp ) { unsigned long strtoul ( const char *p, char **endp, int base ) { unsigned long ret = 0; + int negative = 0; unsigned int charval; + while ( isspace ( *p ) ) + p++; + + if ( *p == '-' ) { + negative = 1; + p++; + } + base = strtoul_base ( &p, base ); while ( 1 ) { @@ -47,6 +56,9 @@ unsigned long strtoul ( const char *p, char **endp, int base ) { p++; } + if ( negative ) + ret = -ret; + if ( endp ) *endp = ( char * ) p; diff --git a/src/core/strtoull.c b/src/core/strtoull.c index b1ceeb45..00986eef 100644 --- a/src/core/strtoull.c +++ b/src/core/strtoull.c @@ -29,8 +29,17 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ unsigned long long strtoull ( const char *p, char **endp, int base ) { unsigned long long ret = 0; + int negative = 0; unsigned int charval; + while ( isspace ( *p ) ) + p++; + + if ( *p == '-' ) { + negative = 1; + p++; + } + base = strtoul_base ( &p, base ); while ( 1 ) { @@ -41,6 +50,9 @@ unsigned long long strtoull ( const char *p, char **endp, int base ) { p++; } + if ( negative ) + ret = -ret; + if ( endp ) *endp = ( char * ) p; diff --git a/src/include/stdlib.h b/src/include/stdlib.h index 19a7c8e0..3d30858f 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -5,7 +5,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> #include <assert.h> -#include <ctype.h> /***************************************************************************** * @@ -18,9 +17,6 @@ static inline int strtoul_base ( const char **pp, int base ) { const char *p = *pp; - while ( isspace ( *p ) ) - p++; - if ( base == 0 ) { base = 10; if ( *p == '0' ) { From 46409231ba7c94791a95bda98f90c892bd2c4580 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Tue, 17 Apr 2012 10:38:30 +0100 Subject: [PATCH 166/221] [test] Add self-tests for setting types Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/include/ipxe/settings.h | 2 + src/tests/settings_test.c | 278 ++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 3 files changed, 281 insertions(+) create mode 100644 src/tests/settings_test.c diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 0f1ec5ba..27ce1f9d 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -283,6 +283,7 @@ extern int fetchf_named_setting ( const char *name, char *name_buf, extern char * expand_settings ( const char *string ); extern struct setting_type setting_type_string __setting_type; +extern struct setting_type setting_type_uristring __setting_type; extern struct setting_type setting_type_ipv4 __setting_type; extern struct setting_type setting_type_int8 __setting_type; extern struct setting_type setting_type_int16 __setting_type; @@ -291,6 +292,7 @@ extern struct setting_type setting_type_uint8 __setting_type; extern struct setting_type setting_type_uint16 __setting_type; extern struct setting_type setting_type_uint32 __setting_type; extern struct setting_type setting_type_hex __setting_type; +extern struct setting_type setting_type_hexhyp __setting_type; extern struct setting_type setting_type_uuid __setting_type; extern struct setting ip_setting __setting ( SETTING_IPv4 ); diff --git a/src/tests/settings_test.c b/src/tests/settings_test.c new file mode 100644 index 00000000..ccc2694b --- /dev/null +++ b/src/tests/settings_test.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * Settings self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include <string.h> +#include <ipxe/settings.h> +#include <ipxe/test.h> + +/** Define inline raw data */ +#define RAW(...) { __VA_ARGS__ } + +/** + * Report a formatted-store test result + * + * @v settings Settings block + * @v setting Setting + * @v formatted Formatted value + * @v raw_array Expected raw value + */ +#define storef_ok( settings, setting, formatted, raw_array ) do { \ + const uint8_t expected[] = raw_array; \ + uint8_t actual[ sizeof ( expected ) ]; \ + int len; \ + \ + ok ( storef_setting ( settings, setting, formatted ) == 0 ); \ + len = fetch_setting ( settings, setting, actual, \ + sizeof ( actual ) ); \ + DBGC ( settings, "Stored %s \"%s\", got:\n", \ + (setting)->type->name, formatted ); \ + DBGC_HDA ( settings, 0, actual, len ); \ + ok ( len == ( int ) sizeof ( actual ) ); \ + ok ( memcmp ( actual, expected, sizeof ( actual ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report a formatted-fetch test result + * + * @v settings Settings block + * @v setting Setting + * @v raw_array Raw value + * @v formatted Expected formatted value + */ +#define fetchf_ok( settings, setting, raw_array, formatted ) do { \ + const uint8_t raw[] = raw_array; \ + char actual[ strlen ( formatted ) + 1 ]; \ + int len; \ + \ + ok ( store_setting ( settings, setting, raw, \ + sizeof ( raw ) ) == 0 ); \ + len = fetchf_setting ( settings, setting, actual, \ + sizeof ( actual ) ); \ + DBGC ( settings, "Fetched %s \"%s\" from:\n", \ + (setting)->type->name, formatted ); \ + DBGC_HDA ( settings, 0, raw, sizeof ( raw ) ); \ + ok ( len == ( int ) ( sizeof ( actual ) - 1 ) ); \ + ok ( strcmp ( actual, formatted ) == 0 ); \ + } while ( 0 ) + +/** Test generic settings block */ +struct generic_settings test_generic_settings = { + .settings = { + .refcnt = NULL, + .siblings = + LIST_HEAD_INIT ( test_generic_settings.settings.siblings ), + .children = + LIST_HEAD_INIT ( test_generic_settings.settings.children ), + .op = &generic_settings_operations, + }, + .list = LIST_HEAD_INIT ( test_generic_settings.list ), +}; + +/** Test settings block */ +#define test_settings test_generic_settings.settings + +/** Test string setting */ +static struct setting test_string_setting = { + .name = "test_string", + .type = &setting_type_string, +}; + +/** Test URI-encoded string setting */ +static struct setting test_uristring_setting = { + .name = "test_uristring", + .type = &setting_type_uristring, +}; + +/** Test IPv4 address setting type */ +static struct setting test_ipv4_setting = { + .name = "test_ipv4", + .type = &setting_type_ipv4, +}; + +/** Test signed 8-bit integer setting type */ +static struct setting test_int8_setting = { + .name = "test_int8", + .type = &setting_type_int8, +}; + +/** Test signed 16-bit integer setting type */ +static struct setting test_int16_setting = { + .name = "test_int16", + .type = &setting_type_int16, +}; + +/** Test signed 32-bit integer setting type */ +static struct setting test_int32_setting = { + .name = "test_int32", + .type = &setting_type_int32, +}; + +/** Test unsigned 8-bit integer setting type */ +static struct setting test_uint8_setting = { + .name = "test_uint8", + .type = &setting_type_uint8, +}; + +/** Test unsigned 16-bit integer setting type */ +static struct setting test_uint16_setting = { + .name = "test_uint16", + .type = &setting_type_uint16, +}; + +/** Test unsigned 32-bit integer setting type */ +static struct setting test_uint32_setting = { + .name = "test_uint32", + .type = &setting_type_uint32, +}; + +/** Test colon-separated hex string setting type */ +static struct setting test_hex_setting = { + .name = "test_hex", + .type = &setting_type_hex, +}; + +/** Test hyphen-separated hex string setting type */ +static struct setting test_hexhyp_setting = { + .name = "test_hexhyp", + .type = &setting_type_hexhyp, +}; + +/** Test UUID setting type */ +static struct setting test_uuid_setting = { + .name = "test_uuid", + .type = &setting_type_uuid, +}; + +/** + * Perform settings self-tests + * + */ +static void settings_test_exec ( void ) { + + /* Register test settings block */ + ok ( register_settings ( &test_settings, NULL, "test" ) == 0 ); + + /* "string" setting type */ + storef_ok ( &test_settings, &test_string_setting, "hello", + RAW ( 'h', 'e', 'l', 'l', 'o' ) ); + fetchf_ok ( &test_settings, &test_string_setting, + RAW ( 'w', 'o', 'r', 'l', 'd' ), "world" ); + + /* "uristring" setting type */ + storef_ok ( &test_settings, &test_uristring_setting, "hello%20world", + RAW ( 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', + 'd' ) ); + fetchf_ok ( &test_settings, &test_uristring_setting, + RAW ( 1, 2, 3, 4, 5 ), "%01%02%03%04%05" ); + + /* "ipv4" setting type */ + storef_ok ( &test_settings, &test_ipv4_setting, "192.168.0.1", + RAW ( 192, 168, 0, 1 ) ); + fetchf_ok ( &test_settings, &test_ipv4_setting, + RAW ( 212, 13, 204, 60 ), "212.13.204.60" ); + + /* Integer setting types */ + storef_ok ( &test_settings, &test_int8_setting, + "54", RAW ( 54 ) ); + storef_ok ( &test_settings, &test_int8_setting, + "0x7f", RAW ( 0x7f ) ); + storef_ok ( &test_settings, &test_int8_setting, + "0x1234", RAW ( 0x34 ) ); + storef_ok ( &test_settings, &test_int8_setting, + "-32", RAW ( -32 ) ); + fetchf_ok ( &test_settings, &test_int8_setting, + RAW ( -9 ), "-9" ); + fetchf_ok ( &test_settings, &test_int8_setting, + RAW ( 106 ), "106" ); + storef_ok ( &test_settings, &test_uint8_setting, + "129", RAW ( 129 ) ); + storef_ok ( &test_settings, &test_uint8_setting, + "0x3421", RAW ( 0x21 ) ); + fetchf_ok ( &test_settings, &test_uint8_setting, + RAW ( 0x54 ), "0x54" ); + storef_ok ( &test_settings, &test_int16_setting, + "29483", RAW ( 0x73, 0x2b ) ); + fetchf_ok ( &test_settings, &test_int16_setting, + RAW ( 0x82, 0x14 ), "-32236" ); + fetchf_ok ( &test_settings, &test_int16_setting, + RAW ( 0x12, 0x78 ), "4728" ); + storef_ok ( &test_settings, &test_uint16_setting, + "48727", RAW ( 0xbe, 0x57 ) ); + fetchf_ok ( &test_settings, &test_uint16_setting, + RAW ( 0x9a, 0x24 ), "0x9a24" ); + storef_ok ( &test_settings, &test_int32_setting, + "2901274", RAW ( 0x00, 0x2c, 0x45, 0x1a ) ); + fetchf_ok ( &test_settings, &test_int32_setting, + RAW ( 0xff, 0x34, 0x2d, 0xaf ), "-13357649" ); + fetchf_ok ( &test_settings, &test_int32_setting, + RAW ( 0x01, 0x00, 0x34, 0xab ), "16790699" ); + storef_ok ( &test_settings, &test_uint32_setting, + "0xb598d21", RAW ( 0x0b, 0x59, 0x8d, 0x21 ) ); + fetchf_ok ( &test_settings, &test_uint32_setting, + RAW ( 0xf2, 0x37, 0xb2, 0x18 ), "0xf237b218" ); + + /* "hex" setting type */ + storef_ok ( &test_settings, &test_hex_setting, + "", RAW ( 0x00 ) ); + storef_ok ( &test_settings, &test_hex_setting, + ":", RAW ( 0x00, 0x00 ) ); + storef_ok ( &test_settings, &test_hex_setting, + "1:2:", RAW ( 0x01, 0x02, 0x00 ) ); + storef_ok ( &test_settings, &test_hex_setting, + "08:12:f5:22:90:1b:4b:47:a8:30:cb:4d:67:4c:d6:76", + RAW ( 0x08, 0x12, 0xf5, 0x22, 0x90, 0x1b, 0x4b, 0x47, 0xa8, + 0x30, 0xcb, 0x4d, 0x67, 0x4c, 0xd6, 0x76 ) ); + fetchf_ok ( &test_settings, &test_hex_setting, + RAW ( 0x62, 0xd9, 0xd4, 0xc4, 0x7e, 0x3b, 0x41, 0x46, 0x91, + 0xc6, 0xfd, 0x0c, 0xbf ), + "62:d9:d4:c4:7e:3b:41:46:91:c6:fd:0c:bf" ); + + /* "hexhyp" setting type */ + storef_ok ( &test_settings, &test_hexhyp_setting, + "11-33-22", RAW ( 0x11, 0x33, 0x22 ) ); + fetchf_ok ( &test_settings, &test_hexhyp_setting, + RAW ( 0x9f, 0xe5, 0x6d, 0xfb, 0x24, 0x3a, 0x4c, 0xbb, 0xa9, + 0x09, 0x6c, 0x66, 0x13, 0xc1, 0xa8, 0xec, 0x27 ), + "9f-e5-6d-fb-24-3a-4c-bb-a9-09-6c-66-13-c1-a8-ec-27" ); + + /* "uuid" setting type (no store capability) */ + fetchf_ok ( &test_settings, &test_uuid_setting, + RAW ( 0x1a, 0x6a, 0x74, 0x9d, 0x0e, 0xda, 0x46, 0x1a,0xa8, + 0x7a, 0x7c, 0xfe, 0x4f, 0xca, 0x4a, 0x57 ), + "1a6a749d-0eda-461a-a87a-7cfe4fca4a57" ); + + /* Unregister test settings block */ + unregister_settings ( &test_settings ); +} + +/** Settings self-test */ +struct self_test settings_test __self_test = { + .name = "settings", + .exec = settings_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index ccbdde27..fc1a3978 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); /* Drag in all applicable self-tests */ REQUIRE_OBJECT ( list_test ); REQUIRE_OBJECT ( byteswap_test ); +REQUIRE_OBJECT ( settings_test ); REQUIRE_OBJECT ( time_test ); REQUIRE_OBJECT ( md5_test ); REQUIRE_OBJECT ( sha1_test ); From 831b16addefd7e26ed1027deb7f089ad1350d1f2 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Mon, 16 Apr 2012 21:47:35 +0100 Subject: [PATCH 167/221] [settings] Split fetching and storing out of setting type handlers Refactor setting type handlers to parse and format values, rather than storing and fetching formatted values. Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/core/settings.c | 577 +++++++++++++++++++++--------------- src/core/uuid.c | 2 +- src/include/ipxe/settings.h | 41 +-- src/include/ipxe/uuid.h | 2 +- 4 files changed, 351 insertions(+), 271 deletions(-) diff --git a/src/core/settings.c b/src/core/settings.c index 0a8c5f68..6fd046f1 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -776,6 +776,41 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, return fetch_ipv4_array_setting ( settings, setting, inp, 1 ); } +/** + * Extract numeric value of setting + * + * @v raw Raw setting data + * @v len Length of raw setting data + * @ret signed_value Value, when interpreted as a signed integer + * @ret unsigned_value Value, when interpreted as an unsigned integer + * @ret len Length of setting, or negative error + */ +static int numeric_setting_value ( const void *raw, size_t len, + signed long *signed_value, + unsigned long *unsigned_value ) { + const uint8_t *unsigned_bytes = raw; + const int8_t *signed_bytes = raw; + int is_negative; + unsigned int i; + uint8_t byte; + + /* Range check */ + if ( len > sizeof ( long ) ) + return -ERANGE; + + /* Convert to host-ordered longs */ + is_negative = ( len && ( signed_bytes[0] < 0 ) ); + *signed_value = ( is_negative ? -1L : 0 ); + *unsigned_value = 0; + for ( i = 0 ; i < len ; i++ ) { + byte = unsigned_bytes[i]; + *signed_value = ( ( *signed_value << 8 ) | byte ); + *unsigned_value = ( ( *unsigned_value << 8 ) | byte ); + } + + return len; +} + /** * Fetch value of signed integer setting * @@ -786,30 +821,20 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, */ int fetch_int_setting ( struct settings *settings, struct setting *setting, long *value ) { - union { - uint8_t u8[ sizeof ( long ) ]; - int8_t s8[ sizeof ( long ) ]; - } buf; + unsigned long dummy; + long tmp; int len; - int i; /* Avoid returning uninitialised data on error */ *value = 0; /* Fetch raw (network-ordered, variable-length) setting */ - len = fetch_setting ( settings, setting, &buf, sizeof ( buf ) ); + len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) ); if ( len < 0 ) return len; - if ( len > ( int ) sizeof ( buf ) ) - return -ERANGE; - /* Convert to host-ordered signed long */ - *value = ( ( buf.s8[0] >= 0 ) ? 0 : -1L ); - for ( i = 0 ; i < len ; i++ ) { - *value = ( ( *value << 8 ) | buf.u8[i] ); - } - - return len; + /* Extract numeric value */ + return numeric_setting_value ( &tmp, len, value, &dummy ); } /** @@ -822,22 +847,20 @@ int fetch_int_setting ( struct settings *settings, struct setting *setting, */ int fetch_uint_setting ( struct settings *settings, struct setting *setting, unsigned long *value ) { - long svalue; + signed long dummy; + long tmp; int len; /* Avoid returning uninitialised data on error */ *value = 0; - /* Fetch as a signed long */ - len = fetch_int_setting ( settings, setting, &svalue ); + /* Fetch raw (network-ordered, variable-length) setting */ + len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) ); if ( len < 0 ) return len; - /* Mask off sign-extended bits */ - assert ( len <= ( int ) sizeof ( long ) ); - *value = ( svalue & ( -1UL >> ( 8 * ( sizeof ( long ) - len ) ) ) ); - - return len; + /* Extract numeric value */ + return numeric_setting_value ( &tmp, len, &dummy, value ); } /** @@ -929,27 +952,83 @@ int setting_cmp ( struct setting *a, struct setting *b ) { */ /** - * Store value of typed setting + * Fetch and format value of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v type Settings type + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +int fetchf_setting ( struct settings *settings, struct setting *setting, + char *buf, size_t len ) { + int raw_len; + int check_len; + int rc; + + /* Fetch raw value */ + raw_len = fetch_setting_len ( settings, setting ); + if ( raw_len < 0 ) { + rc = raw_len; + return rc; + } else { + uint8_t raw[raw_len]; + + /* Fetch raw value */ + check_len = fetch_setting ( settings, setting, raw, + sizeof ( raw ) ); + if ( check_len < 0 ) + return check_len; + assert ( check_len == raw_len ); + + /* Format value */ + return setting->type->format ( raw, sizeof ( raw ), buf, len ); + } +} + +/** + * Store formatted value of setting * * @v settings Settings block * @v setting Setting to store - * @v type Settings type * @v value Formatted setting data, or NULL * @ret rc Return status code */ int storef_setting ( struct settings *settings, struct setting *setting, const char *value ) { + int raw_len; + int check_len; + int rc; - /* NULL value implies deletion. Avoid imposing the burden of - * checking for NULL values on each typed setting's storef() - * method. - */ + /* NULL value implies deletion */ if ( ! value ) return delete_setting ( settings, setting ); - - return setting->type->storef ( settings, setting, value ); + + /* Parse formatted value */ + raw_len = setting->type->parse ( value, NULL, 0 ); + if ( raw_len < 0 ) { + rc = raw_len; + return rc; + } else { + uint8_t raw[raw_len]; + + /* Parse formatted value */ + check_len = setting->type->parse ( value, raw, sizeof ( raw ) ); + assert ( check_len == raw_len ); + + /* Store raw value */ + return store_setting ( settings, setting, raw, sizeof ( raw ) ); + } } +/****************************************************************************** + * + * Named settings + * + ****************************************************************************** + */ + /** * Find named setting * @@ -1176,302 +1255,334 @@ int fetchf_named_setting ( const char *name, */ /** - * Parse and store value of string setting + * Parse string setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error */ -static int storef_string ( struct settings *settings, struct setting *setting, - const char *value ) { - return store_setting ( settings, setting, value, strlen ( value ) ); +static int parse_string_setting ( const char *value, void *buf, size_t len ) { + size_t raw_len = strlen ( value ); /* Exclude terminating NUL */ + + /* Copy string to buffer */ + if ( len > raw_len ) + len = raw_len; + memcpy ( buf, value, len ); + + return raw_len; } /** - * Fetch and format value of string setting + * Format string setting value * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_string ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - return fetch_string_setting ( settings, setting, buf, len ); +static int format_string_setting ( const void *raw, size_t raw_len, char *buf, + size_t len ) { + + /* Copy string to buffer, and terminate */ + memset ( buf, 0, len ); + if ( len > raw_len ) + len = raw_len; + memcpy ( buf, raw, len ); + + return raw_len; } /** A string setting type */ struct setting_type setting_type_string __setting_type = { .name = "string", - .storef = storef_string, - .fetchf = fetchf_string, + .parse = parse_string_setting, + .format = format_string_setting, }; /** - * Parse and store value of URI-encoded string setting + * Parse URI-encoded string setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error */ -static int storef_uristring ( struct settings *settings, - struct setting *setting, - const char *value ) { - char buf[ strlen ( value ) + 1 ]; /* Decoding never expands string */ - size_t len; +static int parse_uristring_setting ( const char *value, void *buf, + size_t len ) { + char tmp[ len + 1 /* NUL */ ]; + size_t raw_len; - len = uri_decode ( value, buf, sizeof ( buf ) ); - return store_setting ( settings, setting, buf, len ); + /* Decode to temporary buffer (including NUL) */ + raw_len = uri_decode ( value, tmp, sizeof ( tmp ) ); + + /* Copy to output buffer (excluding NUL) */ + if ( len > raw_len ) + len = raw_len; + memcpy ( buf, tmp, len ); + + return raw_len; } /** - * Fetch and format value of URI-encoded string setting + * Format URI-encoded string setting value * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_uristring ( struct settings *settings, - struct setting *setting, - char *buf, size_t len ) { - ssize_t raw_len; +static int format_uristring_setting ( const void *raw, size_t raw_len, + char *buf, size_t len ) { + char tmp[ raw_len + 1 /* NUL */ ]; - /* We need to always retrieve the full raw string to know the - * length of the encoded string. - */ - raw_len = fetch_setting ( settings, setting, NULL, 0 ); - if ( raw_len < 0 ) - return raw_len; + /* Copy to temporary buffer and terminate */ + memcpy ( tmp, raw, raw_len ); + tmp[raw_len] = '\0'; - { - char raw_buf[ raw_len + 1 ]; - - fetch_string_setting ( settings, setting, raw_buf, - sizeof ( raw_buf ) ); - return uri_encode ( raw_buf, buf, len, URI_FRAGMENT ); - } + /* Encode directly into output buffer */ + return uri_encode ( tmp, buf, len, URI_FRAGMENT ); } /** A URI-encoded string setting type */ struct setting_type setting_type_uristring __setting_type = { .name = "uristring", - .storef = storef_uristring, - .fetchf = fetchf_uristring, + .parse = parse_uristring_setting, + .format = format_uristring_setting, }; /** - * Parse and store value of IPv4 address setting + * Parse IPv4 address setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error */ -static int storef_ipv4 ( struct settings *settings, struct setting *setting, - const char *value ) { +static int parse_ipv4_setting ( const char *value, void *buf, size_t len ) { struct in_addr ipv4; + /* Parse IPv4 address */ if ( inet_aton ( value, &ipv4 ) == 0 ) return -EINVAL; - return store_setting ( settings, setting, &ipv4, sizeof ( ipv4 ) ); + + /* Copy to buffer */ + if ( len > sizeof ( ipv4 ) ) + len = sizeof ( ipv4 ); + memcpy ( buf, &ipv4, len ); + + return ( sizeof ( ipv4 ) ); } /** - * Fetch and format value of IPv4 address setting + * Format IPv4 address setting value * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_ipv4 ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - struct in_addr ipv4; - int raw_len; +static int format_ipv4_setting ( const void *raw, size_t raw_len, char *buf, + size_t len ) { + const struct in_addr *ipv4 = raw; - if ( ( raw_len = fetch_ipv4_setting ( settings, setting, &ipv4 ) ) < 0) - return raw_len; - return snprintf ( buf, len, "%s", inet_ntoa ( ipv4 ) ); + if ( raw_len < sizeof ( *ipv4 ) ) + return -EINVAL; + return snprintf ( buf, len, "%s", inet_ntoa ( *ipv4 ) ); } /** An IPv4 address setting type */ struct setting_type setting_type_ipv4 __setting_type = { .name = "ipv4", - .storef = storef_ipv4, - .fetchf = fetchf_ipv4, + .parse = parse_ipv4_setting, + .format = format_ipv4_setting, }; /** - * Parse and store value of integer setting + * Parse integer setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer * @v size Integer size, in bytes - * @ret rc Return status code + * @ret len Length of raw value, or negative error */ -static int storef_int ( struct settings *settings, struct setting *setting, - const char *value, unsigned int size ) { +static int parse_int_setting ( const char *value, void *buf, size_t len, + unsigned int size ) { union { uint32_t num; uint8_t bytes[4]; } u; char *endp; + /* Parse value */ u.num = htonl ( strtoul ( value, &endp, 0 ) ); if ( *endp ) return -EINVAL; - return store_setting ( settings, setting, - &u.bytes[ sizeof ( u ) - size ], size ); + + /* Copy to buffer */ + if ( len > size ) + len = size; + memcpy ( buf, &u.bytes[ sizeof ( u ) - size ], len ); + + return size; } /** - * Parse and store value of 8-bit integer setting + * Parse 8-bit integer setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer * @v size Integer size, in bytes - * @ret rc Return status code + * @ret len Length of raw value, or negative error */ -static int storef_int8 ( struct settings *settings, struct setting *setting, - const char *value ) { - return storef_int ( settings, setting, value, 1 ); +static int parse_int8_setting ( const char *value, void *buf, size_t len ) { + return parse_int_setting ( value, buf, len, sizeof ( uint8_t ) ); } /** - * Parse and store value of 16-bit integer setting + * Parse 16-bit integer setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer * @v size Integer size, in bytes - * @ret rc Return status code + * @ret len Length of raw value, or negative error */ -static int storef_int16 ( struct settings *settings, struct setting *setting, - const char *value ) { - return storef_int ( settings, setting, value, 2 ); +static int parse_int16_setting ( const char *value, void *buf, size_t len ) { + return parse_int_setting ( value, buf, len, sizeof ( uint16_t ) ); } /** - * Parse and store value of 32-bit integer setting + * Parse 32-bit integer setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer * @v size Integer size, in bytes - * @ret rc Return status code + * @ret len Length of raw value, or negative error */ -static int storef_int32 ( struct settings *settings, struct setting *setting, - const char *value ) { - return storef_int ( settings, setting, value, 4 ); +static int parse_int32_setting ( const char *value, void *buf, size_t len ) { + return parse_int_setting ( value, buf, len, sizeof ( uint32_t ) ); } /** - * Fetch and format value of signed integer setting + * Format signed integer setting value * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_int ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - long value; - int rc; +static int format_int_setting ( const void *raw, size_t raw_len, char *buf, + size_t len ) { + signed long value; + unsigned long dummy; + int check_len; - if ( ( rc = fetch_int_setting ( settings, setting, &value ) ) < 0 ) - return rc; + /* Extract numeric value */ + check_len = numeric_setting_value ( raw, raw_len, &value, &dummy ); + if ( check_len < 0 ) + return check_len; + assert ( check_len == ( int ) raw_len ); + + /* Format value */ return snprintf ( buf, len, "%ld", value ); } /** - * Fetch and format value of unsigned integer setting + * Format unsigned integer setting value * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_uint ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { +static int format_uint_setting ( const void *raw, size_t raw_len, char *buf, + size_t len ) { + signed long dummy; unsigned long value; - int rc; + int check_len; - if ( ( rc = fetch_uint_setting ( settings, setting, &value ) ) < 0 ) - return rc; + /* Extract numeric value */ + check_len = numeric_setting_value ( raw, raw_len, &dummy, &value ); + if ( check_len < 0 ) + return check_len; + assert ( check_len == ( int ) raw_len ); + + /* Format value */ return snprintf ( buf, len, "%#lx", value ); } /** A signed 8-bit integer setting type */ struct setting_type setting_type_int8 __setting_type = { .name = "int8", - .storef = storef_int8, - .fetchf = fetchf_int, + .parse = parse_int8_setting, + .format = format_int_setting, }; /** A signed 16-bit integer setting type */ struct setting_type setting_type_int16 __setting_type = { .name = "int16", - .storef = storef_int16, - .fetchf = fetchf_int, + .parse = parse_int16_setting, + .format = format_int_setting, }; /** A signed 32-bit integer setting type */ struct setting_type setting_type_int32 __setting_type = { .name = "int32", - .storef = storef_int32, - .fetchf = fetchf_int, + .parse = parse_int32_setting, + .format = format_int_setting, }; /** An unsigned 8-bit integer setting type */ struct setting_type setting_type_uint8 __setting_type = { .name = "uint8", - .storef = storef_int8, - .fetchf = fetchf_uint, + .parse = parse_int8_setting, + .format = format_uint_setting, }; /** An unsigned 16-bit integer setting type */ struct setting_type setting_type_uint16 __setting_type = { .name = "uint16", - .storef = storef_int16, - .fetchf = fetchf_uint, + .parse = parse_int16_setting, + .format = format_uint_setting, }; /** An unsigned 32-bit integer setting type */ struct setting_type setting_type_uint32 __setting_type = { .name = "uint32", - .storef = storef_int32, - .fetchf = fetchf_uint, + .parse = parse_int32_setting, + .format = format_uint_setting, }; /** - * Parse and store value of hex string setting + * Parse hex string setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error */ -static int storef_hex ( struct settings *settings, struct setting *setting, - const char *value ) { +static int parse_hex_setting ( const char *value, void *buf, size_t len ) { char *ptr = ( char * ) value; - uint8_t bytes[ strlen ( value ) ]; /* cannot exceed strlen(value) */ - unsigned int len = 0; + uint8_t *bytes = buf; + unsigned int count = 0; + uint8_t byte; while ( 1 ) { - bytes[len++] = strtoul ( ptr, &ptr, 16 ); + byte = strtoul ( ptr, &ptr, 16 ); + if ( count++ < len ) + *bytes++ = byte; switch ( *ptr ) { case '\0' : - return store_setting ( settings, setting, bytes, len ); + return count; case ':' : case '-' : ptr++; @@ -1483,128 +1594,112 @@ static int storef_hex ( struct settings *settings, struct setting *setting, } /** - * Fetch and format value of hex string setting + * Format hex string setting value * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @v delimiter Byte delimiter * @ret len Length of formatted value, or negative error */ -static int fetchf_hex ( struct settings *settings, struct setting *setting, - char *buf, size_t len, const char *delimiter ) { - int raw_len; - int check_len; +static int format_hex_setting ( const void *raw, size_t raw_len, char *buf, + size_t len, const char *delimiter ) { + const uint8_t *bytes = raw; int used = 0; - int i; + unsigned int i; - raw_len = fetch_setting_len ( settings, setting ); - if ( raw_len < 0 ) - return raw_len; - - { - uint8_t raw[raw_len]; - - check_len = fetch_setting ( settings, setting, raw, - sizeof ( raw ) ); - if ( check_len < 0 ) - return check_len; - assert ( check_len == raw_len ); - - if ( len ) - buf[0] = 0; /* Ensure that a terminating NUL exists */ - for ( i = 0 ; i < raw_len ; i++ ) { - used += ssnprintf ( ( buf + used ), ( len - used ), - "%s%02x", ( used ? delimiter : "" ), - raw[i] ); - } - return used; + if ( len ) + buf[0] = 0; /* Ensure that a terminating NUL exists */ + for ( i = 0 ; i < raw_len ; i++ ) { + used += ssnprintf ( ( buf + used ), ( len - used ), + "%s%02x", ( used ? delimiter : "" ), + bytes[i] ); } + return used; } /** - * Fetch and format value of hex string setting (using colon delimiter) + * Format hex string setting value (using colon delimiter) * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_hex_colon ( struct settings *settings, - struct setting *setting, - char *buf, size_t len ) { - return fetchf_hex ( settings, setting, buf, len, ":" ); +static int format_hex_colon_setting ( const void *raw, size_t raw_len, + char *buf, size_t len ) { + return format_hex_setting ( raw, raw_len, buf, len, ":" ); } /** - * Fetch and format value of hex string setting (using hyphen delimiter) + * Format hex string setting value (using hyphen delimiter) * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_hex_hyphen ( struct settings *settings, - struct setting *setting, - char *buf, size_t len ) { - return fetchf_hex ( settings, setting, buf, len, "-" ); +static int format_hex_hyphen_setting ( const void *raw, size_t raw_len, + char *buf, size_t len ) { + return format_hex_setting ( raw, raw_len, buf, len, "-" ); } /** A hex-string setting (colon-delimited) */ struct setting_type setting_type_hex __setting_type = { .name = "hex", - .storef = storef_hex, - .fetchf = fetchf_hex_colon, + .parse = parse_hex_setting, + .format = format_hex_colon_setting, }; /** A hex-string setting (hyphen-delimited) */ struct setting_type setting_type_hexhyp __setting_type = { .name = "hexhyp", - .storef = storef_hex, - .fetchf = fetchf_hex_hyphen, + .parse = parse_hex_setting, + .format = format_hex_hyphen_setting, }; /** - * Parse and store value of UUID setting + * Parse UUID setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error */ -static int storef_uuid ( struct settings *settings __unused, - struct setting *setting __unused, - const char *value __unused ) { +static int parse_uuid_setting ( const char *value __unused, + void *buf __unused, size_t len __unused ) { return -ENOTSUP; } /** - * Fetch and format value of UUID setting + * Format UUID setting value * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int fetchf_uuid ( struct settings *settings, struct setting *setting, - char *buf, size_t len ) { - union uuid uuid; - int raw_len; +static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf, + size_t len ) { + const union uuid *uuid = raw; - if ( ( raw_len = fetch_uuid_setting ( settings, setting, &uuid ) ) < 0) - return raw_len; - return snprintf ( buf, len, "%s", uuid_ntoa ( &uuid ) ); + /* Range check */ + if ( raw_len != sizeof ( *uuid ) ) + return -ERANGE; + + /* Format value */ + return snprintf ( buf, len, "%s", uuid_ntoa ( uuid ) ); } /** UUID setting type */ struct setting_type setting_type_uuid __setting_type = { .name = "uuid", - .storef = storef_uuid, - .fetchf = fetchf_uuid, + .parse = parse_uuid_setting, + .format = format_uuid_setting, }; /****************************************************************************** diff --git a/src/core/uuid.c b/src/core/uuid.c index d98553f0..cc41afda 100644 --- a/src/core/uuid.c +++ b/src/core/uuid.c @@ -35,7 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v uuid UUID * @ret string UUID in canonical form */ -char * uuid_ntoa ( union uuid *uuid ) { +char * uuid_ntoa ( const union uuid *uuid ) { static char buf[37]; /* "00000000-0000-0000-0000-000000000000" */ sprintf ( buf, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 27ce1f9d..1f4af17f 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -161,25 +161,24 @@ struct setting_type { * This is the name exposed to the user (e.g. "string"). */ const char *name; - /** Parse and set value of setting + /** Parse formatted setting value * - * @v settings Settings block - * @v setting Setting to store - * @v value Formatted setting data - * @ret rc Return status code + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error */ - int ( * storef ) ( struct settings *settings, struct setting *setting, - const char *value ); - /** Fetch and format value of setting + int ( * parse ) ( const char *value, void *buf, size_t len ); + /** Format setting value * - * @v settings Settings block - * @v setting Setting to fetch + * @v raw Raw setting value + * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ - int ( * fetchf ) ( struct settings *settings, struct setting *setting, - char *buf, size_t len ); + int ( * format ) ( const void *raw, size_t raw_len, char *buf, + size_t len ); }; /** Configuration setting type table */ @@ -273,6 +272,8 @@ extern struct setting * find_setting ( const char *name ); extern int setting_name ( struct settings *settings, struct setting *setting, char *buf, size_t len ); +extern int fetchf_setting ( struct settings *settings, struct setting *setting, + char *buf, size_t len ); extern int storef_setting ( struct settings *settings, struct setting *setting, const char *value ); @@ -354,22 +355,6 @@ static inline int delete_setting ( struct settings *settings, return store_setting ( settings, setting, NULL, 0 ); } -/** - * Fetch and format value of setting - * - * @v settings Settings block, or NULL to search all blocks - * @v setting Setting to fetch - * @v type Settings type - * @v buf Buffer to contain formatted value - * @v len Length of buffer - * @ret len Length of formatted value, or negative error - */ -static inline int fetchf_setting ( struct settings *settings, - struct setting *setting, - char *buf, size_t len ) { - return setting->type->fetchf ( settings, setting, buf, len ); -} - /** * Delete named setting * diff --git a/src/include/ipxe/uuid.h b/src/include/ipxe/uuid.h index 2f3c2248..5de56b94 100644 --- a/src/include/ipxe/uuid.h +++ b/src/include/ipxe/uuid.h @@ -28,6 +28,6 @@ union uuid { uint8_t raw[16]; }; -extern char * uuid_ntoa ( union uuid *uuid ); +extern char * uuid_ntoa ( const union uuid *uuid ); #endif /* _IPXE_UUID_H */ From 52e5ddce68adfe4afe3fe55ba317a2ba98d27b01 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Tue, 17 Apr 2012 11:50:11 +0100 Subject: [PATCH 168/221] [tftp] Allow builds without TFTP support Allow TFTP to be configured out by moving the next-server setting definition (which is used by autoboot.c) from tftp.c to settings.c. Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/core/settings.c | 8 ++++++++ src/net/udp/tftp.c | 8 -------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/core/settings.c b/src/core/settings.c index 6fd046f1..e80355c7 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -1798,6 +1798,14 @@ struct setting hostname_setting __setting ( SETTING_HOST ) = { .type = &setting_type_string, }; +/** TFTP server setting */ +struct setting next_server_setting __setting ( SETTING_BOOT ) = { + .name = "next-server", + .description = "TFTP server", + .tag = DHCP_EB_SIADDR, + .type = &setting_type_ipv4, +}; + /** Filename setting */ struct setting filename_setting __setting ( SETTING_BOOT ) = { .name = "filename", diff --git a/src/net/udp/tftp.c b/src/net/udp/tftp.c index 7cd211e4..a2d6473c 100644 --- a/src/net/udp/tftp.c +++ b/src/net/udp/tftp.c @@ -1214,14 +1214,6 @@ struct uri_opener mtftp_uri_opener __uri_opener = { ****************************************************************************** */ -/** TFTP server setting */ -struct setting next_server_setting __setting ( SETTING_BOOT ) = { - .name = "next-server", - .description = "TFTP server", - .tag = DHCP_EB_SIADDR, - .type = &setting_type_ipv4, -}; - /** * Apply TFTP configuration settings * From a9cf527641bde04b6a09891ebc0696e28eaea188 Mon Sep 17 00:00:00 2001 From: Michael Brown <mcb30@ipxe.org> Date: Thu, 1 Mar 2012 15:58:08 +0000 Subject: [PATCH 169/221] [vmware] Allow settings to be specified in the VMware .vmx file Allow iPXE settings to be specified in the .vmx file via the VMware GuestInfo mechanism. For example: guestinfo.ipxe.filename = "http://boot.ipxe.org/demo/boot.php" guestinfo.ipxe.dns = "192.168.0.1" guestinfo.ipxe.net0.ip = "192.168.0.15" guestinfo.ipxe.net0.netmask = "255.255.255.0" guestinfo.ipxe.net0.gateway = "192.168.0.1" Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/arch/i386/include/bits/errfile.h | 1 + src/arch/i386/interface/vmware/guestinfo.c | 281 +++++++++++++++++++++ src/config/config.c | 5 +- src/config/sideband.h | 1 + 4 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 src/arch/i386/interface/vmware/guestinfo.c diff --git a/src/arch/i386/include/bits/errfile.h b/src/arch/i386/include/bits/errfile.h index 1077bae8..ccf00b86 100644 --- a/src/arch/i386/include/bits/errfile.h +++ b/src/arch/i386/include/bits/errfile.h @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_runtime ( ERRFILE_ARCH | ERRFILE_CORE | 0x00070000 ) #define ERRFILE_vmware ( ERRFILE_ARCH | ERRFILE_CORE | 0x00080000 ) #define ERRFILE_guestrpc ( ERRFILE_ARCH | ERRFILE_CORE | 0x00090000 ) +#define ERRFILE_guestinfo ( ERRFILE_ARCH | ERRFILE_CORE | 0x000a0000 ) #define ERRFILE_bootsector ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 ) #define ERRFILE_bzimage ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 ) diff --git a/src/arch/i386/interface/vmware/guestinfo.c b/src/arch/i386/interface/vmware/guestinfo.c new file mode 100644 index 00000000..5f73e949 --- /dev/null +++ b/src/arch/i386/interface/vmware/guestinfo.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * VMware GuestInfo settings + * + */ + +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <ipxe/init.h> +#include <ipxe/settings.h> +#include <ipxe/netdevice.h> +#include <ipxe/guestrpc.h> + +/** GuestInfo GuestRPC channel */ +static int guestinfo_channel; + +/** + * Fetch value of typed GuestInfo setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v type Setting type to attempt (or NULL for default) + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret found Setting found in GuestInfo + * @ret len Length of setting data, or negative error + */ +static int guestinfo_fetch_type ( struct settings *settings, + struct setting *setting, + struct setting_type *type, + void *data, size_t len, int *found ) { + const char *parent_name = settings->parent->name; + char command[ 24 /* "info-get guestinfo.ipxe." */ + + strlen ( parent_name ) + 1 /* "." */ + + strlen ( setting->name ) + 1 /* "." */ + + ( type ? strlen ( type->name ) : 0 ) + 1 /* NUL */ ]; + struct setting *named_setting; + char *info; + int info_len; + int check_len; + int ret; + + /* Construct info-get command */ + snprintf ( command, sizeof ( command ), + "info-get guestinfo.ipxe.%s%s%s%s%s", + parent_name, ( parent_name[0] ? "." : "" ), setting->name, + ( type ? "." : "" ), ( type ? type->name : "" ) ); + + /* Check for existence and obtain length of GuestInfo value */ + info_len = guestrpc_command ( guestinfo_channel, command, NULL, 0 ); + if ( info_len < 0 ) { + ret = info_len; + goto err_get_info_len; + } + + /* Mark as found */ + *found = 1; + + /* Determine default type if necessary */ + if ( ! type ) { + named_setting = find_setting ( setting->name ); + type = ( named_setting ? + named_setting->type : &setting_type_string ); + } + assert ( type != NULL ); + + /* Allocate temporary block to hold GuestInfo value */ + info = zalloc ( info_len + 1 /* NUL */ ); + if ( ! info ) { + DBGC ( settings, "GuestInfo %p could not allocate %zd bytes\n", + settings, info_len ); + ret = -ENOMEM; + goto err_alloc; + } + info[info_len] = '\0'; + + /* Fetch GuestInfo value */ + check_len = guestrpc_command ( guestinfo_channel, command, + info, info_len ); + if ( check_len < 0 ) { + ret = check_len; + goto err_get_info; + } + if ( check_len != info_len ) { + DBGC ( settings, "GuestInfo %p length mismatch (expected %d, " + "got %d)\n", settings, info_len, check_len ); + ret = -EIO; + goto err_get_info; + } + DBGC2 ( settings, "GuestInfo %p found %s = \"%s\"\n", + settings, &command[9] /* Skip "info-get " */, info ); + + /* Parse GuestInfo value according to type */ + ret = type->parse ( info, data, len ); + if ( ret < 0 ) { + DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: " + "%s\n", settings, info, type->name, strerror ( ret ) ); + goto err_parse; + } + + err_parse: + err_get_info: + free ( info ); + err_alloc: + err_get_info_len: + return ret; +} + +/** + * Fetch value of GuestInfo setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int guestinfo_fetch ( struct settings *settings, + struct setting *setting, + void *data, size_t len ) { + struct setting_type *type; + int found = 0; + int ret; + + /* Try default type first */ + ret = guestinfo_fetch_type ( settings, setting, NULL, + data, len, &found ); + if ( found ) + return ret; + + /* Otherwise, try all possible types */ + for_each_table_entry ( type, SETTING_TYPES ) { + ret = guestinfo_fetch_type ( settings, setting, type, + data, len, &found ); + if ( found ) + return ret; + } + + /* Not found */ + return -ENOENT; +} + +/** GuestInfo settings operations */ +static struct settings_operations guestinfo_settings_operations = { + .fetch = guestinfo_fetch, +}; + +/** GuestInfo settings */ +static struct settings guestinfo_settings = { + .refcnt = NULL, + .siblings = LIST_HEAD_INIT ( guestinfo_settings.siblings ), + .children = LIST_HEAD_INIT ( guestinfo_settings.children ), + .op = &guestinfo_settings_operations, +}; + +/** Initialise GuestInfo settings */ +static void guestinfo_init ( void ) { + int rc; + + /* Open GuestRPC channel */ + guestinfo_channel = guestrpc_open(); + if ( guestinfo_channel < 0 ) { + rc = guestinfo_channel; + DBG ( "GuestInfo could not open channel: %s\n", + strerror ( rc ) ); + return; + } + + /* Register root GuestInfo settings */ + if ( ( rc = register_settings ( &guestinfo_settings, NULL, + "vmware" ) ) != 0 ) { + DBG ( "GuestInfo could not register settings: %s\n", + strerror ( rc ) ); + return; + } +} + +/** GuestInfo settings initialiser */ +struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = guestinfo_init, +}; + +/** + * Create per-netdevice GuestInfo settings + * + * @v netdev Network device + * @ret rc Return status code + */ +static int guestinfo_net_probe ( struct net_device *netdev ) { + struct settings *settings; + int rc; + + /* Do nothing unless we have a GuestInfo channel available */ + if ( guestinfo_channel < 0 ) + return 0; + + /* Allocate and initialise settings block */ + settings = zalloc ( sizeof ( *settings ) ); + if ( ! settings ) { + rc = -ENOMEM; + goto err_alloc; + } + settings_init ( settings, &guestinfo_settings_operations, NULL, 0 ); + + /* Register settings */ + if ( ( rc = register_settings ( settings, netdev_settings ( netdev ), + "vmware" ) ) != 0 ) { + DBGC ( settings, "GuestInfo %p could not register for %s: %s\n", + settings, netdev->name, strerror ( rc ) ); + goto err_register; + } + DBGC ( settings, "GuestInfo %p registered for %s\n", + settings, netdev->name ); + + return 0; + + err_register: + free ( settings ); + err_alloc: + return rc; +} + +/** + * Handle network device or link state change + * + * @v netdev Network device + */ +static void guestinfo_net_notify ( struct net_device *netdev __unused ) { + /* Nothing to do */ +} + +/** + * Remove per-netdevice GuestInfo settings + * + * @v netdev Network device + */ +static void guestinfo_net_remove ( struct net_device *netdev ) { + struct settings *parent = netdev_settings ( netdev ); + struct settings *settings; + + list_for_each_entry ( settings, &parent->children, siblings ) { + if ( settings->op == &guestinfo_settings_operations ) { + DBGC ( settings, "GuestInfo %p unregistered for %s\n", + settings, netdev->name ); + unregister_settings ( settings ); + free ( settings ); + return; + } + } +} + +/** GuestInfo per-netdevice driver */ +struct net_driver guestinfo_net_driver __net_driver = { + .name = "GuestInfo", + .probe = guestinfo_net_probe, + .notify = guestinfo_net_notify, + .remove = guestinfo_net_remove, +}; diff --git a/src/config/config.c b/src/config/config.c index 513f054f..4ce1909d 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -280,13 +280,16 @@ REQUIRE_OBJECT ( tap ); #endif /* - * Drag in relevant BOFM entry points + * Drag in relevant sideband entry points */ #ifdef CONFIG_BOFM #ifdef BOFM_EFI REQUIRE_OBJECT ( efi_bofm ); #endif /* BOFM_EFI */ #endif /* CONFIG_BOFM */ +#ifdef VMWARE_SETTINGS +REQUIRE_OBJECT ( guestinfo ); +#endif /* VMWARE_SETTINGS */ /* * Drag in selected keyboard map diff --git a/src/config/sideband.h b/src/config/sideband.h index 5385dd72..a16c2e37 100644 --- a/src/config/sideband.h +++ b/src/config/sideband.h @@ -10,5 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); //#define CONFIG_BOFM /* IBM's BladeCenter Open Fabric Manager */ +//#define VMWARE_SETTINGS /* VMware GuestInfo settings */ #endif /* CONFIG_SIDEBAND_H */ From eadb6bc3fea672d85382bfef6635eb27a8c0c310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robin=20Smidsr=C3=B8d?= <robin@smidsrod.no> Date: Wed, 11 Apr 2012 22:26:04 +0200 Subject: [PATCH 170/221] [util] Add utility to generate list of supported network cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit niclist.pl recursively scans specified source folders and builds a list of supported NICs by looking for ISA_ROM and PCI_ROM lines and outputs the list in text, CSV, JSON, HTML or DokuWiki format. Sorting and column selection is possible. The pci-utils pci.ids file is fetched from SourceForge once a day to also output the "official" vendor/device names associated with the PCI device. Signed-off-by: Robin Smidsrød <robin@smidsrod.no> Signed-off-by: Michael Brown <mcb30@ipxe.org> --- src/util/niclist.pl | 588 +++++++++++++++++++++++++++++++++++++++++++ src/util/parserom.pl | 2 +- 2 files changed, 589 insertions(+), 1 deletion(-) create mode 100755 src/util/niclist.pl mode change 100644 => 100755 src/util/parserom.pl diff --git a/src/util/niclist.pl b/src/util/niclist.pl new file mode 100755 index 00000000..0600c823 --- /dev/null +++ b/src/util/niclist.pl @@ -0,0 +1,588 @@ +#!/usr/bin/env perl +# +# Generates list of supported NICs with PCI vendor/device IDs, driver name +# and other useful things. +# +# Initial version by Robin Smidsrød <robin@smidsrod.no> +# + +use strict; +use warnings; +use autodie; +use v5.10; + +use File::stat; +use File::Basename qw(basename); +use File::Find (); +use Getopt::Long qw(GetOptions); + +GetOptions( + 'help' => \( my $help = 0 ), + 'format=s' => \( my $format = 'text' ), + 'sort=s' => \( my $sort = 'bus,ipxe_driver,ipxe_name' ), + 'columns=s' => \( my $columns = 'bus,vendor_id,device_id,' + . 'vendor_name,device_name,ipxe_driver,' + . 'ipxe_name,ipxe_description,file,legacy_api' + ), + 'pci-url=s' => \( my $pci_url = 'http://pciids.sourceforge.net/v2.2/pci.ids' ), + 'pci-file=s' => \( my $pci_file = '/tmp/pci.ids' ), + 'output=s' => \( my $output = '' ), +); + +die(<<"EOM") if $help; +Usage: $0 [options] [<directory>] + +Options: + --help This page + --format Set output format + --sort Set output sort order (comma-separated) + --columns Set output columns (comma-separated) + --pci-url URL to pci.ids file + --pci-file Cache file for downloaded pci.ids + --output Output file (not specified is STDOUT) + +Output formats: + text, csv, json, html, dokuwiki + +Column names (default order): + bus, vendor_id, device_id, vendor_name, device_name, + ipxe_driver, ipxe_name, ipxe_description, file, legacy_api +EOM + +# Only load runtime requirements if actually in use +given($format) { + when( /csv/ ) { + eval { require Text::CSV; }; + die("Please install Text::CSV CPAN module to use this feature.\n") + if $@; + } + when( /json/ ) { + eval { require JSON; }; + die("Please install JSON CPAN module to use this feature.\n") + if $@; + } + when( /html/ ) { + eval { require HTML::Entities; }; + die("Please install HTML::Entities CPAN module to use this feature.\n") + if $@; + } + default { } +} + +# Scan source dir and build NIC list +my $ipxe_src_dir = shift || '.'; # Default to current directory +my $ipxe_nic_list = build_ipxe_nic_list( $ipxe_src_dir ); + +# Download pci.ids file and parse it +fetch_pci_ids_file($pci_url, $pci_file); +my $pci_id_map = build_pci_id_map($pci_file); + +# Merge 'official' vendor/device names and sort list +update_ipxe_nic_names($ipxe_nic_list, $pci_id_map); +my $sorted_list = sort_ipxe_nic_list($ipxe_nic_list, $sort); + +# Run specified formatter +my $column_names = parse_columns_param($columns); +say STDERR "Formatting NIC list in format '$format' with columns: " + . join(", ", @$column_names); +my $formatter = \&{ "format_nic_list_$format" }; +my $report = $formatter->( $sorted_list, $column_names ); + +# Print final report +if ( $output and $output ne '-' ) { + say STDERR "Printing report to '$output'..."; + open( my $out_fh, ">", $output ); + print $out_fh $report; + close($out_fh); +} +else { + print STDOUT $report; +} + +exit; + +# fetch URL into specified filename +sub fetch_pci_ids_file { + my ($url, $filename) = @_; + my @cmd = ( "wget", "--quiet", "-O", $filename, $url ); + my @touch = ( "touch", $filename ); + if ( -r $filename ) { + my $age = time - stat($filename)->mtime; + # Refresh if older than 1 day + if ( $age > 86400 ) { + say STDERR "Refreshing $filename from $url..."; + system(@cmd); + system(@touch); + } + } + else { + say STDERR "Fetching $url into $filename..."; + system(@cmd); + system(@touch); + } + return $filename; +} + +sub build_pci_id_map { + my ($filename) = @_; + say STDERR "Building PCI ID map..."; + + my $devices = {}; + my $classes = {}; + my $pci_id = qr/[[:xdigit:]]{4}/; + my $c_id = qr/[[:xdigit:]]{2}/; + my $non_space = qr/[^\s]/; + + # open pci.ids file specified + open( my $fh, "<", $filename ); + + # For devices + my $vendor_id = ""; + my $vendor_name = ""; + my $device_id = ""; + my $device_name = ""; + + # For classes + my $class_id = ""; + my $class_name = ""; + my $subclass_id = ""; + my $subclass_name = ""; + + while(<$fh>) { + # skip # and blank lines + next if m/^$/; + next if m/^\s*#/; + + # Vendors, devices and subsystems. Please keep sorted. + # Syntax: + # vendor vendor_name + # device device_name <-- single tab + # subvendor subdevice subsystem_name <-- two tabs + if ( m/^ ($pci_id) \s+ ( $non_space .* ) /x ) { + $vendor_id = lc $1; + $vendor_name = $2; + $devices->{$vendor_id} = { name => $vendor_name }; + next; + } + + if ( $vendor_id and m/^ \t ($pci_id) \s+ ( $non_space .* ) /x ) { + $device_id = lc $1; + $device_name = $2; + $devices->{$vendor_id}->{'devices'} //= {}; + $devices->{$vendor_id}->{'devices'}->{$device_id} = { name => $device_name }; + next; + } + + if ( $vendor_id and $device_id and m/^ \t{2} ($pci_id) \s+ ($pci_id) \s+ ( $non_space .* ) /x ) { + my $subvendor_id = lc $1; + my $subdevice_id = lc $2; + my $subsystem_name = $3; + $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'} //= {}; + $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'}->{$subvendor_id} //= {}; + $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'}->{$subvendor_id}->{'devices'} //= {}; + $devices->{$vendor_id}->{'devices'}->{$device_id}->{'subvendor'}->{$subvendor_id}->{'devices'}->{$subdevice_id} = { name => $subsystem_name }; + next; + } + + # List of known device classes, subclasses and programming interfaces + # Syntax: + # C class class_name + # subclass subclass_name <-- single tab + # prog-if prog-if_name <-- two tabs + if ( m/^C \s+ ($c_id) \s+ ( $non_space .* ) /x ) { + $class_id = lc $1; + $class_name = $2; + $classes->{$class_id} = { name => $class_name }; + next; + } + + if ( $class_id and m/^ \t ($c_id) \s+ ( $non_space .* ) /x ) { + $subclass_id = lc $1; + $subclass_name = $2; + $classes->{$class_id}->{'subclasses'} //= {}; + $classes->{$class_id}->{'subclasses'}->{$subclass_id} = { name => $subclass_name }; + next; + } + + if ( $class_id and $subclass_id and m/^ \t{2} ($c_id) \s+ ( $non_space .* ) /x ) { + my $prog_if_id = lc $1; + my $prog_if_name = $2; + $classes->{$class_id}->{'subclasses'}->{$subclass_id}->{'programming_interfaces'} //= {}; + $classes->{$class_id}->{'subclasses'}->{$subclass_id}->{'programming_interfaces'}->{$prog_if_id} = { name => $prog_if_name }; + next; + } + } + + close($fh); + + # Populate subvendor names + foreach my $vendor_id ( keys %$devices ) { + my $device_map = $devices->{$vendor_id}->{'devices'}; + foreach my $device_id ( keys %$device_map ) { + my $subvendor_map = $device_map->{$device_id}->{'subvendor'}; + foreach my $subvendor_id ( keys %$subvendor_map ) { + $subvendor_map->{$subvendor_id}->{'name'} = $devices->{$subvendor_id}->{'name'} || ""; + } + } + } + + return { + 'devices' => $devices, + 'classes' => $classes, + }; +} + +# Scan through C code and parse ISA_ROM and PCI_ROM lines +sub build_ipxe_nic_list { + my ($dir) = @_; + say STDERR "Building iPXE NIC list from " . ( $dir eq '.' ? 'current directory' : $dir ) . "..."; + + # recursively iterate through dir and find .c files + my @c_files; + File::Find::find(sub { + # only process files + return if -d $_; + # skip unreadable files + return unless -r $_; + # skip all but files with .c extension + return unless /\.c$/; + push @c_files, $File::Find::name; + }, $dir); + + # Look for ISA_ROM or PCI_ROM lines + my $ipxe_nic_list = []; + my $hex_id = qr/0 x [[:xdigit:]]{4} /x; + my $quote = qr/ ['"] /x; + my $non_space = qr/ [^\s] /x; + my $rom_line_counter = 0; + foreach my $c_path ( sort @c_files ) { + my $legacy = 0; + open( my $fh, "<", $c_path ); + my $c_file = $c_path; + $c_file =~ s{^\Q$dir\E/?}{} if -d $dir; # Strip directory from reported filename + my $ipxe_driver = basename($c_file, '.c'); + while(<$fh>) { + # Most likely EtherBoot legacy API + $legacy = 1 if m/struct \s* nic \s*/x; + + # parse ISA|PCI_ROM lines into hashref and append to $ipxe_nic_list + next unless m/^ \s* (?:ISA|PCI)_ROM /x; + $rom_line_counter++; + chomp; + #say; # for debugging regexp + if ( m/^ \s* ISA_ROM \s* \( \s* $quote ( .*? ) $quote \s* , \s* $quote ( .*? ) $quote \s* \) /x ) { + my $image = $1; + my $name = $2; + push @$ipxe_nic_list, { + file => $c_file, + bus => 'isa', + ipxe_driver => $ipxe_driver, + ipxe_name => $image, + ipxe_description => $name, + legacy_api => ( $legacy ? 'yes' : 'no' ), + }; + next; + } + if ( m/^ \s* PCI_ROM \s* \( \s* ($hex_id) \s* , \s* ($hex_id) \s* , \s* $quote (.*?) $quote \s* , \s* $quote (.*?) $quote /x ) { + my $vendor_id = lc $1; + my $device_id = lc $2; + my $name = $3; + my $desc = $4; + push @$ipxe_nic_list, { + file => $c_file, + bus => 'pci', + vendor_id => substr($vendor_id, 2), # strip 0x + device_id => substr($device_id, 2), # strip 0x + ipxe_driver => $ipxe_driver, + ipxe_name => $name, + ipxe_description => $desc, + legacy_api => ( $legacy ? 'yes' : 'no' ), + }; + next; + } + } + close($fh); + } + + # Verify all ROM lines where parsed properly + my @isa_roms = grep { $_->{'bus'} eq 'isa' } @$ipxe_nic_list; + my @pci_roms = grep { $_->{'bus'} eq 'pci' } @$ipxe_nic_list; + if ( $rom_line_counter != ( @isa_roms + @pci_roms ) ) { + say STDERR "Found ROM lines: $rom_line_counter"; + say STDERR "Extracted ISA_ROM lines: " . scalar @isa_roms; + say STDERR "Extracted PCI_ROM lines: " . scalar @pci_roms; + die("Mismatch between number of ISA_ROM/PCI_ROM lines and extracted entries. Verify regular expressions.\n"); + } + + return $ipxe_nic_list; +} + +# merge vendor/product name from $pci_id_map into $ipxe_nic_list +sub update_ipxe_nic_names { + my ($ipxe_nic_list, $pci_id_map) = @_; + say STDERR "Merging 'official' vendor/device names..."; + + foreach my $nic ( @$ipxe_nic_list ) { + next unless $nic->{'bus'} eq 'pci'; + $nic->{'vendor_name'} = $pci_id_map->{'devices'}->{ $nic->{'vendor_id'} }->{'name'} || ""; + $nic->{'device_name'} = $pci_id_map->{'devices'}->{ $nic->{'vendor_id'} }->{'devices'}->{ $nic->{'device_id'} }->{'name'} || ""; + } + return $ipxe_nic_list; # Redundant, as we're mutating the input list, useful for chaining calls +} + +# Sort entries in NIC list according to sort criteria +sub sort_ipxe_nic_list { + my ($ipxe_nic_list, $sort_column_names) = @_; + my @sort_column_names = @{ parse_columns_param($sort_column_names) }; + say STDERR "Sorting NIC list by: " . join(", ", @sort_column_names ); + # Start at the end of the list and resort until list is exhausted + my @sorted_list = @{ $ipxe_nic_list }; + while(@sort_column_names) { + my $column_name = pop @sort_column_names; + @sorted_list = sort { ( $a->{$column_name} || "" ) cmp ( $b->{$column_name} || "" ) } + @sorted_list; + } + return \@sorted_list; +} + +# Parse comma-separated values into array +sub parse_columns_param { + my ($columns) = @_; + return [ + grep { is_valid_column($_) } # only include valid entries + map { s/\s//g; $_; } # filter whitespace + split( /,/, $columns ) # split on comma + ]; +} + +# Return true if the input column name is valid +sub is_valid_column { + my ($name) = @_; + my $valid_column_map = { + map { $_ => 1 } + qw( + bus file legacy_api + ipxe_driver ipxe_name ipxe_description + vendor_id device_id vendor_name device_name + ) + }; + return unless $name; + return unless $valid_column_map->{$name}; + return 1; +} + +# Output NIC list in plain text +sub format_nic_list_text { + my ($nic_list, $column_names) = @_; + return join("\n", + map { format_nic_text($_, $column_names) } + @$nic_list + ); +} + +# Format one ipxe_nic_list entry for display +# Column order not supported by text format +sub format_nic_text { + my ($nic, $column_names) = @_; + my $labels = { + bus => 'Bus: ', + ipxe_driver => 'iPXE driver: ', + ipxe_name => 'iPXE name: ', + ipxe_description => 'iPXE description:', + file => 'Source file: ', + legacy_api => 'Using legacy API:', + vendor_id => 'PCI vendor ID: ', + device_id => 'PCI device ID: ', + vendor_name => 'Vendor name: ', + device_name => 'Device name: ', + }; + my $pci_only = { + vendor_id => 1, + device_id => 1, + vendor_name => 1, + device_name => 1, + }; + my $output = ""; + foreach my $column ( @$column_names ) { + next if $nic->{'bus'} eq 'isa' and $pci_only->{$column}; + $output .= $labels->{$column} + . " " + . ( $nic->{$column} || "" ) + . "\n"; + } + return $output; +} + +# Output NIC list in JSON +sub format_nic_list_json { + my ($nic_list, $column_names) = @_; + + # Filter columns not mentioned + my @nics; + foreach my $nic ( @$nic_list ) { + my $filtered_nic = {}; + foreach my $key ( @$column_names ) { + $filtered_nic->{$key} = $nic->{$key}; + } + push @nics, $filtered_nic; + } + + return JSON->new->pretty->utf8->encode(\@nics); +} + +# Output NIC list in CSV +sub format_nic_list_csv { + my ($nic_list, $column_names) = @_; + my @output; + + # Output CSV header + my $csv = Text::CSV->new(); + if ( $csv->combine( @$column_names ) ) { + push @output, $csv->string(); + } + + # Output CSV lines + foreach my $nic ( @$nic_list ) { + my @columns = @{ $nic }{ @$column_names }; + if ( $csv->combine( @columns ) ) { + push @output, $csv->string(); + } + } + return join("\n", @output) . "\n"; +} + +# Output NIC list in HTML +sub format_nic_list_html { + my ($nic_list, $column_names) = @_; + my @output; + + push @output, <<'EOM'; +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>Network cards supported by iPXE + + + +

Network cards supported by iPXE

+ + +EOM + + # Output HTML header + push @output, "" + . join("", + map { "" } + @$column_names + ) + . ""; + + push @output, <<"EOM"; + + +EOM + # Output HTML lines + my $counter = 0; + foreach my $nic ( @$nic_list ) { + my @columns = @{ $nic }{ @$column_names }; # array slice from hashref, see perldoc perldata if confusing + push @output, q!! + . join("", + map { "" } + @columns + ) + . ""; + $counter++; + } + + push @output, <<'EOM'; + +
" . HTML::Entities::encode($_) . "
" . HTML::Entities::encode( $_ || "" ) . "
+ + + + + +EOM + return join("\n", @output); +} + +# Output NIC list in DokuWiki format (for http://ipxe.org) +sub format_nic_list_dokuwiki { + my ($nic_list, $column_names) = @_; + my @output; + + push @output, <<'EOM'; +EOM + + # Output DokuWiki table header + push @output, "^" + . join("^", + map { $_ || "" } + @$column_names + ) + . "^"; + + # Output DokuWiki table entries + foreach my $nic ( @$nic_list ) { + my @columns = @{ $nic }{ @$column_names }; # array slice from hashref, see perldoc perldata if confusing + push @output, '|' + . join('|', + map { $_ || "" } + @columns + ) + . '|'; + } + + return join("\n", @output); +} diff --git a/src/util/parserom.pl b/src/util/parserom.pl old mode 100644 new mode 100755 index 5e55c6da..e278e633 --- a/src/util/parserom.pl +++ b/src/util/parserom.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl -w +#!/usr/bin/env perl # # Parse PCI_ROM and ISA_ROM entries from a source file on stdin and # output the relevant Makefile variable definitions to stdout From 2f3f0ca9533db60fff932153ab71cfcf2036c5df Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 18 Apr 2012 15:29:48 +0100 Subject: [PATCH 171/221] [mii] Remove unused functionality Signed-off-by: Michael Brown --- src/include/mii.h | 59 ------------------- src/net/mii.c | 147 ---------------------------------------------- 2 files changed, 206 deletions(-) delete mode 100644 src/net/mii.c diff --git a/src/include/mii.h b/src/include/mii.h index 2baff2f1..b7dce13a 100644 --- a/src/include/mii.h +++ b/src/include/mii.h @@ -157,63 +157,4 @@ struct mii_if_info { void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val); }; - -extern int mii_link_ok (struct mii_if_info *mii); -extern void mii_check_link (struct mii_if_info *mii); -extern unsigned int mii_check_media (struct mii_if_info *mii, - unsigned int ok_to_print, - unsigned int init_media); - - -/** - * mii_nway_result - * @negotiated: value of MII ANAR and'd with ANLPAR - * - * Given a set of MII abilities, check each bit and returns the - * currently supported media, in the priority order defined by - * IEEE 802.3u. We use LPA_xxx constants but note this is not the - * value of LPA solely, as described above. - * - * The one exception to IEEE 802.3u is that 100baseT4 is placed - * between 100T-full and 100T-half. If your phy does not support - * 100T4 this is fine. If your phy places 100T4 elsewhere in the - * priority order, you will need to roll your own function. - */ -static inline unsigned int mii_nway_result (unsigned int negotiated) -{ - unsigned int ret; - - if (negotiated & LPA_100FULL) - ret = LPA_100FULL; - else if (negotiated & LPA_100BASE4) - ret = LPA_100BASE4; - else if (negotiated & LPA_100HALF) - ret = LPA_100HALF; - else if (negotiated & LPA_10FULL) - ret = LPA_10FULL; - else - ret = LPA_10HALF; - - return ret; -} - -/** - * mii_duplex - * @duplex_lock: Non-zero if duplex is locked at full - * @negotiated: value of MII ANAR and'd with ANLPAR - * - * A small helper function for a common case. Returns one - * if the media is operating or locked at full duplex, and - * returns zero otherwise. - */ -static inline unsigned int mii_duplex (unsigned int duplex_lock, - unsigned int negotiated) -{ - if (duplex_lock) - return 1; - if (mii_nway_result(negotiated) & LPA_DUPLEX) - return 1; - return 0; -} - #endif diff --git a/src/net/mii.c b/src/net/mii.c deleted file mode 100644 index dbaecf11..00000000 --- a/src/net/mii.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - - mii.c: MII interface library - - Ported to iPXE by Daniel Verkamp - from Linux drivers/net/mii.c - - Maintained by Jeff Garzik - Copyright 2001,2002 Jeff Garzik - - Various code came from myson803.c and other files by - Donald Becker. Copyright: - - Written 1998-2002 by Donald Becker. - - This software may be used and distributed according - to the terms of the GNU General Public License (GPL), - incorporated herein by reference. Drivers based on - or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. - This file is not a complete program and may only be - used when the entire operating system is licensed - under the GPL. - - The author may be reached as becker@scyld.com, or C/O - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - -*/ - -#include - -/** - * mii_link_ok - is link status up/ok - * @mii: the MII interface - * - * Returns 1 if the MII reports link status up/ok, 0 otherwise. - */ -int -mii_link_ok ( struct mii_if_info *mii ) -{ - /* first, a dummy read, needed to latch some MII phys */ - mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR ); - if ( mii->mdio_read ( mii->dev, mii->phy_id, MII_BMSR ) & BMSR_LSTATUS ) - return 1; - return 0; -} - -/** - * mii_check_link - check MII link status - * @mii: MII interface - * - * If the link status changed (previous != current), call - * netif_carrier_on() if current link status is Up or call - * netif_carrier_off() if current link status is Down. - */ -void -mii_check_link ( struct mii_if_info *mii ) -{ - int cur_link = mii_link_ok ( mii ); - int prev_link = netdev_link_ok ( mii->dev ); - - if ( cur_link && !prev_link ) - netdev_link_up ( mii->dev ); - else if (prev_link && !cur_link) - netdev_link_down ( mii->dev ); -} - - -/** - * mii_check_media - check the MII interface for a duplex change - * @mii: the MII interface - * @ok_to_print: OK to print link up/down messages - * @init_media: OK to save duplex mode in @mii - * - * Returns 1 if the duplex mode changed, 0 if not. - * If the media type is forced, always returns 0. - */ -unsigned int -mii_check_media ( struct mii_if_info *mii, - unsigned int ok_to_print, - unsigned int init_media ) -{ - unsigned int old_carrier, new_carrier; - int advertise, lpa, media, duplex; - int lpa2 = 0; - - /* if forced media, go no further */ - if (mii->force_media) - return 0; /* duplex did not change */ - - /* check current and old link status */ - old_carrier = netdev_link_ok ( mii->dev ) ? 1 : 0; - new_carrier = (unsigned int) mii_link_ok ( mii ); - - /* if carrier state did not change, this is a "bounce", - * just exit as everything is already set correctly - */ - if ( ( ! init_media ) && ( old_carrier == new_carrier ) ) - return 0; /* duplex did not change */ - - /* no carrier, nothing much to do */ - if ( ! new_carrier ) { - netdev_link_down ( mii->dev ); - if ( ok_to_print ) - DBG ( "%s: link down\n", mii->dev->name); - return 0; /* duplex did not change */ - } - - /* - * we have carrier, see who's on the other end - */ - netdev_link_up ( mii->dev ); - - /* get MII advertise and LPA values */ - if ( ( ! init_media ) && ( mii->advertising ) ) { - advertise = mii->advertising; - } else { - advertise = mii->mdio_read ( mii->dev, mii->phy_id, MII_ADVERTISE ); - mii->advertising = advertise; - } - lpa = mii->mdio_read ( mii->dev, mii->phy_id, MII_LPA ); - if ( mii->supports_gmii ) - lpa2 = mii->mdio_read ( mii->dev, mii->phy_id, MII_STAT1000 ); - - /* figure out media and duplex from advertise and LPA values */ - media = mii_nway_result ( lpa & advertise ); - duplex = ( media & ADVERTISE_FULL ) ? 1 : 0; - if ( lpa2 & LPA_1000FULL ) - duplex = 1; - - if ( ok_to_print ) - DBG ( "%s: link up, %sMbps, %s-duplex, lpa 0x%04X\n", - mii->dev->name, - lpa2 & ( LPA_1000FULL | LPA_1000HALF ) ? "1000" : - media & ( ADVERTISE_100FULL | ADVERTISE_100HALF ) ? "100" : "10", - duplex ? "full" : "half", - lpa); - - if ( ( init_media ) || ( mii->full_duplex != duplex ) ) { - mii->full_duplex = duplex; - return 1; /* duplex changed */ - } - - return 0; /* duplex did not change */ -} From d27e6d6efdfb0d40e83a8c297b9eae9ca84a7638 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 18 Apr 2012 15:42:55 +0100 Subject: [PATCH 172/221] [mii] Synchronise constants with current Linux include/linux/mii.h Signed-off-by: Michael Brown --- src/drivers/net/etherfabric.c | 1 - src/include/mii.h | 225 +++++++++++++++++----------------- 2 files changed, 111 insertions(+), 115 deletions(-) diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index e82d6eb8..a0a009cb 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -93,7 +93,6 @@ static int falcon_mdio_read ( struct efab_nic *efab, int device, int location ); #define LPA_EF_10000FULL 0x00040000 #define LPA_EF_10000HALF 0x00080000 -#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) #define LPA_EF_1000 ( LPA_EF_1000FULL | LPA_EF_1000HALF ) #define LPA_EF_10000 ( LPA_EF_10000FULL | LPA_EF_10000HALF ) #define LPA_EF_DUPLEX ( LPA_10FULL | LPA_100FULL | LPA_EF_1000FULL | \ diff --git a/src/include/mii.h b/src/include/mii.h index b7dce13a..e2afef85 100644 --- a/src/include/mii.h +++ b/src/include/mii.h @@ -1,144 +1,141 @@ -/* - * linux/mii.h: definitions for MII-compatible transceivers - * Originally drivers/net/sunhme.h. +#ifndef _MII_H_ +#define _MII_H_ + +/** @file + * + * Media Independent Interface constants + * + * Extracted from Linux's include/linux/mii.h * * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com) * - * Copied Form Linux 2.4.25 an unneeded items removed by: - * Timothy Legge (timlegge at etherboot dot org) - * - * 03/26/2004 */ FILE_LICENCE ( GPL2_ONLY ); -#ifndef _MII_H_ -#define _MII_H_ - /* Generic MII registers. */ - -#define MII_BMCR 0x00 /* Basic mode control register */ -#define MII_BMSR 0x01 /* Basic mode status register */ -#define MII_PHYSID1 0x02 /* PHYS ID 1 */ -#define MII_PHYSID2 0x03 /* PHYS ID 2 */ -#define MII_ADVERTISE 0x04 /* Advertisement control reg */ -#define MII_LPA 0x05 /* Link partner ability reg */ -#define MII_EXPANSION 0x06 /* Expansion register */ -#define MII_CTRL1000 0x09 /* 1000BASE-T control */ -#define MII_STAT1000 0x0a /* 1000BASE-T status */ -#define MII_ESTATUS 0x0f /* Extended Status */ -#define MII_DCOUNTER 0x12 /* Disconnect counter */ -#define MII_FCSCOUNTER 0x13 /* False carrier counter */ -#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ -#define MII_RERRCOUNTER 0x15 /* Receive error counter */ -#define MII_SREVISION 0x16 /* Silicon revision */ -#define MII_RESV1 0x17 /* Reserved... */ -#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ -#define MII_PHYADDR 0x19 /* PHY address */ -#define MII_RESV2 0x1a /* Reserved... */ -#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ -#define MII_NCONFIG 0x1c /* Network interface config */ +#define MII_BMCR 0x00 /* Basic mode control register */ +#define MII_BMSR 0x01 /* Basic mode status register */ +#define MII_PHYSID1 0x02 /* PHYS ID 1 */ +#define MII_PHYSID2 0x03 /* PHYS ID 2 */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ +#define MII_LPA 0x05 /* Link partner ability reg */ +#define MII_EXPANSION 0x06 /* Expansion register */ +#define MII_CTRL1000 0x09 /* 1000BASE-T control */ +#define MII_STAT1000 0x0a /* 1000BASE-T status */ +#define MII_ESTATUS 0x0f /* Extended Status */ +#define MII_DCOUNTER 0x12 /* Disconnect counter */ +#define MII_FCSCOUNTER 0x13 /* False carrier counter */ +#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ +#define MII_RERRCOUNTER 0x15 /* Receive error counter */ +#define MII_SREVISION 0x16 /* Silicon revision */ +#define MII_RESV1 0x17 /* Reserved... */ +#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ +#define MII_PHYADDR 0x19 /* PHY address */ +#define MII_RESV2 0x1a /* Reserved... */ +#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ +#define MII_NCONFIG 0x1c /* Network interface config */ /* Basic mode control register. */ -#define BMCR_RESV 0x003f /* Unused... */ -#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ -#define BMCR_CTST 0x0080 /* Collision test */ -#define BMCR_FULLDPLX 0x0100 /* Full duplex */ -#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ -#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ -#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ -#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ -#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ -#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ -#define BMCR_RESET 0x8000 /* Reset the DP83840 */ +#define BMCR_RESV 0x003f /* Unused... */ +#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ +#define BMCR_CTST 0x0080 /* Collision test */ +#define BMCR_FULLDPLX 0x0100 /* Full duplex */ +#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ +#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */ +#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */ +#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ +#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ +#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ +#define BMCR_RESET 0x8000 /* Reset the DP83840 */ /* Basic mode status register. */ -#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ -#define BMSR_JCD 0x0002 /* Jabber detected */ -#define BMSR_LSTATUS 0x0004 /* Link status */ -#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ -#define BMSR_RFAULT 0x0010 /* Remote fault detected */ -#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ -#define BMSR_RESV 0x00c0 /* Unused... */ -#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ -#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ -#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ -#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ -#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ -#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ -#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ -#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ +#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ +#define BMSR_JCD 0x0002 /* Jabber detected */ +#define BMSR_LSTATUS 0x0004 /* Link status */ +#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ +#define BMSR_RFAULT 0x0010 /* Remote fault detected */ +#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ +#define BMSR_RESV 0x00c0 /* Unused... */ +#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ +#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ +#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ +#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ +#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ +#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ +#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ +#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ /* Advertisement control register. */ -#define ADVERTISE_SLCT 0x001f /* Selector bits */ -#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ -#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ -#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ -#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ -#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ -#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ -#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ -#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ -#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ -#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ -#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ -#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ -#define ADVERTISE_RESV 0x1000 /* Unused... */ -#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ -#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ -#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ +#define ADVERTISE_SLCT 0x001f /* Selector bits */ +#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ +#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ +#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ +#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +#define ADVERTISE_RESV 0x1000 /* Unused... */ +#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ +#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ +#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ -#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ - ADVERTISE_CSMA) -#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ - ADVERTISE_100HALF | ADVERTISE_100FULL) +#define ADVERTISE_FULL ( ADVERTISE_100FULL | ADVERTISE_10FULL | \ + ADVERTISE_CSMA) +#define ADVERTISE_ALL ( ADVERTISE_10HALF | ADVERTISE_10FULL | \ + ADVERTISE_100HALF | ADVERTISE_100FULL ) /* Link partner ability register. */ -#define LPA_SLCT 0x001f /* Same as advertise selector */ -#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ -#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */ -#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ -#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */ -#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ -#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */ -#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ -#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/ -#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ -#define LPA_PAUSE_CAP 0x0400 /* Can pause */ -#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ -#define LPA_RESV 0x1000 /* Unused... */ -#define LPA_RFAULT 0x2000 /* Link partner faulted */ -#define LPA_LPACK 0x4000 /* Link partner acked us */ -#define LPA_NPAGE 0x8000 /* Next page bit */ +#define LPA_SLCT 0x001f /* Same as advertise selector */ +#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ +#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */ +#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ +#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */ +#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ +#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */ +#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ +#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/ +#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ +#define LPA_PAUSE_CAP 0x0400 /* Can pause */ +#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ +#define LPA_RESV 0x1000 /* Unused... */ +#define LPA_RFAULT 0x2000 /* Link partner faulted */ +#define LPA_LPACK 0x4000 /* Link partner acked us */ +#define LPA_NPAGE 0x8000 /* Next page bit */ -#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL) -#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) +#define LPA_DUPLEX ( LPA_10FULL | LPA_100FULL ) +#define LPA_100 ( LPA_100FULL | LPA_100HALF | LPA_100BASE4 ) /* Expansion register for auto-negotiation. */ -#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */ -#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */ -#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */ -#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */ -#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */ -#define EXPANSION_RESV 0xffe0 /* Unused... */ +#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */ +#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */ +#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */ +#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */ +#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */ +#define EXPANSION_RESV 0xffe0 /* Unused... */ -#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ -#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ +#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ +#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ /* N-way test register. */ -#define NWAYTEST_RESV1 0x00ff /* Unused... */ -#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ -#define NWAYTEST_RESV2 0xfe00 /* Unused... */ +#define NWAYTEST_RESV1 0x00ff /* Unused... */ +#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ +#define NWAYTEST_RESV2 0xfe00 /* Unused... */ /* 1000BASE-T Control register */ -#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ -#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ +#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ /* 1000BASE-T Status register */ -#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */ -#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */ -#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */ -#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */ +#define LPA_1000LOCALRXOK 0x2000 /* Partner local receiver status */ +#define LPA_1000REMRXOK 0x1000 /* Partner remote receiver status */ +#define LPA_1000FULL 0x0800 /* Partner 1000BASE-T full duplex */ +#define LPA_1000HALF 0x0400 /* Partner 1000BASE-T half duplex */ #include From 9b2aabe534eb3804130ca0861cb23c1479cd7e02 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 18 Apr 2012 16:30:11 +0100 Subject: [PATCH 173/221] [mii] Add generic MII reset function iPXE provides no support for manually configuring the link speed. Provide a generic routine which should be able to reset any MII/GMII PHY and enable autonegotiation. Prototyped-by: Thomas Miletich Signed-off-by: Michael Brown --- src/drivers/net/mii.c | 85 +++++++++++++++++++++++++++++++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/mii.h | 86 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 src/drivers/net/mii.c create mode 100644 src/include/ipxe/mii.h diff --git a/src/drivers/net/mii.c b/src/drivers/net/mii.c new file mode 100644 index 00000000..c8e6529d --- /dev/null +++ b/src/drivers/net/mii.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include + +/** @file + * + * Media Independent Interface + * + */ + +/** + * Reset MII interface + * + * @v mii MII interface + * @ret rc Return status code + */ +int mii_reset ( struct mii_interface *mii ) { + unsigned int i; + int bmcr; + int rc; + + /* Power-up, enable autonegotiation and initiate reset */ + if ( ( rc = mii_write ( mii, MII_BMCR, + ( BMCR_RESET | BMCR_ANENABLE ) ) ) != 0 ) { + DBGC ( mii, "MII %p could not write BMCR: %s\n", + mii, strerror ( rc ) ); + return rc; + } + + /* Wait for reset to complete */ + for ( i = 0 ; i < MII_RESET_MAX_WAIT_MS ; i++ ) { + + /* Check if reset has completed */ + bmcr = mii_read ( mii, MII_BMCR ); + if ( bmcr < 0 ) { + rc = bmcr; + DBGC ( mii, "MII %p could not read BMCR: %s\n", + mii, strerror ( rc ) ); + return rc; + } + + /* If reset is not complete, delay 1ms and retry */ + if ( bmcr & BMCR_RESET ) { + mdelay ( 1 ); + continue; + } + + /* Force autonegotation on again, in case it was + * cleared by the reset. + */ + if ( ( rc = mii_write ( mii, MII_BMCR, BMCR_ANENABLE ) ) != 0 ){ + DBGC ( mii, "MII %p could not write BMCR: %s\n", + mii, strerror ( rc ) ); + return rc; + } + + DBGC ( mii, "MII %p reset after %dms\n", mii, i ); + return 0; + } + + DBGC ( mii, "MII %p timed out waiting for reset\n", mii ); + return -ETIMEDOUT; +} diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 77c2f809..87b5ac72 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -141,6 +141,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_ath9k ( ERRFILE_DRIVER | 0x005f0000 ) #define ERRFILE_ath ( ERRFILE_DRIVER | 0x00600000 ) #define ERRFILE_vmxnet3 ( ERRFILE_DRIVER | 0x00610000 ) +#define ERRFILE_mii ( ERRFILE_DRIVER | 0x00620000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) diff --git a/src/include/ipxe/mii.h b/src/include/ipxe/mii.h new file mode 100644 index 00000000..a33a31d9 --- /dev/null +++ b/src/include/ipxe/mii.h @@ -0,0 +1,86 @@ +#ifndef _IPXE_MII_H +#define _IPXE_MII_H + +/** @file + * + * Media Independent Interface + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +struct mii_interface; + +/** MII interface operations */ +struct mii_operations { + /** + * Read from MII register + * + * @v mii MII interface + * @v reg Register address + * @ret data Data read, or negative error + */ + int ( * read ) ( struct mii_interface *mii, unsigned int reg ); + /** + * Write to MII register + * + * @v mii MII interface + * @v reg Register address + * @v data Data to write + * @ret rc Return status code + */ + int ( * write ) ( struct mii_interface *mii, unsigned int reg, + unsigned int data ); +}; + +/** An MII interface */ +struct mii_interface { + /** Interface operations */ + struct mii_operations *op; +}; + +/** + * Initialise MII interface + * + * @v mii MII interface + * @v op MII interface operations + */ +static inline __attribute__ (( always_inline )) void +mii_init ( struct mii_interface *mii, struct mii_operations *op ) { + mii->op = op; +} + +/** + * Read from MII register + * + * @v mii MII interface + * @v reg Register address + * @ret data Data read, or negative error + */ +static inline __attribute__ (( always_inline )) int +mii_read ( struct mii_interface *mii, unsigned int reg ) { + return mii->op->read ( mii, reg ); +} + +/** + * Write to MII register + * + * @v mii MII interface + * @v reg Register address + * @v data Data to write + * @ret rc Return status code + */ +static inline __attribute__ (( always_inline )) int +mii_write ( struct mii_interface *mii, unsigned int reg, unsigned int data ) { + return mii->op->write ( mii, reg, data ); +} + +/** Maximum time to wait for a reset, in milliseconds */ +#define MII_RESET_MAX_WAIT_MS 500 + +extern int mii_reset ( struct mii_interface *mii ); + +#endif /* _IPXE_MII_H */ From 2a0154db5b9a7d60aa363d48d441bf1bfe4ca7ad Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 17 Apr 2012 21:35:40 +0100 Subject: [PATCH 174/221] [realtek] Replace driver for Realtek Gigabit NICs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested-by: Thomas Miletich Debugged-by: Thomas Miletich Tested-by: Robin Smidsrød Signed-off-by: Michael Brown --- src/drivers/net/r8169.c | 2232 ------------------------------------ src/drivers/net/r8169.h | 486 -------- src/drivers/net/realtek.c | 779 +++++++++++++ src/drivers/net/realtek.h | 205 ++++ src/include/ipxe/errfile.h | 1 + 5 files changed, 985 insertions(+), 2718 deletions(-) delete mode 100644 src/drivers/net/r8169.c delete mode 100644 src/drivers/net/r8169.h create mode 100644 src/drivers/net/realtek.c create mode 100644 src/drivers/net/realtek.h diff --git a/src/drivers/net/r8169.c b/src/drivers/net/r8169.c deleted file mode 100644 index 13ab65ba..00000000 --- a/src/drivers/net/r8169.c +++ /dev/null @@ -1,2232 +0,0 @@ -/* - * Copyright (c) 2008 Marty Connor - * Copyright (c) 2008 Entity Cyber, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This driver is based on rtl8169 data sheets and work by: - * - * Copyright (c) 2002 ShuChen - * Copyright (c) 2003 - 2007 Francois Romieu - * Copyright (c) a lot of people too. Please respect their work. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "r8169.h" - -/*** Low level hardware routines ***/ - -static void mdio_write(void *ioaddr, int reg_addr, int value) -{ - int i; - - DBGP ( "mdio_write\n" ); - - RTL_W32(PHYAR, 0x80000000 | (reg_addr & 0x1f) << 16 | (value & 0xffff)); - - for (i = 20; i > 0; i--) { - /* - * Check if the RTL8169 has completed writing to the specified - * MII register. - */ - if (!(RTL_R32(PHYAR) & 0x80000000)) - break; - udelay(25); - } -} - -static int mdio_read(void *ioaddr, int reg_addr) -{ - int i, value = -1; - - DBGP ( "mdio_read\n" ); - - RTL_W32(PHYAR, 0x0 | (reg_addr & 0x1f) << 16); - - for (i = 20; i > 0; i--) { - /* - * Check if the RTL8169 has completed retrieving data from - * the specified MII register. - */ - if (RTL_R32(PHYAR) & 0x80000000) { - value = RTL_R32(PHYAR) & 0xffff; - break; - } - udelay(25); - } - return value; -} - -static void mdio_patch(void *ioaddr, int reg_addr, int value) -{ - DBGP ( "mdio_patch\n" ); - - mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value); -} - -static void rtl_ephy_write(void *ioaddr, int reg_addr, int value) -{ - unsigned int i; - - DBGP ( "rtl_ephy_write\n" ); - - RTL_W32(EPHYAR, EPHYAR_WRITE_CMD | (value & EPHYAR_DATA_MASK) | - (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); - - for (i = 0; i < 100; i++) { - if (!(RTL_R32(EPHYAR) & EPHYAR_FLAG)) - break; - udelay(10); - } -} - -static u16 rtl_ephy_read(void *ioaddr, int reg_addr) -{ - u16 value = 0xffff; - unsigned int i; - - DBGP ( "rtl_ephy_read\n" ); - - RTL_W32(EPHYAR, (reg_addr & EPHYAR_REG_MASK) << EPHYAR_REG_SHIFT); - - for (i = 0; i < 100; i++) { - if (RTL_R32(EPHYAR) & EPHYAR_FLAG) { - value = RTL_R32(EPHYAR) & EPHYAR_DATA_MASK; - break; - } - udelay(10); - } - - return value; -} - -static void rtl_csi_write(void *ioaddr, int addr, int value) -{ - unsigned int i; - - DBGP ( "rtl_csi_write\n" ); - - RTL_W32(CSIDR, value); - RTL_W32(CSIAR, CSIAR_WRITE_CMD | (addr & CSIAR_ADDR_MASK) | - CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - - for (i = 0; i < 100; i++) { - if (!(RTL_R32(CSIAR) & CSIAR_FLAG)) - break; - udelay(10); - } -} - -static u32 rtl_csi_read(void *ioaddr, int addr) -{ - u32 value = ~0x00; - unsigned int i; - - DBGP ( "rtl_csi_read\n" ); - - RTL_W32(CSIAR, (addr & CSIAR_ADDR_MASK) | - CSIAR_BYTE_ENABLE << CSIAR_BYTE_ENABLE_SHIFT); - - for (i = 0; i < 100; i++) { - if (RTL_R32(CSIAR) & CSIAR_FLAG) { - value = RTL_R32(CSIDR); - break; - } - udelay(10); - } - - return value; -} - -static void rtl8169_irq_mask_and_ack(void *ioaddr) -{ - DBGP ( "rtl8169_irq_mask_and_ack\n" ); - - RTL_W16(IntrMask, 0x0000); - - RTL_W16(IntrStatus, 0xffff); -} - -static unsigned int rtl8169_tbi_reset_pending(void *ioaddr) -{ - DBGP ( "rtl8169_tbi_reset_pending\n" ); - - return RTL_R32(TBICSR) & TBIReset; -} - -static unsigned int rtl8169_xmii_reset_pending(void *ioaddr) -{ - DBGP ( "rtl8169_xmii_reset_pending\n" ); - - return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET; -} - -static unsigned int rtl8169_tbi_link_ok(void *ioaddr) -{ - DBGP ( "rtl8169_tbi_link_ok\n" ); - - return RTL_R32(TBICSR) & TBILinkOk; -} - -static unsigned int rtl8169_xmii_link_ok(void *ioaddr) -{ - DBGP ( "rtl8169_xmii_link_ok\n" ); - - return RTL_R8(PHYstatus) & LinkStatus; -} - -static void rtl8169_tbi_reset_enable(void *ioaddr) -{ - DBGP ( "rtl8169_tbi_reset_enable\n" ); - - RTL_W32(TBICSR, RTL_R32(TBICSR) | TBIReset); -} - -static void rtl8169_xmii_reset_enable(void *ioaddr) -{ - unsigned int val; - - DBGP ( "rtl8169_xmii_reset_enable\n" ); - - val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET; - mdio_write(ioaddr, MII_BMCR, val & 0xffff); -} - -static int rtl8169_set_speed_tbi(struct net_device *dev, - u8 autoneg, u16 speed, u8 duplex) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void *ioaddr = tp->mmio_addr; - int ret = 0; - u32 reg; - - DBGP ( "rtl8169_set_speed_tbi\n" ); - - reg = RTL_R32(TBICSR); - if ((autoneg == AUTONEG_DISABLE) && (speed == SPEED_1000) && - (duplex == DUPLEX_FULL)) { - RTL_W32(TBICSR, reg & ~(TBINwEnable | TBINwRestart)); - } else if (autoneg == AUTONEG_ENABLE) - RTL_W32(TBICSR, reg | TBINwEnable | TBINwRestart); - else { - DBG ( "incorrect speed setting refused in TBI mode\n" ); - ret = -EOPNOTSUPP; - } - return ret; -} - -static int rtl8169_set_speed_xmii(struct net_device *dev, - u8 autoneg, u16 speed, u8 duplex) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void *ioaddr = tp->mmio_addr; - int auto_nego, giga_ctrl; - - DBGP ( "rtl8169_set_speed_xmii\n" ); - - auto_nego = mdio_read(ioaddr, MII_ADVERTISE); - auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL); - giga_ctrl = mdio_read(ioaddr, MII_CTRL1000); - giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - - if (autoneg == AUTONEG_ENABLE) { - auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL); - giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - } else { - if (speed == SPEED_10) - auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL; - else if (speed == SPEED_100) - auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL; - else if (speed == SPEED_1000) - giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; - - if (duplex == DUPLEX_HALF) - auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL); - - if (duplex == DUPLEX_FULL) - auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF); - - /* This tweak comes straight from Realtek's driver. */ - if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) && - ((tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_16))) { - auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA; - } - } - - /* The 8100e/8101e/8102e do Fast Ethernet only. */ - if ((tp->mac_version == RTL_GIGA_MAC_VER_07) || - (tp->mac_version == RTL_GIGA_MAC_VER_08) || - (tp->mac_version == RTL_GIGA_MAC_VER_09) || - (tp->mac_version == RTL_GIGA_MAC_VER_10) || - (tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_14) || - (tp->mac_version == RTL_GIGA_MAC_VER_15) || - (tp->mac_version == RTL_GIGA_MAC_VER_16)) { - if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF))) { - DBG ( "PHY does not support 1000Mbps.\n" ); - } - giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); - } - - auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - - if ((tp->mac_version == RTL_GIGA_MAC_VER_11) || - (tp->mac_version == RTL_GIGA_MAC_VER_12) || - (tp->mac_version >= RTL_GIGA_MAC_VER_17)) { - /* - * Wake up the PHY. - * Vendor specific (0x1f) and reserved (0x0e) MII registers. - */ - mdio_write(ioaddr, 0x1f, 0x0000); - mdio_write(ioaddr, 0x0e, 0x0000); - } - - tp->phy_auto_nego_reg = auto_nego; - tp->phy_1000_ctrl_reg = giga_ctrl; - - mdio_write(ioaddr, MII_ADVERTISE, auto_nego); - mdio_write(ioaddr, MII_CTRL1000, giga_ctrl); - mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART); - return 0; -} - -static int rtl8169_set_speed(struct net_device *dev, - u8 autoneg, u16 speed, u8 duplex) -{ - struct rtl8169_private *tp = netdev_priv(dev); - int ret; - - DBGP ( "rtl8169_set_speed\n" ); - - ret = tp->set_speed(dev, autoneg, speed, duplex); - - return ret; -} - -static void rtl8169_write_gmii_reg_bit(void *ioaddr, int reg, - int bitnum, int bitval) -{ - int val; - - DBGP ( "rtl8169_write_gmii_reg_bit\n" ); - - val = mdio_read(ioaddr, reg); - val = (bitval == 1) ? - val | (bitval << bitnum) : val & ~(0x0001 << bitnum); - mdio_write(ioaddr, reg, val & 0xffff); -} - -static void rtl8169_get_mac_version(struct rtl8169_private *tp, - void *ioaddr) -{ - /* - * The driver currently handles the 8168Bf and the 8168Be identically - * but they can be identified more specifically through the test below - * if needed: - * - * (RTL_R32(TxConfig) & 0x700000) == 0x500000 ? 8168Bf : 8168Be - * - * Same thing for the 8101Eb and the 8101Ec: - * - * (RTL_R32(TxConfig) & 0x700000) == 0x200000 ? 8101Eb : 8101Ec - */ - const struct { - u32 mask; - u32 val; - int mac_version; - } mac_info[] = { - /* 8168D family. */ - { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 }, - - /* 8168C family. */ - { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 }, - { 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 }, - { 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 }, - { 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 }, - { 0x7cf00000, 0x3c000000, RTL_GIGA_MAC_VER_19 }, - { 0x7cf00000, 0x3c200000, RTL_GIGA_MAC_VER_20 }, - { 0x7cf00000, 0x3c300000, RTL_GIGA_MAC_VER_21 }, - { 0x7cf00000, 0x3c400000, RTL_GIGA_MAC_VER_22 }, - { 0x7c800000, 0x3c000000, RTL_GIGA_MAC_VER_22 }, - - /* 8168B family. */ - { 0x7cf00000, 0x38000000, RTL_GIGA_MAC_VER_12 }, - { 0x7cf00000, 0x38500000, RTL_GIGA_MAC_VER_17 }, - { 0x7c800000, 0x38000000, RTL_GIGA_MAC_VER_17 }, - { 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 }, - - /* 8101 family. */ - { 0x7cf00000, 0x34a00000, RTL_GIGA_MAC_VER_09 }, - { 0x7cf00000, 0x24a00000, RTL_GIGA_MAC_VER_09 }, - { 0x7cf00000, 0x34900000, RTL_GIGA_MAC_VER_08 }, - { 0x7cf00000, 0x24900000, RTL_GIGA_MAC_VER_08 }, - { 0x7cf00000, 0x34800000, RTL_GIGA_MAC_VER_07 }, - { 0x7cf00000, 0x24800000, RTL_GIGA_MAC_VER_07 }, - { 0x7cf00000, 0x34000000, RTL_GIGA_MAC_VER_13 }, - { 0x7cf00000, 0x34300000, RTL_GIGA_MAC_VER_10 }, - { 0x7cf00000, 0x34200000, RTL_GIGA_MAC_VER_16 }, - { 0x7c800000, 0x34800000, RTL_GIGA_MAC_VER_09 }, - { 0x7c800000, 0x24800000, RTL_GIGA_MAC_VER_09 }, - { 0x7c800000, 0x34000000, RTL_GIGA_MAC_VER_16 }, - /* FIXME: where did these entries come from ? -- FR */ - { 0xfc800000, 0x38800000, RTL_GIGA_MAC_VER_15 }, - { 0xfc800000, 0x30800000, RTL_GIGA_MAC_VER_14 }, - - /* 8110 family. */ - { 0xfc800000, 0x98000000, RTL_GIGA_MAC_VER_06 }, - { 0xfc800000, 0x18000000, RTL_GIGA_MAC_VER_05 }, - { 0xfc800000, 0x10000000, RTL_GIGA_MAC_VER_04 }, - { 0xfc800000, 0x04000000, RTL_GIGA_MAC_VER_03 }, - { 0xfc800000, 0x00800000, RTL_GIGA_MAC_VER_02 }, - { 0xfc800000, 0x00000000, RTL_GIGA_MAC_VER_01 }, - - { 0x00000000, 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */ - }, *p = mac_info; - u32 reg; - - DBGP ( "rtl8169_get_mac_version\n" ); - - reg = RTL_R32(TxConfig); - while ((reg & p->mask) != p->val) - p++; - tp->mac_version = p->mac_version; - - DBG ( "tp->mac_version = %d\n", tp->mac_version ); - - if (p->mask == 0x00000000) { - DBG ( "unknown MAC (%08x)\n", reg ); - } -} - -struct phy_reg { - u16 reg; - u16 val; -}; - -static void rtl_phy_write(void *ioaddr, struct phy_reg *regs, int len) -{ - DBGP ( "rtl_phy_write\n" ); - - while (len-- > 0) { - mdio_write(ioaddr, regs->reg, regs->val); - regs++; - } -} - -static void rtl8169s_hw_phy_config(void *ioaddr) -{ - struct { - u16 regs[5]; /* Beware of bit-sign propagation */ - } phy_magic[5] = { { - { 0x0000, //w 4 15 12 0 - 0x00a1, //w 3 15 0 00a1 - 0x0008, //w 2 15 0 0008 - 0x1020, //w 1 15 0 1020 - 0x1000 } },{ //w 0 15 0 1000 - { 0x7000, //w 4 15 12 7 - 0xff41, //w 3 15 0 ff41 - 0xde60, //w 2 15 0 de60 - 0x0140, //w 1 15 0 0140 - 0x0077 } },{ //w 0 15 0 0077 - { 0xa000, //w 4 15 12 a - 0xdf01, //w 3 15 0 df01 - 0xdf20, //w 2 15 0 df20 - 0xff95, //w 1 15 0 ff95 - 0xfa00 } },{ //w 0 15 0 fa00 - { 0xb000, //w 4 15 12 b - 0xff41, //w 3 15 0 ff41 - 0xde20, //w 2 15 0 de20 - 0x0140, //w 1 15 0 0140 - 0x00bb } },{ //w 0 15 0 00bb - { 0xf000, //w 4 15 12 f - 0xdf01, //w 3 15 0 df01 - 0xdf20, //w 2 15 0 df20 - 0xff95, //w 1 15 0 ff95 - 0xbf00 } //w 0 15 0 bf00 - } - }, *p = phy_magic; - unsigned int i; - - DBGP ( "rtl8169s_hw_phy_config\n" ); - - mdio_write(ioaddr, 0x1f, 0x0001); //w 31 2 0 1 - mdio_write(ioaddr, 0x15, 0x1000); //w 21 15 0 1000 - mdio_write(ioaddr, 0x18, 0x65c7); //w 24 15 0 65c7 - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 - - for (i = 0; i < ARRAY_SIZE(phy_magic); i++, p++) { - int val, pos = 4; - - val = (mdio_read(ioaddr, pos) & 0x0fff) | (p->regs[0] & 0xffff); - mdio_write(ioaddr, pos, val); - while (--pos >= 0) - mdio_write(ioaddr, pos, p->regs[4 - pos] & 0xffff); - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 1); //w 4 11 11 1 - rtl8169_write_gmii_reg_bit(ioaddr, 4, 11, 0); //w 4 11 11 0 - } - mdio_write(ioaddr, 0x1f, 0x0000); //w 31 2 0 0 -} - -static void rtl8169sb_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0002 }, - { 0x01, 0x90d0 }, - { 0x1f, 0x0000 } - }; - - DBGP ( "rtl8169sb_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); -} - -static void rtl8168bb_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x10, 0xf41b }, - { 0x1f, 0x0000 } - }; - - mdio_write(ioaddr, 0x1f, 0x0001); - mdio_patch(ioaddr, 0x16, 1 << 0); - - DBGP ( "rtl8168bb_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); -} - -static void rtl8168bef_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x10, 0xf41b }, - { 0x1f, 0x0000 } - }; - - DBGP ( "rtl8168bef_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); -} - -static void rtl8168cp_1_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0000 }, - { 0x1d, 0x0f00 }, - { 0x1f, 0x0002 }, - { 0x0c, 0x1ec8 }, - { 0x1f, 0x0000 } - }; - - DBGP ( "rtl8168cp_1_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); -} - -static void rtl8168cp_2_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x1d, 0x3d98 }, - { 0x1f, 0x0000 } - }; - - DBGP ( "rtl8168cp_2_hw_phy_config\n" ); - - mdio_write(ioaddr, 0x1f, 0x0000); - mdio_patch(ioaddr, 0x14, 1 << 5); - mdio_patch(ioaddr, 0x0d, 1 << 5); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); -} - -static void rtl8168c_1_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x12, 0x2300 }, - { 0x1f, 0x0002 }, - { 0x00, 0x88d4 }, - { 0x01, 0x82b1 }, - { 0x03, 0x7002 }, - { 0x08, 0x9e30 }, - { 0x09, 0x01f0 }, - { 0x0a, 0x5500 }, - { 0x0c, 0x00c8 }, - { 0x1f, 0x0003 }, - { 0x12, 0xc096 }, - { 0x16, 0x000a }, - { 0x1f, 0x0000 }, - { 0x1f, 0x0000 }, - { 0x09, 0x2000 }, - { 0x09, 0x0000 } - }; - - DBGP ( "rtl8168c_1_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); - - mdio_patch(ioaddr, 0x14, 1 << 5); - mdio_patch(ioaddr, 0x0d, 1 << 5); - mdio_write(ioaddr, 0x1f, 0x0000); -} - -static void rtl8168c_2_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x12, 0x2300 }, - { 0x03, 0x802f }, - { 0x02, 0x4f02 }, - { 0x01, 0x0409 }, - { 0x00, 0xf099 }, - { 0x04, 0x9800 }, - { 0x04, 0x9000 }, - { 0x1d, 0x3d98 }, - { 0x1f, 0x0002 }, - { 0x0c, 0x7eb8 }, - { 0x06, 0x0761 }, - { 0x1f, 0x0003 }, - { 0x16, 0x0f0a }, - { 0x1f, 0x0000 } - }; - - DBGP ( "rtl8168c_2_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); - - mdio_patch(ioaddr, 0x16, 1 << 0); - mdio_patch(ioaddr, 0x14, 1 << 5); - mdio_patch(ioaddr, 0x0d, 1 << 5); - mdio_write(ioaddr, 0x1f, 0x0000); -} - -static void rtl8168c_3_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0001 }, - { 0x12, 0x2300 }, - { 0x1d, 0x3d98 }, - { 0x1f, 0x0002 }, - { 0x0c, 0x7eb8 }, - { 0x06, 0x5461 }, - { 0x1f, 0x0003 }, - { 0x16, 0x0f0a }, - { 0x1f, 0x0000 } - }; - - DBGP ( "rtl8168c_3_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); - - mdio_patch(ioaddr, 0x16, 1 << 0); - mdio_patch(ioaddr, 0x14, 1 << 5); - mdio_patch(ioaddr, 0x0d, 1 << 5); - mdio_write(ioaddr, 0x1f, 0x0000); -} - -static void rtl8168c_4_hw_phy_config(void *ioaddr) -{ - DBGP ( "rtl8168c_4_hw_phy_config\n" ); - - rtl8168c_3_hw_phy_config(ioaddr); -} - -static void rtl8168d_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init_0[] = { - { 0x1f, 0x0001 }, - { 0x09, 0x2770 }, - { 0x08, 0x04d0 }, - { 0x0b, 0xad15 }, - { 0x0c, 0x5bf0 }, - { 0x1c, 0xf101 }, - { 0x1f, 0x0003 }, - { 0x14, 0x94d7 }, - { 0x12, 0xf4d6 }, - { 0x09, 0xca0f }, - { 0x1f, 0x0002 }, - { 0x0b, 0x0b10 }, - { 0x0c, 0xd1f7 }, - { 0x1f, 0x0002 }, - { 0x06, 0x5461 }, - { 0x1f, 0x0002 }, - { 0x05, 0x6662 }, - { 0x1f, 0x0000 }, - { 0x14, 0x0060 }, - { 0x1f, 0x0000 }, - { 0x0d, 0xf8a0 }, - { 0x1f, 0x0005 }, - { 0x05, 0xffc2 } - }; - - DBGP ( "rtl8168d_hw_phy_config\n" ); - - rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0)); - - if (mdio_read(ioaddr, 0x06) == 0xc400) { - struct phy_reg phy_reg_init_1[] = { - { 0x1f, 0x0005 }, - { 0x01, 0x0300 }, - { 0x1f, 0x0000 }, - { 0x11, 0x401c }, - { 0x16, 0x4100 }, - { 0x1f, 0x0005 }, - { 0x07, 0x0010 }, - { 0x05, 0x83dc }, - { 0x06, 0x087d }, - { 0x05, 0x8300 }, - { 0x06, 0x0101 }, - { 0x06, 0x05f8 }, - { 0x06, 0xf9fa }, - { 0x06, 0xfbef }, - { 0x06, 0x79e2 }, - { 0x06, 0x835f }, - { 0x06, 0xe0f8 }, - { 0x06, 0x9ae1 }, - { 0x06, 0xf89b }, - { 0x06, 0xef31 }, - { 0x06, 0x3b65 }, - { 0x06, 0xaa07 }, - { 0x06, 0x81e4 }, - { 0x06, 0xf89a }, - { 0x06, 0xe5f8 }, - { 0x06, 0x9baf }, - { 0x06, 0x06ae }, - { 0x05, 0x83dc }, - { 0x06, 0x8300 }, - }; - - rtl_phy_write(ioaddr, phy_reg_init_1, - ARRAY_SIZE(phy_reg_init_1)); - } - - mdio_write(ioaddr, 0x1f, 0x0000); -} - -static void rtl8102e_hw_phy_config(void *ioaddr) -{ - struct phy_reg phy_reg_init[] = { - { 0x1f, 0x0003 }, - { 0x08, 0x441d }, - { 0x01, 0x9100 }, - { 0x1f, 0x0000 } - }; - - DBGP ( "rtl8102e_hw_phy_config\n" ); - - mdio_write(ioaddr, 0x1f, 0x0000); - mdio_patch(ioaddr, 0x11, 1 << 12); - mdio_patch(ioaddr, 0x19, 1 << 13); - - rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init)); -} - -static void rtl_hw_phy_config(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void *ioaddr = tp->mmio_addr; - - DBGP ( "rtl_hw_phy_config\n" ); - - DBG ( "mac_version = 0x%02x\n", tp->mac_version ); - - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_01: - break; - case RTL_GIGA_MAC_VER_02: - case RTL_GIGA_MAC_VER_03: - rtl8169s_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_04: - rtl8169sb_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_07: - case RTL_GIGA_MAC_VER_08: - case RTL_GIGA_MAC_VER_09: - rtl8102e_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_11: - rtl8168bb_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_12: - rtl8168bef_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_17: - rtl8168bef_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_18: - rtl8168cp_1_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_19: - rtl8168c_1_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_20: - rtl8168c_2_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_21: - rtl8168c_3_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_22: - rtl8168c_4_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_23: - case RTL_GIGA_MAC_VER_24: - rtl8168cp_2_hw_phy_config(ioaddr); - break; - case RTL_GIGA_MAC_VER_25: - rtl8168d_hw_phy_config(ioaddr); - break; - - default: - break; - } -} - -static void rtl8169_phy_reset(struct net_device *dev __unused, - struct rtl8169_private *tp) -{ - void *ioaddr = tp->mmio_addr; - unsigned int i; - - DBGP ( "rtl8169_phy_reset\n" ); - - tp->phy_reset_enable(ioaddr); - for (i = 0; i < 100; i++) { - if (!tp->phy_reset_pending(ioaddr)) - return; - mdelay ( 1 ); - } - DBG ( "PHY reset failed.\n" ); -} - -static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp) -{ - void *ioaddr = tp->mmio_addr; - - DBGP ( "rtl8169_init_phy\n" ); - - rtl_hw_phy_config(dev); - - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) { - DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" ); - RTL_W8(0x82, 0x01); - } - - pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40); - - if (tp->mac_version <= RTL_GIGA_MAC_VER_06) - pci_write_config_byte(tp->pci_dev, PCI_CACHE_LINE_SIZE, 0x08); - - if (tp->mac_version == RTL_GIGA_MAC_VER_02) { - DBG ( "Set MAC Reg C+CR Offset 0x82h = 0x01h\n" ); - RTL_W8(0x82, 0x01); - DBG ( "Set PHY Reg 0x0bh = 0x00h\n" ); - mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0 - } - - rtl8169_phy_reset(dev, tp); - - /* - * rtl8169_set_speed_xmii takes good care of the Fast Ethernet - * only 8101. Don't panic. - */ - rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL); - - if ((RTL_R8(PHYstatus) & TBI_Enable)) - DBG ( "TBI auto-negotiating\n" ); -} - -static const struct rtl_cfg_info { - void (*hw_start)(struct net_device *); - unsigned int region; - unsigned int align; - u16 intr_event; - u16 napi_event; - unsigned features; -} rtl_cfg_infos [] = { - [RTL_CFG_0] = { - .hw_start = rtl_hw_start_8169, - .region = 1, - .align = 0, - .intr_event = SYSErr | LinkChg | RxOverflow | - RxFIFOOver | TxErr | TxOK | RxOK | RxErr, - .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_GMII - }, - [RTL_CFG_1] = { - .hw_start = rtl_hw_start_8168, - .region = 2, - .align = 8, - .intr_event = SYSErr | LinkChg | RxOverflow | - TxErr | TxOK | RxOK | RxErr, - .napi_event = TxErr | TxOK | RxOK | RxOverflow, - .features = RTL_FEATURE_GMII - }, - [RTL_CFG_2] = { - .hw_start = rtl_hw_start_8101, - .region = 2, - .align = 8, - .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout | - RxFIFOOver | TxErr | TxOK | RxOK | RxErr, - .napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow, - } -}; - -static void rtl8169_hw_reset(void *ioaddr) -{ - DBGP ( "rtl8169_hw_reset\n" ); - - /* Disable interrupts */ - rtl8169_irq_mask_and_ack(ioaddr); - - /* Reset the chipset */ - RTL_W8(ChipCmd, CmdReset); - - /* PCI commit */ - RTL_R8(ChipCmd); -} - -static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp) -{ - void *ioaddr = tp->mmio_addr; - u32 cfg = rtl8169_rx_config; - - DBGP ( "rtl_set_rx_tx_config_registers\n" ); - - cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask); - RTL_W32(RxConfig, cfg); - - /* Set DMA burst size and Interframe Gap Time */ - RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | - (InterFrameGap << TxInterFrameGapShift)); -} - -static void rtl_soft_reset ( struct net_device *dev ) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void *ioaddr = tp->mmio_addr; - unsigned int i; - - DBGP ( "rtl_hw_soft_reset\n" ); - - /* Soft reset the chip. */ - RTL_W8(ChipCmd, CmdReset); - - /* Check that the chip has finished the reset. */ - for (i = 0; i < 100; i++) { - if ((RTL_R8(ChipCmd) & CmdReset) == 0) - break; - mdelay ( 1 ); - } - - if ( i == 100 ) { - DBG ( "Reset Failed! (> 100 iterations)\n" ); - } -} - -static void rtl_hw_start ( struct net_device *dev ) -{ - struct rtl8169_private *tp = netdev_priv ( dev ); - - DBGP ( "rtl_hw_start\n" ); - - /* Soft reset NIC */ - rtl_soft_reset ( dev ); - - tp->hw_start ( dev ); -} - -static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp, - void *ioaddr) -{ - DBGP ( "rtl_set_rx_tx_desc_registers\n" ); - - /* - * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh - * register to be written before TxDescAddrLow to work. - * Switching from MMIO to I/O access fixes the issue as well. - */ - RTL_W32 ( TxDescStartAddrHigh, 0 ); - RTL_W32 ( TxDescStartAddrLow, virt_to_bus ( tp->tx_base ) ); - RTL_W32 ( RxDescAddrHigh, 0 ); - RTL_W32 ( RxDescAddrLow, virt_to_bus ( tp->rx_base ) ); -} - -static u16 rtl_rw_cpluscmd(void *ioaddr) -{ - u16 cmd; - - DBGP ( "rtl_rw_cpluscmd\n" ); - - cmd = RTL_R16(CPlusCmd); - RTL_W16(CPlusCmd, cmd); - return cmd; -} - -static void rtl_set_rx_max_size(void *ioaddr) -{ - DBGP ( "rtl_set_rx_max_size\n" ); - - RTL_W16 ( RxMaxSize, RX_BUF_SIZE ); -} - -static void rtl8169_set_magic_reg(void *ioaddr, unsigned mac_version) -{ - struct { - u32 mac_version; - u32 clk; - u32 val; - } cfg2_info [] = { - { RTL_GIGA_MAC_VER_05, PCI_Clock_33MHz, 0x000fff00 }, // 8110SCd - { RTL_GIGA_MAC_VER_05, PCI_Clock_66MHz, 0x000fffff }, - { RTL_GIGA_MAC_VER_06, PCI_Clock_33MHz, 0x00ffff00 }, // 8110SCe - { RTL_GIGA_MAC_VER_06, PCI_Clock_66MHz, 0x00ffffff } - }, *p = cfg2_info; - unsigned int i; - u32 clk; - - DBGP ( "rtl8169_set_magic_reg\n" ); - - clk = RTL_R8(Config2) & PCI_Clock_66MHz; - for (i = 0; i < ARRAY_SIZE(cfg2_info); i++, p++) { - if ((p->mac_version == mac_version) && (p->clk == clk)) { - RTL_W32(0x7c, p->val); - break; - } - } -} - -static void rtl_set_rx_mode ( struct net_device *netdev ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - void *ioaddr = tp->mmio_addr; - u32 tmp; - - DBGP ( "rtl_set_rx_mode\n" ); - - /* Accept all Multicast Packets */ - - RTL_W32 ( MAR0 + 0, 0xffffffff ); - RTL_W32 ( MAR0 + 4, 0xffffffff ); - - tmp = rtl8169_rx_config | AcceptBroadcast | AcceptMulticast | AcceptMyPhys | - ( RTL_R32 ( RxConfig ) & rtl_chip_info[tp->chipset].RxConfigMask ); - - RTL_W32 ( RxConfig, tmp ); -} - -static void rtl_hw_start_8169(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void *ioaddr = tp->mmio_addr; - struct pci_device *pdev = tp->pci_dev; - - DBGP ( "rtl_hw_start_8169\n" ); - - if (tp->mac_version == RTL_GIGA_MAC_VER_05) { - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW); - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08); - } - - RTL_W8(Cfg9346, Cfg9346_Unlock); - - if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || - (tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03) || - (tp->mac_version == RTL_GIGA_MAC_VER_04)) - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - - RTL_W8(EarlyTxThres, EarlyTxThld); - - rtl_set_rx_max_size(ioaddr); - - if ((tp->mac_version == RTL_GIGA_MAC_VER_01) || - (tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03) || - (tp->mac_version == RTL_GIGA_MAC_VER_04)) - rtl_set_rx_tx_config_registers(tp); - - tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; - - if ((tp->mac_version == RTL_GIGA_MAC_VER_02) || - (tp->mac_version == RTL_GIGA_MAC_VER_03)) { - DBG ( "Set MAC Reg C+CR Offset 0xE0. " - "Bit-3 and bit-14 MUST be 1\n" ); - tp->cp_cmd |= (1 << 14); - } - - RTL_W16(CPlusCmd, tp->cp_cmd); - - rtl8169_set_magic_reg(ioaddr, tp->mac_version); - - /* - * Undocumented corner. Supposedly: - * (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets - */ - RTL_W16(IntrMitigate, 0x0000); - - rtl_set_rx_tx_desc_registers(tp, ioaddr); - - if ((tp->mac_version != RTL_GIGA_MAC_VER_01) && - (tp->mac_version != RTL_GIGA_MAC_VER_02) && - (tp->mac_version != RTL_GIGA_MAC_VER_03) && - (tp->mac_version != RTL_GIGA_MAC_VER_04)) { - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - rtl_set_rx_tx_config_registers(tp); - } - - RTL_W8(Cfg9346, Cfg9346_Lock); - - /* Initially a 10 us delay. Turned it into a PCI commit. - FR */ - RTL_R8(IntrMask); - - RTL_W32(RxMissed, 0); - - rtl_set_rx_mode(dev); - - /* no early-rx interrupts */ - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); - - // RTL_W16(IntrMask, tp->intr_event); -} - -static void rtl_tx_performance_tweak(struct pci_device *pdev, u16 force) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = netdev_priv(dev); - int cap = tp->pcie_cap; - - DBGP ( "rtl_tx_performance_tweak\n" ); - - if (cap) { - u16 ctl; - - pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl); - ctl = (ctl & ~PCI_EXP_DEVCTL_READRQ) | force; - pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl); - } -} - -static void rtl_csi_access_enable(void *ioaddr) -{ - u32 csi; - - DBGP ( "rtl_csi_access_enable\n" ); - - csi = rtl_csi_read(ioaddr, 0x070c) & 0x00ffffff; - rtl_csi_write(ioaddr, 0x070c, csi | 0x27000000); -} - -struct ephy_info { - unsigned int offset; - u16 mask; - u16 bits; -}; - -static void rtl_ephy_init(void *ioaddr, struct ephy_info *e, int len) -{ - u16 w; - - DBGP ( "rtl_ephy_init\n" ); - - while (len-- > 0) { - w = (rtl_ephy_read(ioaddr, e->offset) & ~e->mask) | e->bits; - rtl_ephy_write(ioaddr, e->offset, w); - e++; - } -} - -static void rtl_disable_clock_request(struct pci_device *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = netdev_priv(dev); - int cap = tp->pcie_cap; - - DBGP ( "rtl_disable_clock_request\n" ); - - if (cap) { - u16 ctl; - - pci_read_config_word(pdev, cap + PCI_EXP_LNKCTL, &ctl); - ctl &= ~PCI_EXP_LNKCTL_CLKREQ_EN; - pci_write_config_word(pdev, cap + PCI_EXP_LNKCTL, ctl); - } -} - -#define R8168_CPCMD_QUIRK_MASK (\ - EnableBist | \ - Mac_dbgo_oe | \ - Force_half_dup | \ - Force_rxflow_en | \ - Force_txflow_en | \ - Cxpl_dbg_sel | \ - ASF | \ - PktCntrDisable | \ - Mac_dbgo_sel) - -static void rtl_hw_start_8168bb(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8168bb\n" ); - - RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); - - rtl_tx_performance_tweak(pdev, - (0x5 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN); -} - -static void rtl_hw_start_8168bef(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8168bef\n" ); - - rtl_hw_start_8168bb(ioaddr, pdev); - - RTL_W8(EarlyTxThres, EarlyTxThld); - - RTL_W8(Config4, RTL_R8(Config4) & ~(1 << 0)); -} - -static void __rtl_hw_start_8168cp(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "__rtl_hw_start_8168cp\n" ); - - RTL_W8(Config1, RTL_R8(Config1) | Speed_down); - - RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - - rtl_disable_clock_request(pdev); - - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); -} - -static void rtl_hw_start_8168cp_1(void *ioaddr, struct pci_device *pdev) -{ - static struct ephy_info e_info_8168cp[] = { - { 0x01, 0, 0x0001 }, - { 0x02, 0x0800, 0x1000 }, - { 0x03, 0, 0x0042 }, - { 0x06, 0x0080, 0x0000 }, - { 0x07, 0, 0x2000 } - }; - - DBGP ( "rtl_hw_start_8168cp_1\n" ); - - rtl_csi_access_enable(ioaddr); - - rtl_ephy_init(ioaddr, e_info_8168cp, ARRAY_SIZE(e_info_8168cp)); - - __rtl_hw_start_8168cp(ioaddr, pdev); -} - -static void rtl_hw_start_8168cp_2(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8168cp_2\n" ); - - rtl_csi_access_enable(ioaddr); - - RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); -} - -static void rtl_hw_start_8168cp_3(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8168cp_3\n" ); - - rtl_csi_access_enable(ioaddr); - - RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - - /* Magic. */ - RTL_W8(DBG_REG, 0x20); - - RTL_W8(EarlyTxThres, EarlyTxThld); - - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); -} - -static void rtl_hw_start_8168c_1(void *ioaddr, struct pci_device *pdev) -{ - static struct ephy_info e_info_8168c_1[] = { - { 0x02, 0x0800, 0x1000 }, - { 0x03, 0, 0x0002 }, - { 0x06, 0x0080, 0x0000 } - }; - - DBGP ( "rtl_hw_start_8168c_1\n" ); - - rtl_csi_access_enable(ioaddr); - - RTL_W8(DBG_REG, 0x06 | FIX_NAK_1 | FIX_NAK_2); - - rtl_ephy_init(ioaddr, e_info_8168c_1, ARRAY_SIZE(e_info_8168c_1)); - - __rtl_hw_start_8168cp(ioaddr, pdev); -} - -static void rtl_hw_start_8168c_2(void *ioaddr, struct pci_device *pdev) -{ - static struct ephy_info e_info_8168c_2[] = { - { 0x01, 0, 0x0001 }, - { 0x03, 0x0400, 0x0220 } - }; - - DBGP ( "rtl_hw_start_8168c_2\n" ); - - rtl_csi_access_enable(ioaddr); - - rtl_ephy_init(ioaddr, e_info_8168c_2, ARRAY_SIZE(e_info_8168c_2)); - - __rtl_hw_start_8168cp(ioaddr, pdev); -} - -static void rtl_hw_start_8168c_3(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8168c_3\n" ); - - rtl_hw_start_8168c_2(ioaddr, pdev); -} - -static void rtl_hw_start_8168c_4(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8168c_4\n" ); - - rtl_csi_access_enable(ioaddr); - - __rtl_hw_start_8168cp(ioaddr, pdev); -} - -static void rtl_hw_start_8168d(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8168d\n" ); - - rtl_csi_access_enable(ioaddr); - - rtl_disable_clock_request(pdev); - - RTL_W8(EarlyTxThres, EarlyTxThld); - - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK); -} - -static void rtl_hw_start_8168(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void *ioaddr = tp->mmio_addr; - struct pci_device *pdev = tp->pci_dev; - - DBGP ( "rtl_hw_start_8168\n" ); - - RTL_W8(Cfg9346, Cfg9346_Unlock); - - RTL_W8(EarlyTxThres, EarlyTxThld); - - rtl_set_rx_max_size(ioaddr); - - tp->cp_cmd |= RTL_R16(CPlusCmd) | PktCntrDisable | INTT_1; - - RTL_W16(CPlusCmd, tp->cp_cmd); - - RTL_W16(IntrMitigate, 0x5151); - - /* Work around for RxFIFO overflow. */ - if (tp->mac_version == RTL_GIGA_MAC_VER_11) { - tp->intr_event |= RxFIFOOver | PCSTimeout; - tp->intr_event &= ~RxOverflow; - } - - rtl_set_rx_tx_desc_registers(tp, ioaddr); - - rtl_set_rx_mode(dev); - - RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) | - (InterFrameGap << TxInterFrameGapShift)); - - RTL_R8(IntrMask); - - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_11: - rtl_hw_start_8168bb(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_12: - case RTL_GIGA_MAC_VER_17: - rtl_hw_start_8168bef(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_18: - rtl_hw_start_8168cp_1(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_19: - rtl_hw_start_8168c_1(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_20: - rtl_hw_start_8168c_2(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_21: - rtl_hw_start_8168c_3(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_22: - rtl_hw_start_8168c_4(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_23: - rtl_hw_start_8168cp_2(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_24: - rtl_hw_start_8168cp_3(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_25: - rtl_hw_start_8168d(ioaddr, pdev); - break; - - default: - DBG ( "Unknown chipset (mac_version = %d).\n", - tp->mac_version ); - break; - } - - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - - RTL_W8(Cfg9346, Cfg9346_Lock); - - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xF000); - - // RTL_W16(IntrMask, tp->intr_event); -} - -#define R810X_CPCMD_QUIRK_MASK (\ - EnableBist | \ - Mac_dbgo_oe | \ - Force_half_dup | \ - Force_half_dup | \ - Force_txflow_en | \ - Cxpl_dbg_sel | \ - ASF | \ - PktCntrDisable | \ - PCIDAC | \ - PCIMulRW) - -static void rtl_hw_start_8102e_1(void *ioaddr, struct pci_device *pdev) -{ - static struct ephy_info e_info_8102e_1[] = { - { 0x01, 0, 0x6e65 }, - { 0x02, 0, 0x091f }, - { 0x03, 0, 0xc2f9 }, - { 0x06, 0, 0xafb5 }, - { 0x07, 0, 0x0e00 }, - { 0x19, 0, 0xec80 }, - { 0x01, 0, 0x2e65 }, - { 0x01, 0, 0x6e65 } - }; - u8 cfg1; - - DBGP ( "rtl_hw_start_8102e_1\n" ); - - rtl_csi_access_enable(ioaddr); - - RTL_W8(DBG_REG, FIX_NAK_1); - - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - - RTL_W8(Config1, - LEDS1 | LEDS0 | Speed_down | MEMMAP | IOMAP | VPD | PMEnable); - RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - - cfg1 = RTL_R8(Config1); - if ((cfg1 & LEDS0) && (cfg1 & LEDS1)) - RTL_W8(Config1, cfg1 & ~LEDS0); - - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); - - rtl_ephy_init(ioaddr, e_info_8102e_1, ARRAY_SIZE(e_info_8102e_1)); -} - -static void rtl_hw_start_8102e_2(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8102e_2\n" ); - - rtl_csi_access_enable(ioaddr); - - rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT); - - RTL_W8(Config1, MEMMAP | IOMAP | VPD | PMEnable); - RTL_W8(Config3, RTL_R8(Config3) & ~Beacon_en); - - RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R810X_CPCMD_QUIRK_MASK); -} - -static void rtl_hw_start_8102e_3(void *ioaddr, struct pci_device *pdev) -{ - DBGP ( "rtl_hw_start_8102e_3\n" ); - - rtl_hw_start_8102e_2(ioaddr, pdev); - - rtl_ephy_write(ioaddr, 0x03, 0xc2f9); -} - -static void rtl_hw_start_8101(struct net_device *dev) -{ - struct rtl8169_private *tp = netdev_priv(dev); - void *ioaddr = tp->mmio_addr; - struct pci_device *pdev = tp->pci_dev; - - DBGP ( "rtl_hw_start_8101\n" ); - - if ((tp->mac_version == RTL_GIGA_MAC_VER_13) || - (tp->mac_version == RTL_GIGA_MAC_VER_16)) { - int cap = tp->pcie_cap; - - if (cap) { - pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_NOSNOOP_EN); - } - } - - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_07: - rtl_hw_start_8102e_1(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_08: - rtl_hw_start_8102e_3(ioaddr, pdev); - break; - - case RTL_GIGA_MAC_VER_09: - rtl_hw_start_8102e_2(ioaddr, pdev); - break; - } - - RTL_W8(Cfg9346, Cfg9346_Unlock); - - RTL_W8(EarlyTxThres, EarlyTxThld); - - rtl_set_rx_max_size(ioaddr); - - tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW; - - RTL_W16(CPlusCmd, tp->cp_cmd); - - RTL_W16(IntrMitigate, 0x0000); - - rtl_set_rx_tx_desc_registers(tp, ioaddr); - - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - rtl_set_rx_tx_config_registers(tp); - - RTL_W8(Cfg9346, Cfg9346_Lock); - - RTL_R8(IntrMask); - - rtl_set_rx_mode(dev); - - RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); - - RTL_W16(MultiIntr, RTL_R16(MultiIntr) & 0xf000); - - // RTL_W16(IntrMask, tp->intr_event); -} - -/*** iPXE API Support Routines ***/ - -/** - * setup_tx_resources - allocate tx resources (descriptors) - * - * @v tp Driver private storage - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int -rtl8169_setup_tx_resources ( struct rtl8169_private *tp ) -{ - DBGP ( "rtl8169_setup_tx_resources\n" ); - - tp->tx_base = malloc_dma ( R8169_TX_RING_BYTES, TX_RING_ALIGN ); - - if ( ! tp->tx_base ) { - return -ENOMEM; - } - - memset ( tp->tx_base, 0, R8169_TX_RING_BYTES ); - - DBG ( "tp->tx_base = %#08lx\n", virt_to_bus ( tp->tx_base ) ); - - tp->tx_fill_ctr = 0; - tp->tx_curr = 0; - tp->tx_tail = 0; - - return 0; -} - -static void -rtl8169_process_tx_packets ( struct net_device *netdev ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - - uint32_t tx_status; - struct TxDesc *tx_curr_desc; - - DBGP ( "rtl8169_process_tx_packets\n" ); - - while ( tp->tx_tail != tp->tx_curr ) { - - tx_curr_desc = tp->tx_base + tp->tx_tail; - - tx_status = tx_curr_desc->opts1; - - DBG2 ( "Before DescOwn check tx_status: %#08x\n", tx_status ); - - /* if the packet at tx_tail is not owned by hardware it is for us */ - if ( tx_status & DescOwn ) - break; - - DBG ( "Transmitted packet.\n" ); - DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr ); - DBG ( "tp->tx_tail = %d\n", tp->tx_tail ); - DBG ( "tp->tx_curr = %d\n", tp->tx_curr ); - DBG ( "tx_status = %d\n", tx_status ); - DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); - - /* Pass packet to core for processing */ - netdev_tx_complete ( netdev, tp->tx_iobuf[tp->tx_tail] ); - - memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); - - /* Decrement count of used descriptors */ - tp->tx_fill_ctr--; - - /* Increment sent packets index */ - tp->tx_tail = ( tp->tx_tail + 1 ) % NUM_TX_DESC; - } -} - -static void -rtl8169_free_tx_resources ( struct rtl8169_private *tp ) -{ - DBGP ( "rtl8169_free_tx_resources\n" ); - - free_dma ( tp->tx_base, R8169_TX_RING_BYTES ); -} - -static void -rtl8169_populate_rx_descriptor ( struct rtl8169_private *tp, struct RxDesc *rx_desc, uint32_t index ) -{ - DBGP ( "rtl8169_populate_rx_descriptor\n" ); - - DBG ( "Populating rx descriptor %d\n", index ); - - memset ( rx_desc, 0, sizeof ( *rx_desc ) ); - - rx_desc->addr_hi = 0; - rx_desc->addr_lo = virt_to_bus ( tp->rx_iobuf[index]->data ); - rx_desc->opts2 = 0; - rx_desc->opts1 = ( index == ( NUM_RX_DESC - 1 ) ? RingEnd : 0 ) | - RX_BUF_SIZE; - rx_desc->opts1 |= DescOwn; -} - -/** - * Refill descriptor ring - * - * @v netdev Net device - */ -static void rtl8169_refill_rx_ring ( struct rtl8169_private *tp ) -{ - struct RxDesc *rx_curr_desc; - int i; - - DBGP ( "rtl8169_refill_rx_ring\n" ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - - rx_curr_desc = ( tp->rx_base ) + i; - - /* Don't touch descriptors owned by the NIC */ - if ( rx_curr_desc->opts1 & DescOwn ) - continue; - - /* Don't touch descriptors with iobufs, they still need to be - processed by the poll routine */ - if ( tp->rx_iobuf[tp->rx_curr] != NULL ) - continue; - - /** If we can't get an iobuf for this descriptor - try again later (next poll). - */ - if ( ! ( tp->rx_iobuf[i] = alloc_iob ( RX_BUF_SIZE ) ) ) { - DBG ( "Refill rx ring failed!!\n" ); - break; - } - - rtl8169_populate_rx_descriptor ( tp, rx_curr_desc, i ); - } -} - -/** - * setup_rx_resources - allocate Rx resources (Descriptors) - * - * @v tp: Driver private structure - * - * @ret rc Returns 0 on success, negative on failure - * - **/ -static int -rtl8169_setup_rx_resources ( struct rtl8169_private *tp ) -{ - DBGP ( "rtl8169_setup_rx_resources\n" ); - - tp->rx_base = malloc_dma ( R8169_RX_RING_BYTES, RX_RING_ALIGN ); - - DBG ( "tp->rx_base = %#08lx\n", virt_to_bus ( tp->rx_base ) ); - - if ( ! tp->rx_base ) { - return -ENOMEM; - } - memset ( tp->rx_base, 0, R8169_RX_RING_BYTES ); - - rtl8169_refill_rx_ring ( tp ); - - tp->rx_curr = 0; - - return 0; -} - -static void -rtl8169_process_rx_packets ( struct net_device *netdev ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - uint32_t rx_status; - uint16_t rx_len; - struct RxDesc *rx_curr_desc; - int i; - - DBGP ( "rtl8169_process_rx_packets\n" ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - - rx_curr_desc = tp->rx_base + tp->rx_curr; - - rx_status = rx_curr_desc->opts1; - - DBG2 ( "Before DescOwn check rx_status: %#08x\n", rx_status ); - - /* Hardware still owns the descriptor */ - if ( rx_status & DescOwn ) - break; - - /* We own the descriptor, but it has not been refilled yet */ - if ( tp->rx_iobuf[tp->rx_curr] == NULL ) - break; - - rx_len = rx_status & 0x3fff; - - DBG ( "Received packet.\n" ); - DBG ( "tp->rx_curr = %d\n", tp->rx_curr ); - DBG ( "rx_len = %d\n", rx_len ); - DBG ( "rx_status = %#08x\n", rx_status ); - DBG ( "rx_curr_desc = %#08lx\n", virt_to_bus ( rx_curr_desc ) ); - - if ( rx_status & RxRES ) { - - netdev_rx_err ( netdev, tp->rx_iobuf[tp->rx_curr], -EINVAL ); - - DBG ( "rtl8169_poll: Corrupted packet received!\n" - " rx_status: %#08x\n", rx_status ); - - } else { - - /* Adjust size of the iobuf to reflect received data */ - iob_put ( tp->rx_iobuf[tp->rx_curr], rx_len ); - - /* Add this packet to the receive queue. */ - netdev_rx ( netdev, tp->rx_iobuf[tp->rx_curr] ); - } - - /* Invalidate this iobuf and descriptor */ - tp->rx_iobuf[tp->rx_curr] = NULL; - memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) ); - - /* Update pointer to next available rx descriptor */ - tp->rx_curr = ( tp->rx_curr + 1 ) % NUM_RX_DESC; - } - rtl8169_refill_rx_ring ( tp ); -} - -static void -rtl8169_free_rx_resources ( struct rtl8169_private *tp ) -{ - int i; - - DBGP ( "rtl8169_free_rx_resources\n" ); - - free_dma ( tp->rx_base, R8169_RX_RING_BYTES ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - free_iob ( tp->rx_iobuf[i] ); - tp->rx_iobuf[i] = NULL; - } -} - -static void rtl8169_irq_enable ( struct rtl8169_private *tp ) -{ - void *ioaddr = tp->mmio_addr; - - DBGP ( "rtl8169_irq_enable\n" ); - - RTL_W16 ( IntrMask, tp->intr_event ); -} - -static void rtl8169_irq_disable ( struct rtl8169_private *tp ) -{ - void *ioaddr = tp->mmio_addr; - - DBGP ( "rtl8169_irq_disable\n" ); - - RTL_W16 ( IntrMask, 0x0000 ); -} - -/*** iPXE Core API Routines ***/ - -/** - * open - Called when a network interface is made active - * - * @v netdev network interface device structure - * @ret rc Return status code, 0 on success, negative value on failure - * - **/ -static int -rtl8169_open ( struct net_device *netdev ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - void *ioaddr = tp->mmio_addr; - int rc; - - DBGP ( "rtl8169_open\n" ); - - /* allocate transmit descriptors */ - rc = rtl8169_setup_tx_resources ( tp ); - if ( rc ) { - DBG ( "Error setting up TX resources!\n" ); - goto err_setup_tx; - } - - /* allocate receive descriptors */ - rc = rtl8169_setup_rx_resources ( tp ); - if ( rc ) { - DBG ( "Error setting up RX resources!\n" ); - goto err_setup_rx; - } - - rtl_hw_start ( netdev ); - - DBG ( "TxDescStartAddrHigh = %#08lx\n", RTL_R32 ( TxDescStartAddrHigh ) ); - DBG ( "TxDescStartAddrLow = %#08lx\n", RTL_R32 ( TxDescStartAddrLow ) ); - DBG ( "RxDescAddrHigh = %#08lx\n", RTL_R32 ( RxDescAddrHigh ) ); - DBG ( "RxDescAddrLow = %#08lx\n", RTL_R32 ( RxDescAddrLow ) ); - - return 0; - -err_setup_rx: - rtl8169_free_tx_resources ( tp ); -err_setup_tx: - rtl8169_hw_reset ( ioaddr ); - - return rc; -} - -/** - * transmit - Transmit a packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * - * @ret rc Returns 0 on success, negative on failure - */ -static int -rtl8169_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - void *ioaddr = tp->mmio_addr; - uint32_t tx_len = iob_len ( iobuf ); - - struct TxDesc *tx_curr_desc; - - DBGP ("rtl8169_transmit\n"); - - if ( tp->tx_fill_ctr == NUM_TX_DESC ) { - DBG ("TX overflow\n"); - return -ENOBUFS; - } - - /** - * The rtl8169 family automatically pads short packets to a - * minimum size, but if it did not, like some older cards, - * we could do: - * iob_pad ( iobuf, ETH_ZLEN ); - */ - - /* Save pointer to this iobuf we have been given to transmit so - we can pass it to netdev_tx_complete() later */ - tp->tx_iobuf[tp->tx_curr] = iobuf; - - tx_curr_desc = tp->tx_base + tp->tx_curr; - - DBG ( "tp->tx_fill_ctr = %d\n", tp->tx_fill_ctr ); - DBG ( "tp->tx_curr = %d\n", tp->tx_curr ); - DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); - DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) ); - DBG ( "tx_len = %d\n", tx_len ); - - /* Configure current descriptor to transmit supplied packet */ - tx_curr_desc->addr_hi = 0; - tx_curr_desc->addr_lo = virt_to_bus ( iobuf->data ); - tx_curr_desc->opts2 = 0; - tx_curr_desc->opts1 = FirstFrag | LastFrag | - ( tp->tx_curr == ( NUM_TX_DESC - 1 ) ? RingEnd : 0 ) | - tx_len; - - /* Mark descriptor as owned by NIC */ - tx_curr_desc->opts1 |= DescOwn; - - DBG ( "tx_curr_desc->opts1 = %#08x\n", tx_curr_desc->opts1 ); - DBG ( "tx_curr_desc->opts2 = %#08x\n", tx_curr_desc->opts2 ); - DBG ( "tx_curr_desc->addr_hi = %#08x\n", tx_curr_desc->addr_hi ); - DBG ( "tx_curr_desc->addr_lo = %#08x\n", tx_curr_desc->addr_lo ); - - RTL_W8 ( TxPoll, NPQ ); /* set polling bit */ - - /* Point to next free descriptor */ - tp->tx_curr = ( tp->tx_curr + 1 ) % NUM_TX_DESC; - - /* Increment number of tx descriptors in use */ - tp->tx_fill_ctr++; - - return 0; -} - -/** - * poll - Poll for received packets - * - * @v netdev Network device - */ -static void -rtl8169_poll ( struct net_device *netdev ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - void *ioaddr = tp->mmio_addr; - - uint16_t intr_status; - uint16_t intr_mask; - - DBGP ( "rtl8169_poll\n" ); - - intr_status = RTL_R16 ( IntrStatus ); - intr_mask = RTL_R16 ( IntrMask ); - - DBG2 ( "rtl8169_poll (before): intr_mask = %#04x intr_status = %#04x\n", - intr_mask, intr_status ); - - RTL_W16 ( IntrStatus, 0xffff ); - - /* hotplug / major error / no more work / shared irq */ - if ( intr_status == 0xffff ) - return; - - /* Process transmitted packets */ - rtl8169_process_tx_packets ( netdev ); - - /* Process received packets */ - rtl8169_process_rx_packets ( netdev ); -} - -/** - * close - Disable network interface - * - * @v netdev network interface device structure - * - **/ -static void -rtl8169_close ( struct net_device *netdev ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - void *ioaddr = tp->mmio_addr; - - DBGP ( "r8169_close\n" ); - - rtl8169_hw_reset ( ioaddr ); - - rtl8169_free_tx_resources ( tp ); - rtl8169_free_rx_resources ( tp ); -} - -/** - * irq - enable or Disable interrupts - * - * @v netdev network adapter - * @v action requested interrupt action - * - **/ -static void -rtl8169_irq ( struct net_device *netdev, int action ) -{ - struct rtl8169_private *tp = netdev_priv ( netdev ); - - DBGP ( "rtl8169_irq\n" ); - - switch ( action ) { - case 0 : - rtl8169_irq_disable ( tp ); - break; - default : - rtl8169_irq_enable ( tp ); - break; - } -} - -static struct net_device_operations rtl8169_operations = { - .open = rtl8169_open, - .transmit = rtl8169_transmit, - .poll = rtl8169_poll, - .close = rtl8169_close, - .irq = rtl8169_irq, -}; - -/** - * probe - Initial configuration of NIC - * - * @v pci PCI device - * @v id PCI IDs - * - * @ret rc Return status code - **/ -static int -rtl8169_probe ( struct pci_device *pdev ) -{ - int i, rc; - struct net_device *netdev; - struct rtl8169_private *tp; - void *ioaddr; - - const struct rtl_cfg_info *cfg = rtl_cfg_infos + pdev->id->driver_data; - - DBGP ( "rtl8169_probe\n" ); - - DBG ( "id->vendor = %#04x, id->device = %#04x\n", - pdev->id->vendor, pdev->id->device ); - - DBG ( "cfg->intr_event = %#04x\n", cfg->intr_event ); - - rc = -ENOMEM; - - /* Allocate net device ( also allocates memory for netdev->priv - and makes netdev-priv point to it ) - */ - netdev = alloc_etherdev ( sizeof ( *tp ) ); - - if ( ! netdev ) - goto err_alloc_etherdev; - - /* Associate driver-specific network operations with - generic network device layer - */ - netdev_init ( netdev, &rtl8169_operations ); - - /* Associate this network device with the given PCI device */ - pci_set_drvdata ( pdev, netdev ); - netdev->dev = &pdev->dev; - - /* Initialize driver private storage */ - tp = netdev_priv ( netdev ); - memset ( tp, 0, ( sizeof ( *tp ) ) ); - - tp->pci_dev = pdev; - tp->irqno = pdev->irq; - tp->netdev = netdev; - tp->intr_event = cfg->intr_event; - tp->cp_cmd = PCIMulRW; - - tp->hw_start = cfg->hw_start; - - rc = -EIO; - - adjust_pci_device ( pdev ); - - /* ioremap MMIO region */ - ioaddr = ioremap ( pdev->membase, R8169_REGS_SIZE ); - - if ( ! ioaddr ) { - DBG ( "cannot remap MMIO\n" ); - rc = -EIO; - goto err_ioremap; - } - - tp->mmio_addr = ioaddr; - - tp->pcie_cap = pci_find_capability ( pdev, PCI_CAP_ID_EXP ); - if ( tp->pcie_cap ) { - DBG ( "PCI Express capability\n" ); - } else { - DBG ( "No PCI Express capability\n" ); - } - - /* Mask interrupts just in case */ - rtl8169_irq_mask_and_ack ( ioaddr ); - - /* Soft reset NIC */ - rtl_soft_reset ( netdev ); - - /* Identify chip attached to board */ - rtl8169_get_mac_version ( tp, ioaddr ); - - for ( i = 0; (u32) i < ARRAY_SIZE ( rtl_chip_info ); i++ ) { - if ( tp->mac_version == rtl_chip_info[i].mac_version ) - break; - } - if ( i == ARRAY_SIZE(rtl_chip_info ) ) { - /* Unknown chip: assume array element #0, original RTL-8169 */ - DBG ( "Unknown chip version, assuming %s\n", rtl_chip_info[0].name ); - i = 0; - } - tp->chipset = i; - - if ((tp->mac_version <= RTL_GIGA_MAC_VER_06) && - (RTL_R8(PHYstatus) & TBI_Enable)) { - tp->set_speed = rtl8169_set_speed_tbi; - tp->phy_reset_enable = rtl8169_tbi_reset_enable; - tp->phy_reset_pending = rtl8169_tbi_reset_pending; - tp->link_ok = rtl8169_tbi_link_ok; - - tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ - } else { - tp->set_speed = rtl8169_set_speed_xmii; - tp->phy_reset_enable = rtl8169_xmii_reset_enable; - tp->phy_reset_pending = rtl8169_xmii_reset_pending; - tp->link_ok = rtl8169_xmii_link_ok; - } - - /* Get MAC address */ - for ( i = 0; i < MAC_ADDR_LEN; i++ ) - netdev->hw_addr[i] = RTL_R8 ( MAC0 + i ); - - DBG ( "%s\n", eth_ntoa ( netdev->hw_addr ) ); - - rtl8169_init_phy ( netdev, tp ); - - if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto err_register; - - /* Mark as link up; we don't yet handle link state */ - netdev_link_up ( netdev ); - - DBG ( "rtl8169_probe succeeded!\n" ); - - /* No errors, return success */ - return 0; - -/* Error return paths */ -err_register: -err_ioremap: - netdev_put ( netdev ); -err_alloc_etherdev: - return rc; -} - -/** - * remove - Device Removal Routine - * - * @v pdev PCI device information struct - * - **/ -static void -rtl8169_remove ( struct pci_device *pdev ) -{ - struct net_device *netdev = pci_get_drvdata ( pdev ); - struct rtl8169_private *tp = netdev_priv ( netdev ); - void *ioaddr = tp->mmio_addr; - - DBGP ( "rtl8169_remove\n" ); - - rtl8169_hw_reset ( ioaddr ); - - unregister_netdev ( netdev ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); -} - -static struct pci_device_id rtl8169_nics[] = { - PCI_ROM(0x10ec, 0x8129, "rtl8169-0x8129", "rtl8169-0x8129", RTL_CFG_0), - PCI_ROM(0x10ec, 0x8136, "rtl8169-0x8136", "rtl8169-0x8136", RTL_CFG_2), - PCI_ROM(0x10ec, 0x8167, "rtl8169-0x8167", "rtl8169-0x8167", RTL_CFG_0), - PCI_ROM(0x10ec, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", RTL_CFG_1), - PCI_ROM(0x10ec, 0x8169, "rtl8169-0x8169", "rtl8169-0x8169", RTL_CFG_0), - PCI_ROM(0x1186, 0x4300, "rtl8169-0x4300", "rtl8169-0x4300", RTL_CFG_0), - PCI_ROM(0x1259, 0xc107, "rtl8169-0xc107", "rtl8169-0xc107", RTL_CFG_0), - PCI_ROM(0x16ec, 0x0116, "rtl8169-0x0116", "rtl8169-0x0116", RTL_CFG_0), - PCI_ROM(0x1737, 0x1032, "rtl8169-0x1032", "rtl8169-0x1032", RTL_CFG_0), - PCI_ROM(0x0001, 0x8168, "rtl8169-0x8168", "rtl8169-0x8168", RTL_CFG_2), -}; - -struct pci_driver rtl8169_driver __pci_driver = { - .ids = rtl8169_nics, - .id_count = ( sizeof ( rtl8169_nics ) / sizeof ( rtl8169_nics[0] ) ), - .probe = rtl8169_probe, - .remove = rtl8169_remove, -}; - -/* - * Local variables: - * c-basic-offset: 8 - * c-indent-level: 8 - * tab-width: 8 - * End: - */ diff --git a/src/drivers/net/r8169.h b/src/drivers/net/r8169.h deleted file mode 100644 index bcf3df0b..00000000 --- a/src/drivers/net/r8169.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright (c) 2008 Marty Connor - * Copyright (c) 2008 Entity Cyber, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * This driver is based on rtl8169 data sheets and work by: - * - * Copyright (c) 2002 ShuChen - * Copyright (c) 2003 - 2007 Francois Romieu - * Copyright (c) a lot of people too. Please respect their work. - * - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _R8169_H_ -#define _R8169_H_ - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -/** FIXME: include/linux/pci_regs.h has these PCI regs, maybe - we need such a file in iPXE? -**/ -#define PCI_EXP_DEVCTL 8 /* Device Control */ -#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ -#define PCI_EXP_LNKCTL 16 /* Link Control */ -#define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ -#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ - -/** FIXME: update mii.h in src/include/mii.h from Linux sources - so we don't have to include these definitiions. -**/ -/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */ -#define SPEED_10 10 -#define SPEED_100 100 -#define SPEED_1000 1000 -#define SPEED_2500 2500 -#define SPEED_10000 10000 - -/* Duplex, half or full. */ -#define DUPLEX_HALF 0x00 -#define DUPLEX_FULL 0x01 - -#define AUTONEG_DISABLE 0x00 -#define AUTONEG_ENABLE 0x01 - -/* MAC address length */ -#define MAC_ADDR_LEN 6 - -#define MAX_READ_REQUEST_SHIFT 12 -#define RX_FIFO_THRESH 7 /* 7 means NO threshold, Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ -#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */ -#define EarlyTxThld 0x3F /* 0x3F means NO early transmit */ -#define RxPacketMaxSize 0x3FE8 /* 16K - 1 - ETH_HLEN - VLAN - CRC... */ -#define SafeMtu 0x1c20 /* ... actually life sucks beyond ~7k */ -#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ - -#define R8169_REGS_SIZE 256 -#define R8169_NAPI_WEIGHT 64 -#define NUM_TX_DESC 8 /* Number of Tx descriptor registers */ -#define NUM_RX_DESC 8 /* Number of Rx descriptor registers */ -#define RX_BUF_SIZE 1536 /* Rx Buffer size */ -#define R8169_TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) -#define R8169_RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) - -#define TX_RING_ALIGN 256 -#define RX_RING_ALIGN 256 - -#define RTL8169_TX_TIMEOUT (6*HZ) -#define RTL8169_PHY_TIMEOUT (10*HZ) - -#define RTL_EEPROM_SIG cpu_to_le32(0x8129) -#define RTL_EEPROM_SIG_MASK cpu_to_le32(0xffff) -#define RTL_EEPROM_SIG_ADDR 0x0000 - -/* write/read MMIO register */ -#define RTL_W8(reg, val8) writeb ((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) writew ((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg)) -#define RTL_R8(reg) readb (ioaddr + (reg)) -#define RTL_R16(reg) readw (ioaddr + (reg)) -#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg))) - -enum mac_version { - RTL_GIGA_MAC_VER_01 = 0x01, // 8169 - RTL_GIGA_MAC_VER_02 = 0x02, // 8169S - RTL_GIGA_MAC_VER_03 = 0x03, // 8110S - RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB - RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd - RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe - RTL_GIGA_MAC_VER_07 = 0x07, // 8102e - RTL_GIGA_MAC_VER_08 = 0x08, // 8102e - RTL_GIGA_MAC_VER_09 = 0x09, // 8102e - RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e - RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb - RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be - RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb - RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ? - RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ? - RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec - RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf - RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP - RTL_GIGA_MAC_VER_19 = 0x13, // 8168C - RTL_GIGA_MAC_VER_20 = 0x14, // 8168C - RTL_GIGA_MAC_VER_21 = 0x15, // 8168C - RTL_GIGA_MAC_VER_22 = 0x16, // 8168C - RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP - RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP - RTL_GIGA_MAC_VER_25 = 0x19, // 8168D -}; - -#define _R(NAME,MAC,MASK) \ - { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK } - -static const struct { - const char *name; - u8 mac_version; - u32 RxConfigMask; /* Clears the bits supported by this chip */ -} rtl_chip_info[] = { - _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169 - _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S - _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S - _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd - _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe - _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E - _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139 - _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139 - _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E - _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E - _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E - _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E - _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880) // PCI-E -}; -#undef _R - -enum cfg_version { - RTL_CFG_0 = 0x00, - RTL_CFG_1, - RTL_CFG_2 -}; - -#if 0 -/** Device Table from Linux Driver **/ -static struct pci_device_id rtl8169_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 }, - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 }, - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 }, - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_1 }, - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 }, - { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 }, - { PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107), 0, 0, RTL_CFG_0 }, - { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 }, - { PCI_VENDOR_ID_LINKSYS, 0x1032, - PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 }, - { 0x0001, 0x8168, - PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 }, - {0,}, -}; -#endif - -enum rtl_registers { - MAC0 = 0, /* Ethernet hardware address. */ - MAC4 = 4, - MAR0 = 8, /* Multicast filter. */ - CounterAddrLow = 0x10, - CounterAddrHigh = 0x14, - TxDescStartAddrLow = 0x20, - TxDescStartAddrHigh = 0x24, - TxHDescStartAddrLow = 0x28, - TxHDescStartAddrHigh = 0x2c, - FLASH = 0x30, - ERSR = 0x36, - ChipCmd = 0x37, - TxPoll = 0x38, - IntrMask = 0x3c, - IntrStatus = 0x3e, - TxConfig = 0x40, - RxConfig = 0x44, - RxMissed = 0x4c, - Cfg9346 = 0x50, - Config0 = 0x51, - Config1 = 0x52, - Config2 = 0x53, - Config3 = 0x54, - Config4 = 0x55, - Config5 = 0x56, - MultiIntr = 0x5c, - PHYAR = 0x60, - PHYstatus = 0x6c, - RxMaxSize = 0xda, - CPlusCmd = 0xe0, - IntrMitigate = 0xe2, - RxDescAddrLow = 0xe4, - RxDescAddrHigh = 0xe8, - EarlyTxThres = 0xec, - FuncEvent = 0xf0, - FuncEventMask = 0xf4, - FuncPresetState = 0xf8, - FuncForceEvent = 0xfc, -}; - -enum rtl8110_registers { - TBICSR = 0x64, - TBI_ANAR = 0x68, - TBI_LPAR = 0x6a, -}; - -enum rtl8168_8101_registers { - CSIDR = 0x64, - CSIAR = 0x68, -#define CSIAR_FLAG 0x80000000 -#define CSIAR_WRITE_CMD 0x80000000 -#define CSIAR_BYTE_ENABLE 0x0f -#define CSIAR_BYTE_ENABLE_SHIFT 12 -#define CSIAR_ADDR_MASK 0x0fff - - EPHYAR = 0x80, -#define EPHYAR_FLAG 0x80000000 -#define EPHYAR_WRITE_CMD 0x80000000 -#define EPHYAR_REG_MASK 0x1f -#define EPHYAR_REG_SHIFT 16 -#define EPHYAR_DATA_MASK 0xffff - DBG_REG = 0xd1, -#define FIX_NAK_1 (1 << 4) -#define FIX_NAK_2 (1 << 3) -}; - -enum rtl_register_content { - /* InterruptStatusBits */ - SYSErr = 0x8000, - PCSTimeout = 0x4000, - SWInt = 0x0100, - TxDescUnavail = 0x0080, - RxFIFOOver = 0x0040, - LinkChg = 0x0020, - RxOverflow = 0x0010, - TxErr = 0x0008, - TxOK = 0x0004, - RxErr = 0x0002, - RxOK = 0x0001, - - /* RxStatusDesc */ - RxFOVF = (1 << 23), - RxRWT = (1 << 22), - RxRES = (1 << 21), - RxRUNT = (1 << 20), - RxCRC = (1 << 19), - - /* ChipCmdBits */ - CmdReset = 0x10, - CmdRxEnb = 0x08, - CmdTxEnb = 0x04, - RxBufEmpty = 0x01, - - /* TXPoll register p.5 */ - HPQ = 0x80, /* Poll cmd on the high prio queue */ - NPQ = 0x40, /* Poll cmd on the low prio queue */ - FSWInt = 0x01, /* Forced software interrupt */ - - /* Cfg9346Bits */ - Cfg9346_Lock = 0x00, - Cfg9346_Unlock = 0xc0, - - /* rx_mode_bits */ - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0x08, - AcceptMulticast = 0x04, - AcceptMyPhys = 0x02, - AcceptAllPhys = 0x01, - - /* RxConfigBits */ - RxCfgFIFOShift = 13, - RxCfgDMAShift = 8, - - /* TxConfigBits */ - TxInterFrameGapShift = 24, - TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ - - /* Config1 register p.24 */ - LEDS1 = (1 << 7), - LEDS0 = (1 << 6), - MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ - Speed_down = (1 << 4), - MEMMAP = (1 << 3), - IOMAP = (1 << 2), - VPD = (1 << 1), - PMEnable = (1 << 0), /* Power Management Enable */ - - /* Config2 register p. 25 */ - PCI_Clock_66MHz = 0x01, - PCI_Clock_33MHz = 0x00, - - /* Config3 register p.25 */ - MagicPacket = (1 << 5), /* Wake up when receives a Magic Packet */ - LinkUp = (1 << 4), /* Wake up when the cable connection is re-established */ - Beacon_en = (1 << 0), /* 8168 only. Reserved in the 8168b */ - - /* Config5 register p.27 */ - BWF = (1 << 6), /* Accept Broadcast wakeup frame */ - MWF = (1 << 5), /* Accept Multicast wakeup frame */ - UWF = (1 << 4), /* Accept Unicast wakeup frame */ - LanWake = (1 << 1), /* LanWake enable/disable */ - PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ - - /* TBICSR p.28 */ - TBIReset = 0x80000000, - TBILoopback = 0x40000000, - TBINwEnable = 0x20000000, - TBINwRestart = 0x10000000, - TBILinkOk = 0x02000000, - TBINwComplete = 0x01000000, - - /* CPlusCmd p.31 */ - EnableBist = (1 << 15), // 8168 8101 - Mac_dbgo_oe = (1 << 14), // 8168 8101 - Normal_mode = (1 << 13), // unused - Force_half_dup = (1 << 12), // 8168 8101 - Force_rxflow_en = (1 << 11), // 8168 8101 - Force_txflow_en = (1 << 10), // 8168 8101 - Cxpl_dbg_sel = (1 << 9), // 8168 8101 - ASF = (1 << 8), // 8168 8101 - PktCntrDisable = (1 << 7), // 8168 8101 - Mac_dbgo_sel = 0x001c, // 8168 - RxVlan = (1 << 6), - RxChkSum = (1 << 5), - PCIDAC = (1 << 4), - PCIMulRW = (1 << 3), - INTT_0 = 0x0000, // 8168 - INTT_1 = 0x0001, // 8168 - INTT_2 = 0x0002, // 8168 - INTT_3 = 0x0003, // 8168 - - /* rtl8169_PHYstatus */ - TBI_Enable = 0x80, - TxFlowCtrl = 0x40, - RxFlowCtrl = 0x20, - _1000bpsF = 0x10, - _100bps = 0x08, - _10bps = 0x04, - LinkStatus = 0x02, - FullDup = 0x01, - - /* _TBICSRBit */ - TBILinkOK = 0x02000000, - - /* DumpCounterCommand */ - CounterDump = 0x8, -}; - -enum desc_status_bit { - DescOwn = (1 << 31), /* Descriptor is owned by NIC */ - RingEnd = (1 << 30), /* End of descriptor ring */ - FirstFrag = (1 << 29), /* First segment of a packet */ - LastFrag = (1 << 28), /* Final segment of a packet */ - - /* Tx private */ - LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */ - MSSShift = 16, /* MSS value position */ - MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */ - IPCS = (1 << 18), /* Calculate IP checksum */ - UDPCS = (1 << 17), /* Calculate UDP/IP checksum */ - TCPCS = (1 << 16), /* Calculate TCP/IP checksum */ - TxVlanTag = (1 << 17), /* Add VLAN tag */ - - /* Rx private */ - PID1 = (1 << 18), /* Protocol ID bit 1/2 */ - PID0 = (1 << 17), /* Protocol ID bit 2/2 */ - -#define RxProtoUDP (PID1) -#define RxProtoTCP (PID0) -#define RxProtoIP (PID1 | PID0) -#define RxProtoMask RxProtoIP - - IPFail = (1 << 16), /* IP checksum failed */ - UDPFail = (1 << 15), /* UDP/IP checksum failed */ - TCPFail = (1 << 14), /* TCP/IP checksum failed */ - RxVlanTag = (1 << 16), /* VLAN tag available */ -}; - -#define RsvdMask 0x3fffc000 - -struct TxDesc { - volatile uint32_t opts1; - volatile uint32_t opts2; - volatile uint32_t addr_lo; - volatile uint32_t addr_hi; -}; - -struct RxDesc { - volatile uint32_t opts1; - volatile uint32_t opts2; - volatile uint32_t addr_lo; - volatile uint32_t addr_hi; -}; - -enum features { - RTL_FEATURE_WOL = (1 << 0), - RTL_FEATURE_MSI = (1 << 1), - RTL_FEATURE_GMII = (1 << 2), -}; - -static void rtl_hw_start_8169(struct net_device *); -static void rtl_hw_start_8168(struct net_device *); -static void rtl_hw_start_8101(struct net_device *); - -struct rtl8169_private { - - struct pci_device *pci_dev; - struct net_device *netdev; - uint8_t *hw_addr; - void *mmio_addr; - uint32_t irqno; - - int chipset; - int mac_version; - u16 intr_event; - - struct io_buffer *tx_iobuf[NUM_TX_DESC]; - struct io_buffer *rx_iobuf[NUM_RX_DESC]; - - struct TxDesc *tx_base; - struct RxDesc *rx_base; - - uint32_t tx_curr; - uint32_t rx_curr; - - uint32_t tx_tail; - - uint32_t tx_fill_ctr; - - u16 cp_cmd; - - int phy_auto_nego_reg; - int phy_1000_ctrl_reg; - - int ( *set_speed ) (struct net_device *, u8 autoneg, u16 speed, u8 duplex ); - void ( *phy_reset_enable ) ( void *ioaddr ); - void ( *hw_start ) ( struct net_device * ); - unsigned int ( *phy_reset_pending ) ( void *ioaddr ); - unsigned int ( *link_ok ) ( void *ioaddr ); - - int pcie_cap; - - unsigned features; - -}; - -static const unsigned int rtl8169_rx_config = - (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); - -#endif /* _R8169_H_ */ - -/* - * Local variables: - * c-basic-offset: 8 - * c-indent-level: 8 - * tab-width: 8 - * End: - */ diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c new file mode 100644 index 00000000..eb16cb71 --- /dev/null +++ b/src/drivers/net/realtek.c @@ -0,0 +1,779 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * (EEPROM code originally implemented for rtl8139.c) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "realtek.h" + +/** @file + * + * Realtek 10/100/1000 network card driver + * + * Based on the following datasheets: + * + * http://www.datasheetarchive.com/dl/Datasheets-8/DSA-153536.pdf + * http://www.datasheetarchive.com/indexdl/Datasheet-028/DSA00494723.pdf + */ + +/****************************************************************************** + * + * EEPROM interface + * + ****************************************************************************** + */ + +/** Pin mapping for SPI bit-bashing interface */ +static const uint8_t realtek_eeprom_bits[] = { + [SPI_BIT_SCLK] = RTL_9346CR_EESK, + [SPI_BIT_MOSI] = RTL_9346CR_EEDI, + [SPI_BIT_MISO] = RTL_9346CR_EEDO, + [SPI_BIT_SS(0)] = ( RTL_9346CR_EECS | RTL_9346CR_EEM1 ), +}; + +/** + * Read input bit + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @ret zero Input is a logic 0 + * @ret non-zero Input is a logic 1 + */ +static int realtek_spi_read_bit ( struct bit_basher *basher, + unsigned int bit_id ) { + struct realtek_nic *rtl = container_of ( basher, struct realtek_nic, + spibit.basher ); + uint8_t mask = realtek_eeprom_bits[bit_id]; + uint8_t reg; + + reg = readb ( rtl->regs + RTL_9346CR ); + return ( reg & mask ); +} + +/** + * Set/clear output bit + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @v data Value to write + */ +static void realtek_spi_write_bit ( struct bit_basher *basher, + unsigned int bit_id, unsigned long data ) { + struct realtek_nic *rtl = container_of ( basher, struct realtek_nic, + spibit.basher ); + uint8_t mask = realtek_eeprom_bits[bit_id]; + uint8_t reg; + + reg = readb ( rtl->regs + RTL_9346CR ); + reg &= ~mask; + reg |= ( data & mask ); + writeb ( reg, rtl->regs + RTL_9346CR ); +} + +/** SPI bit-bashing interface */ +static struct bit_basher_operations realtek_basher_ops = { + .read = realtek_spi_read_bit, + .write = realtek_spi_write_bit, +}; + +/** + * Initialise EEPROM + * + * @v netdev Network device + */ +static void realtek_init_eeprom ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + + /* Initialise SPI bit-bashing interface */ + rtl->spibit.basher.op = &realtek_basher_ops; + rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; + init_spi_bit_basher ( &rtl->spibit ); + + /* Detect EEPROM type and initialise three-wire device */ + if ( readl ( rtl->regs + RTL_RCR ) & RTL_RCR_9356SEL ) { + DBGC ( rtl, "REALTEK %p EEPROM is a 93C56\n", rtl ); + init_at93c56 ( &rtl->eeprom, 16 ); + } else { + DBGC ( rtl, "REALTEK %p EEPROM is a 93C46\n", rtl ); + init_at93c46 ( &rtl->eeprom, 16 ); + } + rtl->eeprom.bus = &rtl->spibit.bus; + + /* Initialise space for non-volatile options, if available + * + * We use offset 0x40 (i.e. address 0x20), length 0x40. This + * block is marked as VPD in the Realtek datasheets, so we use + * it only if we detect that the card is not supporting VPD. + */ + if ( readb ( rtl->regs + RTL_CONFIG1 ) & RTL_CONFIG1_VPD ) { + DBGC ( rtl, "REALTEK %p EEPROM in use for VPD; cannot use " + "for options\n", rtl ); + } else { + nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, RTL_EEPROM_VPD, + RTL_EEPROM_VPD_LEN, NULL, &netdev->refcnt ); + } +} + +/****************************************************************************** + * + * MII interface + * + ****************************************************************************** + */ + +/** + * Read from MII register + * + * @v mii MII interface + * @v reg Register address + * @ret value Data read, or negative error + */ +static int realtek_mii_read ( struct mii_interface *mii, unsigned int reg ) { + struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii ); + unsigned int i; + uint32_t value; + + /* Initiate read */ + writel ( RTL_PHYAR_VALUE ( 0, reg, 0 ), rtl->regs + RTL_PHYAR ); + + /* Wait for read to complete */ + for ( i = 0 ; i < RTL_MII_MAX_WAIT_US ; i++ ) { + + /* If read is not complete, delay 1us and retry */ + value = readl ( rtl->regs + RTL_PHYAR ); + if ( ! ( value & RTL_PHYAR_FLAG ) ) { + udelay ( 1 ); + continue; + } + + /* Return register value */ + return ( RTL_PHYAR_DATA ( value ) ); + } + + DBGC ( rtl, "REALTEK %p timed out waiting for MII read\n", rtl ); + return -ETIMEDOUT; +} + +/** + * Write to MII register + * + * @v mii MII interface + * @v reg Register address + * @v data Data to write + * @ret rc Return status code + */ +static int realtek_mii_write ( struct mii_interface *mii, unsigned int reg, + unsigned int data) { + struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii ); + unsigned int i; + + /* Initiate write */ + writel ( RTL_PHYAR_VALUE ( RTL_PHYAR_FLAG, reg, data ), + rtl->regs + RTL_PHYAR ); + + /* Wait for write to complete */ + for ( i = 0 ; i < RTL_MII_MAX_WAIT_US ; i++ ) { + + /* If write is not complete, delay 1us and retry */ + if ( readl ( rtl->regs + RTL_PHYAR ) & RTL_PHYAR_FLAG ) { + udelay ( 1 ); + continue; + } + + return 0; + } + + DBGC ( rtl, "REALTEK %p timed out waiting for MII write\n", rtl ); + return -ETIMEDOUT; +} + +/** Realtek MII operations */ +static struct mii_operations realtek_mii_operations = { + .read = realtek_mii_read, + .write = realtek_mii_write, +}; + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset hardware + * + * @v rtl Realtek device + * @ret rc Return status code + */ +static int realtek_reset ( struct realtek_nic *rtl ) { + unsigned int i; + + /* Issue reset */ + writeb ( RTL_CR_RST, rtl->regs + RTL_CR ); + + /* Wait for reset to complete */ + for ( i = 0 ; i < RTL_RESET_MAX_WAIT_MS ; i++ ) { + + /* If reset is not complete, delay 1ms and retry */ + if ( readb ( rtl->regs + RTL_CR ) & RTL_CR_RST ) { + mdelay ( 1 ); + continue; + } + + /* Enable PCI Dual Address Cycle (for 64-bit systems) */ + writew ( ( RTL_CPCR_DAC | RTL_CPCR_MULRW ), + rtl->regs + RTL_CPCR ); + + return 0; + } + + DBGC ( rtl, "REALTEK %p timed out waiting for reset\n", rtl ); + return -ETIMEDOUT; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void realtek_check_link ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + + if ( readb ( rtl->regs + RTL_PHYSTATUS ) & RTL_PHYSTATUS_LINKSTS ) { + netdev_link_up ( netdev ); + } else { + netdev_link_down ( netdev ); + } +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Create descriptor ring + * + * @v rtl Realtek device + * @v ring Descriptor ring + * @ret rc Return status code + */ +static int realtek_create_ring ( struct realtek_nic *rtl, + struct realtek_ring *ring ) { + physaddr_t address; + + /* Allocate descriptor ring */ + ring->desc = malloc_dma ( ring->len, RTL_RING_ALIGN ); + if ( ! ring->desc ) + return -ENOMEM; + + /* Initialise descriptor ring */ + memset ( ring->desc, 0, ring->len ); + + /* Program ring address */ + address = virt_to_bus ( ring->desc ); + writel ( ( address & 0xffffffffUL ), rtl->regs + ring->reg ); + if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { + writel ( ( ( ( uint64_t ) address ) >> 32 ), + rtl->regs + ring->reg + 4 ); + } + DBGC ( rtl, "REALTEK %p ring %02x is at [%08llx,%08llx)\n", + rtl, ring->reg, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + ring->len ) ); + + return 0; +} + +/** + * Destroy descriptor ring + * + * @v rtl Realtek device + * @v ring Descriptor ring + */ +static void realtek_destroy_ring ( struct realtek_nic *rtl, + struct realtek_ring *ring ) { + + /* Clear ring address */ + writel ( 0, rtl->regs + ring->reg ); + writel ( 0, rtl->regs + ring->reg + 4 ); + + /* Free descriptor ring */ + free_dma ( ring->desc, ring->len ); + ring->desc = NULL; + ring->prod = 0; + ring->cons = 0; +} + +/** + * Refill receive descriptor ring + * + * @v rtl Realtek device + */ +static void realtek_refill_rx ( struct realtek_nic *rtl ) { + struct realtek_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + physaddr_t address; + int is_last; + + while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( RTL_RX_MAX_LEN ); + if ( ! iobuf ) { + /* Wait for next refill */ + return; + } + + /* Get next receive descriptor */ + rx_idx = ( rtl->rx.prod++ % RTL_NUM_RX_DESC ); + is_last = ( rx_idx == ( RTL_NUM_RX_DESC - 1 ) ); + rx = &rtl->rx.desc[rx_idx]; + + /* Populate receive descriptor */ + address = virt_to_bus ( iobuf->data ); + rx->address = cpu_to_le64 ( address ); + rx->length = RTL_RX_MAX_LEN; + wmb(); + rx->flags = ( cpu_to_le16 ( RTL_DESC_OWN ) | + ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); + wmb(); + + /* Record I/O buffer */ + assert ( rtl->rx_iobuf[rx_idx] == NULL ); + rtl->rx_iobuf[rx_idx] = iobuf; + + DBGC2 ( rtl, "REALTEK %p RX %d is [%llx,%llx)\n", rtl, rx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + RTL_RX_MAX_LEN ) ); + } +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int realtek_open ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + uint32_t rcr; + int rc; + + /* Create transmit descriptor ring */ + if ( ( rc = realtek_create_ring ( rtl, &rtl->tx ) ) != 0 ) + goto err_create_tx; + + /* Create receive descriptor ring */ + if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 ) + goto err_create_rx; + + /* Configure MTU */ + writew ( RTL_RX_MAX_LEN, rtl->regs + RTL_RMS ); + + /* Accept all packets */ + writel ( 0xffffffffUL, rtl->regs + RTL_MAR0 ); + writel ( 0xffffffffUL, rtl->regs + RTL_MAR4 ); + rcr = readl ( rtl->regs + RTL_RCR ); + writel ( ( rcr | RTL_RCR_AB | RTL_RCR_AM | RTL_RCR_APM | RTL_RCR_AAP ), + rtl->regs + RTL_RCR ); + + /* Fill receive ring */ + realtek_refill_rx ( rtl ); + + /* Enable transmitter and receiver */ + writeb ( ( RTL_CR_TE | RTL_CR_RE ), rtl->regs + RTL_CR ); + + return 0; + + realtek_destroy_ring ( rtl, &rtl->rx ); + err_create_rx: + realtek_destroy_ring ( rtl, &rtl->tx ); + err_create_tx: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void realtek_close ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + unsigned int i; + + /* Disable receiver and transmitter */ + writeb ( 0, rtl->regs + RTL_CR ); + + /* Destroy receive descriptor ring */ + realtek_destroy_ring ( rtl, &rtl->rx ); + + /* Discard any unused receive buffers */ + for ( i = 0 ; i < RTL_NUM_RX_DESC ; i++ ) { + if ( rtl->rx_iobuf[i] ) + free_iob ( rtl->rx_iobuf[i] ); + rtl->rx_iobuf[i] = NULL; + } + + /* Destroy transmit descriptor ring */ + realtek_destroy_ring ( rtl, &rtl->tx ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int realtek_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct realtek_nic *rtl = netdev->priv; + struct realtek_descriptor *tx; + unsigned int tx_idx; + physaddr_t address; + int is_last; + + /* Get next transmit descriptor */ + if ( ( rtl->tx.prod - rtl->tx.cons ) >= RTL_NUM_TX_DESC ) { + DBGC ( rtl, "REALTEK %p out of transmit descriptors\n", rtl ); + return -ENOBUFS; + } + tx_idx = ( rtl->tx.prod++ % RTL_NUM_TX_DESC ); + is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) ); + tx = &rtl->tx.desc[tx_idx]; + + /* Populate transmit descriptor */ + address = virt_to_bus ( iobuf->data ); + tx->address = cpu_to_le64 ( address ); + tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); + wmb(); + tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS | RTL_DESC_LS ) | + ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); + wmb(); + + /* Notify card that there are packets ready to transmit */ + writeb ( RTL_TPPOLL_NPQ, rtl->regs + RTL_TPPOLL ); + + DBGC2 ( rtl, "REALTEK %p TX %d is [%llx,%llx)\n", rtl, tx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + iob_len ( iobuf ) ) ); + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void realtek_poll_tx ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + struct realtek_descriptor *tx; + unsigned int tx_idx; + + /* Check for completed packets */ + while ( rtl->tx.cons != rtl->tx.prod ) { + + /* Get next transmit descriptor */ + tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC ); + tx = &rtl->tx.desc[tx_idx]; + + /* Stop if descriptor is still in use */ + if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) + return; + + DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); + + /* Complete TX descriptor */ + netdev_tx_complete_next ( netdev ); + rtl->tx.cons++; + } +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void realtek_poll_rx ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + struct realtek_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + size_t len; + + /* Check for received packets */ + while ( rtl->rx.cons != rtl->rx.prod ) { + + /* Get next receive descriptor */ + rx_idx = ( rtl->rx.cons % RTL_NUM_RX_DESC ); + rx = &rtl->rx.desc[rx_idx]; + + /* Stop if descriptor is still in use */ + if ( rx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) + return; + + /* Populate I/O buffer */ + iobuf = rtl->rx_iobuf[rx_idx]; + rtl->rx_iobuf[rx_idx] = NULL; + len = ( le16_to_cpu ( rx->length ) & RTL_DESC_SIZE_MASK ); + iob_put ( iobuf, ( len - 4 /* strip CRC */ ) ); + + DBGC2 ( rtl, "REALTEK %p RX %d complete (length %zd)\n", + rtl, rx_idx, len ); + + /* Hand off to network stack */ + if ( rx->flags & cpu_to_le16 ( RTL_DESC_RES ) ) { + netdev_rx_err ( netdev, iobuf, -EIO ); + } else { + netdev_rx ( netdev, iobuf ); + } + rtl->rx.cons++; + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void realtek_poll ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + uint16_t isr; + + /* Check for and acknowledge interrupts */ + isr = readw ( rtl->regs + RTL_ISR ); + if ( ! isr ) + return; + writew ( isr, rtl->regs + RTL_ISR ); + + /* Poll for TX completions, if applicable */ + if ( isr & ( RTL_IRQ_TER | RTL_IRQ_TOK ) ) + realtek_poll_tx ( netdev ); + + /* Poll for RX completionsm, if applicable */ + if ( isr & ( RTL_IRQ_RER | RTL_IRQ_ROK ) ) + realtek_poll_rx ( netdev ); + + /* Check link state, if applicable */ + if ( isr & RTL_IRQ_PUN_LINKCHG ) + realtek_check_link ( netdev ); + + /* Refill RX ring */ + realtek_refill_rx ( rtl ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void realtek_irq ( struct net_device *netdev, int enable ) { + struct realtek_nic *rtl = netdev->priv; + uint16_t imr; + + /* Set interrupt mask */ + imr = ( enable ? ( RTL_IRQ_PUN_LINKCHG | RTL_IRQ_TER | RTL_IRQ_TOK | + RTL_IRQ_RER | RTL_IRQ_ROK ) : 0 ); + writew ( imr, rtl->regs + RTL_IMR ); +} + +/** Realtek network device operations */ +static struct net_device_operations realtek_operations = { + .open = realtek_open, + .close = realtek_close, + .transmit = realtek_transmit, + .poll = realtek_poll, + .irq = realtek_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int realtek_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct realtek_nic *rtl; + unsigned int i; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *rtl ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &realtek_operations ); + rtl = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( rtl, 0, sizeof ( *rtl ) ); + realtek_init_ring ( &rtl->tx, RTL_NUM_TX_DESC, RTL_TNPDS ); + realtek_init_ring ( &rtl->rx, RTL_NUM_RX_DESC, RTL_RDSAR ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + rtl->regs = ioremap ( pci->membase, RTL_BAR_SIZE ); + + /* Reset the NIC */ + if ( ( rc = realtek_reset ( rtl ) ) != 0 ) + goto err_reset; + + /* Initialise EEPROM */ + realtek_init_eeprom ( netdev ); + + /* Read MAC address from EEPROM */ + if ( ( rc = nvs_read ( &rtl->eeprom.nvs, RTL_EEPROM_MAC, + netdev->hw_addr, ETH_ALEN ) ) != 0 ) { + DBGC ( rtl, "REALTEK %p could not read MAC address: %s\n", + rtl, strerror ( rc ) ); + goto err_nvs_read; + } + + /* The EEPROM may not be present for onboard NICs. Fall back + * to reading the current ID register value, which will + * hopefully have been programmed by the platform firmware. + */ + if ( ! is_valid_ether_addr ( netdev->hw_addr ) ) { + DBGC ( rtl, "REALTEK %p seems to have no EEPROM\n", rtl ); + for ( i = 0 ; i < ETH_ALEN ; i++ ) + netdev->hw_addr[i] = readb ( rtl->regs + RTL_IDR0 + i ); + } + + /* Initialise and reset MII interface */ + mii_init ( &rtl->mii, &realtek_mii_operations ); + if ( ( rc = mii_reset ( &rtl->mii ) ) != 0 ) { + DBGC ( rtl, "REALTEK %p could not reset MII: %s\n", + rtl, strerror ( rc ) ); + goto err_mii_reset; + } + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + realtek_check_link ( netdev ); + + /* Register non-volatile options, if applicable */ + if ( rtl->nvo.nvs ) { + if ( ( rc = register_nvo ( &rtl->nvo, + netdev_settings ( netdev ) ) ) != 0) + goto err_register_nvo; + } + + return 0; + + err_register_nvo: + unregister_netdev ( netdev ); + err_register_netdev: + err_mii_reset: + err_nvs_read: + realtek_reset ( rtl ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void realtek_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct realtek_nic *rtl = netdev->priv; + + /* Unregister non-volatile options, if applicable */ + if ( rtl->nvo.nvs ) + unregister_nvo ( &rtl->nvo ); + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset card */ + realtek_reset ( rtl ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Realtek PCI device IDs */ +static struct pci_device_id realtek_nics[] = { + PCI_ROM ( 0x10ec, 0x8129, "r8129", "RTL-8129", 0 ), + PCI_ROM ( 0x10ec, 0x8136, "r8136", "RTL8101E/RTL8102E", 0 ), + PCI_ROM ( 0x10ec, 0x8167, "r8167", "RTL-8110SC/8169SC", 0 ), + PCI_ROM ( 0x10ec, 0x8168, "r8168", "RTL8111/8168B", 0 ), + PCI_ROM ( 0x10ec, 0x8169, "r8169", "RTL-8169", 0 ), + PCI_ROM ( 0x1186, 0x4300, "dge528t", "DGE-528T", 0 ), + PCI_ROM ( 0x1259, 0xc107, "allied8169", "Allied Telesyn 8169", 0 ), + PCI_ROM ( 0x16ec, 0x0116, "usr997902", "USR997902", 0 ), + PCI_ROM ( 0x1737, 0x1032, "linksys8169","Linksys 8169", 0 ), + PCI_ROM ( 0x0001, 0x8168, "clone8169", "Cloned 8169", 0 ), +}; + +/** Realtek PCI driver */ +struct pci_driver realtek_driver __pci_driver = { + .ids = realtek_nics, + .id_count = ( sizeof ( realtek_nics ) / sizeof ( realtek_nics[0] ) ), + .probe = realtek_probe, + .remove = realtek_remove, +}; diff --git a/src/drivers/net/realtek.h b/src/drivers/net/realtek.h new file mode 100644 index 00000000..aad4b34c --- /dev/null +++ b/src/drivers/net/realtek.h @@ -0,0 +1,205 @@ +#ifndef _REALTEK_H +#define _REALTEK_H + +/** @file + * + * Realtek 10/100/1000 network card driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include + +/** PCI memory BAR size */ +#define RTL_BAR_SIZE 0x100 + +/** A packet descriptor */ +struct realtek_descriptor { + /** Buffer size */ + uint16_t length; + /** Flags */ + uint16_t flags; + /** Reserved */ + uint32_t reserved; + /** Buffer address */ + uint64_t address; +} __attribute__ (( packed )); + +/** Descriptor buffer size mask */ +#define RTL_DESC_SIZE_MASK 0x3fff + +/** Packet descriptor flags */ +enum realtek_descriptor_flags { + /** Descriptor is owned by NIC */ + RTL_DESC_OWN = 0x8000, + /** End of descriptor ring */ + RTL_DESC_EOR = 0x4000, + /** First segment descriptor */ + RTL_DESC_FS = 0x2000, + /** Last segment descriptor */ + RTL_DESC_LS = 0x1000, + /** Receive error summary */ + RTL_DESC_RES = 0x0020, +}; + +/** Descriptor ring alignment */ +#define RTL_RING_ALIGN 256 + +/** ID Register 0 (6 bytes) */ +#define RTL_IDR0 0x00 + +/** Multicast Register 0 (dword) */ +#define RTL_MAR0 0x08 + +/** Multicast Register 4 (dword) */ +#define RTL_MAR4 0x0c + +/** Transmit Normal Priority Descriptors (qword) */ +#define RTL_TNPDS 0x20 + +/** Number of transmit descriptors */ +#define RTL_NUM_TX_DESC 4 + +/** Command Register (byte) */ +#define RTL_CR 0x37 +#define RTL_CR_RST 0x10 /**< Reset */ +#define RTL_CR_RE 0x08 /**< Receiver Enable */ +#define RTL_CR_TE 0x04 /**< Transmit Enable */ + +/** Maximum time to wait for a reset, in milliseconds */ +#define RTL_RESET_MAX_WAIT_MS 100 + +/** Transmit Priority Polling Register (byte) */ +#define RTL_TPPOLL 0x38 +#define RTL_TPPOLL_NPQ 0x40 /**< Normal Priority Queue Polling */ + +/** Interrupt Mask Register (word) */ +#define RTL_IMR 0x3c +#define RTL_IRQ_PUN_LINKCHG 0x20 /**< Packet underrun / link change */ +#define RTL_IRQ_TER 0x08 /**< Transmit error */ +#define RTL_IRQ_TOK 0x04 /**< Transmit OK */ +#define RTL_IRQ_RER 0x02 /**< Receive error */ +#define RTL_IRQ_ROK 0x01 /**< Receive OK */ + +/** Interrupt Status Register (word) */ +#define RTL_ISR 0x3e + +/** Receive (Rx) Configuration Register (dword) */ +#define RTL_RCR 0x44 +#define RTL_RCR_9356SEL 0x40 /**< EEPROM is a 93C56 */ +#define RTL_RCR_AB 0x08 /**< Accept broadcast packets */ +#define RTL_RCR_AM 0x04 /**< Accept multicast packets */ +#define RTL_RCR_APM 0x02 /**< Accept physical match packets */ +#define RTL_RCR_AAP 0x01 /**< Accept all packets */ + +/** 93C46 (93C56) Command Register (byte) */ +#define RTL_9346CR 0x50 +#define RTL_9346CR_EEM1 0x80 /**< Mode select bit 1 */ +#define RTL_9346CR_EEM0 0x40 /**< Mode select bit 0 */ +#define RTL_9346CR_EECS 0x08 /**< Chip select */ +#define RTL_9346CR_EESK 0x04 /**< Clock */ +#define RTL_9346CR_EEDI 0x02 /**< Data in */ +#define RTL_9346CR_EEDO 0x01 /**< Data out */ + +/** Word offset of MAC address within EEPROM */ +#define RTL_EEPROM_MAC ( 0x0e / 2 ) + +/** Word offset of VPD / non-volatile options within EEPROM */ +#define RTL_EEPROM_VPD ( 0x40 / 2 ) + +/** Length of VPD / non-volatile options within EEPROM */ +#define RTL_EEPROM_VPD_LEN 0x40 + +/** Configuration Register 1 (byte) */ +#define RTL_CONFIG1 0x52 +#define RTL_CONFIG1_VPD 0x02 /**< Vital Product Data enabled */ + +/** PHY Access Register (dword) */ +#define RTL_PHYAR 0x60 +#define RTL_PHYAR_FLAG 0x80000000UL /**< Read/write flag */ + +/** Construct PHY Access Register value */ +#define RTL_PHYAR_VALUE( flag, reg, data ) ( (flag) | ( (reg) << 16 ) | (data) ) + +/** Extract PHY Access Register data */ +#define RTL_PHYAR_DATA( value ) ( (value) & 0xffff ) + +/** Maximum time to wait for PHY access, in microseconds */ +#define RTL_MII_MAX_WAIT_US 500 + +/** PHY (GMII, MII, or TBI) Status Register (byte) */ +#define RTL_PHYSTATUS 0x6c +#define RTL_PHYSTATUS_LINKSTS 0x02 /**< Link ok */ + +/** RX Packet Maximum Size Register (word) */ +#define RTL_RMS 0xda + +/** C+ Command Register (word) */ +#define RTL_CPCR 0xe0 +#define RTL_CPCR_DAC 0x10 /**< PCI Dual Address Cycle Enable */ +#define RTL_CPCR_MULRW 0x08 /**< PCI Multiple Read/Write Enable */ + +/** Receive Descriptor Start Address Register (qword) */ +#define RTL_RDSAR 0xe4 + +/** Number of receive descriptors */ +#define RTL_NUM_RX_DESC 4 + +/** Receive buffer length */ +#define RTL_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ ) + +/** A Realtek descriptor ring */ +struct realtek_ring { + /** Descriptors */ + struct realtek_descriptor *desc; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; + + /** Descriptor start address register */ + unsigned int reg; + /** Length (in bytes) */ + size_t len; +}; + +/** + * Initialise descriptor ring + * + * @v ring Descriptor ring + * @v count Number of descriptors + * @v reg Descriptor start address register + */ +static inline __attribute__ (( always_inline)) void +realtek_init_ring ( struct realtek_ring *ring, unsigned int count, + unsigned int reg ) { + ring->len = ( count * sizeof ( ring->desc[0] ) ); + ring->reg = reg; +} + +/** A Realtek network card */ +struct realtek_nic { + /** Registers */ + void *regs; + /** SPI bit-bashing interface */ + struct spi_bit_basher spibit; + /** EEPROM */ + struct spi_device eeprom; + /** Non-volatile options */ + struct nvo_block nvo; + /** MII interface */ + struct mii_interface mii; + + /** Transmit descriptor ring */ + struct realtek_ring tx; + /** Receive descriptor ring */ + struct realtek_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC]; +}; + +#endif /* _REALTEK_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 87b5ac72..e2d85750 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -142,6 +142,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_ath ( ERRFILE_DRIVER | 0x00600000 ) #define ERRFILE_vmxnet3 ( ERRFILE_DRIVER | 0x00610000 ) #define ERRFILE_mii ( ERRFILE_DRIVER | 0x00620000 ) +#define ERRFILE_realtek ( ERRFILE_DRIVER | 0x00630000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) From 62eb2294f002f16af0af9e4f623dd03c67e8cf4a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 15 Apr 2012 01:35:39 +0100 Subject: [PATCH 175/221] [multiboot] Place multiboot modules low in memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Solaris assumes that there is enough space above the Multiboot modules to use as a decompression and scratch area. This assumption is invalid when using iPXE, which places the Multiboot modules near the top of (32-bit) memory. Fix by copying the modules to an area of memory immediately following the loaded kernel. Debugged-by: Michael Brown Debugged-by: Scott McWhirter Tested-by: Robin Smidsrød Signed-off-by: Michael Brown --- src/arch/i386/image/elfboot.c | 3 +- src/arch/i386/image/multiboot.c | 98 +++++++++++++++++---------------- src/image/elf.c | 18 +++++- src/include/ipxe/elf.h | 2 +- 4 files changed, 69 insertions(+), 52 deletions(-) diff --git a/src/arch/i386/image/elfboot.c b/src/arch/i386/image/elfboot.c index 89e70a3b..21504b7a 100644 --- a/src/arch/i386/image/elfboot.c +++ b/src/arch/i386/image/elfboot.c @@ -42,10 +42,11 @@ FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 ); */ static int elfboot_exec ( struct image *image ) { physaddr_t entry; + physaddr_t max; int rc; /* Load the image using core ELF support */ - if ( ( rc = elf_load ( image, &entry ) ) != 0 ) { + if ( ( rc = elf_load ( image, &entry, &max ) ) != 0 ) { DBGC ( image, "ELF %p could not load: %s\n", image, strerror ( rc ) ); return rc; diff --git a/src/arch/i386/image/multiboot.c b/src/arch/i386/image/multiboot.c index 0336581f..004a01b1 100644 --- a/src/arch/i386/image/multiboot.c +++ b/src/arch/i386/image/multiboot.c @@ -143,7 +143,7 @@ static void multiboot_build_memmap ( struct image *image, * @v image Image * @ret physaddr Physical address of command line */ -physaddr_t multiboot_add_cmdline ( struct image *image ) { +static physaddr_t multiboot_add_cmdline ( struct image *image ) { char *mb_cmdline = ( mb_cmdlines + mb_cmdline_offset ); size_t remaining = ( sizeof ( mb_cmdlines ) - mb_cmdline_offset ); char *buf = mb_cmdline; @@ -174,28 +174,26 @@ physaddr_t multiboot_add_cmdline ( struct image *image ) { } /** - * Build multiboot module list + * Add multiboot modules * * @v image Multiboot image - * @v modules Module list to fill, or NULL - * @ret count Number of modules + * @v start Start address for modules + * @v mbinfo Multiboot information structure + * @v modules Multiboot module list + * @ret rc Return status code */ -static unsigned int -multiboot_build_module_list ( struct image *image, - struct multiboot_module *modules, - unsigned int limit ) { +static int multiboot_add_modules ( struct image *image, physaddr_t start, + struct multiboot_info *mbinfo, + struct multiboot_module *modules, + unsigned int limit ) { struct image *module_image; struct multiboot_module *module; - unsigned int count = 0; - unsigned int insert; - physaddr_t start; - physaddr_t end; - unsigned int i; + int rc; /* Add each image as a multiboot module */ for_each_image ( module_image ) { - if ( count >= limit ) { + if ( mbinfo->mods_count >= limit ) { DBGC ( image, "MULTIBOOT %p limit of %d modules " "reached\n", image, limit ); break; @@ -205,37 +203,36 @@ multiboot_build_module_list ( struct image *image, if ( module_image == image ) continue; - /* At least some OSes expect the multiboot modules to - * be in ascending order, so we have to support it. - */ - start = user_to_phys ( module_image->data, 0 ); - end = user_to_phys ( module_image->data, module_image->len ); - for ( insert = 0 ; insert < count ; insert++ ) { - if ( start < modules[insert].mod_start ) - break; + /* Page-align the module */ + start = ( ( start + 0xfff ) & ~0xfff ); + + /* Prepare segment */ + if ( ( rc = prep_segment ( phys_to_user ( start ), + module_image->len, + module_image->len ) ) != 0 ) { + DBGC ( image, "MULTIBOOT %p could not prepare module " + "%s: %s\n", image, module_image->name, + strerror ( rc ) ); + return rc; } - module = &modules[insert]; - memmove ( ( module + 1 ), module, - ( ( count - insert ) * sizeof ( *module ) ) ); + + /* Copy module */ + memcpy_user ( phys_to_user ( start ), 0, + module_image->data, 0, module_image->len ); + + /* Add module to list */ + module = &modules[mbinfo->mods_count++]; module->mod_start = start; - module->mod_end = end; + module->mod_end = ( start + module_image->len ); module->string = multiboot_add_cmdline ( module_image ); module->reserved = 0; - - /* We promise to page-align modules */ - assert ( ( module->mod_start & 0xfff ) == 0 ); - - count++; + DBGC ( image, "MULTIBOOT %p module %s is [%x,%x)\n", + image, module_image->name, module->mod_start, + module->mod_end ); + start += module_image->len; } - /* Dump module configuration */ - for ( i = 0 ; i < count ; i++ ) { - DBGC ( image, "MULTIBOOT %p module %d is [%x,%x)\n", - image, i, modules[i].mod_start, - modules[i].mod_end ); - } - - return count; + return 0; } /** @@ -314,11 +311,12 @@ static int multiboot_find_header ( struct image *image, * @v image Multiboot file * @v hdr Multiboot header descriptor * @ret entry Entry point + * @ret max Maximum used address * @ret rc Return status code */ static int multiboot_load_raw ( struct image *image, struct multiboot_header_info *hdr, - physaddr_t *entry ) { + physaddr_t *entry, physaddr_t *max ) { size_t offset; size_t filesz; size_t memsz; @@ -349,8 +347,9 @@ static int multiboot_load_raw ( struct image *image, /* Copy image to segment */ memcpy_user ( buffer, 0, image->data, offset, filesz ); - /* Record execution entry point */ + /* Record execution entry point and maximum used address */ *entry = hdr->mb.entry_addr; + *max = ( hdr->mb.load_addr + memsz ); return 0; } @@ -360,13 +359,15 @@ static int multiboot_load_raw ( struct image *image, * * @v image Multiboot file * @ret entry Entry point + * @ret max Maximum used address * @ret rc Return status code */ -static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) { +static int multiboot_load_elf ( struct image *image, physaddr_t *entry, + physaddr_t *max ) { int rc; /* Load ELF image*/ - if ( ( rc = elf_load ( image, entry ) ) != 0 ) { + if ( ( rc = elf_load ( image, entry, max ) ) != 0 ) { DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n", image, strerror ( rc ) ); return rc; @@ -384,6 +385,7 @@ static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) { static int multiboot_exec ( struct image *image ) { struct multiboot_header_info hdr; physaddr_t entry; + physaddr_t max; int rc; /* Locate multiboot header, if present */ @@ -405,8 +407,8 @@ static int multiboot_exec ( struct image *image ) { * the ELF header if present, and Solaris relies on this * behaviour. */ - if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) && - ( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) ) + if ( ( ( rc = multiboot_load_elf ( image, &entry, &max ) ) != 0 ) && + ( ( rc = multiboot_load_raw ( image, &hdr, &entry, &max ) ) != 0 )) return rc; /* Populate multiboot information structure */ @@ -415,11 +417,13 @@ static int multiboot_exec ( struct image *image ) { MBI_FLAG_CMDLINE | MBI_FLAG_MODS ); mb_cmdline_offset = 0; mbinfo.cmdline = multiboot_add_cmdline ( image ); - mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules, - ( sizeof(mbmodules) / sizeof(mbmodules[0]) ) ); mbinfo.mods_addr = virt_to_phys ( mbmodules ); mbinfo.mmap_addr = virt_to_phys ( mbmemmap ); mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name ); + if ( ( rc = multiboot_add_modules ( image, max, &mbinfo, mbmodules, + ( sizeof ( mbmodules ) / + sizeof ( mbmodules[0] ) ) ) ) !=0) + return rc; /* Multiboot images may not return and have no callback * interface, so shut everything down prior to booting the OS. diff --git a/src/image/elf.c b/src/image/elf.c index f4ea4aab..26666ec5 100644 --- a/src/image/elf.c +++ b/src/image/elf.c @@ -47,11 +47,14 @@ typedef Elf32_Off Elf_Off; * @v phdr ELF program header * @v ehdr ELF executable header * @ret entry Entry point, if found + * @ret max Maximum used address * @ret rc Return status code */ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, - Elf_Ehdr *ehdr, physaddr_t *entry ) { + Elf_Ehdr *ehdr, physaddr_t *entry, + physaddr_t *max ) { physaddr_t dest; + physaddr_t end; userptr_t buffer; unsigned long e_offset; int rc; @@ -79,6 +82,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, return -ENOEXEC; } buffer = phys_to_user ( dest ); + end = ( dest + phdr->p_memsz ); DBGC ( image, "ELF %p loading segment [%x,%x) to [%x,%x,%x)\n", image, phdr->p_offset, ( phdr->p_offset + phdr->p_filesz ), @@ -93,6 +97,10 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, return rc; } + /* Update maximum used address, if applicable */ + if ( end > *max ) + *max = end; + /* Copy image to segment */ memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz ); @@ -119,9 +127,10 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, * * @v image ELF file * @ret entry Entry point + * @ret max Maximum used address * @ret rc Return status code */ -int elf_load ( struct image *image, physaddr_t *entry ) { +int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ) { static const uint8_t e_ident[] = { [EI_MAG0] = ELFMAG0, [EI_MAG1] = ELFMAG1, @@ -143,6 +152,9 @@ int elf_load ( struct image *image, physaddr_t *entry ) { return -ENOEXEC; } + /* Initialise maximum used address */ + *max = 0; + /* Invalidate entry point */ *entry = 0; @@ -156,7 +168,7 @@ int elf_load ( struct image *image, physaddr_t *entry ) { } copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) ); if ( ( rc = elf_load_segment ( image, &phdr, &ehdr, - entry ) ) != 0 ) { + entry, max ) ) != 0 ) { return rc; } } diff --git a/src/include/ipxe/elf.h b/src/include/ipxe/elf.h index e5fed2f8..ec675c04 100644 --- a/src/include/ipxe/elf.h +++ b/src/include/ipxe/elf.h @@ -12,6 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -extern int elf_load ( struct image *image, physaddr_t *entry ); +extern int elf_load ( struct image *image, physaddr_t *entry, physaddr_t *max ); #endif /* _IPXE_ELF_H */ From 31e60de6760d5094f1ac662b877bb85b83aa1a53 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 19 Apr 2012 16:09:31 +0100 Subject: [PATCH 176/221] [settings] Add fetch_setting_copy() Signed-off-by: Michael Brown --- src/core/settings.c | 40 +++++++++++++++++++++++++++++++++++++ src/include/ipxe/settings.h | 2 ++ 2 files changed, 42 insertions(+) diff --git a/src/core/settings.c b/src/core/settings.c index e80355c7..c84e1bc2 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -676,6 +676,46 @@ int fetch_setting_len ( struct settings *settings, struct setting *setting ) { return fetch_setting ( settings, setting, NULL, 0 ); } +/** + * Fetch copy of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v data Buffer to allocate and fill with setting data + * @ret len Length of setting, or negative error + * + * The caller is responsible for eventually freeing the allocated + * buffer. + * + * To allow the caller to distinguish between a non-existent setting + * and an error in allocating memory for the copy, this function will + * return success (and a NULL buffer pointer) for a non-existent + * setting. + */ +int fetch_setting_copy ( struct settings *settings, struct setting *setting, + void **data ) { + int len; + int check_len = 0; + + /* Avoid returning uninitialised data on error */ + *data = NULL; + + /* Fetch setting length, and return success if non-existent */ + len = fetch_setting_len ( settings, setting ); + if ( len < 0 ) + return 0; + + /* Allocate buffer */ + *data = malloc ( len ); + if ( ! *data ) + return -ENOMEM; + + /* Fetch setting */ + check_len = fetch_setting ( settings, setting, *data, len ); + assert ( check_len == len ); + return len; +} + /** * Fetch value of string setting * diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 1f4af17f..34c0ed47 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -240,6 +240,8 @@ extern struct settings * fetch_setting_origin ( struct settings *settings, struct setting *setting ); extern int fetch_setting_len ( struct settings *settings, struct setting *setting ); +extern int fetch_setting_copy ( struct settings *settings, + struct setting *setting, void **data ); extern int fetch_string_setting ( struct settings *settings, struct setting *setting, char *data, size_t len ); From 02f1f3066d434cf67b886a1cc482f74dee87479e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 19 Apr 2012 14:52:07 +0100 Subject: [PATCH 177/221] [crypto] Allow trusted root certificate to be changed without a rebuild Changing the trusted root certificate currently requires a rebuild of the iPXE binary, which may be inconvenient or impractical. Allow the list of trusted root certificate fingerprints to be overridden using the "trust" setting, but only at the point of iPXE initialisation. This prevents untrusted sources of settings (e.g. DHCP) from subverting the chain of trust, while allowing trustworthy sources to change the trusted root certificate without requiring a rebuild. The basic idea is that if you are able to manipulate a trustworthy source of settings (e.g. VMware GuestInfo or non-volatile stored options), then you would be able to replace the iPXE binary anyway, and so no security is lost by allowing such sources to override the list of trusted root certificates. Signed-off-by: Michael Brown --- src/crypto/rootcert.c | 65 ++++++++++++++++++++++++++++++++++++- src/include/ipxe/dhcp.h | 3 ++ src/include/ipxe/settings.h | 3 +- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c index 99ee9c87..6a9e594c 100644 --- a/src/crypto/rootcert.c +++ b/src/crypto/rootcert.c @@ -18,9 +18,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include +#include +#include +#include #include /** @file @@ -29,6 +33,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); * */ +/** Length of a root certificate fingerprint */ +#define FINGERPRINT_LEN SHA256_DIGEST_SIZE + /* Use iPXE root CA if no trusted certificates are explicitly specified */ #ifndef TRUSTED #define TRUSTED \ @@ -42,9 +49,65 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Root certificate fingerprints */ static const uint8_t fingerprints[] = { TRUSTED }; +/** Root certificate fingerprint setting */ +struct setting trust_setting __setting ( SETTING_CRYPTO ) = { + .name = "trust", + .description = "Trusted root certificate fingerprint", + .tag = DHCP_EB_TRUST, + .type = &setting_type_hex, +}; + /** Root certificates */ struct x509_root root_certificates = { .digest = &sha256_algorithm, - .count = ( sizeof ( fingerprints ) / SHA256_DIGEST_SIZE ), + .count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ), .fingerprints = fingerprints, }; + +/** + * Initialise root certificate + * + * We allow the list of trusted root certificate fingerprints to be + * overridden using the "trust" setting, but only at the point of iPXE + * initialisation. This prevents untrusted sources of settings + * (e.g. DHCP) from subverting the chain of trust, while allowing + * trustworthy sources (e.g. VMware GuestInfo or non-volatile stored + * options) to change the trusted root certificate without requiring a + * rebuild. + */ +static void rootcert_init ( void ) { + void *external; + int len; + int rc; + + /* Fetch copy of "trust" setting, if it exists. This memory + * will never be freed. + */ + len = fetch_setting_copy ( NULL, &trust_setting, &external ); + if ( len < 0 ) { + rc = len; + DBGC ( &root_certificates, "ROOTCERT cannot fetch trusted " + "root certificate fingerprints: %s\n", strerror ( rc ) ); + /* No way to prevent startup; fail safe by trusting no + * certificates. + */ + root_certificates.count = 0; + return; + } + + /* Use certificates from "trust" setting, if present */ + if ( external ) { + root_certificates.fingerprints = external; + root_certificates.count = ( len / FINGERPRINT_LEN ); + } + + DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n", + root_certificates.count, ( external ? "external" : "built-in" )); + DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints, + ( root_certificates.count * FINGERPRINT_LEN ) ); +} + +/** Root certificate initialiser */ +struct init_fn rootcert_init_fn __init_fn ( INIT_LATE ) = { + .initialise = rootcert_init, +}; diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index f5b3136a..cc594ab1 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -355,6 +355,9 @@ struct dhcp_client_uuid { /** Encrypted syslog server */ #define DHCP_EB_SYSLOGS_SERVER DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x55 ) +/** Trusted root certficate fingerprints */ +#define DHCP_EB_TRUST DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5a ) + /** Skip PXE DHCP protocol extensions such as ProxyDHCP * * If set to a non-zero value, iPXE will not wait for ProxyDHCP offers diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 34c0ed47..d0a142fa 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -83,7 +83,8 @@ struct setting { #define SETTING_HOST_EXTRA 10 /**< Host identity additional settings */ #define SETTING_AUTH 11 /**< Authentication settings */ #define SETTING_AUTH_EXTRA 12 /**< Authentication additional settings */ -#define SETTING_MISC 13 /**< Miscellaneous settings */ +#define SETTING_CRYPTO 13 /**< Cryptography settings */ +#define SETTING_MISC 14 /**< Miscellaneous settings */ /** @} */ From d3d87a2d92fef33d5ac93aaca38170b9666c7378 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 19 Apr 2012 22:52:09 +0100 Subject: [PATCH 178/221] [efi] Update link state in SNP device mode data There is no explicit SNP API call to determine link state; the SNP interface user may check the MediaPresent field within the mode data at any time. Update the MediaPresent field whenever the link state changes. Reported-by: Michael R Turner Signed-off-by: Michael Brown --- src/interface/efi/efi_snp.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index 4c499826..4df221c5 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -1282,8 +1282,21 @@ static int efi_snp_probe ( struct net_device *netdev ) { * * @v netdev Network device */ -static void efi_snp_notify ( struct net_device *netdev __unused ) { - /* Nothing to do */ +static void efi_snp_notify ( struct net_device *netdev ) { + struct efi_snp_device *snpdev; + + /* Locate SNP device */ + snpdev = efi_snp_demux ( netdev ); + if ( ! snpdev ) { + DBG ( "SNP skipping non-SNP device %s\n", netdev->name ); + return; + } + + /* Update link state */ + snpdev->mode.MediaPresent = + ( netdev_link_ok ( netdev ) ? TRUE : FALSE ); + DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev, + ( snpdev->mode.MediaPresent ? "up" : "down" ) ); } /** From 8b0305e285b545c0db337d75fc9611ef2e930206 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 21 Apr 2012 08:02:15 +0100 Subject: [PATCH 179/221] [efi] Fix compiler warning in elf2efi.c Signed-off-by: Michael Brown --- src/util/elf2efi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/util/elf2efi.c b/src/util/elf2efi.c index c8df22e1..fc6bef37 100644 --- a/src/util/elf2efi.c +++ b/src/util/elf2efi.c @@ -405,6 +405,10 @@ static struct pe_section * process_section ( bfd *bfd, EFI_IMAGE_SCN_MEM_WRITE ); applicable_start = &data_mid; applicable_end = &data_end; + } else { + eprintf ( "Unrecognised characteristics %#lx for section %s\n", + flags, section->name ); + exit ( 1 ); } /* Copy in section contents */ From 38d2ad8676cc83e041318b9ec60d0652edcf3c44 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 20 Apr 2012 23:41:00 +0100 Subject: [PATCH 180/221] [skel] Add skeleton network driver Signed-off-by: Michael Brown --- src/drivers/net/skeleton.c | 308 +++++++++++++++++++++++++++++++++++++ src/drivers/net/skeleton.h | 23 +++ src/include/ipxe/errfile.h | 1 + 3 files changed, 332 insertions(+) create mode 100644 src/drivers/net/skeleton.c create mode 100644 src/drivers/net/skeleton.h diff --git a/src/drivers/net/skeleton.c b/src/drivers/net/skeleton.c new file mode 100644 index 00000000..3e1e2d54 --- /dev/null +++ b/src/drivers/net/skeleton.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "skeleton.h" + +/** @file + * + * Skeleton network driver + * + */ + +/****************************************************************************** + * + * MII interface + * + ****************************************************************************** + */ + +/** + * Read from MII register + * + * @v mii MII interface + * @v reg Register address + * @ret value Data read, or negative error + */ +static int skeleton_mii_read ( struct mii_interface *mii, unsigned int reg ) { + struct skeleton_nic *skel = + container_of ( mii, struct skeleton_nic, mii ); + + DBGC ( skel, "SKELETON %p does not yet support MII read\n", skel ); + ( void ) reg; + return -ENOTSUP; +} + +/** + * Write to MII register + * + * @v mii MII interface + * @v reg Register address + * @v data Data to write + * @ret rc Return status code + */ +static int skeleton_mii_write ( struct mii_interface *mii, unsigned int reg, + unsigned int data) { + struct skeleton_nic *skel = + container_of ( mii, struct skeleton_nic, mii ); + + DBGC ( skel, "SKELETON %p does not yet support MII write\n", skel ); + ( void ) reg; + ( void ) data; + return -ENOTSUP; +} + +/** Skeleton MII operations */ +static struct mii_operations skeleton_mii_operations = { + .read = skeleton_mii_read, + .write = skeleton_mii_write, +}; + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset hardware + * + * @v skel Skeleton device + * @ret rc Return status code + */ +static int skeleton_reset ( struct skeleton_nic *skel ) { + + DBGC ( skel, "SKELETON %p does not yet support reset\n", skel ); + return -ENOTSUP; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void skeleton_check_link ( struct net_device *netdev ) { + struct skeleton_nic *skel = netdev->priv; + + DBGC ( skel, "SKELETON %p does not yet support link state\n", skel ); + netdev_link_err ( netdev, -ENOTSUP ); +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int skeleton_open ( struct net_device *netdev ) { + struct skeleton_nic *skel = netdev->priv; + + DBGC ( skel, "SKELETON %p does not yet support open\n", skel ); + return -ENOTSUP; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void skeleton_close ( struct net_device *netdev ) { + struct skeleton_nic *skel = netdev->priv; + + DBGC ( skel, "SKELETON %p does not yet support close\n", skel ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int skeleton_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct skeleton_nic *skel = netdev->priv; + + DBGC ( skel, "SKELETON %p does not yet support transmit\n", skel ); + ( void ) iobuf; + return -ENOTSUP; +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void skeleton_poll ( struct net_device *netdev ) { + struct skeleton_nic *skel = netdev->priv; + + /* Not yet implemented */ + ( void ) skel; +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void skeleton_irq ( struct net_device *netdev, int enable ) { + struct skeleton_nic *skel = netdev->priv; + + DBGC ( skel, "SKELETON %p does not yet support interrupts\n", skel ); + ( void ) enable; +} + +/** Skeleton network device operations */ +static struct net_device_operations skeleton_operations = { + .open = skeleton_open, + .close = skeleton_close, + .transmit = skeleton_transmit, + .poll = skeleton_poll, + .irq = skeleton_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int skeleton_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct skeleton_nic *skel; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *skel ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &skeleton_operations ); + skel = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( skel, 0, sizeof ( *skel ) ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + skel->regs = ioremap ( pci->membase, SKELETON_BAR_SIZE ); + + /* Reset the NIC */ + if ( ( rc = skeleton_reset ( skel ) ) != 0 ) + goto err_reset; + + /* Initialise and reset MII interface */ + mii_init ( &skel->mii, &skeleton_mii_operations ); + if ( ( rc = mii_reset ( &skel->mii ) ) != 0 ) { + DBGC ( skel, "SKELETON %p could not reset MII: %s\n", + skel, strerror ( rc ) ); + goto err_mii_reset; + } + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + skeleton_check_link ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register_netdev: + err_mii_reset: + skeleton_reset ( skel ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void skeleton_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct skeleton_nic *skel = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset card */ + skeleton_reset ( skel ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Skeleton PCI device IDs */ +static struct pci_device_id skeleton_nics[] = { + PCI_ROM ( 0x5ce1, 0x5ce1, "skel", "Skeleton", 0 ), +}; + +/** Skeleton PCI driver */ +struct pci_driver skeleton_driver __pci_driver = { + .ids = skeleton_nics, + .id_count = ( sizeof ( skeleton_nics ) / sizeof ( skeleton_nics[0] ) ), + .probe = skeleton_probe, + .remove = skeleton_remove, +}; diff --git a/src/drivers/net/skeleton.h b/src/drivers/net/skeleton.h new file mode 100644 index 00000000..3de2afa5 --- /dev/null +++ b/src/drivers/net/skeleton.h @@ -0,0 +1,23 @@ +#ifndef _SKELETON_H +#define _SKELETON_H + +/** @file + * + * Skeleton network driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** Skeleton BAR size */ +#define SKELETON_BAR_SIZE 256 + +/** A skeleton network card */ +struct skeleton_nic { + /** Registers */ + void *regs; + /** MII interface */ + struct mii_interface mii; +}; + +#endif /* _SKELETON_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e2d85750..ff87e9b9 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -143,6 +143,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_vmxnet3 ( ERRFILE_DRIVER | 0x00610000 ) #define ERRFILE_mii ( ERRFILE_DRIVER | 0x00620000 ) #define ERRFILE_realtek ( ERRFILE_DRIVER | 0x00630000 ) +#define ERRFILE_skeleton ( ERRFILE_DRIVER | 0x00640000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) From 44d5ef9d7d525edf4c9d8c7a5b8b09f6eb4143b9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 21 Apr 2012 16:25:55 +0100 Subject: [PATCH 181/221] [netdevice] Allow network device to update link state before checking If the network interface has only just been opened (e.g. by the "dhcp" command) then we should allow at least one opportunity for the card to update the link state before testing it, to avoid false positives. Signed-off-by: Michael Brown --- src/usr/ifmgmt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/usr/ifmgmt.c b/src/usr/ifmgmt.c index 04985159..8ee311c0 100644 --- a/src/usr/ifmgmt.c +++ b/src/usr/ifmgmt.c @@ -113,6 +113,9 @@ int iflinkwait ( struct net_device *netdev, unsigned int max_wait_ms ) { int key; int rc; + /* Allow link state to be updated */ + netdev_poll ( netdev ); + if ( netdev_link_ok ( netdev ) ) return 0; From 5b18489685e8424c42b93e3c2707c2c9ffa2fc31 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Apr 2012 10:47:11 +0100 Subject: [PATCH 182/221] [realtek] Update link state when device is opened The link state is currently set at probe time, and updated only when the device is polled. This results in the user seeing a misleading stale "Link: down" message, if autonegotiation did not complete within the short timespan of the probe routine. Fix by updating the link state when the device is opened, so that the message that ends up being displayed to the user reflects the real link state at device open time. Signed-off-by: Michael Brown --- src/drivers/net/realtek.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index eb16cb71..5f111a68 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -426,6 +426,9 @@ static int realtek_open ( struct net_device *netdev ) { /* Enable transmitter and receiver */ writeb ( ( RTL_CR_TE | RTL_CR_RE ), rtl->regs + RTL_CR ); + /* Update link state */ + realtek_check_link ( netdev ); + return 0; realtek_destroy_ring ( rtl, &rtl->rx ); From de2616165be6d57143981265669fd730669fb13f Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Apr 2012 20:17:24 +0100 Subject: [PATCH 183/221] [xfer] Avoid using stack-allocated memory in xfer_printf() xfer_printf() occasionally has to deal with strings that are potentially long, such as HTTP URIs with multiple query parameters. Allocating these on the stack can lead to stack overruns and memory corruption. Fix by using vasprintf() instead of a stack allocation. Signed-off-by: Michael Brown --- src/core/xfer.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/core/xfer.c b/src/core/xfer.c index 4d7d6b43..037c089a 100644 --- a/src/core/xfer.c +++ b/src/core/xfer.c @@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include #include #include @@ -297,17 +298,28 @@ int xfer_deliver_raw ( struct interface *intf, const void *data, size_t len ) { */ int xfer_vprintf ( struct interface *intf, const char *format, va_list args ) { - size_t len; va_list args_tmp; + char *buf; + int len; + int rc; + /* Create temporary string */ va_copy ( args_tmp, args ); - len = vsnprintf ( NULL, 0, format, args ); - { - char buf[len + 1]; - vsnprintf ( buf, sizeof ( buf ), format, args_tmp ); - va_end ( args_tmp ); - return xfer_deliver_raw ( intf, buf, len ); + len = vasprintf ( &buf, format, args ); + if ( len < 0 ) { + rc = len; + goto err_asprintf; } + va_end ( args_tmp ); + + /* Transmit string */ + if ( ( rc = xfer_deliver_raw ( intf, buf, len ) ) != 0 ) + goto err_deliver; + + err_deliver: + free ( buf ); + err_asprintf: + return rc; } /** From a026a27f0450a66d86df2d88152c61c4e425c493 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Apr 2012 22:42:10 +0100 Subject: [PATCH 184/221] [script] Avoid using stack-allocated memory in process_line() Script lines can be arbitrarily long; allocate on the heap rather than on the stack. Signed-off-by: Michael Brown --- src/image/script.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/image/script.c b/src/image/script.c index 460fbf03..b032d18f 100644 --- a/src/image/script.c +++ b/src/image/script.c @@ -58,6 +58,7 @@ static int process_script ( struct image *image, int ( * terminate ) ( int rc ) ) { off_t eol; size_t len; + char *line; int rc; script_offset = 0; @@ -71,23 +72,23 @@ static int process_script ( struct image *image, eol = image->len; len = ( eol - script_offset ); - /* Copy line, terminate with NUL, and execute command */ - { - char cmdbuf[ len + 1 ]; + /* Allocate buffer for line */ + line = zalloc ( len + 1 /* NUL */ ); + if ( ! line ) + return -ENOMEM; - copy_from_user ( cmdbuf, image->data, - script_offset, len ); - cmdbuf[len] = '\0'; - DBG ( "$ %s\n", cmdbuf ); + /* Copy line */ + copy_from_user ( line, image->data, script_offset, len ); + DBG ( "$ %s\n", line ); - /* Move to next line */ - script_offset += ( len + 1 ); + /* Move to next line */ + script_offset += ( len + 1 ); - /* Process line */ - rc = process_line ( cmdbuf ); - if ( terminate ( rc ) ) - return rc; - } + /* Process and free line */ + rc = process_line ( line ); + free ( line ); + if ( terminate ( rc ) ) + return rc; } while ( script_offset < image->len ); From 45e03279872ad697ac3bf048e5c87c851d70c6f9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Apr 2012 23:26:29 +0100 Subject: [PATCH 185/221] [http] Avoid using stack-allocated memory in http_step() http_step() allocates a potentially large block of storage (since the URI can be arbitrarily long), and can be invoked as part of an already deep call stack via xfer_window_changed(). Signed-off-by: Michael Brown --- src/net/tcp/httpcore.c | 46 +++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index 8f5c7bc9..f227e126 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -643,14 +643,16 @@ static void http_step ( struct http_request *http ) { size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ + strlen ( password ) ) : 0 ); size_t user_pw_base64_len = base64_encoded_len ( user_pw_len ); - uint8_t user_pw[ user_pw_len + 1 /* NUL */ ]; - char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ]; - int rc; int request_len = unparse_uri ( NULL, 0, http->uri, URI_PATH_BIT | URI_QUERY_BIT ); - char request[ request_len + 1 /* NUL */ ]; - char range[48]; /* Enough for two 64-bit integers in decimal */ + struct { + uint8_t user_pw[ user_pw_len + 1 /* NUL */ ]; + char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ]; + char request[ request_len + 1 /* NUL */ ]; + char range[48]; /* Enough for two 64-bit integers in decimal */ + } *dynamic; int partial; + int rc; /* Do nothing if we have already transmitted the request */ if ( ! ( http->flags & HTTP_TX_PENDING ) ) @@ -660,18 +662,27 @@ static void http_step ( struct http_request *http ) { if ( ! xfer_window ( &http->socket ) ) return; + /* Allocate dynamic storage */ + dynamic = malloc ( sizeof ( *dynamic ) ); + if ( ! malloc ) { + rc = -ENOMEM; + goto err_alloc; + } + /* Construct path?query request */ - unparse_uri ( request, sizeof ( request ), http->uri, + unparse_uri ( dynamic->request, sizeof ( dynamic->request ), http->uri, URI_PATH_BIT | URI_QUERY_BIT ); /* Construct authorisation, if applicable */ if ( user ) { /* Make "user:password" string from decoded fields */ - snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ), - "%s:%s", user, password ); + snprintf ( ( ( char * ) dynamic->user_pw ), + sizeof ( dynamic->user_pw ), "%s:%s", + user, password ); /* Base64-encode the "user:password" string */ - base64_encode ( user_pw, user_pw_len, user_pw_base64 ); + base64_encode ( dynamic->user_pw, user_pw_len, + dynamic->user_pw_base64 ); } /* Force a HEAD request if we have nowhere to send any received data */ @@ -682,7 +693,8 @@ static void http_step ( struct http_request *http ) { /* Determine type of request */ partial = ( http->partial_len != 0 ); - snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start, + snprintf ( dynamic->range, sizeof ( dynamic->range ), + "%zd-%zd", http->partial_start, ( http->partial_start + http->partial_len - 1 ) ); /* Mark request as transmitted */ @@ -698,7 +710,7 @@ static void http_step ( struct http_request *http ) { ( ( http->flags & HTTP_HEAD_ONLY ) ? "HEAD" : "GET" ), ( http->uri->path ? "" : "/" ), - request, host, + dynamic->request, host, ( http->uri->port ? ":" : "" ), ( http->uri->port ? @@ -706,14 +718,20 @@ static void http_step ( struct http_request *http ) { ( ( http->flags & HTTP_KEEPALIVE ) ? "Connection: Keep-Alive\r\n" : "" ), ( partial ? "Range: bytes=" : "" ), - ( partial ? range : "" ), + ( partial ? dynamic->range : "" ), ( partial ? "\r\n" : "" ), ( user ? "Authorization: Basic " : "" ), - ( user ? user_pw_base64 : "" ), + ( user ? dynamic->user_pw_base64 : "" ), ( user ? "\r\n" : "" ) ) ) != 0 ) { - http_close ( http, rc ); + goto err_xfer; } + + err_xfer: + free ( dynamic ); + err_alloc: + if ( rc != 0 ) + http_close ( http, rc ); } /** From 945e4281375f86da5e59f4c9447edae7af7850c1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 23 Apr 2012 23:29:18 +0100 Subject: [PATCH 186/221] [intel] Replace driver for Intel Gigabit NICs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested-by: Robin Smidsrød Tested-by: Thomas Miletich Signed-off-by: Michael Brown --- src/drivers/net/e1000/e1000.c | 35 - src/drivers/net/e1000/e1000.h | 326 -- src/drivers/net/e1000/e1000_82540.c | 754 ---- src/drivers/net/e1000/e1000_82541.c | 1314 ------- src/drivers/net/e1000/e1000_82541.h | 86 - src/drivers/net/e1000/e1000_82542.c | 571 --- src/drivers/net/e1000/e1000_82543.c | 1635 --------- src/drivers/net/e1000/e1000_82543.h | 45 - src/drivers/net/e1000/e1000_api.c | 1108 ------ src/drivers/net/e1000/e1000_api.h | 127 - src/drivers/net/e1000/e1000_defines.h | 1416 -------- src/drivers/net/e1000/e1000_hw.h | 728 ---- src/drivers/net/e1000/e1000_mac.c | 2196 ------------ src/drivers/net/e1000/e1000_mac.h | 94 - src/drivers/net/e1000/e1000_main.c | 909 ----- src/drivers/net/e1000/e1000_manage.c | 389 --- src/drivers/net/e1000/e1000_manage.h | 84 - src/drivers/net/e1000/e1000_nvm.c | 923 ----- src/drivers/net/e1000/e1000_nvm.h | 63 - src/drivers/net/e1000/e1000_osdep.h | 118 - src/drivers/net/e1000/e1000_phy.c | 2308 ------------ src/drivers/net/e1000/e1000_phy.h | 171 - src/drivers/net/e1000/e1000_regs.h | 329 -- src/drivers/net/e1000e/e1000e.c | 34 - src/drivers/net/e1000e/e1000e.h | 534 --- src/drivers/net/e1000e/e1000e_80003es2lan.c | 1533 -------- src/drivers/net/e1000e/e1000e_80003es2lan.h | 100 - src/drivers/net/e1000e/e1000e_82571.c | 1818 ---------- src/drivers/net/e1000e/e1000e_82571.h | 55 - src/drivers/net/e1000e/e1000e_defines.h | 1471 -------- src/drivers/net/e1000e/e1000e_hw.h | 723 ---- src/drivers/net/e1000e/e1000e_ich8lan.c | 3465 ------------------- src/drivers/net/e1000e/e1000e_ich8lan.h | 199 -- src/drivers/net/e1000e/e1000e_mac.c | 1883 ---------- src/drivers/net/e1000e/e1000e_mac.h | 79 - src/drivers/net/e1000e/e1000e_main.c | 1282 ------- src/drivers/net/e1000e/e1000e_manage.c | 372 -- src/drivers/net/e1000e/e1000e_manage.h | 86 - src/drivers/net/e1000e/e1000e_nvm.c | 596 ---- src/drivers/net/e1000e/e1000e_nvm.h | 53 - src/drivers/net/e1000e/e1000e_phy.c | 3326 ------------------ src/drivers/net/e1000e/e1000e_phy.h | 261 -- src/drivers/net/e1000e/e1000e_regs.h | 340 -- src/drivers/net/igb/igb.c | 32 - src/drivers/net/igb/igb.h | 324 -- src/drivers/net/igb/igb_82575.c | 1617 --------- src/drivers/net/igb/igb_82575.h | 442 --- src/drivers/net/igb/igb_api.c | 1108 ------ src/drivers/net/igb/igb_api.h | 166 - src/drivers/net/igb/igb_defines.h | 1515 -------- src/drivers/net/igb/igb_hw.h | 697 ---- src/drivers/net/igb/igb_mac.c | 1991 ----------- src/drivers/net/igb/igb_mac.h | 82 - src/drivers/net/igb/igb_main.c | 1010 ------ src/drivers/net/igb/igb_manage.c | 388 --- src/drivers/net/igb/igb_manage.h | 83 - src/drivers/net/igb/igb_nvm.c | 627 ---- src/drivers/net/igb/igb_nvm.h | 52 - src/drivers/net/igb/igb_osdep.h | 124 - src/drivers/net/igb/igb_phy.c | 2470 ------------- src/drivers/net/igb/igb_phy.h | 171 - src/drivers/net/igb/igb_regs.h | 486 --- src/drivers/net/intel.c | 946 +++++ src/drivers/net/intel.h | 252 ++ src/include/ipxe/errfile.h | 1 + 65 files changed, 1199 insertions(+), 47324 deletions(-) delete mode 100644 src/drivers/net/e1000/e1000.c delete mode 100644 src/drivers/net/e1000/e1000.h delete mode 100644 src/drivers/net/e1000/e1000_82540.c delete mode 100644 src/drivers/net/e1000/e1000_82541.c delete mode 100644 src/drivers/net/e1000/e1000_82541.h delete mode 100644 src/drivers/net/e1000/e1000_82542.c delete mode 100644 src/drivers/net/e1000/e1000_82543.c delete mode 100644 src/drivers/net/e1000/e1000_82543.h delete mode 100644 src/drivers/net/e1000/e1000_api.c delete mode 100644 src/drivers/net/e1000/e1000_api.h delete mode 100644 src/drivers/net/e1000/e1000_defines.h delete mode 100644 src/drivers/net/e1000/e1000_hw.h delete mode 100644 src/drivers/net/e1000/e1000_mac.c delete mode 100644 src/drivers/net/e1000/e1000_mac.h delete mode 100644 src/drivers/net/e1000/e1000_main.c delete mode 100644 src/drivers/net/e1000/e1000_manage.c delete mode 100644 src/drivers/net/e1000/e1000_manage.h delete mode 100644 src/drivers/net/e1000/e1000_nvm.c delete mode 100644 src/drivers/net/e1000/e1000_nvm.h delete mode 100644 src/drivers/net/e1000/e1000_osdep.h delete mode 100644 src/drivers/net/e1000/e1000_phy.c delete mode 100644 src/drivers/net/e1000/e1000_phy.h delete mode 100644 src/drivers/net/e1000/e1000_regs.h delete mode 100644 src/drivers/net/e1000e/e1000e.c delete mode 100644 src/drivers/net/e1000e/e1000e.h delete mode 100644 src/drivers/net/e1000e/e1000e_80003es2lan.c delete mode 100644 src/drivers/net/e1000e/e1000e_80003es2lan.h delete mode 100644 src/drivers/net/e1000e/e1000e_82571.c delete mode 100644 src/drivers/net/e1000e/e1000e_82571.h delete mode 100644 src/drivers/net/e1000e/e1000e_defines.h delete mode 100644 src/drivers/net/e1000e/e1000e_hw.h delete mode 100644 src/drivers/net/e1000e/e1000e_ich8lan.c delete mode 100644 src/drivers/net/e1000e/e1000e_ich8lan.h delete mode 100644 src/drivers/net/e1000e/e1000e_mac.c delete mode 100644 src/drivers/net/e1000e/e1000e_mac.h delete mode 100644 src/drivers/net/e1000e/e1000e_main.c delete mode 100644 src/drivers/net/e1000e/e1000e_manage.c delete mode 100644 src/drivers/net/e1000e/e1000e_manage.h delete mode 100644 src/drivers/net/e1000e/e1000e_nvm.c delete mode 100644 src/drivers/net/e1000e/e1000e_nvm.h delete mode 100644 src/drivers/net/e1000e/e1000e_phy.c delete mode 100644 src/drivers/net/e1000e/e1000e_phy.h delete mode 100644 src/drivers/net/e1000e/e1000e_regs.h delete mode 100644 src/drivers/net/igb/igb.c delete mode 100644 src/drivers/net/igb/igb.h delete mode 100644 src/drivers/net/igb/igb_82575.c delete mode 100644 src/drivers/net/igb/igb_82575.h delete mode 100644 src/drivers/net/igb/igb_api.c delete mode 100644 src/drivers/net/igb/igb_api.h delete mode 100644 src/drivers/net/igb/igb_defines.h delete mode 100644 src/drivers/net/igb/igb_hw.h delete mode 100644 src/drivers/net/igb/igb_mac.c delete mode 100644 src/drivers/net/igb/igb_mac.h delete mode 100644 src/drivers/net/igb/igb_main.c delete mode 100644 src/drivers/net/igb/igb_manage.c delete mode 100644 src/drivers/net/igb/igb_manage.h delete mode 100644 src/drivers/net/igb/igb_nvm.c delete mode 100644 src/drivers/net/igb/igb_nvm.h delete mode 100644 src/drivers/net/igb/igb_osdep.h delete mode 100644 src/drivers/net/igb/igb_phy.c delete mode 100644 src/drivers/net/igb/igb_phy.h delete mode 100644 src/drivers/net/igb/igb_regs.h create mode 100644 src/drivers/net/intel.c create mode 100644 src/drivers/net/intel.h diff --git a/src/drivers/net/e1000/e1000.c b/src/drivers/net/e1000/e1000.c deleted file mode 100644 index a32a4d7c..00000000 --- a/src/drivers/net/e1000/e1000.c +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -REQUIRE_OBJECT(e1000_main); -REQUIRE_OBJECT(e1000_82540); -REQUIRE_OBJECT(e1000_82541); -REQUIRE_OBJECT(e1000_82542); -REQUIRE_OBJECT(e1000_82543); diff --git a/src/drivers/net/e1000/e1000.h b/src/drivers/net/e1000/e1000.h deleted file mode 100644 index 31dbb859..00000000 --- a/src/drivers/net/e1000/e1000.h +++ /dev/null @@ -1,326 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -/* Linux PRO/1000 Ethernet Driver main header file */ - -#ifndef _E1000_H_ -#define _E1000_H_ - -#include "e1000_api.h" - -#define BAR_0 0 -#define BAR_1 1 -#define BAR_5 5 - -struct e1000_adapter; - -/* TX/RX descriptor defines */ -#define E1000_DEFAULT_TXD 256 -#define E1000_MAX_TXD 256 -#define E1000_MIN_TXD 80 -#define E1000_MAX_82544_TXD 4096 - -#define E1000_DEFAULT_TXD_PWR 12 -#define E1000_MAX_TXD_PWR 12 -#define E1000_MIN_TXD_PWR 7 - -#define E1000_DEFAULT_RXD 256 -#define E1000_MAX_RXD 256 - -#define E1000_MIN_RXD 80 -#define E1000_MAX_82544_RXD 4096 - -#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ -#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ - - -/* this is the size past which hardware will drop packets when setting LPE=0 */ -#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 - -/* Supported Rx Buffer Sizes */ -#define E1000_RXBUFFER_128 128 -#define E1000_RXBUFFER_256 256 -#define E1000_RXBUFFER_512 512 -#define E1000_RXBUFFER_1024 1024 -#define E1000_RXBUFFER_2048 2048 -#define E1000_RXBUFFER_4096 4096 -#define E1000_RXBUFFER_8192 8192 -#define E1000_RXBUFFER_16384 16384 - -/* SmartSpeed delimiters */ -#define E1000_SMARTSPEED_DOWNSHIFT 3 -#define E1000_SMARTSPEED_MAX 15 - -/* Packet Buffer allocations */ -#define E1000_PBA_BYTES_SHIFT 0xA -#define E1000_TX_HEAD_ADDR_SHIFT 7 -#define E1000_PBA_TX_MASK 0xFFFF0000 - -/* Early Receive defines */ -#define E1000_ERT_2048 0x100 - -#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ - -/* How many Tx Descriptors do we need to call netif_wake_queue ? */ -#define E1000_TX_QUEUE_WAKE 16 -/* How many Rx Buffers do we bundle into one write to the hardware ? */ -#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ - -#define AUTO_ALL_MODES 0 -#define E1000_EEPROM_82544_APM 0x0004 -#define E1000_EEPROM_APME 0x0400 - -/* wrapper around a pointer to a socket buffer, - * so a DMA handle can be stored along with the buffer */ -struct e1000_buffer { - struct sk_buff *skb; - dma_addr_t dma; - unsigned long time_stamp; - u16 length; - u16 next_to_watch; -}; - -struct e1000_rx_buffer { - struct sk_buff *skb; - dma_addr_t dma; - struct page *page; -}; - - - -struct e1000_tx_ring { - /* pointer to the descriptor ring memory */ - void *desc; - /* physical address of the descriptor ring */ - dma_addr_t dma; - /* length of descriptor ring in bytes */ - unsigned int size; - /* number of descriptors in the ring */ - unsigned int count; - /* next descriptor to associate a buffer with */ - unsigned int next_to_use; - /* next descriptor to check for DD status bit */ - unsigned int next_to_clean; - /* array of buffer information structs */ - struct e1000_buffer *buffer_info; - - spinlock_t tx_lock; - u16 tdh; - u16 tdt; - - /* TXDdescriptor index increment to be used when advancing - * to the next descriptor. This is normally one, but on some - * architectures, but on some architectures there are cache - * coherency issues that require only the first descriptor in - * cache line can be used. - */ - unsigned int step; - - bool last_tx_tso; -}; - -struct e1000_rx_ring { - struct e1000_adapter *adapter; /* back link */ - /* pointer to the descriptor ring memory */ - void *desc; - /* physical address of the descriptor ring */ - dma_addr_t dma; - /* length of descriptor ring in bytes */ - unsigned int size; - /* number of descriptors in the ring */ - unsigned int count; - /* next descriptor to associate a buffer with */ - unsigned int next_to_use; - /* next descriptor to check for DD status bit */ - unsigned int next_to_clean; - /* array of buffer information structs */ - struct e1000_rx_buffer *buffer_info; - struct sk_buff *rx_skb_top; - - /* cpu for rx queue */ - int cpu; - - u16 rdh; - u16 rdt; -}; - - -#define E1000_TX_DESC_INC(R,index) \ - {index += (R)->step; if (index == (R)->count) index = 0; } - -#define E1000_TX_DESC_DEC(R,index) \ - { if (index == 0) index = (R)->count - (R)->step; \ - else index -= (R)->step; } - -#define E1000_DESC_UNUSED(R) \ - ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ - (R)->next_to_clean - (R)->next_to_use - 1) - -#define E1000_RX_DESC_EXT(R, i) \ - (&(((union e1000_rx_desc_extended *)((R).desc))[i])) -#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) -#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) -#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) -#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc) - -/* board specific private data structure */ - -struct e1000_adapter { - u32 bd_number; - u32 rx_buffer_len; - u32 wol; - u32 smartspeed; - u32 en_mng_pt; - u16 link_speed; - u16 link_duplex; - spinlock_t stats_lock; - unsigned int total_tx_bytes; - unsigned int total_tx_packets; - unsigned int total_rx_bytes; - unsigned int total_rx_packets; - /* Interrupt Throttle Rate */ - u32 itr; - u32 itr_setting; - u16 tx_itr; - u16 rx_itr; - - bool fc_autoneg; - - /* TX */ - struct e1000_tx_ring *tx_ring; - unsigned int restart_queue; - unsigned long tx_queue_len; - u32 txd_cmd; - u32 tx_int_delay; - u32 tx_abs_int_delay; - u32 gotc; - u64 gotc_old; - u64 tpt_old; - u64 colc_old; - u32 tx_timeout_count; - u32 tx_fifo_head; - u32 tx_head_addr; - u32 tx_fifo_size; - u8 tx_timeout_factor; - bool pcix_82544; - bool detect_tx_hung; - - /* RX */ - bool (*clean_rx) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); - void (*alloc_rx_buf) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int cleaned_count); - struct e1000_rx_ring *rx_ring; - - u64 hw_csum_err; - u64 hw_csum_good; - u32 alloc_rx_buff_failed; - u32 rx_int_delay; - u32 rx_abs_int_delay; - bool rx_csum; - u32 gorc; - u64 gorc_old; - u32 max_frame_size; - u32 min_frame_size; - - - /* OS defined structs */ - struct net_device *netdev; - struct pci_device *pdev; - struct net_device_stats net_stats; - - /* structs defined in e1000_hw.h */ - struct e1000_hw hw; - struct e1000_hw_stats stats; - struct e1000_phy_info phy_info; - struct e1000_phy_stats phy_stats; - - int msg_enable; - /* to not mess up cache alignment, always add to the bottom */ - unsigned long state; - u32 eeprom_wol; - - u32 *config_space; - - /* hardware capability, feature, and workaround flags */ - unsigned int flags; - - /* upper limit parameter for tx desc size */ - u32 tx_desc_pwr; - -#define NUM_TX_DESC 8 -#define NUM_RX_DESC 8 - - struct io_buffer *tx_iobuf[NUM_TX_DESC]; - struct io_buffer *rx_iobuf[NUM_RX_DESC]; - - struct e1000_tx_desc *tx_base; - struct e1000_rx_desc *rx_base; - - uint32_t tx_ring_size; - uint32_t rx_ring_size; - - uint32_t tx_head; - uint32_t tx_tail; - uint32_t tx_fill_ctr; - - uint32_t rx_curr; - - uint32_t ioaddr; - uint32_t irqno; -}; - -#define E1000_FLAG_HAS_SMBUS (1 << 0) -#define E1000_FLAG_HAS_INTR_MODERATION (1 << 4) -#define E1000_FLAG_BAD_TX_CARRIER_STATS_FD (1 << 6) -#define E1000_FLAG_QUAD_PORT_A (1 << 8) -#define E1000_FLAG_SMART_POWER_DOWN (1 << 9) - -extern char e1000_driver_name[]; -extern const char e1000_driver_version[]; - -extern void e1000_power_up_phy(struct e1000_hw *hw); - -extern void e1000_set_ethtool_ops(struct net_device *netdev); -extern void e1000_check_options(struct e1000_adapter *adapter); - -extern int e1000_up(struct e1000_adapter *adapter); -extern void e1000_down(struct e1000_adapter *adapter); -extern void e1000_reinit_locked(struct e1000_adapter *adapter); -extern void e1000_reset(struct e1000_adapter *adapter); -extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx); -extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); -extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); -extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); -extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter); -extern void e1000_update_stats(struct e1000_adapter *adapter); - -#endif /* _E1000_H_ */ diff --git a/src/drivers/net/e1000/e1000_82540.c b/src/drivers/net/e1000/e1000_82540.c deleted file mode 100644 index 41f3f979..00000000 --- a/src/drivers/net/e1000/e1000_82540.c +++ /dev/null @@ -1,754 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * 82540EM Gigabit Ethernet Controller - * 82540EP Gigabit Ethernet Controller - * 82545EM Gigabit Ethernet Controller (Copper) - * 82545EM Gigabit Ethernet Controller (Fiber) - * 82545GM Gigabit Ethernet Controller - * 82546EB Gigabit Ethernet Controller (Copper) - * 82546EB Gigabit Ethernet Controller (Fiber) - * 82546GB Gigabit Ethernet Controller - */ - -#include "e1000_api.h" - -static s32 e1000_init_phy_params_82540(struct e1000_hw *hw); -static s32 e1000_init_nvm_params_82540(struct e1000_hw *hw); -static s32 e1000_init_mac_params_82540(struct e1000_hw *hw); -static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw); -static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw); -static s32 e1000_init_hw_82540(struct e1000_hw *hw); -static s32 e1000_reset_hw_82540(struct e1000_hw *hw); -static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw); -static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw); -static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw); -static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw); -static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw); -static s32 e1000_read_mac_addr_82540(struct e1000_hw *hw); - -/** - * e1000_init_phy_params_82540 - Init PHY func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_phy_params_82540(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - phy->addr = 1; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->reset_delay_us = 10000; - phy->type = e1000_phy_m88; - - /* Function Pointers */ - phy->ops.check_polarity = e1000_check_polarity_m88; - phy->ops.commit = e1000_phy_sw_reset_generic; -#if 0 - phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88; -#endif -#if 0 - phy->ops.get_cable_length = e1000_get_cable_length_m88; -#endif - phy->ops.get_cfg_done = e1000_get_cfg_done_generic; - phy->ops.read_reg = e1000_read_phy_reg_m88; - phy->ops.reset = e1000_phy_hw_reset_generic; - phy->ops.write_reg = e1000_write_phy_reg_m88; - phy->ops.get_info = e1000_get_phy_info_m88; - phy->ops.power_up = e1000_power_up_phy_copper; - phy->ops.power_down = e1000_power_down_phy_copper_82540; - - ret_val = e1000_get_phy_id(hw); - if (ret_val) - goto out; - - /* Verify phy id */ - switch (hw->mac.type) { - case e1000_82540: - case e1000_82545: - case e1000_82545_rev_3: - case e1000_82546: - case e1000_82546_rev_3: - if (phy->id == M88E1011_I_PHY_ID) - break; - /* Fall Through */ - default: - ret_val = -E1000_ERR_PHY; - goto out; - break; - } - -out: - return ret_val; -} - -/** - * e1000_init_nvm_params_82540 - Init NVM func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_nvm_params_82540(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - - DEBUGFUNC("e1000_init_nvm_params_82540"); - - nvm->type = e1000_nvm_eeprom_microwire; - nvm->delay_usec = 50; - nvm->opcode_bits = 3; - switch (nvm->override) { - case e1000_nvm_override_microwire_large: - nvm->address_bits = 8; - nvm->word_size = 256; - break; - case e1000_nvm_override_microwire_small: - nvm->address_bits = 6; - nvm->word_size = 64; - break; - default: - nvm->address_bits = eecd & E1000_EECD_SIZE ? 8 : 6; - nvm->word_size = eecd & E1000_EECD_SIZE ? 256 : 64; - break; - } - - /* Function Pointers */ - nvm->ops.acquire = e1000_acquire_nvm_generic; - nvm->ops.read = e1000_read_nvm_microwire; - nvm->ops.release = e1000_release_nvm_generic; - nvm->ops.update = e1000_update_nvm_checksum_generic; - nvm->ops.valid_led_default = e1000_valid_led_default_generic; - nvm->ops.validate = e1000_validate_nvm_checksum_generic; - nvm->ops.write = e1000_write_nvm_microwire; - - return E1000_SUCCESS; -} - -/** - * e1000_init_mac_params_82540 - Init MAC func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_mac_params_82540(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_init_mac_params_82540"); - - /* Set media type */ - switch (hw->device_id) { - case E1000_DEV_ID_82545EM_FIBER: - case E1000_DEV_ID_82545GM_FIBER: - case E1000_DEV_ID_82546EB_FIBER: - case E1000_DEV_ID_82546GB_FIBER: - hw->phy.media_type = e1000_media_type_fiber; - break; - case E1000_DEV_ID_82545GM_SERDES: - case E1000_DEV_ID_82546GB_SERDES: - hw->phy.media_type = e1000_media_type_internal_serdes; - break; - default: - hw->phy.media_type = e1000_media_type_copper; - break; - } - - /* Set mta register count */ - mac->mta_reg_count = 128; - /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES; - - /* Function pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; - /* function id */ - mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci; - /* reset */ - mac->ops.reset_hw = e1000_reset_hw_82540; - /* hw initialization */ - mac->ops.init_hw = e1000_init_hw_82540; - /* link setup */ - mac->ops.setup_link = e1000_setup_link_generic; - /* physical interface setup */ - mac->ops.setup_physical_interface = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_setup_copper_link_82540 - : e1000_setup_fiber_serdes_link_82540; - /* check for link */ - switch (hw->phy.media_type) { - case e1000_media_type_copper: - mac->ops.check_for_link = e1000_check_for_copper_link_generic; - break; - case e1000_media_type_fiber: - mac->ops.check_for_link = e1000_check_for_fiber_link_generic; - break; - case e1000_media_type_internal_serdes: - mac->ops.check_for_link = e1000_check_for_serdes_link_generic; - break; - default: - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } - /* link info */ - mac->ops.get_link_up_info = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_get_speed_and_duplex_copper_generic - : e1000_get_speed_and_duplex_fiber_serdes_generic; - /* multicast address update */ - mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = e1000_write_vfta_generic; - /* clearing VFTA */ - mac->ops.clear_vfta = e1000_clear_vfta_generic; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_generic; - /* read mac address */ - mac->ops.read_mac_addr = e1000_read_mac_addr_82540; - /* ID LED init */ - mac->ops.id_led_init = e1000_id_led_init_generic; - /* setup LED */ - mac->ops.setup_led = e1000_setup_led_generic; - /* cleanup LED */ - mac->ops.cleanup_led = e1000_cleanup_led_generic; - /* turn on/off LED */ - mac->ops.led_on = e1000_led_on_generic; - mac->ops.led_off = e1000_led_off_generic; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82540; - -out: - return ret_val; -} - -/** - * e1000_init_function_pointers_82540 - Init func ptrs. - * @hw: pointer to the HW structure - * - * Called to initialize all function pointers and parameters. - **/ -void e1000_init_function_pointers_82540(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_init_function_pointers_82540"); - - hw->mac.ops.init_params = e1000_init_mac_params_82540; - hw->nvm.ops.init_params = e1000_init_nvm_params_82540; - hw->phy.ops.init_params = e1000_init_phy_params_82540; -} - -/** - * e1000_reset_hw_82540 - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. - **/ -static s32 e1000_reset_hw_82540(struct e1000_hw *hw) -{ - u32 ctrl, manc; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_reset_hw_82540"); - - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF); - - E1000_WRITE_REG(hw, E1000_RCTL, 0); - E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); - E1000_WRITE_FLUSH(hw); - - /* - * Delay to allow any outstanding PCI transactions to complete - * before resetting the device. - */ - msec_delay(10); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGOUT("Issuing a global reset to 82540/82545/82546 MAC\n"); - switch (hw->mac.type) { - case e1000_82545_rev_3: - case e1000_82546_rev_3: - E1000_WRITE_REG(hw, E1000_CTRL_DUP, ctrl | E1000_CTRL_RST); - break; - default: - /* - * These controllers can't ack the 64-bit write when - * issuing the reset, so we use IO-mapping as a - * workaround to issue the reset. - */ - E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); - break; - } - - /* Wait for EEPROM reload */ - msec_delay(5); - - /* Disable HW ARPs on ASF enabled adapters */ - manc = E1000_READ_REG(hw, E1000_MANC); - manc &= ~E1000_MANC_ARP_EN; - E1000_WRITE_REG(hw, E1000_MANC, manc); - - E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); - E1000_READ_REG(hw, E1000_ICR); - - return ret_val; -} - -/** - * e1000_init_hw_82540 - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. - **/ -static s32 e1000_init_hw_82540(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 txdctl, ctrl_ext; - s32 ret_val = E1000_SUCCESS; - u16 i; - - DEBUGFUNC("e1000_init_hw_82540"); - - /* Initialize identification LED */ - ret_val = mac->ops.id_led_init(hw); - if (ret_val) { - DEBUGOUT("Error initializing identification LED\n"); - /* This is not fatal and we should not stop init due to this */ - } - - /* Disabling VLAN filtering */ - DEBUGOUT("Initializing the IEEE VLAN\n"); - if (mac->type < e1000_82545_rev_3) - E1000_WRITE_REG(hw, E1000_VET, 0); - - mac->ops.clear_vfta(hw); - - /* Setup the receive address. */ - e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); - - /* Zero out the Multicast HASH table */ - DEBUGOUT("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) { - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - /* - * Avoid back to back register writes by adding the register - * read (flush). This is to protect against some strange - * bridge configurations that may issue Memory Write Block - * (MWB) to our register space. The *_rev_3 hardware at - * least doesn't respond correctly to every other dword in an - * MWB to our register space. - */ - E1000_WRITE_FLUSH(hw); - } - - if (mac->type < e1000_82545_rev_3) - e1000_pcix_mmrbc_workaround_generic(hw); - - /* Setup link and flow control */ - ret_val = mac->ops.setup_link(hw); - - txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); - txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB; - E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - e1000_clear_hw_cntrs_82540(hw); - - if ((hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER) || - (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3)) { - ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - /* - * Relaxed ordering must be disabled to avoid a parity - * error crash in a PCI slot. - */ - ctrl_ext |= E1000_CTRL_EXT_RO_DIS; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - } - - return ret_val; -} - -/** - * e1000_setup_copper_link_82540 - Configure copper link settings - * @hw: pointer to the HW structure - * - * Calls the appropriate function to configure the link for auto-neg or forced - * speed and duplex. Then we check for link, once link is established calls - * to configure collision distance and flow control are called. If link is - * not established, we return -E1000_ERR_PHY (-2). - **/ -static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - u16 data; - - DEBUGFUNC("e1000_setup_copper_link_82540"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= E1000_CTRL_SLU; - ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - ret_val = e1000_set_phy_mode_82540(hw); - if (ret_val) - goto out; - - if (hw->mac.type == e1000_82545_rev_3 || - hw->mac.type == e1000_82546_rev_3) { - ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &data); - if (ret_val) - goto out; - data |= 0x00000008; - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, data); - if (ret_val) - goto out; - } - - ret_val = e1000_copper_link_setup_m88(hw); - if (ret_val) - goto out; - - ret_val = e1000_setup_copper_link_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes - * @hw: pointer to the HW structure - * - * Set the output amplitude to the value in the EEPROM and adjust the VCO - * speed to improve Bit Error Rate (BER) performance. Configures collision - * distance and flow control for fiber and serdes links. Upon successful - * setup, poll for link. - **/ -static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_setup_fiber_serdes_link_82540"); - - switch (mac->type) { - case e1000_82545_rev_3: - case e1000_82546_rev_3: - if (hw->phy.media_type == e1000_media_type_internal_serdes) { - /* - * If we're on serdes media, adjust the output - * amplitude to value set in the EEPROM. - */ - ret_val = e1000_adjust_serdes_amplitude_82540(hw); - if (ret_val) - goto out; - } - /* Adjust VCO speed to improve BER performance */ - ret_val = e1000_set_vco_speed_82540(hw); - if (ret_val) - goto out; - default: - break; - } - - ret_val = e1000_setup_fiber_serdes_link_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM - * @hw: pointer to the HW structure - * - * Adjust the SERDES output amplitude based on the EEPROM settings. - **/ -static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 nvm_data; - - DEBUGFUNC("e1000_adjust_serdes_amplitude_82540"); - - ret_val = hw->nvm.ops.read(hw, NVM_SERDES_AMPLITUDE, 1, &nvm_data); - if (ret_val) - goto out; - - if (nvm_data != NVM_RESERVED_WORD) { - /* Adjust serdes output amplitude only. */ - nvm_data &= NVM_SERDES_AMPLITUDE_MASK; - ret_val = hw->phy.ops.write_reg(hw, - M88E1000_PHY_EXT_CTRL, - nvm_data); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_set_vco_speed_82540 - Set VCO speed for better performance - * @hw: pointer to the HW structure - * - * Set the VCO speed to improve Bit Error Rate (BER) performance. - **/ -static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 default_page = 0; - u16 phy_data; - - DEBUGFUNC("e1000_set_vco_speed_82540"); - - /* Set PHY register 30, page 5, bit 8 to 0 */ - - ret_val = hw->phy.ops.read_reg(hw, - M88E1000_PHY_PAGE_SELECT, - &default_page); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~M88E1000_PHY_VCO_REG_BIT8; - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data); - if (ret_val) - goto out; - - /* Set PHY register 30, page 4, bit 11 to 1 */ - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_PHY_VCO_REG_BIT11; - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, - default_page); - -out: - return ret_val; -} - -/** - * e1000_set_phy_mode_82540 - Set PHY to class A mode - * @hw: pointer to the HW structure - * - * Sets the PHY to class A mode and assumes the following operations will - * follow to enable the new class mode: - * 1. Do a PHY soft reset. - * 2. Restart auto-negotiation or force link. - **/ -static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 nvm_data; - - DEBUGFUNC("e1000_set_phy_mode_82540"); - - if (hw->mac.type != e1000_82545_rev_3) - goto out; - - ret_val = hw->nvm.ops.read(hw, NVM_PHY_CLASS_WORD, 1, &nvm_data); - if (ret_val) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - if ((nvm_data != NVM_RESERVED_WORD) && (nvm_data & NVM_PHY_CLASS_A)) { - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, - 0x000B); - if (ret_val) { - ret_val = -E1000_ERR_PHY; - goto out; - } - ret_val = hw->phy.ops.write_reg(hw, - M88E1000_PHY_GEN_CONTROL, - 0x8104); - if (ret_val) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - phy->reset_disable = false; - } - -out: - return ret_val; -} - -/** - * e1000_power_down_phy_copper_82540 - Remove link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, remove the link. - **/ -static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw) -{ - /* If the management interface is not enabled, then power down */ - if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN)) - e1000_power_down_phy_copper(hw); - - return; -} - -/** - * e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters - * @hw: pointer to the HW structure - * - * Clears the hardware counters by reading the counter registers. - **/ -static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_clear_hw_cntrs_82540"); - - e1000_clear_hw_cntrs_base_generic(hw); - -#if 0 - E1000_READ_REG(hw, E1000_PRC64); - E1000_READ_REG(hw, E1000_PRC127); - E1000_READ_REG(hw, E1000_PRC255); - E1000_READ_REG(hw, E1000_PRC511); - E1000_READ_REG(hw, E1000_PRC1023); - E1000_READ_REG(hw, E1000_PRC1522); - E1000_READ_REG(hw, E1000_PTC64); - E1000_READ_REG(hw, E1000_PTC127); - E1000_READ_REG(hw, E1000_PTC255); - E1000_READ_REG(hw, E1000_PTC511); - E1000_READ_REG(hw, E1000_PTC1023); - E1000_READ_REG(hw, E1000_PTC1522); - - E1000_READ_REG(hw, E1000_ALGNERRC); - E1000_READ_REG(hw, E1000_RXERRC); - E1000_READ_REG(hw, E1000_TNCRS); - E1000_READ_REG(hw, E1000_CEXTERR); - E1000_READ_REG(hw, E1000_TSCTC); - E1000_READ_REG(hw, E1000_TSCTFC); - - E1000_READ_REG(hw, E1000_MGTPRC); - E1000_READ_REG(hw, E1000_MGTPDC); - E1000_READ_REG(hw, E1000_MGTPTC); -#endif -} - -/** - * e1000_read_mac_addr_82540 - Read device MAC address - * @hw: pointer to the HW structure - * - * Reads the device MAC address from the EEPROM and stores the value. - * Since devices with two ports use the same EEPROM, we increment the - * last bit in the MAC address for the second port. - * - * This version is being used over generic because of customer issues - * with VmWare and Virtual Box when using generic. It seems in - * the emulated 82545, RAR[0] does NOT have a valid address after a - * reset, this older method works and using this breaks nothing for - * these legacy adapters. - **/ -s32 e1000_read_mac_addr_82540(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 offset, nvm_data, i; - - DEBUGFUNC("e1000_read_mac_addr"); - - for (i = 0; i < ETH_ADDR_LEN; i += 2) { - offset = i >> 1; - ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF); - hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8); - } - - /* Flip last bit of mac address if we're on second port */ - if (hw->bus.func == E1000_FUNC_1) - hw->mac.perm_addr[5] ^= 1; - - for (i = 0; i < ETH_ADDR_LEN; i++) - hw->mac.addr[i] = hw->mac.perm_addr[i]; - -out: - return ret_val; -} - -static struct pci_device_id e1000_82540_nics[] = { - PCI_ROM(0x8086, 0x100E, "E1000_DEV_ID_82540EM", "E1000_DEV_ID_82540EM", e1000_82540), - PCI_ROM(0x8086, 0x1015, "E1000_DEV_ID_82540EM_LOM", "E1000_DEV_ID_82540EM_LOM", e1000_82540), - PCI_ROM(0x8086, 0x1016, "E1000_DEV_ID_82540EP_LOM", "E1000_DEV_ID_82540EP_LOM", e1000_82540), - PCI_ROM(0x8086, 0x1017, "E1000_DEV_ID_82540EP", "E1000_DEV_ID_82540EP", e1000_82540), - PCI_ROM(0x8086, 0x101E, "E1000_DEV_ID_82540EP_LP", "E1000_DEV_ID_82540EP_LP", e1000_82540), - PCI_ROM(0x8086, 0x100F, "E1000_DEV_ID_82545EM_COPPER", "E1000_DEV_ID_82545EM_COPPER", e1000_82545), - PCI_ROM(0x8086, 0x1011, "E1000_DEV_ID_82545EM_FIBER", "E1000_DEV_ID_82545EM_FIBER", e1000_82545), - PCI_ROM(0x8086, 0x1026, "E1000_DEV_ID_82545GM_COPPER", "E1000_DEV_ID_82545GM_COPPER", e1000_82545_rev_3), - PCI_ROM(0x8086, 0x1027, "E1000_DEV_ID_82545GM_FIBER", "E1000_DEV_ID_82545GM_FIBER", e1000_82545_rev_3), - PCI_ROM(0x8086, 0x1028, "E1000_DEV_ID_82545GM_SERDES", "E1000_DEV_ID_82545GM_SERDES", e1000_82545_rev_3), - PCI_ROM(0x8086, 0x1010, "E1000_DEV_ID_82546EB_COPPER", "E1000_DEV_ID_82546EB_COPPER", e1000_82546), - PCI_ROM(0x8086, 0x1012, "E1000_DEV_ID_82546EB_FIBER", "E1000_DEV_ID_82546EB_FIBER", e1000_82546), - PCI_ROM(0x8086, 0x101D, "E1000_DEV_ID_82546EB_QUAD_COPPER", "E1000_DEV_ID_82546EB_QUAD_COPPER", e1000_82546), - PCI_ROM(0x8086, 0x1079, "E1000_DEV_ID_82546GB_COPPER", "E1000_DEV_ID_82546GB_COPPER", e1000_82546_rev_3), - PCI_ROM(0x8086, 0x107A, "E1000_DEV_ID_82546GB_FIBER", "E1000_DEV_ID_82546GB_FIBER", e1000_82546_rev_3), - PCI_ROM(0x8086, 0x107B, "E1000_DEV_ID_82546GB_SERDES", "E1000_DEV_ID_82546GB_SERDES", e1000_82546_rev_3), - PCI_ROM(0x8086, 0x108A, "E1000_DEV_ID_82546GB_PCIE", "E1000_DEV_ID_82546GB_PCIE", e1000_82546_rev_3), - PCI_ROM(0x8086, 0x1099, "E1000_DEV_ID_82546GB_QUAD_COPPER", "E1000_DEV_ID_82546GB_QUAD_COPPER", e1000_82546_rev_3), - PCI_ROM(0x8086, 0x10B5, "E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3", "E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3", e1000_82546_rev_3), -}; - -struct pci_driver e1000_82540_driver __pci_driver = { - .ids = e1000_82540_nics, - .id_count = (sizeof (e1000_82540_nics) / sizeof (e1000_82540_nics[0])), - .probe = e1000_probe, - .remove = e1000_remove, -}; diff --git a/src/drivers/net/e1000/e1000_82541.c b/src/drivers/net/e1000/e1000_82541.c deleted file mode 100644 index 2d1aecc7..00000000 --- a/src/drivers/net/e1000/e1000_82541.c +++ /dev/null @@ -1,1314 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * 82541EI Gigabit Ethernet Controller - * 82541ER Gigabit Ethernet Controller - * 82541GI Gigabit Ethernet Controller - * 82541PI Gigabit Ethernet Controller - * 82547EI Gigabit Ethernet Controller - * 82547GI Gigabit Ethernet Controller - */ - -#include "e1000_api.h" - -static s32 e1000_init_phy_params_82541(struct e1000_hw *hw); -static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw); -static s32 e1000_init_mac_params_82541(struct e1000_hw *hw); -static s32 e1000_reset_hw_82541(struct e1000_hw *hw); -static s32 e1000_init_hw_82541(struct e1000_hw *hw); -static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw); -static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw); -static s32 e1000_check_for_link_82541(struct e1000_hw *hw); -#if 0 -static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw); -#endif -static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, - bool active); -static s32 e1000_setup_led_82541(struct e1000_hw *hw); -static s32 e1000_cleanup_led_82541(struct e1000_hw *hw); -static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw); -#if 0 -static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw, - bool link_up); -#endif -static s32 e1000_phy_init_script_82541(struct e1000_hw *hw); -static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw); - -#if 0 -static const u16 e1000_igp_cable_length_table[] = - { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25, - 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90, - 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, - 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, - 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120}; -#define IGP01E1000_AGC_LENGTH_TABLE_SIZE \ - (sizeof(e1000_igp_cable_length_table) / \ - sizeof(e1000_igp_cable_length_table[0])) -#endif -/** - * e1000_init_phy_params_82541 - Init PHY func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_phy_params_82541(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_init_phy_params_82541"); - - phy->addr = 1; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->reset_delay_us = 10000; - phy->type = e1000_phy_igp; - - /* Function Pointers */ - phy->ops.check_polarity = e1000_check_polarity_igp; -#if 0 - phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp; -#endif -#if 0 - phy->ops.get_cable_length = e1000_get_cable_length_igp_82541; -#endif - phy->ops.get_cfg_done = e1000_get_cfg_done_generic; - phy->ops.get_info = e1000_get_phy_info_igp; - phy->ops.read_reg = e1000_read_phy_reg_igp; - phy->ops.reset = e1000_phy_hw_reset_82541; - phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82541; - phy->ops.write_reg = e1000_write_phy_reg_igp; - phy->ops.power_up = e1000_power_up_phy_copper; - phy->ops.power_down = e1000_power_down_phy_copper_82541; - - ret_val = e1000_get_phy_id(hw); - if (ret_val) - goto out; - - /* Verify phy id */ - if (phy->id != IGP01E1000_I_PHY_ID) { - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_init_nvm_params_82541 - Init NVM func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - s32 ret_val = E1000_SUCCESS; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - u16 size; - - DEBUGFUNC("e1000_init_nvm_params_82541"); - - switch (nvm->override) { - case e1000_nvm_override_spi_large: - nvm->type = e1000_nvm_eeprom_spi; - eecd |= E1000_EECD_ADDR_BITS; - break; - case e1000_nvm_override_spi_small: - nvm->type = e1000_nvm_eeprom_spi; - eecd &= ~E1000_EECD_ADDR_BITS; - break; - case e1000_nvm_override_microwire_large: - nvm->type = e1000_nvm_eeprom_microwire; - eecd |= E1000_EECD_SIZE; - break; - case e1000_nvm_override_microwire_small: - nvm->type = e1000_nvm_eeprom_microwire; - eecd &= ~E1000_EECD_SIZE; - break; - default: - nvm->type = eecd & E1000_EECD_TYPE - ? e1000_nvm_eeprom_spi - : e1000_nvm_eeprom_microwire; - break; - } - - if (nvm->type == e1000_nvm_eeprom_spi) { - nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS) - ? 16 : 8; - nvm->delay_usec = 1; - nvm->opcode_bits = 8; - nvm->page_size = (eecd & E1000_EECD_ADDR_BITS) - ? 32 : 8; - - /* Function Pointers */ - nvm->ops.acquire = e1000_acquire_nvm_generic; - nvm->ops.read = e1000_read_nvm_spi; - nvm->ops.release = e1000_release_nvm_generic; - nvm->ops.update = e1000_update_nvm_checksum_generic; - nvm->ops.valid_led_default = e1000_valid_led_default_generic; - nvm->ops.validate = e1000_validate_nvm_checksum_generic; - nvm->ops.write = e1000_write_nvm_spi; - - /* - * nvm->word_size must be discovered after the pointers - * are set so we can verify the size from the nvm image - * itself. Temporarily set it to a dummy value so the - * read will work. - */ - nvm->word_size = 64; - ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size); - if (ret_val) - goto out; - size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT; - /* - * if size != 0, it can be added to a constant and become - * the left-shift value to set the word_size. Otherwise, - * word_size stays at 64. - */ - if (size) { - size += NVM_WORD_SIZE_BASE_SHIFT_82541; - nvm->word_size = 1 << size; - } - } else { - nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS) - ? 8 : 6; - nvm->delay_usec = 50; - nvm->opcode_bits = 3; - nvm->word_size = (eecd & E1000_EECD_ADDR_BITS) - ? 256 : 64; - - /* Function Pointers */ - nvm->ops.acquire = e1000_acquire_nvm_generic; - nvm->ops.read = e1000_read_nvm_microwire; - nvm->ops.release = e1000_release_nvm_generic; - nvm->ops.update = e1000_update_nvm_checksum_generic; - nvm->ops.valid_led_default = e1000_valid_led_default_generic; - nvm->ops.validate = e1000_validate_nvm_checksum_generic; - nvm->ops.write = e1000_write_nvm_microwire; - } - -out: - return ret_val; -} - -/** - * e1000_init_mac_params_82541 - Init MAC func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_mac_params_82541(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - DEBUGFUNC("e1000_init_mac_params_82541"); - - /* Set media type */ - hw->phy.media_type = e1000_media_type_copper; - /* Set mta register count */ - mac->mta_reg_count = 128; - /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES; - /* Set if part includes ASF firmware */ - mac->asf_firmware_present = true; - - /* Function Pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; - /* function id */ - mac->ops.set_lan_id = e1000_set_lan_id_single_port; - /* reset */ - mac->ops.reset_hw = e1000_reset_hw_82541; - /* hw initialization */ - mac->ops.init_hw = e1000_init_hw_82541; - /* link setup */ - mac->ops.setup_link = e1000_setup_link_generic; - /* physical interface link setup */ - mac->ops.setup_physical_interface = e1000_setup_copper_link_82541; - /* check for link */ - mac->ops.check_for_link = e1000_check_for_link_82541; - /* link info */ - mac->ops.get_link_up_info = e1000_get_link_up_info_82541; - /* multicast address update */ - mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = e1000_write_vfta_generic; - /* clearing VFTA */ - mac->ops.clear_vfta = e1000_clear_vfta_generic; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_generic; - /* ID LED init */ - mac->ops.id_led_init = e1000_id_led_init_generic; - /* setup LED */ - mac->ops.setup_led = e1000_setup_led_82541; - /* cleanup LED */ - mac->ops.cleanup_led = e1000_cleanup_led_82541; - /* turn on/off LED */ - mac->ops.led_on = e1000_led_on_generic; - mac->ops.led_off = e1000_led_off_generic; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541; - - return E1000_SUCCESS; -} - -/** - * e1000_init_function_pointers_82541 - Init func ptrs. - * @hw: pointer to the HW structure - * - * Called to initialize all function pointers and parameters. - **/ -void e1000_init_function_pointers_82541(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_init_function_pointers_82541"); - - hw->mac.ops.init_params = e1000_init_mac_params_82541; - hw->nvm.ops.init_params = e1000_init_nvm_params_82541; - hw->phy.ops.init_params = e1000_init_phy_params_82541; -} - -/** - * e1000_reset_hw_82541 - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. - **/ -static s32 e1000_reset_hw_82541(struct e1000_hw *hw) -{ - u32 ledctl, ctrl, manc; - - DEBUGFUNC("e1000_reset_hw_82541"); - - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF); - - E1000_WRITE_REG(hw, E1000_RCTL, 0); - E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); - E1000_WRITE_FLUSH(hw); - - /* - * Delay to allow any outstanding PCI transactions to complete - * before resetting the device. - */ - msec_delay(10); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* Must reset the Phy before resetting the MAC */ - if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) { - E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST)); - msec_delay(5); - } - - DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n"); - switch (hw->mac.type) { - case e1000_82541: - case e1000_82541_rev_2: - /* - * These controllers can't ack the 64-bit write when - * issuing the reset, so we use IO-mapping as a - * workaround to issue the reset. - */ - E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); - break; - default: - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); - break; - } - - /* Wait for NVM reload */ - msec_delay(20); - - /* Disable HW ARPs on ASF enabled adapters */ - manc = E1000_READ_REG(hw, E1000_MANC); - manc &= ~E1000_MANC_ARP_EN; - E1000_WRITE_REG(hw, E1000_MANC, manc); - - if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) { - e1000_phy_init_script_82541(hw); - - /* Configure activity LED after Phy reset */ - ledctl = E1000_READ_REG(hw, E1000_LEDCTL); - ledctl &= IGP_ACTIVITY_LED_MASK; - ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); - } - - /* Once again, mask the interrupts */ - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF); - - /* Clear any pending interrupt events. */ - E1000_READ_REG(hw, E1000_ICR); - - return E1000_SUCCESS; -} - -/** - * e1000_init_hw_82541 - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. - **/ -static s32 e1000_init_hw_82541(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; - u32 i, txdctl; - s32 ret_val; - - DEBUGFUNC("e1000_init_hw_82541"); - - /* Initialize identification LED */ - ret_val = mac->ops.id_led_init(hw); - if (ret_val) { - DEBUGOUT("Error initializing identification LED\n"); - /* This is not fatal and we should not stop init due to this */ - } - - /* Storing the Speed Power Down value for later use */ - ret_val = hw->phy.ops.read_reg(hw, - IGP01E1000_GMII_FIFO, - &dev_spec->spd_default); - if (ret_val) - goto out; - - /* Disabling VLAN filtering */ - DEBUGOUT("Initializing the IEEE VLAN\n"); - mac->ops.clear_vfta(hw); - - /* Setup the receive address. */ - e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); - - /* Zero out the Multicast HASH table */ - DEBUGOUT("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) { - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - /* - * Avoid back to back register writes by adding the register - * read (flush). This is to protect against some strange - * bridge configurations that may issue Memory Write Block - * (MWB) to our register space. - */ - E1000_WRITE_FLUSH(hw); - } - - /* Setup link and flow control */ - ret_val = mac->ops.setup_link(hw); - - txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0)); - txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB; - E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl); - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - e1000_clear_hw_cntrs_82541(hw); - -out: - return ret_val; -} - -/** - * e1000_get_link_up_info_82541 - Report speed and duplex - * @hw: pointer to the HW structure - * @speed: pointer to speed buffer - * @duplex: pointer to duplex buffer - * - * Retrieve the current speed and duplex configuration. - **/ -static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed, - u16 *duplex) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - DEBUGFUNC("e1000_get_link_up_info_82541"); - - ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex); - if (ret_val) - goto out; - - if (!phy->speed_downgraded) - goto out; - - /* - * IGP01 PHY may advertise full duplex operation after speed - * downgrade even if it is operating at half duplex. - * Here we set the duplex settings to match the duplex in the - * link partner's capabilities. - */ - ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data); - if (ret_val) - goto out; - - if (!(data & NWAY_ER_LP_NWAY_CAPS)) { - *duplex = HALF_DUPLEX; - } else { - ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data); - if (ret_val) - goto out; - - if (*speed == SPEED_100) { - if (!(data & NWAY_LPAR_100TX_FD_CAPS)) - *duplex = HALF_DUPLEX; - } else if (*speed == SPEED_10) { - if (!(data & NWAY_LPAR_10T_FD_CAPS)) - *duplex = HALF_DUPLEX; - } - } - -out: - return ret_val; -} - -/** - * e1000_phy_hw_reset_82541 - PHY hardware reset - * @hw: pointer to the HW structure - * - * Verify the reset block is not blocking us from resetting. Acquire - * semaphore (if necessary) and read/set/write the device control reset - * bit in the PHY. Wait the appropriate delay time for the device to - * reset and release the semaphore (if necessary). - **/ -static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw) -{ - s32 ret_val; - u32 ledctl; - - DEBUGFUNC("e1000_phy_hw_reset_82541"); - - ret_val = e1000_phy_hw_reset_generic(hw); - if (ret_val) - goto out; - - e1000_phy_init_script_82541(hw); - - if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) { - /* Configure activity LED after PHY reset */ - ledctl = E1000_READ_REG(hw, E1000_LEDCTL); - ledctl &= IGP_ACTIVITY_LED_MASK; - ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); - } - -out: - return ret_val; -} - -/** - * e1000_setup_copper_link_82541 - Configure copper link settings - * @hw: pointer to the HW structure - * - * Calls the appropriate function to configure the link for auto-neg or forced - * speed and duplex. Then we check for link, once link is established calls - * to configure collision distance and flow control are called. If link is - * not established, we return -E1000_ERR_PHY (-2). - **/ -static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; - s32 ret_val; - u32 ctrl, ledctl; - - DEBUGFUNC("e1000_setup_copper_link_82541"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= E1000_CTRL_SLU; - ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - hw->phy.reset_disable = false; - - /* Earlier revs of the IGP phy require us to force MDI. */ - if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) { - dev_spec->dsp_config = e1000_dsp_config_disabled; - phy->mdix = 1; - } else { - dev_spec->dsp_config = e1000_dsp_config_enabled; - } - - ret_val = e1000_copper_link_setup_igp(hw); - if (ret_val) - goto out; - - if (hw->mac.autoneg) { - if (dev_spec->ffe_config == e1000_ffe_config_active) - dev_spec->ffe_config = e1000_ffe_config_enabled; - } - - /* Configure activity LED after Phy reset */ - ledctl = E1000_READ_REG(hw, E1000_LEDCTL); - ledctl &= IGP_ACTIVITY_LED_MASK; - ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE); - E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); - - ret_val = e1000_setup_copper_link_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_check_for_link_82541 - Check/Store link connection - * @hw: pointer to the HW structure - * - * This checks the link condition of the adapter and stores the - * results in the hw->mac structure. - **/ -static s32 e1000_check_for_link_82541(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - bool link; - - DEBUGFUNC("e1000_check_for_link_82541"); - - /* - * We only want to go out to the PHY registers to see if Auto-Neg - * has completed and/or if our link status has changed. The - * get_link_status flag is set upon receiving a Link Status - * Change or Rx Sequence Error interrupt. - */ - if (!mac->get_link_status) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* - * First we want to see if the MII Status Register reports - * link. If so, then we want to get the current speed/duplex - * of the PHY. - */ - ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - ret_val = -E1000_ERR_CONFIG; -#if 0 - ret_val = e1000_config_dsp_after_link_change_82541(hw, false); -#endif - goto out; /* No link detected */ - } - - mac->get_link_status = false; - - /* - * Check if there was DownShift, must be checked - * immediately after link-up - */ - e1000_check_downshift_generic(hw); - - /* - * If we are forcing speed/duplex, then we simply return since - * we have already determined whether we have link or not. - */ - if (!mac->autoneg) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - -#if 0 - ret_val = e1000_config_dsp_after_link_change_82541(hw, true); -#endif - - /* - * Auto-Neg is enabled. Auto Speed Detection takes care - * of MAC speed/duplex configuration. So we only need to - * configure Collision Distance in the MAC. - */ - e1000_config_collision_dist_generic(hw); - - /* - * Configure Flow Control now that Auto-Neg has completed. - * First, we need to restore the desired flow control - * settings because we may have had to re-autoneg with a - * different link partner. - */ - ret_val = e1000_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - } - -out: - return ret_val; -} - -#if 0 -/** - * e1000_config_dsp_after_link_change_82541 - Config DSP after link - * @hw: pointer to the HW structure - * @link_up: boolean flag for link up status - * - * Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS - * at any other case. - * - * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a - * gigabit link is achieved to improve link quality. - **/ -static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw, - bool link_up) -{ - struct e1000_phy_info *phy = &hw->phy; - struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; - s32 ret_val; - u32 idle_errs = 0; - u16 phy_data, phy_saved_data, speed, duplex, i; - u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20; - u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = - {IGP01E1000_PHY_AGC_PARAM_A, - IGP01E1000_PHY_AGC_PARAM_B, - IGP01E1000_PHY_AGC_PARAM_C, - IGP01E1000_PHY_AGC_PARAM_D}; - - DEBUGFUNC("e1000_config_dsp_after_link_change_82541"); - - if (link_up) { - ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex); - if (ret_val) { - DEBUGOUT("Error getting link speed and duplex\n"); - goto out; - } - - if (speed != SPEED_1000) { - ret_val = E1000_SUCCESS; - goto out; - } - -#if 0 - ret_val = phy->ops.get_cable_length(hw); -#endif - ret_val = -E1000_ERR_CONFIG; - if (ret_val) - goto out; - - if ((dev_spec->dsp_config == e1000_dsp_config_enabled) && - phy->min_cable_length >= 50) { - - for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { - ret_val = phy->ops.read_reg(hw, - dsp_reg_array[i], - &phy_data); - if (ret_val) - goto out; - - phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; - - ret_val = phy->ops.write_reg(hw, - dsp_reg_array[i], - phy_data); - if (ret_val) - goto out; - } - dev_spec->dsp_config = e1000_dsp_config_activated; - } - - if ((dev_spec->ffe_config != e1000_ffe_config_enabled) || - (phy->min_cable_length >= 50)) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* clear previous idle error counts */ - ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); - if (ret_val) - goto out; - - for (i = 0; i < ffe_idle_err_timeout; i++) { - usec_delay(1000); - ret_val = phy->ops.read_reg(hw, - PHY_1000T_STATUS, - &phy_data); - if (ret_val) - goto out; - - idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT); - if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) { - dev_spec->ffe_config = e1000_ffe_config_active; - - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_DSP_FFE, - IGP01E1000_PHY_DSP_FFE_CM_CP); - if (ret_val) - goto out; - break; - } - - if (idle_errs) - ffe_idle_err_timeout = - FFE_IDLE_ERR_COUNT_TIMEOUT_100; - } - } else { - if (dev_spec->dsp_config == e1000_dsp_config_activated) { - /* - * Save off the current value of register 0x2F5B - * to be restored at the end of the routines. - */ - ret_val = phy->ops.read_reg(hw, - 0x2F5B, - &phy_saved_data); - if (ret_val) - goto out; - - /* Disable the PHY transmitter */ - ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003); - if (ret_val) - goto out; - - msec_delay_irq(20); - - ret_val = phy->ops.write_reg(hw, - 0x0000, - IGP01E1000_IEEE_FORCE_GIG); - if (ret_val) - goto out; - for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { - ret_val = phy->ops.read_reg(hw, - dsp_reg_array[i], - &phy_data); - if (ret_val) - goto out; - - phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX; - phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS; - - ret_val = phy->ops.write_reg(hw, - dsp_reg_array[i], - phy_data); - if (ret_val) - goto out; - } - - ret_val = phy->ops.write_reg(hw, - 0x0000, - IGP01E1000_IEEE_RESTART_AUTONEG); - if (ret_val) - goto out; - - msec_delay_irq(20); - - /* Now enable the transmitter */ - ret_val = phy->ops.write_reg(hw, - 0x2F5B, - phy_saved_data); - if (ret_val) - goto out; - - dev_spec->dsp_config = e1000_dsp_config_enabled; - } - - if (dev_spec->ffe_config != e1000_ffe_config_active) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* - * Save off the current value of register 0x2F5B - * to be restored at the end of the routines. - */ - ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data); - if (ret_val) - goto out; - - /* Disable the PHY transmitter */ - ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003); - if (ret_val) - goto out; - - msec_delay_irq(20); - - ret_val = phy->ops.write_reg(hw, - 0x0000, - IGP01E1000_IEEE_FORCE_GIG); - if (ret_val) - goto out; - - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_DSP_FFE, - IGP01E1000_PHY_DSP_FFE_DEFAULT); - if (ret_val) - goto out; - - ret_val = phy->ops.write_reg(hw, - 0x0000, - IGP01E1000_IEEE_RESTART_AUTONEG); - if (ret_val) - goto out; - - msec_delay_irq(20); - - /* Now enable the transmitter */ - ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data); - - if (ret_val) - goto out; - - dev_spec->ffe_config = e1000_ffe_config_enabled; - } - -out: - return ret_val; -} -#endif - -#if 0 -/** - * e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY - * @hw: pointer to the HW structure - * - * The automatic gain control (agc) normalizes the amplitude of the - * received signal, adjusting for the attenuation produced by the - * cable. By reading the AGC registers, which represent the - * combination of coarse and fine gain value, the value can be put - * into a lookup table to obtain the approximate cable length - * for each channel. - **/ -static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 i, data; - u16 cur_agc_value, agc_value = 0; - u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE; - u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = - {IGP01E1000_PHY_AGC_A, - IGP01E1000_PHY_AGC_B, - IGP01E1000_PHY_AGC_C, - IGP01E1000_PHY_AGC_D}; - - DEBUGFUNC("e1000_get_cable_length_igp_82541"); - - /* Read the AGC registers for all channels */ - for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) { - ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data); - if (ret_val) - goto out; - - cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT; - - /* Bounds checking */ - if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) || - (cur_agc_value == 0)) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - agc_value += cur_agc_value; - - if (min_agc_value > cur_agc_value) - min_agc_value = cur_agc_value; - } - - /* Remove the minimal AGC result for length < 50m */ - if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) { - agc_value -= min_agc_value; - /* Average the three remaining channels for the length. */ - agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1); - } else { - /* Average the channels for the length. */ - agc_value /= IGP01E1000_PHY_CHANNEL_NUM; - } - - phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] > - IGP01E1000_AGC_RANGE) - ? (e1000_igp_cable_length_table[agc_value] - - IGP01E1000_AGC_RANGE) - : 0; - phy->max_cable_length = e1000_igp_cable_length_table[agc_value] + - IGP01E1000_AGC_RANGE; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} -#endif - -/** - * e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D3 - * and SmartSpeed is disabled when active is true, else clear lplu for D3 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. - **/ -static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - DEBUGFUNC("e1000_set_d3_lplu_state_82541"); - - switch (hw->mac.type) { - case e1000_82541_rev_2: - case e1000_82547_rev_2: - break; - default: - ret_val = e1000_set_d3_lplu_state_generic(hw, active); - goto out; - break; - } - - ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data); - if (ret_val) - goto out; - - if (!active) { - data &= ~IGP01E1000_GMII_FLEX_SPD; - ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data); - if (ret_val) - goto out; - - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || - (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || - (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { - data |= IGP01E1000_GMII_FLEX_SPD; - ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data); - if (ret_val) - goto out; - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - } - -out: - return ret_val; -} - -/** - * e1000_setup_led_82541 - Configures SW controllable LED - * @hw: pointer to the HW structure - * - * This prepares the SW controllable LED for use and saves the current state - * of the LED so it can be later restored. - **/ -static s32 e1000_setup_led_82541(struct e1000_hw *hw __unused) -{ -#if 0 - struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; - s32 ret_val; - - DEBUGFUNC("e1000_setup_led_82541"); - - ret_val = hw->phy.ops.read_reg(hw, - IGP01E1000_GMII_FIFO, - &dev_spec->spd_default); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, - IGP01E1000_GMII_FIFO, - (u16)(dev_spec->spd_default & - ~IGP01E1000_GMII_SPD)); - if (ret_val) - goto out; - - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); - -out: - return ret_val; -#endif - return 0; -} - -/** - * e1000_cleanup_led_82541 - Set LED config to default operation - * @hw: pointer to the HW structure - * - * Remove the current LED configuration and set the LED configuration - * to the default value, saved from the EEPROM. - **/ -static s32 e1000_cleanup_led_82541(struct e1000_hw *hw __unused) -{ -#if 0 - struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; - s32 ret_val; - - DEBUGFUNC("e1000_cleanup_led_82541"); - - ret_val = hw->phy.ops.write_reg(hw, - IGP01E1000_GMII_FIFO, - dev_spec->spd_default); - if (ret_val) - goto out; - - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); - -out: - return ret_val; -#endif - return 0; -} - -/** - * e1000_phy_init_script_82541 - Initialize GbE PHY - * @hw: pointer to the HW structure - * - * Initializes the IGP PHY. - **/ -static s32 e1000_phy_init_script_82541(struct e1000_hw *hw) -{ - struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541; - u32 ret_val; - u16 phy_saved_data; - - DEBUGFUNC("e1000_phy_init_script_82541"); - - if (!dev_spec->phy_init_script) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* Delay after phy reset to enable NVM configuration to load */ - msec_delay(20); - - /* - * Save off the current value of register 0x2F5B to be restored at - * the end of this routine. - */ - ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data); - - /* Disabled the PHY transmitter */ - hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003); - - msec_delay(20); - - hw->phy.ops.write_reg(hw, 0x0000, 0x0140); - - msec_delay(5); - - switch (hw->mac.type) { - case e1000_82541: - case e1000_82547: - hw->phy.ops.write_reg(hw, 0x1F95, 0x0001); - - hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21); - - hw->phy.ops.write_reg(hw, 0x1F79, 0x0018); - - hw->phy.ops.write_reg(hw, 0x1F30, 0x1600); - - hw->phy.ops.write_reg(hw, 0x1F31, 0x0014); - - hw->phy.ops.write_reg(hw, 0x1F32, 0x161C); - - hw->phy.ops.write_reg(hw, 0x1F94, 0x0003); - - hw->phy.ops.write_reg(hw, 0x1F96, 0x003F); - - hw->phy.ops.write_reg(hw, 0x2010, 0x0008); - break; - case e1000_82541_rev_2: - case e1000_82547_rev_2: - hw->phy.ops.write_reg(hw, 0x1F73, 0x0099); - break; - default: - break; - } - - hw->phy.ops.write_reg(hw, 0x0000, 0x3300); - - msec_delay(20); - - /* Now enable the transmitter */ - hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data); - - if (hw->mac.type == e1000_82547) { - u16 fused, fine, coarse; - - /* Move to analog registers page */ - hw->phy.ops.read_reg(hw, - IGP01E1000_ANALOG_SPARE_FUSE_STATUS, - &fused); - - if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) { - hw->phy.ops.read_reg(hw, - IGP01E1000_ANALOG_FUSE_STATUS, - &fused); - - fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK; - coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK; - - if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) { - coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10; - fine -= IGP01E1000_ANALOG_FUSE_FINE_1; - } else if (coarse == - IGP01E1000_ANALOG_FUSE_COARSE_THRESH) - fine -= IGP01E1000_ANALOG_FUSE_FINE_10; - - fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) | - (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) | - (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK); - - hw->phy.ops.write_reg(hw, - IGP01E1000_ANALOG_FUSE_CONTROL, - fused); - hw->phy.ops.write_reg(hw, - IGP01E1000_ANALOG_FUSE_BYPASS, - IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL); - } - } - -out: - return ret_val; -} - -/** - * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, remove the link. - **/ -static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw) -{ - /* If the management interface is not enabled, then power down */ - if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN)) - e1000_power_down_phy_copper(hw); - - return; -} - -/** - * e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters - * @hw: pointer to the HW structure - * - * Clears the hardware counters by reading the counter registers. - **/ -static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_clear_hw_cntrs_82541"); - - e1000_clear_hw_cntrs_base_generic(hw); - -#if 0 - E1000_READ_REG(hw, E1000_PRC64); - E1000_READ_REG(hw, E1000_PRC127); - E1000_READ_REG(hw, E1000_PRC255); - E1000_READ_REG(hw, E1000_PRC511); - E1000_READ_REG(hw, E1000_PRC1023); - E1000_READ_REG(hw, E1000_PRC1522); - E1000_READ_REG(hw, E1000_PTC64); - E1000_READ_REG(hw, E1000_PTC127); - E1000_READ_REG(hw, E1000_PTC255); - E1000_READ_REG(hw, E1000_PTC511); - E1000_READ_REG(hw, E1000_PTC1023); - E1000_READ_REG(hw, E1000_PTC1522); - - E1000_READ_REG(hw, E1000_ALGNERRC); - E1000_READ_REG(hw, E1000_RXERRC); - E1000_READ_REG(hw, E1000_TNCRS); - E1000_READ_REG(hw, E1000_CEXTERR); - E1000_READ_REG(hw, E1000_TSCTC); - E1000_READ_REG(hw, E1000_TSCTFC); - - E1000_READ_REG(hw, E1000_MGTPRC); - E1000_READ_REG(hw, E1000_MGTPDC); - E1000_READ_REG(hw, E1000_MGTPTC); -#endif -} - -static struct pci_device_id e1000_82541_nics[] = { - PCI_ROM(0x8086, 0x1013, "E1000_DEV_ID_82541EI", "E1000_DEV_ID_82541EI", e1000_82541), - PCI_ROM(0x8086, 0x1014, "E1000_DEV_ID_82541ER_LOM", "E1000_DEV_ID_82541ER_LOM", e1000_82541), - PCI_ROM(0x8086, 0x1018, "E1000_DEV_ID_82541EI_MOBILE", "E1000_DEV_ID_82541EI_MOBILE", e1000_82541), - PCI_ROM(0x8086, 0x1019, "E1000_DEV_ID_82547EI", "E1000_DEV_ID_82547EI", e1000_82547), - PCI_ROM(0x8086, 0x101A, "E1000_DEV_ID_82547EI_MOBILE", "E1000_DEV_ID_82547EI_MOBILE", e1000_82547), - PCI_ROM(0x8086, 0x1075, "E1000_DEV_ID_82547GI", "E1000_DEV_ID_82547GI", e1000_82547_rev_2), - PCI_ROM(0x8086, 0x1076, "E1000_DEV_ID_82541GI", "E1000_DEV_ID_82541GI", e1000_82541_rev_2), - PCI_ROM(0x8086, 0x1077, "E1000_DEV_ID_82541GI_MOBILE", "E1000_DEV_ID_82541GI_MOBILE", e1000_82541_rev_2), - PCI_ROM(0x8086, 0x1078, "E1000_DEV_ID_82541ER", "E1000_DEV_ID_82541ER", e1000_82541_rev_2), - PCI_ROM(0x8086, 0x107C, "E1000_DEV_ID_82541GI_LF", "E1000_DEV_ID_82541GI_LF", e1000_82541_rev_2), -}; - -struct pci_driver e1000_82541_driver __pci_driver = { - .ids = e1000_82541_nics, - .id_count = (sizeof (e1000_82541_nics) / sizeof (e1000_82541_nics[0])), - .probe = e1000_probe, - .remove = e1000_remove, -}; diff --git a/src/drivers/net/e1000/e1000_82541.h b/src/drivers/net/e1000/e1000_82541.h deleted file mode 100644 index f86a1482..00000000 --- a/src/drivers/net/e1000/e1000_82541.h +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_82541_H_ -#define _E1000_82541_H_ - -#define NVM_WORD_SIZE_BASE_SHIFT_82541 (NVM_WORD_SIZE_BASE_SHIFT + 1) - -#define IGP01E1000_PHY_CHANNEL_NUM 4 - -#define IGP01E1000_PHY_AGC_A 0x1172 -#define IGP01E1000_PHY_AGC_B 0x1272 -#define IGP01E1000_PHY_AGC_C 0x1472 -#define IGP01E1000_PHY_AGC_D 0x1872 - -#define IGP01E1000_PHY_AGC_PARAM_A 0x1171 -#define IGP01E1000_PHY_AGC_PARAM_B 0x1271 -#define IGP01E1000_PHY_AGC_PARAM_C 0x1471 -#define IGP01E1000_PHY_AGC_PARAM_D 0x1871 - -#define IGP01E1000_PHY_EDAC_MU_INDEX 0xC000 -#define IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS 0x8000 - -#define IGP01E1000_PHY_DSP_RESET 0x1F33 - -#define IGP01E1000_PHY_DSP_FFE 0x1F35 -#define IGP01E1000_PHY_DSP_FFE_CM_CP 0x0069 -#define IGP01E1000_PHY_DSP_FFE_DEFAULT 0x002A - -#define IGP01E1000_IEEE_FORCE_GIG 0x0140 -#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300 - -#define IGP01E1000_AGC_LENGTH_SHIFT 7 -#define IGP01E1000_AGC_RANGE 10 - -#define FFE_IDLE_ERR_COUNT_TIMEOUT_20 20 -#define FFE_IDLE_ERR_COUNT_TIMEOUT_100 100 - -#define IGP01E1000_ANALOG_FUSE_STATUS 0x20D0 -#define IGP01E1000_ANALOG_SPARE_FUSE_STATUS 0x20D1 -#define IGP01E1000_ANALOG_FUSE_CONTROL 0x20DC -#define IGP01E1000_ANALOG_FUSE_BYPASS 0x20DE - -#define IGP01E1000_ANALOG_SPARE_FUSE_ENABLED 0x0100 -#define IGP01E1000_ANALOG_FUSE_FINE_MASK 0x0F80 -#define IGP01E1000_ANALOG_FUSE_COARSE_MASK 0x0070 -#define IGP01E1000_ANALOG_FUSE_COARSE_THRESH 0x0040 -#define IGP01E1000_ANALOG_FUSE_COARSE_10 0x0010 -#define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080 -#define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500 -#define IGP01E1000_ANALOG_FUSE_POLY_MASK 0xF000 -#define IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL 0x0002 - -#define IGP01E1000_MSE_CHANNEL_D 0x000F -#define IGP01E1000_MSE_CHANNEL_C 0x00F0 -#define IGP01E1000_MSE_CHANNEL_B 0x0F00 -#define IGP01E1000_MSE_CHANNEL_A 0xF000 - -#endif diff --git a/src/drivers/net/e1000/e1000_82542.c b/src/drivers/net/e1000/e1000_82542.c deleted file mode 100644 index b6d5202c..00000000 --- a/src/drivers/net/e1000/e1000_82542.c +++ /dev/null @@ -1,571 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * 82542 Gigabit Ethernet Controller - */ - -#include "e1000_api.h" - -static s32 e1000_init_phy_params_82542(struct e1000_hw *hw); -static s32 e1000_init_nvm_params_82542(struct e1000_hw *hw); -static s32 e1000_init_mac_params_82542(struct e1000_hw *hw); -static s32 e1000_get_bus_info_82542(struct e1000_hw *hw); -static s32 e1000_reset_hw_82542(struct e1000_hw *hw); -static s32 e1000_init_hw_82542(struct e1000_hw *hw); -static s32 e1000_setup_link_82542(struct e1000_hw *hw); -static s32 e1000_led_on_82542(struct e1000_hw *hw); -static s32 e1000_led_off_82542(struct e1000_hw *hw); -static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index); -static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw); - -/** - * e1000_init_phy_params_82542 - Init PHY func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_phy_params_82542(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_init_phy_params_82542"); - - phy->type = e1000_phy_none; - - return ret_val; -} - -/** - * e1000_init_nvm_params_82542 - Init NVM func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_nvm_params_82542(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - - DEBUGFUNC("e1000_init_nvm_params_82542"); - - nvm->address_bits = 6; - nvm->delay_usec = 50; - nvm->opcode_bits = 3; - nvm->type = e1000_nvm_eeprom_microwire; - nvm->word_size = 64; - - /* Function Pointers */ - nvm->ops.read = e1000_read_nvm_microwire; - nvm->ops.release = e1000_stop_nvm; - nvm->ops.write = e1000_write_nvm_microwire; - nvm->ops.update = e1000_update_nvm_checksum_generic; - nvm->ops.validate = e1000_validate_nvm_checksum_generic; - - return E1000_SUCCESS; -} - -/** - * e1000_init_mac_params_82542 - Init MAC func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_mac_params_82542(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - DEBUGFUNC("e1000_init_mac_params_82542"); - - /* Set media type */ - hw->phy.media_type = e1000_media_type_fiber; - - /* Set mta register count */ - mac->mta_reg_count = 128; - /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES; - - /* Function pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = e1000_get_bus_info_82542; - /* function id */ - mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci; - /* reset */ - mac->ops.reset_hw = e1000_reset_hw_82542; - /* hw initialization */ - mac->ops.init_hw = e1000_init_hw_82542; - /* link setup */ - mac->ops.setup_link = e1000_setup_link_82542; - /* phy/fiber/serdes setup */ - mac->ops.setup_physical_interface = e1000_setup_fiber_serdes_link_generic; - /* check for link */ - mac->ops.check_for_link = e1000_check_for_fiber_link_generic; - /* multicast address update */ - mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = e1000_write_vfta_generic; - /* clearing VFTA */ - mac->ops.clear_vfta = e1000_clear_vfta_generic; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_generic; - /* set RAR */ - mac->ops.rar_set = e1000_rar_set_82542; - /* turn on/off LED */ - mac->ops.led_on = e1000_led_on_82542; - mac->ops.led_off = e1000_led_off_82542; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82542; - /* link info */ - mac->ops.get_link_up_info = e1000_get_speed_and_duplex_fiber_serdes_generic; - - return E1000_SUCCESS; -} - -/** - * e1000_init_function_pointers_82542 - Init func ptrs. - * @hw: pointer to the HW structure - * - * Called to initialize all function pointers and parameters. - **/ -void e1000_init_function_pointers_82542(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_init_function_pointers_82542"); - - hw->mac.ops.init_params = e1000_init_mac_params_82542; - hw->nvm.ops.init_params = e1000_init_nvm_params_82542; - hw->phy.ops.init_params = e1000_init_phy_params_82542; -} - -/** - * e1000_get_bus_info_82542 - Obtain bus information for adapter - * @hw: pointer to the HW structure - * - * This will obtain information about the HW bus for which the - * adapter is attached and stores it in the hw structure. - **/ -static s32 e1000_get_bus_info_82542(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_get_bus_info_82542"); - - hw->bus.type = e1000_bus_type_pci; - hw->bus.speed = e1000_bus_speed_unknown; - hw->bus.width = e1000_bus_width_unknown; - - return E1000_SUCCESS; -} - -/** - * e1000_reset_hw_82542 - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. - **/ -static s32 e1000_reset_hw_82542(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - s32 ret_val = E1000_SUCCESS; - u32 ctrl; - - DEBUGFUNC("e1000_reset_hw_82542"); - - if (hw->revision_id == E1000_REVISION_2) { - DEBUGOUT("Disabling MWI on 82542 rev 2\n"); - e1000_pci_clear_mwi(hw); - } - - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); - - E1000_WRITE_REG(hw, E1000_RCTL, 0); - E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); - E1000_WRITE_FLUSH(hw); - - /* - * Delay to allow any outstanding PCI transactions to complete before - * resetting the device - */ - msec_delay(10); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGOUT("Issuing a global reset to 82542/82543 MAC\n"); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); - - hw->nvm.ops.reload(hw); - msec_delay(2); - - E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); - E1000_READ_REG(hw, E1000_ICR); - - if (hw->revision_id == E1000_REVISION_2) { - if (bus->pci_cmd_word & CMD_MEM_WRT_INVALIDATE) - e1000_pci_set_mwi(hw); - } - - return ret_val; -} - -/** - * e1000_init_hw_82542 - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. - **/ -static s32 e1000_init_hw_82542(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - struct e1000_dev_spec_82542 *dev_spec = &hw->dev_spec._82542; - s32 ret_val = E1000_SUCCESS; - u32 ctrl; - u16 i; - - DEBUGFUNC("e1000_init_hw_82542"); - - /* Disabling VLAN filtering */ - E1000_WRITE_REG(hw, E1000_VET, 0); - mac->ops.clear_vfta(hw); - - /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */ - if (hw->revision_id == E1000_REVISION_2) { - DEBUGOUT("Disabling MWI on 82542 rev 2.0\n"); - e1000_pci_clear_mwi(hw); - E1000_WRITE_REG(hw, E1000_RCTL, E1000_RCTL_RST); - E1000_WRITE_FLUSH(hw); - msec_delay(5); - } - - /* Setup the receive address. */ - e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); - - /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */ - if (hw->revision_id == E1000_REVISION_2) { - E1000_WRITE_REG(hw, E1000_RCTL, 0); - E1000_WRITE_FLUSH(hw); - msec_delay(1); - if (hw->bus.pci_cmd_word & CMD_MEM_WRT_INVALIDATE) - e1000_pci_set_mwi(hw); - } - - /* Zero out the Multicast HASH table */ - DEBUGOUT("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - - /* - * Set the PCI priority bit correctly in the CTRL register. This - * determines if the adapter gives priority to receives, or if it - * gives equal priority to transmits and receives. - */ - if (dev_spec->dma_fairness) { - ctrl = E1000_READ_REG(hw, E1000_CTRL); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR); - } - - /* Setup link and flow control */ - ret_val = e1000_setup_link_82542(hw); - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - e1000_clear_hw_cntrs_82542(hw); - - return ret_val; -} - -/** - * e1000_setup_link_82542 - Setup flow control and link settings - * @hw: pointer to the HW structure - * - * Determines which flow control settings to use, then configures flow - * control. Calls the appropriate media-specific link configuration - * function. Assuming the adapter has a valid link partner, a valid link - * should be established. Assumes the hardware has previously been reset - * and the transmitter and receiver are not enabled. - **/ -static s32 e1000_setup_link_82542(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_setup_link_82542"); - - ret_val = e1000_set_default_fc_generic(hw); - if (ret_val) - goto out; - - hw->fc.requested_mode &= ~e1000_fc_tx_pause; - - if (mac->report_tx_early == 1) - hw->fc.requested_mode &= ~e1000_fc_rx_pause; - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - hw->fc.current_mode = hw->fc.requested_mode; - - DEBUGOUT1("After fix-ups FlowControl is now = %x\n", - hw->fc.current_mode); - - /* Call the necessary subroutine to configure the link. */ - ret_val = mac->ops.setup_physical_interface(hw); - if (ret_val) - goto out; - - /* - * Initialize the flow control address, type, and PAUSE timer - * registers to their default values. This is done even if flow - * control is disabled, because it does not hurt anything to - * initialize these registers. - */ - DEBUGOUT("Initializing Flow Control address, type and timer regs\n"); - - E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); - E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); - E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE); - - E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); - - ret_val = e1000_set_fc_watermarks_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_led_on_82542 - Turn on SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED on. - **/ -static s32 e1000_led_on_82542(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGFUNC("e1000_led_on_82542"); - - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_led_off_82542 - Turn off SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED off. - **/ -static s32 e1000_led_off_82542(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGFUNC("e1000_led_off_82542"); - - ctrl &= ~E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_rar_set_82542 - Set receive address register - * @hw: pointer to the HW structure - * @addr: pointer to the receive address - * @index: receive address array register - * - * Sets the receive address array register at index to the address passed - * in by addr. - **/ -static void e1000_rar_set_82542(struct e1000_hw *hw, u8 *addr, u32 index) -{ - u32 rar_low, rar_high; - - DEBUGFUNC("e1000_rar_set_82542"); - - /* - * HW expects these in little endian so we reverse the byte order - * from network order (big endian) to little endian - */ - rar_low = ((u32) addr[0] | - ((u32) addr[1] << 8) | - ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); - - rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); - - /* If MAC address zero, no need to set the AV bit */ - if (rar_low || rar_high) - rar_high |= E1000_RAH_AV; - - E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low); - E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high); -} - -/** - * e1000_translate_register_82542 - Translate the proper register offset - * @reg: e1000 register to be read - * - * Registers in 82542 are located in different offsets than other adapters - * even though they function in the same manner. This function takes in - * the name of the register to read and returns the correct offset for - * 82542 silicon. - **/ -u32 e1000_translate_register_82542(u32 reg) -{ - /* - * Some of the 82542 registers are located at different - * offsets than they are in newer adapters. - * Despite the difference in location, the registers - * function in the same manner. - */ - switch (reg) { - case E1000_RA: - reg = 0x00040; - break; - case E1000_RDTR: - reg = 0x00108; - break; - case E1000_RDBAL(0): - reg = 0x00110; - break; - case E1000_RDBAH(0): - reg = 0x00114; - break; - case E1000_RDLEN(0): - reg = 0x00118; - break; - case E1000_RDH(0): - reg = 0x00120; - break; - case E1000_RDT(0): - reg = 0x00128; - break; - case E1000_RDBAL(1): - reg = 0x00138; - break; - case E1000_RDBAH(1): - reg = 0x0013C; - break; - case E1000_RDLEN(1): - reg = 0x00140; - break; - case E1000_RDH(1): - reg = 0x00148; - break; - case E1000_RDT(1): - reg = 0x00150; - break; - case E1000_FCRTH: - reg = 0x00160; - break; - case E1000_FCRTL: - reg = 0x00168; - break; - case E1000_MTA: - reg = 0x00200; - break; - case E1000_TDBAL(0): - reg = 0x00420; - break; - case E1000_TDBAH(0): - reg = 0x00424; - break; - case E1000_TDLEN(0): - reg = 0x00428; - break; - case E1000_TDH(0): - reg = 0x00430; - break; - case E1000_TDT(0): - reg = 0x00438; - break; - case E1000_TIDV: - reg = 0x00440; - break; - case E1000_VFTA: - reg = 0x00600; - break; - case E1000_TDFH: - reg = 0x08010; - break; - case E1000_TDFT: - reg = 0x08018; - break; - default: - break; - } - - return reg; -} - -/** - * e1000_clear_hw_cntrs_82542 - Clear device specific hardware counters - * @hw: pointer to the HW structure - * - * Clears the hardware counters by reading the counter registers. - **/ -static void e1000_clear_hw_cntrs_82542(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_clear_hw_cntrs_82542"); - - e1000_clear_hw_cntrs_base_generic(hw); - -#if 0 - E1000_READ_REG(hw, E1000_PRC64); - E1000_READ_REG(hw, E1000_PRC127); - E1000_READ_REG(hw, E1000_PRC255); - E1000_READ_REG(hw, E1000_PRC511); - E1000_READ_REG(hw, E1000_PRC1023); - E1000_READ_REG(hw, E1000_PRC1522); - E1000_READ_REG(hw, E1000_PTC64); - E1000_READ_REG(hw, E1000_PTC127); - E1000_READ_REG(hw, E1000_PTC255); - E1000_READ_REG(hw, E1000_PTC511); - E1000_READ_REG(hw, E1000_PTC1023); - E1000_READ_REG(hw, E1000_PTC1522); -#endif -} - -static struct pci_device_id e1000_82542_nics[] = { - PCI_ROM(0x8086, 0x1000, "E1000_DEV_ID_82542", "E1000_DEV_ID_82542", e1000_82542), -}; - -struct pci_driver e1000_82542_driver __pci_driver = { - .ids = e1000_82542_nics, - .id_count = (sizeof (e1000_82542_nics) / sizeof (e1000_82542_nics[0])), - .probe = e1000_probe, - .remove = e1000_remove, -}; diff --git a/src/drivers/net/e1000/e1000_82543.c b/src/drivers/net/e1000/e1000_82543.c deleted file mode 100644 index 848c99e7..00000000 --- a/src/drivers/net/e1000/e1000_82543.c +++ /dev/null @@ -1,1635 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * 82543GC Gigabit Ethernet Controller (Fiber) - * 82543GC Gigabit Ethernet Controller (Copper) - * 82544EI Gigabit Ethernet Controller (Copper) - * 82544EI Gigabit Ethernet Controller (Fiber) - * 82544GC Gigabit Ethernet Controller (Copper) - * 82544GC Gigabit Ethernet Controller (LOM) - */ - -#include "e1000_api.h" - -static s32 e1000_init_phy_params_82543(struct e1000_hw *hw); -static s32 e1000_init_nvm_params_82543(struct e1000_hw *hw); -static s32 e1000_init_mac_params_82543(struct e1000_hw *hw); -static s32 e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset, - u16 *data); -static s32 e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset, - u16 data); -#if 0 -static s32 e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw); -#endif -static s32 e1000_phy_hw_reset_82543(struct e1000_hw *hw); -static s32 e1000_reset_hw_82543(struct e1000_hw *hw); -static s32 e1000_init_hw_82543(struct e1000_hw *hw); -static s32 e1000_setup_link_82543(struct e1000_hw *hw); -static s32 e1000_setup_copper_link_82543(struct e1000_hw *hw); -static s32 e1000_setup_fiber_link_82543(struct e1000_hw *hw); -static s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw); -static s32 e1000_check_for_fiber_link_82543(struct e1000_hw *hw); -static s32 e1000_led_on_82543(struct e1000_hw *hw); -static s32 e1000_led_off_82543(struct e1000_hw *hw); -static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset, - u32 value); -static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value); -static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw); -static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw); -static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw); -static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl); -static s32 e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw); -static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl); -static u16 e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw); -static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data, - u16 count); -static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw); -static void e1000_set_tbi_compatibility_82543(struct e1000_hw *hw, bool state); -static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state); - -/** - * e1000_init_phy_params_82543 - Init PHY func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_phy_params_82543(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_init_phy_params_82543"); - - if (hw->phy.media_type != e1000_media_type_copper) { - phy->type = e1000_phy_none; - goto out; - } else { - phy->ops.power_up = e1000_power_up_phy_copper; - phy->ops.power_down = e1000_power_down_phy_copper; - } - - phy->addr = 1; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->reset_delay_us = 10000; - phy->type = e1000_phy_m88; - - /* Function Pointers */ - phy->ops.check_polarity = e1000_check_polarity_m88; - phy->ops.commit = e1000_phy_sw_reset_generic; -#if 0 - phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_82543; -#endif -#if 0 - phy->ops.get_cable_length = e1000_get_cable_length_m88; -#endif - phy->ops.get_cfg_done = e1000_get_cfg_done_generic; - phy->ops.read_reg = (hw->mac.type == e1000_82543) - ? e1000_read_phy_reg_82543 - : e1000_read_phy_reg_m88; - phy->ops.reset = (hw->mac.type == e1000_82543) - ? e1000_phy_hw_reset_82543 - : e1000_phy_hw_reset_generic; - phy->ops.write_reg = (hw->mac.type == e1000_82543) - ? e1000_write_phy_reg_82543 - : e1000_write_phy_reg_m88; - phy->ops.get_info = e1000_get_phy_info_m88; - - /* - * The external PHY of the 82543 can be in a funky state. - * Resetting helps us read the PHY registers for acquiring - * the PHY ID. - */ - if (!e1000_init_phy_disabled_82543(hw)) { - ret_val = phy->ops.reset(hw); - if (ret_val) { - DEBUGOUT("Resetting PHY during init failed.\n"); - goto out; - } - msec_delay(20); - } - - ret_val = e1000_get_phy_id(hw); - if (ret_val) - goto out; - - /* Verify phy id */ - switch (hw->mac.type) { - case e1000_82543: - if (phy->id != M88E1000_E_PHY_ID) { - ret_val = -E1000_ERR_PHY; - goto out; - } - break; - case e1000_82544: - if (phy->id != M88E1000_I_PHY_ID) { - ret_val = -E1000_ERR_PHY; - goto out; - } - break; - default: - ret_val = -E1000_ERR_PHY; - goto out; - break; - } - -out: - return ret_val; -} - -/** - * e1000_init_nvm_params_82543 - Init NVM func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_nvm_params_82543(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - - DEBUGFUNC("e1000_init_nvm_params_82543"); - - nvm->type = e1000_nvm_eeprom_microwire; - nvm->word_size = 64; - nvm->delay_usec = 50; - nvm->address_bits = 6; - nvm->opcode_bits = 3; - - /* Function Pointers */ - nvm->ops.read = e1000_read_nvm_microwire; - nvm->ops.update = e1000_update_nvm_checksum_generic; - nvm->ops.valid_led_default = e1000_valid_led_default_generic; - nvm->ops.validate = e1000_validate_nvm_checksum_generic; - nvm->ops.write = e1000_write_nvm_microwire; - - return E1000_SUCCESS; -} - -/** - * e1000_init_mac_params_82543 - Init MAC func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000_init_mac_params_82543(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - DEBUGFUNC("e1000_init_mac_params_82543"); - - /* Set media type */ - switch (hw->device_id) { - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82544EI_FIBER: - hw->phy.media_type = e1000_media_type_fiber; - break; - default: - hw->phy.media_type = e1000_media_type_copper; - break; - } - - /* Set mta register count */ - mac->mta_reg_count = 128; - /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES; - - /* Function pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = e1000_get_bus_info_pci_generic; - /* function id */ - mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pci; - /* reset */ - mac->ops.reset_hw = e1000_reset_hw_82543; - /* hw initialization */ - mac->ops.init_hw = e1000_init_hw_82543; - /* link setup */ - mac->ops.setup_link = e1000_setup_link_82543; - /* physical interface setup */ - mac->ops.setup_physical_interface = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_setup_copper_link_82543 - : e1000_setup_fiber_link_82543; - /* check for link */ - mac->ops.check_for_link = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_check_for_copper_link_82543 - : e1000_check_for_fiber_link_82543; - /* link info */ - mac->ops.get_link_up_info = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000_get_speed_and_duplex_copper_generic - : e1000_get_speed_and_duplex_fiber_serdes_generic; - /* multicast address update */ - mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = e1000_write_vfta_82543; - /* clearing VFTA */ - mac->ops.clear_vfta = e1000_clear_vfta_generic; - /* setting MTA */ - mac->ops.mta_set = e1000_mta_set_82543; - /* turn on/off LED */ - mac->ops.led_on = e1000_led_on_82543; - mac->ops.led_off = e1000_led_off_82543; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82543; - - /* Set tbi compatibility */ - if ((hw->mac.type != e1000_82543) || - (hw->phy.media_type == e1000_media_type_fiber)) - e1000_set_tbi_compatibility_82543(hw, false); - - return E1000_SUCCESS; -} - -/** - * e1000_init_function_pointers_82543 - Init func ptrs. - * @hw: pointer to the HW structure - * - * Called to initialize all function pointers and parameters. - **/ -void e1000_init_function_pointers_82543(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_init_function_pointers_82543"); - - hw->mac.ops.init_params = e1000_init_mac_params_82543; - hw->nvm.ops.init_params = e1000_init_nvm_params_82543; - hw->phy.ops.init_params = e1000_init_phy_params_82543; -} - -/** - * e1000_tbi_compatibility_enabled_82543 - Returns TBI compat status - * @hw: pointer to the HW structure - * - * Returns the current status of 10-bit Interface (TBI) compatibility - * (enabled/disabled). - **/ -static bool e1000_tbi_compatibility_enabled_82543(struct e1000_hw *hw) -{ - struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543; - bool state = false; - - DEBUGFUNC("e1000_tbi_compatibility_enabled_82543"); - - if (hw->mac.type != e1000_82543) { - DEBUGOUT("TBI compatibility workaround for 82543 only.\n"); - goto out; - } - - state = (dev_spec->tbi_compatibility & TBI_COMPAT_ENABLED) - ? true : false; - -out: - return state; -} - -/** - * e1000_set_tbi_compatibility_82543 - Set TBI compatibility - * @hw: pointer to the HW structure - * @state: enable/disable TBI compatibility - * - * Enables or disabled 10-bit Interface (TBI) compatibility. - **/ -static void e1000_set_tbi_compatibility_82543(struct e1000_hw *hw, bool state) -{ - struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543; - - DEBUGFUNC("e1000_set_tbi_compatibility_82543"); - - if (hw->mac.type != e1000_82543) { - DEBUGOUT("TBI compatibility workaround for 82543 only.\n"); - goto out; - } - - if (state) - dev_spec->tbi_compatibility |= TBI_COMPAT_ENABLED; - else - dev_spec->tbi_compatibility &= ~TBI_COMPAT_ENABLED; - -out: - return; -} - -/** - * e1000_tbi_sbp_enabled_82543 - Returns TBI SBP status - * @hw: pointer to the HW structure - * - * Returns the current status of 10-bit Interface (TBI) store bad packet (SBP) - * (enabled/disabled). - **/ -bool e1000_tbi_sbp_enabled_82543(struct e1000_hw *hw) -{ - struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543; - bool state = false; - - DEBUGFUNC("e1000_tbi_sbp_enabled_82543"); - - if (hw->mac.type != e1000_82543) { - DEBUGOUT("TBI compatibility workaround for 82543 only.\n"); - goto out; - } - - state = (dev_spec->tbi_compatibility & TBI_SBP_ENABLED) - ? true : false; - -out: - return state; -} - -/** - * e1000_set_tbi_sbp_82543 - Set TBI SBP - * @hw: pointer to the HW structure - * @state: enable/disable TBI store bad packet - * - * Enables or disabled 10-bit Interface (TBI) store bad packet (SBP). - **/ -static void e1000_set_tbi_sbp_82543(struct e1000_hw *hw, bool state) -{ - struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543; - - DEBUGFUNC("e1000_set_tbi_sbp_82543"); - - if (state && e1000_tbi_compatibility_enabled_82543(hw)) - dev_spec->tbi_compatibility |= TBI_SBP_ENABLED; - else - dev_spec->tbi_compatibility &= ~TBI_SBP_ENABLED; - - return; -} - -/** - * e1000_init_phy_disabled_82543 - Returns init PHY status - * @hw: pointer to the HW structure - * - * Returns the current status of whether PHY initialization is disabled. - * True if PHY initialization is disabled else false. - **/ -static bool e1000_init_phy_disabled_82543(struct e1000_hw *hw) -{ - struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543; - bool ret_val; - - DEBUGFUNC("e1000_init_phy_disabled_82543"); - - if (hw->mac.type != e1000_82543) { - ret_val = false; - goto out; - } - - ret_val = dev_spec->init_phy_disabled; - -out: - return ret_val; -} - -#if 0 -/** - * e1000_tbi_adjust_stats_82543 - Adjust stats when TBI enabled - * @hw: pointer to the HW structure - * @stats: Struct containing statistic register values - * @frame_len: The length of the frame in question - * @mac_addr: The Ethernet destination address of the frame in question - * @max_frame_size: The maximum frame size - * - * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT - **/ -void e1000_tbi_adjust_stats_82543(struct e1000_hw *hw, - struct e1000_hw_stats *stats, u32 frame_len, - u8 *mac_addr, u32 max_frame_size) -{ - if (!(e1000_tbi_sbp_enabled_82543(hw))) - goto out; - - /* First adjust the frame length. */ - frame_len--; - /* - * We need to adjust the statistics counters, since the hardware - * counters overcount this packet as a CRC error and undercount - * the packet as a good packet - */ - /* This packet should not be counted as a CRC error. */ - stats->crcerrs--; - /* This packet does count as a Good Packet Received. */ - stats->gprc++; - - /* Adjust the Good Octets received counters */ - stats->gorc += frame_len; - - /* - * Is this a broadcast or multicast? Check broadcast first, - * since the test for a multicast frame will test positive on - * a broadcast frame. - */ - if ((mac_addr[0] == 0xff) && (mac_addr[1] == 0xff)) - /* Broadcast packet */ - stats->bprc++; - else if (*mac_addr & 0x01) - /* Multicast packet */ - stats->mprc++; - - /* - * In this case, the hardware has overcounted the number of - * oversize frames. - */ - if ((frame_len == max_frame_size) && (stats->roc > 0)) - stats->roc--; - - /* - * Adjust the bin counters when the extra byte put the frame in the - * wrong bin. Remember that the frame_len was adjusted above. - */ - if (frame_len == 64) { - stats->prc64++; - stats->prc127--; - } else if (frame_len == 127) { - stats->prc127++; - stats->prc255--; - } else if (frame_len == 255) { - stats->prc255++; - stats->prc511--; - } else if (frame_len == 511) { - stats->prc511++; - stats->prc1023--; - } else if (frame_len == 1023) { - stats->prc1023++; - stats->prc1522--; - } else if (frame_len == 1522) { - stats->prc1522++; - } - -out: - return; -} -#endif - -/** - * e1000_read_phy_reg_82543 - Read PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY at offset and stores the information read to data. - **/ -static s32 e1000_read_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 *data) -{ - u32 mdic; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_read_phy_reg_82543"); - - if (offset > MAX_PHY_REG_ADDRESS) { - DEBUGOUT1("PHY Address %d is out of range\n", offset); - ret_val = -E1000_ERR_PARAM; - goto out; - } - - /* - * We must first send a preamble through the MDIO pin to signal the - * beginning of an MII instruction. This is done by sending 32 - * consecutive "1" bits. - */ - e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); - - /* - * Now combine the next few fields that are required for a read - * operation. We use this method instead of calling the - * e1000_shift_out_mdi_bits routine five different times. The format - * of an MII read instruction consists of a shift out of 14 bits and - * is defined as follows: - * - * followed by a shift in of 18 bits. This first two bits shifted in - * are TurnAround bits used to avoid contention on the MDIO pin when a - * READ operation is performed. These two bits are thrown away - * followed by a shift in of 16 bits which contains the desired data. - */ - mdic = (offset | (hw->phy.addr << 5) | - (PHY_OP_READ << 10) | (PHY_SOF << 12)); - - e1000_shift_out_mdi_bits_82543(hw, mdic, 14); - - /* - * Now that we've shifted out the read command to the MII, we need to - * "shift in" the 16-bit value (18 total bits) of the requested PHY - * register address. - */ - *data = e1000_shift_in_mdi_bits_82543(hw); - -out: - return ret_val; -} - -/** - * e1000_write_phy_reg_82543 - Write PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be written - * @data: pointer to the data to be written at offset - * - * Writes data to the PHY at offset. - **/ -static s32 e1000_write_phy_reg_82543(struct e1000_hw *hw, u32 offset, u16 data) -{ - u32 mdic; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_write_phy_reg_82543"); - - if (offset > MAX_PHY_REG_ADDRESS) { - DEBUGOUT1("PHY Address %d is out of range\n", offset); - ret_val = -E1000_ERR_PARAM; - goto out; - } - - /* - * We'll need to use the SW defined pins to shift the write command - * out to the PHY. We first send a preamble to the PHY to signal the - * beginning of the MII instruction. This is done by sending 32 - * consecutive "1" bits. - */ - e1000_shift_out_mdi_bits_82543(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE); - - /* - * Now combine the remaining required fields that will indicate a - * write operation. We use this method instead of calling the - * e1000_shift_out_mdi_bits routine for each field in the command. The - * format of a MII write instruction is as follows: - * . - */ - mdic = ((PHY_TURNAROUND) | (offset << 2) | (hw->phy.addr << 7) | - (PHY_OP_WRITE << 12) | (PHY_SOF << 14)); - mdic <<= 16; - mdic |= (u32) data; - - e1000_shift_out_mdi_bits_82543(hw, mdic, 32); - -out: - return ret_val; -} - -/** - * e1000_raise_mdi_clk_82543 - Raise Management Data Input clock - * @hw: pointer to the HW structure - * @ctrl: pointer to the control register - * - * Raise the management data input clock by setting the MDC bit in the control - * register. - **/ -static void e1000_raise_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl) -{ - /* - * Raise the clock input to the Management Data Clock (by setting the - * MDC bit), and then delay a sufficient amount of time. - */ - E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl | E1000_CTRL_MDC)); - E1000_WRITE_FLUSH(hw); - usec_delay(10); -} - -/** - * e1000_lower_mdi_clk_82543 - Lower Management Data Input clock - * @hw: pointer to the HW structure - * @ctrl: pointer to the control register - * - * Lower the management data input clock by clearing the MDC bit in the - * control register. - **/ -static void e1000_lower_mdi_clk_82543(struct e1000_hw *hw, u32 *ctrl) -{ - /* - * Lower the clock input to the Management Data Clock (by clearing the - * MDC bit), and then delay a sufficient amount of time. - */ - E1000_WRITE_REG(hw, E1000_CTRL, (*ctrl & ~E1000_CTRL_MDC)); - E1000_WRITE_FLUSH(hw); - usec_delay(10); -} - -/** - * e1000_shift_out_mdi_bits_82543 - Shift data bits our to the PHY - * @hw: pointer to the HW structure - * @data: data to send to the PHY - * @count: number of bits to shift out - * - * We need to shift 'count' bits out to the PHY. So, the value in the - * "data" parameter will be shifted out to the PHY one bit at a time. - * In order to do this, "data" must be broken down into bits. - **/ -static void e1000_shift_out_mdi_bits_82543(struct e1000_hw *hw, u32 data, - u16 count) -{ - u32 ctrl, mask; - - /* - * We need to shift "count" number of bits out to the PHY. So, the - * value in the "data" parameter will be shifted out to the PHY one - * bit at a time. In order to do this, "data" must be broken down - * into bits. - */ - mask = 0x01; - mask <<= (count -1); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */ - ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR); - - while (mask) { - /* - * A "1" is shifted out to the PHY by setting the MDIO bit to - * "1" and then raising and lowering the Management Data Clock. - * A "0" is shifted out to the PHY by setting the MDIO bit to - * "0" and then raising and lowering the clock. - */ - if (data & mask) ctrl |= E1000_CTRL_MDIO; - else ctrl &= ~E1000_CTRL_MDIO; - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - E1000_WRITE_FLUSH(hw); - - usec_delay(10); - - e1000_raise_mdi_clk_82543(hw, &ctrl); - e1000_lower_mdi_clk_82543(hw, &ctrl); - - mask >>= 1; - } -} - -/** - * e1000_shift_in_mdi_bits_82543 - Shift data bits in from the PHY - * @hw: pointer to the HW structure - * - * In order to read a register from the PHY, we need to shift 18 bits - * in from the PHY. Bits are "shifted in" by raising the clock input to - * the PHY (setting the MDC bit), and then reading the value of the data out - * MDIO bit. - **/ -static u16 e1000_shift_in_mdi_bits_82543(struct e1000_hw *hw) -{ - u32 ctrl; - u16 data = 0; - u8 i; - - /* - * In order to read a register from the PHY, we need to shift in a - * total of 18 bits from the PHY. The first two bit (turnaround) - * times are used to avoid contention on the MDIO pin when a read - * operation is performed. These two bits are ignored by us and - * thrown away. Bits are "shifted in" by raising the input to the - * Management Data Clock (setting the MDC bit) and then reading the - * value of the MDIO bit. - */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* - * Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as - * input. - */ - ctrl &= ~E1000_CTRL_MDIO_DIR; - ctrl &= ~E1000_CTRL_MDIO; - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - E1000_WRITE_FLUSH(hw); - - /* - * Raise and lower the clock before reading in the data. This accounts - * for the turnaround bits. The first clock occurred when we clocked - * out the last bit of the Register Address. - */ - e1000_raise_mdi_clk_82543(hw, &ctrl); - e1000_lower_mdi_clk_82543(hw, &ctrl); - - for (data = 0, i = 0; i < 16; i++) { - data <<= 1; - e1000_raise_mdi_clk_82543(hw, &ctrl); - ctrl = E1000_READ_REG(hw, E1000_CTRL); - /* Check to see if we shifted in a "1". */ - if (ctrl & E1000_CTRL_MDIO) - data |= 1; - e1000_lower_mdi_clk_82543(hw, &ctrl); - } - - e1000_raise_mdi_clk_82543(hw, &ctrl); - e1000_lower_mdi_clk_82543(hw, &ctrl); - - return data; -} - -#if 0 -/** - * e1000_phy_force_speed_duplex_82543 - Force speed/duplex for PHY - * @hw: pointer to the HW structure - * - * Calls the function to force speed and duplex for the m88 PHY, and - * if the PHY is not auto-negotiating and the speed is forced to 10Mbit, - * then call the function for polarity reversal workaround. - **/ -static s32 e1000_phy_force_speed_duplex_82543(struct e1000_hw *hw) -{ - s32 ret_val; - - DEBUGFUNC("e1000_phy_force_speed_duplex_82543"); - - ret_val = e1000_phy_force_speed_duplex_m88(hw); - if (ret_val) - goto out; - - if (!hw->mac.autoneg && - (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)) - ret_val = e1000_polarity_reversal_workaround_82543(hw); - -out: - return ret_val; -} -#endif - -/** - * e1000_polarity_reversal_workaround_82543 - Workaround polarity reversal - * @hw: pointer to the HW structure - * - * When forcing link to 10 Full or 10 Half, the PHY can reverse the polarity - * inadvertently. To workaround the issue, we disable the transmitter on - * the PHY until we have established the link partner's link parameters. - **/ -static s32 e1000_polarity_reversal_workaround_82543(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 mii_status_reg; - u16 i; - bool link; - - if (!(hw->phy.ops.write_reg)) - goto out; - - /* Polarity reversal workaround for forced 10F/10H links. */ - - /* Disable the transmitter on the PHY */ - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); - if (ret_val) - goto out; - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000); - if (ret_val) - goto out; - - /* - * This loop will early-out if the NO link condition has been met. - * In other words, DO NOT use e1000_phy_has_link_generic() here. - */ - for (i = PHY_FORCE_TIME; i > 0; i--) { - /* - * Read the MII Status Register and wait for Link Status bit - * to be clear. - */ - - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - - if ((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) - break; - msec_delay_irq(100); - } - - /* Recommended delay time after link has been lost */ - msec_delay_irq(1000); - - /* Now we will re-enable the transmitter on the PHY */ - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019); - if (ret_val) - goto out; - msec_delay_irq(50); - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0); - if (ret_val) - goto out; - msec_delay_irq(50); - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00); - if (ret_val) - goto out; - msec_delay_irq(50); - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000); - if (ret_val) - goto out; - - /* - * Read the MII Status Register and wait for Link Status bit - * to be set. - */ - ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_TIME, 100000, &link); - if (ret_val) - goto out; - -out: - return ret_val; -} - -/** - * e1000_phy_hw_reset_82543 - PHY hardware reset - * @hw: pointer to the HW structure - * - * Sets the PHY_RESET_DIR bit in the extended device control register - * to put the PHY into a reset and waits for completion. Once the reset - * has been accomplished, clear the PHY_RESET_DIR bit to take the PHY out - * of reset. - **/ -static s32 e1000_phy_hw_reset_82543(struct e1000_hw *hw) -{ - u32 ctrl_ext; - s32 ret_val; - - DEBUGFUNC("e1000_phy_hw_reset_82543"); - - /* - * Read the Extended Device Control Register, assert the PHY_RESET_DIR - * bit to put the PHY into reset... - */ - ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR; - ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - E1000_WRITE_FLUSH(hw); - - msec_delay(10); - - /* ...then take it out of reset. */ - ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - E1000_WRITE_FLUSH(hw); - - usec_delay(150); - - if (!(hw->phy.ops.get_cfg_done)) - return E1000_SUCCESS; - - ret_val = hw->phy.ops.get_cfg_done(hw); - - return ret_val; -} - -/** - * e1000_reset_hw_82543 - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. - **/ -static s32 e1000_reset_hw_82543(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_reset_hw_82543"); - - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); - - E1000_WRITE_REG(hw, E1000_RCTL, 0); - E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); - E1000_WRITE_FLUSH(hw); - - e1000_set_tbi_sbp_82543(hw, false); - - /* - * Delay to allow any outstanding PCI transactions to complete before - * resetting the device - */ - msec_delay(10); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGOUT("Issuing a global reset to 82543/82544 MAC\n"); - if (hw->mac.type == e1000_82543) { - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); - } else { - /* - * The 82544 can't ACK the 64-bit write when issuing the - * reset, so use IO-mapping as a workaround. - */ - E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); - } - - /* - * After MAC reset, force reload of NVM to restore power-on - * settings to device. - */ - hw->nvm.ops.reload(hw); - msec_delay(2); - - /* Masking off and clearing any pending interrupts */ - E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); - E1000_READ_REG(hw, E1000_ICR); - - return ret_val; -} - -/** - * e1000_init_hw_82543 - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. - **/ -static s32 e1000_init_hw_82543(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - struct e1000_dev_spec_82543 *dev_spec = &hw->dev_spec._82543; - u32 ctrl; - s32 ret_val; - u16 i; - - DEBUGFUNC("e1000_init_hw_82543"); - - /* Disabling VLAN filtering */ - E1000_WRITE_REG(hw, E1000_VET, 0); - mac->ops.clear_vfta(hw); - - /* Setup the receive address. */ - e1000_init_rx_addrs_generic(hw, mac->rar_entry_count); - - /* Zero out the Multicast HASH table */ - DEBUGOUT("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) { - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - E1000_WRITE_FLUSH(hw); - } - - /* - * Set the PCI priority bit correctly in the CTRL register. This - * determines if the adapter gives priority to receives, or if it - * gives equal priority to transmits and receives. - */ - if (hw->mac.type == e1000_82543 && dev_spec->dma_fairness) { - ctrl = E1000_READ_REG(hw, E1000_CTRL); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PRIOR); - } - - e1000_pcix_mmrbc_workaround_generic(hw); - - /* Setup link and flow control */ - ret_val = mac->ops.setup_link(hw); - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - e1000_clear_hw_cntrs_82543(hw); - - return ret_val; -} - -/** - * e1000_setup_link_82543 - Setup flow control and link settings - * @hw: pointer to the HW structure - * - * Read the EEPROM to determine the initial polarity value and write the - * extended device control register with the information before calling - * the generic setup link function, which does the following: - * Determines which flow control settings to use, then configures flow - * control. Calls the appropriate media-specific link configuration - * function. Assuming the adapter has a valid link partner, a valid link - * should be established. Assumes the hardware has previously been reset - * and the transmitter and receiver are not enabled. - **/ -static s32 e1000_setup_link_82543(struct e1000_hw *hw) -{ - u32 ctrl_ext; - s32 ret_val; - u16 data; - - DEBUGFUNC("e1000_setup_link_82543"); - - /* - * Take the 4 bits from NVM word 0xF that determine the initial - * polarity value for the SW controlled pins, and setup the - * Extended Device Control reg with that info. - * This is needed because one of the SW controlled pins is used for - * signal detection. So this should be done before phy setup. - */ - if (hw->mac.type == e1000_82543) { - ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - ctrl_ext = ((data & NVM_WORD0F_SWPDIO_EXT_MASK) << - NVM_SWDPIO_EXT_SHIFT); - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - } - - ret_val = e1000_setup_link_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_setup_copper_link_82543 - Configure copper link settings - * @hw: pointer to the HW structure - * - * Configures the link for auto-neg or forced speed and duplex. Then we check - * for link, once link is established calls to configure collision distance - * and flow control are called. - **/ -static s32 e1000_setup_copper_link_82543(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - bool link; - - DEBUGFUNC("e1000_setup_copper_link_82543"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL) | E1000_CTRL_SLU; - /* - * With 82543, we need to force speed and duplex on the MAC - * equal to what the PHY speed and duplex configuration is. - * In addition, we need to perform a hardware reset on the - * PHY to take it out of reset. - */ - if (hw->mac.type == e1000_82543) { - ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - ret_val = hw->phy.ops.reset(hw); - if (ret_val) - goto out; - hw->phy.reset_disable = false; - } else { - ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - } - - /* Set MDI/MDI-X, Polarity Reversal, and downshift settings */ - ret_val = e1000_copper_link_setup_m88(hw); - if (ret_val) - goto out; - - if (hw->mac.autoneg) { - /* - * Setup autoneg and flow control advertisement and perform - * autonegotiation. - */ - ret_val = e1000_copper_link_autoneg(hw); - if (ret_val) - goto out; - } else { - /* - * PHY will be set to 10H, 10F, 100H or 100F - * depending on user settings. - */ -#if 0 - DEBUGOUT("Forcing Speed and Duplex\n"); - ret_val = e1000_phy_force_speed_duplex_82543(hw); - if (ret_val) { - DEBUGOUT("Error Forcing Speed and Duplex\n"); - goto out; - } -#endif - } - - /* - * Check link status. Wait up to 100 microseconds for link to become - * valid. - */ - ret_val = e1000_phy_has_link_generic(hw, - COPPER_LINK_UP_LIMIT, - 10, - &link); - if (ret_val) - goto out; - - - if (link) { - DEBUGOUT("Valid link established!!!\n"); - /* Config the MAC and PHY after link is up */ - if (hw->mac.type == e1000_82544) { - e1000_config_collision_dist_generic(hw); - } else { - ret_val = e1000_config_mac_to_phy_82543(hw); - if (ret_val) - goto out; - } - ret_val = e1000_config_fc_after_link_up_generic(hw); - } else { - DEBUGOUT("Unable to establish link!!!\n"); - } - -out: - return ret_val; -} - -/** - * e1000_setup_fiber_link_82543 - Setup link for fiber - * @hw: pointer to the HW structure - * - * Configures collision distance and flow control for fiber links. Upon - * successful setup, poll for link. - **/ -static s32 e1000_setup_fiber_link_82543(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - - DEBUGFUNC("e1000_setup_fiber_link_82543"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* Take the link out of reset */ - ctrl &= ~E1000_CTRL_LRST; - - e1000_config_collision_dist_generic(hw); - - ret_val = e1000_commit_fc_settings_generic(hw); - if (ret_val) - goto out; - - DEBUGOUT("Auto-negotiation enabled\n"); - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - E1000_WRITE_FLUSH(hw); - msec_delay(1); - - /* - * For these adapters, the SW definable pin 1 is cleared when the - * optics detect a signal. If we have a signal, then poll for a - * "Link-Up" indication. - */ - if (!(E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) { - ret_val = e1000_poll_fiber_serdes_link_generic(hw); - } else { - DEBUGOUT("No signal detected\n"); - } - -out: - return ret_val; -} - -/** - * e1000_check_for_copper_link_82543 - Check for link (Copper) - * @hw: pointer to the HW structure - * - * Checks the phy for link, if link exists, do the following: - * - check for downshift - * - do polarity workaround (if necessary) - * - configure collision distance - * - configure flow control after link up - * - configure tbi compatibility - **/ -static s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 icr, rctl; - s32 ret_val; - u16 speed, duplex; - bool link; - - DEBUGFUNC("e1000_check_for_copper_link_82543"); - - if (!mac->get_link_status) { - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) - goto out; /* No link detected */ - - mac->get_link_status = false; - - e1000_check_downshift_generic(hw); - - /* - * If we are forcing speed/duplex, then we can return since - * we have already determined whether we have link or not. - */ - if (!mac->autoneg) { - /* - * If speed and duplex are forced to 10H or 10F, then we will - * implement the polarity reversal workaround. We disable - * interrupts first, and upon returning, place the devices - * interrupt state to its previous value except for the link - * status change interrupt which will happened due to the - * execution of this workaround. - */ - if (mac->forced_speed_duplex & E1000_ALL_10_SPEED) { - E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF); - ret_val = e1000_polarity_reversal_workaround_82543(hw); - icr = E1000_READ_REG(hw, E1000_ICR); - E1000_WRITE_REG(hw, E1000_ICS, (icr & ~E1000_ICS_LSC)); - E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK); - } - - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - /* - * We have a M88E1000 PHY and Auto-Neg is enabled. If we - * have Si on board that is 82544 or newer, Auto - * Speed Detection takes care of MAC speed/duplex - * configuration. So we only need to configure Collision - * Distance in the MAC. Otherwise, we need to force - * speed/duplex on the MAC to the current PHY speed/duplex - * settings. - */ - if (mac->type == e1000_82544) - e1000_config_collision_dist_generic(hw); - else { - ret_val = e1000_config_mac_to_phy_82543(hw); - if (ret_val) { - DEBUGOUT("Error configuring MAC to PHY settings\n"); - goto out; - } - } - - /* - * Configure Flow Control now that Auto-Neg has completed. - * First, we need to restore the desired flow control - * settings because we may have had to re-autoneg with a - * different link partner. - */ - ret_val = e1000_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - } - - /* - * At this point we know that we are on copper and we have - * auto-negotiated link. These are conditions for checking the link - * partner capability register. We use the link speed to determine if - * TBI compatibility needs to be turned on or off. If the link is not - * at gigabit speed, then TBI compatibility is not needed. If we are - * at gigabit speed, we turn on TBI compatibility. - */ - if (e1000_tbi_compatibility_enabled_82543(hw)) { - ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); - if (ret_val) { - DEBUGOUT("Error getting link speed and duplex\n"); - return ret_val; - } - if (speed != SPEED_1000) { - /* - * If link speed is not set to gigabit speed, - * we do not need to enable TBI compatibility. - */ - if (e1000_tbi_sbp_enabled_82543(hw)) { - /* - * If we previously were in the mode, - * turn it off. - */ - e1000_set_tbi_sbp_82543(hw, false); - rctl = E1000_READ_REG(hw, E1000_RCTL); - rctl &= ~E1000_RCTL_SBP; - E1000_WRITE_REG(hw, E1000_RCTL, rctl); - } - } else { - /* - * If TBI compatibility is was previously off, - * turn it on. For compatibility with a TBI link - * partner, we will store bad packets. Some - * frames have an additional byte on the end and - * will look like CRC errors to to the hardware. - */ - if (!e1000_tbi_sbp_enabled_82543(hw)) { - e1000_set_tbi_sbp_82543(hw, true); - rctl = E1000_READ_REG(hw, E1000_RCTL); - rctl |= E1000_RCTL_SBP; - E1000_WRITE_REG(hw, E1000_RCTL, rctl); - } - } - } -out: - return ret_val; -} - -/** - * e1000_check_for_fiber_link_82543 - Check for link (Fiber) - * @hw: pointer to the HW structure - * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. - **/ -static s32 e1000_check_for_fiber_link_82543(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw, ctrl, status; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_check_for_fiber_link_82543"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - status = E1000_READ_REG(hw, E1000_STATUS); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - - /* - * If we don't have link (auto-negotiation failed or link partner - * cannot auto-negotiate), the cable is plugged in (we have signal), - * and our link partner is not trying to auto-negotiate with us (we - * are receiving idles or data), we need to force link up. We also - * need to give auto-negotiation time to complete, in case the cable - * was just plugged in. The autoneg_failed flag does this. - */ - /* (ctrl & E1000_CTRL_SWDPIN1) == 0 == have signal */ - if ((!(ctrl & E1000_CTRL_SWDPIN1)) && - (!(status & E1000_STATUS_LU)) && - (!(rxcw & E1000_RXCW_C))) { - if (mac->autoneg_failed == 0) { - mac->autoneg_failed = 1; - ret_val = 0; - goto out; - } - DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); - - /* Disable auto-negotiation in the TXCW register */ - E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); - - /* Force link-up and also force full-duplex. */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - /* Configure Flow Control after forcing link up. */ - ret_val = e1000_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - goto out; - } - } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - /* - * If we are forcing link and we are receiving /C/ ordered - * sets, re-enable auto-negotiation in the TXCW register - * and disable forced link in the Device Control register - * in an attempt to auto-negotiate with our link partner. - */ - DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); - E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); - E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); - - mac->serdes_has_link = true; - } - -out: - return ret_val; -} - -/** - * e1000_config_mac_to_phy_82543 - Configure MAC to PHY settings - * @hw: pointer to the HW structure - * - * For the 82543 silicon, we need to set the MAC to match the settings - * of the PHY, even if the PHY is auto-negotiating. - **/ -static s32 e1000_config_mac_to_phy_82543(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - u16 phy_data; - - DEBUGFUNC("e1000_config_mac_to_phy_82543"); - - if (!(hw->phy.ops.read_reg)) - goto out; - - /* Set the bits to force speed and duplex */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS); - - /* - * Set up duplex in the Device Control and Transmit Control - * registers depending on negotiated values. - */ - ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if (ret_val) - goto out; - - ctrl &= ~E1000_CTRL_FD; - if (phy_data & M88E1000_PSSR_DPLX) - ctrl |= E1000_CTRL_FD; - - e1000_config_collision_dist_generic(hw); - - /* - * Set up speed in the Device Control register depending on - * negotiated values. - */ - if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) - ctrl |= E1000_CTRL_SPD_1000; - else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS) - ctrl |= E1000_CTRL_SPD_100; - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - -out: - return ret_val; -} - -/** - * e1000_write_vfta_82543 - Write value to VLAN filter table - * @hw: pointer to the HW structure - * @offset: the 32-bit offset in which to write the value to. - * @value: the 32-bit value to write at location offset. - * - * This writes a 32-bit value to a 32-bit offset in the VLAN filter - * table. - **/ -static void e1000_write_vfta_82543(struct e1000_hw *hw, u32 offset, u32 value) -{ - u32 temp; - - DEBUGFUNC("e1000_write_vfta_82543"); - - if ((hw->mac.type == e1000_82544) && (offset & 1)) { - temp = E1000_READ_REG_ARRAY(hw, E1000_VFTA, offset - 1); - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); - E1000_WRITE_FLUSH(hw); - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset - 1, temp); - E1000_WRITE_FLUSH(hw); - } else { - e1000_write_vfta_generic(hw, offset, value); - } -} - -/** - * e1000_mta_set_82543 - Set multicast filter table address - * @hw: pointer to the HW structure - * @hash_value: determines the MTA register and bit to set - * - * The multicast table address is a register array of 32-bit registers. - * The hash_value is used to determine what register the bit is in, the - * current value is read, the new bit is OR'd in and the new value is - * written back into the register. - **/ -static void e1000_mta_set_82543(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg, mta, temp; - - DEBUGFUNC("e1000_mta_set_82543"); - - hash_reg = (hash_value >> 5); - - /* - * If we are on an 82544 and we are trying to write an odd offset - * in the MTA, save off the previous entry before writing and - * restore the old value after writing. - */ - if ((hw->mac.type == e1000_82544) && (hash_reg & 1)) { - hash_reg &= (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); - mta |= (1 << hash_bit); - temp = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg - 1); - - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); - E1000_WRITE_FLUSH(hw); - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg - 1, temp); - E1000_WRITE_FLUSH(hw); - } else { - e1000_mta_set_generic(hw, hash_value); - } -} - -/** - * e1000_led_on_82543 - Turn on SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED on. - **/ -static s32 e1000_led_on_82543(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGFUNC("e1000_led_on_82543"); - - if (hw->mac.type == e1000_82544 && - hw->phy.media_type == e1000_media_type_copper) { - /* Clear SW-definable Pin 0 to turn on the LED */ - ctrl &= ~E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - } else { - /* Fiber 82544 and all 82543 use this method */ - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - } - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_led_off_82543 - Turn off SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED off. - **/ -static s32 e1000_led_off_82543(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGFUNC("e1000_led_off_82543"); - - if (hw->mac.type == e1000_82544 && - hw->phy.media_type == e1000_media_type_copper) { - /* Set SW-definable Pin 0 to turn off the LED */ - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - } else { - ctrl &= ~E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - } - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_clear_hw_cntrs_82543 - Clear device specific hardware counters - * @hw: pointer to the HW structure - * - * Clears the hardware counters by reading the counter registers. - **/ -static void e1000_clear_hw_cntrs_82543(struct e1000_hw *hw) -{ - DEBUGFUNC("e1000_clear_hw_cntrs_82543"); - - e1000_clear_hw_cntrs_base_generic(hw); - -#if 0 - E1000_READ_REG(hw, E1000_PRC64); - E1000_READ_REG(hw, E1000_PRC127); - E1000_READ_REG(hw, E1000_PRC255); - E1000_READ_REG(hw, E1000_PRC511); - E1000_READ_REG(hw, E1000_PRC1023); - E1000_READ_REG(hw, E1000_PRC1522); - E1000_READ_REG(hw, E1000_PTC64); - E1000_READ_REG(hw, E1000_PTC127); - E1000_READ_REG(hw, E1000_PTC255); - E1000_READ_REG(hw, E1000_PTC511); - E1000_READ_REG(hw, E1000_PTC1023); - E1000_READ_REG(hw, E1000_PTC1522); - - E1000_READ_REG(hw, E1000_ALGNERRC); - E1000_READ_REG(hw, E1000_RXERRC); - E1000_READ_REG(hw, E1000_TNCRS); - E1000_READ_REG(hw, E1000_CEXTERR); - E1000_READ_REG(hw, E1000_TSCTC); - E1000_READ_REG(hw, E1000_TSCTFC); -#endif -} - -static struct pci_device_id e1000_82543_nics[] = { - PCI_ROM(0x8086, 0x1001, "E1000_DEV_ID_82543GC_FIBER", "E1000_DEV_ID_82543GC_FIBER", e1000_82543), - PCI_ROM(0x8086, 0x1004, "E1000_DEV_ID_82543GC_COPPER", "E1000_DEV_ID_82543GC_COPPER", e1000_82543), - PCI_ROM(0x8086, 0x1008, "E1000_DEV_ID_82544EI_COPPER", "E1000_DEV_ID_82544EI_COPPER", e1000_82544), - PCI_ROM(0x8086, 0x1009, "E1000_DEV_ID_82544EI_FIBER", "E1000_DEV_ID_82544EI_FIBER", e1000_82544), - PCI_ROM(0x8086, 0x100C, "E1000_DEV_ID_82544GC_COPPER", "E1000_DEV_ID_82544GC_COPPER", e1000_82544), - PCI_ROM(0x8086, 0x100D, "E1000_DEV_ID_82544GC_LOM", "E1000_DEV_ID_82544GC_LOM", e1000_82544), -}; - -struct pci_driver e1000_82543_driver __pci_driver = { - .ids = e1000_82543_nics, - .id_count = (sizeof (e1000_82543_nics) / sizeof (e1000_82543_nics[0])), - .probe = e1000_probe, - .remove = e1000_remove, -}; diff --git a/src/drivers/net/e1000/e1000_82543.h b/src/drivers/net/e1000/e1000_82543.h deleted file mode 100644 index 30073e8b..00000000 --- a/src/drivers/net/e1000/e1000_82543.h +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_82543_H_ -#define _E1000_82543_H_ - -#define PHY_PREAMBLE 0xFFFFFFFF -#define PHY_PREAMBLE_SIZE 32 -#define PHY_SOF 0x1 -#define PHY_OP_READ 0x2 -#define PHY_OP_WRITE 0x1 -#define PHY_TURNAROUND 0x2 - -#define TBI_COMPAT_ENABLED 0x1 /* Global "knob" for the workaround */ -/* If TBI_COMPAT_ENABLED, then this is the current state (on/off) */ -#define TBI_SBP_ENABLED 0x2 - -#endif diff --git a/src/drivers/net/e1000/e1000_api.c b/src/drivers/net/e1000/e1000_api.c deleted file mode 100644 index 72aac4c4..00000000 --- a/src/drivers/net/e1000/e1000_api.c +++ /dev/null @@ -1,1108 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000_api.h" - -/** - * e1000_init_mac_params - Initialize MAC function pointers - * @hw: pointer to the HW structure - * - * This function initializes the function pointers for the MAC - * set of functions. Called by drivers or by e1000_setup_init_funcs. - **/ -s32 e1000_init_mac_params(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->mac.ops.init_params) { - ret_val = hw->mac.ops.init_params(hw); - if (ret_val) { - DEBUGOUT("MAC Initialization Error\n"); - goto out; - } - } else { - DEBUGOUT("mac.init_mac_params was NULL\n"); - ret_val = -E1000_ERR_CONFIG; - } - -out: - return ret_val; -} - -/** - * e1000_init_nvm_params - Initialize NVM function pointers - * @hw: pointer to the HW structure - * - * This function initializes the function pointers for the NVM - * set of functions. Called by drivers or by e1000_setup_init_funcs. - **/ -s32 e1000_init_nvm_params(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->nvm.ops.init_params) { - ret_val = hw->nvm.ops.init_params(hw); - if (ret_val) { - DEBUGOUT("NVM Initialization Error\n"); - goto out; - } - } else { - DEBUGOUT("nvm.init_nvm_params was NULL\n"); - ret_val = -E1000_ERR_CONFIG; - } - -out: - return ret_val; -} - -/** - * e1000_init_phy_params - Initialize PHY function pointers - * @hw: pointer to the HW structure - * - * This function initializes the function pointers for the PHY - * set of functions. Called by drivers or by e1000_setup_init_funcs. - **/ -s32 e1000_init_phy_params(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->phy.ops.init_params) { - ret_val = hw->phy.ops.init_params(hw); - if (ret_val) { - DEBUGOUT("PHY Initialization Error\n"); - goto out; - } - } else { - DEBUGOUT("phy.init_phy_params was NULL\n"); - ret_val = -E1000_ERR_CONFIG; - } - -out: - return ret_val; -} - -/** - * e1000_set_mac_type - Sets MAC type - * @hw: pointer to the HW structure - * - * This function sets the mac type of the adapter based on the - * device ID stored in the hw structure. - * MUST BE FIRST FUNCTION CALLED (explicitly or through - * e1000_setup_init_funcs()). - **/ -s32 e1000_set_mac_type(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_set_mac_type"); - - switch (hw->device_id) { - case E1000_DEV_ID_82542: - mac->type = e1000_82542; - break; - case E1000_DEV_ID_82543GC_FIBER: - case E1000_DEV_ID_82543GC_COPPER: - mac->type = e1000_82543; - break; - case E1000_DEV_ID_82544EI_COPPER: - case E1000_DEV_ID_82544EI_FIBER: - case E1000_DEV_ID_82544GC_COPPER: - case E1000_DEV_ID_82544GC_LOM: - mac->type = e1000_82544; - break; - case E1000_DEV_ID_82540EM: - case E1000_DEV_ID_82540EM_LOM: - case E1000_DEV_ID_82540EP: - case E1000_DEV_ID_82540EP_LOM: - case E1000_DEV_ID_82540EP_LP: - mac->type = e1000_82540; - break; - case E1000_DEV_ID_82545EM_COPPER: - case E1000_DEV_ID_82545EM_FIBER: - mac->type = e1000_82545; - break; - case E1000_DEV_ID_82545GM_COPPER: - case E1000_DEV_ID_82545GM_FIBER: - case E1000_DEV_ID_82545GM_SERDES: - mac->type = e1000_82545_rev_3; - break; - case E1000_DEV_ID_82546EB_COPPER: - case E1000_DEV_ID_82546EB_FIBER: - case E1000_DEV_ID_82546EB_QUAD_COPPER: - mac->type = e1000_82546; - break; - case E1000_DEV_ID_82546GB_COPPER: - case E1000_DEV_ID_82546GB_FIBER: - case E1000_DEV_ID_82546GB_SERDES: - case E1000_DEV_ID_82546GB_PCIE: - case E1000_DEV_ID_82546GB_QUAD_COPPER: - case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: - mac->type = e1000_82546_rev_3; - break; - case E1000_DEV_ID_82541EI: - case E1000_DEV_ID_82541EI_MOBILE: - case E1000_DEV_ID_82541ER_LOM: - mac->type = e1000_82541; - break; - case E1000_DEV_ID_82541ER: - case E1000_DEV_ID_82541GI: - case E1000_DEV_ID_82541GI_LF: - case E1000_DEV_ID_82541GI_MOBILE: - mac->type = e1000_82541_rev_2; - break; - case E1000_DEV_ID_82547EI: - case E1000_DEV_ID_82547EI_MOBILE: - mac->type = e1000_82547; - break; - case E1000_DEV_ID_82547GI: - mac->type = e1000_82547_rev_2; - break; - default: - /* Should never have loaded on this device */ - ret_val = -E1000_ERR_MAC_INIT; - break; - } - - return ret_val; -} - -/** - * e1000_setup_init_funcs - Initializes function pointers - * @hw: pointer to the HW structure - * @init_device: true will initialize the rest of the function pointers - * getting the device ready for use. false will only set - * MAC type and the function pointers for the other init - * functions. Passing false will not generate any hardware - * reads or writes. - * - * This function must be called by a driver in order to use the rest - * of the 'shared' code files. Called by drivers only. - **/ -s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device) -{ - s32 ret_val; - - /* Can't do much good without knowing the MAC type. */ - ret_val = e1000_set_mac_type(hw); - if (ret_val) { - DEBUGOUT("ERROR: MAC type could not be set properly.\n"); - goto out; - } - - if (!hw->hw_addr) { - DEBUGOUT("ERROR: Registers not mapped\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - /* - * Init function pointers to generic implementations. We do this first - * allowing a driver module to override it afterward. - */ - e1000_init_mac_ops_generic(hw); - e1000_init_phy_ops_generic(hw); - e1000_init_nvm_ops_generic(hw); - - /* - * Set up the init function pointers. These are functions within the - * adapter family file that sets up function pointers for the rest of - * the functions in that family. - */ - switch (hw->mac.type) { - case e1000_82542: - e1000_init_function_pointers_82542(hw); - break; - case e1000_82543: - case e1000_82544: - e1000_init_function_pointers_82543(hw); - break; - case e1000_82540: - case e1000_82545: - case e1000_82545_rev_3: - case e1000_82546: - case e1000_82546_rev_3: - e1000_init_function_pointers_82540(hw); - break; - case e1000_82541: - case e1000_82541_rev_2: - case e1000_82547: - case e1000_82547_rev_2: - e1000_init_function_pointers_82541(hw); - break; - default: - DEBUGOUT("Hardware not supported\n"); - ret_val = -E1000_ERR_CONFIG; - break; - } - - /* - * Initialize the rest of the function pointers. These require some - * register reads/writes in some cases. - */ - if (!(ret_val) && init_device) { - ret_val = e1000_init_mac_params(hw); - if (ret_val) - goto out; - - ret_val = e1000_init_nvm_params(hw); - if (ret_val) - goto out; - - ret_val = e1000_init_phy_params(hw); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_get_bus_info - Obtain bus information for adapter - * @hw: pointer to the HW structure - * - * This will obtain information about the HW bus for which the - * adapter is attached and stores it in the hw structure. This is a - * function pointer entry point called by drivers. - **/ -s32 e1000_get_bus_info(struct e1000_hw *hw) -{ - if (hw->mac.ops.get_bus_info) - return hw->mac.ops.get_bus_info(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_clear_vfta - Clear VLAN filter table - * @hw: pointer to the HW structure - * - * This clears the VLAN filter table on the adapter. This is a function - * pointer entry point called by drivers. - **/ -void e1000_clear_vfta(struct e1000_hw *hw) -{ - if (hw->mac.ops.clear_vfta) - hw->mac.ops.clear_vfta(hw); -} - -/** - * e1000_write_vfta - Write value to VLAN filter table - * @hw: pointer to the HW structure - * @offset: the 32-bit offset in which to write the value to. - * @value: the 32-bit value to write at location offset. - * - * This writes a 32-bit value to a 32-bit offset in the VLAN filter - * table. This is a function pointer entry point called by drivers. - **/ -void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) -{ - if (hw->mac.ops.write_vfta) - hw->mac.ops.write_vfta(hw, offset, value); -} - -/** - * e1000_update_mc_addr_list - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * - * Updates the Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - **/ -void e1000_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list, - u32 mc_addr_count) -{ - if (hw->mac.ops.update_mc_addr_list) - hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, - mc_addr_count); -} - -/** - * e1000_force_mac_fc - Force MAC flow control - * @hw: pointer to the HW structure - * - * Force the MAC's flow control settings. Currently no func pointer exists - * and all implementations are handled in the generic version of this - * function. - **/ -s32 e1000_force_mac_fc(struct e1000_hw *hw) -{ - return e1000_force_mac_fc_generic(hw); -} - -/** - * e1000_check_for_link - Check/Store link connection - * @hw: pointer to the HW structure - * - * This checks the link condition of the adapter and stores the - * results in the hw->mac structure. This is a function pointer entry - * point called by drivers. - **/ -s32 e1000_check_for_link(struct e1000_hw *hw) -{ - if (hw->mac.ops.check_for_link) - return hw->mac.ops.check_for_link(hw); - - return -E1000_ERR_CONFIG; -} - -#if 0 -/** - * e1000_check_mng_mode - Check management mode - * @hw: pointer to the HW structure - * - * This checks if the adapter has manageability enabled. - * This is a function pointer entry point called by drivers. - **/ -bool e1000_check_mng_mode(struct e1000_hw *hw) -{ - if (hw->mac.ops.check_mng_mode) - return hw->mac.ops.check_mng_mode(hw); - - return false; -} - -/** - * e1000_mng_write_dhcp_info - Writes DHCP info to host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface - * @length: size of the buffer - * - * Writes the DHCP information to the host interface. - **/ -s32 e1000_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length) -{ - return e1000_mng_write_dhcp_info_generic(hw, buffer, length); -} -#endif - -/** - * e1000_reset_hw - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. This is a function pointer - * entry point called by drivers. - **/ -s32 e1000_reset_hw(struct e1000_hw *hw) -{ - if (hw->mac.ops.reset_hw) - return hw->mac.ops.reset_hw(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * e1000_init_hw - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. This is a function - * pointer entry point called by drivers. - **/ -s32 e1000_init_hw(struct e1000_hw *hw) -{ - if (hw->mac.ops.init_hw) - return hw->mac.ops.init_hw(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * e1000_setup_link - Configures link and flow control - * @hw: pointer to the HW structure - * - * This configures link and flow control settings for the adapter. This - * is a function pointer entry point called by drivers. While modules can - * also call this, they probably call their own version of this function. - **/ -s32 e1000_setup_link(struct e1000_hw *hw) -{ - if (hw->mac.ops.setup_link) - return hw->mac.ops.setup_link(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * e1000_get_speed_and_duplex - Returns current speed and duplex - * @hw: pointer to the HW structure - * @speed: pointer to a 16-bit value to store the speed - * @duplex: pointer to a 16-bit value to store the duplex. - * - * This returns the speed and duplex of the adapter in the two 'out' - * variables passed in. This is a function pointer entry point called - * by drivers. - **/ -s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex) -{ - if (hw->mac.ops.get_link_up_info) - return hw->mac.ops.get_link_up_info(hw, speed, duplex); - - return -E1000_ERR_CONFIG; -} - -/** - * e1000_setup_led - Configures SW controllable LED - * @hw: pointer to the HW structure - * - * This prepares the SW controllable LED for use and saves the current state - * of the LED so it can be later restored. This is a function pointer entry - * point called by drivers. - **/ -s32 e1000_setup_led(struct e1000_hw *hw) -{ - if (hw->mac.ops.setup_led) - return hw->mac.ops.setup_led(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_cleanup_led - Restores SW controllable LED - * @hw: pointer to the HW structure - * - * This restores the SW controllable LED to the value saved off by - * e1000_setup_led. This is a function pointer entry point called by drivers. - **/ -s32 e1000_cleanup_led(struct e1000_hw *hw) -{ - if (hw->mac.ops.cleanup_led) - return hw->mac.ops.cleanup_led(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_blink_led - Blink SW controllable LED - * @hw: pointer to the HW structure - * - * This starts the adapter LED blinking. Request the LED to be setup first - * and cleaned up after. This is a function pointer entry point called by - * drivers. - **/ -s32 e1000_blink_led(struct e1000_hw *hw) -{ - if (hw->mac.ops.blink_led) - return hw->mac.ops.blink_led(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_id_led_init - store LED configurations in SW - * @hw: pointer to the HW structure - * - * Initializes the LED config in SW. This is a function pointer entry point - * called by drivers. - **/ -s32 e1000_id_led_init(struct e1000_hw *hw) -{ - if (hw->mac.ops.id_led_init) - return hw->mac.ops.id_led_init(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_led_on - Turn on SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED on. This is a function pointer entry point - * called by drivers. - **/ -s32 e1000_led_on(struct e1000_hw *hw) -{ - if (hw->mac.ops.led_on) - return hw->mac.ops.led_on(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_led_off - Turn off SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED off. This is a function pointer entry point - * called by drivers. - **/ -s32 e1000_led_off(struct e1000_hw *hw) -{ - if (hw->mac.ops.led_off) - return hw->mac.ops.led_off(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_reset_adaptive - Reset adaptive IFS - * @hw: pointer to the HW structure - * - * Resets the adaptive IFS. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -void e1000_reset_adaptive(struct e1000_hw *hw) -{ - e1000_reset_adaptive_generic(hw); -} - -/** - * e1000_update_adaptive - Update adaptive IFS - * @hw: pointer to the HW structure - * - * Updates adapter IFS. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -void e1000_update_adaptive(struct e1000_hw *hw) -{ - e1000_update_adaptive_generic(hw); -} - -/** - * e1000_disable_pcie_master - Disable PCI-Express master access - * @hw: pointer to the HW structure - * - * Disables PCI-Express master access and verifies there are no pending - * requests. Currently no func pointer exists and all implementations are - * handled in the generic version of this function. - **/ -s32 e1000_disable_pcie_master(struct e1000_hw *hw) -{ - return e1000_disable_pcie_master_generic(hw); -} - -/** - * e1000_config_collision_dist - Configure collision distance - * @hw: pointer to the HW structure - * - * Configures the collision distance to the default value and is used - * during link setup. - **/ -void e1000_config_collision_dist(struct e1000_hw *hw) -{ - if (hw->mac.ops.config_collision_dist) - hw->mac.ops.config_collision_dist(hw); -} - -/** - * e1000_rar_set - Sets a receive address register - * @hw: pointer to the HW structure - * @addr: address to set the RAR to - * @index: the RAR to set - * - * Sets a Receive Address Register (RAR) to the specified address. - **/ -void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) -{ - if (hw->mac.ops.rar_set) - hw->mac.ops.rar_set(hw, addr, index); -} - -/** - * e1000_validate_mdi_setting - Ensures valid MDI/MDIX SW state - * @hw: pointer to the HW structure - * - * Ensures that the MDI/MDIX SW state is valid. - **/ -s32 e1000_validate_mdi_setting(struct e1000_hw *hw) -{ - if (hw->mac.ops.validate_mdi_setting) - return hw->mac.ops.validate_mdi_setting(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_mta_set - Sets multicast table bit - * @hw: pointer to the HW structure - * @hash_value: Multicast hash value. - * - * This sets the bit in the multicast table corresponding to the - * hash value. This is a function pointer entry point called by drivers. - **/ -void e1000_mta_set(struct e1000_hw *hw, u32 hash_value) -{ - if (hw->mac.ops.mta_set) - hw->mac.ops.mta_set(hw, hash_value); -} - -/** - * e1000_hash_mc_addr - Determines address location in multicast table - * @hw: pointer to the HW structure - * @mc_addr: Multicast address to hash. - * - * This hashes an address to determine its location in the multicast - * table. Currently no func pointer exists and all implementations - * are handled in the generic version of this function. - **/ -u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) -{ - return e1000_hash_mc_addr_generic(hw, mc_addr); -} - -#if 0 -/** - * e1000_enable_tx_pkt_filtering - Enable packet filtering on TX - * @hw: pointer to the HW structure - * - * Enables packet filtering on transmit packets if manageability is enabled - * and host interface is enabled. - * Currently no func pointer exists and all implementations are handled in the - * generic version of this function. - **/ -bool e1000_enable_tx_pkt_filtering(struct e1000_hw *hw) -{ - return e1000_enable_tx_pkt_filtering_generic(hw); -} - -/** - * e1000_mng_host_if_write - Writes to the manageability host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface buffer - * @length: size of the buffer - * @offset: location in the buffer to write to - * @sum: sum of the data (not checksum) - * - * This function writes the buffer content at the offset given on the host if. - * It also does alignment considerations to do the writes in most efficient - * way. Also fills up the sum of the buffer in *buffer parameter. - **/ -s32 e1000_mng_host_if_write(struct e1000_hw * hw, u8 *buffer, u16 length, - u16 offset, u8 *sum) -{ - if (hw->mac.ops.mng_host_if_write) - return hw->mac.ops.mng_host_if_write(hw, buffer, length, - offset, sum); - - return E1000_NOT_IMPLEMENTED; -} - -/** - * e1000_mng_write_cmd_header - Writes manageability command header - * @hw: pointer to the HW structure - * @hdr: pointer to the host interface command header - * - * Writes the command header after does the checksum calculation. - **/ -s32 e1000_mng_write_cmd_header(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr) -{ - if (hw->mac.ops.mng_write_cmd_header) - return hw->mac.ops.mng_write_cmd_header(hw, hdr); - - return E1000_NOT_IMPLEMENTED; -} - -/** - * e1000_mng_enable_host_if - Checks host interface is enabled - * @hw: pointer to the HW structure - * - * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND - * - * This function checks whether the HOST IF is enabled for command operation - * and also checks whether the previous command is completed. It busy waits - * in case of previous command is not completed. - **/ -s32 e1000_mng_enable_host_if(struct e1000_hw * hw) -{ - if (hw->mac.ops.mng_enable_host_if) - return hw->mac.ops.mng_enable_host_if(hw); - - return E1000_NOT_IMPLEMENTED; -} -#endif - -/** - * e1000_wait_autoneg - Waits for autonegotiation completion - * @hw: pointer to the HW structure - * - * Waits for autoneg to complete. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -s32 e1000_wait_autoneg(struct e1000_hw *hw) -{ - if (hw->mac.ops.wait_autoneg) - return hw->mac.ops.wait_autoneg(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_check_reset_block - Verifies PHY can be reset - * @hw: pointer to the HW structure - * - * Checks if the PHY is in a state that can be reset or if manageability - * has it tied up. This is a function pointer entry point called by drivers. - **/ -s32 e1000_check_reset_block(struct e1000_hw *hw) -{ - if (hw->phy.ops.check_reset_block) - return hw->phy.ops.check_reset_block(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_read_phy_reg - Reads PHY register - * @hw: pointer to the HW structure - * @offset: the register to read - * @data: the buffer to store the 16-bit read. - * - * Reads the PHY register and returns the value in data. - * This is a function pointer entry point called by drivers. - **/ -s32 e1000_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data) -{ - if (hw->phy.ops.read_reg) - return hw->phy.ops.read_reg(hw, offset, data); - - return E1000_SUCCESS; -} - -/** - * e1000_write_phy_reg - Writes PHY register - * @hw: pointer to the HW structure - * @offset: the register to write - * @data: the value to write. - * - * Writes the PHY register at offset with the value in data. - * This is a function pointer entry point called by drivers. - **/ -s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data) -{ - if (hw->phy.ops.write_reg) - return hw->phy.ops.write_reg(hw, offset, data); - - return E1000_SUCCESS; -} - -/** - * e1000_release_phy - Generic release PHY - * @hw: pointer to the HW structure - * - * Return if silicon family does not require a semaphore when accessing the - * PHY. - **/ -void e1000_release_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.release) - hw->phy.ops.release(hw); -} - -/** - * e1000_acquire_phy - Generic acquire PHY - * @hw: pointer to the HW structure - * - * Return success if silicon family does not require a semaphore when - * accessing the PHY. - **/ -s32 e1000_acquire_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.acquire) - return hw->phy.ops.acquire(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_read_kmrn_reg - Reads register using Kumeran interface - * @hw: pointer to the HW structure - * @offset: the register to read - * @data: the location to store the 16-bit value read. - * - * Reads a register out of the Kumeran interface. Currently no func pointer - * exists and all implementations are handled in the generic version of - * this function. - **/ -s32 e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return e1000_read_kmrn_reg_generic(hw, offset, data); -} - -/** - * e1000_write_kmrn_reg - Writes register using Kumeran interface - * @hw: pointer to the HW structure - * @offset: the register to write - * @data: the value to write. - * - * Writes a register to the Kumeran interface. Currently no func pointer - * exists and all implementations are handled in the generic version of - * this function. - **/ -s32 e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) -{ - return e1000_write_kmrn_reg_generic(hw, offset, data); -} - -#if 0 -/** - * e1000_get_cable_length - Retrieves cable length estimation - * @hw: pointer to the HW structure - * - * This function estimates the cable length and stores them in - * hw->phy.min_length and hw->phy.max_length. This is a function pointer - * entry point called by drivers. - **/ -s32 e1000_get_cable_length(struct e1000_hw *hw) -{ - if (hw->phy.ops.get_cable_length) - return hw->phy.ops.get_cable_length(hw); - - return E1000_SUCCESS; -} -#endif - -/** - * e1000_get_phy_info - Retrieves PHY information from registers - * @hw: pointer to the HW structure - * - * This function gets some information from various PHY registers and - * populates hw->phy values with it. This is a function pointer entry - * point called by drivers. - **/ -s32 e1000_get_phy_info(struct e1000_hw *hw) -{ - if (hw->phy.ops.get_info) - return hw->phy.ops.get_info(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_phy_hw_reset - Hard PHY reset - * @hw: pointer to the HW structure - * - * Performs a hard PHY reset. This is a function pointer entry point called - * by drivers. - **/ -s32 e1000_phy_hw_reset(struct e1000_hw *hw) -{ - if (hw->phy.ops.reset) - return hw->phy.ops.reset(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_phy_commit - Soft PHY reset - * @hw: pointer to the HW structure - * - * Performs a soft PHY reset on those that apply. This is a function pointer - * entry point called by drivers. - **/ -s32 e1000_phy_commit(struct e1000_hw *hw) -{ - if (hw->phy.ops.commit) - return hw->phy.ops.commit(hw); - - return E1000_SUCCESS; -} - -/** - * e1000_set_d0_lplu_state - Sets low power link up state for D0 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D0 - * and SmartSpeed is disabled when active is true, else clear lplu for D0 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. This is a function pointer entry point called by drivers. - **/ -s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active) -{ - if (hw->phy.ops.set_d0_lplu_state) - return hw->phy.ops.set_d0_lplu_state(hw, active); - - return E1000_SUCCESS; -} - -/** - * e1000_set_d3_lplu_state - Sets low power link up state for D3 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D3 - * and SmartSpeed is disabled when active is true, else clear lplu for D3 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. This is a function pointer entry point called by drivers. - **/ -s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active) -{ - if (hw->phy.ops.set_d3_lplu_state) - return hw->phy.ops.set_d3_lplu_state(hw, active); - - return E1000_SUCCESS; -} - -/** - * e1000_read_mac_addr - Reads MAC address - * @hw: pointer to the HW structure - * - * Reads the MAC address out of the adapter and stores it in the HW structure. - * Currently no func pointer exists and all implementations are handled in the - * generic version of this function. - **/ -s32 e1000_read_mac_addr(struct e1000_hw *hw) -{ - if (hw->mac.ops.read_mac_addr) - return hw->mac.ops.read_mac_addr(hw); - - return e1000_read_mac_addr_generic(hw); -} - -/** - * e1000_read_pba_num - Read device part number - * @hw: pointer to the HW structure - * @pba_num: pointer to device part number - * - * Reads the product board assembly (PBA) number from the EEPROM and stores - * the value in pba_num. - * Currently no func pointer exists and all implementations are handled in the - * generic version of this function. - **/ -s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *pba_num) -{ - return e1000_read_pba_num_generic(hw, pba_num); -} - -/** - * e1000_validate_nvm_checksum - Verifies NVM (EEPROM) checksum - * @hw: pointer to the HW structure - * - * Validates the NVM checksum is correct. This is a function pointer entry - * point called by drivers. - **/ -s32 e1000_validate_nvm_checksum(struct e1000_hw *hw) -{ - if (hw->nvm.ops.validate) - return hw->nvm.ops.validate(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * e1000_update_nvm_checksum - Updates NVM (EEPROM) checksum - * @hw: pointer to the HW structure - * - * Updates the NVM checksum. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -s32 e1000_update_nvm_checksum(struct e1000_hw *hw) -{ - if (hw->nvm.ops.update) - return hw->nvm.ops.update(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * e1000_reload_nvm - Reloads EEPROM - * @hw: pointer to the HW structure - * - * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the - * extended control register. - **/ -void e1000_reload_nvm(struct e1000_hw *hw) -{ - if (hw->nvm.ops.reload) - hw->nvm.ops.reload(hw); -} - -/** - * e1000_read_nvm - Reads NVM (EEPROM) - * @hw: pointer to the HW structure - * @offset: the word offset to read - * @words: number of 16-bit words to read - * @data: pointer to the properly sized buffer for the data. - * - * Reads 16-bit chunks of data from the NVM (EEPROM). This is a function - * pointer entry point called by drivers. - **/ -s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - if (hw->nvm.ops.read) - return hw->nvm.ops.read(hw, offset, words, data); - - return -E1000_ERR_CONFIG; -} - -/** - * e1000_write_nvm - Writes to NVM (EEPROM) - * @hw: pointer to the HW structure - * @offset: the word offset to read - * @words: number of 16-bit words to write - * @data: pointer to the properly sized buffer for the data. - * - * Writes 16-bit chunks of data to the NVM (EEPROM). This is a function - * pointer entry point called by drivers. - **/ -s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - if (hw->nvm.ops.write) - return hw->nvm.ops.write(hw, offset, words, data); - - return E1000_SUCCESS; -} - -/** - * e1000_power_up_phy - Restores link in case of PHY power down - * @hw: pointer to the HW structure - * - * The phy may be powered down to save power, to turn off link when the - * driver is unloaded, or wake on lan is not enabled (among others). - **/ -void e1000_power_up_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.power_up) - hw->phy.ops.power_up(hw); - - e1000_setup_link(hw); -} - -/** - * e1000_power_down_phy - Power down PHY - * @hw: pointer to the HW structure - * - * The phy may be powered down to save power, to turn off link when the - * driver is unloaded, or wake on lan is not enabled (among others). - **/ -void e1000_power_down_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.power_down) - hw->phy.ops.power_down(hw); -} diff --git a/src/drivers/net/e1000/e1000_api.h b/src/drivers/net/e1000/e1000_api.h deleted file mode 100644 index fc1e533d..00000000 --- a/src/drivers/net/e1000/e1000_api.h +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_API_H_ -#define _E1000_API_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "e1000_hw.h" - -extern void e1000_init_function_pointers_82542(struct e1000_hw *hw) __attribute__((weak)); -extern void e1000_init_function_pointers_82543(struct e1000_hw *hw) __attribute__((weak)); -extern void e1000_init_function_pointers_82540(struct e1000_hw *hw) __attribute__((weak)); -extern void e1000_init_function_pointers_82541(struct e1000_hw *hw) __attribute__((weak)); - -s32 e1000_set_mac_type(struct e1000_hw *hw); -s32 e1000_setup_init_funcs(struct e1000_hw *hw, bool init_device); -s32 e1000_init_mac_params(struct e1000_hw *hw); -s32 e1000_init_nvm_params(struct e1000_hw *hw); -s32 e1000_init_phy_params(struct e1000_hw *hw); -s32 e1000_get_bus_info(struct e1000_hw *hw); -void e1000_clear_vfta(struct e1000_hw *hw); -void e1000_write_vfta(struct e1000_hw *hw, u32 offset, u32 value); -s32 e1000_force_mac_fc(struct e1000_hw *hw); -s32 e1000_check_for_link(struct e1000_hw *hw); -s32 e1000_reset_hw(struct e1000_hw *hw); -s32 e1000_init_hw(struct e1000_hw *hw); -s32 e1000_setup_link(struct e1000_hw *hw); -s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -s32 e1000_disable_pcie_master(struct e1000_hw *hw); -void e1000_config_collision_dist(struct e1000_hw *hw); -void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); -void e1000_mta_set(struct e1000_hw *hw, u32 hash_value); -u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr); -void e1000_update_mc_addr_list(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count); -s32 e1000_setup_led(struct e1000_hw *hw); -s32 e1000_cleanup_led(struct e1000_hw *hw); -s32 e1000_check_reset_block(struct e1000_hw *hw); -s32 e1000_blink_led(struct e1000_hw *hw); -s32 e1000_led_on(struct e1000_hw *hw); -s32 e1000_led_off(struct e1000_hw *hw); -s32 e1000_id_led_init(struct e1000_hw *hw); -void e1000_reset_adaptive(struct e1000_hw *hw); -void e1000_update_adaptive(struct e1000_hw *hw); -#if 0 -s32 e1000_get_cable_length(struct e1000_hw *hw); -#endif -s32 e1000_validate_mdi_setting(struct e1000_hw *hw); -s32 e1000_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000_get_phy_info(struct e1000_hw *hw); -void e1000_release_phy(struct e1000_hw *hw); -s32 e1000_acquire_phy(struct e1000_hw *hw); -s32 e1000_phy_hw_reset(struct e1000_hw *hw); -s32 e1000_phy_commit(struct e1000_hw *hw); -void e1000_power_up_phy(struct e1000_hw *hw); -void e1000_power_down_phy(struct e1000_hw *hw); -s32 e1000_read_mac_addr(struct e1000_hw *hw); -s32 e1000_read_pba_num(struct e1000_hw *hw, u32 *part_num); -void e1000_reload_nvm(struct e1000_hw *hw); -s32 e1000_update_nvm_checksum(struct e1000_hw *hw); -s32 e1000_validate_nvm_checksum(struct e1000_hw *hw); -s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); -s32 e1000_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 e1000_wait_autoneg(struct e1000_hw *hw); -s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active); -s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active); -bool e1000_check_mng_mode(struct e1000_hw *hw); -bool e1000_enable_tx_pkt_filtering(struct e1000_hw *hw); -s32 e1000_mng_enable_host_if(struct e1000_hw *hw); -s32 e1000_mng_host_if_write(struct e1000_hw *hw, - u8 *buffer, u16 length, u16 offset, u8 *sum); -s32 e1000_mng_write_cmd_header(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr); -s32 e1000_mng_write_dhcp_info(struct e1000_hw * hw, - u8 *buffer, u16 length); -u32 e1000_translate_register_82542(u32 reg) __attribute__((weak)); - -extern int e1000_probe(struct pci_device *pdev); -extern void e1000_remove(struct pci_device *pdev); - -#endif diff --git a/src/drivers/net/e1000/e1000_defines.h b/src/drivers/net/e1000/e1000_defines.h deleted file mode 100644 index c585f09b..00000000 --- a/src/drivers/net/e1000/e1000_defines.h +++ /dev/null @@ -1,1416 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_DEFINES_H_ -#define _E1000_DEFINES_H_ - -/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ -#define REQ_TX_DESCRIPTOR_MULTIPLE 8 -#define REQ_RX_DESCRIPTOR_MULTIPLE 8 - -/* Definitions for power management and wakeup registers */ -/* Wake Up Control */ -#define E1000_WUC_APME 0x00000001 /* APM Enable */ -#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ -#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ -#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ -#define E1000_WUC_LSCWE 0x00000010 /* Link Status wake up enable */ -#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */ -#define E1000_WUC_SPM 0x80000000 /* Enable SPM */ -#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ - -/* Wake Up Filter Control */ -#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ -#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ -#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ -#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ -#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ -#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ -#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ -#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ -#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */ -#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ -#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ -#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ -#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ -#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ -#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ -#define E1000_WUFC_FLX_FILTERS 0x000F0000 /*Mask for the 4 flexible filters */ - -/* Wake Up Status */ -#define E1000_WUS_LNKC E1000_WUFC_LNKC -#define E1000_WUS_MAG E1000_WUFC_MAG -#define E1000_WUS_EX E1000_WUFC_EX -#define E1000_WUS_MC E1000_WUFC_MC -#define E1000_WUS_BC E1000_WUFC_BC -#define E1000_WUS_ARP E1000_WUFC_ARP -#define E1000_WUS_IPV4 E1000_WUFC_IPV4 -#define E1000_WUS_IPV6 E1000_WUFC_IPV6 -#define E1000_WUS_FLX0 E1000_WUFC_FLX0 -#define E1000_WUS_FLX1 E1000_WUFC_FLX1 -#define E1000_WUS_FLX2 E1000_WUFC_FLX2 -#define E1000_WUS_FLX3 E1000_WUFC_FLX3 -#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS - -/* Wake Up Packet Length */ -#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ - -/* Four Flexible Filters are supported */ -#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 - -/* Each Flexible Filter is at most 128 (0x80) bytes in length */ -#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 - -#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX -#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX -#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX - -/* Extended Device Control */ -#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ -#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ -#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN -#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ -#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ -/* Reserved (bits 4,5) in >= 82575 */ -#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */ -#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */ -#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA -#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */ -#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Definable Pin 7 */ -/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */ -#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ -#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ -#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ -#define E1000_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ -#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ -#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ -#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ -#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ -#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ -#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */ -#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 -#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 -#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000 -#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000 -#define E1000_CTRL_EXT_EIAME 0x01000000 -#define E1000_CTRL_EXT_IRCA 0x00000001 -#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 -#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 -#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 -#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 -#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 -#define E1000_CTRL_EXT_CANC 0x04000000 /* Int delay cancellation */ -#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ -/* IAME enable bit (27) was removed in >= 82575 */ -#define E1000_CTRL_EXT_IAME 0x08000000 /* Int acknowledge Auto-mask */ -#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error - * detection enabled */ -#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity - * error detection enable */ -#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 -#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ -#define E1000_I2CCMD_REG_ADDR_SHIFT 16 -#define E1000_I2CCMD_REG_ADDR 0x00FF0000 -#define E1000_I2CCMD_PHY_ADDR_SHIFT 24 -#define E1000_I2CCMD_PHY_ADDR 0x07000000 -#define E1000_I2CCMD_OPCODE_READ 0x08000000 -#define E1000_I2CCMD_OPCODE_WRITE 0x00000000 -#define E1000_I2CCMD_RESET 0x10000000 -#define E1000_I2CCMD_READY 0x20000000 -#define E1000_I2CCMD_INTERRUPT_ENA 0x40000000 -#define E1000_I2CCMD_ERROR 0x80000000 -#define E1000_MAX_SGMII_PHY_REG_ADDR 255 -#define E1000_I2CCMD_PHY_TIMEOUT 200 - -/* Receive Descriptor bit definitions */ -#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ -#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ -#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ -#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ -#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ -#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ -#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ -#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ -#define E1000_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ -#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ -#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ -#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ -#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ -#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ -#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ -#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ -#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ -#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ -#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ -#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ -#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ -#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ -#define E1000_RXD_SPC_PRI_SHIFT 13 -#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ -#define E1000_RXD_SPC_CFI_SHIFT 12 - -#define E1000_RXDEXT_STATERR_CE 0x01000000 -#define E1000_RXDEXT_STATERR_SE 0x02000000 -#define E1000_RXDEXT_STATERR_SEQ 0x04000000 -#define E1000_RXDEXT_STATERR_CXE 0x10000000 -#define E1000_RXDEXT_STATERR_TCPE 0x20000000 -#define E1000_RXDEXT_STATERR_IPE 0x40000000 -#define E1000_RXDEXT_STATERR_RXE 0x80000000 - -/* mask to determine if packets should be dropped due to frame errors */ -#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ - E1000_RXD_ERR_CE | \ - E1000_RXD_ERR_SE | \ - E1000_RXD_ERR_SEQ | \ - E1000_RXD_ERR_CXE | \ - E1000_RXD_ERR_RXE) - -/* Same mask, but for extended and packet split descriptors */ -#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ - E1000_RXDEXT_STATERR_CE | \ - E1000_RXDEXT_STATERR_SE | \ - E1000_RXDEXT_STATERR_SEQ | \ - E1000_RXDEXT_STATERR_CXE | \ - E1000_RXDEXT_STATERR_RXE) - -#define E1000_MRQC_ENABLE_MASK 0x00000007 -#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 -#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 -#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 -#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 -#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 -#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 -#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 -#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 -#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 - -#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 -#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF - -/* Management Control */ -#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ -#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ -#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ -#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ -#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ -#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ -#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ -#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ -#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ -/* Enable Neighbor Discovery Filtering */ -#define E1000_MANC_NEIGHBOR_EN 0x00004000 -#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ -#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ -#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ -#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ -#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ -#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ -/* Enable MAC address filtering */ -#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 -/* Enable MNG packets to host memory */ -#define E1000_MANC_EN_MNG2HOST 0x00200000 -/* Enable IP address filtering */ -#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 -#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ -#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ -#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ -#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ -#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ -#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ -#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ -#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ - -#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ -#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ - -/* Receive Control */ -#define E1000_RCTL_RST 0x00000001 /* Software reset */ -#define E1000_RCTL_EN 0x00000002 /* enable */ -#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ -#define E1000_RCTL_UPE 0x00000008 /* unicast promisc enable */ -#define E1000_RCTL_MPE 0x00000010 /* multicast promisc enable */ -#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ -#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ -#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ -#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ -#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ -#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ -#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ -#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min thresh size */ -#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min thresh size */ -#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min thresh size */ -#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ -#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ -#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ -#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ -#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ -#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ -#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ -#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ -#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ -#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ -#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ -#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ -#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ -#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ -#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ -#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ -#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ -#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ -#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ -#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ -#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ -#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ -#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ - -/* - * Use byte values for the following shift parameters - * Usage: - * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & - * E1000_PSRCTL_BSIZE0_MASK) | - * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & - * E1000_PSRCTL_BSIZE1_MASK) | - * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & - * E1000_PSRCTL_BSIZE2_MASK) | - * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; - * E1000_PSRCTL_BSIZE3_MASK)) - * where value0 = [128..16256], default=256 - * value1 = [1024..64512], default=4096 - * value2 = [0..64512], default=4096 - * value3 = [0..64512], default=0 - */ - -#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F -#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 -#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 -#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 - -#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ -#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ -#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ -#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ - -/* SWFW_SYNC Definitions */ -#define E1000_SWFW_EEP_SM 0x01 -#define E1000_SWFW_PHY0_SM 0x02 -#define E1000_SWFW_PHY1_SM 0x04 -#define E1000_SWFW_CSR_SM 0x08 - -/* FACTPS Definitions */ -#define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */ -/* Device Control */ -#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ -#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ -#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ -#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */ -#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ -#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ -#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ -#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ -#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ -#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ -#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ -#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ -#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ -#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ -#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ -#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ -#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ -#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ -#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock - * indication in SDP[0] */ -#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through - * PHYRST_N pin */ -#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external - * LINK_0 and LINK_1 pins */ -#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ -#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ -#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ -#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ -#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ -#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ -#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ -#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ -#define E1000_CTRL_RST 0x04000000 /* Global reset */ -#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ -#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ -#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ -#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ -#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ -#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */ -#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */ - -/* - * Bit definitions for the Management Data IO (MDIO) and Management Data - * Clock (MDC) pins in the Device Control Register. - */ -#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 -#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 -#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 -#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 -#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 -#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 -#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR -#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA - -#define E1000_CONNSW_ENRGSRC 0x4 -#define E1000_PCS_CFG_PCS_EN 8 -#define E1000_PCS_LCTL_FLV_LINK_UP 1 -#define E1000_PCS_LCTL_FSV_10 0 -#define E1000_PCS_LCTL_FSV_100 2 -#define E1000_PCS_LCTL_FSV_1000 4 -#define E1000_PCS_LCTL_FDV_FULL 8 -#define E1000_PCS_LCTL_FSD 0x10 -#define E1000_PCS_LCTL_FORCE_LINK 0x20 -#define E1000_PCS_LCTL_LOW_LINK_LATCH 0x40 -#define E1000_PCS_LCTL_FORCE_FCTRL 0x80 -#define E1000_PCS_LCTL_AN_ENABLE 0x10000 -#define E1000_PCS_LCTL_AN_RESTART 0x20000 -#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000 -#define E1000_PCS_LCTL_AN_SGMII_BYPASS 0x80000 -#define E1000_PCS_LCTL_AN_SGMII_TRIGGER 0x100000 -#define E1000_PCS_LCTL_FAST_LINK_TIMER 0x1000000 -#define E1000_PCS_LCTL_LINK_OK_FIX 0x2000000 -#define E1000_PCS_LCTL_CRS_ON_NI 0x4000000 -#define E1000_ENABLE_SERDES_LOOPBACK 0x0410 - -#define E1000_PCS_LSTS_LINK_OK 1 -#define E1000_PCS_LSTS_SPEED_10 0 -#define E1000_PCS_LSTS_SPEED_100 2 -#define E1000_PCS_LSTS_SPEED_1000 4 -#define E1000_PCS_LSTS_DUPLEX_FULL 8 -#define E1000_PCS_LSTS_SYNK_OK 0x10 -#define E1000_PCS_LSTS_AN_COMPLETE 0x10000 -#define E1000_PCS_LSTS_AN_PAGE_RX 0x20000 -#define E1000_PCS_LSTS_AN_TIMED_OUT 0x40000 -#define E1000_PCS_LSTS_AN_REMOTE_FAULT 0x80000 -#define E1000_PCS_LSTS_AN_ERROR_RWS 0x100000 - -/* Device Status */ -#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ -#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ -#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ -#define E1000_STATUS_FUNC_SHIFT 2 -#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ -#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ -#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ -#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ -#define E1000_STATUS_SPEED_MASK 0x000000C0 -#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ -#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ -#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ -#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ -#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ -#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */ -#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. - * Clear on write '0'. */ -#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */ -#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ -#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ -#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ -#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ -#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ -#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ -#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ -#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ -#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ -#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution - * disabled */ -#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ -#define E1000_STATUS_FUSE_8 0x04000000 -#define E1000_STATUS_FUSE_9 0x08000000 -#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ -#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ - -/* Constants used to interpret the masked PCI-X bus speed. */ -#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ -#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ -#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/ - -#define SPEED_10 10 -#define SPEED_100 100 -#define SPEED_1000 1000 -#define HALF_DUPLEX 1 -#define FULL_DUPLEX 2 - -#define PHY_FORCE_TIME 20 - -#define ADVERTISE_10_HALF 0x0001 -#define ADVERTISE_10_FULL 0x0002 -#define ADVERTISE_100_HALF 0x0004 -#define ADVERTISE_100_FULL 0x0008 -#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ -#define ADVERTISE_1000_FULL 0x0020 - -/* 1000/H is not supported, nor spec-compliant. */ -#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ - ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ - ADVERTISE_1000_FULL) -#define E1000_ALL_NOT_GIG (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ - ADVERTISE_100_HALF | ADVERTISE_100_FULL) -#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) -#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) -#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \ - ADVERTISE_1000_FULL) -#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) - -#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX - -/* LED Control */ -#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F -#define E1000_LEDCTL_LED0_MODE_SHIFT 0 -#define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020 -#define E1000_LEDCTL_LED0_IVRT 0x00000040 -#define E1000_LEDCTL_LED0_BLINK 0x00000080 -#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 -#define E1000_LEDCTL_LED1_MODE_SHIFT 8 -#define E1000_LEDCTL_LED1_BLINK_RATE 0x00002000 -#define E1000_LEDCTL_LED1_IVRT 0x00004000 -#define E1000_LEDCTL_LED1_BLINK 0x00008000 -#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 -#define E1000_LEDCTL_LED2_MODE_SHIFT 16 -#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000 -#define E1000_LEDCTL_LED2_IVRT 0x00400000 -#define E1000_LEDCTL_LED2_BLINK 0x00800000 -#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 -#define E1000_LEDCTL_LED3_MODE_SHIFT 24 -#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 -#define E1000_LEDCTL_LED3_IVRT 0x40000000 -#define E1000_LEDCTL_LED3_BLINK 0x80000000 - -#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 -#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 -#define E1000_LEDCTL_MODE_LINK_UP 0x2 -#define E1000_LEDCTL_MODE_ACTIVITY 0x3 -#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 -#define E1000_LEDCTL_MODE_LINK_10 0x5 -#define E1000_LEDCTL_MODE_LINK_100 0x6 -#define E1000_LEDCTL_MODE_LINK_1000 0x7 -#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 -#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 -#define E1000_LEDCTL_MODE_COLLISION 0xA -#define E1000_LEDCTL_MODE_BUS_SPEED 0xB -#define E1000_LEDCTL_MODE_BUS_SIZE 0xC -#define E1000_LEDCTL_MODE_PAUSED 0xD -#define E1000_LEDCTL_MODE_LED_ON 0xE -#define E1000_LEDCTL_MODE_LED_OFF 0xF - -/* Transmit Descriptor bit definitions */ -#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ -#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ -#define E1000_TXD_POPTS_SHIFT 8 /* POPTS shift */ -#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ -#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ -#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ -#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ -#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ -#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ -#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ -#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ -#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ -#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ -#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ -#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ -#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ -#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ -#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ -#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ -#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ -#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ -/* Extended desc bits for Linksec and timesync */ - -/* Transmit Control */ -#define E1000_TCTL_RST 0x00000001 /* software reset */ -#define E1000_TCTL_EN 0x00000002 /* enable tx */ -#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ -#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ -#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ -#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ -#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ -#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ -#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ -#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ -#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ - -/* Transmit Arbitration Count */ -#define E1000_TARC0_ENABLE 0x00000400 /* Enable Tx Queue 0 */ - -/* SerDes Control */ -#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 - -/* Receive Checksum Control */ -#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ -#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ -#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ -#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ -#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ -#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ -#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ - -/* Header split receive */ -#define E1000_RFCTL_ISCSI_DIS 0x00000001 -#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E -#define E1000_RFCTL_ISCSI_DWC_SHIFT 1 -#define E1000_RFCTL_NFSW_DIS 0x00000040 -#define E1000_RFCTL_NFSR_DIS 0x00000080 -#define E1000_RFCTL_NFS_VER_MASK 0x00000300 -#define E1000_RFCTL_NFS_VER_SHIFT 8 -#define E1000_RFCTL_IPV6_DIS 0x00000400 -#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800 -#define E1000_RFCTL_ACK_DIS 0x00001000 -#define E1000_RFCTL_ACKD_DIS 0x00002000 -#define E1000_RFCTL_IPFRSP_DIS 0x00004000 -#define E1000_RFCTL_EXTEN 0x00008000 -#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 -#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 -#define E1000_RFCTL_LEF 0x00040000 - -/* Collision related configuration parameters */ -#define E1000_COLLISION_THRESHOLD 15 -#define E1000_CT_SHIFT 4 -#define E1000_COLLISION_DISTANCE 63 -#define E1000_COLD_SHIFT 12 - -/* Default values for the transmit IPG register */ -#define DEFAULT_82542_TIPG_IPGT 10 -#define DEFAULT_82543_TIPG_IPGT_FIBER 9 -#define DEFAULT_82543_TIPG_IPGT_COPPER 8 - -#define E1000_TIPG_IPGT_MASK 0x000003FF -#define E1000_TIPG_IPGR1_MASK 0x000FFC00 -#define E1000_TIPG_IPGR2_MASK 0x3FF00000 - -#define DEFAULT_82542_TIPG_IPGR1 2 -#define DEFAULT_82543_TIPG_IPGR1 8 -#define E1000_TIPG_IPGR1_SHIFT 10 - -#define DEFAULT_82542_TIPG_IPGR2 10 -#define DEFAULT_82543_TIPG_IPGR2 6 -#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 -#define E1000_TIPG_IPGR2_SHIFT 20 - -/* Ethertype field values */ -#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ - -#define ETHERNET_FCS_SIZE 4 -#define MAX_JUMBO_FRAME_SIZE 0x3F00 - -/* Extended Configuration Control and Size */ -#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 -#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 -#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 -#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 -#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 - -#define E1000_PHY_CTRL_SPD_EN 0x00000001 -#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 -#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 -#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 -#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 - -#define E1000_KABGTXD_BGSQLBIAS 0x00050000 - -/* PBA constants */ -#define E1000_PBA_6K 0x0006 /* 6KB */ -#define E1000_PBA_8K 0x0008 /* 8KB */ -#define E1000_PBA_10K 0x000A /* 10KB */ -#define E1000_PBA_12K 0x000C /* 12KB */ -#define E1000_PBA_14K 0x000E /* 14KB */ -#define E1000_PBA_16K 0x0010 /* 16KB */ -#define E1000_PBA_18K 0x0012 -#define E1000_PBA_20K 0x0014 -#define E1000_PBA_22K 0x0016 -#define E1000_PBA_24K 0x0018 -#define E1000_PBA_26K 0x001A -#define E1000_PBA_30K 0x001E -#define E1000_PBA_32K 0x0020 -#define E1000_PBA_34K 0x0022 -#define E1000_PBA_35K 0x0023 -#define E1000_PBA_38K 0x0026 -#define E1000_PBA_40K 0x0028 -#define E1000_PBA_48K 0x0030 /* 48KB */ -#define E1000_PBA_64K 0x0040 /* 64KB */ - -#define E1000_PBS_16K E1000_PBA_16K -#define E1000_PBS_24K E1000_PBA_24K - -#define IFS_MAX 80 -#define IFS_MIN 40 -#define IFS_RATIO 4 -#define IFS_STEP 10 -#define MIN_NUM_XMITS 1000 - -/* SW Semaphore Register */ -#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ -#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ -#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ -#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ - -#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ - -/* Interrupt Cause Read */ -#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ -#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ -#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ -#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ -#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ -#define E1000_ICR_RXO 0x00000040 /* rx overrun */ -#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ -#define E1000_ICR_VMMB 0x00000100 /* VM MB event */ -#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ -#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */ -#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ -#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ -#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ -#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ -#define E1000_ICR_TXD_LOW 0x00008000 -#define E1000_ICR_SRPD 0x00010000 -#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ -#define E1000_ICR_MNG 0x00040000 /* Manageability event */ -#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ -#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver - * should claim the interrupt */ -#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */ -#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */ -#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ -#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */ -#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ -#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW - * bit in the FWSM */ -#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates - * an interrupt */ -#define E1000_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */ -#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */ - - -/* - * This defines the bits that are set in the Interrupt Mask - * Set/Read Register. Each bit is documented below: - * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error - */ -#define POLL_IMS_ENABLE_MASK ( \ - E1000_IMS_RXDMT0 | \ - E1000_IMS_RXSEQ) - -/* - * This defines the bits that are set in the Interrupt Mask - * Set/Read Register. Each bit is documented below: - * o RXT0 = Receiver Timer Interrupt (ring 0) - * o TXDW = Transmit Descriptor Written Back - * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error - * o LSC = Link Status Change - */ -#define IMS_ENABLE_MASK ( \ - E1000_IMS_RXT0 | \ - E1000_IMS_TXDW | \ - E1000_IMS_RXDMT0 | \ - E1000_IMS_RXSEQ | \ - E1000_IMS_LSC) - -/* Interrupt Mask Set */ -#define E1000_IMS_TXDW E1000_ICR_TXDW /* Tx desc written back */ -#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */ -#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ -#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_IMS_SRPD E1000_ICR_SRPD -#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO - * parity error */ -#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO - * parity error */ -#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer - * parity error */ -#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity - * error */ -#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO - * parity error */ -#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO - * parity error */ -#define E1000_IMS_DSW E1000_ICR_DSW -#define E1000_IMS_PHYINT E1000_ICR_PHYINT -#define E1000_IMS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */ -#define E1000_IMS_EPRST E1000_ICR_EPRST - -/* Interrupt Cause Set */ -#define E1000_ICS_TXDW E1000_ICR_TXDW /* Tx desc written back */ -#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ -#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_ICS_SRPD E1000_ICR_SRPD -#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO - * parity error */ -#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO - * parity error */ -#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer - * parity error */ -#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity - * error */ -#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO - * parity error */ -#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO - * parity error */ -#define E1000_ICS_DSW E1000_ICR_DSW -#define E1000_ICS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */ -#define E1000_ICS_PHYINT E1000_ICR_PHYINT -#define E1000_ICS_EPRST E1000_ICR_EPRST - -/* Transmit Descriptor Control */ -#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ -#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */ -#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ -#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ -#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ -#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ -#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */ -/* Enable the counting of descriptors still to be processed. */ -#define E1000_TXDCTL_COUNT_DESC 0x00400000 - -/* Flow Control Constants */ -#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 -#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 -#define FLOW_CONTROL_TYPE 0x8808 - -/* 802.1q VLAN Packet Size */ -#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */ -#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ - -/* Receive Address */ -/* - * Number of high/low register pairs in the RAR. The RAR (Receive Address - * Registers) holds the directed and multicast addresses that we monitor. - * Technically, we have 16 spots. However, we reserve one of these spots - * (RAR[15]) for our directed address used by controllers with - * manageability enabled, allowing us room for 15 multicast addresses. - */ -#define E1000_RAR_ENTRIES 15 -#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ -#define E1000_RAL_MAC_ADDR_LEN 4 -#define E1000_RAH_MAC_ADDR_LEN 2 -#define E1000_RAH_POOL_MASK 0x03FC0000 -#define E1000_RAH_POOL_1 0x00040000 - -/* Error Codes */ -#define E1000_SUCCESS 0 -#define E1000_ERR_NVM 1 -#define E1000_ERR_PHY 2 -#define E1000_ERR_CONFIG 3 -#define E1000_ERR_PARAM 4 -#define E1000_ERR_MAC_INIT 5 -#define E1000_ERR_PHY_TYPE 6 -#define E1000_ERR_RESET 9 -#define E1000_ERR_MASTER_REQUESTS_PENDING 10 -#define E1000_ERR_HOST_INTERFACE_COMMAND 11 -#define E1000_BLK_PHY_RESET 12 -#define E1000_ERR_SWFW_SYNC 13 -#define E1000_NOT_IMPLEMENTED 14 -#define E1000_ERR_MBX 15 - -/* Loop limit on how long we wait for auto-negotiation to complete */ -#define FIBER_LINK_UP_LIMIT 50 -#define COPPER_LINK_UP_LIMIT 10 -#define PHY_AUTO_NEG_LIMIT 45 -#define PHY_FORCE_LIMIT 20 -/* Number of 100 microseconds we wait for PCI Express master disable */ -#define MASTER_DISABLE_TIMEOUT 800 -/* Number of milliseconds we wait for PHY configuration done after MAC reset */ -#define PHY_CFG_TIMEOUT 100 -/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ -#define MDIO_OWNERSHIP_TIMEOUT 10 -/* Number of milliseconds for NVM auto read done after MAC reset. */ -#define AUTO_READ_DONE_TIMEOUT 10 - -/* Flow Control */ -#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ -#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ -#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ -#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ - -/* Transmit Configuration Word */ -#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ -#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ -#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ -#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ -#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ -#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ -#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ -#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ -#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ -#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ - -/* Receive Configuration Word */ -#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ -#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ -#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ -#define E1000_RXCW_CC 0x10000000 /* Receive config change */ -#define E1000_RXCW_C 0x20000000 /* Receive config */ -#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ -#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ - - -/* PCI Express Control */ -#define E1000_GCR_RXD_NO_SNOOP 0x00000001 -#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 -#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 -#define E1000_GCR_TXD_NO_SNOOP 0x00000008 -#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 -#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 -#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 -#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 -#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000 -#define E1000_GCR_CAP_VER2 0x00040000 - -#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ - E1000_GCR_RXDSCW_NO_SNOOP | \ - E1000_GCR_RXDSCR_NO_SNOOP | \ - E1000_GCR_TXD_NO_SNOOP | \ - E1000_GCR_TXDSCW_NO_SNOOP | \ - E1000_GCR_TXDSCR_NO_SNOOP) - -/* PHY Control Register */ -#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ -#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ -#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ -#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ -#define MII_CR_POWER_DOWN 0x0800 /* Power down */ -#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ -#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ -#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ -#define MII_CR_SPEED_1000 0x0040 -#define MII_CR_SPEED_100 0x2000 -#define MII_CR_SPEED_10 0x0000 - -/* PHY Status Register */ -#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ -#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ - -/* Autoneg Advertisement Register */ -#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ -#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ -#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ -#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ -#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ -#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ -#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ -#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ -#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ -#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ - -/* Link Partner Ability Register (Base Page) */ -#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ -#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ -#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ -#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ -#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ -#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ -#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ -#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ -#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ -#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ -#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ - -/* Autoneg Expansion Register */ -#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ -#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ -#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ -#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ -#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ - -/* 1000BASE-T Control Register */ -#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ -#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ -#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ -#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ - /* 0=DTE device */ -#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ - /* 0=Configure PHY as Slave */ -#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ - /* 0=Automatic Master/Slave config */ -#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ -#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ -#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ -#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ -#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ - -/* 1000BASE-T Status Register */ -#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ -#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ -#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ -#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ -#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ -#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ -#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local Tx is Master, 0=Slave */ -#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ - -#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 - -/* PHY 1000 MII Register/Bit Definitions */ -/* PHY Registers defined by IEEE */ -#define PHY_CONTROL 0x00 /* Control Register */ -#define PHY_STATUS 0x01 /* Status Register */ -#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ -#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ -#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ -#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ -#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ -#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */ -#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ -#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ -#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ -#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ - -#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */ - -/* NVM Control */ -#define E1000_EECD_SK 0x00000001 /* NVM Clock */ -#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ -#define E1000_EECD_DI 0x00000004 /* NVM Data In */ -#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ -#define E1000_EECD_FWE_MASK 0x00000030 -#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ -#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ -#define E1000_EECD_FWE_SHIFT 4 -#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ -#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ -#define E1000_EECD_PRES 0x00000100 /* NVM Present */ -#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ -/* NVM Addressing bits based on type 0=small, 1=large */ -#define E1000_EECD_ADDR_BITS 0x00000400 -#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */ -#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ -#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ -#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ -#define E1000_EECD_SIZE_EX_SHIFT 11 -#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ -#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ -#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ -#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ -#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ -#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ -#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ -#define E1000_EECD_SECVAL_SHIFT 22 -#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES) - -#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */ -#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */ -#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write regs */ -#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ -#define E1000_NVM_RW_REG_START 1 /* Start operation */ -#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ -#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ -#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ -#define E1000_FLASH_UPDATES 2000 - -/* NVM Word Offsets */ -#define NVM_COMPAT 0x0003 -#define NVM_ID_LED_SETTINGS 0x0004 -#define NVM_VERSION 0x0005 -#define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */ -#define NVM_PHY_CLASS_WORD 0x0007 -#define NVM_INIT_CONTROL1_REG 0x000A -#define NVM_INIT_CONTROL2_REG 0x000F -#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010 -#define NVM_INIT_CONTROL3_PORT_B 0x0014 -#define NVM_INIT_3GIO_3 0x001A -#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020 -#define NVM_INIT_CONTROL3_PORT_A 0x0024 -#define NVM_CFG 0x0012 -#define NVM_FLASH_VERSION 0x0032 -#define NVM_ALT_MAC_ADDR_PTR 0x0037 -#define NVM_CHECKSUM_REG 0x003F - -#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */ -#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */ - -/* Mask bits for fields in Word 0x0f of the NVM */ -#define NVM_WORD0F_PAUSE_MASK 0x3000 -#define NVM_WORD0F_PAUSE 0x1000 -#define NVM_WORD0F_ASM_DIR 0x2000 -#define NVM_WORD0F_ANE 0x0800 -#define NVM_WORD0F_SWPDIO_EXT_MASK 0x00F0 -#define NVM_WORD0F_LPLU 0x0001 - -/* Mask bits for fields in Word 0x1a of the NVM */ -#define NVM_WORD1A_ASPM_MASK 0x000C - -/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ -#define NVM_SUM 0xBABA - -#define NVM_MAC_ADDR_OFFSET 0 -#define NVM_PBA_OFFSET_0 8 -#define NVM_PBA_OFFSET_1 9 -#define NVM_RESERVED_WORD 0xFFFF -#define NVM_PHY_CLASS_A 0x8000 -#define NVM_SERDES_AMPLITUDE_MASK 0x000F -#define NVM_SIZE_MASK 0x1C00 -#define NVM_SIZE_SHIFT 10 -#define NVM_WORD_SIZE_BASE_SHIFT 6 -#define NVM_SWDPIO_EXT_SHIFT 4 - -/* NVM Commands - Microwire */ -#define NVM_READ_OPCODE_MICROWIRE 0x6 /* NVM read opcode */ -#define NVM_WRITE_OPCODE_MICROWIRE 0x5 /* NVM write opcode */ -#define NVM_ERASE_OPCODE_MICROWIRE 0x7 /* NVM erase opcode */ -#define NVM_EWEN_OPCODE_MICROWIRE 0x13 /* NVM erase/write enable */ -#define NVM_EWDS_OPCODE_MICROWIRE 0x10 /* NVM erase/write disable */ - -/* NVM Commands - SPI */ -#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ -#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */ -#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ -#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ -#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ -#define NVM_WRDI_OPCODE_SPI 0x04 /* NVM reset Write Enable latch */ -#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ -#define NVM_WRSR_OPCODE_SPI 0x01 /* NVM write Status register */ - -/* SPI NVM Status Register */ -#define NVM_STATUS_RDY_SPI 0x01 -#define NVM_STATUS_WEN_SPI 0x02 -#define NVM_STATUS_BP0_SPI 0x04 -#define NVM_STATUS_BP1_SPI 0x08 -#define NVM_STATUS_WPEN_SPI 0x80 - -/* Word definitions for ID LED Settings */ -#define ID_LED_RESERVED_0000 0x0000 -#define ID_LED_RESERVED_FFFF 0xFFFF -#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ - (ID_LED_OFF1_OFF2 << 8) | \ - (ID_LED_DEF1_DEF2 << 4) | \ - (ID_LED_DEF1_DEF2)) -#define ID_LED_DEF1_DEF2 0x1 -#define ID_LED_DEF1_ON2 0x2 -#define ID_LED_DEF1_OFF2 0x3 -#define ID_LED_ON1_DEF2 0x4 -#define ID_LED_ON1_ON2 0x5 -#define ID_LED_ON1_OFF2 0x6 -#define ID_LED_OFF1_DEF2 0x7 -#define ID_LED_OFF1_ON2 0x8 -#define ID_LED_OFF1_OFF2 0x9 - -#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF -#define IGP_ACTIVITY_LED_ENABLE 0x0300 -#define IGP_LED3_MODE 0x07000000 - -/* PCI/PCI-X/PCI-EX Config space */ -#define PCIX_COMMAND_REGISTER 0xE6 -#define PCIX_STATUS_REGISTER_LO 0xE8 -#define PCIX_STATUS_REGISTER_HI 0xEA -#define PCI_HEADER_TYPE_REGISTER 0x0E -#define PCIE_LINK_STATUS 0x12 -#define PCIE_DEVICE_CONTROL2 0x28 - -#define PCIX_COMMAND_MMRBC_MASK 0x000C -#define PCIX_COMMAND_MMRBC_SHIFT 0x2 -#define PCIX_STATUS_HI_MMRBC_MASK 0x0060 -#define PCIX_STATUS_HI_MMRBC_SHIFT 0x5 -#define PCIX_STATUS_HI_MMRBC_4K 0x3 -#define PCIX_STATUS_HI_MMRBC_2K 0x2 -#define PCIX_STATUS_LO_FUNC_MASK 0x7 -#define PCI_HEADER_TYPE_MULTIFUNC 0x80 -#define PCIE_LINK_WIDTH_MASK 0x3F0 -#define PCIE_LINK_WIDTH_SHIFT 4 -#define PCIE_DEVICE_CONTROL2_16ms 0x0005 - -#ifndef ETH_ADDR_LEN -#define ETH_ADDR_LEN 6 -#endif - -#define PHY_REVISION_MASK 0xFFFFFFF0 -#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ -#define MAX_PHY_MULTI_PAGE_REG 0xF - -/* Bit definitions for valid PHY IDs. */ -/* - * I = Integrated - * E = External - */ -#define M88E1000_E_PHY_ID 0x01410C50 -#define M88E1000_I_PHY_ID 0x01410C30 -#define M88E1011_I_PHY_ID 0x01410C20 -#define IGP01E1000_I_PHY_ID 0x02A80380 -#define M88E1011_I_REV_4 0x04 -#define M88E1111_I_PHY_ID 0x01410CC0 -#define GG82563_E_PHY_ID 0x01410CA0 -#define IGP03E1000_E_PHY_ID 0x02A80390 -#define IFE_E_PHY_ID 0x02A80330 -#define IFE_PLUS_E_PHY_ID 0x02A80320 -#define IFE_C_E_PHY_ID 0x02A80310 -#define M88_VENDOR 0x0141 - -/* M88E1000 Specific Registers */ -#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ -#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ -#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ -#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ -#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ -#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ - -#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ -#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ -#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ -#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ -#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ - -/* M88E1000 PHY Specific Control Register */ -#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ -#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */ -#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ -/* 1=CLK125 low, 0=CLK125 toggling */ -#define M88E1000_PSCR_CLK125_DISABLE 0x0010 -#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ - /* Manual MDI configuration */ -#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ -/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ -#define M88E1000_PSCR_AUTO_X_1000T 0x0040 -/* Auto crossover enabled all speeds */ -#define M88E1000_PSCR_AUTO_X_MODE 0x0060 -/* - * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold - * 0=Normal 10BASE-T Rx Threshold - */ -#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080 -/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ -#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 -#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ -#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ -#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Tx */ - -/* M88E1000 PHY Specific Status Register */ -#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ -#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ -#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ -#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ -/* - * 0 = <50M - * 1 = 50-80M - * 2 = 80-110M - * 3 = 110-140M - * 4 = >140M - */ -#define M88E1000_PSSR_CABLE_LENGTH 0x0380 -#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ -#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ -#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ -#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ -#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ -#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ -#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ -#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ - -#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 - -/* M88E1000 Extended PHY Specific Control Register */ -#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ -/* - * 1 = Lost lock detect enabled. - * Will assert lost lock and bring - * link down if idle not seen - * within 1ms in 1000BASE-T - */ -#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 -/* - * Number of times we will attempt to autonegotiate before downshifting if we - * are the master - */ -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00 -/* - * Number of times we will attempt to autonegotiate before downshifting if we - * are the slave - */ -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300 -#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ -#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ -#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ - -/* M88EC018 Rev 2 specific DownShift settings */ -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 - -/* - * Bits... - * 15-5: page - * 4-0: register offset - */ -#define GG82563_PAGE_SHIFT 5 -#define GG82563_REG(page, reg) \ - (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) -#define GG82563_MIN_ALT_REG 30 - -/* GG82563 Specific Registers */ -#define GG82563_PHY_SPEC_CTRL \ - GG82563_REG(0, 16) /* PHY Specific Control */ -#define GG82563_PHY_SPEC_STATUS \ - GG82563_REG(0, 17) /* PHY Specific Status */ -#define GG82563_PHY_INT_ENABLE \ - GG82563_REG(0, 18) /* Interrupt Enable */ -#define GG82563_PHY_SPEC_STATUS_2 \ - GG82563_REG(0, 19) /* PHY Specific Status 2 */ -#define GG82563_PHY_RX_ERR_CNTR \ - GG82563_REG(0, 21) /* Receive Error Counter */ -#define GG82563_PHY_PAGE_SELECT \ - GG82563_REG(0, 22) /* Page Select */ -#define GG82563_PHY_SPEC_CTRL_2 \ - GG82563_REG(0, 26) /* PHY Specific Control 2 */ -#define GG82563_PHY_PAGE_SELECT_ALT \ - GG82563_REG(0, 29) /* Alternate Page Select */ -#define GG82563_PHY_TEST_CLK_CTRL \ - GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */ - -#define GG82563_PHY_MAC_SPEC_CTRL \ - GG82563_REG(2, 21) /* MAC Specific Control Register */ -#define GG82563_PHY_MAC_SPEC_CTRL_2 \ - GG82563_REG(2, 26) /* MAC Specific Control 2 */ - -#define GG82563_PHY_DSP_DISTANCE \ - GG82563_REG(5, 26) /* DSP Distance */ - -/* Page 193 - Port Control Registers */ -#define GG82563_PHY_KMRN_MODE_CTRL \ - GG82563_REG(193, 16) /* Kumeran Mode Control */ -#define GG82563_PHY_PORT_RESET \ - GG82563_REG(193, 17) /* Port Reset */ -#define GG82563_PHY_REVISION_ID \ - GG82563_REG(193, 18) /* Revision ID */ -#define GG82563_PHY_DEVICE_ID \ - GG82563_REG(193, 19) /* Device ID */ -#define GG82563_PHY_PWR_MGMT_CTRL \ - GG82563_REG(193, 20) /* Power Management Control */ -#define GG82563_PHY_RATE_ADAPT_CTRL \ - GG82563_REG(193, 25) /* Rate Adaptation Control */ - -/* Page 194 - KMRN Registers */ -#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \ - GG82563_REG(194, 16) /* FIFO's Control/Status */ -#define GG82563_PHY_KMRN_CTRL \ - GG82563_REG(194, 17) /* Control */ -#define GG82563_PHY_INBAND_CTRL \ - GG82563_REG(194, 18) /* Inband Control */ -#define GG82563_PHY_KMRN_DIAGNOSTIC \ - GG82563_REG(194, 19) /* Diagnostic */ -#define GG82563_PHY_ACK_TIMEOUTS \ - GG82563_REG(194, 20) /* Acknowledge Timeouts */ -#define GG82563_PHY_ADV_ABILITY \ - GG82563_REG(194, 21) /* Advertised Ability */ -#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \ - GG82563_REG(194, 23) /* Link Partner Advertised Ability */ -#define GG82563_PHY_ADV_NEXT_PAGE \ - GG82563_REG(194, 24) /* Advertised Next Page */ -#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \ - GG82563_REG(194, 25) /* Link Partner Advertised Next page */ -#define GG82563_PHY_KMRN_MISC \ - GG82563_REG(194, 26) /* Misc. */ - -/* MDI Control */ -#define E1000_MDIC_DATA_MASK 0x0000FFFF -#define E1000_MDIC_REG_MASK 0x001F0000 -#define E1000_MDIC_REG_SHIFT 16 -#define E1000_MDIC_PHY_MASK 0x03E00000 -#define E1000_MDIC_PHY_SHIFT 21 -#define E1000_MDIC_OP_WRITE 0x04000000 -#define E1000_MDIC_OP_READ 0x08000000 -#define E1000_MDIC_READY 0x10000000 -#define E1000_MDIC_INT_EN 0x20000000 -#define E1000_MDIC_ERROR 0x40000000 - -/* SerDes Control */ -#define E1000_GEN_CTL_READY 0x80000000 -#define E1000_GEN_CTL_ADDRESS_SHIFT 8 -#define E1000_GEN_POLL_TIMEOUT 640 - - - -#endif /* _E1000_DEFINES_H_ */ diff --git a/src/drivers/net/e1000/e1000_hw.h b/src/drivers/net/e1000/e1000_hw.h deleted file mode 100644 index 753f75e7..00000000 --- a/src/drivers/net/e1000/e1000_hw.h +++ /dev/null @@ -1,728 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_HW_H_ -#define _E1000_HW_H_ - -#include "e1000_osdep.h" -#include "e1000_regs.h" -#include "e1000_defines.h" - -struct e1000_hw; - -#define E1000_DEV_ID_82542 0x1000 -#define E1000_DEV_ID_82543GC_FIBER 0x1001 -#define E1000_DEV_ID_82543GC_COPPER 0x1004 -#define E1000_DEV_ID_82544EI_COPPER 0x1008 -#define E1000_DEV_ID_82544EI_FIBER 0x1009 -#define E1000_DEV_ID_82544GC_COPPER 0x100C -#define E1000_DEV_ID_82544GC_LOM 0x100D -#define E1000_DEV_ID_82540EM 0x100E -#define E1000_DEV_ID_82540EM_LOM 0x1015 -#define E1000_DEV_ID_82540EP_LOM 0x1016 -#define E1000_DEV_ID_82540EP 0x1017 -#define E1000_DEV_ID_82540EP_LP 0x101E -#define E1000_DEV_ID_82545EM_COPPER 0x100F -#define E1000_DEV_ID_82545EM_FIBER 0x1011 -#define E1000_DEV_ID_82545GM_COPPER 0x1026 -#define E1000_DEV_ID_82545GM_FIBER 0x1027 -#define E1000_DEV_ID_82545GM_SERDES 0x1028 -#define E1000_DEV_ID_82546EB_COPPER 0x1010 -#define E1000_DEV_ID_82546EB_FIBER 0x1012 -#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D -#define E1000_DEV_ID_82546GB_COPPER 0x1079 -#define E1000_DEV_ID_82546GB_FIBER 0x107A -#define E1000_DEV_ID_82546GB_SERDES 0x107B -#define E1000_DEV_ID_82546GB_PCIE 0x108A -#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099 -#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 -#define E1000_DEV_ID_82541EI 0x1013 -#define E1000_DEV_ID_82541EI_MOBILE 0x1018 -#define E1000_DEV_ID_82541ER_LOM 0x1014 -#define E1000_DEV_ID_82541ER 0x1078 -#define E1000_DEV_ID_82541GI 0x1076 -#define E1000_DEV_ID_82541GI_LF 0x107C -#define E1000_DEV_ID_82541GI_MOBILE 0x1077 -#define E1000_DEV_ID_82547EI 0x1019 -#define E1000_DEV_ID_82547EI_MOBILE 0x101A -#define E1000_DEV_ID_82547GI 0x1075 -#define E1000_REVISION_0 0 -#define E1000_REVISION_1 1 -#define E1000_REVISION_2 2 -#define E1000_REVISION_3 3 -#define E1000_REVISION_4 4 - -#define E1000_FUNC_0 0 -#define E1000_FUNC_1 1 - -#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0 -#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3 - -enum e1000_mac_type { - e1000_undefined = 0, - e1000_82542, - e1000_82543, - e1000_82544, - e1000_82540, - e1000_82545, - e1000_82545_rev_3, - e1000_82546, - e1000_82546_rev_3, - e1000_82541, - e1000_82541_rev_2, - e1000_82547, - e1000_82547_rev_2, - e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ -}; - -enum e1000_media_type { - e1000_media_type_unknown = 0, - e1000_media_type_copper = 1, - e1000_media_type_fiber = 2, - e1000_media_type_internal_serdes = 3, - e1000_num_media_types -}; - -enum e1000_nvm_type { - e1000_nvm_unknown = 0, - e1000_nvm_none, - e1000_nvm_eeprom_spi, - e1000_nvm_eeprom_microwire, - e1000_nvm_flash_hw, - e1000_nvm_flash_sw -}; - -enum e1000_nvm_override { - e1000_nvm_override_none = 0, - e1000_nvm_override_spi_small, - e1000_nvm_override_spi_large, - e1000_nvm_override_microwire_small, - e1000_nvm_override_microwire_large -}; - -enum e1000_phy_type { - e1000_phy_unknown = 0, - e1000_phy_none, - e1000_phy_m88, - e1000_phy_igp, - e1000_phy_igp_2, - e1000_phy_gg82563, - e1000_phy_igp_3, - e1000_phy_ife, -}; - -enum e1000_bus_type { - e1000_bus_type_unknown = 0, - e1000_bus_type_pci, - e1000_bus_type_pcix, - e1000_bus_type_pci_express, - e1000_bus_type_reserved -}; - -enum e1000_bus_speed { - e1000_bus_speed_unknown = 0, - e1000_bus_speed_33, - e1000_bus_speed_66, - e1000_bus_speed_100, - e1000_bus_speed_120, - e1000_bus_speed_133, - e1000_bus_speed_2500, - e1000_bus_speed_5000, - e1000_bus_speed_reserved -}; - -enum e1000_bus_width { - e1000_bus_width_unknown = 0, - e1000_bus_width_pcie_x1, - e1000_bus_width_pcie_x2, - e1000_bus_width_pcie_x4 = 4, - e1000_bus_width_pcie_x8 = 8, - e1000_bus_width_32, - e1000_bus_width_64, - e1000_bus_width_reserved -}; - -enum e1000_1000t_rx_status { - e1000_1000t_rx_status_not_ok = 0, - e1000_1000t_rx_status_ok, - e1000_1000t_rx_status_undefined = 0xFF -}; - -enum e1000_rev_polarity { - e1000_rev_polarity_normal = 0, - e1000_rev_polarity_reversed, - e1000_rev_polarity_undefined = 0xFF -}; - -enum e1000_fc_mode { - e1000_fc_none = 0, - e1000_fc_rx_pause, - e1000_fc_tx_pause, - e1000_fc_full, - e1000_fc_default = 0xFF -}; - -enum e1000_ffe_config { - e1000_ffe_config_enabled = 0, - e1000_ffe_config_active, - e1000_ffe_config_blocked -}; - -enum e1000_dsp_config { - e1000_dsp_config_disabled = 0, - e1000_dsp_config_enabled, - e1000_dsp_config_activated, - e1000_dsp_config_undefined = 0xFF -}; - -enum e1000_ms_type { - e1000_ms_hw_default = 0, - e1000_ms_force_master, - e1000_ms_force_slave, - e1000_ms_auto -}; - -enum e1000_smart_speed { - e1000_smart_speed_default = 0, - e1000_smart_speed_on, - e1000_smart_speed_off -}; - -enum e1000_serdes_link_state { - e1000_serdes_link_down = 0, - e1000_serdes_link_autoneg_progress, - e1000_serdes_link_autoneg_complete, - e1000_serdes_link_forced_up -}; - -/* Receive Descriptor */ -struct e1000_rx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - __le16 length; /* Length of data DMAed into data buffer */ - __le16 csum; /* Packet checksum */ - u8 status; /* Descriptor status */ - u8 errors; /* Descriptor Errors */ - __le16 special; -}; - -/* Receive Descriptor - Extended */ -union e1000_rx_desc_extended { - struct { - __le64 buffer_addr; - __le64 reserved; - } read; - struct { - struct { - __le32 mrq; /* Multiple Rx Queues */ - union { - __le32 rss; /* RSS Hash */ - struct { - __le16 ip_id; /* IP id */ - __le16 csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - __le32 status_error; /* ext status/error */ - __le16 length; - __le16 vlan; /* VLAN tag */ - } upper; - } wb; /* writeback */ -}; - -#define MAX_PS_BUFFERS 4 -/* Receive Descriptor - Packet Split */ -union e1000_rx_desc_packet_split { - struct { - /* one buffer for protocol header(s), three data buffers */ - __le64 buffer_addr[MAX_PS_BUFFERS]; - } read; - struct { - struct { - __le32 mrq; /* Multiple Rx Queues */ - union { - __le32 rss; /* RSS Hash */ - struct { - __le16 ip_id; /* IP id */ - __le16 csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - __le32 status_error; /* ext status/error */ - __le16 length0; /* length of buffer 0 */ - __le16 vlan; /* VLAN tag */ - } middle; - struct { - __le16 header_status; - __le16 length[3]; /* length of buffers 1-3 */ - } upper; - __le64 reserved; - } wb; /* writeback */ -}; - -/* Transmit Descriptor */ -struct e1000_tx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 cso; /* Checksum offset */ - u8 cmd; /* Descriptor control */ - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 css; /* Checksum start */ - __le16 special; - } fields; - } upper; -}; - -/* Offload Context Descriptor */ -struct e1000_context_desc { - union { - __le32 ip_config; - struct { - u8 ipcss; /* IP checksum start */ - u8 ipcso; /* IP checksum offset */ - __le16 ipcse; /* IP checksum end */ - } ip_fields; - } lower_setup; - union { - __le32 tcp_config; - struct { - u8 tucss; /* TCP checksum start */ - u8 tucso; /* TCP checksum offset */ - __le16 tucse; /* TCP checksum end */ - } tcp_fields; - } upper_setup; - __le32 cmd_and_length; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 hdr_len; /* Header length */ - __le16 mss; /* Maximum segment size */ - } fields; - } tcp_seg_setup; -}; - -/* Offload data descriptor */ -struct e1000_data_desc { - __le64 buffer_addr; /* Address of the descriptor's buffer address */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 typ_len_ext; - u8 cmd; - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 popts; /* Packet Options */ - __le16 special; - } fields; - } upper; -}; - -/* Statistics counters collected by the MAC */ -struct e1000_hw_stats { - u64 crcerrs; - u64 algnerrc; - u64 symerrs; - u64 rxerrc; - u64 mpc; - u64 scc; - u64 ecol; - u64 mcc; - u64 latecol; - u64 colc; - u64 dc; - u64 tncrs; - u64 sec; - u64 cexterr; - u64 rlec; - u64 xonrxc; - u64 xontxc; - u64 xoffrxc; - u64 xofftxc; - u64 fcruc; - u64 prc64; - u64 prc127; - u64 prc255; - u64 prc511; - u64 prc1023; - u64 prc1522; - u64 gprc; - u64 bprc; - u64 mprc; - u64 gptc; - u64 gorc; - u64 gotc; - u64 rnbc; - u64 ruc; - u64 rfc; - u64 roc; - u64 rjc; - u64 mgprc; - u64 mgpdc; - u64 mgptc; - u64 tor; - u64 tot; - u64 tpr; - u64 tpt; - u64 ptc64; - u64 ptc127; - u64 ptc255; - u64 ptc511; - u64 ptc1023; - u64 ptc1522; - u64 mptc; - u64 bptc; - u64 tsctc; - u64 tsctfc; - u64 iac; - u64 icrxptc; - u64 icrxatc; - u64 ictxptc; - u64 ictxatc; - u64 ictxqec; - u64 ictxqmtc; - u64 icrxdmtc; - u64 icrxoc; - u64 cbtmpc; - u64 htdpmc; - u64 cbrdpc; - u64 cbrmpc; - u64 rpthc; - u64 hgptc; - u64 htcbdpc; - u64 hgorc; - u64 hgotc; - u64 lenerrs; - u64 scvpc; - u64 hrmpc; - u64 doosync; -}; - - -struct e1000_phy_stats { - u32 idle_errors; - u32 receive_errors; -}; - -struct e1000_host_mng_dhcp_cookie { - u32 signature; - u8 status; - u8 reserved0; - u16 vlan_id; - u32 reserved1; - u16 reserved2; - u8 reserved3; - u8 checksum; -}; - -/* Host Interface "Rev 1" */ -struct e1000_host_command_header { - u8 command_id; - u8 command_length; - u8 command_options; - u8 checksum; -}; - -#define E1000_HI_MAX_DATA_LENGTH 252 -struct e1000_host_command_info { - struct e1000_host_command_header command_header; - u8 command_data[E1000_HI_MAX_DATA_LENGTH]; -}; - -/* Host Interface "Rev 2" */ -struct e1000_host_mng_command_header { - u8 command_id; - u8 checksum; - u16 reserved1; - u16 reserved2; - u16 command_length; -}; - -#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 -struct e1000_host_mng_command_info { - struct e1000_host_mng_command_header command_header; - u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; -}; - -#include "e1000_mac.h" -#include "e1000_phy.h" -#include "e1000_nvm.h" -#include "e1000_manage.h" - -struct e1000_mac_operations { - /* Function pointers for the MAC. */ - s32 (*init_params)(struct e1000_hw *); - s32 (*id_led_init)(struct e1000_hw *); - s32 (*blink_led)(struct e1000_hw *); - s32 (*check_for_link)(struct e1000_hw *); - bool (*check_mng_mode)(struct e1000_hw *hw); - s32 (*cleanup_led)(struct e1000_hw *); - void (*clear_hw_cntrs)(struct e1000_hw *); - void (*clear_vfta)(struct e1000_hw *); - s32 (*get_bus_info)(struct e1000_hw *); - void (*set_lan_id)(struct e1000_hw *); - s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); - s32 (*led_on)(struct e1000_hw *); - s32 (*led_off)(struct e1000_hw *); - void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32); - s32 (*reset_hw)(struct e1000_hw *); - s32 (*init_hw)(struct e1000_hw *); - s32 (*setup_link)(struct e1000_hw *); - s32 (*setup_physical_interface)(struct e1000_hw *); - s32 (*setup_led)(struct e1000_hw *); - void (*write_vfta)(struct e1000_hw *, u32, u32); - void (*mta_set)(struct e1000_hw *, u32); - void (*config_collision_dist)(struct e1000_hw *); - void (*rar_set)(struct e1000_hw *, u8*, u32); - s32 (*read_mac_addr)(struct e1000_hw *); - s32 (*validate_mdi_setting)(struct e1000_hw *); - s32 (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*); - s32 (*mng_write_cmd_header)(struct e1000_hw *hw, - struct e1000_host_mng_command_header*); - s32 (*mng_enable_host_if)(struct e1000_hw *); - s32 (*wait_autoneg)(struct e1000_hw *); -}; - -struct e1000_phy_operations { - s32 (*init_params)(struct e1000_hw *); - s32 (*acquire)(struct e1000_hw *); - s32 (*check_polarity)(struct e1000_hw *); - s32 (*check_reset_block)(struct e1000_hw *); - s32 (*commit)(struct e1000_hw *); -#if 0 - s32 (*force_speed_duplex)(struct e1000_hw *); -#endif - s32 (*get_cfg_done)(struct e1000_hw *hw); -#if 0 - s32 (*get_cable_length)(struct e1000_hw *); -#endif - s32 (*get_info)(struct e1000_hw *); - s32 (*read_reg)(struct e1000_hw *, u32, u16 *); - void (*release)(struct e1000_hw *); - s32 (*reset)(struct e1000_hw *); - s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); - s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); - s32 (*write_reg)(struct e1000_hw *, u32, u16); - void (*power_up)(struct e1000_hw *); - void (*power_down)(struct e1000_hw *); -}; - -struct e1000_nvm_operations { - s32 (*init_params)(struct e1000_hw *); - s32 (*acquire)(struct e1000_hw *); - s32 (*read)(struct e1000_hw *, u16, u16, u16 *); - void (*release)(struct e1000_hw *); - void (*reload)(struct e1000_hw *); - s32 (*update)(struct e1000_hw *); - s32 (*valid_led_default)(struct e1000_hw *, u16 *); - s32 (*validate)(struct e1000_hw *); - s32 (*write)(struct e1000_hw *, u16, u16, u16 *); -}; - -struct e1000_mac_info { - struct e1000_mac_operations ops; - u8 addr[6]; - u8 perm_addr[6]; - - enum e1000_mac_type type; - - u32 collision_delta; - u32 ledctl_default; - u32 ledctl_mode1; - u32 ledctl_mode2; - u32 mc_filter_type; - u32 tx_packet_delta; - u32 txcw; - - u16 current_ifs_val; - u16 ifs_max_val; - u16 ifs_min_val; - u16 ifs_ratio; - u16 ifs_step_size; - u16 mta_reg_count; - - /* Maximum size of the MTA register table in all supported adapters */ - #define MAX_MTA_REG 128 - u32 mta_shadow[MAX_MTA_REG]; - u16 rar_entry_count; - - u8 forced_speed_duplex; - - bool adaptive_ifs; - bool arc_subsystem_valid; - bool asf_firmware_present; - bool autoneg; - bool autoneg_failed; - bool get_link_status; - bool in_ifs_mode; - bool report_tx_early; - enum e1000_serdes_link_state serdes_link_state; - bool serdes_has_link; - bool tx_pkt_filtering; -}; - -struct e1000_phy_info { - struct e1000_phy_operations ops; - enum e1000_phy_type type; - - enum e1000_1000t_rx_status local_rx; - enum e1000_1000t_rx_status remote_rx; - enum e1000_ms_type ms_type; - enum e1000_ms_type original_ms_type; - enum e1000_rev_polarity cable_polarity; - enum e1000_smart_speed smart_speed; - - u32 addr; - u32 id; - u32 reset_delay_us; /* in usec */ - u32 revision; - - enum e1000_media_type media_type; - - u16 autoneg_advertised; - u16 autoneg_mask; - u16 cable_length; - u16 max_cable_length; - u16 min_cable_length; - - u8 mdix; - - bool disable_polarity_correction; - bool is_mdix; - bool polarity_correction; - bool reset_disable; - bool speed_downgraded; - bool autoneg_wait_to_complete; -}; - -struct e1000_nvm_info { - struct e1000_nvm_operations ops; - enum e1000_nvm_type type; - enum e1000_nvm_override override; - - u32 flash_bank_size; - u32 flash_base_addr; - - u16 word_size; - u16 delay_usec; - u16 address_bits; - u16 opcode_bits; - u16 page_size; -}; - -struct e1000_bus_info { - enum e1000_bus_type type; - enum e1000_bus_speed speed; - enum e1000_bus_width width; - - u16 func; - u16 pci_cmd_word; -}; - -struct e1000_fc_info { - u32 high_water; /* Flow control high-water mark */ - u32 low_water; /* Flow control low-water mark */ - u16 pause_time; /* Flow control pause timer */ - bool send_xon; /* Flow control send XON */ - bool strict_ieee; /* Strict IEEE mode */ - enum e1000_fc_mode current_mode; /* FC mode in effect */ - enum e1000_fc_mode requested_mode; /* FC mode requested by caller */ -}; - -struct e1000_dev_spec_82541 { - enum e1000_dsp_config dsp_config; - enum e1000_ffe_config ffe_config; - u16 spd_default; - bool phy_init_script; -}; - -struct e1000_dev_spec_82542 { - bool dma_fairness; -}; - -struct e1000_dev_spec_82543 { - u32 tbi_compatibility; - bool dma_fairness; - bool init_phy_disabled; -}; - -struct e1000_hw { - void *back; - - u8 __iomem *hw_addr; - u8 __iomem *flash_address; - unsigned long io_base; - - struct e1000_mac_info mac; - struct e1000_fc_info fc; - struct e1000_phy_info phy; - struct e1000_nvm_info nvm; - struct e1000_bus_info bus; - struct e1000_host_mng_dhcp_cookie mng_cookie; - - union { - struct e1000_dev_spec_82541 _82541; - struct e1000_dev_spec_82542 _82542; - struct e1000_dev_spec_82543 _82543; - } dev_spec; - - u16 device_id; - u16 subsystem_vendor_id; - u16 subsystem_device_id; - u16 vendor_id; - - u8 revision_id; -}; - -#include "e1000_82541.h" -#include "e1000_82543.h" - -/* These functions must be implemented by drivers */ -void e1000_pci_clear_mwi(struct e1000_hw *hw); -void e1000_pci_set_mwi(struct e1000_hw *hw); -s32 e1000_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); -void e1000_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value); -void e1000_write_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value); - -#endif diff --git a/src/drivers/net/e1000/e1000_mac.c b/src/drivers/net/e1000/e1000_mac.c deleted file mode 100644 index 23513879..00000000 --- a/src/drivers/net/e1000/e1000_mac.c +++ /dev/null @@ -1,2196 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000_api.h" - -static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw); -static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw); - -/** - * e1000_init_mac_ops_generic - Initialize MAC function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void e1000_init_mac_ops_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - DEBUGFUNC("e1000_init_mac_ops_generic"); - - /* General Setup */ - mac->ops.init_params = e1000_null_ops_generic; - mac->ops.init_hw = e1000_null_ops_generic; - mac->ops.reset_hw = e1000_null_ops_generic; - mac->ops.setup_physical_interface = e1000_null_ops_generic; - mac->ops.get_bus_info = e1000_null_ops_generic; - mac->ops.set_lan_id = e1000_set_lan_id_multi_port_pcie; - mac->ops.read_mac_addr = e1000_read_mac_addr_generic; - mac->ops.config_collision_dist = e1000_config_collision_dist_generic; - mac->ops.clear_hw_cntrs = e1000_null_mac_generic; - /* LED */ - mac->ops.cleanup_led = e1000_null_ops_generic; - mac->ops.setup_led = e1000_null_ops_generic; - mac->ops.blink_led = e1000_null_ops_generic; - mac->ops.led_on = e1000_null_ops_generic; - mac->ops.led_off = e1000_null_ops_generic; - /* LINK */ - mac->ops.setup_link = e1000_null_ops_generic; - mac->ops.get_link_up_info = e1000_null_link_info; - mac->ops.check_for_link = e1000_null_ops_generic; - mac->ops.wait_autoneg = e1000_wait_autoneg_generic; -#if 0 - /* Management */ - mac->ops.check_mng_mode = e1000_null_mng_mode; - mac->ops.mng_host_if_write = e1000_mng_host_if_write_generic; - mac->ops.mng_write_cmd_header = e1000_mng_write_cmd_header_generic; - mac->ops.mng_enable_host_if = e1000_mng_enable_host_if_generic; -#endif - /* VLAN, MC, etc. */ - mac->ops.update_mc_addr_list = e1000_null_update_mc; - mac->ops.clear_vfta = e1000_null_mac_generic; - mac->ops.write_vfta = e1000_null_write_vfta; - mac->ops.mta_set = e1000_null_mta_set; - mac->ops.rar_set = e1000_rar_set_generic; - mac->ops.validate_mdi_setting = e1000_validate_mdi_setting_generic; -} - -/** - * e1000_null_ops_generic - No-op function, returns 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_ops_generic(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("e1000_null_ops_generic"); - return E1000_SUCCESS; -} - -/** - * e1000_null_mac_generic - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_mac_generic(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("e1000_null_mac_generic"); - return; -} - -/** - * e1000_null_link_info - No-op function, return 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_link_info(struct e1000_hw *hw __unused, - u16 *s __unused, u16 *d __unused) -{ - DEBUGFUNC("e1000_null_link_info"); - return E1000_SUCCESS; -} - -/** - * e1000_null_mng_mode - No-op function, return false - * @hw: pointer to the HW structure - **/ -bool e1000_null_mng_mode(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("e1000_null_mng_mode"); - return false; -} - -/** - * e1000_null_update_mc - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_update_mc(struct e1000_hw *hw __unused, - u8 *h __unused, u32 a __unused) -{ - DEBUGFUNC("e1000_null_update_mc"); - return; -} - -/** - * e1000_null_write_vfta - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_write_vfta(struct e1000_hw *hw __unused, - u32 a __unused, u32 b __unused) -{ - DEBUGFUNC("e1000_null_write_vfta"); - return; -} - -/** - * e1000_null_set_mta - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_mta_set(struct e1000_hw *hw __unused, u32 a __unused) -{ - DEBUGFUNC("e1000_null_mta_set"); - return; -} - -/** - * e1000_null_rar_set - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_rar_set(struct e1000_hw *hw __unused, u8 *h __unused, - u32 a __unused) -{ - DEBUGFUNC("e1000_null_rar_set"); - return; -} - -/** - * e1000_get_bus_info_pci_generic - Get PCI(x) bus information - * @hw: pointer to the HW structure - * - * Determines and stores the system bus information for a particular - * network interface. The following bus information is determined and stored: - * bus speed, bus width, type (PCI/PCIx), and PCI(-x) function. - **/ -s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw __unused) -{ -#if 0 - struct e1000_mac_info *mac = &hw->mac; - struct e1000_bus_info *bus = &hw->bus; - u32 status = E1000_READ_REG(hw, E1000_STATUS); - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_get_bus_info_pci_generic"); - - /* PCI or PCI-X? */ - bus->type = (status & E1000_STATUS_PCIX_MODE) - ? e1000_bus_type_pcix - : e1000_bus_type_pci; - - /* Bus speed */ - if (bus->type == e1000_bus_type_pci) { - bus->speed = (status & E1000_STATUS_PCI66) - ? e1000_bus_speed_66 - : e1000_bus_speed_33; - } else { - switch (status & E1000_STATUS_PCIX_SPEED) { - case E1000_STATUS_PCIX_SPEED_66: - bus->speed = e1000_bus_speed_66; - break; - case E1000_STATUS_PCIX_SPEED_100: - bus->speed = e1000_bus_speed_100; - break; - case E1000_STATUS_PCIX_SPEED_133: - bus->speed = e1000_bus_speed_133; - break; - default: - bus->speed = e1000_bus_speed_reserved; - break; - } - } - - /* Bus width */ - bus->width = (status & E1000_STATUS_BUS64) - ? e1000_bus_width_64 - : e1000_bus_width_32; - - /* Which PCI(-X) function? */ - mac->ops.set_lan_id(hw); - - return ret_val; -#endif - return 0; -} - -/** - * e1000_get_bus_info_pcie_generic - Get PCIe bus information - * @hw: pointer to the HW structure - * - * Determines and stores the system bus information for a particular - * network interface. The following bus information is determined and stored: - * bus speed, bus width, type (PCIe), and PCIe function. - **/ -s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw __unused) -{ -#if 0 - struct e1000_mac_info *mac = &hw->mac; - struct e1000_bus_info *bus = &hw->bus; - - s32 ret_val; - u16 pcie_link_status; - - DEBUGFUNC("e1000_get_bus_info_pcie_generic"); - - bus->type = e1000_bus_type_pci_express; - bus->speed = e1000_bus_speed_2500; - - ret_val = e1000_read_pcie_cap_reg(hw, - PCIE_LINK_STATUS, - &pcie_link_status); - if (ret_val) - bus->width = e1000_bus_width_unknown; - else - bus->width = (enum e1000_bus_width)((pcie_link_status & - PCIE_LINK_WIDTH_MASK) >> - PCIE_LINK_WIDTH_SHIFT); - - mac->ops.set_lan_id(hw); - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices - * - * @hw: pointer to the HW structure - * - * Determines the LAN function id by reading memory-mapped registers - * and swaps the port value if requested. - **/ -static void e1000_set_lan_id_multi_port_pcie(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - u32 reg; - - /* - * The status register reports the correct function number - * for the device regardless of function swap state. - */ - reg = E1000_READ_REG(hw, E1000_STATUS); - bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; -} - -/** - * e1000_set_lan_id_multi_port_pci - Set LAN id for PCI multiple port devices - * @hw: pointer to the HW structure - * - * Determines the LAN function id by reading PCI config space. - **/ -void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - u16 pci_header_type; - u32 status; - - e1000_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); - if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { - status = E1000_READ_REG(hw, E1000_STATUS); - bus->func = (status & E1000_STATUS_FUNC_MASK) - >> E1000_STATUS_FUNC_SHIFT; - } else { - bus->func = 0; - } -} - -/** - * e1000_set_lan_id_single_port - Set LAN id for a single port device - * @hw: pointer to the HW structure - * - * Sets the LAN function id to zero for a single port device. - **/ -void e1000_set_lan_id_single_port(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - - bus->func = 0; -} - -/** - * e1000_clear_vfta_generic - Clear VLAN filter table - * @hw: pointer to the HW structure - * - * Clears the register array which contains the VLAN filter table by - * setting all the values to 0. - **/ -void e1000_clear_vfta_generic(struct e1000_hw *hw) -{ - u32 offset; - - DEBUGFUNC("e1000_clear_vfta_generic"); - - for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0); - E1000_WRITE_FLUSH(hw); - } -} - -/** - * e1000_write_vfta_generic - Write value to VLAN filter table - * @hw: pointer to the HW structure - * @offset: register offset in VLAN filter table - * @value: register value written to VLAN filter table - * - * Writes value at the given offset in the register array which stores - * the VLAN filter table. - **/ -void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) -{ - DEBUGFUNC("e1000_write_vfta_generic"); - - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); - E1000_WRITE_FLUSH(hw); -} - -/** - * e1000_init_rx_addrs_generic - Initialize receive address's - * @hw: pointer to the HW structure - * @rar_count: receive address registers - * - * Setups the receive address registers by setting the base receive address - * register to the devices MAC address and clearing all the other receive - * address registers to 0. - **/ -void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count) -{ - u32 i; - u8 mac_addr[ETH_ADDR_LEN] = {0}; - - DEBUGFUNC("e1000_init_rx_addrs_generic"); - - /* Setup the receive address */ - DEBUGOUT("Programming MAC Address into RAR[0]\n"); - - hw->mac.ops.rar_set(hw, hw->mac.addr, 0); - - /* Zero out the other (rar_entry_count - 1) receive addresses */ - DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1); - for (i = 1; i < rar_count; i++) - hw->mac.ops.rar_set(hw, mac_addr, i); -} - -/** - * e1000_check_alt_mac_addr_generic - Check for alternate MAC addr - * @hw: pointer to the HW structure - * - * Checks the nvm for an alternate MAC address. An alternate MAC address - * can be setup by pre-boot software and must be treated like a permanent - * address and must override the actual permanent MAC address. If an - * alternate MAC address is found it is programmed into RAR0, replacing - * the permanent address that was installed into RAR0 by the Si on reset. - * This function will return SUCCESS unless it encounters an error while - * reading the EEPROM. - **/ -s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw) -{ - u32 i; - s32 ret_val = E1000_SUCCESS; - u16 offset, nvm_alt_mac_addr_offset, nvm_data; - u8 alt_mac_addr[ETH_ADDR_LEN]; - - DEBUGFUNC("e1000_check_alt_mac_addr_generic"); - - ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1, - &nvm_alt_mac_addr_offset); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - if (nvm_alt_mac_addr_offset == 0xFFFF) { - /* There is no Alternate MAC Address */ - goto out; - } - - if (hw->bus.func == E1000_FUNC_1) - nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1; - for (i = 0; i < ETH_ADDR_LEN; i += 2) { - offset = nvm_alt_mac_addr_offset + (i >> 1); - ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - alt_mac_addr[i] = (u8)(nvm_data & 0xFF); - alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); - } - - /* if multicast bit is set, the alternate address will not be used */ - if (alt_mac_addr[0] & 0x01) { - DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n"); - goto out; - } - - /* - * We have a valid alternate MAC address, and we want to treat it the - * same as the normal permanent MAC address stored by the HW into the - * RAR. Do this by mapping this address into RAR0. - */ - hw->mac.ops.rar_set(hw, alt_mac_addr, 0); - -out: - return ret_val; -} - -/** - * e1000_rar_set_generic - Set receive address register - * @hw: pointer to the HW structure - * @addr: pointer to the receive address - * @index: receive address array register - * - * Sets the receive address array register at index to the address passed - * in by addr. - **/ -void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index) -{ - u32 rar_low, rar_high; - - DEBUGFUNC("e1000_rar_set_generic"); - - /* - * HW expects these in little endian so we reverse the byte order - * from network order (big endian) to little endian - */ - rar_low = ((u32) addr[0] | - ((u32) addr[1] << 8) | - ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); - - rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); - - /* If MAC address zero, no need to set the AV bit */ - if (rar_low || rar_high) - rar_high |= E1000_RAH_AV; - - /* - * Some bridges will combine consecutive 32-bit writes into - * a single burst write, which will malfunction on some parts. - * The flushes avoid this. - */ - E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); - E1000_WRITE_FLUSH(hw); - E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); - E1000_WRITE_FLUSH(hw); -} - -/** - * e1000_mta_set_generic - Set multicast filter table address - * @hw: pointer to the HW structure - * @hash_value: determines the MTA register and bit to set - * - * The multicast table address is a register array of 32-bit registers. - * The hash_value is used to determine what register the bit is in, the - * current value is read, the new bit is OR'd in and the new value is - * written back into the register. - **/ -void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg, mta; - - DEBUGFUNC("e1000_mta_set_generic"); - /* - * The MTA is a register array of 32-bit registers. It is - * treated like an array of (32*mta_reg_count) bits. We want to - * set bit BitArray[hash_value]. So we figure out what register - * the bit is in, read it, OR in the new bit, then write - * back the new value. The (hw->mac.mta_reg_count - 1) serves as a - * mask to bits 31:5 of the hash value which gives us the - * register we're modifying. The hash bit within that register - * is determined by the lower 5 bits of the hash value. - */ - hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - - mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); - - mta |= (1 << hash_bit); - - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); - E1000_WRITE_FLUSH(hw); -} - -/** - * e1000_update_mc_addr_list_generic - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * - * Updates entire Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - **/ -void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count) -{ - u32 hash_value, hash_bit, hash_reg; - int i; - - DEBUGFUNC("e1000_update_mc_addr_list_generic"); - - /* clear mta_shadow */ - memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); - - /* update mta_shadow from mc_addr_list */ - for (i = 0; (u32) i < mc_addr_count; i++) { - hash_value = e1000_hash_mc_addr_generic(hw, mc_addr_list); - - hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - - hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit); - mc_addr_list += (ETH_ADDR_LEN); - } - - /* replace the entire MTA table */ - for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]); - E1000_WRITE_FLUSH(hw); -} - -/** - * e1000_hash_mc_addr_generic - Generate a multicast hash value - * @hw: pointer to the HW structure - * @mc_addr: pointer to a multicast address - * - * Generates a multicast address hash value which is used to determine - * the multicast filter table array address and new table value. See - * e1000_mta_set_generic() - **/ -u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr) -{ - u32 hash_value, hash_mask; - u8 bit_shift = 0; - - DEBUGFUNC("e1000_hash_mc_addr_generic"); - - /* Register count multiplied by bits per register */ - hash_mask = (hw->mac.mta_reg_count * 32) - 1; - - /* - * For a mc_filter_type of 0, bit_shift is the number of left-shifts - * where 0xFF would still fall within the hash mask. - */ - while (hash_mask >> bit_shift != 0xFF) - bit_shift++; - - /* - * The portion of the address that is used for the hash table - * is determined by the mc_filter_type setting. - * The algorithm is such that there is a total of 8 bits of shifting. - * The bit_shift for a mc_filter_type of 0 represents the number of - * left-shifts where the MSB of mc_addr[5] would still fall within - * the hash_mask. Case 0 does this exactly. Since there are a total - * of 8 bits of shifting, then mc_addr[4] will shift right the - * remaining number of bits. Thus 8 - bit_shift. The rest of the - * cases are a variation of this algorithm...essentially raising the - * number of bits to shift mc_addr[5] left, while still keeping the - * 8-bit shifting total. - * - * For example, given the following Destination MAC Address and an - * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), - * we can see that the bit_shift for case 0 is 4. These are the hash - * values resulting from each mc_filter_type... - * [0] [1] [2] [3] [4] [5] - * 01 AA 00 12 34 56 - * LSB MSB - * - * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 - * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 - * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 - * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 - */ - switch (hw->mac.mc_filter_type) { - default: - case 0: - break; - case 1: - bit_shift += 1; - break; - case 2: - bit_shift += 2; - break; - case 3: - bit_shift += 4; - break; - } - - hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | - (((u16) mc_addr[5]) << bit_shift))); - - return hash_value; -} - -/** - * e1000_pcix_mmrbc_workaround_generic - Fix incorrect MMRBC value - * @hw: pointer to the HW structure - * - * In certain situations, a system BIOS may report that the PCIx maximum - * memory read byte count (MMRBC) value is higher than than the actual - * value. We check the PCIx command register with the current PCIx status - * register. - **/ -void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw) -{ - u16 cmd_mmrbc; - u16 pcix_cmd; - u16 pcix_stat_hi_word; - u16 stat_mmrbc; - - DEBUGFUNC("e1000_pcix_mmrbc_workaround_generic"); - - /* Workaround for PCI-X issue when BIOS sets MMRBC incorrectly */ - if (hw->bus.type != e1000_bus_type_pcix) - return; - - e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd); - e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word); - cmd_mmrbc = (pcix_cmd & PCIX_COMMAND_MMRBC_MASK) >> - PCIX_COMMAND_MMRBC_SHIFT; - stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >> - PCIX_STATUS_HI_MMRBC_SHIFT; - if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K) - stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K; - if (cmd_mmrbc > stat_mmrbc) { - pcix_cmd &= ~PCIX_COMMAND_MMRBC_MASK; - pcix_cmd |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT; - e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd); - } -} - -/** - * e1000_clear_hw_cntrs_base_generic - Clear base hardware counters - * @hw: pointer to the HW structure - * - * Clears the base hardware counters by reading the counter registers. - **/ -void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("e1000_clear_hw_cntrs_base_generic"); - -#if 0 - E1000_READ_REG(hw, E1000_CRCERRS); - E1000_READ_REG(hw, E1000_SYMERRS); - E1000_READ_REG(hw, E1000_MPC); - E1000_READ_REG(hw, E1000_SCC); - E1000_READ_REG(hw, E1000_ECOL); - E1000_READ_REG(hw, E1000_MCC); - E1000_READ_REG(hw, E1000_LATECOL); - E1000_READ_REG(hw, E1000_COLC); - E1000_READ_REG(hw, E1000_DC); - E1000_READ_REG(hw, E1000_SEC); - E1000_READ_REG(hw, E1000_RLEC); - E1000_READ_REG(hw, E1000_XONRXC); - E1000_READ_REG(hw, E1000_XONTXC); - E1000_READ_REG(hw, E1000_XOFFRXC); - E1000_READ_REG(hw, E1000_XOFFTXC); - E1000_READ_REG(hw, E1000_FCRUC); - E1000_READ_REG(hw, E1000_GPRC); - E1000_READ_REG(hw, E1000_BPRC); - E1000_READ_REG(hw, E1000_MPRC); - E1000_READ_REG(hw, E1000_GPTC); - E1000_READ_REG(hw, E1000_GORCL); - E1000_READ_REG(hw, E1000_GORCH); - E1000_READ_REG(hw, E1000_GOTCL); - E1000_READ_REG(hw, E1000_GOTCH); - E1000_READ_REG(hw, E1000_RNBC); - E1000_READ_REG(hw, E1000_RUC); - E1000_READ_REG(hw, E1000_RFC); - E1000_READ_REG(hw, E1000_ROC); - E1000_READ_REG(hw, E1000_RJC); - E1000_READ_REG(hw, E1000_TORL); - E1000_READ_REG(hw, E1000_TORH); - E1000_READ_REG(hw, E1000_TOTL); - E1000_READ_REG(hw, E1000_TOTH); - E1000_READ_REG(hw, E1000_TPR); - E1000_READ_REG(hw, E1000_TPT); - E1000_READ_REG(hw, E1000_MPTC); - E1000_READ_REG(hw, E1000_BPTC); -#endif -} - -/** - * e1000_check_for_copper_link_generic - Check for link (Copper) - * @hw: pointer to the HW structure - * - * Checks to see of the link status of the hardware has changed. If a - * change in link status has been detected, then we read the PHY registers - * to get the current speed/duplex if link exists. - **/ -s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - bool link; - - DEBUGFUNC("e1000_check_for_copper_link"); - - /* - * We only want to go out to the PHY registers to see if Auto-Neg - * has completed and/or if our link status has changed. The - * get_link_status flag is set upon receiving a Link Status - * Change or Rx Sequence Error interrupt. - */ - if (!mac->get_link_status) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* - * First we want to see if the MII Status Register reports - * link. If so, then we want to get the current speed/duplex - * of the PHY. - */ - ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) - goto out; /* No link detected */ - - mac->get_link_status = false; - - /* - * Check if there was DownShift, must be checked - * immediately after link-up - */ - e1000_check_downshift_generic(hw); - - /* - * If we are forcing speed/duplex, then we simply return since - * we have already determined whether we have link or not. - */ - if (!mac->autoneg) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - /* - * Auto-Neg is enabled. Auto Speed Detection takes care - * of MAC speed/duplex configuration. So we only need to - * configure Collision Distance in the MAC. - */ - e1000_config_collision_dist_generic(hw); - - /* - * Configure Flow Control now that Auto-Neg has completed. - * First, we need to restore the desired flow control - * settings because we may have had to re-autoneg with a - * different link partner. - */ - ret_val = e1000_config_fc_after_link_up_generic(hw); - if (ret_val) - DEBUGOUT("Error configuring flow control\n"); - -out: - return ret_val; -} - -/** - * e1000_check_for_fiber_link_generic - Check for link (Fiber) - * @hw: pointer to the HW structure - * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. - **/ -s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw; - u32 ctrl; - u32 status; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_check_for_fiber_link_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - status = E1000_READ_REG(hw, E1000_STATUS); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - - /* - * If we don't have link (auto-negotiation failed or link partner - * cannot auto-negotiate), the cable is plugged in (we have signal), - * and our link partner is not trying to auto-negotiate with us (we - * are receiving idles or data), we need to force link up. We also - * need to give auto-negotiation time to complete, in case the cable - * was just plugged in. The autoneg_failed flag does this. - */ - /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ - if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) && - (!(rxcw & E1000_RXCW_C))) { - if (mac->autoneg_failed == 0) { - mac->autoneg_failed = 1; - goto out; - } - DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); - - /* Disable auto-negotiation in the TXCW register */ - E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); - - /* Force link-up and also force full-duplex. */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - /* Configure Flow Control after forcing link up. */ - ret_val = e1000_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - goto out; - } - } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - /* - * If we are forcing link and we are receiving /C/ ordered - * sets, re-enable auto-negotiation in the TXCW register - * and disable forced link in the Device Control register - * in an attempt to auto-negotiate with our link partner. - */ - DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); - E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); - E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); - - mac->serdes_has_link = true; - } - -out: - return ret_val; -} - -/** - * e1000_check_for_serdes_link_generic - Check for link (Serdes) - * @hw: pointer to the HW structure - * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. - **/ -s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw; - u32 ctrl; - u32 status; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_check_for_serdes_link_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - status = E1000_READ_REG(hw, E1000_STATUS); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - - /* - * If we don't have link (auto-negotiation failed or link partner - * cannot auto-negotiate), and our link partner is not trying to - * auto-negotiate with us (we are receiving idles or data), - * we need to force link up. We also need to give auto-negotiation - * time to complete. - */ - /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ - if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) { - if (mac->autoneg_failed == 0) { - mac->autoneg_failed = 1; - goto out; - } - DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); - - /* Disable auto-negotiation in the TXCW register */ - E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); - - /* Force link-up and also force full-duplex. */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - /* Configure Flow Control after forcing link up. */ - ret_val = e1000_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - goto out; - } - } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - /* - * If we are forcing link and we are receiving /C/ ordered - * sets, re-enable auto-negotiation in the TXCW register - * and disable forced link in the Device Control register - * in an attempt to auto-negotiate with our link partner. - */ - DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); - E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); - E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); - - mac->serdes_has_link = true; - } else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) { - /* - * If we force link for non-auto-negotiation switch, check - * link status based on MAC synchronization for internal - * serdes media type. - */ - /* SYNCH bit and IV bit are sticky. */ - usec_delay(10); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - if (rxcw & E1000_RXCW_SYNCH) { - if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = true; - DEBUGOUT("SERDES: Link up - forced.\n"); - } - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - force failed.\n"); - } - } - - if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) { - status = E1000_READ_REG(hw, E1000_STATUS); - if (status & E1000_STATUS_LU) { - /* SYNCH bit and IV bit are sticky, so reread rxcw. */ - usec_delay(10); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - if (rxcw & E1000_RXCW_SYNCH) { - if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = true; - DEBUGOUT("SERDES: Link up - autoneg " - "completed sucessfully.\n"); - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - invalid" - "codewords detected in autoneg.\n"); - } - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - no sync.\n"); - } - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - autoneg failed\n"); - } - } - -out: - return ret_val; -} - -/** - * e1000_setup_link_generic - Setup flow control and link settings - * @hw: pointer to the HW structure - * - * Determines which flow control settings to use, then configures flow - * control. Calls the appropriate media-specific link configuration - * function. Assuming the adapter has a valid link partner, a valid link - * should be established. Assumes the hardware has previously been reset - * and the transmitter and receiver are not enabled. - **/ -s32 e1000_setup_link_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_setup_link_generic"); - - /* - * In the case of the phy reset being blocked, we already have a link. - * We do not need to set it up again. - */ - if (hw->phy.ops.check_reset_block) - if (hw->phy.ops.check_reset_block(hw)) - goto out; - - /* - * If requested flow control is set to default, set flow control - * based on the EEPROM flow control settings. - */ - if (hw->fc.requested_mode == e1000_fc_default) { - ret_val = e1000_set_default_fc_generic(hw); - if (ret_val) - goto out; - } - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - hw->fc.current_mode = hw->fc.requested_mode; - - DEBUGOUT1("After fix-ups FlowControl is now = %x\n", - hw->fc.current_mode); - - /* Call the necessary media_type subroutine to configure the link. */ - ret_val = hw->mac.ops.setup_physical_interface(hw); - if (ret_val) - goto out; - - /* - * Initialize the flow control address, type, and PAUSE timer - * registers to their default values. This is done even if flow - * control is disabled, because it does not hurt anything to - * initialize these registers. - */ - DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); - E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE); - E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); - E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); - - E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); - - ret_val = e1000_set_fc_watermarks_generic(hw); - -out: - return ret_val; -} - -/** - * e1000_setup_fiber_serdes_link_generic - Setup link for fiber/serdes - * @hw: pointer to the HW structure - * - * Configures collision distance and flow control for fiber and serdes - * links. Upon successful setup, poll for link. - **/ -s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_setup_fiber_serdes_link_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* Take the link out of reset */ - ctrl &= ~E1000_CTRL_LRST; - - e1000_config_collision_dist_generic(hw); - - ret_val = e1000_commit_fc_settings_generic(hw); - if (ret_val) - goto out; - - /* - * Since auto-negotiation is enabled, take the link out of reset (the - * link will be in reset, because we previously reset the chip). This - * will restart auto-negotiation. If auto-negotiation is successful - * then the link-up status bit will be set and the flow control enable - * bits (RFCE and TFCE) will be set according to their negotiated value. - */ - DEBUGOUT("Auto-negotiation enabled\n"); - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - E1000_WRITE_FLUSH(hw); - msec_delay(1); - - /* - * For these adapters, the SW definable pin 1 is set when the optics - * detect a signal. If we have a signal, then poll for a "Link-Up" - * indication. - */ - if (hw->phy.media_type == e1000_media_type_internal_serdes || - (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) { - ret_val = e1000_poll_fiber_serdes_link_generic(hw); - } else { - DEBUGOUT("No signal detected\n"); - } - -out: - return ret_val; -} - -/** - * e1000_config_collision_dist_generic - Configure collision distance - * @hw: pointer to the HW structure - * - * Configures the collision distance to the default value and is used - * during link setup. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -void e1000_config_collision_dist_generic(struct e1000_hw *hw) -{ - u32 tctl; - - DEBUGFUNC("e1000_config_collision_dist_generic"); - - tctl = E1000_READ_REG(hw, E1000_TCTL); - - tctl &= ~E1000_TCTL_COLD; - tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; - - E1000_WRITE_REG(hw, E1000_TCTL, tctl); - E1000_WRITE_FLUSH(hw); -} - -/** - * e1000_poll_fiber_serdes_link_generic - Poll for link up - * @hw: pointer to the HW structure - * - * Polls for link up by reading the status register, if link fails to come - * up with auto-negotiation, then the link is forced if a signal is detected. - **/ -s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 i, status; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_poll_fiber_serdes_link_generic"); - - /* - * If we have a signal (the cable is plugged in, or assumed true for - * serdes media) then poll for a "Link-Up" indication in the Device - * Status Register. Time-out if a link isn't seen in 500 milliseconds - * seconds (Auto-negotiation should complete in less than 500 - * milliseconds even if the other end is doing it in SW). - */ - for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msec_delay(10); - status = E1000_READ_REG(hw, E1000_STATUS); - if (status & E1000_STATUS_LU) - break; - } - if (i == FIBER_LINK_UP_LIMIT) { - DEBUGOUT("Never got a valid link from auto-neg!!!\n"); - mac->autoneg_failed = 1; - /* - * AutoNeg failed to achieve a link, so we'll call - * mac->check_for_link. This routine will force the - * link up if we detect a signal. This will allow us to - * communicate with non-autonegotiating link partners. - */ - ret_val = hw->mac.ops.check_for_link(hw); - if (ret_val) { - DEBUGOUT("Error while checking for link\n"); - goto out; - } - mac->autoneg_failed = 0; - } else { - mac->autoneg_failed = 0; - DEBUGOUT("Valid Link Found\n"); - } - -out: - return ret_val; -} - -/** - * e1000_commit_fc_settings_generic - Configure flow control - * @hw: pointer to the HW structure - * - * Write the flow control settings to the Transmit Config Word Register (TXCW) - * base on the flow control settings in e1000_mac_info. - **/ -s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 txcw; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_commit_fc_settings_generic"); - - /* - * Check for a software override of the flow control settings, and - * setup the device accordingly. If auto-negotiation is enabled, then - * software will have to set the "PAUSE" bits to the correct value in - * the Transmit Config Word Register (TXCW) and re-start auto- - * negotiation. However, if auto-negotiation is disabled, then - * software will have to manually configure the two flow control enable - * bits in the CTRL register. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but we - * do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - */ - switch (hw->fc.current_mode) { - case e1000_fc_none: - /* Flow control completely disabled by a software over-ride. */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); - break; - case e1000_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is disabled - * by a software over-ride. Since there really isn't a way to - * advertise that we are capable of Rx Pause ONLY, we will - * advertise that we support both symmetric and asymmetric RX - * PAUSE. Later, we will disable the adapter's ability to send - * PAUSE frames. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); - break; - case e1000_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is disabled, - * by a software over-ride. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); - break; - case e1000_fc_full: - /* - * Flow control (both Rx and Tx) is enabled by a software - * over-ride. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); - break; - default: - DEBUGOUT("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } - - E1000_WRITE_REG(hw, E1000_TXCW, txcw); - mac->txcw = txcw; - -out: - return ret_val; -} - -/** - * e1000_set_fc_watermarks_generic - Set flow control high/low watermarks - * @hw: pointer to the HW structure - * - * Sets the flow control high/low threshold (watermark) registers. If - * flow control XON frame transmission is enabled, then set XON frame - * transmission as well. - **/ -s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u32 fcrtl = 0, fcrth = 0; - - DEBUGFUNC("e1000_set_fc_watermarks_generic"); - - /* - * Set the flow control receive threshold registers. Normally, - * these registers will be set to a default threshold that may be - * adjusted later by the driver's runtime code. However, if the - * ability to transmit pause frames is not enabled, then these - * registers will be set to 0. - */ - if (hw->fc.current_mode & e1000_fc_tx_pause) { - /* - * We need to set up the Receive Threshold high and low water - * marks as well as (optionally) enabling the transmission of - * XON frames. - */ - fcrtl = hw->fc.low_water; - if (hw->fc.send_xon) - fcrtl |= E1000_FCRTL_XONE; - - fcrth = hw->fc.high_water; - } - E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl); - E1000_WRITE_REG(hw, E1000_FCRTH, fcrth); - - return ret_val; -} - -/** - * e1000_set_default_fc_generic - Set flow control default values - * @hw: pointer to the HW structure - * - * Read the EEPROM for the default values for flow control and store the - * values. - **/ -s32 e1000_set_default_fc_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 nvm_data; - - DEBUGFUNC("e1000_set_default_fc_generic"); - - /* - * Read and store word 0x0F of the EEPROM. This word contains bits - * that determine the hardware's default PAUSE (flow control) mode, - * a bit that determines whether the HW defaults to enabling or - * disabling auto-negotiation, and the direction of the - * SW defined pins. If there is no SW over-ride of the flow - * control setting, then the variable hw->fc will - * be initialized based on a value in the EEPROM. - */ - ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); - - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) - hw->fc.requested_mode = e1000_fc_none; - else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == - NVM_WORD0F_ASM_DIR) - hw->fc.requested_mode = e1000_fc_tx_pause; - else - hw->fc.requested_mode = e1000_fc_full; - -out: - return ret_val; -} - -/** - * e1000_force_mac_fc_generic - Force the MAC's flow control settings - * @hw: pointer to the HW structure - * - * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the - * device control register to reflect the adapter settings. TFCE and RFCE - * need to be explicitly set by software when a copper PHY is used because - * autonegotiation is managed by the PHY rather than the MAC. Software must - * also configure these bits when link is forced on a fiber connection. - **/ -s32 e1000_force_mac_fc_generic(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_force_mac_fc_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* - * Because we didn't get link via the internal auto-negotiation - * mechanism (we either forced link or we got link via PHY - * auto-neg), we have to manually enable/disable transmit an - * receive flow control. - * - * The "Case" statement below enables/disable flow control - * according to the "hw->fc.current_mode" parameter. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause - * frames but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * frames but we do not receive pause frames). - * 3: Both Rx and Tx flow control (symmetric) is enabled. - * other: No other values should be possible at this point. - */ - DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode); - - switch (hw->fc.current_mode) { - case e1000_fc_none: - ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); - break; - case e1000_fc_rx_pause: - ctrl &= (~E1000_CTRL_TFCE); - ctrl |= E1000_CTRL_RFCE; - break; - case e1000_fc_tx_pause: - ctrl &= (~E1000_CTRL_RFCE); - ctrl |= E1000_CTRL_TFCE; - break; - case e1000_fc_full: - ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); - break; - default: - DEBUGOUT("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - -out: - return ret_val; -} - -/** - * e1000_config_fc_after_link_up_generic - Configures flow control after link - * @hw: pointer to the HW structure - * - * Checks the status of auto-negotiation after link up to ensure that the - * speed and duplex were not forced. If the link needed to be forced, then - * flow control needs to be forced also. If auto-negotiation is enabled - * and did not fail, then we configure flow control based on our link - * partner. - **/ -s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; - u16 speed, duplex; - - DEBUGFUNC("e1000_config_fc_after_link_up_generic"); - - /* - * Check for the case where we have fiber media and auto-neg failed - * so we had to force link. In this case, we need to force the - * configuration of the MAC to match the "fc" parameter. - */ - if (mac->autoneg_failed) { - if (hw->phy.media_type == e1000_media_type_fiber || - hw->phy.media_type == e1000_media_type_internal_serdes) - ret_val = e1000_force_mac_fc_generic(hw); - } else { - if (hw->phy.media_type == e1000_media_type_copper) - ret_val = e1000_force_mac_fc_generic(hw); - } - - if (ret_val) { - DEBUGOUT("Error forcing flow control settings\n"); - goto out; - } - - /* - * Check for the case where we have copper media and auto-neg is - * enabled. In this case, we need to check and see if Auto-Neg - * has completed, and if so, how the PHY and link partner has - * flow control configured. - */ - if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) { - /* - * Read the MII Status Register and check to see if AutoNeg - * has completed. We read this twice because this reg has - * some "sticky" (latched) bits. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - - if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { - DEBUGOUT("Copper PHY and Auto Neg " - "has not completed.\n"); - goto out; - } - - /* - * The AutoNeg process has completed, so we now need to - * read both the Auto Negotiation Advertisement - * Register (Address 4) and the Auto_Negotiation Base - * Page Ability Register (Address 5) to determine how - * flow control was negotiated. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, - &mii_nway_adv_reg); - if (ret_val) - goto out; - ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, - &mii_nway_lp_ability_reg); - if (ret_val) - goto out; - - /* - * Two bits in the Auto Negotiation Advertisement Register - * (Address 4) and two bits in the Auto Negotiation Base - * Page Ability Register (Address 5) determine flow control - * for both the PHY and the link partner. The following - * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, - * 1999, describes these PAUSE resolution bits and how flow - * control is determined based upon these settings. - * NOTE: DC = Don't Care - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution - *-------|---------|-------|---------|-------------------- - * 0 | 0 | DC | DC | e1000_fc_none - * 0 | 1 | 0 | DC | e1000_fc_none - * 0 | 1 | 1 | 0 | e1000_fc_none - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - * 1 | 0 | 0 | DC | e1000_fc_none - * 1 | DC | 1 | DC | e1000_fc_full - * 1 | 1 | 0 | 0 | e1000_fc_none - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause - * - * Are both PAUSE bits set to 1? If so, this implies - * Symmetric Flow Control is enabled at both ends. The - * ASM_DIR bits are irrelevant per the spec. - * - * For Symmetric Flow Control: - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | DC | 1 | DC | E1000_fc_full - * - */ - if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { - /* - * Now we need to check if the user selected Rx ONLY - * of pause frames. In this case, we had to advertise - * FULL flow control because we could not advertise RX - * ONLY. Hence, we must now check to see if we need to - * turn OFF the TRANSMISSION of PAUSE frames. - */ - if (hw->fc.requested_mode == e1000_fc_full) { - hw->fc.current_mode = e1000_fc_full; - DEBUGOUT("Flow Control = FULL.\r\n"); - } else { - hw->fc.current_mode = e1000_fc_rx_pause; - DEBUGOUT("Flow Control = " - "RX PAUSE frames only.\r\n"); - } - } - /* - * For receiving PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - */ - else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = e1000_fc_tx_pause; - DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); - } - /* - * For transmitting PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause - */ - else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = e1000_fc_rx_pause; - DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); - } else { - /* - * Per the IEEE spec, at this point flow control - * should be disabled. - */ - hw->fc.current_mode = e1000_fc_none; - DEBUGOUT("Flow Control = NONE.\r\n"); - } - - /* - * Now we need to do one last check... If we auto- - * negotiated to HALF DUPLEX, flow control should not be - * enabled per IEEE 802.3 spec. - */ - ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); - if (ret_val) { - DEBUGOUT("Error getting link speed and duplex\n"); - goto out; - } - - if (duplex == HALF_DUPLEX) - hw->fc.current_mode = e1000_fc_none; - - /* - * Now we call a subroutine to actually force the MAC - * controller to use the correct flow control settings. - */ - ret_val = e1000_force_mac_fc_generic(hw); - if (ret_val) { - DEBUGOUT("Error forcing flow control settings\n"); - goto out; - } - } - -out: - return ret_val; -} - -/** - * e1000_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * Read the status register for the current speed/duplex and store the current - * speed and duplex for copper connections. - **/ -s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, - u16 *duplex) -{ - u32 status; - - DEBUGFUNC("e1000_get_speed_and_duplex_copper_generic"); - - status = E1000_READ_REG(hw, E1000_STATUS); - if (status & E1000_STATUS_SPEED_1000) { - *speed = SPEED_1000; - DEBUGOUT("1000 Mbs, "); - } else if (status & E1000_STATUS_SPEED_100) { - *speed = SPEED_100; - DEBUGOUT("100 Mbs, "); - } else { - *speed = SPEED_10; - DEBUGOUT("10 Mbs, "); - } - - if (status & E1000_STATUS_FD) { - *duplex = FULL_DUPLEX; - DEBUGOUT("Full Duplex\n"); - } else { - *duplex = HALF_DUPLEX; - DEBUGOUT("Half Duplex\n"); - } - - return E1000_SUCCESS; -} - -/** - * e1000_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * Sets the speed and duplex to gigabit full duplex (the only possible option) - * for fiber/serdes links. - **/ -s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw __unused, - u16 *speed, u16 *duplex) -{ - DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic"); - - *speed = SPEED_1000; - *duplex = FULL_DUPLEX; - - return E1000_SUCCESS; -} - -/** - * e1000_get_hw_semaphore_generic - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM - **/ -s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 swsm; - s32 ret_val = E1000_SUCCESS; - s32 timeout = hw->nvm.word_size + 1; - s32 i = 0; - - DEBUGFUNC("e1000_get_hw_semaphore_generic"); - - /* Get the SW semaphore */ - while (i < timeout) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - usec_delay(50); - i++; - } - - if (i == timeout) { - DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); - - /* Semaphore acquired if bit latched */ - if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) - break; - - usec_delay(50); - } - - if (i == timeout) { - /* Release semaphores */ - e1000_put_hw_semaphore_generic(hw); - DEBUGOUT("Driver can't access the NVM\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -#endif - return 0; -} - -/** - * e1000_put_hw_semaphore_generic - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - **/ -void e1000_put_hw_semaphore_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 swsm; - - DEBUGFUNC("e1000_put_hw_semaphore_generic"); - - swsm = E1000_READ_REG(hw, E1000_SWSM); - - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); - - E1000_WRITE_REG(hw, E1000_SWSM, swsm); -#endif -} - -/** - * e1000_get_auto_rd_done_generic - Check for auto read completion - * @hw: pointer to the HW structure - * - * Check EEPROM for Auto Read done bit. - **/ -s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw) -{ - s32 i = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_get_auto_rd_done_generic"); - - while (i < AUTO_READ_DONE_TIMEOUT) { - if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD) - break; - msec_delay(1); - i++; - } - - if (i == AUTO_READ_DONE_TIMEOUT) { - DEBUGOUT("Auto read by HW from NVM has not completed.\n"); - ret_val = -E1000_ERR_RESET; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_valid_led_default_generic - Verify a valid default LED config - * @hw: pointer to the HW structure - * @data: pointer to the NVM (EEPROM) - * - * Read the EEPROM for the current default LED configuration. If the - * LED configuration is not valid, set to a valid LED configuration. - **/ -s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data) -{ - s32 ret_val; - - DEBUGFUNC("e1000_valid_led_default_generic"); - - ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT; - -out: - return ret_val; -} - -/** - * e1000_id_led_init_generic - - * @hw: pointer to the HW structure - * - **/ -s32 e1000_id_led_init_generic(struct e1000_hw *hw __unused) -{ -#if 0 - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - const u32 ledctl_mask = 0x000000FF; - const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; - const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; - u16 data, i, temp; - const u16 led_mask = 0x0F; - - DEBUGFUNC("e1000_id_led_init_generic"); - - ret_val = hw->nvm.ops.valid_led_default(hw, &data); - if (ret_val) - goto out; - - mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); - mac->ledctl_mode1 = mac->ledctl_default; - mac->ledctl_mode2 = mac->ledctl_default; - - for (i = 0; i < 4; i++) { - temp = (data >> (i << 2)) & led_mask; - switch (temp) { - case ID_LED_ON1_DEF2: - case ID_LED_ON1_ON2: - case ID_LED_ON1_OFF2: - mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode1 |= ledctl_on << (i << 3); - break; - case ID_LED_OFF1_DEF2: - case ID_LED_OFF1_ON2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode1 |= ledctl_off << (i << 3); - break; - default: - /* Do nothing */ - break; - } - switch (temp) { - case ID_LED_DEF1_ON2: - case ID_LED_ON1_ON2: - case ID_LED_OFF1_ON2: - mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode2 |= ledctl_on << (i << 3); - break; - case ID_LED_DEF1_OFF2: - case ID_LED_ON1_OFF2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode2 |= ledctl_off << (i << 3); - break; - default: - /* Do nothing */ - break; - } - } - -out: - return ret_val; -#endif - return 0; -} - -/** - * e1000_setup_led_generic - Configures SW controllable LED - * @hw: pointer to the HW structure - * - * This prepares the SW controllable LED for use and saves the current state - * of the LED so it can be later restored. - **/ -s32 e1000_setup_led_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ledctl; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_setup_led_generic"); - - if (hw->mac.ops.setup_led != e1000_setup_led_generic) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - if (hw->phy.media_type == e1000_media_type_fiber) { - ledctl = E1000_READ_REG(hw, E1000_LEDCTL); - hw->mac.ledctl_default = ledctl; - /* Turn off LED0 */ - ledctl &= ~(E1000_LEDCTL_LED0_IVRT | - E1000_LEDCTL_LED0_BLINK | - E1000_LEDCTL_LED0_MODE_MASK); - ledctl |= (E1000_LEDCTL_MODE_LED_OFF << - E1000_LEDCTL_LED0_MODE_SHIFT); - E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); - } else if (hw->phy.media_type == e1000_media_type_copper) { - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); - } - -out: - return ret_val; -#endif - return 0; -} - -/** - * e1000_cleanup_led_generic - Set LED config to default operation - * @hw: pointer to the HW structure - * - * Remove the current LED configuration and set the LED configuration - * to the default value, saved from the EEPROM. - **/ -s32 e1000_cleanup_led_generic(struct e1000_hw *hw __unused) -{ -#if 0 - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_cleanup_led_generic"); - - if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); - -out: - return ret_val; -#endif - return 0; -} - -/** - * e1000_blink_led_generic - Blink LED - * @hw: pointer to the HW structure - * - * Blink the LEDs which are set to be on. - **/ -s32 e1000_blink_led_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ledctl_blink = 0; - u32 i; - - DEBUGFUNC("e1000_blink_led_generic"); - - if (hw->phy.media_type == e1000_media_type_fiber) { - /* always blink LED0 for PCI-E fiber */ - ledctl_blink = E1000_LEDCTL_LED0_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); - } else { - /* - * set the blink bit for each LED that's "on" (0x0E) - * in ledctl_mode2 - */ - ledctl_blink = hw->mac.ledctl_mode2; - for (i = 0; i < 4; i++) - if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == - E1000_LEDCTL_MODE_LED_ON) - ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << - (i * 8)); - } - - E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink); - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_led_on_generic - Turn LED on - * @hw: pointer to the HW structure - * - * Turn LED on. - **/ -s32 e1000_led_on_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl; - - DEBUGFUNC("e1000_led_on_generic"); - - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl &= ~E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - break; - case e1000_media_type_copper: - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); - break; - default: - break; - } - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_led_off_generic - Turn LED off - * @hw: pointer to the HW structure - * - * Turn LED off. - **/ -s32 e1000_led_off_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl; - - DEBUGFUNC("e1000_led_off_generic"); - - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - break; - case e1000_media_type_copper: - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); - break; - default: - break; - } - - return E1000_SUCCESS; -#endif - return 0; -} - -/** - * e1000_set_pcie_no_snoop_generic - Set PCI-express capabilities - * @hw: pointer to the HW structure - * @no_snoop: bitmap of snoop events - * - * Set the PCI-express register to snoop for events enabled in 'no_snoop'. - **/ -void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop) -{ - u32 gcr; - - DEBUGFUNC("e1000_set_pcie_no_snoop_generic"); - - if (hw->bus.type != e1000_bus_type_pci_express) - goto out; - - if (no_snoop) { - gcr = E1000_READ_REG(hw, E1000_GCR); - gcr &= ~(PCIE_NO_SNOOP_ALL); - gcr |= no_snoop; - E1000_WRITE_REG(hw, E1000_GCR, gcr); - } -out: - return; -} - -/** - * e1000_disable_pcie_master_generic - Disables PCI-express master access - * @hw: pointer to the HW structure - * - * Returns 0 (E1000_SUCCESS) if successful, else returns -10 - * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused - * the master requests to be disabled. - * - * Disables PCI-Express master access and verifies there are no pending - * requests. - **/ -s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw) -{ - u32 ctrl; - s32 timeout = MASTER_DISABLE_TIMEOUT; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_disable_pcie_master_generic"); - - if (hw->bus.type != e1000_bus_type_pci_express) - goto out; - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - while (timeout) { - if (!(E1000_READ_REG(hw, E1000_STATUS) & - E1000_STATUS_GIO_MASTER_ENABLE)) - break; - usec_delay(100); - timeout--; - } - - if (!timeout) { - DEBUGOUT("Master requests are pending.\n"); - ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_reset_adaptive_generic - Reset Adaptive Interframe Spacing - * @hw: pointer to the HW structure - * - * Reset the Adaptive Interframe Spacing throttle to default values. - **/ -void e1000_reset_adaptive_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - DEBUGFUNC("e1000_reset_adaptive_generic"); - - if (!mac->adaptive_ifs) { - DEBUGOUT("Not in Adaptive IFS mode!\n"); - goto out; - } - - mac->current_ifs_val = 0; - mac->ifs_min_val = IFS_MIN; - mac->ifs_max_val = IFS_MAX; - mac->ifs_step_size = IFS_STEP; - mac->ifs_ratio = IFS_RATIO; - - mac->in_ifs_mode = false; - E1000_WRITE_REG(hw, E1000_AIT, 0); -out: - return; -} - -/** - * e1000_update_adaptive_generic - Update Adaptive Interframe Spacing - * @hw: pointer to the HW structure - * - * Update the Adaptive Interframe Spacing Throttle value based on the - * time between transmitted packets and time between collisions. - **/ -void e1000_update_adaptive_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - DEBUGFUNC("e1000_update_adaptive_generic"); - - if (!mac->adaptive_ifs) { - DEBUGOUT("Not in Adaptive IFS mode!\n"); - goto out; - } - - if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { - if (mac->tx_packet_delta > MIN_NUM_XMITS) { - mac->in_ifs_mode = true; - if (mac->current_ifs_val < mac->ifs_max_val) { - if (!mac->current_ifs_val) - mac->current_ifs_val = mac->ifs_min_val; - else - mac->current_ifs_val += - mac->ifs_step_size; - E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val); - } - } - } else { - if (mac->in_ifs_mode && - (mac->tx_packet_delta <= MIN_NUM_XMITS)) { - mac->current_ifs_val = 0; - mac->in_ifs_mode = false; - E1000_WRITE_REG(hw, E1000_AIT, 0); - } - } -out: - return; -} - -/** - * e1000_validate_mdi_setting_generic - Verify MDI/MDIx settings - * @hw: pointer to the HW structure - * - * Verify that when not using auto-negotiation that MDI/MDIx is correctly - * set, which is forced to MDI mode only. - **/ -static s32 e1000_validate_mdi_setting_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_validate_mdi_setting_generic"); - - if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { - DEBUGOUT("Invalid MDI setting detected\n"); - hw->phy.mdix = 1; - ret_val = -E1000_ERR_CONFIG; - goto out; - } - -out: - return ret_val; -} diff --git a/src/drivers/net/e1000/e1000_mac.h b/src/drivers/net/e1000/e1000_mac.h deleted file mode 100644 index 51acae08..00000000 --- a/src/drivers/net/e1000/e1000_mac.h +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_MAC_H_ -#define _E1000_MAC_H_ - -/* - * Functions that should not be called directly from drivers but can be used - * by other files in this 'shared code' - */ -void e1000_init_mac_ops_generic(struct e1000_hw *hw); -void e1000_null_mac_generic(struct e1000_hw *hw); -s32 e1000_null_ops_generic(struct e1000_hw *hw); -s32 e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d); -bool e1000_null_mng_mode(struct e1000_hw *hw); -void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a); -void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b); -void e1000_null_mta_set(struct e1000_hw *hw, u32 a); -void e1000_null_rar_set(struct e1000_hw *hw, u8 *h, u32 a); -s32 e1000_blink_led_generic(struct e1000_hw *hw); -s32 e1000_check_for_copper_link_generic(struct e1000_hw *hw); -s32 e1000_check_for_fiber_link_generic(struct e1000_hw *hw); -s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw); -s32 e1000_cleanup_led_generic(struct e1000_hw *hw); -s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw); -s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw); -s32 e1000_config_fc_after_link_up_generic(struct e1000_hw *hw); -s32 e1000_disable_pcie_master_generic(struct e1000_hw *hw); -s32 e1000_force_mac_fc_generic(struct e1000_hw *hw); -s32 e1000_get_auto_rd_done_generic(struct e1000_hw *hw); -s32 e1000_get_bus_info_pci_generic(struct e1000_hw *hw); -s32 e1000_get_bus_info_pcie_generic(struct e1000_hw *hw); -void e1000_set_lan_id_single_port(struct e1000_hw *hw); -void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw); -s32 e1000_get_hw_semaphore_generic(struct e1000_hw *hw); -s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw, - u16 *speed, u16 *duplex); -s32 e1000_id_led_init_generic(struct e1000_hw *hw); -s32 e1000_led_on_generic(struct e1000_hw *hw); -s32 e1000_led_off_generic(struct e1000_hw *hw); -void e1000_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count); -s32 e1000_set_default_fc_generic(struct e1000_hw *hw); -s32 e1000_set_fc_watermarks_generic(struct e1000_hw *hw); -s32 e1000_setup_fiber_serdes_link_generic(struct e1000_hw *hw); -s32 e1000_setup_led_generic(struct e1000_hw *hw); -s32 e1000_setup_link_generic(struct e1000_hw *hw); - -u32 e1000_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr); - -void e1000_clear_hw_cntrs_base_generic(struct e1000_hw *hw); -void e1000_clear_vfta_generic(struct e1000_hw *hw); -void e1000_config_collision_dist_generic(struct e1000_hw *hw); -void e1000_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count); -void e1000_mta_set_generic(struct e1000_hw *hw, u32 hash_value); -void e1000_pcix_mmrbc_workaround_generic(struct e1000_hw *hw); -void e1000_put_hw_semaphore_generic(struct e1000_hw *hw); -void e1000_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index); -s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw); -void e1000_reset_adaptive_generic(struct e1000_hw *hw); -void e1000_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop); -void e1000_update_adaptive_generic(struct e1000_hw *hw); -void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); - -#endif diff --git a/src/drivers/net/e1000/e1000_main.c b/src/drivers/net/e1000/e1000_main.c deleted file mode 100644 index bc2aa968..00000000 --- a/src/drivers/net/e1000/e1000_main.c +++ /dev/null @@ -1,909 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - Portions Copyright(c) 2010 Marty Connor - Portions Copyright(c) 2010 Entity Cyber, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#include "e1000.h" - -/** - * e1000_irq_disable - Disable interrupt generation - * - * @adapter: board private structure - **/ -static void e1000_irq_disable ( struct e1000_adapter *adapter ) -{ - E1000_WRITE_REG ( &adapter->hw, E1000_IMC, ~0 ); - E1000_WRITE_FLUSH ( &adapter->hw ); -} - -/** - * e1000_irq_enable - Enable interrupt generation - * - * @adapter: board private structure - **/ -static void e1000_irq_enable ( struct e1000_adapter *adapter ) -{ - E1000_WRITE_REG(&adapter->hw, E1000_IMS, IMS_ENABLE_MASK); - E1000_WRITE_FLUSH(&adapter->hw); -} - -/** - * e1000_sw_init - Initialize general software structures (struct e1000_adapter) - * @adapter: board private structure to initialize - * - * e1000_sw_init initializes the Adapter private data structure. - * Fields are initialized based on PCI device information and - * OS network device settings (MTU size). - **/ -static int e1000_sw_init(struct e1000_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - struct pci_device *pdev = adapter->pdev; - - /* PCI config space info */ - - hw->vendor_id = pdev->vendor; - hw->device_id = pdev->device; - - pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &hw->subsystem_vendor_id); - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &hw->subsystem_device_id); - - pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); - - pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); - - adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; - adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + - ETH_HLEN + ETH_FCS_LEN; - adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; - - hw->fc.requested_mode = e1000_fc_none; - - /* Initialize the hardware-specific values */ - if (e1000_setup_init_funcs(hw, false)) { - DBG ("Hardware Initialization Failure\n"); - return -EIO; - } - - /* Explicitly disable IRQ since the NIC can be in any state. */ - e1000_irq_disable ( adapter ); - - return 0; -} - -int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) -{ - struct e1000_adapter *adapter = hw->back; - uint16_t cap_offset; - -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ - cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); - if (!cap_offset) - return -E1000_ERR_CONFIG; - - pci_read_config_word(adapter->pdev, cap_offset + reg, value); - - return 0; -} - -void e1000_pci_clear_mwi ( struct e1000_hw *hw ) -{ - struct e1000_adapter *adapter = hw->back; - - pci_write_config_word ( adapter->pdev, PCI_COMMAND, - hw->bus.pci_cmd_word & ~PCI_COMMAND_INVALIDATE ); -} - -void e1000_pci_set_mwi ( struct e1000_hw *hw ) -{ - struct e1000_adapter *adapter = hw->back; - - pci_write_config_word ( adapter->pdev, PCI_COMMAND, - hw->bus.pci_cmd_word ); -} - -void e1000_read_pci_cfg ( struct e1000_hw *hw, uint32_t reg, uint16_t *value ) -{ - struct e1000_adapter *adapter = hw->back; - - pci_read_config_word ( adapter->pdev, reg, value ); -} - -void e1000_write_pci_cfg ( struct e1000_hw *hw, uint32_t reg, uint16_t *value ) -{ - struct e1000_adapter *adapter = hw->back; - - pci_write_config_word ( adapter->pdev, reg, *value ); -} - -/** - * e1000_init_manageability - disable interception of ARP packets - * - * @v adapter e1000 private structure - **/ -static void e1000_init_manageability ( struct e1000_adapter *adapter ) -{ - if (adapter->en_mng_pt) { - u32 manc = E1000_READ_REG(&adapter->hw, E1000_MANC); - - /* disable hardware interception of ARP */ - manc &= ~(E1000_MANC_ARP_EN); - - E1000_WRITE_REG(&adapter->hw, E1000_MANC, manc); - } -} - -/** - * e1000_setup_tx_resources - allocate Tx resources (Descriptors) - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int e1000_setup_tx_resources ( struct e1000_adapter *adapter ) -{ - DBG ( "e1000_setup_tx_resources\n" ); - - /* Allocate transmit descriptor ring memory. - It must not cross a 64K boundary because of hardware errata #23 - so we use malloc_dma() requesting a 128 byte block that is - 128 byte aligned. This should guarantee that the memory - allocated will not cross a 64K boundary, because 128 is an - even multiple of 65536 ( 65536 / 128 == 512 ), so all possible - allocations of 128 bytes on a 128 byte boundary will not - cross 64K bytes. - */ - - adapter->tx_base = - malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size ); - - if ( ! adapter->tx_base ) { - return -ENOMEM; - } - - memset ( adapter->tx_base, 0, adapter->tx_ring_size ); - - DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) ); - - return 0; -} - -/** - * e1000_process_tx_packets - process transmitted packets - * - * @v netdev network interface device structure - **/ -static void e1000_process_tx_packets ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - uint32_t i; - uint32_t tx_status; - struct e1000_tx_desc *tx_curr_desc; - - /* Check status of transmitted packets - */ - while ( ( i = adapter->tx_head ) != adapter->tx_tail ) { - - tx_curr_desc = ( void * ) ( adapter->tx_base ) + - ( i * sizeof ( *adapter->tx_base ) ); - - tx_status = tx_curr_desc->upper.data; - - /* if the packet at tx_head is not owned by hardware it is for us */ - if ( ! ( tx_status & E1000_TXD_STAT_DD ) ) - break; - - DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n", - adapter->tx_head, adapter->tx_tail, tx_status ); - - if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | - E1000_TXD_STAT_TU ) ) { - netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL ); - DBG ( "Error transmitting packet, tx_status: %#08x\n", - tx_status ); - } else { - netdev_tx_complete ( netdev, adapter->tx_iobuf[i] ); - DBG ( "Success transmitting packet, tx_status: %#08x\n", - tx_status ); - } - - /* Decrement count of used descriptors, clear this descriptor - */ - adapter->tx_fill_ctr--; - memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); - - adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC; - } -} - -static void e1000_free_tx_resources ( struct e1000_adapter *adapter ) -{ - DBG ( "e1000_free_tx_resources\n" ); - - free_dma ( adapter->tx_base, adapter->tx_ring_size ); -} - -/** - * e1000_configure_tx - Configure 8254x Transmit Unit after Reset - * @adapter: board private structure - * - * Configure the Tx unit of the MAC after a reset. - **/ -static void e1000_configure_tx ( struct e1000_adapter *adapter ) -{ - struct e1000_hw *hw = &adapter->hw; - uint32_t tctl; - - DBG ( "e1000_configure_tx\n" ); - - E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) ); - E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size ); - - DBG ( "E1000_TDBAL(0): %#08x\n", E1000_READ_REG ( hw, E1000_TDBAL(0) ) ); - DBG ( "E1000_TDLEN(0): %d\n", E1000_READ_REG ( hw, E1000_TDLEN(0) ) ); - - /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG ( hw, E1000_TDH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_TDT(0), 0 ); - - adapter->tx_head = 0; - adapter->tx_tail = 0; - adapter->tx_fill_ctr = 0; - - /* Setup Transmit Descriptor Settings for eop descriptor */ - tctl = E1000_TCTL_PSP | E1000_TCTL_EN | - (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT) | - (E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT); - - e1000_config_collision_dist ( hw ); - - E1000_WRITE_REG ( hw, E1000_TCTL, tctl ); - E1000_WRITE_FLUSH ( hw ); -} - -static void e1000_free_rx_resources ( struct e1000_adapter *adapter ) -{ - int i; - - DBG ( "e1000_free_rx_resources\n" ); - - free_dma ( adapter->rx_base, adapter->rx_ring_size ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - free_iob ( adapter->rx_iobuf[i] ); - } -} - -/** - * e1000_refill_rx_ring - allocate Rx io_buffers - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int e1000_refill_rx_ring ( struct e1000_adapter *adapter ) -{ - int i, rx_curr; - int rc = 0; - struct e1000_rx_desc *rx_curr_desc; - struct e1000_hw *hw = &adapter->hw; - struct io_buffer *iob; - - DBG ("e1000_refill_rx_ring\n"); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC ); - rx_curr_desc = adapter->rx_base + rx_curr; - - if ( rx_curr_desc->status & E1000_RXD_STAT_DD ) - continue; - - if ( adapter->rx_iobuf[rx_curr] != NULL ) - continue; - - DBG2 ( "Refilling rx desc %d\n", rx_curr ); - - iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE ); - adapter->rx_iobuf[rx_curr] = iob; - - if ( ! iob ) { - DBG ( "alloc_iob failed\n" ); - rc = -ENOMEM; - break; - } else { - rx_curr_desc->buffer_addr = virt_to_bus ( iob->data ); - - E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr ); - } - } - return rc; -} - -/** - * e1000_setup_rx_resources - allocate Rx resources (Descriptors) - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int e1000_setup_rx_resources ( struct e1000_adapter *adapter ) -{ - int i, rc = 0; - - DBG ( "e1000_setup_rx_resources\n" ); - - /* Allocate receive descriptor ring memory. - It must not cross a 64K boundary because of hardware errata - */ - - adapter->rx_base = - malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size ); - - if ( ! adapter->rx_base ) { - return -ENOMEM; - } - memset ( adapter->rx_base, 0, adapter->rx_ring_size ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - /* let e1000_refill_rx_ring() io_buffer allocations */ - adapter->rx_iobuf[i] = NULL; - } - - /* allocate io_buffers */ - rc = e1000_refill_rx_ring ( adapter ); - if ( rc < 0 ) - e1000_free_rx_resources ( adapter ); - - return rc; -} - -/** - * e1000_configure_rx - Configure 8254x Receive Unit after Reset - * @adapter: board private structure - * - * Configure the Rx unit of the MAC after a reset. - **/ -static void e1000_configure_rx ( struct e1000_adapter *adapter ) -{ - struct e1000_hw *hw = &adapter->hw; - uint32_t rctl; - - DBG ( "e1000_configure_rx\n" ); - - /* disable receives while setting up the descriptors */ - rctl = E1000_READ_REG ( hw, E1000_RCTL ); - E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); - E1000_WRITE_FLUSH ( hw ); - mdelay(10); - - adapter->rx_curr = 0; - - /* Setup the HW Rx Head and Tail Descriptor Pointers and - * the Base and Length of the Rx Descriptor Ring */ - - E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) ); - E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size ); - - E1000_WRITE_REG ( hw, E1000_RDH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 ); - - /* Enable Receives */ - rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | - E1000_RCTL_MPE | E1000_RCTL_SECRC; - E1000_WRITE_REG ( hw, E1000_RCTL, rctl ); - E1000_WRITE_FLUSH ( hw ); - - DBG ( "E1000_RDBAL(0): %#08x\n", E1000_READ_REG ( hw, E1000_RDBAL(0) ) ); - DBG ( "E1000_RDLEN(0): %d\n", E1000_READ_REG ( hw, E1000_RDLEN(0) ) ); - DBG ( "E1000_RCTL: %#08x\n", E1000_READ_REG ( hw, E1000_RCTL ) ); -} - -/** - * e1000_process_rx_packets - process received packets - * - * @v netdev network interface device structure - **/ -static void e1000_process_rx_packets ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - uint32_t i; - uint32_t rx_status; - uint32_t rx_len; - uint32_t rx_err; - struct e1000_rx_desc *rx_curr_desc; - - /* Process received packets - */ - while ( 1 ) { - - i = adapter->rx_curr; - - rx_curr_desc = ( void * ) ( adapter->rx_base ) + - ( i * sizeof ( *adapter->rx_base ) ); - rx_status = rx_curr_desc->status; - - DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status ); - - if ( ! ( rx_status & E1000_RXD_STAT_DD ) ) - break; - - if ( adapter->rx_iobuf[i] == NULL ) - break; - - DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) ); - - rx_len = rx_curr_desc->length; - - DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n", - i, rx_status, rx_len ); - - rx_err = rx_curr_desc->errors; - - iob_put ( adapter->rx_iobuf[i], rx_len ); - - if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) { - - netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL ); - DBG ( "e1000_poll: Corrupted packet received!" - " rx_err: %#08x\n", rx_err ); - } else { - /* Add this packet to the receive queue. */ - netdev_rx ( netdev, adapter->rx_iobuf[i] ); - } - adapter->rx_iobuf[i] = NULL; - - memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) ); - - adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC; - } -} - -/** - * e1000_reset - Put e1000 NIC in known initial state - * - * @v adapter e1000 private structure - **/ -void e1000_reset ( struct e1000_adapter *adapter ) -{ - struct e1000_mac_info *mac = &adapter->hw.mac; - u32 pba = 0; - - DBG ( "e1000_reset\n" ); - - switch (mac->type) { - case e1000_82542: - case e1000_82543: - case e1000_82544: - case e1000_82540: - case e1000_82541: - case e1000_82541_rev_2: - pba = E1000_PBA_48K; - break; - case e1000_82545: - case e1000_82545_rev_3: - case e1000_82546: - case e1000_82546_rev_3: - pba = E1000_PBA_48K; - break; - case e1000_82547: - case e1000_82547_rev_2: - pba = E1000_PBA_30K; - break; - case e1000_undefined: - case e1000_num_macs: - break; - } - - E1000_WRITE_REG ( &adapter->hw, E1000_PBA, pba ); - - /* Allow time for pending master requests to run */ - e1000_reset_hw ( &adapter->hw ); - - if ( mac->type >= e1000_82544 ) - E1000_WRITE_REG ( &adapter->hw, E1000_WUC, 0 ); - - if ( e1000_init_hw ( &adapter->hw ) ) - DBG ( "Hardware Error\n" ); - - e1000_reset_adaptive ( &adapter->hw ); - e1000_get_phy_info ( &adapter->hw ); - - e1000_init_manageability ( adapter ); -} - -/** Functions that implement the iPXE driver API **/ - -/** - * e1000_close - Disables a network interface - * - * @v netdev network interface device structure - * - **/ -static void e1000_close ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - struct e1000_hw *hw = &adapter->hw; - uint32_t rctl; - - DBG ( "e1000_close\n" ); - - /* Disable and acknowledge interrupts */ - e1000_irq_disable ( adapter ); - E1000_READ_REG ( hw, E1000_ICR ); - - /* disable receives */ - rctl = E1000_READ_REG ( hw, E1000_RCTL ); - E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); - E1000_WRITE_FLUSH ( hw ); - - e1000_reset_hw ( hw ); - - e1000_free_tx_resources ( adapter ); - e1000_free_rx_resources ( adapter ); -} - -/** - * e1000_transmit - Transmit a packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * - * @ret rc Returns 0 on success, negative on failure - */ -static int e1000_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) -{ - struct e1000_adapter *adapter = netdev_priv( netdev ); - struct e1000_hw *hw = &adapter->hw; - uint32_t tx_curr = adapter->tx_tail; - struct e1000_tx_desc *tx_curr_desc; - - DBG ("e1000_transmit\n"); - - if ( adapter->tx_fill_ctr == NUM_TX_DESC ) { - DBG ("TX overflow\n"); - return -ENOBUFS; - } - - /* Save pointer to iobuf we have been given to transmit, - netdev_tx_complete() will need it later - */ - adapter->tx_iobuf[tx_curr] = iobuf; - - tx_curr_desc = ( void * ) ( adapter->tx_base ) + - ( tx_curr * sizeof ( *adapter->tx_base ) ); - - DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); - DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 ); - DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) ); - - /* Add the packet to TX ring - */ - tx_curr_desc->buffer_addr = - virt_to_bus ( iobuf->data ); - tx_curr_desc->lower.data = - E1000_TXD_CMD_RS | E1000_TXD_CMD_EOP | - E1000_TXD_CMD_IFCS | iob_len ( iobuf ); - tx_curr_desc->upper.data = 0; - - DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr, - tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); - - /* Point to next free descriptor */ - adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC; - adapter->tx_fill_ctr++; - - /* Write new tail to NIC, making packet available for transmit - */ - wmb(); - E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail ); - - return 0; -} - -/** - * e1000_poll - Poll for received packets - * - * @v netdev Network device - */ -static void e1000_poll ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv( netdev ); - struct e1000_hw *hw = &adapter->hw; - - uint32_t icr; - - DBGP ( "e1000_poll\n" ); - - /* Acknowledge interrupts */ - icr = E1000_READ_REG ( hw, E1000_ICR ); - if ( ! icr ) - return; - - DBG ( "e1000_poll: intr_status = %#08x\n", icr ); - - e1000_process_tx_packets ( netdev ); - - e1000_process_rx_packets ( netdev ); - - e1000_refill_rx_ring(adapter); -} - -/** - * e1000_irq - enable or Disable interrupts - * - * @v adapter e1000 adapter - * @v action requested interrupt action - **/ -static void e1000_irq ( struct net_device *netdev, int enable ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - - DBG ( "e1000_irq\n" ); - - if ( enable ) { - e1000_irq_enable ( adapter ); - } else { - e1000_irq_disable ( adapter ); - } -} - -static struct net_device_operations e1000_operations; - -/** - * e1000_probe - Initial configuration of e1000 NIC - * - * @v pci PCI device - * @v id PCI IDs - * - * @ret rc Return status code - **/ -int e1000_probe ( struct pci_device *pdev ) -{ - int i, err; - struct net_device *netdev; - struct e1000_adapter *adapter; - unsigned long mmio_start, mmio_len; - - DBG ( "e1000_probe\n" ); - - err = -ENOMEM; - - /* Allocate net device ( also allocates memory for netdev->priv - and makes netdev-priv point to it ) */ - netdev = alloc_etherdev ( sizeof ( struct e1000_adapter ) ); - if ( ! netdev ) - goto err_alloc_etherdev; - - /* Associate e1000-specific network operations operations with - * generic network device layer */ - netdev_init ( netdev, &e1000_operations ); - - /* Associate this network device with given PCI device */ - pci_set_drvdata ( pdev, netdev ); - netdev->dev = &pdev->dev; - - /* Initialize driver private storage */ - adapter = netdev_priv ( netdev ); - memset ( adapter, 0, ( sizeof ( *adapter ) ) ); - - adapter->pdev = pdev; - - adapter->ioaddr = pdev->ioaddr; - adapter->hw.io_base = pdev->ioaddr; - - adapter->irqno = pdev->irq; - adapter->netdev = netdev; - adapter->hw.back = adapter; - - adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC; - adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC; - - mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 ); - mmio_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_0 ); - - DBG ( "mmio_start: %#08lx\n", mmio_start ); - DBG ( "mmio_len: %#08lx\n", mmio_len ); - - /* Fix up PCI device */ - adjust_pci_device ( pdev ); - - err = -EIO; - - adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len ); - DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr ); - - if ( ! adapter->hw.hw_addr ) - goto err_ioremap; - - /* Hardware features, flags and workarounds */ - if (adapter->hw.mac.type >= e1000_82540) { - adapter->flags |= E1000_FLAG_HAS_SMBUS; - adapter->flags |= E1000_FLAG_HAS_INTR_MODERATION; - } - - if (adapter->hw.mac.type == e1000_82543) - adapter->flags |= E1000_FLAG_BAD_TX_CARRIER_STATS_FD; - - adapter->hw.phy.autoneg_wait_to_complete = true; - adapter->hw.mac.adaptive_ifs = true; - - /* setup the private structure */ - if ( ( err = e1000_sw_init ( adapter ) ) ) - goto err_sw_init; - - if ((err = e1000_init_mac_params(&adapter->hw))) - goto err_hw_init; - - if ((err = e1000_init_nvm_params(&adapter->hw))) - goto err_hw_init; - - /* Force auto-negotiated speed and duplex */ - adapter->hw.mac.autoneg = 1; - - if ((err = e1000_init_phy_params(&adapter->hw))) - goto err_hw_init; - - DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type ); - - /* before reading the EEPROM, reset the controller to - * put the device in a known good starting state - */ - err = e1000_reset_hw ( &adapter->hw ); - if ( err < 0 ) { - DBG ( "Hardware Initialization Failed\n" ); - goto err_reset; - } - /* make sure the NVM is good */ - - if ( e1000_validate_nvm_checksum(&adapter->hw) < 0 ) { - DBG ( "The NVM Checksum Is Not Valid\n" ); - err = -EIO; - goto err_eeprom; - } - - /* copy the MAC address out of the EEPROM */ - if ( e1000_read_mac_addr ( &adapter->hw ) ) - DBG ( "EEPROM Read Error\n" ); - - memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN ); - - /* reset the hardware with the new settings */ - e1000_reset ( adapter ); - - if ( ( err = register_netdev ( netdev ) ) != 0) - goto err_register; - - /* Mark as link up; we don't yet handle link state */ - netdev_link_up ( netdev ); - - for (i = 0; i < 6; i++) - DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":"); - - DBG ( "e1000_probe succeeded!\n" ); - - /* No errors, return success */ - return 0; - -/* Error return paths */ -err_reset: -err_register: -err_hw_init: -err_eeprom: - if (!e1000_check_reset_block(&adapter->hw)) - e1000_phy_hw_reset(&adapter->hw); - if (adapter->hw.flash_address) - iounmap(adapter->hw.flash_address); -err_sw_init: - iounmap ( adapter->hw.hw_addr ); -err_ioremap: - netdev_put ( netdev ); -err_alloc_etherdev: - return err; -} - -/** - * e1000_remove - Device Removal Routine - * - * @v pdev PCI device information struct - * - **/ -void e1000_remove ( struct pci_device *pdev ) -{ - struct net_device *netdev = pci_get_drvdata ( pdev ); - struct e1000_adapter *adapter = netdev_priv ( netdev ); - - DBG ( "e1000_remove\n" ); - - if ( adapter->hw.flash_address ) - iounmap ( adapter->hw.flash_address ); - if ( adapter->hw.hw_addr ) - iounmap ( adapter->hw.hw_addr ); - - unregister_netdev ( netdev ); - e1000_reset_hw ( &adapter->hw ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); -} - -/** - * e1000_open - Called when a network interface is made active - * - * @v netdev network interface device structure - * @ret rc Return status code, 0 on success, negative value on failure - * - **/ -static int e1000_open ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv(netdev); - int err; - - DBG ( "e1000_open\n" ); - - /* allocate transmit descriptors */ - err = e1000_setup_tx_resources ( adapter ); - if ( err ) { - DBG ( "Error setting up TX resources!\n" ); - goto err_setup_tx; - } - - /* allocate receive descriptors */ - err = e1000_setup_rx_resources ( adapter ); - if ( err ) { - DBG ( "Error setting up RX resources!\n" ); - goto err_setup_rx; - } - - e1000_configure_tx ( adapter ); - - e1000_configure_rx ( adapter ); - - DBG ( "E1000_RXDCTL(0): %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) ); - - return 0; - -err_setup_rx: - e1000_free_tx_resources ( adapter ); -err_setup_tx: - e1000_reset ( adapter ); - - return err; -} - -/** e1000 net device operations */ -static struct net_device_operations e1000_operations = { - .open = e1000_open, - .close = e1000_close, - .transmit = e1000_transmit, - .poll = e1000_poll, - .irq = e1000_irq, -}; diff --git a/src/drivers/net/e1000/e1000_manage.c b/src/drivers/net/e1000/e1000_manage.c deleted file mode 100644 index 3362942e..00000000 --- a/src/drivers/net/e1000/e1000_manage.c +++ /dev/null @@ -1,389 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#if 0 - -#include "e1000_api.h" - -static u8 e1000_calculate_checksum(u8 *buffer, u32 length); - -/** - * e1000_calculate_checksum - Calculate checksum for buffer - * @buffer: pointer to EEPROM - * @length: size of EEPROM to calculate a checksum for - * - * Calculates the checksum for some buffer on a specified length. The - * checksum calculated is returned. - **/ -static u8 e1000_calculate_checksum(u8 *buffer, u32 length) -{ - u32 i; - u8 sum = 0; - - DEBUGFUNC("e1000_calculate_checksum"); - - if (!buffer) - return 0; - - for (i = 0; i < length; i++) - sum += buffer[i]; - - return (u8) (0 - sum); -} - -/** - * e1000_mng_enable_host_if_generic - Checks host interface is enabled - * @hw: pointer to the HW structure - * - * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND - * - * This function checks whether the HOST IF is enabled for command operation - * and also checks whether the previous command is completed. It busy waits - * in case of previous command is not completed. - **/ -s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw) -{ - u32 hicr; - s32 ret_val = E1000_SUCCESS; - u8 i; - - DEBUGFUNC("e1000_mng_enable_host_if_generic"); - - /* Check that the host interface is enabled. */ - hicr = E1000_READ_REG(hw, E1000_HICR); - if ((hicr & E1000_HICR_EN) == 0) { - DEBUGOUT("E1000_HOST_EN bit disabled.\n"); - ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; - goto out; - } - /* check the previous command is completed */ - for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { - hicr = E1000_READ_REG(hw, E1000_HICR); - if (!(hicr & E1000_HICR_C)) - break; - msec_delay_irq(1); - } - - if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { - DEBUGOUT("Previous command timeout failed .\n"); - ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_check_mng_mode_generic - Generic check management mode - * @hw: pointer to the HW structure - * - * Reads the firmware semaphore register and returns true (>0) if - * manageability is enabled, else false (0). - **/ -bool e1000_check_mng_mode_generic(struct e1000_hw *hw) -{ - u32 fwsm; - - DEBUGFUNC("e1000_check_mng_mode_generic"); - - fwsm = E1000_READ_REG(hw, E1000_FWSM); - - return (fwsm & E1000_FWSM_MODE_MASK) == - (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); -} - -/** - * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX - * @hw: pointer to the HW structure - * - * Enables packet filtering on transmit packets if manageability is enabled - * and host interface is enabled. - **/ -bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) -{ - struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; - u32 *buffer = (u32 *)&hw->mng_cookie; - u32 offset; - s32 ret_val, hdr_csum, csum; - u8 i, len; - bool tx_filter = true; - - DEBUGFUNC("e1000_enable_tx_pkt_filtering_generic"); - - /* No manageability, no filtering */ - if (!hw->mac.ops.check_mng_mode(hw)) { - tx_filter = false; - goto out; - } - - /* - * If we can't read from the host interface for whatever - * reason, disable filtering. - */ - ret_val = hw->mac.ops.mng_enable_host_if(hw); - if (ret_val != E1000_SUCCESS) { - tx_filter = false; - goto out; - } - - /* Read in the header. Length and offset are in dwords. */ - len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; - offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; - for (i = 0; i < len; i++) { - *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, - E1000_HOST_IF, - offset + i); - } - hdr_csum = hdr->checksum; - hdr->checksum = 0; - csum = e1000_calculate_checksum((u8 *)hdr, - E1000_MNG_DHCP_COOKIE_LENGTH); - /* - * If either the checksums or signature don't match, then - * the cookie area isn't considered valid, in which case we - * take the safe route of assuming Tx filtering is enabled. - */ - if (hdr_csum != csum) - goto out; - if (hdr->signature != E1000_IAMT_SIGNATURE) - goto out; - - /* Cookie area is valid, make the final check for filtering. */ - if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) - tx_filter = false; - -out: - hw->mac.tx_pkt_filtering = tx_filter; - return tx_filter; -} - -/** - * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface - * @length: size of the buffer - * - * Writes the DHCP information to the host interface. - **/ -s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer, - u16 length) -{ - struct e1000_host_mng_command_header hdr; - s32 ret_val; - u32 hicr; - - DEBUGFUNC("e1000_mng_write_dhcp_info_generic"); - - hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; - hdr.command_length = length; - hdr.reserved1 = 0; - hdr.reserved2 = 0; - hdr.checksum = 0; - - /* Enable the host interface */ - ret_val = hw->mac.ops.mng_enable_host_if(hw); - if (ret_val) - goto out; - - /* Populate the host interface with the contents of "buffer". */ - ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length, - sizeof(hdr), &(hdr.checksum)); - if (ret_val) - goto out; - - /* Write the manageability command header */ - ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr); - if (ret_val) - goto out; - - /* Tell the ARC a new command is pending. */ - hicr = E1000_READ_REG(hw, E1000_HICR); - E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C); - -out: - return ret_val; -} - -/** - * e1000_mng_write_cmd_header_generic - Writes manageability command header - * @hw: pointer to the HW structure - * @hdr: pointer to the host interface command header - * - * Writes the command header after does the checksum calculation. - **/ -s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr) -{ - u16 i, length = sizeof(struct e1000_host_mng_command_header); - - DEBUGFUNC("e1000_mng_write_cmd_header_generic"); - - /* Write the whole command header structure with new checksum. */ - - hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); - - length >>= 2; - /* Write the relevant command block into the ram area. */ - for (i = 0; i < length; i++) { - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, - *((u32 *) hdr + i)); - E1000_WRITE_FLUSH(hw); - } - - return E1000_SUCCESS; -} - -/** - * e1000_mng_host_if_write_generic - Write to the manageability host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface buffer - * @length: size of the buffer - * @offset: location in the buffer to write to - * @sum: sum of the data (not checksum) - * - * This function writes the buffer content at the offset given on the host if. - * It also does alignment considerations to do the writes in most efficient - * way. Also fills up the sum of the buffer in *buffer parameter. - **/ -s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, - u16 length, u16 offset, u8 *sum) -{ - u8 *tmp; - u8 *bufptr = buffer; - u32 data = 0; - s32 ret_val = E1000_SUCCESS; - u16 remaining, i, j, prev_bytes; - - DEBUGFUNC("e1000_mng_host_if_write_generic"); - - /* sum = only sum of the data and it is not checksum */ - - if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { - ret_val = -E1000_ERR_PARAM; - goto out; - } - - tmp = (u8 *)&data; - prev_bytes = offset & 0x3; - offset >>= 2; - - if (prev_bytes) { - data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); - for (j = prev_bytes; j < sizeof(u32); j++) { - *(tmp + j) = *bufptr++; - *sum += *(tmp + j); - } - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); - length -= j - prev_bytes; - offset++; - } - - remaining = length & 0x3; - length -= remaining; - - /* Calculate length in DWORDs */ - length >>= 2; - - /* - * The device driver writes the relevant command block into the - * ram area. - */ - for (i = 0; i < length; i++) { - for (j = 0; j < sizeof(u32); j++) { - *(tmp + j) = *bufptr++; - *sum += *(tmp + j); - } - - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, - data); - } - if (remaining) { - for (j = 0; j < sizeof(u32); j++) { - if (j < remaining) - *(tmp + j) = *bufptr++; - else - *(tmp + j) = 0; - - *sum += *(tmp + j); - } - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data); - } - -out: - return ret_val; -} - -/** - * e1000_enable_mng_pass_thru - Enable processing of ARP's - * @hw: pointer to the HW structure - * - * Verifies the hardware needs to allow ARPs to be processed by the host. - **/ -bool e1000_enable_mng_pass_thru(struct e1000_hw *hw) -{ - u32 manc; - u32 fwsm, factps; - bool ret_val = false; - - DEBUGFUNC("e1000_enable_mng_pass_thru"); - - if (!hw->mac.asf_firmware_present) - goto out; - - manc = E1000_READ_REG(hw, E1000_MANC); - - if (!(manc & E1000_MANC_RCV_TCO_EN) || - !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) - goto out; - - if (hw->mac.arc_subsystem_valid) { - fwsm = E1000_READ_REG(hw, E1000_FWSM); - factps = E1000_READ_REG(hw, E1000_FACTPS); - - if (!(factps & E1000_FACTPS_MNGCG) && - ((fwsm & E1000_FWSM_MODE_MASK) == - (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { - ret_val = true; - goto out; - } - } else { - if ((manc & E1000_MANC_SMBUS_EN) && - !(manc & E1000_MANC_ASF_EN)) { - ret_val = true; - goto out; - } - } - -out: - return ret_val; -} - -#endif diff --git a/src/drivers/net/e1000/e1000_manage.h b/src/drivers/net/e1000/e1000_manage.h deleted file mode 100644 index 14467aa6..00000000 --- a/src/drivers/net/e1000/e1000_manage.h +++ /dev/null @@ -1,84 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_MANAGE_H_ -#define _E1000_MANAGE_H_ - -bool e1000_check_mng_mode_generic(struct e1000_hw *hw); -bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw); -s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw); -s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, - u16 length, u16 offset, u8 *sum); -s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr); -s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, - u8 *buffer, u16 length); -bool e1000_enable_mng_pass_thru(struct e1000_hw *hw); - -enum e1000_mng_mode { - e1000_mng_mode_none = 0, - e1000_mng_mode_asf, - e1000_mng_mode_pt, - e1000_mng_mode_ipmi, - e1000_mng_mode_host_if_only -}; - -#define E1000_FACTPS_MNGCG 0x20000000 - -#define E1000_FWSM_MODE_MASK 0xE -#define E1000_FWSM_MODE_SHIFT 1 - -#define E1000_MNG_IAMT_MODE 0x3 -#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 -#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 -#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 -#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 -#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1 -#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 - -#define E1000_VFTA_ENTRY_SHIFT 5 -#define E1000_VFTA_ENTRY_MASK 0x7F -#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F - -#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */ -#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */ -#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */ - -#define E1000_HICR_EN 0x01 /* Enable bit - RO */ -/* Driver sets this bit when done to put command in RAM */ -#define E1000_HICR_C 0x02 -#define E1000_HICR_SV 0x04 /* Status Validity */ -#define E1000_HICR_FW_RESET_ENABLE 0x40 -#define E1000_HICR_FW_RESET 0x80 - -/* Intel(R) Active Management Technology signature */ -#define E1000_IAMT_SIGNATURE 0x544D4149 - -#endif diff --git a/src/drivers/net/e1000/e1000_nvm.c b/src/drivers/net/e1000/e1000_nvm.c deleted file mode 100644 index 488252f4..00000000 --- a/src/drivers/net/e1000/e1000_nvm.c +++ /dev/null @@ -1,923 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000_api.h" - -static void e1000_reload_nvm_generic(struct e1000_hw *hw); - -/** - * e1000_init_nvm_ops_generic - Initialize NVM function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void e1000_init_nvm_ops_generic(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - DEBUGFUNC("e1000_init_nvm_ops_generic"); - - /* Initialize function pointers */ - nvm->ops.init_params = e1000_null_ops_generic; - nvm->ops.acquire = e1000_null_ops_generic; - nvm->ops.read = e1000_null_read_nvm; - nvm->ops.release = e1000_null_nvm_generic; - nvm->ops.reload = e1000_reload_nvm_generic; - nvm->ops.update = e1000_null_ops_generic; - nvm->ops.valid_led_default = e1000_null_led_default; - nvm->ops.validate = e1000_null_ops_generic; - nvm->ops.write = e1000_null_write_nvm; -} - -/** - * e1000_null_nvm_read - No-op function, return 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_read_nvm(struct e1000_hw *hw __unused, u16 a __unused, - u16 b __unused, u16 *c __unused) -{ - DEBUGFUNC("e1000_null_read_nvm"); - return E1000_SUCCESS; -} - -/** - * e1000_null_nvm_generic - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_nvm_generic(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("e1000_null_nvm_generic"); - return; -} - -/** - * e1000_null_led_default - No-op function, return 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_led_default(struct e1000_hw *hw __unused, - u16 *data __unused) -{ - DEBUGFUNC("e1000_null_led_default"); - return E1000_SUCCESS; -} - -/** - * e1000_null_write_nvm - No-op function, return 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_write_nvm(struct e1000_hw *hw __unused, u16 a __unused, - u16 b __unused, u16 *c __unused) -{ - DEBUGFUNC("e1000_null_write_nvm"); - return E1000_SUCCESS; -} - -/** - * e1000_raise_eec_clk - Raise EEPROM clock - * @hw: pointer to the HW structure - * @eecd: pointer to the EEPROM - * - * Enable/Raise the EEPROM clock bit. - **/ -static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) -{ - *eecd = *eecd | E1000_EECD_SK; - E1000_WRITE_REG(hw, E1000_EECD, *eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(hw->nvm.delay_usec); -} - -/** - * e1000_lower_eec_clk - Lower EEPROM clock - * @hw: pointer to the HW structure - * @eecd: pointer to the EEPROM - * - * Clear/Lower the EEPROM clock bit. - **/ -static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) -{ - *eecd = *eecd & ~E1000_EECD_SK; - E1000_WRITE_REG(hw, E1000_EECD, *eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(hw->nvm.delay_usec); -} - -/** - * e1000_shift_out_eec_bits - Shift data bits our to the EEPROM - * @hw: pointer to the HW structure - * @data: data to send to the EEPROM - * @count: number of bits to shift out - * - * We need to shift 'count' bits out to the EEPROM. So, the value in the - * "data" parameter will be shifted out to the EEPROM one bit at a time. - * In order to do this, "data" must be broken down into bits. - **/ -static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - u32 mask; - - DEBUGFUNC("e1000_shift_out_eec_bits"); - - mask = 0x01 << (count - 1); - if (nvm->type == e1000_nvm_eeprom_microwire) - eecd &= ~E1000_EECD_DO; - else - if (nvm->type == e1000_nvm_eeprom_spi) - eecd |= E1000_EECD_DO; - - do { - eecd &= ~E1000_EECD_DI; - - if (data & mask) - eecd |= E1000_EECD_DI; - - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - - usec_delay(nvm->delay_usec); - - e1000_raise_eec_clk(hw, &eecd); - e1000_lower_eec_clk(hw, &eecd); - - mask >>= 1; - } while (mask); - - eecd &= ~E1000_EECD_DI; - E1000_WRITE_REG(hw, E1000_EECD, eecd); -} - -/** - * e1000_shift_in_eec_bits - Shift data bits in from the EEPROM - * @hw: pointer to the HW structure - * @count: number of bits to shift in - * - * In order to read a register from the EEPROM, we need to shift 'count' bits - * in from the EEPROM. Bits are "shifted in" by raising the clock input to - * the EEPROM (setting the SK bit), and then reading the value of the data out - * "DO" bit. During this "shifting in" process the data in "DI" bit should - * always be clear. - **/ -static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count) -{ - u32 eecd; - u32 i; - u16 data; - - DEBUGFUNC("e1000_shift_in_eec_bits"); - - eecd = E1000_READ_REG(hw, E1000_EECD); - - eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); - data = 0; - - for (i = 0; i < count; i++) { - data <<= 1; - e1000_raise_eec_clk(hw, &eecd); - - eecd = E1000_READ_REG(hw, E1000_EECD); - - eecd &= ~E1000_EECD_DI; - if (eecd & E1000_EECD_DO) - data |= 1; - - e1000_lower_eec_clk(hw, &eecd); - } - - return data; -} - -/** - * e1000_poll_eerd_eewr_done - Poll for EEPROM read/write completion - * @hw: pointer to the HW structure - * @ee_reg: EEPROM flag for polling - * - * Polls the EEPROM status bit for either read or write completion based - * upon the value of 'ee_reg'. - **/ -s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) -{ - u32 attempts = 100000; - u32 i, reg = 0; - s32 ret_val = -E1000_ERR_NVM; - - DEBUGFUNC("e1000_poll_eerd_eewr_done"); - - for (i = 0; i < attempts; i++) { - if (ee_reg == E1000_NVM_POLL_READ) - reg = E1000_READ_REG(hw, E1000_EERD); - else - reg = E1000_READ_REG(hw, E1000_EEWR); - - if (reg & E1000_NVM_RW_REG_DONE) { - ret_val = E1000_SUCCESS; - break; - } - - usec_delay(5); - } - - return ret_val; -} - -/** - * e1000_acquire_nvm_generic - Generic request for access to EEPROM - * @hw: pointer to the HW structure - * - * Set the EEPROM access request bit and wait for EEPROM access grant bit. - * Return successful if access grant bit set, else clear the request for - * EEPROM access and return -E1000_ERR_NVM (-1). - **/ -s32 e1000_acquire_nvm_generic(struct e1000_hw *hw) -{ - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - s32 timeout = E1000_NVM_GRANT_ATTEMPTS; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_acquire_nvm_generic"); - - E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ); - eecd = E1000_READ_REG(hw, E1000_EECD); - - while (timeout) { - if (eecd & E1000_EECD_GNT) - break; - usec_delay(5); - eecd = E1000_READ_REG(hw, E1000_EECD); - timeout--; - } - - if (!timeout) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - DEBUGOUT("Could not acquire NVM grant\n"); - ret_val = -E1000_ERR_NVM; - } - - return ret_val; -} - -/** - * e1000_standby_nvm - Return EEPROM to standby state - * @hw: pointer to the HW structure - * - * Return the EEPROM to a standby state. - **/ -static void e1000_standby_nvm(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - - DEBUGFUNC("e1000_standby_nvm"); - - if (nvm->type == e1000_nvm_eeprom_microwire) { - eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(nvm->delay_usec); - - e1000_raise_eec_clk(hw, &eecd); - - /* Select EEPROM */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(nvm->delay_usec); - - e1000_lower_eec_clk(hw, &eecd); - } else - if (nvm->type == e1000_nvm_eeprom_spi) { - /* Toggle CS to flush commands */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(nvm->delay_usec); - eecd &= ~E1000_EECD_CS; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(nvm->delay_usec); - } -} - -/** - * e1000_stop_nvm - Terminate EEPROM command - * @hw: pointer to the HW structure - * - * Terminates the current command by inverting the EEPROM's chip select pin. - **/ -void e1000_stop_nvm(struct e1000_hw *hw) -{ - u32 eecd; - - DEBUGFUNC("e1000_stop_nvm"); - - eecd = E1000_READ_REG(hw, E1000_EECD); - if (hw->nvm.type == e1000_nvm_eeprom_spi) { - /* Pull CS high */ - eecd |= E1000_EECD_CS; - e1000_lower_eec_clk(hw, &eecd); - } else if (hw->nvm.type == e1000_nvm_eeprom_microwire) { - /* CS on Microwire is active-high */ - eecd &= ~(E1000_EECD_CS | E1000_EECD_DI); - E1000_WRITE_REG(hw, E1000_EECD, eecd); - e1000_raise_eec_clk(hw, &eecd); - e1000_lower_eec_clk(hw, &eecd); - } -} - -/** - * e1000_release_nvm_generic - Release exclusive access to EEPROM - * @hw: pointer to the HW structure - * - * Stop any current commands to the EEPROM and clear the EEPROM request bit. - **/ -void e1000_release_nvm_generic(struct e1000_hw *hw) -{ - u32 eecd; - - DEBUGFUNC("e1000_release_nvm_generic"); - - e1000_stop_nvm(hw); - - eecd = E1000_READ_REG(hw, E1000_EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, E1000_EECD, eecd); -} - -/** - * e1000_ready_nvm_eeprom - Prepares EEPROM for read/write - * @hw: pointer to the HW structure - * - * Setups the EEPROM for reading and writing. - **/ -static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - s32 ret_val = E1000_SUCCESS; - u16 timeout = 0; - u8 spi_stat_reg; - - DEBUGFUNC("e1000_ready_nvm_eeprom"); - - if (nvm->type == e1000_nvm_eeprom_microwire) { - /* Clear SK and DI */ - eecd &= ~(E1000_EECD_DI | E1000_EECD_SK); - E1000_WRITE_REG(hw, E1000_EECD, eecd); - /* Set CS */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - } else - if (nvm->type == e1000_nvm_eeprom_spi) { - /* Clear SK and CS */ - eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); - E1000_WRITE_REG(hw, E1000_EECD, eecd); - usec_delay(1); - timeout = NVM_MAX_RETRY_SPI; - - /* - * Read "Status Register" repeatedly until the LSB is cleared. - * The EEPROM will signal that the command has been completed - * by clearing bit 0 of the internal status register. If it's - * not cleared within 'timeout', then error out. - */ - while (timeout) { - e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, - hw->nvm.opcode_bits); - spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8); - if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) - break; - - usec_delay(5); - e1000_standby_nvm(hw); - timeout--; - } - - if (!timeout) { - DEBUGOUT("SPI NVM Status error\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - } - -out: - return ret_val; -} - -/** - * e1000_read_nvm_spi - Read EEPROM's using SPI - * @hw: pointer to the HW structure - * @offset: offset of word in the EEPROM to read - * @words: number of words to read - * @data: word read from the EEPROM - * - * Reads a 16 bit word from the EEPROM. - **/ -s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 i = 0; - s32 ret_val; - u16 word_in; - u8 read_opcode = NVM_READ_OPCODE_SPI; - - DEBUGFUNC("e1000_read_nvm_spi"); - - /* - * A check for invalid values: offset too large, too many words, - * and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - DEBUGOUT("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = e1000_ready_nvm_eeprom(hw); - if (ret_val) - goto release; - - e1000_standby_nvm(hw); - - if ((nvm->address_bits == 8) && (offset >= 128)) - read_opcode |= NVM_A8_OPCODE_SPI; - - /* Send the READ command (opcode + addr) */ - e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); - e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits); - - /* - * Read the data. SPI NVMs increment the address with each byte - * read and will roll over if reading beyond the end. This allows - * us to read the whole NVM from any offset - */ - for (i = 0; i < words; i++) { - word_in = e1000_shift_in_eec_bits(hw, 16); - data[i] = (word_in >> 8) | (word_in << 8); - } - -release: - nvm->ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_read_nvm_microwire - Reads EEPROM's using microwire - * @hw: pointer to the HW structure - * @offset: offset of word in the EEPROM to read - * @words: number of words to read - * @data: word read from the EEPROM - * - * Reads a 16 bit word from the EEPROM. - **/ -s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 i = 0; - s32 ret_val; - u8 read_opcode = NVM_READ_OPCODE_MICROWIRE; - - DEBUGFUNC("e1000_read_nvm_microwire"); - - /* - * A check for invalid values: offset too large, too many words, - * and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - DEBUGOUT("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = e1000_ready_nvm_eeprom(hw); - if (ret_val) - goto release; - - for (i = 0; i < words; i++) { - /* Send the READ command (opcode + addr) */ - e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits); - e1000_shift_out_eec_bits(hw, (u16)(offset + i), - nvm->address_bits); - - /* - * Read the data. For microwire, each word requires the - * overhead of setup and tear-down. - */ - data[i] = e1000_shift_in_eec_bits(hw, 16); - e1000_standby_nvm(hw); - } - -release: - nvm->ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_read_nvm_eerd - Reads EEPROM using EERD register - * @hw: pointer to the HW structure - * @offset: offset of word in the EEPROM to read - * @words: number of words to read - * @data: word read from the EEPROM - * - * Reads a 16 bit word from the EEPROM using the EERD register. - **/ -s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 i, eerd = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_read_nvm_eerd"); - - /* - * A check for invalid values: offset too large, too many words, - * too many words for the offset, and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - DEBUGOUT("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - for (i = 0; i < words; i++) { - eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + - E1000_NVM_RW_REG_START; - - E1000_WRITE_REG(hw, E1000_EERD, eerd); - ret_val = e1000_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); - if (ret_val) - break; - - data[i] = (E1000_READ_REG(hw, E1000_EERD) >> - E1000_NVM_RW_REG_DATA); - } - -out: - return ret_val; -} - -/** - * e1000_write_nvm_spi - Write to EEPROM using SPI - * @hw: pointer to the HW structure - * @offset: offset within the EEPROM to be written to - * @words: number of words to write - * @data: 16 bit word(s) to be written to the EEPROM - * - * Writes data to EEPROM at offset using SPI interface. - * - * If e1000_update_nvm_checksum is not called after this function , the - * EEPROM will most likely contain an invalid checksum. - **/ -s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - s32 ret_val; - u16 widx = 0; - - DEBUGFUNC("e1000_write_nvm_spi"); - - /* - * A check for invalid values: offset too large, too many words, - * and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - DEBUGOUT("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; - - while (widx < words) { - u8 write_opcode = NVM_WRITE_OPCODE_SPI; - - ret_val = e1000_ready_nvm_eeprom(hw); - if (ret_val) - goto release; - - e1000_standby_nvm(hw); - - /* Send the WRITE ENABLE command (8 bit opcode) */ - e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, - nvm->opcode_bits); - - e1000_standby_nvm(hw); - - /* - * Some SPI eeproms use the 8th address bit embedded in the - * opcode - */ - if ((nvm->address_bits == 8) && (offset >= 128)) - write_opcode |= NVM_A8_OPCODE_SPI; - - /* Send the Write command (8-bit opcode + addr) */ - e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); - e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), - nvm->address_bits); - - /* Loop to allow for up to whole page write of eeprom */ - while (widx < words) { - u16 word_out = data[widx]; - word_out = (word_out >> 8) | (word_out << 8); - e1000_shift_out_eec_bits(hw, word_out, 16); - widx++; - - if ((((offset + widx) * 2) % nvm->page_size) == 0) { - e1000_standby_nvm(hw); - break; - } - } - } - - msec_delay(10); -release: - nvm->ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_write_nvm_microwire - Writes EEPROM using microwire - * @hw: pointer to the HW structure - * @offset: offset within the EEPROM to be written to - * @words: number of words to write - * @data: 16 bit word(s) to be written to the EEPROM - * - * Writes data to EEPROM at offset using microwire interface. - * - * If e1000_update_nvm_checksum is not called after this function , the - * EEPROM will most likely contain an invalid checksum. - **/ -s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - s32 ret_val; - u32 eecd; - u16 words_written = 0; - u16 widx = 0; - - DEBUGFUNC("e1000_write_nvm_microwire"); - - /* - * A check for invalid values: offset too large, too many words, - * and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - DEBUGOUT("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = e1000_ready_nvm_eeprom(hw); - if (ret_val) - goto release; - - e1000_shift_out_eec_bits(hw, NVM_EWEN_OPCODE_MICROWIRE, - (u16)(nvm->opcode_bits + 2)); - - e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2)); - - e1000_standby_nvm(hw); - - while (words_written < words) { - e1000_shift_out_eec_bits(hw, NVM_WRITE_OPCODE_MICROWIRE, - nvm->opcode_bits); - - e1000_shift_out_eec_bits(hw, (u16)(offset + words_written), - nvm->address_bits); - - e1000_shift_out_eec_bits(hw, data[words_written], 16); - - e1000_standby_nvm(hw); - - for (widx = 0; widx < 200; widx++) { - eecd = E1000_READ_REG(hw, E1000_EECD); - if (eecd & E1000_EECD_DO) - break; - usec_delay(50); - } - - if (widx == 200) { - DEBUGOUT("NVM Write did not complete\n"); - ret_val = -E1000_ERR_NVM; - goto release; - } - - e1000_standby_nvm(hw); - - words_written++; - } - - e1000_shift_out_eec_bits(hw, NVM_EWDS_OPCODE_MICROWIRE, - (u16)(nvm->opcode_bits + 2)); - - e1000_shift_out_eec_bits(hw, 0, (u16)(nvm->address_bits - 2)); - -release: - nvm->ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_read_pba_num_generic - Read device part number - * @hw: pointer to the HW structure - * @pba_num: pointer to device part number - * - * Reads the product board assembly (PBA) number from the EEPROM and stores - * the value in pba_num. - **/ -s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num) -{ - s32 ret_val; - u16 nvm_data; - - DEBUGFUNC("e1000_read_pba_num_generic"); - - ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - *pba_num = (u32)(nvm_data << 16); - - ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - *pba_num |= nvm_data; - -out: - return ret_val; -} - -/** - * e1000_read_mac_addr_generic - Read device MAC address - * @hw: pointer to the HW structure - * - * Reads the device MAC address from the EEPROM and stores the value. - * Since devices with two ports use the same EEPROM, we increment the - * last bit in the MAC address for the second port. - **/ -s32 e1000_read_mac_addr_generic(struct e1000_hw *hw) -{ - u32 rar_high; - u32 rar_low; - u16 i; - - rar_high = E1000_READ_REG(hw, E1000_RAH(0)); - rar_low = E1000_READ_REG(hw, E1000_RAL(0)); - - for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++) - hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8)); - - for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++) - hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8)); - - for (i = 0; i < ETH_ADDR_LEN; i++) - hw->mac.addr[i] = hw->mac.perm_addr[i]; - - return E1000_SUCCESS; -} - -/** - * e1000_validate_nvm_checksum_generic - Validate EEPROM checksum - * @hw: pointer to the HW structure - * - * Calculates the EEPROM checksum by reading/adding each word of the EEPROM - * and then verifies that the sum of the EEPROM is equal to 0xBABA. - **/ -s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 checksum = 0; - u16 i, nvm_data; - - DEBUGFUNC("e1000_validate_nvm_checksum_generic"); - - for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { - ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - checksum += nvm_data; - } - - if (checksum != (u16) NVM_SUM) { - DEBUGOUT("NVM Checksum Invalid\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_update_nvm_checksum_generic - Update EEPROM checksum - * @hw: pointer to the HW structure - * - * Updates the EEPROM checksum by reading/adding each word of the EEPROM - * up to the checksum. Then calculates the EEPROM checksum and writes the - * value to the EEPROM. - **/ -s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw) -{ - s32 ret_val; - u16 checksum = 0; - u16 i, nvm_data; - - DEBUGFUNC("e1000_update_nvm_checksum"); - - for (i = 0; i < NVM_CHECKSUM_REG; i++) { - ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error while updating checksum.\n"); - goto out; - } - checksum += nvm_data; - } - checksum = (u16) NVM_SUM - checksum; - ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum); - if (ret_val) - DEBUGOUT("NVM Write Error while updating checksum.\n"); - -out: - return ret_val; -} - -/** - * e1000_reload_nvm_generic - Reloads EEPROM - * @hw: pointer to the HW structure - * - * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the - * extended control register. - **/ -static void e1000_reload_nvm_generic(struct e1000_hw *hw) -{ - u32 ctrl_ext; - - DEBUGFUNC("e1000_reload_nvm_generic"); - - usec_delay(10); - ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_EE_RST; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - E1000_WRITE_FLUSH(hw); -} diff --git a/src/drivers/net/e1000/e1000_nvm.h b/src/drivers/net/e1000/e1000_nvm.h deleted file mode 100644 index 1585417c..00000000 --- a/src/drivers/net/e1000/e1000_nvm.h +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_NVM_H_ -#define _E1000_NVM_H_ - -void e1000_init_nvm_ops_generic(struct e1000_hw *hw); -s32 e1000_null_read_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c); -void e1000_null_nvm_generic(struct e1000_hw *hw); -s32 e1000_null_led_default(struct e1000_hw *hw, u16 *data); -s32 e1000_null_write_nvm(struct e1000_hw *hw, u16 a, u16 b, u16 *c); -s32 e1000_acquire_nvm_generic(struct e1000_hw *hw); - -s32 e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); -s32 e1000_read_mac_addr_generic(struct e1000_hw *hw); -s32 e1000_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num); -s32 e1000_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); -s32 e1000_read_nvm_microwire(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -s32 e1000_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 e1000_valid_led_default_generic(struct e1000_hw *hw, u16 *data); -s32 e1000_validate_nvm_checksum_generic(struct e1000_hw *hw); -s32 e1000_write_nvm_eewr(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -s32 e1000_write_nvm_microwire(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -s32 e1000_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 e1000_update_nvm_checksum_generic(struct e1000_hw *hw); -void e1000_stop_nvm(struct e1000_hw *hw); -void e1000_release_nvm_generic(struct e1000_hw *hw); - -#define E1000_STM_OPCODE 0xDB00 - -#endif diff --git a/src/drivers/net/e1000/e1000_osdep.h b/src/drivers/net/e1000/e1000_osdep.h deleted file mode 100644 index 5cd8e391..00000000 --- a/src/drivers/net/e1000/e1000_osdep.h +++ /dev/null @@ -1,118 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* glue for the OS-dependent part of e1000 - * includes register access macros - */ - -#ifndef _E1000_OSDEP_H_ -#define _E1000_OSDEP_H_ - -#define u8 unsigned char -#define bool boolean_t -#define dma_addr_t unsigned long -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - -#define __iomem - -#define ETH_FCS_LEN 4 - -typedef int spinlock_t; -typedef enum { - false = 0, - true = 1 -} boolean_t; - -#define usec_delay(x) udelay(x) -#define msec_delay(x) mdelay(x) -#define msec_delay_irq(x) mdelay(x) - -#define PCI_COMMAND_REGISTER PCI_COMMAND -#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE -#define ETH_ADDR_LEN ETH_ALEN - -#define DEBUGFUNC(F) DBG(F "\n") - -#define DEBUGOUT(S) DBG(S) -#define DEBUGOUT1(S, A...) DBG(S, A) - -#define DEBUGOUT2 DEBUGOUT1 -#define DEBUGOUT3 DEBUGOUT2 -#define DEBUGOUT7 DEBUGOUT3 - -#define E1000_REGISTER(a, reg) (((a)->mac.type >= e1000_82543) \ - ? reg \ - : e1000_translate_register_82542(reg)) - -#define E1000_WRITE_REG(a, reg, value) \ - writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg))) - -#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_REGISTER(a, reg))) - -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ - writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2))) - -#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ - readl((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2))) - -#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY -#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY - -#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \ - writew((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1)))) - -#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \ - readw((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1))) - -#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \ - writeb((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + (offset)))) - -#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \ - readb((a)->hw_addr + E1000_REGISTER(a, reg) + (offset))) - -#define E1000_WRITE_REG_IO(a, reg, offset) do { \ - outl(reg, ((a)->io_base)); \ - outl(offset, ((a)->io_base + 4)); } while(0) - -#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS) - -#define E1000_WRITE_FLASH_REG(a, reg, value) ( \ - writel((value), ((a)->flash_address + reg))) - -#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \ - writew((value), ((a)->flash_address + reg))) - -#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg)) - -#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg)) - -#endif /* _E1000_OSDEP_H_ */ diff --git a/src/drivers/net/e1000/e1000_phy.c b/src/drivers/net/e1000/e1000_phy.c deleted file mode 100644 index b3cad480..00000000 --- a/src/drivers/net/e1000/e1000_phy.c +++ /dev/null @@ -1,2308 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000_api.h" - -#if 0 -/* Cable length tables */ -static const u16 e1000_m88_cable_length_table[] = - { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; -#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_m88_cable_length_table) / \ - sizeof(e1000_m88_cable_length_table[0])) - -static const u16 e1000_igp_2_cable_length_table[] = - { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, - 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, - 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, - 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, - 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, - 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, - 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, - 104, 109, 114, 118, 121, 124}; -#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_igp_2_cable_length_table) / \ - sizeof(e1000_igp_2_cable_length_table[0])) -#endif - -/** - * e1000_init_phy_ops_generic - Initialize PHY function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void e1000_init_phy_ops_generic(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - DEBUGFUNC("e1000_init_phy_ops_generic"); - - /* Initialize function pointers */ - phy->ops.init_params = e1000_null_ops_generic; - phy->ops.acquire = e1000_null_ops_generic; - phy->ops.check_polarity = e1000_null_ops_generic; - phy->ops.check_reset_block = e1000_null_ops_generic; - phy->ops.commit = e1000_null_ops_generic; -#if 0 - phy->ops.force_speed_duplex = e1000_null_ops_generic; -#endif - phy->ops.get_cfg_done = e1000_null_ops_generic; -#if 0 - phy->ops.get_cable_length = e1000_null_ops_generic; -#endif - phy->ops.get_info = e1000_null_ops_generic; - phy->ops.read_reg = e1000_null_read_reg; - phy->ops.release = e1000_null_phy_generic; - phy->ops.reset = e1000_null_ops_generic; - phy->ops.set_d0_lplu_state = e1000_null_lplu_state; - phy->ops.set_d3_lplu_state = e1000_null_lplu_state; - phy->ops.write_reg = e1000_null_write_reg; - phy->ops.power_up = e1000_null_phy_generic; - phy->ops.power_down = e1000_null_phy_generic; -} - -/** - * e1000_null_read_reg - No-op function, return 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_read_reg(struct e1000_hw *hw __unused, u32 offset __unused, - u16 *data __unused) -{ - DEBUGFUNC("e1000_null_read_reg"); - return E1000_SUCCESS; -} - -/** - * e1000_null_phy_generic - No-op function, return void - * @hw: pointer to the HW structure - **/ -void e1000_null_phy_generic(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("e1000_null_phy_generic"); - return; -} - -/** - * e1000_null_lplu_state - No-op function, return 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_lplu_state(struct e1000_hw *hw __unused, bool active __unused) -{ - DEBUGFUNC("e1000_null_lplu_state"); - return E1000_SUCCESS; -} - -/** - * e1000_null_write_reg - No-op function, return 0 - * @hw: pointer to the HW structure - **/ -s32 e1000_null_write_reg(struct e1000_hw *hw __unused, u32 offset __unused, - u16 data __unused) -{ - DEBUGFUNC("e1000_null_write_reg"); - return E1000_SUCCESS; -} - -/** - * e1000_check_reset_block_generic - Check if PHY reset is blocked - * @hw: pointer to the HW structure - * - * Read the PHY management control register and check whether a PHY reset - * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise - * return E1000_BLK_PHY_RESET (12). - **/ -s32 e1000_check_reset_block_generic(struct e1000_hw *hw) -{ - u32 manc; - - DEBUGFUNC("e1000_check_reset_block"); - - manc = E1000_READ_REG(hw, E1000_MANC); - - return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? - E1000_BLK_PHY_RESET : E1000_SUCCESS; -} - -/** - * e1000_get_phy_id - Retrieve the PHY ID and revision - * @hw: pointer to the HW structure - * - * Reads the PHY registers and stores the PHY ID and possibly the PHY - * revision in the hardware structure. - **/ -s32 e1000_get_phy_id(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_id; - - DEBUGFUNC("e1000_get_phy_id"); - - if (!(phy->ops.read_reg)) - goto out; - - ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); - if (ret_val) - goto out; - - phy->id = (u32)(phy_id << 16); - usec_delay(20); - ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); - if (ret_val) - goto out; - - phy->id |= (u32)(phy_id & PHY_REVISION_MASK); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); - -out: - return ret_val; -} - -/** - * e1000_phy_reset_dsp_generic - Reset PHY DSP - * @hw: pointer to the HW structure - * - * Reset the digital signal processor. - **/ -s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_phy_reset_dsp_generic"); - - if (!(hw->phy.ops.write_reg)) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0); - -out: - return ret_val; -} - -/** - * e1000_read_phy_reg_mdic - Read MDI control register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the MDI control register in the PHY at offset and stores the - * information read to data. - **/ -s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, mdic = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_read_phy_reg_mdic"); - - /* - * Set up Op-code, Phy Address, and register offset in the MDI - * Control register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - mdic = ((offset << E1000_MDIC_REG_SHIFT) | - (phy->addr << E1000_MDIC_PHY_SHIFT) | - (E1000_MDIC_OP_READ)); - - E1000_WRITE_REG(hw, E1000_MDIC, mdic); - - /* - * Poll the ready bit to see if the MDI read completed - * Increasing the time out as testing showed failures with - * the lower time out - */ - for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { - usec_delay(50); - mdic = E1000_READ_REG(hw, E1000_MDIC); - if (mdic & E1000_MDIC_READY) - break; - } - if (!(mdic & E1000_MDIC_READY)) { - DEBUGOUT("MDI Read did not complete\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - if (mdic & E1000_MDIC_ERROR) { - DEBUGOUT("MDI Error\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - *data = (u16) mdic; - -out: - return ret_val; -} - -/** - * e1000_write_phy_reg_mdic - Write MDI control register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write to register at offset - * - * Writes data to MDI control register in the PHY at offset. - **/ -s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, mdic = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_write_phy_reg_mdic"); - - /* - * Set up Op-code, Phy Address, and register offset in the MDI - * Control register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - mdic = (((u32)data) | - (offset << E1000_MDIC_REG_SHIFT) | - (phy->addr << E1000_MDIC_PHY_SHIFT) | - (E1000_MDIC_OP_WRITE)); - - E1000_WRITE_REG(hw, E1000_MDIC, mdic); - - /* - * Poll the ready bit to see if the MDI read completed - * Increasing the time out as testing showed failures with - * the lower time out - */ - for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { - usec_delay(50); - mdic = E1000_READ_REG(hw, E1000_MDIC); - if (mdic & E1000_MDIC_READY) - break; - } - if (!(mdic & E1000_MDIC_READY)) { - DEBUGOUT("MDI Write did not complete\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - if (mdic & E1000_MDIC_ERROR) { - DEBUGOUT("MDI Error\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_read_phy_reg_m88 - Read m88 PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_read_phy_reg_m88"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_write_phy_reg_m88 - Write m88 PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_write_phy_reg_m88"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_read_phy_reg_igp - Read igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_read_phy_reg_igp"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } - } - - ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_write_phy_reg_igp - Write igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_write_phy_reg_igp"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - ret_val = e1000_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) { - hw->phy.ops.release(hw); - goto out; - } - } - - ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_read_kmrn_reg_generic - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore, if necessary. Then reads the PHY register at offset - * using the kumeran interface. The information retrieved is stored in data. - * Release any acquired semaphores before exiting. - **/ -s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_read_kmrn_reg_generic"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; - E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); - - usec_delay(2); - - kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); - *data = (u16)kmrnctrlsta; - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_write_kmrn_reg_generic - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore, if necessary. Then write the data to PHY register - * at the offset using the kumeran interface. Release any acquired semaphores - * before exiting. - **/ -s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("e1000_write_kmrn_reg_generic"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | data; - E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); - - usec_delay(2); - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link - * @hw: pointer to the HW structure - * - * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock - * and downshift values are set also. - **/ -s32 e1000_copper_link_setup_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - - DEBUGFUNC("e1000_copper_link_setup_m88"); - - if (phy->reset_disable) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* Enable CRS on TX. This must be set for half-duplex operation. */ - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - - /* - * Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - - switch (phy->mdix) { - case 1: - phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; - break; - case 2: - phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; - break; - case 3: - phy_data |= M88E1000_PSCR_AUTO_X_1000T; - break; - case 0: - default: - phy_data |= M88E1000_PSCR_AUTO_X_MODE; - break; - } - - /* - * Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if (phy->disable_polarity_correction == 1) - phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - - ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - if (phy->revision < E1000_REVISION_4) { - /* - * Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_EPSCR_TX_CLK_25; - - if ((phy->revision == E1000_REVISION_2) && - (phy->id == M88E1111_I_PHY_ID)) { - /* 82573L PHY - set the downshift counter to 5x. */ - phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; - phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; - } else { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - } - ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - phy_data); - if (ret_val) - goto out; - } - - /* Commit the changes. */ - ret_val = phy->ops.commit(hw); - if (ret_val) { - DEBUGOUT("Error committing the PHY changes\n"); - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_copper_link_setup_igp - Setup igp PHY's for copper link - * @hw: pointer to the HW structure - * - * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for - * igp PHY's. - **/ -s32 e1000_copper_link_setup_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - DEBUGFUNC("e1000_copper_link_setup_igp"); - - if (phy->reset_disable) { - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = hw->phy.ops.reset(hw); - if (ret_val) { - DEBUGOUT("Error resetting the PHY.\n"); - goto out; - } - - /* - * Wait 100ms for MAC to configure PHY from NVM settings, to avoid - * timeout issues when LFS is enabled. - */ - msec_delay(100); - - /* - * The NVM settings will configure LPLU in D3 for - * non-IGP1 PHYs. - */ - if (phy->type == e1000_phy_igp) { - /* disable lplu d3 during driver init */ - ret_val = hw->phy.ops.set_d3_lplu_state(hw, false); - if (ret_val) { - DEBUGOUT("Error Disabling LPLU D3\n"); - goto out; - } - } - - /* disable lplu d0 during driver init */ - if (hw->phy.ops.set_d0_lplu_state) { - ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); - if (ret_val) { - DEBUGOUT("Error Disabling LPLU D0\n"); - goto out; - } - } - /* Configure mdi-mdix settings */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCR_AUTO_MDIX; - - switch (phy->mdix) { - case 1: - data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 2: - data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 0: - default: - data |= IGP01E1000_PSCR_AUTO_MDIX; - break; - } - ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data); - if (ret_val) - goto out; - - /* set auto-master slave resolution settings */ - if (hw->mac.autoneg) { - /* - * when autonegotiation advertisement is only 1000Mbps then we - * should disable SmartSpeed and enable Auto MasterSlave - * resolution as hardware default. - */ - if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { - /* Disable SmartSpeed */ - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - - /* Set auto Master/Slave resolution process */ - ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); - if (ret_val) - goto out; - - data &= ~CR_1000T_MS_ENABLE; - ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); - if (ret_val) - goto out; - } - - ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); - if (ret_val) - goto out; - - /* load defaults for future use */ - phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? - ((data & CR_1000T_MS_VALUE) ? - e1000_ms_force_master : - e1000_ms_force_slave) : - e1000_ms_auto; - - switch (phy->ms_type) { - case e1000_ms_force_master: - data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); - break; - case e1000_ms_force_slave: - data |= CR_1000T_MS_ENABLE; - data &= ~(CR_1000T_MS_VALUE); - break; - case e1000_ms_auto: - data &= ~CR_1000T_MS_ENABLE; - default: - break; - } - ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_copper_link_autoneg - Setup/Enable autoneg for copper link - * @hw: pointer to the HW structure - * - * Performs initial bounds checking on autoneg advertisement parameter, then - * configure to advertise the full capability. Setup the PHY to autoneg - * and restart the negotiation process between the link partner. If - * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. - **/ -s32 e1000_copper_link_autoneg(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_ctrl; - - DEBUGFUNC("e1000_copper_link_autoneg"); - - /* - * Perform some bounds checking on the autoneg advertisement - * parameter. - */ - phy->autoneg_advertised &= phy->autoneg_mask; - - /* - * If autoneg_advertised is zero, we assume it was not defaulted - * by the calling code so we set to advertise full capability. - */ - if (phy->autoneg_advertised == 0) - phy->autoneg_advertised = phy->autoneg_mask; - - DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); - ret_val = e1000_phy_setup_autoneg(hw); - if (ret_val) { - DEBUGOUT("Error Setting up Auto-Negotiation\n"); - goto out; - } - DEBUGOUT("Restarting Auto-Neg\n"); - - /* - * Restart auto-negotiation by setting the Auto Neg Enable bit and - * the Auto Neg Restart bit in the PHY control register. - */ - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); - if (ret_val) - goto out; - - phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); - if (ret_val) - goto out; - - /* - * Does the user want to wait for Auto-Neg to complete here, or - * check at a later time (for example, callback routine). - */ - if (phy->autoneg_wait_to_complete) { - ret_val = hw->mac.ops.wait_autoneg(hw); - if (ret_val) { - DEBUGOUT("Error while waiting for " - "autoneg to complete\n"); - goto out; - } - } - - hw->mac.get_link_status = true; - -out: - return ret_val; -} - -/** - * e1000_phy_setup_autoneg - Configure PHY for auto-negotiation - * @hw: pointer to the HW structure - * - * Reads the MII auto-neg advertisement register and/or the 1000T control - * register and if the PHY is already setup for auto-negotiation, then - * return successful. Otherwise, setup advertisement and flow control to - * the appropriate values for the wanted auto-negotiation. - **/ -s32 e1000_phy_setup_autoneg(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 mii_autoneg_adv_reg; - u16 mii_1000t_ctrl_reg = 0; - - DEBUGFUNC("e1000_phy_setup_autoneg"); - - phy->autoneg_advertised &= phy->autoneg_mask; - - /* Read the MII Auto-Neg Advertisement Register (Address 4). */ - ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); - if (ret_val) - goto out; - - if (phy->autoneg_mask & ADVERTISE_1000_FULL) { - /* Read the MII 1000Base-T Control Register (Address 9). */ - ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, - &mii_1000t_ctrl_reg); - if (ret_val) - goto out; - } - - /* - * Need to parse both autoneg_advertised and fc and set up - * the appropriate PHY registers. First we will parse for - * autoneg_advertised software override. Since we can advertise - * a plethora of combinations, we need to check each bit - * individually. - */ - - /* - * First we clear all the 10/100 mb speed bits in the Auto-Neg - * Advertisement Register (Address 4) and the 1000 mb speed bits in - * the 1000Base-T Control Register (Address 9). - */ - mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | - NWAY_AR_100TX_HD_CAPS | - NWAY_AR_10T_FD_CAPS | - NWAY_AR_10T_HD_CAPS); - mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); - - DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised); - - /* Do we want to advertise 10 Mb Half Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_10_HALF) { - DEBUGOUT("Advertise 10mb Half duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; - } - - /* Do we want to advertise 10 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_10_FULL) { - DEBUGOUT("Advertise 10mb Full duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; - } - - /* Do we want to advertise 100 Mb Half Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_100_HALF) { - DEBUGOUT("Advertise 100mb Half duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; - } - - /* Do we want to advertise 100 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_100_FULL) { - DEBUGOUT("Advertise 100mb Full duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; - } - - /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ - if (phy->autoneg_advertised & ADVERTISE_1000_HALF) - DEBUGOUT("Advertise 1000mb Half duplex request denied!\n"); - - /* Do we want to advertise 1000 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { - DEBUGOUT("Advertise 1000mb Full duplex\n"); - mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; - } - - /* - * Check for a software override of the flow control settings, and - * setup the PHY advertisement registers accordingly. If - * auto-negotiation is enabled, then software will have to set the - * "PAUSE" bits to the correct value in the Auto-Negotiation - * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- - * negotiation. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * but we do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - * other: No software override. The flow control configuration - * in the EEPROM is used. - */ - switch (hw->fc.current_mode) { - case e1000_fc_none: - /* - * Flow control (Rx & Tx) is completely disabled by a - * software over-ride. - */ - mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - case e1000_fc_rx_pause: - /* - * Rx Flow control is enabled, and Tx Flow control is - * disabled, by a software over-ride. - * - * Since there really isn't a way to advertise that we are - * capable of Rx Pause ONLY, we will advertise that we - * support both symmetric and asymmetric Rx PAUSE. Later - * (in e1000_config_fc_after_link_up) we will disable the - * hw's ability to send PAUSE frames. - */ - mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - case e1000_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is - * disabled, by a software over-ride. - */ - mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; - mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; - break; - case e1000_fc_full: - /* - * Flow control (both Rx and Tx) is enabled by a software - * over-ride. - */ - mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - default: - DEBUGOUT("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); - if (ret_val) - goto out; - - DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - - if (phy->autoneg_mask & ADVERTISE_1000_FULL) { - ret_val = phy->ops.write_reg(hw, - PHY_1000T_CTRL, - mii_1000t_ctrl_reg); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_setup_copper_link_generic - Configure copper link settings - * @hw: pointer to the HW structure - * - * Calls the appropriate function to configure the link for auto-neg or forced - * speed and duplex. Then we check for link, once link is established calls - * to configure collision distance and flow control are called. If link is - * not established, we return -E1000_ERR_PHY (-2). - **/ -s32 e1000_setup_copper_link_generic(struct e1000_hw *hw) -{ - s32 ret_val; - bool link; - - DEBUGFUNC("e1000_setup_copper_link_generic"); - - if (hw->mac.autoneg) { - /* - * Setup autoneg and flow control advertisement and perform - * autonegotiation. - */ - ret_val = e1000_copper_link_autoneg(hw); - if (ret_val) - goto out; - } else { -#if 0 - /* - * PHY will be set to 10H, 10F, 100H or 100F - * depending on user settings. - */ - DEBUGOUT("Forcing Speed and Duplex\n"); - ret_val = hw->phy.ops.force_speed_duplex(hw); - if (ret_val) { - DEBUGOUT("Error Forcing Speed and Duplex\n"); - goto out; - } -#endif - } - - /* - * Check link status. Wait up to 100 microseconds for link to become - * valid. - */ - ret_val = e1000_phy_has_link_generic(hw, - COPPER_LINK_UP_LIMIT, - 10, - &link); - if (ret_val) - goto out; - - if (link) { - DEBUGOUT("Valid link established!!!\n"); - e1000_config_collision_dist_generic(hw); - ret_val = e1000_config_fc_after_link_up_generic(hw); - } else { - DEBUGOUT("Unable to establish link!!!\n"); - } - -out: - return ret_val; -} - -#if 0 -/** - * e1000_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY - * @hw: pointer to the HW structure - * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Waits for link and returns - * successful if link up is successful, else -E1000_ERR_PHY (-2). - **/ -s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - DEBUGFUNC("e1000_phy_force_speed_duplex_igp"); - - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - e1000_phy_force_speed_duplex_setup(hw, &phy_data); - - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - /* - * Clear Auto-Crossover to force MDI manually. IGP requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; - phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - - ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); - if (ret_val) - goto out; - - DEBUGOUT1("IGP PSCR: %X\n", phy_data); - - usec_delay(1); - - if (phy->autoneg_wait_to_complete) { - DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n"); - - ret_val = e1000_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) - DEBUGOUT("Link taking longer than expected.\n"); - - /* Try once more */ - ret_val = e1000_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY - * @hw: pointer to the HW structure - * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Resets the PHY to commit the - * changes. If time expires while waiting for link up, we reset the DSP. - * After reset, TX_CLK and CRS on Tx must be set. Return successful upon - * successful completion, else return corresponding error code. - **/ -s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - DEBUGFUNC("e1000_phy_force_speed_duplex_m88"); - - /* - * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data); - - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - e1000_phy_force_speed_duplex_setup(hw, &phy_data); - - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - /* Reset the phy to commit changes. */ - ret_val = hw->phy.ops.commit(hw); - if (ret_val) - goto out; - - if (phy->autoneg_wait_to_complete) { - DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n"); - - ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - - if (!link) { - /* - * We didn't get link. - * Reset the DSP and cross our fingers. - */ - ret_val = phy->ops.write_reg(hw, - M88E1000_PHY_PAGE_SELECT, - 0x001d); - if (ret_val) - goto out; - ret_val = e1000_phy_reset_dsp_generic(hw); - if (ret_val) - goto out; - } - - /* Try once more */ - ret_val = e1000_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - } - - ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - /* - * Resetting the phy means we need to re-force TX_CLK in the - * Extended PHY Specific Control Register to 25MHz clock from - * the reset value of 2.5MHz. - */ - phy_data |= M88E1000_EPSCR_TX_CLK_25; - ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - /* - * In addition, we must re-enable CRS on Tx for both half and full - * duplex. - */ - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - -out: - return ret_val; -} - -/** - * e1000_phy_force_speed_duplex_ife - Force PHY speed & duplex - * @hw: pointer to the HW structure - * - * Forces the speed and duplex settings of the PHY. - * This is a function pointer entry point only called by - * PHY setup routines. - **/ -s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - DEBUGFUNC("e1000_phy_force_speed_duplex_ife"); - - if (phy->type != e1000_phy_ife) { - ret_val = e1000_phy_force_speed_duplex_igp(hw); - goto out; - } - - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); - if (ret_val) - goto out; - - e1000_phy_force_speed_duplex_setup(hw, &data); - - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); - if (ret_val) - goto out; - - /* Disable MDI-X support for 10/100 */ - ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); - if (ret_val) - goto out; - - data &= ~IFE_PMC_AUTO_MDIX; - data &= ~IFE_PMC_FORCE_MDIX; - - ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); - if (ret_val) - goto out; - - DEBUGOUT1("IFE PMC: %X\n", data); - - usec_delay(1); - - if (phy->autoneg_wait_to_complete) { - DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); - - ret_val = e1000_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) - DEBUGOUT("Link taking longer than expected.\n"); - - /* Try once more */ - ret_val = e1000_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex - * @hw: pointer to the HW structure - * @phy_ctrl: pointer to current value of PHY_CONTROL - * - * Forces speed and duplex on the PHY by doing the following: disable flow - * control, force speed/duplex on the MAC, disable auto speed detection, - * disable auto-negotiation, configure duplex, configure speed, configure - * the collision distance, write configuration to CTRL register. The - * caller must write to the PHY_CONTROL register for these settings to - * take affect. - **/ -void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 ctrl; - - DEBUGFUNC("e1000_phy_force_speed_duplex_setup"); - - /* Turn off flow control when forcing speed/duplex */ - hw->fc.current_mode = e1000_fc_none; - - /* Force speed/duplex on the mac */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - ctrl &= ~E1000_CTRL_SPD_SEL; - - /* Disable Auto Speed Detection */ - ctrl &= ~E1000_CTRL_ASDE; - - /* Disable autoneg on the phy */ - *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; - - /* Forcing Full or Half Duplex? */ - if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { - ctrl &= ~E1000_CTRL_FD; - *phy_ctrl &= ~MII_CR_FULL_DUPLEX; - DEBUGOUT("Half Duplex\n"); - } else { - ctrl |= E1000_CTRL_FD; - *phy_ctrl |= MII_CR_FULL_DUPLEX; - DEBUGOUT("Full Duplex\n"); - } - - /* Forcing 10mb or 100mb? */ - if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { - ctrl |= E1000_CTRL_SPD_100; - *phy_ctrl |= MII_CR_SPEED_100; - *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); - DEBUGOUT("Forcing 100mb\n"); - } else { - ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); - *phy_ctrl |= MII_CR_SPEED_10; - *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); - DEBUGOUT("Forcing 10mb\n"); - } - - e1000_config_collision_dist_generic(hw); - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); -} -#endif - -/** - * e1000_set_d3_lplu_state_generic - Sets low power link up state for D3 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D3 - * and SmartSpeed is disabled when active is true, else clear lplu for D3 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. - **/ -s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 data; - - DEBUGFUNC("e1000_set_d3_lplu_state_generic"); - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); - if (ret_val) - goto out; - - if (!active) { - data &= ~IGP02E1000_PM_D3_LPLU; - ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || - (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || - (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { - data |= IGP02E1000_PM_D3_LPLU; - ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - data); - } - -out: - return ret_val; -} - -/** - * e1000_check_downshift_generic - Checks whether a downshift in speed occurred - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns 1 - * - * A downshift is detected by querying the PHY link health. - **/ -s32 e1000_check_downshift_generic(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - DEBUGFUNC("e1000_check_downshift_generic"); - - switch (phy->type) { - case e1000_phy_m88: - case e1000_phy_gg82563: - offset = M88E1000_PHY_SPEC_STATUS; - mask = M88E1000_PSSR_DOWNSHIFT; - break; - case e1000_phy_igp_2: - case e1000_phy_igp: - case e1000_phy_igp_3: - offset = IGP01E1000_PHY_LINK_HEALTH; - mask = IGP01E1000_PLHR_SS_DOWNGRADE; - break; - default: - /* speed downshift not supported */ - phy->speed_downgraded = false; - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = phy->ops.read_reg(hw, offset, &phy_data); - - if (!ret_val) - phy->speed_downgraded = (phy_data & mask) ? true : false; - -out: - return ret_val; -} - -/** - * e1000_check_polarity_m88 - Checks the polarity. - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - * - * Polarity is determined based on the PHY specific status register. - **/ -s32 e1000_check_polarity_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - DEBUGFUNC("e1000_check_polarity_m88"); - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data); - - if (!ret_val) - phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -/** - * e1000_check_polarity_igp - Checks the polarity. - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - * - * Polarity is determined based on the PHY port status register, and the - * current speed (since there is no polarity at 100Mbps). - **/ -s32 e1000_check_polarity_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data, offset, mask; - - DEBUGFUNC("e1000_check_polarity_igp"); - - /* - * Polarity is determined based on the speed of - * our connection. - */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); - if (ret_val) - goto out; - - if ((data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) { - offset = IGP01E1000_PHY_PCS_INIT_REG; - mask = IGP01E1000_PHY_POLARITY_MASK; - } else { - /* - * This really only applies to 10Mbps since - * there is no polarity for 100Mbps (always 0). - */ - offset = IGP01E1000_PHY_PORT_STATUS; - mask = IGP01E1000_PSSR_POLARITY_REVERSED; - } - - ret_val = phy->ops.read_reg(hw, offset, &data); - - if (!ret_val) - phy->cable_polarity = (data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - -out: - return ret_val; -} - -/** - * e1000_check_polarity_ife - Check cable polarity for IFE PHY - * @hw: pointer to the HW structure - * - * Polarity is determined on the polarity reversal feature being enabled. - **/ -s32 e1000_check_polarity_ife(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - DEBUGFUNC("e1000_check_polarity_ife"); - - /* - * Polarity is determined based on the reversal feature being enabled. - */ - if (phy->polarity_correction) { - offset = IFE_PHY_EXTENDED_STATUS_CONTROL; - mask = IFE_PESC_POLARITY_REVERSED; - } else { - offset = IFE_PHY_SPECIAL_CONTROL; - mask = IFE_PSC_FORCE_POLARITY; - } - - ret_val = phy->ops.read_reg(hw, offset, &phy_data); - - if (!ret_val) - phy->cable_polarity = (phy_data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -/** - * e1000_wait_autoneg_generic - Wait for auto-neg completion - * @hw: pointer to the HW structure - * - * Waits for auto-negotiation to complete or for the auto-negotiation time - * limit to expire, which ever happens first. - **/ -s32 e1000_wait_autoneg_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 i, phy_status; - - DEBUGFUNC("e1000_wait_autoneg_generic"); - - if (!(hw->phy.ops.read_reg)) - return E1000_SUCCESS; - - /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ - for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - if (phy_status & MII_SR_AUTONEG_COMPLETE) - break; - msec_delay(100); - } - - /* - * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation - * has completed. - */ - return ret_val; -} - -/** - * e1000_phy_has_link_generic - Polls PHY for link - * @hw: pointer to the HW structure - * @iterations: number of times to poll for link - * @usec_interval: delay between polling attempts - * @success: pointer to whether polling was successful or not - * - * Polls the PHY status register for link, 'iterations' number of times. - **/ -s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, - u32 usec_interval, bool *success) -{ - s32 ret_val = E1000_SUCCESS; - u16 i, phy_status; - - DEBUGFUNC("e1000_phy_has_link_generic"); - - if (!(hw->phy.ops.read_reg)) - return E1000_SUCCESS; - - for (i = 0; i < iterations; i++) { - /* - * Some PHYs require the PHY_STATUS register to be read - * twice due to the link bit being sticky. No harm doing - * it across the board. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) { - /* - * If the first read fails, another entity may have - * ownership of the resources, wait and try again to - * see if they have relinquished the resources yet. - */ - usec_delay(usec_interval); - } - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - if (phy_status & MII_SR_LINK_STATUS) - break; - if (usec_interval >= 1000) - msec_delay_irq(usec_interval/1000); - else - usec_delay(usec_interval); - } - - *success = (i < iterations) ? true : false; - - return ret_val; -} - -#if 0 -/** - * e1000_get_cable_length_m88 - Determine cable length for m88 PHY - * @hw: pointer to the HW structure - * - * Reads the PHY specific status register to retrieve the cable length - * information. The cable length is determined by averaging the minimum and - * maximum values to get the "average" cable length. The m88 PHY has four - * possible cable length values, which are: - * Register Value Cable Length - * 0 < 50 meters - * 1 50 - 80 meters - * 2 80 - 110 meters - * 3 110 - 140 meters - * 4 > 140 meters - **/ -s32 e1000_get_cable_length_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, index; - - DEBUGFUNC("e1000_get_cable_length_m88"); - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if (ret_val) - goto out; - - index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE + 1) { - ret_val = E1000_ERR_PHY; - goto out; - } - - phy->min_cable_length = e1000_m88_cable_length_table[index]; - phy->max_cable_length = e1000_m88_cable_length_table[index+1]; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} - -/** - * e1000_get_cable_length_igp_2 - Determine cable length for igp2 PHY - * @hw: pointer to the HW structure - * - * The automatic gain control (agc) normalizes the amplitude of the - * received signal, adjusting for the attenuation produced by the - * cable. By reading the AGC registers, which represent the - * combination of coarse and fine gain value, the value can be put - * into a lookup table to obtain the approximate cable length - * for each channel. - **/ -s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_data, i, agc_value = 0; - u16 cur_agc_index, max_agc_index = 0; - u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; - u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = - {IGP02E1000_PHY_AGC_A, - IGP02E1000_PHY_AGC_B, - IGP02E1000_PHY_AGC_C, - IGP02E1000_PHY_AGC_D}; - - DEBUGFUNC("e1000_get_cable_length_igp_2"); - - /* Read the AGC registers for all channels */ - for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { - ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data); - if (ret_val) - goto out; - - /* - * Getting bits 15:9, which represent the combination of - * coarse and fine gain values. The result is a number - * that can be put into the lookup table to obtain the - * approximate cable length. - */ - cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & - IGP02E1000_AGC_LENGTH_MASK; - - /* Array index bound check. */ - if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || - (cur_agc_index == 0)) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - /* Remove min & max AGC values from calculation. */ - if (e1000_igp_2_cable_length_table[min_agc_index] > - e1000_igp_2_cable_length_table[cur_agc_index]) - min_agc_index = cur_agc_index; - if (e1000_igp_2_cable_length_table[max_agc_index] < - e1000_igp_2_cable_length_table[cur_agc_index]) - max_agc_index = cur_agc_index; - - agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; - } - - agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + - e1000_igp_2_cable_length_table[max_agc_index]); - agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); - - /* Calculate cable length with the error range of +/- 10 meters. */ - phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? - (agc_value - IGP02E1000_AGC_RANGE) : 0; - phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} -#endif - -/** - * e1000_get_phy_info_m88 - Retrieve PHY information - * @hw: pointer to the HW structure - * - * Valid for only copper links. Read the PHY status register (sticky read) - * to verify that link is up. Read the PHY special control register to - * determine the polarity and 10base-T extended distance. Read the PHY - * special status register to determine MDI/MDIx and current speed. If - * speed is 1000, then determine cable length, local and remote receiver. - **/ -s32 e1000_get_phy_info_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - DEBUGFUNC("e1000_get_phy_info_m88"); - - if (hw->phy.media_type != e1000_media_type_copper) { - DEBUGOUT("Phy info is only valid for copper media\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - DEBUGOUT("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) - ? true : false; - - ret_val = e1000_check_polarity_m88(hw); - if (ret_val) - goto out; - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if (ret_val) - goto out; - - phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false; - - if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { -#if 0 - ret_val = hw->phy.ops.get_cable_length(hw); -#endif - ret_val = -E1000_ERR_CONFIG; - if (ret_val) - goto out; - - ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); - if (ret_val) - goto out; - - phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - - phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - } else { - /* Set values to "undefined" */ - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - } - -out: - return ret_val; -} - -/** - * e1000_get_phy_info_igp - Retrieve igp PHY information - * @hw: pointer to the HW structure - * - * Read PHY status to determine if link is up. If link is up, then - * set/determine 10base-T extended distance and polarity correction. Read - * PHY port status to determine MDI/MDIx and speed. Based on the speed, - * determine on the cable length, local and remote receiver. - **/ -s32 e1000_get_phy_info_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - DEBUGFUNC("e1000_get_phy_info_igp"); - - ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - DEBUGOUT("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - phy->polarity_correction = true; - - ret_val = e1000_check_polarity_igp(hw); - if (ret_val) - goto out; - - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); - if (ret_val) - goto out; - - phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false; - -#if 0 - if ((data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) { - ret_val = hw->phy.ops.get_cable_length(hw); - if (ret_val) - goto out; - - ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data); - if (ret_val) - goto out; - - phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - - phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - } else { -#endif - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; -#if 0 - } -#endif - -out: - return ret_val; -} - -/** - * e1000_phy_sw_reset_generic - PHY software reset - * @hw: pointer to the HW structure - * - * Does a software reset of the PHY by reading the PHY control register and - * setting/write the control register reset bit to the PHY. - **/ -s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 phy_ctrl; - - DEBUGFUNC("e1000_phy_sw_reset_generic"); - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); - if (ret_val) - goto out; - - phy_ctrl |= MII_CR_RESET; - ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl); - if (ret_val) - goto out; - - usec_delay(1); - -out: - return ret_val; -} - -/** - * e1000_phy_hw_reset_generic - PHY hardware reset - * @hw: pointer to the HW structure - * - * Verify the reset block is not blocking us from resetting. Acquire - * semaphore (if necessary) and read/set/write the device control reset - * bit in the PHY. Wait the appropriate delay time for the device to - * reset and release the semaphore (if necessary). - **/ -s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u32 ctrl; - - DEBUGFUNC("e1000_phy_hw_reset_generic"); - - ret_val = phy->ops.check_reset_block(hw); - if (ret_val) { - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = phy->ops.acquire(hw); - if (ret_val) - goto out; - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST); - E1000_WRITE_FLUSH(hw); - - usec_delay(phy->reset_delay_us); - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - E1000_WRITE_FLUSH(hw); - - usec_delay(150); - - phy->ops.release(hw); - - ret_val = phy->ops.get_cfg_done(hw); - -out: - return ret_val; -} - -/** - * e1000_get_cfg_done_generic - Generic configuration done - * @hw: pointer to the HW structure - * - * Generic function to wait 10 milli-seconds for configuration to complete - * and return success. - **/ -s32 e1000_get_cfg_done_generic(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("e1000_get_cfg_done_generic"); - - msec_delay_irq(10); - - return E1000_SUCCESS; -} - -/** - * e1000_phy_init_script_igp3 - Inits the IGP3 PHY - * @hw: pointer to the HW structure - * - * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. - **/ -s32 e1000_phy_init_script_igp3(struct e1000_hw *hw) -{ - DEBUGOUT("Running IGP 3 PHY init script\n"); - - /* PHY init IGP 3 */ - /* Enable rise/fall, 10-mode work in class-A */ - hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018); - /* Remove all caps from Replica path filter */ - hw->phy.ops.write_reg(hw, 0x2F52, 0x0000); - /* Bias trimming for ADC, AFE and Driver (Default) */ - hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24); - /* Increase Hybrid poly bias */ - hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0); - /* Add 4% to Tx amplitude in Gig mode */ - hw->phy.ops.write_reg(hw, 0x2010, 0x10B0); - /* Disable trimming (TTT) */ - hw->phy.ops.write_reg(hw, 0x2011, 0x0000); - /* Poly DC correction to 94.6% + 2% for all channels */ - hw->phy.ops.write_reg(hw, 0x20DD, 0x249A); - /* ABS DC correction to 95.9% */ - hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3); - /* BG temp curve trim */ - hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE); - /* Increasing ADC OPAMP stage 1 currents to max */ - hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4); - /* Force 1000 ( required for enabling PHY regs configuration) */ - hw->phy.ops.write_reg(hw, 0x0000, 0x0140); - /* Set upd_freq to 6 */ - hw->phy.ops.write_reg(hw, 0x1F30, 0x1606); - /* Disable NPDFE */ - hw->phy.ops.write_reg(hw, 0x1F31, 0xB814); - /* Disable adaptive fixed FFE (Default) */ - hw->phy.ops.write_reg(hw, 0x1F35, 0x002A); - /* Enable FFE hysteresis */ - hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067); - /* Fixed FFE for short cable lengths */ - hw->phy.ops.write_reg(hw, 0x1F54, 0x0065); - /* Fixed FFE for medium cable lengths */ - hw->phy.ops.write_reg(hw, 0x1F55, 0x002A); - /* Fixed FFE for long cable lengths */ - hw->phy.ops.write_reg(hw, 0x1F56, 0x002A); - /* Enable Adaptive Clip Threshold */ - hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0); - /* AHT reset limit to 1 */ - hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF); - /* Set AHT master delay to 127 msec */ - hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC); - /* Set scan bits for AHT */ - hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF); - /* Set AHT Preset bits */ - hw->phy.ops.write_reg(hw, 0x1F79, 0x0210); - /* Change integ_factor of channel A to 3 */ - hw->phy.ops.write_reg(hw, 0x1895, 0x0003); - /* Change prop_factor of channels BCD to 8 */ - hw->phy.ops.write_reg(hw, 0x1796, 0x0008); - /* Change cg_icount + enable integbp for channels BCD */ - hw->phy.ops.write_reg(hw, 0x1798, 0xD008); - /* - * Change cg_icount + enable integbp + change prop_factor_master - * to 8 for channel A - */ - hw->phy.ops.write_reg(hw, 0x1898, 0xD918); - /* Disable AHT in Slave mode on channel A */ - hw->phy.ops.write_reg(hw, 0x187A, 0x0800); - /* - * Enable LPLU and disable AN to 1000 in non-D0a states, - * Enable SPD+B2B - */ - hw->phy.ops.write_reg(hw, 0x0019, 0x008D); - /* Enable restart AN on an1000_dis change */ - hw->phy.ops.write_reg(hw, 0x001B, 0x2080); - /* Enable wh_fifo read clock in 10/100 modes */ - hw->phy.ops.write_reg(hw, 0x0014, 0x0045); - /* Restart AN, Speed selection is 1000 */ - hw->phy.ops.write_reg(hw, 0x0000, 0x1340); - - return E1000_SUCCESS; -} - -/** - * e1000_get_phy_type_from_id - Get PHY type from id - * @phy_id: phy_id read from the phy - * - * Returns the phy type from the id. - **/ -enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id) -{ - enum e1000_phy_type phy_type = e1000_phy_unknown; - - switch (phy_id) { - case M88E1000_I_PHY_ID: - case M88E1000_E_PHY_ID: - case M88E1111_I_PHY_ID: - case M88E1011_I_PHY_ID: - phy_type = e1000_phy_m88; - break; - case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ - phy_type = e1000_phy_igp_2; - break; - case GG82563_E_PHY_ID: - phy_type = e1000_phy_gg82563; - break; - case IGP03E1000_E_PHY_ID: - phy_type = e1000_phy_igp_3; - break; - case IFE_E_PHY_ID: - case IFE_PLUS_E_PHY_ID: - case IFE_C_E_PHY_ID: - phy_type = e1000_phy_ife; - break; - default: - phy_type = e1000_phy_unknown; - break; - } - return phy_type; -} - -/** - * e1000_determine_phy_address - Determines PHY address. - * @hw: pointer to the HW structure - * - * This uses a trial and error method to loop through possible PHY - * addresses. It tests each by reading the PHY ID registers and - * checking for a match. - **/ -s32 e1000_determine_phy_address(struct e1000_hw *hw) -{ - s32 ret_val = -E1000_ERR_PHY_TYPE; - u32 phy_addr = 0; - u32 i; - enum e1000_phy_type phy_type = e1000_phy_unknown; - - hw->phy.id = phy_type; - - for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { - hw->phy.addr = phy_addr; - i = 0; - - do { - e1000_get_phy_id(hw); - phy_type = e1000_get_phy_type_from_id(hw->phy.id); - - /* - * If phy_type is valid, break - we found our - * PHY address - */ - if (phy_type != e1000_phy_unknown) { - ret_val = E1000_SUCCESS; - goto out; - } - msec_delay(1); - i++; - } while (i < 10); - } - -out: - return ret_val; -} - -/** - * e1000_power_up_phy_copper - Restore copper link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, restore the link to previous - * settings. - **/ -void e1000_power_up_phy_copper(struct e1000_hw *hw) -{ - u16 mii_reg = 0; - - /* The PHY will retain its settings across a power down/up cycle */ - hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); - mii_reg &= ~MII_CR_POWER_DOWN; - hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); -} - -/** - * e1000_power_down_phy_copper - Restore copper link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, restore the link to previous - * settings. - **/ -void e1000_power_down_phy_copper(struct e1000_hw *hw) -{ - u16 mii_reg = 0; - - /* The PHY will retain its settings across a power down/up cycle */ - hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); - mii_reg |= MII_CR_POWER_DOWN; - hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); - msec_delay(1); -} diff --git a/src/drivers/net/e1000/e1000_phy.h b/src/drivers/net/e1000/e1000_phy.h deleted file mode 100644 index 93bd7a1b..00000000 --- a/src/drivers/net/e1000/e1000_phy.h +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_PHY_H_ -#define _E1000_PHY_H_ - -void e1000_init_phy_ops_generic(struct e1000_hw *hw); -s32 e1000_null_read_reg(struct e1000_hw *hw, u32 offset, u16 *data); -void e1000_null_phy_generic(struct e1000_hw *hw); -s32 e1000_null_lplu_state(struct e1000_hw *hw, bool active); -s32 e1000_null_write_reg(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000_check_downshift_generic(struct e1000_hw *hw); -s32 e1000_check_polarity_m88(struct e1000_hw *hw); -s32 e1000_check_polarity_igp(struct e1000_hw *hw); -s32 e1000_check_polarity_ife(struct e1000_hw *hw); -s32 e1000_check_reset_block_generic(struct e1000_hw *hw); -s32 e1000_copper_link_autoneg(struct e1000_hw *hw); -s32 e1000_copper_link_setup_igp(struct e1000_hw *hw); -s32 e1000_copper_link_setup_m88(struct e1000_hw *hw); -#if 0 -s32 e1000_phy_force_speed_duplex_igp(struct e1000_hw *hw); -s32 e1000_phy_force_speed_duplex_m88(struct e1000_hw *hw); -s32 e1000_phy_force_speed_duplex_ife(struct e1000_hw *hw); -#endif -#if 0 -s32 e1000_get_cable_length_m88(struct e1000_hw *hw); -s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw); -#endif -s32 e1000_get_cfg_done_generic(struct e1000_hw *hw); -s32 e1000_get_phy_id(struct e1000_hw *hw); -s32 e1000_get_phy_info_igp(struct e1000_hw *hw); -s32 e1000_get_phy_info_m88(struct e1000_hw *hw); -s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw); -#if 0 -void e1000_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); -#endif -s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw); -s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw); -s32 e1000_phy_setup_autoneg(struct e1000_hw *hw); -s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active); -s32 e1000_setup_copper_link_generic(struct e1000_hw *hw); -s32 e1000_wait_autoneg_generic(struct e1000_hw *hw); -s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000_phy_reset_dsp(struct e1000_hw *hw); -s32 e1000_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, - u32 usec_interval, bool *success); -s32 e1000_phy_init_script_igp3(struct e1000_hw *hw); -enum e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id); -s32 e1000_determine_phy_address(struct e1000_hw *hw); -void e1000_power_up_phy_copper(struct e1000_hw *hw); -void e1000_power_down_phy_copper(struct e1000_hw *hw); -s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); - -#define E1000_MAX_PHY_ADDR 4 - -/* IGP01E1000 Specific Registers */ -#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ -#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ -#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ -#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ -#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO */ -#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality */ -#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ -#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ -#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */ -#define IGP_PAGE_SHIFT 5 -#define PHY_REG_MASK 0x1F - -#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 -#define IGP01E1000_PHY_POLARITY_MASK 0x0078 - -#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 -#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ - -#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 - -/* Enable flexible speed on link-up */ -#define IGP01E1000_GMII_FLEX_SPD 0x0010 -#define IGP01E1000_GMII_SPD 0x0020 /* Enable SPD */ - -#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ -#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ -#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ - -#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 - -#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0800 -#define IGP01E1000_PSSR_SPEED_MASK 0xC000 -#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 - -#define IGP02E1000_PHY_CHANNEL_NUM 4 -#define IGP02E1000_PHY_AGC_A 0x11B1 -#define IGP02E1000_PHY_AGC_B 0x12B1 -#define IGP02E1000_PHY_AGC_C 0x14B1 -#define IGP02E1000_PHY_AGC_D 0x18B1 - -#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ -#define IGP02E1000_AGC_LENGTH_MASK 0x7F -#define IGP02E1000_AGC_RANGE 15 - -#define IGP03E1000_PHY_MISC_CTRL 0x1B -#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Manually Set Duplex */ - -#define E1000_CABLE_LENGTH_UNDEFINED 0xFF - -#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 -#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 -#define E1000_KMRNCTRLSTA_REN 0x00200000 -#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ -#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */ -#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */ -#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ - -#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 -#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ -#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */ -#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */ - -/* IFE PHY Extended Status Control */ -#define IFE_PESC_POLARITY_REVERSED 0x0100 - -/* IFE PHY Special Control */ -#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 -#define IFE_PSC_FORCE_POLARITY 0x0020 -#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 - -/* IFE PHY Special Control and LED Control */ -#define IFE_PSCL_PROBE_MODE 0x0020 -#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ -#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ - -/* IFE PHY MDIX Control */ -#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ -#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */ -#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */ - -#endif diff --git a/src/drivers/net/e1000/e1000_regs.h b/src/drivers/net/e1000/e1000_regs.h deleted file mode 100644 index 579c0707..00000000 --- a/src/drivers/net/e1000/e1000_regs.h +++ /dev/null @@ -1,329 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000_REGS_H_ -#define _E1000_REGS_H_ - -#define E1000_CTRL 0x00000 /* Device Control - RW */ -#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ -#define E1000_STATUS 0x00008 /* Device Status - RO */ -#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ -#define E1000_EERD 0x00014 /* EEPROM Read - RW */ -#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ -#define E1000_FLA 0x0001C /* Flash Access - RW */ -#define E1000_MDIC 0x00020 /* MDI Control - RW */ -#define E1000_SCTL 0x00024 /* SerDes Control - RW */ -#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ -#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ -#define E1000_FEXT 0x0002C /* Future Extended - RW */ -#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ -#define E1000_FCT 0x00030 /* Flow Control Type - RW */ -#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ -#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ -#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ -#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ -#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ -#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ -#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ -#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ -#define E1000_RCTL 0x00100 /* Rx Control - RW */ -#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ -#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */ -#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */ -#define E1000_TCTL 0x00400 /* Tx Control - RW */ -#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */ -#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */ -#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */ -#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ -#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ -#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ -#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ -#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ -#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ -#define E1000_PBS 0x01008 /* Packet Buffer Size */ -#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ -#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ -#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ -#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ -#define E1000_FLSWCTL 0x01030 /* FLASH control register */ -#define E1000_FLSWDATA 0x01034 /* FLASH data register */ -#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ -#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ -#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */ -#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */ -#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */ -#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */ -#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */ -#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ -#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ -#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ -#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ -#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n))) -#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */ -#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */ -/* Split and Replication Rx Control - RW */ -#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */ -#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */ -#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */ -#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */ -#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */ -#define E1000_RXCTL(_n) (0x0C014 + (0x40 * (_n))) -#define E1000_RQDPC(_n) (0x0C030 + (0x40 * (_n))) -#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */ -#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */ -/* - * Convenience macros - * - * Note: "_n" is the queue number of the register to be written to. - * - * Example usage: - * E1000_RDBAL_REG(current_rx_queue) - */ -#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \ - (0x0C000 + ((_n) * 0x40))) -#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \ - (0x0C004 + ((_n) * 0x40))) -#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \ - (0x0C008 + ((_n) * 0x40))) -#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \ - (0x0C00C + ((_n) * 0x40))) -#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \ - (0x0C010 + ((_n) * 0x40))) -#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \ - (0x0C018 + ((_n) * 0x40))) -#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \ - (0x0C028 + ((_n) * 0x40))) -#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \ - (0x0E000 + ((_n) * 0x40))) -#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \ - (0x0E004 + ((_n) * 0x40))) -#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \ - (0x0E008 + ((_n) * 0x40))) -#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \ - (0x0E010 + ((_n) * 0x40))) -#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \ - (0x0E018 + ((_n) * 0x40))) -#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \ - (0x0E028 + ((_n) * 0x40))) -#define E1000_TARC(_n) (0x03840 + (_n << 8)) -#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8)) -#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8)) -#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \ - (0x0E038 + ((_n) * 0x40))) -#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \ - (0x0E03C + ((_n) * 0x40))) -#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */ -#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ -#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */ -#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ -#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4)) -#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \ - (0x054E0 + ((_i - 16) * 8))) -#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \ - (0x054E4 + ((_i - 16) * 8))) -#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) -#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) -#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) -#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8)) -#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8)) -#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8)) -#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */ -#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ -#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ -#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */ -#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */ -#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */ -#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */ -#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */ -#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */ -#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */ -#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */ -#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */ -#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */ -#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ -#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ -#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ -#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ -#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ -#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ -#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ -#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ -#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ -#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ -#define E1000_COLC 0x04028 /* Collision Count - R/clr */ -#define E1000_DC 0x04030 /* Defer Count - R/clr */ -#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */ -#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ -#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ -#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ -#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */ -#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */ -#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */ -#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */ -#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */ -#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */ -#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */ -#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */ -#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */ -#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */ -#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */ -#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */ -#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */ -#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */ -#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */ -#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */ -#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */ -#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */ -#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */ -#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */ -#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */ -#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */ -#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */ -#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */ -#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */ -#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ -#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */ -#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */ -#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */ -#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */ -#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */ -#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */ -#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */ -#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */ -#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */ -#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */ -#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */ -#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */ -#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */ -#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */ -#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */ -#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ -#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ -#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */ -#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */ -#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */ -#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */ -#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */ -#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */ -#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ - -#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */ -#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */ -#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */ -#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */ -#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ -#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */ -#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */ -#define E1000_RPTHC 0x04104 /* Rx Packets To Host */ -#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */ -#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */ -#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */ -#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */ -#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ -#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ -#define E1000_LENERRS 0x04138 /* Length Errors Count */ -#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ -#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */ -#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */ -#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */ -#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */ -#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */ -#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */ -#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */ -#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */ -#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ -#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ -#define E1000_RA 0x05400 /* Receive Address - RW Array */ -#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ -#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */ -#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */ -#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */ -#define E1000_WUC 0x05800 /* Wakeup Control - RW */ -#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ -#define E1000_WUS 0x05810 /* Wakeup Status - RO */ -#define E1000_MANC 0x05820 /* Management Control - RW */ -#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ -#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ -#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ -#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ -#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ -#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */ -#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ -#define E1000_HOST_IF 0x08800 /* Host Interface */ -#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ -#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ - -#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */ -#define E1000_MDPHYA 0x0003C /* PHY address - RW */ -#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ -#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ -#define E1000_CCMCTL 0x05B48 /* CCM Control Register */ -#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ -#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ -#define E1000_GCR 0x05B00 /* PCI-Ex Control */ -#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */ -#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ -#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ -#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ -#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ -#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ -#define E1000_SWSM 0x05B50 /* SW Semaphore */ -#define E1000_FWSM 0x05B54 /* FW Semaphore */ -#define E1000_SWSM2 0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */ -#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ -#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ -#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ -#define E1000_HICR 0x08F00 /* Host Interface Control */ - -/* RSS registers */ -#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ -#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ -#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */ -#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/ -#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */ -#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register - * (_i) - RW */ -#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr - * low reg - RW */ -#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr - * upper reg - RW */ -#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry - * message reg - RW */ -#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry - * vector ctrl reg - RW */ -#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */ -#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */ -#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */ -#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ -#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ - -#endif diff --git a/src/drivers/net/e1000e/e1000e.c b/src/drivers/net/e1000e/e1000e.c deleted file mode 100644 index b7318b7d..00000000 --- a/src/drivers/net/e1000e/e1000e.c +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -REQUIRE_OBJECT(e1000e_main); -REQUIRE_OBJECT(e1000e_80003es2lan); -REQUIRE_OBJECT(e1000e_82571); -REQUIRE_OBJECT(e1000e_ich8lan); diff --git a/src/drivers/net/e1000e/e1000e.h b/src/drivers/net/e1000e/e1000e.h deleted file mode 100644 index 0e537932..00000000 --- a/src/drivers/net/e1000e/e1000e.h +++ /dev/null @@ -1,534 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* Linux PRO/1000 Ethernet Driver main header file */ - -#ifndef _E1000E_H_ -#define _E1000E_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Begin OS Dependencies */ - -#define u8 unsigned char -#define bool boolean_t -#define dma_addr_t unsigned long -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - -#define __iomem - -#define msleep(x) mdelay(x) - -#define ETH_FCS_LEN 4 - -typedef int spinlock_t; -typedef enum { - false = 0, - true = 1 -} boolean_t; - -/* End OS Dependencies */ - -#include "e1000e_hw.h" - -#define E1000_TX_FLAGS_CSUM 0x00000001 -#define E1000_TX_FLAGS_VLAN 0x00000002 -#define E1000_TX_FLAGS_TSO 0x00000004 -#define E1000_TX_FLAGS_IPV4 0x00000008 -#define E1000_TX_FLAGS_VLAN_MASK 0xffff0000 -#define E1000_TX_FLAGS_VLAN_SHIFT 16 - -#define E1000_MAX_PER_TXD 8192 -#define E1000_MAX_TXD_PWR 12 - -#define MINIMUM_DHCP_PACKET_SIZE 282 - -struct e1000_info; - -#define e_dbg(arg...) if (0) { printf (arg); }; - -#ifdef CONFIG_E1000E_MSIX -/* Interrupt modes, as used by the IntMode paramter */ -#define E1000E_INT_MODE_LEGACY 0 -#define E1000E_INT_MODE_MSI 1 -#define E1000E_INT_MODE_MSIX 2 - -#endif /* CONFIG_E1000E_MSIX */ -#ifndef CONFIG_E1000E_NAPI -#define E1000_MAX_INTR 10 - -#endif /* CONFIG_E1000E_NAPI */ -/* Tx/Rx descriptor defines */ -#define E1000_DEFAULT_TXD 256 -#define E1000_MAX_TXD 4096 -#define E1000_MIN_TXD 64 - -#define E1000_DEFAULT_RXD 256 -#define E1000_MAX_RXD 4096 -#define E1000_MIN_RXD 64 - -#define E1000_MIN_ITR_USECS 10 /* 100000 irq/sec */ -#define E1000_MAX_ITR_USECS 10000 /* 100 irq/sec */ - -/* Early Receive defines */ -#define E1000_ERT_2048 0x100 - -#define E1000_FC_PAUSE_TIME 0x0680 /* 858 usec */ - -/* How many Tx Descriptors do we need to call netif_wake_queue ? */ -/* How many Rx Buffers do we bundle into one write to the hardware ? */ -#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */ - -#define AUTO_ALL_MODES 0 -#define E1000_EEPROM_APME 0x0400 - -#define E1000_MNG_VLAN_NONE (-1) - -/* Number of packet split data buffers (not including the header buffer) */ -#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) - -#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 - -#define DEFAULT_JUMBO 9234 - -enum e1000_boards { - board_82571, - board_82572, - board_82573, - board_82574, - board_80003es2lan, - board_ich8lan, - board_ich9lan, - board_ich10lan, - board_pchlan, - board_pch2lan, - board_82583, -}; - -/* board specific private data structure */ -struct e1000_adapter { - const struct e1000_info *ei; - - /* OS defined structs */ - struct net_device *netdev; - struct pci_device *pdev; - struct net_device_stats net_stats; - - /* structs defined in e1000_hw.h */ - struct e1000_hw hw; - - struct e1000_phy_info phy_info; - - u32 wol; - u32 pba; - u32 max_hw_frame_size; - - bool fc_autoneg; - - unsigned int flags; - unsigned int flags2; - -#define NUM_TX_DESC 8 -#define NUM_RX_DESC 8 - - struct io_buffer *tx_iobuf[NUM_TX_DESC]; - struct io_buffer *rx_iobuf[NUM_RX_DESC]; - - struct e1000_tx_desc *tx_base; - struct e1000_rx_desc *rx_base; - - uint32_t tx_ring_size; - uint32_t rx_ring_size; - - uint32_t tx_head; - uint32_t tx_tail; - uint32_t tx_fill_ctr; - - uint32_t rx_curr; - - uint32_t ioaddr; - uint32_t irqno; - - uint32_t tx_int_delay; - uint32_t tx_abs_int_delay; - uint32_t txd_cmd; -}; - -struct e1000_info { - enum e1000_mac_type mac; - unsigned int flags; - unsigned int flags2; - u32 pba; - u32 max_hw_frame_size; - s32 (*get_variants)(struct e1000_adapter *); - void (*init_ops)(struct e1000_hw *); -}; - -/* hardware capability, feature, and workaround flags */ -#define FLAG_HAS_AMT (1 << 0) -#define FLAG_HAS_FLASH (1 << 1) -#define FLAG_HAS_HW_VLAN_FILTER (1 << 2) -#define FLAG_HAS_WOL (1 << 3) -#define FLAG_HAS_ERT (1 << 4) -#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5) -#define FLAG_HAS_SWSM_ON_LOAD (1 << 6) -#define FLAG_HAS_JUMBO_FRAMES (1 << 7) -#define FLAG_IS_ICH (1 << 9) -#ifdef CONFIG_E1000E_MSIX -#define FLAG_HAS_MSIX (1 << 10) -#endif -#define FLAG_HAS_SMART_POWER_DOWN (1 << 11) -#define FLAG_IS_QUAD_PORT_A (1 << 12) -#define FLAG_IS_QUAD_PORT (1 << 13) -#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN (1 << 14) -#define FLAG_APME_IN_WUC (1 << 15) -#define FLAG_APME_IN_CTRL3 (1 << 16) -#define FLAG_APME_CHECK_PORT_B (1 << 17) -#define FLAG_DISABLE_FC_PAUSE_TIME (1 << 18) -#define FLAG_NO_WAKE_UCAST (1 << 19) -#define FLAG_MNG_PT_ENABLED (1 << 20) -#define FLAG_RESET_OVERWRITES_LAA (1 << 21) -#define FLAG_TARC_SPEED_MODE_BIT (1 << 22) -#define FLAG_TARC_SET_BIT_ZERO (1 << 23) -#define FLAG_RX_NEEDS_RESTART (1 << 24) -#define FLAG_LSC_GIG_SPEED_DROP (1 << 25) -#define FLAG_SMART_POWER_DOWN (1 << 26) -#define FLAG_MSI_ENABLED (1 << 27) -#define FLAG_RX_CSUM_ENABLED (1 << 28) -#define FLAG_TSO_FORCE (1 << 29) -#define FLAG_RX_RESTART_NOW (1 << 30) -#define FLAG_MSI_TEST_FAILED (1 << 31) - -/* CRC Stripping defines */ -#define FLAG2_CRC_STRIPPING (1 << 0) -#define FLAG2_HAS_PHY_WAKEUP (1 << 1) - -#define E1000_RX_DESC_PS(R, i) \ - (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) -#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) -#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) -#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) -#define E1000_CONTEXT_DESC(R, i) E1000_GET_DESC(R, i, e1000_context_desc) - -enum e1000_state_t { - __E1000E_TESTING, - __E1000E_RESETTING, - __E1000E_DOWN -}; - -enum latency_range { - lowest_latency = 0, - low_latency = 1, - bulk_latency = 2, - latency_invalid = 255 -}; - -extern void e1000e_check_options(struct e1000_adapter *adapter); - -extern void e1000e_reset(struct e1000_adapter *adapter); -extern void e1000e_power_up_phy(struct e1000_adapter *adapter); - -extern void e1000e_init_function_pointers_82571(struct e1000_hw *hw) - __attribute__((weak)); -extern void e1000e_init_function_pointers_80003es2lan(struct e1000_hw *hw) - __attribute__((weak)); -extern void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw) - __attribute__((weak)); - -extern int e1000e_probe(struct pci_device *pdev); - -extern void e1000e_remove(struct pci_device *pdev); - -extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num); - -static inline s32 e1000e_commit_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.commit) - return hw->phy.ops.commit(hw); - - return 0; -} - -extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw); - -extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw); -extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); - -extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, - bool state); -extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); -extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); -extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); -extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); - -extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw); -extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); -extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); -extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); -extern s32 e1000e_led_on_generic(struct e1000_hw *hw); -extern s32 e1000e_led_off_generic(struct e1000_hw *hw); -extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw); -extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex); -extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex); -extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw); -extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw); -extern s32 e1000e_id_led_init(struct e1000_hw *hw); -extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw); -extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw); -extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw); -extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw); -extern s32 e1000e_setup_link(struct e1000_hw *hw); -static inline void e1000e_clear_vfta(struct e1000_hw *hw) -{ - hw->mac.ops.clear_vfta(hw); -} -extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); -extern void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, - u32 mc_addr_count); -extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); -extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw); -extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop); -extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw); -extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data); -extern void e1000e_config_collision_dist(struct e1000_hw *hw); -extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); -extern s32 e1000e_force_mac_fc(struct e1000_hw *hw); -extern s32 e1000e_blink_led(struct e1000_hw *hw); -extern void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); -static inline void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) -{ - if (hw->mac.ops.write_vfta) - hw->mac.ops.write_vfta(hw, offset, value); -} -extern void e1000e_reset_adaptive(struct e1000_hw *hw); -extern void e1000e_update_adaptive(struct e1000_hw *hw); - -extern s32 e1000e_setup_copper_link(struct e1000_hw *hw); -extern void e1000e_put_hw_semaphore(struct e1000_hw *hw); -extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw); -#if 0 -extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw); -#endif -#if 0 -extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw); -#endif -extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw); -extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); -extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw); -extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active); -extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); -extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw); -#if 0 -extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw); -#endif -extern s32 e1000e_get_cfg_done(struct e1000_hw *hw); -#if 0 -extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw); -#endif -extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw); -extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); -extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); -extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id); -extern s32 e1000e_determine_phy_address(struct e1000_hw *hw); -extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data); -extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data); -#if 0 -extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); -#endif -extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); -extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); -extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, - u32 usec_interval, bool *success); -extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); -extern s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); -extern s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); -extern s32 e1000e_check_downshift(struct e1000_hw *hw); - -static inline s32 e1000e_phy_hw_reset(struct e1000_hw *hw) -{ - if (hw->phy.ops.reset) - return hw->phy.ops.reset(hw); - - return 0; -} - -static inline s32 e1000e_check_reset_block(struct e1000_hw *hw) -{ - if (hw->phy.ops.check_reset_block) - return hw->phy.ops.check_reset_block(hw); - - return 0; -} - -static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data) -{ - if (hw->phy.ops.read_reg) - return hw->phy.ops.read_reg(hw, offset, data); - - return 0; -} - -static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data) -{ - if (hw->phy.ops.write_reg) - return hw->phy.ops.write_reg(hw, offset, data); - - return 0; -} - -#if 0 -static inline s32 e1000e_get_cable_length(struct e1000_hw *hw) -{ - if (hw->phy.ops.get_cable_length) - return hw->phy.ops.get_cable_length(hw); - - return 0; -} -#endif - -extern s32 e1000e_acquire_nvm(struct e1000_hw *hw); -extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); -extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw); -extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); -extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); -extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw); -extern void e1000e_release_nvm(struct e1000_hw *hw); - -static inline s32 e1000e_read_mac_addr(struct e1000_hw *hw) -{ - if (hw->mac.ops.read_mac_addr) - return hw->mac.ops.read_mac_addr(hw); - - return e1000e_read_mac_addr_generic(hw); -} - -static inline s32 e1000e_validate_nvm_checksum(struct e1000_hw *hw) -{ - return hw->nvm.ops.validate(hw); -} - -static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw) -{ - return hw->nvm.ops.update(hw); -} - -static inline s32 e1000e_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - return hw->nvm.ops.read(hw, offset, words, data); -} - -static inline s32 e1000e_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - return hw->nvm.ops.write(hw, offset, words, data); -} - -static inline s32 e1000e_get_phy_info(struct e1000_hw *hw) -{ - if (hw->phy.ops.get_info) - return hw->phy.ops.get_info(hw); - - return 0; -} - -extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw); -#if 0 -extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length); -#endif - -static inline u32 __er32(struct e1000_hw *hw, unsigned long reg) -{ - return readl(hw->hw_addr + reg); -} - -static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val) -{ - writel(val, hw->hw_addr + reg); -} - -#define er32(reg) __er32(hw, E1000_##reg) -#define ew32(reg, val) __ew32(hw, E1000_##reg, (val)) -#define e1e_flush() er32(STATUS) - -#define E1000_WRITE_REG(a, reg, value) \ - writel((value), ((a)->hw_addr + reg)) - -#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + reg)) - -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \ - writel((value), ((a)->hw_addr + reg + ((offset) << 2))) - -#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ - readl((a)->hw_addr + reg + ((offset) << 2))) - -#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY -#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY - -static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) -{ - return readw(hw->flash_address + reg); -} - -static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg) -{ - return readl(hw->flash_address + reg); -} - -static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val) -{ - writew(val, hw->flash_address + reg); -} - -static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) -{ - writel(val, hw->flash_address + reg); -} - -#define er16flash(reg) __er16flash(hw, (reg)) -#define er32flash(reg) __er32flash(hw, (reg)) -#define ew16flash(reg, val) __ew16flash(hw, (reg), (val)) -#define ew32flash(reg, val) __ew32flash(hw, (reg), (val)) - -#endif /* _E1000E_H_ */ diff --git a/src/drivers/net/e1000e/e1000e_80003es2lan.c b/src/drivers/net/e1000e/e1000e_80003es2lan.c deleted file mode 100644 index a3eed9b7..00000000 --- a/src/drivers/net/e1000e/e1000e_80003es2lan.c +++ /dev/null @@ -1,1533 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * 80003ES2LAN Gigabit Ethernet Controller (Copper) - * 80003ES2LAN Gigabit Ethernet Controller (Serdes) - */ - -#include "e1000e.h" - -static s32 e1000e_init_phy_params_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_init_nvm_params_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_init_mac_params_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_acquire_phy_80003es2lan(struct e1000_hw *hw); -static void e1000e_release_phy_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_acquire_nvm_80003es2lan(struct e1000_hw *hw); -static void e1000e_release_nvm_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, - u32 offset, - u16 *data); -static s32 e1000e_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, - u32 offset, - u16 data); -static s32 e1000e_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -static s32 e1000e_get_cfg_done_80003es2lan(struct e1000_hw *hw); -#if 0 -static s32 e1000e_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw); -#endif -#if 0 -static s32 e1000e_get_cable_length_80003es2lan(struct e1000_hw *hw); -#endif -static s32 e1000e_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -static s32 e1000e_reset_hw_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_init_hw_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_setup_copper_link_80003es2lan(struct e1000_hw *hw); -static void e1000e_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); -static s32 e1000e_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); -static s32 e1000e_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_cfg_on_link_up_80003es2lan(struct e1000_hw *hw); -static s32 e1000e_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, - u16 *data); -static s32 e1000e_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, - u16 data); -static s32 e1000e_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw); -static void e1000e_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); -static void e1000e_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask); -static s32 e1000e_read_mac_addr_80003es2lan(struct e1000_hw *hw); -static void e1000e_power_down_phy_copper_80003es2lan(struct e1000_hw *hw); - -#if 0 -/* - * A table for the GG82563 cable length where the range is defined - * with a lower bound at "index" and the upper bound at - * "index + 5". - */ -static const u16 e1000_gg82563_cable_length_table[] = - { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF }; -#define GG82563_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_gg82563_cable_length_table) / \ - sizeof(e1000_gg82563_cable_length_table[0])) -#endif - -/** - * e1000e_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000e_init_phy_params_80003es2lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - if (hw->phy.media_type != e1000_media_type_copper) { - phy->type = e1000_phy_none; - goto out; - } else { - phy->ops.power_up = e1000e_power_up_phy_copper; - phy->ops.power_down = e1000e_power_down_phy_copper_80003es2lan; - } - - phy->addr = 1; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->reset_delay_us = 100; - phy->type = e1000_phy_gg82563; - - phy->ops.acquire = e1000e_acquire_phy_80003es2lan; - phy->ops.check_polarity = e1000e_check_polarity_m88; - phy->ops.check_reset_block = e1000e_check_reset_block_generic; - phy->ops.commit = e1000e_phy_sw_reset; - phy->ops.get_cfg_done = e1000e_get_cfg_done_80003es2lan; - phy->ops.get_info = e1000e_get_phy_info_m88; - phy->ops.release = e1000e_release_phy_80003es2lan; - phy->ops.reset = e1000e_phy_hw_reset_generic; - phy->ops.set_d3_lplu_state = e1000e_set_d3_lplu_state; -#if 0 - phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_80003es2lan; -#endif -#if 0 - phy->ops.get_cable_length = e1000e_get_cable_length_80003es2lan; -#endif - phy->ops.read_reg = e1000e_read_phy_reg_gg82563_80003es2lan; - phy->ops.write_reg = e1000e_write_phy_reg_gg82563_80003es2lan; - - phy->ops.cfg_on_link_up = e1000e_cfg_on_link_up_80003es2lan; - - /* This can only be done after all function pointers are setup. */ - ret_val = e1000e_get_phy_id(hw); - - /* Verify phy id */ - if (phy->id != GG82563_E_PHY_ID) { - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000e_init_nvm_params_80003es2lan(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = er32(EECD); - u16 size; - - nvm->opcode_bits = 8; - nvm->delay_usec = 1; - switch (nvm->override) { - case e1000_nvm_override_spi_large: - nvm->page_size = 32; - nvm->address_bits = 16; - break; - case e1000_nvm_override_spi_small: - nvm->page_size = 8; - nvm->address_bits = 8; - break; - default: - nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; - nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; - break; - } - - nvm->type = e1000_nvm_eeprom_spi; - - size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> - E1000_EECD_SIZE_EX_SHIFT); - - /* - * Added to a constant, "size" becomes the left-shift value - * for setting word_size. - */ - size += NVM_WORD_SIZE_BASE_SHIFT; - - /* EEPROM access above 16k is unsupported */ - if (size > 14) - size = 14; - nvm->word_size = 1 << size; - - /* Function Pointers */ - nvm->ops.acquire = e1000e_acquire_nvm_80003es2lan; - nvm->ops.read = e1000e_read_nvm_eerd; - nvm->ops.release = e1000e_release_nvm_80003es2lan; - nvm->ops.update = e1000e_update_nvm_checksum_generic; - nvm->ops.valid_led_default = e1000e_valid_led_default; - nvm->ops.validate = e1000e_validate_nvm_checksum_generic; - nvm->ops.write = e1000e_write_nvm_80003es2lan; - - return E1000_SUCCESS; -} - -/** - * e1000e_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000e_init_mac_params_80003es2lan(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - - /* Set media type */ - switch (hw->device_id) { - case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: - hw->phy.media_type = e1000_media_type_internal_serdes; - break; - default: - hw->phy.media_type = e1000_media_type_copper; - break; - } - - /* Set mta register count */ - mac->mta_reg_count = 128; - /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES; - /* Set if part includes ASF firmware */ - mac->asf_firmware_present = true; - /* Set if manageability features are enabled. */ - mac->arc_subsystem_valid = - (er32(FWSM) & E1000_FWSM_MODE_MASK) - ? true : false; - - /* Function pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = e1000e_get_bus_info_pcie; - /* reset */ - mac->ops.reset_hw = e1000e_reset_hw_80003es2lan; - /* hw initialization */ - mac->ops.init_hw = e1000e_init_hw_80003es2lan; - /* link setup */ - mac->ops.setup_link = e1000e_setup_link; - /* physical interface link setup */ - mac->ops.setup_physical_interface = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000e_setup_copper_link_80003es2lan - : e1000e_setup_fiber_serdes_link; - /* check for link */ - switch (hw->phy.media_type) { - case e1000_media_type_copper: - mac->ops.check_for_link = e1000e_check_for_copper_link; - break; - case e1000_media_type_fiber: - mac->ops.check_for_link = e1000e_check_for_fiber_link; - break; - case e1000_media_type_internal_serdes: - mac->ops.check_for_link = e1000e_check_for_serdes_link; - break; - default: - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } - /* check management mode */ -#if 0 - mac->ops.check_mng_mode = e1000e_check_mng_mode_generic; -#endif - /* multicast address update */ - mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = e1000e_write_vfta_generic; - /* clearing VFTA */ - mac->ops.clear_vfta = e1000e_clear_vfta_generic; - /* setting MTA */ - mac->ops.mta_set = e1000e_mta_set_generic; - /* read mac address */ - mac->ops.read_mac_addr = e1000e_read_mac_addr_80003es2lan; - /* ID LED init */ - mac->ops.id_led_init = e1000e_id_led_init; - /* blink LED */ - mac->ops.blink_led = e1000e_blink_led; - /* setup LED */ - mac->ops.setup_led = e1000e_setup_led_generic; - /* cleanup LED */ - mac->ops.cleanup_led = e1000e_cleanup_led_generic; - /* turn on/off LED */ - mac->ops.led_on = e1000e_led_on_generic; - mac->ops.led_off = e1000e_led_off_generic; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_80003es2lan; - /* link info */ - mac->ops.get_link_up_info = e1000e_get_link_up_info_80003es2lan; - - /* set lan id for port to determine which phy lock to use */ - hw->mac.ops.set_lan_id(hw); - -out: - return ret_val; -} - -/** - * e1000e_init_function_pointers_80003es2lan - Init ESB2 func ptrs. - * @hw: pointer to the HW structure - * - * Called to initialize all function pointers and parameters. - **/ -void e1000e_init_function_pointers_80003es2lan(struct e1000_hw *hw) -{ - e1000e_init_mac_ops_generic(hw); - e1000e_init_nvm_ops_generic(hw); - hw->mac.ops.init_params = e1000e_init_mac_params_80003es2lan; - hw->nvm.ops.init_params = e1000e_init_nvm_params_80003es2lan; - hw->phy.ops.init_params = e1000e_init_phy_params_80003es2lan; -} - -/** - * e1000e_acquire_phy_80003es2lan - Acquire rights to access PHY - * @hw: pointer to the HW structure - * - * A wrapper to acquire access rights to the correct PHY. - **/ -static s32 e1000e_acquire_phy_80003es2lan(struct e1000_hw *hw) -{ - u16 mask; - - mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - return e1000e_acquire_swfw_sync_80003es2lan(hw, mask); -} - -/** - * e1000e_release_phy_80003es2lan - Release rights to access PHY - * @hw: pointer to the HW structure - * - * A wrapper to release access rights to the correct PHY. - **/ -static void e1000e_release_phy_80003es2lan(struct e1000_hw *hw) -{ - u16 mask; - - mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - e1000e_release_swfw_sync_80003es2lan(hw, mask); -} - -/** - * e1000e_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register - * @hw: pointer to the HW structure - * - * Acquire the semaphore to access the Kumeran interface. - * - **/ -static s32 e1000e_acquire_mac_csr_80003es2lan(struct e1000_hw *hw) -{ - u16 mask; - - mask = E1000_SWFW_CSR_SM; - - return e1000e_acquire_swfw_sync_80003es2lan(hw, mask); -} - -/** - * e1000e_release_mac_csr_80003es2lan - Release rights to access Kumeran Register - * @hw: pointer to the HW structure - * - * Release the semaphore used to access the Kumeran interface - **/ -static void e1000e_release_mac_csr_80003es2lan(struct e1000_hw *hw) -{ - u16 mask; - - mask = E1000_SWFW_CSR_SM; - - e1000e_release_swfw_sync_80003es2lan(hw, mask); -} - -/** - * e1000e_acquire_nvm_80003es2lan - Acquire rights to access NVM - * @hw: pointer to the HW structure - * - * Acquire the semaphore to access the EEPROM. - **/ -static s32 e1000e_acquire_nvm_80003es2lan(struct e1000_hw *hw) -{ - s32 ret_val; - - ret_val = e1000e_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); - if (ret_val) - goto out; - - ret_val = e1000e_acquire_nvm(hw); - - if (ret_val) - e1000e_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); - -out: - return ret_val; -} - -/** - * e1000e_release_nvm_80003es2lan - Relinquish rights to access NVM - * @hw: pointer to the HW structure - * - * Release the semaphore used to access the EEPROM. - **/ -static void e1000e_release_nvm_80003es2lan(struct e1000_hw *hw) -{ - e1000e_release_nvm(hw); - e1000e_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM); -} - -/** - * e1000e_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Acquire the SW/FW semaphore to access the PHY or NVM. The mask - * will also specify which port we're acquiring the lock for. - **/ -static s32 e1000e_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - u32 swmask = mask; - u32 fwmask = mask << 16; - s32 ret_val = E1000_SUCCESS; - s32 i = 0, timeout = 50; - - while (i < timeout) { - if (e1000e_get_hw_semaphore(hw)) { - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync = er32(SW_FW_SYNC); - if (!(swfw_sync & (fwmask | swmask))) - break; - - /* - * Firmware currently using resource (fwmask) - * or other software thread using resource (swmask) - */ - e1000e_put_hw_semaphore(hw); - mdelay(5); - i++; - } - - if (i == timeout) { - e_dbg("Driver can't access resource, SW_FW_SYNC timeout.\n"); - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync |= swmask; - ew32(SW_FW_SYNC, swfw_sync); - - e1000e_put_hw_semaphore(hw); - -out: - return ret_val; -} - -/** - * e1000e_release_swfw_sync_80003es2lan - Release SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Release the SW/FW semaphore used to access the PHY or NVM. The mask - * will also specify which port we're releasing the lock for. - **/ -static void e1000e_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - - while (e1000e_get_hw_semaphore(hw) != E1000_SUCCESS) - ; /* Empty */ - - swfw_sync = er32(SW_FW_SYNC); - swfw_sync &= ~mask; - ew32(SW_FW_SYNC, swfw_sync); - - e1000e_put_hw_semaphore(hw); -} - -/** - * e1000e_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register - * @hw: pointer to the HW structure - * @offset: offset of the register to read - * @data: pointer to the data returned from the operation - * - * Read the GG82563 PHY register. - **/ -static s32 e1000e_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, - u32 offset, u16 *data) -{ - s32 ret_val; - u32 page_select; - u16 temp; - - ret_val = e1000e_acquire_phy_80003es2lan(hw); - if (ret_val) - goto out; - - /* Select Configuration Page */ - if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { - page_select = GG82563_PHY_PAGE_SELECT; - } else { - /* - * Use Alternative Page Select register to access - * registers 30 and 31 - */ - page_select = GG82563_PHY_PAGE_SELECT_ALT; - } - - temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); - ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp); - if (ret_val) { - e1000e_release_phy_80003es2lan(hw); - goto out; - } - - if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) { - /* - * The "ready" bit in the MDIC register may be incorrectly set - * before the device has completed the "Page Select" MDI - * transaction. So we wait 200us after each MDI command... - */ - udelay(200); - - /* ...and verify the command was successful. */ - ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); - - if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { - ret_val = -E1000_ERR_PHY; - e1000e_release_phy_80003es2lan(hw); - goto out; - } - - udelay(200); - - ret_val = e1000e_read_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, - data); - - udelay(200); - } else - ret_val = e1000e_read_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, - data); - - e1000e_release_phy_80003es2lan(hw); - -out: - return ret_val; -} - -/** - * e1000e_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register - * @hw: pointer to the HW structure - * @offset: offset of the register to read - * @data: value to write to the register - * - * Write to the GG82563 PHY register. - **/ -static s32 e1000e_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw, - u32 offset, u16 data) -{ - s32 ret_val; - u32 page_select; - u16 temp; - - ret_val = e1000e_acquire_phy_80003es2lan(hw); - if (ret_val) - goto out; - - /* Select Configuration Page */ - if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { - page_select = GG82563_PHY_PAGE_SELECT; - } else { - /* - * Use Alternative Page Select register to access - * registers 30 and 31 - */ - page_select = GG82563_PHY_PAGE_SELECT_ALT; - } - - temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT); - ret_val = e1000e_write_phy_reg_mdic(hw, page_select, temp); - if (ret_val) { - e1000e_release_phy_80003es2lan(hw); - goto out; - } - - if (hw->dev_spec._80003es2lan.mdic_wa_enable == true) { - /* - * The "ready" bit in the MDIC register may be incorrectly set - * before the device has completed the "Page Select" MDI - * transaction. So we wait 200us after each MDI command... - */ - udelay(200); - - /* ...and verify the command was successful. */ - ret_val = e1000e_read_phy_reg_mdic(hw, page_select, &temp); - - if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) { - ret_val = -E1000_ERR_PHY; - e1000e_release_phy_80003es2lan(hw); - goto out; - } - - udelay(200); - - ret_val = e1000e_write_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, - data); - - udelay(200); - } else - ret_val = e1000e_write_phy_reg_mdic(hw, - MAX_PHY_REG_ADDRESS & offset, - data); - - e1000e_release_phy_80003es2lan(hw); - -out: - return ret_val; -} - -/** - * e1000e_write_nvm_80003es2lan - Write to ESB2 NVM - * @hw: pointer to the HW structure - * @offset: offset of the register to read - * @words: number of words to write - * @data: buffer of data to write to the NVM - * - * Write "words" of data to the ESB2 NVM. - **/ -static s32 e1000e_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data) -{ - return e1000e_write_nvm_spi(hw, offset, words, data); -} - -/** - * e1000e_get_cfg_done_80003es2lan - Wait for configuration to complete - * @hw: pointer to the HW structure - * - * Wait a specific amount of time for manageability processes to complete. - * This is a function pointer entry point called by the phy module. - **/ -static s32 e1000e_get_cfg_done_80003es2lan(struct e1000_hw *hw) -{ - s32 timeout = PHY_CFG_TIMEOUT; - s32 ret_val = E1000_SUCCESS; - u32 mask = E1000_NVM_CFG_DONE_PORT_0; - - if (hw->bus.func == 1) - mask = E1000_NVM_CFG_DONE_PORT_1; - - while (timeout) { - if (er32(EEMNGCTL) & mask) - break; - msleep(1); - timeout--; - } - if (!timeout) { - e_dbg("MNG configuration cycle has not completed.\n"); - ret_val = -E1000_ERR_RESET; - goto out; - } - -out: - return ret_val; -} -#if 0 -/** - * e1000e_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex - * @hw: pointer to the HW structure - * - * Force the speed and duplex settings onto the PHY. This is a - * function pointer entry point called by the phy module. - **/ -static s32 e1000e_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 phy_data; - bool link; - - if (!(hw->phy.ops.read_reg)) - goto out; - - /* - * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO; - ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - e_dbg("GG82563 PSCR: %X\n", phy_data); - - ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - e1000e_phy_force_speed_duplex_setup(hw, &phy_data); - - /* Reset the phy to commit changes. */ - phy_data |= MII_CR_RESET; - - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - udelay(1); - - if (hw->phy.autoneg_wait_to_complete) { - e_dbg("Waiting for forced speed/duplex link " - "on GG82563 phy.\n"); - - ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - - if (!link) { - /* - * We didn't get link. - * Reset the DSP and cross our fingers. - */ - ret_val = e1000e_phy_reset_dsp(hw); - if (ret_val) - goto out; - } - - /* Try once more */ - ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - } - - ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - /* - * Resetting the phy means we need to verify the TX_CLK corresponds - * to the link speed. 10Mbps -> 2.5MHz, else 25MHz. - */ - phy_data &= ~GG82563_MSCR_TX_CLK_MASK; - if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED) - phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5; - else - phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25; - - /* - * In addition, we must re-enable CRS on Tx for both half and full - * duplex. - */ - phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; - ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); - -out: - return ret_val; -} -#endif - -#if 0 -/** - * e1000e_get_cable_length_80003es2lan - Set approximate cable length - * @hw: pointer to the HW structure - * - * Find the approximate cable length as measured by the GG82563 PHY. - * This is a function pointer entry point called by the phy module. - **/ -static s32 e1000e_get_cable_length_80003es2lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_data, index; - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data); - if (ret_val) - goto out; - - index = phy_data & GG82563_DSPD_CABLE_LENGTH; - - if (index >= GG82563_CABLE_LENGTH_TABLE_SIZE - 5) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - phy->min_cable_length = e1000_gg82563_cable_length_table[index]; - phy->max_cable_length = e1000_gg82563_cable_length_table[index + 5]; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} -#endif - -/** - * e1000e_get_link_up_info_80003es2lan - Report speed and duplex - * @hw: pointer to the HW structure - * @speed: pointer to speed buffer - * @duplex: pointer to duplex buffer - * - * Retrieve the current speed and duplex configuration. - **/ -static s32 e1000e_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, - u16 *duplex) -{ - s32 ret_val; - - if (hw->phy.media_type == e1000_media_type_copper) { - ret_val = e1000e_get_speed_and_duplex_copper(hw, - speed, - duplex); - hw->phy.ops.cfg_on_link_up(hw); - } else { - ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw, - speed, - duplex); - } - - return ret_val; -} - -/** - * e1000e_reset_hw_80003es2lan - Reset the ESB2 controller - * @hw: pointer to the HW structure - * - * Perform a global reset to the ESB2 controller. - **/ -static s32 e1000e_reset_hw_80003es2lan(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - - /* - * Prevent the PCI-E bus from sticking if there is no TLP connection - * on the last TLP read/write transaction when MAC is reset. - */ - ret_val = e1000e_disable_pcie_master(hw); - if (ret_val) - e_dbg("PCI-E Master disable polling has failed.\n"); - - e_dbg("Masking off all interrupts\n"); - ew32(IMC, 0xffffffff); - - ew32(RCTL, 0); - ew32(TCTL, E1000_TCTL_PSP); - e1e_flush(); - - msleep(10); - - ctrl = er32(CTRL); - - ret_val = e1000e_acquire_phy_80003es2lan(hw); - e_dbg("Issuing a global reset to MAC\n"); - ew32(CTRL, ctrl | E1000_CTRL_RST); - e1000e_release_phy_80003es2lan(hw); - - ret_val = e1000e_get_auto_rd_done(hw); - if (ret_val) - /* We don't want to continue accessing MAC registers. */ - goto out; - - /* Clear any pending interrupt events. */ - ew32(IMC, 0xffffffff); - er32(ICR); - - ret_val = e1000e_check_alt_mac_addr_generic(hw); - -out: - return ret_val; -} - -/** - * e1000e_init_hw_80003es2lan - Initialize the ESB2 controller - * @hw: pointer to the HW structure - * - * Initialize the hw bits, LED, VFTA, MTA, link and hw counters. - **/ -static s32 e1000e_init_hw_80003es2lan(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 reg_data; - s32 ret_val; - u16 i; - - e1000e_initialize_hw_bits_80003es2lan(hw); - - /* Initialize identification LED */ - ret_val = mac->ops.id_led_init(hw); - if (ret_val) { - e_dbg("Error initializing identification LED\n"); - /* This is not fatal and we should not stop init due to this */ - } - - /* Disabling VLAN filtering */ - e_dbg("Initializing the IEEE VLAN\n"); - e1000e_clear_vfta(hw); - - /* Setup the receive address. */ - e1000e_init_rx_addrs(hw, mac->rar_entry_count); - - /* Zero out the Multicast HASH table */ - e_dbg("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - - /* Setup link and flow control */ - ret_val = mac->ops.setup_link(hw); - - /* Set the transmit descriptor write-back policy */ - reg_data = er32(TXDCTL(0)); - reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; - ew32(TXDCTL(0), reg_data); - - /* ...for both queues. */ - reg_data = er32(TXDCTL(1)); - reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC; - ew32(TXDCTL(1), reg_data); - - /* Enable retransmit on late collisions */ - reg_data = er32(TCTL); - reg_data |= E1000_TCTL_RTLC; - ew32(TCTL, reg_data); - - /* Configure Gigabit Carry Extend Padding */ - reg_data = er32(TCTL_EXT); - reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; - reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN; - ew32(TCTL_EXT, reg_data); - - /* Configure Transmit Inter-Packet Gap */ - reg_data = er32(TIPG); - reg_data &= ~E1000_TIPG_IPGT_MASK; - reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; - ew32(TIPG, reg_data); - - reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001); - reg_data &= ~0x00100000; - E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data); - - /* default to true to enable the MDIC W/A */ - hw->dev_spec._80003es2lan.mdic_wa_enable = true; - - ret_val = e1000e_read_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET >> - E1000_KMRNCTRLSTA_OFFSET_SHIFT, - &i); - if (!ret_val) { - if ((i & E1000_KMRNCTRLSTA_OPMODE_MASK) == - E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO) - hw->dev_spec._80003es2lan.mdic_wa_enable = false; - } - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - e1000e_clear_hw_cntrs_80003es2lan(hw); - - return ret_val; -} - -/** - * e1000e_initialize_hw_bits_80003es2lan - Init hw bits of ESB2 - * @hw: pointer to the HW structure - * - * Initializes required hardware-dependent bits needed for normal operation. - **/ -static void e1000e_initialize_hw_bits_80003es2lan(struct e1000_hw *hw) -{ - u32 reg; - - /* Transmit Descriptor Control 0 */ - reg = er32(TXDCTL(0)); - reg |= (1 << 22); - ew32(TXDCTL(0), reg); - - /* Transmit Descriptor Control 1 */ - reg = er32(TXDCTL(1)); - reg |= (1 << 22); - ew32(TXDCTL(1), reg); - - /* Transmit Arbitration Control 0 */ - reg = er32(TARC(0)); - reg &= ~(0xF << 27); /* 30:27 */ - if (hw->phy.media_type != e1000_media_type_copper) - reg &= ~(1 << 20); - ew32(TARC(0), reg); - - /* Transmit Arbitration Control 1 */ - reg = er32(TARC(1)); - if (er32(TCTL) & E1000_TCTL_MULR) - reg &= ~(1 << 28); - else - reg |= (1 << 28); - ew32(TARC(1), reg); - - return; -} - -/** - * e1000e_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link - * @hw: pointer to the HW structure - * - * Setup some GG82563 PHY registers for obtaining link - **/ -static s32 e1000e_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u32 ctrl_ext; - u16 data; - - if (!phy->reset_disable) { - ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, - &data); - if (ret_val) - goto out; - - data |= GG82563_MSCR_ASSERT_CRS_ON_TX; - /* Use 25MHz for both link down and 1000Base-T for Tx clock. */ - data |= GG82563_MSCR_TX_CLK_1000MBPS_25; - - ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, - data); - if (ret_val) - goto out; - - /* - * Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data); - if (ret_val) - goto out; - - data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; - - switch (phy->mdix) { - case 1: - data |= GG82563_PSCR_CROSSOVER_MODE_MDI; - break; - case 2: - data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; - break; - case 0: - default: - data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; - break; - } - - /* - * Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; - if (phy->disable_polarity_correction) - data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; - - ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data); - if (ret_val) - goto out; - - /* SW Reset the PHY so all changes take effect */ - ret_val = e1000e_commit_phy(hw); - if (ret_val) { - e_dbg("Error Resetting the PHY\n"); - goto out; - } - - } - - /* Bypass Rx and Tx FIFO's */ - ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, - E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS | - E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS); - if (ret_val) - goto out; - - ret_val = e1000e_read_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, - &data); - if (ret_val) - goto out; - data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE; - ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, - data); - if (ret_val) - goto out; - - ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data); - if (ret_val) - goto out; - - data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; - ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data); - if (ret_val) - goto out; - - ctrl_ext = er32(CTRL_EXT); - ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); - ew32(CTRL_EXT, ctrl_ext); - - ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data); - if (ret_val) - goto out; - - /* - * Do not init these registers when the HW is in IAMT mode, since the - * firmware will have already initialized them. We only initialize - * them if the HW is not in IAMT mode. - */ - if (!(hw->mac.ops.check_mng_mode(hw))) { - /* Enable Electrical Idle on the PHY */ - data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; - ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL, - data); - if (ret_val) - goto out; - - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - &data); - if (ret_val) - goto out; - - data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; - ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - data); - if (ret_val) - goto out; - } - - /* - * Workaround: Disable padding in Kumeran interface in the MAC - * and in the PHY to avoid CRC errors. - */ - ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data); - if (ret_val) - goto out; - - data |= GG82563_ICR_DIS_PADDING; - ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data); - if (ret_val) - goto out; - -out: - return ret_val; -} - -/** - * e1000e_setup_copper_link_80003es2lan - Setup Copper Link for ESB2 - * @hw: pointer to the HW structure - * - * Essentially a wrapper for setting up all things "copper" related. - * This is a function pointer entry point called by the mac module. - **/ -static s32 e1000e_setup_copper_link_80003es2lan(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - u16 reg_data; - - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_SLU; - ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - ew32(CTRL, ctrl); - - /* - * Set the mac to wait the maximum time between each - * iteration and increase the max iterations when - * polling the phy; this fixes erroneous timeouts at 10Mbps. - */ - ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4), - 0xFFFF); - if (ret_val) - goto out; - ret_val = e1000e_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), - ®_data); - if (ret_val) - goto out; - reg_data |= 0x3F; - ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), - reg_data); - if (ret_val) - goto out; - ret_val = e1000e_read_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, - ®_data); - if (ret_val) - goto out; - reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING; - ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, - reg_data); - if (ret_val) - goto out; - - ret_val = e1000e_copper_link_setup_gg82563_80003es2lan(hw); - if (ret_val) - goto out; - - ret_val = e1000e_setup_copper_link(hw); - -out: - return ret_val; -} - -/** - * e1000e_cfg_on_link_up_80003es2lan - es2 link configuration after link-up - * @hw: pointer to the HW structure - * @duplex: current duplex setting - * - * Configure the KMRN interface by applying last minute quirks for - * 10/100 operation. - **/ -static s32 e1000e_cfg_on_link_up_80003es2lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 speed; - u16 duplex; - - if (hw->phy.media_type == e1000_media_type_copper) { - ret_val = e1000e_get_speed_and_duplex_copper(hw, - &speed, - &duplex); - if (ret_val) - goto out; - - if (speed == SPEED_1000) - ret_val = e1000e_cfg_kmrn_1000_80003es2lan(hw); - else - ret_val = e1000e_cfg_kmrn_10_100_80003es2lan(hw, duplex); - } - -out: - return ret_val; -} - -/** - * e1000e_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation - * @hw: pointer to the HW structure - * @duplex: current duplex setting - * - * Configure the KMRN interface by applying last minute quirks for - * 10/100 operation. - **/ -static s32 e1000e_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) -{ - s32 ret_val = E1000_SUCCESS; - u32 tipg; - u32 i = 0; - u16 reg_data, reg_data2; - - reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; - ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, - reg_data); - if (ret_val) - goto out; - - /* Configure Transmit Inter-Packet Gap */ - tipg = er32(TIPG); - tipg &= ~E1000_TIPG_IPGT_MASK; - tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN; - ew32(TIPG, tipg); - - - do { - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - ®_data); - if (ret_val) - goto out; - - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - ®_data2); - if (ret_val) - goto out; - i++; - } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); - - if (duplex == HALF_DUPLEX) - reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER; - else - reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; - - ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); - -out: - return ret_val; -} - -/** - * e1000e_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation - * @hw: pointer to the HW structure - * - * Configure the KMRN interface by applying last minute quirks for - * gigabit operation. - **/ -static s32 e1000e_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 reg_data, reg_data2; - u32 tipg; - u32 i = 0; - - reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; - ret_val = e1000e_write_kmrn_reg_80003es2lan(hw, - E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, - reg_data); - if (ret_val) - goto out; - - /* Configure Transmit Inter-Packet Gap */ - tipg = er32(TIPG); - tipg &= ~E1000_TIPG_IPGT_MASK; - tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN; - ew32(TIPG, tipg); - - - do { - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - ®_data); - if (ret_val) - goto out; - - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - ®_data2); - if (ret_val) - goto out; - i++; - } while ((reg_data != reg_data2) && (i < GG82563_MAX_KMRN_RETRY)); - - reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; - ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data); - -out: - return ret_val; -} - -/** - * e1000e_read_kmrn_reg_80003es2lan - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquire semaphore, then read the PHY register at offset - * using the kumeran interface. The information retrieved is stored in data. - * Release the semaphore before exiting. - **/ -static s32 e1000e_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, - u16 *data) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - ret_val = e1000e_acquire_mac_csr_80003es2lan(hw); - if (ret_val) - goto out; - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; - ew32(KMRNCTRLSTA, kmrnctrlsta); - - udelay(2); - - kmrnctrlsta = er32(KMRNCTRLSTA); - *data = (u16)kmrnctrlsta; - - e1000e_release_mac_csr_80003es2lan(hw); - -out: - return ret_val; -} - -/** - * e1000e_write_kmrn_reg_80003es2lan - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquire semaphore, then write the data to PHY register - * at the offset using the kumeran interface. Release semaphore - * before exiting. - **/ -static s32 e1000e_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, - u16 data) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - ret_val = e1000e_acquire_mac_csr_80003es2lan(hw); - if (ret_val) - goto out; - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | data; - ew32(KMRNCTRLSTA, kmrnctrlsta); - - udelay(2); - - e1000e_release_mac_csr_80003es2lan(hw); - -out: - return ret_val; -} - -/** - * e1000e_read_mac_addr_80003es2lan - Read device MAC address - * @hw: pointer to the HW structure - **/ -static s32 e1000e_read_mac_addr_80003es2lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - /* - * If there's an alternate MAC address place it in RAR0 - * so that it will override the Si installed default perm - * address. - */ - ret_val = e1000e_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; - - ret_val = e1000e_read_mac_addr_generic(hw); - -out: - return ret_val; -} - -/** - * e1000e_power_down_phy_copper_80003es2lan - Remove link during PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, remove the link. - **/ -static void e1000e_power_down_phy_copper_80003es2lan(struct e1000_hw *hw) -{ - /* If the management interface is not enabled, then power down */ - if (!(hw->mac.ops.check_mng_mode(hw) || - e1000e_check_reset_block(hw))) - e1000e_power_down_phy_copper(hw); - - return; -} - -/** - * e1000e_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters - * @hw: pointer to the HW structure - * - * Clears the hardware counters by reading the counter registers. - **/ -static void e1000e_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw __unused) -{ -#if 0 - e1000e_clear_hw_cntrs_base(hw); - - er32(PRC64); - er32(PRC127); - er32(PRC255); - er32(PRC511); - er32(PRC1023); - er32(PRC1522); - er32(PTC64); - er32(PTC127); - er32(PTC255); - er32(PTC511); - er32(PTC1023); - er32(PTC1522); - - er32(ALGNERRC); - er32(RXERRC); - er32(TNCRS); - er32(CEXTERR); - er32(TSCTC); - er32(TSCTFC); - - er32(MGTPRC); - er32(MGTPDC); - er32(MGTPTC); - - er32(IAC); - er32(ICRXOC); - - er32(ICRXPTC); - er32(ICRXATC); - er32(ICTXPTC); - er32(ICTXATC); - er32(ICTXQEC); - er32(ICTXQMTC); - er32(ICRXDMTC); -#endif -} - -static struct pci_device_id e1000e_80003es2lan_nics[] = { - PCI_ROM(0x8086, 0x1096, "E1000_DEV_ID_80003ES2LAN_COPPER_DPT", "E1000_DEV_ID_80003ES2LAN_COPPER_DPT", board_80003es2lan), - PCI_ROM(0x8086, 0x10BA, "E1000_DEV_ID_80003ES2LAN_COPPER_SPT", "E1000_DEV_ID_80003ES2LAN_COPPER_SPT", board_80003es2lan), - PCI_ROM(0x8086, 0x1098, "E1000_DEV_ID_80003ES2LAN_SERDES_DPT", "E1000_DEV_ID_80003ES2LAN_SERDES_DPT", board_80003es2lan), - PCI_ROM(0x8086, 0x10BB, "E1000_DEV_ID_80003ES2LAN_SERDES_SPT", "E1000_DEV_ID_80003ES2LAN_SERDES_SPT", board_80003es2lan), -}; - -struct pci_driver e1000e_80003es2lan_driver __pci_driver = { - .ids = e1000e_80003es2lan_nics, - .id_count = (sizeof (e1000e_80003es2lan_nics) / sizeof (e1000e_80003es2lan_nics[0])), - .probe = e1000e_probe, - .remove = e1000e_remove, -}; diff --git a/src/drivers/net/e1000e/e1000e_80003es2lan.h b/src/drivers/net/e1000e/e1000e_80003es2lan.h deleted file mode 100644 index 93430a16..00000000 --- a/src/drivers/net/e1000e/e1000e_80003es2lan.h +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_80003ES2LAN_H_ -#define _E1000E_80003ES2LAN_H_ - -#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL 0x00 -#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL 0x02 -#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL 0x10 -#define E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE 0x1F - -#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS 0x0008 -#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS 0x0800 -#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING 0x0010 - -#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004 -#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT 0x0000 -#define E1000_KMRNCTRLSTA_OPMODE_E_IDLE 0x2000 - -#define E1000_KMRNCTRLSTA_OPMODE_MASK 0x000C -#define E1000_KMRNCTRLSTA_OPMODE_INBAND_MDIO 0x0004 - -#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ -#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN 0x00010000 - -#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN 0x8 -#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN 0x9 - -/* GG82563 PHY Specific Status Register (Page 0, Register 16 */ -#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Reversal Disabled */ -#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060 -#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI */ -#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX */ -#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Auto crossover */ - -/* PHY Specific Control Register 2 (Page 0, Register 26) */ -#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 - /* 1=Reverse Auto-Negotiation */ - -/* MAC Specific Control Register (Page 2, Register 21) */ -/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */ -#define GG82563_MSCR_TX_CLK_MASK 0x0007 -#define GG82563_MSCR_TX_CLK_10MBPS_2_5 0x0004 -#define GG82563_MSCR_TX_CLK_100MBPS_25 0x0005 -#define GG82563_MSCR_TX_CLK_1000MBPS_2_5 0x0006 -#define GG82563_MSCR_TX_CLK_1000MBPS_25 0x0007 - -#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */ - -/* DSP Distance Register (Page 5, Register 26) */ -/* - * 0 = <50M - * 1 = 50-80M - * 2 = 80-100M - * 3 = 110-140M - * 4 = >140M - */ -#define GG82563_DSPD_CABLE_LENGTH 0x0007 - -/* Kumeran Mode Control Register (Page 193, Register 16) */ -#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 - -/* Max number of times Kumeran read/write should be validated */ -#define GG82563_MAX_KMRN_RETRY 0x5 - -/* Power Management Control Register (Page 193, Register 20) */ -#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 - /* 1=Enable SERDES Electrical Idle */ - -/* In-Band Control Register (Page 194, Register 18) */ -#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding */ - -#endif diff --git a/src/drivers/net/e1000e/e1000e_82571.c b/src/drivers/net/e1000e/e1000e_82571.c deleted file mode 100644 index a061d6d4..00000000 --- a/src/drivers/net/e1000e/e1000e_82571.c +++ /dev/null @@ -1,1818 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * 82571EB Gigabit Ethernet Controller - * 82571EB Gigabit Ethernet Controller (Copper) - * 82571EB Gigabit Ethernet Controller (Fiber) - * 82571EB Dual Port Gigabit Mezzanine Adapter - * 82571EB Quad Port Gigabit Mezzanine Adapter - * 82571PT Gigabit PT Quad Port Server ExpressModule - * 82572EI Gigabit Ethernet Controller (Copper) - * 82572EI Gigabit Ethernet Controller (Fiber) - * 82572EI Gigabit Ethernet Controller - * 82573V Gigabit Ethernet Controller (Copper) - * 82573E Gigabit Ethernet Controller (Copper) - * 82573L Gigabit Ethernet Controller - * 82574L Gigabit Network Connection - * 82574L Gigabit Network Connection - * 82583V Gigabit Network Connection - */ - -#include "e1000e.h" - -static s32 e1000e_init_phy_params_82571(struct e1000_hw *hw); -static s32 e1000e_init_nvm_params_82571(struct e1000_hw *hw); -static s32 e1000e_init_mac_params_82571(struct e1000_hw *hw); -static s32 e1000e_acquire_nvm_82571(struct e1000_hw *hw); -static void e1000e_release_nvm_82571(struct e1000_hw *hw); -static s32 e1000e_write_nvm_82571(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -static s32 e1000e_update_nvm_checksum_82571(struct e1000_hw *hw); -static s32 e1000e_validate_nvm_checksum_82571(struct e1000_hw *hw); -static s32 e1000e_get_cfg_done_82571(struct e1000_hw *hw); -static s32 e1000e_set_d0_lplu_state_82571(struct e1000_hw *hw, - bool active); -static s32 e1000e_reset_hw_82571(struct e1000_hw *hw); -static s32 e1000e_init_hw_82571(struct e1000_hw *hw); -static void e1000e_clear_vfta_82571(struct e1000_hw *hw); -#if 0 -static bool e1000e_check_mng_mode_82574(struct e1000_hw *hw); -#endif -static s32 e1000e_led_on_82574(struct e1000_hw *hw); -static s32 e1000e_setup_link_82571(struct e1000_hw *hw); -static s32 e1000e_setup_copper_link_82571(struct e1000_hw *hw); -static s32 e1000e_check_for_serdes_link_82571(struct e1000_hw *hw); -static s32 e1000e_setup_fiber_serdes_link_82571(struct e1000_hw *hw); -static s32 e1000e_valid_led_default_82571(struct e1000_hw *hw, u16 *data); -static void e1000e_clear_hw_cntrs_82571(struct e1000_hw *hw); -static s32 e1000e_get_hw_semaphore_82571(struct e1000_hw *hw); -static s32 e1000e_fix_nvm_checksum_82571(struct e1000_hw *hw); -static s32 e1000e_get_phy_id_82571(struct e1000_hw *hw); -static void e1000e_put_hw_semaphore_82571(struct e1000_hw *hw); -static void e1000e_initialize_hw_bits_82571(struct e1000_hw *hw); -static s32 e1000e_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -static s32 e1000e_read_mac_addr_82571(struct e1000_hw *hw); -static void e1000e_power_down_phy_copper_82571(struct e1000_hw *hw); - -/** - * e1000e_init_phy_params_82571 - Init PHY func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000e_init_phy_params_82571(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - if (hw->phy.media_type != e1000_media_type_copper) { - phy->type = e1000_phy_none; - goto out; - } - - phy->addr = 1; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->reset_delay_us = 100; - - phy->ops.acquire = e1000e_get_hw_semaphore_82571; - phy->ops.check_polarity = e1000e_check_polarity_igp; - phy->ops.check_reset_block = e1000e_check_reset_block_generic; - phy->ops.release = e1000e_put_hw_semaphore_82571; - phy->ops.reset = e1000e_phy_hw_reset_generic; - phy->ops.set_d0_lplu_state = e1000e_set_d0_lplu_state_82571; - phy->ops.set_d3_lplu_state = e1000e_set_d3_lplu_state; - phy->ops.power_up = e1000e_power_up_phy_copper; - phy->ops.power_down = e1000e_power_down_phy_copper_82571; - - switch (hw->mac.type) { - case e1000_82571: - case e1000_82572: - phy->type = e1000_phy_igp_2; - phy->ops.get_cfg_done = e1000e_get_cfg_done_82571; - phy->ops.get_info = e1000e_get_phy_info_igp; -#if 0 - phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_igp; -#endif -#if 0 - phy->ops.get_cable_length = e1000e_get_cable_length_igp_2; -#endif - phy->ops.read_reg = e1000e_read_phy_reg_igp; - phy->ops.write_reg = e1000e_write_phy_reg_igp; - - /* This uses above function pointers */ - ret_val = e1000e_get_phy_id_82571(hw); - - /* Verify PHY ID */ - if (phy->id != IGP01E1000_I_PHY_ID) { - ret_val = -E1000_ERR_PHY; - goto out; - } - break; - case e1000_82573: - phy->type = e1000_phy_m88; - phy->ops.get_cfg_done = e1000e_get_cfg_done; - phy->ops.get_info = e1000e_get_phy_info_m88; - phy->ops.commit = e1000e_phy_sw_reset; -#if 0 - phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88; -#endif -#if 0 - phy->ops.get_cable_length = e1000e_get_cable_length_m88; -#endif - phy->ops.read_reg = e1000e_read_phy_reg_m88; - phy->ops.write_reg = e1000e_write_phy_reg_m88; - - /* This uses above function pointers */ - ret_val = e1000e_get_phy_id_82571(hw); - - /* Verify PHY ID */ - if (phy->id != M88E1111_I_PHY_ID) { - ret_val = -E1000_ERR_PHY; - e_dbg("PHY ID unknown: type = 0x%08x\n", phy->id); - goto out; - } - break; - case e1000_82583: - case e1000_82574: - phy->type = e1000_phy_bm; - phy->ops.get_cfg_done = e1000e_get_cfg_done; - phy->ops.get_info = e1000e_get_phy_info_m88; - phy->ops.commit = e1000e_phy_sw_reset; -#if 0 - phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88; -#endif -#if 0 - phy->ops.get_cable_length = e1000e_get_cable_length_m88; -#endif - phy->ops.read_reg = e1000e_read_phy_reg_bm2; - phy->ops.write_reg = e1000e_write_phy_reg_bm2; - - /* This uses above function pointers */ - ret_val = e1000e_get_phy_id_82571(hw); - /* Verify PHY ID */ - if (phy->id != BME1000_E_PHY_ID_R2) { - ret_val = -E1000_ERR_PHY; - e_dbg("PHY ID unknown: type = 0x%08x\n", phy->id); - goto out; - } - break; - default: - ret_val = -E1000_ERR_PHY; - goto out; - break; - } - -out: - return ret_val; -} - -/** - * e1000e_init_nvm_params_82571 - Init NVM func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000e_init_nvm_params_82571(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = er32(EECD); - u16 size; - - nvm->opcode_bits = 8; - nvm->delay_usec = 1; - switch (nvm->override) { - case e1000_nvm_override_spi_large: - nvm->page_size = 32; - nvm->address_bits = 16; - break; - case e1000_nvm_override_spi_small: - nvm->page_size = 8; - nvm->address_bits = 8; - break; - default: - nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; - nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; - break; - } - - switch (hw->mac.type) { - case e1000_82573: - case e1000_82574: - case e1000_82583: - if (((eecd >> 15) & 0x3) == 0x3) { - nvm->type = e1000_nvm_flash_hw; - nvm->word_size = 2048; - /* - * Autonomous Flash update bit must be cleared due - * to Flash update issue. - */ - eecd &= ~E1000_EECD_AUPDEN; - ew32(EECD, eecd); - break; - } - /* Fall Through */ - default: - nvm->type = e1000_nvm_eeprom_spi; - size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> - E1000_EECD_SIZE_EX_SHIFT); - /* - * Added to a constant, "size" becomes the left-shift value - * for setting word_size. - */ - size += NVM_WORD_SIZE_BASE_SHIFT; - - /* EEPROM access above 16k is unsupported */ - if (size > 14) - size = 14; - nvm->word_size = 1 << size; - break; - } - - /* Function Pointers */ - nvm->ops.acquire = e1000e_acquire_nvm_82571; - nvm->ops.read = e1000e_read_nvm_eerd; - nvm->ops.release = e1000e_release_nvm_82571; - nvm->ops.update = e1000e_update_nvm_checksum_82571; - nvm->ops.validate = e1000e_validate_nvm_checksum_82571; - nvm->ops.valid_led_default = e1000e_valid_led_default_82571; - nvm->ops.write = e1000e_write_nvm_82571; - - return E1000_SUCCESS; -} - -/** - * e1000e_init_mac_params_82571 - Init MAC func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 e1000e_init_mac_params_82571(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - u32 swsm = 0; - u32 swsm2 = 0; - bool force_clear_smbi = false; - - /* Set media type */ - switch (hw->device_id) { - case E1000_DEV_ID_82571EB_FIBER: - case E1000_DEV_ID_82572EI_FIBER: - case E1000_DEV_ID_82571EB_QUAD_FIBER: - hw->phy.media_type = e1000_media_type_fiber; - break; - case E1000_DEV_ID_82571EB_SERDES: - case E1000_DEV_ID_82571EB_SERDES_DUAL: - case E1000_DEV_ID_82571EB_SERDES_QUAD: - case E1000_DEV_ID_82572EI_SERDES: - hw->phy.media_type = e1000_media_type_internal_serdes; - break; - default: - hw->phy.media_type = e1000_media_type_copper; - break; - } - - /* Set mta register count */ - mac->mta_reg_count = 128; - /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES; - /* Set if part includes ASF firmware */ - mac->asf_firmware_present = true; - /* Set if manageability features are enabled. */ - mac->arc_subsystem_valid = - (er32(FWSM) & E1000_FWSM_MODE_MASK) - ? true : false; - - /* Function pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = e1000e_get_bus_info_pcie; - /* function id */ - switch (hw->mac.type) { - case e1000_82573: - case e1000_82574: - case e1000_82583: - mac->ops.set_lan_id = e1000e_set_lan_id_single_port; - break; - default: - break; - } - /* reset */ - mac->ops.reset_hw = e1000e_reset_hw_82571; - /* hw initialization */ - mac->ops.init_hw = e1000e_init_hw_82571; - /* link setup */ - mac->ops.setup_link = e1000e_setup_link_82571; - /* physical interface link setup */ - mac->ops.setup_physical_interface = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000e_setup_copper_link_82571 - : e1000e_setup_fiber_serdes_link_82571; - /* check for link */ - switch (hw->phy.media_type) { - case e1000_media_type_copper: - mac->ops.check_for_link = e1000e_check_for_copper_link; - break; - case e1000_media_type_fiber: - mac->ops.check_for_link = e1000e_check_for_fiber_link; - break; - case e1000_media_type_internal_serdes: - mac->ops.check_for_link = e1000e_check_for_serdes_link_82571; - break; - default: - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } - /* check management mode */ -#if 0 - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - mac->ops.check_mng_mode = e1000e_check_mng_mode_82574; - break; - default: - mac->ops.check_mng_mode = e1000e_check_mng_mode_generic; - break; - } -#endif - /* multicast address update */ - mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = e1000e_write_vfta_generic; - /* clearing VFTA */ - mac->ops.clear_vfta = e1000e_clear_vfta_82571; - /* setting MTA */ - mac->ops.mta_set = e1000e_mta_set_generic; - /* read mac address */ - mac->ops.read_mac_addr = e1000e_read_mac_addr_82571; - /* ID LED init */ - mac->ops.id_led_init = e1000e_id_led_init; - /* blink LED */ - mac->ops.blink_led = e1000e_blink_led; - /* setup LED */ - mac->ops.setup_led = e1000e_setup_led_generic; - /* cleanup LED */ - mac->ops.cleanup_led = e1000e_cleanup_led_generic; - /* turn on/off LED */ - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - mac->ops.led_on = e1000e_led_on_82574; - break; - default: - mac->ops.led_on = e1000e_led_on_generic; - break; - } - mac->ops.led_off = e1000e_led_off_generic; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_82571; - /* link info */ - mac->ops.get_link_up_info = - (hw->phy.media_type == e1000_media_type_copper) - ? e1000e_get_speed_and_duplex_copper - : e1000e_get_speed_and_duplex_fiber_serdes; - - /* - * Ensure that the inter-port SWSM.SMBI lock bit is clear before - * first NVM or PHY acess. This should be done for single-port - * devices, and for one port only on dual-port devices so that - * for those devices we can still use the SMBI lock to synchronize - * inter-port accesses to the PHY & NVM. - */ - switch (hw->mac.type) { - case e1000_82571: - case e1000_82572: - swsm2 = er32(SWSM2); - - if (!(swsm2 & E1000_SWSM2_LOCK)) { - /* Only do this for the first interface on this card */ - ew32(SWSM2, - swsm2 | E1000_SWSM2_LOCK); - force_clear_smbi = true; - } else - force_clear_smbi = false; - break; - default: - force_clear_smbi = true; - break; - } - - if (force_clear_smbi) { - /* Make sure SWSM.SMBI is clear */ - swsm = er32(SWSM); - if (swsm & E1000_SWSM_SMBI) { - /* This bit should not be set on a first interface, and - * indicates that the bootagent or EFI code has - * improperly left this bit enabled - */ - e_dbg("Please update your 82571 Bootagent\n"); - } - ew32(SWSM, swsm & ~E1000_SWSM_SMBI); - } - - /* - * Initialze device specific counter of SMBI acquisition - * timeouts. - */ - hw->dev_spec._82571.smb_counter = 0; - -out: - return ret_val; -} - -/** - * e1000e_init_function_pointers_82571 - Init func ptrs. - * @hw: pointer to the HW structure - * - * Called to initialize all function pointers and parameters. - **/ -void e1000e_init_function_pointers_82571(struct e1000_hw *hw) -{ - e1000e_init_mac_ops_generic(hw); - e1000e_init_nvm_ops_generic(hw); - hw->mac.ops.init_params = e1000e_init_mac_params_82571; - hw->nvm.ops.init_params = e1000e_init_nvm_params_82571; - hw->phy.ops.init_params = e1000e_init_phy_params_82571; -} - -/** - * e1000e_get_phy_id_82571 - Retrieve the PHY ID and revision - * @hw: pointer to the HW structure - * - * Reads the PHY registers and stores the PHY ID and possibly the PHY - * revision in the hardware structure. - **/ -static s32 e1000e_get_phy_id_82571(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_id = 0; - - switch (hw->mac.type) { - case e1000_82571: - case e1000_82572: - /* - * The 82571 firmware may still be configuring the PHY. - * In this case, we cannot access the PHY until the - * configuration is done. So we explicitly set the - * PHY ID. - */ - phy->id = IGP01E1000_I_PHY_ID; - break; - case e1000_82573: - ret_val = e1000e_get_phy_id(hw); - break; - case e1000_82574: - case e1000_82583: - ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); - if (ret_val) - goto out; - - phy->id = (u32)(phy_id << 16); - udelay(20); - ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); - if (ret_val) - goto out; - - phy->id |= (u32)(phy_id); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); - break; - default: - ret_val = -E1000_ERR_PHY; - break; - } -out: - return ret_val; -} - -/** - * e1000e_get_hw_semaphore_82571 - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM - **/ -s32 e1000e_get_hw_semaphore_82571(struct e1000_hw *hw) -{ - u32 swsm; - s32 ret_val = E1000_SUCCESS; - s32 sw_timeout = hw->nvm.word_size + 1; - s32 fw_timeout = hw->nvm.word_size + 1; - s32 i = 0; - - /* - * If we have timedout 3 times on trying to acquire - * the inter-port SMBI semaphore, there is old code - * operating on the other port, and it is not - * releasing SMBI. Modify the number of times that - * we try for the semaphore to interwork with this - * older code. - */ - if (hw->dev_spec._82571.smb_counter > 2) - sw_timeout = 1; - - /* Get the SW semaphore */ - while (i < sw_timeout) { - swsm = er32(SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - udelay(50); - i++; - } - - if (i == sw_timeout) { - e_dbg("Driver can't access device - SMBI bit is set.\n"); - hw->dev_spec._82571.smb_counter++; - } - /* Get the FW semaphore. */ - for (i = 0; i < fw_timeout; i++) { - swsm = er32(SWSM); - ew32(SWSM, swsm | E1000_SWSM_SWESMBI); - - /* Semaphore acquired if bit latched */ - if (er32(SWSM) & E1000_SWSM_SWESMBI) - break; - - udelay(50); - } - - if (i == fw_timeout) { - /* Release semaphores */ - e1000e_put_hw_semaphore_82571(hw); - e_dbg("Driver can't access the NVM\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_put_hw_semaphore_82571 - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - **/ -void e1000e_put_hw_semaphore_82571(struct e1000_hw *hw) -{ - u32 swsm; - - swsm = er32(SWSM); - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); - ew32(SWSM, swsm); -} - -/** - * e1000e_acquire_nvm_82571 - Request for access to the EEPROM - * @hw: pointer to the HW structure - * - * To gain access to the EEPROM, first we must obtain a hardware semaphore. - * Then for non-82573 hardware, set the EEPROM access request bit and wait - * for EEPROM access grant bit. If the access grant bit is not set, release - * hardware semaphore. - **/ -static s32 e1000e_acquire_nvm_82571(struct e1000_hw *hw) -{ - s32 ret_val; - - ret_val = e1000e_get_hw_semaphore_82571(hw); - if (ret_val) - goto out; - - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - break; - default: - ret_val = e1000e_acquire_nvm(hw); - break; - } - - if (ret_val) - e1000e_put_hw_semaphore_82571(hw); - -out: - return ret_val; -} - -/** - * e1000e_release_nvm_82571 - Release exclusive access to EEPROM - * @hw: pointer to the HW structure - * - * Stop any current commands to the EEPROM and clear the EEPROM request bit. - **/ -static void e1000e_release_nvm_82571(struct e1000_hw *hw) -{ - e1000e_release_nvm(hw); - e1000e_put_hw_semaphore_82571(hw); -} - -/** - * e1000e_write_nvm_82571 - Write to EEPROM using appropriate interface - * @hw: pointer to the HW structure - * @offset: offset within the EEPROM to be written to - * @words: number of words to write - * @data: 16 bit word(s) to be written to the EEPROM - * - * For non-82573 silicon, write data to EEPROM at offset using SPI interface. - * - * If e1000e_update_nvm_checksum is not called after this function, the - * EEPROM will most likely contain an invalid checksum. - **/ -static s32 e1000e_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data) -{ - s32 ret_val = E1000_SUCCESS; - - switch (hw->mac.type) { - case e1000_82573: - case e1000_82574: - case e1000_82583: - ret_val = e1000e_write_nvm_eewr_82571(hw, offset, words, data); - break; - case e1000_82571: - case e1000_82572: - ret_val = e1000e_write_nvm_spi(hw, offset, words, data); - break; - default: - ret_val = -E1000_ERR_NVM; - break; - } - - return ret_val; -} - -/** - * e1000e_update_nvm_checksum_82571 - Update EEPROM checksum - * @hw: pointer to the HW structure - * - * Updates the EEPROM checksum by reading/adding each word of the EEPROM - * up to the checksum. Then calculates the EEPROM checksum and writes the - * value to the EEPROM. - **/ -static s32 e1000e_update_nvm_checksum_82571(struct e1000_hw *hw) -{ - u32 eecd; - s32 ret_val; - u16 i; - - ret_val = e1000e_update_nvm_checksum_generic(hw); - if (ret_val) - goto out; - - /* - * If our nvm is an EEPROM, then we're done - * otherwise, commit the checksum to the flash NVM. - */ - if (hw->nvm.type != e1000_nvm_flash_hw) - goto out; - - /* Check for pending operations. */ - for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); - if ((er32(EECD) & E1000_EECD_FLUPD) == 0) - break; - } - - if (i == E1000_FLASH_UPDATES) { - ret_val = -E1000_ERR_NVM; - goto out; - } - - /* Reset the firmware if using STM opcode. */ - if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) { - /* - * The enabling of and the actual reset must be done - * in two write cycles. - */ - ew32(HICR, E1000_HICR_FW_RESET_ENABLE); - e1e_flush(); - ew32(HICR, E1000_HICR_FW_RESET); - } - - /* Commit the write to flash */ - eecd = er32(EECD) | E1000_EECD_FLUPD; - ew32(EECD, eecd); - - for (i = 0; i < E1000_FLASH_UPDATES; i++) { - msleep(1); - if ((er32(EECD) & E1000_EECD_FLUPD) == 0) - break; - } - - if (i == E1000_FLASH_UPDATES) { - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_validate_nvm_checksum_82571 - Validate EEPROM checksum - * @hw: pointer to the HW structure - * - * Calculates the EEPROM checksum by reading/adding each word of the EEPROM - * and then verifies that the sum of the EEPROM is equal to 0xBABA. - **/ -static s32 e1000e_validate_nvm_checksum_82571(struct e1000_hw *hw) -{ - if (hw->nvm.type == e1000_nvm_flash_hw) - e1000e_fix_nvm_checksum_82571(hw); - - return e1000e_validate_nvm_checksum_generic(hw); -} - -/** - * e1000e_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon - * @hw: pointer to the HW structure - * @offset: offset within the EEPROM to be written to - * @words: number of words to write - * @data: 16 bit word(s) to be written to the EEPROM - * - * After checking for invalid values, poll the EEPROM to ensure the previous - * command has completed before trying to write the next word. After write - * poll for completion. - * - * If e1000e_update_nvm_checksum is not called after this function, the - * EEPROM will most likely contain an invalid checksum. - **/ -static s32 e1000e_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 i, eewr = 0; - s32 ret_val = 0; - - /* - * A check for invalid values: offset too large, too many words, - * and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - e_dbg("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - for (i = 0; i < words; i++) { - eewr = (data[i] << E1000_NVM_RW_REG_DATA) | - ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) | - E1000_NVM_RW_REG_START; - - ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); - if (ret_val) - break; - - ew32(EEWR, eewr); - - ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE); - if (ret_val) - break; - } - -out: - return ret_val; -} - -/** - * e1000e_get_cfg_done_82571 - Poll for configuration done - * @hw: pointer to the HW structure - * - * Reads the management control register for the config done bit to be set. - **/ -static s32 e1000e_get_cfg_done_82571(struct e1000_hw *hw) -{ - s32 timeout = PHY_CFG_TIMEOUT; - s32 ret_val = E1000_SUCCESS; - - while (timeout) { - if (er32(EEMNGCTL) & E1000_NVM_CFG_DONE_PORT_0) - break; - msleep(1); - timeout--; - } - if (!timeout) { - e_dbg("MNG configuration cycle has not completed.\n"); - ret_val = -E1000_ERR_RESET; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state - * @hw: pointer to the HW structure - * @active: true to enable LPLU, false to disable - * - * Sets the LPLU D0 state according to the active flag. When activating LPLU - * this function also disables smart speed and vice versa. LPLU will not be - * activated unless the device autonegotiation advertisement meets standards - * of either 10 or 10/100 or 10/100/1000 at all duplexes. This is a function - * pointer entry point only called by PHY setup routines. - **/ -static s32 e1000e_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 data; - - if (!(phy->ops.read_reg)) - goto out; - - ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data); - if (ret_val) - goto out; - - if (active) { - data |= IGP02E1000_PM_D0_LPLU; - ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, - &data); - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else { - data &= ~IGP02E1000_PM_D0_LPLU; - ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, - data); - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } - -out: - return ret_val; -} - -/** - * e1000e_reset_hw_82571 - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. - **/ -static s32 e1000e_reset_hw_82571(struct e1000_hw *hw) -{ - u32 ctrl, extcnf_ctrl, ctrl_ext; - s32 ret_val; - u16 i = 0; - - /* - * Prevent the PCI-E bus from sticking if there is no TLP connection - * on the last TLP read/write transaction when MAC is reset. - */ - ret_val = e1000e_disable_pcie_master(hw); - if (ret_val) - e_dbg("PCI-E Master disable polling has failed.\n"); - - e_dbg("Masking off all interrupts\n"); - ew32(IMC, 0xffffffff); - - ew32(RCTL, 0); - ew32(TCTL, E1000_TCTL_PSP); - e1e_flush(); - - msleep(10); - - /* - * Must acquire the MDIO ownership before MAC reset. - * Ownership defaults to firmware after a reset. - */ - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - extcnf_ctrl = er32(EXTCNF_CTRL); - extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; - - do { - ew32(EXTCNF_CTRL, extcnf_ctrl); - extcnf_ctrl = er32(EXTCNF_CTRL); - - if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP) - break; - - extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP; - - msleep(2); - i++; - } while (i < MDIO_OWNERSHIP_TIMEOUT); - break; - default: - break; - } - - ctrl = er32(CTRL); - - e_dbg("Issuing a global reset to MAC\n"); - ew32(CTRL, ctrl | E1000_CTRL_RST); - - if (hw->nvm.type == e1000_nvm_flash_hw) { - udelay(10); - ctrl_ext = er32(CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_EE_RST; - ew32(CTRL_EXT, ctrl_ext); - e1e_flush(); - } - - ret_val = e1000e_get_auto_rd_done(hw); - if (ret_val) - /* We don't want to continue accessing MAC registers. */ - goto out; - - /* - * Phy configuration from NVM just starts after EECD_AUTO_RD is set. - * Need to wait for Phy configuration completion before accessing - * NVM and Phy. - */ - - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - msleep(25); - break; - default: - break; - } - - /* Clear any pending interrupt events. */ - ew32(IMC, 0xffffffff); - er32(ICR); - - /* Install any alternate MAC address into RAR0 */ - ret_val = e1000e_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; - - e1000e_set_laa_state_82571(hw, true); - - /* Reinitialize the 82571 serdes link state machine */ - if (hw->phy.media_type == e1000_media_type_internal_serdes) - hw->mac.serdes_link_state = e1000_serdes_link_down; - -out: - return ret_val; -} - -/** - * e1000e_init_hw_82571 - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. - **/ -static s32 e1000e_init_hw_82571(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 reg_data; - s32 ret_val; - u16 i, rar_count = mac->rar_entry_count; - - e1000e_initialize_hw_bits_82571(hw); - - /* Initialize identification LED */ - ret_val = mac->ops.id_led_init(hw); - if (ret_val) { - e_dbg("Error initializing identification LED\n"); - /* This is not fatal and we should not stop init due to this */ - } - - /* Disabling VLAN filtering */ - e_dbg("Initializing the IEEE VLAN\n"); - e1000e_clear_vfta(hw); - - /* Setup the receive address. */ - /* - * If, however, a locally administered address was assigned to the - * 82571, we must reserve a RAR for it to work around an issue where - * resetting one port will reload the MAC on the other port. - */ - if (e1000e_get_laa_state_82571(hw)) - rar_count--; - e1000e_init_rx_addrs(hw, rar_count); - - /* Zero out the Multicast HASH table */ - e_dbg("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - - /* Setup link and flow control */ - ret_val = mac->ops.setup_link(hw); - - /* Set the transmit descriptor write-back policy */ - reg_data = er32(TXDCTL(0)); - reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB | - E1000_TXDCTL_COUNT_DESC; - ew32(TXDCTL(0), reg_data); - - /* ...for both queues. */ - switch (mac->type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: -#if 0 - e1000e_enable_tx_pkt_filtering(hw); -#endif - reg_data = er32(GCR); - reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX; - ew32(GCR, reg_data); - break; - default: - reg_data = er32(TXDCTL(1)); - reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB | - E1000_TXDCTL_COUNT_DESC; - ew32(TXDCTL(1), reg_data); - break; - } - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - e1000e_clear_hw_cntrs_82571(hw); - - return ret_val; -} - -/** - * e1000e_initialize_hw_bits_82571 - Initialize hardware-dependent bits - * @hw: pointer to the HW structure - * - * Initializes required hardware-dependent bits needed for normal operation. - **/ -static void e1000e_initialize_hw_bits_82571(struct e1000_hw *hw) -{ - u32 reg; - - /* Transmit Descriptor Control 0 */ - reg = er32(TXDCTL(0)); - reg |= (1 << 22); - ew32(TXDCTL(0), reg); - - /* Transmit Descriptor Control 1 */ - reg = er32(TXDCTL(1)); - reg |= (1 << 22); - ew32(TXDCTL(1), reg); - - /* Transmit Arbitration Control 0 */ - reg = er32(TARC(0)); - reg &= ~(0xF << 27); /* 30:27 */ - switch (hw->mac.type) { - case e1000_82571: - case e1000_82572: - reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26); - break; - default: - break; - } - ew32(TARC(0), reg); - - /* Transmit Arbitration Control 1 */ - reg = er32(TARC(1)); - switch (hw->mac.type) { - case e1000_82571: - case e1000_82572: - reg &= ~((1 << 29) | (1 << 30)); - reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26); - if (er32(TCTL) & E1000_TCTL_MULR) - reg &= ~(1 << 28); - else - reg |= (1 << 28); - ew32(TARC(1), reg); - break; - default: - break; - } - - /* Device Control */ - - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - reg = er32(CTRL); - reg &= ~(1 << 29); - ew32(CTRL, reg); - break; - default: - break; - } - - /* Extended Device Control */ - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - reg = er32(CTRL_EXT); - reg &= ~(1 << 23); - reg |= (1 << 22); - ew32(CTRL_EXT, reg); - break; - default: - break; - } - - - if (hw->mac.type == e1000_82571) { - reg = er32(PBA_ECC); - reg |= E1000_PBA_ECC_CORR_EN; - ew32(PBA_ECC, reg); - } - - /* - * Workaround for hardware errata. - * Ensure that DMA Dynamic Clock gating is disabled on 82571 and 82572 - */ - - if ((hw->mac.type == e1000_82571) || - (hw->mac.type == e1000_82572)) { - reg = er32(CTRL_EXT); - reg &= ~E1000_CTRL_EXT_DMA_DYN_CLK_EN; - ew32(CTRL_EXT, reg); - } - - /* PCI-Ex Control Registers */ - - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - reg = er32(GCR); - reg |= (1 << 22); - ew32(GCR, reg); - /* - * Workaround for hardware errata. - * apply workaround for hardware errata documented in errata - * docs Fixes issue where some error prone or unreliable PCIe - * completions are occurring, particularly with ASPM enabled. - * Without fix, issue can cause tx timeouts. - */ - reg = er32(GCR2); - reg |= 1; - ew32(GCR2, reg); - break; - default: - break; - } - return; -} - -/** - * e1000e_clear_vfta_82571 - Clear VLAN filter table - * @hw: pointer to the HW structure - * - * Clears the register array which contains the VLAN filter table by - * setting all the values to 0. - **/ -static void e1000e_clear_vfta_82571(struct e1000_hw *hw) -{ - u32 offset; - u32 vfta_value = 0; - u32 vfta_offset = 0; - u32 vfta_bit_in_reg = 0; - - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - if (hw->mng_cookie.vlan_id != 0) { - /* - *The VFTA is a 4096b bit-field, each identifying - *a single VLAN ID. The following operations - *determine which 32b entry (i.e. offset) into the - *array we want to set the VLAN ID (i.e. bit) of - *the manageability unit. - */ - vfta_offset = (hw->mng_cookie.vlan_id >> - E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK; - vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id & - E1000_VFTA_ENTRY_BIT_SHIFT_MASK); - } - - for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { - /* - *If the offset we want to clear is the same offset of - *the manageability VLAN ID, then clear all bits except - *that of the manageability unit - */ - vfta_value = (offset == vfta_offset) ? - vfta_bit_in_reg : 0; - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, - vfta_value); - e1e_flush(); - } - break; - default: - break; - } -} - -#if 0 -/** - * e1000e_check_mng_mode_82574 - Check manageability is enabled - * @hw: pointer to the HW structure - * - * Reads the NVM Initialization Control Word 2 and returns true - * (>0) if any manageability is enabled, else false (0). - **/ -static bool e1000e_check_mng_mode_82574(struct e1000_hw *hw) -{ - u16 data; - - e1000e_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data); - return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0; -} -#endif - -/** - * e1000e_led_on_82574 - Turn LED on - * @hw: pointer to the HW structure - * - * Turn LED on. - **/ -static s32 e1000e_led_on_82574(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl; - u32 i; - - ctrl = hw->mac.ledctl_mode2; - if (!(E1000_STATUS_LU & er32(STATUS))) { - /* - * If no link, then turn LED on by setting the invert bit - * for each LED that's "on" (0x0E) in ledctl_mode2. - */ - for (i = 0; i < 4; i++) - if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == - E1000_LEDCTL_MODE_LED_ON) - ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8)); - } - ew32(LEDCTL, ctrl); -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_setup_link_82571 - Setup flow control and link settings - * @hw: pointer to the HW structure - * - * Determines which flow control settings to use, then configures flow - * control. Calls the appropriate media-specific link configuration - * function. Assuming the adapter has a valid link partner, a valid link - * should be established. Assumes the hardware has previously been reset - * and the transmitter and receiver are not enabled. - **/ -static s32 e1000e_setup_link_82571(struct e1000_hw *hw) -{ - /* - * 82573 does not have a word in the NVM to determine - * the default flow control setting, so we explicitly - * set it to full. - */ - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - if (hw->fc.requested_mode == e1000_fc_default) - hw->fc.requested_mode = e1000_fc_full; - break; - default: - break; - } - return e1000e_setup_link(hw); -} - -/** - * e1000e_setup_copper_link_82571 - Configure copper link settings - * @hw: pointer to the HW structure - * - * Configures the link for auto-neg or forced speed and duplex. Then we check - * for link, once link is established calls to configure collision distance - * and flow control are called. - **/ -static s32 e1000e_setup_copper_link_82571(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_SLU; - ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - ew32(CTRL, ctrl); - - switch (hw->phy.type) { - case e1000_phy_m88: - case e1000_phy_bm: - ret_val = e1000e_copper_link_setup_m88(hw); - break; - case e1000_phy_igp_2: - ret_val = e1000e_copper_link_setup_igp(hw); - break; - default: - ret_val = -E1000_ERR_PHY; - break; - } - - if (ret_val) - goto out; - - ret_val = e1000e_setup_copper_link(hw); - -out: - return ret_val; -} - -/** - * e1000e_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes - * @hw: pointer to the HW structure - * - * Configures collision distance and flow control for fiber and serdes links. - * Upon successful setup, poll for link. - **/ -static s32 e1000e_setup_fiber_serdes_link_82571(struct e1000_hw *hw) -{ - switch (hw->mac.type) { - case e1000_82571: - case e1000_82572: - /* - * If SerDes loopback mode is entered, there is no form - * of reset to take the adapter out of that mode. So we - * have to explicitly take the adapter out of loopback - * mode. This prevents drivers from twiddling their thumbs - * if another tool failed to take it out of loopback mode. - */ - ew32(SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK); - break; - default: - break; - } - - return e1000e_setup_fiber_serdes_link(hw); -} - -/** - * e1000e_check_for_serdes_link_82571 - Check for link (Serdes) - * @hw: pointer to the HW structure - * - * Reports the link state as up or down. - * - * If autonegotiation is supported by the link partner, the link state is - * determined by the result of autongotiation. This is the most likely case. - * If autonegotiation is not supported by the link partner, and the link - * has a valid signal, force the link up. - * - * The link state is represented internally here by 4 states: - * - * 1) down - * 2) autoneg_progress - * 3) autoneg_complete (the link sucessfully autonegotiated) - * 4) forced_up (the link has been forced up, it did not autonegotiate) - * - **/ -s32 e1000e_check_for_serdes_link_82571(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw; - u32 ctrl; - u32 status; - s32 ret_val = E1000_SUCCESS; - - ctrl = er32(CTRL); - status = er32(STATUS); - rxcw = er32(RXCW); - - if ((rxcw & E1000_RXCW_SYNCH) && !(rxcw & E1000_RXCW_IV)) { - - /* Receiver is synchronized with no invalid bits. */ - switch (mac->serdes_link_state) { - case e1000_serdes_link_autoneg_complete: - if (!(status & E1000_STATUS_LU)) { - /* - * We have lost link, retry autoneg before - * reporting link failure - */ - mac->serdes_link_state = - e1000_serdes_link_autoneg_progress; - mac->serdes_has_link = false; - e_dbg("AN_UP -> AN_PROG\n"); - } - break; - - case e1000_serdes_link_forced_up: - /* - * If we are receiving /C/ ordered sets, re-enable - * auto-negotiation in the TXCW register and disable - * forced link in the Device Control register in an - * attempt to auto-negotiate with our link partner. - */ - if (rxcw & E1000_RXCW_C) { - /* Enable autoneg, and unforce link up */ - ew32(TXCW, mac->txcw); - ew32(CTRL, - (ctrl & ~E1000_CTRL_SLU)); - mac->serdes_link_state = - e1000_serdes_link_autoneg_progress; - mac->serdes_has_link = false; - e_dbg("FORCED_UP -> AN_PROG\n"); - } - break; - - case e1000_serdes_link_autoneg_progress: - if (rxcw & E1000_RXCW_C) { - /* We received /C/ ordered sets, meaning the - * link partner has autonegotiated, and we can - * trust the Link Up (LU) status bit - */ - if (status & E1000_STATUS_LU) { - mac->serdes_link_state = - e1000_serdes_link_autoneg_complete; - e_dbg("AN_PROG -> AN_UP\n"); - mac->serdes_has_link = true; - } else { - /* Autoneg completed, but failed */ - mac->serdes_link_state = - e1000_serdes_link_down; - e_dbg("AN_PROG -> DOWN\n"); - } - } else { - /* The link partner did not autoneg. - * Force link up and full duplex, and change - * state to forced. - */ - ew32(TXCW, - (mac->txcw & ~E1000_TXCW_ANE)); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - ew32(CTRL, ctrl); - - /* Configure Flow Control after link up. */ - ret_val = - e1000e_config_fc_after_link_up(hw); - if (ret_val) { - e_dbg("Error config flow control\n"); - break; - } - mac->serdes_link_state = - e1000_serdes_link_forced_up; - mac->serdes_has_link = true; - e_dbg("AN_PROG -> FORCED_UP\n"); - } - break; - - case e1000_serdes_link_down: - default: - /* The link was down but the receiver has now gained - * valid sync, so lets see if we can bring the link - * up. */ - ew32(TXCW, mac->txcw); - ew32(CTRL, - (ctrl & ~E1000_CTRL_SLU)); - mac->serdes_link_state = - e1000_serdes_link_autoneg_progress; - e_dbg("DOWN -> AN_PROG\n"); - break; - } - } else { - if (!(rxcw & E1000_RXCW_SYNCH)) { - mac->serdes_has_link = false; - mac->serdes_link_state = e1000_serdes_link_down; - e_dbg("ANYSTATE -> DOWN\n"); - } else { - /* - * We have sync, and can tolerate one - * invalid (IV) codeword before declaring - * link down, so reread to look again - */ - udelay(10); - rxcw = er32(RXCW); - if (rxcw & E1000_RXCW_IV) { - mac->serdes_link_state = e1000_serdes_link_down; - mac->serdes_has_link = false; - e_dbg("ANYSTATE -> DOWN\n"); - } - } - } - - return ret_val; -} - -/** - * e1000e_valid_led_default_82571 - Verify a valid default LED config - * @hw: pointer to the HW structure - * @data: pointer to the NVM (EEPROM) - * - * Read the EEPROM for the current default LED configuration. If the - * LED configuration is not valid, set to a valid LED configuration. - **/ -static s32 e1000e_valid_led_default_82571(struct e1000_hw *hw, u16 *data) -{ - s32 ret_val; - - ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - - switch (hw->mac.type) { - case e1000_82574: - case e1000_82583: - case e1000_82573: - if(*data == ID_LED_RESERVED_F746) - *data = ID_LED_DEFAULT_82573; - break; - default: - if (*data == ID_LED_RESERVED_0000 || - *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT; - break; - } - -out: - return ret_val; -} - -/** - * e1000e_get_laa_state_82571 - Get locally administered address state - * @hw: pointer to the HW structure - * - * Retrieve and return the current locally administered address state. - **/ -bool e1000e_get_laa_state_82571(struct e1000_hw *hw) -{ - if (hw->mac.type != e1000_82571) - return false; - - return hw->dev_spec._82571.laa_is_present; -} - -/** - * e1000e_set_laa_state_82571 - Set locally administered address state - * @hw: pointer to the HW structure - * @state: enable/disable locally administered address - * - * Enable/Disable the current locally administered address state. - **/ -void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state) -{ - if (hw->mac.type != e1000_82571) - return; - - hw->dev_spec._82571.laa_is_present = state; - - /* If workaround is activated... */ - if (state) - /* - * Hold a copy of the LAA in RAR[14] This is done so that - * between the time RAR[0] gets clobbered and the time it - * gets fixed, the actual LAA is in one of the RARs and no - * incoming packets directed to this port are dropped. - * Eventually the LAA will be in RAR[0] and RAR[14]. - */ - e1000e_rar_set(hw, hw->mac.addr, - hw->mac.rar_entry_count - 1); - return; -} - -/** - * e1000e_fix_nvm_checksum_82571 - Fix EEPROM checksum - * @hw: pointer to the HW structure - * - * Verifies that the EEPROM has completed the update. After updating the - * EEPROM, we need to check bit 15 in work 0x23 for the checksum fix. If - * the checksum fix is not implemented, we need to set the bit and update - * the checksum. Otherwise, if bit 15 is set and the checksum is incorrect, - * we need to return bad checksum. - **/ -static s32 e1000e_fix_nvm_checksum_82571(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - s32 ret_val = E1000_SUCCESS; - u16 data; - - if (nvm->type != e1000_nvm_flash_hw) - goto out; - - /* - * Check bit 4 of word 10h. If it is 0, firmware is done updating - * 10h-12h. Checksum may need to be fixed. - */ - ret_val = e1000e_read_nvm(hw, 0x10, 1, &data); - if (ret_val) - goto out; - - if (!(data & 0x10)) { - /* - * Read 0x23 and check bit 15. This bit is a 1 - * when the checksum has already been fixed. If - * the checksum is still wrong and this bit is a - * 1, we need to return bad checksum. Otherwise, - * we need to set this bit to a 1 and update the - * checksum. - */ - ret_val = e1000e_read_nvm(hw, 0x23, 1, &data); - if (ret_val) - goto out; - - if (!(data & 0x8000)) { - data |= 0x8000; - ret_val = e1000e_write_nvm(hw, 0x23, 1, &data); - if (ret_val) - goto out; - ret_val = e1000e_update_nvm_checksum(hw); - } - } - -out: - return ret_val; -} - -/** - * e1000e_read_mac_addr_82571 - Read device MAC address - * @hw: pointer to the HW structure - **/ -static s32 e1000e_read_mac_addr_82571(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - /* - * If there's an alternate MAC address place it in RAR0 - * so that it will override the Si installed default perm - * address. - */ - ret_val = e1000e_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; - - ret_val = e1000e_read_mac_addr_generic(hw); - -out: - return ret_val; -} - -/** - * e1000e_power_down_phy_copper_82571 - Remove link during PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, remove the link. - **/ -static void e1000e_power_down_phy_copper_82571(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - struct e1000_mac_info *mac = &hw->mac; - - if (!(phy->ops.check_reset_block)) - return; - - /* If the management interface is not enabled, then power down */ - if (!(mac->ops.check_mng_mode(hw) || e1000e_check_reset_block(hw))) - e1000e_power_down_phy_copper(hw); - - return; -} - -/** - * e1000e_clear_hw_cntrs_82571 - Clear device specific hardware counters - * @hw: pointer to the HW structure - * - * Clears the hardware counters by reading the counter registers. - **/ -static void e1000e_clear_hw_cntrs_82571(struct e1000_hw *hw __unused) -{ -#if 0 - e1000e_clear_hw_cntrs_base(hw); - - er32(PRC64); - er32(PRC127); - er32(PRC255); - er32(PRC511); - er32(PRC1023); - er32(PRC1522); - er32(PTC64); - er32(PTC127); - er32(PTC255); - er32(PTC511); - er32(PTC1023); - er32(PTC1522); - - er32(ALGNERRC); - er32(RXERRC); - er32(TNCRS); - er32(CEXTERR); - er32(TSCTC); - er32(TSCTFC); - - er32(MGTPRC); - er32(MGTPDC); - er32(MGTPTC); - - er32(IAC); - er32(ICRXOC); - - er32(ICRXPTC); - er32(ICRXATC); - er32(ICTXPTC); - er32(ICTXATC); - er32(ICTXQEC); - er32(ICTXQMTC); - er32(ICRXDMTC); -#endif -} - -static struct pci_device_id e1000e_82571_nics[] = { - PCI_ROM(0x8086, 0x105E, "E1000_DEV_ID_82571EB_COPPER", "E1000_DEV_ID_82571EB_COPPER", board_82571), - PCI_ROM(0x8086, 0x105F, "E1000_DEV_ID_82571EB_FIBER", "E1000_DEV_ID_82571EB_FIBER", board_82571), - PCI_ROM(0x8086, 0x10A4, "E1000_DEV_ID_82571EB_QUAD_COPPER", "E1000_DEV_ID_82571EB_QUAD_COPPER", board_82571), - PCI_ROM(0x8086, 0x10BC, "E1000_DEV_ID_82571EB_QUAD_COPPER_LP", "E1000_DEV_ID_82571EB_QUAD_COPPER_LP", board_82571), - PCI_ROM(0x8086, 0x10A5, "E1000_DEV_ID_82571EB_QUAD_FIBER", "E1000_DEV_ID_82571EB_QUAD_FIBER", board_82571), - PCI_ROM(0x8086, 0x1060, "E1000_DEV_ID_82571EB_SERDES", "E1000_DEV_ID_82571EB_SERDES", board_82571), - PCI_ROM(0x8086, 0x10D9, "E1000_DEV_ID_82571EB_SERDES_DUAL", "E1000_DEV_ID_82571EB_SERDES_DUAL", board_82571), - PCI_ROM(0x8086, 0x10DA, "E1000_DEV_ID_82571EB_SERDES_QUAD", "E1000_DEV_ID_82571EB_SERDES_QUAD", board_82571), - PCI_ROM(0x8086, 0x10D5, "E1000_DEV_ID_82571PT_QUAD_COPPER", "E1000_DEV_ID_82571PT_QUAD_COPPER", board_82571), - PCI_ROM(0x8086, 0x10B9, "E1000_DEV_ID_82572EI", "E1000_DEV_ID_82572EI", board_82572), - PCI_ROM(0x8086, 0x107D, "E1000_DEV_ID_82572EI_COPPER", "E1000_DEV_ID_82572EI_COPPER", board_82572), - PCI_ROM(0x8086, 0x107E, "E1000_DEV_ID_82572EI_FIBER", "E1000_DEV_ID_82572EI_FIBER", board_82572), - PCI_ROM(0x8086, 0x107F, "E1000_DEV_ID_82572EI_SERDES", "E1000_DEV_ID_82572EI_SERDES", board_82572), - PCI_ROM(0x8086, 0x108B, "E1000_DEV_ID_82573E", "E1000_DEV_ID_82573E", board_82573), - PCI_ROM(0x8086, 0x108C, "E1000_DEV_ID_82573E_IAMT", "E1000_DEV_ID_82573E_IAMT", board_82573), - PCI_ROM(0x8086, 0x109A, "E1000_DEV_ID_82573L", "E1000_DEV_ID_82573L", board_82573), - PCI_ROM(0x8086, 0x10D3, "E1000_DEV_ID_82574L", "E1000_DEV_ID_82574L", board_82574), - PCI_ROM(0x8086, 0x10F6, "E1000_DEV_ID_82574LA", "E1000_DEV_ID_82574LA", board_82574), - PCI_ROM(0x8086, 0x150C, "E1000_DEV_ID_82583V", "E1000_DEV_ID_82583V", board_82583), -}; - -struct pci_driver e1000e_82571_driver __pci_driver = { - .ids = e1000e_82571_nics, - .id_count = (sizeof (e1000e_82571_nics) / sizeof (e1000e_82571_nics[0])), - .probe = e1000e_probe, - .remove = e1000e_remove, -}; diff --git a/src/drivers/net/e1000e/e1000e_82571.h b/src/drivers/net/e1000e/e1000e_82571.h deleted file mode 100644 index c645e25a..00000000 --- a/src/drivers/net/e1000e/e1000e_82571.h +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_82571_H_ -#define _E1000E_82571_H_ - -#define ID_LED_RESERVED_F746 0xF746 -#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \ - (ID_LED_OFF1_ON2 << 8) | \ - (ID_LED_DEF1_DEF2 << 4) | \ - (ID_LED_DEF1_DEF2)) - -#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 - -/* Intr Throttling - RW */ -#define E1000_EITR_82574(_n) (0x000E8 + (0x4 * (_n))) - -#define E1000_EIAC_82574 0x000DC /* Ext. Interrupt Auto Clear - RW */ -#define E1000_EIAC_MASK_82574 0x01F00000 - -#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */ - -#define E1000_RXCFGL 0x0B634 /* TimeSync Rx EtherType & Msg Type Reg - RW */ - -bool e1000e_get_laa_state_82571(struct e1000_hw *hw); -void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state); - -#endif diff --git a/src/drivers/net/e1000e/e1000e_defines.h b/src/drivers/net/e1000e/e1000e_defines.h deleted file mode 100644 index 8cfc6ed8..00000000 --- a/src/drivers/net/e1000e/e1000e_defines.h +++ /dev/null @@ -1,1471 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_DEFINES_H_ -#define _E1000E_DEFINES_H_ - -/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ -#define REQ_TX_DESCRIPTOR_MULTIPLE 8 -#define REQ_RX_DESCRIPTOR_MULTIPLE 8 - -/* Definitions for power management and wakeup registers */ -/* Wake Up Control */ -#define E1000_WUC_APME 0x00000001 /* APM Enable */ -#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ -#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ -#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ -#define E1000_WUC_LSCWE 0x00000010 /* Link Status wake up enable */ -#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */ -#define E1000_WUC_SPM 0x80000000 /* Enable SPM */ -#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ - -/* Wake Up Filter Control */ -#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ -#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ -#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ -#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ -#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ -#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ -#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ -#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ -#define E1000_WUFC_IGNORE_TCO_PHY 0x00000800 /* Ignore WakeOn TCO packets */ -#define E1000_WUFC_FLX0_PHY 0x00001000 /* Flexible Filter 0 Enable */ -#define E1000_WUFC_FLX1_PHY 0x00002000 /* Flexible Filter 1 Enable */ -#define E1000_WUFC_FLX2_PHY 0x00004000 /* Flexible Filter 2 Enable */ -#define E1000_WUFC_FLX3_PHY 0x00008000 /* Flexible Filter 3 Enable */ -#define E1000_WUFC_FLX4_PHY 0x00000200 /* Flexible Filter 4 Enable */ -#define E1000_WUFC_FLX5_PHY 0x00000400 /* Flexible Filter 5 Enable */ -#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */ -#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ -#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ -#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ -#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ -#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */ -#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */ -#define E1000_WUFC_ALL_FILTERS_PHY_4 0x0000F0FF /*Mask for all wakeup filters*/ -#define E1000_WUFC_FLX_OFFSET_PHY 12 /* Offset to the Flexible Filters bits */ -#define E1000_WUFC_FLX_FILTERS_PHY_4 0x0000F000 /*Mask for 4 flexible filters*/ -#define E1000_WUFC_ALL_FILTERS_PHY_6 0x0000F6FF /*Mask for 6 wakeup filters */ -#define E1000_WUFC_FLX_FILTERS_PHY_6 0x0000F600 /*Mask for 6 flexible filters*/ -#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ -#define E1000_WUFC_ALL_FILTERS_6 0x003F00FF /* Mask for all 6 wakeup filters*/ -#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ -#define E1000_WUFC_FLX_FILTERS 0x000F0000 /*Mask for the 4 flexible filters */ -#define E1000_WUFC_FLX_FILTERS_6 0x003F0000 /* Mask for 6 flexible filters */ - -/* Wake Up Status */ -#define E1000_WUS_LNKC E1000_WUFC_LNKC -#define E1000_WUS_MAG E1000_WUFC_MAG -#define E1000_WUS_EX E1000_WUFC_EX -#define E1000_WUS_MC E1000_WUFC_MC -#define E1000_WUS_BC E1000_WUFC_BC -#define E1000_WUS_ARP E1000_WUFC_ARP -#define E1000_WUS_IPV4 E1000_WUFC_IPV4 -#define E1000_WUS_IPV6 E1000_WUFC_IPV6 -#define E1000_WUS_FLX0_PHY E1000_WUFC_FLX0_PHY -#define E1000_WUS_FLX1_PHY E1000_WUFC_FLX1_PHY -#define E1000_WUS_FLX2_PHY E1000_WUFC_FLX2_PHY -#define E1000_WUS_FLX3_PHY E1000_WUFC_FLX3_PHY -#define E1000_WUS_FLX_FILTERS_PHY_4 E1000_WUFC_FLX_FILTERS_PHY_4 -#define E1000_WUS_FLX0 E1000_WUFC_FLX0 -#define E1000_WUS_FLX1 E1000_WUFC_FLX1 -#define E1000_WUS_FLX2 E1000_WUFC_FLX2 -#define E1000_WUS_FLX3 E1000_WUFC_FLX3 -#define E1000_WUS_FLX4 E1000_WUFC_FLX4 -#define E1000_WUS_FLX5 E1000_WUFC_FLX5 -#define E1000_WUS_FLX4_PHY E1000_WUFC_FLX4_PHY -#define E1000_WUS_FLX5_PHY E1000_WUFC_FLX5_PHY -#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS -#define E1000_WUS_FLX_FILTERS_6 E1000_WUFC_FLX_FILTERS_6 -#define E1000_WUS_FLX_FILTERS_PHY_6 E1000_WUFC_FLX_FILTERS_PHY_6 - -/* Wake Up Packet Length */ -#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ - -/* Four Flexible Filters are supported */ -#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 -/* Six Flexible Filters are supported */ -#define E1000_FLEXIBLE_FILTER_COUNT_MAX_6 6 - -/* Each Flexible Filter is at most 128 (0x80) bytes in length */ -#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 - -#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX -#define E1000_FFLT_SIZE_6 E1000_FLEXIBLE_FILTER_COUNT_MAX_6 -#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX -#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX - -/* Extended Device Control */ -#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ -#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ -#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN -#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ -#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ -/* Reserved (bits 4,5) in >= 82575 */ -#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */ -#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */ -#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA -#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */ -#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */ -/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */ -#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ -#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ -#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ -#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* Direction of SDP3 0=in 1=out */ -#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ -#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ -#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ -#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ -#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ -#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */ -#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 -#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 -#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000 -#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000 -#define E1000_CTRL_EXT_EIAME 0x01000000 -#define E1000_CTRL_EXT_IRCA 0x00000001 -#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 -#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 -#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 -#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 -#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 -#define E1000_CTRL_EXT_CANC 0x04000000 /* Int delay cancellation */ -#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ -/* IAME enable bit (27) was removed in >= 82575 */ -#define E1000_CTRL_EXT_IAME 0x08000000 /* Int acknowledge Auto-mask */ -#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error - * detection enabled */ -#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity - * error detection enable */ -#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 -#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ -#define E1000_CTRL_EXT_LSECCK 0x00001000 -#define E1000_CTRL_EXT_PHYPDEN 0x00100000 -#define E1000_I2CCMD_REG_ADDR_SHIFT 16 -#define E1000_I2CCMD_REG_ADDR 0x00FF0000 -#define E1000_I2CCMD_PHY_ADDR_SHIFT 24 -#define E1000_I2CCMD_PHY_ADDR 0x07000000 -#define E1000_I2CCMD_OPCODE_READ 0x08000000 -#define E1000_I2CCMD_OPCODE_WRITE 0x00000000 -#define E1000_I2CCMD_RESET 0x10000000 -#define E1000_I2CCMD_READY 0x20000000 -#define E1000_I2CCMD_INTERRUPT_ENA 0x40000000 -#define E1000_I2CCMD_ERROR 0x80000000 -#define E1000_MAX_SGMII_PHY_REG_ADDR 255 -#define E1000_I2CCMD_PHY_TIMEOUT 200 - -/* Receive Descriptor bit definitions */ -#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ -#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ -#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ -#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ -#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ -#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ -#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ -#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ -#define E1000_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ -#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ -#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ -#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ -#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ -#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ -#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ -#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ -#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ -#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ -#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ -#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ -#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ -#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ -#define E1000_RXD_SPC_PRI_SHIFT 13 -#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ -#define E1000_RXD_SPC_CFI_SHIFT 12 - -#define E1000_RXDEXT_STATERR_CE 0x01000000 -#define E1000_RXDEXT_STATERR_SE 0x02000000 -#define E1000_RXDEXT_STATERR_SEQ 0x04000000 -#define E1000_RXDEXT_STATERR_CXE 0x10000000 -#define E1000_RXDEXT_STATERR_TCPE 0x20000000 -#define E1000_RXDEXT_STATERR_IPE 0x40000000 -#define E1000_RXDEXT_STATERR_RXE 0x80000000 - -#define E1000_RXDEXT_LSECH 0x01000000 -#define E1000_RXDEXT_LSECE_MASK 0x60000000 -#define E1000_RXDEXT_LSECE_NO_ERROR 0x00000000 -#define E1000_RXDEXT_LSECE_NO_SA_MATCH 0x20000000 -#define E1000_RXDEXT_LSECE_REPLAY_DETECT 0x40000000 -#define E1000_RXDEXT_LSECE_BAD_SIG 0x60000000 - -/* mask to determine if packets should be dropped due to frame errors */ -#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ - E1000_RXD_ERR_CE | \ - E1000_RXD_ERR_SE | \ - E1000_RXD_ERR_SEQ | \ - E1000_RXD_ERR_CXE | \ - E1000_RXD_ERR_RXE) - -/* Same mask, but for extended and packet split descriptors */ -#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ - E1000_RXDEXT_STATERR_CE | \ - E1000_RXDEXT_STATERR_SE | \ - E1000_RXDEXT_STATERR_SEQ | \ - E1000_RXDEXT_STATERR_CXE | \ - E1000_RXDEXT_STATERR_RXE) - -#define E1000_MRQC_ENABLE_MASK 0x00000007 -#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 -#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 -#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 -#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 -#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 -#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 -#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 -#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 -#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 - -#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 -#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF - -/* Management Control */ -#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ -#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ -#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ -#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ -#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ -#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ -#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ -#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ -#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ -/* Enable Neighbor Discovery Filtering */ -#define E1000_MANC_NEIGHBOR_EN 0x00004000 -#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ -#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ -#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ -#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ -#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ -#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ -/* Enable MAC address filtering */ -#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 -/* Enable MNG packets to host memory */ -#define E1000_MANC_EN_MNG2HOST 0x00200000 -/* Enable IP address filtering */ -#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 -#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ -#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ -#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ -#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ -#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ -#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ -#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ -#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ - -#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ -#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ - -/* Receive Control */ -#define E1000_RCTL_RST 0x00000001 /* Software reset */ -#define E1000_RCTL_EN 0x00000002 /* enable */ -#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ -#define E1000_RCTL_UPE 0x00000008 /* unicast promisc enable */ -#define E1000_RCTL_MPE 0x00000010 /* multicast promisc enable */ -#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ -#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ -#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ -#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ -#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ -#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ -#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ -#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min thresh size */ -#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min thresh size */ -#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min thresh size */ -#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ -#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ -#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ -#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ -#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ -#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ -#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ -#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ -#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ -#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ -#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ -#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ -#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ -#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ -#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ -#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ -#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ -#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ -#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ -#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ -#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ -#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ -#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ - -/* - * Use byte values for the following shift parameters - * Usage: - * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & - * E1000_PSRCTL_BSIZE0_MASK) | - * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & - * E1000_PSRCTL_BSIZE1_MASK) | - * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & - * E1000_PSRCTL_BSIZE2_MASK) | - * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; - * E1000_PSRCTL_BSIZE3_MASK)) - * where value0 = [128..16256], default=256 - * value1 = [1024..64512], default=4096 - * value2 = [0..64512], default=4096 - * value3 = [0..64512], default=0 - */ - -#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F -#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 -#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 -#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 - -#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ -#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ -#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ -#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ - -/* SWFW_SYNC Definitions */ -#define E1000_SWFW_EEP_SM 0x01 -#define E1000_SWFW_PHY0_SM 0x02 -#define E1000_SWFW_PHY1_SM 0x04 -#define E1000_SWFW_CSR_SM 0x08 - -/* FACTPS Definitions */ -#define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */ -/* Device Control */ -#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ -#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ -#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ -#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */ -#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ -#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ -#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ -#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ -#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ -#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ -#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ -#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ -#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ -#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ -#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ -#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ -#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ -#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ -#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock - * indication in SDP[0] */ -#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through - * PHYRST_N pin */ -#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external - * LINK_0 and LINK_1 pins */ -#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ -#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ -#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ -#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ -#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ -#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ -#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ -#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ -#define E1000_CTRL_RST 0x04000000 /* Global reset */ -#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ -#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ -#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ -#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ -#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ -#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */ -#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */ - -/* - * Bit definitions for the Management Data IO (MDIO) and Management Data - * Clock (MDC) pins in the Device Control Register. - */ -#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 -#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 -#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 -#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 -#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 -#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 -#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR -#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA - -#define E1000_CONNSW_ENRGSRC 0x4 -#define E1000_PCS_CFG_PCS_EN 8 -#define E1000_PCS_LCTL_FLV_LINK_UP 1 -#define E1000_PCS_LCTL_FSV_10 0 -#define E1000_PCS_LCTL_FSV_100 2 -#define E1000_PCS_LCTL_FSV_1000 4 -#define E1000_PCS_LCTL_FDV_FULL 8 -#define E1000_PCS_LCTL_FSD 0x10 -#define E1000_PCS_LCTL_FORCE_LINK 0x20 -#define E1000_PCS_LCTL_LOW_LINK_LATCH 0x40 -#define E1000_PCS_LCTL_FORCE_FCTRL 0x80 -#define E1000_PCS_LCTL_AN_ENABLE 0x10000 -#define E1000_PCS_LCTL_AN_RESTART 0x20000 -#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000 -#define E1000_PCS_LCTL_AN_SGMII_BYPASS 0x80000 -#define E1000_PCS_LCTL_AN_SGMII_TRIGGER 0x100000 -#define E1000_PCS_LCTL_FAST_LINK_TIMER 0x1000000 -#define E1000_PCS_LCTL_LINK_OK_FIX 0x2000000 -#define E1000_PCS_LCTL_CRS_ON_NI 0x4000000 -#define E1000_ENABLE_SERDES_LOOPBACK 0x0410 - -#define E1000_PCS_LSTS_LINK_OK 1 -#define E1000_PCS_LSTS_SPEED_10 0 -#define E1000_PCS_LSTS_SPEED_100 2 -#define E1000_PCS_LSTS_SPEED_1000 4 -#define E1000_PCS_LSTS_DUPLEX_FULL 8 -#define E1000_PCS_LSTS_SYNK_OK 0x10 -#define E1000_PCS_LSTS_AN_COMPLETE 0x10000 -#define E1000_PCS_LSTS_AN_PAGE_RX 0x20000 -#define E1000_PCS_LSTS_AN_TIMED_OUT 0x40000 -#define E1000_PCS_LSTS_AN_REMOTE_FAULT 0x80000 -#define E1000_PCS_LSTS_AN_ERROR_RWS 0x100000 - -/* Device Status */ -#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ -#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ -#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ -#define E1000_STATUS_FUNC_SHIFT 2 -#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ -#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ -#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ -#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ -#define E1000_STATUS_SPEED_MASK 0x000000C0 -#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ -#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ -#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ -#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ -#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ -#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */ -#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. - * Clear on write '0'. */ -#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */ -#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ -#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ -#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ -#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ -#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ -#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ -#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ -#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ -#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ -#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution - * disabled */ -#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ -#define E1000_STATUS_FUSE_8 0x04000000 -#define E1000_STATUS_FUSE_9 0x08000000 -#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ -#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ - -/* Constants used to interpret the masked PCI-X bus speed. */ -#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ -#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ -#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/ - -#define SPEED_10 10 -#define SPEED_100 100 -#define SPEED_1000 1000 -#define HALF_DUPLEX 1 -#define FULL_DUPLEX 2 - -#define PHY_FORCE_TIME 20 - -#define ADVERTISE_10_HALF 0x0001 -#define ADVERTISE_10_FULL 0x0002 -#define ADVERTISE_100_HALF 0x0004 -#define ADVERTISE_100_FULL 0x0008 -#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ -#define ADVERTISE_1000_FULL 0x0020 - -/* 1000/H is not supported, nor spec-compliant. */ -#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ - ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ - ADVERTISE_1000_FULL) -#define E1000_ALL_NOT_GIG (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ - ADVERTISE_100_HALF | ADVERTISE_100_FULL) -#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) -#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) -#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \ - ADVERTISE_1000_FULL) -#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) - -#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX - -/* LED Control */ -#define E1000_PHY_LED0_MODE_MASK 0x00000007 -#define E1000_PHY_LED0_IVRT 0x00000008 -#define E1000_PHY_LED0_BLINK 0x00000010 -#define E1000_PHY_LED0_MASK 0x0000001F - -#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F -#define E1000_LEDCTL_LED0_MODE_SHIFT 0 -#define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020 -#define E1000_LEDCTL_LED0_IVRT 0x00000040 -#define E1000_LEDCTL_LED0_BLINK 0x00000080 -#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 -#define E1000_LEDCTL_LED1_MODE_SHIFT 8 -#define E1000_LEDCTL_LED1_BLINK_RATE 0x00002000 -#define E1000_LEDCTL_LED1_IVRT 0x00004000 -#define E1000_LEDCTL_LED1_BLINK 0x00008000 -#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 -#define E1000_LEDCTL_LED2_MODE_SHIFT 16 -#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000 -#define E1000_LEDCTL_LED2_IVRT 0x00400000 -#define E1000_LEDCTL_LED2_BLINK 0x00800000 -#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 -#define E1000_LEDCTL_LED3_MODE_SHIFT 24 -#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 -#define E1000_LEDCTL_LED3_IVRT 0x40000000 -#define E1000_LEDCTL_LED3_BLINK 0x80000000 - -#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 -#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 -#define E1000_LEDCTL_MODE_LINK_UP 0x2 -#define E1000_LEDCTL_MODE_ACTIVITY 0x3 -#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 -#define E1000_LEDCTL_MODE_LINK_10 0x5 -#define E1000_LEDCTL_MODE_LINK_100 0x6 -#define E1000_LEDCTL_MODE_LINK_1000 0x7 -#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 -#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 -#define E1000_LEDCTL_MODE_COLLISION 0xA -#define E1000_LEDCTL_MODE_BUS_SPEED 0xB -#define E1000_LEDCTL_MODE_BUS_SIZE 0xC -#define E1000_LEDCTL_MODE_PAUSED 0xD -#define E1000_LEDCTL_MODE_LED_ON 0xE -#define E1000_LEDCTL_MODE_LED_OFF 0xF - -/* Transmit Descriptor bit definitions */ -#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ -#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ -#define E1000_TXD_POPTS_SHIFT 8 /* POPTS shift */ -#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ -#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ -#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ -#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ -#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ -#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ -#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ -#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ -#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ -#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ -#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ -#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ -#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ -#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ -#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ -#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ -#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ -#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ -/* Extended desc bits for Linksec and timesync */ -#define E1000_TXD_CMD_LINKSEC 0x10000000 /* Apply LinkSec on packet */ -#define E1000_TXD_EXTCMD_TSTAMP 0x00000010 /* IEEE1588 Timestamp packet */ - -/* Transmit Control */ -#define E1000_TCTL_RST 0x00000001 /* software reset */ -#define E1000_TCTL_EN 0x00000002 /* enable tx */ -#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ -#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ -#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ -#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ -#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ -#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ -#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ -#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ -#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ - -/* Transmit Arbitration Count */ -#define E1000_TARC0_ENABLE 0x00000400 /* Enable Tx Queue 0 */ - -/* SerDes Control */ -#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 - -/* Receive Checksum Control */ -#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ -#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ -#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ -#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ -#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ -#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ -#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ - -/* Header split receive */ -#define E1000_RFCTL_ISCSI_DIS 0x00000001 -#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E -#define E1000_RFCTL_ISCSI_DWC_SHIFT 1 -#define E1000_RFCTL_NFSW_DIS 0x00000040 -#define E1000_RFCTL_NFSR_DIS 0x00000080 -#define E1000_RFCTL_NFS_VER_MASK 0x00000300 -#define E1000_RFCTL_NFS_VER_SHIFT 8 -#define E1000_RFCTL_IPV6_DIS 0x00000400 -#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800 -#define E1000_RFCTL_ACK_DIS 0x00001000 -#define E1000_RFCTL_ACKD_DIS 0x00002000 -#define E1000_RFCTL_IPFRSP_DIS 0x00004000 -#define E1000_RFCTL_EXTEN 0x00008000 -#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 -#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 -#define E1000_RFCTL_LEF 0x00040000 - -/* Collision related configuration parameters */ -#define E1000_COLLISION_THRESHOLD 15 -#define E1000_CT_SHIFT 4 -#define E1000_COLLISION_DISTANCE 63 -#define E1000_COLD_SHIFT 12 - -/* Default values for the transmit IPG register */ -#define DEFAULT_82543_TIPG_IPGT_FIBER 9 -#define DEFAULT_82543_TIPG_IPGT_COPPER 8 - -#define E1000_TIPG_IPGT_MASK 0x000003FF -#define E1000_TIPG_IPGR1_MASK 0x000FFC00 -#define E1000_TIPG_IPGR2_MASK 0x3FF00000 - -#define DEFAULT_82543_TIPG_IPGR1 8 -#define E1000_TIPG_IPGR1_SHIFT 10 - -#define DEFAULT_82543_TIPG_IPGR2 6 -#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 -#define E1000_TIPG_IPGR2_SHIFT 20 - -/* Ethertype field values */ -#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ - -#define ETHERNET_FCS_SIZE 4 -#define MAX_JUMBO_FRAME_SIZE 0x3F00 - -/* Extended Configuration Control and Size */ -#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 -#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 -#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008 -#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 -#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080 -#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 -#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 - -#define E1000_PHY_CTRL_SPD_EN 0x00000001 -#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 -#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 -#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 -#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 - -#define E1000_KABGTXD_BGSQLBIAS 0x00050000 - -/* PBA constants */ -#define E1000_PBA_6K 0x0006 /* 6KB */ -#define E1000_PBA_8K 0x0008 /* 8KB */ -#define E1000_PBA_10K 0x000A /* 10KB */ -#define E1000_PBA_12K 0x000C /* 12KB */ -#define E1000_PBA_14K 0x000E /* 14KB */ -#define E1000_PBA_16K 0x0010 /* 16KB */ -#define E1000_PBA_18K 0x0012 -#define E1000_PBA_20K 0x0014 -#define E1000_PBA_22K 0x0016 -#define E1000_PBA_24K 0x0018 -#define E1000_PBA_26K 0x001A -#define E1000_PBA_30K 0x001E -#define E1000_PBA_32K 0x0020 -#define E1000_PBA_34K 0x0022 -#define E1000_PBA_35K 0x0023 -#define E1000_PBA_38K 0x0026 -#define E1000_PBA_40K 0x0028 -#define E1000_PBA_48K 0x0030 /* 48KB */ -#define E1000_PBA_64K 0x0040 /* 64KB */ - -#define E1000_PBS_16K E1000_PBA_16K -#define E1000_PBS_24K E1000_PBA_24K - -#define IFS_MAX 80 -#define IFS_MIN 40 -#define IFS_RATIO 4 -#define IFS_STEP 10 -#define MIN_NUM_XMITS 1000 - -/* SW Semaphore Register */ -#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ -#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ -#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ -#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ - -#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ - -/* Interrupt Cause Read */ -#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ -#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ -#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ -#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ -#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ -#define E1000_ICR_RXO 0x00000040 /* rx overrun */ -#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ -#define E1000_ICR_VMMB 0x00000100 /* VM MB event */ -#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ -#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */ -#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ -#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ -#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ -#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ -#define E1000_ICR_TXD_LOW 0x00008000 -#define E1000_ICR_SRPD 0x00010000 -#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ -#define E1000_ICR_MNG 0x00040000 /* Manageability event */ -#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ -#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver - * should claim the interrupt */ -#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */ -#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */ -#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ -#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */ -#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ -#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW - * bit in the FWSM */ -#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates - * an interrupt */ -#define E1000_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */ -#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */ -#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */ -#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */ -#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */ -#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ -#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ - -/* PBA ECC Register */ -#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ -#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */ -#define E1000_PBA_ECC_CORR_EN 0x00000001 /* Enable ECC error correction */ -#define E1000_PBA_ECC_STAT_CLR 0x00000002 /* Clear ECC error counter */ -#define E1000_PBA_ECC_INT_EN 0x00000004 /* Enable ICR bit 5 on ECC error */ - -/* - * This defines the bits that are set in the Interrupt Mask - * Set/Read Register. Each bit is documented below: - * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error - */ -#define POLL_IMS_ENABLE_MASK ( \ - E1000_IMS_RXDMT0 | \ - E1000_IMS_RXSEQ) - -/* - * This defines the bits that are set in the Interrupt Mask - * Set/Read Register. Each bit is documented below: - * o RXT0 = Receiver Timer Interrupt (ring 0) - * o TXDW = Transmit Descriptor Written Back - * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error - * o LSC = Link Status Change - */ -#define IMS_ENABLE_MASK ( \ - E1000_IMS_RXT0 | \ - E1000_IMS_TXDW | \ - E1000_IMS_RXDMT0 | \ - E1000_IMS_RXSEQ | \ - E1000_IMS_LSC) - -/* Interrupt Mask Set */ -#define E1000_IMS_TXDW E1000_ICR_TXDW /* Tx desc written back */ -#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */ -#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ -#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_IMS_SRPD E1000_ICR_SRPD -#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO - * parity error */ -#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO - * parity error */ -#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer - * parity error */ -#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity - * error */ -#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO - * parity error */ -#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO - * parity error */ -#define E1000_IMS_DSW E1000_ICR_DSW -#define E1000_IMS_PHYINT E1000_ICR_PHYINT -#define E1000_IMS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */ -#define E1000_IMS_EPRST E1000_ICR_EPRST -#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */ -#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */ -#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */ -#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */ -#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */ - -/* Interrupt Cause Set */ -#define E1000_ICS_TXDW E1000_ICR_TXDW /* Tx desc written back */ -#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ -#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_ICS_SRPD E1000_ICR_SRPD -#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO - * parity error */ -#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO - * parity error */ -#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer - * parity error */ -#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity - * error */ -#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO - * parity error */ -#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO - * parity error */ -#define E1000_ICS_DSW E1000_ICR_DSW -#define E1000_ICS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */ -#define E1000_ICS_PHYINT E1000_ICR_PHYINT -#define E1000_ICS_EPRST E1000_ICR_EPRST - -/* Transmit Descriptor Control */ -#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ -#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */ -#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ -#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ -#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ -#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ -#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */ -/* Enable the counting of descriptors still to be processed. */ -#define E1000_TXDCTL_COUNT_DESC 0x00400000 - -/* Flow Control Constants */ -#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 -#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 -#define FLOW_CONTROL_TYPE 0x8808 - -/* 802.1q VLAN Packet Size */ -#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */ -#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ - -/* Receive Address */ -/* - * Number of high/low register pairs in the RAR. The RAR (Receive Address - * Registers) holds the directed and multicast addresses that we monitor. - * Technically, we have 16 spots. However, we reserve one of these spots - * (RAR[15]) for our directed address used by controllers with - * manageability enabled, allowing us room for 15 multicast addresses. - */ -#define E1000_RAR_ENTRIES 15 -#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ -#define E1000_RAL_MAC_ADDR_LEN 4 -#define E1000_RAH_MAC_ADDR_LEN 2 -#define E1000_RAH_POOL_MASK 0x03FC0000 -#define E1000_RAH_POOL_1 0x00040000 - -/* Error Codes */ -#define E1000_SUCCESS 0 -#define E1000_ERR_NVM 1 -#define E1000_ERR_PHY 2 -#define E1000_ERR_CONFIG 3 -#define E1000_ERR_PARAM 4 -#define E1000_ERR_MAC_INIT 5 -#define E1000_ERR_PHY_TYPE 6 -#define E1000_ERR_RESET 9 -#define E1000_ERR_MASTER_REQUESTS_PENDING 10 -#define E1000_ERR_HOST_INTERFACE_COMMAND 11 -#define E1000_BLK_PHY_RESET 12 -#define E1000_ERR_SWFW_SYNC 13 -#define E1000_NOT_IMPLEMENTED 14 -#define E1000_ERR_MBX 15 - -/* Loop limit on how long we wait for auto-negotiation to complete */ -#define FIBER_LINK_UP_LIMIT 50 -#define COPPER_LINK_UP_LIMIT 10 -#define PHY_AUTO_NEG_LIMIT 45 -#define PHY_FORCE_LIMIT 20 -/* Number of 100 microseconds we wait for PCI Express master disable */ -#define MASTER_DISABLE_TIMEOUT 800 -/* Number of milliseconds we wait for PHY configuration done after MAC reset */ -#define PHY_CFG_TIMEOUT 100 -/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ -#define MDIO_OWNERSHIP_TIMEOUT 10 -/* Number of milliseconds for NVM auto read done after MAC reset. */ -#define AUTO_READ_DONE_TIMEOUT 10 - -/* Flow Control */ -#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ -#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ -#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ -#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ - -/* Transmit Configuration Word */ -#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ -#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ -#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ -#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ -#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ -#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ -#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ -#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ -#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ -#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ - -/* Receive Configuration Word */ -#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ -#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ -#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ -#define E1000_RXCW_CC 0x10000000 /* Receive config change */ -#define E1000_RXCW_C 0x20000000 /* Receive config */ -#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ -#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ - - -/* PCI Express Control */ -#define E1000_GCR_RXD_NO_SNOOP 0x00000001 -#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 -#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 -#define E1000_GCR_TXD_NO_SNOOP 0x00000008 -#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 -#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 -#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 -#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 -#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000 -#define E1000_GCR_CAP_VER2 0x00040000 - -#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ - E1000_GCR_RXDSCW_NO_SNOOP | \ - E1000_GCR_RXDSCR_NO_SNOOP | \ - E1000_GCR_TXD_NO_SNOOP | \ - E1000_GCR_TXDSCW_NO_SNOOP | \ - E1000_GCR_TXDSCR_NO_SNOOP) - -/* PHY Control Register */ -#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ -#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ -#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ -#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ -#define MII_CR_POWER_DOWN 0x0800 /* Power down */ -#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ -#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ -#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ -#define MII_CR_SPEED_1000 0x0040 -#define MII_CR_SPEED_100 0x2000 -#define MII_CR_SPEED_10 0x0000 - -/* PHY Status Register */ -#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ -#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ - -/* Autoneg Advertisement Register */ -#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ -#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ -#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ -#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ -#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ -#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ -#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ -#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ -#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ -#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ - -/* Link Partner Ability Register (Base Page) */ -#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ -#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ -#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ -#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ -#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ -#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ -#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ -#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ -#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ -#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ -#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ - -/* Autoneg Expansion Register */ -#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ -#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ -#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ -#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ -#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ - -/* 1000BASE-T Control Register */ -#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ -#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ -#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ -#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ - /* 0=DTE device */ -#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ - /* 0=Configure PHY as Slave */ -#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ - /* 0=Automatic Master/Slave config */ -#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ -#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ -#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ -#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ -#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ - -/* 1000BASE-T Status Register */ -#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ -#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ -#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ -#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ -#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ -#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ -#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local Tx is Master, 0=Slave */ -#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ - -#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 - -/* PHY 1000 MII Register/Bit Definitions */ -/* PHY Registers defined by IEEE */ -#define PHY_CONTROL 0x00 /* Control Register */ -#define PHY_STATUS 0x01 /* Status Register */ -#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ -#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ -#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ -#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ -#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ -#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */ -#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ -#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ -#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ -#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ - -#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */ - -/* NVM Control */ -#define E1000_EECD_SK 0x00000001 /* NVM Clock */ -#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ -#define E1000_EECD_DI 0x00000004 /* NVM Data In */ -#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ -#define E1000_EECD_FWE_MASK 0x00000030 -#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ -#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ -#define E1000_EECD_FWE_SHIFT 4 -#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ -#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ -#define E1000_EECD_PRES 0x00000100 /* NVM Present */ -#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ -/* NVM Addressing bits based on type 0=small, 1=large */ -#define E1000_EECD_ADDR_BITS 0x00000400 -#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */ -#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ -#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ -#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ -#define E1000_EECD_SIZE_EX_SHIFT 11 -#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ -#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ -#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ -#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ -#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ -#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ -#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ -#define E1000_EECD_SECVAL_SHIFT 22 -#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES) - -#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */ -#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */ -#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write regs */ -#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ -#define E1000_NVM_RW_REG_START 1 /* Start operation */ -#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ -#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ -#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ -#define E1000_FLASH_UPDATES 2000 - -/* NVM Word Offsets */ -#define NVM_COMPAT 0x0003 -#define NVM_ID_LED_SETTINGS 0x0004 -#define NVM_VERSION 0x0005 -#define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */ -#define NVM_PHY_CLASS_WORD 0x0007 -#define NVM_INIT_CONTROL1_REG 0x000A -#define NVM_INIT_CONTROL2_REG 0x000F -#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010 -#define NVM_INIT_CONTROL3_PORT_B 0x0014 -#define NVM_INIT_3GIO_3 0x001A -#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020 -#define NVM_INIT_CONTROL3_PORT_A 0x0024 -#define NVM_CFG 0x0012 -#define NVM_FLASH_VERSION 0x0032 -#define NVM_ALT_MAC_ADDR_PTR 0x0037 -#define NVM_CHECKSUM_REG 0x003F - -#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */ -#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */ - -/* Mask bits for fields in Word 0x0f of the NVM */ -#define NVM_WORD0F_PAUSE_MASK 0x3000 -#define NVM_WORD0F_PAUSE 0x1000 -#define NVM_WORD0F_ASM_DIR 0x2000 -#define NVM_WORD0F_ANE 0x0800 -#define NVM_WORD0F_SWPDIO_EXT_MASK 0x00F0 -#define NVM_WORD0F_LPLU 0x0001 - -/* Mask bits for fields in Word 0x1a of the NVM */ -#define NVM_WORD1A_ASPM_MASK 0x000C - -/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ -#define NVM_SUM 0xBABA - -#define NVM_MAC_ADDR_OFFSET 0 -#define NVM_PBA_OFFSET_0 8 -#define NVM_PBA_OFFSET_1 9 -#define NVM_RESERVED_WORD 0xFFFF -#define NVM_PHY_CLASS_A 0x8000 -#define NVM_SERDES_AMPLITUDE_MASK 0x000F -#define NVM_SIZE_MASK 0x1C00 -#define NVM_SIZE_SHIFT 10 -#define NVM_WORD_SIZE_BASE_SHIFT 6 -#define NVM_SWDPIO_EXT_SHIFT 4 - -/* NVM Commands - SPI */ -#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ -#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */ -#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ -#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ -#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ -#define NVM_WRDI_OPCODE_SPI 0x04 /* NVM reset Write Enable latch */ -#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ -#define NVM_WRSR_OPCODE_SPI 0x01 /* NVM write Status register */ - -/* SPI NVM Status Register */ -#define NVM_STATUS_RDY_SPI 0x01 -#define NVM_STATUS_WEN_SPI 0x02 -#define NVM_STATUS_BP0_SPI 0x04 -#define NVM_STATUS_BP1_SPI 0x08 -#define NVM_STATUS_WPEN_SPI 0x80 - -/* Word definitions for ID LED Settings */ -#define ID_LED_RESERVED_0000 0x0000 -#define ID_LED_RESERVED_FFFF 0xFFFF -#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ - (ID_LED_OFF1_OFF2 << 8) | \ - (ID_LED_DEF1_DEF2 << 4) | \ - (ID_LED_DEF1_DEF2)) -#define ID_LED_DEF1_DEF2 0x1 -#define ID_LED_DEF1_ON2 0x2 -#define ID_LED_DEF1_OFF2 0x3 -#define ID_LED_ON1_DEF2 0x4 -#define ID_LED_ON1_ON2 0x5 -#define ID_LED_ON1_OFF2 0x6 -#define ID_LED_OFF1_DEF2 0x7 -#define ID_LED_OFF1_ON2 0x8 -#define ID_LED_OFF1_OFF2 0x9 - -#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF -#define IGP_ACTIVITY_LED_ENABLE 0x0300 -#define IGP_LED3_MODE 0x07000000 - -/* PCI/PCI-X/PCI-EX Config space */ -#define PCI_HEADER_TYPE_REGISTER 0x0E -#define PCIE_LINK_STATUS 0x12 -#define PCIE_DEVICE_CONTROL2 0x28 - -#define PCI_HEADER_TYPE_MULTIFUNC 0x80 -#define PCIE_LINK_WIDTH_MASK 0x3F0 -#define PCIE_LINK_WIDTH_SHIFT 4 -#define PCIE_DEVICE_CONTROL2_16ms 0x0005 - -#ifndef ETH_ADDR_LEN -#define ETH_ADDR_LEN 6 -#endif - -#define PHY_REVISION_MASK 0xFFFFFFF0 -#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ -#define MAX_PHY_MULTI_PAGE_REG 0xF - -/* Bit definitions for valid PHY IDs. */ -/* - * I = Integrated - * E = External - */ -#define M88E1000_E_PHY_ID 0x01410C50 -#define M88E1000_I_PHY_ID 0x01410C30 -#define M88E1011_I_PHY_ID 0x01410C20 -#define IGP01E1000_I_PHY_ID 0x02A80380 -#define M88E1011_I_REV_4 0x04 -#define M88E1111_I_PHY_ID 0x01410CC0 -#define GG82563_E_PHY_ID 0x01410CA0 -#define IGP03E1000_E_PHY_ID 0x02A80390 -#define IFE_E_PHY_ID 0x02A80330 -#define IFE_PLUS_E_PHY_ID 0x02A80320 -#define IFE_C_E_PHY_ID 0x02A80310 -#define BME1000_E_PHY_ID 0x01410CB0 -#define BME1000_E_PHY_ID_R2 0x01410CB1 -#define I82577_E_PHY_ID 0x01540050 -#define I82578_E_PHY_ID 0x004DD040 -#define I82579_E_PHY_ID 0x01540090 -#define M88_VENDOR 0x0141 - -/* M88E1000 Specific Registers */ -#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ -#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ -#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ -#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ -#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ -#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ - -#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ -#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ -#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ -#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ -#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ - -/* M88E1000 PHY Specific Control Register */ -#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ -#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */ -#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ -/* 1=CLK125 low, 0=CLK125 toggling */ -#define M88E1000_PSCR_CLK125_DISABLE 0x0010 -#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ - /* Manual MDI configuration */ -#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ -/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ -#define M88E1000_PSCR_AUTO_X_1000T 0x0040 -/* Auto crossover enabled all speeds */ -#define M88E1000_PSCR_AUTO_X_MODE 0x0060 -/* - * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold - * 0=Normal 10BASE-T Rx Threshold - */ -#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080 -/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ -#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 -#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ -#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ -#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Tx */ - -/* M88E1000 PHY Specific Status Register */ -#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ -#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ -#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ -#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ -/* - * 0 = <50M - * 1 = 50-80M - * 2 = 80-110M - * 3 = 110-140M - * 4 = >140M - */ -#define M88E1000_PSSR_CABLE_LENGTH 0x0380 -#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ -#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ -#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ -#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ -#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ -#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ -#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ -#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ - -#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 - -/* M88E1000 Extended PHY Specific Control Register */ -#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ -/* - * 1 = Lost lock detect enabled. - * Will assert lost lock and bring - * link down if idle not seen - * within 1ms in 1000BASE-T - */ -#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 -/* - * Number of times we will attempt to autonegotiate before downshifting if we - * are the master - */ -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00 -/* - * Number of times we will attempt to autonegotiate before downshifting if we - * are the slave - */ -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300 -#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ -#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ -#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ - -/* M88EC018 Rev 2 specific DownShift settings */ -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 - -#define I82578_EPSCR_DOWNSHIFT_ENABLE 0x0020 -#define I82578_EPSCR_DOWNSHIFT_COUNTER_MASK 0x001C - -/* BME1000 PHY Specific Control Register */ -#define BME1000_PSCR_ENABLE_DOWNSHIFT 0x0800 /* 1 = enable downshift */ - -/* - * Bits... - * 15-5: page - * 4-0: register offset - */ -#define GG82563_PAGE_SHIFT 5 -#define GG82563_REG(page, reg) \ - (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) -#define GG82563_MIN_ALT_REG 30 - -/* GG82563 Specific Registers */ -#define GG82563_PHY_SPEC_CTRL \ - GG82563_REG(0, 16) /* PHY Specific Control */ -#define GG82563_PHY_SPEC_STATUS \ - GG82563_REG(0, 17) /* PHY Specific Status */ -#define GG82563_PHY_INT_ENABLE \ - GG82563_REG(0, 18) /* Interrupt Enable */ -#define GG82563_PHY_SPEC_STATUS_2 \ - GG82563_REG(0, 19) /* PHY Specific Status 2 */ -#define GG82563_PHY_RX_ERR_CNTR \ - GG82563_REG(0, 21) /* Receive Error Counter */ -#define GG82563_PHY_PAGE_SELECT \ - GG82563_REG(0, 22) /* Page Select */ -#define GG82563_PHY_SPEC_CTRL_2 \ - GG82563_REG(0, 26) /* PHY Specific Control 2 */ -#define GG82563_PHY_PAGE_SELECT_ALT \ - GG82563_REG(0, 29) /* Alternate Page Select */ -#define GG82563_PHY_TEST_CLK_CTRL \ - GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */ - -#define GG82563_PHY_MAC_SPEC_CTRL \ - GG82563_REG(2, 21) /* MAC Specific Control Register */ -#define GG82563_PHY_MAC_SPEC_CTRL_2 \ - GG82563_REG(2, 26) /* MAC Specific Control 2 */ - -#define GG82563_PHY_DSP_DISTANCE \ - GG82563_REG(5, 26) /* DSP Distance */ - -/* Page 193 - Port Control Registers */ -#define GG82563_PHY_KMRN_MODE_CTRL \ - GG82563_REG(193, 16) /* Kumeran Mode Control */ -#define GG82563_PHY_PORT_RESET \ - GG82563_REG(193, 17) /* Port Reset */ -#define GG82563_PHY_REVISION_ID \ - GG82563_REG(193, 18) /* Revision ID */ -#define GG82563_PHY_DEVICE_ID \ - GG82563_REG(193, 19) /* Device ID */ -#define GG82563_PHY_PWR_MGMT_CTRL \ - GG82563_REG(193, 20) /* Power Management Control */ -#define GG82563_PHY_RATE_ADAPT_CTRL \ - GG82563_REG(193, 25) /* Rate Adaptation Control */ - -/* Page 194 - KMRN Registers */ -#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \ - GG82563_REG(194, 16) /* FIFO's Control/Status */ -#define GG82563_PHY_KMRN_CTRL \ - GG82563_REG(194, 17) /* Control */ -#define GG82563_PHY_INBAND_CTRL \ - GG82563_REG(194, 18) /* Inband Control */ -#define GG82563_PHY_KMRN_DIAGNOSTIC \ - GG82563_REG(194, 19) /* Diagnostic */ -#define GG82563_PHY_ACK_TIMEOUTS \ - GG82563_REG(194, 20) /* Acknowledge Timeouts */ -#define GG82563_PHY_ADV_ABILITY \ - GG82563_REG(194, 21) /* Advertised Ability */ -#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \ - GG82563_REG(194, 23) /* Link Partner Advertised Ability */ -#define GG82563_PHY_ADV_NEXT_PAGE \ - GG82563_REG(194, 24) /* Advertised Next Page */ -#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \ - GG82563_REG(194, 25) /* Link Partner Advertised Next page */ -#define GG82563_PHY_KMRN_MISC \ - GG82563_REG(194, 26) /* Misc. */ - -/* MDI Control */ -#define E1000_MDIC_DATA_MASK 0x0000FFFF -#define E1000_MDIC_REG_MASK 0x001F0000 -#define E1000_MDIC_REG_SHIFT 16 -#define E1000_MDIC_PHY_MASK 0x03E00000 -#define E1000_MDIC_PHY_SHIFT 21 -#define E1000_MDIC_OP_WRITE 0x04000000 -#define E1000_MDIC_OP_READ 0x08000000 -#define E1000_MDIC_READY 0x10000000 -#define E1000_MDIC_INT_EN 0x20000000 -#define E1000_MDIC_ERROR 0x40000000 - -/* SerDes Control */ -#define E1000_GEN_CTL_READY 0x80000000 -#define E1000_GEN_CTL_ADDRESS_SHIFT 8 -#define E1000_GEN_POLL_TIMEOUT 640 - - - -#endif /* _E1000E_DEFINES_H_ */ diff --git a/src/drivers/net/e1000e/e1000e_hw.h b/src/drivers/net/e1000e/e1000e_hw.h deleted file mode 100644 index 336af30d..00000000 --- a/src/drivers/net/e1000e/e1000e_hw.h +++ /dev/null @@ -1,723 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_HW_H_ -#define _E1000E_HW_H_ - -#include "e1000e_regs.h" -#include "e1000e_defines.h" - -struct e1000_hw; - -#define E1000_DEV_ID_82571EB_COPPER 0x105E -#define E1000_DEV_ID_82571EB_FIBER 0x105F -#define E1000_DEV_ID_82571EB_SERDES 0x1060 -#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9 -#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA -#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4 -#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5 -#define E1000_DEV_ID_82571EB_QUAD_FIBER 0x10A5 -#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP 0x10BC -#define E1000_DEV_ID_82572EI_COPPER 0x107D -#define E1000_DEV_ID_82572EI_FIBER 0x107E -#define E1000_DEV_ID_82572EI_SERDES 0x107F -#define E1000_DEV_ID_82572EI 0x10B9 -#define E1000_DEV_ID_82573E 0x108B -#define E1000_DEV_ID_82573E_IAMT 0x108C -#define E1000_DEV_ID_82573L 0x109A -#define E1000_DEV_ID_82574L 0x10D3 -#define E1000_DEV_ID_82574LA 0x10F6 -#define E1000_DEV_ID_82583V 0x150C -#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 -#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 -#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA -#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB -#define E1000_DEV_ID_ICH8_82567V_3 0x1501 -#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049 -#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A -#define E1000_DEV_ID_ICH8_IGP_C 0x104B -#define E1000_DEV_ID_ICH8_IFE 0x104C -#define E1000_DEV_ID_ICH8_IFE_GT 0x10C4 -#define E1000_DEV_ID_ICH8_IFE_G 0x10C5 -#define E1000_DEV_ID_ICH8_IGP_M 0x104D -#define E1000_DEV_ID_ICH9_IGP_M 0x10BF -#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5 -#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB -#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD -#define E1000_DEV_ID_ICH9_BM 0x10E5 -#define E1000_DEV_ID_ICH9_IGP_C 0x294C -#define E1000_DEV_ID_ICH9_IFE 0x10C0 -#define E1000_DEV_ID_ICH9_IFE_GT 0x10C3 -#define E1000_DEV_ID_ICH9_IFE_G 0x10C2 -#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC -#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD -#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE -#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE -#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF -#define E1000_DEV_ID_PCH_M_HV_LM 0x10EA -#define E1000_DEV_ID_PCH_M_HV_LC 0x10EB -#define E1000_DEV_ID_PCH_D_HV_DM 0x10EF -#define E1000_DEV_ID_PCH_D_HV_DC 0x10F0 -#define E1000_DEV_ID_PCH2_LV_LM 0x1502 -#define E1000_DEV_ID_PCH2_LV_V 0x1503 -#define E1000_REVISION_0 0 -#define E1000_REVISION_1 1 -#define E1000_REVISION_2 2 -#define E1000_REVISION_3 3 -#define E1000_REVISION_4 4 - -#define E1000_FUNC_0 0 -#define E1000_FUNC_1 1 - -#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0 -#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3 - -enum e1000_mac_type { - e1000_undefined = 0, - e1000_82571, - e1000_82572, - e1000_82573, - e1000_82574, - e1000_82583, - e1000_80003es2lan, - e1000_ich8lan, - e1000_ich9lan, - e1000_ich10lan, - e1000_pchlan, - e1000_pch2lan, - e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ -}; - -enum e1000_media_type { - e1000_media_type_unknown = 0, - e1000_media_type_copper = 1, - e1000_media_type_fiber = 2, - e1000_media_type_internal_serdes = 3, - e1000_num_media_types -}; - -enum e1000_nvm_type { - e1000_nvm_unknown = 0, - e1000_nvm_none, - e1000_nvm_eeprom_spi, - e1000_nvm_flash_hw, - e1000_nvm_flash_sw -}; - -enum e1000_nvm_override { - e1000_nvm_override_none = 0, - e1000_nvm_override_spi_small, - e1000_nvm_override_spi_large, -}; - -enum e1000_phy_type { - e1000_phy_unknown = 0, - e1000_phy_none, - e1000_phy_m88, - e1000_phy_igp, - e1000_phy_igp_2, - e1000_phy_gg82563, - e1000_phy_igp_3, - e1000_phy_ife, - e1000_phy_bm, - e1000_phy_82578, - e1000_phy_82577, - e1000_phy_82579, -}; - -enum e1000_bus_type { - e1000_bus_type_unknown = 0, - e1000_bus_type_pci, - e1000_bus_type_pcix, - e1000_bus_type_pci_express, - e1000_bus_type_reserved -}; - -enum e1000_bus_speed { - e1000_bus_speed_unknown = 0, - e1000_bus_speed_33, - e1000_bus_speed_66, - e1000_bus_speed_100, - e1000_bus_speed_120, - e1000_bus_speed_133, - e1000_bus_speed_2500, - e1000_bus_speed_5000, - e1000_bus_speed_reserved -}; - -enum e1000_bus_width { - e1000_bus_width_unknown = 0, - e1000_bus_width_pcie_x1, - e1000_bus_width_pcie_x2, - e1000_bus_width_pcie_x4 = 4, - e1000_bus_width_pcie_x8 = 8, - e1000_bus_width_32, - e1000_bus_width_64, - e1000_bus_width_reserved -}; - -enum e1000_1000t_rx_status { - e1000_1000t_rx_status_not_ok = 0, - e1000_1000t_rx_status_ok, - e1000_1000t_rx_status_undefined = 0xFF -}; - -enum e1000_rev_polarity { - e1000_rev_polarity_normal = 0, - e1000_rev_polarity_reversed, - e1000_rev_polarity_undefined = 0xFF -}; - -enum e1000_fc_mode { - e1000_fc_none = 0, - e1000_fc_rx_pause, - e1000_fc_tx_pause, - e1000_fc_full, - e1000_fc_default = 0xFF -}; - -enum e1000_ms_type { - e1000_ms_hw_default = 0, - e1000_ms_force_master, - e1000_ms_force_slave, - e1000_ms_auto -}; - -enum e1000_smart_speed { - e1000_smart_speed_default = 0, - e1000_smart_speed_on, - e1000_smart_speed_off -}; - -enum e1000_serdes_link_state { - e1000_serdes_link_down = 0, - e1000_serdes_link_autoneg_progress, - e1000_serdes_link_autoneg_complete, - e1000_serdes_link_forced_up -}; - -/* Receive Descriptor */ -struct e1000_rx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - __le16 length; /* Length of data DMAed into data buffer */ - __le16 csum; /* Packet checksum */ - u8 status; /* Descriptor status */ - u8 errors; /* Descriptor Errors */ - __le16 special; -}; - -/* Receive Descriptor - Extended */ -union e1000_rx_desc_extended { - struct { - __le64 buffer_addr; - __le64 reserved; - } read; - struct { - struct { - __le32 mrq; /* Multiple Rx Queues */ - union { - __le32 rss; /* RSS Hash */ - struct { - __le16 ip_id; /* IP id */ - __le16 csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - __le32 status_error; /* ext status/error */ - __le16 length; - __le16 vlan; /* VLAN tag */ - } upper; - } wb; /* writeback */ -}; - -#define MAX_PS_BUFFERS 4 -/* Receive Descriptor - Packet Split */ -union e1000_rx_desc_packet_split { - struct { - /* one buffer for protocol header(s), three data buffers */ - __le64 buffer_addr[MAX_PS_BUFFERS]; - } read; - struct { - struct { - __le32 mrq; /* Multiple Rx Queues */ - union { - __le32 rss; /* RSS Hash */ - struct { - __le16 ip_id; /* IP id */ - __le16 csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - __le32 status_error; /* ext status/error */ - __le16 length0; /* length of buffer 0 */ - __le16 vlan; /* VLAN tag */ - } middle; - struct { - __le16 header_status; - __le16 length[3]; /* length of buffers 1-3 */ - } upper; - __le64 reserved; - } wb; /* writeback */ -}; - -/* Transmit Descriptor */ -struct e1000_tx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 cso; /* Checksum offset */ - u8 cmd; /* Descriptor control */ - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 css; /* Checksum start */ - __le16 special; - } fields; - } upper; -}; - -/* Offload Context Descriptor */ -struct e1000_context_desc { - union { - __le32 ip_config; - struct { - u8 ipcss; /* IP checksum start */ - u8 ipcso; /* IP checksum offset */ - __le16 ipcse; /* IP checksum end */ - } ip_fields; - } lower_setup; - union { - __le32 tcp_config; - struct { - u8 tucss; /* TCP checksum start */ - u8 tucso; /* TCP checksum offset */ - __le16 tucse; /* TCP checksum end */ - } tcp_fields; - } upper_setup; - __le32 cmd_and_length; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 hdr_len; /* Header length */ - __le16 mss; /* Maximum segment size */ - } fields; - } tcp_seg_setup; -}; - -/* Offload data descriptor */ -struct e1000_data_desc { - __le64 buffer_addr; /* Address of the descriptor's buffer address */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 typ_len_ext; - u8 cmd; - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 popts; /* Packet Options */ - __le16 special; - } fields; - } upper; -}; - -/* Statistics counters collected by the MAC */ -struct e1000_hw_stats { - u64 crcerrs; - u64 algnerrc; - u64 symerrs; - u64 rxerrc; - u64 mpc; - u64 scc; - u64 ecol; - u64 mcc; - u64 latecol; - u64 colc; - u64 dc; - u64 tncrs; - u64 sec; - u64 cexterr; - u64 rlec; - u64 xonrxc; - u64 xontxc; - u64 xoffrxc; - u64 xofftxc; - u64 fcruc; - u64 prc64; - u64 prc127; - u64 prc255; - u64 prc511; - u64 prc1023; - u64 prc1522; - u64 gprc; - u64 bprc; - u64 mprc; - u64 gptc; - u64 gorc; - u64 gotc; - u64 rnbc; - u64 ruc; - u64 rfc; - u64 roc; - u64 rjc; - u64 mgprc; - u64 mgpdc; - u64 mgptc; - u64 tor; - u64 tot; - u64 tpr; - u64 tpt; - u64 ptc64; - u64 ptc127; - u64 ptc255; - u64 ptc511; - u64 ptc1023; - u64 ptc1522; - u64 mptc; - u64 bptc; - u64 tsctc; - u64 tsctfc; - u64 iac; - u64 icrxptc; - u64 icrxatc; - u64 ictxptc; - u64 ictxatc; - u64 ictxqec; - u64 ictxqmtc; - u64 icrxdmtc; - u64 icrxoc; - u64 doosync; -}; - - -struct e1000_phy_stats { - u32 idle_errors; - u32 receive_errors; -}; - -struct e1000_host_mng_dhcp_cookie { - u32 signature; - u8 status; - u8 reserved0; - u16 vlan_id; - u32 reserved1; - u16 reserved2; - u8 reserved3; - u8 checksum; -}; - -/* Host Interface "Rev 1" */ -struct e1000_host_command_header { - u8 command_id; - u8 command_length; - u8 command_options; - u8 checksum; -}; - -#define E1000_HI_MAX_DATA_LENGTH 252 -struct e1000_host_command_info { - struct e1000_host_command_header command_header; - u8 command_data[E1000_HI_MAX_DATA_LENGTH]; -}; - -/* Host Interface "Rev 2" */ -struct e1000_host_mng_command_header { - u8 command_id; - u8 checksum; - u16 reserved1; - u16 reserved2; - u16 command_length; -}; - -#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 -struct e1000_host_mng_command_info { - struct e1000_host_mng_command_header command_header; - u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; -}; - -#include "e1000e_mac.h" -#include "e1000e_phy.h" -#include "e1000e_nvm.h" -#include "e1000e_manage.h" - -struct e1000_mac_operations { - /* Function pointers for the MAC. */ - s32 (*init_params)(struct e1000_hw *); - s32 (*id_led_init)(struct e1000_hw *); - s32 (*blink_led)(struct e1000_hw *); - s32 (*check_for_link)(struct e1000_hw *); - bool (*check_mng_mode)(struct e1000_hw *hw); - s32 (*cleanup_led)(struct e1000_hw *); - void (*clear_hw_cntrs)(struct e1000_hw *); - void (*clear_vfta)(struct e1000_hw *); - s32 (*get_bus_info)(struct e1000_hw *); - void (*set_lan_id)(struct e1000_hw *); - s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); - s32 (*led_on)(struct e1000_hw *); - s32 (*led_off)(struct e1000_hw *); - void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32); - s32 (*reset_hw)(struct e1000_hw *); - s32 (*init_hw)(struct e1000_hw *); - s32 (*setup_link)(struct e1000_hw *); - s32 (*setup_physical_interface)(struct e1000_hw *); - s32 (*setup_led)(struct e1000_hw *); - void (*write_vfta)(struct e1000_hw *, u32, u32); - void (*mta_set)(struct e1000_hw *, u32); - void (*config_collision_dist)(struct e1000_hw *); - void (*rar_set)(struct e1000_hw *, u8*, u32); - s32 (*read_mac_addr)(struct e1000_hw *); - s32 (*validate_mdi_setting)(struct e1000_hw *); - s32 (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*); - s32 (*mng_write_cmd_header)(struct e1000_hw *hw, - struct e1000_host_mng_command_header*); - s32 (*mng_enable_host_if)(struct e1000_hw *); - s32 (*wait_autoneg)(struct e1000_hw *); -}; - -struct e1000_phy_operations { - s32 (*init_params)(struct e1000_hw *); - s32 (*acquire)(struct e1000_hw *); - s32 (*cfg_on_link_up)(struct e1000_hw *); - s32 (*check_polarity)(struct e1000_hw *); - s32 (*check_reset_block)(struct e1000_hw *); - s32 (*commit)(struct e1000_hw *); -#if 0 - s32 (*force_speed_duplex)(struct e1000_hw *); -#endif - s32 (*get_cfg_done)(struct e1000_hw *hw); -#if 0 - s32 (*get_cable_length)(struct e1000_hw *); -#endif - s32 (*get_info)(struct e1000_hw *); - s32 (*read_reg)(struct e1000_hw *, u32, u16 *); - s32 (*read_reg_locked)(struct e1000_hw *, u32, u16 *); - void (*release)(struct e1000_hw *); - s32 (*reset)(struct e1000_hw *); - s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); - s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); - s32 (*write_reg)(struct e1000_hw *, u32, u16); - s32 (*write_reg_locked)(struct e1000_hw *, u32, u16); - void (*power_up)(struct e1000_hw *); - void (*power_down)(struct e1000_hw *); -}; - -struct e1000_nvm_operations { - s32 (*init_params)(struct e1000_hw *); - s32 (*acquire)(struct e1000_hw *); - s32 (*read)(struct e1000_hw *, u16, u16, u16 *); - void (*release)(struct e1000_hw *); - void (*reload)(struct e1000_hw *); - s32 (*update)(struct e1000_hw *); - s32 (*valid_led_default)(struct e1000_hw *, u16 *); - s32 (*validate)(struct e1000_hw *); - s32 (*write)(struct e1000_hw *, u16, u16, u16 *); -}; - -struct e1000_mac_info { - struct e1000_mac_operations ops; - u8 addr[6]; - u8 perm_addr[6]; - - enum e1000_mac_type type; - - u32 collision_delta; - u32 ledctl_default; - u32 ledctl_mode1; - u32 ledctl_mode2; - u32 mc_filter_type; - u32 tx_packet_delta; - u32 txcw; - - u16 current_ifs_val; - u16 ifs_max_val; - u16 ifs_min_val; - u16 ifs_ratio; - u16 ifs_step_size; - u16 mta_reg_count; - - /* Maximum size of the MTA register table in all supported adapters */ - #define MAX_MTA_REG 128 - u32 mta_shadow[MAX_MTA_REG]; - u16 rar_entry_count; - - u8 forced_speed_duplex; - - bool adaptive_ifs; - bool arc_subsystem_valid; - bool asf_firmware_present; - bool autoneg; - bool autoneg_failed; - bool get_link_status; - bool in_ifs_mode; - enum e1000_serdes_link_state serdes_link_state; - bool serdes_has_link; - bool tx_pkt_filtering; -}; - -struct e1000_phy_info { - struct e1000_phy_operations ops; - enum e1000_phy_type type; - - enum e1000_1000t_rx_status local_rx; - enum e1000_1000t_rx_status remote_rx; - enum e1000_ms_type ms_type; - enum e1000_ms_type original_ms_type; - enum e1000_rev_polarity cable_polarity; - enum e1000_smart_speed smart_speed; - - u32 addr; - u32 id; - u32 reset_delay_us; /* in usec */ - u32 revision; - - enum e1000_media_type media_type; - - u16 autoneg_advertised; - u16 autoneg_mask; - u16 cable_length; - u16 max_cable_length; - u16 min_cable_length; - - u8 mdix; - - bool disable_polarity_correction; - bool is_mdix; - bool polarity_correction; - bool reset_disable; - bool speed_downgraded; - bool autoneg_wait_to_complete; -}; - -struct e1000_nvm_info { - struct e1000_nvm_operations ops; - enum e1000_nvm_type type; - enum e1000_nvm_override override; - - u32 flash_bank_size; - u32 flash_base_addr; - - u16 word_size; - u16 delay_usec; - u16 address_bits; - u16 opcode_bits; - u16 page_size; -}; - -struct e1000_bus_info { - enum e1000_bus_type type; - enum e1000_bus_speed speed; - enum e1000_bus_width width; - - u16 func; - u16 pci_cmd_word; -}; - -struct e1000_fc_info { - u32 high_water; /* Flow control high-water mark */ - u32 low_water; /* Flow control low-water mark */ - u16 pause_time; /* Flow control pause timer */ - bool send_xon; /* Flow control send XON */ - bool strict_ieee; /* Strict IEEE mode */ - enum e1000_fc_mode current_mode; /* FC mode in effect */ - enum e1000_fc_mode requested_mode; /* FC mode requested by caller */ -}; - -struct e1000_dev_spec_82571 { - bool laa_is_present; - u32 smb_counter; -}; - -struct e1000_dev_spec_80003es2lan { - bool mdic_wa_enable; -}; - -struct e1000_shadow_ram { - u16 value; - bool modified; -}; - -#define E1000_ICH8_SHADOW_RAM_WORDS 2048 - -struct e1000_dev_spec_ich8lan { - bool kmrn_lock_loss_workaround_enabled; - struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS]; - bool nvm_k1_enabled; -}; - -struct e1000_hw { - struct e1000_adapter *adapter; - - u8 __iomem *hw_addr; - u8 __iomem *flash_address; - - void *back; - unsigned long io_base; - - struct e1000_mac_info mac; - struct e1000_fc_info fc; - struct e1000_phy_info phy; - struct e1000_nvm_info nvm; - struct e1000_bus_info bus; - struct e1000_host_mng_dhcp_cookie mng_cookie; - - union { - struct e1000_dev_spec_82571 _82571; - struct e1000_dev_spec_80003es2lan _80003es2lan; - struct e1000_dev_spec_ich8lan ich8lan; - } dev_spec; - - u16 device_id; - u16 subsystem_vendor_id; - u16 subsystem_device_id; - u16 vendor_id; - - u8 revision_id; -}; - -#include "e1000e_82571.h" -#include "e1000e_80003es2lan.h" -#include "e1000e_ich8lan.h" - -/* These functions must be implemented by drivers */ -s32 e1000e_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); - -#endif diff --git a/src/drivers/net/e1000e/e1000e_ich8lan.c b/src/drivers/net/e1000e/e1000e_ich8lan.c deleted file mode 100644 index d438ff1e..00000000 --- a/src/drivers/net/e1000e/e1000e_ich8lan.c +++ /dev/null @@ -1,3465 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* - * 82562G 10/100 Network Connection - * 82562G-2 10/100 Network Connection - * 82562GT 10/100 Network Connection - * 82562GT-2 10/100 Network Connection - * 82562V 10/100 Network Connection - * 82562V-2 10/100 Network Connection - * 82566DC-2 Gigabit Network Connection - * 82566DC Gigabit Network Connection - * 82566DM-2 Gigabit Network Connection - * 82566DM Gigabit Network Connection - * 82566MC Gigabit Network Connection - * 82566MM Gigabit Network Connection - * 82567LM Gigabit Network Connection - * 82567LF Gigabit Network Connection - * 82567V Gigabit Network Connection - * 82567LM-2 Gigabit Network Connection - * 82567LF-2 Gigabit Network Connection - * 82567V-2 Gigabit Network Connection - * 82567LF-3 Gigabit Network Connection - * 82567LM-3 Gigabit Network Connection - * 82567LM-4 Gigabit Network Connection - * 82577LM Gigabit Network Connection - * 82577LC Gigabit Network Connection - * 82578DM Gigabit Network Connection - * 82578DC Gigabit Network Connection - */ - -#include "e1000e.h" - -static s32 e1000e_init_phy_params_ich8lan(struct e1000_hw *hw); -static s32 e1000e_init_phy_params_pchlan(struct e1000_hw *hw); -static s32 e1000e_init_nvm_params_ich8lan(struct e1000_hw *hw); -static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw); -static s32 e1000e_acquire_swflag_ich8lan(struct e1000_hw *hw); -static void e1000e_release_swflag_ich8lan(struct e1000_hw *hw); -static s32 e1000e_acquire_nvm_ich8lan(struct e1000_hw *hw); -static void e1000e_release_nvm_ich8lan(struct e1000_hw *hw); -static bool e1000e_check_mng_mode_ich8lan(struct e1000_hw *hw); -static s32 e1000e_check_reset_block_ich8lan(struct e1000_hw *hw); -static s32 e1000e_phy_hw_reset_ich8lan(struct e1000_hw *hw); -static s32 e1000e_get_phy_info_ich8lan(struct e1000_hw *hw); -static s32 e1000e_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); -static s32 e1000e_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, - bool active); -static s32 e1000e_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, - bool active); -static s32 e1000e_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -static s32 e1000e_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -static s32 e1000e_validate_nvm_checksum_ich8lan(struct e1000_hw *hw); -static s32 e1000e_update_nvm_checksum_ich8lan(struct e1000_hw *hw); -static s32 e1000e_valid_led_default_ich8lan(struct e1000_hw *hw, - u16 *data); -static s32 e1000e_id_led_init_pchlan(struct e1000_hw *hw); -static s32 e1000e_get_bus_info_ich8lan(struct e1000_hw *hw); -static s32 e1000e_reset_hw_ich8lan(struct e1000_hw *hw); -static s32 e1000e_init_hw_ich8lan(struct e1000_hw *hw); -static s32 e1000e_setup_link_ich8lan(struct e1000_hw *hw); -static s32 e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw); -static s32 e1000e_get_link_up_info_ich8lan(struct e1000_hw *hw, - u16 *speed, u16 *duplex); -static s32 e1000e_cleanup_led_ich8lan(struct e1000_hw *hw); -static s32 e1000e_led_on_ich8lan(struct e1000_hw *hw); -static s32 e1000e_led_off_ich8lan(struct e1000_hw *hw); -static s32 e1000e_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); -static s32 e1000e_setup_led_pchlan(struct e1000_hw *hw); -static s32 e1000e_cleanup_led_pchlan(struct e1000_hw *hw); -static s32 e1000e_led_on_pchlan(struct e1000_hw *hw); -static s32 e1000e_led_off_pchlan(struct e1000_hw *hw); -static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); -static s32 e1000e_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); -static s32 e1000e_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout); -static s32 e1000e_flash_cycle_init_ich8lan(struct e1000_hw *hw); -static s32 e1000e_get_phy_info_ife_ich8lan(struct e1000_hw *hw); -static void e1000e_initialize_hw_bits_ich8lan(struct e1000_hw *hw); -static s32 e1000e_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); -static s32 e1000e_read_flash_byte_ich8lan(struct e1000_hw *hw, - u32 offset, u8 *data); -static s32 e1000e_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, - u8 size, u16 *data); -static s32 e1000e_read_flash_word_ich8lan(struct e1000_hw *hw, - u32 offset, u16 *data); -static s32 e1000e_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, - u32 offset, u8 byte); -static s32 e1000e_write_flash_byte_ich8lan(struct e1000_hw *hw, - u32 offset, u8 data); -static s32 e1000e_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, - u8 size, u16 data); -static s32 e1000e_get_cfg_done_ich8lan(struct e1000_hw *hw); -static void e1000e_power_down_phy_copper_ich8lan(struct e1000_hw *hw); -static s32 e1000e_check_for_copper_link_ich8lan(struct e1000_hw *hw); -static void e1000e_lan_init_done_ich8lan(struct e1000_hw *hw); -static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw); - -/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ -/* Offset 04h HSFSTS */ -union ich8_hws_flash_status { - struct ich8_hsfsts { - u16 flcdone :1; /* bit 0 Flash Cycle Done */ - u16 flcerr :1; /* bit 1 Flash Cycle Error */ - u16 dael :1; /* bit 2 Direct Access error Log */ - u16 berasesz :2; /* bit 4:3 Sector Erase Size */ - u16 flcinprog :1; /* bit 5 flash cycle in Progress */ - u16 reserved1 :2; /* bit 13:6 Reserved */ - u16 reserved2 :6; /* bit 13:6 Reserved */ - u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */ - u16 flockdn :1; /* bit 15 Flash Config Lock-Down */ - } hsf_status; - u16 regval; -}; - -/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ -/* Offset 06h FLCTL */ -union ich8_hws_flash_ctrl { - struct ich8_hsflctl { - u16 flcgo :1; /* 0 Flash Cycle Go */ - u16 flcycle :2; /* 2:1 Flash Cycle */ - u16 reserved :5; /* 7:3 Reserved */ - u16 fldbcount :2; /* 9:8 Flash Data Byte Count */ - u16 flockdn :6; /* 15:10 Reserved */ - } hsf_ctrl; - u16 regval; -}; - -/* ICH Flash Region Access Permissions */ -union ich8_hws_flash_regacc { - struct ich8_flracc { - u32 grra :8; /* 0:7 GbE region Read Access */ - u32 grwa :8; /* 8:15 GbE region Write Access */ - u32 gmrag :8; /* 23:16 GbE Master Read Access Grant */ - u32 gmwag :8; /* 31:24 GbE Master Write Access Grant */ - } hsf_flregacc; - u16 regval; -}; - -/** - * e1000e_init_phy_params_pchlan - Initialize PHY function pointers - * @hw: pointer to the HW structure - * - * Initialize family-specific PHY parameters and function pointers. - **/ -static s32 e1000e_init_phy_params_pchlan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - phy->addr = 1; - phy->reset_delay_us = 100; - - phy->ops.acquire = e1000e_acquire_swflag_ich8lan; - phy->ops.check_polarity = e1000e_check_polarity_ife; - phy->ops.check_reset_block = e1000e_check_reset_block_ich8lan; -#if 0 - phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_ife; -#endif -#if 0 - phy->ops.get_cable_length = e1000e_get_cable_length_igp_2; -#endif - phy->ops.get_cfg_done = e1000e_get_cfg_done_ich8lan; - phy->ops.get_info = e1000e_get_phy_info_ich8lan; - phy->ops.read_reg = e1000e_read_phy_reg_hv; - phy->ops.read_reg_locked = e1000e_read_phy_reg_hv_locked; - phy->ops.release = e1000e_release_swflag_ich8lan; - phy->ops.reset = e1000e_phy_hw_reset_ich8lan; - phy->ops.set_d0_lplu_state = e1000e_set_lplu_state_pchlan; - phy->ops.set_d3_lplu_state = e1000e_set_lplu_state_pchlan; - phy->ops.write_reg = e1000e_write_phy_reg_hv; - phy->ops.write_reg_locked = e1000e_write_phy_reg_hv_locked; - phy->ops.power_up = e1000e_power_up_phy_copper; - phy->ops.power_down = e1000e_power_down_phy_copper_ich8lan; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - - phy->id = e1000_phy_unknown; - e1000e_get_phy_id(hw); - phy->type = e1000e_get_phy_type_from_id(phy->id); - - if (phy->type == e1000_phy_82577 || phy->type == e1000_phy_82579) { - phy->ops.check_polarity = e1000e_check_polarity_82577; -#if 0 - phy->ops.force_speed_duplex = - e1000e_phy_force_speed_duplex_82577; -#endif -#if 0 - phy->ops.get_cable_length = e1000e_get_cable_length_82577; -#endif - phy->ops.get_info = e1000e_get_phy_info_82577; - phy->ops.commit = e1000e_phy_sw_reset; - } - - return ret_val; -} - -/** - * e1000e_init_phy_params_ich8lan - Initialize PHY function pointers - * @hw: pointer to the HW structure - * - * Initialize family-specific PHY parameters and function pointers. - **/ -static s32 e1000e_init_phy_params_ich8lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 i = 0; - - phy->addr = 1; - phy->reset_delay_us = 100; - - phy->ops.acquire = e1000e_acquire_swflag_ich8lan; - phy->ops.check_polarity = e1000e_check_polarity_ife; - phy->ops.check_reset_block = e1000e_check_reset_block_ich8lan; -#if 0 - phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_ife; -#endif -#if 0 - phy->ops.get_cable_length = e1000e_get_cable_length_igp_2; -#endif - phy->ops.get_cfg_done = e1000e_get_cfg_done_ich8lan; - phy->ops.get_info = e1000e_get_phy_info_ich8lan; - phy->ops.read_reg = e1000e_read_phy_reg_igp; - phy->ops.release = e1000e_release_swflag_ich8lan; - phy->ops.reset = e1000e_phy_hw_reset_ich8lan; - phy->ops.set_d0_lplu_state = e1000e_set_d0_lplu_state_ich8lan; - phy->ops.set_d3_lplu_state = e1000e_set_d3_lplu_state_ich8lan; - phy->ops.write_reg = e1000e_write_phy_reg_igp; - phy->ops.power_up = e1000e_power_up_phy_copper; - phy->ops.power_down = e1000e_power_down_phy_copper_ich8lan; - - /* - * We may need to do this twice - once for IGP and if that fails, - * we'll set BM func pointers and try again - */ - ret_val = e1000e_determine_phy_address(hw); - if (ret_val) { - phy->ops.write_reg = e1000e_write_phy_reg_bm; - phy->ops.read_reg = e1000e_read_phy_reg_bm; - ret_val = e1000e_determine_phy_address(hw); - if (ret_val) { - DBG("Cannot determine PHY addr. Erroring out\n"); - goto out; - } - } - - phy->id = 0; - while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) && - (i++ < 100)) { - msleep(1); - ret_val = e1000e_get_phy_id(hw); - if (ret_val) - goto out; - } - - /* Verify phy id */ - switch (phy->id) { - case IGP03E1000_E_PHY_ID: - phy->type = e1000_phy_igp_3; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->ops.read_reg_locked = e1000e_read_phy_reg_igp_locked; - phy->ops.write_reg_locked = e1000e_write_phy_reg_igp_locked; - break; - case IFE_E_PHY_ID: - case IFE_PLUS_E_PHY_ID: - case IFE_C_E_PHY_ID: - phy->type = e1000_phy_ife; - phy->autoneg_mask = E1000_ALL_NOT_GIG; - break; - case BME1000_E_PHY_ID: - phy->type = e1000_phy_bm; - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->ops.read_reg = e1000e_read_phy_reg_bm; - phy->ops.write_reg = e1000e_write_phy_reg_bm; - phy->ops.commit = e1000e_phy_sw_reset; - break; - default: - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_init_nvm_params_ich8lan - Initialize NVM function pointers - * @hw: pointer to the HW structure - * - * Initialize family-specific NVM parameters and function - * pointers. - **/ -static s32 e1000e_init_nvm_params_ich8lan(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - u32 gfpreg, sector_base_addr, sector_end_addr; - s32 ret_val = E1000_SUCCESS; - u16 i; - - /* Can't read flash registers if the register set isn't mapped. */ - if (!hw->flash_address) { - e_dbg("ERROR: Flash registers not mapped\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - nvm->type = e1000_nvm_flash_sw; - - gfpreg = er32flash(ICH_FLASH_GFPREG); - - /* - * sector_X_addr is a "sector"-aligned address (4096 bytes) - * Add 1 to sector_end_addr since this sector is included in - * the overall size. - */ - sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; - sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; - - /* flash_base_addr is byte-aligned */ - nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT; - - /* - * find total size of the NVM, then cut in half since the total - * size represents two separate NVM banks. - */ - nvm->flash_bank_size = (sector_end_addr - sector_base_addr) - << FLASH_SECTOR_ADDR_SHIFT; - nvm->flash_bank_size /= 2; - /* Adjust to word count */ - nvm->flash_bank_size /= sizeof(u16); - - nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS; - - /* Clear shadow ram */ - for (i = 0; i < nvm->word_size; i++) { - dev_spec->shadow_ram[i].modified = false; - dev_spec->shadow_ram[i].value = 0xFFFF; - } - - /* Function Pointers */ - nvm->ops.acquire = e1000e_acquire_nvm_ich8lan; - nvm->ops.release = e1000e_release_nvm_ich8lan; - nvm->ops.read = e1000e_read_nvm_ich8lan; - nvm->ops.update = e1000e_update_nvm_checksum_ich8lan; - nvm->ops.valid_led_default = e1000e_valid_led_default_ich8lan; - nvm->ops.validate = e1000e_validate_nvm_checksum_ich8lan; - nvm->ops.write = e1000e_write_nvm_ich8lan; - -out: - return ret_val; -} - -/** - * e1000e_init_mac_params_ich8lan - Initialize MAC function pointers - * @hw: pointer to the HW structure - * - * Initialize family-specific MAC parameters and function - * pointers. - **/ -static s32 e1000e_init_mac_params_ich8lan(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - /* Set media type function pointer */ - hw->phy.media_type = e1000_media_type_copper; - - /* Set mta register count */ - mac->mta_reg_count = 32; - /* Set rar entry count */ - mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; - if (mac->type == e1000_ich8lan) - mac->rar_entry_count--; - /* Set if part includes ASF firmware */ - mac->asf_firmware_present = true; - /* Set if manageability features are enabled. */ - mac->arc_subsystem_valid = true; - - /* Function pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = e1000e_get_bus_info_ich8lan; - /* function id */ - mac->ops.set_lan_id = e1000e_set_lan_id_single_port; - /* reset */ - mac->ops.reset_hw = e1000e_reset_hw_ich8lan; - /* hw initialization */ - mac->ops.init_hw = e1000e_init_hw_ich8lan; - /* link setup */ - mac->ops.setup_link = e1000e_setup_link_ich8lan; - /* physical interface setup */ - mac->ops.setup_physical_interface = e1000e_setup_copper_link_ich8lan; - /* check for link */ - mac->ops.check_for_link = e1000e_check_for_copper_link_ich8lan; - /* check management mode */ - mac->ops.check_mng_mode = e1000e_check_mng_mode_ich8lan; - /* link info */ - mac->ops.get_link_up_info = e1000e_get_link_up_info_ich8lan; - /* multicast address update */ - mac->ops.update_mc_addr_list = e1000e_update_mc_addr_list_generic; - /* setting MTA */ - mac->ops.mta_set = e1000e_mta_set_generic; - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = e1000e_clear_hw_cntrs_ich8lan; - - /* LED operations */ - switch (mac->type) { - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: - /* ID LED init */ - mac->ops.id_led_init = e1000e_id_led_init; - /* blink LED */ - mac->ops.blink_led = e1000e_blink_led; - /* setup LED */ - mac->ops.setup_led = e1000e_setup_led_generic; - /* cleanup LED */ - mac->ops.cleanup_led = e1000e_cleanup_led_ich8lan; - /* turn on/off LED */ - mac->ops.led_on = e1000e_led_on_ich8lan; - mac->ops.led_off = e1000e_led_off_ich8lan; - break; - case e1000_pchlan: - case e1000_pch2lan: - /* ID LED init */ - mac->ops.id_led_init = e1000e_id_led_init_pchlan; - /* setup LED */ - mac->ops.setup_led = e1000e_setup_led_pchlan; - /* cleanup LED */ - mac->ops.cleanup_led = e1000e_cleanup_led_pchlan; - /* turn on/off LED */ - mac->ops.led_on = e1000e_led_on_pchlan; - mac->ops.led_off = e1000e_led_off_pchlan; - break; - default: - break; - } - - /* Enable PCS Lock-loss workaround for ICH8 */ - if (mac->type == e1000_ich8lan) - e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true); - - /* Disable PHY configuration by hardware, config by software */ - if (mac->type == e1000_pch2lan) { - u32 extcnf_ctrl = er32(EXTCNF_CTRL); - - extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; - ew32(EXTCNF_CTRL, extcnf_ctrl); - } - - - return E1000_SUCCESS; -} - -/** - * e1000e_check_for_copper_link_ich8lan - Check for link (Copper) - * @hw: pointer to the HW structure - * - * Checks to see of the link status of the hardware has changed. If a - * change in link status has been detected, then we read the PHY registers - * to get the current speed/duplex if link exists. - **/ -static s32 e1000e_check_for_copper_link_ich8lan(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - bool link; - - /* - * We only want to go out to the PHY registers to see if Auto-Neg - * has completed and/or if our link status has changed. The - * get_link_status flag is set upon receiving a Link Status - * Change or Rx Sequence Error interrupt. - */ - if (!mac->get_link_status) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* - * First we want to see if the MII Status Register reports - * link. If so, then we want to get the current speed/duplex - * of the PHY. - */ - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (hw->mac.type == e1000_pchlan) { - ret_val = e1000e_k1_gig_workaround_hv(hw, link); - if (ret_val) - goto out; - } - - if (!link) - goto out; /* No link detected */ - - mac->get_link_status = false; - - if (hw->phy.type == e1000_phy_82578) { - ret_val = e1000e_link_stall_workaround_hv(hw); - if (ret_val) - goto out; - } - - /* - * Check if there was DownShift, must be checked - * immediately after link-up - */ - e1000e_check_downshift(hw); - - /* - * If we are forcing speed/duplex, then we simply return since - * we have already determined whether we have link or not. - */ - if (!mac->autoneg) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - /* - * Auto-Neg is enabled. Auto Speed Detection takes care - * of MAC speed/duplex configuration. So we only need to - * configure Collision Distance in the MAC. - */ - e1000e_config_collision_dist(hw); - - /* - * Configure Flow Control now that Auto-Neg has completed. - * First, we need to restore the desired flow control - * settings because we may have had to re-autoneg with a - * different link partner. - */ - ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) - e_dbg("Error configuring flow control\n"); - -out: - return ret_val; -} - -/** - * e1000e_init_function_pointers_ich8lan - Initialize ICH8 function pointers - * @hw: pointer to the HW structure - * - * Initialize family-specific function pointers for PHY, MAC, and NVM. - **/ -void e1000e_init_function_pointers_ich8lan(struct e1000_hw *hw) -{ - e1000e_init_mac_ops_generic(hw); - e1000e_init_nvm_ops_generic(hw); - hw->mac.ops.init_params = e1000e_init_mac_params_ich8lan; - hw->nvm.ops.init_params = e1000e_init_nvm_params_ich8lan; - switch (hw->mac.type) { - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: - hw->phy.ops.init_params = e1000e_init_phy_params_ich8lan; - break; - case e1000_pchlan: - case e1000_pch2lan: - hw->phy.ops.init_params = e1000e_init_phy_params_pchlan; - break; - default: - break; - } -} - -#if 0 -static DEFINE_MUTEX(nvm_mutex); -#endif - -/** - * e1000e_acquire_nvm_ich8lan - Acquire NVM mutex - * @hw: pointer to the HW structure - * - * Acquires the mutex for performing NVM operations. - **/ -static s32 e1000e_acquire_nvm_ich8lan(struct e1000_hw *hw __unused) -{ -#if 0 - mutex_lock(&nvm_mutex); -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_release_nvm_ich8lan - Release NVM mutex - * @hw: pointer to the HW structure - * - * Releases the mutex used while performing NVM operations. - **/ -static void e1000e_release_nvm_ich8lan(struct e1000_hw *hw __unused) -{ -#if 0 - mutex_unlock(&nvm_mutex); -#endif - return; -} - -#if 0 -static DEFINE_MUTEX(swflag_mutex); -#endif - -/** - * e1000e_acquire_swflag_ich8lan - Acquire software control flag - * @hw: pointer to the HW structure - * - * Acquires the software control flag for performing PHY and select - * MAC CSR accesses. - **/ -static s32 e1000e_acquire_swflag_ich8lan(struct e1000_hw *hw) -{ - u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; - s32 ret_val = E1000_SUCCESS; - -#if 0 - mutex_lock(&swflag_mutex); -#endif - - while (timeout) { - extcnf_ctrl = er32(EXTCNF_CTRL); - if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) - break; - - mdelay(1); - timeout--; - } - - if (!timeout) { - e_dbg("SW/FW/HW has locked the resource for too long.\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - timeout = SW_FLAG_TIMEOUT; - - extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; - ew32(EXTCNF_CTRL, extcnf_ctrl); - - while (timeout) { - extcnf_ctrl = er32(EXTCNF_CTRL); - if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) - break; - - mdelay(1); - timeout--; - } - - if (!timeout) { - e_dbg("Failed to acquire the semaphore.\n"); - extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; - ew32(EXTCNF_CTRL, extcnf_ctrl); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - -out: -#if 0 - if (ret_val) - mutex_unlock(&swflag_mutex); -#endif - return ret_val; -} - -/** - * e1000e_release_swflag_ich8lan - Release software control flag - * @hw: pointer to the HW structure - * - * Releases the software control flag for performing PHY and select - * MAC CSR accesses. - **/ -static void e1000e_release_swflag_ich8lan(struct e1000_hw *hw) -{ - u32 extcnf_ctrl; - - extcnf_ctrl = er32(EXTCNF_CTRL); - extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; - ew32(EXTCNF_CTRL, extcnf_ctrl); - -#if 0 - mutex_unlock(&swflag_mutex); -#endif - return; -} - -/** - * e1000e_check_mng_mode_ich8lan - Checks management mode - * @hw: pointer to the HW structure - * - * This checks if the adapter has manageability enabled. - * This is a function pointer entry point only called by read/write - * routines for the PHY and NVM parts. - **/ -static bool e1000e_check_mng_mode_ich8lan(struct e1000_hw *hw) -{ - u32 fwsm; - - fwsm = er32(FWSM); - return (fwsm & E1000_FWSM_MODE_MASK) == - (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); -} -/** - * e1000e_check_reset_block_ich8lan - Check if PHY reset is blocked - * @hw: pointer to the HW structure - * - * Checks if firmware is blocking the reset of the PHY. - * This is a function pointer entry point only called by - * reset routines. - **/ -static s32 e1000e_check_reset_block_ich8lan(struct e1000_hw *hw) -{ - u32 fwsm; - - fwsm = er32(FWSM); - return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS - : E1000_BLK_PHY_RESET; -} - -/** - * e1000e_sw_lcd_config_ich8lan - SW-based LCD Configuration - * @hw: pointer to the HW structure - * - * SW should configure the LCD from the NVM extended configuration region - * as a workaround for certain parts. - **/ -static s32 e1000e_sw_lcd_config_ich8lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; - s32 ret_val; - u16 word_addr, reg_data, reg_addr, phy_page = 0; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - - /* - * Initialize the PHY from the NVM on ICH platforms. This - * is needed due to an issue where the NVM configuration is - * not properly autoloaded after power transitions. - * Therefore, after each PHY reset, we will load the - * configuration data out of the NVM manually. - */ - if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) || - (hw->mac.type == e1000_pchlan)) { - /* Check if SW needs to configure the PHY */ - if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) || - (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) || - (hw->mac.type == e1000_pchlan) || - (hw->mac.type == e1000_pch2lan)) - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; - else - sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; - - data = er32(FEXTNVM); - if (!(data & sw_cfg_mask)) - goto out; - - /* Wait for basic configuration completes before proceeding */ - e1000e_lan_init_done_ich8lan(hw); - - if (hw->mac.type != e1000_pch2lan) { - /* - * Make sure HW does not configure LCD from PHY - * extended configuration before SW configuration - */ - data = er32(EXTCNF_CTRL); - if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) - goto out; - } - - cnf_size = er32(EXTCNF_SIZE); - cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; - cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; - if (!cnf_size) - goto out; - - cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; - cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; - - if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) && - (hw->mac.type == e1000_pchlan || - hw->mac.type == e1000_pch2lan)) { - /* - * HW configures the SMBus address and LEDs when the - * OEM and LCD Write Enable bits are set in the NVM. - * When both NVM bits are cleared, SW will configure - * them instead. - */ - data = er32(STRAP); - data &= E1000_STRAP_SMBUS_ADDRESS_MASK; - reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT; - reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; - ret_val = e1000e_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, - reg_data); - if (ret_val) - goto out; - - data = er32(LEDCTL); - ret_val = e1000e_write_phy_reg_hv_locked(hw, - HV_LED_CONFIG, - (u16)data); - if (ret_val) - goto out; - } - - /* Configure LCD from extended configuration region. */ - - /* cnf_base_addr is in DWORD */ - word_addr = (u16)(cnf_base_addr << 1); - - for (i = 0; i < cnf_size; i++) { - ret_val = e1000e_read_nvm(hw, (word_addr + i * 2), 1, - ®_data); - if (ret_val) - goto out; - - ret_val = e1000e_read_nvm(hw, (word_addr + i * 2 + 1), - 1, ®_addr); - if (ret_val) - goto out; - - /* Save off the PHY page for future writes. */ - if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { - phy_page = reg_data; - continue; - } - - reg_addr &= PHY_REG_MASK; - reg_addr |= phy_page; - - ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr, - reg_data); - if (ret_val) - goto out; - } - } - -out: - hw->phy.ops.release(hw); - return ret_val; -} - -/** - * e1000e_k1_gig_workaround_hv - K1 Si workaround - * @hw: pointer to the HW structure - * @link: link up bool flag - * - * If K1 is enabled for 1Gbps, the MAC might stall when transitioning - * from a lower speed. This workaround disables K1 whenever link is at 1Gig - * If link is down, the function will restore the default K1 setting located - * in the NVM. - **/ -static s32 e1000e_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) -{ - s32 ret_val = E1000_SUCCESS; - u16 status_reg = 0; - bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; - - if (hw->mac.type != e1000_pchlan) - goto out; - - /* Wrap the whole flow with the sw flag */ - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ - if (link) { - if (hw->phy.type == e1000_phy_82578) { - ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS, - &status_reg); - if (ret_val) - goto release; - - status_reg &= BM_CS_STATUS_LINK_UP | - BM_CS_STATUS_RESOLVED | - BM_CS_STATUS_SPEED_MASK; - - if (status_reg == (BM_CS_STATUS_LINK_UP | - BM_CS_STATUS_RESOLVED | - BM_CS_STATUS_SPEED_1000)) - k1_enable = false; - } - - if (hw->phy.type == e1000_phy_82577) { - ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS, - &status_reg); - if (ret_val) - goto release; - - status_reg &= HV_M_STATUS_LINK_UP | - HV_M_STATUS_AUTONEG_COMPLETE | - HV_M_STATUS_SPEED_MASK; - - if (status_reg == (HV_M_STATUS_LINK_UP | - HV_M_STATUS_AUTONEG_COMPLETE | - HV_M_STATUS_SPEED_1000)) - k1_enable = false; - } - - /* Link stall fix for link up */ - ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), - 0x0100); - if (ret_val) - goto release; - - } else { - /* Link stall fix for link down */ - ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19), - 0x4100); - if (ret_val) - goto release; - } - - ret_val = e1000e_configure_k1_ich8lan(hw, k1_enable); - -release: - hw->phy.ops.release(hw); -out: - return ret_val; -} - -/** - * e1000e_configure_k1_ich8lan - Configure K1 power state - * @hw: pointer to the HW structure - * @enable: K1 state to configure - * - * Configure the K1 power state based on the provided parameter. - * Assumes semaphore already acquired. - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - **/ -s32 e1000e_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) -{ - s32 ret_val = E1000_SUCCESS; - u32 ctrl_reg = 0; - u32 ctrl_ext = 0; - u32 reg = 0; - u16 kmrn_reg = 0; - - ret_val = e1000e_read_kmrn_reg_locked(hw, - E1000_KMRNCTRLSTA_K1_CONFIG, - &kmrn_reg); - if (ret_val) - goto out; - - if (k1_enable) - kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; - else - kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; - - ret_val = e1000e_write_kmrn_reg_locked(hw, - E1000_KMRNCTRLSTA_K1_CONFIG, - kmrn_reg); - if (ret_val) - goto out; - - udelay(20); - ctrl_ext = er32(CTRL_EXT); - ctrl_reg = er32(CTRL); - - reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); - reg |= E1000_CTRL_FRCSPD; - ew32(CTRL, reg); - - E1000_WRITE_REG(hw, - E1000_CTRL_EXT, - ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); - udelay(20); - ew32(CTRL, ctrl_reg); - ew32(CTRL_EXT, ctrl_ext); - udelay(20); - -out: - return ret_val; -} - -/** - * e1000e_oem_bits_config_ich8lan - SW-based LCD Configuration - * @hw: pointer to the HW structure - * @d0_state: boolean if entering d0 or d3 device state - * - * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are - * collectively called OEM bits. The OEM Write Enable bit and SW Config bit - * in NVM determines whether HW should configure LPLU and Gbe Disable. - **/ -s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) -{ - s32 ret_val = 0; - u32 mac_reg; - u16 oem_reg; - - if (hw->mac.type != e1000_pchlan && hw->mac.type != e1000_pch2lan) - return ret_val; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - - if (hw->mac.type != e1000_pch2lan) { - mac_reg = er32(EXTCNF_CTRL); - if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) - goto out; - } - - mac_reg = er32(FEXTNVM); - if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) - goto out; - - mac_reg = er32(PHY_CTRL); - - ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg); - if (ret_val) - goto out; - - oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); - - if (d0_state) { - if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) - oem_reg |= HV_OEM_BITS_GBE_DIS; - - if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) - oem_reg |= HV_OEM_BITS_LPLU; - } else { - if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE) - oem_reg |= HV_OEM_BITS_GBE_DIS; - - if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU) - oem_reg |= HV_OEM_BITS_LPLU; - } - /* Restart auto-neg to activate the bits */ - if (!e1000e_check_reset_block(hw)) - oem_reg |= HV_OEM_BITS_RESTART_AN; - ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg); - -out: - hw->phy.ops.release(hw); - - return ret_val; -} - -/** - * e1000e_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be - * done after every PHY reset. - **/ -static s32 e1000e_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->mac.type != e1000_pchlan) - goto out; - - if (((hw->phy.type == e1000_phy_82577) && - ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || - ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { - /* Disable generation of early preamble */ - ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431); - if (ret_val) - goto out; - - /* Preamble tuning for SSC */ - ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204); - if (ret_val) - goto out; - } - - if (hw->phy.type == e1000_phy_82578) { - /* - * Return registers to default by doing a soft reset then - * writing 0x3140 to the control register. - */ - if (hw->phy.revision < 2) { - e1000e_phy_sw_reset(hw); - ret_val = e1e_wphy(hw, PHY_CONTROL, - 0x3140); - } - } - - /* Select page 0 */ - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - hw->phy.addr = 1; - ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); - if (ret_val) - goto out; - hw->phy.ops.release(hw); - - /* - * Configure the K1 Si workaround during phy reset assuming there is - * link so that it disables K1 if link is in 1Gbps. - */ - ret_val = e1000e_k1_gig_workaround_hv(hw, true); - -out: - return ret_val; -} - -/** - * e1000e_lan_init_done_ich8lan - Check for PHY config completion - * @hw: pointer to the HW structure - * - * Check the appropriate indication the MAC has finished configuring the - * PHY after a software reset. - **/ -static void e1000e_lan_init_done_ich8lan(struct e1000_hw *hw) -{ - u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; - - /* Wait for basic configuration completes before proceeding */ - do { - data = er32(STATUS); - data &= E1000_STATUS_LAN_INIT_DONE; - udelay(100); - } while ((!data) && --loop); - - /* - * If basic configuration is incomplete before the above loop - * count reaches 0, loading the configuration from NVM will - * leave the PHY in a bad state possibly resulting in no link. - */ - if (loop == 0) - e_dbg("LAN_INIT_DONE not set, increase timeout\n"); - - /* Clear the Init Done bit for the next init event */ - data = er32(STATUS); - data &= ~E1000_STATUS_LAN_INIT_DONE; - ew32(STATUS, data); -} - -/** - * e1000e_phy_hw_reset_ich8lan - Performs a PHY reset - * @hw: pointer to the HW structure - * - * Resets the PHY - * This is a function pointer entry point called by drivers - * or other shared routines. - **/ -static s32 e1000e_phy_hw_reset_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 reg; - - ret_val = e1000e_phy_hw_reset_generic(hw); - if (ret_val) - goto out; - - /* Allow time for h/w to get to a quiescent state after reset */ - msleep(10); - - if (hw->mac.type == e1000_pchlan) { - ret_val = e1000e_hv_phy_workarounds_ich8lan(hw); - if (ret_val) - goto out; - } - - /* Dummy read to clear the phy wakeup bit after lcd reset */ - if (hw->mac.type == e1000_pchlan) - e1e_rphy(hw, BM_WUC, ®); - - /* Configure the LCD with the extended configuration region in NVM */ - ret_val = e1000e_sw_lcd_config_ich8lan(hw); - if (ret_val) - goto out; - - /* Configure the LCD with the OEM bits in NVM */ - if (hw->mac.type == e1000_pchlan) - ret_val = e1000e_oem_bits_config_ich8lan(hw, true); - -out: - return ret_val; -} - -/** - * e1000e_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info - * @hw: pointer to the HW structure - * - * Wrapper for calling the get_phy_info routines for the appropriate phy type. - **/ -static s32 e1000e_get_phy_info_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = -E1000_ERR_PHY_TYPE; - - switch (hw->phy.type) { - case e1000_phy_ife: - ret_val = e1000e_get_phy_info_ife_ich8lan(hw); - break; - case e1000_phy_igp_3: - case e1000_phy_bm: - case e1000_phy_82578: - case e1000_phy_82577: - ret_val = e1000e_get_phy_info_igp(hw); - break; - default: - break; - } - - return ret_val; -} - -/** - * e1000e_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states - * @hw: pointer to the HW structure - * - * Populates "phy" structure with various feature states. - * This function is only called by other family-specific - * routines. - **/ -static s32 e1000e_get_phy_info_ife_ich8lan(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - e_dbg("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data); - if (ret_val) - goto out; - phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE) - ? false : true; - - if (phy->polarity_correction) { - ret_val = e1000e_check_polarity_ife(hw); - if (ret_val) - goto out; - } else { - /* Polarity is forced */ - phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - } - - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); - if (ret_val) - goto out; - - phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false; - - /* The following parameters are undefined for 10/100 operation. */ - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - -out: - return ret_val; -} - -/** - * e1000e_set_lplu_state_pchlan - Set Low Power Link Up state - * @hw: pointer to the HW structure - * @active: true to enable LPLU, false to disable - * - * Sets the LPLU state according to the active flag. For PCH, if OEM write - * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set - * the phy speed. This function will manually set the LPLU bit and restart - * auto-neg as hw would do. D3 and D0 LPLU will call the same function - * since it configures the same bit. - **/ -static s32 e1000e_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) -{ - s32 ret_val = E1000_SUCCESS; - u16 oem_reg; - - ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg); - if (ret_val) - goto out; - - if (active) - oem_reg |= HV_OEM_BITS_LPLU; - else - oem_reg &= ~HV_OEM_BITS_LPLU; - - oem_reg |= HV_OEM_BITS_RESTART_AN; - ret_val = e1e_wphy(hw, HV_OEM_BITS, oem_reg); - -out: - return ret_val; -} - -/** - * e1000e_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state - * @hw: pointer to the HW structure - * @active: true to enable LPLU, false to disable - * - * Sets the LPLU D0 state according to the active flag. When - * activating LPLU this function also disables smart speed - * and vice versa. LPLU will not be activated unless the - * device autonegotiation advertisement meets standards of - * either 10 or 10/100 or 10/100/1000 at all duplexes. - * This is a function pointer entry point only called by - * PHY setup routines. - **/ -static s32 e1000e_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 phy_ctrl; - s32 ret_val = E1000_SUCCESS; - u16 data; - - if (phy->type == e1000_phy_ife) - goto out; - - phy_ctrl = er32(PHY_CTRL); - - if (active) { - phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; - ew32(PHY_CTRL, phy_ctrl); - - if (phy->type != e1000_phy_igp_3) - goto out; - - /* - * Call gig speed drop workaround on LPLU before accessing - * any PHY registers - */ - if (hw->mac.type == e1000_ich8lan) - e1000e_gig_downshift_workaround_ich8lan(hw); - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else { - phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; - ew32(PHY_CTRL, phy_ctrl); - - if (phy->type != e1000_phy_igp_3) - goto out; - - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } - -out: - return ret_val; -} - -/** - * e1000e_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state - * @hw: pointer to the HW structure - * @active: true to enable LPLU, false to disable - * - * Sets the LPLU D3 state according to the active flag. When - * activating LPLU this function also disables smart speed - * and vice versa. LPLU will not be activated unless the - * device autonegotiation advertisement meets standards of - * either 10 or 10/100 or 10/100/1000 at all duplexes. - * This is a function pointer entry point only called by - * PHY setup routines. - **/ -static s32 e1000e_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 phy_ctrl; - s32 ret_val = E1000_SUCCESS; - u16 data; - - phy_ctrl = er32(PHY_CTRL); - - if (!active) { - phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; - ew32(PHY_CTRL, phy_ctrl); - - if (phy->type != e1000_phy_igp_3) - goto out; - - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || - (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || - (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { - phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; - ew32(PHY_CTRL, phy_ctrl); - - if (phy->type != e1000_phy_igp_3) - goto out; - - /* - * Call gig speed drop workaround on LPLU before accessing - * any PHY registers - */ - if (hw->mac.type == e1000_ich8lan) - e1000e_gig_downshift_workaround_ich8lan(hw); - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - } - -out: - return ret_val; -} - -/** - * e1000e_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 - * @hw: pointer to the HW structure - * @bank: pointer to the variable that returns the active bank - * - * Reads signature byte from the NVM using the flash access registers. - * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. - **/ -static s32 e1000e_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) -{ - u32 eecd; - struct e1000_nvm_info *nvm = &hw->nvm; - u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); - u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; - u8 sig_byte = 0; - s32 ret_val = E1000_SUCCESS; - - switch (hw->mac.type) { - case e1000_ich8lan: - case e1000_ich9lan: - eecd = er32(EECD); - if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == - E1000_EECD_SEC1VAL_VALID_MASK) { - if (eecd & E1000_EECD_SEC1VAL) - *bank = 1; - else - *bank = 0; - - goto out; - } - e_dbg("Unable to determine valid NVM bank via EEC - " - "reading flash signature\n"); - /* fall-thru */ - default: - /* set bank to 0 in case flash read fails */ - *bank = 0; - - /* Check bank 0 */ - ret_val = e1000e_read_flash_byte_ich8lan(hw, act_offset, - &sig_byte); - if (ret_val) - goto out; - if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == - E1000_ICH_NVM_SIG_VALUE) { - *bank = 0; - goto out; - } - - /* Check bank 1 */ - ret_val = e1000e_read_flash_byte_ich8lan(hw, act_offset + - bank1_offset, - &sig_byte); - if (ret_val) - goto out; - if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == - E1000_ICH_NVM_SIG_VALUE) { - *bank = 1; - goto out; - } - - e_dbg("ERROR: No valid NVM bank present\n"); - ret_val = -E1000_ERR_NVM; - break; - } -out: - return ret_val; -} - -/** - * e1000e_read_nvm_ich8lan - Read word(s) from the NVM - * @hw: pointer to the HW structure - * @offset: The offset (in bytes) of the word(s) to read. - * @words: Size of data to read in words - * @data: Pointer to the word(s) to read at offset. - * - * Reads a word(s) from the NVM using the flash access registers. - **/ -static s32 e1000e_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - u32 act_offset; - s32 ret_val = E1000_SUCCESS; - u32 bank = 0; - u16 i, word; - - if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || - (words == 0)) { - e_dbg("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - nvm->ops.acquire(hw); - - ret_val = e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank); - if (ret_val != E1000_SUCCESS) { - e_dbg("Could not detect valid bank, assuming bank 0\n"); - bank = 0; - } - - act_offset = (bank) ? nvm->flash_bank_size : 0; - act_offset += offset; - - ret_val = E1000_SUCCESS; - for (i = 0; i < words; i++) { - if ((dev_spec->shadow_ram) && - (dev_spec->shadow_ram[offset+i].modified)) { - data[i] = dev_spec->shadow_ram[offset+i].value; - } else { - ret_val = e1000e_read_flash_word_ich8lan(hw, - act_offset + i, - &word); - if (ret_val) - break; - data[i] = word; - } - } - - nvm->ops.release(hw); - -out: - if (ret_val) - e_dbg("NVM read error: %d\n", ret_val); - - return ret_val; -} - -/** - * e1000e_flash_cycle_init_ich8lan - Initialize flash - * @hw: pointer to the HW structure - * - * This function does initial flash setup so that a new read/write/erase cycle - * can be started. - **/ -static s32 e1000e_flash_cycle_init_ich8lan(struct e1000_hw *hw) -{ - union ich8_hws_flash_status hsfsts; - s32 ret_val = -E1000_ERR_NVM; - s32 i = 0; - - hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - - /* Check if the flash descriptor is valid */ - if (hsfsts.hsf_status.fldesvalid == 0) { - e_dbg("Flash descriptor invalid. " - "SW Sequencing must be used."); - goto out; - } - - /* Clear FCERR and DAEL in hw status by writing 1 */ - hsfsts.hsf_status.flcerr = 1; - hsfsts.hsf_status.dael = 1; - - ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); - - /* - * Either we should have a hardware SPI cycle in progress - * bit to check against, in order to start a new cycle or - * FDONE bit should be changed in the hardware so that it - * is 1 after hardware reset, which can then be used as an - * indication whether a cycle is in progress or has been - * completed. - */ - - if (hsfsts.hsf_status.flcinprog == 0) { - /* - * There is no cycle running at present, - * so we can start a cycle. - * Begin by setting Flash Cycle Done. - */ - hsfsts.hsf_status.flcdone = 1; - ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); - ret_val = E1000_SUCCESS; - } else { - /* - * Otherwise poll for sometime so the current - * cycle has a chance to end before giving up. - */ - for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { - hsfsts.regval = er16flash( - ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcinprog == 0) { - ret_val = E1000_SUCCESS; - break; - } - udelay(1); - } - if (ret_val == E1000_SUCCESS) { - /* - * Successful in waiting for previous cycle to timeout, - * now set the Flash Cycle Done. - */ - hsfsts.hsf_status.flcdone = 1; - ew16flash(ICH_FLASH_HSFSTS, - hsfsts.regval); - } else { - e_dbg("Flash controller busy, cannot get access"); - } - } - -out: - return ret_val; -} - -/** - * e1000e_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) - * @hw: pointer to the HW structure - * @timeout: maximum time to wait for completion - * - * This function starts a flash cycle and waits for its completion. - **/ -static s32 e1000e_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) -{ - union ich8_hws_flash_ctrl hsflctl; - union ich8_hws_flash_status hsfsts; - s32 ret_val = -E1000_ERR_NVM; - u32 i = 0; - - /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ - hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); - hsflctl.hsf_ctrl.flcgo = 1; - ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); - - /* wait till FDONE bit is set to 1 */ - do { - hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcdone == 1) - break; - udelay(1); - } while (i++ < timeout); - - if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) - ret_val = E1000_SUCCESS; - - return ret_val; -} - -/** - * e1000e_read_flash_word_ich8lan - Read word from flash - * @hw: pointer to the HW structure - * @offset: offset to data location - * @data: pointer to the location for storing the data - * - * Reads the flash word at offset into data. Offset is converted - * to bytes before read. - **/ -static s32 e1000e_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, - u16 *data) -{ - s32 ret_val; - - if (!data) { - ret_val = -E1000_ERR_NVM; - goto out; - } - - /* Must convert offset into bytes. */ - offset <<= 1; - - ret_val = e1000e_read_flash_data_ich8lan(hw, offset, 2, data); - -out: - return ret_val; -} - -/** - * e1000e_read_flash_byte_ich8lan - Read byte from flash - * @hw: pointer to the HW structure - * @offset: The offset of the byte to read. - * @data: Pointer to a byte to store the value read. - * - * Reads a single byte from the NVM using the flash access registers. - **/ -static s32 e1000e_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, - u8 *data) -{ - s32 ret_val = E1000_SUCCESS; - u16 word = 0; - - ret_val = e1000e_read_flash_data_ich8lan(hw, offset, 1, &word); - if (ret_val) - goto out; - - *data = (u8)word; - -out: - return ret_val; -} - -/** - * e1000e_read_flash_data_ich8lan - Read byte or word from NVM - * @hw: pointer to the HW structure - * @offset: The offset (in bytes) of the byte or word to read. - * @size: Size of data to read, 1=byte 2=word - * @data: Pointer to the word to store the value read. - * - * Reads a byte or word from the NVM using the flash access registers. - **/ -static s32 e1000e_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, - u8 size, u16 *data) -{ - union ich8_hws_flash_status hsfsts; - union ich8_hws_flash_ctrl hsflctl; - u32 flash_linear_addr; - u32 flash_data = 0; - s32 ret_val = -E1000_ERR_NVM; - u8 count = 0; - - if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) - goto out; - flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + - hw->nvm.flash_base_addr; - - do { - udelay(1); - /* Steps */ - ret_val = e1000e_flash_cycle_init_ich8lan(hw); - if (ret_val != E1000_SUCCESS) - break; - - hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); - /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ - hsflctl.hsf_ctrl.fldbcount = size - 1; - hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; - ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); - - ew32flash(ICH_FLASH_FADDR, flash_linear_addr); - - ret_val = e1000e_flash_cycle_ich8lan(hw, - ICH_FLASH_READ_COMMAND_TIMEOUT); - - /* - * Check if FCERR is set to 1, if set to 1, clear it - * and try the whole sequence a few more times, else - * read in (shift in) the Flash Data0, the order is - * least significant byte first msb to lsb - */ - if (ret_val == E1000_SUCCESS) { - flash_data = er32flash(ICH_FLASH_FDATA0); - if (size == 1) - *data = (u8)(flash_data & 0x000000FF); - else if (size == 2) - *data = (u16)(flash_data & 0x0000FFFF); - break; - } else { - /* - * If we've gotten here, then things are probably - * completely hosed, but if the error condition is - * detected, it won't hurt to give it another try... - * ICH_FLASH_CYCLE_REPEAT_COUNT times. - */ - hsfsts.regval = er16flash( - ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcerr == 1) { - /* Repeat for some time before giving up. */ - continue; - } else if (hsfsts.hsf_status.flcdone == 0) { - e_dbg("Timeout error - flash cycle " - "did not complete."); - break; - } - } - } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); - -out: - return ret_val; -} - -/** - * e1000e_write_nvm_ich8lan - Write word(s) to the NVM - * @hw: pointer to the HW structure - * @offset: The offset (in bytes) of the word(s) to write. - * @words: Size of data to write in words - * @data: Pointer to the word(s) to write at offset. - * - * Writes a byte or word to the NVM using the flash access registers. - **/ -static s32 e1000e_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - s32 ret_val = E1000_SUCCESS; - u16 i; - - if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || - (words == 0)) { - e_dbg("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - nvm->ops.acquire(hw); - - for (i = 0; i < words; i++) { - dev_spec->shadow_ram[offset+i].modified = true; - dev_spec->shadow_ram[offset+i].value = data[i]; - } - - nvm->ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000e_update_nvm_checksum_ich8lan - Update the checksum for NVM - * @hw: pointer to the HW structure - * - * The NVM checksum is updated by calling the generic update_nvm_checksum, - * which writes the checksum to the shadow ram. The changes in the shadow - * ram are then committed to the EEPROM by processing each bank at a time - * checking for the modified bit and writing only the pending changes. - * After a successful commit, the shadow ram is cleared and is ready for - * future writes. - **/ -static s32 e1000e_update_nvm_checksum_ich8lan(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - u32 i, act_offset, new_bank_offset, old_bank_offset, bank; - s32 ret_val; - u16 data; - - ret_val = e1000e_update_nvm_checksum_generic(hw); - if (ret_val) - goto out; - - if (nvm->type != e1000_nvm_flash_sw) - goto out; - - nvm->ops.acquire(hw); - - /* - * We're writing to the opposite bank so if we're on bank 1, - * write to bank 0 etc. We also need to erase the segment that - * is going to be written - */ - ret_val = e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank); - if (ret_val != E1000_SUCCESS) { - e_dbg("Could not detect valid bank, assuming bank 0\n"); - bank = 0; - } - - if (bank == 0) { - new_bank_offset = nvm->flash_bank_size; - old_bank_offset = 0; - ret_val = e1000e_erase_flash_bank_ich8lan(hw, 1); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } - } else { - old_bank_offset = nvm->flash_bank_size; - new_bank_offset = 0; - ret_val = e1000e_erase_flash_bank_ich8lan(hw, 0); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } - } - - for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { - /* - * Determine whether to write the value stored - * in the other NVM bank or a modified value stored - * in the shadow RAM - */ - if (dev_spec->shadow_ram[i].modified) { - data = dev_spec->shadow_ram[i].value; - } else { - ret_val = e1000e_read_flash_word_ich8lan(hw, i + - old_bank_offset, - &data); - if (ret_val) - break; - } - - /* - * If the word is 0x13, then make sure the signature bits - * (15:14) are 11b until the commit has completed. - * This will allow us to write 10b which indicates the - * signature is valid. We want to do this after the write - * has completed so that we don't mark the segment valid - * while the write is still in progress - */ - if (i == E1000_ICH_NVM_SIG_WORD) - data |= E1000_ICH_NVM_SIG_MASK; - - /* Convert offset to bytes. */ - act_offset = (i + new_bank_offset) << 1; - - udelay(100); - /* Write the bytes to the new bank. */ - ret_val = e1000e_retry_write_flash_byte_ich8lan(hw, - act_offset, - (u8)data); - if (ret_val) - break; - - udelay(100); - ret_val = e1000e_retry_write_flash_byte_ich8lan(hw, - act_offset + 1, - (u8)(data >> 8)); - if (ret_val) - break; - } - - /* - * Don't bother writing the segment valid bits if sector - * programming failed. - */ - if (ret_val) { - e_dbg("Flash commit failed.\n"); - nvm->ops.release(hw); - goto out; - } - - /* - * Finally validate the new segment by setting bit 15:14 - * to 10b in word 0x13 , this can be done without an - * erase as well since these bits are 11 to start with - * and we need to change bit 14 to 0b - */ - act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; - ret_val = e1000e_read_flash_word_ich8lan(hw, act_offset, &data); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } - - data &= 0xBFFF; - ret_val = e1000e_retry_write_flash_byte_ich8lan(hw, - act_offset * 2 + 1, - (u8)(data >> 8)); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } - - /* - * And invalidate the previously valid segment by setting - * its signature word (0x13) high_byte to 0b. This can be - * done without an erase because flash erase sets all bits - * to 1's. We can write 1's to 0's without an erase - */ - act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; - ret_val = e1000e_retry_write_flash_byte_ich8lan(hw, act_offset, 0); - if (ret_val) { - nvm->ops.release(hw); - goto out; - } - - /* Great! Everything worked, we can now clear the cached entries. */ - for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { - dev_spec->shadow_ram[i].modified = false; - dev_spec->shadow_ram[i].value = 0xFFFF; - } - - nvm->ops.release(hw); - - /* - * Reload the EEPROM, or else modifications will not appear - * until after the next adapter reset. - */ - nvm->ops.reload(hw); - msleep(10); - -out: - if (ret_val) - e_dbg("NVM update error: %d\n", ret_val); - - return ret_val; -} - -/** - * e1000e_validate_nvm_checksum_ich8lan - Validate EEPROM checksum - * @hw: pointer to the HW structure - * - * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. - * If the bit is 0, that the EEPROM had been modified, but the checksum was not - * calculated, in which case we need to calculate the checksum and set bit 6. - **/ -static s32 e1000e_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 data; - - /* - * Read 0x19 and check bit 6. If this bit is 0, the checksum - * needs to be fixed. This bit is an indication that the NVM - * was prepared by OEM software and did not calculate the - * checksum...a likely scenario. - */ - ret_val = e1000e_read_nvm(hw, 0x19, 1, &data); - if (ret_val) - goto out; - - if ((data & 0x40) == 0) { - data |= 0x40; - ret_val = e1000e_write_nvm(hw, 0x19, 1, &data); - if (ret_val) - goto out; - ret_val = e1000e_update_nvm_checksum(hw); - if (ret_val) - goto out; - } - - ret_val = e1000e_validate_nvm_checksum_generic(hw); - -out: - return ret_val; -} - -/** - * e1000e_write_flash_data_ich8lan - Writes bytes to the NVM - * @hw: pointer to the HW structure - * @offset: The offset (in bytes) of the byte/word to read. - * @size: Size of data to read, 1=byte 2=word - * @data: The byte(s) to write to the NVM. - * - * Writes one/two bytes to the NVM using the flash access registers. - **/ -static s32 e1000e_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, - u8 size, u16 data) -{ - union ich8_hws_flash_status hsfsts; - union ich8_hws_flash_ctrl hsflctl; - u32 flash_linear_addr; - u32 flash_data = 0; - s32 ret_val = -E1000_ERR_NVM; - u8 count = 0; - - if (size < 1 || size > 2 || data > size * 0xff || - offset > ICH_FLASH_LINEAR_ADDR_MASK) - goto out; - - flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) + - hw->nvm.flash_base_addr; - - do { - udelay(1); - /* Steps */ - ret_val = e1000e_flash_cycle_init_ich8lan(hw); - if (ret_val != E1000_SUCCESS) - break; - - hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); - /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ - hsflctl.hsf_ctrl.fldbcount = size - 1; - hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; - ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); - - ew32flash(ICH_FLASH_FADDR, flash_linear_addr); - - if (size == 1) - flash_data = (u32)data & 0x00FF; - else - flash_data = (u32)data; - - ew32flash(ICH_FLASH_FDATA0, flash_data); - - /* - * check if FCERR is set to 1 , if set to 1, clear it - * and try the whole sequence a few more times else done - */ - ret_val = e1000e_flash_cycle_ich8lan(hw, - ICH_FLASH_WRITE_COMMAND_TIMEOUT); - if (ret_val == E1000_SUCCESS) - break; - - /* - * If we're here, then things are most likely - * completely hosed, but if the error condition - * is detected, it won't hurt to give it another - * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. - */ - hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcerr == 1) { - /* Repeat for some time before giving up. */ - continue; - } else if (hsfsts.hsf_status.flcdone == 0) { - e_dbg("Timeout error - flash cycle " - "did not complete."); - break; - } - } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); - -out: - return ret_val; -} - -/** - * e1000e_write_flash_byte_ich8lan - Write a single byte to NVM - * @hw: pointer to the HW structure - * @offset: The index of the byte to read. - * @data: The byte to write to the NVM. - * - * Writes a single byte to the NVM using the flash access registers. - **/ -static s32 e1000e_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, - u8 data) -{ - u16 word = (u16)data; - - return e1000e_write_flash_data_ich8lan(hw, offset, 1, word); -} - -/** - * e1000e_retry_write_flash_byte_ich8lan - Writes a single byte to NVM - * @hw: pointer to the HW structure - * @offset: The offset of the byte to write. - * @byte: The byte to write to the NVM. - * - * Writes a single byte to the NVM using the flash access registers. - * Goes through a retry algorithm before giving up. - **/ -static s32 e1000e_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, - u32 offset, u8 byte) -{ - s32 ret_val; - u16 program_retries; - - ret_val = e1000e_write_flash_byte_ich8lan(hw, offset, byte); - if (ret_val == E1000_SUCCESS) - goto out; - - for (program_retries = 0; program_retries < 100; program_retries++) { - e_dbg("Retrying Byte %2.2X at offset %u\n", byte, offset); - udelay(100); - ret_val = e1000e_write_flash_byte_ich8lan(hw, offset, byte); - if (ret_val == E1000_SUCCESS) - break; - } - if (program_retries == 100) { - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM - * @hw: pointer to the HW structure - * @bank: 0 for first bank, 1 for second bank, etc. - * - * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. - * bank N is 4096 * N + flash_reg_addr. - **/ -static s32 e1000e_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - union ich8_hws_flash_status hsfsts; - union ich8_hws_flash_ctrl hsflctl; - u32 flash_linear_addr; - /* bank size is in 16bit words - adjust to bytes */ - u32 flash_bank_size = nvm->flash_bank_size * 2; - s32 ret_val = E1000_SUCCESS; - s32 count = 0; - s32 j, iteration, sector_size; - - hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); - - /* - * Determine HW Sector size: Read BERASE bits of hw flash status - * register - * 00: The Hw sector is 256 bytes, hence we need to erase 16 - * consecutive sectors. The start index for the nth Hw sector - * can be calculated as = bank * 4096 + n * 256 - * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. - * The start index for the nth Hw sector can be calculated - * as = bank * 4096 - * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 - * (ich9 only, otherwise error condition) - * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 - */ - switch (hsfsts.hsf_status.berasesz) { - case 0: - /* Hw sector size 256 */ - sector_size = ICH_FLASH_SEG_SIZE_256; - iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; - break; - case 1: - sector_size = ICH_FLASH_SEG_SIZE_4K; - iteration = 1; - break; - case 2: - sector_size = ICH_FLASH_SEG_SIZE_8K; - iteration = 1; - break; - case 3: - sector_size = ICH_FLASH_SEG_SIZE_64K; - iteration = 1; - break; - default: - ret_val = -E1000_ERR_NVM; - goto out; - } - - /* Start with the base address, then add the sector offset. */ - flash_linear_addr = hw->nvm.flash_base_addr; - flash_linear_addr += (bank) ? flash_bank_size : 0; - - for (j = 0; j < iteration ; j++) { - do { - /* Steps */ - ret_val = e1000e_flash_cycle_init_ich8lan(hw); - if (ret_val) - goto out; - - /* - * Write a value 11 (block Erase) in Flash - * Cycle field in hw flash control - */ - hsflctl.regval = er16flash( - ICH_FLASH_HSFCTL); - hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; - ew16flash(ICH_FLASH_HSFCTL, - hsflctl.regval); - - /* - * Write the last 24 bits of an index within the - * block into Flash Linear address field in Flash - * Address. - */ - flash_linear_addr += (j * sector_size); - ew32flash(ICH_FLASH_FADDR, - flash_linear_addr); - - ret_val = e1000e_flash_cycle_ich8lan(hw, - ICH_FLASH_ERASE_COMMAND_TIMEOUT); - if (ret_val == E1000_SUCCESS) - break; - - /* - * Check if FCERR is set to 1. If 1, - * clear it and try the whole sequence - * a few more times else Done - */ - hsfsts.regval = er16flash( - ICH_FLASH_HSFSTS); - if (hsfsts.hsf_status.flcerr == 1) - /* repeat for some time before giving up */ - continue; - else if (hsfsts.hsf_status.flcdone == 0) - goto out; - } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); - } - -out: - return ret_val; -} - -/** - * e1000e_valid_led_default_ich8lan - Set the default LED settings - * @hw: pointer to the HW structure - * @data: Pointer to the LED settings - * - * Reads the LED default settings from the NVM to data. If the NVM LED - * settings is all 0's or F's, set the LED default to a valid LED default - * setting. - **/ -static s32 e1000e_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) -{ - s32 ret_val; - - ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - - if (*data == ID_LED_RESERVED_0000 || - *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT_ICH8LAN; - -out: - return ret_val; -} - -/** - * e1000e_id_led_init_pchlan - store LED configurations - * @hw: pointer to the HW structure - * - * PCH does not control LEDs via the LEDCTL register, rather it uses - * the PHY LED configuration register. - * - * PCH also does not have an "always on" or "always off" mode which - * complicates the ID feature. Instead of using the "on" mode to indicate - * in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init()), - * use "link_up" mode. The LEDs will still ID on request if there is no - * link based on logic in e1000e_led_[on|off]_pchlan(). - **/ -static s32 e1000e_id_led_init_pchlan(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; - const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; - u16 data, i, temp, shift; - - /* Get default ID LED modes */ - ret_val = hw->nvm.ops.valid_led_default(hw, &data); - if (ret_val) - goto out; - - mac->ledctl_default = er32(LEDCTL); - mac->ledctl_mode1 = mac->ledctl_default; - mac->ledctl_mode2 = mac->ledctl_default; - - for (i = 0; i < 4; i++) { - temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; - shift = (i * 5); - switch (temp) { - case ID_LED_ON1_DEF2: - case ID_LED_ON1_ON2: - case ID_LED_ON1_OFF2: - mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); - mac->ledctl_mode1 |= (ledctl_on << shift); - break; - case ID_LED_OFF1_DEF2: - case ID_LED_OFF1_ON2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); - mac->ledctl_mode1 |= (ledctl_off << shift); - break; - default: - /* Do nothing */ - break; - } - switch (temp) { - case ID_LED_DEF1_ON2: - case ID_LED_ON1_ON2: - case ID_LED_OFF1_ON2: - mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); - mac->ledctl_mode2 |= (ledctl_on << shift); - break; - case ID_LED_DEF1_OFF2: - case ID_LED_ON1_OFF2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); - mac->ledctl_mode2 |= (ledctl_off << shift); - break; - default: - /* Do nothing */ - break; - } - } - -out: - return ret_val; -} - -/** - * e1000e_get_bus_info_ich8lan - Get/Set the bus type and width - * @hw: pointer to the HW structure - * - * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability - * register, so the the bus width is hard coded. - **/ -static s32 e1000e_get_bus_info_ich8lan(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - s32 ret_val; - - ret_val = e1000e_get_bus_info_pcie(hw); - - /* - * ICH devices are "PCI Express"-ish. They have - * a configuration space, but do not contain - * PCI Express Capability registers, so bus width - * must be hardcoded. - */ - if (bus->width == e1000_bus_width_unknown) - bus->width = e1000_bus_width_pcie_x1; - - return ret_val; -} - -/** - * e1000e_reset_hw_ich8lan - Reset the hardware - * @hw: pointer to the HW structure - * - * Does a full reset of the hardware which includes a reset of the PHY and - * MAC. - **/ -static s32 e1000e_reset_hw_ich8lan(struct e1000_hw *hw) -{ - struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - u16 reg; - u32 ctrl, kab; - s32 ret_val; - - /* - * Prevent the PCI-E bus from sticking if there is no TLP connection - * on the last TLP read/write transaction when MAC is reset. - */ - ret_val = e1000e_disable_pcie_master(hw); - if (ret_val) - e_dbg("PCI-E Master disable polling has failed.\n"); - - e_dbg("Masking off all interrupts\n"); - ew32(IMC, 0xffffffff); - - /* - * Disable the Transmit and Receive units. Then delay to allow - * any pending transactions to complete before we hit the MAC - * with the global reset. - */ - ew32(RCTL, 0); - ew32(TCTL, E1000_TCTL_PSP); - e1e_flush(); - - msleep(10); - - /* Workaround for ICH8 bit corruption issue in FIFO memory */ - if (hw->mac.type == e1000_ich8lan) { - /* Set Tx and Rx buffer allocation to 8k apiece. */ - ew32(PBA, E1000_PBA_8K); - /* Set Packet Buffer Size to 16k. */ - ew32(PBS, E1000_PBS_16K); - } - - if (hw->mac.type == e1000_pchlan) { - /* Save the NVM K1 bit setting*/ - ret_val = e1000e_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®); - if (ret_val) - return ret_val; - - if (reg & E1000_NVM_K1_ENABLE) - dev_spec->nvm_k1_enabled = true; - else - dev_spec->nvm_k1_enabled = false; - } - - ctrl = er32(CTRL); - - if (!e1000e_check_reset_block(hw) && !hw->phy.reset_disable) { - /* Clear PHY Reset Asserted bit */ - if (hw->mac.type >= e1000_pchlan) { - u32 status = er32(STATUS); - ew32(STATUS, status & - ~E1000_STATUS_PHYRA); - } - - /* - * PHY HW reset requires MAC CORE reset at the same - * time to make sure the interface between MAC and the - * external PHY is reset. - */ - ctrl |= E1000_CTRL_PHY_RST; - } - ret_val = e1000e_acquire_swflag_ich8lan(hw); - e_dbg("Issuing a global reset to ich8lan\n"); - ew32(CTRL, (ctrl | E1000_CTRL_RST)); - msleep(20); - - if (!ret_val) - e1000e_release_swflag_ich8lan(hw); - - if (ctrl & E1000_CTRL_PHY_RST) - ret_val = hw->phy.ops.get_cfg_done(hw); - - if (hw->mac.type >= e1000_ich10lan) { - e1000e_lan_init_done_ich8lan(hw); - } else { - ret_val = e1000e_get_auto_rd_done(hw); - if (ret_val) { - /* - * When auto config read does not complete, do not - * return with an error. This can happen in situations - * where there is no eeprom and prevents getting link. - */ - e_dbg("Auto Read Done did not complete\n"); - } - } - /* Dummy read to clear the phy wakeup bit after lcd reset */ - if (hw->mac.type == e1000_pchlan || hw->mac.type == e1000_pch2lan) - e1e_rphy(hw, BM_WUC, ®); - - ret_val = e1000e_sw_lcd_config_ich8lan(hw); - if (ret_val) - goto out; - - if (hw->mac.type == e1000_pchlan) { - ret_val = e1000e_oem_bits_config_ich8lan(hw, true); - if (ret_val) - goto out; - } - /* - * For PCH, this write will make sure that any noise - * will be detected as a CRC error and be dropped rather than show up - * as a bad packet to the DMA engine. - */ - if (hw->mac.type == e1000_pchlan) - ew32(CRC_OFFSET, 0x65656565); - - ew32(IMC, 0xffffffff); - er32(ICR); - - kab = er32(KABGTXD); - kab |= E1000_KABGTXD_BGSQLBIAS; - ew32(KABGTXD, kab); - - if (hw->mac.type == e1000_pchlan) - ret_val = e1000e_hv_phy_workarounds_ich8lan(hw); - -out: - return ret_val; -} - -/** - * e1000e_init_hw_ich8lan - Initialize the hardware - * @hw: pointer to the HW structure - * - * Prepares the hardware for transmit and receive by doing the following: - * - initialize hardware bits - * - initialize LED identification - * - setup receive address registers - * - setup flow control - * - setup transmit descriptors - * - clear statistics - **/ -static s32 e1000e_init_hw_ich8lan(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 ctrl_ext, txdctl, snoop; - s32 ret_val; - u16 i; - - e1000e_initialize_hw_bits_ich8lan(hw); - - /* Initialize identification LED */ - ret_val = mac->ops.id_led_init(hw); - if (ret_val) - /* This is not fatal and we should not stop init due to this */ - e_dbg("Error initializing identification LED\n"); - - /* Setup the receive address. */ - e1000e_init_rx_addrs(hw, mac->rar_entry_count); - - /* Zero out the Multicast HASH table */ - e_dbg("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - - /* - * The 82578 Rx buffer will stall if wakeup is enabled in host and - * the ME. Reading the BM_WUC register will clear the host wakeup bit. - * Reset the phy after disabling host wakeup to reset the Rx buffer. - */ - if (hw->phy.type == e1000_phy_82578) { - e1e_rphy(hw, BM_WUC, &i); - ret_val = e1000e_phy_hw_reset_ich8lan(hw); - if (ret_val) - return ret_val; - } - - /* Setup link and flow control */ - ret_val = mac->ops.setup_link(hw); - - /* Set the transmit descriptor write-back policy for both queues */ - txdctl = er32(TXDCTL(0)); - txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB; - txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | - E1000_TXDCTL_MAX_TX_DESC_PREFETCH; - ew32(TXDCTL(0), txdctl); - txdctl = er32(TXDCTL(1)); - txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) | - E1000_TXDCTL_FULL_TX_DESC_WB; - txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) | - E1000_TXDCTL_MAX_TX_DESC_PREFETCH; - ew32(TXDCTL(1), txdctl); - - /* - * ICH8 has opposite polarity of no_snoop bits. - * By default, we should use snoop behavior. - */ - if (mac->type == e1000_ich8lan) - snoop = PCIE_ICH8_SNOOP_ALL; - else - snoop = (u32)~(PCIE_NO_SNOOP_ALL); - e1000e_set_pcie_no_snoop(hw, snoop); - - ctrl_ext = er32(CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_RO_DIS; - ew32(CTRL_EXT, ctrl_ext); - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - e1000e_clear_hw_cntrs_ich8lan(hw); - - return ret_val; -} -/** - * e1000e_initialize_hw_bits_ich8lan - Initialize required hardware bits - * @hw: pointer to the HW structure - * - * Sets/Clears required hardware bits necessary for correctly setting up the - * hardware for transmit and receive. - **/ -static void e1000e_initialize_hw_bits_ich8lan(struct e1000_hw *hw) -{ - u32 reg; - - /* Extended Device Control */ - reg = er32(CTRL_EXT); - reg |= (1 << 22); - /* Enable PHY low-power state when MAC is at D3 w/o WoL */ - if (hw->mac.type >= e1000_pchlan) - reg |= E1000_CTRL_EXT_PHYPDEN; - ew32(CTRL_EXT, reg); - - /* Transmit Descriptor Control 0 */ - reg = er32(TXDCTL(0)); - reg |= (1 << 22); - ew32(TXDCTL(0), reg); - - /* Transmit Descriptor Control 1 */ - reg = er32(TXDCTL(1)); - reg |= (1 << 22); - ew32(TXDCTL(1), reg); - - /* Transmit Arbitration Control 0 */ - reg = er32(TARC(0)); - if (hw->mac.type == e1000_ich8lan) - reg |= (1 << 28) | (1 << 29); - reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27); - ew32(TARC(0), reg); - - /* Transmit Arbitration Control 1 */ - reg = er32(TARC(1)); - if (er32(TCTL) & E1000_TCTL_MULR) - reg &= ~(1 << 28); - else - reg |= (1 << 28); - reg |= (1 << 24) | (1 << 26) | (1 << 30); - ew32(TARC(1), reg); - - /* Device Status */ - if (hw->mac.type == e1000_ich8lan) { - reg = er32(STATUS); - reg &= ~(1 << 31); - ew32(STATUS, reg); - } - - return; -} - -/** - * e1000e_setup_link_ich8lan - Setup flow control and link settings - * @hw: pointer to the HW structure - * - * Determines which flow control settings to use, then configures flow - * control. Calls the appropriate media-specific link configuration - * function. Assuming the adapter has a valid link partner, a valid link - * should be established. Assumes the hardware has previously been reset - * and the transmitter and receiver are not enabled. - **/ -static s32 e1000e_setup_link_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (e1000e_check_reset_block(hw)) - goto out; - - /* - * ICH parts do not have a word in the NVM to determine - * the default flow control setting, so we explicitly - * set it to full. - */ - if (hw->fc.requested_mode == e1000_fc_default) - hw->fc.requested_mode = e1000_fc_full; - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - hw->fc.current_mode = hw->fc.requested_mode; - - e_dbg("After fix-ups FlowControl is now = %x\n", - hw->fc.current_mode); - - /* Continue to configure the copper link. */ - ret_val = hw->mac.ops.setup_physical_interface(hw); - if (ret_val) - goto out; - - ew32(FCTTV, hw->fc.pause_time); - if ((hw->phy.type == e1000_phy_82578) || - (hw->phy.type == e1000_phy_82579) || - (hw->phy.type == e1000_phy_82577)) { - ret_val = e1e_wphy(hw, - PHY_REG(BM_PORT_CTRL_PAGE, 27), - hw->fc.pause_time); - if (ret_val) - goto out; - } - - ret_val = e1000e_set_fc_watermarks(hw); - -out: - return ret_val; -} - -/** - * e1000e_setup_copper_link_ich8lan - Configure MAC/PHY interface - * @hw: pointer to the HW structure - * - * Configures the kumeran interface to the PHY to wait the appropriate time - * when polling the PHY, then call the generic setup_copper_link to finish - * configuring the copper link. - **/ -static s32 e1000e_setup_copper_link_ich8lan(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - u16 reg_data; - - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_SLU; - ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - ew32(CTRL, ctrl); - - /* - * Set the mac to wait the maximum time between each iteration - * and increase the max iterations when polling the phy; - * this fixes erroneous timeouts at 10Mbps. - */ - ret_val = e1000e_write_kmrn_reg(hw, - E1000_KMRNCTRLSTA_TIMEOUTS, - 0xFFFF); - if (ret_val) - goto out; - ret_val = e1000e_read_kmrn_reg(hw, - E1000_KMRNCTRLSTA_INBAND_PARAM, - ®_data); - if (ret_val) - goto out; - reg_data |= 0x3F; - ret_val = e1000e_write_kmrn_reg(hw, - E1000_KMRNCTRLSTA_INBAND_PARAM, - reg_data); - if (ret_val) - goto out; - - switch (hw->phy.type) { - case e1000_phy_igp_3: - ret_val = e1000e_copper_link_setup_igp(hw); - if (ret_val) - goto out; - break; - case e1000_phy_bm: - case e1000_phy_82578: - ret_val = e1000e_copper_link_setup_m88(hw); - if (ret_val) - goto out; - break; - case e1000_phy_82577: - case e1000_phy_82579: - ret_val = e1000e_copper_link_setup_82577(hw); - if (ret_val) - goto out; - break; - case e1000_phy_ife: - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, - ®_data); - if (ret_val) - goto out; - - reg_data &= ~IFE_PMC_AUTO_MDIX; - - switch (hw->phy.mdix) { - case 1: - reg_data &= ~IFE_PMC_FORCE_MDIX; - break; - case 2: - reg_data |= IFE_PMC_FORCE_MDIX; - break; - case 0: - default: - reg_data |= IFE_PMC_AUTO_MDIX; - break; - } - ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, - reg_data); - if (ret_val) - goto out; - break; - default: - break; - } - ret_val = e1000e_setup_copper_link(hw); - -out: - return ret_val; -} - -/** - * e1000e_get_link_up_info_ich8lan - Get current link speed and duplex - * @hw: pointer to the HW structure - * @speed: pointer to store current link speed - * @duplex: pointer to store the current link duplex - * - * Calls the generic get_speed_and_duplex to retrieve the current link - * information and then calls the Kumeran lock loss workaround for links at - * gigabit speeds. - **/ -static s32 e1000e_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, - u16 *duplex) -{ - s32 ret_val; - - ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex); - if (ret_val) - goto out; - - if ((hw->mac.type == e1000_ich8lan) && - (hw->phy.type == e1000_phy_igp_3) && - (*speed == SPEED_1000)) { - ret_val = e1000e_kmrn_lock_loss_workaround_ich8lan(hw); - } - -out: - return ret_val; -} - -/** - * e1000e_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround - * @hw: pointer to the HW structure - * - * Work-around for 82566 Kumeran PCS lock loss: - * On link status change (i.e. PCI reset, speed change) and link is up and - * speed is gigabit- - * 0) if workaround is optionally disabled do nothing - * 1) wait 1ms for Kumeran link to come up - * 2) check Kumeran Diagnostic register PCS lock loss bit - * 3) if not set the link is locked (all is good), otherwise... - * 4) reset the PHY - * 5) repeat up to 10 times - * Note: this is only called for IGP3 copper when speed is 1gb. - **/ -static s32 e1000e_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) -{ - struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - u32 phy_ctrl; - s32 ret_val = E1000_SUCCESS; - u16 i, data; - bool link; - - if (!(dev_spec->kmrn_lock_loss_workaround_enabled)) - goto out; - - /* - * Make sure link is up before proceeding. If not just return. - * Attempting this while link is negotiating fouled up link - * stability - */ - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (!link) { - ret_val = E1000_SUCCESS; - goto out; - } - - for (i = 0; i < 10; i++) { - /* read once to clear */ - ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); - if (ret_val) - goto out; - /* and again to get new status */ - ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); - if (ret_val) - goto out; - - /* check for PCS lock */ - if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* Issue PHY reset */ - e1000e_phy_hw_reset(hw); - mdelay(5); - } - /* Disable GigE link negotiation */ - phy_ctrl = er32(PHY_CTRL); - phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | - E1000_PHY_CTRL_NOND0A_GBE_DISABLE); - ew32(PHY_CTRL, phy_ctrl); - - /* - * Call gig speed drop workaround on Gig disable before accessing - * any PHY registers - */ - e1000e_gig_downshift_workaround_ich8lan(hw); - - /* unable to acquire PCS lock */ - ret_val = -E1000_ERR_PHY; - -out: - return ret_val; -} - -/** - * e1000e_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state - * @hw: pointer to the HW structure - * @state: boolean value used to set the current Kumeran workaround state - * - * If ICH8, set the current Kumeran workaround state (enabled - true - * /disabled - false). - **/ -void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, - bool state) -{ - struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; - - if (hw->mac.type != e1000_ich8lan) { - e_dbg("Workaround applies to ICH8 only.\n"); - return; - } - - dev_spec->kmrn_lock_loss_workaround_enabled = state; - - return; -} - -/** - * e1000e_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 - * @hw: pointer to the HW structure - * - * Workaround for 82566 power-down on D3 entry: - * 1) disable gigabit link - * 2) write VR power-down enable - * 3) read it back - * Continue if successful, else issue LCD reset and repeat - **/ -void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) -{ - u32 reg; - u16 data; - u8 retry = 0; - - if (hw->phy.type != e1000_phy_igp_3) - goto out; - - /* Try the workaround twice (if needed) */ - do { - /* Disable link */ - reg = er32(PHY_CTRL); - reg |= (E1000_PHY_CTRL_GBE_DISABLE | - E1000_PHY_CTRL_NOND0A_GBE_DISABLE); - ew32(PHY_CTRL, reg); - - /* - * Call gig speed drop workaround on Gig disable before - * accessing any PHY registers - */ - if (hw->mac.type == e1000_ich8lan) - e1000e_gig_downshift_workaround_ich8lan(hw); - - /* Write VR power-down enable */ - e1e_rphy(hw, IGP3_VR_CTRL, &data); - data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; - e1e_wphy(hw, IGP3_VR_CTRL, - data | IGP3_VR_CTRL_MODE_SHUTDOWN); - - /* Read it back and test */ - e1e_rphy(hw, IGP3_VR_CTRL, &data); - data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; - if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) - break; - - /* Issue PHY reset and repeat at most one more time */ - reg = er32(CTRL); - ew32(CTRL, reg | E1000_CTRL_PHY_RST); - retry++; - } while (retry); - -out: - return; -} - -/** - * e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working - * @hw: pointer to the HW structure - * - * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), - * LPLU, Gig disable, MDIC PHY reset): - * 1) Set Kumeran Near-end loopback - * 2) Clear Kumeran Near-end loopback - * Should only be called for ICH8[m] devices with IGP_3 Phy. - **/ -void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 reg_data; - - if ((hw->mac.type != e1000_ich8lan) || - (hw->phy.type != e1000_phy_igp_3)) - goto out; - - ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, - ®_data); - if (ret_val) - goto out; - reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; - ret_val = e1000e_write_kmrn_reg(hw, - E1000_KMRNCTRLSTA_DIAG_OFFSET, - reg_data); - if (ret_val) - goto out; - reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; - ret_val = e1000e_write_kmrn_reg(hw, - E1000_KMRNCTRLSTA_DIAG_OFFSET, - reg_data); -out: - return; -} - -/** - * e1000e_disable_gig_wol_ich8lan - disable gig during WoL - * @hw: pointer to the HW structure - * - * During S0 to Sx transition, it is possible the link remains at gig - * instead of negotiating to a lower speed. Before going to Sx, set - * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation - * to a lower speed. - * - * Should only be called for applicable parts. - **/ -void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) -{ - u32 phy_ctrl; - - switch (hw->mac.type) { - case e1000_ich8lan: - case e1000_ich9lan: - case e1000_ich10lan: - case e1000_pchlan: - phy_ctrl = er32(PHY_CTRL); - phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU | - E1000_PHY_CTRL_GBE_DISABLE; - ew32(PHY_CTRL, phy_ctrl); - - if (hw->mac.type == e1000_pchlan) - e1000e_phy_hw_reset_ich8lan(hw); - default: - break; - } - - return; -} - -/** - * e1000e_cleanup_led_ich8lan - Restore the default LED operation - * @hw: pointer to the HW structure - * - * Return the LED back to the default configuration. - **/ -static s32 e1000e_cleanup_led_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->phy.type == e1000_phy_ife) - ret_val = e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, - 0); - else - ew32(LEDCTL, hw->mac.ledctl_default); - - return ret_val; -} - -/** - * e1000e_led_on_ich8lan - Turn LEDs on - * @hw: pointer to the HW structure - * - * Turn on the LEDs. - **/ -static s32 e1000e_led_on_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->phy.type == e1000_phy_ife) - ret_val = e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, - (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); - else - ew32(LEDCTL, hw->mac.ledctl_mode2); - - return ret_val; -} - -/** - * e1000e_led_off_ich8lan - Turn LEDs off - * @hw: pointer to the HW structure - * - * Turn off the LEDs. - **/ -static s32 e1000e_led_off_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->phy.type == e1000_phy_ife) - ret_val = e1e_wphy(hw, - IFE_PHY_SPECIAL_CONTROL_LED, - (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF)); - else - ew32(LEDCTL, hw->mac.ledctl_mode1); - - return ret_val; -} - -/** - * e1000e_setup_led_pchlan - Configures SW controllable LED - * @hw: pointer to the HW structure - * - * This prepares the SW controllable LED for use. - **/ -static s32 e1000e_setup_led_pchlan(struct e1000_hw *hw) -{ - return e1e_wphy(hw, HV_LED_CONFIG, - (u16)hw->mac.ledctl_mode1); -} - -/** - * e1000e_cleanup_led_pchlan - Restore the default LED operation - * @hw: pointer to the HW structure - * - * Return the LED back to the default configuration. - **/ -static s32 e1000e_cleanup_led_pchlan(struct e1000_hw *hw) -{ - return e1e_wphy(hw, HV_LED_CONFIG, - (u16)hw->mac.ledctl_default); -} - -/** - * e1000e_led_on_pchlan - Turn LEDs on - * @hw: pointer to the HW structure - * - * Turn on the LEDs. - **/ -static s32 e1000e_led_on_pchlan(struct e1000_hw *hw) -{ - u16 data = (u16)hw->mac.ledctl_mode2; - u32 i, led; - - /* - * If no link, then turn LED on by setting the invert bit - * for each LED that's mode is "link_up" in ledctl_mode2. - */ - if (!(er32(STATUS) & E1000_STATUS_LU)) { - for (i = 0; i < 3; i++) { - led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; - if ((led & E1000_PHY_LED0_MODE_MASK) != - E1000_LEDCTL_MODE_LINK_UP) - continue; - if (led & E1000_PHY_LED0_IVRT) - data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); - else - data |= (E1000_PHY_LED0_IVRT << (i * 5)); - } - } - - return e1e_wphy(hw, HV_LED_CONFIG, data); -} - -/** - * e1000e_led_off_pchlan - Turn LEDs off - * @hw: pointer to the HW structure - * - * Turn off the LEDs. - **/ -static s32 e1000e_led_off_pchlan(struct e1000_hw *hw) -{ - u16 data = (u16)hw->mac.ledctl_mode1; - u32 i, led; - - /* - * If no link, then turn LED off by clearing the invert bit - * for each LED that's mode is "link_up" in ledctl_mode1. - */ - if (!(er32(STATUS) & E1000_STATUS_LU)) { - for (i = 0; i < 3; i++) { - led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; - if ((led & E1000_PHY_LED0_MODE_MASK) != - E1000_LEDCTL_MODE_LINK_UP) - continue; - if (led & E1000_PHY_LED0_IVRT) - data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); - else - data |= (E1000_PHY_LED0_IVRT << (i * 5)); - } - } - - return e1e_wphy(hw, HV_LED_CONFIG, data); -} - -/** - * e1000e_get_cfg_done_ich8lan - Read config done bit - * @hw: pointer to the HW structure - * - * Read the management control register for the config done bit for - * completion status. NOTE: silicon which is EEPROM-less will fail trying - * to read the config done bit, so an error is *ONLY* logged and returns - * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon - * would not be able to be reset or change link. - **/ -static s32 e1000e_get_cfg_done_ich8lan(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u32 bank = 0; - - if (hw->mac.type >= e1000_pchlan) { - u32 status = er32(STATUS); - - if (status & E1000_STATUS_PHYRA) { - ew32(STATUS, status & - ~E1000_STATUS_PHYRA); - } else - e_dbg("PHY Reset Asserted not set - needs delay\n"); - } - - e1000e_get_cfg_done(hw); - - /* If EEPROM is not marked present, init the IGP 3 PHY manually */ - if ((hw->mac.type != e1000_ich10lan) && - (hw->mac.type != e1000_pchlan)) { - if (((er32(EECD) & E1000_EECD_PRES) == 0) && - (hw->phy.type == e1000_phy_igp_3)) { - e1000e_phy_init_script_igp3(hw); - } - } else { - if (e1000e_valid_nvm_bank_detect_ich8lan(hw, &bank)) { - /* Maybe we should do a basic PHY config */ - e_dbg("EEPROM not present\n"); - ret_val = -E1000_ERR_CONFIG; - } - } - - return ret_val; -} - -/** - * e1000e_power_down_phy_copper_ich8lan - Remove link during PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, remove the link. - **/ -static void e1000e_power_down_phy_copper_ich8lan(struct e1000_hw *hw) -{ - /* If the management interface is not enabled, then power down */ - if (!(hw->mac.ops.check_mng_mode(hw) || - e1000e_check_reset_block(hw))) - e1000e_power_down_phy_copper(hw); - - return; -} - -/** - * e1000e_clear_hw_cntrs_ich8lan - Clear statistical counters - * @hw: pointer to the HW structure - * - * Clears hardware counters specific to the silicon family and calls - * clear_hw_cntrs_generic to clear all general purpose counters. - **/ -static void e1000e_clear_hw_cntrs_ich8lan(struct e1000_hw *hw __unused) -{ -#if 0 - u16 phy_data; - - e1000e_clear_hw_cntrs_base(hw); - - er32(ALGNERRC); - er32(RXERRC); - er32(TNCRS); - er32(CEXTERR); - er32(TSCTC); - er32(TSCTFC); - - er32(MGTPRC); - er32(MGTPDC); - er32(MGTPTC); - - er32(IAC); - er32(ICRXOC); - - /* Clear PHY statistics registers */ - if ((hw->phy.type == e1000_phy_82578) || - (hw->phy.type == e1000_phy_82579) || - (hw->phy.type == e1000_phy_82577)) { - e1e_rphy(hw, HV_SCC_UPPER, &phy_data); - e1e_rphy(hw, HV_SCC_LOWER, &phy_data); - e1e_rphy(hw, HV_ECOL_UPPER, &phy_data); - e1e_rphy(hw, HV_ECOL_LOWER, &phy_data); - e1e_rphy(hw, HV_MCC_UPPER, &phy_data); - e1e_rphy(hw, HV_MCC_LOWER, &phy_data); - e1e_rphy(hw, HV_LATECOL_UPPER, &phy_data); - e1e_rphy(hw, HV_LATECOL_LOWER, &phy_data); - e1e_rphy(hw, HV_COLC_UPPER, &phy_data); - e1e_rphy(hw, HV_COLC_LOWER, &phy_data); - e1e_rphy(hw, HV_DC_UPPER, &phy_data); - e1e_rphy(hw, HV_DC_LOWER, &phy_data); - e1e_rphy(hw, HV_TNCRS_UPPER, &phy_data); - e1e_rphy(hw, HV_TNCRS_LOWER, &phy_data); - } -#endif -} - -static struct pci_device_id e1000e_ich8lan_nics[] = { - PCI_ROM(0x8086, 0x104C, "E1000_DEV_ID_ICH8_IFE", "E1000_DEV_ID_ICH8_IFE", board_ich8lan), - PCI_ROM(0x8086, 0x10C5, "E1000_DEV_ID_ICH8_IFE_G", "E1000_DEV_ID_ICH8_IFE_G", board_ich8lan), - PCI_ROM(0x8086, 0x10C4, "E1000_DEV_ID_ICH8_IFE_GT", "E1000_DEV_ID_ICH8_IFE_GT", board_ich8lan), - PCI_ROM(0x8086, 0x104A, "E1000_DEV_ID_ICH8_IGP_AMT", "E1000_DEV_ID_ICH8_IGP_AMT", board_ich8lan), - PCI_ROM(0x8086, 0x104B, "E1000_DEV_ID_ICH8_IGP_C", "E1000_DEV_ID_ICH8_IGP_C", board_ich8lan), - PCI_ROM(0x8086, 0x104D, "E1000_DEV_ID_ICH8_IGP_M", "E1000_DEV_ID_ICH8_IGP_M", board_ich8lan), - PCI_ROM(0x8086, 0x1049, "E1000_DEV_ID_ICH8_IGP_M_AMT", "E1000_DEV_ID_ICH8_IGP_M_AMT", board_ich8lan), - PCI_ROM(0x8086, 0x1501, "E1000_DEV_ID_ICH8_82567V_3", "E1000_DEV_ID_ICH8_82567V_3", board_ich8lan), - PCI_ROM(0x8086, 0x10C0, "E1000_DEV_ID_ICH9_IFE", "E1000_DEV_ID_ICH9_IFE", board_ich9lan), - PCI_ROM(0x8086, 0x10C2, "E1000_DEV_ID_ICH9_IFE_G", "E1000_DEV_ID_ICH9_IFE_G", board_ich9lan), - PCI_ROM(0x8086, 0x10C3, "E1000_DEV_ID_ICH9_IFE_GT", "E1000_DEV_ID_ICH9_IFE_GT", board_ich9lan), - PCI_ROM(0x8086, 0x10BD, "E1000_DEV_ID_ICH9_IGP_AMT", "E1000_DEV_ID_ICH9_IGP_AMT", board_ich9lan), - PCI_ROM(0x8086, 0x294C, "E1000_DEV_ID_ICH9_IGP_C", "E1000_DEV_ID_ICH9_IGP_C", board_ich9lan), - PCI_ROM(0x8086, 0x10E5, "E1000_DEV_ID_ICH9_BM", "E1000_DEV_ID_ICH9_BM", board_ich9lan), - PCI_ROM(0x8086, 0x10BF, "E1000_DEV_ID_ICH9_IGP_M", "E1000_DEV_ID_ICH9_IGP_M", board_ich9lan), - PCI_ROM(0x8086, 0x10F5, "E1000_DEV_ID_ICH9_IGP_M_AMT", "E1000_DEV_ID_ICH9_IGP_M_AMT", board_ich9lan), - PCI_ROM(0x8086, 0x10CB, "E1000_DEV_ID_ICH9_IGP_M_V", "E1000_DEV_ID_ICH9_IGP_M_V", board_ich9lan), - PCI_ROM(0x8086, 0x10CC, "E1000_DEV_ID_ICH10_R_BM_LM", "E1000_DEV_ID_ICH10_R_BM_LM", board_ich9lan), - PCI_ROM(0x8086, 0x10CD, "E1000_DEV_ID_ICH10_R_BM_LF", "E1000_DEV_ID_ICH10_R_BM_LF", board_ich9lan), - PCI_ROM(0x8086, 0x10CE, "E1000_DEV_ID_ICH10_R_BM_V", "E1000_DEV_ID_ICH10_R_BM_V", board_ich9lan), - PCI_ROM(0x8086, 0x10DE, "E1000_DEV_ID_ICH10_D_BM_LM", "E1000_DEV_ID_ICH10_D_BM_LM", board_ich10lan), - PCI_ROM(0x8086, 0x10DF, "E1000_DEV_ID_ICH10_D_BM_LF", "E1000_DEV_ID_ICH10_D_BM_LF", board_ich10lan), - PCI_ROM(0x8086, 0x10EA, "E1000_DEV_ID_PCH_M_HV_LM", "E1000_DEV_ID_PCH_M_HV_LM", board_pchlan), - PCI_ROM(0x8086, 0x10EB, "E1000_DEV_ID_PCH_M_HV_LC", "E1000_DEV_ID_PCH_M_HV_LC", board_pchlan), - PCI_ROM(0x8086, 0x10EF, "E1000_DEV_ID_PCH_D_HV_DM", "E1000_DEV_ID_PCH_D_HV_DM", board_pchlan), - PCI_ROM(0x8086, 0x10F0, "E1000_DEV_ID_PCH_D_HV_DC", "E1000_DEV_ID_PCH_D_HV_DC", board_pchlan), - PCI_ROM(0x8086, 0x1502, "E1000_DEV_ID_PCH2_LV_LM", "E1000_DEV_ID_PCH2_LV_LM", board_pch2lan), - PCI_ROM(0x8086, 0x1503, "E1000_DEV_ID_PCH2_LV_V", "E1000_DEV_ID_PCH2_LV_V", board_pch2lan), -}; - -struct pci_driver e1000e_ich8lan_driver __pci_driver = { - .ids = e1000e_ich8lan_nics, - .id_count = (sizeof (e1000e_ich8lan_nics) / sizeof (e1000e_ich8lan_nics[0])), - .probe = e1000e_probe, - .remove = e1000e_remove, -}; diff --git a/src/drivers/net/e1000e/e1000e_ich8lan.h b/src/drivers/net/e1000e/e1000e_ich8lan.h deleted file mode 100644 index 8b145d92..00000000 --- a/src/drivers/net/e1000e/e1000e_ich8lan.h +++ /dev/null @@ -1,199 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_ICH8LAN_H_ -#define _E1000E_ICH8LAN_H_ - -#define ICH_FLASH_GFPREG 0x0000 -#define ICH_FLASH_HSFSTS 0x0004 -#define ICH_FLASH_HSFCTL 0x0006 -#define ICH_FLASH_FADDR 0x0008 -#define ICH_FLASH_FDATA0 0x0010 - -/* Requires up to 10 seconds when MNG might be accessing part. */ -#define ICH_FLASH_READ_COMMAND_TIMEOUT 10000000 -#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 10000000 -#define ICH_FLASH_ERASE_COMMAND_TIMEOUT 10000000 -#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF -#define ICH_FLASH_CYCLE_REPEAT_COUNT 10 - -#define ICH_CYCLE_READ 0 -#define ICH_CYCLE_WRITE 2 -#define ICH_CYCLE_ERASE 3 - -#define FLASH_GFPREG_BASE_MASK 0x1FFF -#define FLASH_SECTOR_ADDR_SHIFT 12 - -#define ICH_FLASH_SEG_SIZE_256 256 -#define ICH_FLASH_SEG_SIZE_4K 4096 -#define ICH_FLASH_SEG_SIZE_8K 8192 -#define ICH_FLASH_SEG_SIZE_64K 65536 -#define ICH_FLASH_SECTOR_SIZE 4096 - -#define ICH_FLASH_REG_MAPSIZE 0x00A0 - -#define E1000_ICH_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI Reset */ -#define E1000_ICH_FWSM_DISSW 0x10000000 /* FW Disables SW Writes */ -/* FW established a valid mode */ -#define E1000_ICH_FWSM_FW_VALID 0x00008000 - -#define E1000_ICH_MNG_IAMT_MODE 0x2 - -#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ - (ID_LED_OFF1_OFF2 << 8) | \ - (ID_LED_OFF1_ON2 << 4) | \ - (ID_LED_DEF1_DEF2)) - -#define E1000_ICH_NVM_SIG_WORD 0x13 -#define E1000_ICH_NVM_SIG_MASK 0xC000 -#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0 -#define E1000_ICH_NVM_SIG_VALUE 0x80 - -#define E1000_ICH8_LAN_INIT_TIMEOUT 1500 - -#define E1000_FEXTNVM_SW_CONFIG 1 -#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M */ - -#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL - -#define E1000_ICH_RAR_ENTRIES 7 - -#define PHY_PAGE_SHIFT 5 -#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \ - ((reg) & MAX_PHY_REG_ADDRESS)) -#define IGP3_KMRN_DIAG PHY_REG(770, 19) /* KMRN Diagnostic */ -#define IGP3_VR_CTRL PHY_REG(776, 18) /* Voltage Regulator Control */ -#define IGP3_CAPABILITY PHY_REG(776, 19) /* Capability */ -#define IGP3_PM_CTRL PHY_REG(769, 20) /* Power Management Control */ - -#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 -#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300 -#define IGP3_VR_CTRL_MODE_SHUTDOWN 0x0200 -#define IGP3_PM_CTRL_FORCE_PWR_DOWN 0x0020 - -/* PHY Wakeup Registers and defines */ -#define BM_RCTL PHY_REG(BM_WUC_PAGE, 0) -#define BM_WUC PHY_REG(BM_WUC_PAGE, 1) -#define BM_WUFC PHY_REG(BM_WUC_PAGE, 2) -#define BM_WUS PHY_REG(BM_WUC_PAGE, 3) -#define BM_RAR_L(_i) (BM_PHY_REG(BM_WUC_PAGE, 16 + ((_i) << 2))) -#define BM_RAR_M(_i) (BM_PHY_REG(BM_WUC_PAGE, 17 + ((_i) << 2))) -#define BM_RAR_H(_i) (BM_PHY_REG(BM_WUC_PAGE, 18 + ((_i) << 2))) -#define BM_RAR_CTRL(_i) (BM_PHY_REG(BM_WUC_PAGE, 19 + ((_i) << 2))) -#define BM_MTA(_i) (BM_PHY_REG(BM_WUC_PAGE, 128 + ((_i) << 1))) - -#define BM_RCTL_UPE 0x0001 /* Unicast Promiscuous Mode */ -#define BM_RCTL_MPE 0x0002 /* Multicast Promiscuous Mode */ -#define BM_RCTL_MO_SHIFT 3 /* Multicast Offset Shift */ -#define BM_RCTL_MO_MASK (3 << 3) /* Multicast Offset Mask */ -#define BM_RCTL_BAM 0x0020 /* Broadcast Accept Mode */ -#define BM_RCTL_PMCF 0x0040 /* Pass MAC Control Frames */ -#define BM_RCTL_RFCE 0x0080 /* Rx Flow Control Enable */ - -#define HV_LED_CONFIG PHY_REG(768, 30) /* LED Configuration */ -#define HV_MUX_DATA_CTRL PHY_REG(776, 16) -#define HV_MUX_DATA_CTRL_GEN_TO_MAC 0x0400 -#define HV_MUX_DATA_CTRL_FORCE_SPEED 0x0004 -#define HV_SCC_UPPER PHY_REG(778, 16) /* Single Collision Count */ -#define HV_SCC_LOWER PHY_REG(778, 17) -#define HV_ECOL_UPPER PHY_REG(778, 18) /* Excessive Collision Count */ -#define HV_ECOL_LOWER PHY_REG(778, 19) -#define HV_MCC_UPPER PHY_REG(778, 20) /* Multiple Collision Count */ -#define HV_MCC_LOWER PHY_REG(778, 21) -#define HV_LATECOL_UPPER PHY_REG(778, 23) /* Late Collision Count */ -#define HV_LATECOL_LOWER PHY_REG(778, 24) -#define HV_COLC_UPPER PHY_REG(778, 25) /* Collision Count */ -#define HV_COLC_LOWER PHY_REG(778, 26) -#define HV_DC_UPPER PHY_REG(778, 27) /* Defer Count */ -#define HV_DC_LOWER PHY_REG(778, 28) -#define HV_TNCRS_UPPER PHY_REG(778, 29) /* Transmit with no CRS */ -#define HV_TNCRS_LOWER PHY_REG(778, 30) - -#define E1000_FCRTV_PCH 0x05F40 /* PCH Flow Control Refresh Timer Value */ - -#define E1000_NVM_K1_CONFIG 0x1B /* NVM K1 Config Word */ -#define E1000_NVM_K1_ENABLE 0x1 /* NVM Enable K1 bit */ - -/* SMBus Address Phy Register */ -#define HV_SMB_ADDR PHY_REG(768, 26) -#define HV_SMB_ADDR_PEC_EN 0x0200 -#define HV_SMB_ADDR_VALID 0x0080 - -/* PHY Power Management Control */ -#define HV_PM_CTRL PHY_REG(770, 17) - -/* Strapping Option Register - RO */ -#define E1000_STRAP 0x0000C -#define E1000_STRAP_SMBUS_ADDRESS_MASK 0x00FE0000 -#define E1000_STRAP_SMBUS_ADDRESS_SHIFT 17 - -/* OEM Bits Phy Register */ -#define HV_OEM_BITS PHY_REG(768, 25) -#define HV_OEM_BITS_LPLU 0x0004 /* Low Power Link Up */ -#define HV_OEM_BITS_GBE_DIS 0x0040 /* Gigabit Disable */ -#define HV_OEM_BITS_RESTART_AN 0x0400 /* Restart Auto-negotiation */ - -#define LCD_CFG_PHY_ADDR_BIT 0x0020 /* Phy address bit from LCD Config word */ - -#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in milliseconds */ - -/* - * Additional interrupts need to be handled for ICH family: - * DSW = The FW changed the status of the DISSW bit in FWSM - * PHYINT = The LAN connected device generates an interrupt - * EPRST = Manageability reset event - */ -#define IMS_ICH_ENABLE_MASK (\ - E1000_IMS_DSW | \ - E1000_IMS_PHYINT | \ - E1000_IMS_EPRST) - -/* Additional interrupt register bit definitions */ -#define E1000_ICR_LSECPNC 0x00004000 /* PN threshold - client */ -#define E1000_IMS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */ -#define E1000_ICS_LSECPNC E1000_ICR_LSECPNC /* PN threshold - client */ - -/* Security Processing bit Indication */ -#define E1000_RXDEXT_LINKSEC_STATUS_LSECH 0x01000000 -#define E1000_RXDEXT_LINKSEC_ERROR_BIT_MASK 0x60000000 -#define E1000_RXDEXT_LINKSEC_ERROR_NO_SA_MATCH 0x20000000 -#define E1000_RXDEXT_LINKSEC_ERROR_REPLAY_ERROR 0x40000000 -#define E1000_RXDEXT_LINKSEC_ERROR_BAD_SIG 0x60000000 - - -void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, - bool state); -void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); -void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); -void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); -s32 e1000e_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); -s32 e1000e_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_config); - -#endif diff --git a/src/drivers/net/e1000e/e1000e_mac.c b/src/drivers/net/e1000e/e1000e_mac.c deleted file mode 100644 index d96b279f..00000000 --- a/src/drivers/net/e1000e/e1000e_mac.c +++ /dev/null @@ -1,1883 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000e.h" - -static u32 e1000e_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr); -static s32 e1000e_set_default_fc_generic(struct e1000_hw *hw); -static s32 e1000e_commit_fc_settings_generic(struct e1000_hw *hw); -static s32 e1000e_poll_fiber_serdes_link_generic(struct e1000_hw *hw); -static s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw); -static void e1000e_set_lan_id_multi_port_pcie(struct e1000_hw *hw); - -/** - * e1000e_init_mac_ops_generic - Initialize MAC function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void e1000e_init_mac_ops_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - /* General Setup */ - mac->ops.set_lan_id = e1000e_set_lan_id_multi_port_pcie; - mac->ops.read_mac_addr = e1000e_read_mac_addr_generic; - mac->ops.config_collision_dist = e1000e_config_collision_dist; - /* LINK */ - mac->ops.wait_autoneg = e1000e_wait_autoneg; - /* Management */ -#if 0 - mac->ops.mng_host_if_write = e1000e_mng_host_if_write_generic; - mac->ops.mng_write_cmd_header = e1000e_mng_write_cmd_header_generic; - mac->ops.mng_enable_host_if = e1000e_mng_enable_host_if_generic; -#endif - /* VLAN, MC, etc. */ - mac->ops.rar_set = e1000e_rar_set; - mac->ops.validate_mdi_setting = e1000e_validate_mdi_setting_generic; -} - -/** - * e1000e_get_bus_info_pcie - Get PCIe bus information - * @hw: pointer to the HW structure - * - * Determines and stores the system bus information for a particular - * network interface. The following bus information is determined and stored: - * bus speed, bus width, type (PCIe), and PCIe function. - **/ -s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - struct e1000_bus_info *bus = &hw->bus; - - s32 ret_val; - u16 pcie_link_status; - - bus->type = e1000_bus_type_pci_express; - bus->speed = e1000_bus_speed_2500; - - ret_val = e1000e_read_pcie_cap_reg(hw, - PCIE_LINK_STATUS, - &pcie_link_status); - if (ret_val) - bus->width = e1000_bus_width_unknown; - else - bus->width = (enum e1000_bus_width)((pcie_link_status & - PCIE_LINK_WIDTH_MASK) >> - PCIE_LINK_WIDTH_SHIFT); - - mac->ops.set_lan_id(hw); - - return E1000_SUCCESS; -} - -/** - * e1000e_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices - * - * @hw: pointer to the HW structure - * - * Determines the LAN function id by reading memory-mapped registers - * and swaps the port value if requested. - **/ -static void e1000e_set_lan_id_multi_port_pcie(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - u32 reg; - - /* - * The status register reports the correct function number - * for the device regardless of function swap state. - */ - reg = er32(STATUS); - bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; -} - -/** - * e1000e_set_lan_id_single_port - Set LAN id for a single port device - * @hw: pointer to the HW structure - * - * Sets the LAN function id to zero for a single port device. - **/ -void e1000e_set_lan_id_single_port(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - - bus->func = 0; -} - -/** - * e1000e_clear_vfta_generic - Clear VLAN filter table - * @hw: pointer to the HW structure - * - * Clears the register array which contains the VLAN filter table by - * setting all the values to 0. - **/ -void e1000e_clear_vfta_generic(struct e1000_hw *hw) -{ - u32 offset; - - for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0); - e1e_flush(); - } -} - -/** - * e1000e_write_vfta_generic - Write value to VLAN filter table - * @hw: pointer to the HW structure - * @offset: register offset in VLAN filter table - * @value: register value written to VLAN filter table - * - * Writes value at the given offset in the register array which stores - * the VLAN filter table. - **/ -void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) -{ - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); - e1e_flush(); -} - -/** - * e1000e_init_rx_addrs - Initialize receive address's - * @hw: pointer to the HW structure - * @rar_count: receive address registers - * - * Setups the receive address registers by setting the base receive address - * register to the devices MAC address and clearing all the other receive - * address registers to 0. - **/ -void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count) -{ - u32 i; - u8 mac_addr[ETH_ADDR_LEN] = {0}; - - /* Setup the receive address */ - e_dbg("Programming MAC Address into RAR[0]\n"); - - hw->mac.ops.rar_set(hw, hw->mac.addr, 0); - - /* Zero out the other (rar_entry_count - 1) receive addresses */ - e_dbg("Clearing RAR[1-%u]\n", rar_count-1); - for (i = 1; i < rar_count; i++) - hw->mac.ops.rar_set(hw, mac_addr, i); -} - -/** - * e1000e_check_alt_mac_addr_generic - Check for alternate MAC addr - * @hw: pointer to the HW structure - * - * Checks the nvm for an alternate MAC address. An alternate MAC address - * can be setup by pre-boot software and must be treated like a permanent - * address and must override the actual permanent MAC address. If an - * alternate MAC address is found it is programmed into RAR0, replacing - * the permanent address that was installed into RAR0 by the Si on reset. - * This function will return SUCCESS unless it encounters an error while - * reading the EEPROM. - **/ -s32 e1000e_check_alt_mac_addr_generic(struct e1000_hw *hw) -{ - u32 i; - s32 ret_val = E1000_SUCCESS; - u16 offset, nvm_alt_mac_addr_offset, nvm_data; - u8 alt_mac_addr[ETH_ADDR_LEN]; - - ret_val = e1000e_read_nvm(hw, NVM_ALT_MAC_ADDR_PTR, 1, - &nvm_alt_mac_addr_offset); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - - if (nvm_alt_mac_addr_offset == 0xFFFF) { - /* There is no Alternate MAC Address */ - goto out; - } - - if (hw->bus.func == E1000_FUNC_1) - nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1; - for (i = 0; i < ETH_ADDR_LEN; i += 2) { - offset = nvm_alt_mac_addr_offset + (i >> 1); - ret_val = e1000e_read_nvm(hw, offset, 1, &nvm_data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - - alt_mac_addr[i] = (u8)(nvm_data & 0xFF); - alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); - } - - /* if multicast bit is set, the alternate address will not be used */ - if (alt_mac_addr[0] & 0x01) { - e_dbg("Ignoring Alternate Mac Address with MC bit set\n"); - goto out; - } - - /* - * We have a valid alternate MAC address, and we want to treat it the - * same as the normal permanent MAC address stored by the HW into the - * RAR. Do this by mapping this address into RAR0. - */ - hw->mac.ops.rar_set(hw, alt_mac_addr, 0); - -out: - return ret_val; -} - -/** - * e1000e_rar_set - Set receive address register - * @hw: pointer to the HW structure - * @addr: pointer to the receive address - * @index: receive address array register - * - * Sets the receive address array register at index to the address passed - * in by addr. - **/ -void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) -{ - u32 rar_low, rar_high; - - /* - * HW expects these in little endian so we reverse the byte order - * from network order (big endian) to little endian - */ - rar_low = ((u32) addr[0] | - ((u32) addr[1] << 8) | - ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); - - rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); - - /* If MAC address zero, no need to set the AV bit */ - if (rar_low || rar_high) - rar_high |= E1000_RAH_AV; - - /* - * Some bridges will combine consecutive 32-bit writes into - * a single burst write, which will malfunction on some parts. - * The flushes avoid this. - */ - ew32(RAL(index), rar_low); - e1e_flush(); - ew32(RAH(index), rar_high); - e1e_flush(); -} - -/** - * e1000e_mta_set_generic - Set multicast filter table address - * @hw: pointer to the HW structure - * @hash_value: determines the MTA register and bit to set - * - * The multicast table address is a register array of 32-bit registers. - * The hash_value is used to determine what register the bit is in, the - * current value is read, the new bit is OR'd in and the new value is - * written back into the register. - **/ -void e1000e_mta_set_generic(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg, mta; - - /* - * The MTA is a register array of 32-bit registers. It is - * treated like an array of (32*mta_reg_count) bits. We want to - * set bit BitArray[hash_value]. So we figure out what register - * the bit is in, read it, OR in the new bit, then write - * back the new value. The (hw->mac.mta_reg_count - 1) serves as a - * mask to bits 31:5 of the hash value which gives us the - * register we're modifying. The hash bit within that register - * is determined by the lower 5 bits of the hash value. - */ - hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - - mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); - - mta |= (1 << hash_bit); - - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); - e1e_flush(); -} - -/** - * e1000e_update_mc_addr_list_generic - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * - * Updates entire Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - **/ -void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count) -{ - u32 hash_value, hash_bit, hash_reg; - int i; - - /* clear mta_shadow */ - memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); - - /* update mta_shadow from mc_addr_list */ - for (i = 0; (u32) i < mc_addr_count; i++) { - hash_value = e1000e_hash_mc_addr_generic(hw, mc_addr_list); - - hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - - hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit); - mc_addr_list += (ETH_ADDR_LEN); - } - - /* replace the entire MTA table */ - for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]); - e1e_flush(); -} - -/** - * e1000e_hash_mc_addr_generic - Generate a multicast hash value - * @hw: pointer to the HW structure - * @mc_addr: pointer to a multicast address - * - * Generates a multicast address hash value which is used to determine - * the multicast filter table array address and new table value. See - * e1000e_mta_set_generic() - **/ -static u32 e1000e_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr) -{ - u32 hash_value, hash_mask; - u8 bit_shift = 0; - - /* Register count multiplied by bits per register */ - hash_mask = (hw->mac.mta_reg_count * 32) - 1; - - /* - * For a mc_filter_type of 0, bit_shift is the number of left-shifts - * where 0xFF would still fall within the hash mask. - */ - while (hash_mask >> bit_shift != 0xFF) - bit_shift++; - - /* - * The portion of the address that is used for the hash table - * is determined by the mc_filter_type setting. - * The algorithm is such that there is a total of 8 bits of shifting. - * The bit_shift for a mc_filter_type of 0 represents the number of - * left-shifts where the MSB of mc_addr[5] would still fall within - * the hash_mask. Case 0 does this exactly. Since there are a total - * of 8 bits of shifting, then mc_addr[4] will shift right the - * remaining number of bits. Thus 8 - bit_shift. The rest of the - * cases are a variation of this algorithm...essentially raising the - * number of bits to shift mc_addr[5] left, while still keeping the - * 8-bit shifting total. - * - * For example, given the following Destination MAC Address and an - * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), - * we can see that the bit_shift for case 0 is 4. These are the hash - * values resulting from each mc_filter_type... - * [0] [1] [2] [3] [4] [5] - * 01 AA 00 12 34 56 - * LSB MSB - * - * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 - * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 - * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 - * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 - */ - switch (hw->mac.mc_filter_type) { - default: - case 0: - break; - case 1: - bit_shift += 1; - break; - case 2: - bit_shift += 2; - break; - case 3: - bit_shift += 4; - break; - } - - hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | - (((u16) mc_addr[5]) << bit_shift))); - - return hash_value; -} - -/** - * e1000e_clear_hw_cntrs_base - Clear base hardware counters - * @hw: pointer to the HW structure - * - * Clears the base hardware counters by reading the counter registers. - **/ -void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw __unused) -{ -#if 0 - er32(CRCERRS); - er32(SYMERRS); - er32(MPC); - er32(SCC); - er32(ECOL); - er32(MCC); - er32(LATECOL); - er32(COLC); - er32(DC); - er32(SEC); - er32(RLEC); - er32(XONRXC); - er32(XONTXC); - er32(XOFFRXC); - er32(XOFFTXC); - er32(FCRUC); - er32(GPRC); - er32(BPRC); - er32(MPRC); - er32(GPTC); - er32(GORCL); - er32(GORCH); - er32(GOTCL); - er32(GOTCH); - er32(RNBC); - er32(RUC); - er32(RFC); - er32(ROC); - er32(RJC); - er32(TORL); - er32(TORH); - er32(TOTL); - er32(TOTH); - er32(TPR); - er32(TPT); - er32(MPTC); - er32(BPTC); -#endif -} - -/** - * e1000e_check_for_copper_link - Check for link (Copper) - * @hw: pointer to the HW structure - * - * Checks to see of the link status of the hardware has changed. If a - * change in link status has been detected, then we read the PHY registers - * to get the current speed/duplex if link exists. - **/ -s32 e1000e_check_for_copper_link(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - bool link; - - /* - * We only want to go out to the PHY registers to see if Auto-Neg - * has completed and/or if our link status has changed. The - * get_link_status flag is set upon receiving a Link Status - * Change or Rx Sequence Error interrupt. - */ - if (!mac->get_link_status) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* - * First we want to see if the MII Status Register reports - * link. If so, then we want to get the current speed/duplex - * of the PHY. - */ - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) - goto out; /* No link detected */ - - mac->get_link_status = false; - - /* - * Check if there was DownShift, must be checked - * immediately after link-up - */ - e1000e_check_downshift(hw); - - /* - * If we are forcing speed/duplex, then we simply return since - * we have already determined whether we have link or not. - */ - if (!mac->autoneg) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - /* - * Auto-Neg is enabled. Auto Speed Detection takes care - * of MAC speed/duplex configuration. So we only need to - * configure Collision Distance in the MAC. - */ - e1000e_config_collision_dist(hw); - - /* - * Configure Flow Control now that Auto-Neg has completed. - * First, we need to restore the desired flow control - * settings because we may have had to re-autoneg with a - * different link partner. - */ - ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) - e_dbg("Error configuring flow control\n"); - -out: - return ret_val; -} - -/** - * e1000e_check_for_fiber_link - Check for link (Fiber) - * @hw: pointer to the HW structure - * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. - **/ -s32 e1000e_check_for_fiber_link(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw; - u32 ctrl; - u32 status; - s32 ret_val = E1000_SUCCESS; - - ctrl = er32(CTRL); - status = er32(STATUS); - rxcw = er32(RXCW); - - /* - * If we don't have link (auto-negotiation failed or link partner - * cannot auto-negotiate), the cable is plugged in (we have signal), - * and our link partner is not trying to auto-negotiate with us (we - * are receiving idles or data), we need to force link up. We also - * need to give auto-negotiation time to complete, in case the cable - * was just plugged in. The autoneg_failed flag does this. - */ - /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ - if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) && - (!(rxcw & E1000_RXCW_C))) { - if (mac->autoneg_failed == 0) { - mac->autoneg_failed = 1; - goto out; - } - e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n"); - - /* Disable auto-negotiation in the TXCW register */ - ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE)); - - /* Force link-up and also force full-duplex. */ - ctrl = er32(CTRL); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - ew32(CTRL, ctrl); - - /* Configure Flow Control after forcing link up. */ - ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) { - e_dbg("Error configuring flow control\n"); - goto out; - } - } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - /* - * If we are forcing link and we are receiving /C/ ordered - * sets, re-enable auto-negotiation in the TXCW register - * and disable forced link in the Device Control register - * in an attempt to auto-negotiate with our link partner. - */ - e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n"); - ew32(TXCW, mac->txcw); - ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); - - mac->serdes_has_link = true; - } - -out: - return ret_val; -} - -/** - * e1000e_check_for_serdes_link - Check for link (Serdes) - * @hw: pointer to the HW structure - * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. - **/ -s32 e1000e_check_for_serdes_link(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw; - u32 ctrl; - u32 status; - s32 ret_val = E1000_SUCCESS; - - ctrl = er32(CTRL); - status = er32(STATUS); - rxcw = er32(RXCW); - - /* - * If we don't have link (auto-negotiation failed or link partner - * cannot auto-negotiate), and our link partner is not trying to - * auto-negotiate with us (we are receiving idles or data), - * we need to force link up. We also need to give auto-negotiation - * time to complete. - */ - /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ - if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) { - if (mac->autoneg_failed == 0) { - mac->autoneg_failed = 1; - goto out; - } - e_dbg("NOT RXing /C/, disable AutoNeg and force link.\n"); - - /* Disable auto-negotiation in the TXCW register */ - ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE)); - - /* Force link-up and also force full-duplex. */ - ctrl = er32(CTRL); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - ew32(CTRL, ctrl); - - /* Configure Flow Control after forcing link up. */ - ret_val = e1000e_config_fc_after_link_up(hw); - if (ret_val) { - e_dbg("Error configuring flow control\n"); - goto out; - } - } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - /* - * If we are forcing link and we are receiving /C/ ordered - * sets, re-enable auto-negotiation in the TXCW register - * and disable forced link in the Device Control register - * in an attempt to auto-negotiate with our link partner. - */ - e_dbg("RXing /C/, enable AutoNeg and stop forcing link.\n"); - ew32(TXCW, mac->txcw); - ew32(CTRL, (ctrl & ~E1000_CTRL_SLU)); - - mac->serdes_has_link = true; - } else if (!(E1000_TXCW_ANE & er32(TXCW))) { - /* - * If we force link for non-auto-negotiation switch, check - * link status based on MAC synchronization for internal - * serdes media type. - */ - /* SYNCH bit and IV bit are sticky. */ - udelay(10); - rxcw = er32(RXCW); - if (rxcw & E1000_RXCW_SYNCH) { - if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = true; - e_dbg("SERDES: Link up - forced.\n"); - } - } else { - mac->serdes_has_link = false; - e_dbg("SERDES: Link down - force failed.\n"); - } - } - - if (E1000_TXCW_ANE & er32(TXCW)) { - status = er32(STATUS); - if (status & E1000_STATUS_LU) { - /* SYNCH bit and IV bit are sticky, so reread rxcw. */ - udelay(10); - rxcw = er32(RXCW); - if (rxcw & E1000_RXCW_SYNCH) { - if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = true; - e_dbg("SERDES: Link up - autoneg " - "completed sucessfully.\n"); - } else { - mac->serdes_has_link = false; - e_dbg("SERDES: Link down - invalid" - "codewords detected in autoneg.\n"); - } - } else { - mac->serdes_has_link = false; - e_dbg("SERDES: Link down - no sync.\n"); - } - } else { - mac->serdes_has_link = false; - e_dbg("SERDES: Link down - autoneg failed\n"); - } - } - -out: - return ret_val; -} - -/** - * e1000e_setup_link - Setup flow control and link settings - * @hw: pointer to the HW structure - * - * Determines which flow control settings to use, then configures flow - * control. Calls the appropriate media-specific link configuration - * function. Assuming the adapter has a valid link partner, a valid link - * should be established. Assumes the hardware has previously been reset - * and the transmitter and receiver are not enabled. - **/ -s32 e1000e_setup_link(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - /* - * In the case of the phy reset being blocked, we already have a link. - * We do not need to set it up again. - */ - if (hw->phy.ops.check_reset_block) - if (e1000e_check_reset_block(hw)) - goto out; - - /* - * If requested flow control is set to default, set flow control - * based on the EEPROM flow control settings. - */ - if (hw->fc.requested_mode == e1000_fc_default) { - ret_val = e1000e_set_default_fc_generic(hw); - if (ret_val) - goto out; - } - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - hw->fc.current_mode = hw->fc.requested_mode; - - e_dbg("After fix-ups FlowControl is now = %x\n", - hw->fc.current_mode); - - /* Call the necessary media_type subroutine to configure the link. */ - ret_val = hw->mac.ops.setup_physical_interface(hw); - if (ret_val) - goto out; - - /* - * Initialize the flow control address, type, and PAUSE timer - * registers to their default values. This is done even if flow - * control is disabled, because it does not hurt anything to - * initialize these registers. - */ - e_dbg("Initializing the Flow Control address, type and timer regs\n"); - ew32(FCT, FLOW_CONTROL_TYPE); - ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH); - ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW); - - ew32(FCTTV, hw->fc.pause_time); - - ret_val = e1000e_set_fc_watermarks(hw); - -out: - return ret_val; -} - -/** - * e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes - * @hw: pointer to the HW structure - * - * Configures collision distance and flow control for fiber and serdes - * links. Upon successful setup, poll for link. - **/ -s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - - ctrl = er32(CTRL); - - /* Take the link out of reset */ - ctrl &= ~E1000_CTRL_LRST; - - e1000e_config_collision_dist(hw); - - ret_val = e1000e_commit_fc_settings_generic(hw); - if (ret_val) - goto out; - - /* - * Since auto-negotiation is enabled, take the link out of reset (the - * link will be in reset, because we previously reset the chip). This - * will restart auto-negotiation. If auto-negotiation is successful - * then the link-up status bit will be set and the flow control enable - * bits (RFCE and TFCE) will be set according to their negotiated value. - */ - e_dbg("Auto-negotiation enabled\n"); - - ew32(CTRL, ctrl); - e1e_flush(); - msleep(1); - - /* - * For these adapters, the SW definable pin 1 is set when the optics - * detect a signal. If we have a signal, then poll for a "Link-Up" - * indication. - */ - if (hw->phy.media_type == e1000_media_type_internal_serdes || - (er32(CTRL) & E1000_CTRL_SWDPIN1)) { - ret_val = e1000e_poll_fiber_serdes_link_generic(hw); - } else { - e_dbg("No signal detected\n"); - } - -out: - return ret_val; -} - -/** - * e1000e_config_collision_dist - Configure collision distance - * @hw: pointer to the HW structure - * - * Configures the collision distance to the default value and is used - * during link setup. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -void e1000e_config_collision_dist(struct e1000_hw *hw) -{ - u32 tctl; - - tctl = er32(TCTL); - - tctl &= ~E1000_TCTL_COLD; - tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; - - ew32(TCTL, tctl); - e1e_flush(); -} - -/** - * e1000e_poll_fiber_serdes_link_generic - Poll for link up - * @hw: pointer to the HW structure - * - * Polls for link up by reading the status register, if link fails to come - * up with auto-negotiation, then the link is forced if a signal is detected. - **/ -static s32 e1000e_poll_fiber_serdes_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 i, status; - s32 ret_val = E1000_SUCCESS; - - /* - * If we have a signal (the cable is plugged in, or assumed true for - * serdes media) then poll for a "Link-Up" indication in the Device - * Status Register. Time-out if a link isn't seen in 500 milliseconds - * seconds (Auto-negotiation should complete in less than 500 - * milliseconds even if the other end is doing it in SW). - */ - for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msleep(10); - status = er32(STATUS); - if (status & E1000_STATUS_LU) - break; - } - if (i == FIBER_LINK_UP_LIMIT) { - e_dbg("Never got a valid link from auto-neg!!!\n"); - mac->autoneg_failed = 1; - /* - * AutoNeg failed to achieve a link, so we'll call - * mac->check_for_link. This routine will force the - * link up if we detect a signal. This will allow us to - * communicate with non-autonegotiating link partners. - */ - ret_val = hw->mac.ops.check_for_link(hw); - if (ret_val) { - e_dbg("Error while checking for link\n"); - goto out; - } - mac->autoneg_failed = 0; - } else { - mac->autoneg_failed = 0; - e_dbg("Valid Link Found\n"); - } - -out: - return ret_val; -} - -/** - * e1000e_commit_fc_settings_generic - Configure flow control - * @hw: pointer to the HW structure - * - * Write the flow control settings to the Transmit Config Word Register (TXCW) - * base on the flow control settings in e1000_mac_info. - **/ -static s32 e1000e_commit_fc_settings_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 txcw; - s32 ret_val = E1000_SUCCESS; - - /* - * Check for a software override of the flow control settings, and - * setup the device accordingly. If auto-negotiation is enabled, then - * software will have to set the "PAUSE" bits to the correct value in - * the Transmit Config Word Register (TXCW) and re-start auto- - * negotiation. However, if auto-negotiation is disabled, then - * software will have to manually configure the two flow control enable - * bits in the CTRL register. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but we - * do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - */ - switch (hw->fc.current_mode) { - case e1000_fc_none: - /* Flow control completely disabled by a software over-ride. */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); - break; - case e1000_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is disabled - * by a software over-ride. Since there really isn't a way to - * advertise that we are capable of Rx Pause ONLY, we will - * advertise that we support both symmetric and asymmetric RX - * PAUSE. Later, we will disable the adapter's ability to send - * PAUSE frames. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); - break; - case e1000_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is disabled, - * by a software over-ride. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); - break; - case e1000_fc_full: - /* - * Flow control (both Rx and Tx) is enabled by a software - * over-ride. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); - break; - default: - e_dbg("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } - - ew32(TXCW, txcw); - mac->txcw = txcw; - -out: - return ret_val; -} - -/** - * e1000e_set_fc_watermarks - Set flow control high/low watermarks - * @hw: pointer to the HW structure - * - * Sets the flow control high/low threshold (watermark) registers. If - * flow control XON frame transmission is enabled, then set XON frame - * transmission as well. - **/ -s32 e1000e_set_fc_watermarks(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u32 fcrtl = 0, fcrth = 0; - - /* - * Set the flow control receive threshold registers. Normally, - * these registers will be set to a default threshold that may be - * adjusted later by the driver's runtime code. However, if the - * ability to transmit pause frames is not enabled, then these - * registers will be set to 0. - */ - if (hw->fc.current_mode & e1000_fc_tx_pause) { - /* - * We need to set up the Receive Threshold high and low water - * marks as well as (optionally) enabling the transmission of - * XON frames. - */ - fcrtl = hw->fc.low_water; - if (hw->fc.send_xon) - fcrtl |= E1000_FCRTL_XONE; - - fcrth = hw->fc.high_water; - } - ew32(FCRTL, fcrtl); - ew32(FCRTH, fcrth); - - return ret_val; -} - -/** - * e1000e_set_default_fc_generic - Set flow control default values - * @hw: pointer to the HW structure - * - * Read the EEPROM for the default values for flow control and store the - * values. - **/ -static s32 e1000e_set_default_fc_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 nvm_data; - - /* - * Read and store word 0x0F of the EEPROM. This word contains bits - * that determine the hardware's default PAUSE (flow control) mode, - * a bit that determines whether the HW defaults to enabling or - * disabling auto-negotiation, and the direction of the - * SW defined pins. If there is no SW over-ride of the flow - * control setting, then the variable hw->fc will - * be initialized based on a value in the EEPROM. - */ - ret_val = e1000e_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); - - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - - if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) - hw->fc.requested_mode = e1000_fc_none; - else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == - NVM_WORD0F_ASM_DIR) - hw->fc.requested_mode = e1000_fc_tx_pause; - else - hw->fc.requested_mode = e1000_fc_full; - -out: - return ret_val; -} - -/** - * e1000e_force_mac_fc - Force the MAC's flow control settings - * @hw: pointer to the HW structure - * - * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the - * device control register to reflect the adapter settings. TFCE and RFCE - * need to be explicitly set by software when a copper PHY is used because - * autonegotiation is managed by the PHY rather than the MAC. Software must - * also configure these bits when link is forced on a fiber connection. - **/ -s32 e1000e_force_mac_fc(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - - ctrl = er32(CTRL); - - /* - * Because we didn't get link via the internal auto-negotiation - * mechanism (we either forced link or we got link via PHY - * auto-neg), we have to manually enable/disable transmit an - * receive flow control. - * - * The "Case" statement below enables/disable flow control - * according to the "hw->fc.current_mode" parameter. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause - * frames but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * frames but we do not receive pause frames). - * 3: Both Rx and Tx flow control (symmetric) is enabled. - * other: No other values should be possible at this point. - */ - e_dbg("hw->fc.current_mode = %u\n", hw->fc.current_mode); - - switch (hw->fc.current_mode) { - case e1000_fc_none: - ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); - break; - case e1000_fc_rx_pause: - ctrl &= (~E1000_CTRL_TFCE); - ctrl |= E1000_CTRL_RFCE; - break; - case e1000_fc_tx_pause: - ctrl &= (~E1000_CTRL_RFCE); - ctrl |= E1000_CTRL_TFCE; - break; - case e1000_fc_full: - ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); - break; - default: - e_dbg("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ew32(CTRL, ctrl); - -out: - return ret_val; -} - -/** - * e1000e_config_fc_after_link_up - Configures flow control after link - * @hw: pointer to the HW structure - * - * Checks the status of auto-negotiation after link up to ensure that the - * speed and duplex were not forced. If the link needed to be forced, then - * flow control needs to be forced also. If auto-negotiation is enabled - * and did not fail, then we configure flow control based on our link - * partner. - **/ -s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; - u16 speed, duplex; - - /* - * Check for the case where we have fiber media and auto-neg failed - * so we had to force link. In this case, we need to force the - * configuration of the MAC to match the "fc" parameter. - */ - if (mac->autoneg_failed) { - if (hw->phy.media_type == e1000_media_type_fiber || - hw->phy.media_type == e1000_media_type_internal_serdes) - ret_val = e1000e_force_mac_fc(hw); - } else { - if (hw->phy.media_type == e1000_media_type_copper) - ret_val = e1000e_force_mac_fc(hw); - } - - if (ret_val) { - e_dbg("Error forcing flow control settings\n"); - goto out; - } - - /* - * Check for the case where we have copper media and auto-neg is - * enabled. In this case, we need to check and see if Auto-Neg - * has completed, and if so, how the PHY and link partner has - * flow control configured. - */ - if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) { - /* - * Read the MII Status Register and check to see if AutoNeg - * has completed. We read this twice because this reg has - * some "sticky" (latched) bits. - */ - ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - - if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { - e_dbg("Copper PHY and Auto Neg " - "has not completed.\n"); - goto out; - } - - /* - * The AutoNeg process has completed, so we now need to - * read both the Auto Negotiation Advertisement - * Register (Address 4) and the Auto_Negotiation Base - * Page Ability Register (Address 5) to determine how - * flow control was negotiated. - */ - ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, - &mii_nway_adv_reg); - if (ret_val) - goto out; - ret_val = e1e_rphy(hw, PHY_LP_ABILITY, - &mii_nway_lp_ability_reg); - if (ret_val) - goto out; - - /* - * Two bits in the Auto Negotiation Advertisement Register - * (Address 4) and two bits in the Auto Negotiation Base - * Page Ability Register (Address 5) determine flow control - * for both the PHY and the link partner. The following - * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, - * 1999, describes these PAUSE resolution bits and how flow - * control is determined based upon these settings. - * NOTE: DC = Don't Care - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution - *-------|---------|-------|---------|-------------------- - * 0 | 0 | DC | DC | e1000_fc_none - * 0 | 1 | 0 | DC | e1000_fc_none - * 0 | 1 | 1 | 0 | e1000_fc_none - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - * 1 | 0 | 0 | DC | e1000_fc_none - * 1 | DC | 1 | DC | e1000_fc_full - * 1 | 1 | 0 | 0 | e1000_fc_none - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause - * - * Are both PAUSE bits set to 1? If so, this implies - * Symmetric Flow Control is enabled at both ends. The - * ASM_DIR bits are irrelevant per the spec. - * - * For Symmetric Flow Control: - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | DC | 1 | DC | E1000_fc_full - * - */ - if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { - /* - * Now we need to check if the user selected Rx ONLY - * of pause frames. In this case, we had to advertise - * FULL flow control because we could not advertise RX - * ONLY. Hence, we must now check to see if we need to - * turn OFF the TRANSMISSION of PAUSE frames. - */ - if (hw->fc.requested_mode == e1000_fc_full) { - hw->fc.current_mode = e1000_fc_full; - e_dbg("Flow Control = FULL.\r\n"); - } else { - hw->fc.current_mode = e1000_fc_rx_pause; - e_dbg("Flow Control = " - "RX PAUSE frames only.\r\n"); - } - } - /* - * For receiving PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - */ - else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = e1000_fc_tx_pause; - e_dbg("Flow Control = TX PAUSE frames only.\r\n"); - } - /* - * For transmitting PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause - */ - else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = e1000_fc_rx_pause; - e_dbg("Flow Control = RX PAUSE frames only.\r\n"); - } else { - /* - * Per the IEEE spec, at this point flow control - * should be disabled. - */ - hw->fc.current_mode = e1000_fc_none; - e_dbg("Flow Control = NONE.\r\n"); - } - - /* - * Now we need to do one last check... If we auto- - * negotiated to HALF DUPLEX, flow control should not be - * enabled per IEEE 802.3 spec. - */ - ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); - if (ret_val) { - e_dbg("Error getting link speed and duplex\n"); - goto out; - } - - if (duplex == HALF_DUPLEX) - hw->fc.current_mode = e1000_fc_none; - - /* - * Now we call a subroutine to actually force the MAC - * controller to use the correct flow control settings. - */ - ret_val = e1000e_force_mac_fc(hw); - if (ret_val) { - e_dbg("Error forcing flow control settings\n"); - goto out; - } - } - -out: - return ret_val; -} - -/** - * e1000e_get_speed_and_duplex_copper - Retrieve current speed/duplex - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * Read the status register for the current speed/duplex and store the current - * speed and duplex for copper connections. - **/ -s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, - u16 *duplex) -{ - u32 status; - - status = er32(STATUS); - if (status & E1000_STATUS_SPEED_1000) { - *speed = SPEED_1000; - e_dbg("1000 Mbs, "); - } else if (status & E1000_STATUS_SPEED_100) { - *speed = SPEED_100; - e_dbg("100 Mbs, "); - } else { - *speed = SPEED_10; - e_dbg("10 Mbs, "); - } - - if (status & E1000_STATUS_FD) { - *duplex = FULL_DUPLEX; - e_dbg("Full Duplex\n"); - } else { - *duplex = HALF_DUPLEX; - e_dbg("Half Duplex\n"); - } - - return E1000_SUCCESS; -} - -/** - * e1000e_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * Sets the speed and duplex to gigabit full duplex (the only possible option) - * for fiber/serdes links. - **/ -s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw __unused, - u16 *speed, u16 *duplex) -{ - *speed = SPEED_1000; - *duplex = FULL_DUPLEX; - - return E1000_SUCCESS; -} - -/** - * e1000e_get_hw_semaphore - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM - **/ -s32 e1000e_get_hw_semaphore(struct e1000_hw *hw) -{ - u32 swsm; - s32 ret_val = E1000_SUCCESS; - s32 timeout = hw->nvm.word_size + 1; - s32 i = 0; - - /* Get the SW semaphore */ - while (i < timeout) { - swsm = er32(SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - udelay(50); - i++; - } - - if (i == timeout) { - e_dbg("Driver can't access device - SMBI bit is set.\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { - swsm = er32(SWSM); - ew32(SWSM, swsm | E1000_SWSM_SWESMBI); - - /* Semaphore acquired if bit latched */ - if (er32(SWSM) & E1000_SWSM_SWESMBI) - break; - - udelay(50); - } - - if (i == timeout) { - /* Release semaphores */ - e1000e_put_hw_semaphore(hw); - e_dbg("Driver can't access the NVM\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_put_hw_semaphore - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - **/ -void e1000e_put_hw_semaphore(struct e1000_hw *hw) -{ - u32 swsm; - - swsm = er32(SWSM); - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); - ew32(SWSM, swsm); -} -/** - * e1000e_get_auto_rd_done - Check for auto read completion - * @hw: pointer to the HW structure - * - * Check EEPROM for Auto Read done bit. - **/ -s32 e1000e_get_auto_rd_done(struct e1000_hw *hw) -{ - s32 i = 0; - s32 ret_val = E1000_SUCCESS; - - while (i < AUTO_READ_DONE_TIMEOUT) { - if (er32(EECD) & E1000_EECD_AUTO_RD) - break; - msleep(1); - i++; - } - - if (i == AUTO_READ_DONE_TIMEOUT) { - e_dbg("Auto read by HW from NVM has not completed.\n"); - ret_val = -E1000_ERR_RESET; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_valid_led_default - Verify a valid default LED config - * @hw: pointer to the HW structure - * @data: pointer to the NVM (EEPROM) - * - * Read the EEPROM for the current default LED configuration. If the - * LED configuration is not valid, set to a valid LED configuration. - **/ -s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data) -{ - s32 ret_val; - - ret_val = e1000e_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - - if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT; - -out: - return ret_val; -} - -/** - * e1000e_id_led_init - - * @hw: pointer to the HW structure - * - **/ -s32 e1000e_id_led_init(struct e1000_hw *hw __unused) -{ -#if 0 - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - const u32 ledctl_mask = 0x000000FF; - const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; - const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; - u16 data, i, temp; - const u16 led_mask = 0x0F; - - ret_val = hw->nvm.ops.valid_led_default(hw, &data); - if (ret_val) - goto out; - - mac->ledctl_default = er32(LEDCTL); - mac->ledctl_mode1 = mac->ledctl_default; - mac->ledctl_mode2 = mac->ledctl_default; - - for (i = 0; i < 4; i++) { - temp = (data >> (i << 2)) & led_mask; - switch (temp) { - case ID_LED_ON1_DEF2: - case ID_LED_ON1_ON2: - case ID_LED_ON1_OFF2: - mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode1 |= ledctl_on << (i << 3); - break; - case ID_LED_OFF1_DEF2: - case ID_LED_OFF1_ON2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode1 |= ledctl_off << (i << 3); - break; - default: - /* Do nothing */ - break; - } - switch (temp) { - case ID_LED_DEF1_ON2: - case ID_LED_ON1_ON2: - case ID_LED_OFF1_ON2: - mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode2 |= ledctl_on << (i << 3); - break; - case ID_LED_DEF1_OFF2: - case ID_LED_ON1_OFF2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode2 |= ledctl_off << (i << 3); - break; - default: - /* Do nothing */ - break; - } - } - -out: - return ret_val; -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_setup_led_generic - Configures SW controllable LED - * @hw: pointer to the HW structure - * - * This prepares the SW controllable LED for use and saves the current state - * of the LED so it can be later restored. - **/ -s32 e1000e_setup_led_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ledctl; - s32 ret_val = E1000_SUCCESS; - - if (hw->mac.ops.setup_led != e1000e_setup_led_generic) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - if (hw->phy.media_type == e1000_media_type_fiber) { - ledctl = er32(LEDCTL); - hw->mac.ledctl_default = ledctl; - /* Turn off LED0 */ - ledctl &= ~(E1000_LEDCTL_LED0_IVRT | - E1000_LEDCTL_LED0_BLINK | - E1000_LEDCTL_LED0_MODE_MASK); - ledctl |= (E1000_LEDCTL_MODE_LED_OFF << - E1000_LEDCTL_LED0_MODE_SHIFT); - ew32(LEDCTL, ledctl); - } else if (hw->phy.media_type == e1000_media_type_copper) { - ew32(LEDCTL, hw->mac.ledctl_mode1); - } - -out: - return ret_val; -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_cleanup_led_generic - Set LED config to default operation - * @hw: pointer to the HW structure - * - * Remove the current LED configuration and set the LED configuration - * to the default value, saved from the EEPROM. - **/ -s32 e1000e_cleanup_led_generic(struct e1000_hw *hw __unused) -{ -#if 0 - s32 ret_val = E1000_SUCCESS; - - if (hw->mac.ops.cleanup_led != e1000e_cleanup_led_generic) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ew32(LEDCTL, hw->mac.ledctl_default); - -out: - return ret_val; -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_blink_led - Blink LED - * @hw: pointer to the HW structure - * - * Blink the LEDs which are set to be on. - **/ -s32 e1000e_blink_led(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ledctl_blink = 0; - u32 i; - - if (hw->phy.media_type == e1000_media_type_fiber) { - /* always blink LED0 for PCI-E fiber */ - ledctl_blink = E1000_LEDCTL_LED0_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); - } else { - /* - * set the blink bit for each LED that's "on" (0x0E) - * in ledctl_mode2 - */ - ledctl_blink = hw->mac.ledctl_mode2; - for (i = 0; i < 4; i++) - if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == - E1000_LEDCTL_MODE_LED_ON) - ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << - (i * 8)); - } - - ew32(LEDCTL, ledctl_blink); -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_led_on_generic - Turn LED on - * @hw: pointer to the HW structure - * - * Turn LED on. - **/ -s32 e1000e_led_on_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl; - - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = er32(CTRL); - ctrl &= ~E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - ew32(CTRL, ctrl); - break; - case e1000_media_type_copper: - ew32(LEDCTL, hw->mac.ledctl_mode2); - break; - default: - break; - } -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_led_off_generic - Turn LED off - * @hw: pointer to the HW structure - * - * Turn LED off. - **/ -s32 e1000e_led_off_generic(struct e1000_hw *hw __unused) -{ -#if 0 - u32 ctrl; - - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - ew32(CTRL, ctrl); - break; - case e1000_media_type_copper: - ew32(LEDCTL, hw->mac.ledctl_mode1); - break; - default: - break; - } -#endif - return E1000_SUCCESS; -} - -/** - * e1000e_set_pcie_no_snoop - Set PCI-express capabilities - * @hw: pointer to the HW structure - * @no_snoop: bitmap of snoop events - * - * Set the PCI-express register to snoop for events enabled in 'no_snoop'. - **/ -void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop) -{ - u32 gcr; - - if (hw->bus.type != e1000_bus_type_pci_express) - goto out; - - if (no_snoop) { - gcr = er32(GCR); - gcr &= ~(PCIE_NO_SNOOP_ALL); - gcr |= no_snoop; - ew32(GCR, gcr); - } -out: - return; -} - -/** - * e1000e_disable_pcie_master - Disables PCI-express master access - * @hw: pointer to the HW structure - * - * Returns 0 (E1000_SUCCESS) if successful, else returns -10 - * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused - * the master requests to be disabled. - * - * Disables PCI-Express master access and verifies there are no pending - * requests. - **/ -s32 e1000e_disable_pcie_master(struct e1000_hw *hw) -{ - u32 ctrl; - s32 timeout = MASTER_DISABLE_TIMEOUT; - s32 ret_val = E1000_SUCCESS; - - if (hw->bus.type != e1000_bus_type_pci_express) - goto out; - - ctrl = er32(CTRL); - ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; - ew32(CTRL, ctrl); - - while (timeout) { - if (!(er32(STATUS) & - E1000_STATUS_GIO_MASTER_ENABLE)) - break; - udelay(100); - timeout--; - } - - if (!timeout) { - e_dbg("Master requests are pending.\n"); - ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_reset_adaptive - Reset Adaptive Interframe Spacing - * @hw: pointer to the HW structure - * - * Reset the Adaptive Interframe Spacing throttle to default values. - **/ -void e1000e_reset_adaptive(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - if (!mac->adaptive_ifs) { - e_dbg("Not in Adaptive IFS mode!\n"); - goto out; - } - - mac->current_ifs_val = 0; - mac->ifs_min_val = IFS_MIN; - mac->ifs_max_val = IFS_MAX; - mac->ifs_step_size = IFS_STEP; - mac->ifs_ratio = IFS_RATIO; - - mac->in_ifs_mode = false; - ew32(AIT, 0); -out: - return; -} - -/** - * e1000e_update_adaptive - Update Adaptive Interframe Spacing - * @hw: pointer to the HW structure - * - * Update the Adaptive Interframe Spacing Throttle value based on the - * time between transmitted packets and time between collisions. - **/ -void e1000e_update_adaptive(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - if (!mac->adaptive_ifs) { - e_dbg("Not in Adaptive IFS mode!\n"); - goto out; - } - - if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { - if (mac->tx_packet_delta > MIN_NUM_XMITS) { - mac->in_ifs_mode = true; - if (mac->current_ifs_val < mac->ifs_max_val) { - if (!mac->current_ifs_val) - mac->current_ifs_val = mac->ifs_min_val; - else - mac->current_ifs_val += - mac->ifs_step_size; - ew32(AIT, mac->current_ifs_val); - } - } - } else { - if (mac->in_ifs_mode && - (mac->tx_packet_delta <= MIN_NUM_XMITS)) { - mac->current_ifs_val = 0; - mac->in_ifs_mode = false; - ew32(AIT, 0); - } - } -out: - return; -} - -/** - * e1000e_validate_mdi_setting_generic - Verify MDI/MDIx settings - * @hw: pointer to the HW structure - * - * Verify that when not using auto-negotiation that MDI/MDIx is correctly - * set, which is forced to MDI mode only. - **/ -static s32 e1000e_validate_mdi_setting_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { - e_dbg("Invalid MDI setting detected\n"); - hw->phy.mdix = 1; - ret_val = -E1000_ERR_CONFIG; - goto out; - } - -out: - return ret_val; -} diff --git a/src/drivers/net/e1000e/e1000e_mac.h b/src/drivers/net/e1000e/e1000e_mac.h deleted file mode 100644 index 5b8a4251..00000000 --- a/src/drivers/net/e1000e/e1000e_mac.h +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_MAC_H_ -#define _E1000E_MAC_H_ - -/* - * Functions that should not be called directly from drivers but can be used - * by other files in this 'shared code' - */ -void e1000e_init_mac_ops_generic(struct e1000_hw *hw); -s32 e1000e_blink_led(struct e1000_hw *hw); -s32 e1000e_check_for_copper_link(struct e1000_hw *hw); -s32 e1000e_check_for_fiber_link(struct e1000_hw *hw); -s32 e1000e_check_for_serdes_link(struct e1000_hw *hw); -s32 e1000e_cleanup_led_generic(struct e1000_hw *hw); -s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw); -s32 e1000e_disable_pcie_master(struct e1000_hw *hw); -s32 e1000e_force_mac_fc(struct e1000_hw *hw); -s32 e1000e_get_auto_rd_done(struct e1000_hw *hw); -s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw); -void e1000e_set_lan_id_single_port(struct e1000_hw *hw); -s32 e1000e_get_hw_semaphore(struct e1000_hw *hw); -s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, - u16 *speed, u16 *duplex); -s32 e1000e_id_led_init(struct e1000_hw *hw); -s32 e1000e_led_on_generic(struct e1000_hw *hw); -s32 e1000e_led_off_generic(struct e1000_hw *hw); -void e1000e_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count); -s32 e1000e_set_fc_watermarks(struct e1000_hw *hw); -s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw); -s32 e1000e_setup_led_generic(struct e1000_hw *hw); -s32 e1000e_setup_link(struct e1000_hw *hw); - -void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw); -void e1000e_clear_vfta_generic(struct e1000_hw *hw); -void e1000e_config_collision_dist(struct e1000_hw *hw); -void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count); -void e1000e_mta_set_generic(struct e1000_hw *hw, u32 hash_value); -void e1000e_pcix_mmrbc_workaround_generic(struct e1000_hw *hw); -void e1000e_put_hw_semaphore(struct e1000_hw *hw); -void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); -s32 e1000e_check_alt_mac_addr_generic(struct e1000_hw *hw); -void e1000e_reset_adaptive(struct e1000_hw *hw); -void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop); -void e1000e_update_adaptive(struct e1000_hw *hw); -void e1000e_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); - -#endif diff --git a/src/drivers/net/e1000e/e1000e_main.c b/src/drivers/net/e1000e/e1000e_main.c deleted file mode 100644 index 69a5bc20..00000000 --- a/src/drivers/net/e1000e/e1000e_main.c +++ /dev/null @@ -1,1282 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - Portions Copyright(c) 2010 Marty Connor - Portions Copyright(c) 2010 Entity Cyber, Inc. - Portions Copyright(c) 2010 Northrop Grumman Corporation - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000e.h" - -static s32 e1000e_get_variants_82571(struct e1000_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - static int global_quad_port_a; /* global port a indication */ - struct pci_device *pdev = adapter->pdev; - u16 eeprom_data = 0; - int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1; - - /* tag quad port adapters first, it's used below */ - switch (pdev->device) { - case E1000_DEV_ID_82571EB_QUAD_COPPER: - case E1000_DEV_ID_82571EB_QUAD_FIBER: - case E1000_DEV_ID_82571EB_QUAD_COPPER_LP: - case E1000_DEV_ID_82571PT_QUAD_COPPER: - adapter->flags |= FLAG_IS_QUAD_PORT; - /* mark the first port */ - if (global_quad_port_a == 0) - adapter->flags |= FLAG_IS_QUAD_PORT_A; - /* Reset for multiple quad port adapters */ - global_quad_port_a++; - if (global_quad_port_a == 4) - global_quad_port_a = 0; - break; - default: - break; - } - - switch (adapter->hw.mac.type) { - case e1000_82571: - /* these dual ports don't have WoL on port B at all */ - if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) || - (pdev->device == E1000_DEV_ID_82571EB_SERDES) || - (pdev->device == E1000_DEV_ID_82571EB_COPPER)) && - (is_port_b)) - adapter->flags &= ~FLAG_HAS_WOL; - /* quad ports only support WoL on port A */ - if (adapter->flags & FLAG_IS_QUAD_PORT && - (!(adapter->flags & FLAG_IS_QUAD_PORT_A))) - adapter->flags &= ~FLAG_HAS_WOL; - /* Does not support WoL on any port */ - if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD) - adapter->flags &= ~FLAG_HAS_WOL; - break; - - case e1000_82573: - if (pdev->device == E1000_DEV_ID_82573L) { - if (e1000e_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, - &eeprom_data) < 0) - break; - if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) { - adapter->flags |= FLAG_HAS_JUMBO_FRAMES; - adapter->max_hw_frame_size = DEFAULT_JUMBO; - } - } - break; - - default: - break; - } - - return 0; -} - -static struct e1000_info e1000_82571_info = { - .mac = e1000_82571, - .flags = FLAG_HAS_HW_VLAN_FILTER - | FLAG_HAS_JUMBO_FRAMES - | FLAG_HAS_WOL - | FLAG_APME_IN_CTRL3 - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_HAS_SMART_POWER_DOWN - | FLAG_RESET_OVERWRITES_LAA /* errata */ - | FLAG_TARC_SPEED_MODE_BIT /* errata */ - | FLAG_APME_CHECK_PORT_B, - .pba = 38, - .max_hw_frame_size = DEFAULT_JUMBO, - .init_ops = e1000e_init_function_pointers_82571, - .get_variants = e1000e_get_variants_82571, -}; - -static struct e1000_info e1000_82572_info = { - .mac = e1000_82572, - .flags = FLAG_HAS_HW_VLAN_FILTER - | FLAG_HAS_JUMBO_FRAMES - | FLAG_HAS_WOL - | FLAG_APME_IN_CTRL3 - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_TARC_SPEED_MODE_BIT, /* errata */ - .pba = 38, - .max_hw_frame_size = DEFAULT_JUMBO, - .init_ops = e1000e_init_function_pointers_82571, - .get_variants = e1000e_get_variants_82571, -}; - -static struct e1000_info e1000_82573_info = { - .mac = e1000_82573, - .flags = FLAG_HAS_HW_VLAN_FILTER - | FLAG_HAS_WOL - | FLAG_APME_IN_CTRL3 - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_SMART_POWER_DOWN - | FLAG_HAS_AMT - | FLAG_HAS_ERT - | FLAG_HAS_SWSM_ON_LOAD, - .pba = 20, - .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, - .init_ops = e1000e_init_function_pointers_82571, - .get_variants = e1000e_get_variants_82571, -}; - -static struct e1000_info e1000_82574_info = { - .mac = e1000_82574, - .flags = FLAG_HAS_HW_VLAN_FILTER -#ifdef CONFIG_E1000E_MSIX - | FLAG_HAS_MSIX -#endif - | FLAG_HAS_JUMBO_FRAMES - | FLAG_HAS_WOL - | FLAG_APME_IN_CTRL3 - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_SMART_POWER_DOWN - | FLAG_HAS_AMT - | FLAG_HAS_CTRLEXT_ON_LOAD, - .pba = 20, - .max_hw_frame_size = DEFAULT_JUMBO, - .init_ops = e1000e_init_function_pointers_82571, - .get_variants = e1000e_get_variants_82571, -}; - -static struct e1000_info e1000_82583_info = { - .mac = e1000_82583, - .flags = FLAG_HAS_HW_VLAN_FILTER - | FLAG_HAS_WOL - | FLAG_APME_IN_CTRL3 - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_SMART_POWER_DOWN - | FLAG_HAS_AMT - | FLAG_HAS_CTRLEXT_ON_LOAD, - .pba = 20, - .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, - .init_ops = e1000e_init_function_pointers_82571, - .get_variants = e1000e_get_variants_82571, -}; - -static struct e1000_info e1000_es2_info = { - .mac = e1000_80003es2lan, - .flags = FLAG_HAS_HW_VLAN_FILTER - | FLAG_HAS_JUMBO_FRAMES - | FLAG_HAS_WOL - | FLAG_APME_IN_CTRL3 - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_RX_NEEDS_RESTART /* errata */ - | FLAG_TARC_SET_BIT_ZERO /* errata */ - | FLAG_APME_CHECK_PORT_B - | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ - | FLAG_TIPG_MEDIUM_FOR_80003ESLAN, - .pba = 38, - .max_hw_frame_size = DEFAULT_JUMBO, - .init_ops = e1000e_init_function_pointers_80003es2lan, - .get_variants = NULL, -}; - -static s32 e1000e_get_variants_ich8lan(struct e1000_adapter *adapter) -{ - if (adapter->hw.phy.type == e1000_phy_ife) { - adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; - adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; - } - - if ((adapter->hw.mac.type == e1000_ich8lan) && - (adapter->hw.phy.type == e1000_phy_igp_3)) - adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; - - return 0; -} - -static struct e1000_info e1000_ich8_info = { - .mac = e1000_ich8lan, - .flags = FLAG_HAS_WOL - | FLAG_IS_ICH - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_HAS_AMT - | FLAG_HAS_FLASH - | FLAG_APME_IN_WUC, - .pba = 8, - .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN, - .init_ops = e1000e_init_function_pointers_ich8lan, - .get_variants = e1000e_get_variants_ich8lan, -}; - -static struct e1000_info e1000_ich9_info = { - .mac = e1000_ich9lan, - .flags = FLAG_HAS_JUMBO_FRAMES - | FLAG_IS_ICH - | FLAG_HAS_WOL - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_HAS_AMT - | FLAG_HAS_ERT - | FLAG_HAS_FLASH - | FLAG_APME_IN_WUC, - .pba = 10, - .max_hw_frame_size = DEFAULT_JUMBO, - .init_ops = e1000e_init_function_pointers_ich8lan, - .get_variants = e1000e_get_variants_ich8lan, -}; - -static struct e1000_info e1000_ich10_info = { - .mac = e1000_ich10lan, - .flags = FLAG_HAS_JUMBO_FRAMES - | FLAG_IS_ICH - | FLAG_HAS_WOL - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_HAS_AMT - | FLAG_HAS_ERT - | FLAG_HAS_FLASH - | FLAG_APME_IN_WUC, - .pba = 10, - .max_hw_frame_size = DEFAULT_JUMBO, - .init_ops = e1000e_init_function_pointers_ich8lan, - .get_variants = e1000e_get_variants_ich8lan, -}; - -static struct e1000_info e1000_pch_info = { - .mac = e1000_pchlan, - .flags = FLAG_IS_ICH - | FLAG_HAS_WOL - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_HAS_AMT - | FLAG_HAS_FLASH - | FLAG_HAS_JUMBO_FRAMES - | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ - | FLAG_APME_IN_WUC, - .pba = 26, - .max_hw_frame_size = 4096, - .init_ops = e1000e_init_function_pointers_ich8lan, - .get_variants = e1000e_get_variants_ich8lan, -}; - -static struct e1000_info e1000_pch2_info = { - .mac = e1000_pch2lan, - .flags = FLAG_IS_ICH - | FLAG_HAS_WOL - | FLAG_RX_CSUM_ENABLED - | FLAG_HAS_CTRLEXT_ON_LOAD - | FLAG_HAS_AMT - | FLAG_HAS_FLASH - | FLAG_HAS_JUMBO_FRAMES - | FLAG_APME_IN_WUC, - .pba = 26, - .max_hw_frame_size = DEFAULT_JUMBO, - .init_ops = e1000e_init_function_pointers_ich8lan, - .get_variants = e1000e_get_variants_ich8lan, -}; - -static const struct e1000_info *e1000_info_tbl[] = { - [board_82571] = &e1000_82571_info, - [board_82572] = &e1000_82572_info, - [board_82573] = &e1000_82573_info, - [board_82574] = &e1000_82574_info, - [board_82583] = &e1000_82583_info, - [board_80003es2lan] = &e1000_es2_info, - [board_ich8lan] = &e1000_ich8_info, - [board_ich9lan] = &e1000_ich9_info, - [board_ich10lan] = &e1000_ich10_info, - [board_pchlan] = &e1000_pch_info, - [board_pch2lan] = &e1000_pch2_info, -}; - -/* Low-level support routines */ - -s32 e1000e_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - u16 cap_offset; - - cap_offset = pci_find_capability(hw->adapter->pdev, PCI_CAP_ID_EXP); - if (!cap_offset) - return -E1000_ERR_CONFIG; - - pci_read_config_word(hw->adapter->pdev, cap_offset + reg, value); - - return E1000_SUCCESS; -} - -/** - * e1000e_irq_disable - Mask off interrupt generation on the NIC - **/ -static void e1000e_irq_disable(struct e1000_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - - ew32(IMC, ~0); - e1e_flush(); -} - -/** - * e1000e_irq_enable - Enable default interrupt generation settings - **/ -static void e1000e_irq_enable(struct e1000_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - - ew32(IMS, IMS_ENABLE_MASK); - e1e_flush(); -} - -/** - * e1000_get_hw_control - get control of the h/w from f/w - * @adapter: address of board private structure - * - * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit. - * For ASF and Pass Through versions of f/w this means that - * the driver is loaded. For AMT version (only with 82573) - * of the f/w this means that the network i/f is open. - **/ -static void e1000e_get_hw_control(struct e1000_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - u32 ctrl_ext; - u32 swsm; - - /* Let firmware know the driver has taken over */ - if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) { - swsm = er32(SWSM); - ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD); - } else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) { - ctrl_ext = er32(CTRL_EXT); - ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); - } -} - -/** - * e1000e_power_up_phy - restore link in case the phy was powered down - * @adapter: address of board private structure - * - * The phy may be powered down to save power and turn off link when the - * driver is unloaded and wake on lan is not enabled (among others) - * *** this routine MUST be followed by a call to e1000e_reset *** - **/ -void e1000e_power_up_phy(struct e1000_adapter *adapter) -{ - if (adapter->hw.phy.ops.power_up) - adapter->hw.phy.ops.power_up(&adapter->hw); - - adapter->hw.mac.ops.setup_link(&adapter->hw); -} - -/** - * e1000_power_down_phy - Power down the PHY - * - * Power down the PHY so no link is implied when interface is down. - * The PHY cannot be powered down if management or WoL is active. - */ -void e1000e_power_down_phy(struct e1000_adapter *adapter) -{ - /* WoL is enabled */ - if (adapter->wol) - return; - - if (adapter->hw.phy.ops.power_down) - adapter->hw.phy.ops.power_down(&adapter->hw); -} - -/** - * e1000e_reset - bring the hardware into a known good state - * - * This function boots the hardware and enables some settings that - * require a configuration cycle of the hardware - those cannot be - * set/changed during runtime. After reset the device needs to be - * properly configured for Rx, Tx etc. - */ -void e1000e_reset(struct e1000_adapter *adapter) -{ - struct e1000_mac_info *mac = &adapter->hw.mac; - struct e1000_fc_info *fc = &adapter->hw.fc; - u32 pba = adapter->pba; - struct e1000_hw *hw = &adapter->hw; - - /* Reset Packet Buffer Allocation to default */ - ew32(PBA, pba); - - hw->fc.requested_mode = e1000_fc_none; - fc->current_mode = fc->requested_mode; - - /* Allow time for pending master requests to run */ - mac->ops.reset_hw(hw); - - /* - * For parts with AMT enabled, let the firmware know - * that the network interface is in control - */ - if (adapter->flags & FLAG_HAS_AMT) - e1000e_get_hw_control(adapter); - - ew32(WUC, 0); - if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) - e1e_wphy(&adapter->hw, BM_WUC, 0); - - if (mac->ops.init_hw(hw)) - DBG("Hardware Error\n"); - - /* additional part of the flow-control workaround above */ - if (hw->mac.type == e1000_pchlan) - ew32(FCRTV_PCH, 0x1000); - - e1000e_reset_adaptive(hw); - - e1000e_get_phy_info(hw); - - if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN) && - !(adapter->flags & FLAG_SMART_POWER_DOWN)) { - u16 phy_data = 0; - /* - * speed up time to link by disabling smart power down, ignore - * the return value of this function because there is nothing - * different we would do if it failed - */ - e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data); - phy_data &= ~IGP02E1000_PM_SPD; - e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); - } -} - -static int e1000e_sw_init(struct e1000_adapter *adapter) -{ - s32 rc; - - /* Set various function pointers */ - adapter->ei->init_ops(&adapter->hw); - - rc = adapter->hw.mac.ops.init_params(&adapter->hw); - if (rc) - return rc; - - rc = adapter->hw.nvm.ops.init_params(&adapter->hw); - if (rc) - return rc; - - rc = adapter->hw.phy.ops.init_params(&adapter->hw); - if (rc) - return rc; - - /* Explicitly disable IRQ since the NIC can be in any state. */ - e1000e_irq_disable(adapter); - - return E1000_SUCCESS; -} - -/* TX support routines */ - -/** - * e1000_setup_tx_resources - allocate Tx resources (Descriptors) - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int e1000e_setup_tx_resources ( struct e1000_adapter *adapter ) -{ - DBGP ( "e1000_setup_tx_resources\n" ); - - /* Allocate transmit descriptor ring memory. - It must not cross a 64K boundary because of hardware errata #23 - so we use malloc_dma() requesting a 128 byte block that is - 128 byte aligned. This should guarantee that the memory - allocated will not cross a 64K boundary, because 128 is an - even multiple of 65536 ( 65536 / 128 == 512 ), so all possible - allocations of 128 bytes on a 128 byte boundary will not - cross 64K bytes. - */ - - adapter->tx_base = - malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size ); - - if ( ! adapter->tx_base ) { - return -ENOMEM; - } - - memset ( adapter->tx_base, 0, adapter->tx_ring_size ); - - DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) ); - - return 0; -} - -/** - * e1000_process_tx_packets - process transmitted packets - * - * @v netdev network interface device structure - **/ -static void e1000e_process_tx_packets ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - uint32_t i; - uint32_t tx_status; - struct e1000_tx_desc *tx_curr_desc; - - /* Check status of transmitted packets - */ - DBG ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head, - adapter->tx_tail ); - - while ( ( i = adapter->tx_head ) != adapter->tx_tail ) { - - tx_curr_desc = ( void * ) ( adapter->tx_base ) + - ( i * sizeof ( *adapter->tx_base ) ); - - tx_status = tx_curr_desc->upper.data; - - DBG ( " tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); - DBG ( " tx_status = %#08x\n", tx_status ); - - /* if the packet at tx_head is not owned by hardware it is for us */ - if ( ! ( tx_status & E1000_TXD_STAT_DD ) ) - break; - - DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n", - adapter->tx_head, adapter->tx_tail, tx_status ); - - if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | - E1000_TXD_STAT_TU ) ) { - netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL ); - DBG ( "Error transmitting packet, tx_status: %#08x\n", - tx_status ); - } else { - netdev_tx_complete ( netdev, adapter->tx_iobuf[i] ); - DBG ( "Success transmitting packet, tx_status: %#08x\n", - tx_status ); - } - - /* Decrement count of used descriptors, clear this descriptor - */ - adapter->tx_fill_ctr--; - memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); - - adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC; - } -} - -static void e1000e_free_tx_resources ( struct e1000_adapter *adapter ) -{ - DBGP ( "e1000_free_tx_resources\n" ); - - free_dma ( adapter->tx_base, adapter->tx_ring_size ); -} - -/** - * e1000_configure_tx - Configure 8254x Transmit Unit after Reset - * @adapter: board private structure - * - * Configure the Tx unit of the MAC after a reset. - **/ -static void e1000e_configure_tx ( struct e1000_adapter *adapter ) -{ - struct e1000_hw *hw = &adapter->hw; - u32 tctl, tipg, tarc; - u32 ipgr1, ipgr2; - - DBGP ( "e1000_configure_tx\n" ); - - /* disable transmits while setting up the descriptors */ - tctl = E1000_READ_REG ( hw, E1000_TCTL ); - E1000_WRITE_REG ( hw, E1000_TCTL, tctl & ~E1000_TCTL_EN ); - e1e_flush(); - mdelay(10); - - E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) ); - E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size ); - - DBG ( "E1000_TDBAL(0): %#08x\n", E1000_READ_REG ( hw, E1000_TDBAL(0) ) ); - DBG ( "E1000_TDLEN(0): %d\n", E1000_READ_REG ( hw, E1000_TDLEN(0) ) ); - - /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG ( hw, E1000_TDH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_TDT(0), 0 ); - - adapter->tx_head = 0; - adapter->tx_tail = 0; - adapter->tx_fill_ctr = 0; - - /* Set the default values for the Tx Inter Packet Gap timer */ - tipg = DEFAULT_82543_TIPG_IPGT_COPPER; /* 8 */ - ipgr1 = DEFAULT_82543_TIPG_IPGR1; /* 8 */ - ipgr2 = DEFAULT_82543_TIPG_IPGR2; /* 6 */ - - if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN) - ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /* 7 */ - - tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT; - tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT; - ew32(TIPG, tipg); - - /* Program the Transmit Control Register */ - tctl = er32(TCTL); - tctl &= ~E1000_TCTL_CT; - tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | - (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); - - if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) { - tarc = er32(TARC(0)); - /* - * set the speed mode bit, we'll clear it if we're not at - * gigabit link later - */ -#define SPEED_MODE_BIT (1 << 21) - tarc |= SPEED_MODE_BIT; - ew32(TARC(0), tarc); - } - - /* errata: program both queues to unweighted RR */ - if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) { - tarc = er32(TARC(0)); - tarc |= 1; - ew32(TARC(0), tarc); - tarc = er32(TARC(1)); - tarc |= 1; - ew32(TARC(1), tarc); - } - - /* Setup Transmit Descriptor Settings for eop descriptor */ - adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - - /* enable Report Status bit */ - adapter->txd_cmd |= E1000_TXD_CMD_RS; - - /* - * enable transmits in the hardware, need to do this - * after setting TARC(0) - */ - tctl |= E1000_TCTL_EN; - ew32(TCTL, tctl); - e1e_flush(); - - e1000e_config_collision_dist(hw); -} - -/* RX support routines */ - -static void e1000e_free_rx_resources ( struct e1000_adapter *adapter ) -{ - int i; - - DBGP ( "e1000_free_rx_resources\n" ); - - free_dma ( adapter->rx_base, adapter->rx_ring_size ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - free_iob ( adapter->rx_iobuf[i] ); - } -} - -/** - * e1000_refill_rx_ring - allocate Rx io_buffers - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int e1000e_refill_rx_ring ( struct e1000_adapter *adapter ) -{ - int i, rx_curr; - int rc = 0; - struct e1000_rx_desc *rx_curr_desc; - struct e1000_hw *hw = &adapter->hw; - struct io_buffer *iob; - - DBGP ("e1000_refill_rx_ring\n"); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC ); - rx_curr_desc = adapter->rx_base + rx_curr; - - if ( rx_curr_desc->status & E1000_RXD_STAT_DD ) - continue; - - if ( adapter->rx_iobuf[rx_curr] != NULL ) - continue; - - DBG2 ( "Refilling rx desc %d\n", rx_curr ); - - iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE ); - adapter->rx_iobuf[rx_curr] = iob; - - if ( ! iob ) { - DBG ( "alloc_iob failed\n" ); - rc = -ENOMEM; - break; - } else { - rx_curr_desc->buffer_addr = virt_to_bus ( iob->data ); - - E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr ); - } - } - return rc; -} - -/** - * e1000_setup_rx_resources - allocate Rx resources (Descriptors) - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int e1000e_setup_rx_resources ( struct e1000_adapter *adapter ) -{ - int i, rc = 0; - - DBGP ( "e1000_setup_rx_resources\n" ); - - /* Allocate receive descriptor ring memory. - It must not cross a 64K boundary because of hardware errata - */ - - adapter->rx_base = - malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size ); - - if ( ! adapter->rx_base ) { - return -ENOMEM; - } - memset ( adapter->rx_base, 0, adapter->rx_ring_size ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - /* let e1000_refill_rx_ring() io_buffer allocations */ - adapter->rx_iobuf[i] = NULL; - } - - /* allocate io_buffers */ - rc = e1000e_refill_rx_ring ( adapter ); - if ( rc < 0 ) - e1000e_free_rx_resources ( adapter ); - - return rc; -} - -/** - * e1000_configure_rx - Configure 8254x Receive Unit after Reset - * @adapter: board private structure - * - * Configure the Rx unit of the MAC after a reset. - **/ -static void e1000e_configure_rx ( struct e1000_adapter *adapter ) -{ - struct e1000_hw *hw = &adapter->hw; - uint32_t rctl; - - DBGP ( "e1000_configure_rx\n" ); - - /* disable receives while setting up the descriptors */ - rctl = E1000_READ_REG ( hw, E1000_RCTL ); - E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); - e1e_flush(); - mdelay(10); - - adapter->rx_curr = 0; - - /* Setup the HW Rx Head and Tail Descriptor Pointers and - * the Base and Length of the Rx Descriptor Ring */ - - E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) ); - E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size ); - - E1000_WRITE_REG ( hw, E1000_RDH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 ); - - /* Enable Receives */ - rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | - E1000_RCTL_MPE | E1000_RCTL_SECRC; - E1000_WRITE_REG ( hw, E1000_RCTL, rctl ); - e1e_flush(); - - DBG ( "E1000_RDBAL(0): %#08x\n", E1000_READ_REG ( hw, E1000_RDBAL(0) ) ); - DBG ( "E1000_RDLEN(0): %d\n", E1000_READ_REG ( hw, E1000_RDLEN(0) ) ); - DBG ( "E1000_RCTL: %#08x\n", E1000_READ_REG ( hw, E1000_RCTL ) ); -} - -/** - * e1000_process_rx_packets - process received packets - * - * @v netdev network interface device structure - **/ -static void e1000e_process_rx_packets ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - uint32_t i; - uint32_t rx_status; - uint32_t rx_len; - uint32_t rx_err; - struct e1000_rx_desc *rx_curr_desc; - - /* Process received packets - */ - while ( 1 ) { - - i = adapter->rx_curr; - - rx_curr_desc = ( void * ) ( adapter->rx_base ) + - ( i * sizeof ( *adapter->rx_base ) ); - rx_status = rx_curr_desc->status; - - DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status ); - - if ( ! ( rx_status & E1000_RXD_STAT_DD ) ) - break; - - if ( adapter->rx_iobuf[i] == NULL ) - break; - - DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) ); - - rx_len = rx_curr_desc->length; - - DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n", - i, rx_status, rx_len ); - - rx_err = rx_curr_desc->errors; - - iob_put ( adapter->rx_iobuf[i], rx_len ); - - if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) { - - netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL ); - DBG ( "e1000_poll: Corrupted packet received!" - " rx_err: %#08x\n", rx_err ); - } else { - /* Add this packet to the receive queue. */ - netdev_rx ( netdev, adapter->rx_iobuf[i] ); - } - adapter->rx_iobuf[i] = NULL; - - memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) ); - - adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC; - } -} - -/** Functions that implement the iPXE driver API **/ - -/** - * e1000_close - Disables a network interface - * - * @v netdev network interface device structure - * - **/ -static void e1000e_close ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - struct e1000_hw *hw = &adapter->hw; - uint32_t rctl; - - DBGP ( "e1000_close\n" ); - - /* Disable and acknowledge interrupts */ - e1000e_irq_disable ( adapter ); - E1000_READ_REG ( hw, E1000_ICR ); - - /* disable receives */ - rctl = E1000_READ_REG ( hw, E1000_RCTL ); - E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); - e1e_flush(); - - e1000e_reset ( adapter ); - - e1000e_free_tx_resources ( adapter ); - e1000e_free_rx_resources ( adapter ); -} - -/** - * e1000_transmit - Transmit a packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * - * @ret rc Returns 0 on success, negative on failure - */ -static int e1000e_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) -{ - struct e1000_adapter *adapter = netdev_priv( netdev ); - struct e1000_hw *hw = &adapter->hw; - uint32_t tx_curr = adapter->tx_tail; - struct e1000_tx_desc *tx_curr_desc; - - DBGP ("e1000_transmit\n"); - - if ( adapter->tx_fill_ctr == NUM_TX_DESC ) { - DBG ("TX overflow\n"); - return -ENOBUFS; - } - - /* Save pointer to iobuf we have been given to transmit, - netdev_tx_complete() will need it later - */ - adapter->tx_iobuf[tx_curr] = iobuf; - - tx_curr_desc = ( void * ) ( adapter->tx_base ) + - ( tx_curr * sizeof ( *adapter->tx_base ) ); - - DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); - DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 ); - DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) ); - - /* Add the packet to TX ring - */ - tx_curr_desc->buffer_addr = virt_to_bus ( iobuf->data ); - tx_curr_desc->upper.data = 0; - tx_curr_desc->lower.data = adapter->txd_cmd | iob_len ( iobuf ); - - DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr, - tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); - - /* Point to next free descriptor */ - adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC; - adapter->tx_fill_ctr++; - - /* Write new tail to NIC, making packet available for transmit - */ - E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail ); - e1e_flush(); - - return 0; -} - -/** - * e1000_poll - Poll for received packets - * - * @v netdev Network device - */ -static void e1000e_poll ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv( netdev ); - struct e1000_hw *hw = &adapter->hw; - - uint32_t icr; - - DBGP ( "e1000_poll\n" ); - - /* Acknowledge interrupts */ - icr = E1000_READ_REG ( hw, E1000_ICR ); - if ( ! icr ) - return; - - DBG ( "e1000_poll: intr_status = %#08x\n", icr ); - - e1000e_process_tx_packets ( netdev ); - - e1000e_process_rx_packets ( netdev ); - - e1000e_refill_rx_ring(adapter); -} - -/** - * e1000_irq - enable or Disable interrupts - * - * @v adapter e1000 adapter - * @v action requested interrupt action - **/ -static void e1000e_irq ( struct net_device *netdev, int enable ) -{ - struct e1000_adapter *adapter = netdev_priv ( netdev ); - - DBGP ( "e1000_irq\n" ); - - if ( enable ) { - e1000e_irq_enable ( adapter ); - } else { - e1000e_irq_disable ( adapter ); - } -} - -static struct net_device_operations e1000e_operations; - -/** - * e1000_probe - Initial configuration of e1000 NIC - * - * @v pci PCI device - * @v id PCI IDs - * - * @ret rc Return status code - **/ -int e1000e_probe ( struct pci_device *pdev ) -{ - int i, err; - struct net_device *netdev; - struct e1000_adapter *adapter; - unsigned long mmio_start, mmio_len; - unsigned long flash_start, flash_len; - struct e1000_hw *hw; - const struct e1000_info *ei = e1000_info_tbl[pdev->id->driver_data]; - - DBGP ( "e1000_probe\n" ); - - err = -ENOMEM; - - /* Allocate net device ( also allocates memory for netdev->priv - and makes netdev-priv point to it ) */ - netdev = alloc_etherdev ( sizeof ( struct e1000_adapter ) ); - if ( ! netdev ) { - DBG ( "err_alloc_etherdev\n" ); - goto err_alloc_etherdev; - } - - /* Associate e1000-specific network operations operations with - * generic network device layer */ - netdev_init ( netdev, &e1000e_operations ); - - /* Associate this network device with given PCI device */ - pci_set_drvdata ( pdev, netdev ); - netdev->dev = &pdev->dev; - - /* Initialize driver private storage */ - adapter = netdev_priv ( netdev ); - memset ( adapter, 0, ( sizeof ( *adapter ) ) ); - - adapter->pdev = pdev; - - adapter->ioaddr = pdev->ioaddr; - adapter->hw.io_base = pdev->ioaddr; - - hw = &adapter->hw; - hw->device_id = pdev->device; - - adapter->irqno = pdev->irq; - adapter->netdev = netdev; - adapter->hw.back = adapter; - - adapter->ei = ei; - adapter->pba = ei->pba; - adapter->flags = ei->flags; - adapter->flags2 = ei->flags2; - - adapter->hw.adapter = adapter; - adapter->hw.mac.type = ei->mac; - adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; - - adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC; - adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC; - - /* Fix up PCI device */ - adjust_pci_device ( pdev ); - - err = -EIO; - - mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 ); - mmio_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_0 ); - - DBG ( "mmio_start: %#08lx\n", mmio_start ); - DBG ( "mmio_len: %#08lx\n", mmio_len ); - - adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len ); - DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr ); - - if ( ! adapter->hw.hw_addr ) { - DBG ( "err_ioremap\n" ); - goto err_ioremap; - } - - /* Flash BAR mapping depends on mac_type */ - if ( ( adapter->flags & FLAG_HAS_FLASH) && ( pdev->ioaddr ) ) { - flash_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_1 ); - flash_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_1 ); - adapter->hw.flash_address = ioremap ( flash_start, flash_len ); - if ( ! adapter->hw.flash_address ) { - DBG ( "err_flashmap\n" ); - goto err_flashmap; - } - } - - /* setup adapter struct */ - err = e1000e_sw_init ( adapter ); - if (err) { - DBG ( "err_sw_init\n" ); - goto err_sw_init; - } - - if (ei->get_variants) { - err = ei->get_variants(adapter); - if (err) { - DBG ( "err_hw_initr\n" ); - goto err_hw_init; - } - } - - /* Copper options */ - if (adapter->hw.phy.media_type == e1000_media_type_copper) { - adapter->hw.phy.mdix = AUTO_ALL_MODES; - adapter->hw.phy.disable_polarity_correction = 0; - adapter->hw.phy.ms_type = e1000_ms_hw_default; - } - - DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type ); - - /* Force auto-negotiation */ - adapter->hw.mac.autoneg = 1; - adapter->fc_autoneg = 1; - adapter->hw.phy.autoneg_wait_to_complete = true; - adapter->hw.mac.adaptive_ifs = true; - adapter->hw.fc.requested_mode = e1000_fc_default; - adapter->hw.fc.current_mode = e1000_fc_default; - - /* - * before reading the NVM, reset the controller to - * put the device in a known good starting state - */ - adapter->hw.mac.ops.reset_hw(&adapter->hw); - - /* - * systems with ASPM and others may see the checksum fail on the first - * attempt. Let's give it a few tries - */ - for (i = 0;; i++) { - if (e1000e_validate_nvm_checksum(&adapter->hw) >= 0) - break; - if (i == 2) { - DBG("The NVM Checksum Is Not Valid\n"); - err = -EIO; - goto err_eeprom; - } - } - - /* copy the MAC address out of the EEPROM */ - if ( e1000e_read_mac_addr ( &adapter->hw ) ) - DBG ( "EEPROM Read Error\n" ); - - memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN ); - - /* reset the hardware with the new settings */ - e1000e_reset ( adapter ); - - if ( ( err = register_netdev ( netdev ) ) != 0) { - DBG ( "err_register\n" ); - goto err_register; - } - - /* Mark as link up; we don't yet handle link state */ - netdev_link_up ( netdev ); - - for (i = 0; i < 6; i++) - DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":"); - - DBG ( "e1000e_probe succeeded!\n" ); - - /* No errors, return success */ - return 0; - -/* Error return paths */ -err_register: -err_hw_init: -err_eeprom: -err_flashmap: - if (!e1000e_check_reset_block(&adapter->hw)) - e1000e_phy_hw_reset(&adapter->hw); - if (adapter->hw.flash_address) - iounmap(adapter->hw.flash_address); -err_sw_init: - iounmap ( adapter->hw.hw_addr ); -err_ioremap: - netdev_put ( netdev ); -err_alloc_etherdev: - return err; -} - -/** - * e1000e_remove - Device Removal Routine - * - * @v pdev PCI device information struct - * - **/ -void e1000e_remove ( struct pci_device *pdev ) -{ - struct net_device *netdev = pci_get_drvdata ( pdev ); - struct e1000_adapter *adapter = netdev_priv ( netdev ); - - DBGP ( "e1000e_remove\n" ); - - if ( adapter->hw.flash_address ) - iounmap ( adapter->hw.flash_address ); - if ( adapter->hw.hw_addr ) - iounmap ( adapter->hw.hw_addr ); - - unregister_netdev ( netdev ); - e1000e_reset ( adapter ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); -} - -/** - * e1000e_open - Called when a network interface is made active - * - * @v netdev network interface device structure - * @ret rc Return status code, 0 on success, negative value on failure - * - **/ -static int e1000e_open ( struct net_device *netdev ) -{ - struct e1000_adapter *adapter = netdev_priv(netdev); - int err; - - DBGP ( "e1000e_open\n" ); - - /* allocate transmit descriptors */ - err = e1000e_setup_tx_resources ( adapter ); - if ( err ) { - DBG ( "Error setting up TX resources!\n" ); - goto err_setup_tx; - } - - /* allocate receive descriptors */ - err = e1000e_setup_rx_resources ( adapter ); - if ( err ) { - DBG ( "Error setting up RX resources!\n" ); - goto err_setup_rx; - } - - e1000e_configure_tx ( adapter ); - - e1000e_configure_rx ( adapter ); - - DBG ( "E1000_RXDCTL(0): %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) ); - - return 0; - -err_setup_rx: - DBG ( "err_setup_rx\n" ); - e1000e_free_tx_resources ( adapter ); -err_setup_tx: - DBG ( "err_setup_tx\n" ); - e1000e_reset ( adapter ); - - return err; -} - -/** e1000e net device operations */ -static struct net_device_operations e1000e_operations = { - .open = e1000e_open, - .close = e1000e_close, - .transmit = e1000e_transmit, - .poll = e1000e_poll, - .irq = e1000e_irq, -}; diff --git a/src/drivers/net/e1000e/e1000e_manage.c b/src/drivers/net/e1000e/e1000e_manage.c deleted file mode 100644 index e0935362..00000000 --- a/src/drivers/net/e1000e/e1000e_manage.c +++ /dev/null @@ -1,372 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#if 0 - -#include "e1000e.h" - -static u8 e1000e_calculate_checksum(u8 *buffer, u32 length); - -/** - * e1000e_calculate_checksum - Calculate checksum for buffer - * @buffer: pointer to EEPROM - * @length: size of EEPROM to calculate a checksum for - * - * Calculates the checksum for some buffer on a specified length. The - * checksum calculated is returned. - **/ -static u8 e1000e_calculate_checksum(u8 *buffer, u32 length) -{ - u32 i; - u8 sum = 0; - - if (!buffer) - return 0; - for (i = 0; i < length; i++) - sum += buffer[i]; - - return (u8) (0 - sum); -} - -/** - * e1000e_mng_enable_host_if_generic - Checks host interface is enabled - * @hw: pointer to the HW structure - * - * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND - * - * This function checks whether the HOST IF is enabled for command operation - * and also checks whether the previous command is completed. It busy waits - * in case of previous command is not completed. - **/ -s32 e1000e_mng_enable_host_if_generic(struct e1000_hw *hw) -{ - u32 hicr; - s32 ret_val = E1000_SUCCESS; - u8 i; - - /* Check that the host interface is enabled. */ - hicr = er32(HICR); - if ((hicr & E1000_HICR_EN) == 0) { - e_dbg("E1000_HOST_EN bit disabled.\n"); - ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; - goto out; - } - /* check the previous command is completed */ - for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { - hicr = er32(HICR); - if (!(hicr & E1000_HICR_C)) - break; - mdelay(1); - } - - if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { - e_dbg("Previous command timeout failed .\n"); - ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_check_mng_mode_generic - Generic check management mode - * @hw: pointer to the HW structure - * - * Reads the firmware semaphore register and returns true (>0) if - * manageability is enabled, else false (0). - **/ -bool e1000e_check_mng_mode_generic(struct e1000_hw *hw) -{ - u32 fwsm; - - fwsm = er32(FWSM); - return (fwsm & E1000_FWSM_MODE_MASK) == - (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); -} - -/** - * e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX - * @hw: pointer to the HW structure - * - * Enables packet filtering on transmit packets if manageability is enabled - * and host interface is enabled. - **/ -bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw) -{ - struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; - u32 *buffer = (u32 *)&hw->mng_cookie; - u32 offset; - s32 ret_val, hdr_csum, csum; - u8 i, len; - bool tx_filter = true; - - /* No manageability, no filtering */ - if (!hw->mac.ops.check_mng_mode(hw)) { - tx_filter = false; - goto out; - } - - /* - * If we can't read from the host interface for whatever - * reason, disable filtering. - */ - ret_val = hw->mac.ops.mng_enable_host_if(hw); - if (ret_val != E1000_SUCCESS) { - tx_filter = false; - goto out; - } - - /* Read in the header. Length and offset are in dwords. */ - len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; - offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; - for (i = 0; i < len; i++) { - *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, - E1000_HOST_IF, - offset + i); - } - hdr_csum = hdr->checksum; - hdr->checksum = 0; - csum = e1000e_calculate_checksum((u8 *)hdr, - E1000_MNG_DHCP_COOKIE_LENGTH); - /* - * If either the checksums or signature don't match, then - * the cookie area isn't considered valid, in which case we - * take the safe route of assuming Tx filtering is enabled. - */ - if (hdr_csum != csum) - goto out; - if (hdr->signature != E1000_IAMT_SIGNATURE) - goto out; - - /* Cookie area is valid, make the final check for filtering. */ - if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) - tx_filter = false; - -out: - hw->mac.tx_pkt_filtering = tx_filter; - return tx_filter; -} - -/** - * e1000e_mng_write_dhcp_info - Writes DHCP info to host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface - * @length: size of the buffer - * - * Writes the DHCP information to the host interface. - **/ -s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, - u16 length) -{ - struct e1000_host_mng_command_header hdr; - s32 ret_val; - u32 hicr; - - hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; - hdr.command_length = length; - hdr.reserved1 = 0; - hdr.reserved2 = 0; - hdr.checksum = 0; - - /* Enable the host interface */ - ret_val = hw->mac.ops.mng_enable_host_if(hw); - if (ret_val) - goto out; - - /* Populate the host interface with the contents of "buffer". */ - ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length, - sizeof(hdr), &(hdr.checksum)); - if (ret_val) - goto out; - - /* Write the manageability command header */ - ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr); - if (ret_val) - goto out; - - /* Tell the ARC a new command is pending. */ - hicr = er32(HICR); - ew32(HICR, hicr | E1000_HICR_C); - -out: - return ret_val; -} - -/** - * e1000e_mng_write_cmd_header_generic - Writes manageability command header - * @hw: pointer to the HW structure - * @hdr: pointer to the host interface command header - * - * Writes the command header after does the checksum calculation. - **/ -s32 e1000e_mng_write_cmd_header_generic(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr) -{ - u16 i, length = sizeof(struct e1000_host_mng_command_header); - - /* Write the whole command header structure with new checksum. */ - - hdr->checksum = e1000e_calculate_checksum((u8 *)hdr, length); - - length >>= 2; - /* Write the relevant command block into the ram area. */ - for (i = 0; i < length; i++) { - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, - *((u32 *) hdr + i)); - e1e_flush(); - } - - return E1000_SUCCESS; -} - -/** - * e1000e_mng_host_if_write_generic - Write to the manageability host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface buffer - * @length: size of the buffer - * @offset: location in the buffer to write to - * @sum: sum of the data (not checksum) - * - * This function writes the buffer content at the offset given on the host if. - * It also does alignment considerations to do the writes in most efficient - * way. Also fills up the sum of the buffer in *buffer parameter. - **/ -s32 e1000e_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, - u16 length, u16 offset, u8 *sum) -{ - u8 *tmp; - u8 *bufptr = buffer; - u32 data = 0; - s32 ret_val = E1000_SUCCESS; - u16 remaining, i, j, prev_bytes; - - /* sum = only sum of the data and it is not checksum */ - - if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { - ret_val = -E1000_ERR_PARAM; - goto out; - } - - tmp = (u8 *)&data; - prev_bytes = offset & 0x3; - offset >>= 2; - - if (prev_bytes) { - data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); - for (j = prev_bytes; j < sizeof(u32); j++) { - *(tmp + j) = *bufptr++; - *sum += *(tmp + j); - } - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); - length -= j - prev_bytes; - offset++; - } - - remaining = length & 0x3; - length -= remaining; - - /* Calculate length in DWORDs */ - length >>= 2; - - /* - * The device driver writes the relevant command block into the - * ram area. - */ - for (i = 0; i < length; i++) { - for (j = 0; j < sizeof(u32); j++) { - *(tmp + j) = *bufptr++; - *sum += *(tmp + j); - } - - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, - data); - } - if (remaining) { - for (j = 0; j < sizeof(u32); j++) { - if (j < remaining) - *(tmp + j) = *bufptr++; - else - *(tmp + j) = 0; - - *sum += *(tmp + j); - } - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data); - } - -out: - return ret_val; -} - -/** - * e1000e_enable_mng_pass_thru - Enable processing of ARP's - * @hw: pointer to the HW structure - * - * Verifies the hardware needs to allow ARPs to be processed by the host. - **/ -bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw) -{ - u32 manc; - u32 fwsm, factps; - bool ret_val = false; - - if (!hw->mac.asf_firmware_present) - goto out; - - manc = er32(MANC); - - if (!(manc & E1000_MANC_RCV_TCO_EN) || - !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) - goto out; - - if (hw->mac.arc_subsystem_valid) { - fwsm = er32(FWSM); - factps = er32(FACTPS); - - if (!(factps & E1000_FACTPS_MNGCG) && - ((fwsm & E1000_FWSM_MODE_MASK) == - (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { - ret_val = true; - goto out; - } - } else { - if ((manc & E1000_MANC_SMBUS_EN) && - !(manc & E1000_MANC_ASF_EN)) { - ret_val = true; - goto out; - } - } - -out: - return ret_val; -} - -#endif - diff --git a/src/drivers/net/e1000e/e1000e_manage.h b/src/drivers/net/e1000e/e1000e_manage.h deleted file mode 100644 index f136aee8..00000000 --- a/src/drivers/net/e1000e/e1000e_manage.h +++ /dev/null @@ -1,86 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_MANAGE_H_ -#define _E1000E_MANAGE_H_ - -bool e1000e_check_mng_mode_generic(struct e1000_hw *hw); -bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw); -s32 e1000e_mng_enable_host_if_generic(struct e1000_hw *hw); -s32 e1000e_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, - u16 length, u16 offset, u8 *sum); -s32 e1000e_mng_write_cmd_header_generic(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr); -#if 0 -s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, - u8 *buffer, u16 length); -#endif -bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw); - -enum e1000_mng_mode { - e1000_mng_mode_none = 0, - e1000_mng_mode_asf, - e1000_mng_mode_pt, - e1000_mng_mode_ipmi, - e1000_mng_mode_host_if_only -}; - -#define E1000_FACTPS_MNGCG 0x20000000 - -#define E1000_FWSM_MODE_MASK 0xE -#define E1000_FWSM_MODE_SHIFT 1 - -#define E1000_MNG_IAMT_MODE 0x3 -#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 -#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 -#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 -#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 -#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1 -#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 - -#define E1000_VFTA_ENTRY_SHIFT 5 -#define E1000_VFTA_ENTRY_MASK 0x7F -#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F - -#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */ -#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */ -#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */ - -#define E1000_HICR_EN 0x01 /* Enable bit - RO */ -/* Driver sets this bit when done to put command in RAM */ -#define E1000_HICR_C 0x02 -#define E1000_HICR_SV 0x04 /* Status Validity */ -#define E1000_HICR_FW_RESET_ENABLE 0x40 -#define E1000_HICR_FW_RESET 0x80 - -/* Intel(R) Active Management Technology signature */ -#define E1000_IAMT_SIGNATURE 0x544D4149 - -#endif diff --git a/src/drivers/net/e1000e/e1000e_nvm.c b/src/drivers/net/e1000e/e1000e_nvm.c deleted file mode 100644 index f49d421f..00000000 --- a/src/drivers/net/e1000e/e1000e_nvm.c +++ /dev/null @@ -1,596 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000e.h" - -static void e1000e_stop_nvm(struct e1000_hw *hw); -static void e1000e_reload_nvm(struct e1000_hw *hw); - -/** - * e1000e_init_nvm_ops_generic - Initialize NVM function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void e1000e_init_nvm_ops_generic(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - /* Initialize function pointers */ - nvm->ops.reload = e1000e_reload_nvm; -} - -/** - * e1000e_raise_eec_clk - Raise EEPROM clock - * @hw: pointer to the HW structure - * @eecd: pointer to the EEPROM - * - * Enable/Raise the EEPROM clock bit. - **/ -static void e1000e_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) -{ - *eecd = *eecd | E1000_EECD_SK; - ew32(EECD, *eecd); - e1e_flush(); - udelay(hw->nvm.delay_usec); -} - -/** - * e1000e_lower_eec_clk - Lower EEPROM clock - * @hw: pointer to the HW structure - * @eecd: pointer to the EEPROM - * - * Clear/Lower the EEPROM clock bit. - **/ -static void e1000e_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) -{ - *eecd = *eecd & ~E1000_EECD_SK; - ew32(EECD, *eecd); - e1e_flush(); - udelay(hw->nvm.delay_usec); -} - -/** - * e1000e_shift_out_eec_bits - Shift data bits our to the EEPROM - * @hw: pointer to the HW structure - * @data: data to send to the EEPROM - * @count: number of bits to shift out - * - * We need to shift 'count' bits out to the EEPROM. So, the value in the - * "data" parameter will be shifted out to the EEPROM one bit at a time. - * In order to do this, "data" must be broken down into bits. - **/ -static void e1000e_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = er32(EECD); - u32 mask; - - mask = 0x01 << (count - 1); - if (nvm->type == e1000_nvm_eeprom_spi) - eecd |= E1000_EECD_DO; - - do { - eecd &= ~E1000_EECD_DI; - - if (data & mask) - eecd |= E1000_EECD_DI; - - ew32(EECD, eecd); - e1e_flush(); - - udelay(nvm->delay_usec); - - e1000e_raise_eec_clk(hw, &eecd); - e1000e_lower_eec_clk(hw, &eecd); - - mask >>= 1; - } while (mask); - - eecd &= ~E1000_EECD_DI; - ew32(EECD, eecd); -} - -/** - * e1000e_shift_in_eec_bits - Shift data bits in from the EEPROM - * @hw: pointer to the HW structure - * @count: number of bits to shift in - * - * In order to read a register from the EEPROM, we need to shift 'count' bits - * in from the EEPROM. Bits are "shifted in" by raising the clock input to - * the EEPROM (setting the SK bit), and then reading the value of the data out - * "DO" bit. During this "shifting in" process the data in "DI" bit should - * always be clear. - **/ -static u16 e1000e_shift_in_eec_bits(struct e1000_hw *hw, u16 count) -{ - u32 eecd; - u32 i; - u16 data; - - eecd = er32(EECD); - eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); - data = 0; - - for (i = 0; i < count; i++) { - data <<= 1; - e1000e_raise_eec_clk(hw, &eecd); - - eecd = er32(EECD); - - eecd &= ~E1000_EECD_DI; - if (eecd & E1000_EECD_DO) - data |= 1; - - e1000e_lower_eec_clk(hw, &eecd); - } - - return data; -} - -/** - * e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion - * @hw: pointer to the HW structure - * @ee_reg: EEPROM flag for polling - * - * Polls the EEPROM status bit for either read or write completion based - * upon the value of 'ee_reg'. - **/ -s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) -{ - u32 attempts = 100000; - u32 i, reg = 0; - s32 ret_val = -E1000_ERR_NVM; - - for (i = 0; i < attempts; i++) { - if (ee_reg == E1000_NVM_POLL_READ) - reg = er32(EERD); - else - reg = er32(EEWR); - - if (reg & E1000_NVM_RW_REG_DONE) { - ret_val = E1000_SUCCESS; - break; - } - - udelay(5); - } - - return ret_val; -} - -/** - * e1000e_acquire_nvm - Generic request for access to EEPROM - * @hw: pointer to the HW structure - * - * Set the EEPROM access request bit and wait for EEPROM access grant bit. - * Return successful if access grant bit set, else clear the request for - * EEPROM access and return -E1000_ERR_NVM (-1). - **/ -s32 e1000e_acquire_nvm(struct e1000_hw *hw) -{ - u32 eecd = er32(EECD); - s32 timeout = E1000_NVM_GRANT_ATTEMPTS; - s32 ret_val = E1000_SUCCESS; - - ew32(EECD, eecd | E1000_EECD_REQ); - eecd = er32(EECD); - while (timeout) { - if (eecd & E1000_EECD_GNT) - break; - udelay(5); - eecd = er32(EECD); - timeout--; - } - - if (!timeout) { - eecd &= ~E1000_EECD_REQ; - ew32(EECD, eecd); - e_dbg("Could not acquire NVM grant\n"); - ret_val = -E1000_ERR_NVM; - } - - return ret_val; -} - -/** - * e1000e_standby_nvm - Return EEPROM to standby state - * @hw: pointer to the HW structure - * - * Return the EEPROM to a standby state. - **/ -static void e1000e_standby_nvm(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = er32(EECD); - - if (nvm->type == e1000_nvm_eeprom_spi) { - /* Toggle CS to flush commands */ - eecd |= E1000_EECD_CS; - ew32(EECD, eecd); - e1e_flush(); - udelay(nvm->delay_usec); - eecd &= ~E1000_EECD_CS; - ew32(EECD, eecd); - e1e_flush(); - udelay(nvm->delay_usec); - } -} - -/** - * e1000e_stop_nvm - Terminate EEPROM command - * @hw: pointer to the HW structure - * - * Terminates the current command by inverting the EEPROM's chip select pin. - **/ -static void e1000e_stop_nvm(struct e1000_hw *hw) -{ - u32 eecd; - - eecd = er32(EECD); - if (hw->nvm.type == e1000_nvm_eeprom_spi) { - /* Pull CS high */ - eecd |= E1000_EECD_CS; - e1000e_lower_eec_clk(hw, &eecd); - } -} - -/** - * e1000e_release_nvm - Release exclusive access to EEPROM - * @hw: pointer to the HW structure - * - * Stop any current commands to the EEPROM and clear the EEPROM request bit. - **/ -void e1000e_release_nvm(struct e1000_hw *hw) -{ - u32 eecd; - - e1000e_stop_nvm(hw); - - eecd = er32(EECD); - eecd &= ~E1000_EECD_REQ; - ew32(EECD, eecd); -} - -/** - * e1000e_ready_nvm_eeprom - Prepares EEPROM for read/write - * @hw: pointer to the HW structure - * - * Setups the EEPROM for reading and writing. - **/ -static s32 e1000e_ready_nvm_eeprom(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = er32(EECD); - s32 ret_val = E1000_SUCCESS; - u16 timeout = 0; - u8 spi_stat_reg; - - if (nvm->type == e1000_nvm_eeprom_spi) { - /* Clear SK and CS */ - eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); - ew32(EECD, eecd); - udelay(1); - timeout = NVM_MAX_RETRY_SPI; - - /* - * Read "Status Register" repeatedly until the LSB is cleared. - * The EEPROM will signal that the command has been completed - * by clearing bit 0 of the internal status register. If it's - * not cleared within 'timeout', then error out. - */ - while (timeout) { - e1000e_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, - hw->nvm.opcode_bits); - spi_stat_reg = (u8)e1000e_shift_in_eec_bits(hw, 8); - if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) - break; - - udelay(5); - e1000e_standby_nvm(hw); - timeout--; - } - - if (!timeout) { - e_dbg("SPI NVM Status error\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - } - -out: - return ret_val; -} - -/** - * e1000e_read_nvm_eerd - Reads EEPROM using EERD register - * @hw: pointer to the HW structure - * @offset: offset of word in the EEPROM to read - * @words: number of words to read - * @data: word read from the EEPROM - * - * Reads a 16 bit word from the EEPROM using the EERD register. - **/ -s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 i, eerd = 0; - s32 ret_val = E1000_SUCCESS; - - /* - * A check for invalid values: offset too large, too many words, - * too many words for the offset, and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - e_dbg("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - for (i = 0; i < words; i++) { - eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + - E1000_NVM_RW_REG_START; - - ew32(EERD, eerd); - ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); - if (ret_val) - break; - - data[i] = (er32(EERD) >> - E1000_NVM_RW_REG_DATA); - } - -out: - return ret_val; -} - -/** - * e1000e_write_nvm_spi - Write to EEPROM using SPI - * @hw: pointer to the HW structure - * @offset: offset within the EEPROM to be written to - * @words: number of words to write - * @data: 16 bit word(s) to be written to the EEPROM - * - * Writes data to EEPROM at offset using SPI interface. - * - * If e1000e_update_nvm_checksum is not called after this function , the - * EEPROM will most likely contain an invalid checksum. - **/ -s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - s32 ret_val; - u16 widx = 0; - - /* - * A check for invalid values: offset too large, too many words, - * and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - e_dbg("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; - - while (widx < words) { - u8 write_opcode = NVM_WRITE_OPCODE_SPI; - - ret_val = e1000e_ready_nvm_eeprom(hw); - if (ret_val) - goto release; - - e1000e_standby_nvm(hw); - - /* Send the WRITE ENABLE command (8 bit opcode) */ - e1000e_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, - nvm->opcode_bits); - - e1000e_standby_nvm(hw); - - /* - * Some SPI eeproms use the 8th address bit embedded in the - * opcode - */ - if ((nvm->address_bits == 8) && (offset >= 128)) - write_opcode |= NVM_A8_OPCODE_SPI; - - /* Send the Write command (8-bit opcode + addr) */ - e1000e_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); - e1000e_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), - nvm->address_bits); - - /* Loop to allow for up to whole page write of eeprom */ - while (widx < words) { - u16 word_out = data[widx]; - word_out = (word_out >> 8) | (word_out << 8); - e1000e_shift_out_eec_bits(hw, word_out, 16); - widx++; - - if ((((offset + widx) * 2) % nvm->page_size) == 0) { - e1000e_standby_nvm(hw); - break; - } - } - } - - msleep(10); -release: - nvm->ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000e_read_pba_num - Read device part number - * @hw: pointer to the HW structure - * @pba_num: pointer to device part number - * - * Reads the product board assembly (PBA) number from the EEPROM and stores - * the value in pba_num. - **/ -s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num) -{ - s32 ret_val; - u16 nvm_data; - - ret_val = e1000e_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - *pba_num = (u32)(nvm_data << 16); - - ret_val = e1000e_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - *pba_num |= nvm_data; - -out: - return ret_val; -} - -/** - * e1000e_read_mac_addr_generic - Read device MAC address - * @hw: pointer to the HW structure - * - * Reads the device MAC address from the EEPROM and stores the value. - * Since devices with two ports use the same EEPROM, we increment the - * last bit in the MAC address for the second port. - **/ -s32 e1000e_read_mac_addr_generic(struct e1000_hw *hw) -{ - u32 rar_high; - u32 rar_low; - u16 i; - - rar_high = er32(RAH(0)); - rar_low = er32(RAL(0)); - - for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++) - hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8)); - - for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++) - hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8)); - - for (i = 0; i < ETH_ADDR_LEN; i++) - hw->mac.addr[i] = hw->mac.perm_addr[i]; - - return E1000_SUCCESS; -} - -/** - * e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum - * @hw: pointer to the HW structure - * - * Calculates the EEPROM checksum by reading/adding each word of the EEPROM - * and then verifies that the sum of the EEPROM is equal to 0xBABA. - **/ -s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 checksum = 0; - u16 i, nvm_data; - - for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { - ret_val = e1000e_read_nvm(hw, i, 1, &nvm_data); - if (ret_val) { - e_dbg("NVM Read Error\n"); - goto out; - } - checksum += nvm_data; - } - - if (checksum != (u16) NVM_SUM) { - e_dbg("NVM Checksum Invalid\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_update_nvm_checksum_generic - Update EEPROM checksum - * @hw: pointer to the HW structure - * - * Updates the EEPROM checksum by reading/adding each word of the EEPROM - * up to the checksum. Then calculates the EEPROM checksum and writes the - * value to the EEPROM. - **/ -s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw) -{ - s32 ret_val; - u16 checksum = 0; - u16 i, nvm_data; - - for (i = 0; i < NVM_CHECKSUM_REG; i++) { - ret_val = e1000e_read_nvm(hw, i, 1, &nvm_data); - if (ret_val) { - e_dbg("NVM Read Error while updating checksum.\n"); - goto out; - } - checksum += nvm_data; - } - checksum = (u16) NVM_SUM - checksum; - ret_val = e1000e_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum); - if (ret_val) - e_dbg("NVM Write Error while updating checksum.\n"); - -out: - return ret_val; -} - -/** - * e1000e_reload_nvm - Reloads EEPROM - * @hw: pointer to the HW structure - * - * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the - * extended control register. - **/ -static void e1000e_reload_nvm(struct e1000_hw *hw) -{ - u32 ctrl_ext; - - udelay(10); - ctrl_ext = er32(CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_EE_RST; - ew32(CTRL_EXT, ctrl_ext); - e1e_flush(); -} - diff --git a/src/drivers/net/e1000e/e1000e_nvm.h b/src/drivers/net/e1000e/e1000e_nvm.h deleted file mode 100644 index 1a8e0f3f..00000000 --- a/src/drivers/net/e1000e/e1000e_nvm.h +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_NVM_H_ -#define _E1000E_NVM_H_ - -void e1000e_init_nvm_ops_generic(struct e1000_hw *hw); -s32 e1000e_acquire_nvm(struct e1000_hw *hw); - -s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); -s32 e1000e_read_mac_addr_generic(struct e1000_hw *hw); -s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num); -s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data); -s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw); -s32 e1000e_write_nvm_eewr(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw); -void e1000e_release_nvm(struct e1000_hw *hw); - -#define E1000_STM_OPCODE 0xDB00 - -#endif diff --git a/src/drivers/net/e1000e/e1000e_phy.c b/src/drivers/net/e1000e/e1000e_phy.c deleted file mode 100644 index 133109dc..00000000 --- a/src/drivers/net/e1000e/e1000e_phy.c +++ /dev/null @@ -1,3326 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include "e1000e.h" - -static s32 e1000e_copper_link_autoneg(struct e1000_hw *hw); -static s32 e1000e_phy_setup_autoneg(struct e1000_hw *hw); -static u32 e1000e_get_phy_addr_for_bm_page(u32 page, u32 reg); -static s32 e1000e_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, - u16 *data, bool read); -static u32 e1000e_get_phy_addr_for_hv_page(u32 page); -static s32 e1000e_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, - u16 *data, bool read); -#if 0 -/* Cable length tables */ -static const u16 e1000_m88_cable_length_table[] = - { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; -#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_m88_cable_length_table) / \ - sizeof(e1000_m88_cable_length_table[0])) - -static const u16 e1000_igp_2_cable_length_table[] = - { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, - 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, - 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, - 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, - 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, - 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, - 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, - 104, 109, 114, 118, 121, 124}; -#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_igp_2_cable_length_table) / \ - sizeof(e1000_igp_2_cable_length_table[0])) -#endif - -/** - * e1000e_check_reset_block_generic - Check if PHY reset is blocked - * @hw: pointer to the HW structure - * - * Read the PHY management control register and check whether a PHY reset - * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise - * return E1000_BLK_PHY_RESET (12). - **/ -s32 e1000e_check_reset_block_generic(struct e1000_hw *hw) -{ - u32 manc; - - manc = er32(MANC); - - return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? - E1000_BLK_PHY_RESET : E1000_SUCCESS; -} - -/** - * e1000e_get_phy_id - Retrieve the PHY ID and revision - * @hw: pointer to the HW structure - * - * Reads the PHY registers and stores the PHY ID and possibly the PHY - * revision in the hardware structure. - **/ -s32 e1000e_get_phy_id(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_id; - u16 retry_count = 0; - - if (!(phy->ops.read_reg)) - goto out; - - while (retry_count < 2) { - ret_val = e1e_rphy(hw, PHY_ID1, &phy_id); - if (ret_val) - goto out; - - phy->id = (u32)(phy_id << 16); - udelay(20); - ret_val = e1e_rphy(hw, PHY_ID2, &phy_id); - if (ret_val) - goto out; - - phy->id |= (u32)(phy_id & PHY_REVISION_MASK); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); - - if (phy->id != 0 && phy->id != PHY_REVISION_MASK) - goto out; - - /* - * If the PHY ID is still unknown, we may have an 82577 - * without link. We will try again after setting Slow MDIC - * mode. No harm in trying again in this case since the PHY - * ID is unknown at this point anyway. - */ - ret_val = phy->ops.acquire(hw); - if (ret_val) - goto out; - ret_val = e1000e_set_mdio_slow_mode_hv(hw, true); - if (ret_val) - goto out; - phy->ops.release(hw); - - retry_count++; - } -out: - /* Revert to MDIO fast mode, if applicable */ - if (retry_count) { - ret_val = phy->ops.acquire(hw); - if (ret_val) - return ret_val; - ret_val = e1000e_set_mdio_slow_mode_hv(hw, false); - phy->ops.release(hw); - } - - return ret_val; -} - -/** - * e1000e_phy_reset_dsp - Reset PHY DSP - * @hw: pointer to the HW structure - * - * Reset the digital signal processor. - **/ -s32 e1000e_phy_reset_dsp(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (!(hw->phy.ops.write_reg)) - goto out; - - ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); - if (ret_val) - goto out; - - ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0); - -out: - return ret_val; -} - -/** - * e1000e_read_phy_reg_mdic - Read MDI control register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the MDI control register in the PHY at offset and stores the - * information read to data. - **/ -s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, mdic = 0; - s32 ret_val = E1000_SUCCESS; - - /* - * Set up Op-code, Phy Address, and register offset in the MDI - * Control register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - mdic = ((offset << E1000_MDIC_REG_SHIFT) | - (phy->addr << E1000_MDIC_PHY_SHIFT) | - (E1000_MDIC_OP_READ)); - - ew32(MDIC, mdic); - - /* - * Poll the ready bit to see if the MDI read completed - * Increasing the time out as testing showed failures with - * the lower time out - */ - for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { - udelay(50); - mdic = er32(MDIC); - if (mdic & E1000_MDIC_READY) - break; - } - if (!(mdic & E1000_MDIC_READY)) { - e_dbg("MDI Read did not complete\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - if (mdic & E1000_MDIC_ERROR) { - e_dbg("MDI Error\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - *data = (u16) mdic; - -out: - return ret_val; -} - -/** - * e1000e_write_phy_reg_mdic - Write MDI control register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write to register at offset - * - * Writes data to MDI control register in the PHY at offset. - **/ -s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, mdic = 0; - s32 ret_val = E1000_SUCCESS; - - /* - * Set up Op-code, Phy Address, and register offset in the MDI - * Control register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - mdic = (((u32)data) | - (offset << E1000_MDIC_REG_SHIFT) | - (phy->addr << E1000_MDIC_PHY_SHIFT) | - (E1000_MDIC_OP_WRITE)); - - ew32(MDIC, mdic); - - /* - * Poll the ready bit to see if the MDI read completed - * Increasing the time out as testing showed failures with - * the lower time out - */ - for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { - udelay(50); - mdic = er32(MDIC); - if (mdic & E1000_MDIC_READY) - break; - } - if (!(mdic & E1000_MDIC_READY)) { - e_dbg("MDI Write did not complete\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - if (mdic & E1000_MDIC_ERROR) { - e_dbg("MDI Error\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_read_phy_reg_m88 - Read m88 PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) -{ - s32 ret_val = E1000_SUCCESS; - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000e_write_phy_reg_m88 - Write m88 PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) -{ - s32 ret_val = E1000_SUCCESS; - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * __e1000e_read_phy_reg_igp - Read igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and stores the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -static s32 __e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data, - bool locked) -{ - s32 ret_val = E1000_SUCCESS; - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - ret_val = e1000e_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) - goto release; - } - - ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - -release: - if (!locked) - hw->phy.ops.release(hw); -out: - return ret_val; -} - -/** - * e1000e_read_phy_reg_igp - Read igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore then reads the PHY register at offset and stores the - * retrieved information in data. - * Release the acquired semaphore before exiting. - **/ -s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __e1000e_read_phy_reg_igp(hw, offset, data, false); -} - -/** - * e1000e_read_phy_reg_igp_locked - Read igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY register at offset and stores the retrieved information - * in data. Assumes semaphore already acquired. - **/ -s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __e1000e_read_phy_reg_igp(hw, offset, data, true); -} - -/** - * e1000e_write_phy_reg_igp - Write igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -static s32 __e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data, - bool locked) -{ - s32 ret_val = E1000_SUCCESS; - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - ret_val = e1000e_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) - goto release; - } - - ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - -release: - if (!locked) - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000e_write_phy_reg_igp - Write igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __e1000e_write_phy_reg_igp(hw, offset, data, false); -} - -/** - * e1000e_write_phy_reg_igp_locked - Write igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Writes the data to PHY register at the offset. - * Assumes semaphore already acquired. - **/ -s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __e1000e_write_phy_reg_igp(hw, offset, data, true); -} - -/** - * __e1000e_read_kmrn_reg - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary. Then reads the PHY register at offset - * using the kumeran interface. The information retrieved is stored in data. - * Release any acquired semaphores before exiting. - **/ -static s32 __e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, - bool locked) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; - ew32(KMRNCTRLSTA, kmrnctrlsta); - - udelay(2); - - kmrnctrlsta = er32(KMRNCTRLSTA); - *data = (u16)kmrnctrlsta; - - if (!locked) - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000e_read_kmrn_reg - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore then reads the PHY register at offset using the - * kumeran interface. The information retrieved is stored in data. - * Release the acquired semaphore before exiting. - **/ -s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __e1000e_read_kmrn_reg(hw, offset, data, false); -} - -/** - * e1000e_read_kmrn_reg_locked - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY register at offset using the kumeran interface. The - * information retrieved is stored in data. - * Assumes semaphore already acquired. - **/ -s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __e1000e_read_kmrn_reg(hw, offset, data, true); -} - -/** - * __e1000e_write_kmrn_reg - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary. Then write the data to PHY register - * at the offset using the kumeran interface. Release any acquired semaphores - * before exiting. - **/ -static s32 __e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, - bool locked) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | data; - ew32(KMRNCTRLSTA, kmrnctrlsta); - - udelay(2); - - if (!locked) - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * e1000e_write_kmrn_reg - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore then writes the data to the PHY register at the offset - * using the kumeran interface. Release the acquired semaphore before exiting. - **/ -s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __e1000e_write_kmrn_reg(hw, offset, data, false); -} - -/** - * e1000e_write_kmrn_reg_locked - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Write the data to PHY register at the offset using the kumeran interface. - * Assumes semaphore already acquired. - **/ -s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __e1000e_write_kmrn_reg(hw, offset, data, true); -} - -/** - * e1000e_copper_link_setup_82577 - Setup 82577 PHY for copper link - * @hw: pointer to the HW structure - * - * Sets up Carrier-sense on Transmit and downshift values. - **/ -s32 e1000e_copper_link_setup_82577(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - - if (phy->reset_disable) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* Enable CRS on TX. This must be set for half-duplex operation. */ - ret_val = e1e_rphy(hw, I82577_CFG_REG, &phy_data); - if (ret_val) - goto out; - - phy_data |= I82577_CFG_ASSERT_CRS_ON_TX; - - /* Enable downshift */ - phy_data |= I82577_CFG_ENABLE_DOWNSHIFT; - - ret_val = e1e_wphy(hw, I82577_CFG_REG, phy_data); - -out: - return ret_val; -} - -/** - * e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link - * @hw: pointer to the HW structure - * - * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock - * and downshift values are set also. - **/ -s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - - if (phy->reset_disable) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* Enable CRS on TX. This must be set for half-duplex operation. */ - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - /* For BM PHY this bit is downshift enable */ - if (phy->type != e1000_phy_bm) - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - - /* - * Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - - switch (phy->mdix) { - case 1: - phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; - break; - case 2: - phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; - break; - case 3: - phy_data |= M88E1000_PSCR_AUTO_X_1000T; - break; - case 0: - default: - phy_data |= M88E1000_PSCR_AUTO_X_MODE; - break; - } - - /* - * Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if (phy->disable_polarity_correction == 1) - phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - - /* Enable downshift on BM (disabled by default) */ - if (phy->type == e1000_phy_bm) - phy_data |= BME1000_PSCR_ENABLE_DOWNSHIFT; - - ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - if ((phy->type == e1000_phy_m88) && - (phy->revision < E1000_REVISION_4) && - (phy->id != BME1000_E_PHY_ID_R2)) { - /* - * Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, - &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_EPSCR_TX_CLK_25; - - if ((phy->revision == E1000_REVISION_2) && - (phy->id == M88E1111_I_PHY_ID)) { - /* 82573L PHY - set the downshift counter to 5x. */ - phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; - phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; - } else { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - } - ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, - phy_data); - if (ret_val) - goto out; - } - - if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) { - /* Set PHY page 0, register 29 to 0x0003 */ - ret_val = e1e_wphy(hw, 29, 0x0003); - if (ret_val) - goto out; - - /* Set PHY page 0, register 30 to 0x0000 */ - ret_val = e1e_wphy(hw, 30, 0x0000); - if (ret_val) - goto out; - } - - /* Commit the changes. */ - ret_val = e1000e_commit_phy(hw); - if (ret_val) { - e_dbg("Error committing the PHY changes\n"); - goto out; - } - - if (phy->type == e1000_phy_82578) { - ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, - &phy_data); - if (ret_val) - goto out; - - /* 82578 PHY - set the downshift count to 1x. */ - phy_data |= I82578_EPSCR_DOWNSHIFT_ENABLE; - phy_data &= ~I82578_EPSCR_DOWNSHIFT_COUNTER_MASK; - ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, - phy_data); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_copper_link_setup_igp - Setup igp PHY's for copper link - * @hw: pointer to the HW structure - * - * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for - * igp PHY's. - **/ -s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - if (phy->reset_disable) { - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = e1000e_phy_hw_reset(hw); - if (ret_val) { - e_dbg("Error resetting the PHY.\n"); - goto out; - } - - /* - * Wait 100ms for MAC to configure PHY from NVM settings, to avoid - * timeout issues when LFS is enabled. - */ - msleep(100); - - /* - * The NVM settings will configure LPLU in D3 for - * non-IGP1 PHYs. - */ - if (phy->type == e1000_phy_igp) { - /* disable lplu d3 during driver init */ - ret_val = hw->phy.ops.set_d3_lplu_state(hw, false); - if (ret_val) { - e_dbg("Error Disabling LPLU D3\n"); - goto out; - } - } - - /* disable lplu d0 during driver init */ - if (hw->phy.ops.set_d0_lplu_state) { - ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); - if (ret_val) { - e_dbg("Error Disabling LPLU D0\n"); - goto out; - } - } - /* Configure mdi-mdix settings */ - ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCR_AUTO_MDIX; - - switch (phy->mdix) { - case 1: - data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 2: - data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 0: - default: - data |= IGP01E1000_PSCR_AUTO_MDIX; - break; - } - ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data); - if (ret_val) - goto out; - - /* set auto-master slave resolution settings */ - if (hw->mac.autoneg) { - /* - * when autonegotiation advertisement is only 1000Mbps then we - * should disable SmartSpeed and enable Auto MasterSlave - * resolution as hardware default. - */ - if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { - /* Disable SmartSpeed */ - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - - /* Set auto Master/Slave resolution process */ - ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data); - if (ret_val) - goto out; - - data &= ~CR_1000T_MS_ENABLE; - ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data); - if (ret_val) - goto out; - } - - ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data); - if (ret_val) - goto out; - - /* load defaults for future use */ - phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? - ((data & CR_1000T_MS_VALUE) ? - e1000_ms_force_master : - e1000_ms_force_slave) : - e1000_ms_auto; - - switch (phy->ms_type) { - case e1000_ms_force_master: - data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); - break; - case e1000_ms_force_slave: - data |= CR_1000T_MS_ENABLE; - data &= ~(CR_1000T_MS_VALUE); - break; - case e1000_ms_auto: - data &= ~CR_1000T_MS_ENABLE; - default: - break; - } - ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_copper_link_autoneg - Setup/Enable autoneg for copper link - * @hw: pointer to the HW structure - * - * Performs initial bounds checking on autoneg advertisement parameter, then - * configure to advertise the full capability. Setup the PHY to autoneg - * and restart the negotiation process between the link partner. If - * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. - **/ -static s32 e1000e_copper_link_autoneg(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_ctrl; - - /* - * Perform some bounds checking on the autoneg advertisement - * parameter. - */ - phy->autoneg_advertised &= phy->autoneg_mask; - - /* - * If autoneg_advertised is zero, we assume it was not defaulted - * by the calling code so we set to advertise full capability. - */ - if (phy->autoneg_advertised == 0) - phy->autoneg_advertised = phy->autoneg_mask; - - e_dbg("Reconfiguring auto-neg advertisement params\n"); - ret_val = e1000e_phy_setup_autoneg(hw); - if (ret_val) { - e_dbg("Error Setting up Auto-Negotiation\n"); - goto out; - } - e_dbg("Restarting Auto-Neg\n"); - - /* - * Restart auto-negotiation by setting the Auto Neg Enable bit and - * the Auto Neg Restart bit in the PHY control register. - */ - ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl); - if (ret_val) - goto out; - - phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl); - if (ret_val) - goto out; - - /* - * Does the user want to wait for Auto-Neg to complete here, or - * check at a later time (for example, callback routine). - */ - if (phy->autoneg_wait_to_complete) { - ret_val = hw->mac.ops.wait_autoneg(hw); - if (ret_val) { - e_dbg("Error while waiting for " - "autoneg to complete\n"); - goto out; - } - } - - hw->mac.get_link_status = true; - -out: - return ret_val; -} - -/** - * e1000e_phy_setup_autoneg - Configure PHY for auto-negotiation - * @hw: pointer to the HW structure - * - * Reads the MII auto-neg advertisement register and/or the 1000T control - * register and if the PHY is already setup for auto-negotiation, then - * return successful. Otherwise, setup advertisement and flow control to - * the appropriate values for the wanted auto-negotiation. - **/ -static s32 e1000e_phy_setup_autoneg(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 mii_autoneg_adv_reg; - u16 mii_1000t_ctrl_reg = 0; - - phy->autoneg_advertised &= phy->autoneg_mask; - - /* Read the MII Auto-Neg Advertisement Register (Address 4). */ - ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); - if (ret_val) - goto out; - - if (phy->autoneg_mask & ADVERTISE_1000_FULL) { - /* Read the MII 1000Base-T Control Register (Address 9). */ - ret_val = e1e_rphy(hw, PHY_1000T_CTRL, - &mii_1000t_ctrl_reg); - if (ret_val) - goto out; - } - - /* - * Need to parse both autoneg_advertised and fc and set up - * the appropriate PHY registers. First we will parse for - * autoneg_advertised software override. Since we can advertise - * a plethora of combinations, we need to check each bit - * individually. - */ - - /* - * First we clear all the 10/100 mb speed bits in the Auto-Neg - * Advertisement Register (Address 4) and the 1000 mb speed bits in - * the 1000Base-T Control Register (Address 9). - */ - mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | - NWAY_AR_100TX_HD_CAPS | - NWAY_AR_10T_FD_CAPS | - NWAY_AR_10T_HD_CAPS); - mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); - - e_dbg("autoneg_advertised %x\n", phy->autoneg_advertised); - - /* Do we want to advertise 10 Mb Half Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_10_HALF) { - e_dbg("Advertise 10mb Half duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; - } - - /* Do we want to advertise 10 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_10_FULL) { - e_dbg("Advertise 10mb Full duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; - } - - /* Do we want to advertise 100 Mb Half Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_100_HALF) { - e_dbg("Advertise 100mb Half duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; - } - - /* Do we want to advertise 100 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_100_FULL) { - e_dbg("Advertise 100mb Full duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; - } - - /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ - if (phy->autoneg_advertised & ADVERTISE_1000_HALF) - e_dbg("Advertise 1000mb Half duplex request denied!\n"); - - /* Do we want to advertise 1000 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { - e_dbg("Advertise 1000mb Full duplex\n"); - mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; - } - - /* - * Check for a software override of the flow control settings, and - * setup the PHY advertisement registers accordingly. If - * auto-negotiation is enabled, then software will have to set the - * "PAUSE" bits to the correct value in the Auto-Negotiation - * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- - * negotiation. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * but we do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - * other: No software override. The flow control configuration - * in the EEPROM is used. - */ - switch (hw->fc.current_mode) { - case e1000_fc_none: - /* - * Flow control (Rx & Tx) is completely disabled by a - * software over-ride. - */ - mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - case e1000_fc_rx_pause: - /* - * Rx Flow control is enabled, and Tx Flow control is - * disabled, by a software over-ride. - * - * Since there really isn't a way to advertise that we are - * capable of Rx Pause ONLY, we will advertise that we - * support both symmetric and asymmetric Rx PAUSE. Later - * (in e1000e_config_fc_after_link_up) we will disable the - * hw's ability to send PAUSE frames. - */ - mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - case e1000_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is - * disabled, by a software over-ride. - */ - mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; - mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; - break; - case e1000_fc_full: - /* - * Flow control (both Rx and Tx) is enabled by a software - * over-ride. - */ - mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - default: - e_dbg("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); - if (ret_val) - goto out; - - e_dbg("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - - if (phy->autoneg_mask & ADVERTISE_1000_FULL) { - ret_val = e1e_wphy(hw, - PHY_1000T_CTRL, - mii_1000t_ctrl_reg); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_setup_copper_link - Configure copper link settings - * @hw: pointer to the HW structure - * - * Calls the appropriate function to configure the link for auto-neg or forced - * speed and duplex. Then we check for link, once link is established calls - * to configure collision distance and flow control are called. If link is - * not established, we return -E1000_ERR_PHY (-2). - **/ -s32 e1000e_setup_copper_link(struct e1000_hw *hw) -{ - s32 ret_val; - bool link; - - if (hw->mac.autoneg) { - /* - * Setup autoneg and flow control advertisement and perform - * autonegotiation. - */ - ret_val = e1000e_copper_link_autoneg(hw); - if (ret_val) - goto out; - } else { -#if 0 - /* - * PHY will be set to 10H, 10F, 100H or 100F - * depending on user settings. - */ - e_dbg("Forcing Speed and Duplex\n"); - ret_val = hw->phy.ops.force_speed_duplex(hw); - if (ret_val) { - e_dbg("Error Forcing Speed and Duplex\n"); - goto out; - } -#endif - } - - /* - * Check link status. Wait up to 100 microseconds for link to become - * valid. - */ - ret_val = e1000e_phy_has_link_generic(hw, - COPPER_LINK_UP_LIMIT, - 10, - &link); - if (ret_val) - goto out; - - if (link) { - e_dbg("Valid link established!!!\n"); - e1000e_config_collision_dist(hw); - ret_val = e1000e_config_fc_after_link_up(hw); - } else { - e_dbg("Unable to establish link!!!\n"); - } - -out: - return ret_val; -} - -#if 0 -/** - * e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY - * @hw: pointer to the HW structure - * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Waits for link and returns - * successful if link up is successful, else -E1000_ERR_PHY (-2). - **/ -s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - e1000e_phy_force_speed_duplex_setup(hw, &phy_data); - - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - /* - * Clear Auto-Crossover to force MDI manually. IGP requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; - phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - - ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); - if (ret_val) - goto out; - - e_dbg("IGP PSCR: %X\n", phy_data); - - udelay(1); - - if (phy->autoneg_wait_to_complete) { - e_dbg("Waiting for forced speed/duplex link on IGP phy.\n"); - - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) - e_dbg("Link taking longer than expected.\n"); - - /* Try once more */ - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } - -out: - return ret_val; -} -#endif - -#if 0 -/** - * e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY - * @hw: pointer to the HW structure - * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Resets the PHY to commit the - * changes. If time expires while waiting for link up, we reset the DSP. - * After reset, TX_CLK and CRS on Tx must be set. Return successful upon - * successful completion, else return corresponding error code. - **/ -s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - /* - * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - e_dbg("M88E1000 PSCR: %X\n", phy_data); - - ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - e1000e_phy_force_speed_duplex_setup(hw, &phy_data); - - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - /* Reset the phy to commit changes. */ - ret_val = e1000e_commit_phy(hw); - if (ret_val) - goto out; - - if (phy->autoneg_wait_to_complete) { - e_dbg("Waiting for forced speed/duplex link on M88 phy.\n"); - - ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - - if (!link) { - /* - * We didn't get link. - * Reset the DSP and cross our fingers. - */ - ret_val = e1e_wphy(hw, - M88E1000_PHY_PAGE_SELECT, - 0x001d); - if (ret_val) - goto out; - ret_val = e1000e_phy_reset_dsp(hw); - if (ret_val) - goto out; - } - - /* Try once more */ - ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - } - - ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - /* - * Resetting the phy means we need to re-force TX_CLK in the - * Extended PHY Specific Control Register to 25MHz clock from - * the reset value of 2.5MHz. - */ - phy_data |= M88E1000_EPSCR_TX_CLK_25; - ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - /* - * In addition, we must re-enable CRS on Tx for both half and full - * duplex. - */ - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - -out: - return ret_val; -} -#endif - -#if 0 -/** - * e1000e_phy_force_speed_duplex_ife - Force PHY speed & duplex - * @hw: pointer to the HW structure - * - * Forces the speed and duplex settings of the PHY. - * This is a function pointer entry point only called by - * PHY setup routines. - **/ -s32 e1000e_phy_force_speed_duplex_ife(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - if (phy->type != e1000_phy_ife) { - ret_val = e1000e_phy_force_speed_duplex_igp(hw); - goto out; - } - - ret_val = e1e_rphy(hw, PHY_CONTROL, &data); - if (ret_val) - goto out; - - e1000e_phy_force_speed_duplex_setup(hw, &data); - - ret_val = e1e_wphy(hw, PHY_CONTROL, data); - if (ret_val) - goto out; - - /* Disable MDI-X support for 10/100 */ - ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data); - if (ret_val) - goto out; - - data &= ~IFE_PMC_AUTO_MDIX; - data &= ~IFE_PMC_FORCE_MDIX; - - ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data); - if (ret_val) - goto out; - - e_dbg("IFE PMC: %X\n", data); - - udelay(1); - - if (phy->autoneg_wait_to_complete) { - e_dbg("Waiting for forced speed/duplex link on IFE phy.\n"); - - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) - e_dbg("Link taking longer than expected.\n"); - - /* Try once more */ - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } - -out: - return ret_val; -} -#endif - -#if 0 -/** - * e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex - * @hw: pointer to the HW structure - * @phy_ctrl: pointer to current value of PHY_CONTROL - * - * Forces speed and duplex on the PHY by doing the following: disable flow - * control, force speed/duplex on the MAC, disable auto speed detection, - * disable auto-negotiation, configure duplex, configure speed, configure - * the collision distance, write configuration to CTRL register. The - * caller must write to the PHY_CONTROL register for these settings to - * take affect. - **/ -void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 ctrl; - - /* Turn off flow control when forcing speed/duplex */ - hw->fc.current_mode = e1000_fc_none; - - /* Force speed/duplex on the mac */ - ctrl = er32(CTRL); - ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - ctrl &= ~E1000_CTRL_SPD_SEL; - - /* Disable Auto Speed Detection */ - ctrl &= ~E1000_CTRL_ASDE; - - /* Disable autoneg on the phy */ - *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; - - /* Forcing Full or Half Duplex? */ - if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { - ctrl &= ~E1000_CTRL_FD; - *phy_ctrl &= ~MII_CR_FULL_DUPLEX; - e_dbg("Half Duplex\n"); - } else { - ctrl |= E1000_CTRL_FD; - *phy_ctrl |= MII_CR_FULL_DUPLEX; - e_dbg("Full Duplex\n"); - } - - /* Forcing 10mb or 100mb? */ - if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { - ctrl |= E1000_CTRL_SPD_100; - *phy_ctrl |= MII_CR_SPEED_100; - *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); - e_dbg("Forcing 100mb\n"); - } else { - ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); - *phy_ctrl |= MII_CR_SPEED_10; - *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); - e_dbg("Forcing 10mb\n"); - } - - e1000e_config_collision_dist(hw); - - ew32(CTRL, ctrl); -} -#endif - -/** - * e1000e_set_d3_lplu_state - Sets low power link up state for D3 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D3 - * and SmartSpeed is disabled when active is true, else clear lplu for D3 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. - **/ -s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 data; - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data); - if (ret_val) - goto out; - - if (!active) { - data &= ~IGP02E1000_PM_D3_LPLU; - ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = e1e_rphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || - (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || - (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { - data |= IGP02E1000_PM_D3_LPLU; - ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, - data); - } - -out: - return ret_val; -} - -/** - * e1000e_check_downshift - Checks whether a downshift in speed occurred - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns 1 - * - * A downshift is detected by querying the PHY link health. - **/ -s32 e1000e_check_downshift(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - switch (phy->type) { - case e1000_phy_m88: - case e1000_phy_gg82563: - case e1000_phy_bm: - case e1000_phy_82578: - offset = M88E1000_PHY_SPEC_STATUS; - mask = M88E1000_PSSR_DOWNSHIFT; - break; - case e1000_phy_igp_2: - case e1000_phy_igp: - case e1000_phy_igp_3: - offset = IGP01E1000_PHY_LINK_HEALTH; - mask = IGP01E1000_PLHR_SS_DOWNGRADE; - break; - default: - /* speed downshift not supported */ - phy->speed_downgraded = false; - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = e1e_rphy(hw, offset, &phy_data); - - if (!ret_val) - phy->speed_downgraded = (phy_data & mask) ? true : false; - -out: - return ret_val; -} - -/** - * e1000e_check_polarity_m88 - Checks the polarity. - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - * - * Polarity is determined based on the PHY specific status register. - **/ -s32 e1000e_check_polarity_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data); - - if (!ret_val) - phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -/** - * e1000e_check_polarity_igp - Checks the polarity. - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - * - * Polarity is determined based on the PHY port status register, and the - * current speed (since there is no polarity at 100Mbps). - **/ -s32 e1000e_check_polarity_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data, offset, mask; - - /* - * Polarity is determined based on the speed of - * our connection. - */ - ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data); - if (ret_val) - goto out; - - if ((data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) { - offset = IGP01E1000_PHY_PCS_INIT_REG; - mask = IGP01E1000_PHY_POLARITY_MASK; - } else { - /* - * This really only applies to 10Mbps since - * there is no polarity for 100Mbps (always 0). - */ - offset = IGP01E1000_PHY_PORT_STATUS; - mask = IGP01E1000_PSSR_POLARITY_REVERSED; - } - - ret_val = e1e_rphy(hw, offset, &data); - - if (!ret_val) - phy->cable_polarity = (data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - -out: - return ret_val; -} - -/** - * e1000e_check_polarity_ife - Check cable polarity for IFE PHY - * @hw: pointer to the HW structure - * - * Polarity is determined on the polarity reversal feature being enabled. - **/ -s32 e1000e_check_polarity_ife(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - /* - * Polarity is determined based on the reversal feature being enabled. - */ - if (phy->polarity_correction) { - offset = IFE_PHY_EXTENDED_STATUS_CONTROL; - mask = IFE_PESC_POLARITY_REVERSED; - } else { - offset = IFE_PHY_SPECIAL_CONTROL; - mask = IFE_PSC_FORCE_POLARITY; - } - - ret_val = e1e_rphy(hw, offset, &phy_data); - - if (!ret_val) - phy->cable_polarity = (phy_data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -/** - * e1000e_wait_autoneg - Wait for auto-neg completion - * @hw: pointer to the HW structure - * - * Waits for auto-negotiation to complete or for the auto-negotiation time - * limit to expire, which ever happens first. - **/ -s32 e1000e_wait_autoneg(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 i, phy_status; - - if (!(hw->phy.ops.read_reg)) - return E1000_SUCCESS; - - /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ - for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { - ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - if (phy_status & MII_SR_AUTONEG_COMPLETE) - break; - msleep(100); - } - - /* - * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation - * has completed. - */ - return ret_val; -} - -/** - * e1000e_phy_has_link_generic - Polls PHY for link - * @hw: pointer to the HW structure - * @iterations: number of times to poll for link - * @usec_interval: delay between polling attempts - * @success: pointer to whether polling was successful or not - * - * Polls the PHY status register for link, 'iterations' number of times. - **/ -s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, - u32 usec_interval, bool *success) -{ - s32 ret_val = E1000_SUCCESS; - u16 i, phy_status; - - if (!(hw->phy.ops.read_reg)) - return E1000_SUCCESS; - - for (i = 0; i < iterations; i++) { - /* - * Some PHYs require the PHY_STATUS register to be read - * twice due to the link bit being sticky. No harm doing - * it across the board. - */ - ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); - if (ret_val) { - /* - * If the first read fails, another entity may have - * ownership of the resources, wait and try again to - * see if they have relinquished the resources yet. - */ - udelay(usec_interval); - } - ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - if (phy_status & MII_SR_LINK_STATUS) - break; - if (usec_interval >= 1000) - mdelay(usec_interval/1000); - else - udelay(usec_interval); - } - - *success = (i < iterations) ? true : false; - - return ret_val; -} - -#if 0 -/** - * e1000e_get_cable_length_m88 - Determine cable length for m88 PHY - * @hw: pointer to the HW structure - * - * Reads the PHY specific status register to retrieve the cable length - * information. The cable length is determined by averaging the minimum and - * maximum values to get the "average" cable length. The m88 PHY has four - * possible cable length values, which are: - * Register Value Cable Length - * 0 < 50 meters - * 1 50 - 80 meters - * 2 80 - 110 meters - * 3 110 - 140 meters - * 4 > 140 meters - **/ -s32 e1000e_get_cable_length_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, index; - - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if (ret_val) - goto out; - - index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - phy->min_cable_length = e1000_m88_cable_length_table[index]; - phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} - -/** - * e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY - * @hw: pointer to the HW structure - * - * The automatic gain control (agc) normalizes the amplitude of the - * received signal, adjusting for the attenuation produced by the - * cable. By reading the AGC registers, which represent the - * combination of coarse and fine gain value, the value can be put - * into a lookup table to obtain the approximate cable length - * for each channel. - **/ -s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_data, i, agc_value = 0; - u16 cur_agc_index, max_agc_index = 0; - u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; - u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = - {IGP02E1000_PHY_AGC_A, - IGP02E1000_PHY_AGC_B, - IGP02E1000_PHY_AGC_C, - IGP02E1000_PHY_AGC_D}; - - /* Read the AGC registers for all channels */ - for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { - ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data); - if (ret_val) - goto out; - - /* - * Getting bits 15:9, which represent the combination of - * coarse and fine gain values. The result is a number - * that can be put into the lookup table to obtain the - * approximate cable length. - */ - cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & - IGP02E1000_AGC_LENGTH_MASK; - - /* Array index bound check. */ - if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || - (cur_agc_index == 0)) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - /* Remove min & max AGC values from calculation. */ - if (e1000_igp_2_cable_length_table[min_agc_index] > - e1000_igp_2_cable_length_table[cur_agc_index]) - min_agc_index = cur_agc_index; - if (e1000_igp_2_cable_length_table[max_agc_index] < - e1000_igp_2_cable_length_table[cur_agc_index]) - max_agc_index = cur_agc_index; - - agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; - } - - agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + - e1000_igp_2_cable_length_table[max_agc_index]); - agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); - - /* Calculate cable length with the error range of +/- 10 meters. */ - phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? - (agc_value - IGP02E1000_AGC_RANGE) : 0; - phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} -#endif - -/** - * e1000e_get_phy_info_m88 - Retrieve PHY information - * @hw: pointer to the HW structure - * - * Valid for only copper links. Read the PHY status register (sticky read) - * to verify that link is up. Read the PHY special control register to - * determine the polarity and 10base-T extended distance. Read the PHY - * special status register to determine MDI/MDIx and current speed. If - * speed is 1000, then determine cable length, local and remote receiver. - **/ -s32 e1000e_get_phy_info_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - if (phy->media_type != e1000_media_type_copper) { - e_dbg("Phy info is only valid for copper media\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - e_dbg("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) - ? true : false; - - ret_val = e1000e_check_polarity_m88(hw); - if (ret_val) - goto out; - - ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if (ret_val) - goto out; - - phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false; - - if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { -#if 0 - ret_val = e1000e_get_cable_length(hw); -#endif - ret_val = -E1000_ERR_CONFIG; - if (ret_val) - goto out; -#if 0 - ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data); - if (ret_val) - goto out; - - phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - - phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; -#endif - } else { - /* Set values to "undefined" */ - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - } -out: - return ret_val; -} - -/** - * e1000e_get_phy_info_igp - Retrieve igp PHY information - * @hw: pointer to the HW structure - * - * Read PHY status to determine if link is up. If link is up, then - * set/determine 10base-T extended distance and polarity correction. Read - * PHY port status to determine MDI/MDIx and speed. Based on the speed, - * determine on the cable length, local and remote receiver. - **/ -s32 e1000e_get_phy_info_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - e_dbg("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - phy->polarity_correction = true; - - ret_val = e1000e_check_polarity_igp(hw); - if (ret_val) - goto out; - - ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data); - if (ret_val) - goto out; - - phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false; - - if ((data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) { -#if 0 - ret_val = phy->ops.get_cable_length(hw); -#endif - ret_val = -E1000_ERR_CONFIG; - if (ret_val) - goto out; -#if 0 - ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data); - if (ret_val) - goto out; - - phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - - phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; -#endif - } else { - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - } -out: - return ret_val; -} - -/** - * e1000e_phy_sw_reset - PHY software reset - * @hw: pointer to the HW structure - * - * Does a software reset of the PHY by reading the PHY control register and - * setting/write the control register reset bit to the PHY. - **/ -s32 e1000e_phy_sw_reset(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 phy_ctrl; - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl); - if (ret_val) - goto out; - - phy_ctrl |= MII_CR_RESET; - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl); - if (ret_val) - goto out; - - udelay(1); - -out: - return ret_val; -} - -/** - * e1000e_phy_hw_reset_generic - PHY hardware reset - * @hw: pointer to the HW structure - * - * Verify the reset block is not blocking us from resetting. Acquire - * semaphore (if necessary) and read/set/write the device control reset - * bit in the PHY. Wait the appropriate delay time for the device to - * reset and release the semaphore (if necessary). - **/ -s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u32 ctrl; - - ret_val = e1000e_check_reset_block(hw); - if (ret_val) { - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = phy->ops.acquire(hw); - if (ret_val) - goto out; - - ctrl = er32(CTRL); - ew32(CTRL, ctrl | E1000_CTRL_PHY_RST); - e1e_flush(); - - udelay(phy->reset_delay_us); - - ew32(CTRL, ctrl); - e1e_flush(); - - udelay(150); - - phy->ops.release(hw); - - ret_val = phy->ops.get_cfg_done(hw); - -out: - return ret_val; -} - -/** - * e1000e_get_cfg_done - Generic configuration done - * @hw: pointer to the HW structure - * - * Generic function to wait 10 milli-seconds for configuration to complete - * and return success. - **/ -s32 e1000e_get_cfg_done(struct e1000_hw *hw __unused) -{ - mdelay(10); - - return E1000_SUCCESS; -} - -/** - * e1000e_phy_init_script_igp3 - Inits the IGP3 PHY - * @hw: pointer to the HW structure - * - * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. - **/ -s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw) -{ - e_dbg("Running IGP 3 PHY init script\n"); - - /* PHY init IGP 3 */ - /* Enable rise/fall, 10-mode work in class-A */ - e1e_wphy(hw, 0x2F5B, 0x9018); - /* Remove all caps from Replica path filter */ - e1e_wphy(hw, 0x2F52, 0x0000); - /* Bias trimming for ADC, AFE and Driver (Default) */ - e1e_wphy(hw, 0x2FB1, 0x8B24); - /* Increase Hybrid poly bias */ - e1e_wphy(hw, 0x2FB2, 0xF8F0); - /* Add 4% to Tx amplitude in Gig mode */ - e1e_wphy(hw, 0x2010, 0x10B0); - /* Disable trimming (TTT) */ - e1e_wphy(hw, 0x2011, 0x0000); - /* Poly DC correction to 94.6% + 2% for all channels */ - e1e_wphy(hw, 0x20DD, 0x249A); - /* ABS DC correction to 95.9% */ - e1e_wphy(hw, 0x20DE, 0x00D3); - /* BG temp curve trim */ - e1e_wphy(hw, 0x28B4, 0x04CE); - /* Increasing ADC OPAMP stage 1 currents to max */ - e1e_wphy(hw, 0x2F70, 0x29E4); - /* Force 1000 ( required for enabling PHY regs configuration) */ - e1e_wphy(hw, 0x0000, 0x0140); - /* Set upd_freq to 6 */ - e1e_wphy(hw, 0x1F30, 0x1606); - /* Disable NPDFE */ - e1e_wphy(hw, 0x1F31, 0xB814); - /* Disable adaptive fixed FFE (Default) */ - e1e_wphy(hw, 0x1F35, 0x002A); - /* Enable FFE hysteresis */ - e1e_wphy(hw, 0x1F3E, 0x0067); - /* Fixed FFE for short cable lengths */ - e1e_wphy(hw, 0x1F54, 0x0065); - /* Fixed FFE for medium cable lengths */ - e1e_wphy(hw, 0x1F55, 0x002A); - /* Fixed FFE for long cable lengths */ - e1e_wphy(hw, 0x1F56, 0x002A); - /* Enable Adaptive Clip Threshold */ - e1e_wphy(hw, 0x1F72, 0x3FB0); - /* AHT reset limit to 1 */ - e1e_wphy(hw, 0x1F76, 0xC0FF); - /* Set AHT master delay to 127 msec */ - e1e_wphy(hw, 0x1F77, 0x1DEC); - /* Set scan bits for AHT */ - e1e_wphy(hw, 0x1F78, 0xF9EF); - /* Set AHT Preset bits */ - e1e_wphy(hw, 0x1F79, 0x0210); - /* Change integ_factor of channel A to 3 */ - e1e_wphy(hw, 0x1895, 0x0003); - /* Change prop_factor of channels BCD to 8 */ - e1e_wphy(hw, 0x1796, 0x0008); - /* Change cg_icount + enable integbp for channels BCD */ - e1e_wphy(hw, 0x1798, 0xD008); - /* - * Change cg_icount + enable integbp + change prop_factor_master - * to 8 for channel A - */ - e1e_wphy(hw, 0x1898, 0xD918); - /* Disable AHT in Slave mode on channel A */ - e1e_wphy(hw, 0x187A, 0x0800); - /* - * Enable LPLU and disable AN to 1000 in non-D0a states, - * Enable SPD+B2B - */ - e1e_wphy(hw, 0x0019, 0x008D); - /* Enable restart AN on an1000_dis change */ - e1e_wphy(hw, 0x001B, 0x2080); - /* Enable wh_fifo read clock in 10/100 modes */ - e1e_wphy(hw, 0x0014, 0x0045); - /* Restart AN, Speed selection is 1000 */ - e1e_wphy(hw, 0x0000, 0x1340); - - return E1000_SUCCESS; -} - -/** - * e1000e_get_phy_type_from_id - Get PHY type from id - * @phy_id: phy_id read from the phy - * - * Returns the phy type from the id. - **/ -enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id) -{ - enum e1000_phy_type phy_type = e1000_phy_unknown; - - switch (phy_id) { - case M88E1000_I_PHY_ID: - case M88E1000_E_PHY_ID: - case M88E1111_I_PHY_ID: - case M88E1011_I_PHY_ID: - phy_type = e1000_phy_m88; - break; - case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ - phy_type = e1000_phy_igp_2; - break; - case GG82563_E_PHY_ID: - phy_type = e1000_phy_gg82563; - break; - case IGP03E1000_E_PHY_ID: - phy_type = e1000_phy_igp_3; - break; - case IFE_E_PHY_ID: - case IFE_PLUS_E_PHY_ID: - case IFE_C_E_PHY_ID: - phy_type = e1000_phy_ife; - break; - case BME1000_E_PHY_ID: - case BME1000_E_PHY_ID_R2: - phy_type = e1000_phy_bm; - break; - case I82578_E_PHY_ID: - phy_type = e1000_phy_82578; - break; - case I82577_E_PHY_ID: - phy_type = e1000_phy_82577; - break; - case I82579_E_PHY_ID: - phy_type = e1000_phy_82579; - break; - default: - phy_type = e1000_phy_unknown; - break; - } - return phy_type; -} - -/** - * e1000e_determine_phy_address - Determines PHY address. - * @hw: pointer to the HW structure - * - * This uses a trial and error method to loop through possible PHY - * addresses. It tests each by reading the PHY ID registers and - * checking for a match. - **/ -s32 e1000e_determine_phy_address(struct e1000_hw *hw) -{ - s32 ret_val = -E1000_ERR_PHY_TYPE; - u32 phy_addr = 0; - u32 i; - enum e1000_phy_type phy_type = e1000_phy_unknown; - - hw->phy.id = phy_type; - - for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { - hw->phy.addr = phy_addr; - i = 0; - - do { - e1000e_get_phy_id(hw); - phy_type = e1000e_get_phy_type_from_id(hw->phy.id); - - /* - * If phy_type is valid, break - we found our - * PHY address - */ - if (phy_type != e1000_phy_unknown) { - ret_val = E1000_SUCCESS; - goto out; - } - msleep(1); - i++; - } while (i < 10); - } - -out: - return ret_val; -} - -/** - * e1000e_get_phy_addr_for_bm_page - Retrieve PHY page address - * @page: page to access - * - * Returns the phy address for the page requested. - **/ -static u32 e1000e_get_phy_addr_for_bm_page(u32 page, u32 reg) -{ - u32 phy_addr = 2; - - if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31)) - phy_addr = 1; - - return phy_addr; -} - -/** - * e1000e_write_phy_reg_bm - Write BM PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data) -{ - s32 ret_val; - u32 page_select = 0; - u32 page = offset >> IGP_PAGE_SHIFT; - u32 page_shift = 0; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - - /* Page 800 works differently than the rest so it has its own func */ - if (page == BM_WUC_PAGE) { - ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, &data, - false); - goto out; - } - - hw->phy.addr = e1000e_get_phy_addr_for_bm_page(page, offset); - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - /* - * Page select is register 31 for phy address 1 and 22 for - * phy address 2 and 3. Page select is shifted only for - * phy address 1. - */ - if (hw->phy.addr == 1) { - page_shift = IGP_PAGE_SHIFT; - page_select = IGP01E1000_PHY_PAGE_SELECT; - } else { - page_shift = 0; - page_select = BM_PHY_PAGE_SELECT; - } - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, page_select, - (page << page_shift)); - if (ret_val) - goto out; - } - - ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - -out: - hw->phy.ops.release(hw); - return ret_val; -} - -/** - * e1000e_read_phy_reg_bm - Read BM PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data) -{ - s32 ret_val; - u32 page_select = 0; - u32 page = offset >> IGP_PAGE_SHIFT; - u32 page_shift = 0; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - - /* Page 800 works differently than the rest so it has its own func */ - if (page == BM_WUC_PAGE) { - ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, data, - true); - goto out; - } - - hw->phy.addr = e1000e_get_phy_addr_for_bm_page(page, offset); - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - /* - * Page select is register 31 for phy address 1 and 22 for - * phy address 2 and 3. Page select is shifted only for - * phy address 1. - */ - if (hw->phy.addr == 1) { - page_shift = IGP_PAGE_SHIFT; - page_select = IGP01E1000_PHY_PAGE_SELECT; - } else { - page_shift = 0; - page_select = BM_PHY_PAGE_SELECT; - } - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, page_select, - (page << page_shift)); - if (ret_val) - goto out; - } - - ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); -out: - hw->phy.ops.release(hw); - return ret_val; -} - -/** - * e1000e_read_phy_reg_bm2 - Read BM PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data) -{ - s32 ret_val; - u16 page = (u16)(offset >> IGP_PAGE_SHIFT); - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - - /* Page 800 works differently than the rest so it has its own func */ - if (page == BM_WUC_PAGE) { - ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, data, - true); - goto out; - } - - hw->phy.addr = 1; - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, - page); - - if (ret_val) - goto out; - } - - ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); -out: - hw->phy.ops.release(hw); - return ret_val; -} - -/** - * e1000e_write_phy_reg_bm2 - Write BM PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data) -{ - s32 ret_val; - u16 page = (u16)(offset >> IGP_PAGE_SHIFT); - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - - /* Page 800 works differently than the rest so it has its own func */ - if (page == BM_WUC_PAGE) { - ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, &data, - false); - goto out; - } - - hw->phy.addr = 1; - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT, - page); - - if (ret_val) - goto out; - } - - ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - -out: - hw->phy.ops.release(hw); - return ret_val; -} - -/** - * e1000e_access_phy_wakeup_reg_bm - Read BM PHY wakeup register - * @hw: pointer to the HW structure - * @offset: register offset to be read or written - * @data: pointer to the data to read or write - * @read: determines if operation is read or write - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphores before exiting. Note that procedure to read the wakeup - * registers are different. It works as such: - * 1) Set page 769, register 17, bit 2 = 1 - * 2) Set page to 800 for host (801 if we were manageability) - * 3) Write the address using the address opcode (0x11) - * 4) Read or write the data using the data opcode (0x12) - * 5) Restore 769_17.2 to its original value - * - * Assumes semaphore already acquired. - **/ -static s32 e1000e_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset, - u16 *data, bool read) -{ - s32 ret_val; - u16 reg = BM_PHY_REG_NUM(offset); - u16 phy_reg = 0; - - /* Gig must be disabled for MDIO accesses to page 800 */ - if ((hw->mac.type == e1000_pchlan) && - (!(er32(PHY_CTRL) & E1000_PHY_CTRL_GBE_DISABLE))) - e_dbg("Attempting to access page 800 while gig enabled.\n"); - - /* All operations in this function are phy address 1 */ - hw->phy.addr = 1; - - /* Set page 769 */ - e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, - (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); - - ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg); - if (ret_val) { - e_dbg("Could not read PHY page 769\n"); - goto out; - } - - /* First clear bit 4 to avoid a power state change */ - phy_reg &= ~(BM_WUC_HOST_WU_BIT); - ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); - if (ret_val) { - e_dbg("Could not clear PHY page 769 bit 4\n"); - goto out; - } - - /* Write bit 2 = 1, and clear bit 4 to 769_17 */ - ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, - phy_reg | BM_WUC_ENABLE_BIT); - if (ret_val) { - e_dbg("Could not write PHY page 769 bit 2\n"); - goto out; - } - - /* Select page 800 */ - ret_val = e1000e_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (BM_WUC_PAGE << IGP_PAGE_SHIFT)); - - /* Write the page 800 offset value using opcode 0x11 */ - ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg); - if (ret_val) { - e_dbg("Could not write address opcode to page 800\n"); - goto out; - } - - if (read) { - /* Read the page 800 value using opcode 0x12 */ - ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, - data); - } else { - /* Write the page 800 value using opcode 0x12 */ - ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE, - *data); - } - - if (ret_val) { - e_dbg("Could not access data value from page 800\n"); - goto out; - } - - /* - * Restore 769_17.2 to its original value - * Set page 769 - */ - e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, - (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT)); - - /* Clear 769_17.2 */ - ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg); - if (ret_val) { - e_dbg("Could not clear PHY page 769 bit 2\n"); - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_power_up_phy_copper - Restore copper link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, restore the link to previous - * settings. - **/ -void e1000e_power_up_phy_copper(struct e1000_hw *hw) -{ - u16 mii_reg = 0; - - /* The PHY will retain its settings across a power down/up cycle */ - e1e_rphy(hw, PHY_CONTROL, &mii_reg); - mii_reg &= ~MII_CR_POWER_DOWN; - e1e_wphy(hw, PHY_CONTROL, mii_reg); -} - -/** - * e1000e_power_down_phy_copper - Restore copper link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, restore the link to previous - * settings. - **/ -void e1000e_power_down_phy_copper(struct e1000_hw *hw) -{ - u16 mii_reg = 0; - - /* The PHY will retain its settings across a power down/up cycle */ - e1e_rphy(hw, PHY_CONTROL, &mii_reg); - mii_reg |= MII_CR_POWER_DOWN; - e1e_wphy(hw, PHY_CONTROL, mii_reg); - msleep(1); -} - -/** - * e1000e_set_mdio_slow_mode_hv - Set slow MDIO access mode - * @hw: pointer to the HW structure - * @slow: true for slow mode, false for normal mode - * - * Assumes semaphore already acquired. - **/ -s32 e1000e_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow) -{ - s32 ret_val = E1000_SUCCESS; - u16 data = 0; - - /* Set MDIO mode - page 769, register 16: 0x2580==slow, 0x2180==fast */ - hw->phy.addr = 1; - ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, - (BM_PORT_CTRL_PAGE << IGP_PAGE_SHIFT)); - if (ret_val) - goto out; - - ret_val = e1000e_write_phy_reg_mdic(hw, BM_CS_CTRL1, - (0x2180 | (slow << 10))); - if (ret_val) - goto out; - - /* dummy read when reverting to fast mode - throw away result */ - if (!slow) - ret_val = e1000e_read_phy_reg_mdic(hw, BM_CS_CTRL1, &data); - -out: - return ret_val; -} - -/** - * __e1000e_read_phy_reg_hv - Read HV PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and stores the retrieved information in data. Release any acquired - * semaphore before exiting. - **/ -static s32 __e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data, - bool locked) -{ - s32 ret_val; - u16 page = BM_PHY_REG_PAGE(offset); - u16 reg = BM_PHY_REG_NUM(offset); - bool in_slow_mode = false; - - if (!locked) { - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - } - - /* Workaround failure in MDIO access while cable is disconnected */ - if ((hw->phy.type == e1000_phy_82577) && - !(er32(STATUS) & E1000_STATUS_LU)) { - ret_val = e1000e_set_mdio_slow_mode_hv(hw, true); - if (ret_val) - goto out; - - in_slow_mode = true; - } - - /* Page 800 works differently than the rest so it has its own func */ - if (page == BM_WUC_PAGE) { - ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, - data, true); - goto out; - } - - if (page > 0 && page < HV_INTC_FC_PAGE_START) { - ret_val = e1000e_access_phy_debug_regs_hv(hw, offset, - data, true); - goto out; - } - - hw->phy.addr = e1000e_get_phy_addr_for_hv_page(page); - - if (page == HV_INTC_FC_PAGE_START) - page = 0; - - if (reg > MAX_PHY_MULTI_PAGE_REG) { - u32 phy_addr = hw->phy.addr; - - hw->phy.addr = 1; - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); - hw->phy.addr = phy_addr; - - if (ret_val) - goto out; - } - - ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, - data); -out: - /* Revert to MDIO fast mode, if applicable */ - if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) - ret_val |= e1000e_set_mdio_slow_mode_hv(hw, false); - - if (!locked) - hw->phy.ops.release(hw); - - return ret_val; -} - -/** - * e1000e_read_phy_reg_hv - Read HV PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore then reads the PHY register at offset and stores - * the retrieved information in data. Release the acquired semaphore - * before exiting. - **/ -s32 e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __e1000e_read_phy_reg_hv(hw, offset, data, false); -} - -/** - * e1000e_read_phy_reg_hv_locked - Read HV PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY register at offset and stores the retrieved information - * in data. Assumes semaphore already acquired. - **/ -s32 e1000e_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __e1000e_read_phy_reg_hv(hw, offset, data, true); -} - -/** - * __e1000e_write_phy_reg_hv - Write HV PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -static s32 __e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data, - bool locked) -{ - s32 ret_val; - u16 page = BM_PHY_REG_PAGE(offset); - u16 reg = BM_PHY_REG_NUM(offset); - bool in_slow_mode = false; - - if (!locked) { - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; - } - - /* Workaround failure in MDIO access while cable is disconnected */ - if ((hw->phy.type == e1000_phy_82577) && - !(er32(STATUS) & E1000_STATUS_LU)) { - ret_val = e1000e_set_mdio_slow_mode_hv(hw, true); - if (ret_val) - goto out; - - in_slow_mode = true; - } - - /* Page 800 works differently than the rest so it has its own func */ - if (page == BM_WUC_PAGE) { - ret_val = e1000e_access_phy_wakeup_reg_bm(hw, offset, - &data, false); - goto out; - } - - if (page > 0 && page < HV_INTC_FC_PAGE_START) { - ret_val = e1000e_access_phy_debug_regs_hv(hw, offset, - &data, false); - goto out; - } - - hw->phy.addr = e1000e_get_phy_addr_for_hv_page(page); - - if (page == HV_INTC_FC_PAGE_START) - page = 0; - - /* - * Workaround MDIO accesses being disabled after entering IEEE Power - * Down (whenever bit 11 of the PHY Control register is set) - */ - if ((hw->phy.type == e1000_phy_82578) && - (hw->phy.revision >= 1) && - (hw->phy.addr == 2) && - ((MAX_PHY_REG_ADDRESS & reg) == 0) && - (data & (1 << 11))) { - u16 data2 = 0x7EFF; - ret_val = e1000e_access_phy_debug_regs_hv(hw, (1 << 6) | 0x3, - &data2, false); - if (ret_val) - goto out; - } - - if (reg > MAX_PHY_MULTI_PAGE_REG) { - u32 phy_addr = hw->phy.addr; - - hw->phy.addr = 1; - - /* Page is shifted left, PHY expects (page x 32) */ - ret_val = e1000e_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (page << IGP_PAGE_SHIFT)); - hw->phy.addr = phy_addr; - - if (ret_val) - goto out; - } - - ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & reg, - data); - -out: - /* Revert to MDIO fast mode, if applicable */ - if ((hw->phy.type == e1000_phy_82577) && in_slow_mode) - ret_val |= e1000e_set_mdio_slow_mode_hv(hw, false); - - if (!locked) - hw->phy.ops.release(hw); - - return ret_val; -} - -/** - * e1000e_write_phy_reg_hv - Write HV PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore then writes the data to PHY register at the offset. - * Release the acquired semaphores before exiting. - **/ -s32 e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __e1000e_write_phy_reg_hv(hw, offset, data, false); -} - -/** - * e1000e_write_phy_reg_hv_locked - Write HV PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Writes the data to PHY register at the offset. Assumes semaphore - * already acquired. - **/ -s32 e1000e_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __e1000e_write_phy_reg_hv(hw, offset, data, true); -} - -/** - * e1000e_get_phy_addr_for_hv_page - Get PHY adrress based on page - * @page: page to be accessed - **/ -static u32 e1000e_get_phy_addr_for_hv_page(u32 page) -{ - u32 phy_addr = 2; - - if (page >= HV_INTC_FC_PAGE_START) - phy_addr = 1; - - return phy_addr; -} - -/** - * e1000e_access_phy_debug_regs_hv - Read HV PHY vendor specific high registers - * @hw: pointer to the HW structure - * @offset: register offset to be read or written - * @data: pointer to the data to be read or written - * @read: determines if operation is read or written - * - * Reads the PHY register at offset and stores the retreived information - * in data. Assumes semaphore already acquired. Note that the procedure - * to read these regs uses the address port and data port to read/write. - **/ -static s32 e1000e_access_phy_debug_regs_hv(struct e1000_hw *hw, u32 offset, - u16 *data, bool read) -{ - s32 ret_val; - u32 addr_reg = 0; - u32 data_reg = 0; - - /* This takes care of the difference with desktop vs mobile phy */ - addr_reg = (hw->phy.type == e1000_phy_82578) ? - I82578_ADDR_REG : I82577_ADDR_REG; - data_reg = addr_reg + 1; - - /* All operations in this function are phy address 2 */ - hw->phy.addr = 2; - - /* masking with 0x3F to remove the page from offset */ - ret_val = e1000e_write_phy_reg_mdic(hw, addr_reg, (u16)offset & 0x3F); - if (ret_val) { - e_dbg("Could not write PHY the HV address register\n"); - goto out; - } - - /* Read or write the data value next */ - if (read) - ret_val = e1000e_read_phy_reg_mdic(hw, data_reg, data); - else - ret_val = e1000e_write_phy_reg_mdic(hw, data_reg, *data); - - if (ret_val) { - e_dbg("Could not read data value from HV data register\n"); - goto out; - } - -out: - return ret_val; -} - -/** - * e1000e_link_stall_workaround_hv - Si workaround - * @hw: pointer to the HW structure - * - * This function works around a Si bug where the link partner can get - * a link up indication before the PHY does. If small packets are sent - * by the link partner they can be placed in the packet buffer without - * being properly accounted for by the PHY and will stall preventing - * further packets from being received. The workaround is to clear the - * packet buffer after the PHY detects link up. - **/ -s32 e1000e_link_stall_workaround_hv(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 data; - - if (hw->phy.type != e1000_phy_82578) - goto out; - - /* Do not apply workaround if in PHY loopback bit 14 set */ - e1e_rphy(hw, PHY_CONTROL, &data); - if (data & PHY_CONTROL_LB) - goto out; - - /* check if link is up and at 1Gbps */ - ret_val = e1e_rphy(hw, BM_CS_STATUS, &data); - if (ret_val) - goto out; - - data &= BM_CS_STATUS_LINK_UP | - BM_CS_STATUS_RESOLVED | - BM_CS_STATUS_SPEED_MASK; - - if (data != (BM_CS_STATUS_LINK_UP | - BM_CS_STATUS_RESOLVED | - BM_CS_STATUS_SPEED_1000)) - goto out; - - msleep(200); - - /* flush the packets in the fifo buffer */ - ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL, - HV_MUX_DATA_CTRL_GEN_TO_MAC | - HV_MUX_DATA_CTRL_FORCE_SPEED); - if (ret_val) - goto out; - - ret_val = e1e_wphy(hw, HV_MUX_DATA_CTRL, - HV_MUX_DATA_CTRL_GEN_TO_MAC); - -out: - return ret_val; -} - -/** - * e1000e_check_polarity_82577 - Checks the polarity. - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - * - * Polarity is determined based on the PHY specific status register. - **/ -s32 e1000e_check_polarity_82577(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data); - - if (!ret_val) - phy->cable_polarity = (data & I82577_PHY_STATUS2_REV_POLARITY) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -#if 0 -/** - * e1000e_phy_force_speed_duplex_82577 - Force speed/duplex for I82577 PHY - * @hw: pointer to the HW structure - * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Waits for link and returns - * successful if link up is successful, else -E1000_ERR_PHY (-2). - **/ -s32 e1000e_phy_force_speed_duplex_82577(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - e1000e_phy_force_speed_duplex_setup(hw, &phy_data); - - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - /* - * Clear Auto-Crossover to force MDI manually. 82577 requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = e1e_rphy(hw, I82577_PHY_CTRL_2, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~I82577_PHY_CTRL2_AUTO_MDIX; - phy_data &= ~I82577_PHY_CTRL2_FORCE_MDI_MDIX; - - ret_val = e1e_wphy(hw, I82577_PHY_CTRL_2, phy_data); - if (ret_val) - goto out; - - e_dbg("I82577_PHY_CTRL_2: %X\n", phy_data); - - udelay(1); - - if (phy->autoneg_wait_to_complete) { - e_dbg("Waiting for forced speed/duplex link on 82577 phy\n"); - - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) - e_dbg("Link taking longer than expected.\n"); - - /* Try once more */ - ret_val = e1000e_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } - -out: - return ret_val; -} -#endif - -/** - * e1000e_get_phy_info_82577 - Retrieve I82577 PHY information - * @hw: pointer to the HW structure - * - * Read PHY status to determine if link is up. If link is up, then - * set/determine 10base-T extended distance and polarity correction. Read - * PHY port status to determine MDI/MDIx and speed. Based on the speed, - * determine on the cable length, local and remote receiver. - **/ -s32 e1000e_get_phy_info_82577(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - e_dbg("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - phy->polarity_correction = true; - - ret_val = e1000e_check_polarity_82577(hw); - if (ret_val) - goto out; - - ret_val = e1e_rphy(hw, I82577_PHY_STATUS_2, &data); - if (ret_val) - goto out; - - phy->is_mdix = (data & I82577_PHY_STATUS2_MDIX) ? true : false; - - if ((data & I82577_PHY_STATUS2_SPEED_MASK) == - I82577_PHY_STATUS2_SPEED_1000MBPS) { -#if 0 - ret_val = e1000e_get_cable_length(hw); -#endif - ret_val = -E1000_ERR_CONFIG; - if (ret_val) - goto out; -#if 0 - ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data); - if (ret_val) - goto out; - - phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - - phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; -#endif - } else { - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - } -out: - return ret_val; -} - -#if 0 -/** - * e1000e_get_cable_length_82577 - Determine cable length for 82577 PHY - * @hw: pointer to the HW structure - * - * Reads the diagnostic status register and verifies result is valid before - * placing it in the phy_cable_length field. - **/ -s32 e1000e_get_cable_length_82577(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, length; - - ret_val = e1e_rphy(hw, I82577_PHY_DIAG_STATUS, &phy_data); - if (ret_val) - goto out; - - length = (phy_data & I82577_DSTATUS_CABLE_LENGTH) >> - I82577_DSTATUS_CABLE_LENGTH_SHIFT; - - if (length == E1000_CABLE_LENGTH_UNDEFINED) - ret_val = -E1000_ERR_PHY; - - phy->cable_length = length; - -out: - return ret_val; -} -#endif diff --git a/src/drivers/net/e1000e/e1000e_phy.h b/src/drivers/net/e1000e/e1000e_phy.h deleted file mode 100644 index 9081050f..00000000 --- a/src/drivers/net/e1000e/e1000e_phy.h +++ /dev/null @@ -1,261 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_PHY_H_ -#define _E1000E_PHY_H_ - -void e1000e_init_phy_ops_generic(struct e1000_hw *hw); -s32 e1000e_check_downshift(struct e1000_hw *hw); -s32 e1000e_check_polarity_m88(struct e1000_hw *hw); -s32 e1000e_check_polarity_igp(struct e1000_hw *hw); -s32 e1000e_check_polarity_ife(struct e1000_hw *hw); -s32 e1000e_check_reset_block_generic(struct e1000_hw *hw); -s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw); -s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw); -#if 0 -s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw); -s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw); -s32 e1000e_phy_force_speed_duplex_ife(struct e1000_hw *hw); -#endif -#if 0 -s32 e1000e_get_cable_length_m88(struct e1000_hw *hw); -s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw); -#endif -s32 e1000e_get_cfg_done(struct e1000_hw *hw); -s32 e1000e_get_phy_id(struct e1000_hw *hw); -s32 e1000e_get_phy_info_igp(struct e1000_hw *hw); -s32 e1000e_get_phy_info_m88(struct e1000_hw *hw); -s32 e1000e_phy_sw_reset(struct e1000_hw *hw); -#if 0 -void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); -#endif -s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw); -s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); -s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active); -s32 e1000e_setup_copper_link(struct e1000_hw *hw); -s32 e1000e_wait_autoneg(struct e1000_hw *hw); -s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_phy_reset_dsp(struct e1000_hw *hw); -s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, - u32 usec_interval, bool *success); -s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw); -enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id); -s32 e1000e_determine_phy_address(struct e1000_hw *hw); -s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data); -void e1000e_power_up_phy_copper(struct e1000_hw *hw); -void e1000e_power_down_phy_copper(struct e1000_hw *hw); -s32 e1000e_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_read_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_read_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 *data); -s32 e1000e_write_phy_reg_hv(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_write_phy_reg_hv_locked(struct e1000_hw *hw, u32 offset, u16 data); -s32 e1000e_set_mdio_slow_mode_hv(struct e1000_hw *hw, bool slow); -s32 e1000e_link_stall_workaround_hv(struct e1000_hw *hw); -s32 e1000e_copper_link_setup_82577(struct e1000_hw *hw); -s32 e1000e_check_polarity_82577(struct e1000_hw *hw); -s32 e1000e_get_phy_info_82577(struct e1000_hw *hw); -#if 0 -s32 e1000e_phy_force_speed_duplex_82577(struct e1000_hw *hw); -#endif -#if 0 -s32 e1000e_get_cable_length_82577(struct e1000_hw *hw); -#endif - -#define E1000_MAX_PHY_ADDR 4 - -/* IGP01E1000 Specific Registers */ -#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ -#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ -#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ -#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ -#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO */ -#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality */ -#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ -#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ -#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */ -#define IGP_PAGE_SHIFT 5 -#define PHY_REG_MASK 0x1F - -/* BM/HV Specific Registers */ -#define BM_PORT_CTRL_PAGE 769 -#define BM_PCIE_PAGE 770 -#define BM_WUC_PAGE 800 -#define BM_WUC_ADDRESS_OPCODE 0x11 -#define BM_WUC_DATA_OPCODE 0x12 -#define BM_WUC_ENABLE_PAGE BM_PORT_CTRL_PAGE -#define BM_WUC_ENABLE_REG 17 -#define BM_WUC_ENABLE_BIT (1 << 2) -#define BM_WUC_HOST_WU_BIT (1 << 4) - -#define PHY_UPPER_SHIFT 21 -#define BM_PHY_REG(page, reg) \ - (((reg) & MAX_PHY_REG_ADDRESS) |\ - (((page) & 0xFFFF) << PHY_PAGE_SHIFT) |\ - (((reg) & ~MAX_PHY_REG_ADDRESS) << (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT))) -#define BM_PHY_REG_PAGE(offset) \ - ((u16)(((offset) >> PHY_PAGE_SHIFT) & 0xFFFF)) -#define BM_PHY_REG_NUM(offset) \ - ((u16)(((offset) & MAX_PHY_REG_ADDRESS) |\ - (((offset) >> (PHY_UPPER_SHIFT - PHY_PAGE_SHIFT)) &\ - ~MAX_PHY_REG_ADDRESS))) - -#define HV_INTC_FC_PAGE_START 768 -#define I82578_ADDR_REG 29 -#define I82577_ADDR_REG 16 -#define I82577_CFG_REG 22 -#define I82577_CFG_ASSERT_CRS_ON_TX (1 << 15) -#define I82577_CFG_ENABLE_DOWNSHIFT (3 << 10) /* auto downshift 100/10 */ -#define I82577_CTRL_REG 23 - -/* 82577 specific PHY registers */ -#define I82577_PHY_CTRL_2 18 -#define I82577_PHY_LBK_CTRL 19 -#define I82577_PHY_STATUS_2 26 -#define I82577_PHY_DIAG_STATUS 31 - -/* I82577 PHY Status 2 */ -#define I82577_PHY_STATUS2_REV_POLARITY 0x0400 -#define I82577_PHY_STATUS2_MDIX 0x0800 -#define I82577_PHY_STATUS2_SPEED_MASK 0x0300 -#define I82577_PHY_STATUS2_SPEED_1000MBPS 0x0200 -#define I82577_PHY_STATUS2_SPEED_100MBPS 0x0100 - -/* I82577 PHY Control 2 */ -#define I82577_PHY_CTRL2_AUTO_MDIX 0x0400 -#define I82577_PHY_CTRL2_FORCE_MDI_MDIX 0x0200 - -/* I82577 PHY Diagnostics Status */ -#define I82577_DSTATUS_CABLE_LENGTH 0x03FC -#define I82577_DSTATUS_CABLE_LENGTH_SHIFT 2 - -/* BM PHY Copper Specific Control 1 */ -#define BM_CS_CTRL1 16 -#define BM_CS_CTRL1_ENERGY_DETECT 0x0300 /* Enable Energy Detect */ - -/* BM PHY Copper Specific Status */ -#define BM_CS_STATUS 17 -#define BM_CS_STATUS_ENERGY_DETECT 0x0010 /* Energy Detect Status */ -#define BM_CS_STATUS_LINK_UP 0x0400 -#define BM_CS_STATUS_RESOLVED 0x0800 -#define BM_CS_STATUS_SPEED_MASK 0xC000 -#define BM_CS_STATUS_SPEED_1000 0x8000 - -/* 82577 Mobile Phy Status Register */ -#define HV_M_STATUS 26 -#define HV_M_STATUS_AUTONEG_COMPLETE 0x1000 -#define HV_M_STATUS_SPEED_MASK 0x0300 -#define HV_M_STATUS_SPEED_1000 0x0200 -#define HV_M_STATUS_LINK_UP 0x0040 - -#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 -#define IGP01E1000_PHY_POLARITY_MASK 0x0078 - -#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 -#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ - -#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 - -/* Enable flexible speed on link-up */ -#define IGP01E1000_GMII_FLEX_SPD 0x0010 -#define IGP01E1000_GMII_SPD 0x0020 /* Enable SPD */ - -#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ -#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ -#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ - -#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 - -#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0800 -#define IGP01E1000_PSSR_SPEED_MASK 0xC000 -#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 - -#define IGP02E1000_PHY_CHANNEL_NUM 4 -#define IGP02E1000_PHY_AGC_A 0x11B1 -#define IGP02E1000_PHY_AGC_B 0x12B1 -#define IGP02E1000_PHY_AGC_C 0x14B1 -#define IGP02E1000_PHY_AGC_D 0x18B1 - -#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ -#define IGP02E1000_AGC_LENGTH_MASK 0x7F -#define IGP02E1000_AGC_RANGE 15 - -#define IGP03E1000_PHY_MISC_CTRL 0x1B -#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Manually Set Duplex */ - -#define E1000_CABLE_LENGTH_UNDEFINED 0xFF - -#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 -#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 -#define E1000_KMRNCTRLSTA_REN 0x00200000 -#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ -#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */ -#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */ -#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ -#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7 -#define E1000_KMRNCTRLSTA_K1_ENABLE 0x0002 - -#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 -#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ -#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */ -#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */ - -/* IFE PHY Extended Status Control */ -#define IFE_PESC_POLARITY_REVERSED 0x0100 - -/* IFE PHY Special Control */ -#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 -#define IFE_PSC_FORCE_POLARITY 0x0020 -#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 - -/* IFE PHY Special Control and LED Control */ -#define IFE_PSCL_PROBE_MODE 0x0020 -#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ -#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ - -/* IFE PHY MDIX Control */ -#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ -#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */ -#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */ - -#endif diff --git a/src/drivers/net/e1000e/e1000e_regs.h b/src/drivers/net/e1000e/e1000e_regs.h deleted file mode 100644 index 064d92c9..00000000 --- a/src/drivers/net/e1000e/e1000e_regs.h +++ /dev/null @@ -1,340 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#ifndef _E1000E_REGS_H_ -#define _E1000E_REGS_H_ - -#define E1000_CTRL 0x00000 /* Device Control - RW */ -#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ -#define E1000_STATUS 0x00008 /* Device Status - RO */ -#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ -#define E1000_EERD 0x00014 /* EEPROM Read - RW */ -#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ -#define E1000_FLA 0x0001C /* Flash Access - RW */ -#define E1000_MDIC 0x00020 /* MDI Control - RW */ -#define E1000_SCTL 0x00024 /* SerDes Control - RW */ -#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ -#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ -#define E1000_FEXT 0x0002C /* Future Extended - RW */ -#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ -#define E1000_FCT 0x00030 /* Flow Control Type - RW */ -#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ -#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ -#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ -#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ -#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ -#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ -#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ -#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ -#define E1000_IVAR 0x000E4 /* Interrupt Vector Allocation Register - RW */ -#define E1000_SVCR 0x000F0 -#define E1000_SVT 0x000F4 -#define E1000_RCTL 0x00100 /* Rx Control - RW */ -#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ -#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */ -#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */ -#define E1000_PBA_ECC 0x01100 /* PBA ECC Register */ -#define E1000_TCTL 0x00400 /* Tx Control - RW */ -#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */ -#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */ -#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */ -#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ -#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ -#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ -#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ -#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ -#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ -#define E1000_PBS 0x01008 /* Packet Buffer Size */ -#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ -#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ -#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ -#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ -#define E1000_FLSWCTL 0x01030 /* FLASH control register */ -#define E1000_FLSWDATA 0x01034 /* FLASH data register */ -#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ -#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ -#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */ -#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */ -#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */ -#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */ -#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */ -#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ -#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ -#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ -#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ -#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n))) -#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */ -#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */ -/* Split and Replication Rx Control - RW */ -#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */ -#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */ -#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */ -#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */ -#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */ -#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */ -#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */ -/* - * Convenience macros - * - * Note: "_n" is the queue number of the register to be written to. - * - * Example usage: - * E1000_RDBAL_REG(current_rx_queue) - */ -#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \ - (0x0C000 + ((_n) * 0x40))) -#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \ - (0x0C004 + ((_n) * 0x40))) -#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \ - (0x0C008 + ((_n) * 0x40))) -#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \ - (0x0C00C + ((_n) * 0x40))) -#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \ - (0x0C010 + ((_n) * 0x40))) -#define E1000_RXCTL(_n) ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \ - (0x0C014 + ((_n) * 0x40))) -#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n) -#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \ - (0x0C018 + ((_n) * 0x40))) -#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \ - (0x0C028 + ((_n) * 0x40))) -#define E1000_RQDPC(_n) ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \ - (0x0C030 + ((_n) * 0x40))) -#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \ - (0x0E000 + ((_n) * 0x40))) -#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \ - (0x0E004 + ((_n) * 0x40))) -#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \ - (0x0E008 + ((_n) * 0x40))) -#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \ - (0x0E010 + ((_n) * 0x40))) -#define E1000_TXCTL(_n) ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \ - (0x0E014 + ((_n) * 0x40))) -#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n) -#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \ - (0x0E018 + ((_n) * 0x40))) -#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \ - (0x0E028 + ((_n) * 0x40))) -#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \ - (0x0E038 + ((_n) * 0x40))) -#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \ - (0x0E03C + ((_n) * 0x40))) -#define E1000_TARC(_n) (0x03840 + ((_n) * 0x100)) -#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */ -#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ -#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */ -#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ -#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4)) -#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \ - (0x054E0 + ((_i - 16) * 8))) -#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \ - (0x054E4 + ((_i - 16) * 8))) -#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) -#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) -#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) -#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8)) -#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8)) -#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8)) -#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */ -#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ -#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ -#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */ -#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */ -#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */ -#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */ -#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */ -#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */ -#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */ -#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */ -#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */ -#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */ -#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ -#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ -#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ -#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ -#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ -#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ -#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ -#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ -#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ -#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ -#define E1000_COLC 0x04028 /* Collision Count - R/clr */ -#define E1000_DC 0x04030 /* Defer Count - R/clr */ -#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */ -#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ -#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ -#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ -#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */ -#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */ -#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */ -#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */ -#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */ -#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */ -#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */ -#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */ -#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */ -#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */ -#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */ -#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */ -#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */ -#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */ -#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */ -#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */ -#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */ -#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */ -#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */ -#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */ -#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */ -#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */ -#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */ -#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */ -#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */ -#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ -#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */ -#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */ -#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */ -#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */ -#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */ -#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */ -#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */ -#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */ -#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */ -#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */ -#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */ -#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */ -#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */ -#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */ -#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */ -#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ -#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ -#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */ -#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */ -#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */ -#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */ -#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */ -#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */ -#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ -#define E1000_CRC_OFFSET 0x05F50 /* CRC Offset register */ - -#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */ -#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */ -#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */ -#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */ -#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ -#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */ -#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */ -#define E1000_RPTHC 0x04104 /* Rx Packets To Host */ -#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */ -#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */ -#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */ -#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */ -#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ -#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ -#define E1000_LENERRS 0x04138 /* Length Errors Count */ -#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ -#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */ -#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */ -#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */ -#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */ -#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */ -#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */ -#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */ -#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */ -#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ -#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ -#define E1000_RA 0x05400 /* Receive Address - RW Array */ -#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ -#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */ -#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */ -#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */ -#define E1000_WUC 0x05800 /* Wakeup Control - RW */ -#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ -#define E1000_WUS 0x05810 /* Wakeup Status - RO */ -#define E1000_MANC 0x05820 /* Management Control - RW */ -#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ -#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ -#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ -#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ -#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ -#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */ -#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ -#define E1000_HOST_IF 0x08800 /* Host Interface */ -#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ -#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ - -#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */ -#define E1000_MDPHYA 0x0003C /* PHY address - RW */ -#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ -#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ -#define E1000_CCMCTL 0x05B48 /* CCM Control Register */ -#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ -#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ -#define E1000_GCR 0x05B00 /* PCI-Ex Control */ -#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */ -#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ -#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ -#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ -#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ -#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ -#define E1000_SWSM 0x05B50 /* SW Semaphore */ -#define E1000_FWSM 0x05B54 /* FW Semaphore */ -#define E1000_SWSM2 0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */ -#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ -#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ -#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ -#define E1000_HICR 0x08F00 /* Host Interface Control */ - -/* RSS registers */ -#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ -#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ -#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */ -#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/ -#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */ -#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register - * (_i) - RW */ -#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr - * low reg - RW */ -#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr - * upper reg - RW */ -#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry - * message reg - RW */ -#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry - * vector ctrl reg - RW */ -#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */ -#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */ -#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */ -#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ -#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ -#define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */ -#define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ - -#endif diff --git a/src/drivers/net/igb/igb.c b/src/drivers/net/igb/igb.c deleted file mode 100644 index cd5db1ff..00000000 --- a/src/drivers/net/igb/igb.c +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2008 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -REQUIRE_OBJECT(igb_main); -REQUIRE_OBJECT(igb_82575); diff --git a/src/drivers/net/igb/igb.h b/src/drivers/net/igb/igb.h deleted file mode 100644 index c8e8205d..00000000 --- a/src/drivers/net/igb/igb.h +++ /dev/null @@ -1,324 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -/* Linux PRO/1000 Ethernet Driver main header file */ - -#ifndef _IGB_H_ -#define _IGB_H_ - -#include "igb_api.h" - -extern int igb_probe ( struct pci_device *pdev ); -extern void igb_remove ( struct pci_device *pdev ); - -struct igb_adapter; - -/* Interrupt defines */ -#define IGB_START_ITR 648 /* ~6000 ints/sec */ - -/* Interrupt modes, as used by the IntMode paramter */ -#define IGB_INT_MODE_LEGACY 0 -#define IGB_INT_MODE_MSI 1 -#define IGB_INT_MODE_MSIX 2 - -#define HW_PERF -/* TX/RX descriptor defines */ -#define IGB_DEFAULT_TXD 256 -#define IGB_MIN_TXD 80 -#define IGB_MAX_TXD 4096 - -#define IGB_DEFAULT_RXD 256 -#define IGB_MIN_RXD 80 -#define IGB_MAX_RXD 4096 - -#define IGB_MIN_ITR_USECS 10 /* 100k irq/sec */ -#define IGB_MAX_ITR_USECS 8191 /* 120 irq/sec */ - -#define NON_Q_VECTORS 1 -#define MAX_Q_VECTORS 8 - -/* Transmit and receive queues */ -#define IGB_MAX_RX_QUEUES (adapter->vfs_allocated_count ? 2 : \ - (hw->mac.type > e1000_82575 ? 8 : 4)) -#define IGB_ABS_MAX_TX_QUEUES 8 -#define IGB_MAX_TX_QUEUES IGB_MAX_RX_QUEUES - -#define IGB_MAX_VF_MC_ENTRIES 30 -#define IGB_MAX_VF_FUNCTIONS 8 -#define IGB_MAX_VFTA_ENTRIES 128 -#define IGB_MAX_UTA_ENTRIES 128 -#define MAX_EMULATION_MAC_ADDRS 16 -#define OUI_LEN 3 - -struct vf_data_storage { - unsigned char vf_mac_addresses[ETH_ALEN]; - u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES]; - u16 num_vf_mc_hashes; - u16 default_vf_vlan_id; - u16 vlans_enabled; - unsigned char em_mac_addresses[MAX_EMULATION_MAC_ADDRS * ETH_ALEN]; - u32 uta_table_copy[IGB_MAX_UTA_ENTRIES]; - u32 flags; - unsigned long last_nack; -}; - -#define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */ -#define IGB_VF_FLAG_UNI_PROMISC 0x00000002 /* VF has unicast promisc */ -#define IGB_VF_FLAG_MULTI_PROMISC 0x00000004 /* VF has multicast promisc */ - -/* RX descriptor control thresholds. - * PTHRESH - MAC will consider prefetch if it has fewer than this number of - * descriptors available in its onboard memory. - * Setting this to 0 disables RX descriptor prefetch. - * HTHRESH - MAC will only prefetch if there are at least this many descriptors - * available in host memory. - * If PTHRESH is 0, this should also be 0. - * WTHRESH - RX descriptor writeback threshold - MAC will delay writing back - * descriptors until either it has this many to write back, or the - * ITR timer expires. - */ -#define IGB_RX_PTHRESH (hw->mac.type <= e1000_82576 ? 16 : 8) -#define IGB_RX_HTHRESH 8 -#define IGB_RX_WTHRESH 1 -#define IGB_TX_PTHRESH 8 -#define IGB_TX_HTHRESH 1 -#define IGB_TX_WTHRESH ((hw->mac.type == e1000_82576 && \ - adapter->msix_entries) ? 0 : 16) - -/* this is the size past which hardware will drop packets when setting LPE=0 */ -#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 - -/* Supported Rx Buffer Sizes */ -#define IGB_RXBUFFER_128 128 /* Used for packet split */ -#define IGB_RXBUFFER_256 256 /* Used for packet split */ -#define IGB_RXBUFFER_512 512 -#define IGB_RXBUFFER_1024 1024 -#define IGB_RXBUFFER_2048 2048 -#define IGB_RXBUFFER_4096 4096 -#define IGB_RXBUFFER_8192 8192 -#define IGB_RXBUFFER_16384 16384 - -/* Packet Buffer allocations */ -#define IGB_PBA_BYTES_SHIFT 0xA -#define IGB_TX_HEAD_ADDR_SHIFT 7 -#define IGB_PBA_TX_MASK 0xFFFF0000 - -#define IGB_FC_PAUSE_TIME 0x0680 /* 858 usec */ - -/* How many Tx Descriptors do we need to call netif_wake_queue ? */ -#define IGB_TX_QUEUE_WAKE 32 -/* How many Rx Buffers do we bundle into one write to the hardware ? */ -#define IGB_RX_BUFFER_WRITE 16 /* Must be power of 2 */ - -#define AUTO_ALL_MODES 0 -#define IGB_EEPROM_APME 0x0400 - -#ifndef IGB_MASTER_SLAVE -/* Switch to override PHY master/slave setting */ -#define IGB_MASTER_SLAVE e1000_ms_hw_default -#endif - -#define IGB_MNG_VLAN_NONE -1 - -/* wrapper around a pointer to a socket buffer, - * so a DMA handle can be stored along with the buffer */ -struct igb_buffer { - struct sk_buff *skb; - dma_addr_t dma; - dma_addr_t page_dma; - union { - /* TX */ - struct { - unsigned long time_stamp; - u16 length; - u16 next_to_watch; - }; - -#ifndef CONFIG_IGB_DISABLE_PACKET_SPLIT - /* RX */ - struct { - unsigned long page_offset; - struct page *page; - }; -#endif - }; -}; - -struct igb_queue_stats { - u64 packets; - u64 bytes; -}; - -struct igb_q_vector { - struct igb_adapter *adapter; /* backlink */ - struct igb_ring *rx_ring; - struct igb_ring *tx_ring; -#if 0 - struct napi_struct napi; -#endif - u32 eims_value; - u16 cpu; - - u16 itr_val; - u8 set_itr; - u8 itr_shift; - void __iomem *itr_register; - -#if 0 - char name[IFNAMSIZ + 9]; -#endif -#ifndef HAVE_NETDEV_NAPI_LIST - struct net_device poll_dev; -#endif -}; - -struct igb_ring { - struct igb_q_vector *q_vector; /* backlink to q_vector */ - struct pci_dev *pdev; /* pci device for dma mapping */ - dma_addr_t dma; /* phys address of the ring */ - void *desc; /* descriptor ring memory */ - unsigned int size; /* length of desc. ring in bytes */ - u16 count; /* number of desc. in the ring */ - u16 next_to_use; - u16 next_to_clean; - u8 queue_index; - u8 reg_idx; - void __iomem *head; - void __iomem *tail; - struct igb_buffer *buffer_info; /* array of buffer info structs */ - - unsigned int total_bytes; - unsigned int total_packets; - - struct igb_queue_stats stats; - - union { - /* TX */ - struct { - unsigned int restart_queue; - u32 ctx_idx; - bool detect_tx_hung; - }; - /* RX */ - struct { - u64 hw_csum_err; - u64 hw_csum_good; - u32 rx_buffer_len; - u16 rx_ps_hdr_size; - bool rx_csum; -#ifdef IGB_LRO - struct net_lro_mgr lro_mgr; - bool lro_used; -#endif - }; - }; -}; - - -#define IGB_ADVTXD_DCMD (E1000_ADVTXD_DCMD_EOP | E1000_ADVTXD_DCMD_RS) - -#define IGB_DESC_UNUSED(R) \ - ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \ - (R)->next_to_clean - (R)->next_to_use - 1) - -#define E1000_RX_DESC_ADV(R, i) \ - (&(((union e1000_adv_rx_desc *)((R).desc))[i])) -#define E1000_TX_DESC_ADV(R, i) \ - (&(((union e1000_adv_tx_desc *)((R).desc))[i])) -#define E1000_TX_CTXTDESC_ADV(R, i) \ - (&(((struct e1000_adv_tx_context_desc *)((R).desc))[i])) -#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i])) -#define E1000_TX_DESC(R, i) E1000_GET_DESC(R, i, e1000_tx_desc) -#define E1000_RX_DESC(R, i) E1000_GET_DESC(R, i, e1000_rx_desc) - -#define MAX_MSIX_COUNT 10 -/* board specific private data structure */ - -/* board specific private data structure */ -struct igb_adapter { - - /* OS defined structs */ - struct net_device *netdev; - struct pci_device *pdev; - struct net_device_stats net_stats; - - /* structs defined in e1000_hw.h */ - struct e1000_hw hw; - - struct e1000_phy_info phy_info; - - u32 min_frame_size; - u32 max_frame_size; - - u32 wol; - u32 pba; - u32 max_hw_frame_size; - - bool fc_autoneg; - - unsigned int flags; - unsigned int flags2; - -#define NUM_TX_DESC 8 -#define NUM_RX_DESC 8 - - struct io_buffer *tx_iobuf[NUM_TX_DESC]; - struct io_buffer *rx_iobuf[NUM_RX_DESC]; - - struct e1000_tx_desc *tx_base; - struct e1000_rx_desc *rx_base; - - uint32_t tx_ring_size; - uint32_t rx_ring_size; - - uint32_t tx_head; - uint32_t tx_tail; - uint32_t tx_fill_ctr; - - uint32_t rx_curr; - - uint32_t ioaddr; - uint32_t irqno; - - uint32_t tx_int_delay; - uint32_t tx_abs_int_delay; - uint32_t txd_cmd; -}; - -#define IGB_FLAG_HAS_MSI (1 << 0) -#define IGB_FLAG_MSI_ENABLE (1 << 1) -#define IGB_FLAG_DCA_ENABLED (1 << 3) -#define IGB_FLAG_LLI_PUSH (1 << 4) -#define IGB_FLAG_IN_NETPOLL (1 << 5) -#define IGB_FLAG_QUAD_PORT_A (1 << 6) -#define IGB_FLAG_QUEUE_PAIRS (1 << 7) - -#define IGB_82576_TSYNC_SHIFT 19 - -#endif /* _IGB_H_ */ diff --git a/src/drivers/net/igb/igb_82575.c b/src/drivers/net/igb/igb_82575.c deleted file mode 100644 index b5b615ad..00000000 --- a/src/drivers/net/igb/igb_82575.c +++ /dev/null @@ -1,1617 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -/* - * 82575EB Gigabit Network Connection - * 82575EB Gigabit Backplane Connection - * 82575GB Gigabit Network Connection - * 82576 Gigabit Network Connection - * 82576 Quad Port Gigabit Mezzanine Adapter - */ - -#include "igb.h" - -static s32 igb_init_phy_params_82575(struct e1000_hw *hw); -static s32 igb_init_nvm_params_82575(struct e1000_hw *hw); -static s32 igb_init_mac_params_82575(struct e1000_hw *hw); -static s32 igb_acquire_phy_82575(struct e1000_hw *hw); -static void igb_release_phy_82575(struct e1000_hw *hw); -static s32 igb_acquire_nvm_82575(struct e1000_hw *hw); -static void igb_release_nvm_82575(struct e1000_hw *hw); -static s32 igb_check_for_link_82575(struct e1000_hw *hw); -static s32 igb_get_cfg_done_82575(struct e1000_hw *hw); -static s32 igb_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -static s32 igb_init_hw_82575(struct e1000_hw *hw); -static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw); -static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, - u16 *data); -static s32 igb_reset_hw_82575(struct e1000_hw *hw); -static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, - bool active); -static s32 igb_setup_copper_link_82575(struct e1000_hw *hw); -static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw); -static s32 igb_valid_led_default_82575(struct e1000_hw *hw, u16 *data); -static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, - u32 offset, u16 data); -static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw); -static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask); -static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, - u16 *speed, u16 *duplex); -static s32 igb_get_phy_id_82575(struct e1000_hw *hw); -static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask); -static bool igb_sgmii_active_82575(struct e1000_hw *hw); -static s32 igb_reset_init_script_82575(struct e1000_hw *hw); -static s32 igb_read_mac_addr_82575(struct e1000_hw *hw); -static void igb_power_down_phy_copper_82575(struct e1000_hw *hw); -static void igb_shutdown_serdes_link_82575(struct e1000_hw *hw); -static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw); - -/** - * igb_init_phy_params_82575 - Init PHY func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 igb_init_phy_params_82575(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_init_phy_params_82575"); - - if (hw->phy.media_type != e1000_media_type_copper) { - phy->type = e1000_phy_none; - goto out; - } - - phy->ops.power_up = igb_power_up_phy_copper; - phy->ops.power_down = igb_power_down_phy_copper_82575; - - phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; - phy->reset_delay_us = 100; - - phy->ops.acquire = igb_acquire_phy_82575; - phy->ops.check_reset_block = igb_check_reset_block_generic; - phy->ops.commit = igb_phy_sw_reset_generic; - phy->ops.get_cfg_done = igb_get_cfg_done_82575; - phy->ops.release = igb_release_phy_82575; - - if (igb_sgmii_active_82575(hw)) { - phy->ops.reset = igb_phy_hw_reset_sgmii_82575; - phy->ops.read_reg = igb_read_phy_reg_sgmii_82575; - phy->ops.write_reg = igb_write_phy_reg_sgmii_82575; - } else { - phy->ops.reset = igb_phy_hw_reset_generic; - phy->ops.read_reg = igb_read_phy_reg_igp; - phy->ops.write_reg = igb_write_phy_reg_igp; - } - - /* Set phy->phy_addr and phy->id. */ - ret_val = igb_get_phy_id_82575(hw); - - /* Verify phy id and set remaining function pointers */ - switch (phy->id) { - case M88E1111_I_PHY_ID: - phy->type = e1000_phy_m88; - phy->ops.check_polarity = igb_check_polarity_m88; - phy->ops.get_info = igb_get_phy_info_m88; -#if 0 - phy->ops.get_cable_length = igb_get_cable_length_m88; -#endif -#if 0 - phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_m88; -#endif - break; - case IGP03E1000_E_PHY_ID: - case IGP04E1000_E_PHY_ID: - phy->type = e1000_phy_igp_3; - phy->ops.check_polarity = igb_check_polarity_igp; - phy->ops.get_info = igb_get_phy_info_igp; -#if 0 - phy->ops.get_cable_length = igb_get_cable_length_igp_2; -#endif -#if 0 - phy->ops.force_speed_duplex = igb_phy_force_speed_duplex_igp; -#endif - phy->ops.set_d0_lplu_state = igb_set_d0_lplu_state_82575; - phy->ops.set_d3_lplu_state = igb_set_d3_lplu_state_generic; - break; - default: - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} - -/** - * igb_init_nvm_params_82575 - Init NVM func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 igb_init_nvm_params_82575(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - u16 size; - - DEBUGFUNC("igb_init_nvm_params_82575"); - - nvm->opcode_bits = 8; - nvm->delay_usec = 1; - switch (nvm->override) { - case e1000_nvm_override_spi_large: - nvm->page_size = 32; - nvm->address_bits = 16; - break; - case e1000_nvm_override_spi_small: - nvm->page_size = 8; - nvm->address_bits = 8; - break; - default: - nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8; - nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8; - break; - } - - nvm->type = e1000_nvm_eeprom_spi; - - size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >> - E1000_EECD_SIZE_EX_SHIFT); - - /* - * Added to a constant, "size" becomes the left-shift value - * for setting word_size. - */ - size += NVM_WORD_SIZE_BASE_SHIFT; - - /* EEPROM access above 16k is unsupported */ - if (size > 14) - size = 14; - nvm->word_size = 1 << size; - - /* Function Pointers */ - nvm->ops.acquire = igb_acquire_nvm_82575; - nvm->ops.read = igb_read_nvm_eerd; - nvm->ops.release = igb_release_nvm_82575; - nvm->ops.update = igb_update_nvm_checksum_generic; - nvm->ops.valid_led_default = igb_valid_led_default_82575; - nvm->ops.validate = igb_validate_nvm_checksum_generic; - nvm->ops.write = igb_write_nvm_spi; - - return E1000_SUCCESS; -} - -/** - * igb_init_mac_params_82575 - Init MAC func ptrs. - * @hw: pointer to the HW structure - **/ -static s32 igb_init_mac_params_82575(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; - u32 ctrl_ext = 0; - - DEBUGFUNC("igb_init_mac_params_82575"); - - /* Set media type */ - /* - * The 82575 uses bits 22:23 for link mode. The mode can be changed - * based on the EEPROM. We cannot rely upon device ID. There - * is no distinguishable difference between fiber and internal - * SerDes mode on the 82575. There can be an external PHY attached - * on the SGMII interface. For this, we'll set sgmii_active to true. - */ - hw->phy.media_type = e1000_media_type_copper; - dev_spec->sgmii_active = false; - - ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) { - case E1000_CTRL_EXT_LINK_MODE_SGMII: - dev_spec->sgmii_active = true; - ctrl_ext |= E1000_CTRL_I2C_ENA; - break; - case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES: - hw->phy.media_type = e1000_media_type_internal_serdes; - ctrl_ext |= E1000_CTRL_I2C_ENA; - break; - default: - ctrl_ext &= ~E1000_CTRL_I2C_ENA; - break; - } - - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - - /* Set mta register count */ - mac->mta_reg_count = 128; - /* Set uta register count */ - mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128; - /* Set rar entry count */ - mac->rar_entry_count = E1000_RAR_ENTRIES_82575; - if (mac->type == e1000_82576) - mac->rar_entry_count = E1000_RAR_ENTRIES_82576; - /* Set if part includes ASF firmware */ - mac->asf_firmware_present = true; - /* Set if manageability features are enabled. */ - mac->arc_subsystem_valid = - (E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK) - ? true : false; - - /* Function pointers */ - - /* bus type/speed/width */ - mac->ops.get_bus_info = igb_get_bus_info_pcie_generic; - /* reset */ - mac->ops.reset_hw = igb_reset_hw_82575; - /* hw initialization */ - mac->ops.init_hw = igb_init_hw_82575; - /* link setup */ - mac->ops.setup_link = igb_setup_link_generic; - /* physical interface link setup */ - mac->ops.setup_physical_interface = - (hw->phy.media_type == e1000_media_type_copper) - ? igb_setup_copper_link_82575 - : igb_setup_serdes_link_82575; - /* physical interface shutdown */ - mac->ops.shutdown_serdes = igb_shutdown_serdes_link_82575; - /* check for link */ - mac->ops.check_for_link = igb_check_for_link_82575; - /* receive address register setting */ - mac->ops.rar_set = igb_rar_set_generic; - /* read mac address */ - mac->ops.read_mac_addr = igb_read_mac_addr_82575; - /* multicast address update */ - mac->ops.update_mc_addr_list = igb_update_mc_addr_list_generic; - /* writing VFTA */ - mac->ops.write_vfta = igb_write_vfta_generic; - /* clearing VFTA */ - mac->ops.clear_vfta = igb_clear_vfta_generic; - /* setting MTA */ -#if 0 - mac->ops.mta_set = igb_mta_set_generic; - /* ID LED init */ - mac->ops.id_led_init = igb_id_led_init_generic; - /* blink LED */ - mac->ops.blink_led = igb_blink_led_generic; - /* setup LED */ - mac->ops.setup_led = igb_setup_led_generic; - /* cleanup LED */ - mac->ops.cleanup_led = igb_cleanup_led_generic; - /* turn on/off LED */ - mac->ops.led_on = igb_led_on_generic; - mac->ops.led_off = igb_led_off_generic; -#endif - /* clear hardware counters */ - mac->ops.clear_hw_cntrs = igb_clear_hw_cntrs_82575; - /* link info */ - mac->ops.get_link_up_info = igb_get_link_up_info_82575; - - /* set lan id for port to determine which phy lock to use */ - hw->mac.ops.set_lan_id(hw); - - return E1000_SUCCESS; -} - -/** - * igb_init_function_pointers_82575 - Init func ptrs. - * @hw: pointer to the HW structure - * - * Called to initialize all function pointers and parameters. - **/ -void igb_init_function_pointers_82575(struct e1000_hw *hw) -{ - DEBUGFUNC("igb_init_function_pointers_82575"); - - hw->mac.ops.init_params = igb_init_mac_params_82575; - hw->nvm.ops.init_params = igb_init_nvm_params_82575; - hw->phy.ops.init_params = igb_init_phy_params_82575; -#if 0 - hw->mbx.ops.init_params = igb_init_mbx_params_pf; -#endif -} - -/** - * igb_acquire_phy_82575 - Acquire rights to access PHY - * @hw: pointer to the HW structure - * - * Acquire access rights to the correct PHY. - **/ -static s32 igb_acquire_phy_82575(struct e1000_hw *hw) -{ - u16 mask = E1000_SWFW_PHY0_SM; - - DEBUGFUNC("igb_acquire_phy_82575"); - - if (hw->bus.func == E1000_FUNC_1) - mask = E1000_SWFW_PHY1_SM; - - return igb_acquire_swfw_sync_82575(hw, mask); -} - -/** - * igb_release_phy_82575 - Release rights to access PHY - * @hw: pointer to the HW structure - * - * A wrapper to release access rights to the correct PHY. - **/ -static void igb_release_phy_82575(struct e1000_hw *hw) -{ - u16 mask = E1000_SWFW_PHY0_SM; - - DEBUGFUNC("igb_release_phy_82575"); - - if (hw->bus.func == E1000_FUNC_1) - mask = E1000_SWFW_PHY1_SM; - - igb_release_swfw_sync_82575(hw, mask); -} - -/** - * igb_read_phy_reg_sgmii_82575 - Read PHY register using sgmii - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY register at offset using the serial gigabit media independent - * interface and stores the retrieved information in data. - **/ -static s32 igb_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, - u16 *data) -{ - s32 ret_val = -E1000_ERR_PARAM; - - DEBUGFUNC("igb_read_phy_reg_sgmii_82575"); - - if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { - DEBUGOUT1("PHY Address %u is out of range\n", offset); - goto out; - } - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = igb_read_phy_reg_i2c(hw, offset, data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * igb_write_phy_reg_sgmii_82575 - Write PHY register using sgmii - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Writes the data to PHY register at the offset using the serial gigabit - * media independent interface. - **/ -static s32 igb_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset, - u16 data) -{ - s32 ret_val = -E1000_ERR_PARAM; - - DEBUGFUNC("igb_write_phy_reg_sgmii_82575"); - - if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) { - DEBUGOUT1("PHY Address %d is out of range\n", offset); - goto out; - } - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = igb_write_phy_reg_i2c(hw, offset, data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * igb_get_phy_id_82575 - Retrieve PHY addr and id - * @hw: pointer to the HW structure - * - * Retrieves the PHY address and ID for both PHY's which do and do not use - * sgmi interface. - **/ -static s32 igb_get_phy_id_82575(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_id; - u32 ctrl_ext; - - DEBUGFUNC("igb_get_phy_id_82575"); - - /* - * For SGMII PHYs, we try the list of possible addresses until - * we find one that works. For non-SGMII PHYs - * (e.g. integrated copper PHYs), an address of 1 should - * work. The result of this function should mean phy->phy_addr - * and phy->id are set correctly. - */ - if (!igb_sgmii_active_82575(hw)) { - phy->addr = 1; - ret_val = igb_get_phy_id(hw); - goto out; - } - - /* Power on sgmii phy if it is disabled */ - ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - E1000_WRITE_REG(hw, E1000_CTRL_EXT, - ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA); - E1000_WRITE_FLUSH(hw); - msec_delay(300); - - /* - * The address field in the I2CCMD register is 3 bits and 0 is invalid. - * Therefore, we need to test 1-7 - */ - for (phy->addr = 1; phy->addr < 8; phy->addr++) { - ret_val = igb_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id); - if (ret_val == E1000_SUCCESS) { - DEBUGOUT2("Vendor ID 0x%08X read at address %u\n", - phy_id, - phy->addr); - /* - * At the time of this writing, The M88 part is - * the only supported SGMII PHY product. - */ - if (phy_id == M88_VENDOR) - break; - } else { - DEBUGOUT1("PHY address %u was unreadable\n", - phy->addr); - } - } - - /* A valid PHY type couldn't be found. */ - if (phy->addr == 8) { - phy->addr = 0; - ret_val = -E1000_ERR_PHY; - } else { - ret_val = igb_get_phy_id(hw); - } - - /* restore previous sfp cage power state */ - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - -out: - return ret_val; -} - -/** - * igb_phy_hw_reset_sgmii_82575 - Performs a PHY reset - * @hw: pointer to the HW structure - * - * Resets the PHY using the serial gigabit media independent interface. - **/ -static s32 igb_phy_hw_reset_sgmii_82575(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_phy_hw_reset_sgmii_82575"); - - /* - * This isn't a true "hard" reset, but is the only reset - * available to us at this time. - */ - - DEBUGOUT("Soft resetting SGMII attached PHY...\n"); - - if (!(hw->phy.ops.write_reg)) - goto out; - - /* - * SFP documentation requires the following to configure the SPF module - * to work on SGMII. No further documentation is given. - */ - ret_val = hw->phy.ops.write_reg(hw, 0x1B, 0x8084); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.commit(hw); - -out: - return ret_val; -} - -/** - * igb_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state - * @hw: pointer to the HW structure - * @active: true to enable LPLU, false to disable - * - * Sets the LPLU D0 state according to the active flag. When - * activating LPLU this function also disables smart speed - * and vice versa. LPLU will not be activated unless the - * device autonegotiation advertisement meets standards of - * either 10 or 10/100 or 10/100/1000 at all duplexes. - * This is a function pointer entry point only called by - * PHY setup routines. - **/ -static s32 igb_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 data; - - DEBUGFUNC("igb_set_d0_lplu_state_82575"); - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); - if (ret_val) - goto out; - - if (active) { - data |= IGP02E1000_PM_D0_LPLU; - ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - &data); - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else { - data &= ~IGP02E1000_PM_D0_LPLU; - ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, - data); - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } - -out: - return ret_val; -} - -/** - * igb_acquire_nvm_82575 - Request for access to EEPROM - * @hw: pointer to the HW structure - * - * Acquire the necessary semaphores for exclusive access to the EEPROM. - * Set the EEPROM access request bit and wait for EEPROM access grant bit. - * Return successful if access grant bit set, else clear the request for - * EEPROM access and return -E1000_ERR_NVM (-1). - **/ -static s32 igb_acquire_nvm_82575(struct e1000_hw *hw) -{ - s32 ret_val; - - DEBUGFUNC("igb_acquire_nvm_82575"); - - ret_val = igb_acquire_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); - if (ret_val) - goto out; - - ret_val = igb_acquire_nvm_generic(hw); - - if (ret_val) - igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); - -out: - return ret_val; -} - -/** - * igb_release_nvm_82575 - Release exclusive access to EEPROM - * @hw: pointer to the HW structure - * - * Stop any current commands to the EEPROM and clear the EEPROM request bit, - * then release the semaphores acquired. - **/ -static void igb_release_nvm_82575(struct e1000_hw *hw) -{ - DEBUGFUNC("igb_release_nvm_82575"); - - igb_release_nvm_generic(hw); - igb_release_swfw_sync_82575(hw, E1000_SWFW_EEP_SM); -} - -/** - * igb_acquire_swfw_sync_82575 - Acquire SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Acquire the SW/FW semaphore to access the PHY or NVM. The mask - * will also specify which port we're acquiring the lock for. - **/ -static s32 igb_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - u32 swmask = mask; - u32 fwmask = mask << 16; - s32 ret_val = E1000_SUCCESS; - s32 i = 0, timeout = 200; /* FIXME: find real value to use here */ - - DEBUGFUNC("igb_acquire_swfw_sync_82575"); - - while (i < timeout) { - if (igb_get_hw_semaphore_generic(hw)) { - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - if (!(swfw_sync & (fwmask | swmask))) - break; - - /* - * Firmware currently using resource (fwmask) - * or other software thread using resource (swmask) - */ - igb_put_hw_semaphore_generic(hw); - msec_delay_irq(5); - i++; - } - - if (i == timeout) { - DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); - ret_val = -E1000_ERR_SWFW_SYNC; - goto out; - } - - swfw_sync |= swmask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - igb_put_hw_semaphore_generic(hw); - -out: - return ret_val; -} - -/** - * igb_release_swfw_sync_82575 - Release SW/FW semaphore - * @hw: pointer to the HW structure - * @mask: specifies which semaphore to acquire - * - * Release the SW/FW semaphore used to access the PHY or NVM. The mask - * will also specify which port we're releasing the lock for. - **/ -static void igb_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask) -{ - u32 swfw_sync; - - DEBUGFUNC("igb_release_swfw_sync_82575"); - - while (igb_get_hw_semaphore_generic(hw) != E1000_SUCCESS); - /* Empty */ - - swfw_sync = E1000_READ_REG(hw, E1000_SW_FW_SYNC); - swfw_sync &= ~mask; - E1000_WRITE_REG(hw, E1000_SW_FW_SYNC, swfw_sync); - - igb_put_hw_semaphore_generic(hw); -} - -/** - * igb_get_cfg_done_82575 - Read config done bit - * @hw: pointer to the HW structure - * - * Read the management control register for the config done bit for - * completion status. NOTE: silicon which is EEPROM-less will fail trying - * to read the config done bit, so an error is *ONLY* logged and returns - * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon - * would not be able to be reset or change link. - **/ -static s32 igb_get_cfg_done_82575(struct e1000_hw *hw) -{ - s32 timeout = PHY_CFG_TIMEOUT; - s32 ret_val = E1000_SUCCESS; - u32 mask = E1000_NVM_CFG_DONE_PORT_0; - - DEBUGFUNC("igb_get_cfg_done_82575"); - - if (hw->bus.func == E1000_FUNC_1) - mask = E1000_NVM_CFG_DONE_PORT_1; - while (timeout) { - if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask) - break; - msec_delay(1); - timeout--; - } - if (!timeout) { - DEBUGOUT("MNG configuration cycle has not completed.\n"); - } - - /* If EEPROM is not marked present, init the PHY manually */ - if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) && - (hw->phy.type == e1000_phy_igp_3)) - igb_phy_init_script_igp3(hw); - - return ret_val; -} - -/** - * igb_get_link_up_info_82575 - Get link speed/duplex info - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * This is a wrapper function, if using the serial gigabit media independent - * interface, use PCS to retrieve the link speed and duplex information. - * Otherwise, use the generic function to get the link speed and duplex info. - **/ -static s32 igb_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed, - u16 *duplex) -{ - s32 ret_val; - - DEBUGFUNC("igb_get_link_up_info_82575"); - - if (hw->phy.media_type != e1000_media_type_copper) - ret_val = igb_get_pcs_speed_and_duplex_82575(hw, speed, - duplex); - else - ret_val = igb_get_speed_and_duplex_copper_generic(hw, speed, - duplex); - - return ret_val; -} - -/** - * igb_check_for_link_82575 - Check for link - * @hw: pointer to the HW structure - * - * If sgmii is enabled, then use the pcs register to determine link, otherwise - * use the generic interface for determining link. - **/ -static s32 igb_check_for_link_82575(struct e1000_hw *hw) -{ - s32 ret_val; - u16 speed, duplex; - - DEBUGFUNC("igb_check_for_link_82575"); - - if (hw->phy.media_type != e1000_media_type_copper) { - ret_val = igb_get_pcs_speed_and_duplex_82575(hw, &speed, - &duplex); - /* - * Use this flag to determine if link needs to be checked or - * not. If we have link clear the flag so that we do not - * continue to check for link. - */ - hw->mac.get_link_status = !hw->mac.serdes_has_link; - } else { - ret_val = igb_check_for_copper_link_generic(hw); - } - - return ret_val; -} - -/** - * igb_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * Using the physical coding sub-layer (PCS), retrieve the current speed and - * duplex, then store the values in the pointers provided. - **/ -static s32 igb_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw, - u16 *speed, u16 *duplex) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 pcs; - - DEBUGFUNC("igb_get_pcs_speed_and_duplex_82575"); - - /* Set up defaults for the return values of this function */ - mac->serdes_has_link = false; - *speed = 0; - *duplex = 0; - - /* - * Read the PCS Status register for link state. For non-copper mode, - * the status register is not accurate. The PCS status register is - * used instead. - */ - pcs = E1000_READ_REG(hw, E1000_PCS_LSTAT); - - /* - * The link up bit determines when link is up on autoneg. The sync ok - * gets set once both sides sync up and agree upon link. Stable link - * can be determined by checking for both link up and link sync ok - */ - if ((pcs & E1000_PCS_LSTS_LINK_OK) && (pcs & E1000_PCS_LSTS_SYNK_OK)) { - mac->serdes_has_link = true; - - /* Detect and store PCS speed */ - if (pcs & E1000_PCS_LSTS_SPEED_1000) { - *speed = SPEED_1000; - } else if (pcs & E1000_PCS_LSTS_SPEED_100) { - *speed = SPEED_100; - } else { - *speed = SPEED_10; - } - - /* Detect and store PCS duplex */ - if (pcs & E1000_PCS_LSTS_DUPLEX_FULL) { - *duplex = FULL_DUPLEX; - } else { - *duplex = HALF_DUPLEX; - } - } - - return E1000_SUCCESS; -} - -/** - * igb_shutdown_serdes_link_82575 - Remove link during power down - * @hw: pointer to the HW structure - * - * In the case of serdes shut down sfp and PCS on driver unload - * when management pass thru is not enabled. - **/ -void igb_shutdown_serdes_link_82575(struct e1000_hw *hw) -{ -#if 0 - u32 reg; -#endif - u16 eeprom_data = 0; - - if ((hw->phy.media_type != e1000_media_type_internal_serdes) && - !igb_sgmii_active_82575(hw)) - return; - - if (hw->bus.func == E1000_FUNC_0) - hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data); - else if (hw->bus.func == E1000_FUNC_1) - hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); - - /* - * If APM is not enabled in the EEPROM and management interface is - * not enabled, then power down. - */ -#if 0 - if (!(eeprom_data & E1000_NVM_APME_82575) && - !igb_enable_mng_pass_thru(hw)) { - /* Disable PCS to turn off link */ - reg = E1000_READ_REG(hw, E1000_PCS_CFG0); - reg &= ~E1000_PCS_CFG_PCS_EN; - E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg); - - /* shutdown the laser */ - reg = E1000_READ_REG(hw, E1000_CTRL_EXT); - reg |= E1000_CTRL_EXT_SDP3_DATA; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); - - /* flush the write to verify completion */ - E1000_WRITE_FLUSH(hw); - msec_delay(1); - } -#endif - return; -} - -/** - * igb_reset_hw_82575 - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. - **/ -static s32 igb_reset_hw_82575(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - - DEBUGFUNC("igb_reset_hw_82575"); - - /* - * Prevent the PCI-E bus from sticking if there is no TLP connection - * on the last TLP read/write transaction when MAC is reset. - */ - ret_val = igb_disable_pcie_master_generic(hw); - if (ret_val) { - DEBUGOUT("PCI-E Master disable polling has failed.\n"); - } - - /* set the completion timeout for interface */ - ret_val = igb_set_pcie_completion_timeout(hw); - if (ret_val) { - DEBUGOUT("PCI-E Set completion timeout has failed.\n"); - } - - DEBUGOUT("Masking off all interrupts\n"); - E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); - - E1000_WRITE_REG(hw, E1000_RCTL, 0); - E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP); - E1000_WRITE_FLUSH(hw); - - msec_delay(10); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - DEBUGOUT("Issuing a global reset to MAC\n"); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST); - - ret_val = igb_get_auto_rd_done_generic(hw); - if (ret_val) { - /* - * When auto config read does not complete, do not - * return with an error. This can happen in situations - * where there is no eeprom and prevents getting link. - */ - DEBUGOUT("Auto Read Done did not complete\n"); - } - - /* If EEPROM is not present, run manual init scripts */ - if ((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) - igb_reset_init_script_82575(hw); - - /* Clear any pending interrupt events. */ - E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff); - E1000_READ_REG(hw, E1000_ICR); - - /* Install any alternate MAC address into RAR0 */ - ret_val = igb_check_alt_mac_addr_generic(hw); - - return ret_val; -} - -/** - * igb_init_hw_82575 - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. - **/ -static s32 igb_init_hw_82575(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - u16 i, rar_count = mac->rar_entry_count; - - DEBUGFUNC("igb_init_hw_82575"); - - /* Initialize identification LED */ - ret_val = mac->ops.id_led_init(hw); - if (ret_val) { - DEBUGOUT("Error initializing identification LED\n"); - /* This is not fatal and we should not stop init due to this */ - } - - /* Disabling VLAN filtering */ - DEBUGOUT("Initializing the IEEE VLAN\n"); - mac->ops.clear_vfta(hw); - - /* Setup the receive address */ - igb_init_rx_addrs_generic(hw, rar_count); - - /* Zero out the Multicast HASH table */ - DEBUGOUT("Zeroing the MTA\n"); - for (i = 0; i < mac->mta_reg_count; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); - - /* Zero out the Unicast HASH table */ - DEBUGOUT("Zeroing the UTA\n"); - for (i = 0; i < mac->uta_reg_count; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0); - - /* Setup link and flow control */ - ret_val = mac->ops.setup_link(hw); - - /* - * Clear all of the statistics registers (clear on read). It is - * important that we do this after we have tried to establish link - * because the symbol error count will increment wildly if there - * is no link. - */ - igb_clear_hw_cntrs_82575(hw); - - return ret_val; -} - -/** - * igb_setup_copper_link_82575 - Configure copper link settings - * @hw: pointer to the HW structure - * - * Configures the link for auto-neg or forced speed and duplex. Then we check - * for link, once link is established calls to configure collision distance - * and flow control are called. - **/ -static s32 igb_setup_copper_link_82575(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val; - - DEBUGFUNC("igb_setup_copper_link_82575"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= E1000_CTRL_SLU; - ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - ret_val = igb_setup_serdes_link_82575(hw); - if (ret_val) - goto out; - - if (igb_sgmii_active_82575(hw) && !hw->phy.reset_disable) { - ret_val = hw->phy.ops.reset(hw); - if (ret_val) { - DEBUGOUT("Error resetting the PHY.\n"); - goto out; - } - } - switch (hw->phy.type) { - case e1000_phy_m88: - ret_val = igb_copper_link_setup_m88(hw); - break; - case e1000_phy_igp_3: - ret_val = igb_copper_link_setup_igp(hw); - break; - default: - ret_val = -E1000_ERR_PHY; - break; - } - - if (ret_val) - goto out; - - ret_val = igb_setup_copper_link_generic(hw); -out: - return ret_val; -} - -/** - * igb_setup_serdes_link_82575 - Setup link for serdes - * @hw: pointer to the HW structure - * - * Configure the physical coding sub-layer (PCS) link. The PCS link is - * used on copper connections where the serialized gigabit media independent - * interface (sgmii), or serdes fiber is being used. Configures the link - * for auto-negotiation or forces speed/duplex. - **/ -static s32 igb_setup_serdes_link_82575(struct e1000_hw *hw) -{ - u32 ctrl_reg, reg; - - DEBUGFUNC("igb_setup_serdes_link_82575"); - - if ((hw->phy.media_type != e1000_media_type_internal_serdes) && - !igb_sgmii_active_82575(hw)) - return E1000_SUCCESS; - - /* - * On the 82575, SerDes loopback mode persists until it is - * explicitly turned off or a power cycle is performed. A read to - * the register does not indicate its status. Therefore, we ensure - * loopback mode is disabled during initialization. - */ - E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK); - - /* power on the sfp cage if present */ - reg = E1000_READ_REG(hw, E1000_CTRL_EXT); - reg &= ~E1000_CTRL_EXT_SDP3_DATA; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg); - - ctrl_reg = E1000_READ_REG(hw, E1000_CTRL); - ctrl_reg |= E1000_CTRL_SLU; - - if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576) { - /* set both sw defined pins */ - ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1; - - /* Set switch control to serdes energy detect */ - reg = E1000_READ_REG(hw, E1000_CONNSW); - reg |= E1000_CONNSW_ENRGSRC; - E1000_WRITE_REG(hw, E1000_CONNSW, reg); - } - - reg = E1000_READ_REG(hw, E1000_PCS_LCTL); - - if (igb_sgmii_active_82575(hw)) { - /* allow time for SFP cage to power up phy */ - msec_delay(300); - - /* AN time out should be disabled for SGMII mode */ - reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT); - } else { - ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD | - E1000_CTRL_FD | E1000_CTRL_FRCDPX; - } - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg); - - /* - * New SerDes mode allows for forcing speed or autonegotiating speed - * at 1gb. Autoneg should be default set by most drivers. This is the - * mode that will be compatible with older link partners and switches. - * However, both are supported by the hardware and some drivers/tools. - */ - - reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP | - E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK); - - /* - * We force flow control to prevent the CTRL register values from being - * overwritten by the autonegotiated flow control values - */ - reg |= E1000_PCS_LCTL_FORCE_FCTRL; - - /* - * we always set sgmii to autoneg since it is the phy that will be - * forcing the link and the serdes is just a go-between - */ - if (hw->mac.autoneg || igb_sgmii_active_82575(hw)) { - /* Set PCS register for autoneg */ - reg |= E1000_PCS_LCTL_FSV_1000 | /* Force 1000 */ - E1000_PCS_LCTL_FDV_FULL | /* SerDes Full dplx */ - E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */ - E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */ - DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg); - } else { - /* Check for duplex first */ - if (hw->mac.forced_speed_duplex & E1000_ALL_FULL_DUPLEX) - reg |= E1000_PCS_LCTL_FDV_FULL; - - /* No need to check for 1000/full since the spec states that - * it requires autoneg to be enabled */ - /* Now set speed */ - if (hw->mac.forced_speed_duplex & E1000_ALL_100_SPEED) - reg |= E1000_PCS_LCTL_FSV_100; - - /* Force speed and force link */ - reg |= E1000_PCS_LCTL_FSD | - E1000_PCS_LCTL_FORCE_LINK | - E1000_PCS_LCTL_FLV_LINK_UP; - - DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg); - } - - E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg); - - if (!igb_sgmii_active_82575(hw)) - igb_force_mac_fc_generic(hw); - - return E1000_SUCCESS; -} - -/** - * igb_valid_led_default_82575 - Verify a valid default LED config - * @hw: pointer to the HW structure - * @data: pointer to the NVM (EEPROM) - * - * Read the EEPROM for the current default LED configuration. If the - * LED configuration is not valid, set to a valid LED configuration. - **/ -static s32 igb_valid_led_default_82575(struct e1000_hw *hw, u16 *data) -{ - s32 ret_val; - - DEBUGFUNC("igb_valid_led_default_82575"); - - ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) { - switch(hw->phy.media_type) { - case e1000_media_type_internal_serdes: - *data = ID_LED_DEFAULT_82575_SERDES; - break; - case e1000_media_type_copper: - default: - *data = ID_LED_DEFAULT; - break; - } - } -out: - return ret_val; -} - -/** - * igb_sgmii_active_82575 - Return sgmii state - * @hw: pointer to the HW structure - * - * 82575 silicon has a serialized gigabit media independent interface (sgmii) - * which can be enabled for use in the embedded applications. Simply - * return the current state of the sgmii interface. - **/ -static bool igb_sgmii_active_82575(struct e1000_hw *hw) -{ - struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575; - return dev_spec->sgmii_active; -} - -/** - * igb_reset_init_script_82575 - Inits HW defaults after reset - * @hw: pointer to the HW structure - * - * Inits recommended HW defaults after a reset when there is no EEPROM - * detected. This is only for the 82575. - **/ -static s32 igb_reset_init_script_82575(struct e1000_hw* hw) -{ - DEBUGFUNC("igb_reset_init_script_82575"); - - if (hw->mac.type == e1000_82575) { - DEBUGOUT("Running reset init script for 82575\n"); - /* SerDes configuration via SERDESCTRL */ - igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x00, 0x0C); - igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x01, 0x78); - igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x1B, 0x23); - igb_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x23, 0x15); - - /* CCM configuration via CCMCTL register */ - igb_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x14, 0x00); - igb_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x10, 0x00); - - /* PCIe lanes configuration */ - igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x00, 0xEC); - igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x61, 0xDF); - igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x34, 0x05); - igb_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x2F, 0x81); - - /* PCIe PLL Configuration */ - igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x02, 0x47); - igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x14, 0x00); - igb_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x10, 0x00); - } - - return E1000_SUCCESS; -} - -/** - * igb_read_mac_addr_82575 - Read device MAC address - * @hw: pointer to the HW structure - **/ -static s32 igb_read_mac_addr_82575(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_read_mac_addr_82575"); - - /* - * If there's an alternate MAC address place it in RAR0 - * so that it will override the Si installed default perm - * address. - */ - ret_val = igb_check_alt_mac_addr_generic(hw); - if (ret_val) - goto out; - - ret_val = igb_read_mac_addr_generic(hw); - -out: - return ret_val; -} - -/** - * igb_power_down_phy_copper_82575 - Remove link during PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, remove the link. - **/ -static void igb_power_down_phy_copper_82575(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - struct e1000_mac_info *mac = &hw->mac; - - if (!(phy->ops.check_reset_block)) - return; - - /* If the management interface is not enabled, then power down */ - if (!(mac->ops.check_mng_mode(hw) || phy->ops.check_reset_block(hw))) - igb_power_down_phy_copper(hw); - - return; -} - -/** - * igb_clear_hw_cntrs_82575 - Clear device specific hardware counters - * @hw: pointer to the HW structure - * - * Clears the hardware counters by reading the counter registers. - **/ -static void igb_clear_hw_cntrs_82575(struct e1000_hw *hw) -{ - DEBUGFUNC("igb_clear_hw_cntrs_82575"); - - igb_clear_hw_cntrs_base_generic(hw); - - E1000_READ_REG(hw, E1000_PRC64); - E1000_READ_REG(hw, E1000_PRC127); - E1000_READ_REG(hw, E1000_PRC255); - E1000_READ_REG(hw, E1000_PRC511); - E1000_READ_REG(hw, E1000_PRC1023); - E1000_READ_REG(hw, E1000_PRC1522); - E1000_READ_REG(hw, E1000_PTC64); - E1000_READ_REG(hw, E1000_PTC127); - E1000_READ_REG(hw, E1000_PTC255); - E1000_READ_REG(hw, E1000_PTC511); - E1000_READ_REG(hw, E1000_PTC1023); - E1000_READ_REG(hw, E1000_PTC1522); - - E1000_READ_REG(hw, E1000_ALGNERRC); - E1000_READ_REG(hw, E1000_RXERRC); - E1000_READ_REG(hw, E1000_TNCRS); - E1000_READ_REG(hw, E1000_CEXTERR); - E1000_READ_REG(hw, E1000_TSCTC); - E1000_READ_REG(hw, E1000_TSCTFC); - - E1000_READ_REG(hw, E1000_MGTPRC); - E1000_READ_REG(hw, E1000_MGTPDC); - E1000_READ_REG(hw, E1000_MGTPTC); - - E1000_READ_REG(hw, E1000_IAC); - E1000_READ_REG(hw, E1000_ICRXOC); - - E1000_READ_REG(hw, E1000_ICRXPTC); - E1000_READ_REG(hw, E1000_ICRXATC); - E1000_READ_REG(hw, E1000_ICTXPTC); - E1000_READ_REG(hw, E1000_ICTXATC); - E1000_READ_REG(hw, E1000_ICTXQEC); - E1000_READ_REG(hw, E1000_ICTXQMTC); - E1000_READ_REG(hw, E1000_ICRXDMTC); - - E1000_READ_REG(hw, E1000_CBTMPC); - E1000_READ_REG(hw, E1000_HTDPMC); - E1000_READ_REG(hw, E1000_CBRMPC); - E1000_READ_REG(hw, E1000_RPTHC); - E1000_READ_REG(hw, E1000_HGPTC); - E1000_READ_REG(hw, E1000_HTCBDPC); - E1000_READ_REG(hw, E1000_HGORCL); - E1000_READ_REG(hw, E1000_HGORCH); - E1000_READ_REG(hw, E1000_HGOTCL); - E1000_READ_REG(hw, E1000_HGOTCH); - E1000_READ_REG(hw, E1000_LENERRS); - - /* This register should not be read in copper configurations */ - if ((hw->phy.media_type == e1000_media_type_internal_serdes) || - igb_sgmii_active_82575(hw)) - E1000_READ_REG(hw, E1000_SCVPC); -} - -/** - * igb_rx_fifo_flush_82575 - Clean rx fifo after RX enable - * @hw: pointer to the HW structure - * - * After rx enable if managability is enabled then there is likely some - * bad data at the start of the fifo and possibly in the DMA fifo. This - * function clears the fifos and flushes any packets that came in as rx was - * being enabled. - **/ -void igb_rx_fifo_flush_82575(struct e1000_hw *hw) -{ - u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled; - int i, ms_wait; - - DEBUGFUNC("igb_rx_fifo_workaround_82575"); - if (hw->mac.type != e1000_82575 || - !(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN)) - return; - - /* Disable all RX queues */ - for (i = 0; i < 4; i++) { - rxdctl[i] = E1000_READ_REG(hw, E1000_RXDCTL(i)); - E1000_WRITE_REG(hw, E1000_RXDCTL(i), - rxdctl[i] & ~E1000_RXDCTL_QUEUE_ENABLE); - } - /* Poll all queues to verify they have shut down */ - for (ms_wait = 0; ms_wait < 10; ms_wait++) { - msec_delay(1); - rx_enabled = 0; - for (i = 0; i < 4; i++) - rx_enabled |= E1000_READ_REG(hw, E1000_RXDCTL(i)); - if (!(rx_enabled & E1000_RXDCTL_QUEUE_ENABLE)) - break; - } - - if (ms_wait == 10) { - DEBUGOUT("Queue disable timed out after 10ms\n"); - } - /* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all - * incoming packets are rejected. Set enable and wait 2ms so that - * any packet that was coming in as RCTL.EN was set is flushed - */ - rfctl = E1000_READ_REG(hw, E1000_RFCTL); - E1000_WRITE_REG(hw, E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF); - - rlpml = E1000_READ_REG(hw, E1000_RLPML); - E1000_WRITE_REG(hw, E1000_RLPML, 0); - - rctl = E1000_READ_REG(hw, E1000_RCTL); - temp_rctl = rctl & ~(E1000_RCTL_EN | E1000_RCTL_SBP); - temp_rctl |= E1000_RCTL_LPE; - - E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl); - E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl | E1000_RCTL_EN); - E1000_WRITE_FLUSH(hw); - msec_delay(2); - - /* Enable RX queues that were previously enabled and restore our - * previous state - */ - for (i = 0; i < 4; i++) - E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl[i]); - E1000_WRITE_REG(hw, E1000_RCTL, rctl); - E1000_WRITE_FLUSH(hw); - - E1000_WRITE_REG(hw, E1000_RLPML, rlpml); - E1000_WRITE_REG(hw, E1000_RFCTL, rfctl); - - /* Flush receive errors generated by workaround */ - E1000_READ_REG(hw, E1000_ROC); - E1000_READ_REG(hw, E1000_RNBC); - E1000_READ_REG(hw, E1000_MPC); -} - -/** - * igb_set_pcie_completion_timeout - set pci-e completion timeout - * @hw: pointer to the HW structure - * - * The defaults for 82575 and 82576 should be in the range of 50us to 50ms, - * however the hardware default for these parts is 500us to 1ms which is less - * than the 10ms recommended by the pci-e spec. To address this we need to - * increase the value to either 10ms to 200ms for capability version 1 config, - * or 16ms to 55ms for version 2. - **/ -static s32 igb_set_pcie_completion_timeout(struct e1000_hw *hw) -{ - u32 gcr = E1000_READ_REG(hw, E1000_GCR); - s32 ret_val = E1000_SUCCESS; - u16 pcie_devctl2; - - /* only take action if timeout value is defaulted to 0 */ - if (gcr & E1000_GCR_CMPL_TMOUT_MASK) - goto out; - - /* - * if capababilities version is type 1 we can write the - * timeout of 10ms to 200ms through the GCR register - */ - if (!(gcr & E1000_GCR_CAP_VER2)) { - gcr |= E1000_GCR_CMPL_TMOUT_10ms; - goto out; - } - - /* - * for version 2 capabilities we need to write the config space - * directly in order to set the completion timeout value for - * 16ms to 55ms - */ - ret_val = igb_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, - &pcie_devctl2); - if (ret_val) - goto out; - - pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms; - - ret_val = igb_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2, - &pcie_devctl2); -out: - /* disable completion timeout resend */ - gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND; - - E1000_WRITE_REG(hw, E1000_GCR, gcr); - return ret_val; -} - -/** - * igb_vmdq_set_loopback_pf - enable or disable vmdq loopback - * @hw: pointer to the hardware struct - * @enable: state to enter, either enabled or disabled - * - * enables/disables L2 switch loopback functionality. - **/ -void igb_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable) -{ - u32 dtxswc = E1000_READ_REG(hw, E1000_DTXSWC); - - if (enable) - dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN; - else - dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN; - - E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc); -} - -/** - * igb_vmdq_set_replication_pf - enable or disable vmdq replication - * @hw: pointer to the hardware struct - * @enable: state to enter, either enabled or disabled - * - * enables/disables replication of packets across multiple pools. - **/ -void igb_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable) -{ - u32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL); - - if (enable) - vt_ctl |= E1000_VT_CTL_VM_REPL_EN; - else - vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN; - - E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl); -} - -static struct pci_device_id igb_82575_nics[] = { - PCI_ROM(0x8086, 0x10C9, "E1000_DEV_ID_82576", "E1000_DEV_ID_82576", 0), - PCI_ROM(0x8086, 0x150A, "E1000_DEV_ID_82576_NS", "E1000_DEV_ID_82576_NS", 0), - PCI_ROM(0x8086, 0x1518, "E1000_DEV_ID_82576_NS_SERDES", "E1000_DEV_ID_82576_NS_SERDES", 0), - PCI_ROM(0x8086, 0x10E6, "E1000_DEV_ID_82576_FIBER", "E1000_DEV_ID_82576_FIBER", 0), - PCI_ROM(0x8086, 0x10E7, "E1000_DEV_ID_82576_SERDES", "E1000_DEV_ID_82576_SERDES", 0), - PCI_ROM(0x8086, 0x150D, "E1000_DEV_ID_82576_SERDES_QUAD", "E1000_DEV_ID_82576_SERDES_QUAD", 0), - PCI_ROM(0x8086, 0x10E8, "E1000_DEV_ID_82576_QUAD_COPPER", "E1000_DEV_ID_82576_QUAD_COPPER", 0), - PCI_ROM(0x8086, 0x10A7, "E1000_DEV_ID_82575EB_COPPER", "E1000_DEV_ID_82575EB_COPPER", 0), - PCI_ROM(0x8086, 0x10A9, "E1000_DEV_ID_82575EB_FIBER_SERDES", "E1000_DEV_ID_82575EB_FIBER_SERDES", 0), - PCI_ROM(0x8086, 0x10D6, "E1000_DEV_ID_82575GB_QUAD_COPPER", "E1000_DEV_ID_82575GB_QUAD_COPPER", 0), -}; - -struct pci_driver igb_82575_driver __pci_driver = { - .ids = igb_82575_nics, - .id_count = (sizeof (igb_82575_nics) / sizeof (igb_82575_nics[0])), - .probe = igb_probe, - .remove = igb_remove, -}; diff --git a/src/drivers/net/igb/igb_82575.h b/src/drivers/net/igb/igb_82575.h deleted file mode 100644 index 12c9a249..00000000 --- a/src/drivers/net/igb/igb_82575.h +++ /dev/null @@ -1,442 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_82575_H_ -#define _IGB_82575_H_ - -#define ID_LED_DEFAULT_82575_SERDES ((ID_LED_DEF1_DEF2 << 12) | \ - (ID_LED_DEF1_DEF2 << 8) | \ - (ID_LED_DEF1_DEF2 << 4) | \ - (ID_LED_OFF1_ON2)) -/* - * Receive Address Register Count - * Number of high/low register pairs in the RAR. The RAR (Receive Address - * Registers) holds the directed and multicast addresses that we monitor. - * These entries are also used for MAC-based filtering. - */ -/* - * For 82576, there are an additional set of RARs that begin at an offset - * separate from the first set of RARs. - */ -#define E1000_RAR_ENTRIES_82575 16 -#define E1000_RAR_ENTRIES_82576 24 - -struct e1000_adv_data_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - union { - u32 data; - struct { - u32 datalen :16; /* Data buffer length */ - u32 rsvd :4; - u32 dtyp :4; /* Descriptor type */ - u32 dcmd :8; /* Descriptor command */ - } config; - } lower; - union { - u32 data; - struct { - u32 status :4; /* Descriptor status */ - u32 idx :4; - u32 popts :6; /* Packet Options */ - u32 paylen :18; /* Payload length */ - } options; - } upper; -}; - -#define E1000_TXD_DTYP_ADV_C 0x2 /* Advanced Context Descriptor */ -#define E1000_TXD_DTYP_ADV_D 0x3 /* Advanced Data Descriptor */ -#define E1000_ADV_TXD_CMD_DEXT 0x20 /* Descriptor extension (0 = legacy) */ -#define E1000_ADV_TUCMD_IPV4 0x2 /* IP Packet Type: 1=IPv4 */ -#define E1000_ADV_TUCMD_IPV6 0x0 /* IP Packet Type: 0=IPv6 */ -#define E1000_ADV_TUCMD_L4T_UDP 0x0 /* L4 Packet TYPE of UDP */ -#define E1000_ADV_TUCMD_L4T_TCP 0x4 /* L4 Packet TYPE of TCP */ -#define E1000_ADV_TUCMD_MKRREQ 0x10 /* Indicates markers are required */ -#define E1000_ADV_DCMD_EOP 0x1 /* End of Packet */ -#define E1000_ADV_DCMD_IFCS 0x2 /* Insert FCS (Ethernet CRC) */ -#define E1000_ADV_DCMD_RS 0x8 /* Report Status */ -#define E1000_ADV_DCMD_VLE 0x40 /* Add VLAN tag */ -#define E1000_ADV_DCMD_TSE 0x80 /* TCP Seg enable */ -/* Extended Device Control */ -#define E1000_CTRL_EXT_NSICR 0x00000001 /* Disable Intr Clear all on read */ - -struct e1000_adv_context_desc { - union { - u32 ip_config; - struct { - u32 iplen :9; - u32 maclen :7; - u32 vlan_tag :16; - } fields; - } ip_setup; - u32 seq_num; - union { - u64 l4_config; - struct { - u32 mkrloc :9; - u32 tucmd :11; - u32 dtyp :4; - u32 adv :8; - u32 rsvd :4; - u32 idx :4; - u32 l4len :8; - u32 mss :16; - } fields; - } l4_setup; -}; - -/* SRRCTL bit definitions */ -#define E1000_SRRCTL_BSIZEPKT_SHIFT 10 /* Shift _right_ */ -#define E1000_SRRCTL_BSIZEHDRSIZE_MASK 0x00000F00 -#define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT 2 /* Shift _left_ */ -#define E1000_SRRCTL_DESCTYPE_LEGACY 0x00000000 -#define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000 -#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT 0x04000000 -#define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000 -#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION 0x06000000 -#define E1000_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000 -#define E1000_SRRCTL_DESCTYPE_MASK 0x0E000000 -#define E1000_SRRCTL_DROP_EN 0x80000000 - -#define E1000_SRRCTL_BSIZEPKT_MASK 0x0000007F -#define E1000_SRRCTL_BSIZEHDR_MASK 0x00003F00 - -#define E1000_TX_HEAD_WB_ENABLE 0x1 -#define E1000_TX_SEQNUM_WB_ENABLE 0x2 - -#define E1000_MRQC_ENABLE_RSS_4Q 0x00000002 -#define E1000_MRQC_ENABLE_VMDQ 0x00000003 -#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q 0x00000005 -#define E1000_MRQC_RSS_FIELD_IPV4_UDP 0x00400000 -#define E1000_MRQC_RSS_FIELD_IPV6_UDP 0x00800000 -#define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX 0x01000000 - -#define E1000_VMRCTL_MIRROR_PORT_SHIFT 8 -#define E1000_VMRCTL_MIRROR_DSTPORT_MASK (7 << E1000_VMRCTL_MIRROR_PORT_SHIFT) -#define E1000_VMRCTL_POOL_MIRROR_ENABLE (1 << 0) -#define E1000_VMRCTL_UPLINK_MIRROR_ENABLE (1 << 1) -#define E1000_VMRCTL_DOWNLINK_MIRROR_ENABLE (1 << 2) - -#define E1000_EICR_TX_QUEUE ( \ - E1000_EICR_TX_QUEUE0 | \ - E1000_EICR_TX_QUEUE1 | \ - E1000_EICR_TX_QUEUE2 | \ - E1000_EICR_TX_QUEUE3) - -#define E1000_EICR_RX_QUEUE ( \ - E1000_EICR_RX_QUEUE0 | \ - E1000_EICR_RX_QUEUE1 | \ - E1000_EICR_RX_QUEUE2 | \ - E1000_EICR_RX_QUEUE3) - -#define E1000_EIMS_RX_QUEUE E1000_EICR_RX_QUEUE -#define E1000_EIMS_TX_QUEUE E1000_EICR_TX_QUEUE - -#define EIMS_ENABLE_MASK ( \ - E1000_EIMS_RX_QUEUE | \ - E1000_EIMS_TX_QUEUE | \ - E1000_EIMS_TCP_TIMER | \ - E1000_EIMS_OTHER) - -/* Immediate Interrupt Rx (A.K.A. Low Latency Interrupt) */ -#define E1000_IMIR_PORT_IM_EN 0x00010000 /* TCP port enable */ -#define E1000_IMIR_PORT_BP 0x00020000 /* TCP port check bypass */ -#define E1000_IMIREXT_SIZE_BP 0x00001000 /* Packet size bypass */ -#define E1000_IMIREXT_CTRL_URG 0x00002000 /* Check URG bit in header */ -#define E1000_IMIREXT_CTRL_ACK 0x00004000 /* Check ACK bit in header */ -#define E1000_IMIREXT_CTRL_PSH 0x00008000 /* Check PSH bit in header */ -#define E1000_IMIREXT_CTRL_RST 0x00010000 /* Check RST bit in header */ -#define E1000_IMIREXT_CTRL_SYN 0x00020000 /* Check SYN bit in header */ -#define E1000_IMIREXT_CTRL_FIN 0x00040000 /* Check FIN bit in header */ -#define E1000_IMIREXT_CTRL_BP 0x00080000 /* Bypass check of ctrl bits */ - -/* Receive Descriptor - Advanced */ -union e1000_adv_rx_desc { - struct { - __le64 pkt_addr; /* Packet buffer address */ - __le64 hdr_addr; /* Header buffer address */ - } read; - struct { - struct { - union { - __le32 data; - struct { - __le16 pkt_info; /*RSS type, Pkt type*/ - __le16 hdr_info; /* Split Header, - * header buffer len*/ - } hs_rss; - } lo_dword; - union { - __le32 rss; /* RSS Hash */ - struct { - __le16 ip_id; /* IP id */ - __le16 csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - __le32 status_error; /* ext status/error */ - __le16 length; /* Packet length */ - __le16 vlan; /* VLAN tag */ - } upper; - } wb; /* writeback */ -}; - -#define E1000_RXDADV_RSSTYPE_MASK 0x0000000F -#define E1000_RXDADV_RSSTYPE_SHIFT 12 -#define E1000_RXDADV_HDRBUFLEN_MASK 0x7FE0 -#define E1000_RXDADV_HDRBUFLEN_SHIFT 5 -#define E1000_RXDADV_SPLITHEADER_EN 0x00001000 -#define E1000_RXDADV_SPH 0x8000 -#define E1000_RXDADV_STAT_TS 0x10000 /* Pkt was time stamped */ -#define E1000_RXDADV_ERR_HBO 0x00800000 - -/* RSS Hash results */ -#define E1000_RXDADV_RSSTYPE_NONE 0x00000000 -#define E1000_RXDADV_RSSTYPE_IPV4_TCP 0x00000001 -#define E1000_RXDADV_RSSTYPE_IPV4 0x00000002 -#define E1000_RXDADV_RSSTYPE_IPV6_TCP 0x00000003 -#define E1000_RXDADV_RSSTYPE_IPV6_EX 0x00000004 -#define E1000_RXDADV_RSSTYPE_IPV6 0x00000005 -#define E1000_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006 -#define E1000_RXDADV_RSSTYPE_IPV4_UDP 0x00000007 -#define E1000_RXDADV_RSSTYPE_IPV6_UDP 0x00000008 -#define E1000_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009 - -/* RSS Packet Types as indicated in the receive descriptor */ -#define E1000_RXDADV_PKTTYPE_NONE 0x00000000 -#define E1000_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */ -#define E1000_RXDADV_PKTTYPE_IPV4_EX 0x00000020 /* IPV4 hdr + extensions */ -#define E1000_RXDADV_PKTTYPE_IPV6 0x00000040 /* IPV6 hdr present */ -#define E1000_RXDADV_PKTTYPE_IPV6_EX 0x00000080 /* IPV6 hdr + extensions */ -#define E1000_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */ -#define E1000_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */ -#define E1000_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */ -#define E1000_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */ - -#define E1000_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */ -#define E1000_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */ -#define E1000_RXDADV_PKTTYPE_LINKSEC 0x00004000 /* LinkSec Encap */ -#define E1000_RXDADV_PKTTYPE_ETQF 0x00008000 /* PKTTYPE is ETQF index */ -#define E1000_RXDADV_PKTTYPE_ETQF_MASK 0x00000070 /* ETQF has 8 indices */ -#define E1000_RXDADV_PKTTYPE_ETQF_SHIFT 4 /* Right-shift 4 bits */ - -/* LinkSec results */ -/* Security Processing bit Indication */ -#define E1000_RXDADV_LNKSEC_STATUS_SECP 0x00020000 -#define E1000_RXDADV_LNKSEC_ERROR_BIT_MASK 0x18000000 -#define E1000_RXDADV_LNKSEC_ERROR_NO_SA_MATCH 0x08000000 -#define E1000_RXDADV_LNKSEC_ERROR_REPLAY_ERROR 0x10000000 -#define E1000_RXDADV_LNKSEC_ERROR_BAD_SIG 0x18000000 - -#define E1000_RXDADV_IPSEC_STATUS_SECP 0x00020000 -#define E1000_RXDADV_IPSEC_ERROR_BIT_MASK 0x18000000 -#define E1000_RXDADV_IPSEC_ERROR_INVALID_PROTOCOL 0x08000000 -#define E1000_RXDADV_IPSEC_ERROR_INVALID_LENGTH 0x10000000 -#define E1000_RXDADV_IPSEC_ERROR_AUTHENTICATION_FAILED 0x18000000 - -/* Transmit Descriptor - Advanced */ -union e1000_adv_tx_desc { - struct { - __le64 buffer_addr; /* Address of descriptor's data buf */ - __le32 cmd_type_len; - __le32 olinfo_status; - } read; - struct { - __le64 rsvd; /* Reserved */ - __le32 nxtseq_seed; - __le32 status; - } wb; -}; - -/* Adv Transmit Descriptor Config Masks */ -#define E1000_ADVTXD_DTYP_CTXT 0x00200000 /* Advanced Context Descriptor */ -#define E1000_ADVTXD_DTYP_DATA 0x00300000 /* Advanced Data Descriptor */ -#define E1000_ADVTXD_DCMD_EOP 0x01000000 /* End of Packet */ -#define E1000_ADVTXD_DCMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ -#define E1000_ADVTXD_DCMD_RS 0x08000000 /* Report Status */ -#define E1000_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000 /* DDP hdr type or iSCSI */ -#define E1000_ADVTXD_DCMD_DEXT 0x20000000 /* Descriptor extension (1=Adv) */ -#define E1000_ADVTXD_DCMD_VLE 0x40000000 /* VLAN pkt enable */ -#define E1000_ADVTXD_DCMD_TSE 0x80000000 /* TCP Seg enable */ -#define E1000_ADVTXD_MAC_LINKSEC 0x00040000 /* Apply LinkSec on packet */ -#define E1000_ADVTXD_MAC_TSTAMP 0x00080000 /* IEEE1588 Timestamp packet */ -#define E1000_ADVTXD_STAT_SN_CRC 0x00000002 /* NXTSEQ/SEED present in WB */ -#define E1000_ADVTXD_IDX_SHIFT 4 /* Adv desc Index shift */ -#define E1000_ADVTXD_POPTS_ISCO_1ST 0x00000000 /* 1st TSO of iSCSI PDU */ -#define E1000_ADVTXD_POPTS_ISCO_MDL 0x00000800 /* Middle TSO of iSCSI PDU */ -#define E1000_ADVTXD_POPTS_ISCO_LAST 0x00001000 /* Last TSO of iSCSI PDU */ -#define E1000_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/ -#define E1000_ADVTXD_POPTS_IPSEC 0x00000400 /* IPSec offload request */ -#define E1000_ADVTXD_PAYLEN_SHIFT 14 /* Adv desc PAYLEN shift */ - -/* Context descriptors */ -struct e1000_adv_tx_context_desc { - __le32 vlan_macip_lens; - __le32 seqnum_seed; - __le32 type_tucmd_mlhl; - __le32 mss_l4len_idx; -}; - -#define E1000_ADVTXD_MACLEN_SHIFT 9 /* Adv ctxt desc mac len shift */ -#define E1000_ADVTXD_VLAN_SHIFT 16 /* Adv ctxt vlan tag shift */ -#define E1000_ADVTXD_TUCMD_IPV4 0x00000400 /* IP Packet Type: 1=IPv4 */ -#define E1000_ADVTXD_TUCMD_IPV6 0x00000000 /* IP Packet Type: 0=IPv6 */ -#define E1000_ADVTXD_TUCMD_L4T_UDP 0x00000000 /* L4 Packet TYPE of UDP */ -#define E1000_ADVTXD_TUCMD_L4T_TCP 0x00000800 /* L4 Packet TYPE of TCP */ -#define E1000_ADVTXD_TUCMD_L4T_SCTP 0x00001000 /* L4 Packet TYPE of SCTP */ -#define E1000_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */ -/* IPSec Encrypt Enable for ESP */ -#define E1000_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000 -#define E1000_ADVTXD_TUCMD_MKRREQ 0x00002000 /* Req requires Markers and CRC */ -#define E1000_ADVTXD_L4LEN_SHIFT 8 /* Adv ctxt L4LEN shift */ -#define E1000_ADVTXD_MSS_SHIFT 16 /* Adv ctxt MSS shift */ -/* Adv ctxt IPSec SA IDX mask */ -#define E1000_ADVTXD_IPSEC_SA_INDEX_MASK 0x000000FF -/* Adv ctxt IPSec ESP len mask */ -#define E1000_ADVTXD_IPSEC_ESP_LEN_MASK 0x000000FF - -/* Additional Transmit Descriptor Control definitions */ -#define E1000_TXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Tx Queue */ -#define E1000_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */ -/* Tx Queue Arbitration Priority 0=low, 1=high */ -#define E1000_TXDCTL_PRIORITY 0x08000000 - -/* Additional Receive Descriptor Control definitions */ -#define E1000_RXDCTL_QUEUE_ENABLE 0x02000000 /* Enable specific Rx Queue */ -#define E1000_RXDCTL_SWFLSH 0x04000000 /* Rx Desc. write-back flushing */ - -/* Direct Cache Access (DCA) definitions */ -#define E1000_DCA_CTRL_DCA_ENABLE 0x00000000 /* DCA Enable */ -#define E1000_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */ - -#define E1000_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */ -#define E1000_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */ - -#define E1000_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */ -#define E1000_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */ -#define E1000_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */ -#define E1000_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */ - -#define E1000_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */ -#define E1000_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */ -#define E1000_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */ - -#define E1000_DCA_TXCTRL_CPUID_MASK_82576 0xFF000000 /* Tx CPUID Mask */ -#define E1000_DCA_RXCTRL_CPUID_MASK_82576 0xFF000000 /* Rx CPUID Mask */ -#define E1000_DCA_TXCTRL_CPUID_SHIFT_82576 24 /* Tx CPUID */ -#define E1000_DCA_RXCTRL_CPUID_SHIFT_82576 24 /* Rx CPUID */ - -/* Additional interrupt register bit definitions */ -#define E1000_ICR_LSECPNS 0x00000020 /* PN threshold - server */ -#define E1000_IMS_LSECPNS E1000_ICR_LSECPNS /* PN threshold - server */ -#define E1000_ICS_LSECPNS E1000_ICR_LSECPNS /* PN threshold - server */ - -/* ETQF register bit definitions */ -#define E1000_ETQF_FILTER_ENABLE (1 << 26) -#define E1000_ETQF_IMM_INT (1 << 29) -#define E1000_ETQF_1588 (1 << 30) -#define E1000_ETQF_QUEUE_ENABLE (1 << 31) -/* - * ETQF filter list: one static filter per filter consumer. This is - * to avoid filter collisions later. Add new filters - * here!! - * - * Current filters: - * EAPOL 802.1x (0x888e): Filter 0 - */ -#define E1000_ETQF_FILTER_EAPOL 0 - -#define E1000_FTQF_VF_BP 0x00008000 -#define E1000_FTQF_1588_TIME_STAMP 0x08000000 -#define E1000_FTQF_MASK 0xF0000000 -#define E1000_FTQF_MASK_PROTO_BP 0x10000000 -#define E1000_FTQF_MASK_SOURCE_ADDR_BP 0x20000000 -#define E1000_FTQF_MASK_DEST_ADDR_BP 0x40000000 -#define E1000_FTQF_MASK_SOURCE_PORT_BP 0x80000000 - -#define E1000_NVM_APME_82575 0x0400 -#define MAX_NUM_VFS 8 - -#define E1000_DTXSWC_MAC_SPOOF_MASK 0x000000FF /* Per VF MAC spoof control */ -#define E1000_DTXSWC_VLAN_SPOOF_MASK 0x0000FF00 /* Per VF VLAN spoof control */ -#define E1000_DTXSWC_LLE_MASK 0x00FF0000 /* Per VF Local LB enables */ -#define E1000_DTXSWC_VLAN_SPOOF_SHIFT 8 -#define E1000_DTXSWC_LLE_SHIFT 16 -#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31) /* global VF LB enable */ - -/* Easy defines for setting default pool, would normally be left a zero */ -#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7 -#define E1000_VT_CTL_DEFAULT_POOL_MASK (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT) - -/* Other useful VMD_CTL register defines */ -#define E1000_VT_CTL_IGNORE_MAC (1 << 28) -#define E1000_VT_CTL_DISABLE_DEF_POOL (1 << 29) -#define E1000_VT_CTL_VM_REPL_EN (1 << 30) - -/* Per VM Offload register setup */ -#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */ -#define E1000_VMOLR_LPE 0x00010000 /* Accept Long packet */ -#define E1000_VMOLR_RSSE 0x00020000 /* Enable RSS */ -#define E1000_VMOLR_AUPE 0x01000000 /* Accept untagged packets */ -#define E1000_VMOLR_ROMPE 0x02000000 /* Accept overflow multicast */ -#define E1000_VMOLR_ROPE 0x04000000 /* Accept overflow unicast */ -#define E1000_VMOLR_BAM 0x08000000 /* Accept Broadcast packets */ -#define E1000_VMOLR_MPME 0x10000000 /* Multicast promiscuous mode */ -#define E1000_VMOLR_STRVLAN 0x40000000 /* Vlan stripping enable */ -#define E1000_VMOLR_STRCRC 0x80000000 /* CRC stripping enable */ - -#define E1000_VLVF_ARRAY_SIZE 32 -#define E1000_VLVF_VLANID_MASK 0x00000FFF -#define E1000_VLVF_POOLSEL_SHIFT 12 -#define E1000_VLVF_POOLSEL_MASK (0xFF << E1000_VLVF_POOLSEL_SHIFT) -#define E1000_VLVF_LVLAN 0x00100000 -#define E1000_VLVF_VLANID_ENABLE 0x80000000 - -#define E1000_VF_INIT_TIMEOUT 200 /* Number of retries to clear RSTI */ - -#define E1000_IOVCTL 0x05BBC -#define E1000_IOVCTL_REUSE_VFQ 0x00000001 - -#define E1000_RPLOLR_STRVLAN 0x40000000 -#define E1000_RPLOLR_STRCRC 0x80000000 - -#define E1000_DTXCTL_8023LL 0x0004 -#define E1000_DTXCTL_VLAN_ADDED 0x0008 -#define E1000_DTXCTL_OOS_ENABLE 0x0010 -#define E1000_DTXCTL_MDP_EN 0x0020 -#define E1000_DTXCTL_SPOOF_INT 0x0040 - -#define ALL_QUEUES 0xFFFF - -/* RX packet buffer size defines */ -#define E1000_RXPBS_SIZE_MASK_82576 0x0000007F -void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable); -void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable); - -#endif /* _IGB_82575_H_ */ diff --git a/src/drivers/net/igb/igb_api.c b/src/drivers/net/igb/igb_api.c deleted file mode 100644 index eda6bc01..00000000 --- a/src/drivers/net/igb/igb_api.c +++ /dev/null @@ -1,1108 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#include "igb.h" - -/** - * igb_init_mac_params - Initialize MAC function pointers - * @hw: pointer to the HW structure - * - * This function initializes the function pointers for the MAC - * set of functions. Called by drivers or by e1000_setup_init_funcs. - **/ -s32 igb_init_mac_params(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->mac.ops.init_params) { - ret_val = hw->mac.ops.init_params(hw); - if (ret_val) { - DEBUGOUT("MAC Initialization Error\n"); - goto out; - } - } else { - DEBUGOUT("mac.init_mac_params was NULL\n"); - ret_val = -E1000_ERR_CONFIG; - } - -out: - return ret_val; -} - -/** - * igb_init_nvm_params - Initialize NVM function pointers - * @hw: pointer to the HW structure - * - * This function initializes the function pointers for the NVM - * set of functions. Called by drivers or by e1000_setup_init_funcs. - **/ -s32 igb_init_nvm_params(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->nvm.ops.init_params) { - ret_val = hw->nvm.ops.init_params(hw); - if (ret_val) { - DEBUGOUT("NVM Initialization Error\n"); - goto out; - } - } else { - DEBUGOUT("nvm.init_nvm_params was NULL\n"); - ret_val = -E1000_ERR_CONFIG; - } - -out: - return ret_val; -} - -/** - * igb_init_phy_params - Initialize PHY function pointers - * @hw: pointer to the HW structure - * - * This function initializes the function pointers for the PHY - * set of functions. Called by drivers or by e1000_setup_init_funcs. - **/ -s32 igb_init_phy_params(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->phy.ops.init_params) { - ret_val = hw->phy.ops.init_params(hw); - if (ret_val) { - DEBUGOUT("PHY Initialization Error\n"); - goto out; - } - } else { - DEBUGOUT("phy.init_phy_params was NULL\n"); - ret_val = -E1000_ERR_CONFIG; - } - -out: - return ret_val; -} - -#if 0 -/** - * igb_init_mbx_params - Initialize mailbox function pointers - * @hw: pointer to the HW structure - * - * This function initializes the function pointers for the PHY - * set of functions. Called by drivers or by e1000_setup_init_funcs. - **/ -s32 igb_init_mbx_params(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - if (hw->mbx.ops.init_params) { - ret_val = hw->mbx.ops.init_params(hw); - if (ret_val) { - DEBUGOUT("Mailbox Initialization Error\n"); - goto out; - } - } else { - DEBUGOUT("mbx.init_mbx_params was NULL\n"); - ret_val = -E1000_ERR_CONFIG; - } - -out: - return ret_val; -} -#endif - -/** - * igb_set_mac_type - Sets MAC type - * @hw: pointer to the HW structure - * - * This function sets the mac type of the adapter based on the - * device ID stored in the hw structure. - * MUST BE FIRST FUNCTION CALLED (explicitly or through - * igb_setup_init_funcs()). - **/ -s32 igb_set_mac_type(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_set_mac_type"); - - switch (hw->device_id) { - case E1000_DEV_ID_82575EB_COPPER: - case E1000_DEV_ID_82575EB_FIBER_SERDES: - case E1000_DEV_ID_82575GB_QUAD_COPPER: - mac->type = e1000_82575; - break; - case E1000_DEV_ID_82576: - case E1000_DEV_ID_82576_FIBER: - case E1000_DEV_ID_82576_SERDES: - case E1000_DEV_ID_82576_QUAD_COPPER: - case E1000_DEV_ID_82576_NS: - case E1000_DEV_ID_82576_NS_SERDES: - case E1000_DEV_ID_82576_SERDES_QUAD: - mac->type = e1000_82576; - break; - default: - /* Should never have loaded on this device */ - ret_val = -E1000_ERR_MAC_INIT; - break; - } - - return ret_val; -} - -/** - * igb_setup_init_funcs - Initializes function pointers - * @hw: pointer to the HW structure - * @init_device: true will initialize the rest of the function pointers - * getting the device ready for use. false will only set - * MAC type and the function pointers for the other init - * functions. Passing false will not generate any hardware - * reads or writes. - * - * This function must be called by a driver in order to use the rest - * of the 'shared' code files. Called by drivers only. - **/ -s32 igb_setup_init_funcs(struct e1000_hw *hw, bool init_device) -{ - s32 ret_val; - - /* Can't do much good without knowing the MAC type. */ - ret_val = igb_set_mac_type(hw); - if (ret_val) { - DEBUGOUT("ERROR: MAC type could not be set properly.\n"); - goto out; - } - - if (!hw->hw_addr) { - DEBUGOUT("ERROR: Registers not mapped\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - /* - * Init function pointers to generic implementations. We do this first - * allowing a driver module to override it afterward. - */ - igb_init_mac_ops_generic(hw); - igb_init_nvm_ops_generic(hw); -#if 0 - igb_init_mbx_ops_generic(hw); -#endif - /* - * Set up the init function pointers. These are functions within the - * adapter family file that sets up function pointers for the rest of - * the functions in that family. - */ - switch (hw->mac.type) { - case e1000_82575: - case e1000_82576: - igb_init_function_pointers_82575(hw); - break; - default: - DEBUGOUT("Hardware not supported\n"); - ret_val = -E1000_ERR_CONFIG; - break; - } - - /* - * Initialize the rest of the function pointers. These require some - * register reads/writes in some cases. - */ - if (!(ret_val) && init_device) { - ret_val = igb_init_mac_params(hw); - if (ret_val) - goto out; - - ret_val = igb_init_nvm_params(hw); - if (ret_val) - goto out; - - ret_val = igb_init_phy_params(hw); - if (ret_val) - goto out; -#if 0 - ret_val = igb_init_mbx_params(hw); - if (ret_val) - goto out; -#endif - } - -out: - return ret_val; -} - -/** - * igb_get_bus_info - Obtain bus information for adapter - * @hw: pointer to the HW structure - * - * This will obtain information about the HW bus for which the - * adapter is attached and stores it in the hw structure. This is a - * function pointer entry point called by drivers. - **/ -s32 igb_get_bus_info(struct e1000_hw *hw) -{ - if (hw->mac.ops.get_bus_info) - return hw->mac.ops.get_bus_info(hw); - - return E1000_SUCCESS; -} - -/** - * igb_clear_vfta - Clear VLAN filter table - * @hw: pointer to the HW structure - * - * This clears the VLAN filter table on the adapter. This is a function - * pointer entry point called by drivers. - **/ -void igb_clear_vfta(struct e1000_hw *hw) -{ - if (hw->mac.ops.clear_vfta) - hw->mac.ops.clear_vfta(hw); -} - -/** - * igb_write_vfta - Write value to VLAN filter table - * @hw: pointer to the HW structure - * @offset: the 32-bit offset in which to write the value to. - * @value: the 32-bit value to write at location offset. - * - * This writes a 32-bit value to a 32-bit offset in the VLAN filter - * table. This is a function pointer entry point called by drivers. - **/ -void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value) -{ - if (hw->mac.ops.write_vfta) - hw->mac.ops.write_vfta(hw, offset, value); -} - -/** - * igb_update_mc_addr_list - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * - * Updates the Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - **/ -void igb_update_mc_addr_list(struct e1000_hw *hw, u8 *mc_addr_list, - u32 mc_addr_count) -{ - if (hw->mac.ops.update_mc_addr_list) - hw->mac.ops.update_mc_addr_list(hw, mc_addr_list, - mc_addr_count); -} - -/** - * igb_force_mac_fc - Force MAC flow control - * @hw: pointer to the HW structure - * - * Force the MAC's flow control settings. Currently no func pointer exists - * and all implementations are handled in the generic version of this - * function. - **/ -s32 igb_force_mac_fc(struct e1000_hw *hw) -{ - return igb_force_mac_fc_generic(hw); -} - -/** - * igb_check_for_link - Check/Store link connection - * @hw: pointer to the HW structure - * - * This checks the link condition of the adapter and stores the - * results in the hw->mac structure. This is a function pointer entry - * point called by drivers. - **/ -s32 igb_check_for_link(struct e1000_hw *hw) -{ - if (hw->mac.ops.check_for_link) - return hw->mac.ops.check_for_link(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_check_mng_mode - Check management mode - * @hw: pointer to the HW structure - * - * This checks if the adapter has manageability enabled. - * This is a function pointer entry point called by drivers. - **/ -bool igb_check_mng_mode(struct e1000_hw *hw) -{ - if (hw->mac.ops.check_mng_mode) - return hw->mac.ops.check_mng_mode(hw); - - return false; -} - -#if 0 -/** - * igb_mng_write_dhcp_info - Writes DHCP info to host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface - * @length: size of the buffer - * - * Writes the DHCP information to the host interface. - **/ -s32 igb_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length) -{ - return igb_mng_write_dhcp_info_generic(hw, buffer, length); -} -#endif - -/** - * igb_reset_hw - Reset hardware - * @hw: pointer to the HW structure - * - * This resets the hardware into a known state. This is a function pointer - * entry point called by drivers. - **/ -s32 igb_reset_hw(struct e1000_hw *hw) -{ - if (hw->mac.ops.reset_hw) - return hw->mac.ops.reset_hw(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_init_hw - Initialize hardware - * @hw: pointer to the HW structure - * - * This inits the hardware readying it for operation. This is a function - * pointer entry point called by drivers. - **/ -s32 igb_init_hw(struct e1000_hw *hw) -{ - if (hw->mac.ops.init_hw) - return hw->mac.ops.init_hw(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_setup_link - Configures link and flow control - * @hw: pointer to the HW structure - * - * This configures link and flow control settings for the adapter. This - * is a function pointer entry point called by drivers. While modules can - * also call this, they probably call their own version of this function. - **/ -s32 igb_setup_link(struct e1000_hw *hw) -{ - if (hw->mac.ops.setup_link) - return hw->mac.ops.setup_link(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_get_speed_and_duplex - Returns current speed and duplex - * @hw: pointer to the HW structure - * @speed: pointer to a 16-bit value to store the speed - * @duplex: pointer to a 16-bit value to store the duplex. - * - * This returns the speed and duplex of the adapter in the two 'out' - * variables passed in. This is a function pointer entry point called - * by drivers. - **/ -s32 igb_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16 *duplex) -{ - if (hw->mac.ops.get_link_up_info) - return hw->mac.ops.get_link_up_info(hw, speed, duplex); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_setup_led - Configures SW controllable LED - * @hw: pointer to the HW structure - * - * This prepares the SW controllable LED for use and saves the current state - * of the LED so it can be later restored. This is a function pointer entry - * point called by drivers. - **/ -s32 igb_setup_led(struct e1000_hw *hw) -{ - if (hw->mac.ops.setup_led) - return hw->mac.ops.setup_led(hw); - - return E1000_SUCCESS; -} - -/** - * igb_cleanup_led - Restores SW controllable LED - * @hw: pointer to the HW structure - * - * This restores the SW controllable LED to the value saved off by - * e1000_setup_led. This is a function pointer entry point called by drivers. - **/ -s32 igb_cleanup_led(struct e1000_hw *hw) -{ - if (hw->mac.ops.cleanup_led) - return hw->mac.ops.cleanup_led(hw); - - return E1000_SUCCESS; -} - -/** - * igb_blink_led - Blink SW controllable LED - * @hw: pointer to the HW structure - * - * This starts the adapter LED blinking. Request the LED to be setup first - * and cleaned up after. This is a function pointer entry point called by - * drivers. - **/ -s32 igb_blink_led(struct e1000_hw *hw) -{ - if (hw->mac.ops.blink_led) - return hw->mac.ops.blink_led(hw); - - return E1000_SUCCESS; -} - -/** - * igb_id_led_init - store LED configurations in SW - * @hw: pointer to the HW structure - * - * Initializes the LED config in SW. This is a function pointer entry point - * called by drivers. - **/ -s32 igb_id_led_init(struct e1000_hw *hw) -{ - if (hw->mac.ops.id_led_init) - return hw->mac.ops.id_led_init(hw); - - return E1000_SUCCESS; -} - -/** - * igb_led_on - Turn on SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED on. This is a function pointer entry point - * called by drivers. - **/ -s32 igb_led_on(struct e1000_hw *hw) -{ - if (hw->mac.ops.led_on) - return hw->mac.ops.led_on(hw); - - return E1000_SUCCESS; -} - -/** - * igb_led_off - Turn off SW controllable LED - * @hw: pointer to the HW structure - * - * Turns the SW defined LED off. This is a function pointer entry point - * called by drivers. - **/ -s32 igb_led_off(struct e1000_hw *hw) -{ - if (hw->mac.ops.led_off) - return hw->mac.ops.led_off(hw); - - return E1000_SUCCESS; -} - -/** - * igb_reset_adaptive - Reset adaptive IFS - * @hw: pointer to the HW structure - * - * Resets the adaptive IFS. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -void igb_reset_adaptive(struct e1000_hw *hw) -{ - igb_reset_adaptive_generic(hw); -} - -/** - * igb_update_adaptive - Update adaptive IFS - * @hw: pointer to the HW structure - * - * Updates adapter IFS. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -void igb_update_adaptive(struct e1000_hw *hw) -{ - igb_update_adaptive_generic(hw); -} - -/** - * igb_disable_pcie_master - Disable PCI-Express master access - * @hw: pointer to the HW structure - * - * Disables PCI-Express master access and verifies there are no pending - * requests. Currently no func pointer exists and all implementations are - * handled in the generic version of this function. - **/ -s32 igb_disable_pcie_master(struct e1000_hw *hw) -{ - return igb_disable_pcie_master_generic(hw); -} - -/** - * igb_config_collision_dist - Configure collision distance - * @hw: pointer to the HW structure - * - * Configures the collision distance to the default value and is used - * during link setup. - **/ -void igb_config_collision_dist(struct e1000_hw *hw) -{ - if (hw->mac.ops.config_collision_dist) - hw->mac.ops.config_collision_dist(hw); -} - -/** - * igb_rar_set - Sets a receive address register - * @hw: pointer to the HW structure - * @addr: address to set the RAR to - * @index: the RAR to set - * - * Sets a Receive Address Register (RAR) to the specified address. - **/ -void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) -{ - if (hw->mac.ops.rar_set) - hw->mac.ops.rar_set(hw, addr, index); -} - -/** - * igb_validate_mdi_setting - Ensures valid MDI/MDIX SW state - * @hw: pointer to the HW structure - * - * Ensures that the MDI/MDIX SW state is valid. - **/ -s32 igb_validate_mdi_setting(struct e1000_hw *hw) -{ - if (hw->mac.ops.validate_mdi_setting) - return hw->mac.ops.validate_mdi_setting(hw); - - return E1000_SUCCESS; -} - -/** - * igb_mta_set - Sets multicast table bit - * @hw: pointer to the HW structure - * @hash_value: Multicast hash value. - * - * This sets the bit in the multicast table corresponding to the - * hash value. This is a function pointer entry point called by drivers. - **/ -void igb_mta_set(struct e1000_hw *hw, u32 hash_value) -{ - if (hw->mac.ops.mta_set) - hw->mac.ops.mta_set(hw, hash_value); -} - -/** - * igb_hash_mc_addr - Determines address location in multicast table - * @hw: pointer to the HW structure - * @mc_addr: Multicast address to hash. - * - * This hashes an address to determine its location in the multicast - * table. Currently no func pointer exists and all implementations - * are handled in the generic version of this function. - **/ -u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr) -{ - return igb_hash_mc_addr_generic(hw, mc_addr); -} - -/** - * igb_enable_tx_pkt_filtering - Enable packet filtering on TX - * @hw: pointer to the HW structure - * - * Enables packet filtering on transmit packets if manageability is enabled - * and host interface is enabled. - * Currently no func pointer exists and all implementations are handled in the - * generic version of this function. - **/ -#if 0 -bool igb_enable_tx_pkt_filtering(struct e1000_hw *hw) -{ - return igb_enable_tx_pkt_filtering_generic(hw); -} -#endif - -/** - * igb_mng_host_if_write - Writes to the manageability host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface buffer - * @length: size of the buffer - * @offset: location in the buffer to write to - * @sum: sum of the data (not checksum) - * - * This function writes the buffer content at the offset given on the host if. - * It also does alignment considerations to do the writes in most efficient - * way. Also fills up the sum of the buffer in *buffer parameter. - **/ -s32 igb_mng_host_if_write(struct e1000_hw * hw, u8 *buffer, u16 length, - u16 offset, u8 *sum) -{ - if (hw->mac.ops.mng_host_if_write) - return hw->mac.ops.mng_host_if_write(hw, buffer, length, - offset, sum); - - return E1000_NOT_IMPLEMENTED; -} - -/** - * igb_mng_write_cmd_header - Writes manageability command header - * @hw: pointer to the HW structure - * @hdr: pointer to the host interface command header - * - * Writes the command header after does the checksum calculation. - **/ -s32 igb_mng_write_cmd_header(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr) -{ - if (hw->mac.ops.mng_write_cmd_header) - return hw->mac.ops.mng_write_cmd_header(hw, hdr); - - return E1000_NOT_IMPLEMENTED; -} - -/** - * igb_mng_enable_host_if - Checks host interface is enabled - * @hw: pointer to the HW structure - * - * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND - * - * This function checks whether the HOST IF is enabled for command operation - * and also checks whether the previous command is completed. It busy waits - * in case of previous command is not completed. - **/ -s32 igb_mng_enable_host_if(struct e1000_hw * hw) -{ - if (hw->mac.ops.mng_enable_host_if) - return hw->mac.ops.mng_enable_host_if(hw); - - return E1000_NOT_IMPLEMENTED; -} - -/** - * igb_wait_autoneg - Waits for autonegotiation completion - * @hw: pointer to the HW structure - * - * Waits for autoneg to complete. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -s32 igb_wait_autoneg(struct e1000_hw *hw) -{ - if (hw->mac.ops.wait_autoneg) - return hw->mac.ops.wait_autoneg(hw); - - return E1000_SUCCESS; -} - -/** - * igb_check_reset_block - Verifies PHY can be reset - * @hw: pointer to the HW structure - * - * Checks if the PHY is in a state that can be reset or if manageability - * has it tied up. This is a function pointer entry point called by drivers. - **/ -s32 igb_check_reset_block(struct e1000_hw *hw) -{ - if (hw->phy.ops.check_reset_block) - return hw->phy.ops.check_reset_block(hw); - - return E1000_SUCCESS; -} - -/** - * igb_read_phy_reg - Reads PHY register - * @hw: pointer to the HW structure - * @offset: the register to read - * @data: the buffer to store the 16-bit read. - * - * Reads the PHY register and returns the value in data. - * This is a function pointer entry point called by drivers. - **/ -s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data) -{ - if (hw->phy.ops.read_reg) - return hw->phy.ops.read_reg(hw, offset, data); - - return E1000_SUCCESS; -} - -/** - * igb_write_phy_reg - Writes PHY register - * @hw: pointer to the HW structure - * @offset: the register to write - * @data: the value to write. - * - * Writes the PHY register at offset with the value in data. - * This is a function pointer entry point called by drivers. - **/ -s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data) -{ - if (hw->phy.ops.write_reg) - return hw->phy.ops.write_reg(hw, offset, data); - - return E1000_SUCCESS; -} - -/** - * igb_release_phy - Generic release PHY - * @hw: pointer to the HW structure - * - * Return if silicon family does not require a semaphore when accessing the - * PHY. - **/ -void igb_release_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.release) - hw->phy.ops.release(hw); -} - -/** - * igb_acquire_phy - Generic acquire PHY - * @hw: pointer to the HW structure - * - * Return success if silicon family does not require a semaphore when - * accessing the PHY. - **/ -s32 igb_acquire_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.acquire) - return hw->phy.ops.acquire(hw); - - return E1000_SUCCESS; -} - -/** - * igb_read_kmrn_reg - Reads register using Kumeran interface - * @hw: pointer to the HW structure - * @offset: the register to read - * @data: the location to store the 16-bit value read. - * - * Reads a register out of the Kumeran interface. Currently no func pointer - * exists and all implementations are handled in the generic version of - * this function. - **/ -s32 igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return igb_read_kmrn_reg_generic(hw, offset, data); -} - -/** - * igb_write_kmrn_reg - Writes register using Kumeran interface - * @hw: pointer to the HW structure - * @offset: the register to write - * @data: the value to write. - * - * Writes a register to the Kumeran interface. Currently no func pointer - * exists and all implementations are handled in the generic version of - * this function. - **/ -s32 igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data) -{ - return igb_write_kmrn_reg_generic(hw, offset, data); -} - -#if 0 -/** - * igb_get_cable_length - Retrieves cable length estimation - * @hw: pointer to the HW structure - * - * This function estimates the cable length and stores them in - * hw->phy.min_length and hw->phy.max_length. This is a function pointer - * entry point called by drivers. - **/ -s32 igb_get_cable_length(struct e1000_hw *hw) -{ - if (hw->phy.ops.get_cable_length) - return hw->phy.ops.get_cable_length(hw); - - return E1000_SUCCESS; -} -#endif - -/** - * igb_get_phy_info - Retrieves PHY information from registers - * @hw: pointer to the HW structure - * - * This function gets some information from various PHY registers and - * populates hw->phy values with it. This is a function pointer entry - * point called by drivers. - **/ -s32 igb_get_phy_info(struct e1000_hw *hw) -{ - if (hw->phy.ops.get_info) - return hw->phy.ops.get_info(hw); - - return E1000_SUCCESS; -} - -/** - * igb_phy_hw_reset - Hard PHY reset - * @hw: pointer to the HW structure - * - * Performs a hard PHY reset. This is a function pointer entry point called - * by drivers. - **/ -s32 igb_phy_hw_reset(struct e1000_hw *hw) -{ - if (hw->phy.ops.reset) - return hw->phy.ops.reset(hw); - - return E1000_SUCCESS; -} - -/** - * igb_phy_commit - Soft PHY reset - * @hw: pointer to the HW structure - * - * Performs a soft PHY reset on those that apply. This is a function pointer - * entry point called by drivers. - **/ -s32 igb_phy_commit(struct e1000_hw *hw) -{ - if (hw->phy.ops.commit) - return hw->phy.ops.commit(hw); - - return E1000_SUCCESS; -} - -/** - * igb_set_d0_lplu_state - Sets low power link up state for D0 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D0 - * and SmartSpeed is disabled when active is true, else clear lplu for D0 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. This is a function pointer entry point called by drivers. - **/ -s32 igb_set_d0_lplu_state(struct e1000_hw *hw, bool active) -{ - if (hw->phy.ops.set_d0_lplu_state) - return hw->phy.ops.set_d0_lplu_state(hw, active); - - return E1000_SUCCESS; -} - -/** - * igb_set_d3_lplu_state - Sets low power link up state for D3 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D3 - * and SmartSpeed is disabled when active is true, else clear lplu for D3 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. This is a function pointer entry point called by drivers. - **/ -s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active) -{ - if (hw->phy.ops.set_d3_lplu_state) - return hw->phy.ops.set_d3_lplu_state(hw, active); - - return E1000_SUCCESS; -} - -/** - * igb_read_mac_addr - Reads MAC address - * @hw: pointer to the HW structure - * - * Reads the MAC address out of the adapter and stores it in the HW structure. - * Currently no func pointer exists and all implementations are handled in the - * generic version of this function. - **/ -s32 igb_read_mac_addr(struct e1000_hw *hw) -{ - if (hw->mac.ops.read_mac_addr) - return hw->mac.ops.read_mac_addr(hw); - - return igb_read_mac_addr_generic(hw); -} - -/** - * igb_read_pba_num - Read device part number - * @hw: pointer to the HW structure - * @pba_num: pointer to device part number - * - * Reads the product board assembly (PBA) number from the EEPROM and stores - * the value in pba_num. - * Currently no func pointer exists and all implementations are handled in the - * generic version of this function. - **/ -s32 igb_read_pba_num(struct e1000_hw *hw, u32 *pba_num) -{ - return igb_read_pba_num_generic(hw, pba_num); -} - -/** - * igb_validate_nvm_checksum - Verifies NVM (EEPROM) checksum - * @hw: pointer to the HW structure - * - * Validates the NVM checksum is correct. This is a function pointer entry - * point called by drivers. - **/ -s32 igb_validate_nvm_checksum(struct e1000_hw *hw) -{ - if (hw->nvm.ops.validate) - return hw->nvm.ops.validate(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_update_nvm_checksum - Updates NVM (EEPROM) checksum - * @hw: pointer to the HW structure - * - * Updates the NVM checksum. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -s32 igb_update_nvm_checksum(struct e1000_hw *hw) -{ - if (hw->nvm.ops.update) - return hw->nvm.ops.update(hw); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_reload_nvm - Reloads EEPROM - * @hw: pointer to the HW structure - * - * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the - * extended control register. - **/ -void igb_reload_nvm(struct e1000_hw *hw) -{ - if (hw->nvm.ops.reload) - hw->nvm.ops.reload(hw); -} - -/** - * igb_read_nvm - Reads NVM (EEPROM) - * @hw: pointer to the HW structure - * @offset: the word offset to read - * @words: number of 16-bit words to read - * @data: pointer to the properly sized buffer for the data. - * - * Reads 16-bit chunks of data from the NVM (EEPROM). This is a function - * pointer entry point called by drivers. - **/ -s32 igb_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - if (hw->nvm.ops.read) - return hw->nvm.ops.read(hw, offset, words, data); - - return -E1000_ERR_CONFIG; -} - -/** - * igb_write_nvm - Writes to NVM (EEPROM) - * @hw: pointer to the HW structure - * @offset: the word offset to read - * @words: number of 16-bit words to write - * @data: pointer to the properly sized buffer for the data. - * - * Writes 16-bit chunks of data to the NVM (EEPROM). This is a function - * pointer entry point called by drivers. - **/ -s32 igb_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - if (hw->nvm.ops.write) - return hw->nvm.ops.write(hw, offset, words, data); - - return E1000_SUCCESS; -} - -/** - * igb_write_8bit_ctrl_reg - Writes 8bit Control register - * @hw: pointer to the HW structure - * @reg: 32bit register offset - * @offset: the register to write - * @data: the value to write. - * - * Writes the PHY register at offset with the value in data. - * This is a function pointer entry point called by drivers. - **/ -s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, u32 offset, - u8 data) -{ - return igb_write_8bit_ctrl_reg_generic(hw, reg, offset, data); -} - -/** - * igb_power_up_phy - Restores link in case of PHY power down - * @hw: pointer to the HW structure - * - * The phy may be powered down to save power, to turn off link when the - * driver is unloaded, or wake on lan is not enabled (among others). - **/ -void igb_power_up_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.power_up) - hw->phy.ops.power_up(hw); - - igb_setup_link(hw); -} - -/** - * igb_power_down_phy - Power down PHY - * @hw: pointer to the HW structure - * - * The phy may be powered down to save power, to turn off link when the - * driver is unloaded, or wake on lan is not enabled (among others). - **/ -void igb_power_down_phy(struct e1000_hw *hw) -{ - if (hw->phy.ops.power_down) - hw->phy.ops.power_down(hw); -} - -/** - * igb_shutdown_fiber_serdes_link - Remove link during power down - * @hw: pointer to the HW structure - * - * Shutdown the optics and PCS on driver unload. - **/ -void igb_shutdown_fiber_serdes_link(struct e1000_hw *hw) -{ - if (hw->mac.ops.shutdown_serdes) - hw->mac.ops.shutdown_serdes(hw); -} - diff --git a/src/drivers/net/igb/igb_api.h b/src/drivers/net/igb/igb_api.h deleted file mode 100644 index 2d97fecc..00000000 --- a/src/drivers/net/igb/igb_api.h +++ /dev/null @@ -1,166 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_API_H_ -#define _IGB_API_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "igb_hw.h" - -extern void igb_init_function_pointers_82575(struct e1000_hw *hw) __attribute__((weak)); -extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw) __attribute__((weak)); -extern void igb_init_function_pointers_vf(struct e1000_hw *hw) __attribute__((weak)); -extern void igb_shutdown_fiber_serdes_link(struct e1000_hw *hw) __attribute__((weak)); - -s32 igb_set_mac_type(struct e1000_hw *hw); -s32 igb_setup_init_funcs(struct e1000_hw *hw, bool init_device); -s32 igb_init_mac_params(struct e1000_hw *hw); -s32 igb_init_nvm_params(struct e1000_hw *hw); -s32 igb_init_phy_params(struct e1000_hw *hw); -s32 igb_init_mbx_params(struct e1000_hw *hw); -s32 igb_get_bus_info(struct e1000_hw *hw); -void igb_clear_vfta(struct e1000_hw *hw); -void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value); -s32 igb_force_mac_fc(struct e1000_hw *hw); -s32 igb_check_for_link(struct e1000_hw *hw); -s32 igb_reset_hw(struct e1000_hw *hw); -s32 igb_init_hw(struct e1000_hw *hw); -s32 igb_setup_link(struct e1000_hw *hw); -s32 igb_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -s32 igb_disable_pcie_master(struct e1000_hw *hw); -void igb_config_collision_dist(struct e1000_hw *hw); -void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index); -void igb_mta_set(struct e1000_hw *hw, u32 hash_value); -u32 igb_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr); -void igb_update_mc_addr_list(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count); -s32 igb_setup_led(struct e1000_hw *hw); -s32 igb_cleanup_led(struct e1000_hw *hw); -s32 igb_check_reset_block(struct e1000_hw *hw); -s32 igb_blink_led(struct e1000_hw *hw); -s32 igb_led_on(struct e1000_hw *hw); -s32 igb_led_off(struct e1000_hw *hw); -s32 igb_id_led_init(struct e1000_hw *hw); -void igb_reset_adaptive(struct e1000_hw *hw); -void igb_update_adaptive(struct e1000_hw *hw); -#if 0 -s32 igb_get_cable_length(struct e1000_hw *hw); -#endif -s32 igb_validate_mdi_setting(struct e1000_hw *hw); -s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg, - u32 offset, u8 data); -s32 igb_get_phy_info(struct e1000_hw *hw); -void igb_release_phy(struct e1000_hw *hw); -s32 igb_acquire_phy(struct e1000_hw *hw); -s32 igb_phy_hw_reset(struct e1000_hw *hw); -s32 igb_phy_commit(struct e1000_hw *hw); -void igb_power_up_phy(struct e1000_hw *hw); -void igb_power_down_phy(struct e1000_hw *hw); -s32 igb_read_mac_addr(struct e1000_hw *hw); -s32 igb_read_pba_num(struct e1000_hw *hw, u32 *part_num); -void igb_reload_nvm(struct e1000_hw *hw); -s32 igb_update_nvm_checksum(struct e1000_hw *hw); -s32 igb_validate_nvm_checksum(struct e1000_hw *hw); -s32 igb_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); -s32 igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 igb_wait_autoneg(struct e1000_hw *hw); -s32 igb_set_d3_lplu_state(struct e1000_hw *hw, bool active); -s32 igb_set_d0_lplu_state(struct e1000_hw *hw, bool active); -bool igb_check_mng_mode(struct e1000_hw *hw); -bool igb_enable_tx_pkt_filtering(struct e1000_hw *hw); -s32 igb_mng_enable_host_if(struct e1000_hw *hw); -s32 igb_mng_host_if_write(struct e1000_hw *hw, - u8 *buffer, u16 length, u16 offset, u8 *sum); -s32 igb_mng_write_cmd_header(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr); -s32 igb_mng_write_dhcp_info(struct e1000_hw * hw, - u8 *buffer, u16 length); - -/* - * TBI_ACCEPT macro definition: - * - * This macro requires: - * adapter = a pointer to struct e1000_hw - * status = the 8 bit status field of the Rx descriptor with EOP set - * error = the 8 bit error field of the Rx descriptor with EOP set - * length = the sum of all the length fields of the Rx descriptors that - * make up the current frame - * last_byte = the last byte of the frame DMAed by the hardware - * max_frame_length = the maximum frame length we want to accept. - * min_frame_length = the minimum frame length we want to accept. - * - * This macro is a conditional that should be used in the interrupt - * handler's Rx processing routine when RxErrors have been detected. - * - * Typical use: - * ... - * if (TBI_ACCEPT) { - * accept_frame = true; - * e1000_tbi_adjust_stats(adapter, MacAddress); - * frame_length--; - * } else { - * accept_frame = false; - * } - * ... - */ - -/* The carrier extension symbol, as received by the NIC. */ -#define CARRIER_EXTENSION 0x0F - -#define TBI_ACCEPT(a, status, errors, length, last_byte, min_frame_size, max_frame_size) \ - (e1000_tbi_sbp_enabled_82543(a) && \ - (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \ - ((last_byte) == CARRIER_EXTENSION) && \ - (((status) & E1000_RXD_STAT_VP) ? \ - (((length) > (min_frame_size - VLAN_TAG_SIZE)) && \ - ((length) <= (max_frame_size + 1))) : \ - (((length) > min_frame_size) && \ - ((length) <= (max_frame_size + VLAN_TAG_SIZE + 1))))) - -#endif /* _IGB_API_H_ */ diff --git a/src/drivers/net/igb/igb_defines.h b/src/drivers/net/igb/igb_defines.h deleted file mode 100644 index 4f58ba83..00000000 --- a/src/drivers/net/igb/igb_defines.h +++ /dev/null @@ -1,1515 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_DEFINES_H_ -#define _IGB_DEFINES_H_ - -/* Number of Transmit and Receive Descriptors must be a multiple of 8 */ -#define REQ_TX_DESCRIPTOR_MULTIPLE 8 -#define REQ_RX_DESCRIPTOR_MULTIPLE 8 - -/* Definitions for power management and wakeup registers */ -/* Wake Up Control */ -#define E1000_WUC_APME 0x00000001 /* APM Enable */ -#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ -#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ -#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ -#define E1000_WUC_LSCWE 0x00000010 /* Link Status wake up enable */ -#define E1000_WUC_LSCWO 0x00000020 /* Link Status wake up override */ -#define E1000_WUC_SPM 0x80000000 /* Enable SPM */ -#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ - -/* Wake Up Filter Control */ -#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ -#define E1000_WUFC_MAG 0x00000002 /* Magic Packet Wakeup Enable */ -#define E1000_WUFC_EX 0x00000004 /* Directed Exact Wakeup Enable */ -#define E1000_WUFC_MC 0x00000008 /* Directed Multicast Wakeup Enable */ -#define E1000_WUFC_BC 0x00000010 /* Broadcast Wakeup Enable */ -#define E1000_WUFC_ARP 0x00000020 /* ARP Request Packet Wakeup Enable */ -#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */ -#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */ -#define E1000_WUFC_IGNORE_TCO 0x00008000 /* Ignore WakeOn TCO packets */ -#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */ -#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */ -#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */ -#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */ -#define E1000_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */ -#define E1000_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */ -#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */ -#define E1000_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */ -#define E1000_WUFC_FLX_FILTERS 0x000F0000 /*Mask for the 4 flexible filters */ -/* - * For 82576 to utilize Extended filter masks in addition to - * existing (filter) masks - */ -#define E1000_WUFC_EXT_FLX_FILTERS 0x00300000 /* Ext. FLX filter mask */ - -/* Wake Up Status */ -#define E1000_WUS_LNKC E1000_WUFC_LNKC -#define E1000_WUS_MAG E1000_WUFC_MAG -#define E1000_WUS_EX E1000_WUFC_EX -#define E1000_WUS_MC E1000_WUFC_MC -#define E1000_WUS_BC E1000_WUFC_BC -#define E1000_WUS_ARP E1000_WUFC_ARP -#define E1000_WUS_IPV4 E1000_WUFC_IPV4 -#define E1000_WUS_IPV6 E1000_WUFC_IPV6 -#define E1000_WUS_FLX0 E1000_WUFC_FLX0 -#define E1000_WUS_FLX1 E1000_WUFC_FLX1 -#define E1000_WUS_FLX2 E1000_WUFC_FLX2 -#define E1000_WUS_FLX3 E1000_WUFC_FLX3 -#define E1000_WUS_FLX_FILTERS E1000_WUFC_FLX_FILTERS - -/* Wake Up Packet Length */ -#define E1000_WUPL_LENGTH_MASK 0x0FFF /* Only the lower 12 bits are valid */ - -/* Four Flexible Filters are supported */ -#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4 -/* Two Extended Flexible Filters are supported (82576) */ -#define E1000_EXT_FLEXIBLE_FILTER_COUNT_MAX 2 -#define E1000_FHFT_LENGTH_OFFSET 0xFC /* Length byte in FHFT */ -#define E1000_FHFT_LENGTH_MASK 0x0FF /* Length in lower byte */ - -/* Each Flexible Filter is at most 128 (0x80) bytes in length */ -#define E1000_FLEXIBLE_FILTER_SIZE_MAX 128 - -#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX -#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX -#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX - -/* Extended Device Control */ -#define E1000_CTRL_EXT_GPI0_EN 0x00000001 /* Maps SDP4 to GPI0 */ -#define E1000_CTRL_EXT_GPI1_EN 0x00000002 /* Maps SDP5 to GPI1 */ -#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN -#define E1000_CTRL_EXT_GPI2_EN 0x00000004 /* Maps SDP6 to GPI2 */ -#define E1000_CTRL_EXT_GPI3_EN 0x00000008 /* Maps SDP7 to GPI3 */ -/* Reserved (bits 4,5) in >= 82575 */ -#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Definable Pin 4 */ -#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Definable Pin 5 */ -#define E1000_CTRL_EXT_PHY_INT E1000_CTRL_EXT_SDP5_DATA -#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Definable Pin 6 */ -#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */ -/* SDP 4/5 (bits 8,9) are reserved in >= 82575 */ -#define E1000_CTRL_EXT_SDP4_DIR 0x00000100 /* Direction of SDP4 0=in 1=out */ -#define E1000_CTRL_EXT_SDP5_DIR 0x00000200 /* Direction of SDP5 0=in 1=out */ -#define E1000_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ -#define E1000_CTRL_EXT_SDP3_DIR 0x00000800 /* Direction of SDP3 0=in 1=out */ -#define E1000_CTRL_EXT_ASDCHK 0x00001000 /* Initiate an ASD sequence */ -#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */ -#define E1000_CTRL_EXT_IPS 0x00004000 /* Invert Power State */ -/* Physical Func Reset Done Indication */ -#define E1000_CTRL_EXT_PFRSTD 0x00004000 -#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */ -#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */ -#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clock Gating */ -#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 -#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 -#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 -#define E1000_CTRL_EXT_LINK_MODE_PCIX_SERDES 0x00800000 -#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000 -#define E1000_CTRL_EXT_EIAME 0x01000000 -#define E1000_CTRL_EXT_IRCA 0x00000001 -#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 -#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 -#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 -#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000 -#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000 -#define E1000_CTRL_EXT_CANC 0x04000000 /* Int delay cancellation */ -#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ -/* IAME enable bit (27) was removed in >= 82575 */ -#define E1000_CTRL_EXT_IAME 0x08000000 /* Int acknowledge Auto-mask */ -#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error - * detection enabled */ -#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity - * error detection enable */ -#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 -#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */ -#define E1000_I2CCMD_REG_ADDR_SHIFT 16 -#define E1000_I2CCMD_REG_ADDR 0x00FF0000 -#define E1000_I2CCMD_PHY_ADDR_SHIFT 24 -#define E1000_I2CCMD_PHY_ADDR 0x07000000 -#define E1000_I2CCMD_OPCODE_READ 0x08000000 -#define E1000_I2CCMD_OPCODE_WRITE 0x00000000 -#define E1000_I2CCMD_RESET 0x10000000 -#define E1000_I2CCMD_READY 0x20000000 -#define E1000_I2CCMD_INTERRUPT_ENA 0x40000000 -#define E1000_I2CCMD_ERROR 0x80000000 -#define E1000_MAX_SGMII_PHY_REG_ADDR 255 -#define E1000_I2CCMD_PHY_TIMEOUT 200 -#define E1000_IVAR_VALID 0x80 -#define E1000_GPIE_NSICR 0x00000001 -#define E1000_GPIE_MSIX_MODE 0x00000010 -#define E1000_GPIE_EIAME 0x40000000 -#define E1000_GPIE_PBA 0x80000000 - -/* Receive Descriptor bit definitions */ -#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */ -#define E1000_RXD_STAT_EOP 0x02 /* End of Packet */ -#define E1000_RXD_STAT_IXSM 0x04 /* Ignore checksum */ -#define E1000_RXD_STAT_VP 0x08 /* IEEE VLAN Packet */ -#define E1000_RXD_STAT_UDPCS 0x10 /* UDP xsum calculated */ -#define E1000_RXD_STAT_TCPCS 0x20 /* TCP xsum calculated */ -#define E1000_RXD_STAT_IPCS 0x40 /* IP xsum calculated */ -#define E1000_RXD_STAT_PIF 0x80 /* passed in-exact filter */ -#define E1000_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */ -#define E1000_RXD_STAT_IPIDV 0x200 /* IP identification valid */ -#define E1000_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */ -#define E1000_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */ -#define E1000_RXD_STAT_ACK 0x8000 /* ACK Packet indication */ -#define E1000_RXD_ERR_CE 0x01 /* CRC Error */ -#define E1000_RXD_ERR_SE 0x02 /* Symbol Error */ -#define E1000_RXD_ERR_SEQ 0x04 /* Sequence Error */ -#define E1000_RXD_ERR_CXE 0x10 /* Carrier Extension Error */ -#define E1000_RXD_ERR_TCPE 0x20 /* TCP/UDP Checksum Error */ -#define E1000_RXD_ERR_IPE 0x40 /* IP Checksum Error */ -#define E1000_RXD_ERR_RXE 0x80 /* Rx Data Error */ -#define E1000_RXD_SPC_VLAN_MASK 0x0FFF /* VLAN ID is in lower 12 bits */ -#define E1000_RXD_SPC_PRI_MASK 0xE000 /* Priority is in upper 3 bits */ -#define E1000_RXD_SPC_PRI_SHIFT 13 -#define E1000_RXD_SPC_CFI_MASK 0x1000 /* CFI is bit 12 */ -#define E1000_RXD_SPC_CFI_SHIFT 12 - -#define E1000_RXDEXT_STATERR_CE 0x01000000 -#define E1000_RXDEXT_STATERR_SE 0x02000000 -#define E1000_RXDEXT_STATERR_SEQ 0x04000000 -#define E1000_RXDEXT_STATERR_CXE 0x10000000 -#define E1000_RXDEXT_STATERR_TCPE 0x20000000 -#define E1000_RXDEXT_STATERR_IPE 0x40000000 -#define E1000_RXDEXT_STATERR_RXE 0x80000000 - -/* mask to determine if packets should be dropped due to frame errors */ -#define E1000_RXD_ERR_FRAME_ERR_MASK ( \ - E1000_RXD_ERR_CE | \ - E1000_RXD_ERR_SE | \ - E1000_RXD_ERR_SEQ | \ - E1000_RXD_ERR_CXE | \ - E1000_RXD_ERR_RXE) - -/* Same mask, but for extended and packet split descriptors */ -#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \ - E1000_RXDEXT_STATERR_CE | \ - E1000_RXDEXT_STATERR_SE | \ - E1000_RXDEXT_STATERR_SEQ | \ - E1000_RXDEXT_STATERR_CXE | \ - E1000_RXDEXT_STATERR_RXE) - -#define E1000_MRQC_ENABLE_MASK 0x00000007 -#define E1000_MRQC_ENABLE_RSS_2Q 0x00000001 -#define E1000_MRQC_ENABLE_RSS_INT 0x00000004 -#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 -#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 -#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 -#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 -#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 -#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 -#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 - -#define E1000_RXDPS_HDRSTAT_HDRSP 0x00008000 -#define E1000_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF - -/* Management Control */ -#define E1000_MANC_SMBUS_EN 0x00000001 /* SMBus Enabled - RO */ -#define E1000_MANC_ASF_EN 0x00000002 /* ASF Enabled - RO */ -#define E1000_MANC_R_ON_FORCE 0x00000004 /* Reset on Force TCO - RO */ -#define E1000_MANC_RMCP_EN 0x00000100 /* Enable RCMP 026Fh Filtering */ -#define E1000_MANC_0298_EN 0x00000200 /* Enable RCMP 0298h Filtering */ -#define E1000_MANC_IPV4_EN 0x00000400 /* Enable IPv4 */ -#define E1000_MANC_IPV6_EN 0x00000800 /* Enable IPv6 */ -#define E1000_MANC_SNAP_EN 0x00001000 /* Accept LLC/SNAP */ -#define E1000_MANC_ARP_EN 0x00002000 /* Enable ARP Request Filtering */ -/* Enable Neighbor Discovery Filtering */ -#define E1000_MANC_NEIGHBOR_EN 0x00004000 -#define E1000_MANC_ARP_RES_EN 0x00008000 /* Enable ARP response Filtering */ -#define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ -#define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ -#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ -#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ -#define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ -/* Enable MAC address filtering */ -#define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 -/* Enable MNG packets to host memory */ -#define E1000_MANC_EN_MNG2HOST 0x00200000 -/* Enable IP address filtering */ -#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 -#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */ -#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */ -#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */ -#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */ -#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */ -#define E1000_MANC_SMB_DATA_IN 0x08000000 /* SMBus Data In */ -#define E1000_MANC_SMB_DATA_OUT 0x10000000 /* SMBus Data Out */ -#define E1000_MANC_SMB_CLK_OUT 0x20000000 /* SMBus Clock Out */ - -#define E1000_MANC_SMB_DATA_OUT_SHIFT 28 /* SMBus Data Out Shift */ -#define E1000_MANC_SMB_CLK_OUT_SHIFT 29 /* SMBus Clock Out Shift */ - -/* Receive Control */ -#define E1000_RCTL_RST 0x00000001 /* Software reset */ -#define E1000_RCTL_EN 0x00000002 /* enable */ -#define E1000_RCTL_SBP 0x00000004 /* store bad packet */ -#define E1000_RCTL_UPE 0x00000008 /* unicast promisc enable */ -#define E1000_RCTL_MPE 0x00000010 /* multicast promisc enable */ -#define E1000_RCTL_LPE 0x00000020 /* long packet enable */ -#define E1000_RCTL_LBM_NO 0x00000000 /* no loopback mode */ -#define E1000_RCTL_LBM_MAC 0x00000040 /* MAC loopback mode */ -#define E1000_RCTL_LBM_SLP 0x00000080 /* serial link loopback mode */ -#define E1000_RCTL_LBM_TCVR 0x000000C0 /* tcvr loopback mode */ -#define E1000_RCTL_DTYP_MASK 0x00000C00 /* Descriptor type mask */ -#define E1000_RCTL_DTYP_PS 0x00000400 /* Packet Split descriptor */ -#define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min thresh size */ -#define E1000_RCTL_RDMTS_QUAT 0x00000100 /* rx desc min thresh size */ -#define E1000_RCTL_RDMTS_EIGTH 0x00000200 /* rx desc min thresh size */ -#define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ -#define E1000_RCTL_MO_0 0x00000000 /* multicast offset 11:0 */ -#define E1000_RCTL_MO_1 0x00001000 /* multicast offset 12:1 */ -#define E1000_RCTL_MO_2 0x00002000 /* multicast offset 13:2 */ -#define E1000_RCTL_MO_3 0x00003000 /* multicast offset 15:4 */ -#define E1000_RCTL_MDR 0x00004000 /* multicast desc ring 0 */ -#define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ -#define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ -#define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ -#define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ -#define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ -#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ -#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ -#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ -#define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ -#define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ -#define E1000_RCTL_CFI 0x00100000 /* canonical form indicator */ -#define E1000_RCTL_DPF 0x00400000 /* discard pause frames */ -#define E1000_RCTL_PMCF 0x00800000 /* pass MAC control frames */ -#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ -#define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ -#define E1000_RCTL_FLXBUF_MASK 0x78000000 /* Flexible buffer size */ -#define E1000_RCTL_FLXBUF_SHIFT 27 /* Flexible buffer shift */ - -/* - * Use byte values for the following shift parameters - * Usage: - * psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) & - * E1000_PSRCTL_BSIZE0_MASK) | - * ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) & - * E1000_PSRCTL_BSIZE1_MASK) | - * ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) & - * E1000_PSRCTL_BSIZE2_MASK) | - * ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |; - * E1000_PSRCTL_BSIZE3_MASK)) - * where value0 = [128..16256], default=256 - * value1 = [1024..64512], default=4096 - * value2 = [0..64512], default=4096 - * value3 = [0..64512], default=0 - */ - -#define E1000_PSRCTL_BSIZE0_MASK 0x0000007F -#define E1000_PSRCTL_BSIZE1_MASK 0x00003F00 -#define E1000_PSRCTL_BSIZE2_MASK 0x003F0000 -#define E1000_PSRCTL_BSIZE3_MASK 0x3F000000 - -#define E1000_PSRCTL_BSIZE0_SHIFT 7 /* Shift _right_ 7 */ -#define E1000_PSRCTL_BSIZE1_SHIFT 2 /* Shift _right_ 2 */ -#define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ -#define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ - -/* SWFW_SYNC Definitions */ -#define E1000_SWFW_EEP_SM 0x01 -#define E1000_SWFW_PHY0_SM 0x02 -#define E1000_SWFW_PHY1_SM 0x04 -#define E1000_SWFW_CSR_SM 0x08 - -/* FACTPS Definitions */ -#define E1000_FACTPS_LFS 0x40000000 /* LAN Function Select */ -/* Device Control */ -#define E1000_CTRL_FD 0x00000001 /* Full duplex.0=half; 1=full */ -#define E1000_CTRL_BEM 0x00000002 /* Endian Mode.0=little,1=big */ -#define E1000_CTRL_PRIOR 0x00000004 /* Priority on PCI. 0=rx,1=fair */ -#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master reqs */ -#define E1000_CTRL_LRST 0x00000008 /* Link reset. 0=normal,1=reset */ -#define E1000_CTRL_TME 0x00000010 /* Test mode. 0=normal,1=test */ -#define E1000_CTRL_SLE 0x00000020 /* Serial Link on 0=dis,1=en */ -#define E1000_CTRL_ASDE 0x00000020 /* Auto-speed detect enable */ -#define E1000_CTRL_SLU 0x00000040 /* Set link up (Force Link) */ -#define E1000_CTRL_ILOS 0x00000080 /* Invert Loss-Of Signal */ -#define E1000_CTRL_SPD_SEL 0x00000300 /* Speed Select Mask */ -#define E1000_CTRL_SPD_10 0x00000000 /* Force 10Mb */ -#define E1000_CTRL_SPD_100 0x00000100 /* Force 100Mb */ -#define E1000_CTRL_SPD_1000 0x00000200 /* Force 1Gb */ -#define E1000_CTRL_BEM32 0x00000400 /* Big Endian 32 mode */ -#define E1000_CTRL_FRCSPD 0x00000800 /* Force Speed */ -#define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ -#define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ -#define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock - * indication in SDP[0] */ -#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through - * PHYRST_N pin */ -#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external - * LINK_0 and LINK_1 pins */ -#define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ -#define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ -#define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ -#define E1000_CTRL_ADVD3WUC 0x00100000 /* D3 WUC */ -#define E1000_CTRL_SWDPIN3 0x00200000 /* SWDPIN 3 value */ -#define E1000_CTRL_SWDPIO0 0x00400000 /* SWDPIN 0 Input or output */ -#define E1000_CTRL_SWDPIO1 0x00800000 /* SWDPIN 1 input or output */ -#define E1000_CTRL_SWDPIO2 0x01000000 /* SWDPIN 2 input or output */ -#define E1000_CTRL_SWDPIO3 0x02000000 /* SWDPIN 3 input or output */ -#define E1000_CTRL_RST 0x04000000 /* Global reset */ -#define E1000_CTRL_RFCE 0x08000000 /* Receive Flow Control enable */ -#define E1000_CTRL_TFCE 0x10000000 /* Transmit flow control enable */ -#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */ -#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */ -#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */ -#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to ME */ -#define E1000_CTRL_I2C_ENA 0x02000000 /* I2C enable */ - -/* - * Bit definitions for the Management Data IO (MDIO) and Management Data - * Clock (MDC) pins in the Device Control Register. - */ -#define E1000_CTRL_PHY_RESET_DIR E1000_CTRL_SWDPIO0 -#define E1000_CTRL_PHY_RESET E1000_CTRL_SWDPIN0 -#define E1000_CTRL_MDIO_DIR E1000_CTRL_SWDPIO2 -#define E1000_CTRL_MDIO E1000_CTRL_SWDPIN2 -#define E1000_CTRL_MDC_DIR E1000_CTRL_SWDPIO3 -#define E1000_CTRL_MDC E1000_CTRL_SWDPIN3 -#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR -#define E1000_CTRL_PHY_RESET4 E1000_CTRL_EXT_SDP4_DATA - -#define E1000_CONNSW_ENRGSRC 0x4 -#define E1000_PCS_CFG_PCS_EN 8 -#define E1000_PCS_LCTL_FLV_LINK_UP 1 -#define E1000_PCS_LCTL_FSV_10 0 -#define E1000_PCS_LCTL_FSV_100 2 -#define E1000_PCS_LCTL_FSV_1000 4 -#define E1000_PCS_LCTL_FDV_FULL 8 -#define E1000_PCS_LCTL_FSD 0x10 -#define E1000_PCS_LCTL_FORCE_LINK 0x20 -#define E1000_PCS_LCTL_LOW_LINK_LATCH 0x40 -#define E1000_PCS_LCTL_FORCE_FCTRL 0x80 -#define E1000_PCS_LCTL_AN_ENABLE 0x10000 -#define E1000_PCS_LCTL_AN_RESTART 0x20000 -#define E1000_PCS_LCTL_AN_TIMEOUT 0x40000 -#define E1000_PCS_LCTL_AN_SGMII_BYPASS 0x80000 -#define E1000_PCS_LCTL_AN_SGMII_TRIGGER 0x100000 -#define E1000_PCS_LCTL_FAST_LINK_TIMER 0x1000000 -#define E1000_PCS_LCTL_LINK_OK_FIX 0x2000000 -#define E1000_PCS_LCTL_CRS_ON_NI 0x4000000 -#define E1000_ENABLE_SERDES_LOOPBACK 0x0410 - -#define E1000_PCS_LSTS_LINK_OK 1 -#define E1000_PCS_LSTS_SPEED_10 0 -#define E1000_PCS_LSTS_SPEED_100 2 -#define E1000_PCS_LSTS_SPEED_1000 4 -#define E1000_PCS_LSTS_DUPLEX_FULL 8 -#define E1000_PCS_LSTS_SYNK_OK 0x10 -#define E1000_PCS_LSTS_AN_COMPLETE 0x10000 -#define E1000_PCS_LSTS_AN_PAGE_RX 0x20000 -#define E1000_PCS_LSTS_AN_TIMED_OUT 0x40000 -#define E1000_PCS_LSTS_AN_REMOTE_FAULT 0x80000 -#define E1000_PCS_LSTS_AN_ERROR_RWS 0x100000 - -/* Device Status */ -#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */ -#define E1000_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ -#define E1000_STATUS_FUNC_MASK 0x0000000C /* PCI Function Mask */ -#define E1000_STATUS_FUNC_SHIFT 2 -#define E1000_STATUS_FUNC_0 0x00000000 /* Function 0 */ -#define E1000_STATUS_FUNC_1 0x00000004 /* Function 1 */ -#define E1000_STATUS_TXOFF 0x00000010 /* transmission paused */ -#define E1000_STATUS_TBIMODE 0x00000020 /* TBI mode */ -#define E1000_STATUS_SPEED_MASK 0x000000C0 -#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */ -#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */ -#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */ -#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion by NVM */ -#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */ -#define E1000_STATUS_PHYRA 0x00000400 /* PHY Reset Asserted */ -#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. - * Clear on write '0'. */ -#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Master request status */ -#define E1000_STATUS_MTXCKOK 0x00000400 /* MTX clock running OK */ -#define E1000_STATUS_PCI66 0x00000800 /* In 66Mhz slot */ -#define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ -#define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ -#define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ -#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ -#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ -#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ -#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ -#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution - * disabled */ -#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ -#define E1000_STATUS_FUSE_8 0x04000000 -#define E1000_STATUS_FUSE_9 0x08000000 -#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ -#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ - -/* Constants used to interpret the masked PCI-X bus speed. */ -#define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ -#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed 66-100 MHz */ -#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /*PCI-X bus speed 100-133 MHz*/ - -#define SPEED_10 10 -#define SPEED_100 100 -#define SPEED_1000 1000 -#define HALF_DUPLEX 1 -#define FULL_DUPLEX 2 - -#define PHY_FORCE_TIME 20 - -#define ADVERTISE_10_HALF 0x0001 -#define ADVERTISE_10_FULL 0x0002 -#define ADVERTISE_100_HALF 0x0004 -#define ADVERTISE_100_FULL 0x0008 -#define ADVERTISE_1000_HALF 0x0010 /* Not used, just FYI */ -#define ADVERTISE_1000_FULL 0x0020 - -/* 1000/H is not supported, nor spec-compliant. */ -#define E1000_ALL_SPEED_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ - ADVERTISE_100_HALF | ADVERTISE_100_FULL | \ - ADVERTISE_1000_FULL) -#define E1000_ALL_NOT_GIG (ADVERTISE_10_HALF | ADVERTISE_10_FULL | \ - ADVERTISE_100_HALF | ADVERTISE_100_FULL) -#define E1000_ALL_100_SPEED (ADVERTISE_100_HALF | ADVERTISE_100_FULL) -#define E1000_ALL_10_SPEED (ADVERTISE_10_HALF | ADVERTISE_10_FULL) -#define E1000_ALL_FULL_DUPLEX (ADVERTISE_10_FULL | ADVERTISE_100_FULL | \ - ADVERTISE_1000_FULL) -#define E1000_ALL_HALF_DUPLEX (ADVERTISE_10_HALF | ADVERTISE_100_HALF) - -#define AUTONEG_ADVERTISE_SPEED_DEFAULT E1000_ALL_SPEED_DUPLEX - -/* LED Control */ -#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F -#define E1000_LEDCTL_LED0_MODE_SHIFT 0 -#define E1000_LEDCTL_LED0_BLINK_RATE 0x00000020 -#define E1000_LEDCTL_LED0_IVRT 0x00000040 -#define E1000_LEDCTL_LED0_BLINK 0x00000080 -#define E1000_LEDCTL_LED1_MODE_MASK 0x00000F00 -#define E1000_LEDCTL_LED1_MODE_SHIFT 8 -#define E1000_LEDCTL_LED1_BLINK_RATE 0x00002000 -#define E1000_LEDCTL_LED1_IVRT 0x00004000 -#define E1000_LEDCTL_LED1_BLINK 0x00008000 -#define E1000_LEDCTL_LED2_MODE_MASK 0x000F0000 -#define E1000_LEDCTL_LED2_MODE_SHIFT 16 -#define E1000_LEDCTL_LED2_BLINK_RATE 0x00200000 -#define E1000_LEDCTL_LED2_IVRT 0x00400000 -#define E1000_LEDCTL_LED2_BLINK 0x00800000 -#define E1000_LEDCTL_LED3_MODE_MASK 0x0F000000 -#define E1000_LEDCTL_LED3_MODE_SHIFT 24 -#define E1000_LEDCTL_LED3_BLINK_RATE 0x20000000 -#define E1000_LEDCTL_LED3_IVRT 0x40000000 -#define E1000_LEDCTL_LED3_BLINK 0x80000000 - -#define E1000_LEDCTL_MODE_LINK_10_1000 0x0 -#define E1000_LEDCTL_MODE_LINK_100_1000 0x1 -#define E1000_LEDCTL_MODE_LINK_UP 0x2 -#define E1000_LEDCTL_MODE_ACTIVITY 0x3 -#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4 -#define E1000_LEDCTL_MODE_LINK_10 0x5 -#define E1000_LEDCTL_MODE_LINK_100 0x6 -#define E1000_LEDCTL_MODE_LINK_1000 0x7 -#define E1000_LEDCTL_MODE_PCIX_MODE 0x8 -#define E1000_LEDCTL_MODE_FULL_DUPLEX 0x9 -#define E1000_LEDCTL_MODE_COLLISION 0xA -#define E1000_LEDCTL_MODE_BUS_SPEED 0xB -#define E1000_LEDCTL_MODE_BUS_SIZE 0xC -#define E1000_LEDCTL_MODE_PAUSED 0xD -#define E1000_LEDCTL_MODE_LED_ON 0xE -#define E1000_LEDCTL_MODE_LED_OFF 0xF - -/* Transmit Descriptor bit definitions */ -#define E1000_TXD_DTYP_D 0x00100000 /* Data Descriptor */ -#define E1000_TXD_DTYP_C 0x00000000 /* Context Descriptor */ -#define E1000_TXD_POPTS_SHIFT 8 /* POPTS shift */ -#define E1000_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ -#define E1000_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ -#define E1000_TXD_CMD_EOP 0x01000000 /* End of Packet */ -#define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ -#define E1000_TXD_CMD_IC 0x04000000 /* Insert Checksum */ -#define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ -#define E1000_TXD_CMD_RPS 0x10000000 /* Report Packet Sent */ -#define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ -#define E1000_TXD_CMD_VLE 0x40000000 /* Add VLAN tag */ -#define E1000_TXD_CMD_IDE 0x80000000 /* Enable Tidv register */ -#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ -#define E1000_TXD_STAT_EC 0x00000002 /* Excess Collisions */ -#define E1000_TXD_STAT_LC 0x00000004 /* Late Collisions */ -#define E1000_TXD_STAT_TU 0x00000008 /* Transmit underrun */ -#define E1000_TXD_CMD_TCP 0x01000000 /* TCP packet */ -#define E1000_TXD_CMD_IP 0x02000000 /* IP packet */ -#define E1000_TXD_CMD_TSE 0x04000000 /* TCP Seg enable */ -#define E1000_TXD_STAT_TC 0x00000004 /* Tx Underrun */ -/* Extended desc bits for Linksec and timesync */ - -/* Transmit Control */ -#define E1000_TCTL_RST 0x00000001 /* software reset */ -#define E1000_TCTL_EN 0x00000002 /* enable tx */ -#define E1000_TCTL_BCE 0x00000004 /* busy check enable */ -#define E1000_TCTL_PSP 0x00000008 /* pad short packets */ -#define E1000_TCTL_CT 0x00000ff0 /* collision threshold */ -#define E1000_TCTL_COLD 0x003ff000 /* collision distance */ -#define E1000_TCTL_SWXOFF 0x00400000 /* SW Xoff transmission */ -#define E1000_TCTL_PBE 0x00800000 /* Packet Burst Enable */ -#define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ -#define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ -#define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ - -/* Transmit Arbitration Count */ -#define E1000_TARC0_ENABLE 0x00000400 /* Enable Tx Queue 0 */ - -/* SerDes Control */ -#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400 - -/* Receive Checksum Control */ -#define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ -#define E1000_RXCSUM_IPOFL 0x00000100 /* IPv4 checksum offload */ -#define E1000_RXCSUM_TUOFL 0x00000200 /* TCP / UDP checksum offload */ -#define E1000_RXCSUM_IPV6OFL 0x00000400 /* IPv6 checksum offload */ -#define E1000_RXCSUM_CRCOFL 0x00000800 /* CRC32 offload enable */ -#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */ -#define E1000_RXCSUM_PCSD 0x00002000 /* packet checksum disabled */ - -/* Header split receive */ -#define E1000_RFCTL_ISCSI_DIS 0x00000001 -#define E1000_RFCTL_ISCSI_DWC_MASK 0x0000003E -#define E1000_RFCTL_ISCSI_DWC_SHIFT 1 -#define E1000_RFCTL_NFSW_DIS 0x00000040 -#define E1000_RFCTL_NFSR_DIS 0x00000080 -#define E1000_RFCTL_NFS_VER_MASK 0x00000300 -#define E1000_RFCTL_NFS_VER_SHIFT 8 -#define E1000_RFCTL_IPV6_DIS 0x00000400 -#define E1000_RFCTL_IPV6_XSUM_DIS 0x00000800 -#define E1000_RFCTL_ACK_DIS 0x00001000 -#define E1000_RFCTL_ACKD_DIS 0x00002000 -#define E1000_RFCTL_IPFRSP_DIS 0x00004000 -#define E1000_RFCTL_EXTEN 0x00008000 -#define E1000_RFCTL_IPV6_EX_DIS 0x00010000 -#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000 -#define E1000_RFCTL_LEF 0x00040000 - -/* Collision related configuration parameters */ -#define E1000_COLLISION_THRESHOLD 15 -#define E1000_CT_SHIFT 4 -#define E1000_COLLISION_DISTANCE 63 -#define E1000_COLD_SHIFT 12 - -/* Default values for the transmit IPG register */ -#define DEFAULT_82543_TIPG_IPGT_FIBER 9 -#define DEFAULT_82543_TIPG_IPGT_COPPER 8 - -#define E1000_TIPG_IPGT_MASK 0x000003FF -#define E1000_TIPG_IPGR1_MASK 0x000FFC00 -#define E1000_TIPG_IPGR2_MASK 0x3FF00000 - -#define DEFAULT_82543_TIPG_IPGR1 8 -#define E1000_TIPG_IPGR1_SHIFT 10 - -#define DEFAULT_82543_TIPG_IPGR2 6 -#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 -#define E1000_TIPG_IPGR2_SHIFT 20 - -/* Ethertype field values */ -#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */ - -#define ETHERNET_FCS_SIZE 4 -#define MAX_JUMBO_FRAME_SIZE 0x3F00 - -/* Extended Configuration Control and Size */ -#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020 -#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 -#define E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE 0x00000008 -#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 -#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK 0x00FF0000 -#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT 16 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK 0x0FFF0000 -#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT 16 - -#define E1000_PHY_CTRL_SPD_EN 0x00000001 -#define E1000_PHY_CTRL_D0A_LPLU 0x00000002 -#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004 -#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008 -#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040 - -#define E1000_KABGTXD_BGSQLBIAS 0x00050000 - -/* PBA constants */ -#define E1000_PBA_6K 0x0006 /* 6KB */ -#define E1000_PBA_8K 0x0008 /* 8KB */ -#define E1000_PBA_10K 0x000A /* 10KB */ -#define E1000_PBA_12K 0x000C /* 12KB */ -#define E1000_PBA_14K 0x000E /* 14KB */ -#define E1000_PBA_16K 0x0010 /* 16KB */ -#define E1000_PBA_18K 0x0012 -#define E1000_PBA_20K 0x0014 -#define E1000_PBA_22K 0x0016 -#define E1000_PBA_24K 0x0018 -#define E1000_PBA_26K 0x001A -#define E1000_PBA_30K 0x001E -#define E1000_PBA_32K 0x0020 -#define E1000_PBA_34K 0x0022 -#define E1000_PBA_35K 0x0023 -#define E1000_PBA_38K 0x0026 -#define E1000_PBA_40K 0x0028 -#define E1000_PBA_48K 0x0030 /* 48KB */ -#define E1000_PBA_64K 0x0040 /* 64KB */ - -#define E1000_PBS_16K E1000_PBA_16K -#define E1000_PBS_24K E1000_PBA_24K - -#define IFS_MAX 80 -#define IFS_MIN 40 -#define IFS_RATIO 4 -#define IFS_STEP 10 -#define MIN_NUM_XMITS 1000 - -/* SW Semaphore Register */ -#define E1000_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ -#define E1000_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ -#define E1000_SWSM_WMNG 0x00000004 /* Wake MNG Clock */ -#define E1000_SWSM_DRV_LOAD 0x00000008 /* Driver Loaded Bit */ - -#define E1000_SWSM2_LOCK 0x00000002 /* Secondary driver semaphore bit */ - -/* Interrupt Cause Read */ -#define E1000_ICR_TXDW 0x00000001 /* Transmit desc written back */ -#define E1000_ICR_TXQE 0x00000002 /* Transmit Queue empty */ -#define E1000_ICR_LSC 0x00000004 /* Link Status Change */ -#define E1000_ICR_RXSEQ 0x00000008 /* rx sequence error */ -#define E1000_ICR_RXDMT0 0x00000010 /* rx desc min. threshold (0) */ -#define E1000_ICR_RXO 0x00000040 /* rx overrun */ -#define E1000_ICR_RXT0 0x00000080 /* rx timer intr (ring 0) */ -#define E1000_ICR_VMMB 0x00000100 /* VM MB event */ -#define E1000_ICR_MDAC 0x00000200 /* MDIO access complete */ -#define E1000_ICR_RXCFG 0x00000400 /* Rx /c/ ordered set */ -#define E1000_ICR_GPI_EN0 0x00000800 /* GP Int 0 */ -#define E1000_ICR_GPI_EN1 0x00001000 /* GP Int 1 */ -#define E1000_ICR_GPI_EN2 0x00002000 /* GP Int 2 */ -#define E1000_ICR_GPI_EN3 0x00004000 /* GP Int 3 */ -#define E1000_ICR_TXD_LOW 0x00008000 -#define E1000_ICR_SRPD 0x00010000 -#define E1000_ICR_ACK 0x00020000 /* Receive Ack frame */ -#define E1000_ICR_MNG 0x00040000 /* Manageability event */ -#define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ -#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver - * should claim the interrupt */ -#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* Q0 Rx desc FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* Q0 Tx desc FIFO parity error */ -#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity err */ -#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ -#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* Q1 Rx desc FIFO parity error */ -#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* Q1 Tx desc FIFO parity error */ -#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ -#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW - * bit in the FWSM */ -#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates - * an interrupt */ -#define E1000_ICR_DOUTSYNC 0x10000000 /* NIC DMA out of sync */ -#define E1000_ICR_EPRST 0x00100000 /* ME hardware reset occurs */ - - -/* Extended Interrupt Cause Read */ -#define E1000_EICR_RX_QUEUE0 0x00000001 /* Rx Queue 0 Interrupt */ -#define E1000_EICR_RX_QUEUE1 0x00000002 /* Rx Queue 1 Interrupt */ -#define E1000_EICR_RX_QUEUE2 0x00000004 /* Rx Queue 2 Interrupt */ -#define E1000_EICR_RX_QUEUE3 0x00000008 /* Rx Queue 3 Interrupt */ -#define E1000_EICR_TX_QUEUE0 0x00000100 /* Tx Queue 0 Interrupt */ -#define E1000_EICR_TX_QUEUE1 0x00000200 /* Tx Queue 1 Interrupt */ -#define E1000_EICR_TX_QUEUE2 0x00000400 /* Tx Queue 2 Interrupt */ -#define E1000_EICR_TX_QUEUE3 0x00000800 /* Tx Queue 3 Interrupt */ -#define E1000_EICR_TCP_TIMER 0x40000000 /* TCP Timer */ -#define E1000_EICR_OTHER 0x80000000 /* Interrupt Cause Active */ -/* TCP Timer */ -#define E1000_TCPTIMER_KS 0x00000100 /* KickStart */ -#define E1000_TCPTIMER_COUNT_ENABLE 0x00000200 /* Count Enable */ -#define E1000_TCPTIMER_COUNT_FINISH 0x00000400 /* Count finish */ -#define E1000_TCPTIMER_LOOP 0x00000800 /* Loop */ - -/* - * This defines the bits that are set in the Interrupt Mask - * Set/Read Register. Each bit is documented below: - * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error - */ -#define POLL_IMS_ENABLE_MASK ( \ - E1000_IMS_RXDMT0 | \ - E1000_IMS_RXSEQ) - -/* - * This defines the bits that are set in the Interrupt Mask - * Set/Read Register. Each bit is documented below: - * o RXT0 = Receiver Timer Interrupt (ring 0) - * o TXDW = Transmit Descriptor Written Back - * o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0) - * o RXSEQ = Receive Sequence Error - * o LSC = Link Status Change - */ -#define IMS_ENABLE_MASK ( \ - E1000_IMS_RXT0 | \ - E1000_IMS_TXDW | \ - E1000_IMS_RXDMT0 | \ - E1000_IMS_RXSEQ | \ - E1000_IMS_LSC) - -/* Interrupt Mask Set */ -#define E1000_IMS_TXDW E1000_ICR_TXDW /* Tx desc written back */ -#define E1000_IMS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_IMS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_IMS_VMMB E1000_ICR_VMMB /* Mail box activity */ -#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_IMS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_IMS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_IMS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ -#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_IMS_SRPD E1000_ICR_SRPD -#define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO - * parity error */ -#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO - * parity error */ -#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer - * parity error */ -#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity - * error */ -#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO - * parity error */ -#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO - * parity error */ -#define E1000_IMS_DSW E1000_ICR_DSW -#define E1000_IMS_PHYINT E1000_ICR_PHYINT -#define E1000_IMS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */ -#define E1000_IMS_EPRST E1000_ICR_EPRST - -/* Extended Interrupt Mask Set */ -#define E1000_EIMS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */ -#define E1000_EIMS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */ -#define E1000_EIMS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */ -#define E1000_EIMS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */ -#define E1000_EIMS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */ -#define E1000_EIMS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */ -#define E1000_EIMS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */ -#define E1000_EIMS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */ -#define E1000_EIMS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ -#define E1000_EIMS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ - -/* Interrupt Cause Set */ -#define E1000_ICS_TXDW E1000_ICR_TXDW /* Tx desc written back */ -#define E1000_ICS_TXQE E1000_ICR_TXQE /* Transmit Queue empty */ -#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */ -#define E1000_ICS_RXSEQ E1000_ICR_RXSEQ /* rx sequence error */ -#define E1000_ICS_RXDMT0 E1000_ICR_RXDMT0 /* rx desc min. threshold */ -#define E1000_ICS_RXO E1000_ICR_RXO /* rx overrun */ -#define E1000_ICS_RXT0 E1000_ICR_RXT0 /* rx timer intr */ -#define E1000_ICS_MDAC E1000_ICR_MDAC /* MDIO access complete */ -#define E1000_ICS_RXCFG E1000_ICR_RXCFG /* Rx /c/ ordered set */ -#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0 /* GP Int 0 */ -#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1 /* GP Int 1 */ -#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2 /* GP Int 2 */ -#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3 /* GP Int 3 */ -#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW -#define E1000_ICS_SRPD E1000_ICR_SRPD -#define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ -#define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ -#define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ -#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* Q0 Rx desc FIFO - * parity error */ -#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* Q0 Tx desc FIFO - * parity error */ -#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer - * parity error */ -#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity - * error */ -#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* Q1 Rx desc FIFO - * parity error */ -#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* Q1 Tx desc FIFO - * parity error */ -#define E1000_ICS_DSW E1000_ICR_DSW -#define E1000_ICS_DOUTSYNC E1000_ICR_DOUTSYNC /* NIC DMA out of sync */ -#define E1000_ICS_PHYINT E1000_ICR_PHYINT -#define E1000_ICS_EPRST E1000_ICR_EPRST - -/* Extended Interrupt Cause Set */ -#define E1000_EICS_RX_QUEUE0 E1000_EICR_RX_QUEUE0 /* Rx Queue 0 Interrupt */ -#define E1000_EICS_RX_QUEUE1 E1000_EICR_RX_QUEUE1 /* Rx Queue 1 Interrupt */ -#define E1000_EICS_RX_QUEUE2 E1000_EICR_RX_QUEUE2 /* Rx Queue 2 Interrupt */ -#define E1000_EICS_RX_QUEUE3 E1000_EICR_RX_QUEUE3 /* Rx Queue 3 Interrupt */ -#define E1000_EICS_TX_QUEUE0 E1000_EICR_TX_QUEUE0 /* Tx Queue 0 Interrupt */ -#define E1000_EICS_TX_QUEUE1 E1000_EICR_TX_QUEUE1 /* Tx Queue 1 Interrupt */ -#define E1000_EICS_TX_QUEUE2 E1000_EICR_TX_QUEUE2 /* Tx Queue 2 Interrupt */ -#define E1000_EICS_TX_QUEUE3 E1000_EICR_TX_QUEUE3 /* Tx Queue 3 Interrupt */ -#define E1000_EICS_TCP_TIMER E1000_EICR_TCP_TIMER /* TCP Timer */ -#define E1000_EICS_OTHER E1000_EICR_OTHER /* Interrupt Cause Active */ - -#define E1000_EITR_ITR_INT_MASK 0x0000FFFF - -/* Transmit Descriptor Control */ -#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */ -#define E1000_TXDCTL_HTHRESH 0x00003F00 /* TXDCTL Host Threshold */ -#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */ -#define E1000_TXDCTL_GRAN 0x01000000 /* TXDCTL Granularity */ -#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */ -#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */ -#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */ -/* Enable the counting of descriptors still to be processed. */ -#define E1000_TXDCTL_COUNT_DESC 0x00400000 - -/* Flow Control Constants */ -#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001 -#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100 -#define FLOW_CONTROL_TYPE 0x8808 - -/* 802.1q VLAN Packet Size */ -#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMA'd) */ -#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */ - -/* Receive Address */ -/* - * Number of high/low register pairs in the RAR. The RAR (Receive Address - * Registers) holds the directed and multicast addresses that we monitor. - * Technically, we have 16 spots. However, we reserve one of these spots - * (RAR[15]) for our directed address used by controllers with - * manageability enabled, allowing us room for 15 multicast addresses. - */ -#define E1000_RAR_ENTRIES 15 -#define E1000_RAH_AV 0x80000000 /* Receive descriptor valid */ -#define E1000_RAL_MAC_ADDR_LEN 4 -#define E1000_RAH_MAC_ADDR_LEN 2 -#define E1000_RAH_POOL_MASK 0x03FC0000 -#define E1000_RAH_POOL_1 0x00040000 - -/* Error Codes */ -#define E1000_SUCCESS 0 -#define E1000_ERR_NVM 1 -#define E1000_ERR_PHY 2 -#define E1000_ERR_CONFIG 3 -#define E1000_ERR_PARAM 4 -#define E1000_ERR_MAC_INIT 5 -#define E1000_ERR_PHY_TYPE 6 -#define E1000_ERR_RESET 9 -#define E1000_ERR_MASTER_REQUESTS_PENDING 10 -#define E1000_ERR_HOST_INTERFACE_COMMAND 11 -#define E1000_BLK_PHY_RESET 12 -#define E1000_ERR_SWFW_SYNC 13 -#define E1000_NOT_IMPLEMENTED 14 -#define E1000_ERR_MBX 15 - -/* Loop limit on how long we wait for auto-negotiation to complete */ -#define FIBER_LINK_UP_LIMIT 50 -#define COPPER_LINK_UP_LIMIT 10 -#define PHY_AUTO_NEG_LIMIT 45 -#define PHY_FORCE_LIMIT 20 -/* Number of 100 microseconds we wait for PCI Express master disable */ -#define MASTER_DISABLE_TIMEOUT 800 -/* Number of milliseconds we wait for PHY configuration done after MAC reset */ -#define PHY_CFG_TIMEOUT 100 -/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */ -#define MDIO_OWNERSHIP_TIMEOUT 10 -/* Number of milliseconds for NVM auto read done after MAC reset. */ -#define AUTO_READ_DONE_TIMEOUT 10 - -/* Flow Control */ -#define E1000_FCRTH_RTH 0x0000FFF8 /* Mask Bits[15:3] for RTH */ -#define E1000_FCRTH_XFCE 0x80000000 /* External Flow Control Enable */ -#define E1000_FCRTL_RTL 0x0000FFF8 /* Mask Bits[15:3] for RTL */ -#define E1000_FCRTL_XONE 0x80000000 /* Enable XON frame transmission */ - -/* Transmit Configuration Word */ -#define E1000_TXCW_FD 0x00000020 /* TXCW full duplex */ -#define E1000_TXCW_HD 0x00000040 /* TXCW half duplex */ -#define E1000_TXCW_PAUSE 0x00000080 /* TXCW sym pause request */ -#define E1000_TXCW_ASM_DIR 0x00000100 /* TXCW astm pause direction */ -#define E1000_TXCW_PAUSE_MASK 0x00000180 /* TXCW pause request mask */ -#define E1000_TXCW_RF 0x00003000 /* TXCW remote fault */ -#define E1000_TXCW_NP 0x00008000 /* TXCW next page */ -#define E1000_TXCW_CW 0x0000ffff /* TxConfigWord mask */ -#define E1000_TXCW_TXC 0x40000000 /* Transmit Config control */ -#define E1000_TXCW_ANE 0x80000000 /* Auto-neg enable */ - -/* Receive Configuration Word */ -#define E1000_RXCW_CW 0x0000ffff /* RxConfigWord mask */ -#define E1000_RXCW_NC 0x04000000 /* Receive config no carrier */ -#define E1000_RXCW_IV 0x08000000 /* Receive config invalid */ -#define E1000_RXCW_CC 0x10000000 /* Receive config change */ -#define E1000_RXCW_C 0x20000000 /* Receive config */ -#define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ -#define E1000_RXCW_ANC 0x80000000 /* Auto-neg complete */ - -#define E1000_TSYNCTXCTL_VALID 0x00000001 /* tx timestamp valid */ -#define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable tx timestampping */ - -#define E1000_TSYNCRXCTL_VALID 0x00000001 /* rx timestamp valid */ -#define E1000_TSYNCRXCTL_TYPE_MASK 0x0000000E /* rx type mask */ -#define E1000_TSYNCRXCTL_TYPE_L2_V2 0x00 -#define E1000_TSYNCRXCTL_TYPE_L4_V1 0x02 -#define E1000_TSYNCRXCTL_TYPE_L2_L4_V2 0x04 -#define E1000_TSYNCRXCTL_TYPE_ALL 0x08 -#define E1000_TSYNCRXCTL_TYPE_EVENT_V2 0x0A -#define E1000_TSYNCRXCTL_ENABLED 0x00000010 /* enable rx timestampping */ - -#define E1000_TSYNCRXCFG_PTP_V1_CTRLT_MASK 0x000000FF -#define E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE 0x00 -#define E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE 0x01 -#define E1000_TSYNCRXCFG_PTP_V1_FOLLOWUP_MESSAGE 0x02 -#define E1000_TSYNCRXCFG_PTP_V1_DELAY_RESP_MESSAGE 0x03 -#define E1000_TSYNCRXCFG_PTP_V1_MANAGEMENT_MESSAGE 0x04 - -#define E1000_TSYNCRXCFG_PTP_V2_MSGID_MASK 0x00000F00 -#define E1000_TSYNCRXCFG_PTP_V2_SYNC_MESSAGE 0x0000 -#define E1000_TSYNCRXCFG_PTP_V2_DELAY_REQ_MESSAGE 0x0100 -#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_REQ_MESSAGE 0x0200 -#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_RESP_MESSAGE 0x0300 -#define E1000_TSYNCRXCFG_PTP_V2_FOLLOWUP_MESSAGE 0x0800 -#define E1000_TSYNCRXCFG_PTP_V2_DELAY_RESP_MESSAGE 0x0900 -#define E1000_TSYNCRXCFG_PTP_V2_PATH_DELAY_FOLLOWUP_MESSAGE 0x0A00 -#define E1000_TSYNCRXCFG_PTP_V2_ANNOUNCE_MESSAGE 0x0B00 -#define E1000_TSYNCRXCFG_PTP_V2_SIGNALLING_MESSAGE 0x0C00 -#define E1000_TSYNCRXCFG_PTP_V2_MANAGEMENT_MESSAGE 0x0D00 - -#define E1000_TIMINCA_16NS_SHIFT 24 - -/* PCI Express Control */ -#define E1000_GCR_RXD_NO_SNOOP 0x00000001 -#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 -#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 -#define E1000_GCR_TXD_NO_SNOOP 0x00000008 -#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 -#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 -#define E1000_GCR_CMPL_TMOUT_MASK 0x0000F000 -#define E1000_GCR_CMPL_TMOUT_10ms 0x00001000 -#define E1000_GCR_CMPL_TMOUT_RESEND 0x00010000 -#define E1000_GCR_CAP_VER2 0x00040000 - -#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ - E1000_GCR_RXDSCW_NO_SNOOP | \ - E1000_GCR_RXDSCR_NO_SNOOP | \ - E1000_GCR_TXD_NO_SNOOP | \ - E1000_GCR_TXDSCW_NO_SNOOP | \ - E1000_GCR_TXDSCR_NO_SNOOP) - -/* PHY Control Register */ -#define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_COLL_TEST_ENABLE 0x0080 /* Collision test enable */ -#define MII_CR_FULL_DUPLEX 0x0100 /* FDX =1, half duplex =0 */ -#define MII_CR_RESTART_AUTO_NEG 0x0200 /* Restart auto negotiation */ -#define MII_CR_ISOLATE 0x0400 /* Isolate PHY from MII */ -#define MII_CR_POWER_DOWN 0x0800 /* Power down */ -#define MII_CR_AUTO_NEG_EN 0x1000 /* Auto Neg Enable */ -#define MII_CR_SPEED_SELECT_LSB 0x2000 /* bits 6,13: 10=1000, 01=100, 00=10 */ -#define MII_CR_LOOPBACK 0x4000 /* 0 = normal, 1 = loopback */ -#define MII_CR_RESET 0x8000 /* 0 = normal, 1 = PHY reset */ -#define MII_CR_SPEED_1000 0x0040 -#define MII_CR_SPEED_100 0x2000 -#define MII_CR_SPEED_10 0x0000 - -/* PHY Status Register */ -#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */ -#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */ -#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */ -#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */ -#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */ -#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */ -#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */ -#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */ -#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */ -#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */ -#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */ -#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */ -#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */ -#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */ -#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */ - -/* Autoneg Advertisement Register */ -#define NWAY_AR_SELECTOR_FIELD 0x0001 /* indicates IEEE 802.3 CSMA/CD */ -#define NWAY_AR_10T_HD_CAPS 0x0020 /* 10T Half Duplex Capable */ -#define NWAY_AR_10T_FD_CAPS 0x0040 /* 10T Full Duplex Capable */ -#define NWAY_AR_100TX_HD_CAPS 0x0080 /* 100TX Half Duplex Capable */ -#define NWAY_AR_100TX_FD_CAPS 0x0100 /* 100TX Full Duplex Capable */ -#define NWAY_AR_100T4_CAPS 0x0200 /* 100T4 Capable */ -#define NWAY_AR_PAUSE 0x0400 /* Pause operation desired */ -#define NWAY_AR_ASM_DIR 0x0800 /* Asymmetric Pause Direction bit */ -#define NWAY_AR_REMOTE_FAULT 0x2000 /* Remote Fault detected */ -#define NWAY_AR_NEXT_PAGE 0x8000 /* Next Page ability supported */ - -/* Link Partner Ability Register (Base Page) */ -#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */ -#define NWAY_LPAR_10T_HD_CAPS 0x0020 /* LP is 10T Half Duplex Capable */ -#define NWAY_LPAR_10T_FD_CAPS 0x0040 /* LP is 10T Full Duplex Capable */ -#define NWAY_LPAR_100TX_HD_CAPS 0x0080 /* LP is 100TX Half Duplex Capable */ -#define NWAY_LPAR_100TX_FD_CAPS 0x0100 /* LP is 100TX Full Duplex Capable */ -#define NWAY_LPAR_100T4_CAPS 0x0200 /* LP is 100T4 Capable */ -#define NWAY_LPAR_PAUSE 0x0400 /* LP Pause operation desired */ -#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */ -#define NWAY_LPAR_REMOTE_FAULT 0x2000 /* LP has detected Remote Fault */ -#define NWAY_LPAR_ACKNOWLEDGE 0x4000 /* LP has rx'd link code word */ -#define NWAY_LPAR_NEXT_PAGE 0x8000 /* Next Page ability supported */ - -/* Autoneg Expansion Register */ -#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */ -#define NWAY_ER_PAGE_RXD 0x0002 /* LP is 10T Half Duplex Capable */ -#define NWAY_ER_NEXT_PAGE_CAPS 0x0004 /* LP is 10T Full Duplex Capable */ -#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */ -#define NWAY_ER_PAR_DETECT_FAULT 0x0010 /* LP is 100TX Full Duplex Capable */ - -/* 1000BASE-T Control Register */ -#define CR_1000T_ASYM_PAUSE 0x0080 /* Advertise asymmetric pause bit */ -#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */ -#define CR_1000T_FD_CAPS 0x0200 /* Advertise 1000T FD capability */ -#define CR_1000T_REPEATER_DTE 0x0400 /* 1=Repeater/switch device port */ - /* 0=DTE device */ -#define CR_1000T_MS_VALUE 0x0800 /* 1=Configure PHY as Master */ - /* 0=Configure PHY as Slave */ -#define CR_1000T_MS_ENABLE 0x1000 /* 1=Master/Slave manual config value */ - /* 0=Automatic Master/Slave config */ -#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */ -#define CR_1000T_TEST_MODE_1 0x2000 /* Transmit Waveform test */ -#define CR_1000T_TEST_MODE_2 0x4000 /* Master Transmit Jitter test */ -#define CR_1000T_TEST_MODE_3 0x6000 /* Slave Transmit Jitter test */ -#define CR_1000T_TEST_MODE_4 0x8000 /* Transmitter Distortion test */ - -/* 1000BASE-T Status Register */ -#define SR_1000T_IDLE_ERROR_CNT 0x00FF /* Num idle errors since last read */ -#define SR_1000T_ASYM_PAUSE_DIR 0x0100 /* LP asymmetric pause direction bit */ -#define SR_1000T_LP_HD_CAPS 0x0400 /* LP is 1000T HD capable */ -#define SR_1000T_LP_FD_CAPS 0x0800 /* LP is 1000T FD capable */ -#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */ -#define SR_1000T_LOCAL_RX_STATUS 0x2000 /* Local receiver OK */ -#define SR_1000T_MS_CONFIG_RES 0x4000 /* 1=Local Tx is Master, 0=Slave */ -#define SR_1000T_MS_CONFIG_FAULT 0x8000 /* Master/Slave config fault */ - -#define SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT 5 - -/* PHY 1000 MII Register/Bit Definitions */ -/* PHY Registers defined by IEEE */ -#define PHY_CONTROL 0x00 /* Control Register */ -#define PHY_STATUS 0x01 /* Status Register */ -#define PHY_ID1 0x02 /* Phy Id Reg (word 1) */ -#define PHY_ID2 0x03 /* Phy Id Reg (word 2) */ -#define PHY_AUTONEG_ADV 0x04 /* Autoneg Advertisement */ -#define PHY_LP_ABILITY 0x05 /* Link Partner Ability (Base Page) */ -#define PHY_AUTONEG_EXP 0x06 /* Autoneg Expansion Reg */ -#define PHY_NEXT_PAGE_TX 0x07 /* Next Page Tx */ -#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */ -#define PHY_1000T_CTRL 0x09 /* 1000Base-T Control Reg */ -#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */ -#define PHY_EXT_STATUS 0x0F /* Extended Status Reg */ - -#define PHY_CONTROL_LB 0x4000 /* PHY Loopback bit */ - -/* NVM Control */ -#define E1000_EECD_SK 0x00000001 /* NVM Clock */ -#define E1000_EECD_CS 0x00000002 /* NVM Chip Select */ -#define E1000_EECD_DI 0x00000004 /* NVM Data In */ -#define E1000_EECD_DO 0x00000008 /* NVM Data Out */ -#define E1000_EECD_FWE_MASK 0x00000030 -#define E1000_EECD_FWE_DIS 0x00000010 /* Disable FLASH writes */ -#define E1000_EECD_FWE_EN 0x00000020 /* Enable FLASH writes */ -#define E1000_EECD_FWE_SHIFT 4 -#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */ -#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */ -#define E1000_EECD_PRES 0x00000100 /* NVM Present */ -#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */ -/* NVM Addressing bits based on type 0=small, 1=large */ -#define E1000_EECD_ADDR_BITS 0x00000400 -#define E1000_EECD_TYPE 0x00002000 /* NVM Type (1-SPI, 0-Microwire) */ -#define E1000_NVM_GRANT_ATTEMPTS 1000 /* NVM # attempts to gain grant */ -#define E1000_EECD_AUTO_RD 0x00000200 /* NVM Auto Read done */ -#define E1000_EECD_SIZE_EX_MASK 0x00007800 /* NVM Size */ -#define E1000_EECD_SIZE_EX_SHIFT 11 -#define E1000_EECD_NVADDS 0x00018000 /* NVM Address Size */ -#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */ -#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */ -#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ -#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ -#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */ -#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ -#define E1000_EECD_SECVAL_SHIFT 22 -#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES) - -#define E1000_NVM_SWDPIN0 0x0001 /* SWDPIN 0 NVM Value */ -#define E1000_NVM_LED_LOGIC 0x0020 /* Led Logic Word */ -#define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write regs */ -#define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ -#define E1000_NVM_RW_REG_START 1 /* Start operation */ -#define E1000_NVM_RW_ADDR_SHIFT 2 /* Shift to the address bits */ -#define E1000_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ -#define E1000_NVM_POLL_READ 0 /* Flag for polling for read complete */ -#define E1000_FLASH_UPDATES 2000 - -/* NVM Word Offsets */ -#define NVM_COMPAT 0x0003 -#define NVM_ID_LED_SETTINGS 0x0004 -#define NVM_VERSION 0x0005 -#define NVM_SERDES_AMPLITUDE 0x0006 /* SERDES output amplitude */ -#define NVM_PHY_CLASS_WORD 0x0007 -#define NVM_INIT_CONTROL1_REG 0x000A -#define NVM_INIT_CONTROL2_REG 0x000F -#define NVM_SWDEF_PINS_CTRL_PORT_1 0x0010 -#define NVM_INIT_CONTROL3_PORT_B 0x0014 -#define NVM_INIT_3GIO_3 0x001A -#define NVM_SWDEF_PINS_CTRL_PORT_0 0x0020 -#define NVM_INIT_CONTROL3_PORT_A 0x0024 -#define NVM_CFG 0x0012 -#define NVM_FLASH_VERSION 0x0032 -#define NVM_ALT_MAC_ADDR_PTR 0x0037 -#define NVM_CHECKSUM_REG 0x003F - -#define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */ -#define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */ - -/* Mask bits for fields in Word 0x0f of the NVM */ -#define NVM_WORD0F_PAUSE_MASK 0x3000 -#define NVM_WORD0F_PAUSE 0x1000 -#define NVM_WORD0F_ASM_DIR 0x2000 -#define NVM_WORD0F_ANE 0x0800 -#define NVM_WORD0F_SWPDIO_EXT_MASK 0x00F0 -#define NVM_WORD0F_LPLU 0x0001 - -/* Mask bits for fields in Word 0x1a of the NVM */ -#define NVM_WORD1A_ASPM_MASK 0x000C - -/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */ -#define NVM_SUM 0xBABA - -#define NVM_MAC_ADDR_OFFSET 0 -#define NVM_PBA_OFFSET_0 8 -#define NVM_PBA_OFFSET_1 9 -#define NVM_RESERVED_WORD 0xFFFF -#define NVM_PHY_CLASS_A 0x8000 -#define NVM_SERDES_AMPLITUDE_MASK 0x000F -#define NVM_SIZE_MASK 0x1C00 -#define NVM_SIZE_SHIFT 10 -#define NVM_WORD_SIZE_BASE_SHIFT 6 -#define NVM_SWDPIO_EXT_SHIFT 4 - -/* NVM Commands - SPI */ -#define NVM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */ -#define NVM_READ_OPCODE_SPI 0x03 /* NVM read opcode */ -#define NVM_WRITE_OPCODE_SPI 0x02 /* NVM write opcode */ -#define NVM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */ -#define NVM_WREN_OPCODE_SPI 0x06 /* NVM set Write Enable latch */ -#define NVM_WRDI_OPCODE_SPI 0x04 /* NVM reset Write Enable latch */ -#define NVM_RDSR_OPCODE_SPI 0x05 /* NVM read Status register */ -#define NVM_WRSR_OPCODE_SPI 0x01 /* NVM write Status register */ - -/* SPI NVM Status Register */ -#define NVM_STATUS_RDY_SPI 0x01 -#define NVM_STATUS_WEN_SPI 0x02 -#define NVM_STATUS_BP0_SPI 0x04 -#define NVM_STATUS_BP1_SPI 0x08 -#define NVM_STATUS_WPEN_SPI 0x80 - -/* Word definitions for ID LED Settings */ -#define ID_LED_RESERVED_0000 0x0000 -#define ID_LED_RESERVED_FFFF 0xFFFF -#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \ - (ID_LED_OFF1_OFF2 << 8) | \ - (ID_LED_DEF1_DEF2 << 4) | \ - (ID_LED_DEF1_DEF2)) -#define ID_LED_DEF1_DEF2 0x1 -#define ID_LED_DEF1_ON2 0x2 -#define ID_LED_DEF1_OFF2 0x3 -#define ID_LED_ON1_DEF2 0x4 -#define ID_LED_ON1_ON2 0x5 -#define ID_LED_ON1_OFF2 0x6 -#define ID_LED_OFF1_DEF2 0x7 -#define ID_LED_OFF1_ON2 0x8 -#define ID_LED_OFF1_OFF2 0x9 - -#define IGP_ACTIVITY_LED_MASK 0xFFFFF0FF -#define IGP_ACTIVITY_LED_ENABLE 0x0300 -#define IGP_LED3_MODE 0x07000000 - -/* PCI/PCI-X/PCI-EX Config space */ -#define PCI_HEADER_TYPE_REGISTER 0x0E -#define PCIE_LINK_STATUS 0x12 -#define PCIE_DEVICE_CONTROL2 0x28 - -#define PCI_HEADER_TYPE_MULTIFUNC 0x80 -#define PCIE_LINK_WIDTH_MASK 0x3F0 -#define PCIE_LINK_WIDTH_SHIFT 4 -#define PCIE_DEVICE_CONTROL2_16ms 0x0005 - -#ifndef ETH_ADDR_LEN -#define ETH_ADDR_LEN 6 -#endif - -#define PHY_REVISION_MASK 0xFFFFFFF0 -#define MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ -#define MAX_PHY_MULTI_PAGE_REG 0xF - -/* Bit definitions for valid PHY IDs. */ -/* - * I = Integrated - * E = External - */ -#define M88E1000_E_PHY_ID 0x01410C50 -#define M88E1000_I_PHY_ID 0x01410C30 -#define M88E1011_I_PHY_ID 0x01410C20 -#define IGP01E1000_I_PHY_ID 0x02A80380 -#define M88E1011_I_REV_4 0x04 -#define M88E1111_I_PHY_ID 0x01410CC0 -#define GG82563_E_PHY_ID 0x01410CA0 -#define IGP03E1000_E_PHY_ID 0x02A80390 -#define IFE_E_PHY_ID 0x02A80330 -#define IFE_PLUS_E_PHY_ID 0x02A80320 -#define IFE_C_E_PHY_ID 0x02A80310 -#define IGP04E1000_E_PHY_ID 0x02A80391 -#define M88_VENDOR 0x0141 - -/* M88E1000 Specific Registers */ -#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */ -#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */ -#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */ -#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */ -#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */ -#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */ - -#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */ -#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */ -#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */ -#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */ -#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */ - -/* M88E1000 PHY Specific Control Register */ -#define M88E1000_PSCR_JABBER_DISABLE 0x0001 /* 1=Jabber Function disabled */ -#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reverse enabled */ -#define M88E1000_PSCR_SQE_TEST 0x0004 /* 1=SQE Test enabled */ -/* 1=CLK125 low, 0=CLK125 toggling */ -#define M88E1000_PSCR_CLK125_DISABLE 0x0010 -#define M88E1000_PSCR_MDI_MANUAL_MODE 0x0000 /* MDI Crossover Mode bits 6:5 */ - /* Manual MDI configuration */ -#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020 /* Manual MDIX configuration */ -/* 1000BASE-T: Auto crossover, 100BASE-TX/10BASE-T: MDI Mode */ -#define M88E1000_PSCR_AUTO_X_1000T 0x0040 -/* Auto crossover enabled all speeds */ -#define M88E1000_PSCR_AUTO_X_MODE 0x0060 -/* - * 1=Enable Extended 10BASE-T distance (Lower 10BASE-T Rx Threshold - * 0=Normal 10BASE-T Rx Threshold - */ -#define M88E1000_PSCR_EN_10BT_EXT_DIST 0x0080 -/* 1=5-bit interface in 100BASE-TX, 0=MII interface in 100BASE-TX */ -#define M88E1000_PSCR_MII_5BIT_ENABLE 0x0100 -#define M88E1000_PSCR_SCRAMBLER_DISABLE 0x0200 /* 1=Scrambler disable */ -#define M88E1000_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force link good */ -#define M88E1000_PSCR_ASSERT_CRS_ON_TX 0x0800 /* 1=Assert CRS on Tx */ - -/* M88E1000 PHY Specific Status Register */ -#define M88E1000_PSSR_JABBER 0x0001 /* 1=Jabber */ -#define M88E1000_PSSR_REV_POLARITY 0x0002 /* 1=Polarity reversed */ -#define M88E1000_PSSR_DOWNSHIFT 0x0020 /* 1=Downshifted */ -#define M88E1000_PSSR_MDIX 0x0040 /* 1=MDIX; 0=MDI */ -/* - * 0 = <50M - * 1 = 50-80M - * 2 = 80-110M - * 3 = 110-140M - * 4 = >140M - */ -#define M88E1000_PSSR_CABLE_LENGTH 0x0380 -#define M88E1000_PSSR_LINK 0x0400 /* 1=Link up, 0=Link down */ -#define M88E1000_PSSR_SPD_DPLX_RESOLVED 0x0800 /* 1=Speed & Duplex resolved */ -#define M88E1000_PSSR_PAGE_RCVD 0x1000 /* 1=Page received */ -#define M88E1000_PSSR_DPLX 0x2000 /* 1=Duplex 0=Half Duplex */ -#define M88E1000_PSSR_SPEED 0xC000 /* Speed, bits 14:15 */ -#define M88E1000_PSSR_10MBS 0x0000 /* 00=10Mbs */ -#define M88E1000_PSSR_100MBS 0x4000 /* 01=100Mbs */ -#define M88E1000_PSSR_1000MBS 0x8000 /* 10=1000Mbs */ - -#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7 - -/* M88E1000 Extended PHY Specific Control Register */ -#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */ -/* - * 1 = Lost lock detect enabled. - * Will assert lost lock and bring - * link down if idle not seen - * within 1ms in 1000BASE-T - */ -#define M88E1000_EPSCR_DOWN_NO_IDLE 0x8000 -/* - * Number of times we will attempt to autonegotiate before downshifting if we - * are the master - */ -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X 0x0000 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X 0x0400 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X 0x0800 -#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X 0x0C00 -/* - * Number of times we will attempt to autonegotiate before downshifting if we - * are the slave - */ -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK 0x0300 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS 0x0000 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X 0x0100 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X 0x0200 -#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X 0x0300 -#define M88E1000_EPSCR_TX_CLK_2_5 0x0060 /* 2.5 MHz TX_CLK */ -#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */ -#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */ - -/* M88EC018 Rev 2 specific DownShift settings */ -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00 -#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00 - -/* - * Bits... - * 15-5: page - * 4-0: register offset - */ -#define GG82563_PAGE_SHIFT 5 -#define GG82563_REG(page, reg) \ - (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) -#define GG82563_MIN_ALT_REG 30 - -/* GG82563 Specific Registers */ -#define GG82563_PHY_SPEC_CTRL \ - GG82563_REG(0, 16) /* PHY Specific Control */ -#define GG82563_PHY_SPEC_STATUS \ - GG82563_REG(0, 17) /* PHY Specific Status */ -#define GG82563_PHY_INT_ENABLE \ - GG82563_REG(0, 18) /* Interrupt Enable */ -#define GG82563_PHY_SPEC_STATUS_2 \ - GG82563_REG(0, 19) /* PHY Specific Status 2 */ -#define GG82563_PHY_RX_ERR_CNTR \ - GG82563_REG(0, 21) /* Receive Error Counter */ -#define GG82563_PHY_PAGE_SELECT \ - GG82563_REG(0, 22) /* Page Select */ -#define GG82563_PHY_SPEC_CTRL_2 \ - GG82563_REG(0, 26) /* PHY Specific Control 2 */ -#define GG82563_PHY_PAGE_SELECT_ALT \ - GG82563_REG(0, 29) /* Alternate Page Select */ -#define GG82563_PHY_TEST_CLK_CTRL \ - GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */ - -#define GG82563_PHY_MAC_SPEC_CTRL \ - GG82563_REG(2, 21) /* MAC Specific Control Register */ -#define GG82563_PHY_MAC_SPEC_CTRL_2 \ - GG82563_REG(2, 26) /* MAC Specific Control 2 */ - -#define GG82563_PHY_DSP_DISTANCE \ - GG82563_REG(5, 26) /* DSP Distance */ - -/* Page 193 - Port Control Registers */ -#define GG82563_PHY_KMRN_MODE_CTRL \ - GG82563_REG(193, 16) /* Kumeran Mode Control */ -#define GG82563_PHY_PORT_RESET \ - GG82563_REG(193, 17) /* Port Reset */ -#define GG82563_PHY_REVISION_ID \ - GG82563_REG(193, 18) /* Revision ID */ -#define GG82563_PHY_DEVICE_ID \ - GG82563_REG(193, 19) /* Device ID */ -#define GG82563_PHY_PWR_MGMT_CTRL \ - GG82563_REG(193, 20) /* Power Management Control */ -#define GG82563_PHY_RATE_ADAPT_CTRL \ - GG82563_REG(193, 25) /* Rate Adaptation Control */ - -/* Page 194 - KMRN Registers */ -#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \ - GG82563_REG(194, 16) /* FIFO's Control/Status */ -#define GG82563_PHY_KMRN_CTRL \ - GG82563_REG(194, 17) /* Control */ -#define GG82563_PHY_INBAND_CTRL \ - GG82563_REG(194, 18) /* Inband Control */ -#define GG82563_PHY_KMRN_DIAGNOSTIC \ - GG82563_REG(194, 19) /* Diagnostic */ -#define GG82563_PHY_ACK_TIMEOUTS \ - GG82563_REG(194, 20) /* Acknowledge Timeouts */ -#define GG82563_PHY_ADV_ABILITY \ - GG82563_REG(194, 21) /* Advertised Ability */ -#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \ - GG82563_REG(194, 23) /* Link Partner Advertised Ability */ -#define GG82563_PHY_ADV_NEXT_PAGE \ - GG82563_REG(194, 24) /* Advertised Next Page */ -#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \ - GG82563_REG(194, 25) /* Link Partner Advertised Next page */ -#define GG82563_PHY_KMRN_MISC \ - GG82563_REG(194, 26) /* Misc. */ - -/* MDI Control */ -#define E1000_MDIC_DATA_MASK 0x0000FFFF -#define E1000_MDIC_REG_MASK 0x001F0000 -#define E1000_MDIC_REG_SHIFT 16 -#define E1000_MDIC_PHY_MASK 0x03E00000 -#define E1000_MDIC_PHY_SHIFT 21 -#define E1000_MDIC_OP_WRITE 0x04000000 -#define E1000_MDIC_OP_READ 0x08000000 -#define E1000_MDIC_READY 0x10000000 -#define E1000_MDIC_INT_EN 0x20000000 -#define E1000_MDIC_ERROR 0x40000000 - -/* SerDes Control */ -#define E1000_GEN_CTL_READY 0x80000000 -#define E1000_GEN_CTL_ADDRESS_SHIFT 8 -#define E1000_GEN_POLL_TIMEOUT 640 - -/* LinkSec register fields */ -#define E1000_LSECTXCAP_SUM_MASK 0x00FF0000 -#define E1000_LSECTXCAP_SUM_SHIFT 16 -#define E1000_LSECRXCAP_SUM_MASK 0x00FF0000 -#define E1000_LSECRXCAP_SUM_SHIFT 16 - -#define E1000_LSECTXCTRL_EN_MASK 0x00000003 -#define E1000_LSECTXCTRL_DISABLE 0x0 -#define E1000_LSECTXCTRL_AUTH 0x1 -#define E1000_LSECTXCTRL_AUTH_ENCRYPT 0x2 -#define E1000_LSECTXCTRL_AISCI 0x00000020 -#define E1000_LSECTXCTRL_PNTHRSH_MASK 0xFFFFFF00 -#define E1000_LSECTXCTRL_RSV_MASK 0x000000D8 - -#define E1000_LSECRXCTRL_EN_MASK 0x0000000C -#define E1000_LSECRXCTRL_EN_SHIFT 2 -#define E1000_LSECRXCTRL_DISABLE 0x0 -#define E1000_LSECRXCTRL_CHECK 0x1 -#define E1000_LSECRXCTRL_STRICT 0x2 -#define E1000_LSECRXCTRL_DROP 0x3 -#define E1000_LSECRXCTRL_PLSH 0x00000040 -#define E1000_LSECRXCTRL_RP 0x00000080 -#define E1000_LSECRXCTRL_RSV_MASK 0xFFFFFF33 - - - -#endif /* _IGB_DEFINES_H_ */ diff --git a/src/drivers/net/igb/igb_hw.h b/src/drivers/net/igb/igb_hw.h deleted file mode 100644 index 65a04f20..00000000 --- a/src/drivers/net/igb/igb_hw.h +++ /dev/null @@ -1,697 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_HW_H_ -#define _IGB_HW_H_ - -#include "igb_osdep.h" -#include "igb_regs.h" -#include "igb_defines.h" - -struct e1000_hw; - -#define E1000_DEV_ID_82576 0x10C9 -#define E1000_DEV_ID_82576_FIBER 0x10E6 -#define E1000_DEV_ID_82576_SERDES 0x10E7 -#define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 -#define E1000_DEV_ID_82576_NS 0x150A -#define E1000_DEV_ID_82576_NS_SERDES 0x1518 -#define E1000_DEV_ID_82576_SERDES_QUAD 0x150D -#define E1000_DEV_ID_82575EB_COPPER 0x10A7 -#define E1000_DEV_ID_82575EB_FIBER_SERDES 0x10A9 -#define E1000_DEV_ID_82575GB_QUAD_COPPER 0x10D6 -#define E1000_REVISION_0 0 -#define E1000_REVISION_1 1 -#define E1000_REVISION_2 2 -#define E1000_REVISION_3 3 -#define E1000_REVISION_4 4 - -#define E1000_FUNC_0 0 -#define E1000_FUNC_1 1 - -#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN0 0 -#define E1000_ALT_MAC_ADDRESS_OFFSET_LAN1 3 - -enum e1000_mac_type { - e1000_undefined = 0, - e1000_82575, - e1000_82576, - e1000_num_macs /* List is 1-based, so subtract 1 for true count. */ -}; - -enum e1000_media_type { - e1000_media_type_unknown = 0, - e1000_media_type_copper = 1, - e1000_media_type_fiber = 2, - e1000_media_type_internal_serdes = 3, - e1000_num_media_types -}; - -enum e1000_nvm_type { - e1000_nvm_unknown = 0, - e1000_nvm_none, - e1000_nvm_eeprom_spi, - e1000_nvm_flash_hw, - e1000_nvm_flash_sw -}; - -enum e1000_nvm_override { - e1000_nvm_override_none = 0, - e1000_nvm_override_spi_small, - e1000_nvm_override_spi_large, -}; - -enum e1000_phy_type { - e1000_phy_unknown = 0, - e1000_phy_none, - e1000_phy_m88, - e1000_phy_igp, - e1000_phy_igp_2, - e1000_phy_gg82563, - e1000_phy_igp_3, - e1000_phy_ife, - e1000_phy_vf, -}; - -enum e1000_bus_type { - e1000_bus_type_unknown = 0, - e1000_bus_type_pci, - e1000_bus_type_pcix, - e1000_bus_type_pci_express, - e1000_bus_type_reserved -}; - -enum e1000_bus_speed { - e1000_bus_speed_unknown = 0, - e1000_bus_speed_33, - e1000_bus_speed_66, - e1000_bus_speed_100, - e1000_bus_speed_120, - e1000_bus_speed_133, - e1000_bus_speed_2500, - e1000_bus_speed_5000, - e1000_bus_speed_reserved -}; - -enum e1000_bus_width { - e1000_bus_width_unknown = 0, - e1000_bus_width_pcie_x1, - e1000_bus_width_pcie_x2, - e1000_bus_width_pcie_x4 = 4, - e1000_bus_width_pcie_x8 = 8, - e1000_bus_width_32, - e1000_bus_width_64, - e1000_bus_width_reserved -}; - -enum e1000_1000t_rx_status { - e1000_1000t_rx_status_not_ok = 0, - e1000_1000t_rx_status_ok, - e1000_1000t_rx_status_undefined = 0xFF -}; - -enum e1000_rev_polarity { - e1000_rev_polarity_normal = 0, - e1000_rev_polarity_reversed, - e1000_rev_polarity_undefined = 0xFF -}; - -enum e1000_fc_mode { - e1000_fc_none = 0, - e1000_fc_rx_pause, - e1000_fc_tx_pause, - e1000_fc_full, - e1000_fc_default = 0xFF -}; - -enum e1000_ms_type { - e1000_ms_hw_default = 0, - e1000_ms_force_master, - e1000_ms_force_slave, - e1000_ms_auto -}; - -enum e1000_smart_speed { - e1000_smart_speed_default = 0, - e1000_smart_speed_on, - e1000_smart_speed_off -}; - -enum e1000_serdes_link_state { - e1000_serdes_link_down = 0, - e1000_serdes_link_autoneg_progress, - e1000_serdes_link_autoneg_complete, - e1000_serdes_link_forced_up -}; - -/* Receive Descriptor */ -struct e1000_rx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - __le16 length; /* Length of data DMAed into data buffer */ - __le16 csum; /* Packet checksum */ - u8 status; /* Descriptor status */ - u8 errors; /* Descriptor Errors */ - __le16 special; -}; - -/* Receive Descriptor - Extended */ -union e1000_rx_desc_extended { - struct { - __le64 buffer_addr; - __le64 reserved; - } read; - struct { - struct { - __le32 mrq; /* Multiple Rx Queues */ - union { - __le32 rss; /* RSS Hash */ - struct { - __le16 ip_id; /* IP id */ - __le16 csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - __le32 status_error; /* ext status/error */ - __le16 length; - __le16 vlan; /* VLAN tag */ - } upper; - } wb; /* writeback */ -}; - -#define MAX_PS_BUFFERS 4 -/* Receive Descriptor - Packet Split */ -union e1000_rx_desc_packet_split { - struct { - /* one buffer for protocol header(s), three data buffers */ - __le64 buffer_addr[MAX_PS_BUFFERS]; - } read; - struct { - struct { - __le32 mrq; /* Multiple Rx Queues */ - union { - __le32 rss; /* RSS Hash */ - struct { - __le16 ip_id; /* IP id */ - __le16 csum; /* Packet Checksum */ - } csum_ip; - } hi_dword; - } lower; - struct { - __le32 status_error; /* ext status/error */ - __le16 length0; /* length of buffer 0 */ - __le16 vlan; /* VLAN tag */ - } middle; - struct { - __le16 header_status; - __le16 length[3]; /* length of buffers 1-3 */ - } upper; - __le64 reserved; - } wb; /* writeback */ -}; - -/* Transmit Descriptor */ -struct e1000_tx_desc { - __le64 buffer_addr; /* Address of the descriptor's data buffer */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 cso; /* Checksum offset */ - u8 cmd; /* Descriptor control */ - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 css; /* Checksum start */ - __le16 special; - } fields; - } upper; -}; - -/* Offload Context Descriptor */ -struct e1000_context_desc { - union { - __le32 ip_config; - struct { - u8 ipcss; /* IP checksum start */ - u8 ipcso; /* IP checksum offset */ - __le16 ipcse; /* IP checksum end */ - } ip_fields; - } lower_setup; - union { - __le32 tcp_config; - struct { - u8 tucss; /* TCP checksum start */ - u8 tucso; /* TCP checksum offset */ - __le16 tucse; /* TCP checksum end */ - } tcp_fields; - } upper_setup; - __le32 cmd_and_length; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 hdr_len; /* Header length */ - __le16 mss; /* Maximum segment size */ - } fields; - } tcp_seg_setup; -}; - -/* Offload data descriptor */ -struct e1000_data_desc { - __le64 buffer_addr; /* Address of the descriptor's buffer address */ - union { - __le32 data; - struct { - __le16 length; /* Data buffer length */ - u8 typ_len_ext; - u8 cmd; - } flags; - } lower; - union { - __le32 data; - struct { - u8 status; /* Descriptor status */ - u8 popts; /* Packet Options */ - __le16 special; - } fields; - } upper; -}; - -/* Statistics counters collected by the MAC */ -struct e1000_hw_stats { - u64 crcerrs; - u64 algnerrc; - u64 symerrs; - u64 rxerrc; - u64 mpc; - u64 scc; - u64 ecol; - u64 mcc; - u64 latecol; - u64 colc; - u64 dc; - u64 tncrs; - u64 sec; - u64 cexterr; - u64 rlec; - u64 xonrxc; - u64 xontxc; - u64 xoffrxc; - u64 xofftxc; - u64 fcruc; - u64 prc64; - u64 prc127; - u64 prc255; - u64 prc511; - u64 prc1023; - u64 prc1522; - u64 gprc; - u64 bprc; - u64 mprc; - u64 gptc; - u64 gorc; - u64 gotc; - u64 rnbc; - u64 ruc; - u64 rfc; - u64 roc; - u64 rjc; - u64 mgprc; - u64 mgpdc; - u64 mgptc; - u64 tor; - u64 tot; - u64 tpr; - u64 tpt; - u64 ptc64; - u64 ptc127; - u64 ptc255; - u64 ptc511; - u64 ptc1023; - u64 ptc1522; - u64 mptc; - u64 bptc; - u64 tsctc; - u64 tsctfc; - u64 iac; - u64 icrxptc; - u64 icrxatc; - u64 ictxptc; - u64 ictxatc; - u64 ictxqec; - u64 ictxqmtc; - u64 icrxdmtc; - u64 icrxoc; - u64 cbtmpc; - u64 htdpmc; - u64 cbrdpc; - u64 cbrmpc; - u64 rpthc; - u64 hgptc; - u64 htcbdpc; - u64 hgorc; - u64 hgotc; - u64 lenerrs; - u64 scvpc; - u64 hrmpc; - u64 doosync; -}; - - -struct e1000_phy_stats { - u32 idle_errors; - u32 receive_errors; -}; - -struct e1000_host_mng_dhcp_cookie { - u32 signature; - u8 status; - u8 reserved0; - u16 vlan_id; - u32 reserved1; - u16 reserved2; - u8 reserved3; - u8 checksum; -}; - -/* Host Interface "Rev 1" */ -struct e1000_host_command_header { - u8 command_id; - u8 command_length; - u8 command_options; - u8 checksum; -}; - -#define E1000_HI_MAX_DATA_LENGTH 252 -struct e1000_host_command_info { - struct e1000_host_command_header command_header; - u8 command_data[E1000_HI_MAX_DATA_LENGTH]; -}; - -/* Host Interface "Rev 2" */ -struct e1000_host_mng_command_header { - u8 command_id; - u8 checksum; - u16 reserved1; - u16 reserved2; - u16 command_length; -}; - -#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 -struct e1000_host_mng_command_info { - struct e1000_host_mng_command_header command_header; - u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH]; -}; - -#include "igb_mac.h" -#include "igb_phy.h" -#include "igb_nvm.h" -#include "igb_manage.h" - -struct e1000_mac_operations { - /* Function pointers for the MAC. */ - s32 (*init_params)(struct e1000_hw *); - s32 (*id_led_init)(struct e1000_hw *); - s32 (*blink_led)(struct e1000_hw *); - s32 (*check_for_link)(struct e1000_hw *); - bool (*check_mng_mode)(struct e1000_hw *hw); - s32 (*cleanup_led)(struct e1000_hw *); - void (*clear_hw_cntrs)(struct e1000_hw *); - void (*clear_vfta)(struct e1000_hw *); - s32 (*get_bus_info)(struct e1000_hw *); - void (*set_lan_id)(struct e1000_hw *); - s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); - s32 (*led_on)(struct e1000_hw *); - s32 (*led_off)(struct e1000_hw *); - void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32); - s32 (*reset_hw)(struct e1000_hw *); - s32 (*init_hw)(struct e1000_hw *); - void (*shutdown_serdes)(struct e1000_hw *); - s32 (*setup_link)(struct e1000_hw *); - s32 (*setup_physical_interface)(struct e1000_hw *); - s32 (*setup_led)(struct e1000_hw *); - void (*write_vfta)(struct e1000_hw *, u32, u32); - void (*mta_set)(struct e1000_hw *, u32); - void (*config_collision_dist)(struct e1000_hw *); - void (*rar_set)(struct e1000_hw *, u8*, u32); - s32 (*read_mac_addr)(struct e1000_hw *); - s32 (*validate_mdi_setting)(struct e1000_hw *); - s32 (*mng_host_if_write)(struct e1000_hw *, u8*, u16, u16, u8*); - s32 (*mng_write_cmd_header)(struct e1000_hw *hw, - struct e1000_host_mng_command_header*); - s32 (*mng_enable_host_if)(struct e1000_hw *); - s32 (*wait_autoneg)(struct e1000_hw *); -}; - -struct e1000_phy_operations { - s32 (*init_params)(struct e1000_hw *); - s32 (*acquire)(struct e1000_hw *); - s32 (*check_polarity)(struct e1000_hw *); - s32 (*check_reset_block)(struct e1000_hw *); - s32 (*commit)(struct e1000_hw *); -#if 0 - s32 (*force_speed_duplex)(struct e1000_hw *); -#endif - s32 (*get_cfg_done)(struct e1000_hw *hw); -#if 0 - s32 (*get_cable_length)(struct e1000_hw *); -#endif - s32 (*get_info)(struct e1000_hw *); - s32 (*read_reg)(struct e1000_hw *, u32, u16 *); - s32 (*read_reg_locked)(struct e1000_hw *, u32, u16 *); - void (*release)(struct e1000_hw *); - s32 (*reset)(struct e1000_hw *); - s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); - s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); - s32 (*write_reg)(struct e1000_hw *, u32, u16); - s32 (*write_reg_locked)(struct e1000_hw *, u32, u16); - void (*power_up)(struct e1000_hw *); - void (*power_down)(struct e1000_hw *); -}; - -struct e1000_nvm_operations { - s32 (*init_params)(struct e1000_hw *); - s32 (*acquire)(struct e1000_hw *); - s32 (*read)(struct e1000_hw *, u16, u16, u16 *); - void (*release)(struct e1000_hw *); - void (*reload)(struct e1000_hw *); - s32 (*update)(struct e1000_hw *); - s32 (*valid_led_default)(struct e1000_hw *, u16 *); - s32 (*validate)(struct e1000_hw *); - s32 (*write)(struct e1000_hw *, u16, u16, u16 *); -}; - -struct e1000_mac_info { - struct e1000_mac_operations ops; - u8 addr[6]; - u8 perm_addr[6]; - - enum e1000_mac_type type; - - u32 collision_delta; - u32 ledctl_default; - u32 ledctl_mode1; - u32 ledctl_mode2; - u32 mc_filter_type; - u32 tx_packet_delta; - u32 txcw; - - u16 current_ifs_val; - u16 ifs_max_val; - u16 ifs_min_val; - u16 ifs_ratio; - u16 ifs_step_size; - u16 mta_reg_count; - u16 uta_reg_count; - - /* Maximum size of the MTA register table in all supported adapters */ - #define MAX_MTA_REG 128 - u32 mta_shadow[MAX_MTA_REG]; - u16 rar_entry_count; - - u8 forced_speed_duplex; - - bool adaptive_ifs; - bool arc_subsystem_valid; - bool asf_firmware_present; - bool autoneg; - bool autoneg_failed; - bool get_link_status; - bool in_ifs_mode; - enum e1000_serdes_link_state serdes_link_state; - bool serdes_has_link; - bool tx_pkt_filtering; -}; - -struct e1000_phy_info { - struct e1000_phy_operations ops; - enum e1000_phy_type type; - - enum e1000_1000t_rx_status local_rx; - enum e1000_1000t_rx_status remote_rx; - enum e1000_ms_type ms_type; - enum e1000_ms_type original_ms_type; - enum e1000_rev_polarity cable_polarity; - enum e1000_smart_speed smart_speed; - - u32 addr; - u32 id; - u32 reset_delay_us; /* in usec */ - u32 revision; - - enum e1000_media_type media_type; - - u16 autoneg_advertised; - u16 autoneg_mask; - u16 cable_length; - u16 max_cable_length; - u16 min_cable_length; - - u8 mdix; - - bool disable_polarity_correction; - bool is_mdix; - bool polarity_correction; - bool reset_disable; - bool speed_downgraded; - bool autoneg_wait_to_complete; -}; - -struct e1000_nvm_info { - struct e1000_nvm_operations ops; - enum e1000_nvm_type type; - enum e1000_nvm_override override; - - u32 flash_bank_size; - u32 flash_base_addr; - - u16 word_size; - u16 delay_usec; - u16 address_bits; - u16 opcode_bits; - u16 page_size; -}; - -struct e1000_bus_info { - enum e1000_bus_type type; - enum e1000_bus_speed speed; - enum e1000_bus_width width; - - u16 func; - u16 pci_cmd_word; -}; - -struct e1000_fc_info { - u32 high_water; /* Flow control high-water mark */ - u32 low_water; /* Flow control low-water mark */ - u16 pause_time; /* Flow control pause timer */ - bool send_xon; /* Flow control send XON */ - bool strict_ieee; /* Strict IEEE mode */ - enum e1000_fc_mode current_mode; /* FC mode in effect */ - enum e1000_fc_mode requested_mode; /* FC mode requested by caller */ -}; - -struct e1000_mbx_operations { - s32 (*init_params)(struct e1000_hw *hw); - s32 (*read)(struct e1000_hw *, u32 *, u16, u16); - s32 (*write)(struct e1000_hw *, u32 *, u16, u16); - s32 (*read_posted)(struct e1000_hw *, u32 *, u16, u16); - s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16); - s32 (*check_for_msg)(struct e1000_hw *, u16); - s32 (*check_for_ack)(struct e1000_hw *, u16); - s32 (*check_for_rst)(struct e1000_hw *, u16); -}; - -struct e1000_mbx_stats { - u32 msgs_tx; - u32 msgs_rx; - - u32 acks; - u32 reqs; - u32 rsts; -}; - -struct e1000_mbx_info { - struct e1000_mbx_operations ops; - struct e1000_mbx_stats stats; - u32 timeout; - u32 usec_delay; - u16 size; -}; - -struct e1000_dev_spec_82575 { - bool sgmii_active; - bool global_device_reset; -}; - -struct e1000_dev_spec_vf { - u32 vf_number; - u32 v2p_mailbox; -}; - - -struct e1000_hw { - void *back; - - u8 __iomem *hw_addr; - u8 __iomem *flash_address; - unsigned long io_base; - - struct e1000_mac_info mac; - struct e1000_fc_info fc; - struct e1000_phy_info phy; - struct e1000_nvm_info nvm; - struct e1000_bus_info bus; - struct e1000_mbx_info mbx; - struct e1000_host_mng_dhcp_cookie mng_cookie; - - union { - struct e1000_dev_spec_82575 _82575; - struct e1000_dev_spec_vf vf; - } dev_spec; - - u16 device_id; - u16 subsystem_vendor_id; - u16 subsystem_device_id; - u16 vendor_id; - - u8 revision_id; -}; - -#include "igb_82575.h" - -/* These functions must be implemented by drivers */ -s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); -s32 igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value); - -#endif /* _IGB_HW_H_ */ diff --git a/src/drivers/net/igb/igb_mac.c b/src/drivers/net/igb/igb_mac.c deleted file mode 100644 index 237c6c75..00000000 --- a/src/drivers/net/igb/igb_mac.c +++ /dev/null @@ -1,1991 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#include "igb.h" - -static s32 igb_set_default_fc_generic(struct e1000_hw *hw); -static s32 igb_commit_fc_settings_generic(struct e1000_hw *hw); -static s32 igb_poll_fiber_serdes_link_generic(struct e1000_hw *hw); -static s32 igb_validate_mdi_setting_generic(struct e1000_hw *hw); -static void igb_set_lan_id_multi_port_pcie(struct e1000_hw *hw); - -/** - * igb_init_mac_ops_generic - Initialize MAC function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void igb_init_mac_ops_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - DEBUGFUNC("igb_init_mac_ops_generic"); - - /* General Setup */ - mac->ops.set_lan_id = igb_set_lan_id_multi_port_pcie; - mac->ops.read_mac_addr = igb_read_mac_addr_generic; - mac->ops.config_collision_dist = igb_config_collision_dist_generic; - /* LINK */ - mac->ops.wait_autoneg = igb_wait_autoneg_generic; - /* Management */ -#if 0 - mac->ops.mng_host_if_write = igb_mng_host_if_write_generic; - mac->ops.mng_write_cmd_header = igb_mng_write_cmd_header_generic; - mac->ops.mng_enable_host_if = igb_mng_enable_host_if_generic; -#endif - /* VLAN, MC, etc. */ - mac->ops.rar_set = igb_rar_set_generic; - mac->ops.validate_mdi_setting = igb_validate_mdi_setting_generic; -} - -/** - * igb_get_bus_info_pcie_generic - Get PCIe bus information - * @hw: pointer to the HW structure - * - * Determines and stores the system bus information for a particular - * network interface. The following bus information is determined and stored: - * bus speed, bus width, type (PCIe), and PCIe function. - **/ -s32 igb_get_bus_info_pcie_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - struct e1000_bus_info *bus = &hw->bus; - - s32 ret_val; - u16 pcie_link_status; - - DEBUGFUNC("igb_get_bus_info_pcie_generic"); - - bus->type = e1000_bus_type_pci_express; - bus->speed = e1000_bus_speed_2500; - - ret_val = igb_read_pcie_cap_reg(hw, - PCIE_LINK_STATUS, - &pcie_link_status); - if (ret_val) - bus->width = e1000_bus_width_unknown; - else - bus->width = (enum e1000_bus_width)((pcie_link_status & - PCIE_LINK_WIDTH_MASK) >> - PCIE_LINK_WIDTH_SHIFT); - - mac->ops.set_lan_id(hw); - - return E1000_SUCCESS; -} - -/** - * igb_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices - * - * @hw: pointer to the HW structure - * - * Determines the LAN function id by reading memory-mapped registers - * and swaps the port value if requested. - **/ -static void igb_set_lan_id_multi_port_pcie(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - u32 reg; - - /* - * The status register reports the correct function number - * for the device regardless of function swap state. - */ - reg = E1000_READ_REG(hw, E1000_STATUS); - bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; -} - -/** - * igb_set_lan_id_single_port - Set LAN id for a single port device - * @hw: pointer to the HW structure - * - * Sets the LAN function id to zero for a single port device. - **/ -void igb_set_lan_id_single_port(struct e1000_hw *hw) -{ - struct e1000_bus_info *bus = &hw->bus; - - bus->func = 0; -} - -/** - * igb_clear_vfta_generic - Clear VLAN filter table - * @hw: pointer to the HW structure - * - * Clears the register array which contains the VLAN filter table by - * setting all the values to 0. - **/ -void igb_clear_vfta_generic(struct e1000_hw *hw) -{ - u32 offset; - - DEBUGFUNC("igb_clear_vfta_generic"); - - for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0); - E1000_WRITE_FLUSH(hw); - } -} - -/** - * igb_write_vfta_generic - Write value to VLAN filter table - * @hw: pointer to the HW structure - * @offset: register offset in VLAN filter table - * @value: register value written to VLAN filter table - * - * Writes value at the given offset in the register array which stores - * the VLAN filter table. - **/ -void igb_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value) -{ - DEBUGFUNC("igb_write_vfta_generic"); - - E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value); - E1000_WRITE_FLUSH(hw); -} - -/** - * igb_init_rx_addrs_generic - Initialize receive address's - * @hw: pointer to the HW structure - * @rar_count: receive address registers - * - * Setups the receive address registers by setting the base receive address - * register to the devices MAC address and clearing all the other receive - * address registers to 0. - **/ -void igb_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count) -{ - u32 i; - u8 mac_addr[ETH_ADDR_LEN] = {0}; - - DEBUGFUNC("igb_init_rx_addrs_generic"); - - /* Setup the receive address */ - DEBUGOUT("Programming MAC Address into RAR[0]\n"); - - hw->mac.ops.rar_set(hw, hw->mac.addr, 0); - - /* Zero out the other (rar_entry_count - 1) receive addresses */ - DEBUGOUT1("Clearing RAR[1-%u]\n", rar_count-1); - for (i = 1; i < rar_count; i++) - hw->mac.ops.rar_set(hw, mac_addr, i); -} - -/** - * igb_check_alt_mac_addr_generic - Check for alternate MAC addr - * @hw: pointer to the HW structure - * - * Checks the nvm for an alternate MAC address. An alternate MAC address - * can be setup by pre-boot software and must be treated like a permanent - * address and must override the actual permanent MAC address. If an - * alternate MAC address is found it is programmed into RAR0, replacing - * the permanent address that was installed into RAR0 by the Si on reset. - * This function will return SUCCESS unless it encounters an error while - * reading the EEPROM. - **/ -s32 igb_check_alt_mac_addr_generic(struct e1000_hw *hw) -{ - u32 i; - s32 ret_val = E1000_SUCCESS; - u16 offset, nvm_alt_mac_addr_offset, nvm_data; - u8 alt_mac_addr[ETH_ADDR_LEN]; - - DEBUGFUNC("igb_check_alt_mac_addr_generic"); - - ret_val = hw->nvm.ops.read(hw, NVM_ALT_MAC_ADDR_PTR, 1, - &nvm_alt_mac_addr_offset); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - if (nvm_alt_mac_addr_offset == 0xFFFF) { - /* There is no Alternate MAC Address */ - goto out; - } - - if (hw->bus.func == E1000_FUNC_1) - nvm_alt_mac_addr_offset += E1000_ALT_MAC_ADDRESS_OFFSET_LAN1; - for (i = 0; i < ETH_ADDR_LEN; i += 2) { - offset = nvm_alt_mac_addr_offset + (i >> 1); - ret_val = hw->nvm.ops.read(hw, offset, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - alt_mac_addr[i] = (u8)(nvm_data & 0xFF); - alt_mac_addr[i + 1] = (u8)(nvm_data >> 8); - } - - /* if multicast bit is set, the alternate address will not be used */ - if (alt_mac_addr[0] & 0x01) { - DEBUGOUT("Ignoring Alternate Mac Address with MC bit set\n"); - goto out; - } - - /* - * We have a valid alternate MAC address, and we want to treat it the - * same as the normal permanent MAC address stored by the HW into the - * RAR. Do this by mapping this address into RAR0. - */ - hw->mac.ops.rar_set(hw, alt_mac_addr, 0); - -out: - return ret_val; -} - -/** - * igb_rar_set_generic - Set receive address register - * @hw: pointer to the HW structure - * @addr: pointer to the receive address - * @index: receive address array register - * - * Sets the receive address array register at index to the address passed - * in by addr. - **/ -void igb_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index) -{ - u32 rar_low, rar_high; - - DEBUGFUNC("igb_rar_set_generic"); - - /* - * HW expects these in little endian so we reverse the byte order - * from network order (big endian) to little endian - */ - rar_low = ((u32) addr[0] | - ((u32) addr[1] << 8) | - ((u32) addr[2] << 16) | ((u32) addr[3] << 24)); - - rar_high = ((u32) addr[4] | ((u32) addr[5] << 8)); - - /* If MAC address zero, no need to set the AV bit */ - if (rar_low || rar_high) - rar_high |= E1000_RAH_AV; - - /* - * Some bridges will combine consecutive 32-bit writes into - * a single burst write, which will malfunction on some parts. - * The flushes avoid this. - */ - E1000_WRITE_REG(hw, E1000_RAL(index), rar_low); - E1000_WRITE_FLUSH(hw); - E1000_WRITE_REG(hw, E1000_RAH(index), rar_high); - E1000_WRITE_FLUSH(hw); -} - -/** - * igb_mta_set_generic - Set multicast filter table address - * @hw: pointer to the HW structure - * @hash_value: determines the MTA register and bit to set - * - * The multicast table address is a register array of 32-bit registers. - * The hash_value is used to determine what register the bit is in, the - * current value is read, the new bit is OR'd in and the new value is - * written back into the register. - **/ -void igb_mta_set_generic(struct e1000_hw *hw, u32 hash_value) -{ - u32 hash_bit, hash_reg, mta; - - DEBUGFUNC("igb_mta_set_generic"); - /* - * The MTA is a register array of 32-bit registers. It is - * treated like an array of (32*mta_reg_count) bits. We want to - * set bit BitArray[hash_value]. So we figure out what register - * the bit is in, read it, OR in the new bit, then write - * back the new value. The (hw->mac.mta_reg_count - 1) serves as a - * mask to bits 31:5 of the hash value which gives us the - * register we're modifying. The hash bit within that register - * is determined by the lower 5 bits of the hash value. - */ - hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - - mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg); - - mta |= (1 << hash_bit); - - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta); - E1000_WRITE_FLUSH(hw); -} - -/** - * igb_update_mc_addr_list_generic - Update Multicast addresses - * @hw: pointer to the HW structure - * @mc_addr_list: array of multicast addresses to program - * @mc_addr_count: number of multicast addresses to program - * - * Updates entire Multicast Table Array. - * The caller must have a packed mc_addr_list of multicast addresses. - **/ -void igb_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count) -{ - u32 hash_value, hash_bit, hash_reg; - int i; - - DEBUGFUNC("igb_update_mc_addr_list_generic"); - - /* clear mta_shadow */ - memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); - - /* update mta_shadow from mc_addr_list */ - for (i = 0; (u32) i < mc_addr_count; i++) { - hash_value = igb_hash_mc_addr_generic(hw, mc_addr_list); - - hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1); - hash_bit = hash_value & 0x1F; - - hw->mac.mta_shadow[hash_reg] |= (1 << hash_bit); - mc_addr_list += (ETH_ADDR_LEN); - } - - /* replace the entire MTA table */ - for (i = hw->mac.mta_reg_count - 1; i >= 0; i--) - E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, hw->mac.mta_shadow[i]); - E1000_WRITE_FLUSH(hw); -} - -/** - * igb_hash_mc_addr_generic - Generate a multicast hash value - * @hw: pointer to the HW structure - * @mc_addr: pointer to a multicast address - * - * Generates a multicast address hash value which is used to determine - * the multicast filter table array address and new table value. See - * igb_mta_set_generic() - **/ -u32 igb_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr) -{ - u32 hash_value, hash_mask; - u8 bit_shift = 0; - - DEBUGFUNC("igb_hash_mc_addr_generic"); - - /* Register count multiplied by bits per register */ - hash_mask = (hw->mac.mta_reg_count * 32) - 1; - - /* - * For a mc_filter_type of 0, bit_shift is the number of left-shifts - * where 0xFF would still fall within the hash mask. - */ - while (hash_mask >> bit_shift != 0xFF) - bit_shift++; - - /* - * The portion of the address that is used for the hash table - * is determined by the mc_filter_type setting. - * The algorithm is such that there is a total of 8 bits of shifting. - * The bit_shift for a mc_filter_type of 0 represents the number of - * left-shifts where the MSB of mc_addr[5] would still fall within - * the hash_mask. Case 0 does this exactly. Since there are a total - * of 8 bits of shifting, then mc_addr[4] will shift right the - * remaining number of bits. Thus 8 - bit_shift. The rest of the - * cases are a variation of this algorithm...essentially raising the - * number of bits to shift mc_addr[5] left, while still keeping the - * 8-bit shifting total. - * - * For example, given the following Destination MAC Address and an - * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask), - * we can see that the bit_shift for case 0 is 4. These are the hash - * values resulting from each mc_filter_type... - * [0] [1] [2] [3] [4] [5] - * 01 AA 00 12 34 56 - * LSB MSB - * - * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563 - * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6 - * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163 - * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634 - */ - switch (hw->mac.mc_filter_type) { - default: - case 0: - break; - case 1: - bit_shift += 1; - break; - case 2: - bit_shift += 2; - break; - case 3: - bit_shift += 4; - break; - } - - hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) | - (((u16) mc_addr[5]) << bit_shift))); - - return hash_value; -} - -/** - * igb_clear_hw_cntrs_base_generic - Clear base hardware counters - * @hw: pointer to the HW structure - * - * Clears the base hardware counters by reading the counter registers. - **/ -void igb_clear_hw_cntrs_base_generic(struct e1000_hw *hw) -{ - DEBUGFUNC("igb_clear_hw_cntrs_base_generic"); - - E1000_READ_REG(hw, E1000_CRCERRS); - E1000_READ_REG(hw, E1000_SYMERRS); - E1000_READ_REG(hw, E1000_MPC); - E1000_READ_REG(hw, E1000_SCC); - E1000_READ_REG(hw, E1000_ECOL); - E1000_READ_REG(hw, E1000_MCC); - E1000_READ_REG(hw, E1000_LATECOL); - E1000_READ_REG(hw, E1000_COLC); - E1000_READ_REG(hw, E1000_DC); - E1000_READ_REG(hw, E1000_SEC); - E1000_READ_REG(hw, E1000_RLEC); - E1000_READ_REG(hw, E1000_XONRXC); - E1000_READ_REG(hw, E1000_XONTXC); - E1000_READ_REG(hw, E1000_XOFFRXC); - E1000_READ_REG(hw, E1000_XOFFTXC); - E1000_READ_REG(hw, E1000_FCRUC); - E1000_READ_REG(hw, E1000_GPRC); - E1000_READ_REG(hw, E1000_BPRC); - E1000_READ_REG(hw, E1000_MPRC); - E1000_READ_REG(hw, E1000_GPTC); - E1000_READ_REG(hw, E1000_GORCL); - E1000_READ_REG(hw, E1000_GORCH); - E1000_READ_REG(hw, E1000_GOTCL); - E1000_READ_REG(hw, E1000_GOTCH); - E1000_READ_REG(hw, E1000_RNBC); - E1000_READ_REG(hw, E1000_RUC); - E1000_READ_REG(hw, E1000_RFC); - E1000_READ_REG(hw, E1000_ROC); - E1000_READ_REG(hw, E1000_RJC); - E1000_READ_REG(hw, E1000_TORL); - E1000_READ_REG(hw, E1000_TORH); - E1000_READ_REG(hw, E1000_TOTL); - E1000_READ_REG(hw, E1000_TOTH); - E1000_READ_REG(hw, E1000_TPR); - E1000_READ_REG(hw, E1000_TPT); - E1000_READ_REG(hw, E1000_MPTC); - E1000_READ_REG(hw, E1000_BPTC); -} - -/** - * igb_check_for_copper_link_generic - Check for link (Copper) - * @hw: pointer to the HW structure - * - * Checks to see of the link status of the hardware has changed. If a - * change in link status has been detected, then we read the PHY registers - * to get the current speed/duplex if link exists. - **/ -s32 igb_check_for_copper_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - bool link; - - DEBUGFUNC("igb_check_for_copper_link"); - - /* - * We only want to go out to the PHY registers to see if Auto-Neg - * has completed and/or if our link status has changed. The - * get_link_status flag is set upon receiving a Link Status - * Change or Rx Sequence Error interrupt. - */ - if (!mac->get_link_status) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* - * First we want to see if the MII Status Register reports - * link. If so, then we want to get the current speed/duplex - * of the PHY. - */ - ret_val = igb_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) - goto out; /* No link detected */ - - mac->get_link_status = false; - - /* - * Check if there was DownShift, must be checked - * immediately after link-up - */ - igb_check_downshift_generic(hw); - - /* - * If we are forcing speed/duplex, then we simply return since - * we have already determined whether we have link or not. - */ - if (!mac->autoneg) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - /* - * Auto-Neg is enabled. Auto Speed Detection takes care - * of MAC speed/duplex configuration. So we only need to - * configure Collision Distance in the MAC. - */ - igb_config_collision_dist_generic(hw); - - /* - * Configure Flow Control now that Auto-Neg has completed. - * First, we need to restore the desired flow control - * settings because we may have had to re-autoneg with a - * different link partner. - */ - ret_val = igb_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - } -out: - return ret_val; -} - -/** - * igb_check_for_fiber_link_generic - Check for link (Fiber) - * @hw: pointer to the HW structure - * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. - **/ -s32 igb_check_for_fiber_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw; - u32 ctrl; - u32 status; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_check_for_fiber_link_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - status = E1000_READ_REG(hw, E1000_STATUS); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - - /* - * If we don't have link (auto-negotiation failed or link partner - * cannot auto-negotiate), the cable is plugged in (we have signal), - * and our link partner is not trying to auto-negotiate with us (we - * are receiving idles or data), we need to force link up. We also - * need to give auto-negotiation time to complete, in case the cable - * was just plugged in. The autoneg_failed flag does this. - */ - /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ - if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) && - (!(rxcw & E1000_RXCW_C))) { - if (mac->autoneg_failed == 0) { - mac->autoneg_failed = 1; - goto out; - } - DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); - - /* Disable auto-negotiation in the TXCW register */ - E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); - - /* Force link-up and also force full-duplex. */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - /* Configure Flow Control after forcing link up. */ - ret_val = igb_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - goto out; - } - } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - /* - * If we are forcing link and we are receiving /C/ ordered - * sets, re-enable auto-negotiation in the TXCW register - * and disable forced link in the Device Control register - * in an attempt to auto-negotiate with our link partner. - */ - DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); - E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); - E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); - - mac->serdes_has_link = true; - } - -out: - return ret_val; -} - -/** - * igb_check_for_serdes_link_generic - Check for link (Serdes) - * @hw: pointer to the HW structure - * - * Checks for link up on the hardware. If link is not up and we have - * a signal, then we need to force link up. - **/ -s32 igb_check_for_serdes_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 rxcw; - u32 ctrl; - u32 status; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_check_for_serdes_link_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - status = E1000_READ_REG(hw, E1000_STATUS); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - - /* - * If we don't have link (auto-negotiation failed or link partner - * cannot auto-negotiate), and our link partner is not trying to - * auto-negotiate with us (we are receiving idles or data), - * we need to force link up. We also need to give auto-negotiation - * time to complete. - */ - /* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */ - if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) { - if (mac->autoneg_failed == 0) { - mac->autoneg_failed = 1; - goto out; - } - DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\n"); - - /* Disable auto-negotiation in the TXCW register */ - E1000_WRITE_REG(hw, E1000_TXCW, (mac->txcw & ~E1000_TXCW_ANE)); - - /* Force link-up and also force full-duplex. */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - /* Configure Flow Control after forcing link up. */ - ret_val = igb_config_fc_after_link_up_generic(hw); - if (ret_val) { - DEBUGOUT("Error configuring flow control\n"); - goto out; - } - } else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) { - /* - * If we are forcing link and we are receiving /C/ ordered - * sets, re-enable auto-negotiation in the TXCW register - * and disable forced link in the Device Control register - * in an attempt to auto-negotiate with our link partner. - */ - DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n"); - E1000_WRITE_REG(hw, E1000_TXCW, mac->txcw); - E1000_WRITE_REG(hw, E1000_CTRL, (ctrl & ~E1000_CTRL_SLU)); - - mac->serdes_has_link = true; - } else if (!(E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW))) { - /* - * If we force link for non-auto-negotiation switch, check - * link status based on MAC synchronization for internal - * serdes media type. - */ - /* SYNCH bit and IV bit are sticky. */ - usec_delay(10); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - if (rxcw & E1000_RXCW_SYNCH) { - if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = true; - DEBUGOUT("SERDES: Link up - forced.\n"); - } - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - force failed.\n"); - } - } - - if (E1000_TXCW_ANE & E1000_READ_REG(hw, E1000_TXCW)) { - status = E1000_READ_REG(hw, E1000_STATUS); - if (status & E1000_STATUS_LU) { - /* SYNCH bit and IV bit are sticky, so reread rxcw. */ - usec_delay(10); - rxcw = E1000_READ_REG(hw, E1000_RXCW); - if (rxcw & E1000_RXCW_SYNCH) { - if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = true; - DEBUGOUT("SERDES: Link up - autoneg " - "completed sucessfully.\n"); - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - invalid" - "codewords detected in autoneg.\n"); - } - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - no sync.\n"); - } - } else { - mac->serdes_has_link = false; - DEBUGOUT("SERDES: Link down - autoneg failed\n"); - } - } - -out: - return ret_val; -} - -/** - * igb_setup_link_generic - Setup flow control and link settings - * @hw: pointer to the HW structure - * - * Determines which flow control settings to use, then configures flow - * control. Calls the appropriate media-specific link configuration - * function. Assuming the adapter has a valid link partner, a valid link - * should be established. Assumes the hardware has previously been reset - * and the transmitter and receiver are not enabled. - **/ -s32 igb_setup_link_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_setup_link_generic"); - - /* - * In the case of the phy reset being blocked, we already have a link. - * We do not need to set it up again. - */ - if (hw->phy.ops.check_reset_block) - if (hw->phy.ops.check_reset_block(hw)) - goto out; - - /* - * If requested flow control is set to default, set flow control - * based on the EEPROM flow control settings. - */ - if (hw->fc.requested_mode == e1000_fc_default) { - ret_val = igb_set_default_fc_generic(hw); - if (ret_val) - goto out; - } - - /* - * Save off the requested flow control mode for use later. Depending - * on the link partner's capabilities, we may or may not use this mode. - */ - hw->fc.current_mode = hw->fc.requested_mode; - - DEBUGOUT1("After fix-ups FlowControl is now = %x\n", - hw->fc.current_mode); - - /* Call the necessary media_type subroutine to configure the link. */ - ret_val = hw->mac.ops.setup_physical_interface(hw); - if (ret_val) - goto out; - - /* - * Initialize the flow control address, type, and PAUSE timer - * registers to their default values. This is done even if flow - * control is disabled, because it does not hurt anything to - * initialize these registers. - */ - DEBUGOUT("Initializing the Flow Control address, type and timer regs\n"); - E1000_WRITE_REG(hw, E1000_FCT, FLOW_CONTROL_TYPE); - E1000_WRITE_REG(hw, E1000_FCAH, FLOW_CONTROL_ADDRESS_HIGH); - E1000_WRITE_REG(hw, E1000_FCAL, FLOW_CONTROL_ADDRESS_LOW); - - E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time); - - ret_val = igb_set_fc_watermarks_generic(hw); - -out: - return ret_val; -} - -/** - * igb_setup_fiber_serdes_link_generic - Setup link for fiber/serdes - * @hw: pointer to the HW structure - * - * Configures collision distance and flow control for fiber and serdes - * links. Upon successful setup, poll for link. - **/ -s32 igb_setup_fiber_serdes_link_generic(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_setup_fiber_serdes_link_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* Take the link out of reset */ - ctrl &= ~E1000_CTRL_LRST; - - igb_config_collision_dist_generic(hw); - - ret_val = igb_commit_fc_settings_generic(hw); - if (ret_val) - goto out; - - /* - * Since auto-negotiation is enabled, take the link out of reset (the - * link will be in reset, because we previously reset the chip). This - * will restart auto-negotiation. If auto-negotiation is successful - * then the link-up status bit will be set and the flow control enable - * bits (RFCE and TFCE) will be set according to their negotiated value. - */ - DEBUGOUT("Auto-negotiation enabled\n"); - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - E1000_WRITE_FLUSH(hw); - msec_delay(1); - - /* - * For these adapters, the SW definable pin 1 is set when the optics - * detect a signal. If we have a signal, then poll for a "Link-Up" - * indication. - */ - if (hw->phy.media_type == e1000_media_type_internal_serdes || - (E1000_READ_REG(hw, E1000_CTRL) & E1000_CTRL_SWDPIN1)) { - ret_val = igb_poll_fiber_serdes_link_generic(hw); - } else { - DEBUGOUT("No signal detected\n"); - } - -out: - return ret_val; -} - -/** - * igb_config_collision_dist_generic - Configure collision distance - * @hw: pointer to the HW structure - * - * Configures the collision distance to the default value and is used - * during link setup. Currently no func pointer exists and all - * implementations are handled in the generic version of this function. - **/ -void igb_config_collision_dist_generic(struct e1000_hw *hw) -{ - u32 tctl; - - DEBUGFUNC("igb_config_collision_dist_generic"); - - tctl = E1000_READ_REG(hw, E1000_TCTL); - - tctl &= ~E1000_TCTL_COLD; - tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT; - - E1000_WRITE_REG(hw, E1000_TCTL, tctl); - E1000_WRITE_FLUSH(hw); -} - -/** - * igb_poll_fiber_serdes_link_generic - Poll for link up - * @hw: pointer to the HW structure - * - * Polls for link up by reading the status register, if link fails to come - * up with auto-negotiation, then the link is forced if a signal is detected. - **/ -static s32 igb_poll_fiber_serdes_link_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 i, status; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_poll_fiber_serdes_link_generic"); - - /* - * If we have a signal (the cable is plugged in, or assumed true for - * serdes media) then poll for a "Link-Up" indication in the Device - * Status Register. Time-out if a link isn't seen in 500 milliseconds - * seconds (Auto-negotiation should complete in less than 500 - * milliseconds even if the other end is doing it in SW). - */ - for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) { - msec_delay(10); - status = E1000_READ_REG(hw, E1000_STATUS); - if (status & E1000_STATUS_LU) - break; - } - if (i == FIBER_LINK_UP_LIMIT) { - DEBUGOUT("Never got a valid link from auto-neg!!!\n"); - mac->autoneg_failed = 1; - /* - * AutoNeg failed to achieve a link, so we'll call - * mac->check_for_link. This routine will force the - * link up if we detect a signal. This will allow us to - * communicate with non-autonegotiating link partners. - */ - ret_val = hw->mac.ops.check_for_link(hw); - if (ret_val) { - DEBUGOUT("Error while checking for link\n"); - goto out; - } - mac->autoneg_failed = 0; - } else { - mac->autoneg_failed = 0; - DEBUGOUT("Valid Link Found\n"); - } - -out: - return ret_val; -} - -/** - * igb_commit_fc_settings_generic - Configure flow control - * @hw: pointer to the HW structure - * - * Write the flow control settings to the Transmit Config Word Register (TXCW) - * base on the flow control settings in e1000_mac_info. - **/ -static s32 igb_commit_fc_settings_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 txcw; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_commit_fc_settings_generic"); - - /* - * Check for a software override of the flow control settings, and - * setup the device accordingly. If auto-negotiation is enabled, then - * software will have to set the "PAUSE" bits to the correct value in - * the Transmit Config Word Register (TXCW) and re-start auto- - * negotiation. However, if auto-negotiation is disabled, then - * software will have to manually configure the two flow control enable - * bits in the CTRL register. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames, - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames but we - * do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - */ - switch (hw->fc.current_mode) { - case e1000_fc_none: - /* Flow control completely disabled by a software over-ride. */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); - break; - case e1000_fc_rx_pause: - /* - * Rx Flow control is enabled and Tx Flow control is disabled - * by a software over-ride. Since there really isn't a way to - * advertise that we are capable of Rx Pause ONLY, we will - * advertise that we support both symmetric and asymmetric RX - * PAUSE. Later, we will disable the adapter's ability to send - * PAUSE frames. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); - break; - case e1000_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is disabled, - * by a software over-ride. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR); - break; - case e1000_fc_full: - /* - * Flow control (both Rx and Tx) is enabled by a software - * over-ride. - */ - txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK); - break; - default: - DEBUGOUT("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - break; - } - - E1000_WRITE_REG(hw, E1000_TXCW, txcw); - mac->txcw = txcw; - -out: - return ret_val; -} - -/** - * igb_set_fc_watermarks_generic - Set flow control high/low watermarks - * @hw: pointer to the HW structure - * - * Sets the flow control high/low threshold (watermark) registers. If - * flow control XON frame transmission is enabled, then set XON frame - * transmission as well. - **/ -s32 igb_set_fc_watermarks_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u32 fcrtl = 0, fcrth = 0; - - DEBUGFUNC("igb_set_fc_watermarks_generic"); - - /* - * Set the flow control receive threshold registers. Normally, - * these registers will be set to a default threshold that may be - * adjusted later by the driver's runtime code. However, if the - * ability to transmit pause frames is not enabled, then these - * registers will be set to 0. - */ - if (hw->fc.current_mode & e1000_fc_tx_pause) { - /* - * We need to set up the Receive Threshold high and low water - * marks as well as (optionally) enabling the transmission of - * XON frames. - */ - fcrtl = hw->fc.low_water; - if (hw->fc.send_xon) - fcrtl |= E1000_FCRTL_XONE; - - fcrth = hw->fc.high_water; - } - E1000_WRITE_REG(hw, E1000_FCRTL, fcrtl); - E1000_WRITE_REG(hw, E1000_FCRTH, fcrth); - - return ret_val; -} - -/** - * igb_set_default_fc_generic - Set flow control default values - * @hw: pointer to the HW structure - * - * Read the EEPROM for the default values for flow control and store the - * values. - **/ -static s32 igb_set_default_fc_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 nvm_data; - - DEBUGFUNC("igb_set_default_fc_generic"); - - /* - * Read and store word 0x0F of the EEPROM. This word contains bits - * that determine the hardware's default PAUSE (flow control) mode, - * a bit that determines whether the HW defaults to enabling or - * disabling auto-negotiation, and the direction of the - * SW defined pins. If there is no SW over-ride of the flow - * control setting, then the variable hw->fc will - * be initialized based on a value in the EEPROM. - */ - ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data); - - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) - hw->fc.requested_mode = e1000_fc_none; - else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == - NVM_WORD0F_ASM_DIR) - hw->fc.requested_mode = e1000_fc_tx_pause; - else - hw->fc.requested_mode = e1000_fc_full; - -out: - return ret_val; -} - -/** - * igb_force_mac_fc_generic - Force the MAC's flow control settings - * @hw: pointer to the HW structure - * - * Force the MAC's flow control settings. Sets the TFCE and RFCE bits in the - * device control register to reflect the adapter settings. TFCE and RFCE - * need to be explicitly set by software when a copper PHY is used because - * autonegotiation is managed by the PHY rather than the MAC. Software must - * also configure these bits when link is forced on a fiber connection. - **/ -s32 igb_force_mac_fc_generic(struct e1000_hw *hw) -{ - u32 ctrl; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_force_mac_fc_generic"); - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - - /* - * Because we didn't get link via the internal auto-negotiation - * mechanism (we either forced link or we got link via PHY - * auto-neg), we have to manually enable/disable transmit an - * receive flow control. - * - * The "Case" statement below enables/disable flow control - * according to the "hw->fc.current_mode" parameter. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause - * frames but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * frames but we do not receive pause frames). - * 3: Both Rx and Tx flow control (symmetric) is enabled. - * other: No other values should be possible at this point. - */ - DEBUGOUT1("hw->fc.current_mode = %u\n", hw->fc.current_mode); - - switch (hw->fc.current_mode) { - case e1000_fc_none: - ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); - break; - case e1000_fc_rx_pause: - ctrl &= (~E1000_CTRL_TFCE); - ctrl |= E1000_CTRL_RFCE; - break; - case e1000_fc_tx_pause: - ctrl &= (~E1000_CTRL_RFCE); - ctrl |= E1000_CTRL_TFCE; - break; - case e1000_fc_full: - ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE); - break; - default: - DEBUGOUT("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - -out: - return ret_val; -} - -/** - * igb_config_fc_after_link_up_generic - Configures flow control after link - * @hw: pointer to the HW structure - * - * Checks the status of auto-negotiation after link up to ensure that the - * speed and duplex were not forced. If the link needed to be forced, then - * flow control needs to be forced also. If auto-negotiation is enabled - * and did not fail, then we configure flow control based on our link - * partner. - **/ -s32 igb_config_fc_after_link_up_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val = E1000_SUCCESS; - u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg; - u16 speed, duplex; - - DEBUGFUNC("igb_config_fc_after_link_up_generic"); - - /* - * Check for the case where we have fiber media and auto-neg failed - * so we had to force link. In this case, we need to force the - * configuration of the MAC to match the "fc" parameter. - */ - if (mac->autoneg_failed) { - if (hw->phy.media_type == e1000_media_type_fiber || - hw->phy.media_type == e1000_media_type_internal_serdes) - ret_val = igb_force_mac_fc_generic(hw); - } else { - if (hw->phy.media_type == e1000_media_type_copper) - ret_val = igb_force_mac_fc_generic(hw); - } - - if (ret_val) { - DEBUGOUT("Error forcing flow control settings\n"); - goto out; - } - - /* - * Check for the case where we have copper media and auto-neg is - * enabled. In this case, we need to check and see if Auto-Neg - * has completed, and if so, how the PHY and link partner has - * flow control configured. - */ - if ((hw->phy.media_type == e1000_media_type_copper) && mac->autoneg) { - /* - * Read the MII Status Register and check to see if AutoNeg - * has completed. We read this twice because this reg has - * some "sticky" (latched) bits. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &mii_status_reg); - if (ret_val) - goto out; - - if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) { - DEBUGOUT("Copper PHY and Auto Neg " - "has not completed.\n"); - goto out; - } - - /* - * The AutoNeg process has completed, so we now need to - * read both the Auto Negotiation Advertisement - * Register (Address 4) and the Auto_Negotiation Base - * Page Ability Register (Address 5) to determine how - * flow control was negotiated. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_AUTONEG_ADV, - &mii_nway_adv_reg); - if (ret_val) - goto out; - ret_val = hw->phy.ops.read_reg(hw, PHY_LP_ABILITY, - &mii_nway_lp_ability_reg); - if (ret_val) - goto out; - - /* - * Two bits in the Auto Negotiation Advertisement Register - * (Address 4) and two bits in the Auto Negotiation Base - * Page Ability Register (Address 5) determine flow control - * for both the PHY and the link partner. The following - * table, taken out of the IEEE 802.3ab/D6.0 dated March 25, - * 1999, describes these PAUSE resolution bits and how flow - * control is determined based upon these settings. - * NOTE: DC = Don't Care - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution - *-------|---------|-------|---------|-------------------- - * 0 | 0 | DC | DC | e1000_fc_none - * 0 | 1 | 0 | DC | e1000_fc_none - * 0 | 1 | 1 | 0 | e1000_fc_none - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - * 1 | 0 | 0 | DC | e1000_fc_none - * 1 | DC | 1 | DC | e1000_fc_full - * 1 | 1 | 0 | 0 | e1000_fc_none - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause - * - * Are both PAUSE bits set to 1? If so, this implies - * Symmetric Flow Control is enabled at both ends. The - * ASM_DIR bits are irrelevant per the spec. - * - * For Symmetric Flow Control: - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | DC | 1 | DC | E1000_fc_full - * - */ - if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) { - /* - * Now we need to check if the user selected Rx ONLY - * of pause frames. In this case, we had to advertise - * FULL flow control because we could not advertise RX - * ONLY. Hence, we must now check to see if we need to - * turn OFF the TRANSMISSION of PAUSE frames. - */ - if (hw->fc.requested_mode == e1000_fc_full) { - hw->fc.current_mode = e1000_fc_full; - DEBUGOUT("Flow Control = FULL.\r\n"); - } else { - hw->fc.current_mode = e1000_fc_rx_pause; - DEBUGOUT("Flow Control = " - "RX PAUSE frames only.\r\n"); - } - } - /* - * For receiving PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 0 | 1 | 1 | 1 | e1000_fc_tx_pause - */ - else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = e1000_fc_tx_pause; - DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n"); - } - /* - * For transmitting PAUSE frames ONLY. - * - * LOCAL DEVICE | LINK PARTNER - * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result - *-------|---------|-------|---------|-------------------- - * 1 | 1 | 0 | 1 | e1000_fc_rx_pause - */ - else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) && - (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && - !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && - (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.current_mode = e1000_fc_rx_pause; - DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n"); - } else { - /* - * Per the IEEE spec, at this point flow control - * should be disabled. - */ - hw->fc.current_mode = e1000_fc_none; - DEBUGOUT("Flow Control = NONE.\r\n"); - } - - /* - * Now we need to do one last check... If we auto- - * negotiated to HALF DUPLEX, flow control should not be - * enabled per IEEE 802.3 spec. - */ - ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex); - if (ret_val) { - DEBUGOUT("Error getting link speed and duplex\n"); - goto out; - } - - if (duplex == HALF_DUPLEX) - hw->fc.current_mode = e1000_fc_none; - - /* - * Now we call a subroutine to actually force the MAC - * controller to use the correct flow control settings. - */ - ret_val = igb_force_mac_fc_generic(hw); - if (ret_val) { - DEBUGOUT("Error forcing flow control settings\n"); - goto out; - } - } - -out: - return ret_val; -} - -/** - * igb_get_speed_and_duplex_copper_generic - Retrieve current speed/duplex - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * Read the status register for the current speed/duplex and store the current - * speed and duplex for copper connections. - **/ -s32 igb_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, - u16 *duplex) -{ - u32 status; - - DEBUGFUNC("igb_get_speed_and_duplex_copper_generic"); - - status = E1000_READ_REG(hw, E1000_STATUS); - if (status & E1000_STATUS_SPEED_1000) { - *speed = SPEED_1000; - DEBUGOUT("1000 Mbs, "); - } else if (status & E1000_STATUS_SPEED_100) { - *speed = SPEED_100; - DEBUGOUT("100 Mbs, "); - } else { - *speed = SPEED_10; - DEBUGOUT("10 Mbs, "); - } - - if (status & E1000_STATUS_FD) { - *duplex = FULL_DUPLEX; - DEBUGOUT("Full Duplex\n"); - } else { - *duplex = HALF_DUPLEX; - DEBUGOUT("Half Duplex\n"); - } - - return E1000_SUCCESS; -} - -/** - * igb_get_speed_and_duplex_fiber_generic - Retrieve current speed/duplex - * @hw: pointer to the HW structure - * @speed: stores the current speed - * @duplex: stores the current duplex - * - * Sets the speed and duplex to gigabit full duplex (the only possible option) - * for fiber/serdes links. - **/ -s32 igb_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw __unused, - u16 *speed, u16 *duplex) -{ - DEBUGFUNC("igb_get_speed_and_duplex_fiber_serdes_generic"); - - *speed = SPEED_1000; - *duplex = FULL_DUPLEX; - - return E1000_SUCCESS; -} - -/** - * igb_get_hw_semaphore_generic - Acquire hardware semaphore - * @hw: pointer to the HW structure - * - * Acquire the HW semaphore to access the PHY or NVM - **/ -s32 igb_get_hw_semaphore_generic(struct e1000_hw *hw) -{ - u32 swsm; - s32 ret_val = E1000_SUCCESS; - s32 timeout = hw->nvm.word_size + 1; - s32 i = 0; - - DEBUGFUNC("igb_get_hw_semaphore_generic"); - - /* Get the SW semaphore */ - while (i < timeout) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - if (!(swsm & E1000_SWSM_SMBI)) - break; - - usec_delay(50); - i++; - } - - if (i == timeout) { - DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - /* Get the FW semaphore. */ - for (i = 0; i < timeout; i++) { - swsm = E1000_READ_REG(hw, E1000_SWSM); - E1000_WRITE_REG(hw, E1000_SWSM, swsm | E1000_SWSM_SWESMBI); - - /* Semaphore acquired if bit latched */ - if (E1000_READ_REG(hw, E1000_SWSM) & E1000_SWSM_SWESMBI) - break; - - usec_delay(50); - } - - if (i == timeout) { - /* Release semaphores */ - igb_put_hw_semaphore_generic(hw); - DEBUGOUT("Driver can't access the NVM\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * igb_put_hw_semaphore_generic - Release hardware semaphore - * @hw: pointer to the HW structure - * - * Release hardware semaphore used to access the PHY or NVM - **/ -void igb_put_hw_semaphore_generic(struct e1000_hw *hw) -{ - u32 swsm; - - DEBUGFUNC("igb_put_hw_semaphore_generic"); - - swsm = E1000_READ_REG(hw, E1000_SWSM); - - swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); - - E1000_WRITE_REG(hw, E1000_SWSM, swsm); -} - -/** - * igb_get_auto_rd_done_generic - Check for auto read completion - * @hw: pointer to the HW structure - * - * Check EEPROM for Auto Read done bit. - **/ -s32 igb_get_auto_rd_done_generic(struct e1000_hw *hw) -{ - s32 i = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_get_auto_rd_done_generic"); - - while (i < AUTO_READ_DONE_TIMEOUT) { - if (E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_AUTO_RD) - break; - msec_delay(1); - i++; - } - - if (i == AUTO_READ_DONE_TIMEOUT) { - DEBUGOUT("Auto read by HW from NVM has not completed.\n"); - ret_val = -E1000_ERR_RESET; - goto out; - } - -out: - return ret_val; -} - -/** - * igb_valid_led_default_generic - Verify a valid default LED config - * @hw: pointer to the HW structure - * @data: pointer to the NVM (EEPROM) - * - * Read the EEPROM for the current default LED configuration. If the - * LED configuration is not valid, set to a valid LED configuration. - **/ -s32 igb_valid_led_default_generic(struct e1000_hw *hw, u16 *data) -{ - s32 ret_val; - - DEBUGFUNC("igb_valid_led_default_generic"); - - ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - - if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) - *data = ID_LED_DEFAULT; - -out: - return ret_val; -} - -/** - * e1000_id_led_init_generic - - * @hw: pointer to the HW structure - * - **/ -s32 igb_id_led_init_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - s32 ret_val; - const u32 ledctl_mask = 0x000000FF; - const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON; - const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF; - u16 data, i, temp; - const u16 led_mask = 0x0F; - - DEBUGFUNC("igb_id_led_init_generic"); - - ret_val = hw->nvm.ops.valid_led_default(hw, &data); - if (ret_val) - goto out; - - mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL); - mac->ledctl_mode1 = mac->ledctl_default; - mac->ledctl_mode2 = mac->ledctl_default; - - for (i = 0; i < 4; i++) { - temp = (data >> (i << 2)) & led_mask; - switch (temp) { - case ID_LED_ON1_DEF2: - case ID_LED_ON1_ON2: - case ID_LED_ON1_OFF2: - mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode1 |= ledctl_on << (i << 3); - break; - case ID_LED_OFF1_DEF2: - case ID_LED_OFF1_ON2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode1 |= ledctl_off << (i << 3); - break; - default: - /* Do nothing */ - break; - } - switch (temp) { - case ID_LED_DEF1_ON2: - case ID_LED_ON1_ON2: - case ID_LED_OFF1_ON2: - mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode2 |= ledctl_on << (i << 3); - break; - case ID_LED_DEF1_OFF2: - case ID_LED_ON1_OFF2: - case ID_LED_OFF1_OFF2: - mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3)); - mac->ledctl_mode2 |= ledctl_off << (i << 3); - break; - default: - /* Do nothing */ - break; - } - } - -out: - return ret_val; -} - -#if 0 -/** - * igb_setup_led_generic - Configures SW controllable LED - * @hw: pointer to the HW structure - * - * This prepares the SW controllable LED for use and saves the current state - * of the LED so it can be later restored. - **/ -s32 igb_setup_led_generic(struct e1000_hw *hw) -{ - u32 ledctl; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_setup_led_generic"); - - if (hw->mac.ops.setup_led != e1000_setup_led_generic) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - if (hw->phy.media_type == e1000_media_type_fiber) { - ledctl = E1000_READ_REG(hw, E1000_LEDCTL); - hw->mac.ledctl_default = ledctl; - /* Turn off LED0 */ - ledctl &= ~(E1000_LEDCTL_LED0_IVRT | - E1000_LEDCTL_LED0_BLINK | - E1000_LEDCTL_LED0_MODE_MASK); - ledctl |= (E1000_LEDCTL_MODE_LED_OFF << - E1000_LEDCTL_LED0_MODE_SHIFT); - E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl); - } else if (hw->phy.media_type == e1000_media_type_copper) { - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); - } - -out: - return ret_val; -} - -/** - * igb_cleanup_led_generic - Set LED config to default operation - * @hw: pointer to the HW structure - * - * Remove the current LED configuration and set the LED configuration - * to the default value, saved from the EEPROM. - **/ -s32 igb_cleanup_led_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_cleanup_led_generic"); - - if (hw->mac.ops.cleanup_led != e1000_cleanup_led_generic) { - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default); - -out: - return ret_val; -} - -/** - * igb_blink_led_generic - Blink LED - * @hw: pointer to the HW structure - * - * Blink the LEDs which are set to be on. - **/ -s32 igb_blink_led_generic(struct e1000_hw *hw) -{ - u32 ledctl_blink = 0; - u32 i; - - DEBUGFUNC("igb_blink_led_generic"); - - if (hw->phy.media_type == e1000_media_type_fiber) { - /* always blink LED0 for PCI-E fiber */ - ledctl_blink = E1000_LEDCTL_LED0_BLINK | - (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT); - } else { - /* - * set the blink bit for each LED that's "on" (0x0E) - * in ledctl_mode2 - */ - ledctl_blink = hw->mac.ledctl_mode2; - for (i = 0; i < 4; i++) - if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) == - E1000_LEDCTL_MODE_LED_ON) - ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << - (i * 8)); - } - - E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl_blink); - - return E1000_SUCCESS; -} - -/** - * igb_led_on_generic - Turn LED on - * @hw: pointer to the HW structure - * - * Turn LED on. - **/ -s32 igb_led_on_generic(struct e1000_hw *hw) -{ - u32 ctrl; - - DEBUGFUNC("igb_led_on_generic"); - - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl &= ~E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - break; - case e1000_media_type_copper: - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2); - break; - default: - break; - } - - return E1000_SUCCESS; -} - -/** - * igb_led_off_generic - Turn LED off - * @hw: pointer to the HW structure - * - * Turn LED off. - **/ -s32 igb_led_off_generic(struct e1000_hw *hw) -{ - u32 ctrl; - - DEBUGFUNC("igb_led_off_generic"); - - switch (hw->phy.media_type) { - case e1000_media_type_fiber: - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= E1000_CTRL_SWDPIN0; - ctrl |= E1000_CTRL_SWDPIO0; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - break; - case e1000_media_type_copper: - E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1); - break; - default: - break; - } - - return E1000_SUCCESS; -} -#endif - -/** - * igb_set_pcie_no_snoop_generic - Set PCI-express capabilities - * @hw: pointer to the HW structure - * @no_snoop: bitmap of snoop events - * - * Set the PCI-express register to snoop for events enabled in 'no_snoop'. - **/ -void igb_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop) -{ - u32 gcr; - - DEBUGFUNC("igb_set_pcie_no_snoop_generic"); - - if (hw->bus.type != e1000_bus_type_pci_express) - goto out; - - if (no_snoop) { - gcr = E1000_READ_REG(hw, E1000_GCR); - gcr &= ~(PCIE_NO_SNOOP_ALL); - gcr |= no_snoop; - E1000_WRITE_REG(hw, E1000_GCR, gcr); - } -out: - return; -} - -/** - * igb_disable_pcie_master_generic - Disables PCI-express master access - * @hw: pointer to the HW structure - * - * Returns 0 (E1000_SUCCESS) if successful, else returns -10 - * (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not caused - * the master requests to be disabled. - * - * Disables PCI-Express master access and verifies there are no pending - * requests. - **/ -s32 igb_disable_pcie_master_generic(struct e1000_hw *hw) -{ - u32 ctrl; - s32 timeout = MASTER_DISABLE_TIMEOUT; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_disable_pcie_master_generic"); - - if (hw->bus.type != e1000_bus_type_pci_express) - goto out; - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= E1000_CTRL_GIO_MASTER_DISABLE; - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - - while (timeout) { - if (!(E1000_READ_REG(hw, E1000_STATUS) & - E1000_STATUS_GIO_MASTER_ENABLE)) - break; - usec_delay(100); - timeout--; - } - - if (!timeout) { - DEBUGOUT("Master requests are pending.\n"); - ret_val = -E1000_ERR_MASTER_REQUESTS_PENDING; - goto out; - } - -out: - return ret_val; -} - -/** - * igb_reset_adaptive_generic - Reset Adaptive Interframe Spacing - * @hw: pointer to the HW structure - * - * Reset the Adaptive Interframe Spacing throttle to default values. - **/ -void igb_reset_adaptive_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - DEBUGFUNC("igb_reset_adaptive_generic"); - - if (!mac->adaptive_ifs) { - DEBUGOUT("Not in Adaptive IFS mode!\n"); - goto out; - } - - mac->current_ifs_val = 0; - mac->ifs_min_val = IFS_MIN; - mac->ifs_max_val = IFS_MAX; - mac->ifs_step_size = IFS_STEP; - mac->ifs_ratio = IFS_RATIO; - - mac->in_ifs_mode = false; - E1000_WRITE_REG(hw, E1000_AIT, 0); -out: - return; -} - -/** - * igb_update_adaptive_generic - Update Adaptive Interframe Spacing - * @hw: pointer to the HW structure - * - * Update the Adaptive Interframe Spacing Throttle value based on the - * time between transmitted packets and time between collisions. - **/ -void igb_update_adaptive_generic(struct e1000_hw *hw) -{ - struct e1000_mac_info *mac = &hw->mac; - - DEBUGFUNC("igb_update_adaptive_generic"); - - if (!mac->adaptive_ifs) { - DEBUGOUT("Not in Adaptive IFS mode!\n"); - goto out; - } - - if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) { - if (mac->tx_packet_delta > MIN_NUM_XMITS) { - mac->in_ifs_mode = true; - if (mac->current_ifs_val < mac->ifs_max_val) { - if (!mac->current_ifs_val) - mac->current_ifs_val = mac->ifs_min_val; - else - mac->current_ifs_val += - mac->ifs_step_size; - E1000_WRITE_REG(hw, E1000_AIT, mac->current_ifs_val); - } - } - } else { - if (mac->in_ifs_mode && - (mac->tx_packet_delta <= MIN_NUM_XMITS)) { - mac->current_ifs_val = 0; - mac->in_ifs_mode = false; - E1000_WRITE_REG(hw, E1000_AIT, 0); - } - } -out: - return; -} - -/** - * igb_validate_mdi_setting_generic - Verify MDI/MDIx settings - * @hw: pointer to the HW structure - * - * Verify that when not using auto-negotiation that MDI/MDIx is correctly - * set, which is forced to MDI mode only. - **/ -static s32 igb_validate_mdi_setting_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_validate_mdi_setting_generic"); - - if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { - DEBUGOUT("Invalid MDI setting detected\n"); - hw->phy.mdix = 1; - ret_val = -E1000_ERR_CONFIG; - goto out; - } - -out: - return ret_val; -} - -/** - * igb_write_8bit_ctrl_reg_generic - Write a 8bit CTRL register - * @hw: pointer to the HW structure - * @reg: 32bit register offset such as E1000_SCTL - * @offset: register offset to write to - * @data: data to write at register offset - * - * Writes an address/data control type register. There are several of these - * and they all have the format address << 8 | data and bit 31 is polled for - * completion. - **/ -s32 igb_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg, - u32 offset, u8 data) -{ - u32 i, regvalue = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_write_8bit_ctrl_reg_generic"); - - /* Set up the address and data */ - regvalue = ((u32)data) | (offset << E1000_GEN_CTL_ADDRESS_SHIFT); - E1000_WRITE_REG(hw, reg, regvalue); - - /* Poll the ready bit to see if the MDI read completed */ - for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) { - usec_delay(5); - regvalue = E1000_READ_REG(hw, reg); - if (regvalue & E1000_GEN_CTL_READY) - break; - } - if (!(regvalue & E1000_GEN_CTL_READY)) { - DEBUGOUT1("Reg %08x did not indicate ready\n", reg); - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} diff --git a/src/drivers/net/igb/igb_mac.h b/src/drivers/net/igb/igb_mac.h deleted file mode 100644 index 7639e24e..00000000 --- a/src/drivers/net/igb/igb_mac.h +++ /dev/null @@ -1,82 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_MAC_H_ -#define _IGB_MAC_H_ - -/* - * Functions that should not be called directly from drivers but can be used - * by other files in this 'shared code' - */ -void igb_init_mac_ops_generic(struct e1000_hw *hw); -s32 igb_blink_led_generic(struct e1000_hw *hw); -s32 igb_check_for_copper_link_generic(struct e1000_hw *hw); -s32 igb_check_for_fiber_link_generic(struct e1000_hw *hw); -s32 igb_check_for_serdes_link_generic(struct e1000_hw *hw); -s32 igb_cleanup_led_generic(struct e1000_hw *hw); -s32 igb_config_fc_after_link_up_generic(struct e1000_hw *hw); -s32 igb_disable_pcie_master_generic(struct e1000_hw *hw); -s32 igb_force_mac_fc_generic(struct e1000_hw *hw); -s32 igb_get_auto_rd_done_generic(struct e1000_hw *hw); -s32 igb_get_bus_info_pcie_generic(struct e1000_hw *hw); -void igb_set_lan_id_single_port(struct e1000_hw *hw); -s32 igb_get_hw_semaphore_generic(struct e1000_hw *hw); -s32 igb_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16 *speed, - u16 *duplex); -s32 igb_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw, - u16 *speed, u16 *duplex); -s32 igb_id_led_init_generic(struct e1000_hw *hw); -s32 igb_led_on_generic(struct e1000_hw *hw); -s32 igb_led_off_generic(struct e1000_hw *hw); -void igb_update_mc_addr_list_generic(struct e1000_hw *hw, - u8 *mc_addr_list, u32 mc_addr_count); -s32 igb_set_fc_watermarks_generic(struct e1000_hw *hw); -s32 igb_setup_fiber_serdes_link_generic(struct e1000_hw *hw); -s32 igb_setup_led_generic(struct e1000_hw *hw); -s32 igb_setup_link_generic(struct e1000_hw *hw); -s32 igb_write_8bit_ctrl_reg_generic(struct e1000_hw *hw, u32 reg, - u32 offset, u8 data); - -u32 igb_hash_mc_addr_generic(struct e1000_hw *hw, u8 *mc_addr); - -void igb_clear_hw_cntrs_base_generic(struct e1000_hw *hw); -void igb_clear_vfta_generic(struct e1000_hw *hw); -void igb_config_collision_dist_generic(struct e1000_hw *hw); -void igb_init_rx_addrs_generic(struct e1000_hw *hw, u16 rar_count); -void igb_mta_set_generic(struct e1000_hw *hw, u32 hash_value); -void igb_pcix_mmrbc_workaround_generic(struct e1000_hw *hw); -void igb_put_hw_semaphore_generic(struct e1000_hw *hw); -void igb_rar_set_generic(struct e1000_hw *hw, u8 *addr, u32 index); -s32 igb_check_alt_mac_addr_generic(struct e1000_hw *hw); -void igb_reset_adaptive_generic(struct e1000_hw *hw); -void igb_set_pcie_no_snoop_generic(struct e1000_hw *hw, u32 no_snoop); -void igb_update_adaptive_generic(struct e1000_hw *hw); -void igb_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value); - -#endif /* _IGB_MAC_H_ */ diff --git a/src/drivers/net/igb/igb_main.c b/src/drivers/net/igb/igb_main.c deleted file mode 100644 index 9295c2c8..00000000 --- a/src/drivers/net/igb/igb_main.c +++ /dev/null @@ -1,1010 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - Portions Copyright(c) 2010 Marty Connor - Portions Copyright(c) 2010 Entity Cyber, Inc. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#include "igb.h" - -/* Low-level support routines */ - -/** - * igb_read_pcie_cap_reg - retrieve PCIe capability register contents - * @hw: address of board private structure - * @reg: PCIe capability register requested - * @value: where to store requested value - **/ -int32_t igb_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value) -{ - struct igb_adapter *adapter = hw->back; - uint16_t cap_offset; - -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ - cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); - if (!cap_offset) - return -E1000_ERR_CONFIG; - - pci_read_config_word(adapter->pdev, cap_offset + reg, value); - - return E1000_SUCCESS; -} - -/** - * igb_write_pcie_cap_reg - write value to PCIe capability register - * @hw: address of board private structure - * @reg: PCIe capability register to write to - * @value: value to store in given register - **/ -int32_t igb_write_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - struct igb_adapter *adapter = hw->back; - u16 cap_offset; - - cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP); - if (!cap_offset) - return -E1000_ERR_CONFIG; - - pci_write_config_word(adapter->pdev, cap_offset + reg, *value); - - return E1000_SUCCESS; -} - -/** - * igb_irq_disable - Mask off interrupt generation on the NIC - * @adapter: board private structure - **/ -static void igb_irq_disable(struct igb_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - - E1000_WRITE_REG(hw, E1000_IAM, 0); - E1000_WRITE_REG(hw, E1000_IMC, ~0); - E1000_WRITE_FLUSH(hw); -} - -/** - * igb_irq_enable - Enable default interrupt generation settings - * @adapter: board private structure - **/ -static void igb_irq_enable(struct igb_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - - E1000_WRITE_REG(hw, E1000_IMS, IMS_ENABLE_MASK); - E1000_WRITE_REG(hw, E1000_IAM, IMS_ENABLE_MASK); - E1000_WRITE_FLUSH(hw); -} - -/** - * igb_get_hw_control - get control of the h/w from f/w - * @adapter: address of board private structure - * - * igb_get_hw_control sets CTRL_EXT:DRV_LOAD bit. - * For ASF and Pass Through versions of f/w this means that - * the driver is loaded. - * - **/ -void igb_get_hw_control(struct igb_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - u32 ctrl_ext; - - /* Let firmware know the driver has taken over */ - ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - E1000_WRITE_REG(hw, E1000_CTRL_EXT, - ctrl_ext | E1000_CTRL_EXT_DRV_LOAD); -} - -/** - * igb_reset - put adapter in known initial state - * @adapter: board private structure - **/ -void igb_reset(struct igb_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - - struct e1000_mac_info *mac = &hw->mac; - struct e1000_fc_info *fc = &hw->fc; - u32 pba = 0; - u16 hwm; - - /* Repartition Pba for greater than 9k mtu - * To take effect CTRL.RST is required. - */ - switch (mac->type) { - case e1000_82576: - pba = E1000_READ_REG(hw, E1000_RXPBS); - pba &= E1000_RXPBS_SIZE_MASK_82576; - break; - case e1000_82575: - default: - pba = E1000_PBA_34K; - break; - } - - /* flow control settings */ - /* The high water mark must be low enough to fit one full frame - * (or the size used for early receive) above it in the Rx FIFO. - * Set it to the lower of: - * - 90% of the Rx FIFO size, or - * - the full Rx FIFO size minus one full frame */ -#define min(a,b) (((a)<(b))?(a):(b)) - hwm = min(((pba << 10) * 9 / 10), - ((pba << 10) - 2 * adapter->max_frame_size)); - - if (mac->type < e1000_82576) { - fc->high_water = hwm & 0xFFF8; /* 8-byte granularity */ - fc->low_water = fc->high_water - 8; - } else { - fc->high_water = hwm & 0xFFF0; /* 16-byte granularity */ - fc->low_water = fc->high_water - 16; - } - fc->pause_time = 0xFFFF; - fc->send_xon = 1; - fc->current_mode = fc->requested_mode; - - /* Allow time for pending master requests to run */ - igb_reset_hw(hw); - E1000_WRITE_REG(hw, E1000_WUC, 0); - - if (igb_init_hw(hw)) { - DBG ("Hardware Error\n"); - } - - igb_get_phy_info(hw); -} - -/** - * igb_sw_init - Initialize general software structures (struct igb_adapter) - * @adapter: board private structure to initialize - **/ -int igb_sw_init(struct igb_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - struct pci_device *pdev = adapter->pdev; - - /* PCI config space info */ - - hw->vendor_id = pdev->vendor; - hw->device_id = pdev->device; - - pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); - - pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); - - adapter->max_frame_size = MAXIMUM_ETHERNET_VLAN_SIZE + ETH_HLEN + ETH_FCS_LEN; - adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; - - /* Initialize the hardware-specific values */ - if (igb_setup_init_funcs(hw, TRUE)) { - DBG ("Hardware Initialization Failure\n"); - return -EIO; - } - - /* Explicitly disable IRQ since the NIC can be in any state. */ - igb_irq_disable(adapter); - - return 0; -} - -/* TX support routines */ - -/** - * igb_setup_tx_resources - allocate Tx resources (Descriptors) - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int igb_setup_tx_resources ( struct igb_adapter *adapter ) -{ - DBG ( "igb_setup_tx_resources\n" ); - - /* Allocate transmit descriptor ring memory. - It must not cross a 64K boundary because of hardware errata #23 - so we use malloc_dma() requesting a 128 byte block that is - 128 byte aligned. This should guarantee that the memory - allocated will not cross a 64K boundary, because 128 is an - even multiple of 65536 ( 65536 / 128 == 512 ), so all possible - allocations of 128 bytes on a 128 byte boundary will not - cross 64K bytes. - */ - - adapter->tx_base = - malloc_dma ( adapter->tx_ring_size, adapter->tx_ring_size ); - - if ( ! adapter->tx_base ) { - return -ENOMEM; - } - - memset ( adapter->tx_base, 0, adapter->tx_ring_size ); - - DBG ( "adapter->tx_base = %#08lx\n", virt_to_bus ( adapter->tx_base ) ); - - return 0; -} - -/** - * igb_process_tx_packets - process transmitted packets - * - * @v netdev network interface device structure - **/ -static void igb_process_tx_packets ( struct net_device *netdev ) -{ - struct igb_adapter *adapter = netdev_priv ( netdev ); - uint32_t i; - uint32_t tx_status; - struct e1000_tx_desc *tx_curr_desc; - - /* Check status of transmitted packets - */ - DBG ( "process_tx_packets: tx_head = %d, tx_tail = %d\n", adapter->tx_head, - adapter->tx_tail ); - - while ( ( i = adapter->tx_head ) != adapter->tx_tail ) { - - tx_curr_desc = ( void * ) ( adapter->tx_base ) + - ( i * sizeof ( *adapter->tx_base ) ); - - tx_status = tx_curr_desc->upper.data; - - DBG ( " tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); - DBG ( " tx_status = %#08x\n", tx_status ); - - /* if the packet at tx_head is not owned by hardware it is for us */ - if ( ! ( tx_status & E1000_TXD_STAT_DD ) ) - break; - - DBG ( "Sent packet. tx_head: %d tx_tail: %d tx_status: %#08x\n", - adapter->tx_head, adapter->tx_tail, tx_status ); - - if ( tx_status & ( E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | - E1000_TXD_STAT_TU ) ) { - netdev_tx_complete_err ( netdev, adapter->tx_iobuf[i], -EINVAL ); - DBG ( "Error transmitting packet, tx_status: %#08x\n", - tx_status ); - } else { - netdev_tx_complete ( netdev, adapter->tx_iobuf[i] ); - DBG ( "Success transmitting packet, tx_status: %#08x\n", - tx_status ); - } - - /* Decrement count of used descriptors, clear this descriptor - */ - adapter->tx_fill_ctr--; - memset ( tx_curr_desc, 0, sizeof ( *tx_curr_desc ) ); - - adapter->tx_head = ( adapter->tx_head + 1 ) % NUM_TX_DESC; - } -} - -static void igb_free_tx_resources ( struct igb_adapter *adapter ) -{ - DBG ( "igb_free_tx_resources\n" ); - - free_dma ( adapter->tx_base, adapter->tx_ring_size ); -} - -/** - * igb_configure_tx - Configure 8254x Transmit Unit after Reset - * @adapter: board private structure - * - * Configure the Tx unit of the MAC after a reset. - **/ -static void igb_configure_tx ( struct igb_adapter *adapter ) -{ - struct e1000_hw *hw = &adapter->hw; - u32 tctl, txdctl; - - DBG ( "igb_configure_tx\n" ); - - /* disable transmits while setting up the descriptors */ - tctl = E1000_READ_REG ( hw, E1000_TCTL ); - E1000_WRITE_REG ( hw, E1000_TCTL, tctl & ~E1000_TCTL_EN ); - E1000_WRITE_FLUSH(hw); - mdelay(10); - - E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) ); - E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size ); - - DBG ( "E1000_TDBAL(0): %#08x\n", E1000_READ_REG ( hw, E1000_TDBAL(0) ) ); - DBG ( "E1000_TDLEN(0): %d\n", E1000_READ_REG ( hw, E1000_TDLEN(0) ) ); - - /* Setup the HW Tx Head and Tail descriptor pointers */ - E1000_WRITE_REG ( hw, E1000_TDH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_TDT(0), 0 ); - - adapter->tx_head = 0; - adapter->tx_tail = 0; - adapter->tx_fill_ctr = 0; - - txdctl = E1000_READ_REG ( hw, E1000_TXDCTL(0) ); - txdctl |= E1000_TXDCTL_QUEUE_ENABLE; - E1000_WRITE_REG ( hw, E1000_TXDCTL(0), txdctl ); - - /* Setup Transmit Descriptor Settings for eop descriptor */ - adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS; - - /* enable Report Status bit */ - adapter->txd_cmd |= E1000_TXD_CMD_RS; - - /* Program the Transmit Control Register */ - tctl &= ~E1000_TCTL_CT; - tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | - (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); - - igb_config_collision_dist(hw); - - /* Enable transmits */ - tctl |= E1000_TCTL_EN; - E1000_WRITE_REG(hw, E1000_TCTL, tctl); - E1000_WRITE_FLUSH(hw); -} - -/* RX support routines */ - -static void igb_free_rx_resources ( struct igb_adapter *adapter ) -{ - int i; - - DBG ( "igb_free_rx_resources\n" ); - - free_dma ( adapter->rx_base, adapter->rx_ring_size ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - free_iob ( adapter->rx_iobuf[i] ); - } -} - -/** - * igb_refill_rx_ring - allocate Rx io_buffers - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int igb_refill_rx_ring ( struct igb_adapter *adapter ) -{ - int i, rx_curr; - int rc = 0; - struct e1000_rx_desc *rx_curr_desc; - struct e1000_hw *hw = &adapter->hw; - struct io_buffer *iob; - - DBGP ("igb_refill_rx_ring\n"); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - rx_curr = ( ( adapter->rx_curr + i ) % NUM_RX_DESC ); - rx_curr_desc = adapter->rx_base + rx_curr; - - if ( rx_curr_desc->status & E1000_RXD_STAT_DD ) - continue; - - if ( adapter->rx_iobuf[rx_curr] != NULL ) - continue; - - DBG2 ( "Refilling rx desc %d\n", rx_curr ); - - iob = alloc_iob ( MAXIMUM_ETHERNET_VLAN_SIZE ); - adapter->rx_iobuf[rx_curr] = iob; - - if ( ! iob ) { - DBG ( "alloc_iob failed\n" ); - rc = -ENOMEM; - break; - } else { - rx_curr_desc->buffer_addr = virt_to_bus ( iob->data ); - - E1000_WRITE_REG ( hw, E1000_RDT(0), rx_curr ); - } - } - return rc; -} - -/** - * igb_setup_rx_resources - allocate Rx resources (Descriptors) - * - * @v adapter e1000 private structure - * - * @ret rc Returns 0 on success, negative on failure - **/ -static int igb_setup_rx_resources ( struct igb_adapter *adapter ) -{ - int i, rc = 0; - - DBGP ( "igb_setup_rx_resources\n" ); - - /* Allocate receive descriptor ring memory. - It must not cross a 64K boundary because of hardware errata - */ - - adapter->rx_base = - malloc_dma ( adapter->rx_ring_size, adapter->rx_ring_size ); - - if ( ! adapter->rx_base ) { - return -ENOMEM; - } - memset ( adapter->rx_base, 0, adapter->rx_ring_size ); - - for ( i = 0; i < NUM_RX_DESC; i++ ) { - /* let igb_refill_rx_ring() io_buffer allocations */ - adapter->rx_iobuf[i] = NULL; - } - - /* allocate io_buffers */ - rc = igb_refill_rx_ring ( adapter ); - if ( rc < 0 ) - igb_free_rx_resources ( adapter ); - - return rc; -} - -/** - * igb_configure_rx - Configure 8254x Receive Unit after Reset - * @adapter: board private structure - * - * Configure the Rx unit of the MAC after a reset. - **/ -static void igb_configure_rx ( struct igb_adapter *adapter ) -{ - struct e1000_hw *hw = &adapter->hw; - uint32_t rctl, rxdctl, rxcsum, mrqc; - - DBGP ( "igb_configure_rx\n" ); - - /* disable receives while setting up the descriptors */ - rctl = E1000_READ_REG ( hw, E1000_RCTL ); - E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); - E1000_WRITE_FLUSH(hw); - mdelay(10); - - adapter->rx_curr = 0; - - /* Setup the HW Rx Head and Tail Descriptor Pointers and - * the Base and Length of the Rx Descriptor Ring */ - - E1000_WRITE_REG ( hw, E1000_RDBAL(0), virt_to_bus ( adapter->rx_base ) ); - E1000_WRITE_REG ( hw, E1000_RDBAH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_RDLEN(0), adapter->rx_ring_size ); - - E1000_WRITE_REG ( hw, E1000_RDH(0), 0 ); - E1000_WRITE_REG ( hw, E1000_RDT(0), 0 ); - - DBG ( "E1000_RDBAL(0): %#08x\n", E1000_READ_REG ( hw, E1000_RDBAL(0) ) ); - DBG ( "E1000_RDLEN(0): %d\n", E1000_READ_REG ( hw, E1000_RDLEN(0) ) ); - DBG ( "E1000_RCTL: %#08x\n", E1000_READ_REG ( hw, E1000_RCTL ) ); - - rxdctl = E1000_READ_REG ( hw, E1000_RXDCTL(0) ); - rxdctl |= E1000_RXDCTL_QUEUE_ENABLE; - rxdctl &= 0xFFF00000; - rxdctl |= IGB_RX_PTHRESH; - rxdctl |= IGB_RX_HTHRESH << 8; - rxdctl |= IGB_RX_WTHRESH << 16; - E1000_WRITE_REG ( hw, E1000_RXDCTL(0), rxdctl ); - E1000_WRITE_FLUSH ( hw ); - - rxcsum = E1000_READ_REG(hw, E1000_RXCSUM); - rxcsum &= ~( E1000_RXCSUM_TUOFL | E1000_RXCSUM_IPPCSE ); - E1000_WRITE_REG ( hw, E1000_RXCSUM, 0 ); - - /* The initial value for MRQC disables multiple receive - * queues, however this setting is not recommended. - * - Intel® 82576 Gigabit Ethernet Controller Datasheet r2.41 - * Section 8.10.9 Multiple Queues Command Register - MRQC - */ - mrqc = E1000_MRQC_ENABLE_VMDQ; - E1000_WRITE_REG ( hw, E1000_MRQC, mrqc ); - - /* Turn off loopback modes */ - rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); - - /* set maximum packet size */ - rctl |= E1000_RCTL_SZ_2048; - - /* Broadcast enable, multicast promisc, unicast promisc */ - rctl |= E1000_RCTL_BAM | E1000_RCTL_MPE | E1000_RCTL_UPE; - - /* Store bad packets */ - rctl |= E1000_RCTL_SBP; - - /* enable LPE to prevent packets larger than max_frame_size */ - rctl |= E1000_RCTL_LPE; - - /* enable stripping of CRC. */ - rctl |= E1000_RCTL_SECRC; - - /* enable receive control register */ - rctl |= E1000_RCTL_EN; - E1000_WRITE_REG(hw, E1000_RCTL, rctl); - E1000_WRITE_FLUSH(hw); - - /* On the 82576, RDT([0]) must not be "bumped" before - * the enable bit of RXDCTL([0]) is set. - * - Intel® 82576 Gigabit Ethernet Controller Datasheet r2.41 - * Section 4.5.9 receive Initialization - * - * By observation I have found this to occur when the enable bit of - * RCTL is set. The datasheet recommends polling for this bit, - * however as I see no evidence of this in the Linux igb driver - * I have omitted that step. - * - Simon Horman, May 2009 - */ - E1000_WRITE_REG ( hw, E1000_RDT(0), NUM_RX_DESC - 1 ); - - DBG ( "RDBAH: %#08x\n", E1000_READ_REG ( hw, E1000_RDBAH(0) ) ); - DBG ( "RDBAL: %#08x\n", E1000_READ_REG ( hw, E1000_RDBAL(0) ) ); - DBG ( "RDLEN: %d\n", E1000_READ_REG ( hw, E1000_RDLEN(0) ) ); - DBG ( "RCTL: %#08x\n", E1000_READ_REG ( hw, E1000_RCTL ) ); -} - -/** - * igb_process_rx_packets - process received packets - * - * @v netdev network interface device structure - **/ -static void igb_process_rx_packets ( struct net_device *netdev ) -{ - struct igb_adapter *adapter = netdev_priv ( netdev ); - uint32_t i; - uint32_t rx_status; - uint32_t rx_len; - uint32_t rx_err; - struct e1000_rx_desc *rx_curr_desc; - - DBGP ( "igb_process_rx_packets\n" ); - - /* Process received packets - */ - while ( 1 ) { - - i = adapter->rx_curr; - - rx_curr_desc = ( void * ) ( adapter->rx_base ) + - ( i * sizeof ( *adapter->rx_base ) ); - rx_status = rx_curr_desc->status; - - DBG2 ( "Before DD Check RX_status: %#08x\n", rx_status ); - - if ( ! ( rx_status & E1000_RXD_STAT_DD ) ) - break; - - if ( adapter->rx_iobuf[i] == NULL ) - break; - - DBG ( "E1000_RCTL = %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RCTL ) ); - - rx_len = rx_curr_desc->length; - - DBG ( "Received packet, rx_curr: %d rx_status: %#08x rx_len: %d\n", - i, rx_status, rx_len ); - - rx_err = rx_curr_desc->errors; - - iob_put ( adapter->rx_iobuf[i], rx_len ); - - if ( rx_err & E1000_RXD_ERR_FRAME_ERR_MASK ) { - - netdev_rx_err ( netdev, adapter->rx_iobuf[i], -EINVAL ); - DBG ( "igb_process_rx_packets: Corrupted packet received!" - " rx_err: %#08x\n", rx_err ); - } else { - /* Add this packet to the receive queue. */ - netdev_rx ( netdev, adapter->rx_iobuf[i] ); - } - adapter->rx_iobuf[i] = NULL; - - memset ( rx_curr_desc, 0, sizeof ( *rx_curr_desc ) ); - - adapter->rx_curr = ( adapter->rx_curr + 1 ) % NUM_RX_DESC; - } -} - -/** Functions that implement the iPXE driver API **/ - -/** - * igb_close - Disables a network interface - * - * @v netdev network interface device structure - * - **/ -static void igb_close ( struct net_device *netdev ) -{ - struct igb_adapter *adapter = netdev_priv ( netdev ); - struct e1000_hw *hw = &adapter->hw; - uint32_t rctl; - - DBGP ( "igb_close\n" ); - - /* Disable and acknowledge interrupts */ - igb_irq_disable ( adapter ); - E1000_READ_REG ( hw, E1000_ICR ); - - /* disable receives */ - rctl = E1000_READ_REG ( hw, E1000_RCTL ); - E1000_WRITE_REG ( hw, E1000_RCTL, rctl & ~E1000_RCTL_EN ); - E1000_WRITE_FLUSH(hw); - - igb_reset ( adapter ); - - igb_free_tx_resources ( adapter ); - igb_free_rx_resources ( adapter ); -} - -/** - * igb_transmit - Transmit a packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * - * @ret rc Returns 0 on success, negative on failure - */ -static int igb_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) -{ - struct igb_adapter *adapter = netdev_priv( netdev ); - struct e1000_hw *hw = &adapter->hw; - uint32_t tx_curr = adapter->tx_tail; - struct e1000_tx_desc *tx_curr_desc; - - DBGP ("igb_transmit\n"); - - if ( adapter->tx_fill_ctr == NUM_TX_DESC ) { - DBG ("TX overflow\n"); - return -ENOBUFS; - } - - /* Save pointer to iobuf we have been given to transmit, - netdev_tx_complete() will need it later - */ - adapter->tx_iobuf[tx_curr] = iobuf; - - tx_curr_desc = ( void * ) ( adapter->tx_base ) + - ( tx_curr * sizeof ( *adapter->tx_base ) ); - - DBG ( "tx_curr_desc = %#08lx\n", virt_to_bus ( tx_curr_desc ) ); - DBG ( "tx_curr_desc + 16 = %#08lx\n", virt_to_bus ( tx_curr_desc ) + 16 ); - DBG ( "iobuf->data = %#08lx\n", virt_to_bus ( iobuf->data ) ); - - /* Add the packet to TX ring - */ - tx_curr_desc->buffer_addr = virt_to_bus ( iobuf->data ); - tx_curr_desc->upper.data = 0; - tx_curr_desc->lower.data = adapter->txd_cmd | iob_len ( iobuf ); - - DBG ( "TX fill: %d tx_curr: %d addr: %#08lx len: %zd\n", adapter->tx_fill_ctr, - tx_curr, virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); - - /* Point to next free descriptor */ - adapter->tx_tail = ( adapter->tx_tail + 1 ) % NUM_TX_DESC; - adapter->tx_fill_ctr++; - - /* Write new tail to NIC, making packet available for transmit - */ - E1000_WRITE_REG ( hw, E1000_TDT(0), adapter->tx_tail ); - E1000_WRITE_FLUSH(hw); - - return 0; -} - -/** - * igb_poll - Poll for received packets - * - * @v netdev Network device - */ -static void igb_poll ( struct net_device *netdev ) -{ - struct igb_adapter *adapter = netdev_priv( netdev ); - struct e1000_hw *hw = &adapter->hw; - - uint32_t icr; - - DBGP ( "igb_poll\n" ); - - /* Acknowledge interrupts */ - icr = E1000_READ_REG ( hw, E1000_ICR ); - if ( ! icr ) - return; - - DBG ( "igb_poll: intr_status = %#08x\n", icr ); - - igb_process_tx_packets ( netdev ); - - igb_process_rx_packets ( netdev ); - - igb_refill_rx_ring(adapter); -} - -/** - * igb_irq - enable or Disable interrupts - * - * @v adapter e1000 adapter - * @v action requested interrupt action - **/ -static void igb_irq ( struct net_device *netdev, int enable ) -{ - struct igb_adapter *adapter = netdev_priv ( netdev ); - - DBGP ( "igb_irq\n" ); - - if ( enable ) { - igb_irq_enable ( adapter ); - } else { - igb_irq_disable ( adapter ); - } -} - -static struct net_device_operations igb_operations; - -/** - * igb_probe - Initial configuration of NIC - * - * @v pci PCI device - * @v id PCI IDs - * - * @ret rc Return status code - **/ -int igb_probe ( struct pci_device *pdev ) -{ - int i, err; - struct net_device *netdev; - struct igb_adapter *adapter; - unsigned long mmio_start, mmio_len; - struct e1000_hw *hw; - - DBGP ( "igb_probe\n" ); - - err = -ENOMEM; - - /* Allocate net device ( also allocates memory for netdev->priv - and makes netdev-priv point to it ) */ - netdev = alloc_etherdev ( sizeof ( struct igb_adapter ) ); - if ( ! netdev ) { - DBG ( "err_alloc_etherdev\n" ); - goto err_alloc_etherdev; - } - - /* Associate igb-specific network operations operations with - * generic network device layer */ - netdev_init ( netdev, &igb_operations ); - - /* Associate this network device with given PCI device */ - pci_set_drvdata ( pdev, netdev ); - netdev->dev = &pdev->dev; - - /* Initialize driver private storage */ - adapter = netdev_priv ( netdev ); - memset ( adapter, 0, ( sizeof ( *adapter ) ) ); - - adapter->pdev = pdev; - - adapter->ioaddr = pdev->ioaddr; - adapter->hw.io_base = pdev->ioaddr; - - hw = &adapter->hw; - hw->vendor_id = pdev->vendor; - hw->device_id = pdev->device; - - adapter->irqno = pdev->irq; - adapter->netdev = netdev; - adapter->hw.back = adapter; - - adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; - adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN; - - adapter->tx_ring_size = sizeof ( *adapter->tx_base ) * NUM_TX_DESC; - adapter->rx_ring_size = sizeof ( *adapter->rx_base ) * NUM_RX_DESC; - - /* Fix up PCI device */ - adjust_pci_device ( pdev ); - - err = -EIO; - - mmio_start = pci_bar_start ( pdev, PCI_BASE_ADDRESS_0 ); - mmio_len = pci_bar_size ( pdev, PCI_BASE_ADDRESS_0 ); - - DBG ( "mmio_start: %#08lx\n", mmio_start ); - DBG ( "mmio_len: %#08lx\n", mmio_len ); - - adapter->hw.hw_addr = ioremap ( mmio_start, mmio_len ); - DBG ( "adapter->hw.hw_addr: %p\n", adapter->hw.hw_addr ); - - if ( ! adapter->hw.hw_addr ) { - DBG ( "err_ioremap\n" ); - goto err_ioremap; - } - - /* setup adapter struct */ - err = igb_sw_init ( adapter ); - if (err) { - DBG ( "err_sw_init\n" ); - goto err_sw_init; - } - - igb_get_bus_info(hw); - - /* Copper options */ - if (adapter->hw.phy.media_type == e1000_media_type_copper) { - adapter->hw.phy.mdix = AUTO_ALL_MODES; - adapter->hw.phy.disable_polarity_correction = 0; - adapter->hw.phy.ms_type = e1000_ms_hw_default; - } - - DBG ( "adapter->hw.mac.type: %#08x\n", adapter->hw.mac.type ); - - /* Force auto-negotiation */ - adapter->hw.mac.autoneg = 1; - adapter->fc_autoneg = 1; - adapter->hw.phy.autoneg_wait_to_complete = true; - adapter->hw.mac.adaptive_ifs = true; - adapter->hw.fc.requested_mode = e1000_fc_default; - adapter->hw.fc.current_mode = e1000_fc_default; - - igb_validate_mdi_setting(hw); - - /* - * before reading the NVM, reset the controller to - * put the device in a known good starting state - */ - igb_reset_hw(hw); - - /* - * systems with ASPM and others may see the checksum fail on the first - * attempt. Let's give it a few tries - */ - for (i = 0;; i++) { - if (igb_validate_nvm_checksum(&adapter->hw) >= 0) - break; - if (i == 2) { - err = -EIO; - DBG ( "The NVM Checksum Is Not Valid\n" ); - DBG ( "err_eeprom\n" ); - goto err_eeprom; - } - } - - /* copy the MAC address out of the EEPROM */ - if ( igb_read_mac_addr ( &adapter->hw ) ) { - DBG ( "EEPROM Read Error\n" ); - } - - memcpy ( netdev->hw_addr, adapter->hw.mac.perm_addr, ETH_ALEN ); - - /* reset the hardware with the new settings */ - igb_reset ( adapter ); - - /* let the f/w know that the h/w is now under the control of the - * driver. */ - igb_get_hw_control(adapter); - - if ( ( err = register_netdev ( netdev ) ) != 0) { - DBG ( "err_register\n" ); - goto err_register; - } - - /* Mark as link up; we don't yet handle link state */ - netdev_link_up ( netdev ); - - for (i = 0; i < 6; i++) { - DBG ("%02x%s", netdev->ll_addr[i], i == 5 ? "\n" : ":"); - } - - DBG ( "igb_probe succeeded!\n" ); - - /* No errors, return success */ - return 0; - -/* Error return paths */ -err_register: -err_eeprom: -err_sw_init: - iounmap ( adapter->hw.hw_addr ); -err_ioremap: - netdev_put ( netdev ); -err_alloc_etherdev: - return err; -} - -/** - * igb_remove - Device Removal Routine - * - * @v pdev PCI device information struct - * - **/ -void igb_remove ( struct pci_device *pdev ) -{ - struct net_device *netdev = pci_get_drvdata ( pdev ); - struct igb_adapter *adapter = netdev_priv ( netdev ); - - DBGP ( "igb_remove\n" ); - - if ( adapter->hw.flash_address ) - iounmap ( adapter->hw.flash_address ); - if ( adapter->hw.hw_addr ) - iounmap ( adapter->hw.hw_addr ); - - unregister_netdev ( netdev ); - igb_reset ( adapter ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); -} - -/** - * igb_open - Called when a network interface is made active - * - * @v netdev network interface device structure - * @ret rc Return status code, 0 on success, negative value on failure - * - **/ -static int igb_open ( struct net_device *netdev ) -{ - struct igb_adapter *adapter = netdev_priv(netdev); - int err; - - DBGP ( "igb_open\n" ); - - /* allocate transmit descriptors */ - err = igb_setup_tx_resources ( adapter ); - if ( err ) { - DBG ( "Error setting up TX resources!\n" ); - goto err_setup_tx; - } - - /* allocate receive descriptors */ - err = igb_setup_rx_resources ( adapter ); - if ( err ) { - DBG ( "Error setting up RX resources!\n" ); - goto err_setup_rx; - } - - igb_configure_tx ( adapter ); - - igb_configure_rx ( adapter ); - - DBG ( "E1000_RXDCTL(0): %#08x\n", E1000_READ_REG ( &adapter->hw, E1000_RXDCTL(0) ) ); - - return 0; - -err_setup_rx: - DBG ( "err_setup_rx\n" ); - igb_free_tx_resources ( adapter ); -err_setup_tx: - DBG ( "err_setup_tx\n" ); - igb_reset ( adapter ); - - return err; -} - -/** igb net device operations */ -static struct net_device_operations igb_operations = { - .open = igb_open, - .close = igb_close, - .transmit = igb_transmit, - .poll = igb_poll, - .irq = igb_irq, -}; diff --git a/src/drivers/net/igb/igb_manage.c b/src/drivers/net/igb/igb_manage.c deleted file mode 100644 index b29d4c4a..00000000 --- a/src/drivers/net/igb/igb_manage.c +++ /dev/null @@ -1,388 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#include "igb.h" - -#if 0 - -static u8 e1000_calculate_checksum(u8 *buffer, u32 length); - -/** - * e1000_calculate_checksum - Calculate checksum for buffer - * @buffer: pointer to EEPROM - * @length: size of EEPROM to calculate a checksum for - * - * Calculates the checksum for some buffer on a specified length. The - * checksum calculated is returned. - **/ -static u8 e1000_calculate_checksum(u8 *buffer, u32 length) -{ - u32 i; - u8 sum = 0; - - DEBUGFUNC("igb_calculate_checksum"); - - if (!buffer) - return 0; - - for (i = 0; i < length; i++) - sum += buffer[i]; - - return (u8) (0 - sum); -} - -/** - * e1000_mng_enable_host_if_generic - Checks host interface is enabled - * @hw: pointer to the HW structure - * - * Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND - * - * This function checks whether the HOST IF is enabled for command operation - * and also checks whether the previous command is completed. It busy waits - * in case of previous command is not completed. - **/ -s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw) -{ - u32 hicr; - s32 ret_val = E1000_SUCCESS; - u8 i; - - DEBUGFUNC("igb_mng_enable_host_if_generic"); - - /* Check that the host interface is enabled. */ - hicr = E1000_READ_REG(hw, E1000_HICR); - if ((hicr & E1000_HICR_EN) == 0) { - DEBUGOUT("E1000_HOST_EN bit disabled.\n"); - ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; - goto out; - } - /* check the previous command is completed */ - for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) { - hicr = E1000_READ_REG(hw, E1000_HICR); - if (!(hicr & E1000_HICR_C)) - break; - msec_delay_irq(1); - } - - if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) { - DEBUGOUT("Previous command timeout failed .\n"); - ret_val = -E1000_ERR_HOST_INTERFACE_COMMAND; - goto out; - } - -out: - return ret_val; -} - -/** - * e1000_check_mng_mode_generic - Generic check management mode - * @hw: pointer to the HW structure - * - * Reads the firmware semaphore register and returns true (>0) if - * manageability is enabled, else false (0). - **/ -bool e1000_check_mng_mode_generic(struct e1000_hw *hw) -{ - u32 fwsm; - - DEBUGFUNC("igb_check_mng_mode_generic"); - - fwsm = E1000_READ_REG(hw, E1000_FWSM); - - return (fwsm & E1000_FWSM_MODE_MASK) == - (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT); -} - -/** - * e1000_enable_tx_pkt_filtering_generic - Enable packet filtering on TX - * @hw: pointer to the HW structure - * - * Enables packet filtering on transmit packets if manageability is enabled - * and host interface is enabled. - **/ -bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw) -{ - struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie; - u32 *buffer = (u32 *)&hw->mng_cookie; - u32 offset; - s32 ret_val, hdr_csum, csum; - u8 i, len; - bool tx_filter = true; - - DEBUGFUNC("igb_enable_tx_pkt_filtering_generic"); - - /* No manageability, no filtering */ - if (!hw->mac.ops.check_mng_mode(hw)) { - tx_filter = false; - goto out; - } - - /* - * If we can't read from the host interface for whatever - * reason, disable filtering. - */ - ret_val = hw->mac.ops.mng_enable_host_if(hw); - if (ret_val != E1000_SUCCESS) { - tx_filter = false; - goto out; - } - - /* Read in the header. Length and offset are in dwords. */ - len = E1000_MNG_DHCP_COOKIE_LENGTH >> 2; - offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2; - for (i = 0; i < len; i++) { - *(buffer + i) = E1000_READ_REG_ARRAY_DWORD(hw, - E1000_HOST_IF, - offset + i); - } - hdr_csum = hdr->checksum; - hdr->checksum = 0; - csum = e1000_calculate_checksum((u8 *)hdr, - E1000_MNG_DHCP_COOKIE_LENGTH); - /* - * If either the checksums or signature don't match, then - * the cookie area isn't considered valid, in which case we - * take the safe route of assuming Tx filtering is enabled. - */ - if (hdr_csum != csum) - goto out; - if (hdr->signature != E1000_IAMT_SIGNATURE) - goto out; - - /* Cookie area is valid, make the final check for filtering. */ - if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) - tx_filter = false; - -out: - hw->mac.tx_pkt_filtering = tx_filter; - return tx_filter; -} - -/** - * e1000_mng_write_dhcp_info_generic - Writes DHCP info to host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface - * @length: size of the buffer - * - * Writes the DHCP information to the host interface. - **/ -s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, u8 *buffer, - u16 length) -{ - struct e1000_host_mng_command_header hdr; - s32 ret_val; - u32 hicr; - - DEBUGFUNC("igb_mng_write_dhcp_info_generic"); - - hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD; - hdr.command_length = length; - hdr.reserved1 = 0; - hdr.reserved2 = 0; - hdr.checksum = 0; - - /* Enable the host interface */ - ret_val = hw->mac.ops.mng_enable_host_if(hw); - if (ret_val) - goto out; - - /* Populate the host interface with the contents of "buffer". */ - ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length, - sizeof(hdr), &(hdr.checksum)); - if (ret_val) - goto out; - - /* Write the manageability command header */ - ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr); - if (ret_val) - goto out; - - /* Tell the ARC a new command is pending. */ - hicr = E1000_READ_REG(hw, E1000_HICR); - E1000_WRITE_REG(hw, E1000_HICR, hicr | E1000_HICR_C); - -out: - return ret_val; -} - -/** - * e1000_mng_write_cmd_header_generic - Writes manageability command header - * @hw: pointer to the HW structure - * @hdr: pointer to the host interface command header - * - * Writes the command header after does the checksum calculation. - **/ -s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr) -{ - u16 i, length = sizeof(struct e1000_host_mng_command_header); - - DEBUGFUNC("igb_mng_write_cmd_header_generic"); - - /* Write the whole command header structure with new checksum. */ - - hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length); - - length >>= 2; - /* Write the relevant command block into the ram area. */ - for (i = 0; i < length; i++) { - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, i, - *((u32 *) hdr + i)); - E1000_WRITE_FLUSH(hw); - } - - return E1000_SUCCESS; -} - -/** - * e1000_mng_host_if_write_generic - Write to the manageability host interface - * @hw: pointer to the HW structure - * @buffer: pointer to the host interface buffer - * @length: size of the buffer - * @offset: location in the buffer to write to - * @sum: sum of the data (not checksum) - * - * This function writes the buffer content at the offset given on the host if. - * It also does alignment considerations to do the writes in most efficient - * way. Also fills up the sum of the buffer in *buffer parameter. - **/ -s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, - u16 length, u16 offset, u8 *sum) -{ - u8 *tmp; - u8 *bufptr = buffer; - u32 data = 0; - s32 ret_val = E1000_SUCCESS; - u16 remaining, i, j, prev_bytes; - - DEBUGFUNC("igb_mng_host_if_write_generic"); - - /* sum = only sum of the data and it is not checksum */ - - if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH) { - ret_val = -E1000_ERR_PARAM; - goto out; - } - - tmp = (u8 *)&data; - prev_bytes = offset & 0x3; - offset >>= 2; - - if (prev_bytes) { - data = E1000_READ_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset); - for (j = prev_bytes; j < sizeof(u32); j++) { - *(tmp + j) = *bufptr++; - *sum += *(tmp + j); - } - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset, data); - length -= j - prev_bytes; - offset++; - } - - remaining = length & 0x3; - length -= remaining; - - /* Calculate length in DWORDs */ - length >>= 2; - - /* - * The device driver writes the relevant command block into the - * ram area. - */ - for (i = 0; i < length; i++) { - for (j = 0; j < sizeof(u32); j++) { - *(tmp + j) = *bufptr++; - *sum += *(tmp + j); - } - - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, - data); - } - if (remaining) { - for (j = 0; j < sizeof(u32); j++) { - if (j < remaining) - *(tmp + j) = *bufptr++; - else - *(tmp + j) = 0; - - *sum += *(tmp + j); - } - E1000_WRITE_REG_ARRAY_DWORD(hw, E1000_HOST_IF, offset + i, data); - } - -out: - return ret_val; -} - -/** - * e1000_enable_mng_pass_thru - Enable processing of ARP's - * @hw: pointer to the HW structure - * - * Verifies the hardware needs to allow ARPs to be processed by the host. - **/ -bool e1000_enable_mng_pass_thru(struct e1000_hw *hw) -{ - u32 manc; - u32 fwsm, factps; - bool ret_val = false; - - DEBUGFUNC("igb_enable_mng_pass_thru"); - - if (!hw->mac.asf_firmware_present) - goto out; - - manc = E1000_READ_REG(hw, E1000_MANC); - - if (!(manc & E1000_MANC_RCV_TCO_EN) || - !(manc & E1000_MANC_EN_MAC_ADDR_FILTER)) - goto out; - - if (hw->mac.arc_subsystem_valid) { - fwsm = E1000_READ_REG(hw, E1000_FWSM); - factps = E1000_READ_REG(hw, E1000_FACTPS); - - if (!(factps & E1000_FACTPS_MNGCG) && - ((fwsm & E1000_FWSM_MODE_MASK) == - (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) { - ret_val = true; - goto out; - } - } else { - if ((manc & E1000_MANC_SMBUS_EN) && - !(manc & E1000_MANC_ASF_EN)) { - ret_val = true; - goto out; - } - } - -out: - return ret_val; -} - -#endif diff --git a/src/drivers/net/igb/igb_manage.h b/src/drivers/net/igb/igb_manage.h deleted file mode 100644 index ff70d8c9..00000000 --- a/src/drivers/net/igb/igb_manage.h +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_MANAGE_H_ -#define _IGB_MANAGE_H_ - -bool e1000_check_mng_mode_generic(struct e1000_hw *hw); -bool e1000_enable_tx_pkt_filtering_generic(struct e1000_hw *hw); -s32 e1000_mng_enable_host_if_generic(struct e1000_hw *hw); -s32 e1000_mng_host_if_write_generic(struct e1000_hw *hw, u8 *buffer, - u16 length, u16 offset, u8 *sum); -s32 e1000_mng_write_cmd_header_generic(struct e1000_hw *hw, - struct e1000_host_mng_command_header *hdr); -s32 e1000_mng_write_dhcp_info_generic(struct e1000_hw *hw, - u8 *buffer, u16 length); -bool e1000_enable_mng_pass_thru(struct e1000_hw *hw); - -enum e1000_mng_mode { - e1000_mng_mode_none = 0, - e1000_mng_mode_asf, - e1000_mng_mode_pt, - e1000_mng_mode_ipmi, - e1000_mng_mode_host_if_only -}; - -#define E1000_FACTPS_MNGCG 0x20000000 - -#define E1000_FWSM_MODE_MASK 0xE -#define E1000_FWSM_MODE_SHIFT 1 - -#define E1000_MNG_IAMT_MODE 0x3 -#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 -#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 -#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 -#define E1000_MNG_DHCP_TX_PAYLOAD_CMD 64 -#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING 0x1 -#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN 0x2 - -#define E1000_VFTA_ENTRY_SHIFT 5 -#define E1000_VFTA_ENTRY_MASK 0x7F -#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK 0x1F - -#define E1000_HI_MAX_BLOCK_BYTE_LENGTH 1792 /* Num of bytes in range */ -#define E1000_HI_MAX_BLOCK_DWORD_LENGTH 448 /* Num of dwords in range */ -#define E1000_HI_COMMAND_TIMEOUT 500 /* Process HI command limit */ - -#define E1000_HICR_EN 0x01 /* Enable bit - RO */ -/* Driver sets this bit when done to put command in RAM */ -#define E1000_HICR_C 0x02 -#define E1000_HICR_SV 0x04 /* Status Validity */ -#define E1000_HICR_FW_RESET_ENABLE 0x40 -#define E1000_HICR_FW_RESET 0x80 - -/* Intel(R) Active Management Technology signature */ -#define E1000_IAMT_SIGNATURE 0x544D4149 - -#endif /* _IGB_MANAGE_H_ */ diff --git a/src/drivers/net/igb/igb_nvm.c b/src/drivers/net/igb/igb_nvm.c deleted file mode 100644 index 1bad567c..00000000 --- a/src/drivers/net/igb/igb_nvm.c +++ /dev/null @@ -1,627 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#include "igb.h" - -static void igb_stop_nvm(struct e1000_hw *hw); -static void igb_reload_nvm_generic(struct e1000_hw *hw); - -/** - * igb_init_nvm_ops_generic - Initialize NVM function pointers - * @hw: pointer to the HW structure - * - * Setups up the function pointers to no-op functions - **/ -void igb_init_nvm_ops_generic(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - DEBUGFUNC("igb_init_nvm_ops_generic"); - - /* Initialize function pointers */ - nvm->ops.reload = igb_reload_nvm_generic; -} - -/** - * igb_raise_eec_clk - Raise EEPROM clock - * @hw: pointer to the HW structure - * @eecd: pointer to the EEPROM - * - * Enable/Raise the EEPROM clock bit. - **/ -static void igb_raise_eec_clk(struct e1000_hw *hw, u32 *eecd) -{ - *eecd = *eecd | E1000_EECD_SK; - E1000_WRITE_REG(hw, E1000_EECD, *eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(hw->nvm.delay_usec); -} - -/** - * igb_lower_eec_clk - Lower EEPROM clock - * @hw: pointer to the HW structure - * @eecd: pointer to the EEPROM - * - * Clear/Lower the EEPROM clock bit. - **/ -static void igb_lower_eec_clk(struct e1000_hw *hw, u32 *eecd) -{ - *eecd = *eecd & ~E1000_EECD_SK; - E1000_WRITE_REG(hw, E1000_EECD, *eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(hw->nvm.delay_usec); -} - -/** - * igb_shift_out_eec_bits - Shift data bits our to the EEPROM - * @hw: pointer to the HW structure - * @data: data to send to the EEPROM - * @count: number of bits to shift out - * - * We need to shift 'count' bits out to the EEPROM. So, the value in the - * "data" parameter will be shifted out to the EEPROM one bit at a time. - * In order to do this, "data" must be broken down into bits. - **/ -static void igb_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - u32 mask; - - DEBUGFUNC("igb_shift_out_eec_bits"); - - mask = 0x01 << (count - 1); - if (nvm->type == e1000_nvm_eeprom_spi) - eecd |= E1000_EECD_DO; - - do { - eecd &= ~E1000_EECD_DI; - - if (data & mask) - eecd |= E1000_EECD_DI; - - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - - usec_delay(nvm->delay_usec); - - igb_raise_eec_clk(hw, &eecd); - igb_lower_eec_clk(hw, &eecd); - - mask >>= 1; - } while (mask); - - eecd &= ~E1000_EECD_DI; - E1000_WRITE_REG(hw, E1000_EECD, eecd); -} - -/** - * igb_shift_in_eec_bits - Shift data bits in from the EEPROM - * @hw: pointer to the HW structure - * @count: number of bits to shift in - * - * In order to read a register from the EEPROM, we need to shift 'count' bits - * in from the EEPROM. Bits are "shifted in" by raising the clock input to - * the EEPROM (setting the SK bit), and then reading the value of the data out - * "DO" bit. During this "shifting in" process the data in "DI" bit should - * always be clear. - **/ -static u16 igb_shift_in_eec_bits(struct e1000_hw *hw, u16 count) -{ - u32 eecd; - u32 i; - u16 data; - - DEBUGFUNC("igb_shift_in_eec_bits"); - - eecd = E1000_READ_REG(hw, E1000_EECD); - - eecd &= ~(E1000_EECD_DO | E1000_EECD_DI); - data = 0; - - for (i = 0; i < count; i++) { - data <<= 1; - igb_raise_eec_clk(hw, &eecd); - - eecd = E1000_READ_REG(hw, E1000_EECD); - - eecd &= ~E1000_EECD_DI; - if (eecd & E1000_EECD_DO) - data |= 1; - - igb_lower_eec_clk(hw, &eecd); - } - - return data; -} - -/** - * igb_poll_eerd_eewr_done - Poll for EEPROM read/write completion - * @hw: pointer to the HW structure - * @ee_reg: EEPROM flag for polling - * - * Polls the EEPROM status bit for either read or write completion based - * upon the value of 'ee_reg'. - **/ -s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg) -{ - u32 attempts = 100000; - u32 i, reg = 0; - s32 ret_val = -E1000_ERR_NVM; - - DEBUGFUNC("igb_poll_eerd_eewr_done"); - - for (i = 0; i < attempts; i++) { - if (ee_reg == E1000_NVM_POLL_READ) - reg = E1000_READ_REG(hw, E1000_EERD); - else - reg = E1000_READ_REG(hw, E1000_EEWR); - - if (reg & E1000_NVM_RW_REG_DONE) { - ret_val = E1000_SUCCESS; - break; - } - - usec_delay(5); - } - - return ret_val; -} - -/** - * igb_acquire_nvm_generic - Generic request for access to EEPROM - * @hw: pointer to the HW structure - * - * Set the EEPROM access request bit and wait for EEPROM access grant bit. - * Return successful if access grant bit set, else clear the request for - * EEPROM access and return -E1000_ERR_NVM (-1). - **/ -s32 igb_acquire_nvm_generic(struct e1000_hw *hw) -{ - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - s32 timeout = E1000_NVM_GRANT_ATTEMPTS; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_acquire_nvm_generic"); - - E1000_WRITE_REG(hw, E1000_EECD, eecd | E1000_EECD_REQ); - eecd = E1000_READ_REG(hw, E1000_EECD); - - while (timeout) { - if (eecd & E1000_EECD_GNT) - break; - usec_delay(5); - eecd = E1000_READ_REG(hw, E1000_EECD); - timeout--; - } - - if (!timeout) { - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - DEBUGOUT("Could not acquire NVM grant\n"); - ret_val = -E1000_ERR_NVM; - } - - return ret_val; -} - -/** - * igb_standby_nvm - Return EEPROM to standby state - * @hw: pointer to the HW structure - * - * Return the EEPROM to a standby state. - **/ -static void igb_standby_nvm(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - - DEBUGFUNC("igb_standby_nvm"); - - if (nvm->type == e1000_nvm_eeprom_spi) { - /* Toggle CS to flush commands */ - eecd |= E1000_EECD_CS; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(nvm->delay_usec); - eecd &= ~E1000_EECD_CS; - E1000_WRITE_REG(hw, E1000_EECD, eecd); - E1000_WRITE_FLUSH(hw); - usec_delay(nvm->delay_usec); - } -} - -/** - * igb_stop_nvm - Terminate EEPROM command - * @hw: pointer to the HW structure - * - * Terminates the current command by inverting the EEPROM's chip select pin. - **/ -static void igb_stop_nvm(struct e1000_hw *hw) -{ - u32 eecd; - - DEBUGFUNC("igb_stop_nvm"); - - eecd = E1000_READ_REG(hw, E1000_EECD); - if (hw->nvm.type == e1000_nvm_eeprom_spi) { - /* Pull CS high */ - eecd |= E1000_EECD_CS; - igb_lower_eec_clk(hw, &eecd); - } -} - -/** - * igb_release_nvm_generic - Release exclusive access to EEPROM - * @hw: pointer to the HW structure - * - * Stop any current commands to the EEPROM and clear the EEPROM request bit. - **/ -void igb_release_nvm_generic(struct e1000_hw *hw) -{ - u32 eecd; - - DEBUGFUNC("igb_release_nvm_generic"); - - igb_stop_nvm(hw); - - eecd = E1000_READ_REG(hw, E1000_EECD); - eecd &= ~E1000_EECD_REQ; - E1000_WRITE_REG(hw, E1000_EECD, eecd); -} - -/** - * igb_ready_nvm_eeprom - Prepares EEPROM for read/write - * @hw: pointer to the HW structure - * - * Setups the EEPROM for reading and writing. - **/ -static s32 igb_ready_nvm_eeprom(struct e1000_hw *hw) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 eecd = E1000_READ_REG(hw, E1000_EECD); - s32 ret_val = E1000_SUCCESS; - u16 timeout = 0; - u8 spi_stat_reg; - - DEBUGFUNC("igb_ready_nvm_eeprom"); - - if (nvm->type == e1000_nvm_eeprom_spi) { - /* Clear SK and CS */ - eecd &= ~(E1000_EECD_CS | E1000_EECD_SK); - E1000_WRITE_REG(hw, E1000_EECD, eecd); - usec_delay(1); - timeout = NVM_MAX_RETRY_SPI; - - /* - * Read "Status Register" repeatedly until the LSB is cleared. - * The EEPROM will signal that the command has been completed - * by clearing bit 0 of the internal status register. If it's - * not cleared within 'timeout', then error out. - */ - while (timeout) { - igb_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI, - hw->nvm.opcode_bits); - spi_stat_reg = (u8)igb_shift_in_eec_bits(hw, 8); - if (!(spi_stat_reg & NVM_STATUS_RDY_SPI)) - break; - - usec_delay(5); - igb_standby_nvm(hw); - timeout--; - } - - if (!timeout) { - DEBUGOUT("SPI NVM Status error\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - } - -out: - return ret_val; -} - -/** - * igb_read_nvm_eerd - Reads EEPROM using EERD register - * @hw: pointer to the HW structure - * @offset: offset of word in the EEPROM to read - * @words: number of words to read - * @data: word read from the EEPROM - * - * Reads a 16 bit word from the EEPROM using the EERD register. - **/ -s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - u32 i, eerd = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_read_nvm_eerd"); - - /* - * A check for invalid values: offset too large, too many words, - * too many words for the offset, and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - DEBUGOUT("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - for (i = 0; i < words; i++) { - eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) + - E1000_NVM_RW_REG_START; - - E1000_WRITE_REG(hw, E1000_EERD, eerd); - ret_val = igb_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ); - if (ret_val) - break; - - data[i] = (E1000_READ_REG(hw, E1000_EERD) >> - E1000_NVM_RW_REG_DATA); - } - -out: - return ret_val; -} - -/** - * igb_write_nvm_spi - Write to EEPROM using SPI - * @hw: pointer to the HW structure - * @offset: offset within the EEPROM to be written to - * @words: number of words to write - * @data: 16 bit word(s) to be written to the EEPROM - * - * Writes data to EEPROM at offset using SPI interface. - * - * If e1000_update_nvm_checksum is not called after this function , the - * EEPROM will most likely contain an invalid checksum. - **/ -s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data) -{ - struct e1000_nvm_info *nvm = &hw->nvm; - s32 ret_val; - u16 widx = 0; - - DEBUGFUNC("igb_write_nvm_spi"); - - /* - * A check for invalid values: offset too large, too many words, - * and not enough words. - */ - if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) || - (words == 0)) { - DEBUGOUT("nvm parameter(s) out of bounds\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - - ret_val = nvm->ops.acquire(hw); - if (ret_val) - goto out; - - while (widx < words) { - u8 write_opcode = NVM_WRITE_OPCODE_SPI; - - ret_val = igb_ready_nvm_eeprom(hw); - if (ret_val) - goto release; - - igb_standby_nvm(hw); - - /* Send the WRITE ENABLE command (8 bit opcode) */ - igb_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI, - nvm->opcode_bits); - - igb_standby_nvm(hw); - - /* - * Some SPI eeproms use the 8th address bit embedded in the - * opcode - */ - if ((nvm->address_bits == 8) && (offset >= 128)) - write_opcode |= NVM_A8_OPCODE_SPI; - - /* Send the Write command (8-bit opcode + addr) */ - igb_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits); - igb_shift_out_eec_bits(hw, (u16)((offset + widx) * 2), - nvm->address_bits); - - /* Loop to allow for up to whole page write of eeprom */ - while (widx < words) { - u16 word_out = data[widx]; - word_out = (word_out >> 8) | (word_out << 8); - igb_shift_out_eec_bits(hw, word_out, 16); - widx++; - - if ((((offset + widx) * 2) % nvm->page_size) == 0) { - igb_standby_nvm(hw); - break; - } - } - } - - msec_delay(10); -release: - nvm->ops.release(hw); - -out: - return ret_val; -} - -/** - * igb_read_pba_num_generic - Read device part number - * @hw: pointer to the HW structure - * @pba_num: pointer to device part number - * - * Reads the product board assembly (PBA) number from the EEPROM and stores - * the value in pba_num. - **/ -s32 igb_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num) -{ - s32 ret_val; - u16 nvm_data; - - DEBUGFUNC("igb_read_pba_num_generic"); - - ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_0, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - *pba_num = (u32)(nvm_data << 16); - - ret_val = hw->nvm.ops.read(hw, NVM_PBA_OFFSET_1, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - *pba_num |= nvm_data; - -out: - return ret_val; -} - -/** - * igb_read_mac_addr_generic - Read device MAC address - * @hw: pointer to the HW structure - * - * Reads the device MAC address from the EEPROM and stores the value. - * Since devices with two ports use the same EEPROM, we increment the - * last bit in the MAC address for the second port. - **/ -s32 igb_read_mac_addr_generic(struct e1000_hw *hw) -{ - u32 rar_high; - u32 rar_low; - u16 i; - - rar_high = E1000_READ_REG(hw, E1000_RAH(0)); - rar_low = E1000_READ_REG(hw, E1000_RAL(0)); - - for (i = 0; i < E1000_RAL_MAC_ADDR_LEN; i++) - hw->mac.perm_addr[i] = (u8)(rar_low >> (i*8)); - - for (i = 0; i < E1000_RAH_MAC_ADDR_LEN; i++) - hw->mac.perm_addr[i+4] = (u8)(rar_high >> (i*8)); - - for (i = 0; i < ETH_ADDR_LEN; i++) - hw->mac.addr[i] = hw->mac.perm_addr[i]; - - return E1000_SUCCESS; -} - -/** - * igb_validate_nvm_checksum_generic - Validate EEPROM checksum - * @hw: pointer to the HW structure - * - * Calculates the EEPROM checksum by reading/adding each word of the EEPROM - * and then verifies that the sum of the EEPROM is equal to 0xBABA. - **/ -s32 igb_validate_nvm_checksum_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 checksum = 0; - u16 i, nvm_data; - - DEBUGFUNC("igb_validate_nvm_checksum_generic"); - - for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { - ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error\n"); - goto out; - } - checksum += nvm_data; - } - - if (checksum != (u16) NVM_SUM) { - DEBUGOUT("NVM Checksum Invalid\n"); - ret_val = -E1000_ERR_NVM; - goto out; - } - -out: - return ret_val; -} - -/** - * igb_update_nvm_checksum_generic - Update EEPROM checksum - * @hw: pointer to the HW structure - * - * Updates the EEPROM checksum by reading/adding each word of the EEPROM - * up to the checksum. Then calculates the EEPROM checksum and writes the - * value to the EEPROM. - **/ -s32 igb_update_nvm_checksum_generic(struct e1000_hw *hw) -{ - s32 ret_val; - u16 checksum = 0; - u16 i, nvm_data; - - DEBUGFUNC("igb_update_nvm_checksum"); - - for (i = 0; i < NVM_CHECKSUM_REG; i++) { - ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data); - if (ret_val) { - DEBUGOUT("NVM Read Error while updating checksum.\n"); - goto out; - } - checksum += nvm_data; - } - checksum = (u16) NVM_SUM - checksum; - ret_val = hw->nvm.ops.write(hw, NVM_CHECKSUM_REG, 1, &checksum); - if (ret_val) { - DEBUGOUT("NVM Write Error while updating checksum.\n"); - } -out: - return ret_val; -} - -/** - * igb_reload_nvm_generic - Reloads EEPROM - * @hw: pointer to the HW structure - * - * Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the - * extended control register. - **/ -static void igb_reload_nvm_generic(struct e1000_hw *hw) -{ - u32 ctrl_ext; - - DEBUGFUNC("igb_reload_nvm_generic"); - - usec_delay(10); - ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT); - ctrl_ext |= E1000_CTRL_EXT_EE_RST; - E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); - E1000_WRITE_FLUSH(hw); -} - diff --git a/src/drivers/net/igb/igb_nvm.h b/src/drivers/net/igb/igb_nvm.h deleted file mode 100644 index 6b54d44c..00000000 --- a/src/drivers/net/igb/igb_nvm.h +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_NVM_H_ -#define _IGB_NVM_H_ - -void igb_init_nvm_ops_generic(struct e1000_hw *hw); -s32 igb_acquire_nvm_generic(struct e1000_hw *hw); - -s32 igb_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg); -s32 igb_read_mac_addr_generic(struct e1000_hw *hw); -s32 igb_read_pba_num_generic(struct e1000_hw *hw, u32 *pba_num); -s32 igb_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 igb_valid_led_default_generic(struct e1000_hw *hw, u16 *data); -s32 igb_validate_nvm_checksum_generic(struct e1000_hw *hw); -s32 igb_write_nvm_eewr(struct e1000_hw *hw, u16 offset, - u16 words, u16 *data); -s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 igb_update_nvm_checksum_generic(struct e1000_hw *hw); -void igb_release_nvm_generic(struct e1000_hw *hw); - -#define E1000_STM_OPCODE 0xDB00 - -#endif /* _IGB_NVM_H_ */ diff --git a/src/drivers/net/igb/igb_osdep.h b/src/drivers/net/igb/igb_osdep.h deleted file mode 100644 index 84f490f5..00000000 --- a/src/drivers/net/igb/igb_osdep.h +++ /dev/null @@ -1,124 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -/* glue for the OS independent part of e1000 - * includes register access macros - */ - -#ifndef _IGB_OSDEP_H_ -#define _IGB_OSDEP_H_ - -/* Begin OS Dependencies */ - -#define u8 unsigned char -#define bool boolean_t -#define dma_addr_t unsigned long -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - -#define __iomem -#define __devinit - -#define msleep(x) mdelay(x) - -#define ETH_FCS_LEN 4 - -typedef int spinlock_t; -typedef enum { - false = 0, - true = 1 -} boolean_t; - -#define TRUE 1 -#define FALSE 0 - -#define usec_delay(x) udelay(x) -#define msec_delay(x) mdelay(x) -#define msec_delay_irq(x) mdelay(x) - -/* End OS Dependencies */ - -#define PCI_COMMAND_REGISTER PCI_COMMAND -#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE -#define ETH_ADDR_LEN ETH_ALEN - -#define DEBUGOUT(S) if (0) { printf(S); } -#define DEBUGOUT1(S, A...) if (0) { printf(S, A); } - -#define DEBUGFUNC(F) DEBUGOUT(F "\n") -#define DEBUGOUT2 DEBUGOUT1 -#define DEBUGOUT3 DEBUGOUT2 -#define DEBUGOUT7 DEBUGOUT3 - -#define E1000_REGISTER(a, reg) (reg) - -#define E1000_WRITE_REG(a, reg, value) do { \ - writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg))); } while (0) - -#define E1000_READ_REG(a, reg) (readl((a)->hw_addr + E1000_REGISTER(a, reg))) - -#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) do { \ - writel((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2))); } while (0); - -#define E1000_READ_REG_ARRAY(a, reg, offset) ( \ - readl((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 2))) - -#define E1000_READ_REG_ARRAY_DWORD E1000_READ_REG_ARRAY -#define E1000_WRITE_REG_ARRAY_DWORD E1000_WRITE_REG_ARRAY - -#define E1000_WRITE_REG_ARRAY_WORD(a, reg, offset, value) ( \ - writew((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1)))) - -#define E1000_READ_REG_ARRAY_WORD(a, reg, offset) ( \ - readw((a)->hw_addr + E1000_REGISTER(a, reg) + ((offset) << 1))) - -#define E1000_WRITE_REG_ARRAY_BYTE(a, reg, offset, value) ( \ - writeb((value), ((a)->hw_addr + E1000_REGISTER(a, reg) + (offset)))) - -#define E1000_READ_REG_ARRAY_BYTE(a, reg, offset) ( \ - readb((a)->hw_addr + E1000_REGISTER(a, reg) + (offset))) - -#define E1000_WRITE_REG_IO(a, reg, offset) do { \ - outl(reg, ((a)->io_base)); \ - outl(offset, ((a)->io_base + 4)); } while (0) - -#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, E1000_STATUS) - -#define E1000_WRITE_FLASH_REG(a, reg, value) ( \ - writel((value), ((a)->flash_address + reg))) - -#define E1000_WRITE_FLASH_REG16(a, reg, value) ( \ - writew((value), ((a)->flash_address + reg))) - -#define E1000_READ_FLASH_REG(a, reg) (readl((a)->flash_address + reg)) - -#define E1000_READ_FLASH_REG16(a, reg) (readw((a)->flash_address + reg)) - -#endif /* _IGB_OSDEP_H_ */ diff --git a/src/drivers/net/igb/igb_phy.c b/src/drivers/net/igb/igb_phy.c deleted file mode 100644 index 16664fd1..00000000 --- a/src/drivers/net/igb/igb_phy.c +++ /dev/null @@ -1,2470 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#include "igb.h" - -static s32 igb_phy_setup_autoneg(struct e1000_hw *hw); - -#if 0 -/* Cable length tables */ -static const u16 e1000_m88_cable_length_table[] = - { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; -#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_m88_cable_length_table) / \ - sizeof(e1000_m88_cable_length_table[0])) - -static const u16 e1000_igp_2_cable_length_table[] = - { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, - 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, - 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, - 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, - 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, - 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, - 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, - 104, 109, 114, 118, 121, 124}; -#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_igp_2_cable_length_table) / \ - sizeof(e1000_igp_2_cable_length_table[0])) -#endif - -/** - * igb_check_reset_block_generic - Check if PHY reset is blocked - * @hw: pointer to the HW structure - * - * Read the PHY management control register and check whether a PHY reset - * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise - * return E1000_BLK_PHY_RESET (12). - **/ -s32 igb_check_reset_block_generic(struct e1000_hw *hw) -{ - u32 manc; - - DEBUGFUNC("igb_check_reset_block"); - - manc = E1000_READ_REG(hw, E1000_MANC); - - return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? - E1000_BLK_PHY_RESET : E1000_SUCCESS; -} - -/** - * igb_get_phy_id - Retrieve the PHY ID and revision - * @hw: pointer to the HW structure - * - * Reads the PHY registers and stores the PHY ID and possibly the PHY - * revision in the hardware structure. - **/ -s32 igb_get_phy_id(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_id; - - DEBUGFUNC("igb_get_phy_id"); - - if (!(phy->ops.read_reg)) - goto out; - - ret_val = phy->ops.read_reg(hw, PHY_ID1, &phy_id); - if (ret_val) - goto out; - - phy->id = (u32)(phy_id << 16); - usec_delay(20); - ret_val = phy->ops.read_reg(hw, PHY_ID2, &phy_id); - if (ret_val) - goto out; - - phy->id |= (u32)(phy_id & PHY_REVISION_MASK); - phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK); - -out: - return ret_val; -} - -/** - * igb_phy_reset_dsp_generic - Reset PHY DSP - * @hw: pointer to the HW structure - * - * Reset the digital signal processor. - **/ -s32 igb_phy_reset_dsp_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_phy_reset_dsp_generic"); - - if (!(hw->phy.ops.write_reg)) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); - if (ret_val) - goto out; - - ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, 0); - -out: - return ret_val; -} - -/** - * igb_read_phy_reg_mdic - Read MDI control register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the MDI control register in the PHY at offset and stores the - * information read to data. - **/ -s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, mdic = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_read_phy_reg_mdic"); - - /* - * Set up Op-code, Phy Address, and register offset in the MDI - * Control register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - mdic = ((offset << E1000_MDIC_REG_SHIFT) | - (phy->addr << E1000_MDIC_PHY_SHIFT) | - (E1000_MDIC_OP_READ)); - - E1000_WRITE_REG(hw, E1000_MDIC, mdic); - - /* - * Poll the ready bit to see if the MDI read completed - * Increasing the time out as testing showed failures with - * the lower time out - */ - for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { - usec_delay(50); - mdic = E1000_READ_REG(hw, E1000_MDIC); - if (mdic & E1000_MDIC_READY) - break; - } - if (!(mdic & E1000_MDIC_READY)) { - DEBUGOUT("MDI Read did not complete\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - if (mdic & E1000_MDIC_ERROR) { - DEBUGOUT("MDI Error\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - *data = (u16) mdic; - -out: - return ret_val; -} - -/** - * igb_write_phy_reg_mdic - Write MDI control register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write to register at offset - * - * Writes data to MDI control register in the PHY at offset. - **/ -s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, mdic = 0; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_write_phy_reg_mdic"); - - /* - * Set up Op-code, Phy Address, and register offset in the MDI - * Control register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - mdic = (((u32)data) | - (offset << E1000_MDIC_REG_SHIFT) | - (phy->addr << E1000_MDIC_PHY_SHIFT) | - (E1000_MDIC_OP_WRITE)); - - E1000_WRITE_REG(hw, E1000_MDIC, mdic); - - /* - * Poll the ready bit to see if the MDI read completed - * Increasing the time out as testing showed failures with - * the lower time out - */ - for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { - usec_delay(50); - mdic = E1000_READ_REG(hw, E1000_MDIC); - if (mdic & E1000_MDIC_READY) - break; - } - if (!(mdic & E1000_MDIC_READY)) { - DEBUGOUT("MDI Write did not complete\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - if (mdic & E1000_MDIC_ERROR) { - DEBUGOUT("MDI Error\n"); - ret_val = -E1000_ERR_PHY; - goto out; - } - -out: - return ret_val; -} - -/** - * igb_read_phy_reg_i2c - Read PHY register using i2c - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY register at offset using the i2c interface and stores the - * retrieved information in data. - **/ -s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, i2ccmd = 0; - - DEBUGFUNC("igb_read_phy_reg_i2c"); - - /* - * Set up Op-code, Phy Address, and register address in the I2CCMD - * register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | - (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | - (E1000_I2CCMD_OPCODE_READ)); - - E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd); - - /* Poll the ready bit to see if the I2C read completed */ - for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { - usec_delay(50); - i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD); - if (i2ccmd & E1000_I2CCMD_READY) - break; - } - if (!(i2ccmd & E1000_I2CCMD_READY)) { - DEBUGOUT("I2CCMD Read did not complete\n"); - return -E1000_ERR_PHY; - } - if (i2ccmd & E1000_I2CCMD_ERROR) { - DEBUGOUT("I2CCMD Error bit set\n"); - return -E1000_ERR_PHY; - } - - /* Need to byte-swap the 16-bit value. */ - *data = ((i2ccmd >> 8) & 0x00FF) | ((i2ccmd << 8) & 0xFF00); - - return E1000_SUCCESS; -} - -/** - * igb_write_phy_reg_i2c - Write PHY register using i2c - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Writes the data to PHY register at the offset using the i2c interface. - **/ -s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data) -{ - struct e1000_phy_info *phy = &hw->phy; - u32 i, i2ccmd = 0; - u16 phy_data_swapped; - - DEBUGFUNC("igb_write_phy_reg_i2c"); - - /* Swap the data bytes for the I2C interface */ - phy_data_swapped = ((data >> 8) & 0x00FF) | ((data << 8) & 0xFF00); - - /* - * Set up Op-code, Phy Address, and register address in the I2CCMD - * register. The MAC will take care of interfacing with the - * PHY to retrieve the desired data. - */ - i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | - (phy->addr << E1000_I2CCMD_PHY_ADDR_SHIFT) | - E1000_I2CCMD_OPCODE_WRITE | - phy_data_swapped); - - E1000_WRITE_REG(hw, E1000_I2CCMD, i2ccmd); - - /* Poll the ready bit to see if the I2C read completed */ - for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { - usec_delay(50); - i2ccmd = E1000_READ_REG(hw, E1000_I2CCMD); - if (i2ccmd & E1000_I2CCMD_READY) - break; - } - if (!(i2ccmd & E1000_I2CCMD_READY)) { - DEBUGOUT("I2CCMD Write did not complete\n"); - return -E1000_ERR_PHY; - } - if (i2ccmd & E1000_I2CCMD_ERROR) { - DEBUGOUT("I2CCMD Error bit set\n"); - return -E1000_ERR_PHY; - } - - return E1000_SUCCESS; -} - -/** - * igb_read_phy_reg_m88 - Read m88 PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and storing the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -s32 igb_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_read_phy_reg_m88"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * igb_write_phy_reg_m88 - Write m88 PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 igb_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_write_phy_reg_m88"); - - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - - ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * __igb_read_phy_reg_igp - Read igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary, then reads the PHY register at offset - * and stores the retrieved information in data. Release any acquired - * semaphores before exiting. - **/ -static s32 __igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data, - bool locked) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("__igb_read_phy_reg_igp"); - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - ret_val = igb_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) - goto release; - } - - ret_val = igb_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - -release: - if (!locked) - hw->phy.ops.release(hw); -out: - return ret_val; -} -/** - * igb_read_phy_reg_igp - Read igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore then reads the PHY register at offset and stores the - * retrieved information in data. - * Release the acquired semaphore before exiting. - **/ -s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __igb_read_phy_reg_igp(hw, offset, data, false); -} - -/** - * igb_read_phy_reg_igp_locked - Read igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY register at offset and stores the retrieved information - * in data. Assumes semaphore already acquired. - **/ -s32 igb_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __igb_read_phy_reg_igp(hw, offset, data, true); -} - -/** - * igb_write_phy_reg_igp - Write igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary, then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -static s32 __igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data, - bool locked) -{ - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_write_phy_reg_igp"); - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - if (offset > MAX_PHY_MULTI_PAGE_REG) { - ret_val = igb_write_phy_reg_mdic(hw, - IGP01E1000_PHY_PAGE_SELECT, - (u16)offset); - if (ret_val) - goto release; - } - - ret_val = igb_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, - data); - -release: - if (!locked) - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * igb_write_phy_reg_igp - Write igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore then writes the data to PHY register - * at the offset. Release any acquired semaphores before exiting. - **/ -s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __igb_write_phy_reg_igp(hw, offset, data, false); -} - -/** - * igb_write_phy_reg_igp_locked - Write igp PHY register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Writes the data to PHY register at the offset. - * Assumes semaphore already acquired. - **/ -s32 igb_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __igb_write_phy_reg_igp(hw, offset, data, true); -} - -/** - * __igb_read_kmrn_reg - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary. Then reads the PHY register at offset - * using the kumeran interface. The information retrieved is stored in data. - * Release any acquired semaphores before exiting. - **/ -static s32 __igb_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data, - bool locked) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("__igb_read_kmrn_reg"); - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; - E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); - - usec_delay(2); - - kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); - *data = (u16)kmrnctrlsta; - - if (!locked) - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * igb_read_kmrn_reg_generic - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Acquires semaphore then reads the PHY register at offset using the - * kumeran interface. The information retrieved is stored in data. - * Release the acquired semaphore before exiting. - **/ -s32 igb_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __igb_read_kmrn_reg(hw, offset, data, false); -} - -/** - * igb_read_kmrn_reg_locked - Read kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to be read - * @data: pointer to the read data - * - * Reads the PHY register at offset using the kumeran interface. The - * information retrieved is stored in data. - * Assumes semaphore already acquired. - **/ -s32 igb_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data) -{ - return __igb_read_kmrn_reg(hw, offset, data, true); -} - -/** - * __igb_write_kmrn_reg - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * @locked: semaphore has already been acquired or not - * - * Acquires semaphore, if necessary. Then write the data to PHY register - * at the offset using the kumeran interface. Release any acquired semaphores - * before exiting. - **/ -static s32 __igb_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data, - bool locked) -{ - u32 kmrnctrlsta; - s32 ret_val = E1000_SUCCESS; - - DEBUGFUNC("igb_write_kmrn_reg_generic"); - - if (!locked) { - if (!(hw->phy.ops.acquire)) - goto out; - - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - goto out; - } - - kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & - E1000_KMRNCTRLSTA_OFFSET) | data; - E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); - - usec_delay(2); - - if (!locked) - hw->phy.ops.release(hw); - -out: - return ret_val; -} - -/** - * igb_write_kmrn_reg_generic - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Acquires semaphore then writes the data to the PHY register at the offset - * using the kumeran interface. Release the acquired semaphore before exiting. - **/ -s32 igb_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __igb_write_kmrn_reg(hw, offset, data, false); -} - -/** - * igb_write_kmrn_reg_locked - Write kumeran register - * @hw: pointer to the HW structure - * @offset: register offset to write to - * @data: data to write at register offset - * - * Write the data to PHY register at the offset using the kumeran interface. - * Assumes semaphore already acquired. - **/ -s32 igb_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data) -{ - return __igb_write_kmrn_reg(hw, offset, data, true); -} - -/** - * igb_copper_link_setup_m88 - Setup m88 PHY's for copper link - * @hw: pointer to the HW structure - * - * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock - * and downshift values are set also. - **/ -s32 igb_copper_link_setup_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - - DEBUGFUNC("igb_copper_link_setup_m88"); - - if (phy->reset_disable) { - ret_val = E1000_SUCCESS; - goto out; - } - - /* Enable CRS on TX. This must be set for half-duplex operation. */ - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - - /* - * Options: - * MDI/MDI-X = 0 (default) - * 0 - Auto for all speeds - * 1 - MDI mode - * 2 - MDI-X mode - * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) - */ - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - - switch (phy->mdix) { - case 1: - phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; - break; - case 2: - phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; - break; - case 3: - phy_data |= M88E1000_PSCR_AUTO_X_1000T; - break; - case 0: - default: - phy_data |= M88E1000_PSCR_AUTO_X_MODE; - break; - } - - /* - * Options: - * disable_polarity_correction = 0 (default) - * Automatic Correction for Reversed Cable Polarity - * 0 - Disabled - * 1 - Enabled - */ - phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL; - if (phy->disable_polarity_correction == 1) - phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; - - ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - if (phy->revision < E1000_REVISION_4) { - /* - * Force TX_CLK in the Extended PHY Specific Control Register - * to 25MHz clock. - */ - ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_EPSCR_TX_CLK_25; - - if ((phy->revision == E1000_REVISION_2) && - (phy->id == M88E1111_I_PHY_ID)) { - /* 82573L PHY - set the downshift counter to 5x. */ - phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK; - phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X; - } else { - /* Configure Master and Slave downshift values */ - phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK); - phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X | - M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X); - } - ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, - phy_data); - if (ret_val) - goto out; - } - - /* Commit the changes. */ - ret_val = phy->ops.commit(hw); - if (ret_val) { - DEBUGOUT("Error committing the PHY changes\n"); - goto out; - } - -out: - return ret_val; -} - -/** - * igb_copper_link_setup_igp - Setup igp PHY's for copper link - * @hw: pointer to the HW structure - * - * Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for - * igp PHY's. - **/ -s32 igb_copper_link_setup_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - DEBUGFUNC("igb_copper_link_setup_igp"); - - if (phy->reset_disable) { - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = hw->phy.ops.reset(hw); - if (ret_val) { - DEBUGOUT("Error resetting the PHY.\n"); - goto out; - } - - /* - * Wait 100ms for MAC to configure PHY from NVM settings, to avoid - * timeout issues when LFS is enabled. - */ - msec_delay(100); - - /* - * The NVM settings will configure LPLU in D3 for - * non-IGP1 PHYs. - */ - if (phy->type == e1000_phy_igp) { - /* disable lplu d3 during driver init */ - ret_val = hw->phy.ops.set_d3_lplu_state(hw, false); - if (ret_val) { - DEBUGOUT("Error Disabling LPLU D3\n"); - goto out; - } - } - - /* disable lplu d0 during driver init */ - if (hw->phy.ops.set_d0_lplu_state) { - ret_val = hw->phy.ops.set_d0_lplu_state(hw, false); - if (ret_val) { - DEBUGOUT("Error Disabling LPLU D0\n"); - goto out; - } - } - /* Configure mdi-mdix settings */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCR_AUTO_MDIX; - - switch (phy->mdix) { - case 1: - data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 2: - data |= IGP01E1000_PSCR_FORCE_MDI_MDIX; - break; - case 0: - default: - data |= IGP01E1000_PSCR_AUTO_MDIX; - break; - } - ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, data); - if (ret_val) - goto out; - - /* set auto-master slave resolution settings */ - if (hw->mac.autoneg) { - /* - * when autonegotiation advertisement is only 1000Mbps then we - * should disable SmartSpeed and enable Auto MasterSlave - * resolution as hardware default. - */ - if (phy->autoneg_advertised == ADVERTISE_1000_FULL) { - /* Disable SmartSpeed */ - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - - /* Set auto Master/Slave resolution process */ - ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); - if (ret_val) - goto out; - - data &= ~CR_1000T_MS_ENABLE; - ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); - if (ret_val) - goto out; - } - - ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, &data); - if (ret_val) - goto out; - - /* load defaults for future use */ - phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ? - ((data & CR_1000T_MS_VALUE) ? - e1000_ms_force_master : - e1000_ms_force_slave) : - e1000_ms_auto; - - switch (phy->ms_type) { - case e1000_ms_force_master: - data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE); - break; - case e1000_ms_force_slave: - data |= CR_1000T_MS_ENABLE; - data &= ~(CR_1000T_MS_VALUE); - break; - case e1000_ms_auto: - data &= ~CR_1000T_MS_ENABLE; - default: - break; - } - ret_val = phy->ops.write_reg(hw, PHY_1000T_CTRL, data); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * igb_copper_link_autoneg - Setup/Enable autoneg for copper link - * @hw: pointer to the HW structure - * - * Performs initial bounds checking on autoneg advertisement parameter, then - * configure to advertise the full capability. Setup the PHY to autoneg - * and restart the negotiation process between the link partner. If - * autoneg_wait_to_complete, then wait for autoneg to complete before exiting. - **/ -s32 igb_copper_link_autoneg(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_ctrl; - - DEBUGFUNC("igb_copper_link_autoneg"); - - /* - * Perform some bounds checking on the autoneg advertisement - * parameter. - */ - phy->autoneg_advertised &= phy->autoneg_mask; - - /* - * If autoneg_advertised is zero, we assume it was not defaulted - * by the calling code so we set to advertise full capability. - */ - if (phy->autoneg_advertised == 0) - phy->autoneg_advertised = phy->autoneg_mask; - - DEBUGOUT("Reconfiguring auto-neg advertisement params\n"); - ret_val = igb_phy_setup_autoneg(hw); - if (ret_val) { - DEBUGOUT("Error Setting up Auto-Negotiation\n"); - goto out; - } - DEBUGOUT("Restarting Auto-Neg\n"); - - /* - * Restart auto-negotiation by setting the Auto Neg Enable bit and - * the Auto Neg Restart bit in the PHY control register. - */ - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); - if (ret_val) - goto out; - - phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG); - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_ctrl); - if (ret_val) - goto out; - - /* - * Does the user want to wait for Auto-Neg to complete here, or - * check at a later time (for example, callback routine). - */ - if (phy->autoneg_wait_to_complete) { - ret_val = hw->mac.ops.wait_autoneg(hw); - if (ret_val) { - DEBUGOUT("Error while waiting for " - "autoneg to complete\n"); - goto out; - } - } - - hw->mac.get_link_status = true; - -out: - return ret_val; -} - -/** - * igb_phy_setup_autoneg - Configure PHY for auto-negotiation - * @hw: pointer to the HW structure - * - * Reads the MII auto-neg advertisement register and/or the 1000T control - * register and if the PHY is already setup for auto-negotiation, then - * return successful. Otherwise, setup advertisement and flow control to - * the appropriate values for the wanted auto-negotiation. - **/ -static s32 igb_phy_setup_autoneg(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 mii_autoneg_adv_reg; - u16 mii_1000t_ctrl_reg = 0; - - DEBUGFUNC("igb_phy_setup_autoneg"); - - phy->autoneg_advertised &= phy->autoneg_mask; - - /* Read the MII Auto-Neg Advertisement Register (Address 4). */ - ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg); - if (ret_val) - goto out; - - if (phy->autoneg_mask & ADVERTISE_1000_FULL) { - /* Read the MII 1000Base-T Control Register (Address 9). */ - ret_val = phy->ops.read_reg(hw, PHY_1000T_CTRL, - &mii_1000t_ctrl_reg); - if (ret_val) - goto out; - } - - /* - * Need to parse both autoneg_advertised and fc and set up - * the appropriate PHY registers. First we will parse for - * autoneg_advertised software override. Since we can advertise - * a plethora of combinations, we need to check each bit - * individually. - */ - - /* - * First we clear all the 10/100 mb speed bits in the Auto-Neg - * Advertisement Register (Address 4) and the 1000 mb speed bits in - * the 1000Base-T Control Register (Address 9). - */ - mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS | - NWAY_AR_100TX_HD_CAPS | - NWAY_AR_10T_FD_CAPS | - NWAY_AR_10T_HD_CAPS); - mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS); - - DEBUGOUT1("autoneg_advertised %x\n", phy->autoneg_advertised); - - /* Do we want to advertise 10 Mb Half Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_10_HALF) { - DEBUGOUT("Advertise 10mb Half duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS; - } - - /* Do we want to advertise 10 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_10_FULL) { - DEBUGOUT("Advertise 10mb Full duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS; - } - - /* Do we want to advertise 100 Mb Half Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_100_HALF) { - DEBUGOUT("Advertise 100mb Half duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS; - } - - /* Do we want to advertise 100 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_100_FULL) { - DEBUGOUT("Advertise 100mb Full duplex\n"); - mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS; - } - - /* We do not allow the Phy to advertise 1000 Mb Half Duplex */ - if (phy->autoneg_advertised & ADVERTISE_1000_HALF) { - DEBUGOUT("Advertise 1000mb Half duplex request denied!\n"); - } - /* Do we want to advertise 1000 Mb Full Duplex? */ - if (phy->autoneg_advertised & ADVERTISE_1000_FULL) { - DEBUGOUT("Advertise 1000mb Full duplex\n"); - mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS; - } - - /* - * Check for a software override of the flow control settings, and - * setup the PHY advertisement registers accordingly. If - * auto-negotiation is enabled, then software will have to set the - * "PAUSE" bits to the correct value in the Auto-Negotiation - * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto- - * negotiation. - * - * The possible values of the "fc" parameter are: - * 0: Flow control is completely disabled - * 1: Rx flow control is enabled (we can receive pause frames - * but not send pause frames). - * 2: Tx flow control is enabled (we can send pause frames - * but we do not support receiving pause frames). - * 3: Both Rx and Tx flow control (symmetric) are enabled. - * other: No software override. The flow control configuration - * in the EEPROM is used. - */ - switch (hw->fc.current_mode) { - case e1000_fc_none: - /* - * Flow control (Rx & Tx) is completely disabled by a - * software over-ride. - */ - mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - case e1000_fc_rx_pause: - /* - * Rx Flow control is enabled, and Tx Flow control is - * disabled, by a software over-ride. - * - * Since there really isn't a way to advertise that we are - * capable of Rx Pause ONLY, we will advertise that we - * support both symmetric and asymmetric Rx PAUSE. Later - * (in e1000_config_fc_after_link_up) we will disable the - * hw's ability to send PAUSE frames. - */ - mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - case e1000_fc_tx_pause: - /* - * Tx Flow control is enabled, and Rx Flow control is - * disabled, by a software over-ride. - */ - mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR; - mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE; - break; - case e1000_fc_full: - /* - * Flow control (both Rx and Tx) is enabled by a software - * over-ride. - */ - mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE); - break; - default: - DEBUGOUT("Flow control param set incorrectly\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = phy->ops.write_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg); - if (ret_val) - goto out; - - DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg); - - if (phy->autoneg_mask & ADVERTISE_1000_FULL) { - ret_val = phy->ops.write_reg(hw, - PHY_1000T_CTRL, - mii_1000t_ctrl_reg); - if (ret_val) - goto out; - } - -out: - return ret_val; -} - -/** - * igb_setup_copper_link_generic - Configure copper link settings - * @hw: pointer to the HW structure - * - * Calls the appropriate function to configure the link for auto-neg or forced - * speed and duplex. Then we check for link, once link is established calls - * to configure collision distance and flow control are called. If link is - * not established, we return -E1000_ERR_PHY (-2). - **/ -s32 igb_setup_copper_link_generic(struct e1000_hw *hw) -{ - s32 ret_val; - bool link; - - DEBUGFUNC("igb_setup_copper_link_generic"); - - if (hw->mac.autoneg) { - /* - * Setup autoneg and flow control advertisement and perform - * autonegotiation. - */ - ret_val = igb_copper_link_autoneg(hw); - if (ret_val) - goto out; - } else { -#if 0 - /* - * PHY will be set to 10H, 10F, 100H or 100F - * depending on user settings. - */ - DEBUGOUT("Forcing Speed and Duplex\n"); - ret_val = hw->phy.ops.force_speed_duplex(hw); - if (ret_val) { - DEBUGOUT("Error Forcing Speed and Duplex\n"); - goto out; - } -#endif - } - - /* - * Check link status. Wait up to 100 microseconds for link to become - * valid. - */ - ret_val = igb_phy_has_link_generic(hw, - COPPER_LINK_UP_LIMIT, - 10, - &link); - if (ret_val) - goto out; - - if (link) { - DEBUGOUT("Valid link established!!!\n"); - igb_config_collision_dist_generic(hw); - ret_val = igb_config_fc_after_link_up_generic(hw); - } else { - DEBUGOUT("Unable to establish link!!!\n"); - } - -out: - return ret_val; -} - -#if 0 -/** - * igb_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY - * @hw: pointer to the HW structure - * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Waits for link and returns - * successful if link up is successful, else -E1000_ERR_PHY (-2). - **/ -s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - DEBUGFUNC("igb_phy_force_speed_duplex_igp"); - - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - igb_phy_force_speed_duplex_setup(hw, &phy_data); - - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - /* - * Clear Auto-Crossover to force MDI manually. IGP requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX; - phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX; - - ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data); - if (ret_val) - goto out; - - DEBUGOUT1("IGP PSCR: %X\n", phy_data); - - usec_delay(1); - - if (phy->autoneg_wait_to_complete) { - DEBUGOUT("Waiting for forced speed/duplex link on IGP phy.\n"); - - ret_val = igb_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) { - DEBUGOUT("Link taking longer than expected.\n"); - } - /* Try once more */ - ret_val = igb_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } - -out: - return ret_val; -} -#endif - -#if 0 -/** - * igb_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY - * @hw: pointer to the HW structure - * - * Calls the PHY setup function to force speed and duplex. Clears the - * auto-crossover to force MDI manually. Resets the PHY to commit the - * changes. If time expires while waiting for link up, we reset the DSP. - * After reset, TX_CLK and CRS on Tx must be set. Return successful upon - * successful completion, else return corresponding error code. - **/ -s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - DEBUGFUNC("igb_phy_force_speed_duplex_m88"); - - /* - * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - DEBUGOUT1("M88E1000 PSCR: %X\n", phy_data); - - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); - if (ret_val) - goto out; - - igb_phy_force_speed_duplex_setup(hw, &phy_data); - - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, phy_data); - if (ret_val) - goto out; - - /* Reset the phy to commit changes. */ - ret_val = hw->phy.ops.commit(hw); - if (ret_val) - goto out; - - if (phy->autoneg_wait_to_complete) { - DEBUGOUT("Waiting for forced speed/duplex link on M88 phy.\n"); - - ret_val = igb_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - - if (!link) { - /* - * We didn't get link. - * Reset the DSP and cross our fingers. - */ - ret_val = phy->ops.write_reg(hw, - M88E1000_PHY_PAGE_SELECT, - 0x001d); - if (ret_val) - goto out; - ret_val = igb_phy_reset_dsp_generic(hw); - if (ret_val) - goto out; - } - - /* Try once more */ - ret_val = igb_phy_has_link_generic(hw, PHY_FORCE_LIMIT, - 100000, &link); - if (ret_val) - goto out; - } - - ret_val = phy->ops.read_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - /* - * Resetting the phy means we need to re-force TX_CLK in the - * Extended PHY Specific Control Register to 25MHz clock from - * the reset value of 2.5MHz. - */ - phy_data |= M88E1000_EPSCR_TX_CLK_25; - ret_val = phy->ops.write_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; - - /* - * In addition, we must re-enable CRS on Tx for both half and full - * duplex. - */ - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX; - ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - -out: - return ret_val; -} -#endif - -#if 0 -/** - * igb_phy_force_speed_duplex_ife - Force PHY speed & duplex - * @hw: pointer to the HW structure - * - * Forces the speed and duplex settings of the PHY. - * This is a function pointer entry point only called by - * PHY setup routines. - **/ -s32 igb_phy_force_speed_duplex_ife(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - DEBUGFUNC("igb_phy_force_speed_duplex_ife"); - - if (phy->type != e1000_phy_ife) { - ret_val = igb_phy_force_speed_duplex_igp(hw); - goto out; - } - - ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &data); - if (ret_val) - goto out; - - igb_phy_force_speed_duplex_setup(hw, &data); - - ret_val = phy->ops.write_reg(hw, PHY_CONTROL, data); - if (ret_val) - goto out; - - /* Disable MDI-X support for 10/100 */ - ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data); - if (ret_val) - goto out; - - data &= ~IFE_PMC_AUTO_MDIX; - data &= ~IFE_PMC_FORCE_MDIX; - - ret_val = phy->ops.write_reg(hw, IFE_PHY_MDIX_CONTROL, data); - if (ret_val) - goto out; - - DEBUGOUT1("IFE PMC: %X\n", data); - - usec_delay(1); - - if (phy->autoneg_wait_to_complete) { - DEBUGOUT("Waiting for forced speed/duplex link on IFE phy.\n"); - - ret_val = igb_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - - if (!link) { - DEBUGOUT("Link taking longer than expected.\n"); - } - /* Try once more */ - ret_val = igb_phy_has_link_generic(hw, - PHY_FORCE_LIMIT, - 100000, - &link); - if (ret_val) - goto out; - } - -out: - return ret_val; -} -#endif - -#if 0 -/** - * igb_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex - * @hw: pointer to the HW structure - * @phy_ctrl: pointer to current value of PHY_CONTROL - * - * Forces speed and duplex on the PHY by doing the following: disable flow - * control, force speed/duplex on the MAC, disable auto speed detection, - * disable auto-negotiation, configure duplex, configure speed, configure - * the collision distance, write configuration to CTRL register. The - * caller must write to the PHY_CONTROL register for these settings to - * take affect. - **/ -void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) -{ - struct e1000_mac_info *mac = &hw->mac; - u32 ctrl; - - DEBUGFUNC("igb_phy_force_speed_duplex_setup"); - - /* Turn off flow control when forcing speed/duplex */ - hw->fc.current_mode = e1000_fc_none; - - /* Force speed/duplex on the mac */ - ctrl = E1000_READ_REG(hw, E1000_CTRL); - ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); - ctrl &= ~E1000_CTRL_SPD_SEL; - - /* Disable Auto Speed Detection */ - ctrl &= ~E1000_CTRL_ASDE; - - /* Disable autoneg on the phy */ - *phy_ctrl &= ~MII_CR_AUTO_NEG_EN; - - /* Forcing Full or Half Duplex? */ - if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) { - ctrl &= ~E1000_CTRL_FD; - *phy_ctrl &= ~MII_CR_FULL_DUPLEX; - DEBUGOUT("Half Duplex\n"); - } else { - ctrl |= E1000_CTRL_FD; - *phy_ctrl |= MII_CR_FULL_DUPLEX; - DEBUGOUT("Full Duplex\n"); - } - - /* Forcing 10mb or 100mb? */ - if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) { - ctrl |= E1000_CTRL_SPD_100; - *phy_ctrl |= MII_CR_SPEED_100; - *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10); - DEBUGOUT("Forcing 100mb\n"); - } else { - ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); - *phy_ctrl |= MII_CR_SPEED_10; - *phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100); - DEBUGOUT("Forcing 10mb\n"); - } - - igb_config_collision_dist_generic(hw); - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); -} -#endif - -/** - * igb_set_d3_lplu_state_generic - Sets low power link up state for D3 - * @hw: pointer to the HW structure - * @active: boolean used to enable/disable lplu - * - * Success returns 0, Failure returns 1 - * - * The low power link up (lplu) state is set to the power management level D3 - * and SmartSpeed is disabled when active is true, else clear lplu for D3 - * and enable Smartspeed. LPLU and Smartspeed are mutually exclusive. LPLU - * is used during Dx states where the power conservation is most important. - * During driver activity, SmartSpeed should be enabled so performance is - * maintained. - **/ -s32 igb_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 data; - - DEBUGFUNC("igb_set_d3_lplu_state_generic"); - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data); - if (ret_val) - goto out; - - if (!active) { - data &= ~IGP02E1000_PM_D3_LPLU; - ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - /* - * LPLU and SmartSpeed are mutually exclusive. LPLU is used - * during Dx states where the power conservation is most - * important. During driver activity we should enable - * SmartSpeed, so performance is maintained. - */ - if (phy->smart_speed == e1000_smart_speed_on) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data |= IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } else if (phy->smart_speed == e1000_smart_speed_off) { - ret_val = phy->ops.read_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, - IGP01E1000_PHY_PORT_CONFIG, - data); - if (ret_val) - goto out; - } - } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || - (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || - (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { - data |= IGP02E1000_PM_D3_LPLU; - ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT, - data); - if (ret_val) - goto out; - - /* When LPLU is enabled, we should disable SmartSpeed */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - &data); - if (ret_val) - goto out; - - data &= ~IGP01E1000_PSCFR_SMART_SPEED; - ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG, - data); - } - -out: - return ret_val; -} - -/** - * igb_check_downshift_generic - Checks whether a downshift in speed occurred - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns 1 - * - * A downshift is detected by querying the PHY link health. - **/ -s32 igb_check_downshift_generic(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - DEBUGFUNC("igb_check_downshift_generic"); - - switch (phy->type) { - case e1000_phy_m88: - case e1000_phy_gg82563: - offset = M88E1000_PHY_SPEC_STATUS; - mask = M88E1000_PSSR_DOWNSHIFT; - break; - case e1000_phy_igp_2: - case e1000_phy_igp: - case e1000_phy_igp_3: - offset = IGP01E1000_PHY_LINK_HEALTH; - mask = IGP01E1000_PLHR_SS_DOWNGRADE; - break; - default: - /* speed downshift not supported */ - phy->speed_downgraded = false; - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = phy->ops.read_reg(hw, offset, &phy_data); - - if (!ret_val) - phy->speed_downgraded = (phy_data & mask) ? true : false; - -out: - return ret_val; -} - -/** - * igb_check_polarity_m88 - Checks the polarity. - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - * - * Polarity is determined based on the PHY specific status register. - **/ -s32 igb_check_polarity_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - - DEBUGFUNC("igb_check_polarity_m88"); - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &data); - - if (!ret_val) - phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -/** - * igb_check_polarity_igp - Checks the polarity. - * @hw: pointer to the HW structure - * - * Success returns 0, Failure returns -E1000_ERR_PHY (-2) - * - * Polarity is determined based on the PHY port status register, and the - * current speed (since there is no polarity at 100Mbps). - **/ -s32 igb_check_polarity_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data, offset, mask; - - DEBUGFUNC("igb_check_polarity_igp"); - - /* - * Polarity is determined based on the speed of - * our connection. - */ - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); - if (ret_val) - goto out; - - if ((data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) { - offset = IGP01E1000_PHY_PCS_INIT_REG; - mask = IGP01E1000_PHY_POLARITY_MASK; - } else { - /* - * This really only applies to 10Mbps since - * there is no polarity for 100Mbps (always 0). - */ - offset = IGP01E1000_PHY_PORT_STATUS; - mask = IGP01E1000_PSSR_POLARITY_REVERSED; - } - - ret_val = phy->ops.read_reg(hw, offset, &data); - - if (!ret_val) - phy->cable_polarity = (data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - -out: - return ret_val; -} - -/** - * igb_check_polarity_ife - Check cable polarity for IFE PHY - * @hw: pointer to the HW structure - * - * Polarity is determined on the polarity reversal feature being enabled. - **/ -s32 igb_check_polarity_ife(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, offset, mask; - - DEBUGFUNC("igb_check_polarity_ife"); - - /* - * Polarity is determined based on the reversal feature being enabled. - */ - if (phy->polarity_correction) { - offset = IFE_PHY_EXTENDED_STATUS_CONTROL; - mask = IFE_PESC_POLARITY_REVERSED; - } else { - offset = IFE_PHY_SPECIAL_CONTROL; - mask = IFE_PSC_FORCE_POLARITY; - } - - ret_val = phy->ops.read_reg(hw, offset, &phy_data); - - if (!ret_val) - phy->cable_polarity = (phy_data & mask) - ? e1000_rev_polarity_reversed - : e1000_rev_polarity_normal; - - return ret_val; -} - -/** - * igb_wait_autoneg_generic - Wait for auto-neg completion - * @hw: pointer to the HW structure - * - * Waits for auto-negotiation to complete or for the auto-negotiation time - * limit to expire, which ever happens first. - **/ -s32 igb_wait_autoneg_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 i, phy_status; - - DEBUGFUNC("igb_wait_autoneg_generic"); - - if (!(hw->phy.ops.read_reg)) - return E1000_SUCCESS; - - /* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */ - for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) { - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - if (phy_status & MII_SR_AUTONEG_COMPLETE) - break; - msec_delay(100); - } - - /* - * PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation - * has completed. - */ - return ret_val; -} - -/** - * igb_phy_has_link_generic - Polls PHY for link - * @hw: pointer to the HW structure - * @iterations: number of times to poll for link - * @usec_interval: delay between polling attempts - * @success: pointer to whether polling was successful or not - * - * Polls the PHY status register for link, 'iterations' number of times. - **/ -s32 igb_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, - u32 usec_interval, bool *success) -{ - s32 ret_val = E1000_SUCCESS; - u16 i, phy_status; - - DEBUGFUNC("igb_phy_has_link_generic"); - - if (!(hw->phy.ops.read_reg)) - return E1000_SUCCESS; - - for (i = 0; i < iterations; i++) { - /* - * Some PHYs require the PHY_STATUS register to be read - * twice due to the link bit being sticky. No harm doing - * it across the board. - */ - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) { - /* - * If the first read fails, another entity may have - * ownership of the resources, wait and try again to - * see if they have relinquished the resources yet. - */ - usec_delay(usec_interval); - } - ret_val = hw->phy.ops.read_reg(hw, PHY_STATUS, &phy_status); - if (ret_val) - break; - if (phy_status & MII_SR_LINK_STATUS) - break; - if (usec_interval >= 1000) - msec_delay_irq(usec_interval/1000); - else - usec_delay(usec_interval); - } - - *success = (i < iterations) ? true : false; - - return ret_val; -} - -#if 0 -/** - * igb_get_cable_length_m88 - Determine cable length for m88 PHY - * @hw: pointer to the HW structure - * - * Reads the PHY specific status register to retrieve the cable length - * information. The cable length is determined by averaging the minimum and - * maximum values to get the "average" cable length. The m88 PHY has four - * possible cable length values, which are: - * Register Value Cable Length - * 0 < 50 meters - * 1 50 - 80 meters - * 2 80 - 110 meters - * 3 110 - 140 meters - * 4 > 140 meters - **/ -s32 igb_get_cable_length_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data, index; - - DEBUGFUNC("igb_get_cable_length_m88"); - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if (ret_val) - goto out; - - index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - phy->min_cable_length = e1000_m88_cable_length_table[index]; - phy->max_cable_length = e1000_m88_cable_length_table[index + 1]; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} - -/** - * igb_get_cable_length_igp_2 - Determine cable length for igp2 PHY - * @hw: pointer to the HW structure - * - * The automatic gain control (agc) normalizes the amplitude of the - * received signal, adjusting for the attenuation produced by the - * cable. By reading the AGC registers, which represent the - * combination of coarse and fine gain value, the value can be put - * into a lookup table to obtain the approximate cable length - * for each channel. - **/ -s32 igb_get_cable_length_igp_2(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u16 phy_data, i, agc_value = 0; - u16 cur_agc_index, max_agc_index = 0; - u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; - u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = - {IGP02E1000_PHY_AGC_A, - IGP02E1000_PHY_AGC_B, - IGP02E1000_PHY_AGC_C, - IGP02E1000_PHY_AGC_D}; - - DEBUGFUNC("igb_get_cable_length_igp_2"); - - /* Read the AGC registers for all channels */ - for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { - ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &phy_data); - if (ret_val) - goto out; - - /* - * Getting bits 15:9, which represent the combination of - * coarse and fine gain values. The result is a number - * that can be put into the lookup table to obtain the - * approximate cable length. - */ - cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & - IGP02E1000_AGC_LENGTH_MASK; - - /* Array index bound check. */ - if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || - (cur_agc_index == 0)) { - ret_val = -E1000_ERR_PHY; - goto out; - } - - /* Remove min & max AGC values from calculation. */ - if (e1000_igp_2_cable_length_table[min_agc_index] > - e1000_igp_2_cable_length_table[cur_agc_index]) - min_agc_index = cur_agc_index; - if (e1000_igp_2_cable_length_table[max_agc_index] < - e1000_igp_2_cable_length_table[cur_agc_index]) - max_agc_index = cur_agc_index; - - agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; - } - - agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + - e1000_igp_2_cable_length_table[max_agc_index]); - agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); - - /* Calculate cable length with the error range of +/- 10 meters. */ - phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? - (agc_value - IGP02E1000_AGC_RANGE) : 0; - phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; - - phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2; - -out: - return ret_val; -} -#endif - -/** - * igb_get_phy_info_m88 - Retrieve PHY information - * @hw: pointer to the HW structure - * - * Valid for only copper links. Read the PHY status register (sticky read) - * to verify that link is up. Read the PHY special control register to - * determine the polarity and 10base-T extended distance. Read the PHY - * special status register to determine MDI/MDIx and current speed. If - * speed is 1000, then determine cable length, local and remote receiver. - **/ -s32 igb_get_phy_info_m88(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 phy_data; - bool link; - - DEBUGFUNC("igb_get_phy_info_m88"); - - if (phy->media_type != e1000_media_type_copper) { - DEBUGOUT("Phy info is only valid for copper media\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = igb_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - DEBUGOUT("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; - - phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) - ? true : false; - - ret_val = igb_check_polarity_m88(hw); - if (ret_val) - goto out; - - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); - if (ret_val) - goto out; - - phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? true : false; - - if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { -#if 0 - ret_val = hw->phy.ops.get_cable_length(hw); -#endif - ret_val = -E1000_ERR_CONFIG; - if (ret_val) - goto out; -#if 0 - ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data); - if (ret_val) - goto out; - - phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - - phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; -#endif - } else { - /* Set values to "undefined" */ - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - } - -out: - return ret_val; -} - -/** - * igb_get_phy_info_igp - Retrieve igp PHY information - * @hw: pointer to the HW structure - * - * Read PHY status to determine if link is up. If link is up, then - * set/determine 10base-T extended distance and polarity correction. Read - * PHY port status to determine MDI/MDIx and speed. Based on the speed, - * determine on the cable length, local and remote receiver. - **/ -s32 igb_get_phy_info_igp(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val; - u16 data; - bool link; - - DEBUGFUNC("igb_get_phy_info_igp"); - - ret_val = igb_phy_has_link_generic(hw, 1, 0, &link); - if (ret_val) - goto out; - - if (!link) { - DEBUGOUT("Phy info is only valid if link is up\n"); - ret_val = -E1000_ERR_CONFIG; - goto out; - } - - phy->polarity_correction = true; - - ret_val = igb_check_polarity_igp(hw); - if (ret_val) - goto out; - - ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); - if (ret_val) - goto out; - - phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? true : false; - - if ((data & IGP01E1000_PSSR_SPEED_MASK) == - IGP01E1000_PSSR_SPEED_1000MBPS) { -#if 0 - ret_val = phy->ops.get_cable_length(hw); -#endif - ret_val = -E1000_ERR_CONFIG; - if (ret_val) - goto out; -#if 0 - ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &data); - if (ret_val) - goto out; - - phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; - - phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) - ? e1000_1000t_rx_status_ok - : e1000_1000t_rx_status_not_ok; -#endif - } else { - phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; - phy->local_rx = e1000_1000t_rx_status_undefined; - phy->remote_rx = e1000_1000t_rx_status_undefined; - } - -out: - return ret_val; -} - -/** - * igb_phy_sw_reset_generic - PHY software reset - * @hw: pointer to the HW structure - * - * Does a software reset of the PHY by reading the PHY control register and - * setting/write the control register reset bit to the PHY. - **/ -s32 igb_phy_sw_reset_generic(struct e1000_hw *hw) -{ - s32 ret_val = E1000_SUCCESS; - u16 phy_ctrl; - - DEBUGFUNC("igb_phy_sw_reset_generic"); - - if (!(hw->phy.ops.read_reg)) - goto out; - - ret_val = hw->phy.ops.read_reg(hw, PHY_CONTROL, &phy_ctrl); - if (ret_val) - goto out; - - phy_ctrl |= MII_CR_RESET; - ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL, phy_ctrl); - if (ret_val) - goto out; - - usec_delay(1); - -out: - return ret_val; -} - -/** - * igb_phy_hw_reset_generic - PHY hardware reset - * @hw: pointer to the HW structure - * - * Verify the reset block is not blocking us from resetting. Acquire - * semaphore (if necessary) and read/set/write the device control reset - * bit in the PHY. Wait the appropriate delay time for the device to - * reset and release the semaphore (if necessary). - **/ -s32 igb_phy_hw_reset_generic(struct e1000_hw *hw) -{ - struct e1000_phy_info *phy = &hw->phy; - s32 ret_val = E1000_SUCCESS; - u32 ctrl; - - DEBUGFUNC("igb_phy_hw_reset_generic"); - - ret_val = phy->ops.check_reset_block(hw); - if (ret_val) { - ret_val = E1000_SUCCESS; - goto out; - } - - ret_val = phy->ops.acquire(hw); - if (ret_val) - goto out; - - ctrl = E1000_READ_REG(hw, E1000_CTRL); - E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST); - E1000_WRITE_FLUSH(hw); - - usec_delay(phy->reset_delay_us); - - E1000_WRITE_REG(hw, E1000_CTRL, ctrl); - E1000_WRITE_FLUSH(hw); - - usec_delay(150); - - phy->ops.release(hw); - - ret_val = phy->ops.get_cfg_done(hw); - -out: - return ret_val; -} - -/** - * igb_get_cfg_done_generic - Generic configuration done - * @hw: pointer to the HW structure - * - * Generic function to wait 10 milli-seconds for configuration to complete - * and return success. - **/ -s32 igb_get_cfg_done_generic(struct e1000_hw *hw __unused) -{ - DEBUGFUNC("igb_get_cfg_done_generic"); - - msec_delay_irq(10); - - return E1000_SUCCESS; -} - -/** - * igb_phy_init_script_igp3 - Inits the IGP3 PHY - * @hw: pointer to the HW structure - * - * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. - **/ -s32 igb_phy_init_script_igp3(struct e1000_hw *hw) -{ - DEBUGOUT("Running IGP 3 PHY init script\n"); - - /* PHY init IGP 3 */ - /* Enable rise/fall, 10-mode work in class-A */ - hw->phy.ops.write_reg(hw, 0x2F5B, 0x9018); - /* Remove all caps from Replica path filter */ - hw->phy.ops.write_reg(hw, 0x2F52, 0x0000); - /* Bias trimming for ADC, AFE and Driver (Default) */ - hw->phy.ops.write_reg(hw, 0x2FB1, 0x8B24); - /* Increase Hybrid poly bias */ - hw->phy.ops.write_reg(hw, 0x2FB2, 0xF8F0); - /* Add 4% to Tx amplitude in Gig mode */ - hw->phy.ops.write_reg(hw, 0x2010, 0x10B0); - /* Disable trimming (TTT) */ - hw->phy.ops.write_reg(hw, 0x2011, 0x0000); - /* Poly DC correction to 94.6% + 2% for all channels */ - hw->phy.ops.write_reg(hw, 0x20DD, 0x249A); - /* ABS DC correction to 95.9% */ - hw->phy.ops.write_reg(hw, 0x20DE, 0x00D3); - /* BG temp curve trim */ - hw->phy.ops.write_reg(hw, 0x28B4, 0x04CE); - /* Increasing ADC OPAMP stage 1 currents to max */ - hw->phy.ops.write_reg(hw, 0x2F70, 0x29E4); - /* Force 1000 ( required for enabling PHY regs configuration) */ - hw->phy.ops.write_reg(hw, 0x0000, 0x0140); - /* Set upd_freq to 6 */ - hw->phy.ops.write_reg(hw, 0x1F30, 0x1606); - /* Disable NPDFE */ - hw->phy.ops.write_reg(hw, 0x1F31, 0xB814); - /* Disable adaptive fixed FFE (Default) */ - hw->phy.ops.write_reg(hw, 0x1F35, 0x002A); - /* Enable FFE hysteresis */ - hw->phy.ops.write_reg(hw, 0x1F3E, 0x0067); - /* Fixed FFE for short cable lengths */ - hw->phy.ops.write_reg(hw, 0x1F54, 0x0065); - /* Fixed FFE for medium cable lengths */ - hw->phy.ops.write_reg(hw, 0x1F55, 0x002A); - /* Fixed FFE for long cable lengths */ - hw->phy.ops.write_reg(hw, 0x1F56, 0x002A); - /* Enable Adaptive Clip Threshold */ - hw->phy.ops.write_reg(hw, 0x1F72, 0x3FB0); - /* AHT reset limit to 1 */ - hw->phy.ops.write_reg(hw, 0x1F76, 0xC0FF); - /* Set AHT master delay to 127 msec */ - hw->phy.ops.write_reg(hw, 0x1F77, 0x1DEC); - /* Set scan bits for AHT */ - hw->phy.ops.write_reg(hw, 0x1F78, 0xF9EF); - /* Set AHT Preset bits */ - hw->phy.ops.write_reg(hw, 0x1F79, 0x0210); - /* Change integ_factor of channel A to 3 */ - hw->phy.ops.write_reg(hw, 0x1895, 0x0003); - /* Change prop_factor of channels BCD to 8 */ - hw->phy.ops.write_reg(hw, 0x1796, 0x0008); - /* Change cg_icount + enable integbp for channels BCD */ - hw->phy.ops.write_reg(hw, 0x1798, 0xD008); - /* - * Change cg_icount + enable integbp + change prop_factor_master - * to 8 for channel A - */ - hw->phy.ops.write_reg(hw, 0x1898, 0xD918); - /* Disable AHT in Slave mode on channel A */ - hw->phy.ops.write_reg(hw, 0x187A, 0x0800); - /* - * Enable LPLU and disable AN to 1000 in non-D0a states, - * Enable SPD+B2B - */ - hw->phy.ops.write_reg(hw, 0x0019, 0x008D); - /* Enable restart AN on an1000_dis change */ - hw->phy.ops.write_reg(hw, 0x001B, 0x2080); - /* Enable wh_fifo read clock in 10/100 modes */ - hw->phy.ops.write_reg(hw, 0x0014, 0x0045); - /* Restart AN, Speed selection is 1000 */ - hw->phy.ops.write_reg(hw, 0x0000, 0x1340); - - return E1000_SUCCESS; -} - -/** - * igb_get_phy_type_from_id - Get PHY type from id - * @phy_id: phy_id read from the phy - * - * Returns the phy type from the id. - **/ -enum e1000_phy_type igb_get_phy_type_from_id(u32 phy_id) -{ - enum e1000_phy_type phy_type = e1000_phy_unknown; - - switch (phy_id) { - case M88E1000_I_PHY_ID: - case M88E1000_E_PHY_ID: - case M88E1111_I_PHY_ID: - case M88E1011_I_PHY_ID: - phy_type = e1000_phy_m88; - break; - case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ - phy_type = e1000_phy_igp_2; - break; - case GG82563_E_PHY_ID: - phy_type = e1000_phy_gg82563; - break; - case IGP03E1000_E_PHY_ID: - phy_type = e1000_phy_igp_3; - break; - case IFE_E_PHY_ID: - case IFE_PLUS_E_PHY_ID: - case IFE_C_E_PHY_ID: - phy_type = e1000_phy_ife; - break; - default: - phy_type = e1000_phy_unknown; - break; - } - return phy_type; -} - -/** - * igb_determine_phy_address - Determines PHY address. - * @hw: pointer to the HW structure - * - * This uses a trial and error method to loop through possible PHY - * addresses. It tests each by reading the PHY ID registers and - * checking for a match. - **/ -s32 igb_determine_phy_address(struct e1000_hw *hw) -{ - s32 ret_val = -E1000_ERR_PHY_TYPE; - u32 phy_addr = 0; - u32 i; - enum e1000_phy_type phy_type = e1000_phy_unknown; - - hw->phy.id = phy_type; - - for (phy_addr = 0; phy_addr < E1000_MAX_PHY_ADDR; phy_addr++) { - hw->phy.addr = phy_addr; - i = 0; - - do { - igb_get_phy_id(hw); - phy_type = igb_get_phy_type_from_id(hw->phy.id); - - /* - * If phy_type is valid, break - we found our - * PHY address - */ - if (phy_type != e1000_phy_unknown) { - ret_val = E1000_SUCCESS; - goto out; - } - msec_delay(1); - i++; - } while (i < 10); - } - -out: - return ret_val; -} - -/** - * igb_power_up_phy_copper - Restore copper link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, restore the link to previous - * settings. - **/ -void igb_power_up_phy_copper(struct e1000_hw *hw) -{ - u16 mii_reg = 0; - - /* The PHY will retain its settings across a power down/up cycle */ - hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); - mii_reg &= ~MII_CR_POWER_DOWN; - hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); -} - -/** - * igb_power_down_phy_copper - Restore copper link in case of PHY power down - * @hw: pointer to the HW structure - * - * In the case of a PHY power down to save power, or to turn off link during a - * driver unload, or wake on lan is not enabled, restore the link to previous - * settings. - **/ -void igb_power_down_phy_copper(struct e1000_hw *hw) -{ - u16 mii_reg = 0; - - /* The PHY will retain its settings across a power down/up cycle */ - hw->phy.ops.read_reg(hw, PHY_CONTROL, &mii_reg); - mii_reg |= MII_CR_POWER_DOWN; - hw->phy.ops.write_reg(hw, PHY_CONTROL, mii_reg); - msec_delay(1); -} diff --git a/src/drivers/net/igb/igb_phy.h b/src/drivers/net/igb/igb_phy.h deleted file mode 100644 index 8e6bc991..00000000 --- a/src/drivers/net/igb/igb_phy.h +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_PHY_H_ -#define _IGB_PHY_H_ - -void igb_init_phy_ops_generic(struct e1000_hw *hw); -s32 igb_check_downshift_generic(struct e1000_hw *hw); -s32 igb_check_polarity_m88(struct e1000_hw *hw); -s32 igb_check_polarity_igp(struct e1000_hw *hw); -s32 igb_check_polarity_ife(struct e1000_hw *hw); -s32 igb_check_reset_block_generic(struct e1000_hw *hw); -s32 igb_copper_link_autoneg(struct e1000_hw *hw); -s32 igb_copper_link_setup_igp(struct e1000_hw *hw); -s32 igb_copper_link_setup_m88(struct e1000_hw *hw); -#if 0 -s32 igb_phy_force_speed_duplex_igp(struct e1000_hw *hw); -s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw); -s32 igb_phy_force_speed_duplex_ife(struct e1000_hw *hw); -#endif -#if 0 -s32 igb_get_cable_length_m88(struct e1000_hw *hw); -s32 igb_get_cable_length_igp_2(struct e1000_hw *hw); -#endif -s32 igb_get_cfg_done_generic(struct e1000_hw *hw); -s32 igb_get_phy_id(struct e1000_hw *hw); -s32 igb_get_phy_info_igp(struct e1000_hw *hw); -s32 igb_get_phy_info_m88(struct e1000_hw *hw); -s32 igb_phy_sw_reset_generic(struct e1000_hw *hw); -#if 0 -void igb_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl); -#endif -s32 igb_phy_hw_reset_generic(struct e1000_hw *hw); -s32 igb_phy_reset_dsp_generic(struct e1000_hw *hw); -s32 igb_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_read_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_read_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_set_d3_lplu_state_generic(struct e1000_hw *hw, bool active); -s32 igb_setup_copper_link_generic(struct e1000_hw *hw); -s32 igb_wait_autoneg_generic(struct e1000_hw *hw); -s32 igb_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_write_kmrn_reg_locked(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_write_phy_reg_igp_locked(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_phy_reset_dsp(struct e1000_hw *hw); -s32 igb_phy_has_link_generic(struct e1000_hw *hw, u32 iterations, - u32 usec_interval, bool *success); -s32 igb_phy_init_script_igp3(struct e1000_hw *hw); -enum e1000_phy_type igb_get_phy_type_from_id(u32 phy_id); -s32 igb_determine_phy_address(struct e1000_hw *hw); -void igb_power_up_phy_copper(struct e1000_hw *hw); -void igb_power_down_phy_copper(struct e1000_hw *hw); -s32 igb_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); -s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data); -s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data); - -#define E1000_MAX_PHY_ADDR 4 - -/* IGP01E1000 Specific Registers */ -#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* Port Config */ -#define IGP01E1000_PHY_PORT_STATUS 0x11 /* Status */ -#define IGP01E1000_PHY_PORT_CTRL 0x12 /* Control */ -#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health */ -#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO */ -#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality */ -#define IGP02E1000_PHY_POWER_MGMT 0x19 /* Power Management */ -#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ -#define BM_PHY_PAGE_SELECT 22 /* Page Select for BM */ -#define IGP_PAGE_SHIFT 5 -#define PHY_REG_MASK 0x1F - -#define IGP01E1000_PHY_PCS_INIT_REG 0x00B4 -#define IGP01E1000_PHY_POLARITY_MASK 0x0078 - -#define IGP01E1000_PSCR_AUTO_MDIX 0x1000 -#define IGP01E1000_PSCR_FORCE_MDI_MDIX 0x2000 /* 0=MDI, 1=MDIX */ - -#define IGP01E1000_PSCFR_SMART_SPEED 0x0080 - -/* Enable flexible speed on link-up */ -#define IGP01E1000_GMII_FLEX_SPD 0x0010 -#define IGP01E1000_GMII_SPD 0x0020 /* Enable SPD */ - -#define IGP02E1000_PM_SPD 0x0001 /* Smart Power Down */ -#define IGP02E1000_PM_D0_LPLU 0x0002 /* For D0a states */ -#define IGP02E1000_PM_D3_LPLU 0x0004 /* For all other states */ - -#define IGP01E1000_PLHR_SS_DOWNGRADE 0x8000 - -#define IGP01E1000_PSSR_POLARITY_REVERSED 0x0002 -#define IGP01E1000_PSSR_MDIX 0x0800 -#define IGP01E1000_PSSR_SPEED_MASK 0xC000 -#define IGP01E1000_PSSR_SPEED_1000MBPS 0xC000 - -#define IGP02E1000_PHY_CHANNEL_NUM 4 -#define IGP02E1000_PHY_AGC_A 0x11B1 -#define IGP02E1000_PHY_AGC_B 0x12B1 -#define IGP02E1000_PHY_AGC_C 0x14B1 -#define IGP02E1000_PHY_AGC_D 0x18B1 - -#define IGP02E1000_AGC_LENGTH_SHIFT 9 /* Course - 15:13, Fine - 12:9 */ -#define IGP02E1000_AGC_LENGTH_MASK 0x7F -#define IGP02E1000_AGC_RANGE 15 - -#define IGP03E1000_PHY_MISC_CTRL 0x1B -#define IGP03E1000_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Manually Set Duplex */ - -#define E1000_CABLE_LENGTH_UNDEFINED 0xFF - -#define E1000_KMRNCTRLSTA_OFFSET 0x001F0000 -#define E1000_KMRNCTRLSTA_OFFSET_SHIFT 16 -#define E1000_KMRNCTRLSTA_REN 0x00200000 -#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */ -#define E1000_KMRNCTRLSTA_TIMEOUTS 0x4 /* Kumeran Timeouts */ -#define E1000_KMRNCTRLSTA_INBAND_PARAM 0x9 /* Kumeran InBand Parameters */ -#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */ - -#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 -#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */ -#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY Special and LED Control */ -#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control */ - -/* IFE PHY Extended Status Control */ -#define IFE_PESC_POLARITY_REVERSED 0x0100 - -/* IFE PHY Special Control */ -#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 -#define IFE_PSC_FORCE_POLARITY 0x0020 -#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 - -/* IFE PHY Special Control and LED Control */ -#define IFE_PSCL_PROBE_MODE 0x0020 -#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */ -#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */ - -/* IFE PHY MDIX Control */ -#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */ -#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDI-X, 0=force MDI */ -#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */ - -#endif /* _IGB_PHY_H_ */ diff --git a/src/drivers/net/igb/igb_regs.h b/src/drivers/net/igb/igb_regs.h deleted file mode 100644 index e549675b..00000000 --- a/src/drivers/net/igb/igb_regs.h +++ /dev/null @@ -1,486 +0,0 @@ -/******************************************************************************* - - Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2009 Intel Corporation. - - This program is free software; you can redistribute it and/or modify it - under the terms and conditions of the GNU General Public License, - version 2, as published by the Free Software Foundation. - - This program is distributed in the hope it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - e1000-devel Mailing List - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -FILE_LICENCE ( GPL2_ONLY ); - -#ifndef _IGB_REGS_H_ -#define _IGB_REGS_H_ - -#define E1000_CTRL 0x00000 /* Device Control - RW */ -#define E1000_CTRL_DUP 0x00004 /* Device Control Duplicate (Shadow) - RW */ -#define E1000_STATUS 0x00008 /* Device Status - RO */ -#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */ -#define E1000_EERD 0x00014 /* EEPROM Read - RW */ -#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */ -#define E1000_FLA 0x0001C /* Flash Access - RW */ -#define E1000_MDIC 0x00020 /* MDI Control - RW */ -#define E1000_SCTL 0x00024 /* SerDes Control - RW */ -#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ -#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ -#define E1000_FEXT 0x0002C /* Future Extended - RW */ -#define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ -#define E1000_FCT 0x00030 /* Flow Control Type - RW */ -#define E1000_CONNSW 0x00034 /* Copper/Fiber switch control - RW */ -#define E1000_VET 0x00038 /* VLAN Ether Type - RW */ -#define E1000_ICR 0x000C0 /* Interrupt Cause Read - R/clr */ -#define E1000_ITR 0x000C4 /* Interrupt Throttling Rate - RW */ -#define E1000_ICS 0x000C8 /* Interrupt Cause Set - WO */ -#define E1000_IMS 0x000D0 /* Interrupt Mask Set - RW */ -#define E1000_IMC 0x000D8 /* Interrupt Mask Clear - WO */ -#define E1000_IAM 0x000E0 /* Interrupt Acknowledge Auto Mask */ -#define E1000_RCTL 0x00100 /* Rx Control - RW */ -#define E1000_FCTTV 0x00170 /* Flow Control Transmit Timer Value - RW */ -#define E1000_TXCW 0x00178 /* Tx Configuration Word - RW */ -#define E1000_RXCW 0x00180 /* Rx Configuration Word - RO */ -#define E1000_EICR 0x01580 /* Ext. Interrupt Cause Read - R/clr */ -#define E1000_EITR(_n) (0x01680 + (0x4 * (_n))) -#define E1000_EICS 0x01520 /* Ext. Interrupt Cause Set - W0 */ -#define E1000_EIMS 0x01524 /* Ext. Interrupt Mask Set/Read - RW */ -#define E1000_EIMC 0x01528 /* Ext. Interrupt Mask Clear - WO */ -#define E1000_EIAC 0x0152C /* Ext. Interrupt Auto Clear - RW */ -#define E1000_EIAM 0x01530 /* Ext. Interrupt Ack Auto Clear Mask - RW */ -#define E1000_GPIE 0x01514 /* General Purpose Interrupt Enable - RW */ -#define E1000_IVAR0 0x01700 /* Interrupt Vector Allocation (array) - RW */ -#define E1000_IVAR_MISC 0x01740 /* IVAR for "other" causes - RW */ -#define E1000_TCTL 0x00400 /* Tx Control - RW */ -#define E1000_TCTL_EXT 0x00404 /* Extended Tx Control - RW */ -#define E1000_TIPG 0x00410 /* Tx Inter-packet gap -RW */ -#define E1000_TBT 0x00448 /* Tx Burst Timer - RW */ -#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ -#define E1000_LEDCTL 0x00E00 /* LED Control - RW */ -#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */ -#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */ -#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */ -#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */ -#define E1000_PBS 0x01008 /* Packet Buffer Size */ -#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */ -#define E1000_EEARBC 0x01024 /* EEPROM Auto Read Bus Control */ -#define E1000_FLASHT 0x01028 /* FLASH Timer Register */ -#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */ -#define E1000_FLSWCTL 0x01030 /* FLASH control register */ -#define E1000_FLSWDATA 0x01034 /* FLASH data register */ -#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */ -#define E1000_FLOP 0x0103C /* FLASH Opcode Register */ -#define E1000_I2CCMD 0x01028 /* SFPI2C Command Register - RW */ -#define E1000_I2CPARAMS 0x0102C /* SFPI2C Parameters Register - RW */ -#define E1000_WDSTP 0x01040 /* Watchdog Setup - RW */ -#define E1000_SWDSTS 0x01044 /* SW Device Status - RW */ -#define E1000_FRTIMER 0x01048 /* Free Running Timer - RW */ -#define E1000_TCPTIMER 0x0104C /* TCP Timer - RW */ -#define E1000_VPDDIAG 0x01060 /* VPD Diagnostic - RO */ -#define E1000_ICR_V2 0x01500 /* Interrupt Cause - new location - RC */ -#define E1000_ICS_V2 0x01504 /* Interrupt Cause Set - new location - WO */ -#define E1000_IMS_V2 0x01508 /* Interrupt Mask Set/Read - new location - RW */ -#define E1000_IMC_V2 0x0150C /* Interrupt Mask Clear - new location - WO */ -#define E1000_IAM_V2 0x01510 /* Interrupt Ack Auto Mask - new location - RW */ -#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */ -#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */ -#define E1000_FCRTH 0x02168 /* Flow Control Receive Threshold High - RW */ -#define E1000_PSRCTL 0x02170 /* Packet Split Receive Control - RW */ -#define E1000_RDFPCQ(_n) (0x02430 + (0x4 * (_n))) -#define E1000_PBRTH 0x02458 /* PB Rx Arbitration Threshold - RW */ -#define E1000_FCRTV 0x02460 /* Flow Control Refresh Timer Value - RW */ -/* Split and Replication Rx Control - RW */ -#define E1000_RDPUMB 0x025CC /* DMA Rx Descriptor uC Mailbox - RW */ -#define E1000_RDPUAD 0x025D0 /* DMA Rx Descriptor uC Addr Command - RW */ -#define E1000_RDPUWD 0x025D4 /* DMA Rx Descriptor uC Data Write - RW */ -#define E1000_RDPURD 0x025D8 /* DMA Rx Descriptor uC Data Read - RW */ -#define E1000_RDPUCTL 0x025DC /* DMA Rx Descriptor uC Control - RW */ -#define E1000_PBDIAG 0x02458 /* Packet Buffer Diagnostic - RW */ -#define E1000_RXPBS 0x02404 /* Rx Packet Buffer Size - RW */ -#define E1000_RDTR 0x02820 /* Rx Delay Timer - RW */ -#define E1000_RADV 0x0282C /* Rx Interrupt Absolute Delay Timer - RW */ -/* - * Convenience macros - * - * Note: "_n" is the queue number of the register to be written to. - * - * Example usage: - * E1000_RDBAL_REG(current_rx_queue) - */ -#define E1000_RDBAL(_n) ((_n) < 4 ? (0x02800 + ((_n) * 0x100)) : \ - (0x0C000 + ((_n) * 0x40))) -#define E1000_RDBAH(_n) ((_n) < 4 ? (0x02804 + ((_n) * 0x100)) : \ - (0x0C004 + ((_n) * 0x40))) -#define E1000_RDLEN(_n) ((_n) < 4 ? (0x02808 + ((_n) * 0x100)) : \ - (0x0C008 + ((_n) * 0x40))) -#define E1000_SRRCTL(_n) ((_n) < 4 ? (0x0280C + ((_n) * 0x100)) : \ - (0x0C00C + ((_n) * 0x40))) -#define E1000_RDH(_n) ((_n) < 4 ? (0x02810 + ((_n) * 0x100)) : \ - (0x0C010 + ((_n) * 0x40))) -#define E1000_RXCTL(_n) ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \ - (0x0C014 + ((_n) * 0x40))) -#define E1000_DCA_RXCTRL(_n) E1000_RXCTL(_n) -#define E1000_RDT(_n) ((_n) < 4 ? (0x02818 + ((_n) * 0x100)) : \ - (0x0C018 + ((_n) * 0x40))) -#define E1000_RXDCTL(_n) ((_n) < 4 ? (0x02828 + ((_n) * 0x100)) : \ - (0x0C028 + ((_n) * 0x40))) -#define E1000_RQDPC(_n) ((_n) < 4 ? (0x02830 + ((_n) * 0x100)) : \ - (0x0C030 + ((_n) * 0x40))) -#define E1000_TDBAL(_n) ((_n) < 4 ? (0x03800 + ((_n) * 0x100)) : \ - (0x0E000 + ((_n) * 0x40))) -#define E1000_TDBAH(_n) ((_n) < 4 ? (0x03804 + ((_n) * 0x100)) : \ - (0x0E004 + ((_n) * 0x40))) -#define E1000_TDLEN(_n) ((_n) < 4 ? (0x03808 + ((_n) * 0x100)) : \ - (0x0E008 + ((_n) * 0x40))) -#define E1000_TDH(_n) ((_n) < 4 ? (0x03810 + ((_n) * 0x100)) : \ - (0x0E010 + ((_n) * 0x40))) -#define E1000_TXCTL(_n) ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \ - (0x0E014 + ((_n) * 0x40))) -#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n) -#define E1000_TDT(_n) ((_n) < 4 ? (0x03818 + ((_n) * 0x100)) : \ - (0x0E018 + ((_n) * 0x40))) -#define E1000_TXDCTL(_n) ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) : \ - (0x0E028 + ((_n) * 0x40))) -#define E1000_TDWBAL(_n) ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) : \ - (0x0E038 + ((_n) * 0x40))) -#define E1000_TDWBAH(_n) ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) : \ - (0x0E03C + ((_n) * 0x40))) -#define E1000_TARC(_n) (0x03840 + ((_n) * 0x100)) -#define E1000_RSRPD 0x02C00 /* Rx Small Packet Detect - RW */ -#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */ -#define E1000_TXDMAC 0x03000 /* Tx DMA Control - RW */ -#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */ -#define E1000_PSRTYPE(_i) (0x05480 + ((_i) * 4)) -#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \ - (0x054E0 + ((_i - 16) * 8))) -#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \ - (0x054E4 + ((_i - 16) * 8))) -#define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) -#define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) -#define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) -#define E1000_FFMT_REG(_i) (0x09000 + ((_i) * 8)) -#define E1000_FFVT_REG(_i) (0x09800 + ((_i) * 8)) -#define E1000_FFLT_REG(_i) (0x05F00 + ((_i) * 8)) -#define E1000_PBSLAC 0x03100 /* Packet Buffer Slave Access Control */ -#define E1000_PBSLAD(_n) (0x03110 + (0x4 * (_n))) /* Packet Buffer DWORD (_n) */ -#define E1000_TXPBS 0x03404 /* Tx Packet Buffer Size - RW */ -#define E1000_TDFH 0x03410 /* Tx Data FIFO Head - RW */ -#define E1000_TDFT 0x03418 /* Tx Data FIFO Tail - RW */ -#define E1000_TDFHS 0x03420 /* Tx Data FIFO Head Saved - RW */ -#define E1000_TDFTS 0x03428 /* Tx Data FIFO Tail Saved - RW */ -#define E1000_TDFPC 0x03430 /* Tx Data FIFO Packet Count - RW */ -#define E1000_TDPUMB 0x0357C /* DMA Tx Descriptor uC Mail Box - RW */ -#define E1000_TDPUAD 0x03580 /* DMA Tx Descriptor uC Addr Command - RW */ -#define E1000_TDPUWD 0x03584 /* DMA Tx Descriptor uC Data Write - RW */ -#define E1000_TDPURD 0x03588 /* DMA Tx Descriptor uC Data Read - RW */ -#define E1000_TDPUCTL 0x0358C /* DMA Tx Descriptor uC Control - RW */ -#define E1000_DTXCTL 0x03590 /* DMA Tx Control - RW */ -#define E1000_DTXTCPFLGL 0x0359C /* DMA Tx Control flag low - RW */ -#define E1000_DTXTCPFLGH 0x035A0 /* DMA Tx Control flag high - RW */ -#define E1000_DTXMXSZRQ 0x03540 /* DMA Tx Max Total Allow Size Requests - RW */ -#define E1000_TIDV 0x03820 /* Tx Interrupt Delay Value - RW */ -#define E1000_TADV 0x0382C /* Tx Interrupt Absolute Delay Val - RW */ -#define E1000_TSPMT 0x03830 /* TCP Segmentation PAD & Min Threshold - RW */ -#define E1000_CRCERRS 0x04000 /* CRC Error Count - R/clr */ -#define E1000_ALGNERRC 0x04004 /* Alignment Error Count - R/clr */ -#define E1000_SYMERRS 0x04008 /* Symbol Error Count - R/clr */ -#define E1000_RXERRC 0x0400C /* Receive Error Count - R/clr */ -#define E1000_MPC 0x04010 /* Missed Packet Count - R/clr */ -#define E1000_SCC 0x04014 /* Single Collision Count - R/clr */ -#define E1000_ECOL 0x04018 /* Excessive Collision Count - R/clr */ -#define E1000_MCC 0x0401C /* Multiple Collision Count - R/clr */ -#define E1000_LATECOL 0x04020 /* Late Collision Count - R/clr */ -#define E1000_COLC 0x04028 /* Collision Count - R/clr */ -#define E1000_DC 0x04030 /* Defer Count - R/clr */ -#define E1000_TNCRS 0x04034 /* Tx-No CRS - R/clr */ -#define E1000_SEC 0x04038 /* Sequence Error Count - R/clr */ -#define E1000_CEXTERR 0x0403C /* Carrier Extension Error Count - R/clr */ -#define E1000_RLEC 0x04040 /* Receive Length Error Count - R/clr */ -#define E1000_XONRXC 0x04048 /* XON Rx Count - R/clr */ -#define E1000_XONTXC 0x0404C /* XON Tx Count - R/clr */ -#define E1000_XOFFRXC 0x04050 /* XOFF Rx Count - R/clr */ -#define E1000_XOFFTXC 0x04054 /* XOFF Tx Count - R/clr */ -#define E1000_FCRUC 0x04058 /* Flow Control Rx Unsupported Count- R/clr */ -#define E1000_PRC64 0x0405C /* Packets Rx (64 bytes) - R/clr */ -#define E1000_PRC127 0x04060 /* Packets Rx (65-127 bytes) - R/clr */ -#define E1000_PRC255 0x04064 /* Packets Rx (128-255 bytes) - R/clr */ -#define E1000_PRC511 0x04068 /* Packets Rx (255-511 bytes) - R/clr */ -#define E1000_PRC1023 0x0406C /* Packets Rx (512-1023 bytes) - R/clr */ -#define E1000_PRC1522 0x04070 /* Packets Rx (1024-1522 bytes) - R/clr */ -#define E1000_GPRC 0x04074 /* Good Packets Rx Count - R/clr */ -#define E1000_BPRC 0x04078 /* Broadcast Packets Rx Count - R/clr */ -#define E1000_MPRC 0x0407C /* Multicast Packets Rx Count - R/clr */ -#define E1000_GPTC 0x04080 /* Good Packets Tx Count - R/clr */ -#define E1000_GORCL 0x04088 /* Good Octets Rx Count Low - R/clr */ -#define E1000_GORCH 0x0408C /* Good Octets Rx Count High - R/clr */ -#define E1000_GOTCL 0x04090 /* Good Octets Tx Count Low - R/clr */ -#define E1000_GOTCH 0x04094 /* Good Octets Tx Count High - R/clr */ -#define E1000_RNBC 0x040A0 /* Rx No Buffers Count - R/clr */ -#define E1000_RUC 0x040A4 /* Rx Undersize Count - R/clr */ -#define E1000_RFC 0x040A8 /* Rx Fragment Count - R/clr */ -#define E1000_ROC 0x040AC /* Rx Oversize Count - R/clr */ -#define E1000_RJC 0x040B0 /* Rx Jabber Count - R/clr */ -#define E1000_MGTPRC 0x040B4 /* Management Packets Rx Count - R/clr */ -#define E1000_MGTPDC 0x040B8 /* Management Packets Dropped Count - R/clr */ -#define E1000_MGTPTC 0x040BC /* Management Packets Tx Count - R/clr */ -#define E1000_TORL 0x040C0 /* Total Octets Rx Low - R/clr */ -#define E1000_TORH 0x040C4 /* Total Octets Rx High - R/clr */ -#define E1000_TOTL 0x040C8 /* Total Octets Tx Low - R/clr */ -#define E1000_TOTH 0x040CC /* Total Octets Tx High - R/clr */ -#define E1000_TPR 0x040D0 /* Total Packets Rx - R/clr */ -#define E1000_TPT 0x040D4 /* Total Packets Tx - R/clr */ -#define E1000_PTC64 0x040D8 /* Packets Tx (64 bytes) - R/clr */ -#define E1000_PTC127 0x040DC /* Packets Tx (65-127 bytes) - R/clr */ -#define E1000_PTC255 0x040E0 /* Packets Tx (128-255 bytes) - R/clr */ -#define E1000_PTC511 0x040E4 /* Packets Tx (256-511 bytes) - R/clr */ -#define E1000_PTC1023 0x040E8 /* Packets Tx (512-1023 bytes) - R/clr */ -#define E1000_PTC1522 0x040EC /* Packets Tx (1024-1522 Bytes) - R/clr */ -#define E1000_MPTC 0x040F0 /* Multicast Packets Tx Count - R/clr */ -#define E1000_BPTC 0x040F4 /* Broadcast Packets Tx Count - R/clr */ -#define E1000_TSCTC 0x040F8 /* TCP Segmentation Context Tx - R/clr */ -#define E1000_TSCTFC 0x040FC /* TCP Segmentation Context Tx Fail - R/clr */ -#define E1000_IAC 0x04100 /* Interrupt Assertion Count */ -#define E1000_ICRXPTC 0x04104 /* Interrupt Cause Rx Pkt Timer Expire Count */ -#define E1000_ICRXATC 0x04108 /* Interrupt Cause Rx Abs Timer Expire Count */ -#define E1000_ICTXPTC 0x0410C /* Interrupt Cause Tx Pkt Timer Expire Count */ -#define E1000_ICTXATC 0x04110 /* Interrupt Cause Tx Abs Timer Expire Count */ -#define E1000_ICTXQEC 0x04118 /* Interrupt Cause Tx Queue Empty Count */ -#define E1000_ICTXQMTC 0x0411C /* Interrupt Cause Tx Queue Min Thresh Count */ -#define E1000_ICRXDMTC 0x04120 /* Interrupt Cause Rx Desc Min Thresh Count */ -#define E1000_ICRXOC 0x04124 /* Interrupt Cause Receiver Overrun Count */ - -#define E1000_LSECTXUT 0x04300 /* LinkSec Tx Untagged Packet Count - OutPktsUntagged */ -#define E1000_LSECTXPKTE 0x04304 /* LinkSec Encrypted Tx Packets Count - OutPktsEncrypted */ -#define E1000_LSECTXPKTP 0x04308 /* LinkSec Protected Tx Packet Count - OutPktsProtected */ -#define E1000_LSECTXOCTE 0x0430C /* LinkSec Encrypted Tx Octets Count - OutOctetsEncrypted */ -#define E1000_LSECTXOCTP 0x04310 /* LinkSec Protected Tx Octets Count - OutOctetsProtected */ -#define E1000_LSECRXUT 0x04314 /* LinkSec Untagged non-Strict Rx Packet Count - InPktsUntagged/InPktsNoTag */ -#define E1000_LSECRXOCTD 0x0431C /* LinkSec Rx Octets Decrypted Count - InOctetsDecrypted */ -#define E1000_LSECRXOCTV 0x04320 /* LinkSec Rx Octets Validated - InOctetsValidated */ -#define E1000_LSECRXBAD 0x04324 /* LinkSec Rx Bad Tag - InPktsBadTag */ -#define E1000_LSECRXNOSCI 0x04328 /* LinkSec Rx Packet No SCI Count - InPktsNoSci */ -#define E1000_LSECRXUNSCI 0x0432C /* LinkSec Rx Packet Unknown SCI Count - InPktsUnknownSci */ -#define E1000_LSECRXUNCH 0x04330 /* LinkSec Rx Unchecked Packets Count - InPktsUnchecked */ -#define E1000_LSECRXDELAY 0x04340 /* LinkSec Rx Delayed Packet Count - InPktsDelayed */ -#define E1000_LSECRXLATE 0x04350 /* LinkSec Rx Late Packets Count - InPktsLate */ -#define E1000_LSECRXOK(_n) (0x04360 + (0x04 * (_n))) /* LinkSec Rx Packet OK Count - InPktsOk */ -#define E1000_LSECRXINV(_n) (0x04380 + (0x04 * (_n))) /* LinkSec Rx Invalid Count - InPktsInvalid */ -#define E1000_LSECRXNV(_n) (0x043A0 + (0x04 * (_n))) /* LinkSec Rx Not Valid Count - InPktsNotValid */ -#define E1000_LSECRXUNSA 0x043C0 /* LinkSec Rx Unused SA Count - InPktsUnusedSa */ -#define E1000_LSECRXNUSA 0x043D0 /* LinkSec Rx Not Using SA Count - InPktsNotUsingSa */ -#define E1000_LSECTXCAP 0x0B000 /* LinkSec Tx Capabilities Register - RO */ -#define E1000_LSECRXCAP 0x0B300 /* LinkSec Rx Capabilities Register - RO */ -#define E1000_LSECTXCTRL 0x0B004 /* LinkSec Tx Control - RW */ -#define E1000_LSECRXCTRL 0x0B304 /* LinkSec Rx Control - RW */ -#define E1000_LSECTXSCL 0x0B008 /* LinkSec Tx SCI Low - RW */ -#define E1000_LSECTXSCH 0x0B00C /* LinkSec Tx SCI High - RW */ -#define E1000_LSECTXSA 0x0B010 /* LinkSec Tx SA0 - RW */ -#define E1000_LSECTXPN0 0x0B018 /* LinkSec Tx SA PN 0 - RW */ -#define E1000_LSECTXPN1 0x0B01C /* LinkSec Tx SA PN 1 - RW */ -#define E1000_LSECRXSCL 0x0B3D0 /* LinkSec Rx SCI Low - RW */ -#define E1000_LSECRXSCH 0x0B3E0 /* LinkSec Rx SCI High - RW */ -#define E1000_LSECTXKEY0(_n) (0x0B020 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 0 - WO */ -#define E1000_LSECTXKEY1(_n) (0x0B030 + (0x04 * (_n))) /* LinkSec Tx 128-bit Key 1 - WO */ -#define E1000_LSECRXSA(_n) (0x0B310 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */ -#define E1000_LSECRXPN(_n) (0x0B330 + (0x04 * (_n))) /* LinkSec Rx SAs - RW */ -/* - * LinkSec Rx Keys - where _n is the SA no. and _m the 4 dwords of the 128 bit - * key - RW. - */ -#define E1000_LSECRXKEY(_n, _m) (0x0B350 + (0x10 * (_n)) + (0x04 * (_m))) - -#define E1000_SSVPC 0x041A0 /* Switch Security Violation Packet Count */ -#define E1000_IPSCTRL 0xB430 /* IpSec Control Register */ -#define E1000_IPSRXCMD 0x0B408 /* IPSec Rx Command Register - RW */ -#define E1000_IPSRXIDX 0x0B400 /* IPSec Rx Index - RW */ -#define E1000_IPSRXIPADDR(_n) (0x0B420+ (0x04 * (_n))) /* IPSec Rx IPv4/v6 Address - RW */ -#define E1000_IPSRXKEY(_n) (0x0B410 + (0x04 * (_n))) /* IPSec Rx 128-bit Key - RW */ -#define E1000_IPSRXSALT 0x0B404 /* IPSec Rx Salt - RW */ -#define E1000_IPSRXSPI 0x0B40C /* IPSec Rx SPI - RW */ -#define E1000_IPSTXKEY(_n) (0x0B460 + (0x04 * (_n))) /* IPSec Tx 128-bit Key - RW */ -#define E1000_IPSTXSALT 0x0B454 /* IPSec Tx Salt - RW */ -#define E1000_IPSTXIDX 0x0B450 /* IPSec Tx SA IDX - RW */ -#define E1000_PCS_CFG0 0x04200 /* PCS Configuration 0 - RW */ -#define E1000_PCS_LCTL 0x04208 /* PCS Link Control - RW */ -#define E1000_PCS_LSTAT 0x0420C /* PCS Link Status - RO */ -#define E1000_CBTMPC 0x0402C /* Circuit Breaker Tx Packet Count */ -#define E1000_HTDPMC 0x0403C /* Host Transmit Discarded Packets */ -#define E1000_CBRDPC 0x04044 /* Circuit Breaker Rx Dropped Count */ -#define E1000_CBRMPC 0x040FC /* Circuit Breaker Rx Packet Count */ -#define E1000_RPTHC 0x04104 /* Rx Packets To Host */ -#define E1000_HGPTC 0x04118 /* Host Good Packets Tx Count */ -#define E1000_HTCBDPC 0x04124 /* Host Tx Circuit Breaker Dropped Count */ -#define E1000_HGORCL 0x04128 /* Host Good Octets Received Count Low */ -#define E1000_HGORCH 0x0412C /* Host Good Octets Received Count High */ -#define E1000_HGOTCL 0x04130 /* Host Good Octets Transmit Count Low */ -#define E1000_HGOTCH 0x04134 /* Host Good Octets Transmit Count High */ -#define E1000_LENERRS 0x04138 /* Length Errors Count */ -#define E1000_SCVPC 0x04228 /* SerDes/SGMII Code Violation Pkt Count */ -#define E1000_HRMPC 0x0A018 /* Header Redirection Missed Packet Count */ -#define E1000_PCS_ANADV 0x04218 /* AN advertisement - RW */ -#define E1000_PCS_LPAB 0x0421C /* Link Partner Ability - RW */ -#define E1000_PCS_NPTX 0x04220 /* AN Next Page Transmit - RW */ -#define E1000_PCS_LPABNP 0x04224 /* Link Partner Ability Next Page - RW */ -#define E1000_1GSTAT_RCV 0x04228 /* 1GSTAT Code Violation Packet Count - RW */ -#define E1000_RXCSUM 0x05000 /* Rx Checksum Control - RW */ -#define E1000_RLPML 0x05004 /* Rx Long Packet Max Length */ -#define E1000_RFCTL 0x05008 /* Receive Filter Control*/ -#define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ -#define E1000_RA 0x05400 /* Receive Address - RW Array */ -#define E1000_RA2 0x054E0 /* 2nd half of receive address array - RW Array */ -#define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ -#define E1000_VT_CTL 0x0581C /* VMDq Control - RW */ -#define E1000_VFQA0 0x0B000 /* VLAN Filter Queue Array 0 - RW Array */ -#define E1000_VFQA1 0x0B200 /* VLAN Filter Queue Array 1 - RW Array */ -#define E1000_WUC 0x05800 /* Wakeup Control - RW */ -#define E1000_WUFC 0x05808 /* Wakeup Filter Control - RW */ -#define E1000_WUS 0x05810 /* Wakeup Status - RO */ -#define E1000_MANC 0x05820 /* Management Control - RW */ -#define E1000_IPAV 0x05838 /* IP Address Valid - RW */ -#define E1000_IP4AT 0x05840 /* IPv4 Address Table - RW Array */ -#define E1000_IP6AT 0x05880 /* IPv6 Address Table - RW Array */ -#define E1000_WUPL 0x05900 /* Wakeup Packet Length - RW */ -#define E1000_WUPM 0x05A00 /* Wakeup Packet Memory - RO A */ -#define E1000_PBACL 0x05B68 /* MSIx PBA Clear - Read/Write 1's to clear */ -#define E1000_FFLT 0x05F00 /* Flexible Filter Length Table - RW Array */ -#define E1000_HOST_IF 0x08800 /* Host Interface */ -#define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ -#define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ -#define E1000_FHFT(_n) (0x09000 + (_n * 0x100)) /* Flexible Host Filter Table */ -#define E1000_FHFT_EXT(_n) (0x09A00 + (_n * 0x100)) /* Ext Flexible Host Filter Table */ - - -#define E1000_KMRNCTRLSTA 0x00034 /* MAC-PHY interface - RW */ -#define E1000_MDPHYA 0x0003C /* PHY address - RW */ -#define E1000_MANC2H 0x05860 /* Management Control To Host - RW */ -#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ -#define E1000_CCMCTL 0x05B48 /* CCM Control Register */ -#define E1000_GIOCTL 0x05B44 /* GIO Analog Control Register */ -#define E1000_SCCTL 0x05B4C /* PCIc PLL Configuration Register */ -#define E1000_GCR 0x05B00 /* PCI-Ex Control */ -#define E1000_GCR2 0x05B64 /* PCI-Ex Control #2 */ -#define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ -#define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ -#define E1000_GSCL_3 0x05B18 /* PCI-Ex Statistic Control #3 */ -#define E1000_GSCL_4 0x05B1C /* PCI-Ex Statistic Control #4 */ -#define E1000_FACTPS 0x05B30 /* Function Active and Power State to MNG */ -#define E1000_SWSM 0x05B50 /* SW Semaphore */ -#define E1000_FWSM 0x05B54 /* FW Semaphore */ -#define E1000_SWSM2 0x05B58 /* Driver-only SW semaphore (not used by BOOT agents) */ -#define E1000_DCA_ID 0x05B70 /* DCA Requester ID Information - RO */ -#define E1000_DCA_CTRL 0x05B74 /* DCA Control - RW */ -#define E1000_FFLT_DBG 0x05F04 /* Debug Register */ -#define E1000_HICR 0x08F00 /* Host Interface Control */ - -/* RSS registers */ -#define E1000_CPUVEC 0x02C10 /* CPU Vector Register - RW */ -#define E1000_MRQC 0x05818 /* Multiple Receive Control - RW */ -#define E1000_IMIR(_i) (0x05A80 + ((_i) * 4)) /* Immediate Interrupt */ -#define E1000_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* Immediate Interrupt Ext*/ -#define E1000_IMIRVP 0x05AC0 /* Immediate Interrupt Rx VLAN Priority - RW */ -#define E1000_MSIXBM(_i) (0x01600 + ((_i) * 4)) /* MSI-X Allocation Register - * (_i) - RW */ -#define E1000_MSIXTADD(_i) (0x0C000 + ((_i) * 0x10)) /* MSI-X Table entry addr - * low reg - RW */ -#define E1000_MSIXTUADD(_i) (0x0C004 + ((_i) * 0x10)) /* MSI-X Table entry addr - * upper reg - RW */ -#define E1000_MSIXTMSG(_i) (0x0C008 + ((_i) * 0x10)) /* MSI-X Table entry - * message reg - RW */ -#define E1000_MSIXVCTRL(_i) (0x0C00C + ((_i) * 0x10)) /* MSI-X Table entry - * vector ctrl reg - RW */ -#define E1000_MSIXPBA 0x0E000 /* MSI-X Pending bit array */ -#define E1000_RETA(_i) (0x05C00 + ((_i) * 4)) /* Redirection Table - RW */ -#define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW */ -#define E1000_RSSIM 0x05864 /* RSS Interrupt Mask */ -#define E1000_RSSIR 0x05868 /* RSS Interrupt Request */ -/* VT Registers */ -#define E1000_SWPBS 0x03004 /* Switch Packet Buffer Size - RW */ -#define E1000_MBVFICR 0x00C80 /* Mailbox VF Cause - RWC */ -#define E1000_MBVFIMR 0x00C84 /* Mailbox VF int Mask - RW */ -#define E1000_VFLRE 0x00C88 /* VF Register Events - RWC */ -#define E1000_VFRE 0x00C8C /* VF Receive Enables */ -#define E1000_VFTE 0x00C90 /* VF Transmit Enables */ -#define E1000_QDE 0x02408 /* Queue Drop Enable - RW */ -#define E1000_DTXSWC 0x03500 /* DMA Tx Switch Control - RW */ -#define E1000_RPLOLR 0x05AF0 /* Replication Offload - RW */ -#define E1000_UTA 0x0A000 /* Unicast Table Array - RW */ -#define E1000_IOVTCL 0x05BBC /* IOV Control Register */ -#define E1000_VMRCTL 0X05D80 /* Virtual Mirror Rule Control */ -/* These act per VF so an array friendly macro is used */ -#define E1000_V2PMAILBOX(_n) (0x00C40 + (4 * (_n))) -#define E1000_P2VMAILBOX(_n) (0x00C00 + (4 * (_n))) -#define E1000_VMBMEM(_n) (0x00800 + (64 * (_n))) -#define E1000_VFVMBMEM(_n) (0x00800 + (_n)) -#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n))) -#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine - * Filter - RW */ -/* Time Sync */ -#define E1000_TSYNCRXCTL 0x0B620 /* Rx Time Sync Control register - RW */ -#define E1000_TSYNCTXCTL 0x0B614 /* Tx Time Sync Control register - RW */ -#define E1000_TSYNCRXCFG 0x05F50 /* Time Sync Rx Configuration - RW */ -#define E1000_RXSTMPL 0x0B624 /* Rx timestamp Low - RO */ -#define E1000_RXSTMPH 0x0B628 /* Rx timestamp High - RO */ -#define E1000_RXSATRL 0x0B62C /* Rx timestamp attribute low - RO */ -#define E1000_RXSATRH 0x0B630 /* Rx timestamp attribute high - RO */ -#define E1000_TXSTMPL 0x0B618 /* Tx timestamp value Low - RO */ -#define E1000_TXSTMPH 0x0B61C /* Tx timestamp value High - RO */ -#define E1000_SYSTIML 0x0B600 /* System time register Low - RO */ -#define E1000_SYSTIMH 0x0B604 /* System time register High - RO */ -#define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */ - -/* Filtering Registers */ -#define E1000_SAQF(_n) (0x05980 + (4 * (_n))) /* Source Address Queue Fltr */ -#define E1000_DAQF(_n) (0x059A0 + (4 * (_n))) /* Dest Address Queue Fltr */ -#define E1000_SPQF(_n) (0x059C0 + (4 * (_n))) /* Source Port Queue Fltr */ -#define E1000_FTQF(_n) (0x059E0 + (4 * (_n))) /* 5-tuple Queue Fltr */ -#define E1000_TTQF(_n) (0x059E0 + (4 * (_n))) /* 2-tuple Queue Fltr */ -#define E1000_SYNQF(_n) (0x055FC + (4 * (_n))) /* SYN Packet Queue Fltr */ -#define E1000_ETQF(_n) (0x05CB0 + (4 * (_n))) /* EType Queue Fltr */ - -#define E1000_RTTDCS 0x3600 /* Reedtown Tx Desc plane control and status */ -#define E1000_RTTPCS 0x3474 /* Reedtown Tx Packet Plane control and status */ -#define E1000_RTRPCS 0x2474 /* Rx packet plane control and status */ -#define E1000_RTRUP2TC 0x05AC4 /* Rx User Priority to Traffic Class */ -#define E1000_RTTUP2TC 0x0418 /* Transmit User Priority to Traffic Class */ -#define E1000_RTTDTCRC(_n) (0x3610 + ((_n) * 4)) /* Tx Desc plane TC Rate-scheduler config */ -#define E1000_RTTPTCRC(_n) (0x3480 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Config */ -#define E1000_RTRPTCRC(_n) (0x2480 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Config */ -#define E1000_RTTDTCRS(_n) (0x3630 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler Status */ -#define E1000_RTTDTCRM(_n) (0x3650 + ((_n) * 4)) /* Tx Desc Plane TC Rate-Scheduler MMW */ -#define E1000_RTTPTCRS(_n) (0x34A0 + ((_n) * 4)) /* Tx Packet plane TC Rate-Scheduler Status */ -#define E1000_RTTPTCRM(_n) (0x34C0 + ((_n) * 4)) /* Tx Packet plane TC Rate-scheduler MMW */ -#define E1000_RTRPTCRS(_n) (0x24A0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler Status */ -#define E1000_RTRPTCRM(_n) (0x24C0 + ((_n) * 4)) /* Rx Packet plane TC Rate-Scheduler MMW */ -#define E1000_RTTDVMRM(_n) (0x3670 + ((_n) * 4)) /* Tx Desc plane VM Rate-Scheduler MMW*/ -#define E1000_RTTBCNRM(_n) (0x3690 + ((_n) * 4)) /* Tx BCN Rate-Scheduler MMW */ -#define E1000_RTTDQSEL 0x3604 /* Tx Desc Plane Queue Select */ -#define E1000_RTTDVMRC 0x3608 /* Tx Desc Plane VM Rate-Scheduler Config */ -#define E1000_RTTDVMRS 0x360C /* Tx Desc Plane VM Rate-Scheduler Status */ -#define E1000_RTTBCNRC 0x36B0 /* Tx BCN Rate-Scheduler Config */ -#define E1000_RTTBCNRS 0x36B4 /* Tx BCN Rate-Scheduler Status */ -#define E1000_RTTBCNCR 0xB200 /* Tx BCN Control Register */ -#define E1000_RTTBCNTG 0x35A4 /* Tx BCN Tagging */ -#define E1000_RTTBCNCP 0xB208 /* Tx BCN Congestion point */ -#define E1000_RTRBCNCR 0xB20C /* Rx BCN Control Register */ -#define E1000_RTTBCNRD 0x36B8 /* Tx BCN Rate Drift */ -#define E1000_PFCTOP 0x1080 /* Priority Flow Control Type and Opcode */ -#define E1000_RTTBCNIDX 0xB204 /* Tx BCN Congestion Point */ -#define E1000_RTTBCNACH 0x0B214 /* Tx BCN Control High */ -#define E1000_RTTBCNACL 0x0B210 /* Tx BCN Control Low */ - -#endif /* _IGB_REGS_H_ */ diff --git a/src/drivers/net/intel.c b/src/drivers/net/intel.c new file mode 100644 index 00000000..3eb1a377 --- /dev/null +++ b/src/drivers/net/intel.c @@ -0,0 +1,946 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intel.h" + +/** @file + * + * Intel 10/100/1000 network card driver + * + */ + +/****************************************************************************** + * + * EEPROM interface + * + ****************************************************************************** + */ + +/** + * Read data from EEPROM + * + * @v nvs NVS device + * @v address Address from which to read + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + */ +static int intel_read_eeprom ( struct nvs_device *nvs, unsigned int address, + void *data, size_t len ) { + struct intel_nic *intel = + container_of ( nvs, struct intel_nic, eeprom ); + unsigned int i; + uint32_t value; + uint16_t *data_word = data; + + /* Sanity check. We advertise a blocksize of one word, so + * should only ever receive single-word requests. + */ + assert ( len == sizeof ( *data_word ) ); + + /* Initiate read */ + writel ( ( INTEL_EERD_START | ( address << intel->eerd_addr_shift ) ), + intel->regs + INTEL_EERD ); + + /* Wait for read to complete */ + for ( i = 0 ; i < INTEL_EEPROM_MAX_WAIT_MS ; i++ ) { + + /* If read is not complete, delay 1ms and retry */ + value = readl ( intel->regs + INTEL_EERD ); + if ( ! ( value & intel->eerd_done ) ) { + mdelay ( 1 ); + continue; + } + + /* Extract data */ + *data_word = cpu_to_le16 ( INTEL_EERD_DATA ( value ) ); + return 0; + } + + DBGC ( intel, "INTEL %p timed out waiting for EEPROM read\n", intel ); + return -ETIMEDOUT; +} + +/** + * Write data to EEPROM + * + * @v nvs NVS device + * @v address Address to which to write + * @v data Data buffer + * @v len Length of data buffer + * @ret rc Return status code + */ +static int intel_write_eeprom ( struct nvs_device *nvs, + unsigned int address __unused, + const void *data __unused, + size_t len __unused ) { + struct intel_nic *intel = + container_of ( nvs, struct intel_nic, eeprom ); + + DBGC ( intel, "INTEL %p EEPROM write not supported\n", intel ); + return -ENOTSUP; +} + +/** + * Initialise EEPROM + * + * @v intel Intel device + * @ret rc Return status code + */ +static int intel_init_eeprom ( struct intel_nic *intel ) { + unsigned int i; + uint32_t value; + + /* The NIC automatically detects the type of attached EEPROM. + * The EERD register provides access to only a single word at + * a time, so we pretend to have a single-word block size. + * + * The EEPROM size may be larger than the minimum size, but + * this doesn't matter to us since we access only the first + * few words. + */ + intel->eeprom.word_len_log2 = INTEL_EEPROM_WORD_LEN_LOG2; + intel->eeprom.size = INTEL_EEPROM_MIN_SIZE_WORDS; + intel->eeprom.block_size = 1; + intel->eeprom.read = intel_read_eeprom; + intel->eeprom.write = intel_write_eeprom; + + /* The layout of the EERD register was changed at some point + * to accommodate larger EEPROMs. Read from address zero (for + * which the request layouts are compatible) to determine + * which type of register we have. + */ + writel ( INTEL_EERD_START, intel->regs + INTEL_EERD ); + for ( i = 0 ; i < INTEL_EEPROM_MAX_WAIT_MS ; i++ ) { + value = readl ( intel->regs + INTEL_EERD ); + if ( value & INTEL_EERD_DONE_LARGE ) { + DBGC ( intel, "INTEL %p has large-format EERD\n", + intel ); + intel->eerd_done = INTEL_EERD_DONE_LARGE; + intel->eerd_addr_shift = INTEL_EERD_ADDR_SHIFT_LARGE; + return 0; + } + if ( value & INTEL_EERD_DONE_SMALL ) { + DBGC ( intel, "INTEL %p has small-format EERD\n", + intel ); + intel->eerd_done = INTEL_EERD_DONE_SMALL; + intel->eerd_addr_shift = INTEL_EERD_ADDR_SHIFT_SMALL; + return 0; + } + mdelay ( 1 ); + } + + DBGC ( intel, "INTEL %p timed out waiting for initial EEPROM read " + "(value %08x)\n", intel, value ); + return -ETIMEDOUT; +} + +/****************************************************************************** + * + * MAC address + * + ****************************************************************************** + */ + +/** + * Fetch initial MAC address from EEPROM + * + * @v intel Intel device + * @v hw_addr Hardware address to fill in + * @ret rc Return status code + */ +static int intel_fetch_mac_eeprom ( struct intel_nic *intel, + uint8_t *hw_addr ) { + int rc; + + /* Initialise EEPROM */ + if ( ( rc = intel_init_eeprom ( intel ) ) != 0 ) + return rc; + + /* Read base MAC address from EEPROM */ + if ( ( rc = nvs_read ( &intel->eeprom, INTEL_EEPROM_MAC, + hw_addr, ETH_ALEN ) ) != 0 ) { + DBGC ( intel, "INTEL %p could not read EEPROM base MAC " + "address: %s\n", intel, strerror ( rc ) ); + return rc; + } + + /* Adjust MAC address for multi-port devices */ + hw_addr[ETH_ALEN-1] ^= intel->port; + + DBGC ( intel, "INTEL %p has EEPROM MAC address %s (port %d)\n", + intel, eth_ntoa ( hw_addr ), intel->port ); + return 0; +} + +/** + * Fetch initial MAC address + * + * @v intel Intel device + * @v hw_addr Hardware address to fill in + * @ret rc Return status code + */ +static int intel_fetch_mac ( struct intel_nic *intel, uint8_t *hw_addr ) { + union intel_receive_address mac; + int rc; + + /* Read current address from RAL0/RAH0 */ + mac.reg.low = cpu_to_le32 ( readl ( intel->regs + INTEL_RAL0 ) ); + mac.reg.high = cpu_to_le32 ( readl ( intel->regs + INTEL_RAH0 ) ); + DBGC ( intel, "INTEL %p has autoloaded MAC address %s\n", + intel, eth_ntoa ( mac.raw ) ); + + /* Try to read address from EEPROM */ + if ( ( rc = intel_fetch_mac_eeprom ( intel, hw_addr ) ) == 0 ) + return 0; + + /* Use current address if valid */ + if ( is_valid_ether_addr ( mac.raw ) ) { + memcpy ( hw_addr, mac.raw, ETH_ALEN ); + return 0; + } + + DBGC ( intel, "INTEL %p has no MAC address to use\n", intel ); + return -ENOENT; +} + +/****************************************************************************** + * + * Diagnostics + * + ****************************************************************************** + */ + +/** + * Dump diagnostic information + * + * @v intel Intel device + */ +static void __attribute__ (( unused )) intel_diag ( struct intel_nic *intel ) { + + DBGC ( intel, "INTEL %p TDH=%04x TDT=%04x RDH=%04x RDT=%04x\n", intel, + readl ( intel->regs + INTEL_TDH ), + readl ( intel->regs + INTEL_TDT ), + readl ( intel->regs + INTEL_RDH ), + readl ( intel->regs + INTEL_RDT ) ); +} + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset hardware + * + * @v intel Intel device + * @ret rc Return status code + */ +static int intel_reset ( struct intel_nic *intel ) { + uint32_t pbs; + uint32_t ctrl; + uint32_t status; + + /* Force RX and TX packet buffer allocation, to work around an + * errata in ICH devices. + */ + pbs = readl ( intel->regs + INTEL_PBS ); + if ( ( pbs == 0x14 ) || ( pbs == 0x18 ) ) { + DBGC ( intel, "INTEL %p WARNING: applying ICH PBS/PBA errata\n", + intel ); + writel ( 0x08, intel->regs + INTEL_PBA ); + writel ( 0x10, intel->regs + INTEL_PBS ); + } + + /* Always reset MAC. Required to reset the TX and RX rings. */ + ctrl = readl ( intel->regs + INTEL_CTRL ); + writel ( ( ctrl | INTEL_CTRL_RST ), intel->regs + INTEL_CTRL ); + mdelay ( INTEL_RESET_DELAY_MS ); + + /* Set a sensible default configuration */ + ctrl |= ( INTEL_CTRL_SLU | INTEL_CTRL_ASDE ); + ctrl &= ~( INTEL_CTRL_LRST | INTEL_CTRL_FRCSPD | INTEL_CTRL_FRCDPLX ); + writel ( ctrl, intel->regs + INTEL_CTRL ); + mdelay ( INTEL_RESET_DELAY_MS ); + + /* If link is already up, do not attempt to reset the PHY. On + * some models (notably ICH), performing a PHY reset seems to + * drop the link speed to 10Mbps. + */ + status = readl ( intel->regs + INTEL_STATUS ); + if ( status & INTEL_STATUS_LU ) { + DBGC ( intel, "INTEL %p MAC reset (ctrl %08x)\n", + intel, ctrl ); + return 0; + } + + /* Reset PHY and MAC simultaneously */ + writel ( ( ctrl | INTEL_CTRL_RST | INTEL_CTRL_PHY_RST ), + intel->regs + INTEL_CTRL ); + mdelay ( INTEL_RESET_DELAY_MS ); + + /* PHY reset is not self-clearing on all models */ + writel ( ctrl, intel->regs + INTEL_CTRL ); + mdelay ( INTEL_RESET_DELAY_MS ); + + DBGC ( intel, "INTEL %p MAC+PHY reset (ctrl %08x)\n", intel, ctrl ); + return 0; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void intel_check_link ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + uint32_t status; + + /* Read link status */ + status = readl ( intel->regs + INTEL_STATUS ); + DBGC ( intel, "INTEL %p link status is %08x\n", intel, status ); + + /* Update network device */ + if ( status & INTEL_STATUS_LU ) { + netdev_link_up ( netdev ); + } else { + netdev_link_down ( netdev ); + } +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Create descriptor ring + * + * @v intel Intel device + * @v ring Descriptor ring + * @ret rc Return status code + */ +static int intel_create_ring ( struct intel_nic *intel, + struct intel_ring *ring ) { + physaddr_t address; + + /* Allocate descriptor ring. Align ring on its own size to + * prevent any possible page-crossing errors due to hardware + * errata. + */ + ring->desc = malloc_dma ( ring->len, ring->len ); + if ( ! ring->desc ) + return -ENOMEM; + + /* Initialise descriptor ring */ + memset ( ring->desc, 0, ring->len ); + + /* Program ring address */ + address = virt_to_bus ( ring->desc ); + writel ( ( address & 0xffffffffUL ), + ( intel->regs + ring->reg + INTEL_xDBAL ) ); + if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { + writel ( ( ( ( uint64_t ) address ) >> 32 ), + ( intel->regs + ring->reg + INTEL_xDBAH ) ); + } else { + writel ( 0, intel->regs + ring->reg + INTEL_xDBAH ); + } + + /* Program ring length */ + writel ( ring->len, ( intel->regs + ring->reg + INTEL_xDLEN ) ); + + /* Reset head and tail pointers */ + writel ( 0, ( intel->regs + ring->reg + INTEL_xDH ) ); + writel ( 0, ( intel->regs + ring->reg + INTEL_xDT ) ); + + DBGC ( intel, "INTEL %p ring %05x is at [%08llx,%08llx)\n", + intel, ring->reg, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + ring->len ) ); + + return 0; +} + +/** + * Destroy descriptor ring + * + * @v intel Intel device + * @v ring Descriptor ring + */ +static void intel_destroy_ring ( struct intel_nic *intel, + struct intel_ring *ring ) { + + /* Clear ring length */ + writel ( 0, ( intel->regs + ring->reg + INTEL_xDLEN ) ); + + /* Clear ring address */ + writel ( 0, ( intel->regs + ring->reg + INTEL_xDBAL ) ); + writel ( 0, ( intel->regs + ring->reg + INTEL_xDBAH ) ); + + /* Free descriptor ring */ + free_dma ( ring->desc, ring->len ); + ring->desc = NULL; + ring->prod = 0; + ring->cons = 0; +} + +/** + * Refill receive descriptor ring + * + * @v intel Intel device + */ +static void intel_refill_rx ( struct intel_nic *intel ) { + struct intel_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + unsigned int rx_tail; + physaddr_t address; + + while ( ( intel->rx.prod - intel->rx.cons ) < INTEL_RX_FILL ) { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( INTEL_RX_MAX_LEN ); + if ( ! iobuf ) { + /* Wait for next refill */ + return; + } + + /* Get next receive descriptor */ + rx_idx = ( intel->rx.prod++ % INTEL_NUM_RX_DESC ); + rx_tail = ( intel->rx.prod % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; + + /* Populate receive descriptor */ + address = virt_to_bus ( iobuf->data ); + rx->address = cpu_to_le64 ( address ); + rx->length = 0; + rx->status = 0; + rx->errors = 0; + wmb(); + + /* Record I/O buffer */ + assert ( intel->rx_iobuf[rx_idx] == NULL ); + intel->rx_iobuf[rx_idx] = iobuf; + + /* Push descriptor to card */ + writel ( rx_tail, intel->regs + INTEL_RDT ); + + DBGC2 ( intel, "INTEL %p RX %d is [%llx,%llx)\n", intel, rx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + INTEL_RX_MAX_LEN ) ); + } +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int intel_open ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + union intel_receive_address mac; + uint32_t tctl; + uint32_t rctl; + int rc; + + /* Create transmit descriptor ring */ + if ( ( rc = intel_create_ring ( intel, &intel->tx ) ) != 0 ) + goto err_create_tx; + + /* Create receive descriptor ring */ + if ( ( rc = intel_create_ring ( intel, &intel->rx ) ) != 0 ) + goto err_create_rx; + + /* Fill receive ring */ + intel_refill_rx ( intel ); + + /* Program MAC address */ + memset ( &mac, 0, sizeof ( mac ) ); + memcpy ( mac.raw, netdev->ll_addr, sizeof ( mac.raw ) ); + writel ( le32_to_cpu ( mac.reg.low ), intel->regs + INTEL_RAL0 ); + writel ( ( le32_to_cpu ( mac.reg.high ) | INTEL_RAH0_AV ), + intel->regs + INTEL_RAH0 ); + + /* Enable transmitter */ + tctl = readl ( intel->regs + INTEL_TCTL ); + tctl &= ~( INTEL_TCTL_CT_MASK | INTEL_TCTL_COLD_MASK ); + tctl |= ( INTEL_TCTL_EN | INTEL_TCTL_PSP | INTEL_TCTL_CT_DEFAULT | + INTEL_TCTL_COLD_DEFAULT ); + writel ( tctl, intel->regs + INTEL_TCTL ); + + /* Enable receiver */ + rctl = readl ( intel->regs + INTEL_RCTL ); + rctl &= ~( INTEL_RCTL_BSIZE_BSEX_MASK ); + rctl |= ( INTEL_RCTL_EN | INTEL_RCTL_UPE | INTEL_RCTL_MPE | + INTEL_RCTL_BAM | INTEL_RCTL_BSIZE_2048 | INTEL_RCTL_SECRC ); + writel ( rctl, intel->regs + INTEL_RCTL ); + + /* Update link state */ + intel_check_link ( netdev ); + + return 0; + + intel_destroy_ring ( intel, &intel->rx ); + err_create_rx: + intel_destroy_ring ( intel, &intel->tx ); + err_create_tx: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void intel_close ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + unsigned int i; + + /* Disable receiver */ + writel ( 0, intel->regs + INTEL_RCTL ); + + /* Disable transmitter */ + writel ( 0, intel->regs + INTEL_TCTL ); + + /* Destroy receive descriptor ring */ + intel_destroy_ring ( intel, &intel->rx ); + + /* Discard any unused receive buffers */ + for ( i = 0 ; i < INTEL_NUM_RX_DESC ; i++ ) { + if ( intel->rx_iobuf[i] ) + free_iob ( intel->rx_iobuf[i] ); + intel->rx_iobuf[i] = NULL; + } + + /* Destroy transmit descriptor ring */ + intel_destroy_ring ( intel, &intel->tx ); + + /* Reset the NIC, to flush the transmit and receive FIFOs */ + intel_reset ( intel ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int intel_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct intel_nic *intel = netdev->priv; + struct intel_descriptor *tx; + unsigned int tx_idx; + unsigned int tx_tail; + physaddr_t address; + + /* Get next transmit descriptor */ + if ( ( intel->tx.prod - intel->tx.cons ) >= INTEL_NUM_TX_DESC ) { + DBGC ( intel, "INTEL %p out of transmit descriptors\n", intel ); + return -ENOBUFS; + } + tx_idx = ( intel->tx.prod++ % INTEL_NUM_TX_DESC ); + tx_tail = ( intel->tx.prod % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; + + /* Populate transmit descriptor */ + address = virt_to_bus ( iobuf->data ); + tx->address = cpu_to_le64 ( address ); + tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); + tx->command = ( INTEL_DESC_CMD_RS | INTEL_DESC_CMD_IFCS | + INTEL_DESC_CMD_EOP ); + tx->status = 0; + wmb(); + + /* Notify card that there are packets ready to transmit */ + writel ( tx_tail, intel->regs + INTEL_TDT ); + + DBGC2 ( intel, "INTEL %p TX %d is [%llx,%llx)\n", intel, tx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + iob_len ( iobuf ) ) ); + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void intel_poll_tx ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + struct intel_descriptor *tx; + unsigned int tx_idx; + + /* Check for completed packets */ + while ( intel->tx.cons != intel->tx.prod ) { + + /* Get next transmit descriptor */ + tx_idx = ( intel->tx.cons % INTEL_NUM_TX_DESC ); + tx = &intel->tx.desc[tx_idx]; + + /* Stop if descriptor is still in use */ + if ( ! ( tx->status & INTEL_DESC_STATUS_DD ) ) + return; + + DBGC2 ( intel, "INTEL %p TX %d complete\n", intel, tx_idx ); + + /* Complete TX descriptor */ + netdev_tx_complete_next ( netdev ); + intel->tx.cons++; + } +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void intel_poll_rx ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + struct intel_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + size_t len; + + /* Check for received packets */ + while ( intel->rx.cons != intel->rx.prod ) { + + /* Get next receive descriptor */ + rx_idx = ( intel->rx.cons % INTEL_NUM_RX_DESC ); + rx = &intel->rx.desc[rx_idx]; + + /* Stop if descriptor is still in use */ + if ( ! ( rx->status & INTEL_DESC_STATUS_DD ) ) + return; + + /* Populate I/O buffer */ + iobuf = intel->rx_iobuf[rx_idx]; + intel->rx_iobuf[rx_idx] = NULL; + len = le16_to_cpu ( rx->length ); + iob_put ( iobuf, len ); + + /* Hand off to network stack */ + if ( rx->errors ) { + DBGC ( intel, "INTEL %p RX %d error (length %zd, " + "errors %02x)\n", + intel, rx_idx, len, rx->errors ); + netdev_rx_err ( netdev, iobuf, -EIO ); + } else { + DBGC2 ( intel, "INTEL %p RX %d complete (length %zd)\n", + intel, rx_idx, len ); + netdev_rx ( netdev, iobuf ); + } + intel->rx.cons++; + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void intel_poll ( struct net_device *netdev ) { + struct intel_nic *intel = netdev->priv; + uint32_t icr; + + /* Check for and acknowledge interrupts */ + icr = readl ( intel->regs + INTEL_ICR ); + if ( ! icr ) + return; + + /* Poll for TX completions, if applicable */ + if ( icr & INTEL_IRQ_TXDW ) + intel_poll_tx ( netdev ); + + /* Poll for RX completionsm, if applicable */ + if ( icr & INTEL_IRQ_RXT0 ) + intel_poll_rx ( netdev ); + + /* Check link state, if applicable */ + if ( icr & INTEL_IRQ_LSC ) + intel_check_link ( netdev ); + + /* Refill RX ring */ + intel_refill_rx ( intel ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void intel_irq ( struct net_device *netdev, int enable ) { + struct intel_nic *intel = netdev->priv; + uint32_t mask; + + mask = ( INTEL_IRQ_TXDW | INTEL_IRQ_LSC | INTEL_IRQ_RXT0 ); + if ( enable ) { + writel ( mask, intel->regs + INTEL_IMS ); + } else { + writel ( mask, intel->regs + INTEL_IMC ); + } +} + +/** Intel network device operations */ +static struct net_device_operations intel_operations = { + .open = intel_open, + .close = intel_close, + .transmit = intel_transmit, + .poll = intel_poll, + .irq = intel_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int intel_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct intel_nic *intel; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *intel ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &intel_operations ); + intel = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( intel, 0, sizeof ( *intel ) ); + intel->port = PCI_FUNC ( pci->busdevfn ); + intel_init_ring ( &intel->tx, INTEL_NUM_TX_DESC, INTEL_TD ); + intel_init_ring ( &intel->rx, INTEL_NUM_RX_DESC, INTEL_RD ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + intel->regs = ioremap ( pci->membase, INTEL_BAR_SIZE ); + + /* Reset the NIC */ + if ( ( rc = intel_reset ( intel ) ) != 0 ) + goto err_reset; + + /* Fetch MAC address */ + if ( ( rc = intel_fetch_mac ( intel, netdev->hw_addr ) ) != 0 ) + goto err_fetch_mac; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Set initial link state */ + intel_check_link ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register_netdev: + err_fetch_mac: + intel_reset ( intel ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void intel_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct intel_nic *intel = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset the NIC */ + intel_reset ( intel ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Intel PCI device IDs */ +static struct pci_device_id intel_nics[] = { + PCI_ROM ( 0x8086, 0x0438, "dh8900cc", "DH8900CC", 0 ), + PCI_ROM ( 0x8086, 0x043a, "dh8900cc-f", "DH8900CC Fiber", 0 ), + PCI_ROM ( 0x8086, 0x043c, "dh8900cc-b", "DH8900CC Backplane", 0 ), + PCI_ROM ( 0x8086, 0x0440, "dh8900cc-s", "DH8900CC SFP", 0 ), + PCI_ROM ( 0x8086, 0x1000, "82542-f", "82542 (Fiber)", 0 ), + PCI_ROM ( 0x8086, 0x1001, "82543gc-f", "82543GC (Fiber)", 0 ), + PCI_ROM ( 0x8086, 0x1004, "82543gc", "82543GC (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x1008, "82544ei", "82544EI (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x1009, "82544ei-f", "82544EI (Fiber)", 0 ), + PCI_ROM ( 0x8086, 0x100c, "82544gc", "82544GC (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x100d, "82544gc-l", "82544GC (LOM)", 0 ), + PCI_ROM ( 0x8086, 0x100e, "82540em", "82540EM", 0 ), + PCI_ROM ( 0x8086, 0x100f, "82545em", "82545EM (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x1010, "82546eb", "82546EB (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x1011, "82545em-f", "82545EM (Fiber)", 0 ), + PCI_ROM ( 0x8086, 0x1012, "82546eb-f", "82546EB (Fiber)", 0 ), + PCI_ROM ( 0x8086, 0x1013, "82541ei", "82541EI", 0 ), + PCI_ROM ( 0x8086, 0x1014, "82541er", "82541ER", 0 ), + PCI_ROM ( 0x8086, 0x1015, "82540em-l", "82540EM (LOM)", 0 ), + PCI_ROM ( 0x8086, 0x1016, "82540ep-m", "82540EP (Mobile)", 0 ), + PCI_ROM ( 0x8086, 0x1017, "82540ep", "82540EP", 0 ), + PCI_ROM ( 0x8086, 0x1018, "82541ei", "82541EI", 0 ), + PCI_ROM ( 0x8086, 0x1019, "82547ei", "82547EI", 0 ), + PCI_ROM ( 0x8086, 0x101a, "82547ei-m", "82547EI (Mobile)", 0 ), + PCI_ROM ( 0x8086, 0x101d, "82546eb", "82546EB", 0 ), + PCI_ROM ( 0x8086, 0x101e, "82540ep-m", "82540EP (Mobile)", 0 ), + PCI_ROM ( 0x8086, 0x1026, "82545gm", "82545GM", 0 ), + PCI_ROM ( 0x8086, 0x1027, "82545gm-1", "82545GM", 0 ), + PCI_ROM ( 0x8086, 0x1028, "82545gm-2", "82545GM", 0 ), + PCI_ROM ( 0x8086, 0x1049, "82566mm", "82566MM", 0 ), + PCI_ROM ( 0x8086, 0x104a, "82566dm", "82566DM", 0 ), + PCI_ROM ( 0x8086, 0x104b, "82566dc", "82566DC", 0 ), + PCI_ROM ( 0x8086, 0x104c, "82562v", "82562V 10/100", 0 ), + PCI_ROM ( 0x8086, 0x104d, "82566mc", "82566MC", 0 ), + PCI_ROM ( 0x8086, 0x105e, "82571eb", "82571EB", 0 ), + PCI_ROM ( 0x8086, 0x105f, "82571eb-1", "82571EB", 0 ), + PCI_ROM ( 0x8086, 0x1060, "82571eb-2", "82571EB", 0 ), + PCI_ROM ( 0x8086, 0x1075, "82547gi", "82547GI", 0 ), + PCI_ROM ( 0x8086, 0x1076, "82541gi", "82541GI", 0 ), + PCI_ROM ( 0x8086, 0x1077, "82541gi-1", "82541GI", 0 ), + PCI_ROM ( 0x8086, 0x1078, "82541er", "82541ER", 0 ), + PCI_ROM ( 0x8086, 0x1079, "82546gb", "82546GB", 0 ), + PCI_ROM ( 0x8086, 0x107a, "82546gb-1", "82546GB", 0 ), + PCI_ROM ( 0x8086, 0x107b, "82546gb-2", "82546GB", 0 ), + PCI_ROM ( 0x8086, 0x107c, "82541pi", "82541PI", 0 ), + PCI_ROM ( 0x8086, 0x107d, "82572ei", "82572EI (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x107e, "82572ei-f", "82572EI (Fiber)", 0 ), + PCI_ROM ( 0x8086, 0x107f, "82572ei", "82572EI", 0 ), + PCI_ROM ( 0x8086, 0x108a, "82546gb-3", "82546GB", 0 ), + PCI_ROM ( 0x8086, 0x108b, "82573v", "82573V (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x108c, "82573e", "82573E (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x1096, "80003es2lan", "80003ES2LAN (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x1098, "80003es2lan-s", "80003ES2LAN (Serdes)", 0 ), + PCI_ROM ( 0x8086, 0x1099, "82546gb-4", "82546GB (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x109a, "82573l", "82573L", 0 ), + PCI_ROM ( 0x8086, 0x10a4, "82571eb", "82571EB", 0 ), + PCI_ROM ( 0x8086, 0x10a5, "82571eb", "82571EB (Fiber)", 0 ), + PCI_ROM ( 0x8086, 0x10a7, "82575eb", "82575EB", 0 ), + PCI_ROM ( 0x8086, 0x10a9, "82575eb", "82575EB Backplane", 0 ), + PCI_ROM ( 0x8086, 0x10b5, "82546gb", "82546GB (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x10b9, "82572ei", "82572EI (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x10ba, "80003es2lan", "80003ES2LAN (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x10bb, "80003es2lan", "80003ES2LAN (Serdes)", 0 ), + PCI_ROM ( 0x8086, 0x10bc, "82571eb", "82571EB (Copper)", 0 ), + PCI_ROM ( 0x8086, 0x10bd, "82566dm-2", "82566DM-2", 0 ), + PCI_ROM ( 0x8086, 0x10bf, "82567lf", "82567LF", 0 ), + PCI_ROM ( 0x8086, 0x10c0, "82562v-2", "82562V-2 10/100", 0 ), + PCI_ROM ( 0x8086, 0x10c2, "82562g-2", "82562G-2 10/100", 0 ), + PCI_ROM ( 0x8086, 0x10c3, "82562gt-2", "82562GT-2 10/100", 0 ), + PCI_ROM ( 0x8086, 0x10c4, "82562gt", "82562GT 10/100", 0 ), + PCI_ROM ( 0x8086, 0x10c5, "82562g", "82562G 10/100", 0 ), + PCI_ROM ( 0x8086, 0x10c9, "82576", "82576", 0 ), + PCI_ROM ( 0x8086, 0x10cb, "82567v", "82567V", 0 ), + PCI_ROM ( 0x8086, 0x10cc, "82567lm-2", "82567LM-2", 0 ), + PCI_ROM ( 0x8086, 0x10cd, "82567lf-2", "82567LF-2", 0 ), + PCI_ROM ( 0x8086, 0x10ce, "82567v-2", "82567V-2", 0 ), + PCI_ROM ( 0x8086, 0x10d3, "82574l", "82574L", 0 ), + PCI_ROM ( 0x8086, 0x10d5, "82571pt", "82571PT PT Quad", 0 ), + PCI_ROM ( 0x8086, 0x10d6, "82575gb", "82575GB", 0 ), + PCI_ROM ( 0x8086, 0x10d9, "82571eb-d", "82571EB Dual Mezzanine", 0 ), + PCI_ROM ( 0x8086, 0x10da, "82571eb-q", "82571EB Quad Mezzanine", 0 ), + PCI_ROM ( 0x8086, 0x10de, "82567lm-3", "82567LM-3", 0 ), + PCI_ROM ( 0x8086, 0x10df, "82567lf-3", "82567LF-3", 0 ), + PCI_ROM ( 0x8086, 0x10e5, "82567lm-4", "82567LM-4", 0 ), + PCI_ROM ( 0x8086, 0x10e6, "82576", "82576", 0 ), + PCI_ROM ( 0x8086, 0x10e7, "82576-2", "82576", 0 ), + PCI_ROM ( 0x8086, 0x10e8, "82576-3", "82576", 0 ), + PCI_ROM ( 0x8086, 0x10ea, "82577lm", "82577LM", 0 ), + PCI_ROM ( 0x8086, 0x10eb, "82577lc", "82577LC", 0 ), + PCI_ROM ( 0x8086, 0x10ef, "82578dm", "82578DM", 0 ), + PCI_ROM ( 0x8086, 0x10f0, "82578dc", "82578DC", 0 ), + PCI_ROM ( 0x8086, 0x10f5, "82567lm", "82567LM", 0 ), + PCI_ROM ( 0x8086, 0x10f6, "82574l", "82574L", 0 ), + PCI_ROM ( 0x8086, 0x1501, "82567v-3", "82567V-3", 0 ), + PCI_ROM ( 0x8086, 0x1502, "82579lm", "82579LM", 0 ), + PCI_ROM ( 0x8086, 0x1503, "82579v", "82579V", 0 ), + PCI_ROM ( 0x8086, 0x150a, "82576ns", "82576NS", 0 ), + PCI_ROM ( 0x8086, 0x150c, "82583v", "82583V", 0 ), + PCI_ROM ( 0x8086, 0x150d, "82576-4", "82576 Backplane", 0 ), + PCI_ROM ( 0x8086, 0x150e, "82580", "82580", 0 ), + PCI_ROM ( 0x8086, 0x150f, "82580-f", "82580 Fiber", 0 ), + PCI_ROM ( 0x8086, 0x1510, "82580-b", "82580 Backplane", 0 ), + PCI_ROM ( 0x8086, 0x1511, "82580-s", "82580 SFP", 0 ), + PCI_ROM ( 0x8086, 0x1516, "82580-2", "82580", 0 ), + PCI_ROM ( 0x8086, 0x1518, "82576ns", "82576NS SerDes", 0 ), + PCI_ROM ( 0x8086, 0x1521, "i350", "I350", 0 ), + PCI_ROM ( 0x8086, 0x1522, "i350-f", "I350 Fiber", 0 ), + PCI_ROM ( 0x8086, 0x1523, "i350-b", "I350 Backplane", 0 ), + PCI_ROM ( 0x8086, 0x1524, "i350-2", "I350", 0 ), + PCI_ROM ( 0x8086, 0x1525, "82567v-4", "82567V-4", 0 ), + PCI_ROM ( 0x8086, 0x1526, "82576-5", "82576", 0 ), + PCI_ROM ( 0x8086, 0x1527, "82580-f2", "82580 Fiber", 0 ), + PCI_ROM ( 0x8086, 0x294c, "82566dc-2", "82566DC-2", 0 ), + PCI_ROM ( 0x8086, 0x2e6e, "cemedia", "CE Media Processor", 0 ), +}; + +/** Intel PCI driver */ +struct pci_driver intel_driver __pci_driver = { + .ids = intel_nics, + .id_count = ( sizeof ( intel_nics ) / sizeof ( intel_nics[0] ) ), + .probe = intel_probe, + .remove = intel_remove, +}; diff --git a/src/drivers/net/intel.h b/src/drivers/net/intel.h new file mode 100644 index 00000000..6f941d17 --- /dev/null +++ b/src/drivers/net/intel.h @@ -0,0 +1,252 @@ +#ifndef _INTEL_H +#define _INTEL_H + +/** @file + * + * Intel 10/100/1000 network card driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include + +/** Intel BAR size */ +#define INTEL_BAR_SIZE ( 128 * 1024 ) + +/** A packet descriptor */ +struct intel_descriptor { + /** Buffer address */ + uint64_t address; + /** Length */ + uint16_t length; + /** Reserved */ + uint8_t reserved_a; + /** Command */ + uint8_t command; + /** Status */ + uint8_t status; + /** Errors */ + uint8_t errors; + /** Reserved */ + uint16_t reserved_b; +} __attribute__ (( packed )); + +/** Packet descriptor command bits */ +enum intel_descriptor_command { + /** Report status */ + INTEL_DESC_CMD_RS = 0x08, + /** Insert frame checksum (CRC) */ + INTEL_DESC_CMD_IFCS = 0x02, + /** End of packet */ + INTEL_DESC_CMD_EOP = 0x01, +}; + +/** Packet descriptor status bits */ +enum intel_descriptor_status { + /** Descriptor done */ + INTEL_DESC_STATUS_DD = 0x01, +}; + +/** Device Control Register */ +#define INTEL_CTRL 0x00000UL +#define INTEL_CTRL_LRST 0x00000008UL /**< Link reset */ +#define INTEL_CTRL_ASDE 0x00000020UL /**< Auto-speed detection */ +#define INTEL_CTRL_SLU 0x00000040UL /**< Set link up */ +#define INTEL_CTRL_FRCSPD 0x00000800UL /**< Force speed */ +#define INTEL_CTRL_FRCDPLX 0x00001000UL /**< Force duplex */ +#define INTEL_CTRL_RST 0x04000000UL /**< Device reset */ +#define INTEL_CTRL_PHY_RST 0x80000000UL /**< PHY reset */ + +/** Time to delay for device reset, in milliseconds */ +#define INTEL_RESET_DELAY_MS 20 + +/** Device Status Register */ +#define INTEL_STATUS 0x00008UL +#define INTEL_STATUS_LU 0x00000002UL /**< Link up */ + +/** EEPROM Read Register */ +#define INTEL_EERD 0x00014UL +#define INTEL_EERD_START 0x00000001UL /**< Start read */ +#define INTEL_EERD_DONE_SMALL 0x00000010UL /**< Read done (small EERD) */ +#define INTEL_EERD_DONE_LARGE 0x00000002UL /**< Read done (large EERD) */ +#define INTEL_EERD_ADDR_SHIFT_SMALL 8 /**< Address shift (small) */ +#define INTEL_EERD_ADDR_SHIFT_LARGE 2 /**< Address shift (large) */ +#define INTEL_EERD_DATA(value) ( (value) >> 16 ) /**< Read data */ + +/** Maximum time to wait for EEPROM read, in milliseconds */ +#define INTEL_EEPROM_MAX_WAIT_MS 100 + +/** EEPROM word length */ +#define INTEL_EEPROM_WORD_LEN_LOG2 1 + +/** Minimum EEPROM size, in words */ +#define INTEL_EEPROM_MIN_SIZE_WORDS 64 + +/** Offset of MAC address within EEPROM */ +#define INTEL_EEPROM_MAC 0x00 + +/** Interrupt Cause Read Register */ +#define INTEL_ICR 0x000c0UL +#define INTEL_IRQ_TXDW 0x00000001UL /**< Transmit descriptor done */ +#define INTEL_IRQ_LSC 0x00000004UL /**< Link status change */ +#define INTEL_IRQ_RXT0 0x00000080UL /**< Receive timer */ + +/** Interrupt Mask Set/Read Register */ +#define INTEL_IMS 0x000d0UL + +/** Interrupt Mask Clear Register */ +#define INTEL_IMC 0x000d8UL + +/** Receive Control Register */ +#define INTEL_RCTL 0x00100UL +#define INTEL_RCTL_EN 0x00000002UL /**< Receive enable */ +#define INTEL_RCTL_UPE 0x00000008UL /**< Unicast promiscuous mode */ +#define INTEL_RCTL_MPE 0x00000010UL /**< Multicast promiscuous */ +#define INTEL_RCTL_BAM 0x00008000UL /**< Broadcast accept mode */ +#define INTEL_RCTL_BSIZE_BSEX(bsex,bsize) \ + ( ( (bsize) << 16 ) | ( (bsex) << 25 ) ) /**< Buffer size */ +#define INTEL_RCTL_BSIZE_2048 INTEL_RCTL_BSIZE_BSEX ( 0, 0 ) +#define INTEL_RCTL_BSIZE_BSEX_MASK INTEL_RCTL_BSIZE_BSEX ( 1, 3 ) +#define INTEL_RCTL_SECRC 0x04000000UL /**< Strip CRC */ + +/** Transmit Control Register */ +#define INTEL_TCTL 0x00400UL +#define INTEL_TCTL_EN 0x00000002UL /**< Transmit enable */ +#define INTEL_TCTL_PSP 0x00000008UL /**< Pad short packets */ +#define INTEL_TCTL_CT(x) ( (x) << 4 ) /**< Collision threshold */ +#define INTEL_TCTL_CT_DEFAULT INTEL_TCTL_CT ( 0x0f ) +#define INTEL_TCTL_CT_MASK INTEL_TCTL_CT ( 0xff ) +#define INTEL_TCTL_COLD(x) ( (x) << 12 ) /**< Collision distance */ +#define INTEL_TCTL_COLD_DEFAULT INTEL_TCTL_COLD ( 0x040 ) +#define INTEL_TCTL_COLD_MASK INTEL_TCTL_COLD ( 0x3ff ) + +/** Packet Buffer Allocation */ +#define INTEL_PBA 0x01000UL + +/** Packet Buffer Size */ +#define INTEL_PBS 0x01008UL + +/** Receive Descriptor register block */ +#define INTEL_RD 0x02800UL + +/** Number of receive descriptors + * + * Minimum value is 8, since the descriptor ring length must be a + * multiple of 128. + */ +#define INTEL_NUM_RX_DESC 8 + +/** Receive descriptor ring fill level */ +#define INTEL_RX_FILL 4 + +/** Receive buffer length */ +#define INTEL_RX_MAX_LEN 2048 + +/** Transmit Descriptor register block */ +#define INTEL_TD 0x03800UL + +/** Number of transmit descriptors + * + * Descriptor ring length must be a multiple of 16. ICH8/9/10 + * requires a minimum of 16 TX descriptors. + */ +#define INTEL_NUM_TX_DESC 16 + +/** Receive/Transmit Descriptor Base Address Low (offset) */ +#define INTEL_xDBAL 0x00 + +/** Receive/Transmit Descriptor Base Address High (offset) */ +#define INTEL_xDBAH 0x04 + +/** Receive/Transmit Descriptor Length (offset) */ +#define INTEL_xDLEN 0x08 + +/** Receive/Transmit Descriptor Head (offset) */ +#define INTEL_xDH 0x10 + +/** Receive/Transmit Descriptor Tail (offset) */ +#define INTEL_xDT 0x18 + +/** Receive Descriptor Head */ +#define INTEL_RDH ( INTEL_RD + INTEL_xDH ) + +/** Receive Descriptor Tail */ +#define INTEL_RDT ( INTEL_RD + INTEL_xDT ) + +/** Transmit Descriptor Head */ +#define INTEL_TDH ( INTEL_TD + INTEL_xDH ) + +/** Transmit Descriptor Tail */ +#define INTEL_TDT ( INTEL_TD + INTEL_xDT ) + +/** Receive Address Low */ +#define INTEL_RAL0 0x05400UL + +/** Receive Address High */ +#define INTEL_RAH0 0x05404UL +#define INTEL_RAH0_AV 0x80000000UL /**< Address valid */ + +/** Receive address */ +union intel_receive_address { + struct { + uint32_t low; + uint32_t high; + } __attribute__ (( packed )) reg; + uint8_t raw[ETH_ALEN]; +}; + +/** An Intel descriptor ring */ +struct intel_ring { + /** Descriptors */ + struct intel_descriptor *desc; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; + + /** Register block */ + unsigned int reg; + /** Length (in bytes) */ + size_t len; +}; + +/** + * Initialise descriptor ring + * + * @v ring Descriptor ring + * @v count Number of descriptors + * @v reg Descriptor register block + */ +static inline __attribute__ (( always_inline)) void +intel_init_ring ( struct intel_ring *ring, unsigned int count, + unsigned int reg ) { + ring->len = ( count * sizeof ( ring->desc[0] ) ); + ring->reg = reg; +} + +/** An Intel network card */ +struct intel_nic { + /** Registers */ + void *regs; + /** Port number (for multi-port devices) */ + unsigned int port; + + /** EEPROM */ + struct nvs_device eeprom; + /** EEPROM done flag */ + uint32_t eerd_done; + /** EEPROM address shift */ + unsigned int eerd_addr_shift; + + /** Transmit descriptor ring */ + struct intel_ring tx; + /** Receive descriptor ring */ + struct intel_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[INTEL_NUM_RX_DESC]; +}; + +#endif /* _INTEL_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index ff87e9b9..471ba77c 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -144,6 +144,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_mii ( ERRFILE_DRIVER | 0x00620000 ) #define ERRFILE_realtek ( ERRFILE_DRIVER | 0x00630000 ) #define ERRFILE_skeleton ( ERRFILE_DRIVER | 0x00640000 ) +#define ERRFILE_intel ( ERRFILE_DRIVER | 0x00650000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) From 7865ae0deabc377fa29fb53b01647621959c6564 Mon Sep 17 00:00:00 2001 From: Marin Hannache Date: Thu, 12 Apr 2012 23:14:08 +0200 Subject: [PATCH 187/221] [image] Remove non-working image loaders The WinCE, a.out and FreeBSD loaders are designed to be #included by core/loader.c, which no longer exists. These old loaders are not usable anymore and cause compilation failures when enabled in config/general.h. Signed-off-by: Marin Hannache Signed-off-by: Michael Brown --- src/arch/i386/Makefile | 7 - src/arch/i386/core/aout_loader.c | 144 ----------- src/arch/i386/core/freebsd_loader.c | 377 ---------------------------- src/arch/i386/core/wince_loader.c | 273 -------------------- src/config/config.c | 9 - src/config/general.h | 3 - 6 files changed, 813 deletions(-) delete mode 100644 src/arch/i386/core/aout_loader.c delete mode 100644 src/arch/i386/core/freebsd_loader.c delete mode 100644 src/arch/i386/core/wince_loader.c diff --git a/src/arch/i386/Makefile b/src/arch/i386/Makefile index 068fbd67..ca258330 100644 --- a/src/arch/i386/Makefile +++ b/src/arch/i386/Makefile @@ -88,13 +88,6 @@ SRCDIRS += arch/i386/interface/syslinux SRCDIRS += arch/i386/interface/vmware SRCDIRS += arch/i386/hci/commands -# The various xxx_loader.c files are #included into core/loader.c and -# should not be compiled directly. -# -NON_AUTO_SRCS += arch/i386/core/aout_loader.c -NON_AUTO_SRCS += arch/i386/core/freebsd_loader.c -NON_AUTO_SRCS += arch/i386/core/wince_loader.c - # Include common x86 Makefile # MAKEDEPS += arch/x86/Makefile diff --git a/src/arch/i386/core/aout_loader.c b/src/arch/i386/core/aout_loader.c deleted file mode 100644 index f85620e9..00000000 --- a/src/arch/i386/core/aout_loader.c +++ /dev/null @@ -1,144 +0,0 @@ -/* a.out */ -struct exec { - unsigned long a_midmag; /* flags<<26 | mid<<16 | magic */ - unsigned long a_text; /* text segment size */ - unsigned long a_data; /* initialized data size */ - unsigned long a_bss; /* uninitialized data size */ - unsigned long a_syms; /* symbol table size */ - unsigned long a_entry; /* entry point */ - unsigned long a_trsize; /* text relocation size */ - unsigned long a_drsize; /* data relocation size */ -}; - -struct aout_state { - struct exec head; - unsigned long curaddr; - int segment; /* current segment number, -1 for none */ - unsigned long loc; /* start offset of current block */ - unsigned long skip; /* padding to be skipped to current segment */ - unsigned long toread; /* remaining data to be read in the segment */ -}; - -static struct aout_state astate; - -static sector_t aout_download(unsigned char *data, unsigned int len, int eof); -static inline os_download_t aout_probe(unsigned char *data, unsigned int len) -{ - unsigned long start, mid, end, istart, iend; - if (len < sizeof(astate.head)) { - return 0; - } - memcpy(&astate.head, data, sizeof(astate.head)); - if ((astate.head.a_midmag & 0xffff) != 0x010BL) { - return 0; - } - - printf("(a.out"); - aout_freebsd_probe(); - printf(")... "); - /* Check the aout image */ - start = astate.head.a_entry; - mid = (((start + astate.head.a_text) + 4095) & ~4095) + astate.head.a_data; - end = ((mid + 4095) & ~4095) + astate.head.a_bss; - istart = 4096; - iend = istart + (mid - start); - if (!prep_segment(start, mid, end, istart, iend)) - return dead_download; - astate.segment = -1; - astate.loc = 0; - astate.skip = 0; - astate.toread = 0; - return aout_download; -} - -static sector_t aout_download(unsigned char *data, unsigned int len, int eof) -{ - unsigned int offset; /* working offset in the current data block */ - - offset = 0; - -#ifdef AOUT_LYNX_KDI - astate.segment++; - if (astate.segment == 0) { - astate.curaddr = 0x100000; - astate.head.a_entry = astate.curaddr + 0x20; - } - memcpy(phys_to_virt(astate.curaddr), data, len); - astate.curaddr += len; - return 0; -#endif - - do { - if (astate.segment != -1) { - if (astate.skip) { - if (astate.skip >= len - offset) { - astate.skip -= len - offset; - break; - } - offset += astate.skip; - astate.skip = 0; - } - - if (astate.toread) { - if (astate.toread >= len - offset) { - memcpy(phys_to_virt(astate.curaddr), data+offset, - len - offset); - astate.curaddr += len - offset; - astate.toread -= len - offset; - break; - } - memcpy(phys_to_virt(astate.curaddr), data+offset, astate.toread); - offset += astate.toread; - astate.toread = 0; - } - } - - /* Data left, but current segment finished - look for the next - * segment. This is quite simple for a.out files. */ - astate.segment++; - switch (astate.segment) { - case 0: - /* read text */ - astate.curaddr = astate.head.a_entry; - astate.skip = 4096; - astate.toread = astate.head.a_text; - break; - case 1: - /* read data */ - /* skip and curaddr may be wrong, but I couldn't find - * examples where this failed. There is no reasonable - * documentation for a.out available. */ - astate.skip = ((astate.curaddr + 4095) & ~4095) - astate.curaddr; - astate.curaddr = (astate.curaddr + 4095) & ~4095; - astate.toread = astate.head.a_data; - break; - case 2: - /* initialize bss and start kernel */ - astate.curaddr = (astate.curaddr + 4095) & ~4095; - astate.skip = 0; - astate.toread = 0; - memset(phys_to_virt(astate.curaddr), '\0', astate.head.a_bss); - goto aout_startkernel; - default: - break; - } - } while (offset < len); - - astate.loc += len; - - if (eof) { - unsigned long entry; - -aout_startkernel: - entry = astate.head.a_entry; - done(1); - - aout_freebsd_boot(); -#ifdef AOUT_LYNX_KDI - xstart32(entry); -#endif - printf("unexpected a.out variant\n"); - longjmp(restart_etherboot, -2); - } - return 0; -} diff --git a/src/arch/i386/core/freebsd_loader.c b/src/arch/i386/core/freebsd_loader.c deleted file mode 100644 index 464f6d93..00000000 --- a/src/arch/i386/core/freebsd_loader.c +++ /dev/null @@ -1,377 +0,0 @@ -/* bootinfo */ -#define BOOTINFO_VERSION 1 -#define NODEV (-1) /* non-existent device */ -#define PAGE_SHIFT 12 /* LOG2(PAGE_SIZE) */ -#define PAGE_SIZE (1<= estate.p.phdr32[j].p_offset) && - ((shdr[i].sh_offset + shdr[i].sh_size) <= - (estate.p.phdr32[j].p_offset + estate.p.phdr32[j].p_filesz))) - { - shdr[i].sh_offset=0; - shdr[i].sh_size=0; - break; - } - } - } - if ((shdr[i].sh_offset != 0) && (shdr[i].sh_size != 0)) - { - symtabindex = i; - symstrindex = shdr[i].sh_link; - } - } - } - } - - /* Check if we have a symbol table index and have not loaded it */ - if ((symtab_load == 0) && (symtabindex >= 0)) - { - /* No symbol table yet? Load it first... */ - - /* This happens to work out in a strange way. - * If we are past the point in the file already, - * we will skip a *large* number of bytes which - * ends up bringing us to the end of the file and - * an old (default) boot. Less code and lets - * the state machine work in a cleaner way but this - * is a nasty side-effect trick... */ - estate.skip = shdr[symtabindex].sh_offset - (estate.loc + offset); - - /* And we need to read this many bytes... */ - estate.toread = shdr[symtabindex].sh_size; - - if (estate.toread) - { -#if ELF_DEBUG - printf("db sym, size %lX, curaddr %lX\n", - estate.toread, estate.curaddr); -#endif - /* Save where we are loading this... */ - symtab_load = estate.curaddr; - - *((long *)phys_to_virt(estate.curaddr)) = estate.toread; - estate.curaddr += sizeof(long); - - /* Start to read... */ - return 1; - } - } - else if ((symstr_load == 0) && (symstrindex >= 0)) - { - /* We have already loaded the symbol table, so - * now on to the symbol strings... */ - - - /* Same nasty trick as above... */ - estate.skip = shdr[symstrindex].sh_offset - (estate.loc + offset); - - /* And we need to read this many bytes... */ - estate.toread = shdr[symstrindex].sh_size; - - if (estate.toread) - { -#if ELF_DEBUG - printf("db str, size %lX, curaddr %lX\n", - estate.toread, estate.curaddr); -#endif - /* Save where we are loading this... */ - symstr_load = estate.curaddr; - - *((long *)phys_to_virt(estate.curaddr)) = estate.toread; - estate.curaddr += sizeof(long); - - /* Start to read... */ - return 1; - } - } - } - /* all done */ - return 0; -} - -static void elf_freebsd_boot(unsigned long entry) -{ - if (image_type != Elf_FreeBSD) - return; - - memset(&bsdinfo, 0, sizeof(bsdinfo)); - bsdinfo.bi_basemem = meminfo.basememsize; - bsdinfo.bi_extmem = meminfo.memsize; - bsdinfo.bi_memsizes_valid = 1; - bsdinfo.bi_version = BOOTINFO_VERSION; - bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF); - bsdinfo.bi_nfs_diskless = NULL; - bsdinfo.bi_size = sizeof(bsdinfo); -#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ - if(freebsd_kernel_env[0] != '\0'){ - freebsd_howto |= RB_BOOTINFO; - bsdinfo.bi_envp = (unsigned long)freebsd_kernel_env; - } - - /* Check if we have symbols loaded, and if so, - * made the meta_data needed to pass those to - * the kernel. */ - if ((symtab_load !=0) && (symstr_load != 0)) - { - unsigned long *t; - - bsdinfo.bi_symtab = symtab_load; - - /* End of symbols (long aligned...) */ - /* Assumes size of long is a power of 2... */ - bsdinfo.bi_esymtab = (symstr_load + - sizeof(long) + - *((long *)phys_to_virt(symstr_load)) + - sizeof(long) - 1) & ~(sizeof(long) - 1); - - /* Where we will build the meta data... */ - t = phys_to_virt(bsdinfo.bi_esymtab); - -#if ELF_DEBUG - printf("Metadata at %lX\n",t); -#endif - - /* Set up the pointer to the memory... */ - bsdinfo.bi_modulep = virt_to_phys(t); - - /* The metadata structure is an array of 32-bit - * words where we store some information about the - * system. This is critical, as FreeBSD now looks - * only for the metadata for the extended symbol - * information rather than in the bootinfo. - */ - /* First, do the kernel name and the kernel type */ - /* Note that this assumed x86 byte order... */ - - /* 'kernel\0\0' */ - *t++=MODINFO_NAME; *t++= 7; *t++=0x6E72656B; *t++=0x00006C65; - - /* 'elf kernel\0\0' */ - *t++=MODINFO_TYPE; *t++=11; *t++=0x20666C65; *t++=0x6E72656B; *t++ = 0x00006C65; - - /* Now the symbol start/end - note that they are - * here in local/physical address - the Kernel - * boot process will relocate the addresses. */ - *t++=MODINFOMD_SSYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_symtab; - *t++=MODINFOMD_ESYM | MODINFO_METADATA; *t++=sizeof(*t); *t++=bsdinfo.bi_esymtab; - - *t++=MODINFO_END; *t++=0; /* end of metadata */ - - /* Since we have symbols we need to make - * sure that the kernel knows its own end - * of memory... It is not _end but after - * the symbols and the metadata... */ - bsdinfo.bi_kernend = virt_to_phys(t); - - /* Signal locore.s that we have a valid bootinfo - * structure that was completely filled in. */ - freebsd_howto |= 0x80000000; - } - - xstart32(entry, freebsd_howto, NODEV, 0, 0, 0, - virt_to_phys(&bsdinfo), 0, 0, 0); - longjmp(restart_etherboot, -2); -} -#endif - -#ifdef AOUT_IMAGE -static void aout_freebsd_probe(void) -{ - image_type = Aout; - if (((astate.head.a_midmag >> 16) & 0xffff) == 0) { - /* Some other a.out variants have a different - * value, and use other alignments (e.g. 1K), - * not the 4K used by FreeBSD. */ - image_type = Aout_FreeBSD; - printf("/FreeBSD"); - off = -(astate.head.a_entry & 0xff000000); - astate.head.a_entry += off; - } -} - -static void aout_freebsd_boot(void) -{ - if (image_type == Aout_FreeBSD) { - memset(&bsdinfo, 0, sizeof(bsdinfo)); - bsdinfo.bi_basemem = meminfo.basememsize; - bsdinfo.bi_extmem = meminfo.memsize; - bsdinfo.bi_memsizes_valid = 1; - bsdinfo.bi_version = BOOTINFO_VERSION; - bsdinfo.bi_kernelname = virt_to_phys(KERNEL_BUF); - bsdinfo.bi_nfs_diskless = NULL; - bsdinfo.bi_size = sizeof(bsdinfo); - xstart32(astate.head.a_entry, freebsd_howto, NODEV, 0, 0, 0, - virt_to_phys(&bsdinfo), 0, 0, 0); - longjmp(restart_etherboot, -2); - } -} -#endif diff --git a/src/arch/i386/core/wince_loader.c b/src/arch/i386/core/wince_loader.c deleted file mode 100644 index f452b659..00000000 --- a/src/arch/i386/core/wince_loader.c +++ /dev/null @@ -1,273 +0,0 @@ -#define LOAD_DEBUG 0 - -static int get_x_header(unsigned char *data, unsigned long now); -static void jump_2ep(); -static unsigned char ce_signature[] = {'B', '0', '0', '0', 'F', 'F', '\n',}; -static char ** ep; - -#define BOOT_ARG_PTR_LOCATION 0x001FFFFC - -typedef struct _BOOT_ARGS{ - unsigned char ucVideoMode; - unsigned char ucComPort; - unsigned char ucBaudDivisor; - unsigned char ucPCIConfigType; - - unsigned long dwSig; - #define BOOTARG_SIG 0x544F4F42 - unsigned long dwLen; - - unsigned char ucLoaderFlags; - unsigned char ucEshellFlags; - unsigned char ucEdbgAdapterType; - unsigned char ucEdbgIRQ; - - unsigned long dwEdbgBaseAddr; - unsigned long dwEdbgDebugZone; - unsigned long dwDHCPLeaseTime; - unsigned long dwEdbgFlags; - - unsigned long dwEBootFlag; - unsigned long dwEBootAddr; - unsigned long dwLaunchAddr; - - unsigned long pvFlatFrameBuffer; - unsigned short vesaMode; - unsigned short cxDisplayScreen; - unsigned short cyDisplayScreen; - unsigned short cxPhysicalScreen; - unsigned short cyPhysicalScreen; - unsigned short cbScanLineLength; - unsigned short bppScreen; - - unsigned char RedMaskSize; - unsigned char REdMaskPosition; - unsigned char GreenMaskSize; - unsigned char GreenMaskPosition; - unsigned char BlueMaskSize; - unsigned char BlueMaskPosition; -} BOOT_ARGS; - -BOOT_ARGS BootArgs; - -static struct segment_info{ - unsigned long addr; // Section Address - unsigned long size; // Section Size - unsigned long checksum; // Section CheckSum -} X; - -#define PSIZE (1500) //Max Packet Size -#define DSIZE (PSIZE+12) -static unsigned long dbuffer_available =0; -static unsigned long not_loadin =0; -static unsigned long d_now =0; - -unsigned long entry; -static unsigned long ce_curaddr; - - -static sector_t ce_loader(unsigned char *data, unsigned int len, int eof); -static os_download_t wince_probe(unsigned char *data, unsigned int len) -{ - if (strncmp(ce_signature, data, sizeof(ce_signature)) != 0) { - return 0; - } - printf("(WINCE)"); - return ce_loader; -} - -static sector_t ce_loader(unsigned char *data, unsigned int len, int eof) -{ - static unsigned char dbuffer[DSIZE]; - int this_write = 0; - static int firsttime = 1; - - /* - * new packet in, we have to - * [1] copy data to dbuffer, - * - * update... - * [2] dbuffer_available - */ - memcpy( (dbuffer+dbuffer_available), data, len); //[1] - dbuffer_available += len; // [2] - len = 0; - - d_now = 0; - -#if 0 - printf("dbuffer_available =%ld \n", dbuffer_available); -#endif - - if (firsttime) - { - d_now = sizeof(ce_signature); - printf("String Physical Address = %lx \n", - *(unsigned long *)(dbuffer+d_now)); - - d_now += sizeof(unsigned long); - printf("Image Size = %ld [%lx]\n", - *(unsigned long *)(dbuffer+d_now), - *(unsigned long *)(dbuffer+d_now)); - - d_now += sizeof(unsigned long); - dbuffer_available -= d_now; - - d_now = (unsigned long)get_x_header(dbuffer, d_now); - firsttime = 0; - } - - if (not_loadin == 0) - { - d_now = get_x_header(dbuffer, d_now); - } - - while ( not_loadin > 0 ) - { - /* dbuffer do not have enough data to loading, copy all */ -#if LOAD_DEBUG - printf("[0] not_loadin = [%ld], dbuffer_available = [%ld] \n", - not_loadin, dbuffer_available); - printf("[0] d_now = [%ld] \n", d_now); -#endif - - if( dbuffer_available <= not_loadin) - { - this_write = dbuffer_available ; - memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write ); - ce_curaddr += this_write; - not_loadin -= this_write; - - /* reset index and available in the dbuffer */ - dbuffer_available = 0; - d_now = 0; -#if LOAD_DEBUG - printf("[1] not_loadin = [%ld], dbuffer_available = [%ld] \n", - not_loadin, dbuffer_available); - printf("[1] d_now = [%ld], this_write = [%d] \n", - d_now, this_write); -#endif - - // get the next packet... - return (0); - } - - /* dbuffer have more data then loading ... , copy partital.... */ - else - { - this_write = not_loadin; - memcpy(phys_to_virt(ce_curaddr), (dbuffer+d_now), this_write); - ce_curaddr += this_write; - not_loadin = 0; - - /* reset index and available in the dbuffer */ - dbuffer_available -= this_write; - d_now += this_write; -#if LOAD_DEBUG - printf("[2] not_loadin = [%ld], dbuffer_available = [%ld] \n", - not_loadin, dbuffer_available); - printf("[2] d_now = [%ld], this_write = [%d] \n\n", - d_now, this_write); -#endif - - /* dbuffer not empty, proceed processing... */ - - // don't have enough data to get_x_header.. - if ( dbuffer_available < (sizeof(unsigned long) * 3) ) - { -// printf("we don't have enough data remaining to call get_x. \n"); - memcpy( (dbuffer+0), (dbuffer+d_now), dbuffer_available); - return (0); - } - else - { -#if LOAD_DEBUG - printf("with remaining data to call get_x \n"); - printf("dbuffer available = %ld , d_now = %ld\n", - dbuffer_available, d_now); -#endif - d_now = get_x_header(dbuffer, d_now); - } - } - } - return (0); -} - -static int get_x_header(unsigned char *dbuffer, unsigned long now) -{ - X.addr = *(unsigned long *)(dbuffer + now); - X.size = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)); - X.checksum = *(unsigned long *)(dbuffer + now + sizeof(unsigned long)*2); - - if (X.addr == 0) - { - entry = X.size; - done(1); - printf("Entry Point Address = [%lx] \n", entry); - jump_2ep(); - } - - if (!prep_segment(X.addr, X.addr + X.size, X.addr + X.size, 0, 0)) { - longjmp(restart_etherboot, -2); - } - - ce_curaddr = X.addr; - now += sizeof(unsigned long)*3; - - /* re-calculate dbuffer available... */ - dbuffer_available -= sizeof(unsigned long)*3; - - /* reset index of this section */ - not_loadin = X.size; - -#if 1 - printf("\n"); - printf("\t Section Address = [%lx] \n", X.addr); - printf("\t Size = %d [%lx]\n", X.size, X.size); - printf("\t Checksum = %ld [%lx]\n", X.checksum, X.checksum); -#endif -#if LOAD_DEBUG - printf("____________________________________________\n"); - printf("\t dbuffer_now = %ld \n", now); - printf("\t dbuffer available = %ld \n", dbuffer_available); - printf("\t not_loadin = %ld \n", not_loadin); -#endif - - return now; -} - -static void jump_2ep() -{ - BootArgs.ucVideoMode = 1; - BootArgs.ucComPort = 1; - BootArgs.ucBaudDivisor = 1; - BootArgs.ucPCIConfigType = 1; // do not fill with 0 - - BootArgs.dwSig = BOOTARG_SIG; - BootArgs.dwLen = sizeof(BootArgs); - - if(BootArgs.ucVideoMode == 0) - { - BootArgs.cxDisplayScreen = 640; - BootArgs.cyDisplayScreen = 480; - BootArgs.cxPhysicalScreen = 640; - BootArgs.cyPhysicalScreen = 480; - BootArgs.bppScreen = 16; - BootArgs.cbScanLineLength = 1024; - BootArgs.pvFlatFrameBuffer = 0x800a0000; // ollie say 0x98000000 - } - else if(BootArgs.ucVideoMode != 0xFF) - { - BootArgs.cxDisplayScreen = 0; - BootArgs.cyDisplayScreen = 0; - BootArgs.cxPhysicalScreen = 0; - BootArgs.cyPhysicalScreen = 0; - BootArgs.bppScreen = 0; - BootArgs.cbScanLineLength = 0; - BootArgs.pvFlatFrameBuffer = 0; - } - - ep = phys_to_virt(BOOT_ARG_PTR_LOCATION); - *ep= virt_to_phys(&BootArgs); - xstart32(entry); -} diff --git a/src/config/config.c b/src/config/config.c index 4ce1909d..9c1df1f3 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -155,18 +155,9 @@ REQUIRE_OBJECT ( nbi ); #ifdef IMAGE_ELF REQUIRE_OBJECT ( elfboot ); #endif -#ifdef IMAGE_FREEBSD -REQUIRE_OBJECT ( freebsd ); -#endif #ifdef IMAGE_MULTIBOOT REQUIRE_OBJECT ( multiboot ); #endif -#ifdef IMAGE_AOUT -REQUIRE_OBJECT ( aout ); -#endif -#ifdef IMAGE_WINCE -REQUIRE_OBJECT ( wince ); -#endif #ifdef IMAGE_PXE REQUIRE_OBJECT ( pxe_image ); #endif diff --git a/src/config/general.h b/src/config/general.h index ec095028..22a901d6 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -94,10 +94,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ //#define IMAGE_NBI /* NBI image support */ //#define IMAGE_ELF /* ELF image support */ -//#define IMAGE_FREEBSD /* FreeBSD kernel image support */ //#define IMAGE_MULTIBOOT /* MultiBoot image support */ -//#define IMAGE_AOUT /* a.out image support */ -//#define IMAGE_WINCE /* WinCE image support */ //#define IMAGE_PXE /* PXE image support */ //#define IMAGE_SCRIPT /* iPXE script image support */ //#define IMAGE_BZIMAGE /* Linux bzImage image support */ From 8c42e0c210a1365e048a5f18bd15148892de277a Mon Sep 17 00:00:00 2001 From: Marin Hannache Date: Thu, 12 Apr 2012 23:14:46 +0200 Subject: [PATCH 188/221] [util] Remove obsolete Makefile rule for util/prototester.c util/prototester.c was removed in commit a6d1815 ("Obsolete for some time now") back in 2006. Signed-off-by: Marin Hannache Signed-off-by: Michael Brown --- src/util/Makefile | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/util/Makefile b/src/util/Makefile index d72661e2..4a6a7c7c 100644 --- a/src/util/Makefile +++ b/src/util/Makefile @@ -1,17 +1,11 @@ BLIB = ../bin/blib.a CFLAGS = -Os -all : hijack prototester mucurses_test +all : hijack mucurses_test hijack : hijack.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -lpcap -o $@ $< -prototester.o : prototester.c - $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $< -idirafter ../include - -prototester : prototester.o $(BLIB) - $(CC) -o $@ $< -lc $(BLIB) - mucurses_test.o : mucurses_test.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -Wall -o $@ -c $< @@ -19,4 +13,4 @@ mucurses_test : mucurses_test.o $(BLIB) $(CC) -o $@ $< -lc $(BLIB) clean : - rm -f hijack prototester mucurses_test *.o + rm -f hijack mucurses_test *.o From 0e59417cec7f474b4cce8ca896c1ee1a0ea96729 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 24 Apr 2012 13:11:21 +0100 Subject: [PATCH 189/221] [build] Use $(xxx_DEPS) for additional dependency information Some objects (embedded.o, rootcert.o, and clientcert.o) define additional dependencies on external files, using syntax such as: $(BIN)/clientcert.o : $(CERT_LIST) This dependency can be missed when using debug builds. For example, if DEBUG=clientcert is used, then the relevant object is $(BIN)/clientcert.dbg1.o rather than $(BIN)/clientcert.o. Fix by adding dependencies to $(clientcert_DEPS) instead: clientcert_DEPS += $(CERT_LIST) Signed-off-by: Michael Brown --- src/Makefile.housekeeping | 262 +++++++++++++++++++------------------- 1 file changed, 131 insertions(+), 131 deletions(-) diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index bf4b93c5..d2b4ee38 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -517,6 +517,136 @@ RULE_S_to_s = $(Q)$(PREPROCESS_S) $< > $@ DEBUG_TARGETS += dbg%.o c s +# List of embedded images included in the last build of embedded.o. +# This is needed in order to correctly rebuild embedded.o whenever the +# list of objects changes. +# +EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility +EMBEDDED_LIST := $(BIN)/.embedded.list +ifeq ($(wildcard $(EMBEDDED_LIST)),) +EMBED_OLD := +else +EMBED_OLD := $(shell cat $(EMBEDDED_LIST)) +endif +ifneq ($(EMBED_OLD),$(EMBED)) +$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST)) +endif + +$(EMBEDDED_LIST) : + +VERYCLEANUP += $(EMBEDDED_LIST) + +EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED)) +EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\ + EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\ + \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" )) + +embedded_DEPS += $(EMBEDDED_FILES) $(EMBEDDED_LIST) + +CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)" + +# List of trusted root certificates +# +TRUSTED_LIST := $(BIN)/.trusted.list +ifeq ($(wildcard $(TRUSTED_LIST)),) +TRUST_OLD := +else +TRUST_OLD := $(shell cat $(TRUSTED_LIST)) +endif +ifneq ($(TRUST_OLD),$(TRUST)) +$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST)) +endif + +$(TRUSTED_LIST) : + +VERYCLEANUP += $(TRUSTED_LIST) + +# Trusted root certificate fingerprints +# +TRUSTED_CERTS := $(subst $(COMMA), ,$(TRUST)) +TRUSTED_FPS := $(foreach CERT,$(TRUSTED_CERTS),\ + 0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\ + $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \ + -fingerprint))))$(COMMA)) + +rootcert_DEPS += $(TRUSTED_FILES) $(TRUSTED_LIST) + +CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)") + +# (Single-element) list of client certificates +# +CERT_LIST := $(BIN)/.certificate.list +ifeq ($(wildcard $(CERT_LIST)),) +CERT_OLD := +else +CERT_OLD := $(shell cat $(CERT_LIST)) +endif +ifneq ($(CERT_OLD),$(CERT)) +$(shell $(ECHO) "$(CERT)" > $(CERT_LIST)) +endif + +$(CERT_LIST) : + +VERYCLEANUP += $(CERT_LIST) + +# Embedded client certificate +# +CERT_INC := $(BIN)/.certificate.der + +ifdef CERT +$(CERT_INC) : $(CERT) $(CERT_LIST) + $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@ + +clientcert_DEPS += $(CERT_INC) +endif + +CLEANUP += $(CERT_INC) + +clientcert_DEPS += $(CERT_LIST) + +CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"") + +# (Single-element) list of client private keys +# +KEY_LIST := $(BIN)/.private_key.list +ifeq ($(wildcard $(KEY_LIST)),) +KEY_OLD := +else +KEY_OLD := $(shell cat $(KEY_LIST)) +endif +ifneq ($(KEY_OLD),$(KEY)) +$(shell $(ECHO) "$(KEY)" > $(KEY_LIST)) +endif + +$(KEY_LIST) : + +VERYCLEANUP += $(KEY_LIST) + +# Embedded client private key +# +KEY_INC := $(BIN)/.private_key.der + +ifdef KEY +$(KEY_INC) : $(KEY) $(KEY_LIST) + $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@ + +clientcert_DEPS += $(KEY_INC) +endif + +CLEANUP += $(KEY_INC) + +clientcert_DEPS += $(KEY_LIST) + +CFLAGS_clientcert += $(if $(KEY),-DPRIVATE_KEY="\"$(KEY_INC)\"") + +# These files use .incbin inline assembly to include a binary file. +# Unfortunately ccache does not detect this dependency and caches +# builds even when the binary file has changed. +# +$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC) + +$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC) + # We automatically generate rules for any file mentioned in AUTO_SRCS # using the following set of templates. It would be cleaner to use # $(eval ...), but this function exists only in GNU make >= 3.80. @@ -532,7 +662,7 @@ define deps_template @$(MKDIR) -p $(BIN)/deps/$(dir $(1)) @$(CPP) $(CFLAGS) $(CFLAGS_$(2)) $(CFLAGS_$(3)) -DOBJECT=$(3) \ -Wno-error -M $(1) -MG -MP | \ - sed 's/\.o\s*:/_DEPS =/' > $(BIN)/deps/$(1).d + sed 's/\.o\s*:/_DEPS +=/' > $(BIN)/deps/$(1).d endef # rules_template : generate rules for a given source file @@ -606,136 +736,6 @@ drivers : roms : @$(ECHO) $(ROMS) -# List of embedded images included in the last build of embedded.o. -# This is needed in order to correctly rebuild embedded.o whenever the -# list of objects changes. -# -EMBED := $(EMBEDDED_IMAGE) # Maintain backwards compatibility -EMBEDDED_LIST := $(BIN)/.embedded.list -ifeq ($(wildcard $(EMBEDDED_LIST)),) -EMBED_OLD := -else -EMBED_OLD := $(shell cat $(EMBEDDED_LIST)) -endif -ifneq ($(EMBED_OLD),$(EMBED)) -$(shell $(ECHO) "$(EMBED)" > $(EMBEDDED_LIST)) -endif - -$(EMBEDDED_LIST) : - -VERYCLEANUP += $(EMBEDDED_LIST) - -EMBEDDED_FILES := $(subst $(COMMA), ,$(EMBED)) -EMBED_ALL := $(foreach i,$(call seq,1,$(words $(EMBEDDED_FILES))),\ - EMBED ( $(i), \"$(word $(i), $(EMBEDDED_FILES))\",\ - \"$(notdir $(word $(i),$(EMBEDDED_FILES)))\" )) - -$(BIN)/embedded.o : $(EMBEDDED_FILES) $(EMBEDDED_LIST) - -CFLAGS_embedded = -DEMBED_ALL="$(EMBED_ALL)" - -# List of trusted root certificates -# -TRUSTED_LIST := $(BIN)/.trusted.list -ifeq ($(wildcard $(TRUSTED_LIST)),) -TRUST_OLD := -else -TRUST_OLD := $(shell cat $(TRUSTED_LIST)) -endif -ifneq ($(TRUST_OLD),$(TRUST)) -$(shell $(ECHO) "$(TRUST)" > $(TRUSTED_LIST)) -endif - -$(TRUSTED_LIST) : - -VERYCLEANUP += $(TRUSTED_LIST) - -# Trusted root certificate fingerprints -# -TRUSTED_CERTS := $(subst $(COMMA), ,$(TRUST)) -TRUSTED_FPS := $(foreach CERT,$(TRUSTED_CERTS),\ - 0x$(subst :,$(COMMA) 0x,$(lastword $(subst =, ,\ - $(shell $(OPENSSL) x509 -in $(CERT) -noout -sha256 \ - -fingerprint))))$(COMMA)) - -$(BIN)/rootcert.o : $(TRUSTED_FILES) $(TRUSTED_LIST) - -CFLAGS_rootcert = $(if $(TRUSTED_FPS),-DTRUSTED="$(TRUSTED_FPS)") - -# (Single-element) list of client certificates -# -CERT_LIST := $(BIN)/.certificate.list -ifeq ($(wildcard $(CERT_LIST)),) -CERT_OLD := -else -CERT_OLD := $(shell cat $(CERT_LIST)) -endif -ifneq ($(CERT_OLD),$(CERT)) -$(shell $(ECHO) "$(CERT)" > $(CERT_LIST)) -endif - -$(CERT_LIST) : - -VERYCLEANUP += $(CERT_LIST) - -# Embedded client certificate -# -CERT_INC := $(BIN)/.certificate.der - -ifdef CERT -$(CERT_INC) : $(CERT) $(CERT_LIST) - $(Q)$(OPENSSL) x509 -in $< -outform DER -out $@ - -$(BIN)/clientcert.o : $(CERT_INC) -endif - -CLEANUP += $(CERT_INC) - -$(BIN)/clientcert.o : $(CERT_LIST) - -CFLAGS_clientcert += $(if $(CERT),-DCERTIFICATE="\"$(CERT_INC)\"") - -# (Single-element) list of client private keys -# -KEY_LIST := $(BIN)/.private_key.list -ifeq ($(wildcard $(KEY_LIST)),) -KEY_OLD := -else -KEY_OLD := $(shell cat $(KEY_LIST)) -endif -ifneq ($(KEY_OLD),$(KEY)) -$(shell $(ECHO) "$(KEY)" > $(KEY_LIST)) -endif - -$(KEY_LIST) : - -VERYCLEANUP += $(KEY_LIST) - -# Embedded client private key -# -KEY_INC := $(BIN)/.private_key.der - -ifdef KEY -$(KEY_INC) : $(KEY) $(KEY_LIST) - $(Q)$(OPENSSL) rsa -in $< -outform DER -out $@ - -$(BIN)/clientcert.o : $(KEY_INC) -endif - -CLEANUP += $(KEY_INC) - -$(BIN)/clientcert.o : $(KEY_LIST) - -CFLAGS_clientcert += $(if $(KEY),-DPRIVATE_KEY="\"$(KEY_INC)\"") - -# These files use .incbin inline assembly to include a binary file. -# Unfortunately ccache does not detect this dependency and caches -# builds even when the binary file has changed. -# -$(BIN)/embedded.o : override CC := env CCACHE_DISABLE=1 $(CC) - -$(BIN)/clientcert.o : override CC := env CCACHE_DISABLE=1 $(CC) - # Generate error usage information # $(BIN)/%.einfo : $(BIN)/%.o From 63d9cc28b9e0c6a58f0ff2f1e6b638a185c471c6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 24 Apr 2012 13:17:29 +0100 Subject: [PATCH 190/221] [crypto] Allow client certificate to be changed without a rebuild Signed-off-by: Michael Brown --- src/crypto/clientcert.c | 101 ++++++++++++++++++++++++++++++++++++---- src/include/ipxe/dhcp.h | 6 +++ 2 files changed, 98 insertions(+), 9 deletions(-) diff --git a/src/crypto/clientcert.c b/src/crypto/clientcert.c index 03c75284..692aafb4 100644 --- a/src/crypto/clientcert.c +++ b/src/crypto/clientcert.c @@ -19,6 +19,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include +#include +#include +#include #include /** @file @@ -55,12 +59,6 @@ __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" ".equ client_certificate_len, ( . - client_certificate_data )\n\t" ".previous\n\t" ); -/** Client certificate */ -struct client_certificate client_certificate = { - .data = client_certificate_data, - .len = ( ( size_t ) client_certificate_len ), -}; - /* Raw client private key data */ extern char client_private_key_data[]; extern char client_private_key_len[]; @@ -73,8 +71,93 @@ __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" ".equ client_private_key_len, ( . - client_private_key_data )\n\t" ".previous\n\t" ); +/** Client certificate */ +struct client_certificate client_certificate; + /** Client private key */ -struct client_private_key client_private_key = { - .data = client_private_key_data, - .len = ( ( size_t ) client_private_key_len ), +struct client_private_key client_private_key; + +/** Client certificate setting */ +struct setting cert_setting __setting ( SETTING_CRYPTO ) = { + .name = "cert", + .description = "Client certificate", + .tag = DHCP_EB_CERT, + .type = &setting_type_hex, +}; + +/** Client private key setting */ +struct setting key_setting __setting ( SETTING_CRYPTO ) = { + .name = "key", + .description = "Client private key", + .tag = DHCP_EB_KEY, + .type = &setting_type_hex, +}; + +/** + * Apply client certificate store configuration settings + * + * @ret rc Return status code + */ +static int clientcert_apply_settings ( void ) { + static void *cert; + static void *key; + int len; + int rc; + + /* Restore default client certificate */ + client_certificate.data = client_certificate_data; + client_certificate.len = ( ( size_t ) client_certificate_len ); + + /* Fetch new client certificate, if any */ + free ( cert ); + len = fetch_setting_copy ( NULL, &cert_setting, &cert ); + if ( len < 0 ) { + rc = len; + DBGC ( &client_certificate, "CLIENTCERT cannot fetch client " + "certificate: %s\n", strerror ( rc ) ); + return rc; + } + if ( cert ) { + client_certificate.data = cert; + client_certificate.len = len; + } + + /* Restore default client private key */ + client_private_key.data = client_private_key_data; + client_private_key.len = ( ( size_t ) client_private_key_len ); + + /* Fetch new client private key, if any */ + free ( key ); + len = fetch_setting_copy ( NULL, &key_setting, &key ); + if ( len < 0 ) { + rc = len; + DBGC ( &client_certificate, "CLIENTCERT cannot fetch client " + "private key: %s\n", strerror ( rc ) ); + return rc; + } + if ( key ) { + client_private_key.data = key; + client_private_key.len = len; + } + + /* Debug */ + if ( have_client_certificate() ) { + DBGC ( &client_certificate, "CLIENTCERT using %s " + "certificate:\n", ( cert ? "external" : "built-in" ) ); + DBGC_HDA ( &client_certificate, 0, client_certificate.data, + client_certificate.len ); + DBGC ( &client_certificate, "CLIENTCERT using %s private " + "key:\n", ( key ? "external" : "built-in" ) ); + DBGC_HDA ( &client_certificate, 0, client_private_key.data, + client_private_key.len ); + } else { + DBGC ( &client_certificate, "CLIENTCERT has no certificate\n" ); + } + + return 0; +} + +/** Client certificate store settings applicator */ +struct settings_applicator clientcert_applicator __settings_applicator = { + .apply = clientcert_apply_settings, }; diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index cc594ab1..dc8a6fc7 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -358,6 +358,12 @@ struct dhcp_client_uuid { /** Trusted root certficate fingerprints */ #define DHCP_EB_TRUST DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5a ) +/** Client certficate */ +#define DHCP_EB_CERT DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5b ) + +/** Client private key */ +#define DHCP_EB_KEY DHCP_ENCAP_OPT ( DHCP_EB_ENCAP, 0x5c ) + /** Skip PXE DHCP protocol extensions such as ProxyDHCP * * If set to a non-zero value, iPXE will not wait for ProxyDHCP offers From bd16deaa873b67eef9238635f57906f1340861c9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 24 Apr 2012 16:10:22 +0100 Subject: [PATCH 191/221] [crypto] Do not allow build-time cryptography settings to be overridden If a root certificate has been explicitly specified at build time using TRUST=/path/to/cert then do not allow this to be overridden even from a trustworthy settings source (such as VMware GuestInfo). Similarly, if a client certificate (and private key) has been explicitly specified at build time, then do not allow it to be overridden at runtime. Signed-off-by: Michael Brown --- src/crypto/clientcert.c | 93 +++++++++++++++++++++++++---------------- src/crypto/rootcert.c | 67 ++++++++++++++++++----------- 2 files changed, 99 insertions(+), 61 deletions(-) diff --git a/src/crypto/clientcert.c b/src/crypto/clientcert.c index 692aafb4..159a3f4e 100644 --- a/src/crypto/clientcert.c +++ b/src/crypto/clientcert.c @@ -47,6 +47,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); #warning "Attempting to embed private key with no corresponding certificate" #endif +/* Allow client certificates to be overridden if not explicitly specified */ +#ifdef CERTIFICATE +#define ALLOW_CERT_OVERRIDE 0 +#else +#define ALLOW_CERT_OVERRIDE 1 +#endif + /* Raw client certificate data */ extern char client_certificate_data[]; extern char client_certificate_len[]; @@ -72,13 +79,19 @@ __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" ".previous\n\t" ); /** Client certificate */ -struct client_certificate client_certificate; +struct client_certificate client_certificate = { + .data = client_certificate_data, + .len = ( ( size_t ) client_certificate_len ), +}; /** Client private key */ -struct client_private_key client_private_key; +struct client_private_key client_private_key = { + .data = client_private_key_data, + .len = ( ( size_t ) client_private_key_len ), +}; /** Client certificate setting */ -struct setting cert_setting __setting ( SETTING_CRYPTO ) = { +static struct setting cert_setting __setting ( SETTING_CRYPTO ) = { .name = "cert", .description = "Client certificate", .tag = DHCP_EB_CERT, @@ -86,7 +99,7 @@ struct setting cert_setting __setting ( SETTING_CRYPTO ) = { }; /** Client private key setting */ -struct setting key_setting __setting ( SETTING_CRYPTO ) = { +static struct setting key_setting __setting ( SETTING_CRYPTO ) = { .name = "key", .description = "Client private key", .tag = DHCP_EB_KEY, @@ -99,45 +112,51 @@ struct setting key_setting __setting ( SETTING_CRYPTO ) = { * @ret rc Return status code */ static int clientcert_apply_settings ( void ) { - static void *cert; - static void *key; + static void *cert = NULL; + static void *key = NULL; int len; int rc; - /* Restore default client certificate */ - client_certificate.data = client_certificate_data; - client_certificate.len = ( ( size_t ) client_certificate_len ); + /* Allow client certificate to be overridden only if + * not explicitly specified at build time. + */ + if ( ALLOW_CERT_OVERRIDE ) { - /* Fetch new client certificate, if any */ - free ( cert ); - len = fetch_setting_copy ( NULL, &cert_setting, &cert ); - if ( len < 0 ) { - rc = len; - DBGC ( &client_certificate, "CLIENTCERT cannot fetch client " - "certificate: %s\n", strerror ( rc ) ); - return rc; - } - if ( cert ) { - client_certificate.data = cert; - client_certificate.len = len; - } + /* Restore default client certificate */ + client_certificate.data = client_certificate_data; + client_certificate.len = ( ( size_t ) client_certificate_len ); - /* Restore default client private key */ - client_private_key.data = client_private_key_data; - client_private_key.len = ( ( size_t ) client_private_key_len ); + /* Fetch new client certificate, if any */ + free ( cert ); + len = fetch_setting_copy ( NULL, &cert_setting, &cert ); + if ( len < 0 ) { + rc = len; + DBGC ( &client_certificate, "CLIENTCERT cannot fetch " + "client certificate: %s\n", strerror ( rc ) ); + return rc; + } + if ( cert ) { + client_certificate.data = cert; + client_certificate.len = len; + } - /* Fetch new client private key, if any */ - free ( key ); - len = fetch_setting_copy ( NULL, &key_setting, &key ); - if ( len < 0 ) { - rc = len; - DBGC ( &client_certificate, "CLIENTCERT cannot fetch client " - "private key: %s\n", strerror ( rc ) ); - return rc; - } - if ( key ) { - client_private_key.data = key; - client_private_key.len = len; + /* Restore default client private key */ + client_private_key.data = client_private_key_data; + client_private_key.len = ( ( size_t ) client_private_key_len ); + + /* Fetch new client private key, if any */ + free ( key ); + len = fetch_setting_copy ( NULL, &key_setting, &key ); + if ( len < 0 ) { + rc = len; + DBGC ( &client_certificate, "CLIENTCERT cannot fetch " + "client private key: %s\n", strerror ( rc ) ); + return rc; + } + if ( key ) { + client_private_key.data = key; + client_private_key.len = len; + } } /* Debug */ diff --git a/src/crypto/rootcert.c b/src/crypto/rootcert.c index 6a9e594c..ee2a3454 100644 --- a/src/crypto/rootcert.c +++ b/src/crypto/rootcert.c @@ -36,6 +36,13 @@ FILE_LICENCE ( GPL2_OR_LATER ); /** Length of a root certificate fingerprint */ #define FINGERPRINT_LEN SHA256_DIGEST_SIZE +/* Allow trusted certificates to be overridden if not explicitly specified */ +#ifdef TRUSTED +#define ALLOW_TRUST_OVERRIDE 0 +#else +#define ALLOW_TRUST_OVERRIDE 1 +#endif + /* Use iPXE root CA if no trusted certificates are explicitly specified */ #ifndef TRUSTED #define TRUSTED \ @@ -50,9 +57,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); static const uint8_t fingerprints[] = { TRUSTED }; /** Root certificate fingerprint setting */ -struct setting trust_setting __setting ( SETTING_CRYPTO ) = { +static struct setting trust_setting __setting ( SETTING_CRYPTO ) = { .name = "trust", - .description = "Trusted root certificate fingerprint", + .description = "Trusted root certificate fingerprints", .tag = DHCP_EB_TRUST, .type = &setting_type_hex, }; @@ -67,38 +74,50 @@ struct x509_root root_certificates = { /** * Initialise root certificate * - * We allow the list of trusted root certificate fingerprints to be - * overridden using the "trust" setting, but only at the point of iPXE + * The list of trusted root certificates can be specified at build + * time using the TRUST= build parameter. If no certificates are + * specified, then the default iPXE root CA certificate is trusted. + * + * If no certificates were explicitly specified, then we allow the + * list of trusted root certificate fingerprints to be overridden + * using the "trust" setting, but only at the point of iPXE * initialisation. This prevents untrusted sources of settings * (e.g. DHCP) from subverting the chain of trust, while allowing * trustworthy sources (e.g. VMware GuestInfo or non-volatile stored - * options) to change the trusted root certificate without requiring a - * rebuild. + * options) to specify the trusted root certificate without requiring + * a rebuild. */ static void rootcert_init ( void ) { - void *external; + void *external = NULL; int len; int rc; - /* Fetch copy of "trust" setting, if it exists. This memory - * will never be freed. + /* Allow trusted root certificates to be overridden only if + * not explicitly specified at build time. */ - len = fetch_setting_copy ( NULL, &trust_setting, &external ); - if ( len < 0 ) { - rc = len; - DBGC ( &root_certificates, "ROOTCERT cannot fetch trusted " - "root certificate fingerprints: %s\n", strerror ( rc ) ); - /* No way to prevent startup; fail safe by trusting no - * certificates. - */ - root_certificates.count = 0; - return; - } + if ( ALLOW_TRUST_OVERRIDE ) { - /* Use certificates from "trust" setting, if present */ - if ( external ) { - root_certificates.fingerprints = external; - root_certificates.count = ( len / FINGERPRINT_LEN ); + /* Fetch copy of "trust" setting, if it exists. This + * memory will never be freed. + */ + len = fetch_setting_copy ( NULL, &trust_setting, &external ); + if ( len < 0 ) { + rc = len; + DBGC ( &root_certificates, "ROOTCERT cannot fetch " + "trusted root certificate fingerprints: %s\n", + strerror ( rc ) ); + /* No way to prevent startup; fail safe by + * trusting no certificates. + */ + root_certificates.count = 0; + return; + } + + /* Use certificates from "trust" setting, if present */ + if ( external ) { + root_certificates.fingerprints = external; + root_certificates.count = ( len / FINGERPRINT_LEN ); + } } DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n", From 2c1e8d2cb13e2c46c43968765f220ef64f416940 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 24 Apr 2012 21:48:48 +0100 Subject: [PATCH 192/221] [natsemi] Replace driver for National Semicondutor NICs Signed-off-by: Michael Brown --- src/drivers/net/natsemi.c | 1397 +++++++++++++++++++++------------- src/drivers/net/natsemi.h | 517 ++++++++----- src/drivers/net/ns83820.c | 1007 ------------------------ src/include/ipxe/threewire.h | 13 + 4 files changed, 1180 insertions(+), 1754 deletions(-) delete mode 100644 src/drivers/net/ns83820.c diff --git a/src/drivers/net/natsemi.c b/src/drivers/net/natsemi.c index 17154281..fb1eb822 100644 --- a/src/drivers/net/natsemi.c +++ b/src/drivers/net/natsemi.c @@ -1,604 +1,927 @@ -/* - natsemi.c - iPXE driver for the NatSemi DP8381x series. - - Based on: - - natsemi.c: An Etherboot driver for the NatSemi DP8381x series. - - Copyright (C) 2001 Entity Cyber, Inc. - - This development of this Etherboot driver was funded by - - Sicom Systems: http://www.sicompos.com/ - - Author: Marty Connor - Adapted from a Linux driver which was written by Donald Becker - - This software may be used and distributed according to the terms - of the GNU Public License (GPL), incorporated herein by reference. - - Original Copyright Notice: - - Written/copyright 1999-2001 by Donald Becker. - - This software may be used and distributed according to the terms of - the GNU General Public License (GPL), incorporated herein by reference. - Drivers based on or derived from this code fall under the GPL and must - retain the authorship, copyright and license notice. This file is not - a complete program and may only be used when the entire operating - system is licensed under the GPL. License for under other terms may be - available. Contact the original author for details. - - The original author may be reached as becker@scyld.com, or at - Scyld Computing Corporation - 410 Severn Ave., Suite 210 - Annapolis MD 21403 - - Support information and updates available at - http://www.scyld.com/network/netsemi.html - - References: - - http://www.scyld.com/expert/100mbps.html - http://www.scyld.com/expert/NWay.html - Datasheet is available from: - http://www.national.com/pf/DP/DP83815.html - -*/ - -FILE_LICENCE ( GPL_ANY ); - -/* Revision History */ - /* - 02 Jul 2007 Udayan Kumar 1.2 ported the driver from etherboot to iPXE API. - Fully rewritten,adapting the old driver. - Added a circular buffer for transmit and receive. - transmit routine will not wait for transmission to finish. - poll routine deals with it. - 13 Dec 2003 Tim Legge 1.1 Enabled Multicast Support - 29 May 2001 Marty Connor 1.0 Initial Release. Tested with Netgear FA311 and FA312 boards -*/ + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); #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 "natsemi.h" -/* Function Prototypes: */ - -static int natsemi_spi_read_bit ( struct bit_basher *, unsigned int ); -static void natsemi_spi_write_bit ( struct bit_basher *,unsigned int, unsigned long ); -static void natsemi_init_eeprom ( struct natsemi_private * ); -static int natsemi_probe (struct pci_device *pci); -static void natsemi_reset (struct net_device *netdev); -static int natsemi_open (struct net_device *netdev); -static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf); -static void natsemi_poll (struct net_device *netdev); -static void natsemi_close (struct net_device *netdev); -static void natsemi_irq (struct net_device *netdev, int enable); -static void natsemi_remove (struct pci_device *pci); +/** @file + * + * National Semiconductor "MacPhyter" network card driver + * + * Based on the following datasheets: + * + * http://www.ti.com/lit/ds/symlink/dp83820.pdf + * http://www.datasheets.org.uk/indexdl/Datasheet-03/DSA0041338.pdf + * + */ -/** natsemi net device operations */ -static struct net_device_operations natsemi_operations = { - .open = natsemi_open, - .close = natsemi_close, - .transmit = natsemi_transmit, - .poll = natsemi_poll, - .irq = natsemi_irq, +/****************************************************************************** + * + * EEPROM interface + * + ****************************************************************************** + */ + +/** Pin mapping for SPI bit-bashing interface */ +static const uint8_t natsemi_eeprom_bits[] = { + [SPI_BIT_SCLK] = NATSEMI_MEAR_EECLK, + [SPI_BIT_MOSI] = NATSEMI_MEAR_EEDI, + [SPI_BIT_MISO] = NATSEMI_MEAR_EEDO, + [SPI_BIT_SS(0)] = NATSEMI_MEAR_EESEL, }; +/** + * Read input bit + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @ret zero Input is a logic 0 + * @ret non-zero Input is a logic 1 + */ static int natsemi_spi_read_bit ( struct bit_basher *basher, - unsigned int bit_id ) { - struct natsemi_private *np = container_of ( basher, struct natsemi_private, - spibit.basher ); - uint8_t mask = natsemi_ee_bits[bit_id]; - uint8_t eereg; + unsigned int bit_id ) { + struct natsemi_nic *natsemi = container_of ( basher, struct natsemi_nic, + spibit.basher ); + uint32_t mask = natsemi_eeprom_bits[bit_id]; + uint32_t reg; - eereg = inb ( np->ioaddr + EE_REG ); - return ( eereg & mask ); + DBG_DISABLE ( DBGLVL_IO ); + reg = readl ( natsemi->regs + NATSEMI_MEAR ); + DBG_ENABLE ( DBGLVL_IO ); + return ( reg & mask ); } +/** + * Set/clear output bit + * + * @v basher Bit-bashing interface + * @v bit_id Bit number + * @v data Value to write + */ static void natsemi_spi_write_bit ( struct bit_basher *basher, - unsigned int bit_id, unsigned long data ) { - struct natsemi_private *np = container_of ( basher, struct natsemi_private, - spibit.basher ); - uint8_t mask = natsemi_ee_bits[bit_id]; - uint8_t eereg; + unsigned int bit_id, unsigned long data ) { + struct natsemi_nic *natsemi = container_of ( basher, struct natsemi_nic, + spibit.basher ); + uint32_t mask = natsemi_eeprom_bits[bit_id]; + uint32_t reg; - eereg = inb ( np->ioaddr + EE_REG ); - eereg &= ~mask; - eereg |= ( data & mask ); - outb ( eereg, np->ioaddr + EE_REG ); + DBG_DISABLE ( DBGLVL_IO ); + reg = readl ( natsemi->regs + NATSEMI_MEAR ); + reg &= ~mask; + reg |= ( data & mask ); + writel ( reg, natsemi->regs + NATSEMI_MEAR ); + DBG_ENABLE ( DBGLVL_IO ); } +/** SPI bit-bashing interface */ static struct bit_basher_operations natsemi_basher_ops = { .read = natsemi_spi_read_bit, .write = natsemi_spi_write_bit, }; -/* - * Set up for EEPROM access +/** + * Initialise EEPROM * - * @v NAT NATSEMI NIC + * @v natsemi National Semiconductor device */ -static void natsemi_init_eeprom ( struct natsemi_private *np ) { +static void natsemi_init_eeprom ( struct natsemi_nic *natsemi ) { - /* Initialise three-wire bus - */ - np->spibit.basher.op = &natsemi_basher_ops; - np->spibit.bus.mode = SPI_MODE_THREEWIRE; - np->spibit.endianness = SPI_BIT_LITTLE_ENDIAN; - init_spi_bit_basher ( &np->spibit ); + /* Initialise SPI bit-bashing interface */ + natsemi->spibit.basher.op = &natsemi_basher_ops; + natsemi->spibit.bus.mode = SPI_MODE_THREEWIRE; + natsemi->spibit.endianness = + ( ( natsemi->flags & NATSEMI_EEPROM_LITTLE_ENDIAN ) ? + SPI_BIT_LITTLE_ENDIAN : SPI_BIT_BIG_ENDIAN ); + init_spi_bit_basher ( &natsemi->spibit ); - /*natsemi DP 83815 only supports at93c46 - */ - init_at93c46 ( &np->eeprom, 16 ); - np->eeprom.bus = &np->spibit.bus; - - /* It looks that this portion of EEPROM can be used for - * non-volatile stored options. Data sheet does not talk about - * this region. Currently it is not working. But with some - * efforts it can. - */ - nvo_init ( &np->nvo, &np->eeprom.nvs, 0x0c, 0x68, NULL, NULL ); + /* Initialise EEPROM device */ + init_at93c06 ( &natsemi->eeprom, 16 ); + natsemi->eeprom.bus = &natsemi->spibit.bus; } +/** + * Get hardware address from sane EEPROM data + * + * @v natsemi National Semiconductor device + * @v eeprom EEPROM data + * @v hw_addr Hardware address to fill in + */ +static void natsemi_hwaddr_sane ( struct natsemi_nic *natsemi, + const uint16_t *eeprom, uint16_t *hw_addr ) { + int i; + + /* Copy MAC address from EEPROM data */ + for ( i = ( ( ETH_ALEN / 2 ) - 1 ) ; i >= 0 ; i-- ) + *(hw_addr++) = eeprom[ NATSEMI_EEPROM_MAC_SANE + i ]; + + DBGC ( natsemi, "NATSEMI %p has sane EEPROM layout\n", natsemi ); +} + +/** + * Get hardware address from insane EEPROM data + * + * @v natsemi National Semiconductor device + * @v eeprom EEPROM data + * @v hw_addr Hardware address to fill in + */ +static void natsemi_hwaddr_insane ( struct natsemi_nic *natsemi, + const uint16_t *eeprom, + uint16_t *hw_addr ) { + unsigned int i; + unsigned int offset; + uint16_t word; + + /* Copy MAC address from EEPROM data */ + for ( i = 0 ; i < ( ETH_ALEN / 2 ) ; i++ ) { + offset = ( NATSEMI_EEPROM_MAC_INSANE + i ); + word = ( ( le16_to_cpu ( eeprom[ offset ] ) >> 15 ) | + ( le16_to_cpu ( eeprom[ offset + 1 ] << 1 ) ) ); + hw_addr[i] = cpu_to_le16 ( word ); + } + + DBGC ( natsemi, "NATSEMI %p has insane EEPROM layout\n", natsemi ); +} + +/** + * Get hardware address from EEPROM + * + * @v natsemi National Semiconductor device + * @v hw_addr Hardware address to fill in + * @ret rc Return status code + */ +static int natsemi_hwaddr ( struct natsemi_nic *natsemi, void *hw_addr ) { + uint16_t buf[NATSEMI_EEPROM_SIZE]; + void ( * extract ) ( struct natsemi_nic *natsemi, + const uint16_t *eeprom, uint16_t *hw_addr ); + int rc; + + /* Read EEPROM contents */ + if ( ( rc = nvs_read ( &natsemi->eeprom.nvs, 0, buf, + sizeof ( buf ) ) ) != 0 ) { + DBGC ( natsemi, "NATSEMI %p could not read EEPROM: %s\n", + natsemi, strerror ( rc ) ); + return rc; + } + DBGC2 ( natsemi, "NATSEMI %p EEPROM contents:\n", natsemi ); + DBGC2_HDA ( natsemi, 0, buf, sizeof ( buf ) ); + + /* Extract MAC address from EEPROM contents */ + extract = ( ( natsemi->flags & NATSEMI_EEPROM_INSANE ) ? + natsemi_hwaddr_insane : natsemi_hwaddr_sane ); + extract ( natsemi, buf, hw_addr ); + + return 0; +} + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset controller chip + * + * @v natsemi National Semiconductor device + * @ret rc Return status code + */ +static int natsemi_soft_reset ( struct natsemi_nic *natsemi ) { + unsigned int i; + + /* Initiate reset */ + writel ( NATSEMI_CR_RST, natsemi->regs + NATSEMI_CR ); + + /* Wait for reset to complete */ + for ( i = 0 ; i < NATSEMI_RESET_MAX_WAIT_MS ; i++ ) { + + /* If reset is not complete, delay 1ms and retry */ + if ( readl ( natsemi->regs + NATSEMI_CR ) & NATSEMI_CR_RST ) { + mdelay ( 1 ); + continue; + } + + return 0; + } + + DBGC ( natsemi, "NATSEMI %p timed out waiting for reset\n", natsemi ); + return -ETIMEDOUT; +} + +/** + * Reload configuration from EEPROM + * + * @v natsemi National Semiconductor device + * @ret rc Return status code + */ +static int natsemi_reload_config ( struct natsemi_nic *natsemi ) { + unsigned int i; + + /* Initiate reload */ + writel ( NATSEMI_PTSCR_EELOAD_EN, natsemi->regs + NATSEMI_PTSCR ); + + /* Wait for reload to complete */ + for ( i = 0 ; i < NATSEMI_EELOAD_MAX_WAIT_MS ; i++ ) { + + /* If reload is not complete, delay 1ms and retry */ + if ( readl ( natsemi->regs + NATSEMI_PTSCR ) & + NATSEMI_PTSCR_EELOAD_EN ) { + mdelay ( 1 ); + continue; + } + + return 0; + } + + DBGC ( natsemi, "NATSEMI %p timed out waiting for configuration " + "reload\n", natsemi ); + return -ETIMEDOUT; +} + +/** + * Reset hardware + * + * @v natsemi National Semiconductor device + * @ret rc Return status code + */ +static int natsemi_reset ( struct natsemi_nic *natsemi ) { + uint32_t cfg; + int rc; + + /* Perform soft reset */ + if ( ( rc = natsemi_soft_reset ( natsemi ) ) != 0 ) + return rc; + + /* Reload configuration from EEPROM */ + if ( ( rc = natsemi_reload_config ( natsemi ) ) != 0 ) + return rc; + + /* Configure 64-bit operation, if applicable */ + cfg = readl ( natsemi->regs + NATSEMI_CFG ); + if ( natsemi->flags & NATSEMI_64BIT ) { + cfg |= ( NATSEMI_CFG_M64ADDR | NATSEMI_CFG_EXTSTS_EN ); + if ( ! ( cfg & NATSEMI_CFG_PCI64_DET ) ) + cfg &= ~NATSEMI_CFG_DATA64_EN; + } + writel ( cfg, natsemi->regs + NATSEMI_CFG ); + + /* Invalidate link status cache to force an update */ + natsemi->cfg = ~cfg; + + DBGC ( natsemi, "NATSEMI %p using configuration %08x\n", + natsemi, cfg ); + return 0; +} + +/****************************************************************************** + * + * Link state + * + ****************************************************************************** + */ + +/** + * Check link state + * + * @v netdev Network device + */ +static void natsemi_check_link ( struct net_device *netdev ) { + struct natsemi_nic *natsemi = netdev->priv; + uint32_t cfg; + + /* Read link status */ + cfg = readl ( natsemi->regs + NATSEMI_CFG ); + + /* Do nothing unless link status has changed */ + if ( cfg == natsemi->cfg ) + return; + + /* Set gigabit mode (if applicable) */ + if ( natsemi->flags & NATSEMI_1000 ) { + cfg &= ~NATSEMI_CFG_MODE_1000; + if ( ! ( cfg & NATSEMI_CFG_SPDSTS1 ) ) + cfg |= NATSEMI_CFG_MODE_1000; + writel ( cfg, natsemi->regs + NATSEMI_CFG ); + } + + /* Update link status */ + natsemi->cfg = cfg; + DBGC ( natsemi, "NATSEMI %p link status is %08x\n", natsemi, cfg ); + + /* Update network device */ + if ( cfg & NATSEMI_CFG_LNKSTS ) { + netdev_link_up ( netdev ); + } else { + netdev_link_down ( netdev ); + } +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Set perfect match filter address + * + * @v natsemi National Semiconductor device + * @v mac MAC address + */ +static void natsemi_pmatch ( struct natsemi_nic *natsemi, const void *mac ) { + const uint16_t *pmatch = mac; + uint32_t rfcr; + unsigned int rfaddr; + unsigned int i; + + for ( i = 0 ; i < ETH_ALEN ; i += sizeof ( *pmatch ) ) { + + /* Select receive filter register address */ + rfaddr = ( NATSEMI_RFADDR_PMATCH_BASE + i ); + rfcr = readl ( natsemi->regs + NATSEMI_RFCR ); + rfcr &= ~NATSEMI_RFCR_RFADDR_MASK; + rfcr |= NATSEMI_RFCR_RFADDR ( rfaddr ); + writel ( rfcr, natsemi->regs + NATSEMI_RFCR ); + + /* Write receive filter data */ + writel ( ( le16_to_cpu ( *(pmatch++) ) | NATSEMI_RFDR_BMASK ), + natsemi->regs + NATSEMI_RFDR ); + } +} + +/** + * Create descriptor ring + * + * @v natsemi National Semiconductor device + * @v ring Descriptor ring + * @ret rc Return status code + */ +static int natsemi_create_ring ( struct natsemi_nic *natsemi, + struct natsemi_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + union natsemi_descriptor *desc; + union natsemi_descriptor *linked_desc; + physaddr_t address; + physaddr_t link; + size_t offset; + unsigned int i; + int rc; + + /* Calculate descriptor offset */ + offset = ( ( natsemi->flags & NATSEMI_64BIT ) ? 0 : + offsetof ( typeof ( desc[i].d32pad ), d32 ) ); + + /* Allocate descriptor ring. Align ring on its own size to + * ensure that it can't possibly cross the boundary of 32-bit + * address space. + */ + ring->desc = malloc_dma ( len, len ); + if ( ! ring->desc ) { + rc = -ENOMEM; + goto err_alloc; + } + address = ( virt_to_bus ( ring->desc ) + offset ); + + /* Check address is usable by card */ + if ( ! natsemi_address_ok ( natsemi, address ) ) { + DBGC ( natsemi, "NATSEMI %p cannot support 64-bit ring " + "address\n", natsemi ); + rc = -ENOTSUP; + goto err_64bit; + } + + /* Initialise descriptor ring */ + memset ( ring->desc, 0, len ); + for ( i = 0 ; i < ring->count ; i++ ) { + linked_desc = &ring->desc [ ( i + 1 ) % ring->count ]; + link = ( virt_to_bus ( linked_desc ) + offset ); + if ( natsemi->flags & NATSEMI_64BIT ) { + ring->desc[i].d64.link = cpu_to_le64 ( link ); + } else { + ring->desc[i].d32pad.d32.link = cpu_to_le32 ( link ); + } + } + + /* Program ring address */ + writel ( ( address & 0xffffffffUL ), natsemi->regs + ring->reg ); + if ( natsemi->flags & NATSEMI_64BIT ) { + if ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) { + writel ( ( ( ( uint64_t ) address ) >> 32 ), + natsemi->regs + ring->reg + 4 ); + } else { + writel ( 0, natsemi->regs + ring->reg + 4 ); + } + } + + DBGC ( natsemi, "NATSEMI %p ring %02x is at [%08llx,%08llx)\n", + natsemi, ring->reg, + ( ( unsigned long long ) virt_to_bus ( ring->desc ) ), + ( ( unsigned long long ) virt_to_bus ( ring->desc ) + len ) ); + + return 0; + + err_64bit: + free_dma ( ring->desc, len ); + ring->desc = NULL; + err_alloc: + return rc; +} + +/** + * Destroy descriptor ring + * + * @v natsemi National Semiconductor device + * @v ring Descriptor ring + */ +static void natsemi_destroy_ring ( struct natsemi_nic *natsemi, + struct natsemi_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + + /* Clear ring address */ + writel ( 0, natsemi->regs + ring->reg ); + if ( natsemi->flags & NATSEMI_64BIT ) + writel ( 0, natsemi->regs + ring->reg + 4 ); + + /* Free descriptor ring */ + free_dma ( ring->desc, len ); + ring->desc = NULL; + ring->prod = 0; + ring->cons = 0; +} + +/** + * Refill receive descriptor ring + * + * @v netdev Network device + */ +static void natsemi_refill_rx ( struct net_device *netdev ) { + struct natsemi_nic *natsemi = netdev->priv; + union natsemi_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + physaddr_t address; + + while ( ( natsemi->rx.prod - natsemi->rx.cons ) < NATSEMI_NUM_RX_DESC ){ + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( NATSEMI_RX_MAX_LEN ); + if ( ! iobuf ) { + /* Wait for next refill */ + return; + } + + /* Check address is usable by card */ + address = virt_to_bus ( iobuf->data ); + if ( ! natsemi_address_ok ( natsemi, address ) ) { + DBGC ( natsemi, "NATSEMI %p cannot support 64-bit RX " + "buffer address\n", natsemi ); + netdev_rx_err ( netdev, iobuf, -ENOTSUP ); + return; + } + + /* Get next receive descriptor */ + rx_idx = ( natsemi->rx.prod++ % NATSEMI_NUM_RX_DESC ); + rx = &natsemi->rx.desc[rx_idx]; + + /* Populate receive descriptor */ + if ( natsemi->flags & NATSEMI_64BIT ) { + rx->d64.bufptr = cpu_to_le64 ( address ); + } else { + rx->d32pad.d32.bufptr = cpu_to_le32 ( address ); + } + wmb(); + rx->common.cmdsts = cpu_to_le32 ( NATSEMI_DESC_INTR | + NATSEMI_RX_MAX_LEN ); + wmb(); + + /* Record I/O buffer */ + assert ( natsemi->rx_iobuf[rx_idx] == NULL ); + natsemi->rx_iobuf[rx_idx] = iobuf; + + /* Notify card that there are descriptors available */ + writel ( NATSEMI_CR_RXE, natsemi->regs + NATSEMI_CR ); + + DBGC2 ( natsemi, "NATSEMI %p RX %d is [%llx,%llx)\n", natsemi, + rx_idx, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + NATSEMI_RX_MAX_LEN)); + } +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int natsemi_open ( struct net_device *netdev ) { + struct natsemi_nic *natsemi = netdev->priv; + int rc; + + /* Set MAC address */ + natsemi_pmatch ( natsemi, netdev->ll_addr ); + + /* Create transmit descriptor ring */ + if ( ( rc = natsemi_create_ring ( natsemi, &natsemi->tx ) ) != 0 ) + goto err_create_tx; + + /* Set transmit configuration */ + writel ( ( NATSEMI_TXCFG_CSI | NATSEMI_TXCFG_HBI | NATSEMI_TXCFG_ATP | + NATSEMI_TXCFG_ECRETRY | NATSEMI_TXCFG_MXDMA_DEFAULT | + NATSEMI_TXCFG_FLTH_DEFAULT | NATSEMI_TXCFG_DRTH_DEFAULT ), + ( natsemi->regs + ( ( natsemi->flags & NATSEMI_64BIT ) ? + NATSEMI_TXCFG_64 : NATSEMI_TXCFG_32 ) ) ); + + /* Create receive descriptor ring */ + if ( ( rc = natsemi_create_ring ( natsemi, &natsemi->rx ) ) != 0 ) + goto err_create_rx; + + /* Set receive configuration */ + writel ( ( NATSEMI_RXCFG_ARP | NATSEMI_RXCFG_ATX | NATSEMI_RXCFG_ALP | + NATSEMI_RXCFG_MXDMA_DEFAULT | NATSEMI_RXCFG_DRTH_DEFAULT ), + ( natsemi->regs + ( ( natsemi->flags & NATSEMI_64BIT ) ? + NATSEMI_RXCFG_64 : NATSEMI_RXCFG_32 ) ) ); + + /* Set receive filter configuration */ + writel ( ( NATSEMI_RFCR_RFEN | NATSEMI_RFCR_AAB | NATSEMI_RFCR_AAM | + NATSEMI_RFCR_AAU ), natsemi->regs + NATSEMI_RFCR ); + + /* Fill receive ring */ + natsemi_refill_rx ( netdev ); + + /* Unmask transmit and receive interrupts. (Interrupts will + * not be generated unless enabled via the IER.) + */ + writel ( ( NATSEMI_IRQ_TXDESC | NATSEMI_IRQ_RXDESC ), + natsemi->regs + NATSEMI_IMR ); + + /* Update link state */ + natsemi_check_link ( netdev ); + + return 0; + + natsemi_destroy_ring ( natsemi, &natsemi->rx ); + err_create_rx: + natsemi_destroy_ring ( natsemi, &natsemi->tx ); + err_create_tx: + return rc; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void natsemi_close ( struct net_device *netdev ) { + struct natsemi_nic *natsemi = netdev->priv; + unsigned int i; + + /* Mask transmit and receive interrupts */ + writel ( 0, natsemi->regs + NATSEMI_IMR ); + + /* Reset and disable transmitter and receiver */ + writel ( ( NATSEMI_CR_RXR | NATSEMI_CR_TXR ), + natsemi->regs + NATSEMI_CR ); + + /* Discard any unused receive buffers */ + for ( i = 0 ; i < NATSEMI_NUM_RX_DESC ; i++ ) { + if ( natsemi->rx_iobuf[i] ) + free_iob ( natsemi->rx_iobuf[i] ); + natsemi->rx_iobuf[i] = NULL; + } + + /* Destroy receive descriptor ring */ + natsemi_destroy_ring ( natsemi, &natsemi->rx ); + + /* Destroy transmit descriptor ring */ + natsemi_destroy_ring ( natsemi, &natsemi->tx ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int natsemi_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct natsemi_nic *natsemi = netdev->priv; + union natsemi_descriptor *tx; + unsigned int tx_idx; + physaddr_t address; + + /* Check address is usable by card */ + address = virt_to_bus ( iobuf->data ); + if ( ! natsemi_address_ok ( natsemi, address ) ) { + DBGC ( natsemi, "NATSEMI %p cannot support 64-bit TX buffer " + "address\n", natsemi ); + return -ENOTSUP; + } + + /* Get next transmit descriptor */ + if ( ( natsemi->tx.prod - natsemi->tx.cons ) >= NATSEMI_NUM_TX_DESC ) { + DBGC ( natsemi, "NATSEMI %p out of transmit descriptors\n", + natsemi ); + return -ENOBUFS; + } + tx_idx = ( natsemi->tx.prod++ % NATSEMI_NUM_TX_DESC ); + tx = &natsemi->tx.desc[tx_idx]; + + /* Populate transmit descriptor */ + if ( natsemi->flags & NATSEMI_64BIT ) { + tx->d64.bufptr = cpu_to_le64 ( address ); + } else { + tx->d32pad.d32.bufptr = cpu_to_le32 ( address ); + } + wmb(); + tx->common.cmdsts = cpu_to_le32 ( NATSEMI_DESC_OWN | NATSEMI_DESC_INTR | + iob_len ( iobuf ) ); + wmb(); + + /* Notify card that there are packets ready to transmit */ + writel ( NATSEMI_CR_TXE, natsemi->regs + NATSEMI_CR ); + + DBGC2 ( natsemi, "NATSEMI %p TX %d is [%llx,%llx)\n", natsemi, tx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + iob_len ( iobuf ) ) ); + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void natsemi_poll_tx ( struct net_device *netdev ) { + struct natsemi_nic *natsemi = netdev->priv; + union natsemi_descriptor *tx; + unsigned int tx_idx; + + /* Check for completed packets */ + while ( natsemi->tx.cons != natsemi->tx.prod ) { + + /* Get next transmit descriptor */ + tx_idx = ( natsemi->tx.cons % NATSEMI_NUM_TX_DESC ); + tx = &natsemi->tx.desc[tx_idx]; + + /* Stop if descriptor is still in use */ + if ( tx->common.cmdsts & cpu_to_le32 ( NATSEMI_DESC_OWN ) ) + return; + + /* Complete TX descriptor */ + if ( tx->common.cmdsts & cpu_to_le32 ( NATSEMI_DESC_OK ) ) { + DBGC2 ( natsemi, "NATSEMI %p TX %d complete\n", + natsemi, tx_idx ); + netdev_tx_complete_next ( netdev ); + } else { + DBGC ( natsemi, "NATSEMI %p TX %d completion error " + "(%08x)\n", natsemi, tx_idx, + le32_to_cpu ( tx->common.cmdsts ) ); + netdev_tx_complete_next_err ( netdev, -EIO ); + } + natsemi->tx.cons++; + } +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void natsemi_poll_rx ( struct net_device *netdev ) { + struct natsemi_nic *natsemi = netdev->priv; + union natsemi_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + size_t len; + + /* Check for received packets */ + while ( natsemi->rx.cons != natsemi->rx.prod ) { + + /* Get next receive descriptor */ + rx_idx = ( natsemi->rx.cons % NATSEMI_NUM_RX_DESC ); + rx = &natsemi->rx.desc[rx_idx]; + + /* Stop if descriptor is still in use */ + if ( ! ( rx->common.cmdsts & NATSEMI_DESC_OWN ) ) + return; + + /* Populate I/O buffer */ + iobuf = natsemi->rx_iobuf[rx_idx]; + natsemi->rx_iobuf[rx_idx] = NULL; + len = ( le32_to_cpu ( rx->common.cmdsts ) & + NATSEMI_DESC_SIZE_MASK ); + iob_put ( iobuf, len - 4 /* strip CRC */ ); + + /* Hand off to network stack */ + if ( rx->common.cmdsts & cpu_to_le32 ( NATSEMI_DESC_OK ) ) { + DBGC2 ( natsemi, "NATSEMI %p RX %d complete (length " + "%zd)\n", natsemi, rx_idx, len ); + netdev_rx ( netdev, iobuf ); + } else { + DBGC ( natsemi, "NATSEMI %p RX %d error (length %zd, " + "status %08x)\n", natsemi, rx_idx, len, + le32_to_cpu ( rx->common.cmdsts ) ); + netdev_rx_err ( netdev, iobuf, -EIO ); + } + natsemi->rx.cons++; + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void natsemi_poll ( struct net_device *netdev ) { + struct natsemi_nic *natsemi = netdev->priv; + uint32_t isr; + + /* Poll for link state. The PHY interrupt seems not to + * function as expected, and polling for the link state is + * only a single register read. + */ + natsemi_check_link ( netdev ); + + /* Check for and acknowledge interrupts */ + isr = readl ( natsemi->regs + NATSEMI_ISR ); + if ( ! isr ) + return; + + /* Poll for TX completions, if applicable */ + if ( isr & NATSEMI_IRQ_TXDESC ) + natsemi_poll_tx ( netdev ); + + /* Poll for RX completionsm, if applicable */ + if ( isr & NATSEMI_IRQ_RXDESC ) + natsemi_poll_rx ( netdev ); + + /* Refill RX ring */ + natsemi_refill_rx ( netdev ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void natsemi_irq ( struct net_device *netdev, int enable ) { + struct natsemi_nic *natsemi = netdev->priv; + + /* Enable or disable interrupts */ + writel ( ( enable ? NATSEMI_IER_IE : 0 ), natsemi->regs + NATSEMI_IER ); +} + +/** National Semiconductor network device operations */ +static struct net_device_operations natsemi_operations = { + .open = natsemi_open, + .close = natsemi_close, + .transmit = natsemi_transmit, + .poll = natsemi_poll, + .irq = natsemi_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + /** * Probe PCI device * - * @v pci PCI device - * @v id PCI ID - * @ret rc Return status code + * @v pci PCI device + * @ret rc Return status code */ -static int natsemi_probe (struct pci_device *pci) { +static int natsemi_probe ( struct pci_device *pci ) { struct net_device *netdev; - struct natsemi_private *np = NULL; - uint8_t ll_addr_encoded[MAX_LL_ADDR_LEN]; - uint8_t last=0,last1=0; - uint8_t prev_bytes[2]; - int i; + struct natsemi_nic *natsemi; int rc; - /* Allocate net device - */ - netdev = alloc_etherdev (sizeof (*np)); - if (! netdev) - return -ENOMEM; - - netdev_init (netdev, &natsemi_operations); - np = netdev->priv; - pci_set_drvdata (pci, netdev); - netdev->dev = &pci->dev; - memset (np, 0, sizeof (*np)); - np->ioaddr = pci->ioaddr; - - adjust_pci_device (pci); - - natsemi_reset (netdev); - natsemi_init_eeprom ( np ); - nvs_read ( &np->eeprom.nvs, EE_MAC-1, prev_bytes, 1 ); - nvs_read ( &np->eeprom.nvs, EE_MAC, ll_addr_encoded, ETH_ALEN ); - - /* decoding the MAC address read from NVS - * and save it in netdev->ll_addr - */ - last = prev_bytes[1] >> 7; - for ( i = 0 ; i < ETH_ALEN ; i++ ) { - last1 = ll_addr_encoded[i] >> 7; - netdev->hw_addr[i] = ll_addr_encoded[i] << 1 | last; - last = last1; + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *natsemi ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; } + netdev_init ( netdev, &natsemi_operations ); + natsemi = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( natsemi, 0, sizeof ( *natsemi ) ); + natsemi->flags = pci->id->driver_data; + natsemi_init_ring ( &natsemi->tx, NATSEMI_NUM_TX_DESC, NATSEMI_TXDP ); + natsemi_init_ring ( &natsemi->rx, NATSEMI_NUM_RX_DESC, NATSEMI_RXDP ); - if ((rc = register_netdev (netdev)) != 0) + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + natsemi->regs = ioremap ( pci->membase, NATSEMI_BAR_SIZE ); + + /* Reset the NIC */ + if ( ( rc = natsemi_reset ( natsemi ) ) != 0 ) + goto err_reset; + + /* Initialise EEPROM */ + natsemi_init_eeprom ( natsemi ); + + /* Read initial MAC address */ + if ( ( rc = natsemi_hwaddr ( natsemi, netdev->hw_addr ) ) != 0 ) + goto err_hwaddr; + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) goto err_register_netdev; - /* Mark as link up; we don't yet handle link state */ - netdev_link_up ( netdev ); + /* Set initial link state */ + natsemi_check_link ( netdev ); return 0; -err_register_netdev: - - natsemi_reset (netdev); - netdev_put (netdev); + unregister_netdev ( netdev ); + err_register_netdev: + err_hwaddr: + natsemi_reset ( natsemi ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: return rc; } /** * Remove PCI device * - * @v pci PCI device + * @v pci PCI device */ -static void natsemi_remove (struct pci_device *pci) { - struct net_device *netdev = pci_get_drvdata (pci); - - unregister_netdev (netdev); - natsemi_reset (netdev); +static void natsemi_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct natsemi_nic *natsemi = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset card */ + natsemi_reset ( natsemi ); + + /* Free network device */ netdev_nullify ( netdev ); - netdev_put (netdev); + netdev_put ( netdev ); } -/** - * Reset NIC - * - * @v NATSEMI NIC - * - * Issues a hardware reset and waits for the reset to complete. - */ -static void natsemi_reset (struct net_device *netdev) -{ - struct natsemi_private *np = netdev->priv; - int i; - u32 cfg; - u32 wcsr; - u32 rfcr; - u16 pmatch[3]; - u16 sopass[3]; +/** Flags for DP83815 */ +#define DP83815_FLAGS ( NATSEMI_EEPROM_LITTLE_ENDIAN | NATSEMI_EEPROM_INSANE ) - natsemi_irq (netdev, 0); - - /* - * Resetting the chip causes some registers to be lost. - * Natsemi suggests NOT reloading the EEPROM while live, so instead - * we save the state that would have been loaded from EEPROM - * on a normal power-up (see the spec EEPROM map). - */ - - /* CFG */ - cfg = inl (np->ioaddr + ChipConfig) & CFG_RESET_SAVE; - - /* WCSR */ - wcsr = inl (np->ioaddr + WOLCmd) & WCSR_RESET_SAVE; - - /* RFCR */ - rfcr = inl (np->ioaddr + RxFilterAddr) & RFCR_RESET_SAVE; - - /* PMATCH */ - for (i = 0; i < 3; i++) { - outl(i*2, np->ioaddr + RxFilterAddr); - pmatch[i] = inw(np->ioaddr + RxFilterData); - } - - /* SOPAS */ - for (i = 0; i < 3; i++) { - outl(0xa+(i*2), np->ioaddr + RxFilterAddr); - sopass[i] = inw(np->ioaddr + RxFilterData); - } - - /* now whack the chip */ - outl(ChipReset, np->ioaddr + ChipCmd); - for (i=0; iioaddr + ChipCmd) & ChipReset)) - break; - udelay(5); - } - if (i == NATSEMI_HW_TIMEOUT) { - DBG ("natsemi_reset: reset did not complete in %d usec.\n", i*5); - } - - /* restore CFG */ - cfg |= inl(np->ioaddr + ChipConfig) & ~CFG_RESET_SAVE; - cfg &= ~(CfgExtPhy | CfgPhyDis); - outl (cfg, np->ioaddr + ChipConfig); - - /* restore WCSR */ - wcsr |= inl (np->ioaddr + WOLCmd) & ~WCSR_RESET_SAVE; - outl (wcsr, np->ioaddr + WOLCmd); - - /* read RFCR */ - rfcr |= inl (np->ioaddr + RxFilterAddr) & ~RFCR_RESET_SAVE; - - /* restore PMATCH */ - for (i = 0; i < 3; i++) { - outl (i*2, np->ioaddr + RxFilterAddr); - outw (pmatch[i], np->ioaddr + RxFilterData); - } - for (i = 0; i < 3; i++) { - outl (0xa+(i*2), np->ioaddr + RxFilterAddr); - outw (sopass[i], np->ioaddr + RxFilterData); - } - /* restore RFCR */ - outl (rfcr, np->ioaddr + RxFilterAddr); -} - -/** - * Open NIC - * - * @v netdev Net device - * @ret rc Return status code - */ -static int natsemi_open (struct net_device *netdev) -{ - struct natsemi_private *np = netdev->priv; - uint32_t tx_config, rx_config; - int i; - - /* Disable PME: - * The PME bit is initialized from the EEPROM contents. - * PCI cards probably have PME disabled, but motherboard - * implementations may have PME set to enable WakeOnLan. - * With PME set the chip will scan incoming packets but - * nothing will be written to memory. - */ - outl (inl (np->ioaddr + ClkRun) & ~0x100, np->ioaddr + ClkRun); - - /* Set MAC address in NIC - */ - for (i = 0 ; i < ETH_ALEN ; i+=2) { - outl (i, np->ioaddr + RxFilterAddr); - outw (netdev->ll_addr[i] + (netdev->ll_addr[i + 1] << 8), - np->ioaddr + RxFilterData); - } - - /* Setup Tx Ring - */ - np->tx_cur = 0; - np->tx_dirty = 0; - for (i = 0 ; i < TX_RING_SIZE ; i++) { - np->tx[i].link = virt_to_bus ((i + 1 < TX_RING_SIZE) ? &np->tx[i + 1] : &np->tx[0]); - np->tx[i].cmdsts = 0; - np->tx[i].bufptr = 0; - } - outl (virt_to_bus (&np->tx[0]),np->ioaddr + TxRingPtr); - - DBG ("Natsemi Tx descriptor loaded with: %#08x\n", - inl (np->ioaddr + TxRingPtr)); - - /* Setup RX ring - */ - np->rx_cur = 0; - for (i = 0 ; i < NUM_RX_DESC ; i++) { - np->iobuf[i] = alloc_iob (RX_BUF_SIZE); - if (! np->iobuf[i]) - goto memory_alloc_err; - np->rx[i].link = virt_to_bus ((i + 1 < NUM_RX_DESC) - ? &np->rx[i + 1] : &np->rx[0]); - np->rx[i].cmdsts = RX_BUF_SIZE; - np->rx[i].bufptr = virt_to_bus (np->iobuf[i]->data); - DBG (" Address of iobuf [%d] = %p and iobuf->data = %p \n", i, - &np->iobuf[i], &np->iobuf[i]->data); - } - outl (virt_to_bus (&np->rx[0]), np->ioaddr + RxRingPtr); - - DBG ("Natsemi Rx descriptor loaded with: %#08x\n", - inl (np->ioaddr + RxRingPtr)); - - /* Setup RX Filter - */ - outl (RxFilterEnable | AcceptBroadcast | AcceptAllMulticast | AcceptMyPhys, - np->ioaddr + RxFilterAddr); - - /* Initialize other registers. - * Configure the PCI bus bursts and FIFO thresholds. - * Configure for standard, in-spec Ethernet. - */ - if (inl (np->ioaddr + ChipConfig) & 0x20000000) { /* Full duplex */ - DBG ("Full duplex\n"); - tx_config = 0xD0801002 | 0xC0000000; - rx_config = 0x10000020 | 0x10000000; - } else { - DBG ("Half duplex\n"); - tx_config = 0x10801002 & ~0xC0000000; - rx_config = 0x00000020 & ~0x10000000; - } - outl (tx_config, np->ioaddr + TxConfig); - outl (rx_config, np->ioaddr + RxConfig); - - DBG ("Tx config register = %#08x Rx config register = %#08x\n", - inl (np->ioaddr + TxConfig), - inl (np->ioaddr + RxConfig)); - - /*Set the Interrupt Mask register - */ - outl((RxOk|RxErr|TxOk|TxErr),np->ioaddr + IntrMask); - /*start the receiver - */ - outl (RxOn, np->ioaddr + ChipCmd); - - return 0; - -memory_alloc_err: - - /* Frees any allocated buffers when memory - * for all buffers requested is not available - */ - i = 0; - while (np->rx[i].cmdsts == RX_BUF_SIZE) { - free_iob (np->iobuf[i]); - i++; - } - return -ENOMEM; -} - -/** - * Close NIC - * - * @v netdev Net device - */ -static void natsemi_close (struct net_device *netdev) -{ - struct natsemi_private *np = netdev->priv; - int i; - - natsemi_reset (netdev); - - for (i = 0; i < NUM_RX_DESC ; i++) { - free_iob (np->iobuf[i]); - } -} - -/** - * Transmit packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static int natsemi_transmit (struct net_device *netdev, struct io_buffer *iobuf) -{ - struct natsemi_private *np = netdev->priv; - - if (np->tx[np->tx_cur].cmdsts != 0) { - DBG ("TX overflow\n"); - return -ENOBUFS; - } - - /* Used by netdev_tx_complete () - */ - np->tx_iobuf[np->tx_cur] = iobuf; - - /* Pad and align packet has not been used because its not required - * by the hardware. - * iob_pad (iobuf, ETH_ZLEN); - * can be used to achieve it, if required - */ - - /* Add the packet to TX ring - */ - np->tx[np->tx_cur].bufptr = virt_to_bus (iobuf->data); - np->tx[np->tx_cur].cmdsts = iob_len (iobuf) | OWN; - - DBG ("TX id %d at %#08lx + %#08zx\n", np->tx_cur, - virt_to_bus (&iobuf->data), iob_len (iobuf)); - - /* increment the circular buffer pointer to the next buffer location - */ - np->tx_cur = (np->tx_cur + 1) % TX_RING_SIZE; - - /*start the transmitter - */ - outl (TxOn, np->ioaddr + ChipCmd); - - return 0; -} - -/** - * Poll for received packets - * - * @v netdev Network device - */ -static void natsemi_poll (struct net_device *netdev) -{ - struct natsemi_private *np = netdev->priv; - unsigned int tx_status; - unsigned int rx_status; - unsigned int intr_status; - unsigned int rx_len; - struct io_buffer *rx_iob; - int i; - - /* read the interrupt register - */ - intr_status = inl (np->ioaddr + IntrStatus); - - if (!intr_status) - goto end; - - DBG ("natsemi_poll: intr_status = %#08x\n", intr_status); - - /* Check status of transmitted packets - */ - i = np->tx_dirty; - while (i != np->tx_cur) { - tx_status = np->tx[np->tx_dirty].cmdsts; - - DBG ("tx_dirty = %d tx_cur=%d tx_status=%#08x\n", - np->tx_dirty, np->tx_cur, tx_status); - - if (tx_status & OWN) - break; - - if (! (tx_status & DescPktOK)) { - netdev_tx_complete_err (netdev,np->tx_iobuf[np->tx_dirty],-EINVAL); - DBG ("Error transmitting packet, tx_status: %#08x\n", - tx_status); - } else { - netdev_tx_complete (netdev, np->tx_iobuf[np->tx_dirty]); - DBG ("Success transmitting packet\n"); - } - - np->tx[np->tx_dirty].cmdsts = 0; - np->tx_dirty = (np->tx_dirty + 1) % TX_RING_SIZE; - i = (i + 1) % TX_RING_SIZE; - } - - /* Process received packets - */ - rx_status = (unsigned int) np->rx[np->rx_cur].cmdsts; - while ((rx_status & OWN)) { - rx_len = (rx_status & DSIZE) - CRC_SIZE; - - DBG ("Received packet, rx_curr = %d, rx_status = %#08x, rx_len = %d\n", - np->rx_cur, rx_status, rx_len); - - if ((rx_status & (DescMore | DescPktOK | RxTooLong)) != DescPktOK) { - netdev_rx_err (netdev, NULL, -EINVAL); - - DBG ("natsemi_poll: Corrupted packet received!" - " Status = %#08x\n", - np->rx[np->rx_cur].cmdsts); - - } else { - - - /* If unable allocate space for this packet, - * try again next poll - */ - rx_iob = alloc_iob (rx_len); - if (! rx_iob) - goto end; - memcpy (iob_put (rx_iob, rx_len), - np->iobuf[np->rx_cur]->data, rx_len); - /* Add this packet to the receive queue. - */ - netdev_rx (netdev, rx_iob); - } - np->rx[np->rx_cur].cmdsts = RX_BUF_SIZE; - np->rx_cur = (np->rx_cur + 1) % NUM_RX_DESC; - rx_status = np->rx[np->rx_cur].cmdsts; - } -end: - /* re-enable the potentially idle receive state machine - */ - outl (RxOn, np->ioaddr + ChipCmd); -} - -/** - * Enable/disable interrupts - * - * @v netdev Network device - * @v enable Non-zero for enable, zero for disable - */ -static void natsemi_irq (struct net_device *netdev, int enable) -{ - struct natsemi_private *np = netdev->priv; - - outl ((enable ? (RxOk | RxErr | TxOk|TxErr) : 0), - np->ioaddr + IntrMask); - outl ((enable ? 1 : 0), np->ioaddr + IntrEnable); -} +/** Flags for DP83820 */ +#define DP83820_FLAGS ( NATSEMI_64BIT | NATSEMI_1000 ) +/** National Semiconductor PCI device IDs */ static struct pci_device_id natsemi_nics[] = { - PCI_ROM(0x100b, 0x0020, "dp83815", "DP83815", 0), + PCI_ROM ( 0x100b, 0x0020, "dp83815", "DP83815", DP83815_FLAGS ), + PCI_ROM ( 0x100b, 0x0022, "dp83820", "DP83820", DP83820_FLAGS ), }; +/** National Semiconductor PCI driver */ struct pci_driver natsemi_driver __pci_driver = { .ids = natsemi_nics, - .id_count = (sizeof (natsemi_nics) / sizeof (natsemi_nics[0])), + .id_count = ( sizeof ( natsemi_nics ) / sizeof ( natsemi_nics[0] ) ), .probe = natsemi_probe, .remove = natsemi_remove, }; diff --git a/src/drivers/net/natsemi.h b/src/drivers/net/natsemi.h index ae827ba3..e3444712 100644 --- a/src/drivers/net/natsemi.h +++ b/src/drivers/net/natsemi.h @@ -1,232 +1,329 @@ -FILE_LICENCE ( GPL_ANY ); +#ifndef _NATSEMI_H +#define _NATSEMI_H -#define NATSEMI_HW_TIMEOUT 400 +/** @file + * + * National Semiconductor "MacPhyter" network card driver + * + */ -#define TX_RING_SIZE 4 -#define NUM_RX_DESC 4 -#define RX_BUF_SIZE 1536 -#define OWN 0x80000000 -#define DSIZE 0x00000FFF -#define CRC_SIZE 4 +FILE_LICENCE ( GPL2_OR_LATER ); -struct natsemi_tx { +#include +#include +#include + +/** BAR size */ +#define NATSEMI_BAR_SIZE 0x100 + +/** A 32-bit packet descriptor */ +struct natsemi_descriptor_32 { + /** Link to next descriptor */ uint32_t link; + /** Command / status */ uint32_t cmdsts; + /** Buffer pointer */ uint32_t bufptr; +} __attribute__ (( packed )); + +/** A 64-bit packet descriptor */ +struct natsemi_descriptor_64 { + /** Link to next descriptor */ + uint64_t link; + /** Buffer pointer */ + uint64_t bufptr; + /** Command / status */ + uint32_t cmdsts; + /** Extended status */ + uint32_t extsts; +} __attribute__ (( packed )); + +/** A packet descriptor + * + * The 32-bit and 64-bit variants are overlaid such that "cmdsts" can + * be accessed as a common field, and the overall size is a power of + * two (to allow the descriptor ring length to be used as an + * alignment). + */ +union natsemi_descriptor { + /** Common fields */ + struct { + /** Reserved */ + uint8_t reserved_a[16]; + /** Command / status */ + uint32_t cmdsts; + /** Reserved */ + uint8_t reserved_b[12]; + } __attribute__ (( packed )) common; + /** 64-bit descriptor */ + struct natsemi_descriptor_64 d64; + /** 32-bit descriptor */ + struct { + /** Reserved */ + uint8_t reserved[12]; + /** Descriptor */ + struct natsemi_descriptor_32 d32; + } __attribute__ (( packed )) d32pad; }; -struct natsemi_rx { - uint32_t link; - uint32_t cmdsts; - uint32_t bufptr; +/** Descriptor buffer size mask */ +#define NATSEMI_DESC_SIZE_MASK 0xfff + +/** Packet descriptor flags */ +enum natsemi_descriptor_flags { + /** Descriptor is owned by NIC */ + NATSEMI_DESC_OWN = 0x80000000UL, + /** Request descriptor interrupt */ + NATSEMI_DESC_INTR = 0x20000000UL, + /** Packet OK */ + NATSEMI_DESC_OK = 0x08000000UL, }; -struct natsemi_private { - unsigned short ioaddr; - unsigned short tx_cur; - unsigned short tx_dirty; - unsigned short rx_cur; - struct natsemi_tx tx[TX_RING_SIZE]; - struct natsemi_rx rx[NUM_RX_DESC]; +/** Command Register */ +#define NATSEMI_CR 0x0000 +#define NATSEMI_CR_RST 0x00000100UL /**< Reset */ +#define NATSEMI_CR_RXR 0x00000020UL /**< Receiver reset */ +#define NATSEMI_CR_TXR 0x00000010UL /**< Transmit reset */ +#define NATSEMI_CR_RXE 0x00000004UL /**< Receiver enable */ +#define NATSEMI_CR_TXE 0x00000001UL /**< Transmit enable */ - /* need to add iobuf as we cannot free iobuf->data in close without this - * alternatively substracting sizeof(head) and sizeof(list_head) can also - * give the same. - */ - struct io_buffer *iobuf[NUM_RX_DESC]; +/** Maximum time to wait for a reset, in milliseconds */ +#define NATSEMI_RESET_MAX_WAIT_MS 100 - /* netdev_tx_complete needs pointer to the iobuf of the data so as to free - * it from the memory. - */ - struct io_buffer *tx_iobuf[TX_RING_SIZE]; +/** Configuration and Media Status Register */ +#define NATSEMI_CFG 0x0004 +#define NATSEMI_CFG_LNKSTS 0x80000000UL /**< Link status */ +#define NATSEMI_CFG_SPDSTS1 0x40000000UL /**< Speed status bit 1 */ +#define NATSEMI_CFG_MODE_1000 0x00400000UL /**< 1000 Mb/s mode control */ +#define NATSEMI_CFG_PCI64_DET 0x00002000UL /**< PCI 64-bit bus detected */ +#define NATSEMI_CFG_DATA64_EN 0x00001000UL /**< 64-bit data enable */ +#define NATSEMI_CFG_M64ADDR 0x00000800UL /**< 64-bit address enable */ +#define NATSEMI_CFG_EXTSTS_EN 0x00000100UL /**< Extended status enable */ + +/** EEPROM Access Register */ +#define NATSEMI_MEAR 0x0008 +#define NATSEMI_MEAR_EESEL 0x00000008UL /**< EEPROM chip select */ +#define NATSEMI_MEAR_EECLK 0x00000004UL /**< EEPROM serial clock */ +#define NATSEMI_MEAR_EEDO 0x00000002UL /**< EEPROM data out */ +#define NATSEMI_MEAR_EEDI 0x00000001UL /**< EEPROM data in */ + +/** Size of EEPROM (in bytes) */ +#define NATSEMI_EEPROM_SIZE 32 + +/** Word offset of MAC address within sane EEPROM layout */ +#define NATSEMI_EEPROM_MAC_SANE 0x0a + +/** Word offset of MAC address within insane EEPROM layout */ +#define NATSEMI_EEPROM_MAC_INSANE 0x06 + +/** PCI Test Control Register */ +#define NATSEMI_PTSCR 0x000c +#define NATSEMI_PTSCR_EELOAD_EN 0x00000004UL /**< Enable EEPROM load */ + +/** Maximum time to wait for a configuration reload, in milliseconds */ +#define NATSEMI_EELOAD_MAX_WAIT_MS 100 + +/** Interrupt Status Register */ +#define NATSEMI_ISR 0x0010 +#define NATSEMI_IRQ_TXDESC 0x00000080UL /**< TX descriptor */ +#define NATSEMI_IRQ_RXDESC 0x00000002UL /**< RX descriptor */ + +/** Interrupt Mask Register */ +#define NATSEMI_IMR 0x0014 + +/** Interrupt Enable Register */ +#define NATSEMI_IER 0x0018 +#define NATSEMI_IER_IE 0x00000001UL /**< Interrupt enable */ + +/** Transmit Descriptor Pointer */ +#define NATSEMI_TXDP 0x0020 + +/** Transmit Descriptor Pointer High Dword (64-bit) */ +#define NATSEMI_TXDP_HI_64 0x0024 + +/** Number of transmit descriptors */ +#define NATSEMI_NUM_TX_DESC 4 + +/** Transmit configuration register (32-bit) */ +#define NATSEMI_TXCFG_32 0x24 + +/** Transmit configuration register (64-bit) */ +#define NATSEMI_TXCFG_64 0x28 +#define NATSEMI_TXCFG_CSI 0x80000000UL /**< Carrier sense ignore */ +#define NATSEMI_TXCFG_HBI 0x40000000UL /**< Heartbeat ignore */ +#define NATSEMI_TXCFG_ATP 0x10000000UL /**< Automatic padding */ +#define NATSEMI_TXCFG_ECRETRY 0x00800000UL /**< Excess collision retry */ +#define NATSEMI_TXCFG_MXDMA(x) ( (x) << 20 ) /**< Max DMA burst size */ +#define NATSEMI_TXCFG_FLTH(x) ( (x) << 8 ) /**< Fill threshold */ +#define NATSEMI_TXCFG_DRTH(x) ( (x) << 0 ) /**< Drain threshold */ + +/** Max DMA burst size (encoded value) + * + * This represents 256-byte bursts on 83815 controllers and 512-byte + * bursts on 83820 controllers. + */ +#define NATSEMI_TXCFG_MXDMA_DEFAULT NATSEMI_TXCFG_MXDMA ( 0x7 ) + +/** Fill threshold (in units of 32 bytes) + * + * Must be at least as large as the max DMA burst size, so use a value + * of 512 bytes. + */ +#define NATSEMI_TXCFG_FLTH_DEFAULT NATSEMI_TXCFG_FLTH ( 512 / 32 ) + +/** Drain threshold (in units of 32 bytes) + * + * Start transmission once we receive a conservative 1024 bytes, to + * avoid FIFO underrun errors. (83815 does not allow us to specify a + * value of 0 for "wait until whole packet is present".) + * + * Fill threshold plus drain threshold must be less than the transmit + * FIFO size, which is 2kB on 83815 and 8kB on 83820. + */ +#define NATSEMI_TXCFG_DRTH_DEFAULT NATSEMI_TXCFG_DRTH ( 1024 / 32 ) + +/** Receive Descriptor Pointer */ +#define NATSEMI_RXDP 0x0030 + +/** Receive Descriptor Pointer High Dword (64-bit) */ +#define NATSEMI_RXDP_HI_64 0x0034 + +/** Number of receive descriptors */ +#define NATSEMI_NUM_RX_DESC 4 + +/** Receive buffer length */ +#define NATSEMI_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ ) + +/** Receive configuration register (32-bit) */ +#define NATSEMI_RXCFG_32 0x34 + +/** Receive configuration register (64-bit) */ +#define NATSEMI_RXCFG_64 0x38 +#define NATSEMI_RXCFG_ARP 0x40000000UL /**< Accept runt packets */ +#define NATSEMI_RXCFG_ATX 0x10000000UL /**< Accept transmit packets */ +#define NATSEMI_RXCFG_ALP 0x08000000UL /**< Accept long packets */ +#define NATSEMI_RXCFG_MXDMA(x) ( (x) << 20 ) /**< Max DMA burst size */ +#define NATSEMI_RXCFG_DRTH(x) ( (x) << 1 ) /**< Drain threshold */ + +/** Max DMA burst size (encoded value) + * + * This represents 256-byte bursts on 83815 controllers and 512-byte + * bursts on 83820 controllers. + */ +#define NATSEMI_RXCFG_MXDMA_DEFAULT NATSEMI_RXCFG_MXDMA ( 0x7 ) + +/** Drain threshold (in units of 8 bytes) + * + * Start draining after 64 bytes. + * + * Must be large enough to allow packet's accept/reject status to be + * determined before draining begins. + */ +#define NATSEMI_RXCFG_DRTH_DEFAULT NATSEMI_RXCFG_DRTH ( 64 / 8 ) + +/** Receive Filter/Match Control Register */ +#define NATSEMI_RFCR 0x0048 +#define NATSEMI_RFCR_RFEN 0x80000000UL /**< RX filter enable */ +#define NATSEMI_RFCR_AAB 0x40000000UL /**< Accept all broadcast */ +#define NATSEMI_RFCR_AAM 0x20000000UL /**< Accept all multicast */ +#define NATSEMI_RFCR_AAU 0x10000000UL /**< Accept all unicast */ +#define NATSEMI_RFCR_RFADDR( addr ) ( (addr) << 0 ) /**< Extended address */ +#define NATSEMI_RFCR_RFADDR_MASK NATSEMI_RFCR_RFADDR ( 0x3ff ) + +/** Perfect match filter address base */ +#define NATSEMI_RFADDR_PMATCH_BASE 0x000 + +/** Receive Filter/Match Data Register */ +#define NATSEMI_RFDR 0x004c +#define NATSEMI_RFDR_BMASK 0x00030000UL /**< Byte mask */ +#define NATSEMI_RFDR_DATA( value ) ( (value) & 0xffff ) /**< Filter data */ + +/** National Semiconductor network card flags */ +enum natsemi_nic_flags { + /** EEPROM is little-endian */ + NATSEMI_EEPROM_LITTLE_ENDIAN = 0x0001, + /** EEPROM layout is insane */ + NATSEMI_EEPROM_INSANE = 0x0002, + /** Card supports 64-bit operation */ + NATSEMI_64BIT = 0x0004, + /** Card supports 1000Mbps link */ + NATSEMI_1000 = 0x0008, +}; + +/** A National Semiconductor descriptor ring */ +struct natsemi_ring { + /** Descriptors */ + union natsemi_descriptor *desc; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; + + /** Number of descriptors */ + unsigned int count; + /** Descriptor start address register */ + unsigned int reg; +}; + +/** + * Initialise descriptor ring + * + * @v ring Descriptor ring + * @v count Number of descriptors + * @v reg Descriptor start address register + */ +static inline __attribute__ (( always_inline)) void +natsemi_init_ring ( struct natsemi_ring *ring, unsigned int count, + unsigned int reg ) { + ring->count = count; + ring->reg = reg; +} + +/** A National Semiconductor network card */ +struct natsemi_nic { + /** Flags */ + unsigned int flags; + /** Registers */ + void *regs; + /** SPI bit-bashing interface */ struct spi_bit_basher spibit; + /** EEPROM */ struct spi_device eeprom; - struct nvo_block nvo; + + /** Transmit descriptor ring */ + struct natsemi_ring tx; + /** Receive descriptor ring */ + struct natsemi_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[NATSEMI_NUM_RX_DESC]; + + /** Link status (cache) */ + uint32_t cfg; }; -/* - * Support for fibre connections on Am79C874: - * This phy needs a special setup when connected to a fibre cable. - * http://www.amd.com/files/connectivitysolutions/networking/archivednetworking/22235.pdf +/** + * Check if card can access physical address + * + * @v natsemi National Semiconductor device + * @v address Physical address + * @v address_ok Card can access physical address */ -#define PHYID_AM79C874 0x0022561b +static inline __attribute__ (( always_inline )) int +natsemi_address_ok ( struct natsemi_nic *natsemi, physaddr_t address ) { -enum { - MII_MCTRL = 0x15, /* mode control register */ - MII_FX_SEL = 0x0001, /* 100BASE-FX (fiber) */ - MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */ -}; + /* In a 32-bit build, all addresses can be accessed */ + if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) ) + return 1; + /* A 64-bit card can access all addresses */ + if ( natsemi->flags & NATSEMI_64BIT ) + return 1; + /* A 32-bit card can access all address below 4GB */ + if ( ( address & 0xffffffffUL ) == 0 ) + return 1; -/* values we might find in the silicon revision register */ -#define SRR_DP83815_C 0x0302 -#define SRR_DP83815_D 0x0403 -#define SRR_DP83816_A4 0x0504 -#define SRR_DP83816_A5 0x0505 - -/* NATSEMI: Offsets to the device registers. - * Unlike software-only systems, device drivers interact with complex hardware. - * It's not useful to define symbolic names for every register bit in the - * device. - */ -enum register_offsets { - ChipCmd = 0x00, - ChipConfig = 0x04, - EECtrl = 0x08, - PCIBusCfg = 0x0C, - IntrStatus = 0x10, - IntrMask = 0x14, - IntrEnable = 0x18, - TxRingPtr = 0x20, - TxConfig = 0x24, - RxRingPtr = 0x30, - RxConfig = 0x34, - ClkRun = 0x3C, - WOLCmd = 0x40, - PauseCmd = 0x44, - RxFilterAddr = 0x48, - RxFilterData = 0x4C, - BootRomAddr = 0x50, - BootRomData = 0x54, - SiliconRev = 0x58, - StatsCtrl = 0x5C, - StatsData = 0x60, - RxPktErrs = 0x60, - RxMissed = 0x68, - RxCRCErrs = 0x64, - PCIPM = 0x44, - PhyStatus = 0xC0, - MIntrCtrl = 0xC4, - MIntrStatus = 0xC8, - - /* These are from the spec, around page 78... on a separate table. - */ - PGSEL = 0xCC, - PMDCSR = 0xE4, - TSTDAT = 0xFC, - DSPCFG = 0xF4, - SDCFG = 0x8C, - BasicControl = 0x80, - BasicStatus = 0x84 - -}; - -/* the values for the 'magic' registers above (PGSEL=1) */ -#define PMDCSR_VAL 0x189c /* enable preferred adaptation circuitry */ -#define TSTDAT_VAL 0x0 -#define DSPCFG_VAL 0x5040 -#define SDCFG_VAL 0x008c /* set voltage thresholds for Signal Detect */ -#define DSPCFG_LOCK 0x20 /* coefficient lock bit in DSPCFG */ -#define DSPCFG_COEF 0x1000 /* see coefficient (in TSTDAT) bit in DSPCFG */ -#define TSTDAT_FIXED 0xe8 /* magic number for bad coefficients */ - -/* Bit in ChipCmd. - */ -enum ChipCmdBits { - ChipReset = 0x100, - RxReset = 0x20, - TxReset = 0x10, - RxOff = 0x08, - RxOn = 0x04, - TxOff = 0x02, - TxOn = 0x01 -}; - -enum ChipConfig_bits { - CfgPhyDis = 0x200, - CfgPhyRst = 0x400, - CfgExtPhy = 0x1000, - CfgAnegEnable = 0x2000, - CfgAneg100 = 0x4000, - CfgAnegFull = 0x8000, - CfgAnegDone = 0x8000000, - CfgFullDuplex = 0x20000000, - CfgSpeed100 = 0x40000000, - CfgLink = 0x80000000, -}; - - -/* Bits in the RxMode register. - */ -enum rx_mode_bits { - AcceptErr = 0x20, - AcceptRunt = 0x10, - AcceptBroadcast = 0xC0000000, - AcceptMulticast = 0x00200000, - AcceptAllMulticast = 0x20000000, - AcceptAllPhys = 0x10000000, - AcceptMyPhys = 0x08000000, - RxFilterEnable = 0x80000000 -}; - -/* Bits in network_desc.status - */ -enum desc_status_bits { - DescOwn = 0x80000000, - DescMore = 0x40000000, - DescIntr = 0x20000000, - DescNoCRC = 0x10000000, - DescPktOK = 0x08000000, - RxTooLong = 0x00400000 -}; - -/*Bits in Interrupt Mask register - */ -enum Intr_mask_register_bits { - RxOk = 0x001, - RxErr = 0x004, - TxOk = 0x040, - TxErr = 0x100 -}; - -enum MIntrCtrl_bits { - MICRIntEn = 0x2, -}; - -/* CFG bits [13:16] [18:23] */ -#define CFG_RESET_SAVE 0xfde000 -/* WCSR bits [0:4] [9:10] */ -#define WCSR_RESET_SAVE 0x61f -/* RFCR bits [20] [22] [27:31] */ -#define RFCR_RESET_SAVE 0xf8500000; - -/* Delay between EEPROM clock transitions. - No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need - a delay. */ -#define eeprom_delay(ee_addr) inl(ee_addr) - -enum EEPROM_Ctrl_Bits { - EE_ShiftClk = 0x04, - EE_DataIn = 0x01, - EE_ChipSelect = 0x08, - EE_DataOut = 0x02 -}; - -#define EE_Write0 (EE_ChipSelect) -#define EE_Write1 (EE_ChipSelect | EE_DataIn) - -/* The EEPROM commands include the alway-set leading bit. */ -enum EEPROM_Cmds { - EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6), -}; - -/* EEPROM access , values are devices specific - */ -#define EE_CS 0x08 /* EEPROM chip select */ -#define EE_SK 0x04 /* EEPROM shift clock */ -#define EE_DI 0x01 /* Data in */ -#define EE_DO 0x02 /* Data out */ - -/* Offsets within EEPROM (these are word offsets) - */ -#define EE_MAC 7 -#define EE_REG EECtrl - -static const uint8_t natsemi_ee_bits[] = { - [SPI_BIT_SCLK] = EE_SK, - [SPI_BIT_MOSI] = EE_DI, - [SPI_BIT_MISO] = EE_DO, - [SPI_BIT_SS(0)] = EE_CS, -}; + return 0; +} +#endif /* _NATSEMI_H */ diff --git a/src/drivers/net/ns83820.c b/src/drivers/net/ns83820.c deleted file mode 100644 index 0b92a91b..00000000 --- a/src/drivers/net/ns83820.c +++ /dev/null @@ -1,1007 +0,0 @@ -/************************************************************************** -* ns83820.c: Etherboot device driver for the National Semiconductor 83820 -* Written 2004 by Timothy Legge -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Portions of this code based on: -* ns83820.c by Benjamin LaHaise with contributions -* for Linux kernel 2.4.x. -* -* Linux Driver Version 0.20, 20020610 -* -* This development of this Etherboot driver was funded by: -* -* NXTV: http://www.nxtv.com/ -* -* REVISION HISTORY: -* ================ -* -* v1.0 02-16-2004 timlegge Initial port of Linux driver -* v1.1 02-19-2004 timlegge More rohbust transmit and poll -* -* Indent Options: indent -kr -i8 -***************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* to get some global routines like printf */ -#include "etherboot.h" -/* to get the interface to the body of the program */ -#include "nic.h" -/* to get the PCI support functions, if this is a PCI NIC */ -#include - -#if ARCH == ia64 /* Support 64-bit addressing */ -#define USE_64BIT_ADDR -#endif - -#define HZ 100 - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) - -/* NIC specific static variables go here */ - -/* Global parameters. See MODULE_PARM near the bottom. */ -// static int ihr = 2; -static int reset_phy = 0; -static int lnksts = 0; /* CFG_LNKSTS bit polarity */ - -#if defined(CONFIG_HIGHMEM64G) || defined(__ia64__) -#define USE_64BIT_ADDR "+" -#endif - -#if defined(USE_64BIT_ADDR) -#define TRY_DAC 1 -#else -#define TRY_DAC 0 -#endif - -/* tunables */ -#define RX_BUF_SIZE 1500 /* 8192 */ - -/* Must not exceed ~65000. */ -#define NR_RX_DESC 64 -#define NR_TX_DESC 1 - - /* not tunable *//* Extra 6 bytes for 64 bit alignment (divisable by 8) */ -#define REAL_RX_BUF_SIZE (RX_BUF_SIZE + 14 + 6) /* rx/tx mac addr + type */ - -#define MIN_TX_DESC_FREE 8 - -/* register defines */ -#define CFGCS 0x04 - -#define CR_TXE 0x00000001 -#define CR_TXD 0x00000002 -/* Ramit : Here's a tip, don't do a RXD immediately followed by an RXE - * The Receive engine skips one descriptor and moves - * onto the next one!! */ -#define CR_RXE 0x00000004 -#define CR_RXD 0x00000008 -#define CR_TXR 0x00000010 -#define CR_RXR 0x00000020 -#define CR_SWI 0x00000080 -#define CR_RST 0x00000100 - -#define PTSCR_EEBIST_FAIL 0x00000001 -#define PTSCR_EEBIST_EN 0x00000002 -#define PTSCR_EELOAD_EN 0x00000004 -#define PTSCR_RBIST_FAIL 0x000001b8 -#define PTSCR_RBIST_DONE 0x00000200 -#define PTSCR_RBIST_EN 0x00000400 -#define PTSCR_RBIST_RST 0x00002000 - -#define MEAR_EEDI 0x00000001 -#define MEAR_EEDO 0x00000002 -#define MEAR_EECLK 0x00000004 -#define MEAR_EESEL 0x00000008 -#define MEAR_MDIO 0x00000010 -#define MEAR_MDDIR 0x00000020 -#define MEAR_MDC 0x00000040 - -#define ISR_TXDESC3 0x40000000 -#define ISR_TXDESC2 0x20000000 -#define ISR_TXDESC1 0x10000000 -#define ISR_TXDESC0 0x08000000 -#define ISR_RXDESC3 0x04000000 -#define ISR_RXDESC2 0x02000000 -#define ISR_RXDESC1 0x01000000 -#define ISR_RXDESC0 0x00800000 -#define ISR_TXRCMP 0x00400000 -#define ISR_RXRCMP 0x00200000 -#define ISR_DPERR 0x00100000 -#define ISR_SSERR 0x00080000 -#define ISR_RMABT 0x00040000 -#define ISR_RTABT 0x00020000 -#define ISR_RXSOVR 0x00010000 -#define ISR_HIBINT 0x00008000 -#define ISR_PHY 0x00004000 -#define ISR_PME 0x00002000 -#define ISR_SWI 0x00001000 -#define ISR_MIB 0x00000800 -#define ISR_TXURN 0x00000400 -#define ISR_TXIDLE 0x00000200 -#define ISR_TXERR 0x00000100 -#define ISR_TXDESC 0x00000080 -#define ISR_TXOK 0x00000040 -#define ISR_RXORN 0x00000020 -#define ISR_RXIDLE 0x00000010 -#define ISR_RXEARLY 0x00000008 -#define ISR_RXERR 0x00000004 -#define ISR_RXDESC 0x00000002 -#define ISR_RXOK 0x00000001 - -#define TXCFG_CSI 0x80000000 -#define TXCFG_HBI 0x40000000 -#define TXCFG_MLB 0x20000000 -#define TXCFG_ATP 0x10000000 -#define TXCFG_ECRETRY 0x00800000 -#define TXCFG_BRST_DIS 0x00080000 -#define TXCFG_MXDMA1024 0x00000000 -#define TXCFG_MXDMA512 0x00700000 -#define TXCFG_MXDMA256 0x00600000 -#define TXCFG_MXDMA128 0x00500000 -#define TXCFG_MXDMA64 0x00400000 -#define TXCFG_MXDMA32 0x00300000 -#define TXCFG_MXDMA16 0x00200000 -#define TXCFG_MXDMA8 0x00100000 - -#define CFG_LNKSTS 0x80000000 -#define CFG_SPDSTS 0x60000000 -#define CFG_SPDSTS1 0x40000000 -#define CFG_SPDSTS0 0x20000000 -#define CFG_DUPSTS 0x10000000 -#define CFG_TBI_EN 0x01000000 -#define CFG_MODE_1000 0x00400000 -/* Ramit : Dont' ever use AUTO_1000, it never works and is buggy. - * Read the Phy response and then configure the MAC accordingly */ -#define CFG_AUTO_1000 0x00200000 -#define CFG_PINT_CTL 0x001c0000 -#define CFG_PINT_DUPSTS 0x00100000 -#define CFG_PINT_LNKSTS 0x00080000 -#define CFG_PINT_SPDSTS 0x00040000 -#define CFG_TMRTEST 0x00020000 -#define CFG_MRM_DIS 0x00010000 -#define CFG_MWI_DIS 0x00008000 -#define CFG_T64ADDR 0x00004000 -#define CFG_PCI64_DET 0x00002000 -#define CFG_DATA64_EN 0x00001000 -#define CFG_M64ADDR 0x00000800 -#define CFG_PHY_RST 0x00000400 -#define CFG_PHY_DIS 0x00000200 -#define CFG_EXTSTS_EN 0x00000100 -#define CFG_REQALG 0x00000080 -#define CFG_SB 0x00000040 -#define CFG_POW 0x00000020 -#define CFG_EXD 0x00000010 -#define CFG_PESEL 0x00000008 -#define CFG_BROM_DIS 0x00000004 -#define CFG_EXT_125 0x00000002 -#define CFG_BEM 0x00000001 - -#define EXTSTS_UDPPKT 0x00200000 -#define EXTSTS_TCPPKT 0x00080000 -#define EXTSTS_IPPKT 0x00020000 - -#define SPDSTS_POLARITY (CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0)) - -#define MIBC_MIBS 0x00000008 -#define MIBC_ACLR 0x00000004 -#define MIBC_FRZ 0x00000002 -#define MIBC_WRN 0x00000001 - -#define PCR_PSEN (1 << 31) -#define PCR_PS_MCAST (1 << 30) -#define PCR_PS_DA (1 << 29) -#define PCR_STHI_8 (3 << 23) -#define PCR_STLO_4 (1 << 23) -#define PCR_FFHI_8K (3 << 21) -#define PCR_FFLO_4K (1 << 21) -#define PCR_PAUSE_CNT 0xFFFE - -#define RXCFG_AEP 0x80000000 -#define RXCFG_ARP 0x40000000 -#define RXCFG_STRIPCRC 0x20000000 -#define RXCFG_RX_FD 0x10000000 -#define RXCFG_ALP 0x08000000 -#define RXCFG_AIRL 0x04000000 -#define RXCFG_MXDMA512 0x00700000 -#define RXCFG_DRTH 0x0000003e -#define RXCFG_DRTH0 0x00000002 - -#define RFCR_RFEN 0x80000000 -#define RFCR_AAB 0x40000000 -#define RFCR_AAM 0x20000000 -#define RFCR_AAU 0x10000000 -#define RFCR_APM 0x08000000 -#define RFCR_APAT 0x07800000 -#define RFCR_APAT3 0x04000000 -#define RFCR_APAT2 0x02000000 -#define RFCR_APAT1 0x01000000 -#define RFCR_APAT0 0x00800000 -#define RFCR_AARP 0x00400000 -#define RFCR_MHEN 0x00200000 -#define RFCR_UHEN 0x00100000 -#define RFCR_ULM 0x00080000 - -#define VRCR_RUDPE 0x00000080 -#define VRCR_RTCPE 0x00000040 -#define VRCR_RIPE 0x00000020 -#define VRCR_IPEN 0x00000010 -#define VRCR_DUTF 0x00000008 -#define VRCR_DVTF 0x00000004 -#define VRCR_VTREN 0x00000002 -#define VRCR_VTDEN 0x00000001 - -#define VTCR_PPCHK 0x00000008 -#define VTCR_GCHK 0x00000004 -#define VTCR_VPPTI 0x00000002 -#define VTCR_VGTI 0x00000001 - -#define CR 0x00 -#define CFG 0x04 -#define MEAR 0x08 -#define PTSCR 0x0c -#define ISR 0x10 -#define IMR 0x14 -#define IER 0x18 -#define IHR 0x1c -#define TXDP 0x20 -#define TXDP_HI 0x24 -#define TXCFG 0x28 -#define GPIOR 0x2c -#define RXDP 0x30 -#define RXDP_HI 0x34 -#define RXCFG 0x38 -#define PQCR 0x3c -#define WCSR 0x40 -#define PCR 0x44 -#define RFCR 0x48 -#define RFDR 0x4c - -#define SRR 0x58 - -#define VRCR 0xbc -#define VTCR 0xc0 -#define VDR 0xc4 -#define CCSR 0xcc - -#define TBICR 0xe0 -#define TBISR 0xe4 -#define TANAR 0xe8 -#define TANLPAR 0xec -#define TANER 0xf0 -#define TESR 0xf4 - -#define TBICR_MR_AN_ENABLE 0x00001000 -#define TBICR_MR_RESTART_AN 0x00000200 - -#define TBISR_MR_LINK_STATUS 0x00000020 -#define TBISR_MR_AN_COMPLETE 0x00000004 - -#define TANAR_PS2 0x00000100 -#define TANAR_PS1 0x00000080 -#define TANAR_HALF_DUP 0x00000040 -#define TANAR_FULL_DUP 0x00000020 - -#define GPIOR_GP5_OE 0x00000200 -#define GPIOR_GP4_OE 0x00000100 -#define GPIOR_GP3_OE 0x00000080 -#define GPIOR_GP2_OE 0x00000040 -#define GPIOR_GP1_OE 0x00000020 -#define GPIOR_GP3_OUT 0x00000004 -#define GPIOR_GP1_OUT 0x00000001 - -#define LINK_AUTONEGOTIATE 0x01 -#define LINK_DOWN 0x02 -#define LINK_UP 0x04 - - -#define __kick_rx() writel(CR_RXE, ns->base + CR) - -#define kick_rx() do { \ - DBG("kick_rx: maybe kicking\n"); \ - writel(virt_to_le32desc(&rx_ring[ns->cur_rx]), ns->base + RXDP); \ - if (ns->next_rx == ns->next_empty) \ - printf("uh-oh: next_rx == next_empty???\n"); \ - __kick_rx(); \ -} while(0) - - -#ifdef USE_64BIT_ADDR -#define HW_ADDR_LEN 8 -#else -#define HW_ADDR_LEN 4 -#endif - -#define CMDSTS_OWN 0x80000000 -#define CMDSTS_MORE 0x40000000 -#define CMDSTS_INTR 0x20000000 -#define CMDSTS_ERR 0x10000000 -#define CMDSTS_OK 0x08000000 -#define CMDSTS_LEN_MASK 0x0000ffff - -#define CMDSTS_DEST_MASK 0x01800000 -#define CMDSTS_DEST_SELF 0x00800000 -#define CMDSTS_DEST_MULTI 0x01000000 - -#define DESC_SIZE 8 /* Should be cache line sized */ - -#ifdef USE_64BIT_ADDR -struct ring_desc { - uint64_t link; - uint64_t bufptr; - u32 cmdsts; - u32 extsts; /* Extended status field */ -}; -#else -struct ring_desc { - u32 link; - u32 bufptr; - u32 cmdsts; - u32 extsts; /* Extended status field */ -}; -#endif - -/* Private Storage for the NIC */ -static struct ns83820_private { - u8 *base; - int up; - long idle; - u32 *next_rx_desc; - u16 next_rx, next_empty; - u32 cur_rx; - u32 *descs; - unsigned ihr; - u32 CFG_cache; - u32 MEAR_cache; - u32 IMR_cache; - int linkstate; - u16 tx_done_idx; - u16 tx_idx; - u16 tx_intr_idx; - u32 phy_descs; - u32 *tx_descs; - -} nsx; -static struct ns83820_private *ns; - -/* Define the TX and RX Descriptor and Buffers */ -struct { - struct ring_desc tx_ring[NR_TX_DESC] __attribute__ ((aligned(8))); - unsigned char txb[NR_TX_DESC * REAL_RX_BUF_SIZE]; - struct ring_desc rx_ring[NR_RX_DESC] __attribute__ ((aligned(8))); - unsigned char rxb[NR_RX_DESC * REAL_RX_BUF_SIZE] - __attribute__ ((aligned(8))); -} ns83820_bufs __shared; -#define tx_ring ns83820_bufs.tx_ring -#define rx_ring ns83820_bufs.rx_ring -#define txb ns83820_bufs.txb -#define rxb ns83820_bufs.rxb - -static void phy_intr(struct nic *nic __unused) -{ - static char *speeds[] = - { "10", "100", "1000", "1000(?)", "1000F" }; - u32 cfg, new_cfg; - u32 tbisr, tanar, tanlpar; - int speed, fullduplex, newlinkstate; - - cfg = readl(ns->base + CFG) ^ SPDSTS_POLARITY; - if (ns->CFG_cache & CFG_TBI_EN) { - /* we have an optical transceiver */ - tbisr = readl(ns->base + TBISR); - tanar = readl(ns->base + TANAR); - tanlpar = readl(ns->base + TANLPAR); - DBG("phy_intr: tbisr=%hX, tanar=%hX, tanlpar=%hX\n", - tbisr, tanar, tanlpar); - - if ((fullduplex = (tanlpar & TANAR_FULL_DUP) - && (tanar & TANAR_FULL_DUP))) { - - /* both of us are full duplex */ - writel(readl(ns->base + TXCFG) - | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP, - ns->base + TXCFG); - writel(readl(ns->base + RXCFG) | RXCFG_RX_FD, - ns->base + RXCFG); - /* Light up full duplex LED */ - writel(readl(ns->base + GPIOR) | GPIOR_GP1_OUT, - ns->base + GPIOR); - - } else if (((tanlpar & TANAR_HALF_DUP) - && (tanar & TANAR_HALF_DUP)) - || ((tanlpar & TANAR_FULL_DUP) - && (tanar & TANAR_HALF_DUP)) - || ((tanlpar & TANAR_HALF_DUP) - && (tanar & TANAR_FULL_DUP))) { - - /* one or both of us are half duplex */ - writel((readl(ns->base + TXCFG) - & ~(TXCFG_CSI | TXCFG_HBI)) | TXCFG_ATP, - ns->base + TXCFG); - writel(readl(ns->base + RXCFG) & ~RXCFG_RX_FD, - ns->base + RXCFG); - /* Turn off full duplex LED */ - writel(readl(ns->base + GPIOR) & ~GPIOR_GP1_OUT, - ns->base + GPIOR); - } - - speed = 4; /* 1000F */ - - } else { - /* we have a copper transceiver */ - new_cfg = - ns->CFG_cache & ~(CFG_SB | CFG_MODE_1000 | CFG_SPDSTS); - - if (cfg & CFG_SPDSTS1) - new_cfg |= CFG_MODE_1000; - else - new_cfg &= ~CFG_MODE_1000; - - speed = ((cfg / CFG_SPDSTS0) & 3); - fullduplex = (cfg & CFG_DUPSTS); - - if (fullduplex) - new_cfg |= CFG_SB; - - if ((cfg & CFG_LNKSTS) && - ((new_cfg ^ ns->CFG_cache) & CFG_MODE_1000)) { - writel(new_cfg, ns->base + CFG); - ns->CFG_cache = new_cfg; - } - - ns->CFG_cache &= ~CFG_SPDSTS; - ns->CFG_cache |= cfg & CFG_SPDSTS; - } - - newlinkstate = (cfg & CFG_LNKSTS) ? LINK_UP : LINK_DOWN; - - if (newlinkstate & LINK_UP && ns->linkstate != newlinkstate) { - printf("link now %s mbps, %s duplex and up.\n", - speeds[speed], fullduplex ? "full" : "half"); - } else if (newlinkstate & LINK_DOWN - && ns->linkstate != newlinkstate) { - printf("link now down.\n"); - } - ns->linkstate = newlinkstate; -} -static void ns83820_set_multicast(struct nic *nic __unused); -static void ns83820_setup_rx(struct nic *nic) -{ - unsigned i; - ns->idle = 1; - ns->next_rx = 0; - ns->next_rx_desc = ns->descs; - ns->next_empty = 0; - ns->cur_rx = 0; - - - for (i = 0; i < NR_RX_DESC; i++) { - rx_ring[i].link = virt_to_le32desc(&rx_ring[i + 1]); - rx_ring[i].bufptr = - virt_to_le32desc(&rxb[i * REAL_RX_BUF_SIZE]); - rx_ring[i].cmdsts = cpu_to_le32(REAL_RX_BUF_SIZE); - rx_ring[i].extsts = cpu_to_le32(0); - } -// No need to wrap the ring -// rx_ring[i].link = virt_to_le32desc(&rx_ring[0]); - writel(0, ns->base + RXDP_HI); - writel(virt_to_le32desc(&rx_ring[0]), ns->base + RXDP); - - DBG("starting receiver\n"); - - writel(0x0001, ns->base + CCSR); - writel(0, ns->base + RFCR); - writel(0x7fc00000, ns->base + RFCR); - writel(0xffc00000, ns->base + RFCR); - - ns->up = 1; - - phy_intr(nic); - - /* Okay, let it rip */ - ns->IMR_cache |= ISR_PHY; - ns->IMR_cache |= ISR_RXRCMP; - //dev->IMR_cache |= ISR_RXERR; - //dev->IMR_cache |= ISR_RXOK; - ns->IMR_cache |= ISR_RXORN; - ns->IMR_cache |= ISR_RXSOVR; - ns->IMR_cache |= ISR_RXDESC; - ns->IMR_cache |= ISR_RXIDLE; - ns->IMR_cache |= ISR_TXDESC; - ns->IMR_cache |= ISR_TXIDLE; - - // No reason to enable interupts... - // writel(ns->IMR_cache, ns->base + IMR); - // writel(1, ns->base + IER); - ns83820_set_multicast(nic); - kick_rx(); -} - - -static void ns83820_do_reset(struct nic *nic __unused, u32 which) -{ - DBG("resetting chip...\n"); - writel(which, ns->base + CR); - do { - - } while (readl(ns->base + CR) & which); - DBG("okay!\n"); -} - -static void ns83820_reset(struct nic *nic) -{ - unsigned i; - DBG("ns83820_reset\n"); - - writel(0, ns->base + PQCR); - - ns83820_setup_rx(nic); - - for (i = 0; i < NR_TX_DESC; i++) { - tx_ring[i].link = 0; - tx_ring[i].bufptr = 0; - tx_ring[i].cmdsts = cpu_to_le32(0); - tx_ring[i].extsts = cpu_to_le32(0); - } - - ns->tx_idx = 0; - ns->tx_done_idx = 0; - writel(0, ns->base + TXDP_HI); - return; -} -static void ns83820_getmac(struct nic *nic __unused, u8 * mac) -{ - unsigned i; - for (i = 0; i < 3; i++) { - u32 data; - /* Read from the perfect match memory: this is loaded by - * the chip from the EEPROM via the EELOAD self test. - */ - writel(i * 2, ns->base + RFCR); - data = readl(ns->base + RFDR); - *mac++ = data; - *mac++ = data >> 8; - } -} - -static void ns83820_set_multicast(struct nic *nic __unused) -{ - u8 *rfcr = ns->base + RFCR; - u32 and_mask = 0xffffffff; - u32 or_mask = 0; - u32 val; - - /* Support Multicast */ - and_mask &= ~(RFCR_AAU | RFCR_AAM); - or_mask |= RFCR_AAM; - val = (readl(rfcr) & and_mask) | or_mask; - /* Ramit : RFCR Write Fix doc says RFEN must be 0 modify other bits */ - writel(val & ~RFCR_RFEN, rfcr); - writel(val, rfcr); - -} -static void ns83820_run_bist(struct nic *nic __unused, const char *name, - u32 enable, u32 done, u32 fail) -{ - int timed_out = 0; - long start; - u32 status; - int loops = 0; - - DBG("start %s\n", name); - - start = currticks(); - - writel(enable, ns->base + PTSCR); - for (;;) { - loops++; - status = readl(ns->base + PTSCR); - if (!(status & enable)) - break; - if (status & done) - break; - if (status & fail) - break; - if ((currticks() - start) >= HZ) { - timed_out = 1; - break; - } - } - - if (status & fail) - printf("%s failed! (0x%hX & 0x%hX)\n", name, (unsigned int) status, - (unsigned int) fail); - else if (timed_out) - printf("run_bist %s timed out! (%hX)\n", name, (unsigned int) status); - DBG("done %s in %d loops\n", name, loops); -} - -/************************************* -Check Link -*************************************/ -static void ns83820_check_intr(struct nic *nic) { - int i; - u32 isr = readl(ns->base + ISR); - if(ISR_PHY & isr) - phy_intr(nic); - if(( ISR_RXIDLE | ISR_RXDESC | ISR_RXERR) & isr) - kick_rx(); - for (i = 0; i < NR_RX_DESC; i++) { - if (rx_ring[i].cmdsts == CMDSTS_OWN) { -// rx_ring[i].link = virt_to_le32desc(&rx_ring[i + 1]); - rx_ring[i].cmdsts = cpu_to_le32(REAL_RX_BUF_SIZE); - } - } -} -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int ns83820_poll(struct nic *nic, int retrieve) -{ - /* return true if there's an ethernet packet ready to read */ - /* nic->packet should contain data on return */ - /* nic->packetlen should contain length of data */ - u32 cmdsts; - int entry = ns->cur_rx; - - ns83820_check_intr(nic); - - cmdsts = le32_to_cpu(rx_ring[entry].cmdsts); - - if ( ! ( (CMDSTS_OWN & (cmdsts)) && (cmdsts != (CMDSTS_OWN)) ) ) - return 0; - - if ( ! retrieve ) return 1; - - if (! (CMDSTS_OK & cmdsts) ) - return 0; - - nic->packetlen = cmdsts & 0xffff; - memcpy(nic->packet, - rxb + (entry * REAL_RX_BUF_SIZE), - nic->packetlen); - // rx_ring[entry].link = 0; - rx_ring[entry].cmdsts = cpu_to_le32(CMDSTS_OWN); - - ns->cur_rx = (ns->cur_rx + 1) % NR_RX_DESC; - - if (ns->cur_rx == 0) /* We have wrapped the ring */ - kick_rx(); - - return 1; -} - -static inline void kick_tx(struct nic *nic __unused) -{ - DBG("kick_tx\n"); - writel(CR_TXE, ns->base + CR); -} - -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void ns83820_transmit(struct nic *nic, const char *d, /* Destination */ - unsigned int t, /* Type */ - unsigned int s, /* size */ - const char *p) -{ /* Packet */ - /* send the packet to destination */ - - u16 nstype; - u32 cmdsts, extsts; - int cur_tx = 0; - u32 isr = readl(ns->base + ISR); - if (ISR_TXIDLE & isr) - kick_tx(nic); - /* point to the current txb incase multiple tx_rings are used */ - memcpy(txb, d, ETH_ALEN); - memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); - nstype = htons((u16) t); - memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2); - memcpy(txb + ETH_HLEN, p, s); - s += ETH_HLEN; - s &= 0x0FFF; - while (s < ETH_ZLEN) - txb[s++] = '\0'; - - /* Setup the transmit descriptor */ - extsts = 0; - extsts |= EXTSTS_UDPPKT; - - tx_ring[cur_tx].bufptr = virt_to_le32desc(&txb); - tx_ring[cur_tx].extsts = cpu_to_le32(extsts); - - cmdsts = cpu_to_le32(0); - cmdsts |= cpu_to_le32(CMDSTS_OWN | s); - tx_ring[cur_tx].cmdsts = cpu_to_le32(cmdsts); - - writel(virt_to_le32desc(&tx_ring[0]), ns->base + TXDP); - kick_tx(nic); -} - -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void ns83820_disable ( struct nic *nic ) { - - /* put the card in its initial state */ - /* This function serves 3 purposes. - * This disables DMA and interrupts so we don't receive - * unexpected packets or interrupts from the card after - * etherboot has finished. - * This frees resources so etherboot may use - * this driver on another interface - * This allows etherboot to reinitialize the interface - * if something is something goes wrong. - */ - /* disable interrupts */ - writel(0, ns->base + IMR); - writel(0, ns->base + IER); - readl(ns->base + IER); - - ns->up = 0; - - ns83820_do_reset(nic, CR_RST); - - ns->IMR_cache &= - ~(ISR_RXOK | ISR_RXDESC | ISR_RXERR | ISR_RXEARLY | - ISR_RXIDLE); - writel(ns->IMR_cache, ns->base + IMR); - - /* touch the pci bus... */ - readl(ns->base + IMR); - - /* assumes the transmitter is already disabled and reset */ - writel(0, ns->base + RXDP_HI); - writel(0, ns->base + RXDP); -} - -/************************************************************************** -IRQ - Enable, Disable, or Force interrupts -***************************************************************************/ -static void ns83820_irq(struct nic *nic __unused, irq_action_t action __unused) -{ - switch ( action ) { - case DISABLE : - break; - case ENABLE : - break; - case FORCE : - break; - } -} - -static struct nic_operations ns83820_operations = { - .connect = dummy_connect, - .poll = ns83820_poll, - .transmit = ns83820_transmit, - .irq = ns83820_irq, - -}; - -static struct pci_device_id ns83820_nics[] = { - PCI_ROM(0x100b, 0x0022, "ns83820", "National Semiconductor 83820", 0), -}; - -PCI_DRIVER ( ns83820_driver, ns83820_nics, PCI_NO_CLASS ); - -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ - -#define board_found 1 -#define valid_link 0 -static int ns83820_probe ( struct nic *nic, struct pci_device *pci ) { - - long addr; - int using_dac = 0; - - if (pci->ioaddr == 0) - return 0; - - printf("ns83820.c: Found %s, vendor=0x%hX, device=0x%hX\n", - pci->id->name, pci->vendor, pci->device); - - /* point to private storage */ - ns = &nsx; - - adjust_pci_device(pci); - - addr = pci_bar_start(pci, PCI_BASE_ADDRESS_1); - - ns->base = ioremap(addr, (1UL << 12)); - - if (!ns->base) - return 0; - - nic->irqno = 0; - nic->ioaddr = pci->ioaddr & ~3; - - /* disable interrupts */ - writel(0, ns->base + IMR); - writel(0, ns->base + IER); - readl(ns->base + IER); - - ns->IMR_cache = 0; - - ns83820_do_reset(nic, CR_RST); - - /* Must reset the ram bist before running it */ - writel(PTSCR_RBIST_RST, ns->base + PTSCR); - ns83820_run_bist(nic, "sram bist", PTSCR_RBIST_EN, - PTSCR_RBIST_DONE, PTSCR_RBIST_FAIL); - ns83820_run_bist(nic, "eeprom bist", PTSCR_EEBIST_EN, 0, - PTSCR_EEBIST_FAIL); - ns83820_run_bist(nic, "eeprom load", PTSCR_EELOAD_EN, 0, 0); - - /* I love config registers */ - ns->CFG_cache = readl(ns->base + CFG); - - if ((ns->CFG_cache & CFG_PCI64_DET)) { - printf("%s: detected 64 bit PCI data bus.\n", pci->id->name); - /*dev->CFG_cache |= CFG_DATA64_EN; */ - if (!(ns->CFG_cache & CFG_DATA64_EN)) - printf - ("%s: EEPROM did not enable 64 bit bus. Disabled.\n", - pci->id->name); - } else - ns->CFG_cache &= ~(CFG_DATA64_EN); - - ns->CFG_cache &= (CFG_TBI_EN | CFG_MRM_DIS | CFG_MWI_DIS | - CFG_T64ADDR | CFG_DATA64_EN | CFG_EXT_125 | - CFG_M64ADDR); - ns->CFG_cache |= - CFG_PINT_DUPSTS | CFG_PINT_LNKSTS | CFG_PINT_SPDSTS | - CFG_EXTSTS_EN | CFG_EXD | CFG_PESEL; - ns->CFG_cache |= CFG_REQALG; - ns->CFG_cache |= CFG_POW; - ns->CFG_cache |= CFG_TMRTEST; - - /* When compiled with 64 bit addressing, we must always enable - * the 64 bit descriptor format. - */ -#ifdef USE_64BIT_ADDR - ns->CFG_cache |= CFG_M64ADDR; -#endif - -//FIXME: Enable section on dac or remove this - if (using_dac) - ns->CFG_cache |= CFG_T64ADDR; - - /* Big endian mode does not seem to do what the docs suggest */ - ns->CFG_cache &= ~CFG_BEM; - - /* setup optical transceiver if we have one */ - if (ns->CFG_cache & CFG_TBI_EN) { - DBG("%s: enabling optical transceiver\n", pci->id->name); - writel(readl(ns->base + GPIOR) | 0x3e8, ns->base + GPIOR); - - /* setup auto negotiation feature advertisement */ - writel(readl(ns->base + TANAR) - | TANAR_HALF_DUP | TANAR_FULL_DUP, - ns->base + TANAR); - - /* start auto negotiation */ - writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN, - ns->base + TBICR); - writel(TBICR_MR_AN_ENABLE, ns->base + TBICR); - ns->linkstate = LINK_AUTONEGOTIATE; - - ns->CFG_cache |= CFG_MODE_1000; - } - writel(ns->CFG_cache, ns->base + CFG); - DBG("CFG: %hX\n", ns->CFG_cache); - - /* FIXME: reset_phy is defaulted to 0, should we reset anyway? */ - if (reset_phy) { - DBG("%s: resetting phy\n", pci->id->name); - writel(ns->CFG_cache | CFG_PHY_RST, ns->base + CFG); - writel(ns->CFG_cache, ns->base + CFG); - } -#if 0 /* Huh? This sets the PCI latency register. Should be done via - * the PCI layer. FIXME. - */ - if (readl(dev->base + SRR)) - writel(readl(dev->base + 0x20c) | 0xfe00, - dev->base + 0x20c); -#endif - - /* Note! The DMA burst size interacts with packet - * transmission, such that the largest packet that - * can be transmitted is 8192 - FLTH - burst size. - * If only the transmit fifo was larger... - */ - /* Ramit : 1024 DMA is not a good idea, it ends up banging - * some DELL and COMPAQ SMP systems */ - writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512 - | ((1600 / 32) * 0x100), ns->base + TXCFG); - - /* Set Rx to full duplex, don't accept runt, errored, long or length - * range errored packets. Use 512 byte DMA. - */ - /* Ramit : 1024 DMA is not a good idea, it ends up banging - * some DELL and COMPAQ SMP systems - * Turn on ALP, only we are accpeting Jumbo Packets */ - writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD - | RXCFG_STRIPCRC - //| RXCFG_ALP - | (RXCFG_MXDMA512) | 0, ns->base + RXCFG); - - /* Disable priority queueing */ - writel(0, ns->base + PQCR); - - /* Enable IP checksum validation and detetion of VLAN headers. - * Note: do not set the reject options as at least the 0x102 - * revision of the chip does not properly accept IP fragments - * at least for UDP. - */ - /* Ramit : Be sure to turn on RXCFG_ARP if VLAN's are enabled, since - * the MAC it calculates the packetsize AFTER stripping the VLAN - * header, and if a VLAN Tagged packet of 64 bytes is received (like - * a ping with a VLAN header) then the card, strips the 4 byte VLAN - * tag and then checks the packet size, so if RXCFG_ARP is not enabled, - * it discrards it!. These guys...... - */ - writel(VRCR_IPEN | VRCR_VTDEN, ns->base + VRCR); - - /* Enable per-packet TCP/UDP/IP checksumming */ - writel(VTCR_PPCHK, ns->base + VTCR); - - /* Ramit : Enable async and sync pause frames */ -// writel(0, ns->base + PCR); - writel((PCR_PS_MCAST | PCR_PS_DA | PCR_PSEN | PCR_FFLO_4K | - PCR_FFHI_8K | PCR_STLO_4 | PCR_STHI_8 | PCR_PAUSE_CNT), - ns->base + PCR); - - /* Disable Wake On Lan */ - writel(0, ns->base + WCSR); - - ns83820_getmac(nic, nic->node_addr); - - if (using_dac) { - DBG("%s: using 64 bit addressing.\n", pci->id->name); - } - - DBG("%s: DP83820 %d.%d: io=%#04lx\n", - pci->id->name, - (unsigned) readl(ns->base + SRR) >> 8, - (unsigned) readl(ns->base + SRR) & 0xff, - pci->ioaddr); - -#ifdef PHY_CODE_IS_FINISHED - ns83820_probe_phy(dev); -#endif - - ns83820_reset(nic); - /* point to NIC specific routines */ - nic->nic_op = &ns83820_operations; - return 1; -} - -DRIVER ( "NS83820/PCI", nic_driver, pci_driver, ns83820_driver, - ns83820_probe, ns83820_disable ); - -/* - * Local variables: - * c-basic-offset: 8 - * c-indent-level: 8 - * tab-width: 8 - * End: - */ diff --git a/src/include/ipxe/threewire.h b/src/include/ipxe/threewire.h index 135ef56a..b5513ecd 100644 --- a/src/include/ipxe/threewire.h +++ b/src/include/ipxe/threewire.h @@ -61,6 +61,19 @@ init_at93cx6 ( struct spi_device *device, unsigned int organisation ) { device->nvs.write = threewire_write; } +/** + * Initialise Atmel AT93C06 serial EEPROM + * + * @v device SPI device + * @v organisation Word organisation (8 or 16) + */ +static inline __attribute__ (( always_inline )) void +init_at93c06 ( struct spi_device *device, unsigned int organisation ) { + device->nvs.size = ( 256 / organisation ); + device->address_len = ( ( organisation == 8 ) ? 7 : 6 ); + init_at93cx6 ( device, organisation ); +} + /** * Initialise Atmel AT93C46 serial EEPROM * From 35e09c1a7c52da2d85bd0be05765614e7474b271 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 27 Apr 2012 01:18:19 +0100 Subject: [PATCH 193/221] [natsemi] Fix test for addresses below 4GB Signed-off-by: Michael Brown --- src/drivers/net/natsemi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/drivers/net/natsemi.h b/src/drivers/net/natsemi.h index e3444712..7e8d6f80 100644 --- a/src/drivers/net/natsemi.h +++ b/src/drivers/net/natsemi.h @@ -319,8 +319,8 @@ natsemi_address_ok ( struct natsemi_nic *natsemi, physaddr_t address ) { if ( natsemi->flags & NATSEMI_64BIT ) return 1; - /* A 32-bit card can access all address below 4GB */ - if ( ( address & 0xffffffffUL ) == 0 ) + /* A 32-bit card can access all addresses below 4GB */ + if ( ( address & ~0xffffffffULL ) == 0 ) return 1; return 0; From 1fe27a3e0e774d319a1bf3ecefb40590c660cf8d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 26 Apr 2012 22:10:54 +0100 Subject: [PATCH 194/221] [myson] Replace driver for Myson Technology NICs Signed-off-by: Michael Brown --- src/drivers/net/mtd80x.c | 1022 ------------------------------------ src/drivers/net/myson.c | 668 +++++++++++++++++++++++ src/drivers/net/myson.h | 200 +++++++ src/include/ipxe/errfile.h | 1 + 4 files changed, 869 insertions(+), 1022 deletions(-) delete mode 100644 src/drivers/net/mtd80x.c create mode 100644 src/drivers/net/myson.c create mode 100644 src/drivers/net/myson.h diff --git a/src/drivers/net/mtd80x.c b/src/drivers/net/mtd80x.c deleted file mode 100644 index 170b5c52..00000000 --- a/src/drivers/net/mtd80x.c +++ /dev/null @@ -1,1022 +0,0 @@ -/************************************************************************** -* -* mtd80x.c: Etherboot device driver for the mtd80x Ethernet chip. -* Written 2004-2004 by Erdem Güven -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -* Portions of this code based on: -* fealnx.c: A Linux device driver for the mtd80x Ethernet chip -* Written 1998-2000 by Donald Becker -* -***************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -/* to get some global routines like printf */ -#include "etherboot.h" -/* to get the interface to the body of the program */ -#include "nic.h" -/* to get the PCI support functions, if this is a PCI NIC */ -#include -#include -#include - -/* Condensed operations for readability. */ -#define virt_to_le32desc(addr) cpu_to_le32(virt_to_bus(addr)) -#define le32desc_to_virt(addr) bus_to_virt(le32_to_cpu(addr)) -#define get_unaligned(ptr) (*(ptr)) - - -/* Operational parameters that are set at compile time. */ - -/* Keep the ring sizes a power of two for compile efficiency. */ -/* The compiler will convert '%'<2^N> into a bit mask. */ -/* Making the Tx ring too large decreases the effectiveness of channel */ -/* bonding and packet priority. */ -/* There are no ill effects from too-large receive rings. */ -#define TX_RING_SIZE 2 -#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */ -#define RX_RING_SIZE 4 - -/* Operational parameters that usually are not changed. */ -/* Time in jiffies before concluding the transmitter is hung. */ -#define HZ 100 -#define TX_TIME_OUT (6*HZ) - -/* Allocation size of Rx buffers with normal sized Ethernet frames. - Do not change this value without good reason. This is not a limit, - but a way to keep a consistent allocation size among drivers. - */ -#define PKT_BUF_SZ 1536 - -/* for different PHY */ -enum phy_type_flags { - MysonPHY = 1, - AhdocPHY = 2, - SeeqPHY = 3, - MarvellPHY = 4, - Myson981 = 5, - LevelOnePHY = 6, - OtherPHY = 10, -}; - -/* A chip capabilities table*/ -enum chip_capability_flags { - HAS_MII_XCVR, - HAS_CHIP_XCVR, -}; - -#if 0 /* not used */ -static -struct chip_info -{ - u16 dev_id; - int flag; -} -mtd80x_chips[] = { - {0x0800, HAS_MII_XCVR}, - {0x0803, HAS_CHIP_XCVR}, - {0x0891, HAS_MII_XCVR} - }; -static int chip_cnt = sizeof( mtd80x_chips ) / sizeof( struct chip_info ); -#endif - -/* Offsets to the Command and Status Registers. */ -enum mtd_offsets { - PAR0 = 0x0, /* physical address 0-3 */ - PAR1 = 0x04, /* physical address 4-5 */ - MAR0 = 0x08, /* multicast address 0-3 */ - MAR1 = 0x0C, /* multicast address 4-7 */ - FAR0 = 0x10, /* flow-control address 0-3 */ - FAR1 = 0x14, /* flow-control address 4-5 */ - TCRRCR = 0x18, /* receive & transmit configuration */ - BCR = 0x1C, /* bus command */ - TXPDR = 0x20, /* transmit polling demand */ - RXPDR = 0x24, /* receive polling demand */ - RXCWP = 0x28, /* receive current word pointer */ - TXLBA = 0x2C, /* transmit list base address */ - RXLBA = 0x30, /* receive list base address */ - ISR = 0x34, /* interrupt status */ - IMR = 0x38, /* interrupt mask */ - FTH = 0x3C, /* flow control high/low threshold */ - MANAGEMENT = 0x40, /* bootrom/eeprom and mii management */ - TALLY = 0x44, /* tally counters for crc and mpa */ - TSR = 0x48, /* tally counter for transmit status */ - BMCRSR = 0x4c, /* basic mode control and status */ - PHYIDENTIFIER = 0x50, /* phy identifier */ - ANARANLPAR = 0x54, /* auto-negotiation advertisement and link - partner ability */ - ANEROCR = 0x58, /* auto-negotiation expansion and pci conf. */ - BPREMRPSR = 0x5c, /* bypass & receive error mask and phy status */ -}; - -/* Bits in the interrupt status/enable registers. */ -/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */ -enum intr_status_bits { - RFCON = 0x00020000, /* receive flow control xon packet */ - RFCOFF = 0x00010000, /* receive flow control xoff packet */ - LSCStatus = 0x00008000, /* link status change */ - ANCStatus = 0x00004000, /* autonegotiation completed */ - FBE = 0x00002000, /* fatal bus error */ - FBEMask = 0x00001800, /* mask bit12-11 */ - ParityErr = 0x00000000, /* parity error */ - TargetErr = 0x00001000, /* target abort */ - MasterErr = 0x00000800, /* master error */ - TUNF = 0x00000400, /* transmit underflow */ - ROVF = 0x00000200, /* receive overflow */ - ETI = 0x00000100, /* transmit early int */ - ERI = 0x00000080, /* receive early int */ - CNTOVF = 0x00000040, /* counter overflow */ - RBU = 0x00000020, /* receive buffer unavailable */ - TBU = 0x00000010, /* transmit buffer unavilable */ - TI = 0x00000008, /* transmit interrupt */ - RI = 0x00000004, /* receive interrupt */ - RxErr = 0x00000002, /* receive error */ -}; - -/* Bits in the NetworkConfig register. */ -enum rx_mode_bits { - RxModeMask = 0xe0, - AcceptAllPhys = 0x80, /* promiscuous mode */ - AcceptBroadcast = 0x40, /* accept broadcast */ - AcceptMulticast = 0x20, /* accept mutlicast */ - AcceptRunt = 0x08, /* receive runt pkt */ - ALP = 0x04, /* receive long pkt */ - AcceptErr = 0x02, /* receive error pkt */ - - AcceptMyPhys = 0x00000000, - RxEnable = 0x00000001, - RxFlowCtrl = 0x00002000, - TxEnable = 0x00040000, - TxModeFDX = 0x00100000, - TxThreshold = 0x00e00000, - - PS1000 = 0x00010000, - PS10 = 0x00080000, - FD = 0x00100000, -}; - -/* Bits in network_desc.status */ -enum rx_desc_status_bits { - RXOWN = 0x80000000, /* own bit */ - FLNGMASK = 0x0fff0000, /* frame length */ - FLNGShift = 16, - MARSTATUS = 0x00004000, /* multicast address received */ - BARSTATUS = 0x00002000, /* broadcast address received */ - PHYSTATUS = 0x00001000, /* physical address received */ - RXFSD = 0x00000800, /* first descriptor */ - RXLSD = 0x00000400, /* last descriptor */ - ErrorSummary = 0x80, /* error summary */ - RUNT = 0x40, /* runt packet received */ - LONG = 0x20, /* long packet received */ - FAE = 0x10, /* frame align error */ - CRC = 0x08, /* crc error */ - RXER = 0x04, /* receive error */ -}; - -enum rx_desc_control_bits { - RXIC = 0x00800000, /* interrupt control */ - RBSShift = 0, -}; - -enum tx_desc_status_bits { - TXOWN = 0x80000000, /* own bit */ - JABTO = 0x00004000, /* jabber timeout */ - CSL = 0x00002000, /* carrier sense lost */ - LC = 0x00001000, /* late collision */ - EC = 0x00000800, /* excessive collision */ - UDF = 0x00000400, /* fifo underflow */ - DFR = 0x00000200, /* deferred */ - HF = 0x00000100, /* heartbeat fail */ - NCRMask = 0x000000ff, /* collision retry count */ - NCRShift = 0, -}; - -enum tx_desc_control_bits { - TXIC = 0x80000000, /* interrupt control */ - ETIControl = 0x40000000, /* early transmit interrupt */ - TXLD = 0x20000000, /* last descriptor */ - TXFD = 0x10000000, /* first descriptor */ - CRCEnable = 0x08000000, /* crc control */ - PADEnable = 0x04000000, /* padding control */ - RetryTxLC = 0x02000000, /* retry late collision */ - PKTSMask = 0x3ff800, /* packet size bit21-11 */ - PKTSShift = 11, - TBSMask = 0x000007ff, /* transmit buffer bit 10-0 */ - TBSShift = 0, -}; - -/* BootROM/EEPROM/MII Management Register */ -#define MASK_MIIR_MII_READ 0x00000000 -#define MASK_MIIR_MII_WRITE 0x00000008 -#define MASK_MIIR_MII_MDO 0x00000004 -#define MASK_MIIR_MII_MDI 0x00000002 -#define MASK_MIIR_MII_MDC 0x00000001 - -/* ST+OP+PHYAD+REGAD+TA */ -#define OP_READ 0x6000 /* ST:01+OP:10+PHYAD+REGAD+TA:Z0 */ -#define OP_WRITE 0x5002 /* ST:01+OP:01+PHYAD+REGAD+TA:10 */ - -/* ------------------------------------------------------------------------- */ -/* Constants for Myson PHY */ -/* ------------------------------------------------------------------------- */ -#define MysonPHYID 0xd0000302 -/* 89-7-27 add, (begin) */ -#define MysonPHYID0 0x0302 -#define StatusRegister 18 -#define SPEED100 0x0400 // bit10 -#define FULLMODE 0x0800 // bit11 -/* 89-7-27 add, (end) */ - -/* ------------------------------------------------------------------------- */ -/* Constants for Seeq 80225 PHY */ -/* ------------------------------------------------------------------------- */ -#define SeeqPHYID0 0x0016 - -#define MIIRegister18 18 -#define SPD_DET_100 0x80 -#define DPLX_DET_FULL 0x40 - -/* ------------------------------------------------------------------------- */ -/* Constants for Ahdoc 101 PHY */ -/* ------------------------------------------------------------------------- */ -#define AhdocPHYID0 0x0022 - -#define DiagnosticReg 18 -#define DPLX_FULL 0x0800 -#define Speed_100 0x0400 - -/* 89/6/13 add, */ -/* -------------------------------------------------------------------------- */ -/* Constants */ -/* -------------------------------------------------------------------------- */ -#define MarvellPHYID0 0x0141 -#define LevelOnePHYID0 0x0013 - -#define MII1000BaseTControlReg 9 -#define MII1000BaseTStatusReg 10 -#define SpecificReg 17 - -/* for 1000BaseT Control Register */ -#define PHYAbletoPerform1000FullDuplex 0x0200 -#define PHYAbletoPerform1000HalfDuplex 0x0100 -#define PHY1000AbilityMask 0x300 - -// for phy specific status register, marvell phy. -#define SpeedMask 0x0c000 -#define Speed_1000M 0x08000 -#define Speed_100M 0x4000 -#define Speed_10M 0 -#define Full_Duplex 0x2000 - -// 89/12/29 add, for phy specific status register, levelone phy, (begin) -#define LXT1000_100M 0x08000 -#define LXT1000_1000M 0x0c000 -#define LXT1000_Full 0x200 -// 89/12/29 add, for phy specific status register, levelone phy, (end) - -#if 0 -/* for 3-in-1 case */ -#define PS10 0x00080000 -#define FD 0x00100000 -#define PS1000 0x00010000 -#endif - -/* for PHY */ -#define LinkIsUp 0x0004 -#define LinkIsUp2 0x00040000 - -/* Create a static buffer of size PKT_BUF_SZ for each -RX and TX Descriptor. All descriptors point to a -part of this buffer */ -struct { - u8 txb[PKT_BUF_SZ * TX_RING_SIZE] __attribute__ ((aligned(8))); - u8 rxb[PKT_BUF_SZ * RX_RING_SIZE] __attribute__ ((aligned(8))); -} mtd80x_bufs __shared; -#define txb mtd80x_bufs.txb -#define rxb mtd80x_bufs.rxb - -/* The Tulip Rx and Tx buffer descriptors. */ -struct mtd_desc -{ - s32 status; - s32 control; - u32 buffer; - u32 next_desc; - struct mtd_desc *next_desc_logical; - u8* skbuff; - u32 reserved1; - u32 reserved2; -}; - -struct mtd_private -{ - struct mtd_desc rx_ring[RX_RING_SIZE]; - struct mtd_desc tx_ring[TX_RING_SIZE]; - - /* Frequently used values: keep some adjacent for cache effect. */ - int flags; - struct pci_dev *pci_dev; - unsigned long crvalue; - unsigned long bcrvalue; - /*unsigned long imrvalue;*/ - struct mtd_desc *cur_rx; - struct mtd_desc *lack_rxbuf; - int really_rx_count; - struct mtd_desc *cur_tx; - struct mtd_desc *cur_tx_copy; - int really_tx_count; - int free_tx_count; - unsigned int rx_buf_sz; /* Based on MTU+slack. */ - - /* These values are keep track of the transceiver/media in use. */ - unsigned int linkok; - unsigned int line_speed; - unsigned int duplexmode; - unsigned int default_port: - 4; /* Last dev->if_port value. */ - unsigned int PHYType; - - /* MII transceiver section. */ - int mii_cnt; /* MII device addresses. */ - unsigned char phys[1]; /* MII device addresses. */ - - /*other*/ - const char *nic_name; - int ioaddr; - u16 dev_id; -}; - -static struct mtd_private mtdx; - -static int mdio_read(struct nic * , int phy_id, int location); -static void getlinktype(struct nic * ); -static void getlinkstatus(struct nic * ); -static void set_rx_mode(struct nic *); - -/************************************************************************** - * init_ring - setup the tx and rx descriptors - *************************************************************************/ -static void init_ring(struct nic *nic __unused) -{ - int i; - - mtdx.cur_rx = &mtdx.rx_ring[0]; - - mtdx.rx_buf_sz = PKT_BUF_SZ; - /*mtdx.rx_head_desc = &mtdx.rx_ring[0];*/ - - /* Initialize all Rx descriptors. */ - /* Fill in the Rx buffers. Handle allocation failure gracefully. */ - for (i = 0; i < RX_RING_SIZE; i++) - { - mtdx.rx_ring[i].status = RXOWN; - mtdx.rx_ring[i].control = mtdx.rx_buf_sz << RBSShift; - mtdx.rx_ring[i].next_desc = virt_to_le32desc(&mtdx.rx_ring[i+1]); - mtdx.rx_ring[i].next_desc_logical = &mtdx.rx_ring[i+1]; - mtdx.rx_ring[i].buffer = virt_to_le32desc(&rxb[i * PKT_BUF_SZ]); - mtdx.rx_ring[i].skbuff = &rxb[i * PKT_BUF_SZ]; - } - /* Mark the last entry as wrapping the ring. */ - mtdx.rx_ring[i-1].next_desc = virt_to_le32desc(&mtdx.rx_ring[0]); - mtdx.rx_ring[i-1].next_desc_logical = &mtdx.rx_ring[0]; - - /* We only use one transmit buffer, but two - * descriptors so transmit engines have somewhere - * to point should they feel the need */ - mtdx.tx_ring[0].status = 0x00000000; - mtdx.tx_ring[0].buffer = virt_to_bus(&txb[0]); - mtdx.tx_ring[0].next_desc = virt_to_le32desc(&mtdx.tx_ring[1]); - - /* This descriptor is never used */ - mtdx.tx_ring[1].status = 0x00000000; - mtdx.tx_ring[1].buffer = 0; /*virt_to_bus(&txb[1]); */ - mtdx.tx_ring[1].next_desc = virt_to_le32desc(&mtdx.tx_ring[0]); - - return; -} - -/************************************************************************** -RESET - Reset Adapter -***************************************************************************/ -static void mtd_reset( struct nic *nic ) -{ - /* Reset the chip to erase previous misconfiguration. */ - outl(0x00000001, mtdx.ioaddr + BCR); - - init_ring(nic); - - outl(virt_to_bus(mtdx.rx_ring), mtdx.ioaddr + RXLBA); - outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA); - - /* Initialize other registers. */ - /* Configure the PCI bus bursts and FIFO thresholds. */ - mtdx.bcrvalue = 0x10; /* little-endian, 8 burst length */ - mtdx.crvalue = 0xa00; /* rx 128 burst length */ - - if ( mtdx.dev_id == 0x891 ) { - mtdx.bcrvalue |= 0x200; /* set PROG bit */ - mtdx.crvalue |= 0x02000000; /* set enhanced bit */ - } - - outl( mtdx.bcrvalue, mtdx.ioaddr + BCR); - - /* Restart Rx engine if stopped. */ - outl(0, mtdx.ioaddr + RXPDR); - - getlinkstatus(nic); - if (mtdx.linkok) - { - static const char* texts[]={"half","full","10","100","1000"}; - getlinktype(nic); - DBG ( "Link is OK : %s %s\n", texts[mtdx.duplexmode-1], texts[mtdx.line_speed+1] ); - } else - { - DBG ( "No link!!!\n" ); - } - - mtdx.crvalue |= /*TxEnable |*/ RxEnable | TxThreshold; - set_rx_mode(nic); - - /* Clear interrupts by setting the interrupt mask. */ - outl(FBE | TUNF | CNTOVF | RBU | TI | RI, mtdx.ioaddr + ISR); - outl( 0, mtdx.ioaddr + IMR); -} - -/************************************************************************** -POLL - Wait for a frame -***************************************************************************/ -static int mtd_poll(struct nic *nic, __unused int retrieve) -{ - s32 rx_status = mtdx.cur_rx->status; - int retval = 0; - - if( ( rx_status & RXOWN ) != 0 ) - { - return 0; - } - - if (rx_status & ErrorSummary) - { /* there was a fatal error */ - printf( "%s: Receive error, Rx status %8.8x, Error(s) %s%s%s\n", - mtdx.nic_name, (unsigned int) rx_status, - (rx_status & (LONG | RUNT)) ? "length_error ":"", - (rx_status & RXER) ? "frame_error ":"", - (rx_status & CRC) ? "crc_error ":"" ); - retval = 0; - } else if( !((rx_status & RXFSD) && (rx_status & RXLSD)) ) - { - /* this pkt is too long, over one rx buffer */ - printf("Pkt is too long, over one rx buffer.\n"); - retval = 0; - } else - { /* this received pkt is ok */ - /* Omit the four octet CRC from the length. */ - short pkt_len = ((rx_status & FLNGMASK) >> FLNGShift) - 4; - - DBG ( " netdev_rx() normal Rx pkt length %d" - " status %x.\n", pkt_len, (unsigned int) rx_status ); - - nic->packetlen = pkt_len; - memcpy(nic->packet, mtdx.cur_rx->skbuff, pkt_len); - - retval = 1; - } - - while( ( mtdx.cur_rx->status & RXOWN ) == 0 ) - { - mtdx.cur_rx->status = RXOWN; - mtdx.cur_rx = mtdx.cur_rx->next_desc_logical; - } - - /* Restart Rx engine if stopped. */ - outl(0, mtdx.ioaddr + RXPDR); - - return retval; -} - -/************************************************************************** -TRANSMIT - Transmit a frame -***************************************************************************/ -static void mtd_transmit( - struct nic *nic, - const char *dest, /* Destination */ - unsigned int type, /* Type */ - unsigned int size, /* size */ - const char *data) /* Packet */ -{ - u32 to; - u32 tx_status; - unsigned int nstype = htons ( type ); - - memcpy( txb, dest, ETH_ALEN ); - memcpy( txb + ETH_ALEN, nic->node_addr, ETH_ALEN ); - memcpy( txb + 2 * ETH_ALEN, &nstype, 2 ); - memcpy( txb + ETH_HLEN, data, size ); - - size += ETH_HLEN; - size &= 0x0FFF; - while( size < ETH_ZLEN ) - { - txb[size++] = '\0'; - } - - mtdx.tx_ring[0].control = TXLD | TXFD | CRCEnable | PADEnable; - mtdx.tx_ring[0].control |= (size << PKTSShift); /* pkt size */ - mtdx.tx_ring[0].control |= (size << TBSShift); /* buffer size */ - mtdx.tx_ring[0].status = TXOWN; - - /* Point to transmit descriptor */ - outl(virt_to_bus(mtdx.tx_ring), mtdx.ioaddr + TXLBA); - /* Enable Tx */ - outl( mtdx.crvalue | TxEnable, mtdx.ioaddr + TCRRCR); - /* Wake the potentially-idle transmit channel. */ - outl(0, mtdx.ioaddr + TXPDR); - - to = currticks() + TX_TIME_OUT; - while(( mtdx.tx_ring[0].status & TXOWN) && (currticks() < to)); - - /* Disable Tx */ - outl( mtdx.crvalue & (~TxEnable), mtdx.ioaddr + TCRRCR); - - tx_status = mtdx.tx_ring[0].status; - if (currticks() >= to){ - DBG ( "TX Time Out" ); - } else if( tx_status & (CSL | LC | EC | UDF | HF)){ - printf( "Transmit error: %8.8x %s %s %s %s %s\n", - (unsigned int) tx_status, - tx_status & EC ? "abort" : "", - tx_status & CSL ? "carrier" : "", - tx_status & LC ? "late" : "", - tx_status & UDF ? "fifo" : "", - tx_status & HF ? "heartbeat" : "" ); - } - - /*hex_dump( txb, size );*/ - /*pause();*/ - - DBG ( "TRANSMIT\n" ); -} - -/************************************************************************** -DISABLE - Turn off ethernet interface -***************************************************************************/ -static void mtd_disable ( struct nic *nic ) { - - /* Disable Tx Rx*/ - outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR ); - - /* Reset the chip to erase previous misconfiguration. */ - mtd_reset(nic); - - DBG ( "DISABLE\n" ); -} - -static struct nic_operations mtd_operations = { - .connect = dummy_connect, - .poll = mtd_poll, - .transmit = mtd_transmit, - .irq = dummy_irq, - -}; - -static struct pci_device_id mtd80x_nics[] = { - PCI_ROM(0x1516, 0x0800, "MTD800", "Myson MTD800", 0), - PCI_ROM(0x1516, 0x0803, "MTD803", "Surecom EP-320X", 0), - PCI_ROM(0x1516, 0x0891, "MTD891", "Myson MTD891", 0), -}; - -PCI_DRIVER ( mtd80x_driver, mtd80x_nics, PCI_NO_CLASS ); - -/************************************************************************** -PROBE - Look for an adapter, this routine's visible to the outside -***************************************************************************/ - -static int mtd_probe ( struct nic *nic, struct pci_device *pci ) { - - int i; - - if (pci->ioaddr == 0) - return 0; - - adjust_pci_device(pci); - - nic->ioaddr = pci->ioaddr; - nic->irqno = 0; - - mtdx.nic_name = pci->id->name; - mtdx.dev_id = pci->device; - mtdx.ioaddr = nic->ioaddr; - - /* read ethernet id */ - for (i = 0; i < 6; ++i) - { - nic->node_addr[i] = inb(mtdx.ioaddr + PAR0 + i); - } - - if (memcmp(nic->node_addr, "\0\0\0\0\0\0", 6) == 0) - { - return 0; - } - - DBG ( "%s: ioaddr %4.4x MAC %s\n", mtdx.nic_name, mtdx.ioaddr, eth_ntoa ( nic->node_addr ) ); - - /* Reset the chip to erase previous misconfiguration. */ - outl(0x00000001, mtdx.ioaddr + BCR); - - /* find the connected MII xcvrs */ - - if( mtdx.dev_id != 0x803 ) - { - int phy, phy_idx = 0; - - for (phy = 1; phy < 32 && phy_idx < 1; phy++) { - int mii_status = mdio_read(nic, phy, 1); - - if (mii_status != 0xffff && mii_status != 0x0000) { - mtdx.phys[phy_idx] = phy; - - DBG ( "%s: MII PHY found at address %d, status " - "0x%4.4x.\n", mtdx.nic_name, phy, mii_status ); - /* get phy type */ - { - unsigned int data; - - data = mdio_read(nic, mtdx.phys[phy_idx], 2); - if (data == SeeqPHYID0) - mtdx.PHYType = SeeqPHY; - else if (data == AhdocPHYID0) - mtdx.PHYType = AhdocPHY; - else if (data == MarvellPHYID0) - mtdx.PHYType = MarvellPHY; - else if (data == MysonPHYID0) - mtdx.PHYType = Myson981; - else if (data == LevelOnePHYID0) - mtdx.PHYType = LevelOnePHY; - else - mtdx.PHYType = OtherPHY; - } - phy_idx++; - } - } - - mtdx.mii_cnt = phy_idx; - if (phy_idx == 0) { - printf("%s: MII PHY not found -- this device may " - "not operate correctly.\n", mtdx.nic_name); - } - } else { - mtdx.phys[0] = 32; - /* get phy type */ - if (inl(mtdx.ioaddr + PHYIDENTIFIER) == MysonPHYID ) { - mtdx.PHYType = MysonPHY; - DBG ( "MysonPHY\n" ); - } else { - mtdx.PHYType = OtherPHY; - DBG ( "OtherPHY\n" ); - } - } - - getlinkstatus(nic); - if( !mtdx.linkok ) - { - printf("No link!!!\n"); - return 0; - } - - mtd_reset( nic ); - - /* point to NIC specific routines */ - nic->nic_op = &mtd_operations; - return 1; -} - - -/**************************************************************************/ -static void set_rx_mode(struct nic *nic __unused) -{ - u32 mc_filter[2]; /* Multicast hash filter */ - u32 rx_mode; - - /* Too many to match, or accept all multicasts. */ - mc_filter[1] = mc_filter[0] = ~0; - rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; - - outl(mc_filter[0], mtdx.ioaddr + MAR0); - outl(mc_filter[1], mtdx.ioaddr + MAR1); - - mtdx.crvalue = ( mtdx.crvalue & ~RxModeMask ) | rx_mode; - outb( mtdx.crvalue, mtdx.ioaddr + TCRRCR); -} -/**************************************************************************/ -static unsigned int m80x_read_tick(void) -/* function: Reads the Timer tick count register which decrements by 2 from */ -/* 65536 to 0 every 1/36.414 of a second. Each 2 decrements of the */ -/* count represents 838 nsec's. */ -/* input : none. */ -/* output : none. */ -{ - unsigned char tmp; - int value; - - outb((char) 0x06, 0x43); // Command 8254 to latch T0's count - - // now read the count. - tmp = (unsigned char) inb(0x40); - value = ((int) tmp) << 8; - tmp = (unsigned char) inb(0x40); - value |= (((int) tmp) & 0xff); - return (value); -} - -static void m80x_delay(unsigned int interval) -/* function: to wait for a specified time. */ -/* input : interval ... the specified time. */ -/* output : none. */ -{ - unsigned int interval1, interval2, i = 0; - - interval1 = m80x_read_tick(); // get initial value - do - { - interval2 = m80x_read_tick(); - if (interval1 < interval2) - interval1 += 65536; - ++i; - } while (((interval1 - interval2) < (u16) interval) && (i < 65535)); -} - - -static u32 m80x_send_cmd_to_phy(long miiport, int opcode, int phyad, int regad) -{ - u32 miir; - int i; - unsigned int mask, data; - - /* enable MII output */ - miir = (u32) inl(miiport); - miir &= 0xfffffff0; - - miir |= MASK_MIIR_MII_WRITE + MASK_MIIR_MII_MDO; - - /* send 32 1's preamble */ - for (i = 0; i < 32; i++) { - /* low MDC; MDO is already high (miir) */ - miir &= ~MASK_MIIR_MII_MDC; - outl(miir, miiport); - - /* high MDC */ - miir |= MASK_MIIR_MII_MDC; - outl(miir, miiport); - } - - /* calculate ST+OP+PHYAD+REGAD+TA */ - data = opcode | (phyad << 7) | (regad << 2); - - /* sent out */ - mask = 0x8000; - while (mask) { - /* low MDC, prepare MDO */ - miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); - if (mask & data) - miir |= MASK_MIIR_MII_MDO; - - outl(miir, miiport); - /* high MDC */ - miir |= MASK_MIIR_MII_MDC; - outl(miir, miiport); - m80x_delay(30); - - /* next */ - mask >>= 1; - if (mask == 0x2 && opcode == OP_READ) - miir &= ~MASK_MIIR_MII_WRITE; - } - return miir; -} - -static int mdio_read(struct nic *nic __unused, int phyad, int regad) -{ - long miiport = mtdx.ioaddr + MANAGEMENT; - u32 miir; - unsigned int mask, data; - - miir = m80x_send_cmd_to_phy(miiport, OP_READ, phyad, regad); - - /* read data */ - mask = 0x8000; - data = 0; - while (mask) - { - /* low MDC */ - miir &= ~MASK_MIIR_MII_MDC; - outl(miir, miiport); - - /* read MDI */ - miir = inl(miiport); - if (miir & MASK_MIIR_MII_MDI) - data |= mask; - - /* high MDC, and wait */ - miir |= MASK_MIIR_MII_MDC; - outl(miir, miiport); - m80x_delay((int) 30); - - /* next */ - mask >>= 1; - } - - /* low MDC */ - miir &= ~MASK_MIIR_MII_MDC; - outl(miir, miiport); - - return data & 0xffff; -} - -#if 0 /* not used */ -static void mdio_write(struct nic *nic __unused, int phyad, int regad, - int data) -{ - long miiport = mtdx.ioaddr + MANAGEMENT; - u32 miir; - unsigned int mask; - - miir = m80x_send_cmd_to_phy(miiport, OP_WRITE, phyad, regad); - - /* write data */ - mask = 0x8000; - while (mask) - { - /* low MDC, prepare MDO */ - miir &= ~(MASK_MIIR_MII_MDC + MASK_MIIR_MII_MDO); - if (mask & data) - miir |= MASK_MIIR_MII_MDO; - outl(miir, miiport); - - /* high MDC */ - miir |= MASK_MIIR_MII_MDC; - outl(miir, miiport); - - /* next */ - mask >>= 1; - } - - /* low MDC */ - miir &= ~MASK_MIIR_MII_MDC; - outl(miir, miiport); - - return; -} -#endif - -static void getlinkstatus(struct nic *nic) -/* function: Routine will read MII Status Register to get link status. */ -/* input : dev... pointer to the adapter block. */ -/* output : none. */ -{ - unsigned int i, DelayTime = 0x1000; - - mtdx.linkok = 0; - - if (mtdx.PHYType == MysonPHY) - { - for (i = 0; i < DelayTime; ++i) { - if (inl(mtdx.ioaddr + BMCRSR) & LinkIsUp2) { - mtdx.linkok = 1; - return; - } - // delay - m80x_delay(100); - } - } else - { - for (i = 0; i < DelayTime; ++i) { - if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) { - mtdx.linkok = 1; - return; - } - // delay - m80x_delay(100); - } - } -} - - -static void getlinktype(struct nic *dev) -{ - if (mtdx.PHYType == MysonPHY) - { /* 3-in-1 case */ - if (inl(mtdx.ioaddr + TCRRCR) & FD) - mtdx.duplexmode = 2; /* full duplex */ - else - mtdx.duplexmode = 1; /* half duplex */ - if (inl(mtdx.ioaddr + TCRRCR) & PS10) - mtdx.line_speed = 1; /* 10M */ - else - mtdx.line_speed = 2; /* 100M */ - } else - { - if (mtdx.PHYType == SeeqPHY) { /* this PHY is SEEQ 80225 */ - unsigned int data; - - data = mdio_read(dev, mtdx.phys[0], MIIRegister18); - if (data & SPD_DET_100) - mtdx.line_speed = 2; /* 100M */ - else - mtdx.line_speed = 1; /* 10M */ - if (data & DPLX_DET_FULL) - mtdx.duplexmode = 2; /* full duplex mode */ - else - mtdx.duplexmode = 1; /* half duplex mode */ - } else if (mtdx.PHYType == AhdocPHY) { - unsigned int data; - - data = mdio_read(dev, mtdx.phys[0], DiagnosticReg); - if (data & Speed_100) - mtdx.line_speed = 2; /* 100M */ - else - mtdx.line_speed = 1; /* 10M */ - if (data & DPLX_FULL) - mtdx.duplexmode = 2; /* full duplex mode */ - else - mtdx.duplexmode = 1; /* half duplex mode */ - } - /* 89/6/13 add, (begin) */ - else if (mtdx.PHYType == MarvellPHY) { - unsigned int data; - - data = mdio_read(dev, mtdx.phys[0], SpecificReg); - if (data & Full_Duplex) - mtdx.duplexmode = 2; /* full duplex mode */ - else - mtdx.duplexmode = 1; /* half duplex mode */ - data &= SpeedMask; - if (data == Speed_1000M) - mtdx.line_speed = 3; /* 1000M */ - else if (data == Speed_100M) - mtdx.line_speed = 2; /* 100M */ - else - mtdx.line_speed = 1; /* 10M */ - } - /* 89/6/13 add, (end) */ - /* 89/7/27 add, (begin) */ - else if (mtdx.PHYType == Myson981) { - unsigned int data; - - data = mdio_read(dev, mtdx.phys[0], StatusRegister); - - if (data & SPEED100) - mtdx.line_speed = 2; - else - mtdx.line_speed = 1; - - if (data & FULLMODE) - mtdx.duplexmode = 2; - else - mtdx.duplexmode = 1; - } - /* 89/7/27 add, (end) */ - /* 89/12/29 add */ - else if (mtdx.PHYType == LevelOnePHY) { - unsigned int data; - - data = mdio_read(dev, mtdx.phys[0], SpecificReg); - if (data & LXT1000_Full) - mtdx.duplexmode = 2; /* full duplex mode */ - else - mtdx.duplexmode = 1; /* half duplex mode */ - data &= SpeedMask; - if (data == LXT1000_1000M) - mtdx.line_speed = 3; /* 1000M */ - else if (data == LXT1000_100M) - mtdx.line_speed = 2; /* 100M */ - else - mtdx.line_speed = 1; /* 10M */ - } - // chage crvalue - // mtdx.crvalue&=(~PS10)&(~FD); - mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000); - if (mtdx.line_speed == 1) - mtdx.crvalue |= PS10; - else if (mtdx.line_speed == 3) - mtdx.crvalue |= PS1000; - if (mtdx.duplexmode == 2) - mtdx.crvalue |= FD; - } -} - -DRIVER ( "MTD80X", nic_driver, pci_driver, mtd80x_driver, - mtd_probe, mtd_disable ); diff --git a/src/drivers/net/myson.c b/src/drivers/net/myson.c new file mode 100644 index 00000000..25f1a270 --- /dev/null +++ b/src/drivers/net/myson.c @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2012 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "myson.h" + +/** @file + * + * Myson Technology network card driver + * + */ + +/****************************************************************************** + * + * Device reset + * + ****************************************************************************** + */ + +/** + * Reset controller chip + * + * @v myson Myson device + * @ret rc Return status code + */ +static int myson_soft_reset ( struct myson_nic *myson ) { + uint32_t bcr; + unsigned int i; + + /* Initiate reset */ + bcr = readl ( myson->regs + MYSON_BCR ); + writel ( ( bcr | MYSON_BCR_SWR ), myson->regs + MYSON_BCR ); + + /* Wait for reset to complete */ + for ( i = 0 ; i < MYSON_RESET_MAX_WAIT_MS ; i++ ) { + + /* If reset is not complete, delay 1ms and retry */ + if ( readl ( myson->regs + MYSON_BCR ) & MYSON_BCR_SWR ) { + mdelay ( 1 ); + continue; + } + + /* Apply a sensible default bus configuration */ + bcr = readl ( myson->regs + MYSON_BCR ); + bcr &= ~MYSON_BCR_PBL_MASK; + bcr |= ( MYSON_BCR_RLE | MYSON_BCR_RME | MYSON_BCR_WIE | + MYSON_BCR_PBL_DEFAULT ); + writel ( bcr, myson->regs + MYSON_BCR ); + DBGC ( myson, "MYSON %p using configuration %08x\n", + myson, bcr ); + + return 0; + } + + DBGC ( myson, "MYSON %p timed out waiting for reset\n", myson ); + return -ETIMEDOUT; +} + +/** + * Reload configuration from EEPROM + * + * @v myson Myson device + * @ret rc Return status code + */ +static int myson_reload_config ( struct myson_nic *myson ) { + unsigned int i; + + /* Initiate reload */ + writel ( MYSON_ROM_AUTOLD, myson->regs + MYSON_ROM_MII ); + + /* Wait for reload to complete */ + for ( i = 0 ; i < MYSON_AUTOLD_MAX_WAIT_MS ; i++ ) { + + /* If reload is not complete, delay 1ms and retry */ + if ( readl ( myson->regs + MYSON_ROM_MII ) & MYSON_ROM_AUTOLD ){ + mdelay ( 1 ); + continue; + } + + return 0; + } + + DBGC ( myson, "MYSON %p timed out waiting for configuration " + "reload\n", myson ); + return -ETIMEDOUT; +} + +/** + * Reset hardware + * + * @v myson Myson device + * @ret rc Return status code + */ +static int myson_reset ( struct myson_nic *myson ) { + int rc; + + /* Disable all interrupts */ + writel ( 0, myson->regs + MYSON_IMR ); + + /* Perform soft reset */ + if ( ( rc = myson_soft_reset ( myson ) ) != 0 ) + return rc; + + /* Reload configuration from EEPROM */ + if ( ( rc = myson_reload_config ( myson ) ) != 0 ) + return rc; + + return 0; +} + +/****************************************************************************** + * + * Network device interface + * + ****************************************************************************** + */ + +/** + * Create descriptor ring + * + * @v myson Myson device + * @v ring Descriptor ring + * @ret rc Return status code + */ +static int myson_create_ring ( struct myson_nic *myson, + struct myson_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + struct myson_descriptor *desc; + struct myson_descriptor *next; + physaddr_t address; + unsigned int i; + int rc; + + /* Allocate descriptor ring */ + ring->desc = malloc_dma ( len, MYSON_RING_ALIGN ); + if ( ! ring->desc ) { + rc = -ENOMEM; + goto err_alloc; + } + address = virt_to_bus ( ring->desc ); + + /* Check address is usable by card */ + if ( ! myson_address_ok ( address + len ) ) { + DBGC ( myson, "MYSON %p cannot support 64-bit ring address\n", + myson ); + rc = -ENOTSUP; + goto err_64bit; + } + + /* Initialise descriptor ring */ + memset ( ring->desc, 0, len ); + for ( i = 0 ; i < ring->count ; i++ ) { + desc = &ring->desc[i]; + next = &ring->desc[ ( i + 1 ) % ring->count ]; + desc->next = cpu_to_le32 ( virt_to_bus ( next ) ); + } + + /* Program ring address */ + writel ( address, myson->regs + ring->reg ); + DBGC ( myson, "MYSON %p ring %02x is at [%08llx,%08llx)\n", + myson, ring->reg, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + len ) ); + + return 0; + + err_64bit: + free_dma ( ring->desc, len ); + ring->desc = NULL; + err_alloc: + return rc; +} + +/** + * Destroy descriptor ring + * + * @v myson Myson device + * @v ring Descriptor ring + */ +static void myson_destroy_ring ( struct myson_nic *myson, + struct myson_ring *ring ) { + size_t len = ( ring->count * sizeof ( ring->desc[0] ) ); + + /* Clear ring address */ + writel ( 0, myson->regs + ring->reg ); + + /* Free descriptor ring */ + free_dma ( ring->desc, len ); + ring->desc = NULL; + ring->prod = 0; + ring->cons = 0; +} + +/** + * Refill receive descriptor ring + * + * @v netdev Network device + */ +static void myson_refill_rx ( struct net_device *netdev ) { + struct myson_nic *myson = netdev->priv; + struct myson_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + physaddr_t address; + + while ( ( myson->rx.prod - myson->rx.cons ) < MYSON_NUM_RX_DESC ) { + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( MYSON_RX_MAX_LEN ); + if ( ! iobuf ) { + /* Wait for next refill */ + return; + } + + /* Check address is usable by card */ + address = virt_to_bus ( iobuf->data ); + if ( ! myson_address_ok ( address ) ) { + DBGC ( myson, "MYSON %p cannot support 64-bit RX " + "buffer address\n", myson ); + netdev_rx_err ( netdev, iobuf, -ENOTSUP ); + return; + } + + /* Get next receive descriptor */ + rx_idx = ( myson->rx.prod++ % MYSON_NUM_RX_DESC ); + rx = &myson->rx.desc[rx_idx]; + + /* Populate receive descriptor */ + rx->address = cpu_to_le32 ( address ); + rx->control = + cpu_to_le32 ( MYSON_RX_CTRL_RBS ( MYSON_RX_MAX_LEN ) ); + wmb(); + rx->status = cpu_to_le32 ( MYSON_RX_STAT_OWN ); + wmb(); + + /* Record I/O buffer */ + assert ( myson->rx_iobuf[rx_idx] == NULL ); + myson->rx_iobuf[rx_idx] = iobuf; + + /* Notify card that there are descriptors available */ + writel ( 0, myson->regs + MYSON_RXPDR ); + + DBGC2 ( myson, "MYSON %p RX %d is [%llx,%llx)\n", myson, + rx_idx, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + MYSON_RX_MAX_LEN ) ); + } +} + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int myson_open ( struct net_device *netdev ) { + struct myson_nic *myson = netdev->priv; + union myson_physical_address mac; + int rc; + + /* Set MAC address */ + memset ( &mac, 0, sizeof ( mac ) ); + memcpy ( mac.raw, netdev->ll_addr, ETH_ALEN ); + writel ( le32_to_cpu ( mac.reg.low ), myson->regs + MYSON_PAR0 ); + writel ( le32_to_cpu ( mac.reg.high ), myson->regs + MYSON_PAR4 ); + + /* Create transmit descriptor ring */ + if ( ( rc = myson_create_ring ( myson, &myson->tx ) ) != 0 ) + goto err_create_tx; + + /* Create receive descriptor ring */ + if ( ( rc = myson_create_ring ( myson, &myson->rx ) ) != 0 ) + goto err_create_rx; + + /* Configure transmitter and receiver */ + writel ( ( MYSON_TCR_TE | MYSON_RCR_PROM | MYSON_RCR_AB | MYSON_RCR_AM | + MYSON_RCR_ARP | MYSON_RCR_ALP | MYSON_RCR_RE ), + myson->regs + MYSON_TCR_RCR ); + + /* Fill receive ring */ + myson_refill_rx ( netdev ); + + return 0; + + myson_destroy_ring ( myson, &myson->rx ); + err_create_rx: + myson_destroy_ring ( myson, &myson->tx ); + err_create_tx: + return rc; +} + +/** + * Wait for transmit and receive to become idle + * + * @v myson Myson device + * @ret rc Return status code + */ +static int myson_wait_idle ( struct myson_nic *myson ) { + uint32_t tcr_rcr; + unsigned int i; + + /* Wait for both transmit and receive to be idle */ + for ( i = 0 ; i < MYSON_IDLE_MAX_WAIT_MS ; i++ ) { + + /* If either process is running, delay 1ms and retry */ + tcr_rcr = readl ( myson->regs + MYSON_TCR_RCR ); + if ( tcr_rcr & ( MYSON_TCR_TXS | MYSON_RCR_RXS ) ) { + mdelay ( 1 ); + continue; + } + + return 0; + } + + DBGC ( myson, "MYSON %p timed out waiting for idle state (status " + "%08x)\n", myson, tcr_rcr ); + return -ETIMEDOUT; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void myson_close ( struct net_device *netdev ) { + struct myson_nic *myson = netdev->priv; + unsigned int i; + + /* Disable receiver and transmitter */ + writel ( 0, myson->regs + MYSON_TCR_RCR ); + + /* Allow time for receiver and transmitter to become idle */ + myson_wait_idle ( myson ); + + /* Destroy receive descriptor ring */ + myson_destroy_ring ( myson, &myson->rx ); + + /* Discard any unused receive buffers */ + for ( i = 0 ; i < MYSON_NUM_RX_DESC ; i++ ) { + if ( myson->rx_iobuf[i] ) + free_iob ( myson->rx_iobuf[i] ); + myson->rx_iobuf[i] = NULL; + } + + /* Destroy transmit descriptor ring */ + myson_destroy_ring ( myson, &myson->tx ); +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int myson_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + struct myson_nic *myson = netdev->priv; + struct myson_descriptor *tx; + unsigned int tx_idx; + physaddr_t address; + + /* Check address is usable by card */ + address = virt_to_bus ( iobuf->data ); + if ( ! myson_address_ok ( address ) ) { + DBGC ( myson, "MYSON %p cannot support 64-bit TX buffer " + "address\n", myson ); + return -ENOTSUP; + } + + /* Get next transmit descriptor */ + if ( ( myson->tx.prod - myson->tx.cons ) >= MYSON_NUM_TX_DESC ) { + DBGC ( myson, "MYSON %p out of transmit descriptors\n", + myson ); + return -ENOBUFS; + } + tx_idx = ( myson->tx.prod++ % MYSON_NUM_TX_DESC ); + tx = &myson->tx.desc[tx_idx]; + + /* Populate transmit descriptor */ + tx->address = cpu_to_le32 ( address ); + tx->control = cpu_to_le32 ( MYSON_TX_CTRL_IC | MYSON_TX_CTRL_LD | + MYSON_TX_CTRL_FD | MYSON_TX_CTRL_CRC | + MYSON_TX_CTRL_PAD | MYSON_TX_CTRL_RTLC | + MYSON_TX_CTRL_PKTS ( iob_len ( iobuf ) ) | + MYSON_TX_CTRL_TBS ( iob_len ( iobuf ) ) ); + wmb(); + tx->status = cpu_to_le32 ( MYSON_TX_STAT_OWN ); + wmb(); + + /* Notify card that there are packets ready to transmit */ + writel ( 0, myson->regs + MYSON_TXPDR ); + + DBGC2 ( myson, "MYSON %p TX %d is [%llx,%llx)\n", myson, tx_idx, + ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + iob_len ( iobuf ) ) ); + + return 0; +} + +/** + * Poll for completed packets + * + * @v netdev Network device + */ +static void myson_poll_tx ( struct net_device *netdev ) { + struct myson_nic *myson = netdev->priv; + struct myson_descriptor *tx; + unsigned int tx_idx; + + /* Check for completed packets */ + while ( myson->tx.cons != myson->tx.prod ) { + + /* Get next transmit descriptor */ + tx_idx = ( myson->tx.cons % MYSON_NUM_TX_DESC ); + tx = &myson->tx.desc[tx_idx]; + + /* Stop if descriptor is still in use */ + if ( tx->status & cpu_to_le32 ( MYSON_TX_STAT_OWN ) ) + return; + + /* Complete TX descriptor */ + if ( tx->status & cpu_to_le32 ( MYSON_TX_STAT_ABORT | + MYSON_TX_STAT_CSL ) ) { + DBGC ( myson, "MYSON %p TX %d completion error " + "(%08x)\n", myson, tx_idx, + le32_to_cpu ( tx->status ) ); + netdev_tx_complete_next_err ( netdev, -EIO ); + } else { + DBGC2 ( myson, "MYSON %p TX %d complete\n", + myson, tx_idx ); + netdev_tx_complete_next ( netdev ); + } + myson->tx.cons++; + } +} + +/** + * Poll for received packets + * + * @v netdev Network device + */ +static void myson_poll_rx ( struct net_device *netdev ) { + struct myson_nic *myson = netdev->priv; + struct myson_descriptor *rx; + struct io_buffer *iobuf; + unsigned int rx_idx; + size_t len; + + /* Check for received packets */ + while ( myson->rx.cons != myson->rx.prod ) { + + /* Get next receive descriptor */ + rx_idx = ( myson->rx.cons % MYSON_NUM_RX_DESC ); + rx = &myson->rx.desc[rx_idx]; + + /* Stop if descriptor is still in use */ + if ( rx->status & MYSON_RX_STAT_OWN ) + return; + + /* Populate I/O buffer */ + iobuf = myson->rx_iobuf[rx_idx]; + myson->rx_iobuf[rx_idx] = NULL; + len = MYSON_RX_STAT_FLNG ( le32_to_cpu ( rx->status ) ); + iob_put ( iobuf, len - 4 /* strip CRC */ ); + + /* Hand off to network stack */ + if ( rx->status & cpu_to_le32 ( MYSON_RX_STAT_ES ) ) { + DBGC ( myson, "MYSON %p RX %d error (length %zd, " + "status %08x)\n", myson, rx_idx, len, + le32_to_cpu ( rx->status ) ); + netdev_rx_err ( netdev, iobuf, -EIO ); + } else { + DBGC2 ( myson, "MYSON %p RX %d complete (length " + "%zd)\n", myson, rx_idx, len ); + netdev_rx ( netdev, iobuf ); + } + myson->rx.cons++; + } +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void myson_poll ( struct net_device *netdev ) { + struct myson_nic *myson = netdev->priv; + uint32_t isr; + unsigned int i; + + /* Polling the ISR seems to really upset this card; it ends up + * getting no useful PCI transfers done and, for some reason, + * flooding the network with invalid packets. Work around + * this by introducing deliberate delays between ISR reads. + */ + for ( i = 0 ; i < MYSON_ISR_IODELAY_COUNT ; i++ ) + iodelay(); + + /* Check for and acknowledge interrupts */ + isr = readl ( myson->regs + MYSON_ISR ); + if ( ! isr ) + return; + writel ( isr, myson->regs + MYSON_ISR ); + + /* Poll for TX completions, if applicable */ + if ( isr & MYSON_IRQ_TI ) + myson_poll_tx ( netdev ); + + /* Poll for RX completionsm, if applicable */ + if ( isr & MYSON_IRQ_RI ) + myson_poll_rx ( netdev ); + + /* Refill RX ring */ + myson_refill_rx ( netdev ); +} + +/** + * Enable or disable interrupts + * + * @v netdev Network device + * @v enable Interrupts should be enabled + */ +static void myson_irq ( struct net_device *netdev, int enable ) { + struct myson_nic *myson = netdev->priv; + uint32_t imr; + + imr = ( enable ? ( MYSON_IRQ_TI | MYSON_IRQ_RI ) : 0 ); + writel ( imr, myson->regs + MYSON_IMR ); +} + +/** Myson network device operations */ +static struct net_device_operations myson_operations = { + .open = myson_open, + .close = myson_close, + .transmit = myson_transmit, + .poll = myson_poll, + .irq = myson_irq, +}; + +/****************************************************************************** + * + * PCI interface + * + ****************************************************************************** + */ + +/** + * Probe PCI device + * + * @v pci PCI device + * @ret rc Return status code + */ +static int myson_probe ( struct pci_device *pci ) { + struct net_device *netdev; + struct myson_nic *myson; + union myson_physical_address mac; + int rc; + + /* Allocate and initialise net device */ + netdev = alloc_etherdev ( sizeof ( *myson ) ); + if ( ! netdev ) { + rc = -ENOMEM; + goto err_alloc; + } + netdev_init ( netdev, &myson_operations ); + myson = netdev->priv; + pci_set_drvdata ( pci, netdev ); + netdev->dev = &pci->dev; + memset ( myson, 0, sizeof ( *myson ) ); + myson_init_ring ( &myson->tx, MYSON_NUM_TX_DESC, MYSON_TXLBA ); + myson_init_ring ( &myson->rx, MYSON_NUM_RX_DESC, MYSON_RXLBA ); + + /* Fix up PCI device */ + adjust_pci_device ( pci ); + + /* Map registers */ + myson->regs = ioremap ( pci->membase, MYSON_BAR_SIZE ); + + /* Reset the NIC */ + if ( ( rc = myson_reset ( myson ) ) != 0 ) + goto err_reset; + + /* Read MAC address */ + mac.reg.low = cpu_to_le32 ( readl ( myson->regs + MYSON_PAR0 ) ); + mac.reg.high = cpu_to_le32 ( readl ( myson->regs + MYSON_PAR4 ) ); + memcpy ( netdev->hw_addr, mac.raw, ETH_ALEN ); + + /* Register network device */ + if ( ( rc = register_netdev ( netdev ) ) != 0 ) + goto err_register_netdev; + + /* Mark as link up; we don't yet handle link state */ + netdev_link_up ( netdev ); + + return 0; + + unregister_netdev ( netdev ); + err_register_netdev: + myson_reset ( myson ); + err_reset: + netdev_nullify ( netdev ); + netdev_put ( netdev ); + err_alloc: + return rc; +} + +/** + * Remove PCI device + * + * @v pci PCI device + */ +static void myson_remove ( struct pci_device *pci ) { + struct net_device *netdev = pci_get_drvdata ( pci ); + struct myson_nic *myson = netdev->priv; + + /* Unregister network device */ + unregister_netdev ( netdev ); + + /* Reset card */ + myson_reset ( myson ); + + /* Free network device */ + netdev_nullify ( netdev ); + netdev_put ( netdev ); +} + +/** Myson PCI device IDs */ +static struct pci_device_id myson_nics[] = { + PCI_ROM ( 0x1516, 0x0800, "mtd800", "MTD-8xx", 0 ), + PCI_ROM ( 0x1516, 0x0803, "mtd803", "Surecom EP-320X-S", 0 ), + PCI_ROM ( 0x1516, 0x0891, "mtd891", "MTD-8xx", 0 ), +}; + +/** Myson PCI driver */ +struct pci_driver myson_driver __pci_driver = { + .ids = myson_nics, + .id_count = ( sizeof ( myson_nics ) / sizeof ( myson_nics[0] ) ), + .probe = myson_probe, + .remove = myson_remove, +}; diff --git a/src/drivers/net/myson.h b/src/drivers/net/myson.h new file mode 100644 index 00000000..8d7cc585 --- /dev/null +++ b/src/drivers/net/myson.h @@ -0,0 +1,200 @@ +#ifndef _MYSON_H +#define _MYSON_H + +/** @file + * + * Myson Technology network card driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include + +/** BAR size */ +#define MYSON_BAR_SIZE 256 + +/** A packet descriptor */ +struct myson_descriptor { + /** Status */ + uint32_t status; + /** Control */ + uint32_t control; + /** Buffer start address */ + uint32_t address; + /** Next descriptor address */ + uint32_t next; +} __attribute__ (( packed )); + +/* Transmit status */ +#define MYSON_TX_STAT_OWN 0x80000000UL /**< Owner */ +#define MYSON_TX_STAT_ABORT 0x00002000UL /**< Abort */ +#define MYSON_TX_STAT_CSL 0x00001000UL /**< Carrier sense lost */ + +/* Transmit control */ +#define MYSON_TX_CTRL_IC 0x80000000UL /**< Interrupt control */ +#define MYSON_TX_CTRL_LD 0x20000000UL /**< Last descriptor */ +#define MYSON_TX_CTRL_FD 0x10000000UL /**< First descriptor */ +#define MYSON_TX_CTRL_CRC 0x08000000UL /**< CRC append */ +#define MYSON_TX_CTRL_PAD 0x04000000UL /**< Pad control */ +#define MYSON_TX_CTRL_RTLC 0x02000000UL /**< Retry late collision */ +#define MYSON_TX_CTRL_PKTS(x) ( (x) << 11 ) /**< Packet size */ +#define MYSON_TX_CTRL_TBS(x) ( (x) << 0 ) /**< Transmit buffer size */ + +/* Receive status */ +#define MYSON_RX_STAT_OWN 0x80000000UL /**< Owner */ +#define MYSON_RX_STAT_FLNG(status) ( ( (status) >> 16 ) & 0xfff ) +#define MYSON_RX_STAT_ES 0x00000080UL /**< Error summary */ + +/* Receive control */ +#define MYSON_RX_CTRL_RBS(x) ( (x) << 0 ) /**< Receive buffer size */ + +/** Descriptor ring alignment */ +#define MYSON_RING_ALIGN 4 + +/** Physical Address Register 0 */ +#define MYSON_PAR0 0x00 + +/** Physical Address Register 4 */ +#define MYSON_PAR4 0x04 + +/** Physical address */ +union myson_physical_address { + struct { + uint32_t low; + uint32_t high; + } __attribute__ (( packed )) reg; + uint8_t raw[ETH_ALEN]; +}; + +/** Transmit and Receive Configuration Register */ +#define MYSON_TCR_RCR 0x18 +#define MYSON_TCR_TXS 0x80000000UL /**< Transmit status */ +#define MYSON_TCR_TE 0x00040000UL /**< Transmit enable */ +#define MYSON_RCR_RXS 0x00008000UL /**< Receive status */ +#define MYSON_RCR_PROM 0x00000080UL /**< Promiscuous mode */ +#define MYSON_RCR_AB 0x00000040UL /**< Accept broadcast */ +#define MYSON_RCR_AM 0x00000020UL /**< Accept multicast */ +#define MYSON_RCR_ARP 0x00000008UL /**< Accept runt packet */ +#define MYSON_RCR_ALP 0x00000004UL /**< Accept long packet */ +#define MYSON_RCR_RE 0x00000001UL /**< Receive enable */ + +/** Maximum time to wait for transmit and receive to be idle, in milliseconds */ +#define MYSON_IDLE_MAX_WAIT_MS 100 + +/** Bus Command Register */ +#define MYSON_BCR 0x1c +#define MYSON_BCR_RLE 0x00000100UL /**< Read line enable */ +#define MYSON_BCR_RME 0x00000080UL /**< Read multiple enable */ +#define MYSON_BCR_WIE 0x00000040UL /**< Write and invalidate */ +#define MYSON_BCR_PBL(x) ( (x) << 3 ) /**< Burst length */ +#define MYSON_BCR_PBL_MASK MYSON_BCR_PBL ( 0x7 ) +#define MYSON_BCR_PBL_DEFAULT MYSON_BCR_PBL ( 0x6 ) +#define MYSON_BCR_SWR 0x00000001UL /**< Software reset */ + +/** Maximum time to wait for a reset, in milliseconds */ +#define MYSON_RESET_MAX_WAIT_MS 100 + +/** Transmit Poll Demand Register */ +#define MYSON_TXPDR 0x20 + +/** Receive Poll Demand Register */ +#define MYSON_RXPDR 0x24 + +/** Transmit List Base Address */ +#define MYSON_TXLBA 0x2c + +/** Number of transmit descriptors */ +#define MYSON_NUM_TX_DESC 4 + +/** Receive List Base Address */ +#define MYSON_RXLBA 0x30 + +/** Number of receive descriptors */ +#define MYSON_NUM_RX_DESC 4 + +/** Receive buffer length */ +#define MYSON_RX_MAX_LEN ( ETH_FRAME_LEN + 4 /* VLAN */ + 4 /* CRC */ ) + +/** Interrupt Status Register */ +#define MYSON_ISR 0x34 +#define MYSON_IRQ_TI 0x00000008UL /**< Transmit interrupt */ +#define MYSON_IRQ_RI 0x00000004UL /**< Receive interrupt */ + +/** Number of I/O delays between ISR reads */ +#define MYSON_ISR_IODELAY_COUNT 4 + +/** Interrupt Mask Register */ +#define MYSON_IMR 0x38 + +/** Boot ROM / EEPROM / MII Management Register */ +#define MYSON_ROM_MII 0x40 +#define MYSON_ROM_AUTOLD 0x00100000UL /**< Auto load */ + +/** Maximum time to wait for a configuration reload, in milliseconds */ +#define MYSON_AUTOLD_MAX_WAIT_MS 100 + +/** A Myson descriptor ring */ +struct myson_ring { + /** Descriptors */ + struct myson_descriptor *desc; + /** Producer index */ + unsigned int prod; + /** Consumer index */ + unsigned int cons; + + /** Number of descriptors */ + unsigned int count; + /** Descriptor start address register */ + unsigned int reg; +}; + +/** + * Initialise descriptor ring + * + * @v ring Descriptor ring + * @v count Number of descriptors + * @v reg Descriptor base address register + */ +static inline __attribute__ (( always_inline)) void +myson_init_ring ( struct myson_ring *ring, unsigned int count, + unsigned int reg ) { + ring->count = count; + ring->reg = reg; +} + +/** A myson network card */ +struct myson_nic { + /** Registers */ + void *regs; + + /** Transmit descriptor ring */ + struct myson_ring tx; + /** Receive descriptor ring */ + struct myson_ring rx; + /** Receive I/O buffers */ + struct io_buffer *rx_iobuf[MYSON_NUM_RX_DESC]; +}; + +/** + * Check if card can access physical address + * + * @v address Physical address + * @v address_ok Card can access physical address + */ +static inline __attribute__ (( always_inline )) int +myson_address_ok ( physaddr_t address ) { + + /* In a 32-bit build, all addresses can be accessed */ + if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) ) + return 1; + + /* Card can access all addresses below 4GB */ + if ( ( address & ~0xffffffffULL ) == 0 ) + return 1; + + return 0; +} + +#endif /* _MYSON_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 471ba77c..7de833d0 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -145,6 +145,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ERRFILE_realtek ( ERRFILE_DRIVER | 0x00630000 ) #define ERRFILE_skeleton ( ERRFILE_DRIVER | 0x00640000 ) #define ERRFILE_intel ( ERRFILE_DRIVER | 0x00650000 ) +#define ERRFILE_myson ( ERRFILE_DRIVER | 0x00660000 ) #define ERRFILE_scsi ( ERRFILE_DRIVER | 0x00700000 ) #define ERRFILE_arbel ( ERRFILE_DRIVER | 0x00710000 ) From e01cf6fb3a0d31a7a80465c0359207c9b163e76f Mon Sep 17 00:00:00 2001 From: Kevin Tran Date: Fri, 27 Apr 2012 21:07:12 +0100 Subject: [PATCH 195/221] [http] Fix typo in memory allocation Signed-off-by: Michael Brown --- src/net/tcp/httpcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/net/tcp/httpcore.c b/src/net/tcp/httpcore.c index f227e126..d0ad952e 100644 --- a/src/net/tcp/httpcore.c +++ b/src/net/tcp/httpcore.c @@ -664,7 +664,7 @@ static void http_step ( struct http_request *http ) { /* Allocate dynamic storage */ dynamic = malloc ( sizeof ( *dynamic ) ); - if ( ! malloc ) { + if ( ! dynamic ) { rc = -ENOMEM; goto err_alloc; } From f8bb40b002ccf38c90d5dfe181147d7e272fa51a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 28 Apr 2012 15:47:46 +0100 Subject: [PATCH 196/221] [realtek] Support RTL8139 cards within generic Realtek driver RTL8139C+ cards use essentially the same datapath as RTL8169, which is zerocopy and 64-bit capable. Older RTL8139 cards use a single receive ring buffer rather than a descriptor ring, but still share substantial amounts of functionality with RTL8169. Include support for RTL8139 cards within the generic Realtek driver, since there is no way to differentiate between RTL8139 and RTL8139C+ cards based on the PCI IDs alone. Many thanks to all the people who worked on the rtl8139 driver over the years. Signed-off-by: Michael Brown --- src/drivers/net/realtek.c | 351 +++++++++++++++++++--- src/drivers/net/realtek.h | 102 +++++-- src/drivers/net/rtl8139.c | 596 -------------------------------------- 3 files changed, 400 insertions(+), 649 deletions(-) delete mode 100644 src/drivers/net/rtl8139.c diff --git a/src/drivers/net/realtek.c b/src/drivers/net/realtek.c index 5f111a68..c906f251 100644 --- a/src/drivers/net/realtek.c +++ b/src/drivers/net/realtek.c @@ -78,7 +78,9 @@ static int realtek_spi_read_bit ( struct bit_basher *basher, uint8_t mask = realtek_eeprom_bits[bit_id]; uint8_t reg; + DBG_DISABLE ( DBGLVL_IO ); reg = readb ( rtl->regs + RTL_9346CR ); + DBG_ENABLE ( DBGLVL_IO ); return ( reg & mask ); } @@ -96,10 +98,12 @@ static void realtek_spi_write_bit ( struct bit_basher *basher, uint8_t mask = realtek_eeprom_bits[bit_id]; uint8_t reg; + DBG_DISABLE ( DBGLVL_IO ); reg = readb ( rtl->regs + RTL_9346CR ); reg &= ~mask; reg |= ( data & mask ); writeb ( reg, rtl->regs + RTL_9346CR ); + DBG_ENABLE ( DBGLVL_IO ); } /** SPI bit-bashing interface */ @@ -165,6 +169,10 @@ static int realtek_mii_read ( struct mii_interface *mii, unsigned int reg ) { unsigned int i; uint32_t value; + /* Fail if PHYAR register is not present */ + if ( ! rtl->have_phy_regs ) + return -ENOTSUP; + /* Initiate read */ writel ( RTL_PHYAR_VALUE ( 0, reg, 0 ), rtl->regs + RTL_PHYAR ); @@ -199,6 +207,10 @@ static int realtek_mii_write ( struct mii_interface *mii, unsigned int reg, struct realtek_nic *rtl = container_of ( mii, struct realtek_nic, mii ); unsigned int i; + /* Fail if PHYAR register is not present */ + if ( ! rtl->have_phy_regs ) + return -ENOTSUP; + /* Initiate write */ writel ( RTL_PHYAR_VALUE ( RTL_PHYAR_FLAG, reg, data ), rtl->regs + RTL_PHYAR ); @@ -253,10 +265,6 @@ static int realtek_reset ( struct realtek_nic *rtl ) { continue; } - /* Enable PCI Dual Address Cycle (for 64-bit systems) */ - writew ( ( RTL_CPCR_DAC | RTL_CPCR_MULRW ), - rtl->regs + RTL_CPCR ); - return 0; } @@ -278,8 +286,23 @@ static int realtek_reset ( struct realtek_nic *rtl ) { */ static void realtek_check_link ( struct net_device *netdev ) { struct realtek_nic *rtl = netdev->priv; + uint8_t phystatus; + uint8_t msr; + int link_up; - if ( readb ( rtl->regs + RTL_PHYSTATUS ) & RTL_PHYSTATUS_LINKSTS ) { + /* Determine link state */ + if ( rtl->have_phy_regs ) { + phystatus = readb ( rtl->regs + RTL_PHYSTATUS ); + link_up = ( phystatus & RTL_PHYSTATUS_LINKSTS ); + DBGC ( rtl, "REALTEK %p PHY status is %02x\n", rtl, phystatus ); + } else { + msr = readb ( rtl->regs + RTL_MSR ); + link_up = ( ! ( msr & RTL_MSR_LINKB ) ); + DBGC ( rtl, "REALTEK %p media status is %02x\n", rtl, msr ); + } + + /* Report link state */ + if ( link_up ) { netdev_link_up ( netdev ); } else { netdev_link_down ( netdev ); @@ -293,6 +316,74 @@ static void realtek_check_link ( struct net_device *netdev ) { ****************************************************************************** */ +/** + * Create receive buffer (legacy mode) + * + * @v rtl Realtek device + * @ret rc Return status code + */ +static int realtek_create_buffer ( struct realtek_nic *rtl ) { + size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); + physaddr_t address; + int rc; + + /* Do nothing unless in legacy mode */ + if ( ! rtl->legacy ) + return 0; + + /* Allocate buffer */ + rtl->rx_buffer = malloc_dma ( len, RTL_RXBUF_ALIGN ); + if ( ! rtl->rx_buffer ) { + rc = -ENOMEM; + goto err_alloc; + } + address = virt_to_bus ( rtl->rx_buffer ); + + /* Check that card can support address */ + if ( address & ~0xffffffffULL ) { + DBGC ( rtl, "REALTEK %p cannot support 64-bit RX buffer " + "address\n", rtl ); + rc = -ENOTSUP; + goto err_64bit; + } + + /* Program buffer address */ + writel ( address, rtl->regs + RTL_RBSTART ); + DBGC ( rtl, "REALTEK %p receive buffer is at [%08llx,%08llx,%08llx)\n", + rtl, ( ( unsigned long long ) address ), + ( ( unsigned long long ) address + RTL_RXBUF_LEN ), + ( ( unsigned long long ) address + len ) ); + + return 0; + + err_64bit: + free_dma ( rtl->rx_buffer, len ); + rtl->rx_buffer = NULL; + err_alloc: + return rc; +} + +/** + * Destroy receive buffer (legacy mode) + * + * @v rtl Realtek device + */ +static void realtek_destroy_buffer ( struct realtek_nic *rtl ) { + size_t len = ( RTL_RXBUF_LEN + RTL_RXBUF_PAD ); + + /* Do nothing unless in legacy mode */ + if ( ! rtl->legacy ) + return; + + /* Clear buffer address */ + writel ( 0, rtl->regs + RTL_RBSTART ); + + /* Free buffer */ + free_dma ( rtl->rx_buffer, len ); + rtl->rx_buffer = NULL; + rtl->rx_offset = 0; +} + /** * Create descriptor ring * @@ -304,6 +395,10 @@ static int realtek_create_ring ( struct realtek_nic *rtl, struct realtek_ring *ring ) { physaddr_t address; + /* Do nothing in legacy mode */ + if ( rtl->legacy ) + return 0; + /* Allocate descriptor ring */ ring->desc = malloc_dma ( ring->len, RTL_RING_ALIGN ); if ( ! ring->desc ) @@ -335,6 +430,10 @@ static int realtek_create_ring ( struct realtek_nic *rtl, static void realtek_destroy_ring ( struct realtek_nic *rtl, struct realtek_ring *ring ) { + /* Do nothing in legacy mode */ + if ( rtl->legacy ) + return; + /* Clear ring address */ writel ( 0, rtl->regs + ring->reg ); writel ( 0, rtl->regs + ring->reg + 4 ); @@ -358,6 +457,10 @@ static void realtek_refill_rx ( struct realtek_nic *rtl ) { physaddr_t address; int is_last; + /* Do nothing in legacy mode */ + if ( rtl->legacy ) + return; + while ( ( rtl->rx.prod - rtl->rx.cons ) < RTL_NUM_RX_DESC ) { /* Allocate I/O buffer */ @@ -410,27 +513,36 @@ static int realtek_open ( struct net_device *netdev ) { if ( ( rc = realtek_create_ring ( rtl, &rtl->rx ) ) != 0 ) goto err_create_rx; - /* Configure MTU */ - writew ( RTL_RX_MAX_LEN, rtl->regs + RTL_RMS ); + /* Create receive buffer */ + if ( ( rc = realtek_create_buffer ( rtl ) ) != 0 ) + goto err_create_buffer; /* Accept all packets */ writel ( 0xffffffffUL, rtl->regs + RTL_MAR0 ); writel ( 0xffffffffUL, rtl->regs + RTL_MAR4 ); + + /* Enable transmitter and receiver. RTL8139 requires that + * this happens before writing to RCR. + */ + writeb ( ( RTL_CR_TE | RTL_CR_RE ), rtl->regs + RTL_CR ); + + /* Configure receiver */ rcr = readl ( rtl->regs + RTL_RCR ); - writel ( ( rcr | RTL_RCR_AB | RTL_RCR_AM | RTL_RCR_APM | RTL_RCR_AAP ), - rtl->regs + RTL_RCR ); + rcr &= ~( RTL_RCR_RBLEN_MASK ); + rcr |= ( RTL_RCR_RBLEN_DEFAULT | RTL_RCR_WRAP | RTL_RCR_AB | + RTL_RCR_AM | RTL_RCR_APM | RTL_RCR_AAP ); + writel ( rcr, rtl->regs + RTL_RCR ); /* Fill receive ring */ realtek_refill_rx ( rtl ); - /* Enable transmitter and receiver */ - writeb ( ( RTL_CR_TE | RTL_CR_RE ), rtl->regs + RTL_CR ); - /* Update link state */ realtek_check_link ( netdev ); return 0; + realtek_destroy_buffer ( rtl ); + err_create_buffer: realtek_destroy_ring ( rtl, &rtl->rx ); err_create_rx: realtek_destroy_ring ( rtl, &rtl->tx ); @@ -450,6 +562,9 @@ static void realtek_close ( struct net_device *netdev ) { /* Disable receiver and transmitter */ writeb ( 0, rtl->regs + RTL_CR ); + /* Destroy receive buffer */ + realtek_destroy_buffer ( rtl ); + /* Destroy receive descriptor ring */ realtek_destroy_ring ( rtl, &rtl->rx ); @@ -485,24 +600,48 @@ static int realtek_transmit ( struct net_device *netdev, return -ENOBUFS; } tx_idx = ( rtl->tx.prod++ % RTL_NUM_TX_DESC ); - is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) ); - tx = &rtl->tx.desc[tx_idx]; - /* Populate transmit descriptor */ - address = virt_to_bus ( iobuf->data ); - tx->address = cpu_to_le64 ( address ); - tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); - wmb(); - tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS | RTL_DESC_LS ) | - ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); - wmb(); + /* Transmit packet */ + if ( rtl->legacy ) { - /* Notify card that there are packets ready to transmit */ - writeb ( RTL_TPPOLL_NPQ, rtl->regs + RTL_TPPOLL ); + /* Pad and align packet */ + iob_pad ( iobuf, ETH_ZLEN ); + address = virt_to_bus ( iobuf->data ); + + /* Check that card can support address */ + if ( address & ~0xffffffffULL ) { + DBGC ( rtl, "REALTEK %p cannot support 64-bit TX " + "buffer address\n", rtl ); + return -ENOTSUP; + } + + /* Add to transmit ring */ + writel ( address, rtl->regs + RTL_TSAD ( tx_idx ) ); + writel ( ( RTL_TSD_ERTXTH_DEFAULT | iob_len ( iobuf ) ), + rtl->regs + RTL_TSD ( tx_idx ) ); + + } else { + + /* Populate transmit descriptor */ + address = virt_to_bus ( iobuf->data ); + is_last = ( tx_idx == ( RTL_NUM_TX_DESC - 1 ) ); + tx = &rtl->tx.desc[tx_idx]; + tx->address = cpu_to_le64 ( address ); + tx->length = cpu_to_le16 ( iob_len ( iobuf ) ); + wmb(); + tx->flags = ( cpu_to_le16 ( RTL_DESC_OWN | RTL_DESC_FS | + RTL_DESC_LS ) | + ( is_last ? cpu_to_le16 ( RTL_DESC_EOR ) : 0 ) ); + wmb(); + + /* Notify card that there are packets ready to transmit */ + writeb ( RTL_TPPOLL_NPQ, rtl->regs + rtl->tppoll ); + } DBGC2 ( rtl, "REALTEK %p TX %d is [%llx,%llx)\n", rtl, tx_idx, - ( ( unsigned long long ) address ), - ( ( unsigned long long ) address + iob_len ( iobuf ) ) ); + ( ( unsigned long long ) virt_to_bus ( iobuf->data ) ), + ( ( ( unsigned long long ) virt_to_bus ( iobuf->data ) ) + + iob_len ( iobuf ) ) ); return 0; } @@ -522,11 +661,22 @@ static void realtek_poll_tx ( struct net_device *netdev ) { /* Get next transmit descriptor */ tx_idx = ( rtl->tx.cons % RTL_NUM_TX_DESC ); - tx = &rtl->tx.desc[tx_idx]; /* Stop if descriptor is still in use */ - if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) - return; + if ( rtl->legacy ) { + + /* Check ownership bit in transmit status register */ + if ( ! ( readl ( rtl->regs + RTL_TSD ( tx_idx ) ) & + RTL_TSD_OWN ) ) + return; + + } else { + + /* Check ownership bit in descriptor */ + tx = &rtl->tx.desc[tx_idx]; + if ( tx->flags & cpu_to_le16 ( RTL_DESC_OWN ) ) + return; + } DBGC2 ( rtl, "REALTEK %p TX %d complete\n", rtl, tx_idx ); @@ -536,6 +686,59 @@ static void realtek_poll_tx ( struct net_device *netdev ) { } } +/** + * Poll for received packets (legacy mode) + * + * @v netdev Network device + */ +static void realtek_legacy_poll_rx ( struct net_device *netdev ) { + struct realtek_nic *rtl = netdev->priv; + struct realtek_legacy_header *rx; + struct io_buffer *iobuf; + size_t len; + + /* Check for received packets */ + while ( ! ( readb ( rtl->regs + RTL_CR ) & RTL_CR_BUFE ) ) { + + /* Extract packet from receive buffer */ + rx = ( rtl->rx_buffer + rtl->rx_offset ); + len = le16_to_cpu ( rx->length ); + if ( rx->status & cpu_to_le16 ( RTL_STAT_ROK ) ) { + + DBGC2 ( rtl, "REALTEK %p RX offset %x+%zx\n", + rtl, rtl->rx_offset, len ); + + /* Allocate I/O buffer */ + iobuf = alloc_iob ( len ); + if ( ! iobuf ) { + netdev_rx_err ( netdev, NULL, -ENOMEM ); + /* Leave packet for next poll */ + break; + } + + /* Copy data to I/O buffer */ + memcpy ( iob_put ( iobuf, len ), rx->data, len ); + iob_unput ( iobuf, 4 /* strip CRC */ ); + + /* Hand off to network stack */ + netdev_rx ( netdev, iobuf ); + + } else { + + DBGC ( rtl, "REALTEK %p RX offset %x+%zx error %04x\n", + rtl, rtl->rx_offset, len, + le16_to_cpu ( rx->status ) ); + netdev_rx_err ( netdev, NULL, -EIO ); + } + + /* Update buffer offset */ + rtl->rx_offset = ( rtl->rx_offset + sizeof ( *rx ) + len ); + rtl->rx_offset = ( ( rtl->rx_offset + 3 ) & ~3 ); + rtl->rx_offset = ( rtl->rx_offset % RTL_RXBUF_LEN ); + writew ( ( rtl->rx_offset - 16 ), rtl->regs + RTL_CAPR ); + } +} + /** * Poll for received packets * @@ -548,6 +751,12 @@ static void realtek_poll_rx ( struct net_device *netdev ) { unsigned int rx_idx; size_t len; + /* Poll receive buffer if in legacy mode */ + if ( rtl->legacy ) { + realtek_legacy_poll_rx ( netdev ); + return; + } + /* Check for received packets */ while ( rtl->rx.cons != rtl->rx.prod ) { @@ -641,6 +850,51 @@ static struct net_device_operations realtek_operations = { ****************************************************************************** */ +/** + * Detect device type + * + * @v rtl Realtek device + */ +static void realtek_detect ( struct realtek_nic *rtl ) { + uint16_t rms; + uint16_t check_rms; + uint16_t cpcr; + uint16_t check_cpcr; + + /* The RX Packet Maximum Size register is present only on + * 8169. Try to set to our intended MTU. + */ + rms = RTL_RX_MAX_LEN; + writew ( rms, rtl->regs + RTL_RMS ); + check_rms = readw ( rtl->regs + RTL_RMS ); + + /* The C+ Command register is present only on 8169 and 8139C+. + * Try to enable C+ mode and PCI Dual Address Cycle (for + * 64-bit systems), if supported. + */ + cpcr = ( RTL_CPCR_DAC | RTL_CPCR_MULRW | RTL_CPCR_CPRX | + RTL_CPCR_CPTX ); + writew ( cpcr, rtl->regs + RTL_CPCR ); + check_cpcr = readw ( rtl->regs + RTL_CPCR ); + + /* Detect device type */ + if ( check_rms == rms ) { + DBGC ( rtl, "REALTEK %p appears to be an RTL8169\n", rtl ); + rtl->have_phy_regs = 1; + rtl->tppoll = RTL_TPPOLL_8169; + } else { + if ( check_cpcr == cpcr ) { + DBGC ( rtl, "REALTEK %p appears to be an RTL8139C+\n", + rtl ); + rtl->tppoll = RTL_TPPOLL_8139CP; + } else { + DBGC ( rtl, "REALTEK %p appears to be an RTL8139\n", + rtl ); + rtl->legacy = 1; + } + } +} + /** * Probe PCI device * @@ -677,6 +931,9 @@ static int realtek_probe ( struct pci_device *pci ) { if ( ( rc = realtek_reset ( rtl ) ) != 0 ) goto err_reset; + /* Detect device type */ + realtek_detect ( rtl ); + /* Initialise EEPROM */ realtek_init_eeprom ( netdev ); @@ -700,7 +957,8 @@ static int realtek_probe ( struct pci_device *pci ) { /* Initialise and reset MII interface */ mii_init ( &rtl->mii, &realtek_mii_operations ); - if ( ( rc = mii_reset ( &rtl->mii ) ) != 0 ) { + if ( rtl->have_phy_regs && + ( ( rc = mii_reset ( &rtl->mii ) ) != 0 ) ) { DBGC ( rtl, "REALTEK %p could not reset MII: %s\n", rtl, strerror ( rc ) ); goto err_mii_reset; @@ -761,16 +1019,37 @@ static void realtek_remove ( struct pci_device *pci ) { /** Realtek PCI device IDs */ static struct pci_device_id realtek_nics[] = { - PCI_ROM ( 0x10ec, 0x8129, "r8129", "RTL-8129", 0 ), - PCI_ROM ( 0x10ec, 0x8136, "r8136", "RTL8101E/RTL8102E", 0 ), - PCI_ROM ( 0x10ec, 0x8167, "r8167", "RTL-8110SC/8169SC", 0 ), - PCI_ROM ( 0x10ec, 0x8168, "r8168", "RTL8111/8168B", 0 ), - PCI_ROM ( 0x10ec, 0x8169, "r8169", "RTL-8169", 0 ), + PCI_ROM ( 0x0001, 0x8168, "clone8169", "Cloned 8169", 0 ), + PCI_ROM ( 0x018a, 0x0106, "fpc0106tx", "LevelOne FPC-0106TX", 0 ), + PCI_ROM ( 0x021b, 0x8139, "hne300", "Compaq HNE-300", 0 ), + PCI_ROM ( 0x02ac, 0x1012, "s1012", "SpeedStream 1012", 0 ), + PCI_ROM ( 0x0357, 0x000a, "ttpmon", "TTTech TTP-Monitoring", 0 ), + PCI_ROM ( 0x10ec, 0x8129, "rtl8129", "RTL-8129", 0 ), + PCI_ROM ( 0x10ec, 0x8136, "rtl8136", "RTL8101E/RTL8102E", 0 ), + PCI_ROM ( 0x10ec, 0x8138, "rtl8138", "RT8139 (B/C)", 0 ), + PCI_ROM ( 0x10ec, 0x8139, "rtl8139", "RTL-8139/8139C/8139C+", 0 ), + PCI_ROM ( 0x10ec, 0x8167, "rtl8167", "RTL-8110SC/8169SC", 0 ), + PCI_ROM ( 0x10ec, 0x8168, "rtl8168", "RTL8111/8168B", 0 ), + PCI_ROM ( 0x10ec, 0x8169, "rtl8169", "RTL-8169", 0 ), + PCI_ROM ( 0x1113, 0x1211, "smc1211", "SMC2-1211TX", 0 ), + PCI_ROM ( 0x1186, 0x1300, "dfe538", "DFE530TX+/DFE538TX", 0 ), + PCI_ROM ( 0x1186, 0x1340, "dfe690", "DFE-690TXD", 0 ), PCI_ROM ( 0x1186, 0x4300, "dge528t", "DGE-528T", 0 ), + PCI_ROM ( 0x11db, 0x1234, "sega8139", "Sega Enterprises 8139", 0 ), + PCI_ROM ( 0x1259, 0xa117, "allied8139", "Allied Telesyn 8139", 0 ), + PCI_ROM ( 0x1259, 0xa11e, "allied81xx", "Allied Telesyn 81xx", 0 ), PCI_ROM ( 0x1259, 0xc107, "allied8169", "Allied Telesyn 8169", 0 ), + PCI_ROM ( 0x126c, 0x1211, "northen8139","Northern Telecom 8139", 0 ), + PCI_ROM ( 0x13d1, 0xab06, "fe2000vx", "Abocom FE2000VX", 0 ), + PCI_ROM ( 0x1432, 0x9130, "edi8139", "Edimax 8139", 0 ), + PCI_ROM ( 0x14ea, 0xab06, "fnw3603tx", "Planex FNW-3603-TX", 0 ), + PCI_ROM ( 0x14ea, 0xab07, "fnw3800tx", "Planex FNW-3800-TX", 0 ), + PCI_ROM ( 0x1500, 0x1360, "delta8139", "Delta Electronics 8139", 0 ), PCI_ROM ( 0x16ec, 0x0116, "usr997902", "USR997902", 0 ), PCI_ROM ( 0x1737, 0x1032, "linksys8169","Linksys 8169", 0 ), - PCI_ROM ( 0x0001, 0x8168, "clone8169", "Cloned 8169", 0 ), + PCI_ROM ( 0x1743, 0x8139, "rolf100", "Peppercorn ROL/F-100", 0 ), + PCI_ROM ( 0x4033, 0x1360, "addron8139", "Addtron 8139", 0 ), + PCI_ROM ( 0xffff, 0x8139, "clonse8139", "Cloned 8139", 0 ), }; /** Realtek PCI driver */ diff --git a/src/drivers/net/realtek.h b/src/drivers/net/realtek.h index aad4b34c..1c6bc544 100644 --- a/src/drivers/net/realtek.h +++ b/src/drivers/net/realtek.h @@ -49,6 +49,22 @@ enum realtek_descriptor_flags { /** Descriptor ring alignment */ #define RTL_RING_ALIGN 256 +/** A legacy mode receive packet header */ +struct realtek_legacy_header { + /** Status */ + uint16_t status; + /** Length */ + uint16_t length; + /** Packet data */ + uint8_t data[0]; +} __attribute__ (( packed )); + +/** Legacy mode status bits */ +enum realtek_legacy_status { + /** Received OK */ + RTL_STAT_ROK = 0x0001, +}; + /** ID Register 0 (6 bytes) */ #define RTL_IDR0 0x00 @@ -58,43 +74,75 @@ enum realtek_descriptor_flags { /** Multicast Register 4 (dword) */ #define RTL_MAR4 0x0c +/** Transmit Status of Descriptor N (dword, 8139 only) */ +#define RTL_TSD(n) ( 0x10 + 4 * (n) ) +#define RTL_TSD_ERTXTH(x) ( (x) << 16 ) /**< Early TX threshold */ +#define RTL_TSD_ERTXTH_DEFAULT RTL_TSD_ERTXTH ( 256 / 32 ) +#define RTL_TSD_OWN 0x00002000UL /**< Ownership */ + +/** Transmit Start Address of Descriptor N (dword, 8139 only) */ +#define RTL_TSAD(n) ( 0x20 + 4 * (n) ) + /** Transmit Normal Priority Descriptors (qword) */ #define RTL_TNPDS 0x20 -/** Number of transmit descriptors */ +/** Number of transmit descriptors + * + * This is a hardware limit when using legacy mode. + */ #define RTL_NUM_TX_DESC 4 +/** Receive Buffer Start Address (dword, 8139 only) */ +#define RTL_RBSTART 0x30 + +/** Receive buffer length */ +#define RTL_RXBUF_LEN 8192 + +/** Receive buffer padding */ +#define RTL_RXBUF_PAD 2038 /* Allow space for WRAP */ + +/** Receive buffer alignment */ +#define RTL_RXBUF_ALIGN 16 + /** Command Register (byte) */ #define RTL_CR 0x37 #define RTL_CR_RST 0x10 /**< Reset */ #define RTL_CR_RE 0x08 /**< Receiver Enable */ #define RTL_CR_TE 0x04 /**< Transmit Enable */ +#define RTL_CR_BUFE 0x01 /**< Receive buffer empty */ /** Maximum time to wait for a reset, in milliseconds */ #define RTL_RESET_MAX_WAIT_MS 100 -/** Transmit Priority Polling Register (byte) */ -#define RTL_TPPOLL 0x38 +/** Current Address of Packet Read (word, 8139 only) */ +#define RTL_CAPR 0x38 + +/** Transmit Priority Polling Register (byte, 8169 only) */ +#define RTL_TPPOLL_8169 0x38 #define RTL_TPPOLL_NPQ 0x40 /**< Normal Priority Queue Polling */ /** Interrupt Mask Register (word) */ #define RTL_IMR 0x3c -#define RTL_IRQ_PUN_LINKCHG 0x20 /**< Packet underrun / link change */ -#define RTL_IRQ_TER 0x08 /**< Transmit error */ -#define RTL_IRQ_TOK 0x04 /**< Transmit OK */ -#define RTL_IRQ_RER 0x02 /**< Receive error */ -#define RTL_IRQ_ROK 0x01 /**< Receive OK */ +#define RTL_IRQ_PUN_LINKCHG 0x0020 /**< Packet underrun / link change */ +#define RTL_IRQ_TER 0x0008 /**< Transmit error */ +#define RTL_IRQ_TOK 0x0004 /**< Transmit OK */ +#define RTL_IRQ_RER 0x0002 /**< Receive error */ +#define RTL_IRQ_ROK 0x0001 /**< Receive OK */ /** Interrupt Status Register (word) */ #define RTL_ISR 0x3e /** Receive (Rx) Configuration Register (dword) */ #define RTL_RCR 0x44 -#define RTL_RCR_9356SEL 0x40 /**< EEPROM is a 93C56 */ -#define RTL_RCR_AB 0x08 /**< Accept broadcast packets */ -#define RTL_RCR_AM 0x04 /**< Accept multicast packets */ -#define RTL_RCR_APM 0x02 /**< Accept physical match packets */ -#define RTL_RCR_AAP 0x01 /**< Accept all packets */ +#define RTL_RCR_RBLEN(x) ( (x) << 11 ) /**< Receive buffer length */ +#define RTL_RCR_RBLEN_MASK RTL_RCR_RBLEN ( 0x3 ) +#define RTL_RCR_RBLEN_DEFAULT RTL_RCR_RBLEN ( 0 /* 8kB */ ) +#define RTL_RCR_WRAP 0x00000080UL /**< Overrun receive buffer */ +#define RTL_RCR_9356SEL 0x00000040UL /**< EEPROM is a 93C56 */ +#define RTL_RCR_AB 0x00000008UL /**< Accept broadcast packets */ +#define RTL_RCR_AM 0x00000004UL /**< Accept multicast packets */ +#define RTL_RCR_APM 0x00000002UL /**< Accept physical match */ +#define RTL_RCR_AAP 0x00000001UL /**< Accept all packets */ /** 93C46 (93C56) Command Register (byte) */ #define RTL_9346CR 0x50 @@ -118,7 +166,11 @@ enum realtek_descriptor_flags { #define RTL_CONFIG1 0x52 #define RTL_CONFIG1_VPD 0x02 /**< Vital Product Data enabled */ -/** PHY Access Register (dword) */ +/** Media Status Register (byte, 8139 only) */ +#define RTL_MSR 0x58 +#define RTL_MSR_LINKB 0x04 /**< Inverse of link status */ + +/** PHY Access Register (dword, 8169 only) */ #define RTL_PHYAR 0x60 #define RTL_PHYAR_FLAG 0x80000000UL /**< Read/write flag */ @@ -131,17 +183,22 @@ enum realtek_descriptor_flags { /** Maximum time to wait for PHY access, in microseconds */ #define RTL_MII_MAX_WAIT_US 500 -/** PHY (GMII, MII, or TBI) Status Register (byte) */ +/** PHY (GMII, MII, or TBI) Status Register (byte, 8169 only) */ #define RTL_PHYSTATUS 0x6c #define RTL_PHYSTATUS_LINKSTS 0x02 /**< Link ok */ +/** Transmit Priority Polling Register (byte, 8139C+ only) */ +#define RTL_TPPOLL_8139CP 0xd9 + /** RX Packet Maximum Size Register (word) */ #define RTL_RMS 0xda /** C+ Command Register (word) */ #define RTL_CPCR 0xe0 -#define RTL_CPCR_DAC 0x10 /**< PCI Dual Address Cycle Enable */ -#define RTL_CPCR_MULRW 0x08 /**< PCI Multiple Read/Write Enable */ +#define RTL_CPCR_DAC 0x0010 /**< PCI Dual Address Cycle Enable */ +#define RTL_CPCR_MULRW 0x0008 /**< PCI Multiple Read/Write Enable */ +#define RTL_CPCR_CPRX 0x0002 /**< C+ receive enable */ +#define RTL_CPCR_CPTX 0x0001 /**< C+ transmit enable */ /** Receive Descriptor Start Address Register (qword) */ #define RTL_RDSAR 0xe4 @@ -194,12 +251,23 @@ struct realtek_nic { /** MII interface */ struct mii_interface mii; + /** Legacy datapath mode */ + int legacy; + /** PHYAR and PHYSTATUS registers are present */ + int have_phy_regs; + /** TPPoll register offset */ + unsigned int tppoll; + /** Transmit descriptor ring */ struct realtek_ring tx; /** Receive descriptor ring */ struct realtek_ring rx; /** Receive I/O buffers */ struct io_buffer *rx_iobuf[RTL_NUM_RX_DESC]; + /** Receive buffer (legacy mode) */ + void *rx_buffer; + /** Offset within receive buffer (legacy mode) */ + unsigned int rx_offset; }; #endif /* _REALTEK_H */ diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c deleted file mode 100644 index 2da8223a..00000000 --- a/src/drivers/net/rtl8139.c +++ /dev/null @@ -1,596 +0,0 @@ -/* rtl8139.c - etherboot driver for the Realtek 8139 chipset - - ported from the linux driver written by Donald Becker - by Rainer Bawidamann (Rainer.Bawidamann@informatik.uni-ulm.de) 1999 - - This software may be used and distributed according to the terms - of the GNU Public License, incorporated herein by reference. - - changes to the original driver: - - removed support for interrupts, switching to polling mode (yuck!) - - removed support for the 8129 chip (external MII) - -*/ - -FILE_LICENCE ( GPL_ANY ); - -/*********************************************************************/ -/* Revision History */ -/*********************************************************************/ - -/* - 27 May 2006 mcb30@users.sourceforge.net (Michael Brown) - Rewrote to use the new net driver API, the updated PCI API, and - the generic three-wire serial device support for EEPROM access. - - 28 Dec 2002 ken_yap@users.sourceforge.net (Ken Yap) - Put in virt_to_bus calls to allow Etherboot relocation. - - 06 Apr 2001 ken_yap@users.sourceforge.net (Ken Yap) - Following email from Hyun-Joon Cha, added a disable routine, otherwise - NIC remains live and can crash the kernel later. - - 4 Feb 2000 espenlaub@informatik.uni-ulm.de (Klaus Espenlaub) - Shuffled things around, removed the leftovers from the 8129 support - that was in the Linux driver and added a bit more 8139 definitions. - Moved the 8K receive buffer to a fixed, available address outside the - 0x98000-0x9ffff range. This is a bit of a hack, but currently the only - way to make room for the Etherboot features that need substantial amounts - of code like the ANSI console support. Currently the buffer is just below - 0x10000, so this even conforms to the tagged boot image specification, - which reserves the ranges 0x00000-0x10000 and 0x98000-0xA0000. My - interpretation of this "reserved" is that Etherboot may do whatever it - likes, as long as its environment is kept intact (like the BIOS - variables). Hopefully fixed rtl_poll() once and for all. The symptoms - were that if Etherboot was left at the boot menu for several minutes, the - first eth_poll failed. Seems like I am the only person who does this. - First of all I fixed the debugging code and then set out for a long bug - hunting session. It took me about a week full time work - poking around - various places in the driver, reading Don Becker's and Jeff Garzik's Linux - driver and even the FreeBSD driver (what a piece of crap!) - and - eventually spotted the nasty thing: the transmit routine was acknowledging - each and every interrupt pending, including the RxOverrun and RxFIFIOver - interrupts. This confused the RTL8139 thoroughly. It destroyed the - Rx ring contents by dumping the 2K FIFO contents right where we wanted to - get the next packet. Oh well, what fun. - - 18 Jan 2000 mdc@etherboot.org (Marty Connor) - Drastically simplified error handling. Basically, if any error - in transmission or reception occurs, the card is reset. - Also, pointed all transmit descriptors to the same buffer to - save buffer space. This should decrease driver size and avoid - corruption because of exceeding 32K during runtime. - - 28 Jul 1999 (Matthias Meixner - meixner@rbg.informatik.tu-darmstadt.de) - rtl_poll was quite broken: it used the RxOK interrupt flag instead - of the RxBufferEmpty flag which often resulted in very bad - transmission performace - below 1kBytes/s. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TX_RING_SIZE 4 -#define TX_MAX_LEN 8192 - -struct rtl8139_tx { - unsigned int next; - struct io_buffer *iobuf[TX_RING_SIZE]; -}; - -struct rtl8139_rx { - void *ring; - unsigned int offset; -}; - -struct rtl8139_nic { - unsigned short ioaddr; - struct rtl8139_tx tx; - struct rtl8139_rx rx; - struct spi_bit_basher spibit; - struct spi_device eeprom; - struct nvo_block nvo; -}; - -/* Tuning Parameters */ -#define TX_FIFO_THRESH 256 /* In bytes, rounded down to 32 byte units. */ -#define RX_FIFO_THRESH 4 /* Rx buffer level before first PCI xfer. */ -#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 bytes */ -#define TX_DMA_BURST 4 /* Calculate as 16<ioaddr + Cfg9346 ); - return ( eereg & mask ); -} - -static void rtl_spi_write_bit ( struct bit_basher *basher, - unsigned int bit_id, unsigned long data ) { - struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, - spibit.basher ); - uint8_t mask = rtl_ee_bits[bit_id]; - uint8_t eereg; - - eereg = inb ( rtl->ioaddr + Cfg9346 ); - eereg &= ~mask; - eereg |= ( data & mask ); - outb ( eereg, rtl->ioaddr + Cfg9346 ); -} - -static struct bit_basher_operations rtl_basher_ops = { - .read = rtl_spi_read_bit, - .write = rtl_spi_write_bit, -}; - -/** - * Set up for EEPROM access - * - * @v netdev Net device - */ -static void rtl_init_eeprom ( struct net_device *netdev ) { - struct rtl8139_nic *rtl = netdev->priv; - int ee9356; - int vpd; - - /* Initialise three-wire bus */ - rtl->spibit.basher.op = &rtl_basher_ops; - rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; - init_spi_bit_basher ( &rtl->spibit ); - - /* Detect EEPROM type and initialise three-wire device */ - ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 ); - if ( ee9356 ) { - DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C56\n", rtl ); - init_at93c56 ( &rtl->eeprom, 16 ); - } else { - DBGC ( rtl, "rtl8139 %p EEPROM is an AT93C46\n", rtl ); - init_at93c46 ( &rtl->eeprom, 16 ); - } - rtl->eeprom.bus = &rtl->spibit.bus; - - /* Initialise space for non-volatile options, if available - * - * We use offset 0x40 (i.e. address 0x20), length 0x40. This - * block is marked as VPD in the rtl8139 datasheets, so we use - * it only if we detect that the card is not supporting VPD. - */ - vpd = ( inw ( rtl->ioaddr + Config1 ) & VPDEnable ); - if ( vpd ) { - DBGC ( rtl, "rtl8139 %p EEPROM in use for VPD; cannot use " - "for options\n", rtl ); - } else { - nvo_init ( &rtl->nvo, &rtl->eeprom.nvs, 0x20, 0x40, NULL, - &netdev->refcnt ); - } -} - -/** - * Reset NIC - * - * @v netdev Net device - * - * Issues a hardware reset and waits for the reset to complete. - */ -static void rtl_reset ( struct net_device *netdev ) { - struct rtl8139_nic *rtl = netdev->priv; - - /* Reset chip */ - outb ( CmdReset, rtl->ioaddr + ChipCmd ); - mdelay ( 10 ); - memset ( &rtl->tx, 0, sizeof ( rtl->tx ) ); - rtl->rx.offset = 0; -} - -/** - * Open NIC - * - * @v netdev Net device - * @ret rc Return status code - */ -static int rtl_open ( struct net_device *netdev ) { - struct rtl8139_nic *rtl = netdev->priv; - int i; - - /* Program the MAC address */ - for ( i = 0 ; i < ETH_ALEN ; i++ ) - outb ( netdev->ll_addr[i], rtl->ioaddr + MAC0 + i ); - - /* Set up RX ring */ - rtl->rx.ring = malloc ( RX_BUF_LEN + RX_BUF_PAD ); - if ( ! rtl->rx.ring ) - return -ENOMEM; - outl ( virt_to_bus ( rtl->rx.ring ), rtl->ioaddr + RxBuf ); - DBGC ( rtl, "rtl8139 %p RX ring at %lx\n", - rtl, virt_to_bus ( rtl->rx.ring ) ); - - /* Enable TX and RX */ - outb ( ( CmdRxEnb | CmdTxEnb ), rtl->ioaddr + ChipCmd ); - outl ( ( ( RX_FIFO_THRESH << 13 ) | ( RX_BUF_LEN_IDX << 11 ) | - ( RX_DMA_BURST << 8 ) | AcceptBroadcast | AcceptMulticast | - AcceptMyPhys | AcceptAllPhys ), rtl->ioaddr + RxConfig ); - outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 0 ); - outl ( 0xffffffffUL, rtl->ioaddr + MAR0 + 4 ); - outl ( ( ( TX_DMA_BURST << 8 ) | ( TX_IPG << 24 ) ), - rtl->ioaddr + TxConfig ); - - return 0; -} - -/** - * Close NIC - * - * @v netdev Net device - */ -static void rtl_close ( struct net_device *netdev ) { - struct rtl8139_nic *rtl = netdev->priv; - - /* Reset the hardware to disable everything in one go */ - rtl_reset ( netdev ); - - /* Free RX ring */ - free ( rtl->rx.ring ); - rtl->rx.ring = NULL; -} - -/** - * Transmit packet - * - * @v netdev Network device - * @v iobuf I/O buffer - * @ret rc Return status code - */ -static int rtl_transmit ( struct net_device *netdev, - struct io_buffer *iobuf ) { - struct rtl8139_nic *rtl = netdev->priv; - - /* Check for space in TX ring */ - if ( rtl->tx.iobuf[rtl->tx.next] != NULL ) { - DBGC ( rtl, "rtl8139 %p TX overflow\n", rtl ); - return -ENOBUFS; - } - - /* Check for oversized packets */ - if ( iob_len ( iobuf ) >= TX_MAX_LEN ) { - DBGC ( rtl, "rtl8139 %p TX too large (%zd bytes)\n", - rtl, iob_len ( iobuf ) ); - return -ERANGE; - } - - /* Pad and align packet */ - iob_pad ( iobuf, ETH_ZLEN ); - - /* Add to TX ring */ - DBGC2 ( rtl, "rtl8139 %p TX id %d at %lx+%zx\n", rtl, rtl->tx.next, - virt_to_bus ( iobuf->data ), iob_len ( iobuf ) ); - rtl->tx.iobuf[rtl->tx.next] = iobuf; - outl ( virt_to_bus ( iobuf->data ), - rtl->ioaddr + TxAddr0 + 4 * rtl->tx.next ); - outl ( ( ( ( TX_FIFO_THRESH & 0x7e0 ) << 11 ) | iob_len ( iobuf ) ), - rtl->ioaddr + TxStatus0 + 4 * rtl->tx.next ); - rtl->tx.next = ( rtl->tx.next + 1 ) % TX_RING_SIZE; - - return 0; -} - -/** - * Poll for received packets - * - * @v netdev Network device - */ -static void rtl_poll ( struct net_device *netdev ) { - struct rtl8139_nic *rtl = netdev->priv; - unsigned int status; - unsigned int tsad; - unsigned int rx_status; - unsigned int rx_len; - struct io_buffer *rx_iob; - int wrapped_len; - int i; - - /* Acknowledge interrupts */ - status = inw ( rtl->ioaddr + IntrStatus ); - if ( ! status ) - return; - outw ( status, rtl->ioaddr + IntrStatus ); - - /* Handle TX completions */ - tsad = inw ( rtl->ioaddr + TxSummary ); - for ( i = 0 ; i < TX_RING_SIZE ; i++ ) { - if ( ( rtl->tx.iobuf[i] != NULL ) && ( tsad & ( 1 << i ) ) ) { - DBGC2 ( rtl, "rtl8139 %p TX id %d complete\n", - rtl, i ); - netdev_tx_complete ( netdev, rtl->tx.iobuf[i] ); - rtl->tx.iobuf[i] = NULL; - } - } - - /* Handle received packets */ - while ( ! ( inb ( rtl->ioaddr + ChipCmd ) & RxBufEmpty ) ) { - rx_status = * ( ( uint16_t * ) - ( rtl->rx.ring + rtl->rx.offset ) ); - rx_len = * ( ( uint16_t * ) - ( rtl->rx.ring + rtl->rx.offset + 2 ) ); - if ( rx_status & RxOK ) { - DBGC2 ( rtl, "rtl8139 %p RX packet at offset " - "%x+%x\n", rtl, rtl->rx.offset, rx_len ); - - rx_iob = alloc_iob ( rx_len ); - if ( ! rx_iob ) { - netdev_rx_err ( netdev, NULL, -ENOMEM ); - /* Leave packet for next call to poll() */ - break; - } - - wrapped_len = ( ( rtl->rx.offset + 4 + rx_len ) - - RX_BUF_LEN ); - if ( wrapped_len < 0 ) - wrapped_len = 0; - - memcpy ( iob_put ( rx_iob, rx_len - wrapped_len ), - rtl->rx.ring + rtl->rx.offset + 4, - rx_len - wrapped_len ); - memcpy ( iob_put ( rx_iob, wrapped_len ), - rtl->rx.ring, wrapped_len ); - iob_unput ( rx_iob, 4 ); /* Strip CRC */ - - netdev_rx ( netdev, rx_iob ); - } else { - DBGC ( rtl, "rtl8139 %p RX bad packet (status %#04x " - "len %d)\n", rtl, rx_status, rx_len ); - netdev_rx_err ( netdev, NULL, -EINVAL ); - } - rtl->rx.offset = ( ( ( rtl->rx.offset + 4 + rx_len + 3 ) & ~3 ) - % RX_BUF_LEN ); - outw ( rtl->rx.offset - 16, rtl->ioaddr + RxBufPtr ); - } -} - -/** - * Enable/disable interrupts - * - * @v netdev Network device - * @v enable Interrupts should be enabled - */ -static void rtl_irq ( struct net_device *netdev, int enable ) { - struct rtl8139_nic *rtl = netdev->priv; - - DBGC ( rtl, "rtl8139 %p interrupts %s\n", - rtl, ( enable ? "enabled" : "disabled" ) ); - outw ( ( enable ? ( ROK | RER | TOK | TER ) : 0 ), - rtl->ioaddr + IntrMask ); -} - -/** RTL8139 net device operations */ -static struct net_device_operations rtl_operations = { - .open = rtl_open, - .close = rtl_close, - .transmit = rtl_transmit, - .poll = rtl_poll, - .irq = rtl_irq, -}; - -/** - * Probe PCI device - * - * @v pci PCI device - * @v id PCI ID - * @ret rc Return status code - */ -static int rtl_probe ( struct pci_device *pci ) { - struct net_device *netdev; - struct rtl8139_nic *rtl; - int rc; - - /* Allocate net device */ - netdev = alloc_etherdev ( sizeof ( *rtl ) ); - if ( ! netdev ) - return -ENOMEM; - netdev_init ( netdev, &rtl_operations ); - rtl = netdev->priv; - pci_set_drvdata ( pci, netdev ); - netdev->dev = &pci->dev; - memset ( rtl, 0, sizeof ( *rtl ) ); - rtl->ioaddr = pci->ioaddr; - - /* Fix up PCI device */ - adjust_pci_device ( pci ); - - /* Reset the NIC, set up EEPROM access and read MAC address */ - rtl_reset ( netdev ); - rtl_init_eeprom ( netdev ); - nvs_read ( &rtl->eeprom.nvs, EE_MAC, netdev->hw_addr, ETH_ALEN ); - - /* Register network device */ - if ( ( rc = register_netdev ( netdev ) ) != 0 ) - goto err_register_netdev; - - /* Mark as link up; we don't yet handle link state */ - netdev_link_up ( netdev ); - - /* Register non-volatile storage */ - if ( rtl->nvo.nvs ) { - if ( ( rc = register_nvo ( &rtl->nvo, - netdev_settings ( netdev ) ) ) != 0) - goto err_register_nvo; - } - - return 0; - - err_register_nvo: - unregister_netdev ( netdev ); - err_register_netdev: - rtl_reset ( netdev ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); - return rc; -} - -/** - * Remove PCI device - * - * @v pci PCI device - */ -static void rtl_remove ( struct pci_device *pci ) { - struct net_device *netdev = pci_get_drvdata ( pci ); - struct rtl8139_nic *rtl = netdev->priv; - - if ( rtl->nvo.nvs ) - unregister_nvo ( &rtl->nvo ); - unregister_netdev ( netdev ); - rtl_reset ( netdev ); - netdev_nullify ( netdev ); - netdev_put ( netdev ); -} - -static struct pci_device_id rtl8139_nics[] = { -PCI_ROM(0x10ec, 0x8129, "rtl8129", "Realtek 8129", 0), -PCI_ROM(0x10ec, 0x8139, "rtl8139", "Realtek 8139", 0), -PCI_ROM(0x10ec, 0x8138, "rtl8139b", "Realtek 8139B", 0), -PCI_ROM(0x1186, 0x1300, "dfe538", "DFE530TX+/DFE538TX", 0), -PCI_ROM(0x1113, 0x1211, "smc1211-1", "SMC EZ10/100", 0), -PCI_ROM(0x1112, 0x1211, "smc1211", "SMC EZ10/100", 0), -PCI_ROM(0x1500, 0x1360, "delta8139", "Delta Electronics 8139", 0), -PCI_ROM(0x4033, 0x1360, "addtron8139", "Addtron Technology 8139", 0), -PCI_ROM(0x1186, 0x1340, "dfe690txd", "D-Link DFE690TXD", 0), -PCI_ROM(0x13d1, 0xab06, "fe2000vx", "AboCom FE2000VX", 0), -PCI_ROM(0x1259, 0xa117, "allied8139", "Allied Telesyn 8139", 0), -PCI_ROM(0x14ea, 0xab06, "fnw3603tx", "Planex FNW-3603-TX", 0), -PCI_ROM(0x14ea, 0xab07, "fnw3800tx", "Planex FNW-3800-TX", 0), -PCI_ROM(0xffff, 0x8139, "clone-rtl8139", "Cloned 8139", 0), -}; - -struct pci_driver rtl8139_driver __pci_driver = { - .ids = rtl8139_nics, - .id_count = ( sizeof ( rtl8139_nics ) / sizeof ( rtl8139_nics[0] ) ), - .probe = rtl_probe, - .remove = rtl_remove, -}; From 838a76a0426844e918d12ae0d2e2ee7622a0eca6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 28 Apr 2012 23:18:55 +0100 Subject: [PATCH 197/221] [menu] Add "--default" option to "choose" command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Robin Smidsrød Signed-off-by: Michael Brown --- src/hci/commands/menu_cmd.c | 10 +++++++--- src/hci/tui/menu_ui.c | 11 ++++++++--- src/include/ipxe/menu.h | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/hci/commands/menu_cmd.c b/src/hci/commands/menu_cmd.c index 8dac3cb8..ff3b76fa 100644 --- a/src/hci/commands/menu_cmd.c +++ b/src/hci/commands/menu_cmd.c @@ -194,6 +194,8 @@ struct choose_options { const char *menu; /** Timeout */ unsigned int timeout; + /** Default selection */ + const char *select; /** Keep menu */ int keep; }; @@ -202,6 +204,8 @@ struct choose_options { static struct option_descriptor choose_opts[] = { OPTION_DESC ( "menu", 'm', required_argument, struct choose_options, menu, parse_string ), + OPTION_DESC ( "default", 'd', required_argument, + struct choose_options, select, parse_string ), OPTION_DESC ( "timeout", 't', required_argument, struct choose_options, timeout, parse_integer ), OPTION_DESC ( "keep", 'k', no_argument, @@ -211,8 +215,8 @@ static struct option_descriptor choose_opts[] = { /** "choose" command descriptor */ static struct command_descriptor choose_cmd = COMMAND_DESC ( struct choose_options, choose_opts, 1, 1, - "[--menu ] [--timeout ] [--keep] " - "" ); + "[--menu ] [--default