mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	With "getting WIFI MAC from NVMEM" working on ath79 on 5.10, the next logical step I think is to utilize nvmem subsystem to also get the calibration data from there. This will tremendously speed up the wifi bring-up, since we no longer need the userspace helper for the simple devices that can just load them from there. included with this patch is a package/mac80211/refresh. Tested on: WNDR3700v2, TP-Link Archer C7v2 Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
		
			
				
	
	
		
			155 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From dab16ef495dbb3cabb355b6c80f0771a4a25e35d Mon Sep 17 00:00:00 2001
 | |
| From: Christian Lamparter <chunkeey@gmail.com>
 | |
| Date: Fri, 20 Aug 2021 22:44:52 +0200
 | |
| Subject: [PATCH] ath9k: fetch calibration data via nvmem subsystem
 | |
| 
 | |
| On most embedded ath9k devices (like range extenders,
 | |
| routers, accesspoints, ...) the calibration data is
 | |
| stored in a MTD partitions named "ART", or "caldata"/
 | |
| "calibration".
 | |
| 
 | |
| Ever since commit
 | |
| 4b361cfa8624 ("mtd: core: add OTP nvmem provider support")
 | |
| all MTD partitions are all automatically available through
 | |
| the nvmem subsystem. This allows drivers like ath9k to read
 | |
| the necessary data without needing any userspace helpers
 | |
| that would do this extraction.
 | |
| 
 | |
| Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 | |
| ---
 | |
| 
 | |
| includes:
 | |
| 
 | |
| From 57671351379b2051cfb07fc14e0bead9916a0880 Mon Sep 17 00:00:00 2001
 | |
| From: Dan Carpenter <dan.carpenter@oracle.com>
 | |
| Date: Mon, 11 Oct 2021 18:18:01 +0300
 | |
| Subject: ath9k: fix an IS_ERR() vs NULL check
 | |
| 
 | |
| The devm_kmemdup() function doesn't return error pointers, it returns
 | |
| NULL on error.
 | |
| 
 | |
| Fixes: eb3a97a69be8 ("ath9k: fetch calibration data via nvmem subsystem")
 | |
| Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
 | |
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
 | |
| Link: https://lore.kernel.org/r/20211011123533.GA15188@kili
 | |
| 
 | |
| ---
 | |
| 
 | |
| --- a/drivers/net/wireless/ath/ath9k/eeprom.c
 | |
| +++ b/drivers/net/wireless/ath/ath9k/eeprom.c
 | |
| @@ -135,13 +135,23 @@ static bool ath9k_hw_nvram_read_firmware
 | |
|  					 offset, data);
 | |
|  }
 | |
|  
 | |
| +static bool ath9k_hw_nvram_read_nvmem(struct ath_hw *ah, off_t offset,
 | |
| +				      u16 *data)
 | |
| +{
 | |
| +	return ath9k_hw_nvram_read_array(ah->nvmem_blob,
 | |
| +					 ah->nvmem_blob_len / sizeof(u16),
 | |
| +					 offset, data);
 | |
| +}
 | |
| +
 | |
|  bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
 | |
