[target/leon]: add preliminary LEON support
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@25139 3c298f89-4303-0410-b956-a3cf2f4a3e73master
parent
937fe0bbe9
commit
bf8c98a65d
|
@ -0,0 +1,22 @@
|
|||
#
|
||||
# Copyright (C) 2011 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
ARCH:=sparc
|
||||
BOARD:=leon
|
||||
BOARDNAME:=LEON
|
||||
FEATURES+=fpu tgz
|
||||
|
||||
CFLAGS:=-Os -pipe -mcpu=v8 -funit-at-a-time
|
||||
KERNELNAME:="uImage"
|
||||
|
||||
LINUX_VERSION:=2.6.36.2
|
||||
MAINTAINER:=Imre Kaloz <kaloz@openwrt.org>
|
||||
|
||||
include $(INCLUDE_DIR)/target.mk
|
||||
|
||||
$(eval $(call BuildTarget))
|
|
@ -0,0 +1,138 @@
|
|||
# CONFIG_64BIT is not set
|
||||
CONFIG_ARCH_DEFCONFIG="arch/sparc/configs/sparc32_defconfig"
|
||||
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
|
||||
CONFIG_ARCH_NO_VIRT_TO_BUS=y
|
||||
# CONFIG_ARCH_SUPPORTS_MSI is not set
|
||||
CONFIG_ARCH_USES_GETTIMEOFFSET=y
|
||||
CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
|
||||
# CONFIG_ARPD is not set
|
||||
CONFIG_ATA=y
|
||||
CONFIG_AUDIT_ARCH=y
|
||||
CONFIG_BITS=32
|
||||
# CONFIG_BLK_DEV_INITRD is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_SD=y
|
||||
CONFIG_BOUNCE=y
|
||||
# CONFIG_BRIDGE is not set
|
||||
# CONFIG_BSD_PROCESS_ACCT is not set
|
||||
CONFIG_COMPAT_BRK=y
|
||||
CONFIG_CONSOLE_TRANSLATIONS=y
|
||||
CONFIG_DEBUG_BUGVERBOSE=y
|
||||
CONFIG_DECOMPRESS_LZMA=y
|
||||
CONFIG_DNOTIFY=y
|
||||
CONFIG_DUMMY_CONSOLE=y
|
||||
CONFIG_ELF_CORE=y
|
||||
CONFIG_EMULATED_CMPXCHG=y
|
||||
CONFIG_ENABLE_MUST_CHECK=y
|
||||
CONFIG_FB=y
|
||||
# CONFIG_FB_IGA is not set
|
||||
# CONFIG_FB_SBUS is not set
|
||||
# CONFIG_FB_SM7XX is not set
|
||||
# CONFIG_FB_XGI is not set
|
||||
# CONFIG_FIRMWARE_EDID is not set
|
||||
CONFIG_FIRMWARE_IN_KERNEL=y
|
||||
# CONFIG_FONTS is not set
|
||||
# CONFIG_FONT_SUN12x22 is not set
|
||||
CONFIG_FONT_SUN8x16=y
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
|
||||
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
|
||||
CONFIG_FS_POSIX_ACL=y
|
||||
CONFIG_GENERIC_ACL=y
|
||||
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||
CONFIG_GENERIC_FIND_LAST_BIT=y
|
||||
CONFIG_GENERIC_FIND_NEXT_BIT=y
|
||||
CONFIG_GENERIC_ISA_DMA=y
|
||||
# CONFIG_GRETH is not set
|
||||
# CONFIG_HAMRADIO is not set
|
||||
CONFIG_HAPPYMEAL=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=y
|
||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
CONFIG_HAVE_DMA_ATTRS=y
|
||||
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
|
||||
CONFIG_HAVE_IDE=y
|
||||
CONFIG_HAVE_OPROFILE=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HID=m
|
||||
CONFIG_HID_SUPPORT=y
|
||||
CONFIG_HIGHMEM=y
|
||||
CONFIG_HW_CONSOLE=y
|
||||
CONFIG_HZ=250
|
||||
# CONFIG_HZ_100 is not set
|
||||
CONFIG_HZ_250=y
|
||||
CONFIG_INOTIFY_USER=y
|
||||
CONFIG_INPUT=y
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
CONFIG_INPUT_POLLDEV=y
|
||||
CONFIG_LEGACY_PTYS=y
|
||||
CONFIG_LEGACY_PTY_COUNT=256
|
||||
CONFIG_LOCK_KERNEL=y
|
||||
# CONFIG_MISC_DEVICES is not set
|
||||
# CONFIG_MTD is not set
|
||||
CONFIG_MUTEX_SPIN_ON_OWNER=y
|
||||
# CONFIG_MYRI_SBUS is not set
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_SG_DMA_LENGTH=y
|
||||
CONFIG_NR_CPUS=4
|
||||
CONFIG_OF=y
|
||||
CONFIG_OF_DEVICE=y
|
||||
CONFIG_PAGEFLAGS_EXTENDED=y
|
||||
# CONFIG_PARTITION_ADVANCED is not set
|
||||
CONFIG_PATA_CMD64X=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCI_DISABLE_COMMON_QUIRKS=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PROC_PAGE_MONITOR=y
|
||||
CONFIG_RELAY=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RTC_DRV_BQ4802=y
|
||||
CONFIG_RTC_DRV_M48T59=y
|
||||
CONFIG_SATA_PMP=y
|
||||
CONFIG_SBUS=y
|
||||
CONFIG_SBUSCHAR=y
|
||||
# CONFIG_SCHED_HRTICK is not set
|
||||
CONFIG_SCSI=y
|
||||
# CONFIG_SCSI_LOWLEVEL is not set
|
||||
# CONFIG_SCSI_MULTI_LUN is not set
|
||||
CONFIG_SERIAL_8250_NR_UARTS=4
|
||||
CONFIG_SERIAL_8250_RUNTIME_UARTS=4
|
||||
CONFIG_SERIAL_CONSOLE=y
|
||||
CONFIG_SERIAL_SUNCORE=y
|
||||
CONFIG_SERIAL_SUNSAB=y
|
||||
CONFIG_SERIAL_SUNSAB_CONSOLE=y
|
||||
CONFIG_SERIAL_SUNSU=y
|
||||
CONFIG_SERIAL_SUNSU_CONSOLE=y
|
||||
# CONFIG_SERIAL_SUNZILOG is not set
|
||||
# CONFIG_SLAB is not set
|
||||
CONFIG_SLUB=y
|
||||
CONFIG_SMP=y
|
||||
CONFIG_SPARC=y
|
||||
CONFIG_SPARC32=y
|
||||
CONFIG_SPARC32_PCI=y
|
||||
CONFIG_SPARC32_SMP=y
|
||||
# CONFIG_SPARC64 is not set
|
||||
# CONFIG_SPARC_LED is not set
|
||||
CONFIG_SPARC_LEON=y
|
||||
CONFIG_STOP_MACHINE=y
|
||||
# CONFIG_SUNBMAC is not set
|
||||
# CONFIG_SUNLANCE is not set
|
||||
# CONFIG_SUNQE is not set
|
||||
# CONFIG_SUN_JSFLASH is not set
|
||||
CONFIG_SUN_OPENPROMFS=y
|
||||
CONFIG_SUN_OPENPROMIO=y
|
||||
CONFIG_SUN_PARTITION=y
|
||||
CONFIG_SUN_PM=y
|
||||
# CONFIG_TADPOLE_TS102_UCTRL is not set
|
||||
CONFIG_TMPFS_POSIX_ACL=y
|
||||
CONFIG_TREE_RCU=y
|
||||
CONFIG_UID16=y
|
||||
CONFIG_USB_SUPPORT=y
|
||||
# CONFIG_VLAN_8021Q is not set
|
||||
CONFIG_VM_EVENT_COUNTERS=y
|
||||
CONFIG_VT=y
|
||||
CONFIG_VT_CONSOLE=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
# CONFIG_WATCHDOG is not set
|
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# Copyright (C) 2011 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)/image.mk
|
||||
|
||||
define Image/Prepare
|
||||
cp $(LINUX_DIR)/arch/sparc/boot/uImage $(KDIR)/uImage
|
||||
endef
|
||||
|
||||
define Image/BuildKernel
|
||||
mkdir -p $(BIN_DIR)
|
||||
cp $(KDIR)/uImage $(BIN_DIR)/$(IMG_PREFIX)-uImage
|
||||
endef
|
||||
|
||||
$(eval $(call BuildImage))
|
|
@ -0,0 +1,48 @@
|
|||
From af1da1d5a8701f39cdbae4a0ab8e04b450eef298 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 8 Sep 2010 18:05:38 +0200
|
||||
Subject: [PATCH] SPARC/LEON: find IRQ and Timer via OF-Tree, instead of hardcoded.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/kernel/leon_kernel.c | 23 ++++++++++++++++++++++-
|
||||
1 files changed, 22 insertions(+), 1 deletions(-)
|
||||
|
||||
--- a/arch/sparc/kernel/leon_kernel.c
|
||||
+++ b/arch/sparc/kernel/leon_kernel.c
|
||||
@@ -105,13 +105,34 @@ static void leon_disable_irq(unsigned in
|
||||
void __init leon_init_timers(irq_handler_t counter_fn)
|
||||
{
|
||||
int irq;
|
||||
+ struct device_node *rootnp, *np;
|
||||
+ struct property *pp;
|
||||
+ int len;
|
||||
|
||||
leondebug_irq_disable = 0;
|
||||
leon_debug_irqout = 0;
|
||||
master_l10_counter = (unsigned int *)&dummy_master_l10_counter;
|
||||
dummy_master_l10_counter = 0;
|
||||
|
||||
- if (leon3_gptimer_regs && leon3_irqctrl_regs) {
|
||||
+ /* Find IRQMP IRQ Controller Registers base address otherwise bail out. */
|
||||
+ rootnp = of_find_node_by_path("/ambapp0");
|
||||
+ if (rootnp && (np=of_find_node_by_name(rootnp, "GAISLER_IRQMP"))) {
|
||||
+ pp = of_find_property(np, "reg", &len);
|
||||
+ if (pp)
|
||||
+ leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value;
|
||||
+ }
|
||||
+
|
||||
+ /* Find GPTIMER Timer Registers base address otherwise bail out. */
|
||||
+ if (rootnp && (np=of_find_node_by_name(rootnp, "GAISLER_GPTIMER"))) {
|
||||
+ pp = of_find_property(np, "reg", &len);
|
||||
+ if (pp)
|
||||
+ leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **)pp->value;
|
||||
+ pp = of_find_property(np, "interrupts", &len);
|
||||
+ if (pp)
|
||||
+ leon3_gptimer_irq = *(unsigned int *)pp->value;
|
||||
+ }
|
||||
+
|
||||
+ if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) {
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0);
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld,
|
||||
(((1000000 / 100) - 1)));
|
|
@ -0,0 +1,79 @@
|
|||
From 234ef25344b567b3b8dad62c0863ebe16377528f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Tue, 14 Sep 2010 11:26:55 +0200
|
||||
Subject: [PATCH] SPARC: added U-Boot build target: uImage
|
||||
|
||||
---
|
||||
arch/sparc/Makefile | 3 ++-
|
||||
arch/sparc/boot/Makefile | 35 +++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 37 insertions(+), 1 deletions(-)
|
||||
|
||||
--- a/arch/sparc/Makefile
|
||||
+++ b/arch/sparc/Makefile
|
||||
@@ -88,7 +88,7 @@ boot := arch/sparc/boot
|
||||
# Default target
|
||||
all: zImage
|
||||
|
||||
-image zImage tftpboot.img vmlinux.aout: vmlinux
|
||||
+image zImage uImage tftpboot.img vmlinux.aout: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
archclean:
|
||||
@@ -102,6 +102,7 @@ ifeq ($(ARCH),sparc)
|
||||
define archhelp
|
||||
echo '* image - kernel image ($(boot)/image)'
|
||||
echo '* zImage - stripped kernel image ($(boot)/zImage)'
|
||||
+ echo ' uImage - U-Boot SPARC32/LEON Image'
|
||||
echo ' tftpboot.img - image prepared for tftp'
|
||||
endef
|
||||
else
|
||||
--- a/arch/sparc/boot/Makefile
|
||||
+++ b/arch/sparc/boot/Makefile
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
ROOT_IMG := /usr/src/root.img
|
||||
ELFTOAOUT := elftoaout
|
||||
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
|
||||
|
||||
hostprogs-y := piggyback_32 piggyback_64 btfixupprep
|
||||
targets := tftpboot.img btfix.o btfix.S image zImage vmlinux.aout
|
||||
@@ -90,5 +91,39 @@ $(obj)/tftpboot.img: $(obj)/image $(obj)
|
||||
$(obj)/vmlinux.aout: vmlinux FORCE
|
||||
$(call if_changed,elftoaout)
|
||||
@echo ' kernel: $@ is ready'
|
||||
+else
|
||||
+
|
||||
+# The following lines make a readable image for U-Boot.
|
||||
+# uImage - Binary file read by U-boot
|
||||
+# uImage.o - object file of uImage for loading with a
|
||||
+# flash programmer understanding ELF.
|
||||
+
|
||||
+OBJCOPYFLAGS_image.bin := -S -O binary -R .note -R .comment
|
||||
+$(obj)/image.bin: $(obj)/image FORCE
|
||||
+ $(call if_changed,objcopy)
|
||||
+
|
||||
+$(obj)/image.gz: $(obj)/image.bin
|
||||
+ $(call if_changed,gzip)
|
||||
+
|
||||
+# Start of Main memory
|
||||
+ifndef UIMAGE_LOADADDR
|
||||
+UIMAGE_LOADADDR=0x40004000
|
||||
endif
|
||||
|
||||
+# The first sector after the U-Boot image (256k)
|
||||
+ifndef UIMAGE_FLASHADDR
|
||||
+UIMAGE_FLASHADDR=0x00040000
|
||||
+endif
|
||||
+
|
||||
+quiet_cmd_uimage = UIMAGE $@
|
||||
+ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A sparc -O linux -T kernel \
|
||||
+ -C gzip -a $(UIMAGE_LOADADDR) -e 0xf0004000 -n 'Linux-$(KERNELRELEASE)' \
|
||||
+ -d $< $@
|
||||
+
|
||||
+targets += uImage
|
||||
+$(obj)/uImage: $(obj)/image.gz
|
||||
+ $(call if_changed,uimage)
|
||||
+ sparc-linux-ld -Tdata $(UIMAGE_FLASHADDR) -r -b binary arch/sparc/boot/uImage -o arch/sparc/boot/uImage.o
|
||||
+ @echo ' Image $@ is ready'
|
||||
+
|
||||
+endif
|
|
@ -0,0 +1,23 @@
|
|||
From 417bc6751fdd3c24df274f25e020ec3decd09280 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Thu, 16 Sep 2010 11:00:46 +0200
|
||||
Subject: [PATCH] Fixed SPARC/LEON SMP CPU Stuck problem.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/kernel/leon_smp.c | 4 ++--
|
||||
1 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/sparc/kernel/leon_smp.c
|
||||
+++ b/arch/sparc/kernel/leon_smp.c
|
||||
@@ -56,8 +56,8 @@ void __init leon_configure_cache_smp(voi
|
||||
static inline unsigned long do_swap(volatile unsigned long *ptr,
|
||||
unsigned long val)
|
||||
{
|
||||
- __asm__ __volatile__("swapa [%1] %2, %0\n\t" : "=&r"(val)
|
||||
- : "r"(ptr), "i"(ASI_LEON_DCACHE_MISS)
|
||||
+ __asm__ __volatile__("swapa [%2] %3, %0\n\t" : "=&r"(val)
|
||||
+ : "0"(val), "r"(ptr), "i"(ASI_LEON_DCACHE_MISS)
|
||||
: "memory");
|
||||
return val;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
From a729672f117df3602b6d3171d8ab7a84bf53b053 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Thu, 16 Sep 2010 11:12:41 +0200
|
||||
Subject: [PATCH] SPARC/LEON: added support for Extended IRQ controller, partial patches are already in git tree.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/include/asm/irq_32.h | 4 ++++
|
||||
arch/sparc/kernel/irq_32.c | 32 ++++++++++++++++++++++++++------
|
||||
arch/sparc/kernel/leon_kernel.c | 8 +++++++-
|
||||
3 files changed, 37 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/arch/sparc/include/asm/irq_32.h
|
||||
+++ b/arch/sparc/include/asm/irq_32.h
|
||||
@@ -6,7 +6,11 @@
|
||||
#ifndef _SPARC_IRQ_H
|
||||
#define _SPARC_IRQ_H
|
||||
|
||||
+#ifdef CONFIG_SPARC_LEON
|
||||
+#define NR_IRQS 32
|
||||
+#else
|
||||
#define NR_IRQS 16
|
||||
+#endif
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
--- a/arch/sparc/kernel/irq_32.c
|
||||
+++ b/arch/sparc/kernel/irq_32.c
|
||||
@@ -110,6 +110,11 @@ EXPORT_SYMBOL(__raw_local_irq_save);
|
||||
EXPORT_SYMBOL(raw_local_irq_enable);
|
||||
EXPORT_SYMBOL(raw_local_irq_restore);
|
||||
|
||||
+#ifdef CONFIG_SPARC_LEON
|
||||
+extern unsigned int sparc_leon_eirq;
|
||||
+extern int sparc_leon_eirq_get(int eirq, int cpu);
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Dave Redman (djhr@tadpole.co.uk)
|
||||
*
|
||||
@@ -222,10 +227,11 @@ void free_irq(unsigned int irq, void *de
|
||||
return;
|
||||
}
|
||||
cpu_irq = irq & (NR_IRQS - 1);
|
||||
- if (cpu_irq > 14) { /* 14 irq levels on the sparc */
|
||||
- printk("Trying to free bogus IRQ %d\n", irq);
|
||||
- return;
|
||||
- }
|
||||
+ /* 14 irq levels on the sparc, however some LEON systems have 31 IRQs */
|
||||
+ if ((cpu_irq == 15) || (cpu_irq >= NR_IRQS)) {
|
||||
+ printk("Trying to free bogus IRQ %d\n", irq);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
spin_lock_irqsave(&irq_action_lock, flags);
|
||||
|
||||
@@ -303,7 +309,14 @@ void unexpected_irq(int irq, void *dev_i
|
||||
int i;
|
||||
struct irqaction * action;
|
||||
unsigned int cpu_irq;
|
||||
-
|
||||
+
|
||||
+#ifdef CONFIG_SPARC_LEON
|
||||
+ /* LEON Extended IRQ requires one extra IRQ Number fetch stage */
|
||||
+ if ( sparc_leon_eirq == irq ) {
|
||||
+ irq = sparc_leon_eirq_get(irq, smp_processor_id());
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
cpu_irq = irq & (NR_IRQS - 1);
|
||||
action = sparc_irq[cpu_irq].action;
|
||||
|
||||
@@ -330,6 +343,13 @@ void handler_irq(int irq, struct pt_regs
|
||||
extern void smp4m_irq_rotate(int cpu);
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_SPARC_LEON
|
||||
+ /* LEON Extended IRQ requires one extra IRQ Number fetch stage */
|
||||
+ if ( sparc_leon_eirq == irq ) {
|
||||
+ irq = sparc_leon_eirq_get(irq, cpu);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
old_regs = set_irq_regs(regs);
|
||||
irq_enter();
|
||||
disable_pil_irq(irq);
|
||||
@@ -526,7 +546,7 @@ int request_irq(unsigned int irq,
|
||||
return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
|
||||
}
|
||||
cpu_irq = irq & (NR_IRQS - 1);
|
||||
- if(cpu_irq > 14) {
|
||||
+ if(cpu_irq == 15) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
--- a/arch/sparc/kernel/leon_kernel.c
|
||||
+++ b/arch/sparc/kernel/leon_kernel.c
|
||||
@@ -104,7 +104,7 @@ static void leon_disable_irq(unsigned in
|
||||
|
||||
void __init leon_init_timers(irq_handler_t counter_fn)
|
||||
{
|
||||
- int irq;
|
||||
+ int irq, eirq;
|
||||
struct device_node *rootnp, *np;
|
||||
struct property *pp;
|
||||
int len;
|
||||
@@ -153,6 +153,12 @@ void __init leon_init_timers(irq_handler
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
|
||||
# endif
|
||||
|
||||
+ LEON3_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mask[0]), 0);
|
||||
+ eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus) >> 16) & 0xf;
|
||||
+ if ( eirq != 0 ) {
|
||||
+ /* Extended IRQ controller available */
|
||||
+ sparc_leon_eirq_register(eirq);
|
||||
+ }
|
||||
} else {
|
||||
printk(KERN_ERR "No Timer/irqctrl found\n");
|
||||
BUG();
|
|
@ -0,0 +1,58 @@
|
|||
From 486a578298b7ab45c3edfdce8d4feaef93c3229b Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Thu, 16 Sep 2010 11:15:37 +0200
|
||||
Subject: [PATCH] SPARC/LEON: to avoid name duplicates in openprom fs when REG is not available the NAME now includes NODE ID when REG not present
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/kernel/prom_32.c | 27 +++++++++++++++++++--------
|
||||
1 files changed, 19 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/arch/sparc/kernel/prom_32.c
|
||||
+++ b/arch/sparc/kernel/prom_32.c
|
||||
@@ -136,18 +136,29 @@ static void __init ebus_path_component(s
|
||||
/* "name:vendor:device@irq,addrlo" */
|
||||
static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf)
|
||||
{
|
||||
- struct amba_prom_registers *regs; unsigned int *intr;
|
||||
- unsigned int *device, *vendor;
|
||||
+ struct amba_prom_registers *regs;
|
||||
+ unsigned int *intr, *device, *vendor, reg0;
|
||||
struct property *prop;
|
||||
+ int interrupt = 0;
|
||||
|
||||
+ /* In order to get a unique ID in the device tree (multiple AMBA devices
|
||||
+ * may have the same name) the node number is printed
|
||||
+ */
|
||||
prop = of_find_property(dp, "reg", NULL);
|
||||
- if (!prop)
|
||||
- return;
|
||||
- regs = prop->value;
|
||||
+ if (!prop) {
|
||||
+ reg0 = (unsigned int)dp->phandle;
|
||||
+ } else {
|
||||
+ regs = prop->value;
|
||||
+ reg0 = regs->phys_addr;
|
||||
+ }
|
||||
+
|
||||
+ /* Not all cores have Interrupt */
|
||||
prop = of_find_property(dp, "interrupts", NULL);
|
||||
if (!prop)
|
||||
- return;
|
||||
- intr = prop->value;
|
||||
+ intr = &interrupt; /* IRQ0 does not exist */
|
||||
+ else
|
||||
+ intr = prop->value;
|
||||
+
|
||||
prop = of_find_property(dp, "vendor", NULL);
|
||||
if (!prop)
|
||||
return;
|
||||
@@ -159,7 +170,7 @@ static void __init ambapp_path_component
|
||||
|
||||
sprintf(tmp_buf, "%s:%d:%d@%x,%x",
|
||||
dp->name, *vendor, *device,
|
||||
- *intr, regs->phys_addr);
|
||||
+ *intr, reg0);
|
||||
}
|
||||
|
||||
static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
|
|
@ -0,0 +1,85 @@
|
|||
From 25a68b8cd8ea1553f8b56278418d6c1ecc12e247 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 22 Sep 2010 10:19:34 +0200
|
||||
Subject: [PATCH] SPARC/LEON: added support for AMP systems with IRQAMP IRQ Controller.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/include/asm/leon.h | 12 ++++++++++++
|
||||
arch/sparc/include/asm/leon_amba.h | 6 +++---
|
||||
arch/sparc/kernel/leon_kernel.c | 14 ++++++++++++++
|
||||
3 files changed, 29 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/sparc/include/asm/leon.h
|
||||
+++ b/arch/sparc/include/asm/leon.h
|
||||
@@ -224,6 +224,18 @@ static inline void sparc_leon3_disable_c
|
||||
"sta %%l2, [%%g0] 2\n\t" : : : "l1", "l2");
|
||||
};
|
||||
|
||||
+static inline unsigned long sparc_leon3_asr17(void)
|
||||
+{
|
||||
+ u32 asr17;
|
||||
+ __asm__ __volatile__ ("rd %%asr17, %0\n\t" : "=r"(asr17));
|
||||
+ return asr17;
|
||||
+};
|
||||
+
|
||||
+static inline int sparc_leon3_cpuid(void)
|
||||
+{
|
||||
+ return sparc_leon3_asr17() >> 28;
|
||||
+}
|
||||
+
|
||||
#endif /*!__ASSEMBLY__*/
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
--- a/arch/sparc/include/asm/leon_amba.h
|
||||
+++ b/arch/sparc/include/asm/leon_amba.h
|
||||
@@ -100,9 +100,8 @@ struct leon3_irqctrl_regs_map {
|
||||
u32 mpbroadcast;
|
||||
u32 notused02;
|
||||
u32 notused03;
|
||||
- u32 notused10;
|
||||
- u32 notused11;
|
||||
- u32 notused12;
|
||||
+ u32 ampctrl;
|
||||
+ u32 icsel[2];
|
||||
u32 notused13;
|
||||
u32 notused20;
|
||||
u32 notused21;
|
||||
@@ -112,6 +111,7 @@ struct leon3_irqctrl_regs_map {
|
||||
u32 force[16];
|
||||
/* Extended IRQ registers */
|
||||
u32 intid[16]; /* 0xc0 */
|
||||
+ u32 unused[(0x1000-0x100)/4];
|
||||
};
|
||||
|
||||
struct leon3_apbuart_regs_map {
|
||||
--- a/arch/sparc/kernel/leon_kernel.c
|
||||
+++ b/arch/sparc/kernel/leon_kernel.c
|
||||
@@ -108,6 +108,7 @@ void __init leon_init_timers(irq_handler
|
||||
struct device_node *rootnp, *np;
|
||||
struct property *pp;
|
||||
int len;
|
||||
+ int cpu, icsel;
|
||||
|
||||
leondebug_irq_disable = 0;
|
||||
leon_debug_irqout = 0;
|
||||
@@ -153,6 +154,19 @@ void __init leon_init_timers(irq_handler
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
|
||||
# endif
|
||||
|
||||
+ /* The IRQ controller may (if implemented) consist of multiple
|
||||
+ * IRQ controllers, each mapped on a 4Kb boundary.
|
||||
+ * Each CPU may be routed to different IRQCTRLs, however
|
||||
+ * we assume that all CPUs (in SMP system) is routed to the
|
||||
+ * same IRQ Controller, and for non-SMP only one IRQCTRL is
|
||||
+ * accessed anyway.
|
||||
+ * In AMP systems, Linux may not be run on CPU0.
|
||||
+ */
|
||||
+ cpu = sparc_leon3_cpuid();
|
||||
+ icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]);
|
||||
+ icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf;
|
||||
+ leon3_irqctrl_regs += icsel;
|
||||
+
|
||||
LEON3_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mask[0]), 0);
|
||||
eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus) >> 16) & 0xf;
|
||||
if ( eirq != 0 ) {
|
|
@ -0,0 +1,119 @@
|
|||
From 1dffe06838c26b7c3fc99f9ddb7db78e378f6908 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 22 Sep 2010 13:21:13 +0200
|
||||
Subject: [PATCH] SPARC/LEON: added support for selecting Timer Core and Timer within core, useful for AMP systems.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/kernel/leon_kernel.c | 41 +++++++++++++++++++++++++-------------
|
||||
1 files changed, 27 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/arch/sparc/kernel/leon_kernel.c
|
||||
+++ b/arch/sparc/kernel/leon_kernel.c
|
||||
@@ -23,15 +23,16 @@
|
||||
#include "prom.h"
|
||||
#include "irq.h"
|
||||
|
||||
-struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address, initialized by amba_init() */
|
||||
-struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address, initialized by amba_init() */
|
||||
+struct leon3_irqctrl_regs_map *leon3_irqctrl_regs = NULL; /* interrupt controller base address, initialized by amba_init() */
|
||||
+struct leon3_gptimer_regs_map *leon3_gptimer_regs = NULL; /* timer controller base address, initialized by amba_init() */
|
||||
struct amba_apb_device leon_percpu_timer_dev[16];
|
||||
|
||||
int leondebug_irq_disable;
|
||||
int leon_debug_irqout;
|
||||
static int dummy_master_l10_counter;
|
||||
|
||||
-unsigned long leon3_gptimer_irq; /* interrupt controller irq number, initialized by amba_init() */
|
||||
+unsigned long leon3_gptimer_irq = 0; /* interrupt controller irq number, initialized by amba_init() */
|
||||
+unsigned long leon3_gptimer_idx = 0; /* Timer Index (starting at 0) with Timer Core */
|
||||
unsigned int sparc_leon_eirq;
|
||||
#define LEON_IMASK ((&leon3_irqctrl_regs->mask[0]))
|
||||
|
||||
@@ -109,6 +110,7 @@ void __init leon_init_timers(irq_handler
|
||||
struct property *pp;
|
||||
int len;
|
||||
int cpu, icsel;
|
||||
+ int ampopts;
|
||||
|
||||
leondebug_irq_disable = 0;
|
||||
leon_debug_irqout = 0;
|
||||
@@ -124,24 +126,35 @@ void __init leon_init_timers(irq_handler
|
||||
}
|
||||
|
||||
/* Find GPTIMER Timer Registers base address otherwise bail out. */
|
||||
- if (rootnp && (np=of_find_node_by_name(rootnp, "GAISLER_GPTIMER"))) {
|
||||
+ np = rootnp;
|
||||
+ while (np && (np=of_find_node_by_name(np, "GAISLER_GPTIMER"))) {
|
||||
+ ampopts = 0;
|
||||
+ pp = of_find_property(np, "ampopts", &len);
|
||||
+ if ( pp && ((ampopts = *(int *)pp->value) == 0) ) {
|
||||
+ /* Skip this instance, resource already allocated by other OS */
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Select Timer-Instance on Timer Core. Default is zero */
|
||||
+ leon3_gptimer_idx = ampopts & 0x7;
|
||||
+
|
||||
pp = of_find_property(np, "reg", &len);
|
||||
if (pp)
|
||||
leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **)pp->value;
|
||||
pp = of_find_property(np, "interrupts", &len);
|
||||
if (pp)
|
||||
leon3_gptimer_irq = *(unsigned int *)pp->value;
|
||||
+ break;
|
||||
}
|
||||
|
||||
if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) {
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0);
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld,
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
|
||||
(((1000000 / 100) - 1)));
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0);
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs;
|
||||
- leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1;
|
||||
+ leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1+leon3_gptimer_idx;
|
||||
|
||||
if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
|
||||
(1<<LEON3_GPTIMER_SEPIRQ))) {
|
||||
@@ -149,9 +162,9 @@ void __init leon_init_timers(irq_handler
|
||||
BUG();
|
||||
}
|
||||
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0);
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/100) - 1)));
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0);
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0);
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, (((1000000/100) - 1)));
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0);
|
||||
# endif
|
||||
|
||||
/* The IRQ controller may (if implemented) consist of multiple
|
||||
@@ -178,7 +191,7 @@ void __init leon_init_timers(irq_handler
|
||||
BUG();
|
||||
}
|
||||
|
||||
- irq = request_irq(leon3_gptimer_irq,
|
||||
+ irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx,
|
||||
counter_fn,
|
||||
(IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
|
||||
|
||||
@@ -210,13 +223,13 @@ void __init leon_init_timers(irq_handler
|
||||
# endif
|
||||
|
||||
if (leon3_gptimer_regs) {
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl,
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
|
||||
LEON3_GPTIMER_EN |
|
||||
LEON3_GPTIMER_RL |
|
||||
LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl,
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
|
||||
LEON3_GPTIMER_EN |
|
||||
LEON3_GPTIMER_RL |
|
||||
LEON3_GPTIMER_LD |
|
|
@ -0,0 +1,30 @@
|
|||
From e4d697dad4d43109f045a4f25cb1d706122045c0 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 22 Sep 2010 13:24:36 +0200
|
||||
Subject: [PATCH] SPARC/LEON: removed constant timer initialization as if HZ=100, now it reflects the value of HZ
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/kernel/leon_kernel.c | 4 ++--
|
||||
1 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/sparc/kernel/leon_kernel.c
|
||||
+++ b/arch/sparc/kernel/leon_kernel.c
|
||||
@@ -149,7 +149,7 @@ void __init leon_init_timers(irq_handler
|
||||
if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) {
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
|
||||
- (((1000000 / 100) - 1)));
|
||||
+ (((1000000 / HZ) - 1)));
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
@@ -163,7 +163,7 @@ void __init leon_init_timers(irq_handler
|
||||
}
|
||||
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0);
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, (((1000000/100) - 1)));
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, (((1000000 / HZ) - 1)));
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0);
|
||||
# endif
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
From 300f3ee36c3019ee36f81befd91cd1b32544cefe Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 22 Sep 2010 15:39:05 +0200
|
||||
Subject: [PATCH] SPARC/LEON: Removed the need for two timers, per-cpu ticker is shared with system clock timer.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/include/asm/leon.h | 2 +-
|
||||
arch/sparc/include/asm/leon_amba.h | 3 +-
|
||||
arch/sparc/kernel/entry.S | 3 +-
|
||||
arch/sparc/kernel/leon_kernel.c | 37 ++++++++---------------------------
|
||||
arch/sparc/kernel/leon_smp.c | 8 ++++++-
|
||||
5 files changed, 21 insertions(+), 32 deletions(-)
|
||||
|
||||
--- a/arch/sparc/include/asm/leon.h
|
||||
+++ b/arch/sparc/include/asm/leon.h
|
||||
@@ -240,7 +240,7 @@ static inline int sparc_leon3_cpuid(void
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
# define LEON3_IRQ_RESCHEDULE 13
|
||||
-# define LEON3_IRQ_TICKER (leon_percpu_timer_dev[0].irq)
|
||||
+# define LEON3_IRQ_TICKER (leon3_gptimer_irq + leon3_gptimer_idx)
|
||||
# define LEON3_IRQ_CROSS_CALL 15
|
||||
#endif
|
||||
|
||||
--- a/arch/sparc/include/asm/leon_amba.h
|
||||
+++ b/arch/sparc/include/asm/leon_amba.h
|
||||
@@ -182,11 +182,12 @@ void _amba_init(struct device_node *dp,
|
||||
|
||||
extern struct leon3_irqctrl_regs_map *leon3_irqctrl_regs;
|
||||
extern struct leon3_gptimer_regs_map *leon3_gptimer_regs;
|
||||
-extern struct amba_apb_device leon_percpu_timer_dev[16];
|
||||
extern int leondebug_irq_disable;
|
||||
extern int leon_debug_irqout;
|
||||
extern unsigned long leon3_gptimer_irq;
|
||||
+extern unsigned long leon3_gptimer_idx; /* Timer Index (starting at 0) with Timer Core */
|
||||
extern unsigned int sparc_leon_eirq;
|
||||
+extern unsigned long leon3_cpu_idx;
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
--- a/arch/sparc/kernel/entry.S
|
||||
+++ b/arch/sparc/kernel/entry.S
|
||||
@@ -411,8 +411,9 @@ smpleon_ticker:
|
||||
WRITE_PAUSE
|
||||
wr %g2, PSR_ET, %psr
|
||||
WRITE_PAUSE
|
||||
+ mov %l7, %o0 ! irq level
|
||||
call leon_percpu_timer_interrupt
|
||||
- add %sp, STACKFRAME_SZ, %o0
|
||||
+ add %sp, STACKFRAME_SZ, %o1 ! pt_regs
|
||||
wr %l0, PSR_ET, %psr
|
||||
WRITE_PAUSE
|
||||
RESTORE_ALL
|
||||
--- a/arch/sparc/kernel/leon_kernel.c
|
||||
+++ b/arch/sparc/kernel/leon_kernel.c
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
struct leon3_irqctrl_regs_map *leon3_irqctrl_regs = NULL; /* interrupt controller base address, initialized by amba_init() */
|
||||
struct leon3_gptimer_regs_map *leon3_gptimer_regs = NULL; /* timer controller base address, initialized by amba_init() */
|
||||
-struct amba_apb_device leon_percpu_timer_dev[16];
|
||||
|
||||
int leondebug_irq_disable;
|
||||
int leon_debug_irqout;
|
||||
@@ -34,6 +33,7 @@ static int dummy_master_l10_counter;
|
||||
unsigned long leon3_gptimer_irq = 0; /* interrupt controller irq number, initialized by amba_init() */
|
||||
unsigned long leon3_gptimer_idx = 0; /* Timer Index (starting at 0) with Timer Core */
|
||||
unsigned int sparc_leon_eirq;
|
||||
+unsigned long leon3_cpu_idx = 0; /* Boot CPU Index */
|
||||
#define LEON_IMASK ((&leon3_irqctrl_regs->mask[0]))
|
||||
|
||||
/* Return the IRQ of the pending IRQ on the extended IRQ controller */
|
||||
@@ -109,13 +109,14 @@ void __init leon_init_timers(irq_handler
|
||||
struct device_node *rootnp, *np;
|
||||
struct property *pp;
|
||||
int len;
|
||||
- int cpu, icsel;
|
||||
+ int icsel;
|
||||
int ampopts;
|
||||
|
||||
leondebug_irq_disable = 0;
|
||||
leon_debug_irqout = 0;
|
||||
master_l10_counter = (unsigned int *)&dummy_master_l10_counter;
|
||||
dummy_master_l10_counter = 0;
|
||||
+ leon3_cpu_idx = sparc_leon3_cpuid();
|
||||
|
||||
/* Find IRQMP IRQ Controller Registers base address otherwise bail out. */
|
||||
rootnp = of_find_node_by_path("/ambapp0");
|
||||
@@ -152,21 +153,11 @@ void __init leon_init_timers(irq_handler
|
||||
(((1000000 / HZ) - 1)));
|
||||
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);
|
||||
|
||||
-#ifdef CONFIG_SMP
|
||||
- leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs;
|
||||
- leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1+leon3_gptimer_idx;
|
||||
-
|
||||
if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
|
||||
(1<<LEON3_GPTIMER_SEPIRQ))) {
|
||||
- prom_printf("irq timer not configured with separate irqs\n");
|
||||
- BUG();
|
||||
+ prom_printf("LEON-SMP: GPTIMER use shared irqs, using other timers will fail.\n");
|
||||
}
|
||||
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0);
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, (((1000000 / HZ) - 1)));
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0);
|
||||
-# endif
|
||||
-
|
||||
/* The IRQ controller may (if implemented) consist of multiple
|
||||
* IRQ controllers, each mapped on a 4Kb boundary.
|
||||
* Each CPU may be routed to different IRQCTRLs, however
|
||||
@@ -175,9 +166,8 @@ void __init leon_init_timers(irq_handler
|
||||
* accessed anyway.
|
||||
* In AMP systems, Linux may not be run on CPU0.
|
||||
*/
|
||||
- cpu = sparc_leon3_cpuid();
|
||||
- icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]);
|
||||
- icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf;
|
||||
+ icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[leon3_cpu_idx/8]);
|
||||
+ icsel = (icsel >> ((7 - (leon3_cpu_idx & 0x7)) * 4)) & 0xf;
|
||||
leon3_irqctrl_regs += icsel;
|
||||
|
||||
LEON3_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mask[0]), 0);
|
||||
@@ -204,7 +194,8 @@ void __init leon_init_timers(irq_handler
|
||||
# ifdef CONFIG_SMP
|
||||
{
|
||||
unsigned long flags;
|
||||
- struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)];
|
||||
+ struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 +
|
||||
+ (leon3_gptimer_irq + leon3_gptimer_idx - 1)];
|
||||
|
||||
/* For SMP we use the level 14 ticker, however the bootup code
|
||||
* has copied the firmwares level 14 vector into boot cpu's
|
||||
@@ -222,21 +213,11 @@ void __init leon_init_timers(irq_handler
|
||||
}
|
||||
# endif
|
||||
|
||||
- if (leon3_gptimer_regs) {
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
|
||||
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
|
||||
LEON3_GPTIMER_EN |
|
||||
LEON3_GPTIMER_RL |
|
||||
LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN);
|
||||
|
||||
-#ifdef CONFIG_SMP
|
||||
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
|
||||
- LEON3_GPTIMER_EN |
|
||||
- LEON3_GPTIMER_RL |
|
||||
- LEON3_GPTIMER_LD |
|
||||
- LEON3_GPTIMER_IRQEN);
|
||||
-#endif
|
||||
-
|
||||
- }
|
||||
}
|
||||
|
||||
void leon_clear_clock_irq(void)
|
||||
--- a/arch/sparc/kernel/leon_smp.c
|
||||
+++ b/arch/sparc/kernel/leon_smp.c
|
||||
@@ -52,6 +52,7 @@ extern volatile unsigned long cpu_callin
|
||||
extern unsigned char boot_cpu_id;
|
||||
extern cpumask_t smp_commenced_mask;
|
||||
void __init leon_configure_cache_smp(void);
|
||||
+extern void handler_irq(int irq, struct pt_regs * regs);
|
||||
|
||||
static inline unsigned long do_swap(volatile unsigned long *ptr,
|
||||
unsigned long val)
|
||||
@@ -385,7 +386,7 @@ void leon_cross_call_irq(void)
|
||||
ccall_info.processors_out[i] = 1;
|
||||
}
|
||||
|
||||
-void leon_percpu_timer_interrupt(struct pt_regs *regs)
|
||||
+void leon_percpu_timer_interrupt(int irq, struct pt_regs *regs)
|
||||
{
|
||||
struct pt_regs *old_regs;
|
||||
int cpu = smp_processor_id();
|
||||
@@ -406,6 +407,11 @@ void leon_percpu_timer_interrupt(struct
|
||||
prof_counter(cpu) = prof_multiplier(cpu);
|
||||
}
|
||||
set_irq_regs(old_regs);
|
||||
+
|
||||
+ if ( cpu == leon3_cpu_idx ) {
|
||||
+ /* Ticker Clock is shared with the System Clock */
|
||||
+ handler_irq(irq, regs);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void __init smp_setup_percpu_timer(void)
|
|
@ -0,0 +1,41 @@
|
|||
From 8129fa5437f3fe5f95bac180a43cd5a856cebdf3 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 20 Oct 2010 17:00:41 +0200
|
||||
Subject: [PATCH] Added support for ampopts in APBUART driver. Used in AMP systems.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/serial/apbuart.c | 5 ++++-
|
||||
1 files changed, 4 insertions(+), 1 deletions(-)
|
||||
|
||||
--- a/drivers/serial/apbuart.c
|
||||
+++ b/drivers/serial/apbuart.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
+#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/serial_core.h>
|
||||
@@ -573,7 +574,6 @@ static int __devinit apbuart_probe(struc
|
||||
printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n",
|
||||
(unsigned long long) port->mapbase, port->irq);
|
||||
return 0;
|
||||
-
|
||||
}
|
||||
|
||||
static struct of_device_id __initdata apbuart_match[] = {
|
||||
@@ -620,9 +620,12 @@ static void grlib_apbuart_configure(void
|
||||
int *vendor = (int *) of_get_property(np, "vendor", NULL);
|
||||
int *device = (int *) of_get_property(np, "device", NULL);
|
||||
int *irqs = (int *) of_get_property(np, "interrupts", NULL);
|
||||
+ int *ampopts = (int *) of_get_property(np, "ampopts", NULL);
|
||||
regs = (struct amba_prom_registers *)
|
||||
of_get_property(np, "reg", NULL);
|
||||
|
||||
+ if (ampopts && (*ampopts == 0))
|
||||
+ continue; /* Ignore if used by another OS instance */
|
||||
if (vendor)
|
||||
v = *vendor;
|
||||
if (device)
|
|
@ -0,0 +1,21 @@
|
|||
From 3d7788e8f5ae3d44e48f9b7476528acf3d9c8b32 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 20 Oct 2010 17:07:12 +0200
|
||||
Subject: [PATCH] GRETH: Fixed potential future problem where unhandled IRQ is cleared.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 2 +-
|
||||
1 files changed, 1 insertions(+), 1 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -584,7 +584,7 @@ static irqreturn_t greth_interrupt(int i
|
||||
if (status & (GRETH_INT_RX | GRETH_INT_TX)) {
|
||||
|
||||
/* Clear interrupt status */
|
||||
- GRETH_REGORIN(greth->regs->status,
|
||||
+ GRETH_REGSAVE(greth->regs->status,
|
||||
status & (GRETH_INT_RX | GRETH_INT_TX));
|
||||
|
||||
retval = IRQ_HANDLED;
|
|
@ -0,0 +1,22 @@
|
|||
From ff5f2ee8b37f2278dd86946761313c3664c51836 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Thu, 21 Oct 2010 14:34:48 +0200
|
||||
Subject: [PATCH] GRETH: added raw AMBA vendor/device number to match against.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 3 +++
|
||||
1 files changed, 3 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -1600,6 +1600,9 @@ static struct of_device_id greth_of_matc
|
||||
{
|
||||
.name = "GAISLER_ETHMAC",
|
||||
},
|
||||
+ {
|
||||
+ .name = "01_01d",
|
||||
+ },
|
||||
{},
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
From 1c14b8995c1b8212180b5009dc04ac222a449ecb Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Thu, 21 Oct 2010 14:35:09 +0200
|
||||
Subject: [PATCH] APBUART: added raw AMBA vendor/device number to match against.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/serial/apbuart.c | 3 +++
|
||||
1 files changed, 3 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/drivers/serial/apbuart.c
|
||||
+++ b/drivers/serial/apbuart.c
|
||||
@@ -580,6 +580,9 @@ static struct of_device_id __initdata ap
|
||||
{
|
||||
.name = "GAISLER_APBUART",
|
||||
},
|
||||
+ {
|
||||
+ .name = "01_00c",
|
||||
+ },
|
||||
{},
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
From 12782c44d0c687b5b0400a8224a9b1bf9eb9a428 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Tue, 26 Oct 2010 09:59:05 +0200
|
||||
Subject: [PATCH] TIMER,IRQCTRL: added raw AMBA vendor/device number to match against.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/kernel/leon_kernel.c | 6 ++++--
|
||||
1 files changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/arch/sparc/kernel/leon_kernel.c
|
||||
+++ b/arch/sparc/kernel/leon_kernel.c
|
||||
@@ -120,7 +120,8 @@ void __init leon_init_timers(irq_handler
|
||||
|
||||
/* Find IRQMP IRQ Controller Registers base address otherwise bail out. */
|
||||
rootnp = of_find_node_by_path("/ambapp0");
|
||||
- if (rootnp && (np=of_find_node_by_name(rootnp, "GAISLER_IRQMP"))) {
|
||||
+ if (rootnp && ((np=of_find_node_by_name(rootnp, "GAISLER_IRQMP")) ||
|
||||
+ (np=of_find_node_by_name(rootnp, "01_00d")))) {
|
||||
pp = of_find_property(np, "reg", &len);
|
||||
if (pp)
|
||||
leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value;
|
||||
@@ -128,7 +129,8 @@ void __init leon_init_timers(irq_handler
|
||||
|
||||
/* Find GPTIMER Timer Registers base address otherwise bail out. */
|
||||
np = rootnp;
|
||||
- while (np && (np=of_find_node_by_name(np, "GAISLER_GPTIMER"))) {
|
||||
+ while (np && ((np=of_find_node_by_name(np, "GAISLER_GPTIMER")) ||
|
||||
+ (np=of_find_node_by_name(np, "01_011")))) {
|
||||
ampopts = 0;
|
||||
pp = of_find_property(np, "ampopts", &len);
|
||||
if ( pp && ((ampopts = *(int *)pp->value) == 0) ) {
|
|
@ -0,0 +1,296 @@
|
|||
From c6d8f92cfd7f4f19eb3b16545b3b68c561978fe8 Mon Sep 17 00:00:00 2001
|
||||
From: Kristoffer Glembo <kristoffer@gaisler.com>
|
||||
Date: Mon, 7 Jun 2010 14:00:30 +0200
|
||||
Subject: [PATCH] sparc32: Added LEON dma_ops.
|
||||
|
||||
Added leon3_dma_ops and mmu_inval_dma_area.
|
||||
---
|
||||
arch/sparc/kernel/ioport.c | 139 +++++++++++++++++++++++++++++++------------
|
||||
1 files changed, 100 insertions(+), 39 deletions(-)
|
||||
|
||||
--- a/arch/sparc/kernel/ioport.c
|
||||
+++ b/arch/sparc/kernel/ioport.c
|
||||
@@ -50,10 +50,15 @@
|
||||
#include <asm/io-unit.h>
|
||||
#include <asm/leon.h>
|
||||
|
||||
-#ifdef CONFIG_SPARC_LEON
|
||||
-#define mmu_inval_dma_area(p, l) leon_flush_dcache_all()
|
||||
-#else
|
||||
+#ifndef CONFIG_SPARC_LEON
|
||||
#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
|
||||
+#else
|
||||
+static inline void mmu_inval_dma_area(unsigned long va, unsigned long len)
|
||||
+{
|
||||
+ if (!sparc_leon3_snooping_enabled()) {
|
||||
+ leon_flush_dcache_all();
|
||||
+ }
|
||||
+}
|
||||
#endif
|
||||
|
||||
static struct resource *_sparc_find_resource(struct resource *r,
|
||||
@@ -254,7 +259,7 @@ static void *sbus_alloc_coherent(struct
|
||||
dma_addr_t *dma_addrp, gfp_t gfp)
|
||||
{
|
||||
struct platform_device *op = to_platform_device(dev);
|
||||
- unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
|
||||
+ unsigned long len_total = PAGE_ALIGN(len);
|
||||
unsigned long va;
|
||||
struct resource *res;
|
||||
int order;
|
||||
@@ -287,15 +292,19 @@ static void *sbus_alloc_coherent(struct
|
||||
* XXX That's where sdev would be used. Currently we load
|
||||
* all iommu tables with the same translations.
|
||||
*/
|
||||
- if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0)
|
||||
- goto err_noiommu;
|
||||
-
|
||||
- res->name = op->dev.of_node->name;
|
||||
+#ifdef CONFIG_SPARC_LEON
|
||||
+ sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);
|
||||
+ *dma_addrp = virt_to_phys(va);
|
||||
+#else
|
||||
+ if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) {
|
||||
+ release_resource(res);
|
||||
+ goto err_nova;
|
||||
+ }
|
||||
+#endif
|
||||
+ res->name = op->node->name;
|
||||
|
||||
return (void *)(unsigned long)res->start;
|
||||
|
||||
-err_noiommu:
|
||||
- release_resource(res);
|
||||
err_nova:
|
||||
free_pages(va, order);
|
||||
err_nomem:
|
||||
@@ -321,7 +330,7 @@ static void sbus_free_coherent(struct de
|
||||
return;
|
||||
}
|
||||
|
||||
- n = (n + PAGE_SIZE-1) & PAGE_MASK;
|
||||
+ n = PAGE_ALIGN(n);
|
||||
if ((res->end-res->start)+1 != n) {
|
||||
printk("sbus_free_consistent: region 0x%lx asked 0x%zx\n",
|
||||
(long)((res->end-res->start)+1), n);
|
||||
@@ -333,7 +342,12 @@ static void sbus_free_coherent(struct de
|
||||
|
||||
/* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
|
||||
pgv = virt_to_page(p);
|
||||
- mmu_unmap_dma_area(dev, ba, n);
|
||||
+
|
||||
+#ifdef CONFIG_SPARC_LEON
|
||||
+ sparc_unmapiorange((unsigned long)p, n);
|
||||
+#else
|
||||
+ mmu_unmap_dma_area(dev, ba, n);
|
||||
+#endif
|
||||
|
||||
__free_pages(pgv, get_order(n));
|
||||
}
|
||||
@@ -408,9 +422,6 @@ struct dma_map_ops sbus_dma_ops = {
|
||||
.sync_sg_for_device = sbus_sync_sg_for_device,
|
||||
};
|
||||
|
||||
-struct dma_map_ops *dma_ops = &sbus_dma_ops;
|
||||
-EXPORT_SYMBOL(dma_ops);
|
||||
-
|
||||
static int __init sparc_register_ioport(void)
|
||||
{
|
||||
register_proc_sparc_ioport();
|
||||
@@ -422,7 +433,7 @@ arch_initcall(sparc_register_ioport);
|
||||
|
||||
#endif /* CONFIG_SBUS */
|
||||
|
||||
-#ifdef CONFIG_PCI
|
||||
+#if defined(CONFIG_PCI) || defined(CONFIG_SPARC_LEON)
|
||||
|
||||
/* Allocate and map kernel buffer using consistent mode DMA for a device.
|
||||
* hwdev should be valid struct pci_dev pointer for PCI devices.
|
||||
@@ -430,7 +441,7 @@ arch_initcall(sparc_register_ioport);
|
||||
static void *pci32_alloc_coherent(struct device *dev, size_t len,
|
||||
dma_addr_t *pba, gfp_t gfp)
|
||||
{
|
||||
- unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK;
|
||||
+ unsigned long len_total = PAGE_ALIGN(len);
|
||||
unsigned long va;
|
||||
struct resource *res;
|
||||
int order;
|
||||
@@ -463,10 +474,6 @@ static void *pci32_alloc_coherent(struct
|
||||
return NULL;
|
||||
}
|
||||
mmu_inval_dma_area(va, len_total);
|
||||
-#if 0
|
||||
-/* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %lx\n",
|
||||
- (long)va, (long)res->start, (long)virt_to_phys(va), len_total);
|
||||
-#endif
|
||||
sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);
|
||||
|
||||
*pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */
|
||||
@@ -498,7 +505,7 @@ static void pci32_free_coherent(struct d
|
||||
return;
|
||||
}
|
||||
|
||||
- n = (n + PAGE_SIZE-1) & PAGE_MASK;
|
||||
+ n = PAGE_ALIGN(n);
|
||||
if ((res->end-res->start)+1 != n) {
|
||||
printk("pci_free_consistent: region 0x%lx asked 0x%lx\n",
|
||||
(long)((res->end-res->start)+1), (long)n);
|
||||
@@ -515,6 +522,14 @@ static void pci32_free_coherent(struct d
|
||||
free_pages(pgp, get_order(n));
|
||||
}
|
||||
|
||||
+static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
|
||||
+ enum dma_data_direction dir, struct dma_attrs *attrs)
|
||||
+{
|
||||
+ if (dir != PCI_DMA_TODEVICE) {
|
||||
+ mmu_inval_dma_area((unsigned long)phys_to_virt(ba), PAGE_ALIGN(size));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Same as pci_map_single, but with pages.
|
||||
*/
|
||||
@@ -551,8 +566,7 @@ static int pci32_map_sg(struct device *d
|
||||
|
||||
/* IIep is write-through, not flushing. */
|
||||
for_each_sg(sgl, sg, nents, n) {
|
||||
- BUG_ON(page_address(sg_page(sg)) == NULL);
|
||||
- sg->dma_address = virt_to_phys(sg_virt(sg));
|
||||
+ sg->dma_address = sg_phys(sg);
|
||||
sg->dma_length = sg->length;
|
||||
}
|
||||
return nents;
|
||||
@@ -571,10 +585,7 @@ static void pci32_unmap_sg(struct device
|
||||
|
||||
if (dir != PCI_DMA_TODEVICE) {
|
||||
for_each_sg(sgl, sg, nents, n) {
|
||||
- BUG_ON(page_address(sg_page(sg)) == NULL);
|
||||
- mmu_inval_dma_area(
|
||||
- (unsigned long) page_address(sg_page(sg)),
|
||||
- (sg->length + PAGE_SIZE-1) & PAGE_MASK);
|
||||
+ mmu_inval_dma_area((unsigned long)sg_virt(sg), PAGE_ALIGN(sg->length));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -594,7 +605,7 @@ static void pci32_sync_single_for_cpu(st
|
||||
{
|
||||
if (dir != PCI_DMA_TODEVICE) {
|
||||
mmu_inval_dma_area((unsigned long)phys_to_virt(ba),
|
||||
- (size + PAGE_SIZE-1) & PAGE_MASK);
|
||||
+ PAGE_ALIGN(size));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,10 +632,7 @@ static void pci32_sync_sg_for_cpu(struct
|
||||
|
||||
if (dir != PCI_DMA_TODEVICE) {
|
||||
for_each_sg(sgl, sg, nents, n) {
|
||||
- BUG_ON(page_address(sg_page(sg)) == NULL);
|
||||
- mmu_inval_dma_area(
|
||||
- (unsigned long) page_address(sg_page(sg)),
|
||||
- (sg->length + PAGE_SIZE-1) & PAGE_MASK);
|
||||
+ mmu_inval_dma_area((unsigned long)sg_virt(sg), PAGE_ALIGN(sg->length));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,18 +645,38 @@ static void pci32_sync_sg_for_device(str
|
||||
|
||||
if (dir != PCI_DMA_TODEVICE) {
|
||||
for_each_sg(sgl, sg, nents, n) {
|
||||
- BUG_ON(page_address(sg_page(sg)) == NULL);
|
||||
- mmu_inval_dma_area(
|
||||
- (unsigned long) page_address(sg_page(sg)),
|
||||
- (sg->length + PAGE_SIZE-1) & PAGE_MASK);
|
||||
+ mmu_inval_dma_area((unsigned long)sg_virt(sg), PAGE_ALIGN(sg->length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+/* LEON3 unmapping functions
|
||||
+ *
|
||||
+ * We can only invalidate the whole cache so unmap_page and unmap_sg do the same thing
|
||||
+ */
|
||||
+static void leon3_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
|
||||
+ enum dma_data_direction dir, struct dma_attrs *attrs)
|
||||
+{
|
||||
+ if (dir != PCI_DMA_TODEVICE) {
|
||||
+ mmu_inval_dma_area(0, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void leon3_unmap_sg(struct device *dev, struct scatterlist *sgl,
|
||||
+ int nents, enum dma_data_direction dir,
|
||||
+ struct dma_attrs *attrs)
|
||||
+{
|
||||
+
|
||||
+ if (dir != PCI_DMA_TODEVICE) {
|
||||
+ mmu_inval_dma_area(0, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
struct dma_map_ops pci32_dma_ops = {
|
||||
.alloc_coherent = pci32_alloc_coherent,
|
||||
.free_coherent = pci32_free_coherent,
|
||||
.map_page = pci32_map_page,
|
||||
+ .unmap_page = pci32_unmap_page,
|
||||
.map_sg = pci32_map_sg,
|
||||
.unmap_sg = pci32_unmap_sg,
|
||||
.sync_single_for_cpu = pci32_sync_single_for_cpu,
|
||||
@@ -658,7 +686,30 @@ struct dma_map_ops pci32_dma_ops = {
|
||||
};
|
||||
EXPORT_SYMBOL(pci32_dma_ops);
|
||||
|
||||
-#endif /* CONFIG_PCI */
|
||||
+struct dma_map_ops leon3_dma_ops = {
|
||||
+ .alloc_coherent = sbus_alloc_coherent,
|
||||
+ .free_coherent = sbus_free_coherent,
|
||||
+ .map_page = pci32_map_page,
|
||||
+ .unmap_page = leon3_unmap_page,
|
||||
+ .map_sg = pci32_map_sg,
|
||||
+ .unmap_sg = leon3_unmap_sg,
|
||||
+ .sync_single_for_cpu = pci32_sync_single_for_cpu,
|
||||
+ .sync_single_for_device = pci32_sync_single_for_device,
|
||||
+ .sync_sg_for_cpu = pci32_sync_sg_for_cpu,
|
||||
+ .sync_sg_for_device = pci32_sync_sg_for_device,
|
||||
+};
|
||||
+
|
||||
+#endif /* CONFIG_PCI || CONFIG_SPARC_LEON */
|
||||
+
|
||||
+#ifdef CONFIG_SPARC_LEON
|
||||
+struct dma_map_ops *dma_ops = &leon3_dma_ops;
|
||||
+#else
|
||||
+struct dma_map_ops *dma_ops = &sbus_dma_ops;
|
||||
+#endif
|
||||
+
|
||||
+#ifdef CONFIG_SBUS
|
||||
+EXPORT_SYMBOL(dma_ops);
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* Return whether the given PCI device DMA address mask can be
|
||||
@@ -676,6 +727,16 @@ int dma_supported(struct device *dev, u6
|
||||
}
|
||||
EXPORT_SYMBOL(dma_supported);
|
||||
|
||||
+int dma_set_mask(struct device *dev, u64 dma_mask)
|
||||
+{
|
||||
+#ifdef CONFIG_PCI
|
||||
+ if (dev->bus == &pci_bus_type)
|
||||
+ return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
|
||||
+#endif
|
||||
+ return -EOPNOTSUPP;
|
||||
+}
|
||||
+EXPORT_SYMBOL(dma_set_mask);
|
||||
+
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static int sparc_io_proc_show(struct seq_file *m, void *v)
|
||||
@@ -717,7 +778,7 @@ static const struct file_operations spar
|
||||
static struct resource *_sparc_find_resource(struct resource *root,
|
||||
unsigned long hit)
|
||||
{
|
||||
- struct resource *tmp;
|
||||
+ struct resource *tmp;
|
||||
|
||||
for (tmp = root->child; tmp != 0; tmp = tmp->sibling) {
|
||||
if (tmp->start <= hit && tmp->end >= hit)
|
|
@ -0,0 +1,51 @@
|
|||
From 36cad96a50eb877d0c5cb3d8d93c1807ad9c774c Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 09:37:23 +0100
|
||||
Subject: [PATCH] Fix kristoffers ioport.c patch for more recent kernel.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
arch/sparc/include/asm/dma-mapping.h | 13 +------------
|
||||
arch/sparc/kernel/ioport.c | 3 ++-
|
||||
2 files changed, 3 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/arch/sparc/include/asm/dma-mapping.h
|
||||
+++ b/arch/sparc/include/asm/dma-mapping.h
|
||||
@@ -51,17 +51,6 @@ static inline int dma_mapping_error(stru
|
||||
return (dma_addr == DMA_ERROR_CODE);
|
||||
}
|
||||
|
||||
-static inline int dma_set_mask(struct device *dev, u64 mask)
|
||||
-{
|
||||
-#ifdef CONFIG_PCI
|
||||
- if (dev->bus == &pci_bus_type) {
|
||||
- if (!dev->dma_mask || !dma_supported(dev, mask))
|
||||
- return -EINVAL;
|
||||
- *dev->dma_mask = mask;
|
||||
- return 0;
|
||||
- }
|
||||
-#endif
|
||||
- return -EINVAL;
|
||||
-}
|
||||
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
|
||||
|
||||
#endif
|
||||
--- a/arch/sparc/kernel/ioport.c
|
||||
+++ b/arch/sparc/kernel/ioport.c
|
||||
@@ -301,7 +301,7 @@ static void *sbus_alloc_coherent(struct
|
||||
goto err_nova;
|
||||
}
|
||||
#endif
|
||||
- res->name = op->node->name;
|
||||
+ res->name = op->dev.of_node->name;
|
||||
|
||||
return (void *)(unsigned long)res->start;
|
||||
|
||||
@@ -737,6 +737,7 @@ int dma_set_mask(struct device *dev, u64
|
||||
}
|
||||
EXPORT_SYMBOL(dma_set_mask);
|
||||
|
||||
+
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static int sparc_io_proc_show(struct seq_file *m, void *v)
|
|
@ -0,0 +1,66 @@
|
|||
From 2e864d18c31d4e0255269f9e9cfccc09512676c6 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 16:51:38 +0100
|
||||
Subject: [PATCH] GRETH: added greth_no_gbit option
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 15 +++++++++++++--
|
||||
drivers/net/greth.h | 1 +
|
||||
2 files changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -66,6 +66,10 @@ static int greth_edcl = 1;
|
||||
module_param(greth_edcl, int, 0);
|
||||
MODULE_PARM_DESC(greth_edcl, "GRETH EDCL usage indicator. Set to 1 if EDCL is used.");
|
||||
|
||||
+static int no_gbit = 0;
|
||||
+module_param(no_gbit, int, S_IRUGO);
|
||||
+MODULE_PARM_DESC(no_gbit, "GRETH report GBit not supported by MAC enable. Only affects GRETH GBit MAC, default 0 (off).");
|
||||
+
|
||||
static int greth_open(struct net_device *dev);
|
||||
static netdev_tx_t greth_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
@@ -1284,7 +1288,7 @@ static int greth_mdio_probe(struct net_d
|
||||
}
|
||||
|
||||
ret = phy_connect_direct(dev, phy, &greth_link_change,
|
||||
- 0, greth->gbit_mac ?
|
||||
+ 0, greth->gbit_phy_support ?
|
||||
PHY_INTERFACE_MODE_GMII :
|
||||
PHY_INTERFACE_MODE_MII);
|
||||
if (ret) {
|
||||
@@ -1293,7 +1297,7 @@ static int greth_mdio_probe(struct net_d
|
||||
return ret;
|
||||
}
|
||||
|
||||
- if (greth->gbit_mac)
|
||||
+ if (greth->gbit_phy_support)
|
||||
phy->supported &= PHY_GBIT_FEATURES;
|
||||
else
|
||||
phy->supported &= PHY_BASIC_FEATURES;
|
||||
@@ -1441,6 +1445,13 @@ static int __devinit greth_of_probe(stru
|
||||
tmp = GRETH_REGLOAD(regs->control);
|
||||
greth->gbit_mac = (tmp >> 27) & 1;
|
||||
|
||||
+ /* Let user skip GBit link mode by telling MDIO layer that MAC does
|
||||
+ * not support GBIT (for debug) */
|
||||
+ if (greth->gbit_mac && !no_gbit)
|
||||
+ greth->gbit_phy_support = 1;
|
||||
+ else
|
||||
+ greth->gbit_phy_support = 0;
|
||||
+
|
||||
/* Check for multicast capability */
|
||||
greth->multicast = (tmp >> 25) & 1;
|
||||
|
||||
--- a/drivers/net/greth.h
|
||||
+++ b/drivers/net/greth.h
|
||||
@@ -138,6 +138,7 @@ struct greth_private {
|
||||
u8 gbit_mac;
|
||||
u8 mdio_int_en;
|
||||
u8 edcl;
|
||||
+ u8 gbit_phy_support;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
From a498d7076ee0f82ec3f508293a9cf1ccba15829e Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 16:52:19 +0100
|
||||
Subject: [PATCH] GRETH: added greth_compat_mode module parameter
|
||||
|
||||
The greth_compat_mode option can be used to set a GRETH GBit capable MAC
|
||||
in operate as if the GRETH 10/100 device was found. The GRETH GBit supports
|
||||
TCP/UDP checksum offloading, unaligned frame buffers, scatter gather etc.
|
||||
Enabling this mode allows the developer to test the GRETH 10/100 device
|
||||
without all features mentioned above on a GBit MAC capable of the above.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 9 +++++++++
|
||||
1 files changed, 9 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -70,6 +70,11 @@ static int no_gbit = 0;
|
||||
module_param(no_gbit, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(no_gbit, "GRETH report GBit not supported by MAC enable. Only affects GRETH GBit MAC, default 0 (off).");
|
||||
|
||||
+/* Use this option to enable GRETH 10/100 code on GRETH_GBIT hardware (debug legacy code option) */
|
||||
+static int compat_mode = 0;
|
||||
+module_param(compat_mode, int, S_IRUGO);
|
||||
+MODULE_PARM_DESC(compat_mode, "GRETH 10/100 legacy mode enable. Only affects GRETH GBit MAC, default 0 (off).");
|
||||
+
|
||||
static int greth_open(struct net_device *dev);
|
||||
static netdev_tx_t greth_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
@@ -1452,6 +1457,10 @@ static int __devinit greth_of_probe(stru
|
||||
else
|
||||
greth->gbit_phy_support = 0;
|
||||
|
||||
+ /* Force GBit MAC in legacy 10/100 mode (no offloading etc.) */
|
||||
+ if (compat_mode == 1)
|
||||
+ greth->gbit_mac = 0;
|
||||
+
|
||||
/* Check for multicast capability */
|
||||
greth->multicast = (tmp >> 25) & 1;
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
From 6216bc809c5bdd586b14d096fbaf6dc25574b928 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 09:59:14 +0100
|
||||
Subject: [PATCH] GRETH: fix opening/closing
|
||||
|
||||
When NAPI is disabled there is no point in having IRQs enabled, TX/RX
|
||||
should be off before clearing the TX/RX descriptor rings.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 4 ++++
|
||||
1 files changed, 4 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -365,6 +365,8 @@ static int greth_open(struct net_device
|
||||
dev_dbg(&dev->dev, " starting queue\n");
|
||||
netif_start_queue(dev);
|
||||
|
||||
+ GRETH_REGSAVE(greth->regs->status, 0xFF);
|
||||
+
|
||||
napi_enable(&greth->napi);
|
||||
|
||||
greth_enable_irqs(greth);
|
||||
@@ -380,7 +382,9 @@ static int greth_close(struct net_device
|
||||
|
||||
napi_disable(&greth->napi);
|
||||
|
||||
+ greth_disable_irqs(greth);
|
||||
greth_disable_tx(greth);
|
||||
+ greth_disable_rx(greth);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
From 544631281bed5cc37b8f2d3a99f44c9d4b97f9a8 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 10:07:12 +0100
|
||||
Subject: [PATCH] GRETH: GBit transmit descriptor handling optimization
|
||||
|
||||
It is safe to enable all fragments before enabling the first descriptor,
|
||||
this way all descriptors don't have to be processed twice, added extra
|
||||
memory barrier.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 19 ++++++++++---------
|
||||
1 files changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -512,7 +512,7 @@ greth_start_xmit_gbit(struct sk_buff *sk
|
||||
greth->tx_skbuff[curr_tx] = NULL;
|
||||
bdp = greth->tx_bd_base + curr_tx;
|
||||
|
||||
- status = GRETH_TXBD_CSALL;
|
||||
+ status = GRETH_TXBD_CSALL | GRETH_BD_EN;
|
||||
status |= frag->size & GRETH_BD_LEN;
|
||||
|
||||
/* Wrap around descriptor ring */
|
||||
@@ -549,26 +549,27 @@ greth_start_xmit_gbit(struct sk_buff *sk
|
||||
|
||||
wmb();
|
||||
|
||||
- /* Enable the descriptors that we configured ... */
|
||||
- for (i = 0; i < nr_frags + 1; i++) {
|
||||
- bdp = greth->tx_bd_base + greth->tx_next;
|
||||
- greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
|
||||
- greth->tx_next = NEXT_TX(greth->tx_next);
|
||||
- greth->tx_free--;
|
||||
- }
|
||||
+ /* Enable the descriptor chain by enabling the first descriptor */
|
||||
+ bdp = greth->tx_bd_base + greth->tx_next;
|
||||
+ greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
|
||||
+ greth->tx_next = curr_tx;
|
||||
+ greth->tx_free -= nr_frags + 1;
|
||||
+
|
||||
+ wmb();
|
||||
|
||||
greth_enable_tx(greth);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
frag_map_error:
|
||||
- /* Unmap SKB mappings that succeeded */
|
||||
+ /* Unmap SKB mappings that succeeded and disable descriptor */
|
||||
for (i = 0; greth->tx_next + i != curr_tx; i++) {
|
||||
bdp = greth->tx_bd_base + greth->tx_next + i;
|
||||
dma_unmap_single(greth->dev,
|
||||
greth_read_bd(&bdp->addr),
|
||||
greth_read_bd(&bdp->stat) & GRETH_BD_LEN,
|
||||
DMA_TO_DEVICE);
|
||||
+ greth_write_bd(&bdp->stat, 0);
|
||||
}
|
||||
map_error:
|
||||
if (net_ratelimit())
|
|
@ -0,0 +1,49 @@
|
|||
From 54789a03adf9c924d0cf7b890323c9c1ca7ab042 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 10:26:09 +0100
|
||||
Subject: [PATCH] GRETH: fixed skb buffer memory leak on frame errors
|
||||
|
||||
A new SKB buffer should not be allocated when the old SKB is reused.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 17 +++++++++++------
|
||||
1 files changed, 11 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -879,10 +879,8 @@ static int greth_rx_gbit(struct net_devi
|
||||
}
|
||||
}
|
||||
|
||||
- /* Allocate new skb to replace current */
|
||||
- newskb = netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN);
|
||||
-
|
||||
- if (!bad && newskb) {
|
||||
+ /* Allocate new skb to replace current, not needed if the current skb can be reused */
|
||||
+ if (!bad && (newskb=netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN))) {
|
||||
skb_reserve(newskb, NET_IP_ALIGN);
|
||||
|
||||
dma_addr = dma_map_single(greth->dev,
|
||||
@@ -919,12 +917,19 @@ static int greth_rx_gbit(struct net_devi
|
||||
if (net_ratelimit())
|
||||
dev_warn(greth->dev, "Could not create DMA mapping, dropping packet\n");
|
||||
dev_kfree_skb(newskb);
|
||||
- dev->stats.rx_dropped++;
|
||||
+ dev->stats.rx_dropped++; /* reusing current skb, so it is a drop */
|
||||
}
|
||||
+ } else if ( bad ) {
|
||||
+ /* Bad Frame transfer, the skb is reused */
|
||||
+ dev->stats.rx_dropped++;
|
||||
} else {
|
||||
+ /* Failed Allocating a new skb. This is rather stupid but the current "filled"
|
||||
+ * skb is reused, as if transfer failure. One could argue that RX descriptor table
|
||||
+ * handling should be divided into cleaning and filling as the TX part of the driver
|
||||
+ */
|
||||
if (net_ratelimit())
|
||||
dev_warn(greth->dev, "Could not allocate SKB, dropping packet\n");
|
||||
- dev->stats.rx_dropped++;
|
||||
+ dev->stats.rx_dropped++; /* reusing current skb, so it is a drop */
|
||||
}
|
||||
|
||||
status = GRETH_BD_EN | GRETH_BD_IE;
|
|
@ -0,0 +1,50 @@
|
|||
From c2e963057ca5635d6e5387623c3ad0c0b3123754 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 10:28:37 +0100
|
||||
Subject: [PATCH] GRETH: avoid writing bad speed/duplex when setting transfer mode
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 19 ++++++++-----------
|
||||
1 files changed, 8 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -1236,29 +1236,26 @@ static void greth_link_change(struct net
|
||||
struct greth_private *greth = netdev_priv(dev);
|
||||
struct phy_device *phydev = greth->phy;
|
||||
unsigned long flags;
|
||||
-
|
||||
int status_change = 0;
|
||||
+ u32 ctrl;
|
||||
|
||||
spin_lock_irqsave(&greth->devlock, flags);
|
||||
|
||||
if (phydev->link) {
|
||||
|
||||
if ((greth->speed != phydev->speed) || (greth->duplex != phydev->duplex)) {
|
||||
-
|
||||
- GRETH_REGANDIN(greth->regs->control,
|
||||
- ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB));
|
||||
+ ctrl = GRETH_REGLOAD(greth->regs->control) &
|
||||
+ ~(GRETH_CTRL_FD | GRETH_CTRL_SP | GRETH_CTRL_GB);
|
||||
|
||||
if (phydev->duplex)
|
||||
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_FD);
|
||||
-
|
||||
- if (phydev->speed == SPEED_100) {
|
||||
-
|
||||
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_SP);
|
||||
- }
|
||||
+ ctrl |= GRETH_CTRL_FD;
|
||||
|
||||
+ if (phydev->speed == SPEED_100)
|
||||
+ ctrl |= GRETH_CTRL_SP;
|
||||
else if (phydev->speed == SPEED_1000)
|
||||
- GRETH_REGORIN(greth->regs->control, GRETH_CTRL_GB);
|
||||
+ ctrl |= GRETH_CTRL_GB;
|
||||
|
||||
+ GRETH_REGSAVE(greth->regs->control, ctrl);
|
||||
greth->speed = phydev->speed;
|
||||
greth->duplex = phydev->duplex;
|
||||
status_change = 1;
|
|
@ -0,0 +1,49 @@
|
|||
From f62c047af910c9c9696db7b47472a3728b8100e8 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 11:56:22 +0100
|
||||
Subject: [PATCH] GRETH: handle frame error interrupts
|
||||
|
||||
Not handling frame error interrupts are unlikly but may lead to dead
|
||||
lock if 128 error frames are recieved in a row.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 5 +++--
|
||||
drivers/net/greth.h | 2 ++
|
||||
2 files changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -595,11 +595,12 @@ static irqreturn_t greth_interrupt(int i
|
||||
status = GRETH_REGLOAD(greth->regs->status);
|
||||
|
||||
/* Handle rx and tx interrupts through poll */
|
||||
- if (status & (GRETH_INT_RX | GRETH_INT_TX)) {
|
||||
+ if (status & (GRETH_INT_RE | GRETH_INT_RX | GRETH_INT_TE | GRETH_INT_TX)) {
|
||||
|
||||
/* Clear interrupt status */
|
||||
GRETH_REGSAVE(greth->regs->status,
|
||||
- status & (GRETH_INT_RX | GRETH_INT_TX));
|
||||
+ status & (GRETH_INT_RE | GRETH_INT_RX |
|
||||
+ GRETH_INT_TE | GRETH_INT_TX));
|
||||
|
||||
retval = IRQ_HANDLED;
|
||||
|
||||
--- a/drivers/net/greth.h
|
||||
+++ b/drivers/net/greth.h
|
||||
@@ -23,6 +23,7 @@
|
||||
#define GRETH_BD_LEN 0x7FF
|
||||
|
||||
#define GRETH_TXEN 0x1
|
||||
+#define GRETH_INT_TE 0x2
|
||||
#define GRETH_INT_TX 0x8
|
||||
#define GRETH_TXI 0x4
|
||||
#define GRETH_TXBD_STATUS 0x0001C000
|
||||
@@ -35,6 +36,7 @@
|
||||
#define GRETH_TXBD_ERR_UE 0x4000
|
||||
#define GRETH_TXBD_ERR_AL 0x8000
|
||||
|
||||
+#define GRETH_INT_RE 0x1
|
||||
#define GRETH_INT_RX 0x4
|
||||
#define GRETH_RXEN 0x2
|
||||
#define GRETH_RXI 0x8
|
|
@ -0,0 +1,399 @@
|
|||
From 4439d933884ee3c7e320b8d33bd2e268dd5b6fa5 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 11:40:19 +0100
|
||||
Subject: [PATCH] GRETH: resolve SMP issues and other problems
|
||||
|
||||
Fixes the following:
|
||||
1. POLL should not enable IRQ when work is not completed
|
||||
2. No locking between TX descriptor cleaning and XMIT descriptor handling
|
||||
3. No locking between RX POLL and XMIT modifying control register
|
||||
4. Since TX cleaning (called from POLL) is running in parallel with XMIT
|
||||
unnecessary locking is needed.
|
||||
5. IRQ handler looks at RX frame status solely, this is wrong when IRQ is
|
||||
temporarily disabled (in POLL), and when IRQ is shared.
|
||||
6. IRQ handler clears IRQ status, which is unnecessary
|
||||
7. TX queue was stopped in preventing cause when not MAX_SKB_FRAGS+1 descriptors
|
||||
were available after a SKB been scheduled by XMIT. Instead the TX queue is
|
||||
stopped first when not enough descriptors are available upon entering XMIT.
|
||||
|
||||
It was hard to split up this patch in smaller pieces since all are tied
|
||||
together somehow.
|
||||
|
||||
Note the RX flag used in the interrupt handler does not signal that interrtupt
|
||||
was asserted, but that a frame was received. Same goes for TX. Also, IRQ is not
|
||||
asserted when the RX flag is set before enabling IRQ enable until a new frame is
|
||||
received. So extra care must be taken to avoid enabling IRQ and all descriptors
|
||||
are already used, hence dead lock will upon us. See new POLL implementation that
|
||||
enableds IRQ then look at the RX flag to determine if one or more IRQs may have
|
||||
been missed. TX/RX flags are cleared before handling previously enabled
|
||||
descriptors, this ensures that the RX/TX flags are valid when determining if IRQ
|
||||
should be turned on again.
|
||||
|
||||
By moving TX cleaning from POLL to XMIT in the standard case, removes some
|
||||
locking trouble. Enabling TX cleaning from poll only when not enough TX
|
||||
descriptors are available is safe because the TX queue is at the same time
|
||||
stopped, thus XMIT will not be called. The TX queue is woken up again when
|
||||
enough descriptrs are available.
|
||||
|
||||
TX Frames are always enabled with IRQ, however the TX IRQ Enable flag will not
|
||||
be enabled until XMIT must wait for free descriptors.
|
||||
|
||||
Locking RX and XMIT parts of the driver from each other is needed because the
|
||||
RX/TX enable bits share the same register.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 158 ++++++++++++++++++++++++++++++---------------------
|
||||
1 files changed, 93 insertions(+), 65 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
|
||||
*
|
||||
- * 2005-2009 (c) Aeroflex Gaisler AB
|
||||
+ * 2005-2010 (c) Aeroflex Gaisler AB
|
||||
*
|
||||
* This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
|
||||
* available in the GRLIB VHDL IP core library.
|
||||
@@ -401,12 +401,20 @@ greth_start_xmit(struct sk_buff *skb, st
|
||||
struct greth_private *greth = netdev_priv(dev);
|
||||
struct greth_bd *bdp;
|
||||
int err = NETDEV_TX_OK;
|
||||
- u32 status, dma_addr;
|
||||
+ u32 status, dma_addr, ctrl;
|
||||
+ unsigned long flags;
|
||||
|
||||
- bdp = greth->tx_bd_base + greth->tx_next;
|
||||
+ /* Clean TX Ring */
|
||||
+ greth_clean_tx(greth->netdev);
|
||||
|
||||
if (unlikely(greth->tx_free <= 0)) {
|
||||
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
|
||||
+ ctrl = GRETH_REGLOAD(greth->regs->control);
|
||||
+ /* Enable TX IRQ only if not already in poll() routine */
|
||||
+ if ( ctrl & GRETH_RXI )
|
||||
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
|
||||
netif_stop_queue(dev);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
@@ -419,13 +427,14 @@ greth_start_xmit(struct sk_buff *skb, st
|
||||
goto out;
|
||||
}
|
||||
|
||||
+ bdp = greth->tx_bd_base + greth->tx_next;
|
||||
dma_addr = greth_read_bd(&bdp->addr);
|
||||
|
||||
memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);
|
||||
|
||||
dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);
|
||||
|
||||
- status = GRETH_BD_EN | (skb->len & GRETH_BD_LEN);
|
||||
+ status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
|
||||
|
||||
/* Wrap around descriptor ring */
|
||||
if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
|
||||
@@ -435,22 +444,11 @@ greth_start_xmit(struct sk_buff *skb, st
|
||||
greth->tx_next = NEXT_TX(greth->tx_next);
|
||||
greth->tx_free--;
|
||||
|
||||
- /* No more descriptors */
|
||||
- if (unlikely(greth->tx_free == 0)) {
|
||||
-
|
||||
- /* Free transmitted descriptors */
|
||||
- greth_clean_tx(dev);
|
||||
-
|
||||
- /* If nothing was cleaned, stop queue & wait for irq */
|
||||
- if (unlikely(greth->tx_free == 0)) {
|
||||
- status |= GRETH_BD_IE;
|
||||
- netif_stop_queue(dev);
|
||||
- }
|
||||
- }
|
||||
-
|
||||
/* Write descriptor control word and enable transmission */
|
||||
greth_write_bd(&bdp->stat, status);
|
||||
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
|
||||
greth_enable_tx(greth);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
@@ -463,13 +461,24 @@ greth_start_xmit_gbit(struct sk_buff *sk
|
||||
{
|
||||
struct greth_private *greth = netdev_priv(dev);
|
||||
struct greth_bd *bdp;
|
||||
- u32 status = 0, dma_addr;
|
||||
+ u32 status = 0, dma_addr, ctrl;
|
||||
int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
|
||||
+ unsigned long flags;
|
||||
|
||||
nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
|
||||
+ /* Clean TX Ring */
|
||||
+ greth_clean_tx_gbit(dev);
|
||||
+
|
||||
if (greth->tx_free < nr_frags + 1) {
|
||||
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
|
||||
+ ctrl = GRETH_REGLOAD(greth->regs->control);
|
||||
+ /* Enable TX IRQ only if not already in poll() routine */
|
||||
+ if ( ctrl & GRETH_RXI ) {
|
||||
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
|
||||
+ }
|
||||
netif_stop_queue(dev);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
err = NETDEV_TX_BUSY;
|
||||
goto out;
|
||||
}
|
||||
@@ -522,14 +531,8 @@ greth_start_xmit_gbit(struct sk_buff *sk
|
||||
/* More fragments left */
|
||||
if (i < nr_frags - 1)
|
||||
status |= GRETH_TXBD_MORE;
|
||||
-
|
||||
- /* ... last fragment, check if out of descriptors */
|
||||
- else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {
|
||||
-
|
||||
- /* Enable interrupts and stop queue */
|
||||
- status |= GRETH_BD_IE;
|
||||
- netif_stop_queue(dev);
|
||||
- }
|
||||
+ else
|
||||
+ status |= GRETH_BD_IE; /* enable IRQ on last fragment */
|
||||
|
||||
greth_write_bd(&bdp->stat, status);
|
||||
|
||||
@@ -557,7 +560,9 @@ greth_start_xmit_gbit(struct sk_buff *sk
|
||||
|
||||
wmb();
|
||||
|
||||
+ spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
|
||||
greth_enable_tx(greth);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
@@ -579,12 +584,11 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
-
|
||||
static irqreturn_t greth_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct net_device *dev = dev_id;
|
||||
struct greth_private *greth;
|
||||
- u32 status;
|
||||
+ u32 status, ctrl;
|
||||
irqreturn_t retval = IRQ_NONE;
|
||||
|
||||
greth = netdev_priv(dev);
|
||||
@@ -594,13 +598,14 @@ static irqreturn_t greth_interrupt(int i
|
||||
/* Get the interrupt events that caused us to be here. */
|
||||
status = GRETH_REGLOAD(greth->regs->status);
|
||||
|
||||
- /* Handle rx and tx interrupts through poll */
|
||||
- if (status & (GRETH_INT_RE | GRETH_INT_RX | GRETH_INT_TE | GRETH_INT_TX)) {
|
||||
+ /* Must see if interrupts are enabled also, INT_TX|INT_RX flags may be set regardless
|
||||
+ * of whether IRQ is enabled or not. Especially important when shared IRQ.
|
||||
+ */
|
||||
+ ctrl = GRETH_REGLOAD(greth->regs->control);
|
||||
|
||||
- /* Clear interrupt status */
|
||||
- GRETH_REGSAVE(greth->regs->status,
|
||||
- status & (GRETH_INT_RE | GRETH_INT_RX |
|
||||
- GRETH_INT_TE | GRETH_INT_TX));
|
||||
+ /* Handle rx and tx interrupts through poll */
|
||||
+ if (((status & (GRETH_INT_RE | GRETH_INT_RX)) && (ctrl & GRETH_RXI)) ||
|
||||
+ ((status & (GRETH_INT_TE | GRETH_INT_TX)) && (ctrl & GRETH_TXI))) {
|
||||
|
||||
retval = IRQ_HANDLED;
|
||||
|
||||
@@ -625,6 +630,8 @@ static void greth_clean_tx(struct net_de
|
||||
|
||||
while (1) {
|
||||
bdp = greth->tx_bd_base + greth->tx_last;
|
||||
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
|
||||
+ mb();
|
||||
stat = greth_read_bd(&bdp->stat);
|
||||
|
||||
if (unlikely(stat & GRETH_BD_EN))
|
||||
@@ -685,7 +692,10 @@ static void greth_clean_tx_gbit(struct n
|
||||
|
||||
/* We only clean fully completed SKBs */
|
||||
bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
|
||||
- stat = bdp_last_frag->stat;
|
||||
+
|
||||
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
|
||||
+ mb();
|
||||
+ stat = greth_read_bd(&bdp_last_frag->stat);
|
||||
|
||||
if (stat & GRETH_BD_EN)
|
||||
break;
|
||||
@@ -717,23 +727,12 @@ static void greth_clean_tx_gbit(struct n
|
||||
greth->tx_free += nr_frags+1;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
- if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
|
||||
+
|
||||
+ if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS + 1))) {
|
||||
netif_wake_queue(dev);
|
||||
}
|
||||
}
|
||||
|
||||
-static int greth_pending_packets(struct greth_private *greth)
|
||||
-{
|
||||
- struct greth_bd *bdp;
|
||||
- u32 status;
|
||||
- bdp = greth->rx_bd_base + greth->rx_cur;
|
||||
- status = greth_read_bd(&bdp->stat);
|
||||
- if (status & GRETH_BD_EN)
|
||||
- return 0;
|
||||
- else
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
static int greth_rx(struct net_device *dev, int limit)
|
||||
{
|
||||
struct greth_private *greth;
|
||||
@@ -742,20 +741,24 @@ static int greth_rx(struct net_device *d
|
||||
int pkt_len;
|
||||
int bad, count;
|
||||
u32 status, dma_addr;
|
||||
+ unsigned long flags;
|
||||
|
||||
greth = netdev_priv(dev);
|
||||
|
||||
for (count = 0; count < limit; ++count) {
|
||||
|
||||
bdp = greth->rx_bd_base + greth->rx_cur;
|
||||
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
|
||||
+ mb();
|
||||
status = greth_read_bd(&bdp->stat);
|
||||
- dma_addr = greth_read_bd(&bdp->addr);
|
||||
- bad = 0;
|
||||
|
||||
if (unlikely(status & GRETH_BD_EN)) {
|
||||
break;
|
||||
}
|
||||
|
||||
+ dma_addr = greth_read_bd(&bdp->addr);
|
||||
+ bad = 0;
|
||||
+
|
||||
/* Check status for errors. */
|
||||
if (unlikely(status & GRETH_RXBD_STATUS)) {
|
||||
if (status & GRETH_RXBD_ERR_FT) {
|
||||
@@ -817,7 +820,9 @@ static int greth_rx(struct net_device *d
|
||||
|
||||
dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
+ spin_lock_irqsave(&greth->devlock, flags); /* save from XMIT */
|
||||
greth_enable_rx(greth);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
|
||||
greth->rx_cur = NEXT_RX(greth->rx_cur);
|
||||
}
|
||||
@@ -851,6 +856,7 @@ static int greth_rx_gbit(struct net_devi
|
||||
int pkt_len;
|
||||
int bad, count = 0;
|
||||
u32 status, dma_addr;
|
||||
+ unsigned long flags;
|
||||
|
||||
greth = netdev_priv(dev);
|
||||
|
||||
@@ -858,6 +864,8 @@ static int greth_rx_gbit(struct net_devi
|
||||
|
||||
bdp = greth->rx_bd_base + greth->rx_cur;
|
||||
skb = greth->rx_skbuff[greth->rx_cur];
|
||||
+ GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
|
||||
+ mb();
|
||||
status = greth_read_bd(&bdp->stat);
|
||||
bad = 0;
|
||||
|
||||
@@ -940,7 +948,9 @@ static int greth_rx_gbit(struct net_devi
|
||||
|
||||
wmb();
|
||||
greth_write_bd(&bdp->stat, status);
|
||||
+ spin_lock_irqsave(&greth->devlock, flags);
|
||||
greth_enable_rx(greth);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
greth->rx_cur = NEXT_RX(greth->rx_cur);
|
||||
}
|
||||
|
||||
@@ -952,15 +962,19 @@ static int greth_poll(struct napi_struct
|
||||
{
|
||||
struct greth_private *greth;
|
||||
int work_done = 0;
|
||||
+ unsigned long flags;
|
||||
+ u32 mask, ctrl;
|
||||
greth = container_of(napi, struct greth_private, napi);
|
||||
|
||||
- if (greth->gbit_mac) {
|
||||
- greth_clean_tx_gbit(greth->netdev);
|
||||
- } else {
|
||||
- greth_clean_tx(greth->netdev);
|
||||
+restart_txrx_poll:
|
||||
+ if ( netif_queue_stopped(greth->netdev) ) {
|
||||
+ if (greth->gbit_mac) {
|
||||
+ greth_clean_tx_gbit(greth->netdev);
|
||||
+ } else {
|
||||
+ greth_clean_tx(greth->netdev);
|
||||
+ }
|
||||
}
|
||||
|
||||
-restart_poll:
|
||||
if (greth->gbit_mac) {
|
||||
work_done += greth_rx_gbit(greth->netdev, budget - work_done);
|
||||
} else {
|
||||
@@ -969,15 +983,29 @@ restart_poll:
|
||||
|
||||
if (work_done < budget) {
|
||||
|
||||
- napi_complete(napi);
|
||||
+ spin_lock_irqsave(&greth->devlock, flags);
|
||||
|
||||
- if (greth_pending_packets(greth)) {
|
||||
- napi_reschedule(napi);
|
||||
- goto restart_poll;
|
||||
+ ctrl = GRETH_REGLOAD(greth->regs->control);
|
||||
+ if (netif_queue_stopped(greth->netdev)) {
|
||||
+ GRETH_REGSAVE(greth->regs->control,
|
||||
+ ctrl | GRETH_TXI | GRETH_RXI);
|
||||
+ mask = GRETH_INT_RX | GRETH_INT_RE |
|
||||
+ GRETH_INT_TX | GRETH_INT_TE;
|
||||
+ } else {
|
||||
+ GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_RXI);
|
||||
+ mask = GRETH_INT_RX | GRETH_INT_RE;
|
||||
+ }
|
||||
+
|
||||
+ if (GRETH_REGLOAD(greth->regs->status) & mask) {
|
||||
+ GRETH_REGSAVE(greth->regs->control, ctrl);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
+ goto restart_txrx_poll;
|
||||
+ } else {
|
||||
+ __napi_complete(napi);
|
||||
+ spin_unlock_irqrestore(&greth->devlock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
- greth_enable_irqs(greth);
|
||||
return work_done;
|
||||
}
|
||||
|
||||
@@ -1172,11 +1200,11 @@ static const struct ethtool_ops greth_et
|
||||
};
|
||||
|
||||
static struct net_device_ops greth_netdev_ops = {
|
||||
- .ndo_open = greth_open,
|
||||
- .ndo_stop = greth_close,
|
||||
- .ndo_start_xmit = greth_start_xmit,
|
||||
- .ndo_set_mac_address = greth_set_mac_add,
|
||||
- .ndo_validate_addr = eth_validate_addr,
|
||||
+ .ndo_open = greth_open,
|
||||
+ .ndo_stop = greth_close,
|
||||
+ .ndo_start_xmit = greth_start_xmit,
|
||||
+ .ndo_set_mac_address = greth_set_mac_add,
|
||||
+ .ndo_validate_addr = eth_validate_addr,
|
||||
};
|
||||
|
||||
static inline int wait_for_mdio(struct greth_private *greth)
|
|
@ -0,0 +1,25 @@
|
|||
From 66d5b37cc6d32291419bf99161e83e2946ea5f25 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 12:11:03 +0100
|
||||
Subject: [PATCH] GRETH: added option to disable a device node from bootloader.
|
||||
|
||||
Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
|
||||
---
|
||||
drivers/net/greth.c | 6 ++++++
|
||||
1 files changed, 6 insertions(+), 0 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -1428,6 +1428,12 @@ static int __devinit greth_of_probe(stru
|
||||
int err;
|
||||
int tmp;
|
||||
unsigned long timeout;
|
||||
+ int *ampopts;
|
||||
+
|
||||
+ /* Skip device if used by another OS instance */
|
||||
+ ampopts = (int *) of_get_property(ofdev->dev.of_node, "ampopts", NULL);
|
||||
+ if (ampopts && (*ampopts == 0))
|
||||
+ return -EIO;
|
||||
|
||||
dev = alloc_etherdev(sizeof(struct greth_private));
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
From 50fcb51c42bc721f18f1bfa10f705519cd344a2a Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Hellstrom <daniel@gaisler.com>
|
||||
Date: Wed, 1 Dec 2010 16:20:01 +0100
|
||||
Subject: [PATCH] GRETH: Newer GBit MACs need setting EE bit when EDCL should be enabled
|
||||
|
||||
---
|
||||
drivers/net/greth.c | 2 +-
|
||||
drivers/net/greth.h | 1 +
|
||||
2 files changed, 2 insertions(+), 1 deletions(-)
|
||||
|
||||
--- a/drivers/net/greth.c
|
||||
+++ b/drivers/net/greth.c
|
||||
@@ -1511,7 +1511,7 @@ static int __devinit greth_of_probe(stru
|
||||
/* If we have EDCL we disable the EDCL speed-duplex FSM so
|
||||
* it doesn't interfere with the software */
|
||||
if (greth->edcl != 0)
|
||||
- GRETH_REGORIN(regs->control, GRETH_CTRL_DISDUPLEX);
|
||||
+ GRETH_REGORIN(regs->control, GRETH_CTRL_DISDUPLEX|GRETH_CTRL_EE);
|
||||
|
||||
/* Check if MAC can handle MDIO interrupts */
|
||||
greth->mdio_int_en = (tmp >> 26) & 1;
|
||||
--- a/drivers/net/greth.h
|
||||
+++ b/drivers/net/greth.h
|
||||
@@ -15,6 +15,7 @@
|
||||
#define GRETH_CTRL_PSTATIEN 0x400
|
||||
#define GRETH_CTRL_MCEN 0x800
|
||||
#define GRETH_CTRL_DISDUPLEX 0x1000
|
||||
+#define GRETH_CTRL_EE 0x4000
|
||||
#define GRETH_STATUS_PHYSTAT 0x100
|
||||
|
||||
#define GRETH_BD_EN 0x800
|
Loading…
Reference in New Issue