cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

item.h (17818B)


      1/* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 */
      2/* Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved */
      3
      4#ifndef _MLXSW_ITEM_H
      5#define _MLXSW_ITEM_H
      6
      7#include <linux/types.h>
      8#include <linux/string.h>
      9#include <linux/bitops.h>
     10
     11struct mlxsw_item {
     12	unsigned short	offset;		/* bytes in container */
     13	short		step;		/* step in bytes for indexed items */
     14	unsigned short	in_step_offset; /* offset within one step */
     15	unsigned char	shift;		/* shift in bits */
     16	unsigned char	element_size;	/* size of element in bit array */
     17	bool		no_real_shift;
     18	union {
     19		unsigned char	bits;
     20		unsigned short	bytes;
     21	} size;
     22	const char	*name;
     23};
     24
     25static inline unsigned int
     26__mlxsw_item_offset(const struct mlxsw_item *item, unsigned short index,
     27		    size_t typesize)
     28{
     29	BUG_ON(index && !item->step);
     30	if (item->offset % typesize != 0 ||
     31	    item->step % typesize != 0 ||
     32	    item->in_step_offset % typesize != 0) {
     33		pr_err("mlxsw: item bug (name=%s,offset=%x,step=%x,in_step_offset=%x,typesize=%zx)\n",
     34		       item->name, item->offset, item->step,
     35		       item->in_step_offset, typesize);
     36		BUG();
     37	}
     38
     39	return ((item->offset + item->step * index + item->in_step_offset) /
     40		typesize);
     41}
     42
     43static inline u8 __mlxsw_item_get8(const char *buf,
     44				   const struct mlxsw_item *item,
     45				   unsigned short index)
     46{
     47	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u8));
     48	u8 *b = (u8 *) buf;
     49	u8 tmp;
     50
     51	tmp = b[offset];
     52	tmp >>= item->shift;
     53	tmp &= GENMASK(item->size.bits - 1, 0);
     54	if (item->no_real_shift)
     55		tmp <<= item->shift;
     56	return tmp;
     57}
     58
     59static inline void __mlxsw_item_set8(char *buf, const struct mlxsw_item *item,
     60				     unsigned short index, u8 val)
     61{
     62	unsigned int offset = __mlxsw_item_offset(item, index,
     63						  sizeof(u8));
     64	u8 *b = (u8 *) buf;
     65	u8 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
     66	u8 tmp;
     67
     68	if (!item->no_real_shift)
     69		val <<= item->shift;
     70	val &= mask;
     71	tmp = b[offset];
     72	tmp &= ~mask;
     73	tmp |= val;
     74	b[offset] = tmp;
     75}
     76
     77static inline u16 __mlxsw_item_get16(const char *buf,
     78				     const struct mlxsw_item *item,
     79				     unsigned short index)
     80{
     81	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u16));
     82	__be16 *b = (__be16 *) buf;
     83	u16 tmp;
     84
     85	tmp = be16_to_cpu(b[offset]);
     86	tmp >>= item->shift;
     87	tmp &= GENMASK(item->size.bits - 1, 0);
     88	if (item->no_real_shift)
     89		tmp <<= item->shift;
     90	return tmp;
     91}
     92
     93static inline void __mlxsw_item_set16(char *buf, const struct mlxsw_item *item,
     94				      unsigned short index, u16 val)
     95{
     96	unsigned int offset = __mlxsw_item_offset(item, index,
     97						  sizeof(u16));
     98	__be16 *b = (__be16 *) buf;
     99	u16 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
    100	u16 tmp;
    101
    102	if (!item->no_real_shift)
    103		val <<= item->shift;
    104	val &= mask;
    105	tmp = be16_to_cpu(b[offset]);
    106	tmp &= ~mask;
    107	tmp |= val;
    108	b[offset] = cpu_to_be16(tmp);
    109}
    110
    111static inline u32 __mlxsw_item_get32(const char *buf,
    112				     const struct mlxsw_item *item,
    113				     unsigned short index)
    114{
    115	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u32));
    116	__be32 *b = (__be32 *) buf;
    117	u32 tmp;
    118
    119	tmp = be32_to_cpu(b[offset]);
    120	tmp >>= item->shift;
    121	tmp &= GENMASK(item->size.bits - 1, 0);
    122	if (item->no_real_shift)
    123		tmp <<= item->shift;
    124	return tmp;
    125}
    126
    127static inline void __mlxsw_item_set32(char *buf, const struct mlxsw_item *item,
    128				      unsigned short index, u32 val)
    129{
    130	unsigned int offset = __mlxsw_item_offset(item, index,
    131						  sizeof(u32));
    132	__be32 *b = (__be32 *) buf;
    133	u32 mask = GENMASK(item->size.bits - 1, 0) << item->shift;
    134	u32 tmp;
    135
    136	if (!item->no_real_shift)
    137		val <<= item->shift;
    138	val &= mask;
    139	tmp = be32_to_cpu(b[offset]);
    140	tmp &= ~mask;
    141	tmp |= val;
    142	b[offset] = cpu_to_be32(tmp);
    143}
    144
    145static inline u64 __mlxsw_item_get64(const char *buf,
    146				     const struct mlxsw_item *item,
    147				     unsigned short index)
    148{
    149	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
    150	__be64 *b = (__be64 *) buf;
    151	u64 tmp;
    152
    153	tmp = be64_to_cpu(b[offset]);
    154	tmp >>= item->shift;
    155	tmp &= GENMASK_ULL(item->size.bits - 1, 0);
    156	if (item->no_real_shift)
    157		tmp <<= item->shift;
    158	return tmp;
    159}
    160
    161static inline void __mlxsw_item_set64(char *buf, const struct mlxsw_item *item,
    162				      unsigned short index, u64 val)
    163{
    164	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(u64));
    165	__be64 *b = (__be64 *) buf;
    166	u64 mask = GENMASK_ULL(item->size.bits - 1, 0) << item->shift;
    167	u64 tmp;
    168
    169	if (!item->no_real_shift)
    170		val <<= item->shift;
    171	val &= mask;
    172	tmp = be64_to_cpu(b[offset]);
    173	tmp &= ~mask;
    174	tmp |= val;
    175	b[offset] = cpu_to_be64(tmp);
    176}
    177
    178static inline void __mlxsw_item_memcpy_from(const char *buf, char *dst,
    179					    const struct mlxsw_item *item,
    180					    unsigned short index)
    181{
    182	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
    183
    184	memcpy(dst, &buf[offset], item->size.bytes);
    185}
    186
    187static inline void __mlxsw_item_memcpy_to(char *buf, const char *src,
    188					  const struct mlxsw_item *item,
    189					  unsigned short index)
    190{
    191	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
    192
    193	memcpy(&buf[offset], src, item->size.bytes);
    194}
    195
    196static inline char *__mlxsw_item_data(char *buf, const struct mlxsw_item *item,
    197				      unsigned short index)
    198{
    199	unsigned int offset = __mlxsw_item_offset(item, index, sizeof(char));
    200
    201	return &buf[offset];
    202}
    203
    204static inline u16
    205__mlxsw_item_bit_array_offset(const struct mlxsw_item *item,
    206			      u16 index, u8 *shift)
    207{
    208	u16 max_index, be_index;
    209	u16 offset;		/* byte offset inside the array */
    210	u8 in_byte_index;
    211
    212	BUG_ON(index && !item->element_size);
    213	if (item->offset % sizeof(u32) != 0 ||
    214	    BITS_PER_BYTE % item->element_size != 0) {
    215		pr_err("mlxsw: item bug (name=%s,offset=%x,element_size=%x)\n",
    216		       item->name, item->offset, item->element_size);
    217		BUG();
    218	}
    219
    220	max_index = (item->size.bytes << 3) / item->element_size - 1;
    221	be_index = max_index - index;
    222	offset = be_index * item->element_size >> 3;
    223	in_byte_index  = index % (BITS_PER_BYTE / item->element_size);
    224	*shift = in_byte_index * item->element_size;
    225
    226	return item->offset + offset;
    227}
    228
    229static inline u8 __mlxsw_item_bit_array_get(const char *buf,
    230					    const struct mlxsw_item *item,
    231					    u16 index)
    232{
    233	u8 shift, tmp;
    234	u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
    235
    236	tmp = buf[offset];
    237	tmp >>= shift;
    238	tmp &= GENMASK(item->element_size - 1, 0);
    239	return tmp;
    240}
    241
    242static inline void __mlxsw_item_bit_array_set(char *buf,
    243					      const struct mlxsw_item *item,
    244					      u16 index, u8 val)
    245{
    246	u8 shift, tmp;
    247	u16 offset = __mlxsw_item_bit_array_offset(item, index, &shift);
    248	u8 mask = GENMASK(item->element_size - 1, 0) << shift;
    249
    250	val <<= shift;
    251	val &= mask;
    252	tmp = buf[offset];
    253	tmp &= ~mask;
    254	tmp |= val;
    255	buf[offset] = tmp;
    256}
    257
    258#define __ITEM_NAME(_type, _cname, _iname)					\
    259	mlxsw_##_type##_##_cname##_##_iname##_item
    260
    261/* _type: cmd_mbox, reg, etc.
    262 * _cname: containter name (e.g. command name, register name)
    263 * _iname: item name within the container
    264 */
    265
    266#define MLXSW_ITEM8(_type, _cname, _iname, _offset, _shift, _sizebits)		\
    267static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    268	.offset = _offset,							\
    269	.shift = _shift,							\
    270	.size = {.bits = _sizebits,},						\
    271	.name = #_type "_" #_cname "_" #_iname,					\
    272};										\
    273static inline u8 __maybe_unused							\
    274mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)			\
    275{										\
    276	return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname), 0);	\
    277}										\
    278static inline void __maybe_unused						\
    279mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u8 val)			\
    280{										\
    281	__mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);	\
    282}
    283
    284#define MLXSW_ITEM8_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits,	\
    285			    _step, _instepoffset, _norealshift)			\
    286static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    287	.offset = _offset,							\
    288	.step = _step,								\
    289	.in_step_offset = _instepoffset,					\
    290	.shift = _shift,							\
    291	.no_real_shift = _norealshift,						\
    292	.size = {.bits = _sizebits,},						\
    293	.name = #_type "_" #_cname "_" #_iname,					\
    294};										\
    295static inline u8 __maybe_unused							\
    296mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
    297{										\
    298	return __mlxsw_item_get8(buf, &__ITEM_NAME(_type, _cname, _iname),	\
    299				 index);					\
    300}										\
    301static inline void __maybe_unused						\
    302mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,	\
    303					  u8 val)				\
    304{										\
    305	__mlxsw_item_set8(buf, &__ITEM_NAME(_type, _cname, _iname),		\
    306			  index, val);						\
    307}
    308
    309#define MLXSW_ITEM16(_type, _cname, _iname, _offset, _shift, _sizebits)		\
    310static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    311	.offset = _offset,							\
    312	.shift = _shift,							\
    313	.size = {.bits = _sizebits,},						\
    314	.name = #_type "_" #_cname "_" #_iname,					\
    315};										\
    316static inline u16 __maybe_unused						\
    317mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)			\
    318{										\
    319	return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname), 0);	\
    320}										\
    321static inline void __maybe_unused						\
    322mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 val)			\
    323{										\
    324	__mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);	\
    325}
    326
    327#define MLXSW_ITEM16_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits,	\
    328			     _step, _instepoffset, _norealshift)		\
    329static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    330	.offset = _offset,							\
    331	.step = _step,								\
    332	.in_step_offset = _instepoffset,					\
    333	.shift = _shift,							\
    334	.no_real_shift = _norealshift,						\
    335	.size = {.bits = _sizebits,},						\
    336	.name = #_type "_" #_cname "_" #_iname,					\
    337};										\
    338static inline u16 __maybe_unused						\
    339mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
    340{										\
    341	return __mlxsw_item_get16(buf, &__ITEM_NAME(_type, _cname, _iname),	\
    342				  index);					\
    343}										\
    344static inline void __maybe_unused						\
    345mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,	\
    346					  u16 val)				\
    347{										\
    348	__mlxsw_item_set16(buf, &__ITEM_NAME(_type, _cname, _iname),		\
    349			   index, val);						\
    350}
    351
    352#define MLXSW_ITEM32(_type, _cname, _iname, _offset, _shift, _sizebits)		\
    353static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    354	.offset = _offset,							\
    355	.shift = _shift,							\
    356	.size = {.bits = _sizebits,},						\
    357	.name = #_type "_" #_cname "_" #_iname,					\
    358};										\
    359static inline u32 __maybe_unused						\
    360mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)			\
    361{										\
    362	return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname), 0);	\
    363}										\
    364static inline void __maybe_unused						\
    365mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u32 val)			\
    366{										\
    367	__mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname), 0, val);	\
    368}
    369
    370#define LOCAL_PORT_LSB_SIZE 8
    371#define LOCAL_PORT_MSB_SIZE 2
    372
    373#define MLXSW_ITEM32_LP(_type, _cname, _offset1, _shift1, _offset2, _shift2)	\
    374static struct mlxsw_item __ITEM_NAME(_type, _cname, local_port) = {		\
    375	.offset = _offset1,							\
    376	.shift = _shift1,							\
    377	.size = {.bits = LOCAL_PORT_LSB_SIZE,},					\
    378	.name = #_type "_" #_cname "_local_port",				\
    379};										\
    380static struct mlxsw_item __ITEM_NAME(_type, _cname, lp_msb) = {			\
    381	.offset = _offset2,							\
    382	.shift = _shift2,							\
    383	.size = {.bits = LOCAL_PORT_MSB_SIZE,},					\
    384	.name = #_type "_" #_cname "_lp_msb",					\
    385};										\
    386static inline u32 __maybe_unused						\
    387mlxsw_##_type##_##_cname##_local_port_get(const char *buf)			\
    388{										\
    389	u32 local_port, lp_msb;							\
    390										\
    391	local_port = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname,	\
    392					local_port), 0);			\
    393	lp_msb = __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, lp_msb),	\
    394				   0);						\
    395	return (lp_msb << LOCAL_PORT_LSB_SIZE) + local_port;			\
    396}										\
    397static inline void __maybe_unused						\
    398mlxsw_##_type##_##_cname##_local_port_set(char *buf, u32 val)			\
    399{										\
    400	__mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, local_port), 0,	\
    401			   val & ((1 << LOCAL_PORT_LSB_SIZE) - 1));		\
    402	__mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, lp_msb), 0,		\
    403			   val >> LOCAL_PORT_LSB_SIZE);				\
    404}
    405
    406#define MLXSW_ITEM32_INDEXED(_type, _cname, _iname, _offset, _shift, _sizebits,	\
    407			     _step, _instepoffset, _norealshift)		\
    408static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    409	.offset = _offset,							\
    410	.step = _step,								\
    411	.in_step_offset = _instepoffset,					\
    412	.shift = _shift,							\
    413	.no_real_shift = _norealshift,						\
    414	.size = {.bits = _sizebits,},						\
    415	.name = #_type "_" #_cname "_" #_iname,					\
    416};										\
    417static inline u32 __maybe_unused						\
    418mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
    419{										\
    420	return __mlxsw_item_get32(buf, &__ITEM_NAME(_type, _cname, _iname),	\
    421				  index);					\
    422}										\
    423static inline void __maybe_unused						\
    424mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,	\
    425					  u32 val)				\
    426{										\
    427	__mlxsw_item_set32(buf, &__ITEM_NAME(_type, _cname, _iname),		\
    428			   index, val);						\
    429}
    430
    431#define MLXSW_ITEM64(_type, _cname, _iname, _offset, _shift, _sizebits)		\
    432static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    433	.offset = _offset,							\
    434	.shift = _shift,							\
    435	.size = {.bits = _sizebits,},						\
    436	.name = #_type "_" #_cname "_" #_iname,					\
    437};										\
    438static inline u64 __maybe_unused						\
    439mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf)			\
    440{										\
    441	return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname), 0);	\
    442}										\
    443static inline void __maybe_unused						\
    444mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u64 val)			\
    445{										\
    446	__mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname), 0,	val);	\
    447}
    448
    449#define MLXSW_ITEM64_INDEXED(_type, _cname, _iname, _offset, _shift,		\
    450			     _sizebits, _step, _instepoffset, _norealshift)	\
    451static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    452	.offset = _offset,							\
    453	.step = _step,								\
    454	.in_step_offset = _instepoffset,					\
    455	.shift = _shift,							\
    456	.no_real_shift = _norealshift,						\
    457	.size = {.bits = _sizebits,},						\
    458	.name = #_type "_" #_cname "_" #_iname,					\
    459};										\
    460static inline u64 __maybe_unused						\
    461mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, unsigned short index)\
    462{										\
    463	return __mlxsw_item_get64(buf, &__ITEM_NAME(_type, _cname, _iname),	\
    464				  index);					\
    465}										\
    466static inline void __maybe_unused						\
    467mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, unsigned short index,	\
    468					  u64 val)				\
    469{										\
    470	__mlxsw_item_set64(buf, &__ITEM_NAME(_type, _cname, _iname),		\
    471			   index, val);						\
    472}
    473
    474#define MLXSW_ITEM_BUF(_type, _cname, _iname, _offset, _sizebytes)		\
    475static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    476	.offset = _offset,							\
    477	.size = {.bytes = _sizebytes,},						\
    478	.name = #_type "_" #_cname "_" #_iname,					\
    479};										\
    480static inline void __maybe_unused						\
    481mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf, char *dst)	\
    482{										\
    483	__mlxsw_item_memcpy_from(buf, dst,					\
    484				 &__ITEM_NAME(_type, _cname, _iname), 0);	\
    485}										\
    486static inline void __maybe_unused						\
    487mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf, const char *src)	\
    488{										\
    489	__mlxsw_item_memcpy_to(buf, src,					\
    490			       &__ITEM_NAME(_type, _cname, _iname), 0);		\
    491}										\
    492static inline char * __maybe_unused						\
    493mlxsw_##_type##_##_cname##_##_iname##_data(char *buf)				\
    494{										\
    495	return __mlxsw_item_data(buf, &__ITEM_NAME(_type, _cname, _iname), 0);	\
    496}
    497
    498#define MLXSW_ITEM_BUF_INDEXED(_type, _cname, _iname, _offset, _sizebytes,	\
    499			       _step, _instepoffset)				\
    500static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    501	.offset = _offset,							\
    502	.step = _step,								\
    503	.in_step_offset = _instepoffset,					\
    504	.size = {.bytes = _sizebytes,},						\
    505	.name = #_type "_" #_cname "_" #_iname,					\
    506};										\
    507static inline void __maybe_unused						\
    508mlxsw_##_type##_##_cname##_##_iname##_memcpy_from(const char *buf,		\
    509						  unsigned short index,		\
    510						  char *dst)			\
    511{										\
    512	__mlxsw_item_memcpy_from(buf, dst,					\
    513				 &__ITEM_NAME(_type, _cname, _iname), index);	\
    514}										\
    515static inline void __maybe_unused						\
    516mlxsw_##_type##_##_cname##_##_iname##_memcpy_to(char *buf,			\
    517						unsigned short index,		\
    518						const char *src)		\
    519{										\
    520	__mlxsw_item_memcpy_to(buf, src,					\
    521			       &__ITEM_NAME(_type, _cname, _iname), index);	\
    522}										\
    523static inline char * __maybe_unused						\
    524mlxsw_##_type##_##_cname##_##_iname##_data(char *buf, unsigned short index)	\
    525{										\
    526	return __mlxsw_item_data(buf,						\
    527				 &__ITEM_NAME(_type, _cname, _iname), index);	\
    528}
    529
    530#define MLXSW_ITEM_BIT_ARRAY(_type, _cname, _iname, _offset, _sizebytes,	\
    531			     _element_size)					\
    532static struct mlxsw_item __ITEM_NAME(_type, _cname, _iname) = {			\
    533	.offset = _offset,							\
    534	.element_size = _element_size,						\
    535	.size = {.bytes = _sizebytes,},						\
    536	.name = #_type "_" #_cname "_" #_iname,					\
    537};										\
    538static inline u8 __maybe_unused							\
    539mlxsw_##_type##_##_cname##_##_iname##_get(const char *buf, u16 index)		\
    540{										\
    541	return __mlxsw_item_bit_array_get(buf,					\
    542					  &__ITEM_NAME(_type, _cname, _iname),	\
    543					  index);				\
    544}										\
    545static inline void __maybe_unused						\
    546mlxsw_##_type##_##_cname##_##_iname##_set(char *buf, u16 index, u8 val)		\
    547{										\
    548	return __mlxsw_item_bit_array_set(buf,					\
    549					  &__ITEM_NAME(_type, _cname, _iname),	\
    550					  index, val);				\
    551}										\
    552
    553#endif