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

eeprom.c (7696B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
      4 */
      5#include <linux/of.h>
      6#include <linux/of_net.h>
      7#include <linux/mtd/mtd.h>
      8#include <linux/mtd/partitions.h>
      9#include <linux/etherdevice.h>
     10#include "mt76.h"
     11
     12int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
     13{
     14#if defined(CONFIG_OF) && defined(CONFIG_MTD)
     15	struct device_node *np = dev->dev->of_node;
     16	struct mtd_info *mtd;
     17	const __be32 *list;
     18	const void *data;
     19	const char *part;
     20	phandle phandle;
     21	int size;
     22	size_t retlen;
     23	int ret;
     24
     25	if (!np)
     26		return -ENOENT;
     27
     28	data = of_get_property(np, "mediatek,eeprom-data", &size);
     29	if (data) {
     30		if (size > len)
     31			return -EINVAL;
     32
     33		memcpy(eep, data, size);
     34
     35		return 0;
     36	}
     37
     38	list = of_get_property(np, "mediatek,mtd-eeprom", &size);
     39	if (!list)
     40		return -ENOENT;
     41
     42	phandle = be32_to_cpup(list++);
     43	if (!phandle)
     44		return -ENOENT;
     45
     46	np = of_find_node_by_phandle(phandle);
     47	if (!np)
     48		return -EINVAL;
     49
     50	part = of_get_property(np, "label", NULL);
     51	if (!part)
     52		part = np->name;
     53
     54	mtd = get_mtd_device_nm(part);
     55	if (IS_ERR(mtd)) {
     56		ret =  PTR_ERR(mtd);
     57		goto out_put_node;
     58	}
     59
     60	if (size <= sizeof(*list)) {
     61		ret = -EINVAL;
     62		goto out_put_node;
     63	}
     64
     65	offset = be32_to_cpup(list);
     66	ret = mtd_read(mtd, offset, len, &retlen, eep);
     67	put_mtd_device(mtd);
     68	if (mtd_is_bitflip(ret))
     69		ret = 0;
     70	if (ret) {
     71		dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n",
     72			part, ret);
     73		goto out_put_node;
     74	}
     75
     76	if (retlen < len) {
     77		ret = -EINVAL;
     78		goto out_put_node;
     79	}
     80
     81	if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
     82		u8 *data = (u8 *)eep;
     83		int i;
     84
     85		/* convert eeprom data in Little Endian */
     86		for (i = 0; i < round_down(len, 2); i += 2)
     87			put_unaligned_le16(get_unaligned_be16(&data[i]),
     88					   &data[i]);
     89	}
     90
     91#ifdef CONFIG_NL80211_TESTMODE
     92	dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
     93	dev->test_mtd.offset = offset;
     94#endif
     95
     96out_put_node:
     97	of_node_put(np);
     98	return ret;
     99#else
    100	return -ENOENT;
    101#endif
    102}
    103EXPORT_SYMBOL_GPL(mt76_get_of_eeprom);
    104
    105void
    106mt76_eeprom_override(struct mt76_phy *phy)
    107{
    108	struct mt76_dev *dev = phy->dev;
    109	struct device_node *np = dev->dev->of_node;
    110
    111	of_get_mac_address(np, phy->macaddr);
    112
    113	if (!is_valid_ether_addr(phy->macaddr)) {
    114		eth_random_addr(phy->macaddr);
    115		dev_info(dev->dev,
    116			 "Invalid MAC address, using random address %pM\n",
    117			 phy->macaddr);
    118	}
    119}
    120EXPORT_SYMBOL_GPL(mt76_eeprom_override);
    121
    122static bool mt76_string_prop_find(struct property *prop, const char *str)
    123{
    124	const char *cp = NULL;
    125
    126	if (!prop || !str || !str[0])
    127		return false;
    128
    129	while ((cp = of_prop_next_string(prop, cp)) != NULL)
    130		if (!strcasecmp(cp, str))
    131			return true;
    132
    133	return false;
    134}
    135
    136static struct device_node *
    137mt76_find_power_limits_node(struct mt76_dev *dev)
    138{
    139	struct device_node *np = dev->dev->of_node;
    140	const char *const region_names[] = {
    141		[NL80211_DFS_ETSI] = "etsi",
    142		[NL80211_DFS_FCC] = "fcc",
    143		[NL80211_DFS_JP] = "jp",
    144	};
    145	struct device_node *cur, *fallback = NULL;
    146	const char *region_name = NULL;
    147
    148	if (dev->region < ARRAY_SIZE(region_names))
    149		region_name = region_names[dev->region];
    150
    151	np = of_get_child_by_name(np, "power-limits");
    152	if (!np)
    153		return NULL;
    154
    155	for_each_child_of_node(np, cur) {
    156		struct property *country = of_find_property(cur, "country", NULL);
    157		struct property *regd = of_find_property(cur, "regdomain", NULL);
    158
    159		if (!country && !regd) {
    160			fallback = cur;
    161			continue;
    162		}
    163
    164		if (mt76_string_prop_find(country, dev->alpha2) ||
    165		    mt76_string_prop_find(regd, region_name))
    166			return cur;
    167	}
    168
    169	return fallback;
    170}
    171
    172static const __be32 *
    173mt76_get_of_array(struct device_node *np, char *name, size_t *len, int min)
    174{
    175	struct property *prop = of_find_property(np, name, NULL);
    176
    177	if (!prop || !prop->value || prop->length < min * 4)
    178		return NULL;
    179
    180	*len = prop->length;
    181
    182	return prop->value;
    183}
    184
    185static struct device_node *
    186mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan)
    187{
    188	struct device_node *cur;
    189	const __be32 *val;
    190	size_t len;
    191
    192	for_each_child_of_node(np, cur) {
    193		val = mt76_get_of_array(cur, "channels", &len, 2);
    194		if (!val)
    195			continue;
    196
    197		while (len >= 2 * sizeof(*val)) {
    198			if (chan->hw_value >= be32_to_cpu(val[0]) &&
    199			    chan->hw_value <= be32_to_cpu(val[1]))
    200				return cur;
    201
    202			val += 2;
    203			len -= 2 * sizeof(*val);
    204		}
    205	}
    206
    207	return NULL;
    208}
    209
    210static s8
    211mt76_get_txs_delta(struct device_node *np, u8 nss)
    212{
    213	const __be32 *val;
    214	size_t len;
    215
    216	val = mt76_get_of_array(np, "txs-delta", &len, nss);
    217	if (!val)
    218		return 0;
    219
    220	return be32_to_cpu(val[nss - 1]);
    221}
    222
    223static void
    224mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data,
    225		       s8 target_power, s8 nss_delta, s8 *max_power)
    226{
    227	int i;
    228
    229	if (!data)
    230		return;
    231
    232	for (i = 0; i < pwr_len; i++) {
    233		pwr[i] = min_t(s8, target_power,
    234			       be32_to_cpu(data[i]) + nss_delta);
    235		*max_power = max(*max_power, pwr[i]);
    236	}
    237}
    238
    239static void
    240mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
    241			     const __be32 *data, size_t len, s8 target_power,
    242			     s8 nss_delta, s8 *max_power)
    243{
    244	int i, cur;
    245
    246	if (!data)
    247		return;
    248
    249	len /= 4;
    250	cur = be32_to_cpu(data[0]);
    251	for (i = 0; i < pwr_num; i++) {
    252		if (len < pwr_len + 1)
    253			break;
    254
    255		mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
    256				       target_power, nss_delta, max_power);
    257		if (--cur > 0)
    258			continue;
    259
    260		data += pwr_len + 1;
    261		len -= pwr_len + 1;
    262		if (!len)
    263			break;
    264
    265		cur = be32_to_cpu(data[0]);
    266	}
    267}
    268
    269s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
    270			      struct ieee80211_channel *chan,
    271			      struct mt76_power_limits *dest,
    272			      s8 target_power)
    273{
    274	struct mt76_dev *dev = phy->dev;
    275	struct device_node *np;
    276	const __be32 *val;
    277	char name[16];
    278	u32 mcs_rates = dev->drv->mcs_rates;
    279	u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
    280	char band;
    281	size_t len;
    282	s8 max_power = 0;
    283	s8 txs_delta;
    284
    285	if (!mcs_rates)
    286		mcs_rates = 10;
    287
    288	memset(dest, target_power, sizeof(*dest));
    289
    290	if (!IS_ENABLED(CONFIG_OF))
    291		return target_power;
    292
    293	np = mt76_find_power_limits_node(dev);
    294	if (!np)
    295		return target_power;
    296
    297	switch (chan->band) {
    298	case NL80211_BAND_2GHZ:
    299		band = '2';
    300		break;
    301	case NL80211_BAND_5GHZ:
    302		band = '5';
    303		break;
    304	case NL80211_BAND_6GHZ:
    305		band = '6';
    306		break;
    307	default:
    308		return target_power;
    309	}
    310
    311	snprintf(name, sizeof(name), "txpower-%cg", band);
    312	np = of_get_child_by_name(np, name);
    313	if (!np)
    314		return target_power;
    315
    316	np = mt76_find_channel_node(np, chan);
    317	if (!np)
    318		return target_power;
    319
    320	txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask));
    321
    322	val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
    323	mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
    324			       target_power, txs_delta, &max_power);
    325
    326	val = mt76_get_of_array(np, "rates-ofdm",
    327				&len, ARRAY_SIZE(dest->ofdm));
    328	mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
    329			       target_power, txs_delta, &max_power);
    330
    331	val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1);
    332	mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
    333				     ARRAY_SIZE(dest->mcs), val, len,
    334				     target_power, txs_delta, &max_power);
    335
    336	val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1);
    337	mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
    338				     ARRAY_SIZE(dest->ru), val, len,
    339				     target_power, txs_delta, &max_power);
    340
    341	return max_power;
    342}
    343EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);
    344
    345int
    346mt76_eeprom_init(struct mt76_dev *dev, int len)
    347{
    348	dev->eeprom.size = len;
    349	dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL);
    350	if (!dev->eeprom.data)
    351		return -ENOMEM;
    352
    353	return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len);
    354}
    355EXPORT_SYMBOL_GPL(mt76_eeprom_init);