diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/config/Config.in.binutils | 3 | ||||
-rw-r--r-- | target/config/Config.in.compiler | 3 | ||||
-rw-r--r-- | target/config/Config.in.cpu | 4 | ||||
-rw-r--r-- | target/config/Config.in.gdb | 5 | ||||
-rw-r--r-- | target/config/Config.in.kernelcfg | 1 | ||||
-rw-r--r-- | target/config/Config.in.kernelversion | 11 | ||||
-rw-r--r-- | target/config/Config.in.runtime | 1 | ||||
-rw-r--r-- | target/config/Config.in.target | 1 | ||||
-rw-r--r-- | target/linux/config/Config.in.ethernet | 10 | ||||
-rw-r--r-- | target/linux/config/Config.in.kernel | 4 | ||||
-rw-r--r-- | target/linux/config/Config.in.serial | 6 | ||||
-rw-r--r-- | target/linux/patches/3.4.112/nds32.patch | 72132 | ||||
-rw-r--r-- | target/nds32/Makefile | 3 | ||||
-rw-r--r-- | target/nds32/kernel/andes-ag101p | 5 | ||||
-rw-r--r-- | target/nds32/kernel/generic-nds32 | 2 | ||||
-rw-r--r-- | target/nds32/systems/andes-ag101p | 9 | ||||
-rw-r--r-- | target/nds32/uclibc-ng.config | 248 |
17 files changed, 72446 insertions, 2 deletions
diff --git a/target/config/Config.in.binutils b/target/config/Config.in.binutils index 3d31a774b..494aa4469 100644 --- a/target/config/Config.in.binutils +++ b/target/config/Config.in.binutils @@ -17,11 +17,13 @@ config ADK_TOOLCHAIN_BINUTILS_GIT depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_CRIS + depends on !ADK_TARGET_ARCH_NDS32 config ADK_TOOLCHAIN_BINUTILS_2_26_1 bool "2.26.1" depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_AVR32 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_CPU_CRIS_CRISV10 config ADK_TOOLCHAIN_BINUTILS_2_25_1 @@ -31,6 +33,7 @@ config ADK_TOOLCHAIN_BINUTILS_2_25_1 depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_H8300 depends on !ADK_TARGET_ARCH_MOXIE + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_CPU_CRIS_CRISV10 config ADK_TOOLCHAIN_BINUTILS_2_24 diff --git a/target/config/Config.in.compiler b/target/config/Config.in.compiler index ba41d89fb..c9d950c1d 100644 --- a/target/config/Config.in.compiler +++ b/target/config/Config.in.compiler @@ -33,6 +33,7 @@ config ADK_TOOLCHAIN_GCC_GIT depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_METAG + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_OR1K select ADK_DISABLE_HONOUR_CFLAGS @@ -41,6 +42,7 @@ config ADK_TOOLCHAIN_GCC_6_1_0 depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_METAG + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_OR1K select ADK_DISABLE_HONOUR_CFLAGS @@ -54,6 +56,7 @@ config ADK_TOOLCHAIN_GCC_5_4_0 depends on !ADK_TARGET_ARCH_H8300 depends on !ADK_TARGET_ARCH_M32R depends on !ADK_TARGET_ARCH_METAG + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_OR1K depends on !ADK_TARGET_SYSTEM_KINETIS_K70 depends on !(ADK_TARGET_LIB_GLIBC && ADK_TARGET_ARCH_SH) diff --git a/target/config/Config.in.cpu b/target/config/Config.in.cpu index 2b463ed33..d318a6440 100644 --- a/target/config/Config.in.cpu +++ b/target/config/Config.in.cpu @@ -720,7 +720,7 @@ config ADK_TARGET_CPU_MSP430 # nds32 config ADK_TARGET_CPU_NDS32 bool "nds32" - select ADK_TARGET_WITH_NPTL + select ADK_TARGET_WITH_LT select ADK_TARGET_WITH_MMU depends on ADK_TARGET_ARCH_NDS32 @@ -1437,6 +1437,7 @@ config ADK_TARGET_GCC_CPU default "cortex-m4" if ADK_TARGET_CPU_ARM_CORTEX_M4 default "leon" if ADK_TARGET_CPU_SPARC_LEON default "mpcore" if ADK_TARGET_CPU_ARM_ARM11MPCORE + default "n13" if ADK_TARGET_CPU_NDS32 default "powerpc" if ADK_TARGET_CPU_PPC default "powerpc64" if ADK_TARGET_CPU_PPC64_POWERPC64 default "power6" if ADK_TARGET_CPU_PPC64_POWER6 @@ -1623,6 +1624,7 @@ config ADK_TARGET_CPU_TYPE default "mips64r6" if ADK_TARGET_CPU_MIPS64_MIPS64R6 default "mips64" if ADK_TARGET_CPU_MIPS64_LOONGSON2F default "ppc64" if ADK_TARGET_ARCH_PPC64 + default "nds32" if ADK_TARGET_CPU_NDS32 default "v8" if ADK_TARGET_CPU_SPARC_V8 default "v9" if ADK_TARGET_CPU_SPARC64_V9 default "leon" if ADK_TARGET_CPU_SPARC_LEON diff --git a/target/config/Config.in.gdb b/target/config/Config.in.gdb index a9d279044..bbde9df6c 100644 --- a/target/config/Config.in.gdb +++ b/target/config/Config.in.gdb @@ -4,12 +4,14 @@ choice prompt "GNU debugger version" default ADK_TOOLCHAIN_GDB_H8300_GIT if ADK_TARGET_ARCH_H8300 +default ADK_TOOLCHAIN_GDB_NDS32 if ADK_TARGET_ARCH_NDS32 default ADK_TOOLCHAIN_GDB_7_11_1 config ADK_TOOLCHAIN_GDB_GIT bool "git" depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 config ADK_TOOLCHAIN_GDB_H8300_GIT bool "h8300-git" @@ -19,16 +21,19 @@ config ADK_TOOLCHAIN_GDB_7_11_1 bool "7.11.1" depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 config ADK_TOOLCHAIN_GDB_7_10_1 bool "7.10.1" depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 config ADK_TOOLCHAIN_GDB_7_9_1 bool "7.9.1" depends on !ADK_TARGET_ARCH_AVR32 depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 config ADK_TOOLCHAIN_GDB_7_8_2 bool "7.8.2" diff --git a/target/config/Config.in.kernelcfg b/target/config/Config.in.kernelcfg index c1e562f7b..27a6bbf1e 100644 --- a/target/config/Config.in.kernelcfg +++ b/target/config/Config.in.kernelcfg @@ -23,4 +23,5 @@ config ADK_TARGET_KERNEL_DEFCONFIG default "nsim_700_defconfig" if ADK_TARGET_SYSTEM_NSIM_ARCV1 default "nsim_hs_defconfig" if ADK_TARGET_SYSTEM_NSIM_ARCV2 default "10m50_defconfig" if ADK_TARGET_SYSTEM_QEMU_NIOS2 + default "orca_defconfig" if ADK_TARGET_SYSTEM_ANDES_AG101P diff --git a/target/config/Config.in.kernelversion b/target/config/Config.in.kernelversion index 4411d78aa..b6b35d52f 100644 --- a/target/config/Config.in.kernelversion +++ b/target/config/Config.in.kernelversion @@ -11,15 +11,18 @@ default ADK_TARGET_KERNEL_VERSION_4_4_14 config ADK_TARGET_KERNEL_VERSION_GIT bool "linux-git" + depends on !ADK_TARGET_ARCH_NDS32 config ADK_TARGET_KERNEL_VERSION_4_6_3 bool "4.6.3" + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_BOARD_BCM28XX depends on !ADK_TARGET_SYSTEM_SOLIDRUN_IMX6 select ADK_TARGET_KERNEL_VERSION_4_6 config ADK_TARGET_KERNEL_VERSION_4_5_7 bool "4.5.7" + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_BOARD_BCM28XX depends on !ADK_TARGET_SYSTEM_SOLIDRUN_IMX6 @@ -27,6 +30,7 @@ config ADK_TARGET_KERNEL_VERSION_4_5_7 config ADK_TARGET_KERNEL_VERSION_4_4_14 bool "4.4.14" + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_SYSTEM_SOLIDRUN_IMX6 select ADK_TARGET_KERNEL_VERSION_4_4 @@ -37,6 +41,7 @@ config ADK_TARGET_KERNEL_VERSION_4_1_26 depends on !ADK_TARGET_ARCH_BFIN depends on !ADK_TARGET_ARCH_H8300 depends on !ADK_TARGET_ARCH_NIOS2 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_SPARC depends on !ADK_TARGET_SYSTEM_KINETIS_K70 select ADK_TARGET_KERNEL_VERSION_4_1 @@ -46,6 +51,7 @@ config ADK_TARGET_KERNEL_VERSION_3_18_33 depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_BFIN depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_ARCH_SPARC depends on !ADK_TARGET_BOARD_ATH79 @@ -60,6 +66,7 @@ config ADK_TARGET_KERNEL_VERSION_3_14_72 depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_BFIN depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_ARCH_SPARC depends on !ADK_TARGET_BOARD_ATH79 @@ -72,6 +79,7 @@ config ADK_TARGET_KERNEL_VERSION_3_12_59 depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_BFIN depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_ARCH_SPARC depends on !ADK_TARGET_BOARD_ATH79 @@ -86,6 +94,7 @@ config ADK_TARGET_KERNEL_VERSION_3_10_101 depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_BFIN depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_ARCH_SPARC depends on !ADK_TARGET_BOARD_ATH79 @@ -115,6 +124,7 @@ config ADK_TARGET_KERNEL_VERSION_3_2_80 depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_BFIN depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_ARCH_SPARC depends on !ADK_TARGET_BOARD_ATH79 @@ -129,6 +139,7 @@ config ADK_TARGET_KERNEL_VERSION_2_6_32_70 depends on !ADK_TARGET_ARCH_ARC depends on !ADK_TARGET_ARCH_BFIN depends on !ADK_TARGET_ARCH_H8300 + depends on !ADK_TARGET_ARCH_NDS32 depends on !ADK_TARGET_ARCH_NIOS2 depends on !ADK_TARGET_ARCH_SPARC depends on !ADK_TARGET_BOARD_ATH79 diff --git a/target/config/Config.in.runtime b/target/config/Config.in.runtime index 6ed3bc5b7..6657e044c 100644 --- a/target/config/Config.in.runtime +++ b/target/config/Config.in.runtime @@ -285,6 +285,7 @@ config ADK_RUNTIME_CONSOLE_SERIAL_SPEED default "9600" if ADK_TARGET_SYSTEM_FON_FON2100 default "9600" if ADK_TARGET_SYSTEM_NUMATO_MIMASV2 default "38400" if ADK_TARGET_SYSTEM_PCENGINES_WRAP + default "38400" if ADK_TARGET_SYSTEM_ANDES_AG101P default "115200" config ADK_RUNTIME_KBD_LAYOUT diff --git a/target/config/Config.in.target b/target/config/Config.in.target index ec72d1b44..5fef2270e 100644 --- a/target/config/Config.in.target +++ b/target/config/Config.in.target @@ -8,5 +8,6 @@ config ADK_TARGET_CMDLINE default "kinetis_platform=k70-som" if ADK_TARGET_SYSTEM_KINETIS_K70 default "metag_da.console_poll=1" if ADK_TARGET_SYSTEM_QEMU_METAG default "earlycon=uart8250,mmio32,0x9d050020,115200n8 console=ttyS0,115200n8" if ADK_TARGET_CPU_XTENSA_DE212 + default "earlyprintk=uart8250-32bit,0x99600000" if ADK_TARGET_SYSTEM_ANDES_AG101P default "" diff --git a/target/linux/config/Config.in.ethernet b/target/linux/config/Config.in.ethernet index 6ef03ee4b..cfb12e1db 100644 --- a/target/linux/config/Config.in.ethernet +++ b/target/linux/config/Config.in.ethernet @@ -23,6 +23,9 @@ config ADK_KERNEL_NET_VENDOR_IBM config ADK_KERNEL_NET_VENDOR_INTEL bool +config ADK_KERNEL_NET_VENDOR_FARADAY + bool + config ADK_KERNEL_NET_VENDOR_FREESCALE bool @@ -400,6 +403,13 @@ config ADK_KERNEL_ETHOC default y if ADK_TARGET_SYSTEM_QEMU_OR1K default n +config ADK_KERNEL_FTMAC100 + bool "Andes ethernet driver" + select ADK_KERNEL_NET_VENDOR_FARADAY + depends on ADK_TARGET_SYSTEM_ANDES_AG101P + default y if ADK_TARGET_SYSTEM_ANDES_AG101P + default n + config ADK_KERNEL_ATL1 tristate "Atheros/Attansic L1 Gigabit Ethernet support" select ADK_KERNEL_NET_VENDOR_ATHEROS diff --git a/target/linux/config/Config.in.kernel b/target/linux/config/Config.in.kernel index b52c621d1..924d0e6e6 100644 --- a/target/linux/config/Config.in.kernel +++ b/target/linux/config/Config.in.kernel @@ -58,11 +58,15 @@ config ADK_KERNEL_CPU_LITTLE_ENDIAN menu "Kernel options" +config ADK_KERNEL_HOTPLUG + bool + config ADK_KERNEL_DEVTMPFS bool config ADK_KERNEL_DEVTMPFS_MOUNT bool + select ADK_KERNEL_HOTPLUG config ADK_KERNEL_UEVENT_HELPER bool diff --git a/target/linux/config/Config.in.serial b/target/linux/config/Config.in.serial index 113599149..82d745271 100644 --- a/target/linux/config/Config.in.serial +++ b/target/linux/config/Config.in.serial @@ -2,7 +2,7 @@ # material, please see the LICENCE file in the top-level directory. menu "Serial devices support" -depends on ADK_TARGET_WITH_SERIAL || ADK_TARGET_QEMU || ADK_TARGET_VBOX || ADK_TARGET_SIM +depends on ADK_TARGET_WITH_SERIAL || ADK_TARGET_QEMU || ADK_TARGET_VBOX || ADK_TARGET_SIM || ADK_TARGET_GENERIC config ADK_KERNEL_SERIAL_8250_CONSOLE bool @@ -90,6 +90,7 @@ config ADK_KERNEL_SERIAL_8250 depends on ADK_TARGET_SYSTEM_XILINX_KINTEX7 \ || ADK_TARGET_SYSTEM_IMGTEC_CI20 \ || ADK_TARGET_SYSTEM_LINKSYS_NSLU2 \ + || ADK_TARGET_SYSTEM_ANDES_AG101P \ || ADK_TARGET_SYSTEM_PCENGINES_APU \ || ADK_TARGET_SYSTEM_PCENGINES_ALIX \ || ADK_TARGET_SYSTEM_QEMU_MICROBLAZE_ML605 \ @@ -102,6 +103,7 @@ config ADK_KERNEL_SERIAL_8250 || ADK_TARGET_SYSTEM_QEMU_XTENSA \ || ADK_TARGET_SYSTEM_OR1K_SIM \ || ADK_TARGET_SYSTEM_IBM_X40 \ + || ADK_TARGET_SYSTEM_GENERIC_NDS32 \ || ADK_TARGET_SYSTEM_GENERIC_X86 \ || ADK_TARGET_SYSTEM_GENERIC_X86_64 \ || ADK_TARGET_SYSTEM_MIKROTIK_RB532 \ @@ -109,6 +111,7 @@ config ADK_KERNEL_SERIAL_8250 default y if ADK_TARGET_SYSTEM_XILINX_KINTEX7 default y if ADK_TARGET_SYSTEM_IMGTEC_CI20 default y if ADK_TARGET_SYSTEM_LINKSYS_NSLU2 + default y if ADK_TARGET_SYSTEM_ANDES_AG101P default y if ADK_TARGET_SYSTEM_PCENGINES_APU default y if ADK_TARGET_SYSTEM_PCENGINES_ALIX default y if ADK_TARGET_SYSTEM_QEMU_MICROBLAZE_ML605 @@ -121,6 +124,7 @@ config ADK_KERNEL_SERIAL_8250 default y if ADK_TARGET_SYSTEM_QEMU_XTENSA default y if ADK_TARGET_SYSTEM_OR1K_SIM default y if ADK_TARGET_SYSTEM_IBM_X40 + default y if ADK_TARGET_SYSTEM_GENERIC_NDS32 default y if ADK_TARGET_SYSTEM_GENERIC_X86 default y if ADK_TARGET_SYSTEM_GENERIC_X86_64 default y if ADK_TARGET_SYSTEM_MIKROTIK_RB532 diff --git a/target/linux/patches/3.4.112/nds32.patch b/target/linux/patches/3.4.112/nds32.patch new file mode 100644 index 000000000..d0da6f7b3 --- /dev/null +++ b/target/linux/patches/3.4.112/nds32.patch @@ -0,0 +1,72132 @@ +diff -Nur linux-3.4.110.orig/arch/nds32/boot/install.sh linux-3.4.110/arch/nds32/boot/install.sh +--- linux-3.4.110.orig/arch/nds32/boot/install.sh 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/boot/install.sh 2016-04-07 10:20:50.862077930 +0200 +@@ -0,0 +1,47 @@ ++#!/bin/sh ++# ++# arch/nds32/boot/install.sh ++# ++# This file is subject to the terms and conditions of the GNU General Public ++# License. See the file "COPYING" in the main directory of this archive ++# for more details. ++# ++# Copyright (C) 1995 by Linus Torvalds ++# Copyright (C) 2009 Andes Technology Corporation ++# ++# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin ++# Adapted from code in arch/i386/boot/install.sh by Russell King ++# ++# "make install" script for arm architecture ++# ++# Arguments: ++# $1 - kernel version ++# $2 - kernel image file ++# $3 - kernel map file ++# $4 - default install path (blank if root directory) ++# ++ ++# User may have a custom install script ++if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi ++if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi ++ ++# Normal install ++echo "Installing normal kernel" ++base=vmlinux ++ ++if [ -f $4/$base-$1 ]; then ++ mv $4/$base-$1 $4/$base-$1.old ++fi ++cat $2 > $4/$base-$1 ++ ++# Install system map file ++if [ -f $4/System.map-$1 ]; then ++ mv $4/System.map-$1 $4/System.map-$1.old ++fi ++cp $3 $4/System.map-$1 ++ ++if [ -x /sbin/loadmap ]; then ++ /sbin/loadmap ++else ++ echo "You have to install it yourself" ++fi +diff -Nur linux-3.4.110.orig/arch/nds32/boot/Makefile linux-3.4.110/arch/nds32/boot/Makefile +--- linux-3.4.110.orig/arch/nds32/boot/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/boot/Makefile 2016-04-07 10:20:50.862077930 +0200 +@@ -0,0 +1,22 @@ ++# ++# arch/nds32/boot/Makefile ++# ++# This file is subject to the terms and conditions of the GNU General Public ++# License. See the file "COPYING" in the main directory of this archive ++# for more details. ++# ++# Copyright (C) 1995-2002 Russell King ++# Copyright (C) 2009 Andes Technology Corporation ++# ++ ++targets := Image ++ ++$(obj)/Image: vmlinux FORCE ++ $(call if_changed,objcopy) ++ @echo ' Kernel: $@ is ready' ++ ++.PHONY: FORCE ++install: $(obj)/Image ++ $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ ++ $(obj)/Image System.map "$(INSTALL_PATH)" ++ +diff -Nur linux-3.4.110.orig/arch/nds32/common/dmabounce.c linux-3.4.110/arch/nds32/common/dmabounce.c +--- linux-3.4.110.orig/arch/nds32/common/dmabounce.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.4.110/arch/nds32/common/dmabounce.c 2016-04-07 10:20:50.882078703 +0200 +@@ -0,0 +1,672 @@ ++/* ++ * arch/nds32/common/dmabounce.c ++ * ++ * Special dma_{map/unmap/dma_sync}_* routines for systems that have ++ * limited DMA windows. These functions utilize bounce buffers to ++ * copy data to/from buffers located outside the DMA region. This ++ * only works for systems in which DMA memory is at the bottom of ++ * RAM and the remainder of memory is at the top an the DMA memory ++ * can be marked as ZONE_DMA. Anything beyond that such as discontigous ++ * DMA windows will require custom implementations that reserve memory ++ * areas at early bootup. ++ * ++ * Original version by Brad Parker (brad@heeltoe.com) ++ * Re-written by Christopher Hoover <ch@murgatroid.com> ++ * Made generic by Deepak Saxena <dsaxena@plexity.net> ++ * ++ * Copyright (C) 2002 Hewlett Packard Company. ++ * Copyright (C) 2004 MontaVista Software, Inc. ++ * Copyright (C) 2009 Andes Technology Corporation ++ * ++ * 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. ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/device.h> ++#include <linux/dma-mapping.h> ++#include <linux/dmapool.h> ++#include <linux/list.h> ++ ++#undef DEBUG ++ ++#undef STATS ++#ifdef STATS ++#define DO_STATS(X) do { X ; } while (0) ++#else ++#define DO_STATS(X) do { } while (0) ++#endif ++ ++/* ************************************************** */ ++ ++struct safe_buffer { ++ struct list_head node; ++ ++ /* original request */ ++ void *ptr; ++ size_t size; ++ int direction; ++ ++ /* safe buffer info */ ++ struct dma_pool *pool; ++ void *safe; ++ dma_addr_t safe_dma_addr; ++}; ++ ++struct dmabounce_device_info { ++ struct list_head node; ++ ++ struct device *dev; ++ struct dma_pool *small_buffer_pool; ++ struct dma_pool *large_buffer_pool; ++ struct list_head safe_buffers; ++ unsigned long small_buffer_size, large_buffer_size; ++#ifdef STATS ++ unsigned long sbp_allocs; ++ unsigned long lbp_allocs; ++ unsigned long total_allocs; ++ unsigned long map_op_count; ++ unsigned long bounce_count; ++#endif ++}; ++ ++static LIST_HEAD(dmabounce_devs); ++ ++#ifdef STATS ++static void print_alloc_stats(struct dmabounce_device_info *device_info) ++{ ++ printk(KERN_INFO ++ "%s: dmabounce: sbp: %lu, lbp: %lu, other: %lu, total: %lu\n", ++ device_info->dev->bus_id, ++ device_info->sbp_allocs, device_info->lbp_allocs, ++ device_info->total_allocs - device_info->sbp_allocs - ++ device_info->lbp_allocs, device_info->total_allocs); ++} ++#endif ++ ++/* find the given device in the dmabounce device list */ ++static inline struct dmabounce_device_info *find_dmabounce_dev(struct device ++ *dev) ++{ ++ struct list_head *entry; ++ ++ list_for_each(entry, &dmabounce_devs) { ++ struct dmabounce_device_info *d = ++ list_entry(entry, struct dmabounce_device_info, node); ++ ++ if (d->dev == dev) ++ return d; ++ } ++ return NULL; ++} ++ ++/* allocate a 'safe' buffer and keep track of it */ ++static inline struct safe_buffer *alloc_safe_buffer(struct dmabounce_device_info ++ *device_info, void *ptr, ++ size_t size, ++ enum dma_data_direction dir) ++{ ++ struct safe_buffer *buf; ++ struct dma_pool *pool; ++ struct device *dev = device_info->dev; ++ void *safe; ++ dma_addr_t safe_dma_addr; ++ ++ dev_dbg(dev, "%s(ptr=%p, size=%d, dir=%d)\n", __func__, ptr, size, dir); ++ ++ DO_STATS(device_info->total_allocs++); ++ ++ buf = kmalloc(sizeof(struct safe_buffer), GFP_ATOMIC); ++ if (buf == NULL) { ++ dev_warn(dev, "%s: kmalloc failed\n", __func__); ++ return NULL; ++ } ++ ++ if (size <= device_info->small_buffer_size) { ++ pool = device_info->small_buffer_pool; ++ safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); ++ ++ DO_STATS(device_info->sbp_allocs++); ++ } else if (size <= device_info->large_buffer_size) { ++ pool = device_info->large_buffer_pool; ++ safe = dma_pool_alloc(pool, GFP_ATOMIC, &safe_dma_addr); ++ ++ DO_STATS(device_info->lbp_allocs++); ++ } else { ++ pool = NULL; ++ safe = ++ dma_alloc_coherent(dev, size, &safe_dma_addr, GFP_ATOMIC); ++ } ++ ++ if (safe == NULL) { ++ dev_warn(device_info->dev, ++ "%s: could not alloc dma memory (size=%d)\n", ++ __func__, size); ++ kfree(buf); ++ return NULL; ++ } ++#ifdef STATS ++ if (device_info->total_allocs % 1000 == 0) ++ print_alloc_stats(device_info); ++#endif ++ ++ buf->ptr = ptr; ++ buf->size = size; ++ buf->direction = dir; ++ buf->pool = pool; ++ buf->safe = safe; ++ buf->safe_dma_addr = safe_dma_addr; ++ ++ list_add(&buf->node, &device_info->safe_buffers); ++ ++ return buf; ++} ++ ++/* determine if a buffer is from our "safe" pool */ ++static inline struct safe_buffer *find_safe_buffer(struct dmabounce_device_info ++ *device_info, ++ dma_addr_t safe_dma_addr) ++{ ++ struct list_head *entry; ++ ++ list_for_each(entry, &device_info->safe_buffers) { ++ struct safe_buffer *b = ++ list_entry(entry, struct safe_buffer, node); ++ ++ if (b->safe_dma_addr == safe_dma_addr) ++ return b; ++ } ++ ++ return NULL; ++} ++ ++static inline void ++free_safe_buffer(struct dmabounce_device_info *device_info, ++ struct safe_buffer *buf) ++{ ++ dev_dbg(device_info->dev, "%s(buf=%p)\n", __func__, buf); ++ ++ list_del(&buf->node); ++ ++ if (buf->pool) ++ dma_pool_free(buf->pool, buf->safe, buf->safe_dma_addr); ++ else ++ dma_free_coherent(device_info->dev, buf->size, buf->safe, ++ buf->safe_dma_addr); ++ ++ kfree(buf); ++} ++ ++/* ************************************************** */ ++ ++#ifdef STATS ++ ++static void print_map_stats(struct dmabounce_device_info *device_info) ++{ ++ printk(KERN_INFO ++ "%s: dmabounce: map_op_count=%lu, bounce_count=%lu\n", ++ device_info->dev->bus_id, ++ device_info->map_op_count, device_info->bounce_count); ++} ++#endif ++ ++static inline dma_addr_t ++map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); ++ dma_addr_t dma_addr; ++ int needs_bounce = 0; ++ ++ if (device_info) ++ DO_STATS(device_info->map_op_count++); ++ ++ dma_addr = virt_to_dma(dev, ptr); ++ ++ if (dev->dma_mask) { ++ unsigned long mask = *dev->dma_mask; ++ unsigned long limit; ++ ++ limit = (mask + 1) & ~mask; ++ if (limit && size > limit) { ++ dev_err(dev, "DMA mapping too big (requested %#x " ++ "mask %#Lx)\n", size, *dev->dma_mask); ++ return ~0; ++ } ++ ++ /* ++ * Figure out if we need to bounce from the DMA mask. ++ */ ++ needs_bounce = (dma_addr | (dma_addr + size - 1)) & ~mask; ++ } ++ ++ if (device_info ++ && (needs_bounce || dma_needs_bounce(dev, dma_addr, size))) { ++ struct safe_buffer *buf; ++ ++ buf = alloc_safe_buffer(device_info, ptr, size, dir); ++ if (buf == 0) { ++ dev_err(dev, "%s: unable to map unsafe buffer %p!\n", ++ __func__, ptr); ++ return 0; ++ } ++ ++ dev_dbg(dev, ++ "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", ++ __func__, buf->ptr, (void *)virt_to_dma(dev, buf->ptr), ++ buf->safe, (void *)buf->safe_dma_addr); ++ ++ if ((dir == DMA_TO_DEVICE) || (dir == DMA_BIDIRECTIONAL)) { ++ dev_dbg(dev, "%s: copy unsafe %p to safe %p, size %d\n", ++ __func__, ptr, buf->safe, size); ++ memcpy(buf->safe, ptr, size); ++ } ++ consistent_sync(buf->safe, size, dir); ++ ++ dma_addr = buf->safe_dma_addr; ++ } else { ++ consistent_sync(ptr, size, dir); ++ } ++ ++ return dma_addr; ++} ++ ++static inline void ++unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); ++ struct safe_buffer *buf = NULL; ++ ++ /* ++ * Trying to unmap an invalid mapping ++ */ ++ if (dma_addr == ~0) { ++ dev_err(dev, "Trying to unmap invalid mapping\n"); ++ return; ++ } ++ ++ if (device_info) ++ buf = find_safe_buffer(device_info, dma_addr); ++ ++ if (buf) { ++ BUG_ON(buf->size != size); ++ ++ dev_dbg(dev, ++ "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", ++ __func__, buf->ptr, (void *)virt_to_dma(dev, buf->ptr), ++ buf->safe, (void *)buf->safe_dma_addr); ++ ++ DO_STATS(device_info->bounce_count++); ++ ++ if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)) { ++ dev_dbg(dev, ++ "%s: copy back safe %p to unsafe %p size %d\n", ++ __func__, buf->safe, buf->ptr, size); ++ memcpy(buf->ptr, buf->safe, size); ++ } ++ free_safe_buffer(device_info, buf); ++ } ++} ++ ++static inline void ++sync_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ struct dmabounce_device_info *device_info = find_dmabounce_dev(dev); ++ struct safe_buffer *buf = NULL; ++ ++ if (device_info) ++ buf = find_safe_buffer(device_info, dma_addr); ++ ++ if (buf) { ++ /* ++ * Both of these checks from original code need to be ++ * commented out b/c some drivers rely on the following: ++ * ++ * 1) Drivers may map a large chunk of memory into DMA space ++ * but only sync a small portion of it. Good example is ++ * allocating a large buffer, mapping it, and then ++ * breaking it up into small descriptors. No point ++ * in syncing the whole buffer if you only have to ++ * touch one descriptor. ++ * ++ * 2) Buffers that are mapped as DMA_BIDIRECTIONAL are ++ * usually only synced in one dir at a time. ++ * ++ * See drivers/net/eepro100.c for examples of both cases. ++ * ++ * -ds ++ * ++ * BUG_ON(buf->size != size); ++ * BUG_ON(buf->direction != dir); ++ */ ++ ++ dev_dbg(dev, ++ "%s: unsafe buffer %p (phy=%p) mapped to %p (phy=%p)\n", ++ __func__, buf->ptr, (void *)virt_to_dma(dev, buf->ptr), ++ buf->safe, (void *)buf->safe_dma_addr); ++ ++ DO_STATS(device_info->bounce_count++); ++ ++ switch (dir) { ++ case DMA_FROM_DEVICE: ++ dev_dbg(dev, ++ "%s: copy back safe %p to unsafe %p size %d\n", ++ __func__, buf->safe, buf->ptr, size); ++ memcpy(buf->ptr, buf->safe, size); ++ break; ++ case DMA_TO_DEVICE: ++ dev_dbg(dev, ++ "%s: copy out unsafe %p to safe %p, size %d\n", ++ __func__, buf->ptr, buf->safe, size); ++ memcpy(buf->safe, buf->ptr, size); ++ break; ++ case DMA_BIDIRECTIONAL: ++ BUG(); /* is this allowed? what does it mean? */ ++ default: ++ BUG(); ++ } ++ consistent_sync(buf->safe, size, dir); ++ } else { ++ consistent_sync(dma_to_virt(dev, dma_addr), size, dir); ++ } ++} ++ ++/* ************************************************** */ ++ ++/* ++ * see if a buffer address is in an 'unsafe' range. if it is ++ * allocate a 'safe' buffer and copy the unsafe buffer into it. ++ * substitute the safe buffer for the unsafe one. ++ * (basically move the buffer from an unsafe area to a safe one) ++ */ ++dma_addr_t ++dma_map_single(struct device *dev, void *ptr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ dma_addr_t dma_addr; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", __func__, ptr, size, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ dma_addr = map_single(dev, ptr, size, dir); ++ ++ local_irq_restore(flags); ++ ++ return dma_addr; ++} ++ ++/* ++ * see if a mapped address was really a "safe" buffer and if so, copy ++ * the data from the safe buffer back to the unsafe buffer and free up ++ * the safe buffer. (basically return things back to the way they ++ * should be) ++ */ ++ ++void ++dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", ++ __func__, (void *)dma_addr, size, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ unmap_single(dev, dma_addr, size, dir); ++ ++ local_irq_restore(flags); ++} ++ ++int ++dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ struct page *page = sg->page; ++ unsigned int offset = sg->offset; ++ unsigned int length = sg->length; ++ void *ptr = page_address(page) + offset; ++ ++ sg->dma_address = map_single(dev, ptr, length, dir); ++ } ++ ++ local_irq_restore(flags); ++ ++ return nents; ++} ++ ++void ++dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ dma_addr_t dma_addr = sg->dma_address; ++ unsigned int length = sg->length; ++ ++ unmap_single(dev, dma_addr, length, dir); ++ } ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", ++ __func__, (void *)dma_addr, size, dir); ++ ++ local_irq_save(flags); ++ ++ sync_single(dev, dma_addr, size, dir); ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, size_t size, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ ++ dev_dbg(dev, "%s(ptr=%p,size=%d,dir=%x)\n", ++ __func__, (void *)dma_addr, size, dir); ++ ++ local_irq_save(flags); ++ ++ sync_single(dev, dma_addr, size, dir); ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir == DMA_NONE); ++ ++ local_irq_save(flags); ++ ++ for (i = 0; i < nents; i++, sg++) { ++ dma_addr_t dma_addr = sg->dma_address; ++ unsigned int length = sg->length; ++ ++ sync_single(dev, dma_addr, length, dir); ++ } ++ ++ local_irq_restore(flags); ++} ++ ++void ++dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, ++ enum dma_data_direction dir) ++{ ++ unsigned long flags; ++ int i; ++ ++ dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", __func__, sg, nents, dir); ++ ++ BUG_ON(dir = |