linuxOS_D21X/source/linux-5.10/drivers/net/ethernet/artinchip/aicmac_macaddr.c
2024-11-29 16:23:11 +08:00

119 lines
2.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2021 ArtInChip Technology Co., Ltd.
* Author: Keliang Liu <keliang.liu@artinchip.com>
*/
#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/crc32.h>
#include <linux/crypto.h>
#include <crypto/algapi.h>
#include <crypto/hash.h>
#include <linux/random.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/etherdevice.h>
#include <linux/nvmem-consumer.h>
#include "aicmac_util.h"
#define AIC_CHIPID_SIZE 16
#define MAC_MD5_SIZE 16
static int aicmac_macaddr_md5_ahash(unsigned char *chipid, unsigned char *addr)
{
struct shash_desc *desc;
struct crypto_shash *shash = NULL;
unsigned char result[MAC_MD5_SIZE] = { 0 };
int i = 0;
size_t size = 0;
shash = crypto_alloc_shash("md5", 0, CRYPTO_ALG_ASYNC);
size = sizeof(struct shash_desc) + crypto_shash_descsize(shash);
desc = kmalloc(size, GFP_KERNEL);
if (!desc) {
crypto_free_shash(shash);
return -1;
}
desc->tfm = shash;
crypto_shash_init(desc);
crypto_shash_update(desc, chipid, AIC_CHIPID_SIZE);
crypto_shash_final(desc, result);
/* Choose md5 result's [0][2][4][6][8][10] byte as mac address */
for (i = 0; i < ETH_ALEN; i++)
addr[i] = result[2 * i];
crypto_free_shash(shash);
kfree(desc);
return 0;
}
static int aicmac_get_soc_chipid(struct device *dev, unsigned char *chipid)
{
struct nvmem_cell *cell;
size_t len;
void *value;
cell = devm_nvmem_cell_get(dev, "chipid");
if (IS_ERR(cell)) {
dev_info(dev, "Failed to get cell\n");
return -1;
}
value = nvmem_cell_read(cell, &len);
if (len == 0) {
dev_info(dev, "Efuse didn't burn calibration value\n");
return -1;
}
sprintf(chipid, "%llx", *((u64 *)value));
return 0;
}
static void aicmac_macaddr_from_chipid(struct device *dev, int bus_id, unsigned char *addr)
{
unsigned char chipid[17] = { 0 };
int ret = -1;
ret = aicmac_get_soc_chipid(dev, (unsigned char *)chipid);
if (ret != 0) {
pr_err("%s can't get chipid\n", __func__);
return;
}
if (bus_id == 0)
chipid[15] = 'a';
else
chipid[15] = 'A';
ret = aicmac_macaddr_md5_ahash(chipid, addr);
if (ret != 0) {
pr_err("%s failed to md5 chipid\n", __func__);
return;
}
addr[0] &= 0xfe; /* clear multicast bit */
addr[0] |= 0x02; /* set local assignment bit (IEEE802) */
}
static void aicmac_macaddr_from_random(unsigned char *addr)
{
get_random_bytes(addr, ETH_ALEN);
addr[0] &= 0xfe; /* clear multicast bit */
addr[0] |= 0x02; /* set local assignment bit (IEEE802) */
}
void aicmac_get_mac_addr(struct device *dev, int bus_id, unsigned char *addr)
{
if (!is_valid_ether_addr(addr)) {
aicmac_macaddr_from_chipid(dev, bus_id, addr);
if (!is_valid_ether_addr(addr))
aicmac_macaddr_from_random(addr);
}
}