1 From dab16ef495dbb3cabb355b6c80f0771a4a25e35d Mon Sep 17 00:00:00 2001
2 From: Christian Lamparter <chunkeey@gmail.com>
3 Date: Fri, 20 Aug 2021 22:44:52 +0200
4 Subject: [PATCH] ath9k: fetch calibration data via nvmem subsystem
6 On most embedded ath9k devices (like range extenders,
7 routers, accesspoints, ...) the calibration data is
8 stored in a MTD partitions named "ART", or "caldata"/
12 4b361cfa8624 ("mtd: core: add OTP nvmem provider support")
13 all MTD partitions are all automatically available through
14 the nvmem subsystem. This allows drivers like ath9k to read
15 the necessary data without needing any userspace helpers
16 that would do this extraction.
18 Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
23 From 57671351379b2051cfb07fc14e0bead9916a0880 Mon Sep 17 00:00:00 2001
24 From: Dan Carpenter <dan.carpenter@oracle.com>
25 Date: Mon, 11 Oct 2021 18:18:01 +0300
26 Subject: ath9k: fix an IS_ERR() vs NULL check
28 The devm_kmemdup() function doesn't return error pointers, it returns
31 Fixes: eb3a97a69be8 ("ath9k: fetch calibration data via nvmem subsystem")
32 Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
33 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
34 Link: https://lore.kernel.org/r/20211011123533.GA15188@kili
38 --- a/drivers/net/wireless/ath/ath9k/eeprom.c
39 +++ b/drivers/net/wireless/ath/ath9k/eeprom.c
40 @@ -135,13 +135,23 @@ static bool ath9k_hw_nvram_read_firmware
44 +static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset,
47 + return ath9k_hw_nvram_read_array(ah->nvmem_blob,
48 + ah->nvmem_blob_len / sizeof(u16),
52 bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
54 struct ath_common *common = ath9k_hw_common(ah);
55 struct ath9k_platform_data *pdata = ah->dev->platform_data;
58 - if (ah->eeprom_blob)
60 + ret = ath9k_hw_nvram_read_nvmem(ah, off, data);
61 + else if (ah->eeprom_blob)
62 ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
63 else if (pdata && !pdata->use_eeprom)
64 ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
65 --- a/drivers/net/wireless/ath/ath9k/hw.h
66 +++ b/drivers/net/wireless/ath/ath9k/hw.h
67 @@ -988,6 +988,8 @@ struct ath_hw {
70 const struct firmware *eeprom_blob;
71 + u16 *nvmem_blob; /* devres managed */
72 + size_t nvmem_blob_len;
74 struct ath_dynack dynack;
76 --- a/drivers/net/wireless/ath/ath9k/init.c
77 +++ b/drivers/net/wireless/ath/ath9k/init.c
79 #include <linux/module.h>
81 #include <linux/of_net.h>
82 +#include <linux/nvmem-consumer.h>
83 #include <linux/relay.h>
84 #include <linux/dmi.h>
85 #include <net/ieee80211_radiotap.h>
86 @@ -568,6 +569,57 @@ static void ath9k_eeprom_release(struct
87 release_firmware(sc->sc_ah->eeprom_blob);
90 +static int ath9k_nvmem_request_eeprom(struct ath_softc *sc)
92 + struct ath_hw *ah = sc->sc_ah;
93 + struct nvmem_cell *cell;
98 + cell = devm_nvmem_cell_get(sc->dev, "calibration");
100 + err = PTR_ERR(cell);
102 + /* nvmem cell might not be defined, or the nvmem
103 + * subsystem isn't included. In this case, follow
104 + * the established "just return 0;" convention of
105 + * ath9k_init_platform to say:
106 + * "All good. Nothing to see here. Please go on."
108 + if (err == -ENOENT || err == -EOPNOTSUPP)
114 + buf = nvmem_cell_read(cell, &len);
116 + return PTR_ERR(buf);
118 + /* run basic sanity checks on the returned nvram cell length.
119 + * That length has to be a multiple of a "u16" (i.e.: & 1).
120 + * Furthermore, it has to be more than "let's say" 512 bytes
121 + * but less than the maximum of AR9300_EEPROM_SIZE (16kb).
123 + if (((len & 1) == 1) || (len < 512) || (len >= AR9300_EEPROM_SIZE)) {
128 + /* devres manages the calibration values release on shutdown */
129 + ah->nvmem_blob = (u16 *)devm_kmemdup(sc->dev, buf, len, GFP_KERNEL);
131 + if (!ah->nvmem_blob)
134 + ah->nvmem_blob_len = len;
135 + ah->ah_flags &= ~AH_USE_EEPROM;
136 + ah->ah_flags |= AH_NO_EEP_SWAP;
141 static int ath9k_init_platform(struct ath_softc *sc)
143 struct ath9k_platform_data *pdata = sc->dev->platform_data;
144 @@ -710,6 +762,10 @@ static int ath9k_init_softc(u16 devid, s
148 + ret = ath9k_nvmem_request_eeprom(sc);
152 if (ath9k_led_active_high != -1)
153 ah->config.led_active_high = ath9k_led_active_high == 1;