// SPDX-License-Identifier: BSD-3-Clause
/* Copyright (c) 2016-2018, NXP Semiconductors
* Copyright (c) 2018-2019, Vladimir Oltean <olteanv@gmail.com>
*/
#include "sja1105_static_config.h"
#include <linux/crc32.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
/* Convenience wrappers over the generic packing functions. These take into
* account the SJA1105 memory layout quirks and provide some level of
* programmer protection against incorrect API use. The errors are not expected
* to occur durring runtime, therefore printing and swallowing them here is
* appropriate instead of clutterring up higher-level code.
*/
void sja1105_pack(void *buf, const u64 *val, int start, int end, size_t len)
{
int rc = packing(buf, (u64 *)val, start, end, len,
PACK, QUIRK_LSW32_IS_FIRST);
if (likely(!rc))
return;
if (rc == -EINVAL) {
pr_err("Start bit (%d) expected to be larger than end (%d)\n",
start, end);
} else if (rc == -ERANGE) {
if ((start - end + 1) > 64)
pr_err("Field %d-%d too large for 64 bits!\n",
start, end);
else
pr_err("Cannot store %llx inside bits %d-%d (would truncate)\n",
*val, start, end);
}
dump_stack();
}
void sja1105_unpack(const void *buf, u64 *val, int start, int end, size_t len)
{
int rc = packing((void *)buf, val, start, end, len,
UNPACK, QUIRK_LSW32_IS_FIRST);
if (likely(!rc))
return;
if (rc == -EINVAL)
pr_err("Start bit (%d) expected to be larger than end (%d)\n",
start, end);
else if (rc == -ERANGE)
pr_err("Field %d-%d too large for 64 bits!\n",
start, end);
dump_stack();
}
void sja1105_packing(void *buf, u64 *val, int start, int end,
size_t len, enum packing_op op)
{
int rc = packing(buf, val, start, end, len, op, QUIRK_LSW32_IS_FIRST);
if (likely(!rc))
return;
if (rc == -EINVAL) {
pr_err("Start bit (%d) expected to be larger than end (%d)\n",
start, end);
} else if (rc == -ERANGE) {
if ((start - end + 1) > 64)
pr_err("Field %d-%d too large for 64 bits!\n",
start, end);
else
pr_err("Cannot store %llx inside bits %d-%d (would truncate)\n",
*val, start, end);
}
dump_stack();
}
/* Little-endian Ethernet CRC32 of data packed as big-endian u32 words */
u32 sja1105_crc32(const void *buf, size_t len)
{
unsigned int i;
u64 word;
u32 crc;
/* seed */
crc = ~0;
for (i = 0; i < len; i += 4) {
sja1105_unpack((void *)buf + i, &word, 31, 0, 4);
crc = crc32_le(crc, (u8 *)&word, 4);
}
return ~crc;
}
static size_t sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
enum packing_op op)
{
const size_t size = SJA1105ET_SIZE_GENERAL_PARAMS_ENTRY;
struct sja1105_general_params_entry *entry = entry_ptr;
sja1105_packing(buf, &entry->vllupformat, 319, 319, size, op);
sja1105_packing(buf, &entry->mirr_ptacu, 318, 318, size, op);
sja1105_packing(buf, &entry->switchid, 317, 315, size, op);
sja1105_packing(buf, &entry->hostprio, 314, 312, size, op);
sja1105_packing(buf, &entry->mac_fltres1, 311, 264, size, op);
sja1105_packing(buf, &entry->mac_fltres0, 263, 216, size, op);
sja1105_packing(buf, &entry->mac_flt1, 215, 168, size, op