1/*
2 * Byte order utilities
3 *
4 * Copyright (C) 1999-2013, Broadcom Corporation
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 *  $Id: bcmendian.h 241182 2011-02-17 21:50:03Z $
19 *
20 * This file by default provides proper behavior on little-endian architectures.
21 * On big-endian architectures, IL_BIGENDIAN should be defined.
22 */
23
24#ifndef _BCMENDIAN_H_
25#define _BCMENDIAN_H_
26
27#include <typedefs.h>
28
29/* Reverse the bytes in a 16-bit value */
30#define BCMSWAP16(val) \
31	((uint16)((((uint16)(val) & (uint16)0x00ffU) << 8) | \
32		  (((uint16)(val) & (uint16)0xff00U) >> 8)))
33
34/* Reverse the bytes in a 32-bit value */
35#define BCMSWAP32(val) \
36	((uint32)((((uint32)(val) & (uint32)0x000000ffU) << 24) | \
37		  (((uint32)(val) & (uint32)0x0000ff00U) <<  8) | \
38		  (((uint32)(val) & (uint32)0x00ff0000U) >>  8) | \
39		  (((uint32)(val) & (uint32)0xff000000U) >> 24)))
40
41/* Reverse the two 16-bit halves of a 32-bit value */
42#define BCMSWAP32BY16(val) \
43	((uint32)((((uint32)(val) & (uint32)0x0000ffffU) << 16) | \
44		  (((uint32)(val) & (uint32)0xffff0000U) >> 16)))
45
46/* Byte swapping macros
47 *    Host <=> Network (Big Endian) for 16- and 32-bit values
48 *    Host <=> Little-Endian for 16- and 32-bit values
49 */
50#ifndef hton16
51#define HTON16(i) BCMSWAP16(i)
52#define	hton16(i) bcmswap16(i)
53#define	HTON32(i) BCMSWAP32(i)
54#define	hton32(i) bcmswap32(i)
55#define	NTOH16(i) BCMSWAP16(i)
56#define	ntoh16(i) bcmswap16(i)
57#define	NTOH32(i) BCMSWAP32(i)
58#define	ntoh32(i) bcmswap32(i)
59#define LTOH16(i) (i)
60#define ltoh16(i) (i)
61#define LTOH32(i) (i)
62#define ltoh32(i) (i)
63#define HTOL16(i) (i)
64#define htol16(i) (i)
65#define HTOL32(i) (i)
66#define htol32(i) (i)
67#endif /* hton16 */
68
69#define ltoh16_buf(buf, i)
70#define htol16_buf(buf, i)
71
72/* Unaligned loads and stores in host byte order */
73#define load32_ua(a)		ltoh32_ua(a)
74#define store32_ua(a, v)	htol32_ua_store(v, a)
75#define load16_ua(a)		ltoh16_ua(a)
76#define store16_ua(a, v)	htol16_ua_store(v, a)
77
78#define _LTOH16_UA(cp)	((cp)[0] | ((cp)[1] << 8))
79#define _LTOH32_UA(cp)	((cp)[0] | ((cp)[1] << 8) | ((cp)[2] << 16) | ((cp)[3] << 24))
80#define _NTOH16_UA(cp)	(((cp)[0] << 8) | (cp)[1])
81#define _NTOH32_UA(cp)	(((cp)[0] << 24) | ((cp)[1] << 16) | ((cp)[2] << 8) | (cp)[3])
82
83#define ltoh_ua(ptr) \
84	(sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \
85	 sizeof(*(ptr)) == sizeof(uint16) ? _LTOH16_UA((const uint8 *)(ptr)) : \
86	 sizeof(*(ptr)) == sizeof(uint32) ? _LTOH32_UA((const uint8 *)(ptr)) : \
87	 *(uint8 *)0)
88
89#define ntoh_ua(ptr) \
90	(sizeof(*(ptr)) == sizeof(uint8) ? *(const uint8 *)(ptr) : \
91	 sizeof(*(ptr)) == sizeof(uint16) ? _NTOH16_UA((const uint8 *)(ptr)) : \
92	 sizeof(*(ptr)) == sizeof(uint32) ? _NTOH32_UA((const uint8 *)(ptr)) : \
93	 *(uint8 *)0)
94
95#ifdef __GNUC__
96
97/* GNU macro versions avoid referencing the argument multiple times, while also
98 * avoiding the -fno-inline used in ROM builds.
99 */
100
101#define bcmswap16(val) ({ \
102	uint16 _val = (val); \
103	BCMSWAP16(_val); \
104})
105
106#define bcmswap32(val) ({ \
107	uint32 _val = (val); \
108	BCMSWAP32(_val); \
109})
110
111#define bcmswap32by16(val) ({ \
112	uint32 _val = (val); \
113	BCMSWAP32BY16(_val); \
114})
115
116#define bcmswap16_buf(buf, len) ({ \
117	uint16 *_buf = (uint16 *)(buf); \
118	uint _wds = (len) / 2; \
119	while (_wds--) { \
120		*_buf = bcmswap16(*_buf); \
121		_buf++; \
122	} \
123})
124
125#define htol16_ua_store(val, bytes) ({ \
126	uint16 _val = (val); \
127	uint8 *_bytes = (uint8 *)(bytes); \
128	_bytes[0] = _val & 0xff; \
129	_bytes[1] = _val >> 8; \
130})
131
132#define htol32_ua_store(val, bytes) ({ \
133	uint32 _val = (val); \
134	uint8 *_bytes = (uint8 *)(bytes); \
135	_bytes[0] = _val & 0xff; \
136	_bytes[1] = (_val >> 8) & 0xff; \
137	_bytes[2] = (_val >> 16) & 0xff; \
138	_bytes[3] = _val >> 24; \
139})
140
141#define hton16_ua_store(val, bytes) ({ \
142	uint16 _val = (val); \
143	uint8 *_bytes = (uint8 *)(bytes); \
144	_bytes[0] = _val >> 8; \
145	_bytes[1] = _val & 0xff; \
146})
147
148#define hton32_ua_store(val, bytes) ({ \
149	uint32 _val = (val); \
150	uint8 *_bytes = (uint8 *)(bytes); \
151	_bytes[0] = _val >> 24; \
152	_bytes[1] = (_val >> 16) & 0xff; \
153	_bytes[2] = (_val >> 8) & 0xff; \
154	_bytes[3] = _val & 0xff; \
155})
156
157#define ltoh16_ua(bytes) ({ \
158	const uint8 *_bytes = (const uint8 *)(bytes); \
159	_LTOH16_UA(_bytes); \
160})
161
162#define ltoh32_ua(bytes) ({ \
163	const uint8 *_bytes = (const uint8 *)(bytes); \
164	_LTOH32_UA(_bytes); \
165})
166
167#define ntoh16_ua(bytes) ({ \
168	const uint8 *_bytes = (const uint8 *)(bytes); \
169	_NTOH16_UA(_bytes); \
170})
171
172#define ntoh32_ua(bytes) ({ \
173	const uint8 *_bytes = (const uint8 *)(bytes); \
174	_NTOH32_UA(_bytes); \
175})
176
177#else /* !__GNUC__ */
178
179/* Inline versions avoid referencing the argument multiple times */
180static INLINE uint16
181bcmswap16(uint16 val)
182{
183	return BCMSWAP16(val);
184}
185
186static INLINE uint32
187bcmswap32(uint32 val)
188{
189	return BCMSWAP32(val);
190}
191
192static INLINE uint32
193bcmswap32by16(uint32 val)
194{
195	return BCMSWAP32BY16(val);
196}
197
198/* Reverse pairs of bytes in a buffer (not for high-performance use) */
199/* buf	- start of buffer of shorts to swap */
200/* len  - byte length of buffer */
201static INLINE void
202bcmswap16_buf(uint16 *buf, uint len)
203{
204	len = len / 2;
205
206	while (len--) {
207		*buf = bcmswap16(*buf);
208		buf++;
209	}
210}
211
212/*
213 * Store 16-bit value to unaligned little-endian byte array.
214 */
215static INLINE void
216htol16_ua_store(uint16 val, uint8 *bytes)
217{
218	bytes[0] = val & 0xff;
219	bytes[1] = val >> 8;
220}
221
222/*
223 * Store 32-bit value to unaligned little-endian byte array.
224 */
225static INLINE void
226htol32_ua_store(uint32 val, uint8 *bytes)
227{
228	bytes[0] = val & 0xff;
229	bytes[1] = (val >> 8) & 0xff;
230	bytes[2] = (val >> 16) & 0xff;
231	bytes[3] = val >> 24;
232}
233
234/*
235 * Store 16-bit value to unaligned network-(big-)endian byte array.
236 */
237static INLINE void
238hton16_ua_store(uint16 val, uint8 *bytes)
239{
240	bytes[0] = val >> 8;
241	bytes[1] = val & 0xff;
242}
243
244/*
245 * Store 32-bit value to unaligned network-(big-)endian byte array.
246 */
247static INLINE void
248hton32_ua_store(uint32 val, uint8 *bytes)
249{
250	bytes[0] = val >> 24;
251	bytes[1] = (val >> 16) & 0xff;
252	bytes[2] = (val >> 8) & 0xff;
253	bytes[3] = val & 0xff;
254}
255
256/*
257 * Load 16-bit value from unaligned little-endian byte array.
258 */
259static INLINE uint16
260ltoh16_ua(const void *bytes)
261{
262	return _LTOH16_UA((const uint8 *)bytes);
263}
264
265/*
266 * Load 32-bit value from unaligned little-endian byte array.
267 */
268static INLINE uint32
269ltoh32_ua(const void *bytes)
270{
271	return _LTOH32_UA((const uint8 *)bytes);
272}
273
274/*
275 * Load 16-bit value from unaligned big-(network-)endian byte array.
276 */
277static INLINE uint16
278ntoh16_ua(const void *bytes)
279{
280	return _NTOH16_UA((const uint8 *)bytes);
281}
282
283/*
284 * Load 32-bit value from unaligned big-(network-)endian byte array.
285 */
286static INLINE uint32
287ntoh32_ua(const void *bytes)
288{
289	return _NTOH32_UA((const uint8 *)bytes);
290}
291
292#endif /* !__GNUC__ */
293#endif /* !_BCMENDIAN_H_ */
294