 d91318662d
			
		
	
	d91318662d
	
	
	
		
			
			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>
		
			
				
	
	
		
			182 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 9bf31835f11aa3c4fe5a9c1f7462c199c5d8e7ca Mon Sep 17 00:00:00 2001
 | |
| From: Christian Lamparter <chunkeey@gmail.com>
 | |
| Date: Sat, 21 Aug 2021 00:22:39 +0200
 | |
| Subject: [PATCH] ath9k: owl-loader: fetch pci init values through nvmem
 | |
| 
 | |
| extends the owl loader to fetch important pci initialization
 | |
| values - which are stored together with the calibration data -
 | |
| through the nvmem subsystem.
 | |
| 
 | |
| This allows for much faster WIFI/ath9k initializations on devices
 | |
| that do not require to perform any post-processing (like XOR'ing/
 | |
| reversal or unpacking) since no userspace helper is required.
 | |
| 
 | |
| Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 | |
| ---
 | |
|  .../wireless/ath/ath9k/ath9k_pci_owl_loader.c | 105 +++++++++++++-----
 | |
|  1 file changed, 76 insertions(+), 29 deletions(-)
 | |
| 
 | |
| --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
 | |
| +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
 | |
| @@ -19,9 +19,14 @@
 | |
|  #include <linux/delay.h>
 | |
|  #include <linux/platform_device.h>
 | |
|  #include <linux/ath9k_platform.h>
 | |
| +#include <linux/nvmem-consumer.h>
 | |
| +#include <linux/workqueue.h>
 | |
|  
 | |
|  struct owl_ctx {
 | |
| +	struct pci_dev *pdev;
 | |
|  	struct completion eeprom_load;
 | |
| +	struct work_struct work;
 | |
| +	struct nvmem_cell *cell;
 | |
|  };
 | |
|  
 | |
|  #define EEPROM_FILENAME_LEN 100
 | |
| @@ -42,6 +47,12 @@ static int ath9k_pci_fixup(struct pci_de
 | |
|  	u32 bar0;
 | |
|  	bool swap_needed = false;
 | |
|  
 | |
| +	/* also note that we are doing *u16 operations on the file */
 | |
| +	if (cal_len > 4096 || cal_len < 0x200 || (cal_len & 1) == 1) {
 | |
| +		dev_err(&pdev->dev, "eeprom has an invalid size.\n");
 | |
| +		return -EINVAL;
 | |
| +	}
 | |
| +
 | |
|  	if (*cal_data != AR5416_EEPROM_MAGIC) {
 | |
|  		if (*cal_data != swab16(AR5416_EEPROM_MAGIC)) {
 | |
|  			dev_err(&pdev->dev, "invalid calibration data\n");
 | |
| @@ -99,38 +110,31 @@ static int ath9k_pci_fixup(struct pci_de
 | |
|  	return 0;
 | |
|  }
 | |
|  
 | |
| -static void owl_fw_cb(const struct firmware *fw, void *context)
 | |
| +static void owl_rescan(struct pci_dev *pdev)
 | |
|  {
 | |
| -	struct pci_dev *pdev = (struct pci_dev *)context;
 | |
| -	struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev);
 | |
| -	struct pci_bus *bus;
 | |
| -
 | |
| -	complete(&ctx->eeprom_load);
 | |
| -
 | |
| -	if (!fw) {
 | |
| -		dev_err(&pdev->dev, "no eeprom data received.\n");
 | |
| -		goto release;
 | |
| -	}
 | |
| -
 | |
| -	/* also note that we are doing *u16 operations on the file */
 | |
| -	if (fw->size > 4096 || fw->size < 0x200 || (fw->size & 1) == 1) {
 | |
| -		dev_err(&pdev->dev, "eeprom file has an invalid size.\n");
 | |
| -		goto release;
 | |
| -	}
 | |
| -
 | |
| -	if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size))
 | |
| -		goto release;
 | |
| +	struct pci_bus *bus = pdev->bus;
 | |
|  
 | |
|  	pci_lock_rescan_remove();
 | |
| -	bus = pdev->bus;
 | |
|  	pci_stop_and_remove_bus_device(pdev);
 | |
|  	/* the device should come back with the proper
 | |
|  	 * ProductId. But we have to initiate a rescan.
 | |
|  	 */
 | |
|  	pci_rescan_bus(bus);
 | |
|  	pci_unlock_rescan_remove();
 | |
| +}
 | |
