summaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
Diffstat (limited to 'target')
-rw-r--r--target/config/Config.in.binutils3
-rw-r--r--target/config/Config.in.compiler3
-rw-r--r--target/config/Config.in.cpu4
-rw-r--r--target/config/Config.in.gdb5
-rw-r--r--target/config/Config.in.kernelcfg1
-rw-r--r--target/config/Config.in.kernelversion11
-rw-r--r--target/config/Config.in.runtime1
-rw-r--r--target/config/Config.in.target1
-rw-r--r--target/linux/config/Config.in.ethernet10
-rw-r--r--target/linux/config/Config.in.kernel4
-rw-r--r--target/linux/config/Config.in.serial6
-rw-r--r--target/linux/patches/3.4.112/nds32.patch72132
-rw-r--r--target/nds32/Makefile3
-rw-r--r--target/nds32/kernel/andes-ag101p5
-rw-r--r--target/nds32/kernel/generic-nds322
-rw-r--r--target/nds32/systems/andes-ag101p9
-rw-r--r--target/nds32/uclibc-ng.config248
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 =