Hi, why is this code located under package/ and not as a kernel patch under target/linux/generic ?
John On 05/09/2016 06:59, Chris Blake wrote: > From: Christian Lamparter <chunk...@googlemail.com> > > Some devices (like the Cisco Meraki Z1 Cloud Managed Teleworker Gateway) > need to be able to initialize the PCIe wifi device. Normally, this is done > during the early stages of booting linux, because the necessary init code > is read from the memory mapped SPI and passed to pci_enable_ath9k_fixup. > However,this isn't possible for devices which have the init code for the > Atheros chip stored on NAND in an UBI volume. Hence, this module can be > used to initialze the chip when the user-space is ready to extract the > init code. > > Martin Blumenstingl made a few fixes and added support for lantiq: > kernel: owl-loader: add support for OWL emulation PCI devices > kernel: owl-loader: don't re-scan the bus when ath9k_pci_fixup failed > kernel: owl-loader: use dev_* instead of pr_* logging functions > kernel: owl-loader: auto-generate the eeprom filename as fallback > kernel: owl-loader: add a debug message when swapping the eeprom data > kernel: owl-loader: add missing newlines in log messages > kernel: owl-loader: add support for the lantiq platform > > These patches have been integrated. Thanks! > > Signed-off-by: Martin Blumenstingl <martin.blumensti...@googlemail.com> > Signed-off-by: Christian Lamparter <chunk...@googlemail.com> > --- > package/kernel/owl-loader/Makefile | 59 +++++++ > package/kernel/owl-loader/src/Makefile | 1 + > package/kernel/owl-loader/src/owl-loader.c | 246 > +++++++++++++++++++++++++++++ > 3 files changed, 306 insertions(+) > create mode 100644 package/kernel/owl-loader/Makefile > create mode 100644 package/kernel/owl-loader/src/Makefile > create mode 100644 package/kernel/owl-loader/src/owl-loader.c > > diff --git a/package/kernel/owl-loader/Makefile > b/package/kernel/owl-loader/Makefile > new file mode 100644 > index 0000000..b6c58de > --- /dev/null > +++ b/package/kernel/owl-loader/Makefile > @@ -0,0 +1,59 @@ > +# > +# Copyright (C) 2016 OpenWrt.org > +# > +# This is free software, licensed under the GNU General Public License v2. > +# See /LICENSE for more information. > +# > + > +include $(TOPDIR)/rules.mk > +include $(INCLUDE_DIR)/kernel.mk > + > +PKG_NAME:=owl-loader > +PKG_RELEASE:=1 > + > +include $(INCLUDE_DIR)/package.mk > + > +define KernelPackage/owl-loader > + SUBMENU:=Network Support > + TITLE:=Owl loader for initializing Atheros PCI(e) Wifi chips > + DEPENDS:=@PCI_SUPPORT +kmod-ath9k > + FILES:=$(PKG_BUILD_DIR)/owl-loader.ko > + AUTOLOAD:=$(call AutoProbe,owl-loader) > + KCONFIG:= > +endef > + > +define KernelPackage/owl-loader/description > + Kernel module that helps to initialize certain Qualcomm > + Atheros' PCI(e) Wifi chips, which have the init data > + (which contains the PCI device ID for example) stored > + together with the calibration data in the file system. > + > + This is necessary for devices like the Cisco Meraki Z1. > +endef > + > +EXTRA_KCONFIG:= \ > + CONFIG_OWL_LOADER=m > + > +EXTRA_CFLAGS:= \ > + $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=m,%,$(filter > %=m,$(EXTRA_KCONFIG)))) \ > + $(patsubst CONFIG_%, -DCONFIG_%=1, $(patsubst %=y,%,$(filter > %=y,$(EXTRA_KCONFIG)))) \ > + > +MAKE_OPTS:= \ > + ARCH="$(LINUX_KARCH)" \ > + CROSS_COMPILE="$(TARGET_CROSS)" \ > + SUBDIRS="$(PKG_BUILD_DIR)" \ > + EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \ > + $(EXTRA_KCONFIG) > + > +define Build/Prepare > + mkdir -p $(PKG_BUILD_DIR) > + $(CP) ./src/* $(PKG_BUILD_DIR)/ > +endef > + > +define Build/Compile > + $(MAKE) -C "$(LINUX_DIR)" \ > + $(MAKE_OPTS) \ > + modules > +endef > + > +$(eval $(call KernelPackage,owl-loader)) > diff --git a/package/kernel/owl-loader/src/Makefile > b/package/kernel/owl-loader/src/Makefile > new file mode 100644 > index 0000000..6b58276 > --- /dev/null > +++ b/package/kernel/owl-loader/src/Makefile > @@ -0,0 +1 @@ > +obj-${CONFIG_OWL_LOADER} += owl-loader.o > diff --git a/package/kernel/owl-loader/src/owl-loader.c > b/package/kernel/owl-loader/src/owl-loader.c > new file mode 100644 > index 0000000..30340da > --- /dev/null > +++ b/package/kernel/owl-loader/src/owl-loader.c > @@ -0,0 +1,246 @@ > +/* > + * Initialize Owl Emulation Devices > + * > + * Copyright (C) 2016 Christian Lamparter <chunk...@googlemail.com> > + * Copyright (C) 2016 Martin Blumenstingl > <martin.blumensti...@googlemail.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > + * by the Free Software Foundation. > + * > + * Some devices (like the Cisco Meraki Z1 Cloud Managed Teleworker Gateway) > + * need to be able to initialize the PCIe wifi device. Normally, this is done > + * during the early stages of booting linux, because the necessary init code > + * is read from the memory mapped SPI and passed to pci_enable_ath9k_fixup. > + * However,this isn't possible for devices which have the init code for the > + * Atheros chip stored on NAND. Hence, this module can be used to initialze > + * the chip when the user-space is ready to extract the init code. > + */ > +#include <linux/module.h> > +#include <linux/version.h> > +#include <linux/completion.h> > +#include <linux/etherdevice.h> > +#include <linux/firmware.h> > +#include <linux/pci.h> > +#include <linux/delay.h> > +#include <linux/platform_device.h> > +#include <linux/ath9k_platform.h> > + > +struct owl_ctx { > + struct completion eeprom_load; > +}; > + > +#define EEPROM_FILENAME_LEN 100 > + > +#define AR5416_EEPROM_MAGIC 0xa55a > + > +static int ath9k_pci_fixup(struct pci_dev *pdev, const u16 *cal_data, > + size_t cal_len) > +{ > + void __iomem *mem; > + const void *cal_end = (void *)cal_data + cal_len; > + const struct { > + __be16 reg; > + __be16 low_val; > + __be16 high_val; > + } __packed *data; > + u16 cmd; > + u32 bar0; > + bool swap_needed = false; > + > + if (*cal_data != AR5416_EEPROM_MAGIC) { > + if (*cal_data != swab16(AR5416_EEPROM_MAGIC)) { > + dev_err(&pdev->dev, "invalid calibration data\n"); > + return -EINVAL; > + } > + > + dev_dbg(&pdev->dev, "calibration data needs swapping\n"); > + swap_needed = true; > + } > + > + dev_info(&pdev->dev, "fixup device configuration\n"); > + > + mem = pcim_iomap(pdev, 0, 0); > + if (!mem) { > + dev_err(&pdev->dev, "ioremap error\n"); > + return -EINVAL; > + } > + > + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0); > + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, > + pci_resource_start(pdev, 0)); > + pci_read_config_word(pdev, PCI_COMMAND, &cmd); > + cmd |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; > + pci_write_config_word(pdev, PCI_COMMAND, cmd); > + > + /* set pointer to first reg address */ > + for (data = (const void *) (cal_data + 3); > + (const void *) data <= cal_end && data->reg != cpu_to_be16(~0); > + data++) { > + u32 val; > + u16 reg; > + > + reg = data->reg; > + val = data->low_val; > + val |= data->high_val << 16; > + > + if (swap_needed) { > + reg = swab16(reg); > + val = swahb32(val); > + } > + > +#if CONFIG_LANTIQ > + val = swab32(val); > +#endif > + > + __raw_writel(val, mem + reg); > + udelay(100); > + } > + > + pci_read_config_word(pdev, PCI_COMMAND, &cmd); > + cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); > + pci_write_config_word(pdev, PCI_COMMAND, cmd); > + > + pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, bar0); > + pcim_iounmap(pdev, mem); > + > + pci_disable_device(pdev); > + > + return 0; > +} > + > +static void owl_fw_cb(const struct firmware *fw, void *context) > +{ > + struct pci_dev *pdev = (struct pci_dev *) context; > + struct owl_ctx *ctx = (struct owl_ctx *) pci_get_drvdata(pdev); > + struct ath9k_platform_data *pdata = dev_get_platdata(&pdev->dev); > + 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 > sizeof(pdata->eeprom_data) || fw->size < 0x200 || > + (fw->size & 1) == 1) { > + dev_err(&pdev->dev, "eeprom file has an invalid size.\n"); > + goto release; > + } > + > + if (pdata) { > + memcpy(pdata->eeprom_data, fw->data, fw->size); > + > + /* > + * eeprom has been successfully loaded - pass the data to ath9k > + * but remove the eeprom_name, so it doesn't try to load it too. > + */ > + pdata->eeprom_name = NULL; > + } > + > + if (ath9k_pci_fixup(pdev, (const u16 *) fw->data, fw->size)) > + goto release; > + > + 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(); > + > +release: > + release_firmware(fw); > +} > + > +static const char *owl_get_eeprom_name(struct pci_dev *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct ath9k_platform_data *pdata; > + char *eeprom_name; > + > + /* try the existing platform data first */ > + pdata = dev_get_platdata(dev); > + if (pdata && pdata->eeprom_name) > + return pdata->eeprom_name; > + > + dev_dbg(dev, "using auto-generated eeprom filename\n"); > + > + eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL); > + if (!eeprom_name) > + return NULL; > + > + /* this should match the pattern used in ath9k/init.c */ > + scnprintf(eeprom_name, EEPROM_FILENAME_LEN, "ath9k-eeprom-pci-%s.bin", > + dev_name(dev)); > + > + return eeprom_name; > +} > + > +static int owl_probe(struct pci_dev *pdev, > + const struct pci_device_id *id) > +{ > + struct owl_ctx *ctx; > + const char *eeprom_name; > + int err = 0; > + > + if (pcim_enable_device(pdev)) > + return -EIO; > + > + 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 = kzalloc(sizeof(*ctx), GFP_KERNEL); > + if (!ctx) { > + dev_err(&pdev->dev, "failed to alloc device context.\n"); > + return -ENOMEM; > + } > + init_completion(&ctx->eeprom_load); > + > + pci_set_drvdata(pdev, ctx); > + err = request_firmware_nowait(THIS_MODULE, true, eeprom_name, > + &pdev->dev, GFP_KERNEL, pdev, owl_fw_cb); > + if (err) { > + dev_err(&pdev->dev, "failed to request caldata (%d).\n", err); > + kfree(ctx); > + } > + return err; > +} > + > +static void owl_remove(struct pci_dev *pdev) > +{ > + struct owl_ctx *ctx = pci_get_drvdata(pdev); > + > + if (ctx) { > + wait_for_completion(&ctx->eeprom_load); > + pci_set_drvdata(pdev, NULL); > + kfree(ctx); > + } > +} > + > +static const struct pci_device_id owl_pci_table[] = { > + { PCI_VDEVICE(ATHEROS, 0xff1c) }, /* PCIe */ > + { PCI_VDEVICE(ATHEROS, 0xff1d) }, /* PCI */ > + { }, > +}; > +MODULE_DEVICE_TABLE(pci, owl_pci_table); > + > +static struct pci_driver owl_driver = { > + .name = "owl-loader", > + .id_table = owl_pci_table, > + .probe = owl_probe, > + .remove = owl_remove, > +}; > +module_pci_driver(owl_driver); > +MODULE_AUTHOR("Christian Lamparter <chunk...@googlemail.com>"); > +MODULE_DESCRIPTION("Initializes Atheros' Owl Emulation devices"); > +MODULE_LICENSE("GPL v2"); > _______________________________________________ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev