64-bit data integrity field support
Subsystems (7)
Keith Busch
maintainerv3 cover 64-bit data integrity field support
The NVM Express protocol added enhancements to the data integrity field formats beyond the T10 defined protection information. A detailed description of the new formats can be found in the NVMe's NVM Command Set Specification, section 5.2, available at:
https://nvmexpress.org/wp-content/uploads/NVM-Command-Set-Specification-1.0b-2021.12.18-Ratified.pdf
This series implements one possible new format: the CRC64 guard with 48-bit reference tags. This does not add support for the variable "storage tag" field, or any potential hardware acceleration.
Changes since v2:
Introduced lower_48_bits() (Bart)
Added "64" suffix to crc names to distinguish from other crc calculations (Martin)
Added module support to crypto library, and have the integrity generate/verify use that instead of directly calling the generic table lookup implementation. This is modeled after the t10 implementation.
Added an x86 pclmul accelerated crc64 calculation
Added speed tests to the test module so that the generic and library function could be compared.
Bug fix in nvme to select the correct integrity profile.
Added reviews
Note, I am not particularly well versed with x86 assembly, so I'm reasonably sure that the pcl implementation could be improved. It currently is about 20x faster than the generic implementation, but I believe it could be over 30x faster if done more efficiently.
Keith Busch (10):
block: support pi with extended metadata
nvme: allow integrity on extended metadata formats
asm-generic: introduce be48 unaligned accessors linux/kernel: introduce lower_48_bits macro
lib: add rocksoft model crc64
crypto: add rocksoft 64b crc guard tag framework
lib: add crc64 tests
block: add pi for nvme enhanced integrity
nvme: add support for enhanced metadata x86/crypto: add pclmul acceleration for crc64
arch/x86/crypto/Makefile | 3 + arch/x86/crypto/crc64-rocksoft-pcl-asm.S | 215 ++++++++++++++++++++++ arch/x86/crypto/crc64-rocksoft-pcl_glue.c | 117 ++++++++++++ block/Kconfig | 1 + block/bio-integrity.c | 1 + block/t10-pi.c | 198 +++++++++++++++++++- crypto/Kconfig | 20 ++ crypto/Makefile | 1 + crypto/crc64_rocksoft_generic.c | 104 +++++++++++ drivers/nvme/host/core.c | 175 ++++++++++++++---- drivers/nvme/host/nvme.h | 4 +- include/asm-generic/unaligned.h | 26 +++ include/linux/blk-integrity.h | 1 + include/linux/crc64.h | 7 + include/linux/kernel.h | 6 + include/linux/nvme.h | 53 +++++- include/linux/t10-pi.h | 20 ++ lib/Kconfig | 9 + lib/Kconfig.debug | 4 + lib/Makefile | 2 + lib/crc64-rocksoft.c | 129 +++++++++++++ lib/crc64.c | 26 +++ lib/gen_crc64table.c | 51 +++-- lib/test_crc64.c | 133 +++++++++++++ 24 files changed, 1252 insertions(+), 54 deletions(-) create mode 100644 arch/x86/crypto/crc64-rocksoft-pcl-asm.S create mode 100644 arch/x86/crypto/crc64-rocksoft-pcl_glue.c create mode 100644 crypto/crc64_rocksoft_generic.c create mode 100644 lib/crc64-rocksoft.c create mode 100644 lib/test_crc64.c
Signature · 1 line
2.25.4
Keith Busch
maintainerPATCH v3 1/10 block: support pi with extended metadata
The nvme spec allows protection information formats with metadata extending beyond the pi field. Use the actual size of the metadata field for incrementing the buffer.
--- block/bio-integrity.c | 1 + block/t10-pi.c | 4 ++-- include/linux/blk-integrity.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-)
block/bio-integrity.c +1 -0
@@ -165,6 +165,7 @@ static blk_status_t bio_integrity_process(struct bio *bio, iter.disk_name = bio->bi_bdev->bd_disk->disk_name; iter.interval =1 << bi->interval_exp; + iter.tuple_size = bi->tuple_size; iter.seed = proc_iter->bi_sector; iter.prot_buf =bvec_virt (bip->bip_vec);
block/t10-pi.c +2 -2
@@ -44,7 +44,7 @@ static blk_status_t t10_pi_generate(struct blk_integrity_iter *iter, pi->ref_tag =0 ; iter->data_buf += iter->interval; - iter->prot_buf +=sizeof (struct t10_pi_tuple ); + iter->prot_buf += iter->tuple_size; iter->seed++; }
@@ -93,7 +93,7 @@ static blk_status_t t10_pi_verify(struct blk_integrity_iter *iter, next: iter->data_buf += iter->interval; - iter->prot_buf +=sizeof (struct t10_pi_tuple ); + iter->prot_buf += iter->tuple_size; iter->seed++; }
include/linux/blk-integrity.h +1 -0
@@ -19,6 +19,7 @@ struct blk_integrity_iter {sector_t seed;unsigned int data_size;unsigned short interval; +unsigned char tuple_size;const char *disk_name; };
Signature · 1 line
2.25.4
Re: [PATCHv3 01/10] block: support pi with extended metadata
Looks good:
Keith Busch
maintainerPATCH v3 2/10 nvme: allow integrity on extended metadata formats
In reply to Keith BuschThe block integrity subsystem knows how to construct protection information buffers with metadata beyond the protection information fields. Remove the driver restriction.
Note, this can only work if the PI field appears first in the metadata, as the integrity subsystem doesn't calculate guard tags on preceding metadata.
--- drivers/nvme/host/core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
drivers/nvme/host/core.c +2 -5
@@ -1760,12 +1760,9 @@ static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id) {struct nvme_ctrl *ctrl = ns->ctrl; -/* -* The PI implementation requires the metadata size to be equal to the -* t10 pi tuple size. -*/ ns->ms =le16_to_cpu (id->lbaf[id->flbas &NVME_NS_FLBAS_LBA_MASK ].ms); -if (ns->ms ==sizeof (struct t10_pi_tuple )) +if (id->dps &NVME_NS_DPS_PI_FIRST || + ns->ms ==sizeof (struct t10_pi_tuple )) ns->pi_type = id->dps &NVME_NS_DPS_PI_MASK ;else ns->pi_type =0 ;
Signature · 1 line
2.25.4
Re: [PATCHv3 02/10] nvme: allow integrity on extended metadata formats
Quoted 11 lines · Keith Busch
The block integrity subsystem knows how to construct protection information buffers with metadata beyond the protection information fields. Remove the driver restriction.
Note, this can only work if the PI field appears first in the metadata, as the integrity subsystem doesn't calculate guard tags on preceding metadata.
Reviewed-by Hannes Reinecke <[email protected]>Reviewed-by Martin K. Petersen <[email protected]>Signed-off-by Keith Busch <[email protected]>
Looks good,
Keith Busch
maintainerPATCH v3 3/10 asm-generic: introduce be48 unaligned accessors
In reply to Keith BuschThe NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags. Provide some helper accessors in preparation for these.
--- include/asm-generic/unaligned.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
include/asm-generic/unaligned.h +26 -0
@@ -126,4 +126,30 @@ static inline void put_unaligned_le24(const u32 val, void *p)__put_unaligned_le24 (val, p); } +static inline void __put_unaligned_be48 (const u64 val,__u8 *p) +{ + *p++ = val >>40 ; + *p++ = val >>32 ; + *p++ = val >>24 ; + *p++ = val >>16 ; + *p++ = val >>8 ; + *p++ = val; +} + +static inline void put_unaligned_be48 (const u64 val,void *p) +{ +__put_unaligned_be48 (val, p); +} + +static inline u64 __get_unaligned_be48 (const u8 *p) +{ +return (u64 )p[0 ] <<40 | (u64 )p[1 ] <<32 | p[2 ] <<24 | + p[3 ] <<16 | p[4 ] <<8 | p[5 ]; +} + +static inline u64 get_unaligned_be48 (const void *p) +{ +return __get_unaligned_be48 (p); +} +#endif /* __ASM_GENERIC_UNALIGNED_H */
Signature · 1 line
2.25.4
Re: [PATCHv3 03/10] asm-generic: introduce be48 unaligned accessors
Quoted 9 lines · Keith Busch
The NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags. Provide some helper accessors in preparation for these.
Reviewed-by Hannes Reinecke <[email protected]>Reviewed-by Martin K. Petersen <[email protected]>Acked-by Arnd Bergmann <[email protected]>Signed-off-by Keith Busch <[email protected]>---
Looks good.
-ck
Re: [PATCHv3 03/10] asm-generic: introduce be48 unaligned accessors
In reply to Keith BuschQuoted 8 lines · Keith Busch
The NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags. Provide some helper accessors in preparation for these.
Reviewed-by Hannes Reinecke <[email protected]>Reviewed-by Martin K. Petersen <[email protected]>Acked-by Arnd Bergmann <[email protected]>Signed-off-by Keith Busch <[email protected]>
Looks good,
Re: [PATCHv3 03/10] asm-generic: introduce be48 unaligned accessors
Quoted 5 lines · Christoph Hellwig
Quoted 4 lines · Keith Busch
The NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags. Provide some helper accessors in preparation for these.
Quoted 8 lines
Quoted 4 lines
Reviewed-by Hannes Reinecke <[email protected]>Reviewed-by Martin K. Petersen <[email protected]>Acked-by Arnd Bergmann <[email protected]>Signed-off-by Keith Busch <[email protected]>Looks good,
Reviewed-by Christoph Hellwig <[email protected]>
Perhaps for completeness this should also add the le48 variants like the 24 bit accessors above this.
Keith Busch
maintainerRe: [PATCHv3 03/10] asm-generic: introduce be48 unaligned accessors
Quoted 11 lines · Joe Perches
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Keith Busch
The NVMe protocol extended the data integrity fields with unaligned 48-bit reference tags. Provide some helper accessors in preparation for these.
Reviewed-by Hannes Reinecke <[email protected]>Reviewed-by Martin K. Petersen <[email protected]>Acked-by Arnd Bergmann <[email protected]>Signed-off-by Keith Busch <[email protected]>
Quoted 6 lines
Quoted 3 lines
Looks good,
Reviewed-by Christoph Hellwig <[email protected]>Perhaps for completeness this should also add the le48 variants like the 24 bit accessors above this.
I don't know of a user for le48 at this time, and kernel API's without users often get culled. If you think it's useful, though, I can certainly include it.
Keith Busch
maintainerPATCH v3 4/10 linux/kernel: introduce lower_48_bits macro
In reply to Keith BuschRecent data integrity field enhancements allow 48-bit reference tags. Introduce a helper macro since this will be a repeated operation.
--- include/linux/kernel.h | 6 ++++++ 1 file changed, 6 insertions(+)
include/linux/kernel.h +6 -0
@@ -63,6 +63,12 @@ } \ ) +/** +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull)) +/** * upper_32_bits - return bits 32-63 of a number * @n: the number we're accessing
Signature · 1 line
2.25.4
Re: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
Quoted 2 lines · Keith Busch
Recent data integrity field enhancements allow 48-bit reference tags. Introduce a helper macro since this will be a repeated operation.
[]
include/linux/kernel.h
Quoted 1 line
include/linux/kernel.h +0
-0
[]
include/linux/kernel.h line 70
Quoted 9 lines
include/linux/kernel.h +5
-0@@ -63,6 +63,12 @@ } \ ) +/** +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))
why not make this a static inline function?
And visually, it's difficult to quickly count a repeated character to 12.
Perhaps:
static inline u64 lower_48_bits(u64 val)
{
return val & GENMASK_ULL(47, 0);
}Christoph Hellwig
maintainerRe: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
Quoted 10 lines · Joe Perches
Quoted 2 lines · Keith Busch
Recent data integrity field enhancements allow 48-bit reference tags. Introduce a helper macro since this will be a repeated operation.
[]
include/linux/kernel.h
Quoted 1 line
include/linux/kernel.h +0
-0[]
Quoted 4 lines
include/linux/kernel.h +0
-0@@ -63,6 +63,12 @@ } \ )
Quoted 7 lines
include/linux/kernel.h line 70
Quoted 5 lines
include/linux/kernel.h +5
-0+/** +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Agreed.
Quoted 8 lines
And visually, it's difficult to quickly count a repeated character to 12.
Perhaps:
static inline u64
lower_48_bits(u64 val){ return val & GENMASK_ULL(47, 0); }
For anyone who has a minimum knowledge of C and hardware your version is an obsfucated clusterfuck, while the version Keith wrote is trivial to read.
Keith Busch
maintainerRe: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
Quoted 11 lines · Christoph Hellwig
Quoted 8 lines · Joe Perches
include/linux/kernel.h line 70
Quoted 5 lines · Keith Busch
include/linux/kernel.h +5
-0+/** +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Agreed.
Sure, that sounds good to me. I only did it this way to match the existing local convention, but I personally prefer the inline function too.
Re: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
Quoted 11 lines · Keith Busch
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Joe Perches
include/linux/kernel.h line 70
Quoted 5 lines · Keith Busch
include/linux/kernel.h +5
-0+/ * +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Quoted 5 lines
Quoted 1 line
Agreed.
Sure, that sounds good to me. I only did it this way to match the existing local convention, but I personally prefer the inline function too.
The existing convention is used there to allow the compiler to avoid warnings and unnecessary conversions of a u32 to a u64 when shifting by 32 or more bits.
If it's possible to be used with an architecture dependent typedef like dma_addr_t, then perhaps it's reasonable to do something like:
#define lower_48_bits(val) \
({ \
typeof(val) high = lower_16_bits(upper_32_bits(val)); \
typeof(val) low = lower_32_bits(val); \
\
(high << 16 << 16) | low; \
})and have the compiler have the return value be an appropriate type.
RE: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
From: Joe Perches
Quoted 28 lines
Sent: 22 February 2022 18:43
Quoted 11 lines · Keith Busch
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Joe Perches
include/linux/kernel.h line 70
Quoted 5 lines · Keith Busch
include/linux/kernel.h +5
-0+/ * +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Quoted 5 lines
Quoted 1 line
Agreed.
Sure, that sounds good to me. I only did it this way to match the existing local convention, but I personally prefer the inline function too.
The existing convention is used there to allow the compiler to avoid warnings and unnecessary conversions of a u32 to a u64 when shifting by 32 or more bits.
If it's possible to be used with an architecture dependent typedef like
dma_addr_t, then perhaps it's reasonable to do something like:#define
lower_48_bits(val)\
Quoted 8 lines
({ \ typeof(val) high = lower_16_bits(upper_32_bits(val)); \ typeof(val) low = lower_32_bits(val); \ \ (high << 16 << 16) | low; \ })and have the compiler have the return value be an appropriate type.
The compiler could make a real pigs breakfast of that.
For lower_46_bits() an integer promotion to u64 does no harm. But for some other cases you get in a right mess when values that should be unsigned get sign extended.
Although I think:
(val) & (((typeof(val))1 << 48) - 1)
avoids any promotion if anyone tries lower_48_bits(int_var). (It is even likely to be a compile error.)
Oh, did you look for GENMASK([^,]*,[ 0]*) ?
I'd only use something GENMASK() for bit ranges. Even then it is often easier to just write the value in hex.
I think the only time I've written anything like that recently (last 30 years) was for some hardware registers when the documentation user 'bit 1' for the most significant bit.
It's rather like I just know that (x & (x - 1)) checks for 1 bit being set. I have to lookup is_power_of_2() to see what it does.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
Quoted 36 lines · David Laight
From: Joe Perches
Quoted 35 lines
Sent: 22 February 2022 18:43
Quoted 11 lines · Keith Busch
Quoted 10 lines · Christoph Hellwig
Quoted 8 lines · Joe Perches
include/linux/kernel.h line 70
Quoted 5 lines · Keith Busch
include/linux/kernel.h +5
-0+/ * +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Quoted 5 lines
Quoted 1 line
Agreed.
Sure, that sounds good to me. I only did it this way to match the existing local convention, but I personally prefer the inline function too.
The existing convention is used there to allow the compiler to avoid warnings and unnecessary conversions of a u32 to a u64 when shifting by 32 or more bits.
If it's possible to be used with an architecture dependent typedef like
dma_addr_t, then perhaps it's reasonable to do something like:#define
lower_48_bits(val)\({ \ typeof(val) high = lower_16_bits(upper_32_bits(val)); \ typeof(val) low = lower_32_bits(val); \ \ (high << 16 << 16) | low; \ })
Quoted 3 lines
Quoted 1 line
and have the compiler have the return value be an appropriate type.
The compiler could make a real pigs breakfast of that.
Both gcc and clang optimize it just fine.
btw: to return the same type the last line should be:
(typeof(val))((high << 16 << 16) | low);
otherwise the return is sizeof(int) if typeof(val) is not u64
Quoted 1 line
Oh, did you look for
GENMASK([^,]*,[ 0]*)?
No, why? I did look for 47, 0 though.
But it's pretty common really.
$ git grep -P 'GENMASK(?:_ULL)?\s*\(\s*\d+\s*,\s*0\s*\)' | wc -l 6233
Quoted 2 lines
I'd only use something
GENMASK()for bit ranges. Even then it is often easier to just write the value in hex.
Mostly it's the count of the repeated f that's difficult to quickly verify visually.
Quoted 3 lines
I think the only time I've written anything like that recently (last 30 years) was for some hardware registers when the documentation user 'bit 1' for the most significant bit.
Luckily the hardware I've had to deal with never did that. Not even the least significant bit too.
Keith Busch
maintainerRe: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
Quoted 5 lines · Joe Perches
Quoted 2 lines
I'd only use something
GENMASK()for bit ranges. Even then it is often easier to just write the value in hex.Mostly it's the count of the repeated f that's difficult to quickly verify visually.
I admit I made this counting mistake in earlier versions of this series.
I think the earlier suggested "(1ull << 48) - 1" style in an inline function seems good, and it doesn't appear to cause compiler concerns.
Re: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
Quoted 8 lines · Keith Busch
Quoted 5 lines · Joe Perches
Quoted 2 lines
I'd only use something
GENMASK()for bit ranges. Even then it is often easier to just write the value in hex.Mostly it's the count of the repeated f that's difficult to quickly verify visually.
I admit I made this counting mistake in earlier versions of this series.
It's simply hard for humans to do...
Re: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
In reply to Christoph HellwigQuoted 25 lines · Christoph Hellwig
Quoted 10 lines · Joe Perches
Quoted 2 lines · Keith Busch
Recent data integrity field enhancements allow 48-bit reference tags. Introduce a helper macro since this will be a repeated operation.
[]
include/linux/kernel.h
Quoted 1 line
include/linux/kernel.h +0
-0[]
Quoted 4 lines
include/linux/kernel.h +0
-0@@ -63,6 +63,12 @@ } \ )Quoted 7 lines
include/linux/kernel.h line 70
Quoted 5 lines
include/linux/kernel.h +5
-0+/** +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Agreed.
Quoted 4 lines
And visually, it's difficult to quickly count a repeated character to 12.
Perhaps:
Quoted 8 lines
Quoted 4 lines
static inline u64
lower_48_bits(u64 val){ return val & GENMASK_ULL(47, 0); }For anyone who has a minimum knowledge of C and hardware your version is an obsfucated clusterfuck, while the version Keith wrote is trivial to read.
Don't think so. I've dealt with hardware and have more than once seen defects introduced by firmware developers that can't count.
be quick, which one is it:
0xfffffffffffULL or 0xffffffffffffULL or 0xfffffffffffffULL or 0xffffffffffffffULL
RE: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
In reply to Christoph HellwigFrom: Christoph Hellwig
Quoted 27 lines
Sent: 22 February 2022 16:51
Quoted 10 lines · Joe Perches
Quoted 2 lines · Keith Busch
Recent data integrity field enhancements allow 48-bit reference tags. Introduce a helper macro since this will be a repeated operation.
[]
include/linux/kernel.h
Quoted 1 line
include/linux/kernel.h +0
-0[]
Quoted 4 lines
include/linux/kernel.h +0
-0@@ -63,6 +63,12 @@ } \ )Quoted 7 lines
include/linux/kernel.h line 70
Quoted 5 lines
include/linux/kernel.h +5
-0+/** +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Agreed.
Quoted 4 lines
And visually, it's difficult to quickly count a repeated character to 12.
Perhaps:
Quoted 8 lines
Quoted 4 lines
static inline u64
lower_48_bits(u64 val){ return val & GENMASK_ULL(47, 0); }For anyone who has a minimum knowledge of C and hardware your version is an obsfucated clusterfuck, while the version Keith wrote is trivial to read.
I'd use the explicit: val & ((1ull << 48) - 1)
I think it is even fewer characters.
David.
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
In reply to Christoph HellwigQuoted 19 lines · Christoph Hellwig
Quoted 10 lines · Joe Perches
Quoted 2 lines · Keith Busch
Recent data integrity field enhancements allow 48-bit reference tags. Introduce a helper macro since this will be a repeated operation.
[]
include/linux/kernel.h
Quoted 1 line
include/linux/kernel.h +0
-0[]
Quoted 4 lines
include/linux/kernel.h +0
-0@@ -63,6 +63,12 @@ } \ )Quoted 7 lines
include/linux/kernel.h line 70
Quoted 5 lines
include/linux/kernel.h +5
-0+/** +* lower_48_bits - return bits 0-47 of a number +* @n: the number we're accessing +*/ +#define lower_48_bits (n) ((u64)((n) & 0xffffffffffffull))why not make this a static inline function?
Quoted 2 lines
Agreed.
All the bit maskd macros in the same file needs to be converted into static inline to have the right data type, however that needs to be done once this series is in, since clearly objective of this series is different than cleanup of include/linux/kernel.h bit macros.
-ck
Re: [PATCHv3 04/10] linux/kernel: introduce lower_48_bits macro
In reply to Keith BuschQuoted 6 lines · Keith Busch
Recent data integrity field enhancements allow 48-bit reference tags. Introduce a helper macro since this will be a repeated operation.
Suggested-by Bart Van Assche <[email protected]>Signed-off-by Keith Busch <[email protected]>---
Looks good.
Keith Busch
maintainerPATCH v3 5/10 lib: add rocksoft model crc64
In reply to Keith BuschThe NVM Express specification extended data integrity fields to 64 bits using the Rocksoft^TM parameters. Add the poly to the crc64 table generation, and provide a generic library routine implementing the algorithm.
The Rocksoft 64-bit CRC model parameters are as follows:
Poly: 0xAD93D23594C93659
Initial value: 0xFFFFFFFFFFFFFFFF
Reflected Input: True
Reflected Output: True
Xor Final: 0xFFFFFFFFFFFFFFFFSince this model used reflected bits, the implementation generates the reflected table so the result is ordered consistently.
--- include/linux/crc64.h | 2 ++ lib/crc64.c | 26 ++++++++++++++++++++++ lib/gen_crc64table.c | 51 +++++++++++++++++++++++++++++++++---------- 3 files changed, 68 insertions(+), 11 deletions(-)
include/linux/crc64.h +2 -0
@@ -8,4 +8,6 @@#include <linux/types.h> u64 __pure crc64_be (u64 crc,const void *p,size_t len); +u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len); +#endif /* _LINUX_CRC64_H */
lib/crc64.c +26 -0
@@ -22,6 +22,13 @@* x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 + * x^7 + x^4 + x + 1 * +* crc64rocksoft[256] table is from the Rocksoft specification polynomial +* defined as, +* +* x^64 + x^63 + x^61 + x^59 + x^58 + x^56 + x^55 + x^52 + x^49 + x^48 + x^47 + +* x^46 + x^44 + x^41 + x^37 + x^36 + x^34 + x^32 + x^31 + x^28 + x^26 + x^23 + +* x^22 + x^19 + x^16 + x^13 + x^12 + x^10 + x^9 + x^6 + x^4 + x^3 + 1 +* * Copyright 2018 SUSE Linux. * Author: Coly Li <[email protected]> */
@@ -55,3 +62,22 @@ u64 __pure crc64_be(u64 crc, const void *p, size_t len)return crc; }EXPORT_SYMBOL_GPL (crc64_be); + +/** +* crc64_rocksoft_generic - Calculate bitwise Rocksoft CRC64 +* @crc: seed value for computation. (u64)~0 for a new CRC calculation, or the +* previous crc64 value if computing incrementally. +* @p: pointer to buffer over which CRC64 is run +* @len: length of buffer @p +*/ +u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len) +{ +const unsigned char *_p = p; +size_t i; + +for (i =0 ; i < len; i++) + crc = (crc >>8 ) ^ crc64rocksofttable[(crc &0xff ) ^ *_p++]; + +return crc ^ (u64 )~0 ; +} +EXPORT_SYMBOL_GPL (crc64_rocksoft_generic);
lib/gen_crc64table.c +40 -11
85 lines not on this page · raw message
Signature · 1 line
2.25.4
Re: [PATCHv3 05/10] lib: add rocksoft model crc64
Looks good,
Keith Busch
maintainerPATCH v3 6/10 crypto: add rocksoft 64b crc framework
In reply to Keith BuschHardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
--- crypto/Kconfig | 9 +++ crypto/Makefile | 1 + crypto/crc64_rocksoft_generic.c | 104 +++++++++++++++++++++++++ include/linux/crc64.h | 5 ++ lib/Kconfig | 9 +++ lib/Makefile | 1 + lib/crc64-rocksoft.c | 129 ++++++++++++++++++++++++++++++++ 7 files changed, 258 insertions(+) create mode 100644 crypto/crc64_rocksoft_generic.c create mode 100644 lib/crc64-rocksoft.c
crypto/Kconfig +9 -0
@@ -735,6 +735,15 @@ config CRYPTO_CRCT10DIF_VPMSUM multiply-sum (vpmsum) instructions, introduced in POWER8. Enable on POWER8 and newer processors for improved performance. +config CRYPTO_CRC64_ROCKSOFT + tristate "Rocksoft Model CRC64 algorithm" + depends on CRC64 + select CRYPTO_HASH + help + Rocksoft Model CRC64 computation is being cast as a crypto + transform. This allows for faster crc64 transforms to be used + if they are available. + config CRYPTO_VPMSUM_TESTER tristate "Powerpc64 vpmsum hardware acceleration tester" depends on CRYPTO_CRCT10DIF_VPMSUM && CRYPTO_CRC32C_VPMSUM
crypto/Makefile +1 -0
@@ -152,6 +152,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o +obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT) += crc64_rocksoft_generic.o obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o obj-$(CONFIG_CRYPTO_LZO) += lzo.o lzo-rle.o obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
crypto/crc64_rocksoft_generic.c new file +104 -0
104 lines not on this page · raw message
include/linux/crc64.h +5 -0
@@ -7,7 +7,12 @@#include <linux/types.h> +#define CRC64_ROCKSOFT_STRING "crc64-rocksoft" +u64 __pure crc64_be (u64 crc,const void *p,size_t len);u64 __pure crc64_rocksoft_generic (u64 crc,const void *p,size_t len); +u64 crc64_rocksoft (const unsigned char *buffer,size_t len); +u64 crc64_rocksoft_update (u64 crc,const unsigned char *buffer,size_t len); +#endif /* _LINUX_CRC64_H */
lib/Kconfig +9 -0
@@ -146,6 +146,15 @@ config CRC_T10DIF kernel tree needs to calculate CRC checks for use with the SCSI data integrity subsystem. +config CRC64_ROCKSOFT + tristate "CRC calculation for the Rocksoft^TM model CRC64" + select CRYPTO + select CRYPTO_CRC64_ROCKSOFT + help + This option is only needed if a module that's not in the + kernel tree needs to calculate CRC checks for use with the + rocksoft model parameters. + config CRC_ITU_T tristate "CRC ITU-T V.41 functions" help
lib/Makefile +1 -0
@@ -177,6 +177,7 @@ obj-$(CONFIG_LIBCRC32C) += libcrc32c.o obj-$(CONFIG_CRC8) += crc8.o obj-$(CONFIG_XXHASH) += xxhash.o obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o +obj-$(CONFIG_CRC64_ROCKSOFT) += crc64-rocksoft.o obj-$(CONFIG_842_COMPRESS) += 842/ obj-$(CONFIG_842_DECOMPRESS) += 842/
lib/crc64-rocksoft.c new file +129 -0
129 lines not on this page · raw message
Signature · 1 line
2.25.4
Eric Biggers
maintainerRe: [PATCHv3 06/10] crypto: add rocksoft 64b crc framework
crypto/Kconfig config CRYPTO_CRCT10DIF_VPMSUM · line 745
Quoted 8 lines · Keith Busch
crypto/Kconfig +8
-0+config CRYPTO_CRC64_ROCKSOFT + tristate "Rocksoft Model CRC64 algorithm" + depends on CRC64 + select CRYPTO_HASH + help + Rocksoft Model CRC64 computation is being cast as a crypto + transform. This allows for faster crc64 transforms to be used + if they are available.
The first sentence of this help text doesn't make sense.
crypto/crc64_rocksoft_generic.c line 3
Quoted 9 lines
crypto/crc64_rocksoft_generic.c new file +3
-0@@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Cryptographic API.
The "Cryptographic API" line doesn't provide any helpful information.
crypto/crc64_rocksoft_generic.c line 54
Quoted 13 lines
crypto/crc64_rocksoft_generic.c new file +13
-0+static int chksum_final (struct shash_desc *desc,u8 *out) +{ +struct chksum_desc_ctx *ctx =shash_desc_ctx (desc); + + *(u64 *)out = ctx->crc; +return 0 ; +} + +static int __chksum_finup (u64 crc,const u8 *data,unsigned int len,u8 *out) +{ + *(u64 *)out =crc64_rocksoft_generic (crc, data, len); +return 0 ; +}
These 64-bit writes violate alignment rules and will give the wrong result on big endian CPUs. They need to use put_unaligned_le64().
crypto/crc64_rocksoft_generic.c line 95
Quoted 9 lines
crypto/crc64_rocksoft_generic.c new file +9
-0+static int __init crc64_rocksoft_x86_mod_init (void ) +{ +return crypto_register_shash (&alg); +} + +static void __exit crc64_rocksoft_x86_mod_fini(void) +{ +crypto_unregister_shash (&alg); +}
This has nothing to do with x86.
crypto/crc64_rocksoft_generic.c line 27
Quoted 2 lines
crypto/crc64_rocksoft_generic.c new file +2
-0+config CRC64_ROCKSOFT + tristate"CRC calculation for the Rocksoft^TM model CRC64"
I'm sure what the rules for trademarks are, but kernel source code usually doesn't have the trademark symbol/abbreviation scattered everywhere.
crypto/crc64_rocksoft_generic.c line 33
Quoted 6 lines
crypto/crc64_rocksoft_generic.c new file +6
-0+ select CRYPTO + select CRYPTO_CRC64_ROCKSOFT +help + This option is only needed if a module that's not in the + kernel tree needs to calculate CRC checks for use with the + rocksoft model parameters.
Out-of-tree modules can't be the reason to have a kconfig option. What is the real reason?
crypto/crc64_rocksoft_generic.c line 38
Quoted 5 lines
crypto/crc64_rocksoft_generic.c new file +5
-0+u64 crc64_rocksoft (const unsigned char *buffer,size_t len) +{ +return crc64_rocksoft_update (~0ULL , buffer, len); +} +EXPORT_SYMBOL (crc64_rocksoft);
Isn't this missing the bitwise inversion at the end?
crypto/crc64_rocksoft_generic.c line 42
Quoted 4 lines
crypto/crc64_rocksoft_generic.c new file +4
-0+MODULE_AUTHOR ("Keith Busch <[email protected]>" ); +MODULE_DESCRIPTION ("Rocksoft model CRC64 calculation (library API)" ); +MODULE_LICENSE ("GPL" ); +MODULE_SOFTDEP ("pre: crc64" );
Shouldn't the MODULE_SOFTDEP be on crc64-rocksoft?
- Eric
Eric Biggers
maintainerRe: [PATCHv3 06/10] crypto: add rocksoft 64b crc framework
Quoted 6 lines · Eric Biggers
lib/Kconfig config CRC_T10DIF · line 150
Quoted 2 lines
lib/Kconfig +2
-0+config CRC64_ROCKSOFT + tristate "CRC calculation for the Rocksoft^TM model CRC64"I'm sure what the rules for trademarks are, but kernel source code usually doesn't have the trademark symbol/abbreviation scattered everywhere.
Quoted 9 lines
lib/Kconfig config CRC_T10DIF · line 156
Quoted 6 lines
lib/Kconfig +6
-0+ select CRYPTO + select CRYPTO_CRC64_ROCKSOFT + help + This option is only needed if a module that's not in the + kernel tree needs to calculate CRC checks for use with the + rocksoft model parameters.Out-of-tree modules can't be the reason to have a kconfig option. What is the real reason?
Also this option can be enabled without the CONFIG_CRC64 it depends on, which is broken.
- Eric
Keith Busch
maintainerRe: [PATCHv3 06/10] crypto: add rocksoft 64b crc framework
In reply to Eric BiggersQuoted 11 lines · Eric Biggers
crypto/Kconfig config CRYPTO_CRCT10DIF_VPMSUM · line 745
Quoted 8 lines · Keith Busch
crypto/Kconfig +8
-0+config CRYPTO_CRC64_ROCKSOFT + tristate "Rocksoft Model CRC64 algorithm" + depends on CRC64 + select CRYPTO_HASH + help + Rocksoft Model CRC64 computation is being cast as a crypto + transform. This allows for faster crc64 transforms to be used + if they are available.The first sentence of this help text doesn't make sense.
Much of the this patch is a copy from the equivalent T10DIF option, which says the same as above. I meant to revist these help texts because they don't make sense to me either. I'll be sure to do that for the next version.
Christoph Hellwig
maintainerRe: [PATCHv3 06/10] crypto: add rocksoft 64b crc framework
Quoted 13 lines · Keith Busch
Quoted 11 lines · Eric Biggers
crypto/Kconfig config CRYPTO_CRCT10DIF_VPMSUM · line 745
Quoted 8 lines · Keith Busch
crypto/Kconfig +8
-0+config CRYPTO_CRC64_ROCKSOFT + tristate "Rocksoft Model CRC64 algorithm" + depends on CRC64 + select CRYPTO_HASH + help + Rocksoft Model CRC64 computation is being cast as a crypto + transform. This allows for faster crc64 transforms to be used + if they are available.The first sentence of this help text doesn't make sense.
Quoted 4 lines
Much of the this patch is a copy from the equivalent T10DIF option, which says the same as above. I meant to revist these help texts because they don't make sense to me either. I'll be sure to do that for the next version.
It might make sense to make CRC_T10DIF an invisible option as well and drop the help text entirely.
Eric Biggers
maintainerRe: [PATCHv3 06/10] crypto: add rocksoft 64b crc framework
In reply to Keith BuschQuoted 6 lines · Keith Busch
Hardware specific features may be able to calculate a crc64, so provide a framework for drivers to register their implementation. If nothing is registered, fallback to the generic table lookup implementation. The implementation is modeled after the crct10dif equivalent.
Signed-off-by Keith Busch <[email protected]>
Quoted 11 lines
--- crypto/Kconfig | 9 +++ crypto/Makefile | 1 + crypto/crc64_rocksoft_generic.c | 104 +++++++++++++++++++++++++ include/linux/crc64.h | 5 ++ lib/Kconfig | 9 +++ lib/Makefile | 1 + lib/crc64-rocksoft.c | 129 ++++++++++++++++++++++++++++++++ 7 files changed, 258 insertions(+) create mode 100644 crypto/crc64_rocksoft_generic.c create mode 100644 lib/crc64-rocksoft.c
I tried testing this, but I can't because it is missing a self-test:
[ 0.736340] alg: No test for crc64-rocksoft (crc64-rocksoft-generic) [ 5.440398] alg: No test for crc64-rocksoft (crc64-rocksoft-pclmul)
All algorithms registered with the crypto API need to have a self-test (in crypto/testmgr.c).
- Eric
Keith Busch
maintainerPATCH v3 7/10 lib: add crc64 tests
In reply to Keith BuschProvide a module to test the rocksoft crc64 calculations with well known inputs and exepected values. Check the generic table implementation and whatever module is registered from the crypto library, and compare their speeds.
--- lib/Kconfig.debug | 4 ++ lib/Makefile | 1 + lib/test_crc64.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 lib/test_crc64.c
lib/Kconfig.debug +4 -0
@@ -2214,6 +2214,10 @@ config TEST_UUID config TEST_XARRAY tristate "Test the XArray code at runtime" +config TEST_CRC64 + depends on CRC64 + tristate "Test the crc64 code at runtime" + config TEST_OVERFLOW tristate "Test check_*_overflow() functions at runtime"
lib/Makefile +1 -0
@@ -103,6 +103,7 @@ obj-$(CONFIG_TEST_HMM) += test_hmm.o obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o obj-$(CONFIG_TEST_REF_TRACKER) += test_ref_tracker.o +obj-$(CONFIG_TEST_CRC64) += test_crc64.o # # CFLAGS for compiling floating point code inside the kernel. x86/Makefile turns # off the generation of FPU/SSE* instructions for kernel proper but FPU_FLAGS
lib/test_crc64.c new file +133 -0
133 lines not on this page · raw message
Signature · 1 line
2.25.4
Re: [PATCHv3 07/10] lib: add crc64 tests
Quoted 7 lines · Keith Busch
Provide a module to test the rocksoft crc64 calculations with well known inputs and exepected values. Check the generic table implementation and whatever module is registered from the crypto library, and compare their speeds.
Signed-off-by Keith Busch <[email protected]>---
Looks good.
-ck
Christoph Hellwig
maintainerRe: [PATCHv3 07/10] lib: add crc64 tests
In reply to Keith BuschQuoted 4 lines · Keith Busch
Provide a module to test the rocksoft crc64 calculations with well known inputs and exepected values. Check the generic table implementation and whatever module is registered from the crypto library, and compare their speeds.
The code looks good, but isn't the trent to use the kunit framework for these kinds of tests these days?
Keith Busch
maintainerRe: [PATCHv3 07/10] lib: add crc64 tests
Quoted 8 lines · Christoph Hellwig
Quoted 4 lines · Keith Busch
Provide a module to test the rocksoft crc64 calculations with well known inputs and exepected values. Check the generic table implementation and whatever module is registered from the crypto library, and compare their speeds.
The code looks good, but isn't the trent to use the kunit framework for these kinds of tests these days?
I don't have experience with kunit, but I'll look into that.
I am already changing the way this gets tested. Eric recommended adding to the crypto "testmgr", and I've done that on my private tree. That test framework exercises a lot more than this this patch, and it did reveal a problem with how I've implemented the initial XOR when the buffer is split, so I have some minor updates coming soon.
Christoph Hellwig
maintainerRe: [PATCHv3 07/10] lib: add crc64 tests
Quoted 7 lines · Keith Busch
I don't have experience with kunit, but I'll look into that.
I am already changing the way this gets tested. Eric recommended adding to the crypto "testmgr", and I've done that on my private tree. That test framework exercises a lot more than this this patch, and it did reveal a problem with how I've implemented the initial XOR when the buffer is split, so I have some minor updates coming soon.
I guess if we exercise the algorithm through that we don't really need another low-level test anyway, right?
Keith Busch
maintainerPATCH v3 8/10 block: add pi for nvme enhanced integrity
In reply to Keith BuschThe NVMe specification defines new data integrity formats beyond the t10 tuple. Add support for the specification defined CRC64 formats, assuming the reference tag does not need to be split with the "storage tag".
--- block/Kconfig | 1 + block/t10-pi.c | 194 +++++++++++++++++++++++++++++++++++++++++ include/linux/t10-pi.h | 20 +++++ 3 files changed, 215 insertions(+)
block/Kconfig +1 -0
@@ -75,6 +75,7 @@ config BLK_DEV_INTEGRITY_T10 tristate depends on BLK_DEV_INTEGRITY select CRC_T10DIF + select CRC64_ROCKSOFT config BLK_DEV_ZONED bool "Zoned block device support"
block/t10-pi.c +194 -0
206 lines not on this page · raw message
include/linux/t10-pi.h +20 -0
@@ -53,4 +53,24 @@ extern const struct blk_integrity_profile t10_pi_type1_ip;extern const struct blk_integrity_profile t10_pi_type3_crc;extern const struct blk_integrity_profile t10_pi_type3_ip; +struct nvme_crc64_pi_tuple { +__be64 guard_tag; +__be16 app_tag; +__u8 ref_tag[6 ]; +}; + +static inline u64 nvme_pi_extended_ref_tag (struct request *rq) +{ +unsigned int shift =ilog2 (queue_logical_block_size (rq->q)); + +#ifdef CONFIG_BLK_DEV_INTEGRITY +if (rq->q->integrity.interval_exp) + shift = rq->q->integrity.interval_exp; +#endif +return lower_48_bits (blk_rq_pos (rq) >> (shift -SECTOR_SHIFT )); +} + +extern const struct blk_integrity_profile nvme_pi_type1_crc64; +extern const struct blk_integrity_profile nvme_pi_type3_crc64; +#endif
Signature · 1 line
2.25.4
Christoph Hellwig
maintainerRe: [PATCHv3 08/10] block: add pi for nvme enhanced integrity
block/t10-pi.c const struct blk_integrity_profile t10_pi_type3_ip = { · line 289
Quoted 7 lines · Keith Busch
block/t10-pi.c +7
-0+static __be64 nvme_pi_crc64 (void *data,unsigned int len) +{ +return cpu_to_be64 (crc64_rocksoft (data, len)); +} + +static blk_status_t nvme_crc64_generate (struct blk_integrity_iter *iter, +enum t10_dif_type type)
Shouldn't the naming be something more like ext_pi_*? For one thing I kinda hate having the nvme prefix here in block layer code, but also nvme supports the normal 8 byte PI tuples, so this is a bit confusing.
Quoted 164 lines
block/t10-pi.c +164
-0+{ +unsigned int i; + +for (i =0 ; i < iter->data_size ; i += iter->interval) { +struct nvme_crc64_pi_tuple *pi = iter->prot_buf; + + pi->guard_tag =nvme_pi_crc64 (iter->data_buf, iter->interval); + pi->app_tag =0 ; + +if (type ==T10_PI_TYPE1_PROTECTION ) +put_unaligned_be48 (iter->seed, pi->ref_tag); +else +put_unaligned_be48 (0ULL , pi->ref_tag); + + iter->data_buf += iter->interval; + iter->prot_buf += iter->tuple_size; + iter->seed++; + } + +return BLK_STS_OK ; +} + +static bool nvme_crc64_ref_escape (u8 *ref_tag) +{ +static u8 ref_escape[6 ] = {0xff ,0xff ,0xff ,0xff ,0xff ,0xff }; + +return memcmp (ref_tag, ref_escape,sizeof (ref_escape)) ==0 ; +} + +static blk_status_t nvme_crc64_verify (struct blk_integrity_iter *iter, +enum t10_dif_type type) +{ +unsigned int i; + +for (i =0 ; i < iter->data_size; i += iter->interval) { +struct nvme_crc64_pi_tuple *pi = iter->prot_buf; +u64 ref, seed; +__be64 csum; + +if (type ==T10_PI_TYPE1_PROTECTION ) { +if (pi->app_tag ==T10_PI_APP_ESCAPE ) + goto next; + + ref =get_unaligned_be48 (pi->ref_tag); + seed =lower_48_bits (iter->seed); +if (ref != seed) { +pr_err ("%s: ref tag error at location %llu (rcvd %llu)\n" , + iter->disk_name, seed, ref); +return BLK_STS_PROTECTION ; + } + }else if (type ==T10_PI_TYPE3_PROTECTION ) { +if (pi->app_tag ==T10_PI_APP_ESCAPE && +nvme_crc64_ref_escape (pi->ref_tag)) + goto next; + } + + csum =nvme_pi_crc64 (iter->data_buf, iter->interval); +if (pi->guard_tag != csum) { +pr_err ("%s: guard tag error at sector %llu " \ +"(rcvd %016llx, want %016llx)\n" , + iter->disk_name, (unsigned long long )iter->seed, +be64_to_cpu (pi->guard_tag),be64_to_cpu (csum)); +return BLK_STS_PROTECTION ; + } + +next: + iter->data_buf += iter->interval; + iter->prot_buf += iter->tuple_size; + iter->seed++; + } + +return BLK_STS_OK ; +} + +static blk_status_t nvme_pi_type1_verify_crc (struct blk_integrity_iter *iter) +{ +return nvme_crc64_verify (iter,T10_PI_TYPE1_PROTECTION ); +} + +static blk_status_t nvme_pi_type1_generate_crc (struct blk_integrity_iter *iter) +{ +return nvme_crc64_generate (iter,T10_PI_TYPE1_PROTECTION ); +} + +static void nvme_pi_type1_prepare (struct request *rq) +{ +const int tuple_sz = rq->q->integrity.tuple_size; +u64 ref_tag =nvme_pi_extended_ref_tag (rq); +struct bio *bio; + +__rq_for_each_bio (bio, rq) { +struct bio_integrity_payload *bip =bio_integrity (bio); +u64 virt =lower_48_bits (bip_get_seed (bip)); +struct bio_vec iv; +struct bvec_iter iter; + +/* Already remapped? */ +if (bip->bip_flags &BIP_MAPPED_INTEGRITY ) +break ; + +bip_for_each_vec (iv, bip, iter) { +unsigned int j; +void *p; + + p =bvec_kmap_local (&iv); +for (j =0 ; j < iv.bv_len; j += tuple_sz) { +struct nvme_crc64_pi_tuple *pi = p; +u64 ref =get_unaligned_be48 (pi->ref_tag); + +if (ref == virt) +put_unaligned_be48 (ref_tag, pi->ref_tag); + virt++; + ref_tag++; + p += tuple_sz; + } +kunmap_local (p); + } + + bip->bip_flags |=BIP_MAPPED_INTEGRITY ; + } +} + +static void nvme_pi_type1_complete (struct request *rq,unsigned int nr_bytes) +{ +unsigned intervals = nr_bytes >> rq->q->integrity.interval_exp; +const int tuple_sz = rq->q->integrity.tuple_size; +u64 ref_tag =nvme_pi_extended_ref_tag (rq); +struct bio *bio; + +__rq_for_each_bio (bio, rq) { +struct bio_integrity_payload *bip =bio_integrity (bio); +u64 virt =lower_48_bits (bip_get_seed (bip)); +struct bio_vec iv; +struct bvec_iter iter; + +bip_for_each_vec (iv, bip, iter) { +unsigned int j; +void *p; + + p =bvec_kmap_local (&iv); +for (j =0 ; j < iv.bv_len && intervals; j += tuple_sz) { +struct nvme_crc64_pi_tuple *pi = p; +u64 ref =get_unaligned_be48 (pi->ref_tag); + +if (ref == ref_tag) +put_unaligned_be48 (virt, pi->ref_tag); + virt++; + ref_tag++; + intervals--; + p += tuple_sz; + } +kunmap_local (p); + } + } +} + +static blk_status_t nvme_pi_type3_verify_crc (struct blk_integrity_iter *iter) +{ +return nvme_crc64_verify (iter,T10_PI_TYPE3_PROTECTION ); +} + +static blk_status_t nvme_pi_type3_generate_crc (struct blk_integrity_iter *iter) +{ +return nvme_crc64_generate (iter,T10_PI_TYPE3_PROTECTION );
block/t10-pi.c const struct blk_integrity_profile t10_pi_type3_ip = { · line 463
Quoted 10 lines
block/t10-pi.c +10
-0+} + +const struct blk_integrity_profile nvme_pi_type1_crc64 = { + .name ="NVME-DIF-TYPE1-CRC64" , + .generate_fn = nvme_pi_type1_generate_crc, + .verify_fn = nvme_pi_type1_verify_crc, + .prepare_fn = nvme_pi_type1_prepare, + .complete_fn = nvme_pi_type1_complete, +}; +EXPORT_SYMBOL (nvme_pi_type1_crc64);
All this should probably be EXPORT_SYMBOL_GPL (and I have a series pending that would remove the exports of the profiles entirely, but that will need some major rework after your series goes in).
The actual code looks fine to me.
Martin K. Petersen
Reviewed-byRe: [PATCHv3 08/10] block: add pi for nvme enhanced integrity
Christoph,
Quoted 6 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+static blk_status_t nvme_crc64_generate(struct blk_integrity_iter *iter, + enum t10_dif_type type)Shouldn't the naming be something more like ext_pi_*? For one thing I kinda hate having the nvme prefix here in block layer code, but also nvme supports the normal 8 byte PI tuples, so this is a bit confusing.
The rationale behind the original t10 prefix was that the format was defined by the T10 organization. At the time a T13 format was also on the table. So from that perspective, using nvme_ here is correct. I do like ext_ better, though.
I don't particularly appreciate the way the new formats were defined in NVMe. I would have preferred new types instead of this "just like type N except for all these differences" approach. But that comes from NVMe completely missing how DIX removed all the format type knowledge from the controller/device and instead put the burden on the driver to tell the device what and how to check.
In any case: Naming is hard, the code looks fine to me.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Keith Busch
maintainerPATCH v3 9/10 nvme: add support for enhanced metadata
In reply to Keith BuschNVM Express ratified TP 4068 defines new protection information formats. Implement support for the CRC64 guard tags.
Since the block layer doesn't support variable length reference tags, driver support for the Storage Tag space is not supported at this time.
--- drivers/nvme/host/core.c | 172 ++++++++++++++++++++++++++++++++------- drivers/nvme/host/nvme.h | 4 +- include/linux/nvme.h | 53 ++++++++++-- 3 files changed, 191 insertions(+), 38 deletions(-)
drivers/nvme/host/core.c +141 -31
@@ -918,6 +918,30 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,return BLK_STS_OK ; } +static inline void nvme_set_ref_tag (struct nvme_ns *ns,struct nvme_command *cmnd, +struct request *req) +{ +u32 upper, lower; +u64 ref48; + +/* both rw and write zeroes share the same reftag format */ +switch (ns->guard_type) { +case NVME_NVM_NS_16B_GUARD : + cmnd->rw.reftag =cpu_to_le32 (t10_pi_ref_tag (req)); +break ; +case NVME_NVM_NS_64B_GUARD : + ref48 =nvme_pi_extended_ref_tag (req); + lower =lower_32_bits (ref48); + upper =upper_32_bits (ref48); + + cmnd->rw.reftag =cpu_to_le32 (lower); + cmnd->rw.cdw3 =cpu_to_le32 (upper); +break ; +default : +break ; + } +} +static inline blk_status_t nvme_setup_write_zeroes (struct nvme_ns *ns,struct request *req,struct nvme_command *cmnd) {
@@ -939,8 +963,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,switch (ns->pi_type) {case NVME_NS_DPS_PI_TYPE1 :case NVME_NS_DPS_PI_TYPE2 : - cmnd->write_zeroes.reftag = -cpu_to_le32 (t10_pi_ref_tag (req)); +nvme_set_ref_tag (ns, cmnd, req);break ; } }
@@ -967,7 +990,8 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, cmnd->rw.opcode = op; cmnd->rw.flags =0 ; cmnd->rw.nsid =cpu_to_le32 (ns->head->ns_id); - cmnd->rw.rsvd2 =0 ; + cmnd->rw.cdw2 =0 ; + cmnd->rw.cdw3 =0 ; cmnd->rw.metadata =0 ; cmnd->rw.slba =cpu_to_le64 (nvme_sect_to_lba (ns,blk_rq_pos (req))); cmnd->rw.length =cpu_to_le16 ((blk_rq_bytes (req) >> ns->lba_shift) -1 );
@@ -1001,7 +1025,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,NVME_RW_PRINFO_PRCHK_REF ;if (op == nvme_cmd_zone_append) control |=NVME_RW_APPEND_PIREMAP ; - cmnd->rw.reftag =cpu_to_le32 (t10_pi_ref_tag (req)); +nvme_set_ref_tag (ns, cmnd, req);break ; } }
@@ -1653,33 +1677,58 @@ int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo) }#ifdef CONFIG_BLK_DEV_INTEGRITY -static void nvme_init_integrity (struct gendisk *disk,u16 ms,u8 pi_type, +static void nvme_init_integrity (struct gendisk *disk,struct nvme_ns *ns,u32 max_integrity_segments) {struct blk_integrity integrity = { }; -switch (pi_type) { +switch (ns->pi_type) {case NVME_NS_DPS_PI_TYPE3 : - integrity.profile = &t10_pi_type3_crc; - integrity.tag_size =sizeof (u16) +sizeof (u32); - integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +switch (ns->guard_type) { +case NVME_NVM_NS_16B_GUARD : + integrity.profile = &t10_pi_type3_crc; + integrity.tag_size =sizeof (u16) +sizeof (u32); + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +case NVME_NVM_NS_64B_GUARD : + integrity.profile = &nvme_pi_type3_crc64; + integrity.tag_size =sizeof (u16) +6 ; + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +default : + integrity.profile =NULL ; +break ; + }break ;case NVME_NS_DPS_PI_TYPE1 :case NVME_NS_DPS_PI_TYPE2 : - integrity.profile = &t10_pi_type1_crc; - integrity.tag_size =sizeof (u16); - integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +switch (ns->guard_type) { +case NVME_NVM_NS_16B_GUARD : + integrity.profile = &t10_pi_type1_crc; + integrity.tag_size =sizeof (u16); + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +case NVME_NVM_NS_64B_GUARD : + integrity.profile = &nvme_pi_type1_crc64; + integrity.tag_size =sizeof (u16); + integrity.flags |=BLK_INTEGRITY_DEVICE_CAPABLE ; +break ; +default : + integrity.profile =NULL ; +break ; + }break ;default : integrity.profile =NULL ;break ; } - integrity.tuple_size = ms; + + integrity.tuple_size = ns->ms;blk_integrity_register (disk, &integrity);blk_queue_max_integrity_segments (disk->queue, max_integrity_segments); }#else -static void nvme_init_integrity (struct gendisk *disk,u16 ms,u8 pi_type, +static void nvme_init_integrity (struct gendisk *disk,struct nvme_ns *ns,u32 max_integrity_segments) { }
@@ -1756,20 +1805,76 @@ static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns,return 0 ; } -static int nvme_configure_metadata (struct nvme_ns *ns,struct nvme_id_ns *id) +static int nvme_init_ms (struct nvme_ns *ns,struct nvme_id_ns *id) { +bool first = id->dps &NVME_NS_DPS_PI_FIRST ; +unsigned lbaf =nvme_lbaf_index (id->flbas);struct nvme_ctrl *ctrl = ns->ctrl; +struct nvme_command c = { }; +struct nvme_id_ns_nvm *nvm; +int ret =0 ; +u32 elbaf; + + ns->pi_size =0 ; + ns->ms =le16_to_cpu (id->lbaf[lbaf].ms); +if (!(ctrl->ctratt &NVME_CTRL_ATTR_ELBAS )) { + ns->pi_size =sizeof (struct t10_pi_tuple ); + ns->guard_type =NVME_NVM_NS_16B_GUARD ; + goto set_pi; + } + + nvm =kzalloc (sizeof (*nvm),GFP_KERNEL ); +if (!nvm) +return -ENOMEM ; + + c.identify.opcode = nvme_admin_identify; + c.identify.nsid =cpu_to_le32 (ns->head->ns_id); + c.identify.cns =NVME_ID_CNS_CS_NS ; + c.identify.csi =NVME_CSI_NVM ; - ns->ms =le16_to_cpu (id->lbaf[id->flbas &NVME_NS_FLBAS_LBA_MASK ].ms); -if (id->dps &NVME_NS_DPS_PI_FIRST || - ns->ms ==sizeof (struct t10_pi_tuple )) + ret =nvme_submit_sync_cmd (ns->ctrl->admin_q, &c, nvm,sizeof (*nvm)); +if (ret) + goto free_data; + + elbaf =le32_to_cpu (nvm->elbaf[lbaf]); + +/* no support for storage tag formats right now */ +if (nvme_elbaf_sts (elbaf)) + goto free_data; + + ns->guard_type =nvme_elbaf_guard_type (elbaf); +switch (ns->guard_type) { +case NVME_NVM_NS_64B_GUARD : + ns->pi_size =sizeof (struct nvme_crc64_pi_tuple ); +break ; +case NVME_NVM_NS_16B_GUARD : + ns->pi_size =sizeof (struct t10_pi_tuple ); +break ; +default : +break ; + } + +free_data: +kfree (nvm); +set_pi: +if (ns->pi_size && (first || ns->ms == ns->pi_size)) ns->pi_type = id->dps &NVME_NS_DPS_PI_MASK ;else ns->pi_type =0 ; +return ret; +} + +static void nvme_configure_metadata (struct nvme_ns *ns,struct nvme_id_ns *id) +{ +struct nvme_ctrl *ctrl = ns->ctrl; + +if (nvme_init_ms (ns, id)) +return ; + ns->features &= ~(NVME_NS_METADATA_SUPPORTED |NVME_NS_EXT_LBAS );if (!ns->ms || !(ctrl->ops->flags &NVME_F_METADATA_SUPPORTED )) -return 0 ; +return ;if (ctrl->ops->flags &NVME_F_FABRICS ) {/* * The NVMe over Fabrics specification only supports metadata as
@@ -1777,7 +1882,7 @@ static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)* remap the separate metadata buffer from the block layer. */ if (WARN_ON_ONCE (!(id->flbas &NVME_NS_FLBAS_META_EXT ))) -return -EINVAL ; +return ; ns->features |=NVME_NS_EXT_LBAS ;
@@ -1804,8 +1909,6 @@ static int nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)else ns->features |=NVME_NS_METADATA_SUPPORTED ; } - -return 0 ; } static void nvme_set_queue_limits(struct nvme_ctrl *ctrl,
@@ -1884,7 +1987,7 @@ static void nvme_update_disk_info(struct gendisk *disk,if (ns->ms) {if (IS_ENABLED (CONFIG_BLK_DEV_INTEGRITY ) && (ns->features &NVME_NS_METADATA_SUPPORTED )) -nvme_init_integrity (disk, ns->ms, ns->pi_type, +nvme_init_integrity (disk, ns, ns->ctrl->max_integrity_segments);else if (!nvme_ns_has_pi (ns)) capacity =0 ;
@@ -1939,16 +2042,14 @@ static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)static int nvme_update_ns_info (struct nvme_ns *ns,struct nvme_id_ns *id) { -unsigned lbaf = id->flbas &NVME_NS_FLBAS_LBA_MASK ; +unsigned lbaf =nvme_lbaf_index (id->flbas);int ret;blk_mq_freeze_queue (ns->disk->queue); ns->lba_shift = id->lbaf[lbaf].ds;nvme_set_queue_limits (ns->ctrl, ns->queue); - ret =nvme_configure_metadata (ns, id); -if (ret) - goto out_unfreeze; +nvme_configure_metadata (ns, id);nvme_set_chunk_sectors (ns, id);nvme_update_disk_info (ns->disk, ns, id);
@@ -2286,20 +2387,27 @@ static int nvme_configure_timestamp(struct nvme_ctrl *ctrl)return ret; } -static int nvme_configure_acre (struct nvme_ctrl *ctrl) +static int nvme_configure_host_options (struct nvme_ctrl *ctrl) {struct nvme_feat_host_behavior *host; +u8 acre =0 , lbafee =0 ;int ret;/* Don't bother enabling the feature if retry delay is not reported */ -if (!ctrl->crdt[0 ]) +if (ctrl->crdt[0 ]) + acre =NVME_ENABLE_ACRE ; +if (ctrl->ctratt &NVME_CTRL_ATTR_ELBAS ) + lbafee =NVME_ENABLE_LBAFEE ; + +if (!acre && !lbafee)return 0 ; host =kzalloc (sizeof (*host),GFP_KERNEL );if (!host)return 0 ; - host->acre =NVME_ENABLE_ACRE ; + host->acre = acre; + host->lbafee = lbafee; ret =nvme_set_features (ctrl,NVME_FEAT_HOST_BEHAVIOR ,0 , host,sizeof (*host),NULL );kfree (host);
@@ -3141,7 +3249,7 @@ int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl)if (ret <0 )return ret; - ret =nvme_configure_acre (ctrl); + ret =nvme_configure_host_options (ctrl);if (ret <0 )return ret;
@@ -4814,12 +4922,14 @@ static inline void _nvme_check_size(void)BUILD_BUG_ON (sizeof (struct nvme_id_ctrl ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ns ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ns_zns ) !=NVME_IDENTIFY_DATA_SIZE ); +BUILD_BUG_ON (sizeof (struct nvme_id_ns_nvm ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ctrl_zns ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_id_ctrl_nvm ) !=NVME_IDENTIFY_DATA_SIZE );BUILD_BUG_ON (sizeof (struct nvme_lba_range_type ) !=64 );BUILD_BUG_ON (sizeof (struct nvme_smart_log ) !=512 );BUILD_BUG_ON (sizeof (struct nvme_dbbuf ) !=64 );BUILD_BUG_ON (sizeof (struct nvme_directive_cmd ) !=64 ); +BUILD_BUG_ON (sizeof (struct nvme_feat_host_behavior ) !=512 ); }
drivers/nvme/host/nvme.h +3 -1
@@ -454,9 +454,11 @@ struct nvme_ns {int lba_shift;u16 ms; +u16 pi_size;u16 sgs;u32 sws;u8 pi_type; +u8 guard_type;#ifdef CONFIG_BLK_DEV_ZONED u64 zsze;#endif
@@ -479,7 +481,7 @@ struct nvme_ns {/* NVMe ns supports metadata actions by the controller (generate/strip) */ static inline bool nvme_ns_has_pi (struct nvme_ns *ns) { -return ns->pi_type && ns->ms ==sizeof (struct t10_pi_tuple ); +return ns->pi_type && ns->ms == ns->pi_size; }struct nvme_ctrl_ops {
include/linux/nvme.h +47 -6
105 lines not on this page · raw message
Signature · 1 line
2.25.4
Re: [PATCHv3 09/10] nvme: add support for enhanced metadata
drivers/nvme/host/core.c static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, · line 921
Quoted 5 lines · Keith Busch
drivers/nvme/host/core.c +1
-0@@ -918,6 +918,30 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,return BLK_STS_OK ; } +static inline void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd,
Overly long line. But I don't think this should be marked inline anyway.
Otherwise this looks good:
I suspect eventually we'll need to lift the new Identify call into the common revalidation once more fields get added there.
Re: [PATCHv3 09/10] nvme: add support for enhanced metadata
In reply to Keith BuschKeith,
Quoted 6 lines
NVM Express ratified TP 4068 defines new protection information formats. Implement support for the CRC64 guard tags.
Since the block layer doesn't support variable length reference tags, driver support for the Storage Tag space is not supported at this time.
Looks fine.
Signature · 1 line
Martin K. Petersen Oracle Linux Engineering
Keith Busch
maintainerPATCH v3 10/10 x86/crypto: add pclmul acceleration for crc64
In reply to Keith BuschThe crc64 table lookup method is inefficient, using a significant number of CPU cycles in the block stack per IO. If available on x86, use a PCLMULQDQ implementation to accelerate the calculation.
The assembly from this patch was mostly generated by gcc from a C program using library functions provided by x86 intrinsics, and measures ~20x faster than the table lookup.
--- arch/x86/crypto/Makefile | 3 + arch/x86/crypto/crc64-rocksoft-pcl-asm.S | 215 ++++++++++++++++++++++ arch/x86/crypto/crc64-rocksoft-pcl_glue.c | 117 ++++++++++++ crypto/Kconfig | 11 ++ 4 files changed, 346 insertions(+) create mode 100644 arch/x86/crypto/crc64-rocksoft-pcl-asm.S create mode 100644 arch/x86/crypto/crc64-rocksoft-pcl_glue.c
arch/x86/crypto/Makefile +3 -0
@@ -79,6 +79,9 @@ crc32-pclmul-y := crc32-pclmul_asm.o crc32-pclmul_glue.o obj-$(CONFIG_CRYPTO_CRCT10DIF_PCLMUL) += crct10dif-pclmul.o crct10dif-pclmul-y := crct10dif-pcl-asm_64.o crct10dif-pclmul_glue.o +obj-$(CONFIG_CRYPTO_CRC64_ROCKSOFT_PCLMUL) += crc64-rocksoft-pclmul.o +crc64-rocksoft-pclmul-y := crc64-rocksoft-pcl-asm.o crc64-rocksoft-pcl_glue.o + obj-$(CONFIG_CRYPTO_POLY1305_X86_64) += poly1305-x86_64.o poly1305-x86_64-y := poly1305-x86_64-cryptogams.o poly1305_glue.o targets += poly1305-x86_64-cryptogams.S
arch/x86/crypto/crc64-rocksoft-pcl-asm.S new file +215 -0
215 lines not on this page · raw message
arch/x86/crypto/crc64-rocksoft-pcl_glue.c new file +117 -0
117 lines not on this page · raw message
crypto/Kconfig +11 -0
@@ -744,6 +744,17 @@ config CRYPTO_CRC64_ROCKSOFT transform. This allows for faster crc64 transforms to be used if they are available. +config CRYPTO_CRC64_ROCKSOFT_PCLMUL + tristate "Rocksoft model CRC64 PCLMULQDQ hardware acceleration" + depends on X86 && 64BIT && CRC64 + select CRYPTO_HASH + help + For x86_64 processors with SSE4.2 and PCLMULQDQ supported, + CRC64 PCLMULQDQ computation can be hardware accelerated PCLMULQDQ + instruction. This option will create 'crc64-rocksoft-pclmul' + module, which is faster when computing crc64 checksum compared + with the generic table implementation. + config CRYPTO_VPMSUM_TESTER tristate "Powerpc64 vpmsum hardware acceleration tester" depends on CRYPTO_CRCT10DIF_VPMSUM && CRYPTO_CRC32C_VPMSUM
Signature · 1 line
2.25.4
RE: [PATCHv3 10/10] x86/crypto: add pclmul acceleration for crc64
From: Keith Busch
Quoted 9 lines
Sent: 22 February 2022 16:32
The crc64 table lookup method is inefficient, using a significant number of CPU cycles in the block stack per IO. If available on x86, use a PCLMULQDQ implementation to accelerate the calculation.
The assembly from this patch was mostly generated by gcc from a C program using library functions provided by x86 intrinsics, and measures ~20x faster than the table lookup.
I think I'd like to see the C code and compiler options used to generate the assembler as comments in the committed source file. Either that or reasonable comments in the assembler.
It is also quite a lot of code.
What is the break-even length for 'cold cache' including the FPU saves.
...
arch/x86/crypto/crc64-rocksoft-pcl-asm.S line 205
Quoted 8 lines
+.section .rodata
+.align 32
+.type shuffleMasks, @object
+.size shuffleMasks, 32arch/x86/crypto/crc64-rocksoft-pcl-asm.S new file +4
-0+shuffleMasks: + .string "" + .ascii "\001\002\003\004\005\006\007\b\t\n\013\f\r\016\017\217\216\215" + .ascii "\214\213\212\211\210\207\206\205\204\203\202\201\200"
That has to be the worst way to define 32 bytes.
arch/x86/crypto/crc64-rocksoft-pcl-asm.S line 215
Quoted 9 lines
+.section .rodata.cst16,"aM",@progbits,16
+.align 16
+.LC0:arch/x86/crypto/crc64-rocksoft-pcl-asm.S new file +6
-0+ .quad -1523270018343381984 + .quad 2443614144669557164 + .align 16 +.LC1: + .quad 2876949357237608311 + .quad 3808117099328934763
Not sure what those are, but I bet there are better ways to define/describe them.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Keith Busch
maintainerRe: [PATCHv3 10/10] x86/crypto: add pclmul acceleration for crc64
Quoted 7 lines · David Laight
From: Keith Busch
Quoted 6 lines
Sent: 22 February 2022 16:32
The crc64 table lookup method is inefficient, using a significant number of CPU cycles in the block stack per IO. If available on x86, use a PCLMULQDQ implementation to accelerate the calculation.
Quoted 7 lines
Quoted 3 lines
The assembly from this patch was mostly generated by gcc from a C program using library functions provided by x86 intrinsics, and measures ~20x faster than the table lookup.
I think I'd like to see the C code and compiler options used to generate the assembler as comments in the committed source file. Either that or reasonable comments in the assembler.
The C code, compiled as "gcc -O3 -msse4 -mpclmul -S", was adapted from this found on the internet:
https://github.com/rawrunprotected/crc/blob/master/crc64.c
I just ported it to linux, changed the poly parameters and removed the unnecessary stuff.
I'm okay with dropping this patch from the series for now since I don't think I'm qualified to write it. :) I just needed something to test the crytpo module registration.
Eric Biggers
maintainerRe: [PATCHv3 10/10] x86/crypto: add pclmul acceleration for crc64
Quoted 19 lines · Keith Busch
Quoted 7 lines · David Laight
From: Keith Busch
Quoted 6 lines
Sent: 22 February 2022 16:32
The crc64 table lookup method is inefficient, using a significant number of CPU cycles in the block stack per IO. If available on x86, use a PCLMULQDQ implementation to accelerate the calculation.
Quoted 7 lines
Quoted 3 lines
The assembly from this patch was mostly generated by gcc from a C program using library functions provided by x86 intrinsics, and measures ~20x faster than the table lookup.
I think I'd like to see the C code and compiler options used to generate the assembler as comments in the committed source file. Either that or reasonable comments in the assembler.
The C code, compiled as "gcc -O3 -msse4 -mpclmul -S", was adapted from this found on the internet:
Quoted 8 lines
https://github.com/rawrunprotected/crc/blob/master/crc64.c
I just ported it to linux, changed the poly parameters and removed the unnecessary stuff.
I'm okay with dropping this patch from the series for now since I don't think I'm qualified to write it. :) I just needed something to test the crytpo module registration.
Is the license of that code compatible with the kernel's license?
In any case, adding uncommented generated assembly isn't acceptable. The most common convention for Linux kernel crypto is to use hand-written assembly that is properly commented.
There is some precedent for using compiler intrinsics instead, e.g. crypto/aegis128-neon-inner.c. (I'm not sure why they aren't used more often.)
There are also some files where a Perl script generates the assembly code. (This is a bit ugly IMO, but it's what the author of much of OpenSSL's crypto assembly code does, and it was desired to reuse that code.)
Anyway, those are the available options. Checking in some uncommented generated assembly isn't one of them.
- Eric
Keith Busch
maintainerRe: [PATCHv3 10/10] x86/crypto: add pclmul acceleration for crc64
Quoted 1 line · Eric Biggers
Is the license of that code compatible with the kernel's license?
It's released into "public domain", so I assume we can leverage it into GPL licenced code. I don't have similar past experiences with this scenario, so please correct me if I'm mistaken.
Quoted 7 lines
In any case, adding uncommented generated assembly isn't acceptable. The most common convention for Linux kernel crypto is to use hand-written assembly that is properly commented.
There is some precedent for using compiler intrinsics instead, e.g.
crypto/aegis128-neon-inner.c. (I'm not sure why they aren't used more often.)
Quoted 6 lines
There are also some files where a Perl script generates the assembly code. (This is a bit ugly IMO, but it's what the author of much of OpenSSL's crypto assembly code does, and it was desired to reuse that code.)
Anyway, those are the available options. Checking in some uncommented generated assembly isn't one of them.
Fair enough. I'll find help from someone to author an appropriate form to replace this patch.