|  {
 | |
|  	struct ath_common *common = ath9k_hw_common(ah);
 | |
|  	struct ath9k_platform_data *pdata = ah->dev->platform_data;
 | |
|  	bool ret;
 | |
|  
 | |
| -	if (ah->eeprom_blob)
 | |
| +	if (ah->nvmem_blob)
 | |
| +		ret = ath9k_hw_nvram_read_nvmem(ah, off, data);
 | |
| +	else if (ah->eeprom_blob)
 | |
|  		ret = ath9k_hw_nvram_read_firmware(ah->eeprom_blob, off, data);
 | |
|  	else if (pdata && !pdata->use_eeprom)
 | |
|  		ret = ath9k_hw_nvram_read_pdata(pdata, off, data);
 | |
| --- a/drivers/net/wireless/ath/ath9k/hw.h
 | |
| +++ b/drivers/net/wireless/ath/ath9k/hw.h
 | |
| @@ -988,6 +988,8 @@ struct ath_hw {
 | |
|  	bool disable_5ghz;
 | |
|  
 | |
|  	const struct firmware *eeprom_blob;
 | |
| +	u16 *nvmem_blob;	/* devres managed */
 | |
| +	size_t nvmem_blob_len;
 | |
|  
 | |
|  	struct ath_dynack dynack;
 | |
|  
 | |
| --- a/drivers/net/wireless/ath/ath9k/init.c
 | |
| +++ b/drivers/net/wireless/ath/ath9k/init.c
 | |
| @@ -22,6 +22,7 @@
 | |
|  #include <linux/module.h>
 | |
|  #include <linux/of.h>
 | |
|  #include <linux/of_net.h>
 | |
| +#include <linux/nvmem-consumer.h>
 | |
|  #include <linux/relay.h>
 | |
|  #include <linux/dmi.h>
 | |
|  #include <net/ieee80211_radiotap.h>
 | |
| @@ -568,6 +569,57 @@ static void ath9k_eeprom_release(struct
 | |
|  	release_firmware(sc->sc_ah->eeprom_blob);
 | |
|  }
 | |
|  
 | |
| +static int ath9k_nvmem_request_eeprom(struct ath_softc *sc)
 | |
| +{
 | |
| +	struct ath_hw *ah = sc->sc_ah;
 | |
| +	struct nvmem_cell *cell;
 | |
| +	void *buf;
 | |
| +	size_t len;
 | |
| +	int err;
 | |
| +
 | |
| +	cell = devm_nvmem_cell_get(sc->dev, "calibration");
 | |
| +	if (IS_ERR(cell)) {
 | |
| +		err = PTR_ERR(cell);
 | |
| +
 | |
| +		/* nvmem cell might not be defined, or the nvmem
 | |
| +		 * subsystem isn't included. In this case, follow
 | |
| +		 * the established "just return 0;" convention of
 | |
| +		 * ath9k_init_platform to say:
 | |
| +		 * "All good. Nothing to see here. Please go on."
 | |
| +		 */
 | |
| +		if (err == -ENOENT || err == -EOPNOTSUPP)
 | |
| +			return 0;
 | |
| +
 | |
| +		return err;
 | |
| +	}
 | |
| +
 | |
| +	buf = nvmem_cell_read(cell, &len);
 | |
| +	if (IS_ERR(buf))
 | |
| +		return PTR_ERR(buf);
 | |
| +
 | |
| +	/* run basic sanity checks on the returned nvram cell length.
 | |
| +	 * That length has to be a multiple of a "u16" (i.e.: & 1).
 | |
| +	 * Furthermore, it has to be more than "let's say" 512 bytes
 | |
| +	 * but less than the maximum of AR9300_EEPROM_SIZE (16kb).
 | |
| +	 */
 | |
| +	if (((len & 1) == 1) || (len < 512) || (len >= AR9300_EEPROM_SIZE)) {
 | |
| +		kfree(buf);
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
| +	/* devres manages the calibration values release on shutdown */
 | |
| +	ah->nvmem_blob = (u16 *)devm_kmemdup(sc->dev, buf, len, GFP_KERNEL);
 | |
| +	kfree(buf);
 | |
| +	if (!ah->nvmem_blob)
 | |
| +		return -ENOMEM;
 | |
| +
 | |
| +	ah->nvmem_blob_len = len;
 | |
| +	ah->ah_flags &= ~AH_USE_EEPROM;
 | |
| +	ah->ah_flags |= AH_NO_EEP_SWAP;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
|  static int ath9k_init_platform(struct ath_softc *sc)
 | |
|  {
 | |
|  	struct ath9k_platform_data *pdata = sc->dev->platform_data;
 | |
| @@ -710,6 +762,10 @@ static int ath9k_init_softc(u16 devid, s
 | |
|  	if (ret)
 | |
|  		return ret;
 | |
|  
 | |
| +	ret = ath9k_nvmem_request_eeprom(sc);
 | |
| +	if (ret)
 | |
| +		return ret;
 | |
| +
 | |
|  	if (ath9k_led_active_high != -1)
 | |
|  		ah->config.led_active_high = ath9k_led_active_high == 1;
 | |
|  
 |