From 8ae5ae76fb7ff6bf2e4d62f38adf72b05ea661e1 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Wed, 25 Jan 2023 14:53:00 +0100 Subject: [PATCH] wifi: support building for ARM64 This commit introduces support for building the WLAN driver for ARM platforms. It makes the WPA supplicant and its support libraries available for all platforms. It also seperates the PCI parts to accommodate platforms where other bus protocols are used. Issue #4813 --- repos/dde_linux/lib/mk/spec/arm_64/libnl.mk | 6 + .../mk/{spec/x86 => }/wpa_driver_nl80211.mk | 0 .../lib/mk/{spec/x86 => }/wpa_supplicant.mk | 0 .../shadow/{arch/x86 => }/include/linux/pci.h | 0 repos/dde_linux/src/lib/lx_emul/pci_bus.c | 24 +- .../src/lib/lx_emul/spec/arm/irqchip.c | 7 +- repos/pc/lib/mk/wifi.inc | 1 + repos/pc/recipes/src/pc_wifi_drv/content.mk | 2 +- repos/pc/src/lib/wifi/lx_emul.c | 199 +---------------- repos/pc/src/lib/wifi/lx_emul_pci.c | 205 ++++++++++++++++++ repos/pc/src/lib/wifi/lx_socket_call.c | 24 ++ 11 files changed, 268 insertions(+), 200 deletions(-) create mode 100644 repos/dde_linux/lib/mk/spec/arm_64/libnl.mk rename repos/dde_linux/lib/mk/{spec/x86 => }/wpa_driver_nl80211.mk (100%) rename repos/dde_linux/lib/mk/{spec/x86 => }/wpa_supplicant.mk (100%) rename repos/dde_linux/src/include/lx_emul/shadow/{arch/x86 => }/include/linux/pci.h (100%) create mode 100644 repos/pc/src/lib/wifi/lx_emul_pci.c diff --git a/repos/dde_linux/lib/mk/spec/arm_64/libnl.mk b/repos/dde_linux/lib/mk/spec/arm_64/libnl.mk new file mode 100644 index 0000000000..95fabb0ad7 --- /dev/null +++ b/repos/dde_linux/lib/mk/spec/arm_64/libnl.mk @@ -0,0 +1,6 @@ +include $(REP_DIR)/lib/mk/libnl.inc + +INC_DIR += $(LIB_INC_DIR)/spec/64bit + +CC_CXX_WARN_STRICT = + diff --git a/repos/dde_linux/lib/mk/spec/x86/wpa_driver_nl80211.mk b/repos/dde_linux/lib/mk/wpa_driver_nl80211.mk similarity index 100% rename from repos/dde_linux/lib/mk/spec/x86/wpa_driver_nl80211.mk rename to repos/dde_linux/lib/mk/wpa_driver_nl80211.mk diff --git a/repos/dde_linux/lib/mk/spec/x86/wpa_supplicant.mk b/repos/dde_linux/lib/mk/wpa_supplicant.mk similarity index 100% rename from repos/dde_linux/lib/mk/spec/x86/wpa_supplicant.mk rename to repos/dde_linux/lib/mk/wpa_supplicant.mk diff --git a/repos/dde_linux/src/include/lx_emul/shadow/arch/x86/include/linux/pci.h b/repos/dde_linux/src/include/lx_emul/shadow/include/linux/pci.h similarity index 100% rename from repos/dde_linux/src/include/lx_emul/shadow/arch/x86/include/linux/pci.h rename to repos/dde_linux/src/include/lx_emul/shadow/include/linux/pci.h diff --git a/repos/dde_linux/src/lib/lx_emul/pci_bus.c b/repos/dde_linux/src/lib/lx_emul/pci_bus.c index 7e5a517afe..35c23ab1e5 100644 --- a/repos/dde_linux/src/lib/lx_emul/pci_bus.c +++ b/repos/dde_linux/src/lib/lx_emul/pci_bus.c @@ -158,23 +158,27 @@ static void pci_add_single_device_callback(void * data, static int __init pci_subsys_init(void) { struct pci_bus *b; - struct pci_sysdata *sd; /* pci_alloc_bus(NULL) */ b = kzalloc(sizeof (struct pci_bus), GFP_KERNEL); if (!b) return -ENOMEM; - sd = kzalloc(sizeof (struct pci_sysdata), GFP_KERNEL); - if (!sd) { - kfree(b); - return -ENOMEM; +#ifdef CONFIG_X86 + { + struct pci_sysdata *sd; + sd = kzalloc(sizeof (struct pci_sysdata), GFP_KERNEL); + if (!sd) { + kfree(b); + return -ENOMEM; + } + + /* needed by intel_fb */ + sd->domain = 0; + + b->sysdata = sd; } - - /* needed by intel_fb */ - sd->domain = 0; - - b->sysdata = sd; +#endif /* CONFIG_X86 */ INIT_LIST_HEAD(&b->node); INIT_LIST_HEAD(&b->children); diff --git a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c b/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c index 679683c028..c33dc8f1c4 100644 --- a/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c +++ b/repos/dde_linux/src/lib/lx_emul/spec/arm/irqchip.c @@ -28,6 +28,7 @@ static int dde_irq_set_wake(struct irq_data *d, unsigned int on) static void dde_irq_unmask(struct irq_data *d) { + lx_emul_irq_eoi(d->hwirq); lx_emul_irq_unmask(d->hwirq); } @@ -52,7 +53,7 @@ static int dde_irq_set_type(struct irq_data *d, unsigned int type) } -static struct irq_chip dde_irqchip_data_chip = { +struct irq_chip dde_irqchip_data_chip = { .name = "dde-irqs", .irq_eoi = dde_irq_eoi, .irq_mask = dde_irq_mask, @@ -176,7 +177,9 @@ int lx_emul_irq_task_function(void * data) local_irq_save(flags); irq_enter(); - irq = irq_find_mapping(dde_irq_domain, lx_emul_irq_last()); + irq = dde_irq_domain ? irq_find_mapping(dde_irq_domain, + lx_emul_irq_last()) + : lx_emul_irq_last(); if (!irq) { ack_bad_irq(irq); diff --git a/repos/pc/lib/mk/wifi.inc b/repos/pc/lib/mk/wifi.inc index b49dc8ca9f..d0e71ba1a5 100644 --- a/repos/pc/lib/mk/wifi.inc +++ b/repos/pc/lib/mk/wifi.inc @@ -15,6 +15,7 @@ SRC_CC += lx_emul/random.cc SRC_C += dummies.c SRC_C += lx_emul.c +SRC_C += lx_emul_pci.c SRC_C += lx_user.c SRC_C += uplink.c diff --git a/repos/pc/recipes/src/pc_wifi_drv/content.mk b/repos/pc/recipes/src/pc_wifi_drv/content.mk index 276a534c9f..4223ca7d31 100644 --- a/repos/pc/recipes/src/pc_wifi_drv/content.mk +++ b/repos/pc/recipes/src/pc_wifi_drv/content.mk @@ -27,7 +27,7 @@ LIBNL_PORT_DIR := $(call port_dir,$(DDE_LINUX_REP_DIR)/ports/libnl) DDE_LINUX_LIB_MK := \ $(addprefix lib/mk/,libnl.inc libnl_include.mk) \ $(foreach SPEC,x86_32 x86_64,lib/mk/spec/$(SPEC)/libnl.mk) \ - $(addprefix lib/mk/spec/x86/,wpa_driver_nl80211.mk wpa_supplicant.mk) + $(addprefix lib/mk/,wpa_driver_nl80211.mk wpa_supplicant.mk) MIRROR_FROM_DDE_LINUX_DIR := $(DDE_LINUX_LIB_MK) \ lib/import/import-libnl_include.mk \ diff --git a/repos/pc/src/lib/wifi/lx_emul.c b/repos/pc/src/lib/wifi/lx_emul.c index 5b412044d1..7d2d31bcba 100644 --- a/repos/pc/src/lib/wifi/lx_emul.c +++ b/repos/pc/src/lib/wifi/lx_emul.c @@ -259,44 +259,8 @@ int firmware_request_nowarn(const struct firmware ** firmware,const char * name, } -#include - -int pcim_iomap_regions_request_all(struct pci_dev * pdev,int mask,const char * name) -{ - return 0; -} - - -#include - -static unsigned long *_pci_iomap_table; - -void __iomem * const * pcim_iomap_table(struct pci_dev * pdev) -{ - unsigned i; - - if (!_pci_iomap_table) - _pci_iomap_table = kzalloc(sizeof (unsigned long*) * 6, GFP_KERNEL); - - if (!_pci_iomap_table) - return NULL; - - for (i = 0; i < 6; i++) { - struct resource *r = &pdev->resource[i]; - unsigned long phys_addr = r->start; - unsigned long size = r->end - r->start; - - if (!phys_addr || !size) - continue; - - _pci_iomap_table[i] = - (unsigned long)lx_emul_io_mem_map(phys_addr, size); - } - - return (void const *)_pci_iomap_table; -} - - +// XXX add kernel/task_work.c as well +#ifdef CONFIG_X86 #include int task_work_add(struct task_struct * task,struct callback_head * work,enum task_work_notify_mode notify) @@ -304,6 +268,7 @@ int task_work_add(struct task_struct * task,struct callback_head * work,enum tas printk("%s: task: %p work: %p notify: %u\n", __func__, task, work, notify); return -1; } +#endif #include @@ -345,12 +310,14 @@ pid_t __task_pid_nr_ns(struct task_struct * task, #include +#ifndef INLINE_COPY_FROM_USER unsigned long _copy_from_user(void * to, const void __user * from, unsigned long n) { memcpy(to, from, n); return 0; } +#endif #include @@ -462,6 +429,7 @@ u32 prandom_u32(void) } +#include #include void *page_frag_alloc_align(struct page_frag_cache *nc, @@ -469,7 +437,11 @@ void *page_frag_alloc_align(struct page_frag_cache *nc, unsigned int align_mask) { unsigned int const order = fragsz / PAGE_SIZE; +#if LINUX_VERSION_CODE > KERNEL_VERSION(5,12,0) struct page *page = __alloc_pages(gfp_mask, order, 0, NULL); +#else + struct page *page = __alloc_pages(gfp_mask, order, 0); +#endif if (!page) return NULL; @@ -512,7 +484,7 @@ void misc_deregister(struct miscdevice *misc) /* rfkill support */ #include -#include +#include <../net/rfkill/rfkill.h> int __init rfkill_handler_init(void) { @@ -591,154 +563,7 @@ void kvfree_call_rcu(struct rcu_head * head,rcu_callback_t func) } -#include -#include - -int pci_write_config_byte(const struct pci_dev * dev,int where,u8 val) -{ - enum { PCI_CFG_RETRY_TIMEOUT = 0x41 }; - - switch (where) { - /* - * iwlwifi: "We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state" - */ - case PCI_CFG_RETRY_TIMEOUT: - return 0; - - /* - * rtlwifi: "leave D3 mode" - */ - case 0x44: - case PCI_COMMAND: - return 0; - /* - * rtlwifi: needed for enabling DMA 64bit support - */ - case 0x719: - return 0; - /* - * rtlwifi: below are registers related to ASPM and PCI link - * control that we do not handle (yet). - */ - case 0x81: - case 0x98: - return 0; - }; - - return -1; -} - - -int pci_write_config_dword(const struct pci_dev * dev,int where,u32 val) -{ - switch (where) { - /* - * ath9k: "Disable the bETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state." - */ - case 0x40: - return 0; - } - - return -1; -} - - -int pci_read_config_dword(const struct pci_dev * dev,int where,u32 * val) -{ - switch (where) { - /* - * ath9k: "Disable the bETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state." - */ - case 0x40: - return 0; - } - - return -1; -} - - -int pci_read_config_word(const struct pci_dev * dev,int where,u16 * val) -{ - switch (where) { - case PCI_COMMAND: - *val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - return 0; - /* - * rtlwifi: read but ignored - */ - case PCI_INTERRUPT_LINE: - *val = 0; - return 0; - }; - - return -1; -} - - -int pci_read_config_byte(const struct pci_dev * dev,int where,u8 * val) -{ - switch (where) { - /* - * rtlwifi: apparently needed for device distinction - */ - case PCI_REVISION_ID: - *val = dev->revision; - return 0; - /* - * rtlwifi: needed for enabling DMA 64bit support - */ - case 0x719: - *val = 0; - return 0; - /* - * rtlwifi: below are registers related to ASPM and PCI link - * control that we do not handle (yet). - */ - case 0x80: - case 0x81: - case 0x98: - *val = 0; - return 0; - } - - return -1; -} - - -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) -{ - struct resource *r; - unsigned long phys_addr; - unsigned long size; - - if (!dev || bar > 5) { - printk("%s:%d: invalid request for dev: %p bar: %d\n", - __func__, __LINE__, dev, bar); - return NULL; - } - - printk("pci_iomap: request for dev: %s bar: %d\n", dev_name(&dev->dev), bar); - - r = &dev->resource[bar]; - - phys_addr = r->start; - size = r->end - r->start; - - if (!phys_addr || !size) - return NULL; - - return lx_emul_io_mem_map(phys_addr, size); -} - - -void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) -{ - return pci_iomap(pdev, bar, maxlen); -} - +#include void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) diff --git a/repos/pc/src/lib/wifi/lx_emul_pci.c b/repos/pc/src/lib/wifi/lx_emul_pci.c new file mode 100644 index 0000000000..722aadb4ac --- /dev/null +++ b/repos/pc/src/lib/wifi/lx_emul_pci.c @@ -0,0 +1,205 @@ +/* + * \brief Linux emulation environment specific to this driver (PCI) + * \author Josef Soentgen + * \date 2023-02-14 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +#include +#include + +#include +#include +#include + +#include + +int pcim_iomap_regions_request_all(struct pci_dev * pdev,int mask,const char * name) +{ + return 0; +} + + +#include + +static unsigned long *_pci_iomap_table; + +void __iomem * const * pcim_iomap_table(struct pci_dev * pdev) +{ + unsigned i; + + if (!_pci_iomap_table) + _pci_iomap_table = kzalloc(sizeof (unsigned long*) * 6, GFP_KERNEL); + + if (!_pci_iomap_table) + return NULL; + + for (i = 0; i < 6; i++) { + struct resource *r = &pdev->resource[i]; + unsigned long phys_addr = r->start; + unsigned long size = r->end - r->start; + + if (!phys_addr || !size) + continue; + + _pci_iomap_table[i] = + (unsigned long)lx_emul_io_mem_map(phys_addr, size); + } + + return (void const *)_pci_iomap_table; +} + + +#include +#include + +int pci_write_config_byte(const struct pci_dev * dev,int where,u8 val) +{ + enum { PCI_CFG_RETRY_TIMEOUT = 0x41 }; + + switch (where) { + /* + * iwlwifi: "We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state" + */ + case PCI_CFG_RETRY_TIMEOUT: + return 0; + + /* + * rtlwifi: "leave D3 mode" + */ + case 0x44: + case PCI_COMMAND: + return 0; + /* + * rtlwifi: needed for enabling DMA 64bit support + */ + case 0x719: + return 0; + /* + * rtlwifi: below are registers related to ASPM and PCI link + * control that we do not handle (yet). + */ + case 0x81: + case 0x98: + return 0; + }; + + return -1; +} + + +int pci_write_config_dword(const struct pci_dev * dev,int where,u32 val) +{ + switch (where) { + /* + * ath9k: "Disable the bETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state." + */ + case 0x40: + return 0; + } + + return -1; +} + + +int pci_read_config_dword(const struct pci_dev * dev,int where,u32 * val) +{ + switch (where) { + /* + * ath9k: "Disable the bETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state." + */ + case 0x40: + return 0; + } + + return -1; +} + + +int pci_read_config_word(const struct pci_dev * dev,int where,u16 * val) +{ + switch (where) { + case PCI_COMMAND: + *val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; + return 0; + /* + * rtlwifi: read but ignored + */ + case PCI_INTERRUPT_LINE: + *val = 0; + return 0; + }; + + return -1; +} + + +int pci_read_config_byte(const struct pci_dev * dev,int where,u8 * val) +{ + switch (where) { + /* + * rtlwifi: apparently needed for device distinction + */ + case PCI_REVISION_ID: + *val = dev->revision; + return 0; + /* + * rtlwifi: needed for enabling DMA 64bit support + */ + case 0x719: + *val = 0; + return 0; + /* + * rtlwifi: below are registers related to ASPM and PCI link + * control that we do not handle (yet). + */ + case 0x80: + case 0x81: + case 0x98: + *val = 0; + return 0; + } + + return -1; +} + + +void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + struct resource *r; + unsigned long phys_addr; + unsigned long size; + + if (!dev || bar > 5) { + printk("%s:%d: invalid request for dev: %p bar: %d\n", + __func__, __LINE__, dev, bar); + return NULL; + } + + printk("pci_iomap: request for dev: %s bar: %d\n", dev_name(&dev->dev), bar); + + r = &dev->resource[bar]; + + phys_addr = r->start; + size = r->end - r->start; + + if (!phys_addr || !size) + return NULL; + + return lx_emul_io_mem_map(phys_addr, size); +} + + +void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) +{ + return pci_iomap(pdev, bar, maxlen); +} diff --git a/repos/pc/src/lib/wifi/lx_socket_call.c b/repos/pc/src/lib/wifi/lx_socket_call.c index 9ad6ca6830..504ae29ca8 100644 --- a/repos/pc/src/lib/wifi/lx_socket_call.c +++ b/repos/pc/src/lib/wifi/lx_socket_call.c @@ -177,6 +177,30 @@ int lx_sock_setsockopt(struct socket *sock, int level, int optname, } +#include + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,12,0) +int dev_get_mac_address(struct sockaddr *sa, struct net *net, char *dev_name) +{ + size_t size = sizeof(sa->sa_data); + struct net_device *dev = dev_get_by_name_rcu(net, dev_name); + + if (!dev) + return -ENODEV; + + if (!dev->addr_len) + memset(sa->sa_data, 0, size); + else + memcpy(sa->sa_data, dev->dev_addr, + min_t(size_t, size, dev->addr_len)); + sa->sa_family = dev->type; + + return 0; +} +EXPORT_SYMBOL(dev_get_mac_address); +#endif + + unsigned char const* lx_get_mac_addr() { static char mac_addr_buffer[16];