| +
 | |
| +static void owl_fw_cb(const struct firmware *fw, void *context)
 | |
| +{
 | |
| +	struct owl_ctx *ctx = (struct owl_ctx *)context;
 | |
| +
 | |
| +	complete(&ctx->eeprom_load);
 | |
|  
 | |
| -release:
 | |
| +	if (fw) {
 | |
| +		ath9k_pci_fixup(ctx->pdev, (const u16 *)fw->data, fw->size);
 | |
| +		owl_rescan(ctx->pdev);
 | |
| +	} else {
 | |
| +		dev_err(&ctx->pdev->dev, "no eeprom data received.\n");
 | |
| +	}
 | |
|  	release_firmware(fw);
 | |
|  }
 | |
|  
 | |
| @@ -152,6 +156,43 @@ static const char *owl_get_eeprom_name(s
 | |
|  	return eeprom_name;
 | |
|  }
 | |
|  
 | |
| +static void owl_nvmem_work(struct work_struct *work)
 | |
| +{
 | |
| +	struct owl_ctx *ctx = container_of(work, struct owl_ctx, work);
 | |
| +	void *buf;
 | |
| +	size_t len;
 | |
| +
 | |
| +	complete(&ctx->eeprom_load);
 | |
| +
 | |
| +	buf = nvmem_cell_read(ctx->cell, &len);
 | |
| +	if (!IS_ERR(buf)) {
 | |
| +		ath9k_pci_fixup(ctx->pdev, buf, len);
 | |
| +		kfree(buf);
 | |
| +		owl_rescan(ctx->pdev);
 | |
| +	} else {
 | |
| +		dev_err(&ctx->pdev->dev, "no nvmem data received.\n");
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static int owl_nvmem_probe(struct owl_ctx *ctx)
 | |
| +{
 | |
| +	int err;
 | |
| +
 | |
| +	ctx->cell = devm_nvmem_cell_get(&ctx->pdev->dev, "calibration");
 | |
| +	if (IS_ERR(ctx->cell)) {
 | |
| +		err = PTR_ERR(ctx->cell);
 | |
| +		if (err == -ENOENT || err == -EOPNOTSUPP)
 | |
| +			return 1; /* not present, try firmware_request */
 | |
| +
 | |
| +		return err;
 | |
| +	}
 | |
| +
 | |
| +	INIT_WORK(&ctx->work, owl_nvmem_work);
 | |
| +	schedule_work(&ctx->work);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
|  static int owl_probe(struct pci_dev *pdev,
 | |
|  		     const struct pci_device_id *id)
 | |
|  {
 | |
| @@ -164,21 +205,27 @@ static int owl_probe(struct pci_dev *pde
 | |
|  
 | |
|  	pcim_pin_device(pdev);
 | |
|  
 | |
| -	eeprom_name = owl_get_eeprom_name(pdev);
 | |
| -	if (!eeprom_name) {
 | |
| -		dev_err(&pdev->dev, "no eeprom filename found.\n");
 | |
| -		return -ENODEV;
 | |
| -	}
 | |
| -
 | |
|  	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 | |
|  	if (!ctx)
 | |
|  		return -ENOMEM;
 | |
|  
 | |
|  	init_completion(&ctx->eeprom_load);
 | |
| +	ctx->pdev = pdev;
 | |
|  
 | |
|  	pci_set_drvdata(pdev, ctx);
 | |
| +
 | |
| +	err = owl_nvmem_probe(ctx);
 | |
| +	if (err <= 0)
 | |
| +		return err;
 | |
| +
 | |
| +	eeprom_name = owl_get_eeprom_name(pdev);
 | |
| +	if (!eeprom_name) {
 | |
| +		dev_err(&pdev->dev, "no eeprom filename found.\n");
 | |
| +		return -ENODEV;
 | |
| +	}
 | |
| +
 | |
|  	err = request_firmware_nowait(THIS_MODULE, true, eeprom_name,
 | |
| -				      &pdev->dev, GFP_KERNEL, pdev, owl_fw_cb);
 | |
| +				      &pdev->dev, GFP_KERNEL, ctx, owl_fw_cb);
 | |
|  	if (err)
 | |
|  		dev_err(&pdev->dev, "failed to request caldata (%d).\n", err);
 | |
|  
 |