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);
 | 
						|
 
 |