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
This commit is contained in:
Stefan Kalkowski 2023-01-25 14:53:00 +01:00 committed by Christian Helmuth
parent 56d366995c
commit 8ae5ae76fb
11 changed files with 268 additions and 200 deletions

View File

@ -0,0 +1,6 @@
include $(REP_DIR)/lib/mk/libnl.inc
INC_DIR += $(LIB_INC_DIR)/spec/64bit
CC_CXX_WARN_STRICT =

View File

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

View File

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

View File

@ -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

View File

@ -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 \

View File

@ -259,44 +259,8 @@ int firmware_request_nowarn(const struct firmware ** firmware,const char * name,
}
#include <linux/pci.h>
int pcim_iomap_regions_request_all(struct pci_dev * pdev,int mask,const char * name)
{
return 0;
}
#include <linux/pci.h>
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 <linux/task_work.h>
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 <linux/slab.h>
@ -345,12 +310,14 @@ pid_t __task_pid_nr_ns(struct task_struct * task,
#include <linux/uaccess.h>
#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 <linux/uio.h>
@ -462,6 +429,7 @@ u32 prandom_u32(void)
}
#include <linux/version.h>
#include <linux/gfp.h>
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 <linux/rfkill.h>
#include <net/rfkill/rfkill.h>
#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 <linux/pci.h>
#include <uapi/linux/pci_regs.h>
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 <linux/dma-mapping.h>
void *dmam_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t gfp, unsigned long attrs)

View File

@ -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 <lx_emul.h>
#include <linux/slab.h>
#include <lx_emul/random.h>
#include <lx_emul/alloc.h>
#include <lx_emul/io_mem.h>
#include <linux/pci.h>
int pcim_iomap_regions_request_all(struct pci_dev * pdev,int mask,const char * name)
{
return 0;
}
#include <linux/pci.h>
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 <linux/pci.h>
#include <uapi/linux/pci_regs.h>
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);
}

View File

@ -177,6 +177,30 @@ int lx_sock_setsockopt(struct socket *sock, int level, int optname,
}
#include <linux/version.h>
#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];