Commit 311a5ffe authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] CRIS architecture update

From: "Mikael Starvik" <mikael.starvik@axis.com>

- Lots of fixes from 2.4.

- Updated for 2.6.6.

- Added IDE driver
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 772213c8
...@@ -27,19 +27,11 @@ menu "General setup" ...@@ -27,19 +27,11 @@ menu "General setup"
source "fs/Kconfig.binfmt" source "fs/Kconfig.binfmt"
config ETRAX_KGDB config ETRAX_CMDLINE
bool "Use kernel gdb debugger" string "Kernel command line"
---help--- default "root=/dev/mtdblock3"
The CRIS version of gdb can be used to remotely debug a running help
Linux kernel via the serial debug port. Provided you have gdb-cris Pass additional commands to the kernel.
installed, run gdb-cris vmlinux, then type
(gdb) set remotebaud 115200 <- kgdb uses 115200 as default
(gdb) target remote /dev/ttyS0 <- maybe you use another port
This should connect you to your booted kernel (or boot it now if you
didn't before). The kernel halts when it boots, waiting for gdb if
this option is turned on!
config ETRAX_WATCHDOG config ETRAX_WATCHDOG
bool "Enable ETRAX watchdog" bool "Enable ETRAX watchdog"
...@@ -99,11 +91,6 @@ config SVINTO_SIM ...@@ -99,11 +91,6 @@ config SVINTO_SIM
help help
Support the xsim ETRAX Simulator. Support the xsim ETRAX Simulator.
config ETRAX200LX
bool "ETRAX-200LX-V32"
help
Support CRIS V32.
endchoice endchoice
config ETRAX_ARCH_V10 config ETRAX_ARCH_V10
...@@ -111,11 +98,6 @@ config ETRAX_ARCH_V10 ...@@ -111,11 +98,6 @@ config ETRAX_ARCH_V10
default y if ETRAX100LX || ETRAX100LX_V2 default y if ETRAX100LX || ETRAX100LX_V2
default n if !(ETRAX100LX || ETRAX100LX_V2) default n if !(ETRAX100LX || ETRAX100LX_V2)
config ETRAX_ARCH_V32
bool
default y if ETRAX200LX
default n if !(ETRAX200LX)
config ETRAX_DRAM_SIZE config ETRAX_DRAM_SIZE
int "DRAM size (dec, in MB)" int "DRAM size (dec, in MB)"
default "8" default "8"
...@@ -128,35 +110,18 @@ config ETRAX_FLASH_BUSWIDTH ...@@ -128,35 +110,18 @@ config ETRAX_FLASH_BUSWIDTH
help help
Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. Width in bytes of the Flash bus (1, 2 or 4). Is usually 2.
config ETRAX_ROOT_DEVICE
string "Root device name"
default "/dev/mtdblock3"
help
Specifies the device that should be mounted as root file system
when booting from flash. The axisflashmap driver adds an additional
mtd partition for the appended root file system image, so this option
should normally be the mtdblock device for the partition after the
last partition in the partition table.
# duplicate choice configs are not yet supported, so the followinguse
# doesn't work:
source arch/cris/arch-v10/Kconfig source arch/cris/arch-v10/Kconfig
endmenu endmenu
# bring in ETRAX built-in drivers # bring in ETRAX built-in drivers
menu "Drivers for built-in interfaces" menu "Drivers for built-in interfaces"
source arch/cris/arch-v10/drivers/Kconfig source arch/cris/arch-v10/drivers/Kconfig
endmenu endmenu
source "drivers/base/Kconfig" source "drivers/base/Kconfig"
# bring in Etrax built-in drivers
source "arch/cris/drivers/Kconfig"
# standard linux drivers # standard linux drivers
source "drivers/mtd/Kconfig" source "drivers/mtd/Kconfig"
...@@ -212,6 +177,37 @@ config PROFILE_SHIFT ...@@ -212,6 +177,37 @@ config PROFILE_SHIFT
depends on PROFILE depends on PROFILE
default "2" default "2"
config ETRAX_KGDB
bool "Use kernel GDB debugger"
---help---
The CRIS version of gdb can be used to remotely debug a running
Linux kernel via the serial debug port. Provided you have gdb-cris
installed, run gdb-cris vmlinux, then type
(gdb) set remotebaud 115200 <- kgdb uses 115200 as default
(gdb) target remote /dev/ttyS0 <- maybe you use another port
This should connect you to your booted kernel (or boot it now if you
didn't before). The kernel halts when it boots, waiting for gdb if
this option is turned on!
config DEBUG_INFO
bool "Compile the kernel with debug info"
help
If you say Y here the resulting kernel image will include
debugging info resulting in a larger kernel image.
Say Y here only if you plan to use gdb to debug the kernel.
If you don't debug the kernel, you can say N.
config FRAME_POINTER
bool "Compile the kernel with frame pointers"
help
If you say Y here the resulting kernel image will be slightly larger
and slower, but it will give very useful debugging information.
If you don't debug the kernel, you can say N, but we may not be able
to solve problems without frame pointers.
endmenu endmenu
source "security/Kconfig" source "security/Kconfig"
......
# $Id: Makefile,v 1.15 2003/07/04 12:47:53 tobiasa Exp $ # $Id: Makefile,v 1.20 2004/05/14 14:35:58 orjanf Exp $
# cris/Makefile # cris/Makefile
# #
# This file is included by the global makefile so that you can add your own # This file is included by the global makefile so that you can add your own
...@@ -34,7 +34,7 @@ AFLAGS += -mlinux ...@@ -34,7 +34,7 @@ AFLAGS += -mlinux
CFLAGS := $(CFLAGS) -mlinux -march=$(arch-y) -pipe CFLAGS := $(CFLAGS) -mlinux -march=$(arch-y) -pipe
ifdef CONFIG_ETRAX_KGDB ifdef CONFIG_FRAME_POINTER
CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g
CFLAGS += -fno-omit-frame-pointer CFLAGS += -fno-omit-frame-pointer
endif endif
...@@ -90,10 +90,14 @@ prepare: arch/$(ARCH)/.links include/asm-$(ARCH)/.arch \ ...@@ -90,10 +90,14 @@ prepare: arch/$(ARCH)/.links include/asm-$(ARCH)/.arch \
# Create some links to make all tools happy # Create some links to make all tools happy
arch/$(ARCH)/.links: arch/$(ARCH)/.links:
@rm -rf arch/$(ARCH)/drivers
@ln -sfn $(SARCH)/drivers arch/$(ARCH)/drivers @ln -sfn $(SARCH)/drivers arch/$(ARCH)/drivers
@rm -rf arch/$(ARCH)/boot
@ln -sfn $(SARCH)/boot arch/$(ARCH)/boot @ln -sfn $(SARCH)/boot arch/$(ARCH)/boot
@rm -rf arch/$(ARCH)/lib
@ln -sfn $(SARCH)/lib arch/$(ARCH)/lib @ln -sfn $(SARCH)/lib arch/$(ARCH)/lib
@ln -sfn $(SARCH)/vmlinux.lds.S arch/$(ARCH)/kernel/vmlinux.lds.S @ln -sfn $(SARCH) arch/$(ARCH)/arch
@ln -sfn ../$(SARCH)/vmlinux.lds.S arch/$(ARCH)/kernel/vmlinux.lds.S
@touch $@ @touch $@
# Create link to sub arch includes # Create link to sub arch includes
......
/* /*
* misc.c * misc.c
* *
* $Id: misc.c,v 1.4 2003/04/09 05:20:45 starvik Exp $ * $Id: misc.c,v 1.6 2003/10/27 08:04:31 starvik Exp $
* *
* This is a collection of several routines from gzip-1.0.3 * This is a collection of several routines from gzip-1.0.3
* adapted for Linux. * adapted for Linux.
...@@ -263,7 +263,7 @@ decompress_kernel() ...@@ -263,7 +263,7 @@ decompress_kernel()
__asm__ volatile ("move vr,%0" : "=rm" (revision)); __asm__ volatile ("move vr,%0" : "=rm" (revision));
if (revision < 10) if (revision < 10)
{ {
puts("You need an ETRAX 100LX to run linux 2.4\n"); puts("You need an ETRAX 100LX to run linux 2.6\n");
while(1); while(1);
} }
......
...@@ -267,6 +267,7 @@ CONFIG_INET=y ...@@ -267,6 +267,7 @@ CONFIG_INET=y
# CONFIG_BLK_DEV_ISAPNP is not set # CONFIG_BLK_DEV_ISAPNP is not set
# CONFIG_IDE_CHIPSETS is not set # CONFIG_IDE_CHIPSETS is not set
# CONFIG_IDEDMA_AUTO is not set # CONFIG_IDEDMA_AUTO is not set
# CONFIG_BLK_DEV_IDE_MODES is not set
# #
# SCSI support # SCSI support
......
...@@ -11,29 +11,6 @@ config NET_ETHERNET ...@@ -11,29 +11,6 @@ config NET_ETHERNET
bool bool
depends on ETRAX_ETHERNET depends on ETRAX_ETHERNET
default y default y
---help---
Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
type of Local Area Network (LAN) in universities and companies.
Common varieties of Ethernet are: 10BASE-2 or Thinnet (10 Mbps over
coaxial cable, linking computers in a chain), 10BASE-T or twisted
pair (10 Mbps over twisted pair cable, linking computers to central
hubs), 10BASE-F (10 Mbps over optical fiber links, using hubs),
100BASE-TX (100 Mbps over two twisted pair cables, using hubs),
100BASE-T4 (100 Mbps over 4 standard voice-grade twisted pair
cables, using hubs), 100BASE-FX (100 Mbps over optical fiber links)
[the 100BASE varieties are also known as Fast Ethernet], and Gigabit
Ethernet (1 Gbps over optical fiber or short copper links).
If your Linux machine will be connected to an Ethernet and you have
an Ethernet network interface card (NIC) installed in your computer,
say Y here and read the Ethernet-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. You will then also have
to say Y to the driver for your particular NIC.
Note that the answer to this question won't directly affect the
kernel: saying N will just cause the configurator to skip all
the questions about Ethernet network cards. If unsure, say N.
choice choice
prompt "Network LED behavior" prompt "Network LED behavior"
...@@ -109,6 +86,32 @@ config ETRAX_SERIAL_PORT0 ...@@ -109,6 +86,32 @@ config ETRAX_SERIAL_PORT0
Normally you want this on, unless you use external DMA 1 that uses Normally you want this on, unless you use external DMA 1 that uses
the same DMA channels. the same DMA channels.
choice
prompt "Ser0 DMA out assignment"
depends on ETRAX_SERIAL_PORT0
default ETRAX_SERIAL_PORT0_DMA6_OUT
config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT
bool "No DMA out"
config CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
bool "DMA 6"
endchoice
choice
prompt "Ser0 DMA in assignment"
depends on ETRAX_SERIAL_PORT0
default ETRAX_SERIAL_PORT0_DMA7_IN
config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN
bool "No DMA in"
config CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
bool "DMA 7"
endchoice
choice choice
prompt "Ser0 DTR, RI, DSR and CD assignment" prompt "Ser0 DTR, RI, DSR and CD assignment"
depends on ETRAX_SERIAL_PORT0 depends on ETRAX_SERIAL_PORT0
...@@ -197,6 +200,32 @@ config ETRAX_SERIAL_PORT1 ...@@ -197,6 +200,32 @@ config ETRAX_SERIAL_PORT1
help help
Enables the ETRAX 100 serial driver for ser1 (ttyS1). Enables the ETRAX 100 serial driver for ser1 (ttyS1).
choice
prompt "Ser1 DMA out assignment"
depends on ETRAX_SERIAL_PORT1
default ETRAX_SERIAL_PORT1_DMA8_OUT
config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT
bool "No DMA out"
config CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
bool "DMA 8"
endchoice
choice
prompt "Ser1 DMA in assignment"
depends on ETRAX_SERIAL_PORT1
default ETRAX_SERIAL_PORT1_DMA9_IN
config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN
bool "No DMA in"
config CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
bool "DMA 9"
endchoice
choice choice
prompt "Ser1 DTR, RI, DSR and CD assignment" prompt "Ser1 DTR, RI, DSR and CD assignment"
depends on ETRAX_SERIAL_PORT1 depends on ETRAX_SERIAL_PORT1
...@@ -288,6 +317,32 @@ config ETRAX_SERIAL_PORT2 ...@@ -288,6 +317,32 @@ config ETRAX_SERIAL_PORT2
help help
Enables the ETRAX 100 serial driver for ser2 (ttyS2). Enables the ETRAX 100 serial driver for ser2 (ttyS2).
choice
prompt "Ser2 DMA out assignment"
depends on ETRAX_SERIAL_PORT2
default ETRAX_SERIAL_PORT2_DMA2_OUT
config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT
bool "No DMA out"
config CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
bool "DMA 2"
endchoice
choice
prompt "Ser2 DMA in assignment"
depends on ETRAX_SERIAL_PORT2
default ETRAX_SERIAL_PORT2_DMA3_IN
config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN
bool "No DMA in"
config CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
bool "DMA 3"
endchoice
choice choice
prompt "Ser2 DTR, RI, DSR and CD assignment" prompt "Ser2 DTR, RI, DSR and CD assignment"
depends on ETRAX_SERIAL_PORT2 depends on ETRAX_SERIAL_PORT2
...@@ -376,6 +431,32 @@ config ETRAX_SERIAL_PORT3 ...@@ -376,6 +431,32 @@ config ETRAX_SERIAL_PORT3
help help
Enables the ETRAX 100 serial driver for ser3 (ttyS3). Enables the ETRAX 100 serial driver for ser3 (ttyS3).
choice
prompt "Ser3 DMA out assignment"
depends on ETRAX_SERIAL_PORT3
default ETRAX_SERIAL_PORT3_DMA4_OUT
config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_OUT
bool "No DMA out"
config CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
bool "DMA 4"
endchoice
choice
prompt "Ser3 DMA in assignment"
depends on ETRAX_SERIAL_PORT3
default ETRAX_SERIAL_PORT3_DMA5_IN
config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_IN
bool "No DMA in"
config CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
bool "DMA 5"
endchoice
choice choice
prompt "Ser3 DTR, RI, DSR and CD assignment" prompt "Ser3 DTR, RI, DSR and CD assignment"
depends on ETRAX_SERIAL_PORT3 depends on ETRAX_SERIAL_PORT3
...@@ -466,6 +547,95 @@ config ETRAX_RS485_DISABLE_RECEIVER ...@@ -466,6 +547,95 @@ config ETRAX_RS485_DISABLE_RECEIVER
loopback. Not all products are able to do this in software only. loopback. Not all products are able to do this in software only.
Axis 2400/2401 must disable receiver. Axis 2400/2401 must disable receiver.
config ETRAX_IDE
bool "ATA/IDE support"
help
Enable this to get support for ATA/IDE.
You can't use parallell ports or SCSI ports
at the same time.
# here we should add the CONFIG_'s necessary to enable the basic
# general ide drivers so the common case does not need to go
# into that config submenu. enable disk and CD support. others
# need to go fiddle in the submenu..
config IDE
tristate
depends on ETRAX_IDE
default y
config BLK_DEV_IDE
tristate
depends on ETRAX_IDE
default y
config BLK_DEV_IDEDISK
tristate
depends on ETRAX_IDE
default y
config BLK_DEV_IDECD
tristate
depends on ETRAX_IDE
default y
config BLK_DEV_IDEDMA
bool
depends on ETRAX_IDE
default y
config DMA_NONPCI
bool
depends on ETRAX_IDE
default y
config ETRAX_IDE_DELAY
int "Delay for drives to regain consciousness"
depends on ETRAX_IDE
default 15
help
Number of seconds to wait for IDE drives to spin up after an IDE
reset.
choice
prompt "IDE reset pin"
depends on ETRAX_IDE
default ETRAX_IDE_PB7_RESET
config ETRAX_IDE_PB7_RESET
bool "Port_PB_Bit_7"
help
IDE reset on pin 7 on port B
config ETRAX_IDE_G27_RESET
bool "Port_G_Bit_27"
help
IDE reset on pin 27 on port G
endchoice
config ETRAX_USB_HOST
bool "USB host"
help
This option enables the host functionality of the ETRAX 100LX
built-in USB controller. In host mode the controller is designed
for CTRL and BULK traffic only, INTR traffic may work as well
however (depending on the requirements of timeliness).
config USB
tristate
depends on ETRAX_USB_HOST
default y
config ETRAX_USB_HOST_PORT1
bool " USB port 1 enabled"
depends on ETRAX_USB_HOST
default n
config ETRAX_USB_HOST_PORT2
bool " USB port 2 enabled"
depends on ETRAX_USB_HOST
default n
config ETRAX_AXISFLASHMAP config ETRAX_AXISFLASHMAP
bool "Axis flash-map support" bool "Axis flash-map support"
depends on ETRAX_ARCH_V10 depends on ETRAX_ARCH_V10
......
...@@ -10,5 +10,7 @@ obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o ...@@ -10,5 +10,7 @@ obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o
obj-$(CONFIG_ETRAX_GPIO) += gpio.o obj-$(CONFIG_ETRAX_GPIO) += gpio.o
obj-$(CONFIG_ETRAX_DS1302) += ds1302.o obj-$(CONFIG_ETRAX_DS1302) += ds1302.o
obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o
obj-$(CONFIG_ETRAX_IDE) += ide.o
obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
* partition split defined below. * partition split defined below.
* *
* $Log: axisflashmap.c,v $ * $Log: axisflashmap.c,v $
* Revision 1.8 2004/05/14 07:58:03 starvik
* Merge of changes from 2.4
*
* Revision 1.6 2003/07/04 08:27:37 starvik * Revision 1.6 2003/07/04 08:27:37 starvik
* Merge of Linux 2.5.74 * Merge of Linux 2.5.74
* *
...@@ -153,6 +156,9 @@ ...@@ -153,6 +156,9 @@
/* From head.S */ /* From head.S */
extern unsigned long romfs_start, romfs_length, romfs_in_flash; extern unsigned long romfs_start, romfs_length, romfs_in_flash;
/* The master mtd for the entire flash. */
struct mtd_info* axisflash_mtd = NULL;
/* Map driver functions. */ /* Map driver functions. */
static __u8 flash_read8(struct map_info *map, unsigned long ofs) static __u8 flash_read8(struct map_info *map, unsigned long ofs)
...@@ -314,7 +320,8 @@ static struct mtd_info *probe_cs(struct map_info *map_cs) ...@@ -314,7 +320,8 @@ static struct mtd_info *probe_cs(struct map_info *map_cs)
{ {
struct mtd_info *mtd_cs = NULL; struct mtd_info *mtd_cs = NULL;
printk("%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n", printk(KERN_INFO
"%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n",
map_cs->name, map_cs->size, map_cs->map_priv_1); map_cs->name, map_cs->size, map_cs->map_priv_1);
#ifdef CONFIG_MTD_AMDSTD #ifdef CONFIG_MTD_AMDSTD
...@@ -398,7 +405,7 @@ static int __init init_axis_flash(void) ...@@ -398,7 +405,7 @@ static int __init init_axis_flash(void)
struct mtd_info *mymtd; struct mtd_info *mymtd;
int err = 0; int err = 0;
int pidx = 0; int pidx = 0;
struct partitiontable_head *ptable_head; struct partitiontable_head *ptable_head = NULL;
struct partitiontable_entry *ptable; struct partitiontable_entry *ptable;
int use_default_ptable = 1; /* Until proven otherwise. */ int use_default_ptable = 1; /* Until proven otherwise. */
const char *pmsg = " /dev/flash%d at 0x%08x, size 0x%08x\n"; const char *pmsg = " /dev/flash%d at 0x%08x, size 0x%08x\n";
...@@ -407,19 +414,22 @@ static int __init init_axis_flash(void) ...@@ -407,19 +414,22 @@ static int __init init_axis_flash(void)
/* There's no reason to use this module if no flash chip can /* There's no reason to use this module if no flash chip can
* be identified. Make sure that's understood. * be identified. Make sure that's understood.
*/ */
panic("axisflashmap found no flash chip!\n"); printk(KERN_INFO "axisflashmap: Found no flash chip.\n");
} else {
printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n",
mymtd->name, mymtd->size);
axisflash_mtd = mymtd;
} }
printk("%s: 0x%08x bytes of flash memory.\n", if (mymtd) {
mymtd->name, mymtd->size); mymtd->owner = THIS_MODULE;
ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR +
mymtd->owner = THIS_MODULE; CONFIG_ETRAX_PTABLE_SECTOR +
PARTITION_TABLE_OFFSET);
ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + }
CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET);
pidx++; /* First partition is always set to the default. */ pidx++; /* First partition is always set to the default. */
if ((ptable_head->magic == PARTITION_TABLE_MAGIC) if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC)
&& (ptable_head->size < && (ptable_head->size <
(MAX_PARTITIONS * sizeof(struct partitiontable_entry) + (MAX_PARTITIONS * sizeof(struct partitiontable_entry) +
PARTITIONTABLE_END_MARKER_SIZE)) PARTITIONTABLE_END_MARKER_SIZE))
...@@ -454,7 +464,7 @@ static int __init init_axis_flash(void) ...@@ -454,7 +464,7 @@ static int __init init_axis_flash(void)
ptable_ok = (csum == ptable_head->checksum); ptable_ok = (csum == ptable_head->checksum);
/* Read the entries and use/show the info. */ /* Read the entries and use/show the info. */
printk(" Found a%s partition table at 0x%p-0x%p.\n", printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n",
(ptable_ok ? " valid" : "n invalid"), ptable_head, (ptable_ok ? " valid" : "n invalid"), ptable_head,
max_addr); max_addr);
...@@ -486,22 +496,25 @@ static int __init init_axis_flash(void) ...@@ -486,22 +496,25 @@ static int __init init_axis_flash(void)
axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR;
axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; axis_partitions[pidx].mask_flags |= MTD_WRITEABLE;
printk(" Adding readonly flash partition for romfs image:\n"); printk(KERN_INFO
" Adding readonly flash partition for romfs image:\n");
printk(pmsg, pidx, axis_partitions[pidx].offset, printk(pmsg, pidx, axis_partitions[pidx].offset,
axis_partitions[pidx].size); axis_partitions[pidx].size);
pidx++; pidx++;
} }
if (use_default_ptable) { if (mymtd) {
printk(" Using default partition table.\n"); if (use_default_ptable) {
err = add_mtd_partitions(mymtd, axis_default_partitions, printk(KERN_INFO " Using default partition table.\n");
NUM_DEFAULT_PARTITIONS); err = add_mtd_partitions(mymtd, axis_default_partitions,
} else { NUM_DEFAULT_PARTITIONS);
err = add_mtd_partitions(mymtd, axis_partitions, pidx); } else {
} err = add_mtd_partitions(mymtd, axis_partitions, pidx);
}
if (err) { if (err) {
panic("axisflashmap could not add MTD partitions!\n"); panic("axisflashmap could not add MTD partitions!\n");
}
} }
if (!romfs_in_flash) { if (!romfs_in_flash) {
...@@ -522,7 +535,7 @@ static int __init init_axis_flash(void) ...@@ -522,7 +535,7 @@ static int __init init_axis_flash(void)
"mtd_info!\n"); "mtd_info!\n");
} }
printk(" Adding RAM partition for romfs image:\n"); printk(KERN_INFO " Adding RAM partition for romfs image:\n");
printk(pmsg, pidx, romfs_start, romfs_length); printk(pmsg, pidx, romfs_start, romfs_length);
err = mtdram_init_device(mtd_ram, (void*)romfs_start, err = mtdram_init_device(mtd_ram, (void*)romfs_start,
...@@ -539,3 +552,5 @@ static int __init init_axis_flash(void) ...@@ -539,3 +552,5 @@ static int __init init_axis_flash(void)
/* This adds the above to the kernels init-call chain. */ /* This adds the above to the kernels init-call chain. */
module_init(init_axis_flash); module_init(init_axis_flash);
EXPORT_SYMBOL(axisflash_mtd);
...@@ -4,9 +4,18 @@ ...@@ -4,9 +4,18 @@
*! *!
*! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O *! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O
*! *!
*! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init
*! *!
*! $Log: ds1302.c,v $ *! $Log: ds1302.c,v $
*! Revision 1.13 2004/05/28 09:26:59 starvik
*! Modified I2C initialization to work in 2.6.
*!
*! Revision 1.12 2004/05/14 07:58:03 starvik
*! Merge of changes from 2.4
*!
*! Revision 1.10 2004/02/04 09:25:12 starvik
*! Merge of Linux 2.6.2
*!
*! Revision 1.9 2003/07/04 08:27:37 starvik *! Revision 1.9 2003/07/04 08:27:37 starvik
*! Merge of Linux 2.5.74 *! Merge of Linux 2.5.74
*! *!
...@@ -114,7 +123,7 @@ ...@@ -114,7 +123,7 @@
*! *!
*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN
*! *!
*! $Id: ds1302.c,v 1.9 2003/07/04 08:27:37 starvik Exp $ *! $Id: ds1302.c,v 1.13 2004/05/28 09:26:59 starvik Exp $
*! *!
*!***************************************************************************/ *!***************************************************************************/
...@@ -283,12 +292,23 @@ ds1302_readreg(int reg) ...@@ -283,12 +292,23 @@ ds1302_readreg(int reg)
void void
ds1302_writereg(int reg, unsigned char val) ds1302_writereg(int reg, unsigned char val)
{ {
ds1302_wenable(); #ifndef CONFIG_ETRAX_RTC_READONLY
start(); int do_writereg = 1;
out_byte(0x80 | (reg << 1)); /* write register */ #else
out_byte(val); int do_writereg = 0;
stop();
ds1302_wdisable(); if (reg == RTC_TRICKLECHARGER)
do_writereg = 1;
#endif
if (do_writereg) {
ds1302_wenable();
start();
out_byte(0x80 | (reg << 1)); /* write register */
out_byte(val);
stop();
ds1302_wdisable();
}
} }
void void
...@@ -426,20 +446,33 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -426,20 +446,33 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F);
ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); ds1302_writereg(RTC_TRICKLECHARGER, tcs_val);
return 0; return 0;
} }
case RTC_VLOW_RD:
{
/* TODO:
* Implement voltage low detection support
*/
printk(KERN_WARNING "DS1302: RTC Voltage Low detection"
" is not supported\n");
return 0;
}
case RTC_VLOW_SET:
{
/* TODO:
* Nothing to do since Voltage Low detection is not supported
*/
return 0;
}
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
} }
int static void
get_rtc_status(char *buf) print_rtc_status(void)
{ {
char *p;
struct rtc_time tm; struct rtc_time tm;
p = buf;
get_rtc_time(&tm); get_rtc_time(&tm);
/* /*
...@@ -447,16 +480,12 @@ get_rtc_status(char *buf) ...@@ -447,16 +480,12 @@ get_rtc_status(char *buf)
* time or for Universal Standard Time (GMT). Probably local though. * time or for Universal Standard Time (GMT). Probably local though.
*/ */
p += sprintf(p, printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n",
"rtc_time\t: %02d:%02d:%02d\n" tm.tm_hour, tm.tm_min, tm.tm_sec);
"rtc_date\t: %04d-%02d-%02d\n", printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n",
tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
return p - buf;
} }
/* The various file operations we support. */ /* The various file operations we support. */
static struct file_operations rtc_fops = { static struct file_operations rtc_fops = {
...@@ -487,11 +516,10 @@ ds1302_probe(void) ...@@ -487,11 +516,10 @@ ds1302_probe(void)
out_byte(0xc1); /* read RAM byte 0 */ out_byte(0xc1); /* read RAM byte 0 */
if((res = in_byte()) == MAGIC_PATTERN) { if((res = in_byte()) == MAGIC_PATTERN) {
char buf[100];
stop(); stop();
ds1302_wdisable(); ds1302_wdisable();
printk("%s: RTC found.\n", ds1302_name); printk(KERN_INFO "%s: RTC found.\n", ds1302_name);
printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", printk(KERN_INFO "%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n",
ds1302_name, ds1302_name,
CONFIG_ETRAX_DS1302_SDABIT, CONFIG_ETRAX_DS1302_SDABIT,
CONFIG_ETRAX_DS1302_SCLBIT, CONFIG_ETRAX_DS1302_SCLBIT,
...@@ -501,12 +529,10 @@ ds1302_probe(void) ...@@ -501,12 +529,10 @@ ds1302_probe(void)
"PB", "PB",
#endif #endif
CONFIG_ETRAX_DS1302_RSTBIT); CONFIG_ETRAX_DS1302_RSTBIT);
get_rtc_status(buf); print_rtc_status();
printk(buf);
retval = 1; retval = 1;
} else { } else {
stop(); stop();
printk("%s: RTC not found.\n", ds1302_name);
retval = 0; retval = 0;
} }
...@@ -518,7 +544,9 @@ ds1302_probe(void) ...@@ -518,7 +544,9 @@ ds1302_probe(void)
int __init int __init
ds1302_init(void) ds1302_init(void)
{ {
i2c_init();
if (!ds1302_probe()) { if (!ds1302_probe()) {
#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT
#if CONFIG_ETRAX_DS1302_RSTBIT == 27 #if CONFIG_ETRAX_DS1302_RSTBIT == 27
...@@ -539,16 +567,20 @@ ds1302_init(void) ...@@ -539,16 +567,20 @@ ds1302_init(void)
(IO_STATE(R_GEN_CONFIG, g0dir, out))); (IO_STATE(R_GEN_CONFIG, g0dir, out)));
*R_GEN_CONFIG = genconfig_shadow; *R_GEN_CONFIG = genconfig_shadow;
#endif #endif
if (!ds1302_probe()) if (!ds1302_probe()) {
printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
return -1; return -1;
}
#else #else
printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name);
return -1; return -1;
#endif #endif
} }
/* Initialise trickle charger */ /* Initialise trickle charger */
ds1302_writereg(RTC_TRICKLECHARGER, ds1302_writereg(RTC_TRICKLECHARGER,
RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F)); RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F));
/* Start clock by resetting CLOCK_HALT */
ds1302_writereg(RTC_SECONDS, (ds1302_readreg(RTC_SECONDS) & 0x7F));
return 0; return 0;
} }
......
...@@ -20,6 +20,9 @@ ...@@ -20,6 +20,9 @@
*! in the spin-lock. *! in the spin-lock.
*! *!
*! $Log: eeprom.c,v $ *! $Log: eeprom.c,v $
*! Revision 1.10 2003/09/11 07:29:48 starvik
*! Merge of Linux 2.6.0-test5
*!
*! Revision 1.9 2003/07/04 08:27:37 starvik *! Revision 1.9 2003/07/04 08:27:37 starvik
*! Merge of Linux 2.5.74 *! Merge of Linux 2.5.74
*! *!
...@@ -441,9 +444,9 @@ int __init eeprom_init(void) ...@@ -441,9 +444,9 @@ int __init eeprom_init(void)
static int eeprom_open(struct inode * inode, struct file * file) static int eeprom_open(struct inode * inode, struct file * file)
{ {
if(iminor(inode) != EEPROM_MINOR_NR) if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR)
return -ENXIO; return -ENXIO;
if(imajor(inode) != EEPROM_MAJOR_NR) if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR)
return -ENXIO; return -ENXIO;
if( eeprom.size > 0 ) if( eeprom.size > 0 )
......
/* $Id: ethernet.c,v 1.17 2003/07/04 08:27:37 starvik Exp $ /* $Id: ethernet.c,v 1.22 2004/05/14 07:58:03 starvik Exp $
* *
* e100net.c: A network driver for the ETRAX 100LX network controller. * e100net.c: A network driver for the ETRAX 100LX network controller.
* *
...@@ -7,6 +7,15 @@ ...@@ -7,6 +7,15 @@
* The outline of this driver comes from skeleton.c. * The outline of this driver comes from skeleton.c.
* *
* $Log: ethernet.c,v $ * $Log: ethernet.c,v $
* Revision 1.22 2004/05/14 07:58:03 starvik
* Merge of changes from 2.4
*
* Revision 1.20 2004/03/11 11:38:40 starvik
* Merge of Linux 2.6.4
*
* Revision 1.18 2003/12/03 13:45:46 starvik
* Use hardware pad for short packets to prevent information leakage.
*
* Revision 1.17 2003/07/04 08:27:37 starvik * Revision 1.17 2003/07/04 08:27:37 starvik
* Merge of Linux 2.5.74 * Merge of Linux 2.5.74
* *
...@@ -258,6 +267,16 @@ typedef struct etrax_eth_descr ...@@ -258,6 +267,16 @@ typedef struct etrax_eth_descr
struct sk_buff* skb; struct sk_buff* skb;
} etrax_eth_descr; } etrax_eth_descr;
/* Some transceivers requires special handling */
struct transceiver_ops
{
unsigned int oui;
void (*check_speed)(void);
void (*check_duplex)(void);
};
struct transceiver_ops* transceiver;
/* Duplex settings */ /* Duplex settings */
enum duplex enum duplex
{ {
...@@ -278,10 +297,17 @@ enum duplex ...@@ -278,10 +297,17 @@ enum duplex
*/ */
#define MDIO_BASE_STATUS_REG 0x1 #define MDIO_BASE_STATUS_REG 0x1
#define MDIO_BASE_CONTROL_REG 0x0 #define MDIO_BASE_CONTROL_REG 0x0
#define MDIO_PHY_ID_HIGH_REG 0x2
#define MDIO_PHY_ID_LOW_REG 0x3
#define MDIO_BC_NEGOTIATE 0x0200 #define MDIO_BC_NEGOTIATE 0x0200
#define MDIO_BC_FULL_DUPLEX_MASK 0x0100 #define MDIO_BC_FULL_DUPLEX_MASK 0x0100
#define MDIO_BC_AUTO_NEG_MASK 0x1000 #define MDIO_BC_AUTO_NEG_MASK 0x1000
#define MDIO_BC_SPEED_SELECT_MASK 0x2000 #define MDIO_BC_SPEED_SELECT_MASK 0x2000
#define MDIO_STATUS_100_FD 0x4000
#define MDIO_STATUS_100_HD 0x2000
#define MDIO_STATUS_10_FD 0x1000
#define MDIO_STATUS_10_HD 0x0800
#define MDIO_STATUS_SPEED_DUPLEX_MASK 0x7800
#define MDIO_ADVERTISMENT_REG 0x4 #define MDIO_ADVERTISMENT_REG 0x4
#define MDIO_ADVERT_100_FD 0x100 #define MDIO_ADVERT_100_FD 0x100
#define MDIO_ADVERT_100_HD 0x080 #define MDIO_ADVERT_100_HD 0x080
...@@ -295,9 +321,13 @@ enum duplex ...@@ -295,9 +321,13 @@ enum duplex
/* Broadcom specific */ /* Broadcom specific */
#define MDIO_AUX_CTRL_STATUS_REG 0x18 #define MDIO_AUX_CTRL_STATUS_REG 0x18
#define MDIO_FULL_DUPLEX_IND 0x1 #define MDIO_BC_FULL_DUPLEX_IND 0x1
#define MDIO_SPEED 0x2 #define MDIO_BC_SPEED 0x2
#define MDIO_PHYS_ADDR 0x0
/* TDK specific */
#define MDIO_TDK_DIAGNOSTIC_REG 18
#define MDIO_TDK_DIAGNOSTIC_RATE 0x400
#define MDIO_TDK_DIAGNOSTIC_DPLX 0x800
/* Network flash constants */ /* Network flash constants */
#define NET_FLASH_TIME (HZ/50) /* 20 ms */ #define NET_FLASH_TIME (HZ/50) /* 20 ms */
...@@ -341,6 +371,9 @@ static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */ ...@@ -341,6 +371,9 @@ static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */
static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32))); static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32)));
static unsigned int network_rec_config_shadow = 0; static unsigned int network_rec_config_shadow = 0;
static unsigned int mdio_phy_addr; /* Transciever address */
static unsigned int network_tr_ctrl_shadow = 0;
/* Network speed indication. */ /* Network speed indication. */
static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0); static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0);
...@@ -376,6 +409,7 @@ static void set_multicast_list(struct net_device *dev); ...@@ -376,6 +409,7 @@ static void set_multicast_list(struct net_device *dev);
static void e100_hardware_send_packet(char *buf, int length); static void e100_hardware_send_packet(char *buf, int length);
static void update_rx_stats(struct net_device_stats *); static void update_rx_stats(struct net_device_stats *);
static void update_tx_stats(struct net_device_stats *); static void update_tx_stats(struct net_device_stats *);
static int e100_probe_transceiver(void);
static void e100_check_speed(unsigned long dummy); static void e100_check_speed(unsigned long dummy);
static void e100_set_speed(unsigned long speed); static void e100_set_speed(unsigned long speed);
...@@ -393,6 +427,21 @@ static void e100_reset_transceiver(void); ...@@ -393,6 +427,21 @@ static void e100_reset_transceiver(void);
static void e100_clear_network_leds(unsigned long dummy); static void e100_clear_network_leds(unsigned long dummy);
static void e100_set_network_leds(int active); static void e100_set_network_leds(int active);
static void broadcom_check_speed(void);
static void broadcom_check_duplex(void);
static void tdk_check_speed(void);
static void tdk_check_duplex(void);
static void generic_check_speed(void);
static void generic_check_duplex(void);
struct transceiver_ops transceivers[] =
{
{0x1018, broadcom_check_speed, broadcom_check_duplex}, /* Broadcom */
{0xC039, tdk_check_speed, tdk_check_duplex}, /* TDK 2120 */
{0x039C, tdk_check_speed, tdk_check_duplex}, /* TDK 2120C */
{0x0000, generic_check_speed, generic_check_duplex} /* Generic, must be last */
};
#define tx_done(dev) (*R_DMA_CH0_CMD == 0) #define tx_done(dev) (*R_DMA_CH0_CMD == 0)
/* /*
...@@ -409,7 +458,8 @@ etrax_ethernet_init(void) ...@@ -409,7 +458,8 @@ etrax_ethernet_init(void)
struct net_device *dev; struct net_device *dev;
int i, err; int i, err;
printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n"); printk(KERN_INFO
"ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n");
dev = alloc_etherdev(sizeof(struct net_local)); dev = alloc_etherdev(sizeof(struct net_local));
if (!dev) if (!dev)
...@@ -496,7 +546,6 @@ etrax_ethernet_init(void) ...@@ -496,7 +546,6 @@ etrax_ethernet_init(void)
current_speed_selection = 0; /* Auto */ current_speed_selection = 0; /* Auto */
speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
speed_timer.function = e100_check_speed; speed_timer.function = e100_check_speed;
add_timer(&speed_timer);
clear_led_timer.function = e100_clear_network_leds; clear_led_timer.function = e100_clear_network_leds;
...@@ -504,7 +553,6 @@ etrax_ethernet_init(void) ...@@ -504,7 +553,6 @@ etrax_ethernet_init(void)
current_duplex = autoneg; current_duplex = autoneg;
duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL; duplex_timer.expires = jiffies + NET_DUPLEX_CHECK_INTERVAL;
duplex_timer.function = e100_check_duplex; duplex_timer.function = e100_check_duplex;
add_timer(&duplex_timer);
/* Initialize group address registers to make sure that no */ /* Initialize group address registers to make sure that no */
/* unwanted addresses are matched */ /* unwanted addresses are matched */
...@@ -543,7 +591,7 @@ e100_set_mac_address(struct net_device *dev, void *p) ...@@ -543,7 +591,7 @@ e100_set_mac_address(struct net_device *dev, void *p)
/* show it in the log as well */ /* show it in the log as well */
printk("%s: changed MAC to ", dev->name); printk(KERN_INFO "%s: changed MAC to ", dev->name);
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
printk("%02X:", dev->dev_addr[i]); printk("%02X:", dev->dev_addr[i]);
...@@ -569,12 +617,6 @@ e100_open(struct net_device *dev) ...@@ -569,12 +617,6 @@ e100_open(struct net_device *dev)
{ {
unsigned long flags; unsigned long flags;
/* disable the ethernet interface while we configure it */
*R_NETWORK_GEN_CONFIG =
IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) |
IO_STATE(R_NETWORK_GEN_CONFIG, enable, off);
/* enable the MDIO output pin */ /* enable the MDIO output pin */
*R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable); *R_NETWORK_MGM_CTRL = IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable);
...@@ -645,14 +687,14 @@ e100_open(struct net_device *dev) ...@@ -645,14 +687,14 @@ e100_open(struct net_device *dev)
IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) |
IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); IO_STATE(R_NETWORK_GEN_CONFIG, enable, on);
*R_NETWORK_TR_CTRL = SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) | SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, delay, none);
IO_STATE(R_NETWORK_TR_CTRL, delay, none) | SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cancel, dont);
IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) | SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, cd, enable);
IO_STATE(R_NETWORK_TR_CTRL, cd, enable) | SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, retry, enable);
IO_STATE(R_NETWORK_TR_CTRL, retry, enable) | SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, pad, enable);
IO_STATE(R_NETWORK_TR_CTRL, pad, enable) | SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, crc, enable);
IO_STATE(R_NETWORK_TR_CTRL, crc, enable); *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
save_flags(flags); save_flags(flags);
cli(); cli();
...@@ -660,7 +702,8 @@ e100_open(struct net_device *dev) ...@@ -660,7 +702,8 @@ e100_open(struct net_device *dev)
/* enable the irq's for ethernet DMA */ /* enable the irq's for ethernet DMA */
*R_IRQ_MASK2_SET = *R_IRQ_MASK2_SET =
IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
*R_IRQ_MASK0_SET = *R_IRQ_MASK0_SET =
IO_STATE(R_IRQ_MASK0_SET, overrun, set) | IO_STATE(R_IRQ_MASK0_SET, overrun, set) |
...@@ -689,6 +732,14 @@ e100_open(struct net_device *dev) ...@@ -689,6 +732,14 @@ e100_open(struct net_device *dev)
restore_flags(flags); restore_flags(flags);
/* Probe for transceiver */
if (e100_probe_transceiver())
goto grace_exit3;
/* Start duplex/speed timers */
add_timer(&speed_timer);
add_timer(&duplex_timer);
/* We are now ready to accept transmit requeusts from /* We are now ready to accept transmit requeusts from
* the queueing layer of the networking. * the queueing layer of the networking.
*/ */
...@@ -696,6 +747,8 @@ e100_open(struct net_device *dev) ...@@ -696,6 +747,8 @@ e100_open(struct net_device *dev)
return 0; return 0;
grace_exit3:
free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev);
grace_exit2: grace_exit2:
free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev);
grace_exit1: grace_exit1:
...@@ -705,9 +758,38 @@ e100_open(struct net_device *dev) ...@@ -705,9 +758,38 @@ e100_open(struct net_device *dev)
} }
static void
generic_check_speed(void)
{
unsigned long data;
data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
if ((data & MDIO_ADVERT_100_FD) ||
(data & MDIO_ADVERT_100_HD))
current_speed = 100;
else
current_speed = 10;
}
static void
tdk_check_speed(void)
{
unsigned long data;
data = e100_get_mdio_reg(MDIO_TDK_DIAGNOSTIC_REG);
current_speed = (data & MDIO_TDK_DIAGNOSTIC_RATE ? 100 : 10);
}
static void
broadcom_check_speed(void)
{
unsigned long data;
data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG);
current_speed = (data & MDIO_BC_SPEED ? 100 : 10);
}
static void static void
e100_check_speed(unsigned long dummy) e100_check_speed(unsigned long dummy)
{ {
static int led_initiated = 0;
unsigned long data; unsigned long data;
int old_speed = current_speed; int old_speed = current_speed;
...@@ -715,12 +797,13 @@ e100_check_speed(unsigned long dummy) ...@@ -715,12 +797,13 @@ e100_check_speed(unsigned long dummy)
if (!(data & MDIO_LINK_UP_MASK)) { if (!(data & MDIO_LINK_UP_MASK)) {
current_speed = 0; current_speed = 0;
} else { } else {
data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); transceiver->check_speed();
current_speed = (data & MDIO_SPEED ? 100 : 10);
} }
if (old_speed != current_speed) if ((old_speed != current_speed) || !led_initiated) {
led_initiated = 1;
e100_set_network_leds(NO_NETWORK_ACTIVITY); e100_set_network_leds(NO_NETWORK_ACTIVITY);
}
/* Reinitialize the timer. */ /* Reinitialize the timer. */
speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL; speed_timer.expires = jiffies + NET_LINK_UP_CHECK_INTERVAL;
...@@ -781,29 +864,21 @@ e100_negotiate(void) ...@@ -781,29 +864,21 @@ e100_negotiate(void)
static void static void
e100_set_speed(unsigned long speed) e100_set_speed(unsigned long speed)
{ {
current_speed_selection = speed; if (speed != current_speed_selection) {
e100_negotiate(); current_speed_selection = speed;
e100_negotiate();
}
} }
static void static void
e100_check_duplex(unsigned long dummy) e100_check_duplex(unsigned long dummy)
{ {
unsigned long data; int old_duplex = full_duplex;
transceiver->check_duplex();
data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG); if (old_duplex != full_duplex) {
/* Duplex changed */
if (data & MDIO_FULL_DUPLEX_IND) { SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
if (!full_duplex) { /* Duplex changed to full? */ *R_NETWORK_REC_CONFIG = network_rec_config_shadow;
full_duplex = 1;
SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
}
} else { /* half */
if (full_duplex) { /* Duplex changed to half? */
full_duplex = 0;
SETF(network_rec_config_shadow, R_NETWORK_REC_CONFIG, duplex, full_duplex);
*R_NETWORK_REC_CONFIG = network_rec_config_shadow;
}
} }
/* Reinitialize the timer. */ /* Reinitialize the timer. */
...@@ -811,13 +886,72 @@ e100_check_duplex(unsigned long dummy) ...@@ -811,13 +886,72 @@ e100_check_duplex(unsigned long dummy)
add_timer(&duplex_timer); add_timer(&duplex_timer);
} }
static void
generic_check_duplex(void)
{
unsigned long data;
data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG);
if ((data & MDIO_ADVERT_100_FD) ||
(data & MDIO_ADVERT_10_FD))
full_duplex = 1;
else
full_duplex = 0;
}
static void
tdk_check_duplex(void)
{
unsigned long data;
data = e100_get_mdio_reg(MDIO_TDK_DIAGNOSTIC_REG);
full_duplex = (data & MDIO_TDK_DIAGNOSTIC_DPLX) ? 1 : 0;
}
static void
broadcom_check_duplex(void)
{
unsigned long data;
data = e100_get_mdio_reg(MDIO_AUX_CTRL_STATUS_REG);
full_duplex = (data & MDIO_BC_FULL_DUPLEX_IND) ? 1 : 0;
}
static void static void
e100_set_duplex(enum duplex new_duplex) e100_set_duplex(enum duplex new_duplex)
{ {
current_duplex = new_duplex; if (new_duplex != current_duplex) {
e100_negotiate(); current_duplex = new_duplex;
e100_negotiate();
}
} }
static int
e100_probe_transceiver(void)
{
unsigned int phyid_high;
unsigned int phyid_low;
unsigned int oui;
struct transceiver_ops* ops = NULL;
/* Probe MDIO physical address */
for (mdio_phy_addr = 0; mdio_phy_addr <= 31; mdio_phy_addr++) {
if (e100_get_mdio_reg(MDIO_BASE_STATUS_REG) != 0xffff)
break;
}
if (mdio_phy_addr == 32)
return -ENODEV;
/* Get manufacturer */
phyid_high = e100_get_mdio_reg(MDIO_PHY_ID_HIGH_REG);
phyid_low = e100_get_mdio_reg(MDIO_PHY_ID_LOW_REG);
oui = (phyid_high << 6) | (phyid_low >> 10);
for (ops = &transceivers[0]; ops->oui; ops++) {
if (ops->oui == oui)
break;
}
transceiver = ops;
return 0;
}
static unsigned short static unsigned short
e100_get_mdio_reg(unsigned char reg_num) e100_get_mdio_reg(unsigned char reg_num)
...@@ -827,7 +961,7 @@ e100_get_mdio_reg(unsigned char reg_num) ...@@ -827,7 +961,7 @@ e100_get_mdio_reg(unsigned char reg_num)
int bitCounter; int bitCounter;
/* Start of frame, OP Code, Physical Address, Register Address */ /* Start of frame, OP Code, Physical Address, Register Address */
cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (MDIO_PHYS_ADDR << 7) | cmd = (MDIO_START << 14) | (MDIO_READ << 12) | (mdio_phy_addr << 7) |
(reg_num << 2); (reg_num << 2);
e100_send_mdio_cmd(cmd, 0); e100_send_mdio_cmd(cmd, 0);
...@@ -848,7 +982,7 @@ e100_set_mdio_reg(unsigned char reg, unsigned short data) ...@@ -848,7 +982,7 @@ e100_set_mdio_reg(unsigned char reg, unsigned short data)
int bitCounter; int bitCounter;
unsigned short cmd; unsigned short cmd;
cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) |
(reg << 2); (reg << 2);
e100_send_mdio_cmd(cmd, 1); e100_send_mdio_cmd(cmd, 1);
...@@ -916,7 +1050,7 @@ e100_reset_transceiver(void) ...@@ -916,7 +1050,7 @@ e100_reset_transceiver(void)
data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG);
cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | (MDIO_BASE_CONTROL_REG << 2); cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (mdio_phy_addr << 7) | (MDIO_BASE_CONTROL_REG << 2);
e100_send_mdio_cmd(cmd, 1); e100_send_mdio_cmd(cmd, 1);
...@@ -984,7 +1118,6 @@ static int ...@@ -984,7 +1118,6 @@ static int
e100_send_packet(struct sk_buff *skb, struct net_device *dev) e100_send_packet(struct sk_buff *skb, struct net_device *dev)
{ {
struct net_local *np = (struct net_local *)dev->priv; struct net_local *np = (struct net_local *)dev->priv;
int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data; unsigned char *buf = skb->data;
unsigned long flags; unsigned long flags;
...@@ -997,15 +1130,12 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -997,15 +1130,12 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies; dev->trans_start = jiffies;
e100_hardware_send_packet(buf, length); e100_hardware_send_packet(buf, skb->len);
myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next); myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next);
/* Stop queue if full */ /* Stop queue if full */
if (myNextTxDesc == myFirstTxDesc) { if (myNextTxDesc == myFirstTxDesc) {
/* Enable transmit interrupt to wake up queue */
*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
*R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set);
netif_stop_queue(dev); netif_stop_queue(dev);
} }
...@@ -1026,6 +1156,11 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -1026,6 +1156,11 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
struct net_local *np = (struct net_local *)dev->priv; struct net_local *np = (struct net_local *)dev->priv;
unsigned long irqbits = *R_IRQ_MASK2_RD; unsigned long irqbits = *R_IRQ_MASK2_RD;
/* Disable RX/TX IRQs to avoid reentrancy */
*R_IRQ_MASK2_CLR =
IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr) |
IO_STATE(R_IRQ_MASK2_CLR, dma1_eop, clr);
/* Handle received packets */ /* Handle received packets */
if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) {
/* acknowledge the eop interrupt */ /* acknowledge the eop interrupt */
...@@ -1069,9 +1204,14 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -1069,9 +1204,14 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) {
/* acknowledge the eop interrupt and wake up queue */ /* acknowledge the eop interrupt and wake up queue */
*R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
*R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr);
netif_wake_queue(dev); netif_wake_queue(dev);
} }
/* Enable RX/TX IRQs again */
*R_IRQ_MASK2_SET =
IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1084,7 +1224,9 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -1084,7 +1224,9 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* check for underrun irq */ /* check for underrun irq */
if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) { if (irqbits & IO_STATE(R_IRQ_MASK0_RD, underrun, active)) {
*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
np->stats.tx_errors++; np->stats.tx_errors++;
D(printk("ethernet receiver underrun!\n")); D(printk("ethernet receiver underrun!\n"));
} }
...@@ -1096,6 +1238,9 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -1096,6 +1238,9 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
} }
/* check for excessive collision irq */ /* check for excessive collision irq */
if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) { if (irqbits & IO_STATE(R_IRQ_MASK0_RD, excessive_col, active)) {
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
*R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
*R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr); *R_NETWORK_TR_CTRL = IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr);
np->stats.tx_errors++; np->stats.tx_errors++;
D(printk("ethernet excessive collisions!\n")); D(printk("ethernet excessive collisions!\n"));
...@@ -1210,14 +1355,10 @@ e100_close(struct net_device *dev) ...@@ -1210,14 +1355,10 @@ e100_close(struct net_device *dev)
{ {
struct net_local *np = (struct net_local *)dev->priv; struct net_local *np = (struct net_local *)dev->priv;
printk("Closing %s.\n", dev->name); printk(KERN_INFO "Closing %s.\n", dev->name);
netif_stop_queue(dev); netif_stop_queue(dev);
*R_NETWORK_GEN_CONFIG =
IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) |
IO_STATE(R_NETWORK_GEN_CONFIG, enable, off);
*R_IRQ_MASK0_CLR = *R_IRQ_MASK0_CLR =
IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) | IO_STATE(R_IRQ_MASK0_CLR, overrun, clr) |
IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) | IO_STATE(R_IRQ_MASK0_CLR, underrun, clr) |
...@@ -1245,6 +1386,10 @@ e100_close(struct net_device *dev) ...@@ -1245,6 +1386,10 @@ e100_close(struct net_device *dev)
update_rx_stats(&np->stats); update_rx_stats(&np->stats);
update_tx_stats(&np->stats); update_tx_stats(&np->stats);
/* Stop speed/duplex timers */
del_timer(&speed_timer);
del_timer(&duplex_timer);
return 0; return 0;
} }
...@@ -1259,7 +1404,7 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1259,7 +1404,7 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCETHTOOL: case SIOCETHTOOL:
return e100_ethtool_ioctl(dev,ifr); return e100_ethtool_ioctl(dev,ifr);
case SIOCGMIIPHY: /* Get PHY address */ case SIOCGMIIPHY: /* Get PHY address */
data->phy_id = MDIO_PHYS_ADDR; data->phy_id = mdio_phy_addr;
break; break;
case SIOCGMIIREG: /* Read MII register */ case SIOCGMIIREG: /* Read MII register */
data->val_out = e100_get_mdio_reg(data->reg_num); data->val_out = e100_get_mdio_reg(data->reg_num);
...@@ -1278,7 +1423,7 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -1278,7 +1423,7 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */ case SET_ETH_SPEED_AUTO: /* Auto negotiate speed */
e100_set_speed(0); e100_set_speed(0);
break; break;
case SET_ETH_DUPLEX_HALF: /* Hhalf duplex. */ case SET_ETH_DUPLEX_HALF: /* Half duplex. */
e100_set_duplex(half); e100_set_duplex(half);
break; break;
case SET_ETH_DUPLEX_FULL: /* Full duplex. */ case SET_ETH_DUPLEX_FULL: /* Full duplex. */
...@@ -1312,12 +1457,12 @@ e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -1312,12 +1457,12 @@ e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
ecmd.port = PORT_TP; ecmd.port = PORT_TP;
ecmd.transceiver = XCVR_EXTERNAL; ecmd.transceiver = XCVR_EXTERNAL;
ecmd.phy_address = MDIO_PHYS_ADDR; ecmd.phy_address = mdio_phy_addr;
ecmd.speed = current_speed; ecmd.speed = current_speed;
ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
ecmd.advertising = ADVERTISED_TP; ecmd.advertising = ADVERTISED_TP;
if (current_duplex == autoneg && current_speed_selection == 0) if (current_duplex == autoneg && current_speed_selection == 0)
ecmd.advertising = ADVERTISED_Autoneg; ecmd.advertising |= ADVERTISED_Autoneg;
else { else {
ecmd.advertising |= ecmd.advertising |=
ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
...@@ -1355,7 +1500,7 @@ e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) ...@@ -1355,7 +1500,7 @@ e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
struct ethtool_drvinfo info; struct ethtool_drvinfo info;
memset((void *) &info, 0, sizeof (info)); memset((void *) &info, 0, sizeof (info));
strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1); strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1);
strncpy(info.version, "$Revision: 1.17 $", sizeof(info.version) - 1); strncpy(info.version, "$Revision: 1.22 $", sizeof(info.version) - 1);
strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1); strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1); strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
info.regdump_len = 0; info.regdump_len = 0;
...@@ -1595,7 +1740,11 @@ e100_set_network_leds(int active) ...@@ -1595,7 +1740,11 @@ e100_set_network_leds(int active)
if (!current_speed) { if (!current_speed) {
/* Make LED red, link is down */ /* Make LED red, link is down */
#if defined(CONFIG_ETRAX_NETWORK_RED_ON_NO_CONNECTION)
LED_NETWORK_SET(LED_RED);
#else
LED_NETWORK_SET(LED_OFF); LED_NETWORK_SET(LED_OFF);
#endif
} }
else if (light_leds) { else if (light_leds) {
if (current_speed == 10) { if (current_speed == 10) {
...@@ -1615,4 +1764,26 @@ etrax_init_module(void) ...@@ -1615,4 +1764,26 @@ etrax_init_module(void)
return etrax_ethernet_init(); return etrax_ethernet_init();
} }
static int __init
e100_boot_setup(char* str)
{
struct sockaddr sa = {0};
int i;
/* Parse the colon separated Ethernet station address */
for (i = 0; i < ETH_ALEN; i++) {
unsigned int tmp;
if (sscanf(str + 3*i, "%2x", &tmp) != 1) {
printk(KERN_WARNING "Malformed station address");
return 0;
}
sa.sa_data[i] = (char)tmp;
}
default_mac = sa;
return 1;
}
__setup("etrax100_eth=", e100_boot_setup);
module_init(etrax_init_module); module_init(etrax_init_module);
/* $Id: gpio.c,v 1.8 2003/07/04 08:27:37 starvik Exp $ /* $Id: gpio.c,v 1.11 2004/05/14 07:58:03 starvik Exp $
* *
* Etrax general port I/O device * Etrax general port I/O device
* *
...@@ -9,6 +9,12 @@ ...@@ -9,6 +9,12 @@
* Johan Adolfsson (read/set directions, write, port G) * Johan Adolfsson (read/set directions, write, port G)
* *
* $Log: gpio.c,v $ * $Log: gpio.c,v $
* Revision 1.11 2004/05/14 07:58:03 starvik
* Merge of changes from 2.4
*
* Revision 1.9 2003/09/11 07:29:48 starvik
* Merge of Linux 2.6.0-test5
*
* Revision 1.8 2003/07/04 08:27:37 starvik * Revision 1.8 2003/07/04 08:27:37 starvik
* Merge of Linux 2.5.74 * Merge of Linux 2.5.74
* *
...@@ -183,6 +189,7 @@ struct gpio_private { ...@@ -183,6 +189,7 @@ struct gpio_private {
static struct gpio_private *alarmlist = 0; static struct gpio_private *alarmlist = 0;
static int gpio_some_alarms = 0; /* Set if someone uses alarm */ static int gpio_some_alarms = 0; /* Set if someone uses alarm */
static unsigned long gpio_pa_irq_enabled_mask = 0;
/* Port A and B use 8 bit access, but Port G is 32 bit */ /* Port A and B use 8 bit access, but Port G is 32 bit */
#define NUM_PORTS (GPIO_MINOR_B+1) #define NUM_PORTS (GPIO_MINOR_B+1)
...@@ -252,13 +259,19 @@ gpio_poll(struct file *file, ...@@ -252,13 +259,19 @@ gpio_poll(struct file *file,
unsigned long data; unsigned long data;
poll_wait(file, &priv->alarm_wq, wait); poll_wait(file, &priv->alarm_wq, wait);
if (priv->minor == GPIO_MINOR_A) { if (priv->minor == GPIO_MINOR_A) {
unsigned long flags;
unsigned long tmp; unsigned long tmp;
data = *R_PORT_PA_DATA; data = *R_PORT_PA_DATA;
/* PA has support for high level interrupt - /* PA has support for high level interrupt -
* lets activate for those low and with highalarm set * lets activate for those low and with highalarm set
*/ */
tmp = ~data & priv->highalarm & 0xFF; tmp = ~data & priv->highalarm & 0xFF;
*R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR);
save_flags(flags); cli();
gpio_pa_irq_enabled_mask |= tmp;
*R_IRQ_MASK1_SET = tmp;
restore_flags(flags);
} else if (priv->minor == GPIO_MINOR_B) } else if (priv->minor == GPIO_MINOR_B)
data = *R_PORT_PB_DATA; data = *R_PORT_PB_DATA;
else if (priv->minor == GPIO_MINOR_G) else if (priv->minor == GPIO_MINOR_G)
...@@ -312,12 +325,15 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -312,12 +325,15 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
unsigned long tmp; unsigned long tmp;
/* Find what PA interrupts are active */ /* Find what PA interrupts are active */
tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF; tmp = (*R_IRQ_READ1);
/* Find those that we have enabled */
tmp &= gpio_pa_irq_enabled_mask;
/* Clear them.. */ /* Clear them.. */
/* NOTE: Maybe we need to be more careful here if some other *R_IRQ_MASK1_CLR = tmp;
* driver uses PA interrupt as well? gpio_pa_irq_enabled_mask &= ~tmp;
*/
*R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR);
if (gpio_some_alarms) { if (gpio_some_alarms) {
return IRQ_RETVAL(etrax_gpio_wake_up_check()); return IRQ_RETVAL(etrax_gpio_wake_up_check());
} }
...@@ -386,7 +402,7 @@ static int ...@@ -386,7 +402,7 @@ static int
gpio_open(struct inode *inode, struct file *filp) gpio_open(struct inode *inode, struct file *filp)
{ {
struct gpio_private *priv; struct gpio_private *priv;
int p = iminor(inode); int p = MINOR(inode->i_rdev);
if (p > GPIO_MINOR_LAST) if (p > GPIO_MINOR_LAST)
return -EINVAL; return -EINVAL;
...@@ -479,6 +495,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) ...@@ -479,6 +495,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */
} else if (priv->minor == GPIO_MINOR_G) { } else if (priv->minor == GPIO_MINOR_G) {
/* We must fiddle with R_GEN_CONFIG to change dir */ /* We must fiddle with R_GEN_CONFIG to change dir */
save_flags(flags); cli();
if (((arg & dir_g_in_bits) != arg) && if (((arg & dir_g_in_bits) != arg) &&
(arg & changeable_dir_g)) { (arg & changeable_dir_g)) {
arg &= changeable_dir_g; arg &= changeable_dir_g;
...@@ -503,16 +520,17 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) ...@@ -503,16 +520,17 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg)
dir_g_in_bits |= (1<<24); dir_g_in_bits |= (1<<24);
dir_g_out_bits &= ~(1<<24); dir_g_out_bits &= ~(1<<24);
} }
printk("gpio: SETINPUT on port G set " D(printk(KERN_INFO "gpio: SETINPUT on port G set "
"genconfig to 0x%08lX " "genconfig to 0x%08lX "
"in_bits: 0x%08lX " "in_bits: 0x%08lX "
"out_bits: 0x%08lX\n", "out_bits: 0x%08lX\n",
(unsigned long)genconfig_shadow, (unsigned long)genconfig_shadow,
dir_g_in_bits, dir_g_out_bits); dir_g_in_bits, dir_g_out_bits));
*R_GEN_CONFIG = genconfig_shadow; *R_GEN_CONFIG = genconfig_shadow;
/* Must be a >120 ns delay before writing this again */ /* Must be a >120 ns delay before writing this again */
} }
restore_flags(flags);
return dir_g_in_bits; return dir_g_in_bits;
} }
return 0; return 0;
...@@ -529,6 +547,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) ...@@ -529,6 +547,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
return *priv->dir_shadow; return *priv->dir_shadow;
} else if (priv->minor == GPIO_MINOR_G) { } else if (priv->minor == GPIO_MINOR_G) {
/* We must fiddle with R_GEN_CONFIG to change dir */ /* We must fiddle with R_GEN_CONFIG to change dir */
save_flags(flags); cli();
if (((arg & dir_g_out_bits) != arg) && if (((arg & dir_g_out_bits) != arg) &&
(arg & changeable_dir_g)) { (arg & changeable_dir_g)) {
/* Set bits in genconfig to set to output */ /* Set bits in genconfig to set to output */
...@@ -552,15 +571,16 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) ...@@ -552,15 +571,16 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg)
dir_g_out_bits |= (1<<24); dir_g_out_bits |= (1<<24);
dir_g_in_bits &= ~(1<<24); dir_g_in_bits &= ~(1<<24);
} }
printk("gpio: SETOUTPUT on port G set " D(printk(KERN_INFO "gpio: SETOUTPUT on port G set "
"genconfig to 0x%08lX " "genconfig to 0x%08lX "
"in_bits: 0x%08lX " "in_bits: 0x%08lX "
"out_bits: 0x%08lX\n", "out_bits: 0x%08lX\n",
(unsigned long)genconfig_shadow, (unsigned long)genconfig_shadow,
dir_g_in_bits, dir_g_out_bits); dir_g_in_bits, dir_g_out_bits));
*R_GEN_CONFIG = genconfig_shadow; *R_GEN_CONFIG = genconfig_shadow;
/* Must be a >120 ns delay before writing this again */ /* Must be a >120 ns delay before writing this again */
} }
restore_flags(flags);
return dir_g_out_bits & 0x7FFFFFFF; return dir_g_out_bits & 0x7FFFFFFF;
} }
return 0; return 0;
...@@ -625,6 +645,20 @@ gpio_ioctl(struct inode *inode, struct file *file, ...@@ -625,6 +645,20 @@ gpio_ioctl(struct inode *inode, struct file *file,
// clear alarm for bits with 1 in arg // clear alarm for bits with 1 in arg
priv->highalarm &= ~arg; priv->highalarm &= ~arg;
priv->lowalarm &= ~arg; priv->lowalarm &= ~arg;
{
/* Must update gpio_some_alarms */
struct gpio_private *p = alarmlist;
int some_alarms;
some_alarms = 0;
while (p) {
if (p->highalarm | p->lowalarm) {
some_alarms = 1;
break;
}
p = p->next;
}
gpio_some_alarms = some_alarms;
}
break; break;
case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */
/* Read direction 0=input 1=output */ /* Read direction 0=input 1=output */
...@@ -844,9 +878,9 @@ static void __init gpio_init_port_g(void) ...@@ -844,9 +878,9 @@ static void __init gpio_init_port_g(void)
dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g);
printk("GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n",
dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA);
printk("GPIO port G: dir: %08lX changeable: %08lX\n", printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n",
dir_g_shadow, changeable_dir_g); dir_g_shadow, changeable_dir_g);
} }
...@@ -883,7 +917,7 @@ gpio_init(void) ...@@ -883,7 +917,7 @@ gpio_init(void)
#endif #endif
gpio_init_port_g(); gpio_init_port_g();
printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n");
/* We call etrax_gpio_wake_up_check() from timer interrupt and /* We call etrax_gpio_wake_up_check() from timer interrupt and
* from cpu_idle() in kernel/process.c * from cpu_idle() in kernel/process.c
* The check in cpu_idle() reduces latency from ~15 ms to ~6 ms * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms
...@@ -891,11 +925,11 @@ gpio_init(void) ...@@ -891,11 +925,11 @@ gpio_init(void)
*/ */
if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt, if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) { SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) {
printk("err: timer0 irq for gpio\n"); printk(KERN_CRIT "err: timer0 irq for gpio\n");
} }
if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt, if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt,
SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) { SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) {
printk("err: PA irq for gpio\n"); printk(KERN_CRIT "err: PA irq for gpio\n");
} }
......
...@@ -12,6 +12,12 @@ ...@@ -12,6 +12,12 @@
*! don't use PB_I2C if DS1302 uses same bits, *! don't use PB_I2C if DS1302 uses same bits,
*! use PB. *! use PB.
*! $Log: i2c.c,v $ *! $Log: i2c.c,v $
*! Revision 1.7 2004/05/28 09:26:59 starvik
*! Modified I2C initialization to work in 2.6.
*!
*! Revision 1.6 2004/05/14 07:58:03 starvik
*! Merge of changes from 2.4
*!
*! Revision 1.4 2002/12/11 13:13:57 starvik *! Revision 1.4 2002/12/11 13:13:57 starvik
*! Added arch/ to v10 specific includes *! Added arch/ to v10 specific includes
*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) *! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer)
...@@ -63,7 +69,7 @@ ...@@ -63,7 +69,7 @@
*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN
*! *!
*!***************************************************************************/ *!***************************************************************************/
/* $Id: i2c.c,v 1.4 2002/12/11 13:13:57 starvik Exp $ */ /* $Id: i2c.c,v 1.7 2004/05/28 09:26:59 starvik Exp $ */
/****************** INCLUDE FILES SECTION ***********************************/ /****************** INCLUDE FILES SECTION ***********************************/
...@@ -310,6 +316,12 @@ i2c_inbyte(void) ...@@ -310,6 +316,12 @@ i2c_inbyte(void)
} }
i2c_clk(I2C_CLOCK_HIGH); i2c_clk(I2C_CLOCK_HIGH);
i2c_delay(CLOCK_HIGH_TIME); i2c_delay(CLOCK_HIGH_TIME);
/*
* we leave the clock low, getbyte is usually followed
* by sendack/nack, they assume the clock to be low
*/
i2c_clk(I2C_CLOCK_LOW);
return aBitByte; return aBitByte;
} }
...@@ -371,6 +383,13 @@ i2c_getack(void) ...@@ -371,6 +383,13 @@ i2c_getack(void)
i2c_delay(CLOCK_HIGH_TIME/2); i2c_delay(CLOCK_HIGH_TIME/2);
} }
/*
* our clock is high now, make sure data is low
* before we enable our output. If we keep data high
* and enable output, we would generate a stop condition.
*/
i2c_data(I2C_DATA_LOW);
/* /*
* end clock pulse * end clock pulse
*/ */
...@@ -426,6 +445,37 @@ i2c_sendack(void) ...@@ -426,6 +445,37 @@ i2c_sendack(void)
i2c_dir_in(); i2c_dir_in();
} }
/*#---------------------------------------------------------------------------
*#
*# FUNCTION NAME: i2c_sendnack
*#
*# DESCRIPTION : Sends NACK on received data
*#
*#--------------------------------------------------------------------------*/
void
i2c_sendnack(void)
{
/*
* enable output
*/
i2c_delay(CLOCK_LOW_TIME);
i2c_dir_out();
/*
* set data high
*/
i2c_data(I2C_DATA_HIGH);
/*
* generate clock pulse
*/
i2c_delay(CLOCK_HIGH_TIME/6);
i2c_clk(I2C_CLOCK_HIGH);
i2c_delay(CLOCK_HIGH_TIME);
i2c_clk(I2C_CLOCK_LOW);
i2c_delay(CLOCK_LOW_TIME);
i2c_dir_in();
}
/*#--------------------------------------------------------------------------- /*#---------------------------------------------------------------------------
*# *#
*# FUNCTION NAME: i2c_writereg *# FUNCTION NAME: i2c_writereg
...@@ -489,7 +539,7 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, ...@@ -489,7 +539,7 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg,
} while(error && cntr--); } while(error && cntr--);
i2c_delay(CLOCK_LOW_TIME); i2c_delay(CLOCK_LOW_TIME);
return -error; return -error;
} }
...@@ -557,7 +607,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) ...@@ -557,7 +607,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg)
*/ */
b = i2c_inbyte(); b = i2c_inbyte();
/* /*
* send Ack * last received byte needs to be nacked
* instead of acked
*/ */
i2c_sendack(); i2c_sendack();
/* /*
...@@ -634,11 +685,9 @@ static struct file_operations i2c_fops = { ...@@ -634,11 +685,9 @@ static struct file_operations i2c_fops = {
.release = i2c_release, .release = i2c_release,
}; };
static int __init int __init
i2c_init(void) i2c_init(void)
{ {
int res;
/* Setup and enable the Port B I2C interface */ /* Setup and enable the Port B I2C interface */
#ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C
...@@ -656,21 +705,28 @@ i2c_init(void) ...@@ -656,21 +705,28 @@ i2c_init(void)
IO_STATE(R_PORT_PB_DIR, dir0, input) | IO_STATE(R_PORT_PB_DIR, dir0, input) |
IO_STATE(R_PORT_PB_DIR, dir1, output)); IO_STATE(R_PORT_PB_DIR, dir1, output));
/* register char device */ return 0;
}
static int __init
i2c_register(void)
{
int res;
res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); i2c_init();
res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops);
if(res < 0) { if(res < 0) {
printk(KERN_ERR "i2c: couldn't get a major number.\n"); printk(KERN_ERR "i2c: couldn't get a major number.\n");
return res; return res;
} }
printk("I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n");
return 0; return 0;
} }
/* this makes sure that i2c_init is called during boot */ /* this makes sure that i2c_register is called during boot */
module_init(i2c_init); module_init(i2c_register);
/****************** END OF FILE i2c.c ********************************/ /****************** END OF FILE i2c.c ********************************/
/* $Id: i2c.h,v 1.2 2002/11/18 13:16:06 starvik Exp $ */ /* $Id: i2c.h,v 1.3 2004/05/28 09:26:59 starvik Exp $ */
int i2c_init(void);
/* High level I2C actions */ /* High level I2C actions */
int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue);
......
/* $Id: ide.c,v 1.1 2004/01/22 08:22:58 starvik Exp $
*
* Etrax specific IDE functions, like init and PIO-mode setting etc.
* Almost the entire ide.c is used for the rest of the Etrax ATA driver.
* Copyright (c) 2000-2004 Axis Communications AB
*
* Authors: Bjorn Wesen (initial version)
* Mikael Starvik (pio setup stuff, Linux 2.6 port)
*/
/* Regarding DMA:
*
* There are two forms of DMA - "DMA handshaking" between the interface and the drive,
* and DMA between the memory and the interface. We can ALWAYS use the latter, since it's
* something built-in in the Etrax. However only some drives support the DMA-mode handshaking
* on the ATA-bus. The normal PC driver and Triton interface disables memory-if DMA when the
* device can't do DMA handshaking for some stupid reason. We don't need to do that.
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/arch/svinto.h>
#include <asm/dma.h>
/* number of Etrax DMA descriptors */
#define MAX_DMA_DESCRS 64
/* number of times to retry busy-flags when reading/writing IDE-registers
* this can't be too high because a hung harddisk might cause the watchdog
* to trigger (sometimes INB and OUTB are called with irq's disabled)
*/
#define IDE_REGISTER_TIMEOUT 300
#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
/* address where the memory-mapped IDE reset bit lives, if used */
static volatile unsigned long *reset_addr;
#endif
static int e100_read_command = 0;
#define LOWDB(x)
#define D(x)
void
etrax100_ide_outw(unsigned short data, ide_ioreg_t reg) {
int timeleft;
LOWDB(printk("ow: data 0x%x, reg 0x%x\n", data, reg));
/* note the lack of handling any timeouts. we stop waiting, but we don't
* really notify anybody.
*/
timeleft = IDE_REGISTER_TIMEOUT;
/* wait for busy flag */
while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
timeleft--;
/*
* Fall through at a timeout, so the ongoing command will be
* aborted by the write below, which is expected to be a dummy
* command to the command register. This happens when a faulty
* drive times out on a command. See comment on timeout in
* INB.
*/
if(!timeleft)
printk("ATA timeout reg 0x%lx := 0x%x\n", reg, data);
*R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */
timeleft = IDE_REGISTER_TIMEOUT;
/* wait for transmitter ready */
while(timeleft && !(*R_ATA_STATUS_DATA &
IO_MASK(R_ATA_STATUS_DATA, tr_rdy)))
timeleft--;
}
void
etrax100_ide_outb(unsigned char data, ide_ioreg_t reg)
{
etrax100_ide_outw(data, reg);
}
void
etrax100_ide_outbsync(ide_drive_t *drive, u8 addr, unsigned long port)
{
etrax100_ide_outw(addr, port);
}
unsigned short
etrax100_ide_inw(ide_ioreg_t reg) {
int status;
int timeleft;
timeleft = IDE_REGISTER_TIMEOUT;
/* wait for busy flag */
while(timeleft && (*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)))
timeleft--;
if(!timeleft) {
/*
* If we're asked to read the status register, like for
* example when a command does not complete for an
* extended time, but the ATA interface is stuck in a
* busy state at the *ETRAX* ATA interface level (as has
* happened repeatedly with at least one bad disk), then
* the best thing to do is to pretend that we read
* "busy" in the status register, so the IDE driver will
* time-out, abort the ongoing command and perform a
* reset sequence. Note that the subsequent OUT_BYTE
* call will also timeout on busy, but as long as the
* write is still performed, everything will be fine.
*/
if ((reg & IO_MASK (R_ATA_CTRL_DATA, addr))
== IO_FIELD (R_ATA_CTRL_DATA, addr, IDE_STATUS_OFFSET))
return BUSY_STAT;
else
/* For other rare cases we assume 0 is good enough. */
return 0;
}
*R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */
timeleft = IDE_REGISTER_TIMEOUT;
/* wait for available */
while(timeleft && !((status = *R_ATA_STATUS_DATA) &
IO_MASK(R_ATA_STATUS_DATA, dav)))
timeleft--;
if(!timeleft)
return 0;
LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg));
return (unsigned short)status;
}
unsigned char
etrax100_ide_inb(ide_ioreg_t reg)
{
return (unsigned char)etrax100_ide_inw(reg);
}
/* PIO timing (in R_ATA_CONFIG)
*
* _____________________________
* ADDRESS : ________/
*
* _______________
* DIOR : ____________/ \__________
*
* _______________
* DATA : XXXXXXXXXXXXXXXX_______________XXXXXXXX
*
*
* DIOR is unbuffered while address and data is buffered.
* This creates two problems:
* 1. The DIOR pulse is to early (because it is unbuffered)
* 2. The rise time of DIOR is long
*
* There are at least three different plausible solutions
* 1. Use a pad capable of larger currents in Etrax
* 2. Use an external buffer
* 3. Make the strobe pulse longer
*
* Some of the strobe timings below are modified to compensate
* for this. This implies a slight performance decrease.
*
* THIS SHOULD NEVER BE CHANGED!
*
* TODO: Is this true for the latest LX boards still ?
*/
#define ATA_DMA2_STROBE 4
#define ATA_DMA2_HOLD 0
#define ATA_DMA1_STROBE 4
#define ATA_DMA1_HOLD 1
#define ATA_DMA0_STROBE 12
#define ATA_DMA0_HOLD 9
#define ATA_PIO4_SETUP 1
#define ATA_PIO4_STROBE 5
#define ATA_PIO4_HOLD 0
#define ATA_PIO3_SETUP 1
#define ATA_PIO3_STROBE 5
#define ATA_PIO3_HOLD 1
#define ATA_PIO2_SETUP 1
#define ATA_PIO2_STROBE 6
#define ATA_PIO2_HOLD 2
#define ATA_PIO1_SETUP 2
#define ATA_PIO1_STROBE 11
#define ATA_PIO1_HOLD 4
#define ATA_PIO0_SETUP 4
#define ATA_PIO0_STROBE 19
#define ATA_PIO0_HOLD 4
static int e100_dma_check (ide_drive_t *drive);
static int e100_dma_begin (ide_drive_t *drive);
static int e100_dma_end (ide_drive_t *drive);
static int e100_dma_read (ide_drive_t *drive);
static int e100_dma_write (ide_drive_t *drive);
static void e100_ide_input_data (ide_drive_t *drive, void *, unsigned int);
static void e100_ide_output_data (ide_drive_t *drive, void *, unsigned int);
static void e100_atapi_input_bytes(ide_drive_t *drive, void *, unsigned int);
static void e100_atapi_output_bytes(ide_drive_t *drive, void *, unsigned int);
static int e100_dma_off (ide_drive_t *drive);
static int e100_dma_verbose (ide_drive_t *drive);
/*
* good_dma_drives() lists the model names (from "hdparm -i")
* of drives which do not support mword2 DMA but which are
* known to work fine with this interface under Linux.
*/
const char *good_dma_drives[] = {"Micropolis 2112A",
"CONNER CTMA 4000",
"CONNER CTT8000-A",
NULL};
static void tune_e100_ide(ide_drive_t *drive, byte pio)
{
pio = 4;
/* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */
/* set pio mode! */
switch(pio) {
case 0:
*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO0_SETUP ) |
IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO0_STROBE ) |
IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO0_HOLD ) );
break;
case 1:
*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO1_SETUP ) |
IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO1_STROBE ) |
IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO1_HOLD ) );
break;
case 2:
*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO2_SETUP ) |
IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO2_STROBE ) |
IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO2_HOLD ) );
break;
case 3:
*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO3_SETUP ) |
IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO3_STROBE ) |
IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO3_HOLD ) );
break;
case 4:
*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) |
IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) );
break;
}
}
void __init
init_e100_ide (void)
{
volatile unsigned int dummy;
int h;
printk("ide: ETRAX 100LX built-in ATA DMA controller\n");
/* first fill in some stuff in the ide_hwifs fields */
for(h = 0; h < MAX_HWIFS; h++) {
ide_hwif_t *hwif = &ide_hwifs[h];
hwif->mmio = 2;
hwif->chipset = ide_etrax100;
hwif->tuneproc = &tune_e100_ide;
hwif->ata_input_data = &e100_ide_input_data;
hwif->ata_output_data = &e100_ide_output_data;
hwif->atapi_input_bytes = &e100_atapi_input_bytes;
hwif->atapi_output_bytes = &e100_atapi_output_bytes;
hwif->ide_dma_check = &e100_dma_check;
hwif->ide_dma_end = &e100_dma_end;
hwif->ide_dma_write = &e100_dma_write;
hwif->ide_dma_read = &e100_dma_read;
hwif->ide_dma_begin = &e100_dma_begin;
hwif->OUTB = &etrax100_ide_outb;
hwif->OUTW = &etrax100_ide_outw;
hwif->OUTBSYNC = &etrax100_ide_outbsync;
hwif->INB = &etrax100_ide_inb;
hwif->INW = &etrax100_ide_inw;
hwif->ide_dma_off_quietly = &e100_dma_off;
hwif->ide_dma_verbose = &e100_dma_verbose;
hwif->sg_table =
kmalloc(sizeof(struct scatterlist) * PRD_ENTRIES, GFP_KERNEL);
}
/* actually reset and configure the etrax100 ide/ata interface */
*R_ATA_CTRL_DATA = 0;
*R_ATA_TRANSFER_CNT = 0;
*R_ATA_CONFIG = 0;
genconfig_shadow = (genconfig_shadow &
~IO_MASK(R_GEN_CONFIG, dma2) &
~IO_MASK(R_GEN_CONFIG, dma3) &
~IO_MASK(R_GEN_CONFIG, ata)) |
( IO_STATE( R_GEN_CONFIG, dma3, ata ) |
IO_STATE( R_GEN_CONFIG, dma2, ata ) |
IO_STATE( R_GEN_CONFIG, ata, select ) );
*R_GEN_CONFIG = genconfig_shadow;
/* pull the chosen /reset-line low */
#ifdef CONFIG_ETRAX_IDE_G27_RESET
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 0);
#endif
#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0);
#endif
#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0);
#endif
#ifdef CONFIG_ETRAX_IDE_PB7_RESET
port_pb_dir_shadow = port_pb_dir_shadow |
IO_STATE(R_PORT_PB_DIR, dir7, output);
*R_PORT_PB_DIR = port_pb_dir_shadow;
REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 7, 1);
#endif
/* wait some */
udelay(25);
/* de-assert bus-reset */
#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 1);
#endif
#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 1);
#endif
#ifdef CONFIG_ETRAX_IDE_G27_RESET
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, 1);
#endif
/* make a dummy read to set the ata controller in a proper state */
dummy = *R_ATA_STATUS_DATA;
*R_ATA_CONFIG = ( IO_FIELD( R_ATA_CONFIG, enable, 1 ) |
IO_FIELD( R_ATA_CONFIG, dma_strobe, ATA_DMA2_STROBE ) |
IO_FIELD( R_ATA_CONFIG, dma_hold, ATA_DMA2_HOLD ) |
IO_FIELD( R_ATA_CONFIG, pio_setup, ATA_PIO4_SETUP ) |
IO_FIELD( R_ATA_CONFIG, pio_strobe, ATA_PIO4_STROBE ) |
IO_FIELD( R_ATA_CONFIG, pio_hold, ATA_PIO4_HOLD ) );
*R_ATA_CTRL_DATA = ( IO_STATE( R_ATA_CTRL_DATA, rw, read) |
IO_FIELD( R_ATA_CTRL_DATA, addr, 1 ) );
while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag*/
*R_IRQ_MASK0_SET = ( IO_STATE( R_IRQ_MASK0_SET, ata_irq0, set ) |
IO_STATE( R_IRQ_MASK0_SET, ata_irq1, set ) |
IO_STATE( R_IRQ_MASK0_SET, ata_irq2, set ) |
IO_STATE( R_IRQ_MASK0_SET, ata_irq3, set ) );
printk("ide: waiting %d seconds for drives to regain consciousness\n",
CONFIG_ETRAX_IDE_DELAY);
h = jiffies + (CONFIG_ETRAX_IDE_DELAY * HZ);
while(time_before(jiffies, h)) /* nothing */ ;
/* reset the dma channels we will use */
RESET_DMA(ATA_TX_DMA_NBR);
RESET_DMA(ATA_RX_DMA_NBR);
WAIT_DMA(ATA_TX_DMA_NBR);
WAIT_DMA(ATA_RX_DMA_NBR);
}
static int e100_dma_off (ide_drive_t *drive)
{
return 0;
}
static int e100_dma_verbose (ide_drive_t *drive)
{
printk(", DMA(mode 2)");
return 0;
}
static etrax_dma_descr mydescr;
/*
* The following routines are mainly used by the ATAPI drivers.
*
* These routines will round up any request for an odd number of bytes,
* so if an odd bytecount is specified, be sure that there's at least one
* extra byte allocated for the buffer.
*/
static void
e100_atapi_input_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
ide_ioreg_t data_reg = IDE_DATA_REG;
D(printk("atapi_input_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));
if(bytecount & 1) {
printk("warning, odd bytecount in cdrom_in_bytes = %d.\n", bytecount);
bytecount++; /* to round off */
}
/* make sure the DMA channel is available */
RESET_DMA(ATA_RX_DMA_NBR);
WAIT_DMA(ATA_RX_DMA_NBR);
/* setup DMA descriptor */
mydescr.sw_len = bytecount;
mydescr.ctrl = d_eol;
mydescr.buf = virt_to_phys(buffer);
/* start the dma channel */
*R_DMA_CH3_FIRST = virt_to_phys(&mydescr);
*R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
/* initiate a multi word dma read using PIO handshaking */
*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
*R_ATA_CTRL_DATA = data_reg |
IO_STATE(R_ATA_CTRL_DATA, rw, read) |
IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
IO_STATE(R_ATA_CTRL_DATA, multi, on) |
IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
/* wait for completion */
LED_DISK_READ(1);
WAIT_DMA(ATA_RX_DMA_NBR);
LED_DISK_READ(0);
#if 0
/* old polled transfer code
* this should be moved into a new function that can do polled
* transfers if DMA is not available
*/
/* initiate a multi word read */
*R_ATA_TRANSFER_CNT = wcount << 1;
*R_ATA_CTRL_DATA = data_reg |
IO_STATE(R_ATA_CTRL_DATA, rw, read) |
IO_STATE(R_ATA_CTRL_DATA, src_dst, register) |
IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
IO_STATE(R_ATA_CTRL_DATA, multi, on) |
IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
/* svinto has a latency until the busy bit actually is set */
nop(); nop();
nop(); nop();
nop(); nop();
nop(); nop();
nop(); nop();
/* unit should be busy during multi transfer */
while((status = *R_ATA_STATUS_DATA) & IO_MASK(R_ATA_STATUS_DATA, busy)) {
while(!(status & IO_MASK(R_ATA_STATUS_DATA, dav)))
status = *R_ATA_STATUS_DATA;
*ptr++ = (unsigned short)(status & 0xffff);
}
#endif
}
static void
e100_atapi_output_bytes (ide_drive_t *drive, void *buffer, unsigned int bytecount)
{
ide_ioreg_t data_reg = IDE_DATA_REG;
D(printk("atapi_output_bytes, dreg 0x%x, buffer 0x%x, count %d\n",
data_reg, buffer, bytecount));
if(bytecount & 1) {
printk("odd bytecount %d in atapi_out_bytes!\n", bytecount);
bytecount++;
}
/* make sure the DMA channel is available */
RESET_DMA(ATA_TX_DMA_NBR);
WAIT_DMA(ATA_TX_DMA_NBR);
/* setup DMA descriptor */
mydescr.sw_len = bytecount;
mydescr.ctrl = d_eol;
mydescr.buf = virt_to_phys(buffer);
/* start the dma channel */
*R_DMA_CH2_FIRST = virt_to_phys(&mydescr);
*R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
/* initiate a multi word dma write using PIO handshaking */
*R_ATA_TRANSFER_CNT = IO_FIELD(R_ATA_TRANSFER_CNT, count, bytecount >> 1);
*R_ATA_CTRL_DATA = data_reg |
IO_STATE(R_ATA_CTRL_DATA, rw, write) |
IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
IO_STATE(R_ATA_CTRL_DATA, multi, on) |
IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
/* wait for completion */
LED_DISK_WRITE(1);
WAIT_DMA(ATA_TX_DMA_NBR);
LED_DISK_WRITE(0);
#if 0
/* old polled write code - see comment in input_bytes */
/* wait for busy flag */
while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
/* initiate a multi word write */
*R_ATA_TRANSFER_CNT = bytecount >> 1;
ctrl = data_reg |
IO_STATE(R_ATA_CTRL_DATA, rw, write) |
IO_STATE(R_ATA_CTRL_DATA, src_dst, register) |
IO_STATE(R_ATA_CTRL_DATA, handsh, pio) |
IO_STATE(R_ATA_CTRL_DATA, multi, on) |
IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
LED_DISK_WRITE(1);
/* Etrax will set busy = 1 until the multi pio transfer has finished
* and tr_rdy = 1 after each successful word transfer.
* When the last byte has been transferred Etrax will first set tr_tdy = 1
* and then busy = 0 (not in the same cycle). If we read busy before it
* has been set to 0 we will think that we should transfer more bytes
* and then tr_rdy would be 0 forever. This is solved by checking busy
* in the inner loop.
*/
do {
*R_ATA_CTRL_DATA = ctrl | *ptr++;
while(!(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, tr_rdy)) &&
(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)));
} while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy));
LED_DISK_WRITE(0);
#endif
}
/*
* This is used for most PIO data transfers *from* the IDE interface
*/
static void
e100_ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
e100_atapi_input_bytes(drive, buffer, wcount << 2);
}
/*
* This is used for most PIO data transfers *to* the IDE interface
*/
static void
e100_ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
e100_atapi_output_bytes(drive, buffer, wcount << 2);
}
/* we only have one DMA channel on the chip for ATA, so we can keep these statically */
static etrax_dma_descr ata_descrs[MAX_DMA_DESCRS];
static unsigned int ata_tot_size;
/*
* e100_ide_build_dmatable() prepares a dma request.
* Returns 0 if all went okay, returns 1 otherwise.
*/
static int e100_ide_build_dmatable (ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
struct scatterlist* sg;
struct request *rq = HWGROUP(drive)->rq;
unsigned long size, addr;
unsigned int count = 0;
int i = 0;
sg = hwif->sg_table;
ata_tot_size = 0;
if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
u8 *virt_addr = rq->buffer;
int sector_count = rq->nr_sectors;
memset(&sg[0], 0, sizeof(*sg));
sg[0].page = virt_to_page(virt_addr);
sg[0].offset = offset_in_page(virt_addr);
sg[0].length = sector_count * SECTOR_SIZE;
hwif->sg_nents = i = 1;
}
else
{
hwif->sg_nents = i = blk_rq_map_sg(drive->queue, rq, hwif->sg_table);
}
while(i) {
/*
* Determine addr and size of next buffer area. We assume that
* individual virtual buffers are always composed linearly in
* physical memory. For example, we assume that any 8kB buffer
* is always composed of two adjacent physical 4kB pages rather
* than two possibly non-adjacent physical 4kB pages.
*/
/* group sequential buffers into one large buffer */
addr = page_to_phys(sg->page) + sg->offset;
size = sg_dma_len(sg);
while (sg++, --i) {
if ((addr + size) != page_to_phys(sg->page) + sg->offset)
break;
size += sg_dma_len(sg);
}
/* did we run out of descriptors? */
if(count >= MAX_DMA_DESCRS) {
printk("%s: too few DMA descriptors\n", drive->name);
return 1;
}
/* however, this case is more difficult - R_ATA_TRANSFER_CNT cannot be more
than 65536 words per transfer, so in that case we need to either
1) use a DMA interrupt to re-trigger R_ATA_TRANSFER_CNT and continue with
the descriptors, or
2) simply do the request here, and get dma_intr to only ide_end_request on
those blocks that were actually set-up for transfer.
*/
if(ata_tot_size + size > 131072) {
printk("too large total ATA DMA request, %d + %d!\n", ata_tot_size, (int)size);
return 1;
}
/* If size > 65536 it has to be splitted into new descriptors. Since we don't handle
size > 131072 only one split is necessary */
if(size > 65536) {
/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */
ata_descrs[count].ctrl = 0;
ata_descrs[count].buf = addr;
ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
count++;
ata_tot_size += 65536;
/* size and addr should refere to not handled data */
size -= 65536;
addr += 65536;
}
/* ok we want to do IO at addr, size bytes. set up a new descriptor entry */
if(size == 65536) {
ata_descrs[count].sw_len = 0; /* 0 means 65536, this is a 16-bit field */
} else {
ata_descrs[count].sw_len = size;
}
ata_descrs[count].ctrl = 0;
ata_descrs[count].buf = addr;
ata_descrs[count].next = virt_to_phys(&ata_descrs[count + 1]);
count++;
ata_tot_size += size;
}
if (count) {
/* set the end-of-list flag on the last descriptor */
ata_descrs[count - 1].ctrl |= d_eol;
/* return and say all is ok */
return 0;
}
printk("%s: empty DMA table?\n", drive->name);
return 1; /* let the PIO routines handle this weirdness */
}
static int config_drive_for_dma (ide_drive_t *drive)
{
const char **list;
struct hd_driveid *id = drive->id;
if (id && (id->capability & 1)) {
/* Enable DMA on any drive that supports mword2 DMA */
if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
drive->using_dma = 1;
return 0; /* DMA enabled */
}
/* Consult the list of known "good" drives */
list = good_dma_drives;
while (*list) {
if (!strcmp(*list++,id->model)) {
drive->using_dma = 1;
return 0; /* DMA enabled */
}
}
}
return 1; /* DMA not enabled */
}
/*
* etrax_dma_intr() is the handler for disk read/write DMA interrupts
*/
static ide_startstop_t etrax_dma_intr (ide_drive_t *drive)
{
int i, dma_stat;
byte stat;
LED_DISK_READ(0);
LED_DISK_WRITE(0);
dma_stat = HWIF(drive)->ide_dma_end(drive);
stat = HWIF(drive)->INB(IDE_STATUS_REG); /* get drive status */
if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
if (!dma_stat) {
struct request *rq;
rq = HWGROUP(drive)->rq;
for (i = rq->nr_sectors; i > 0;) {
i -= rq->current_nr_sectors;
DRIVER(drive)->end_request(drive, 1, rq->nr_sectors);
}
return ide_stopped;
}
printk("%s: bad DMA status\n", drive->name);
}
return DRIVER(drive)->error(drive, "dma_intr", stat);
}
/*
* Functions below initiates/aborts DMA read/write operations on a drive.
*
* The caller is assumed to have selected the drive and programmed the drive's
* sector address using CHS or LBA. All that remains is to prepare for DMA
* and then issue the actual read/write DMA/PIO command to the drive.
*
* For ATAPI devices, we just prepare for DMA and return. The caller should
* then issue the packet command to the drive and call us again with
* ide_dma_begin afterwards.
*
* Returns 0 if all went well.
* Returns 1 if DMA read/write could not be started, in which case
* the caller should revert to PIO for the current request.
*/
static int e100_dma_check(ide_drive_t *drive)
{
return config_drive_for_dma (drive);
}
static int e100_dma_end(ide_drive_t *drive)
{
/* TODO: check if something went wrong with the DMA */
return 0;
}
static int e100_start_dma(ide_drive_t *drive, int atapi, int reading)
{
if(reading) {
RESET_DMA(ATA_RX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
WAIT_DMA(ATA_RX_DMA_NBR);
/* set up the Etrax DMA descriptors */
if(e100_ide_build_dmatable (drive))
return 1;
if(!atapi) {
/* set the irq handler which will finish the request when DMA is done */
ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
/* issue cmd to drive */
if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
(drive->addressing == 1)) {
ide_task_t *args = HWGROUP(drive)->rq->special;
etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
} else if (drive->addressing) {
etrax100_ide_outb(WIN_READDMA_EXT, IDE_COMMAND_REG);
} else {
etrax100_ide_outb(WIN_READDMA, IDE_COMMAND_REG);
}
}
/* begin DMA */
/* need to do this before RX DMA due to a chip bug
* it is enough to just flush the part of the cache that
* corresponds to the buffers we start, but since HD transfers
* usually are more than 8 kB, it is easier to optimize for the
* normal case and just flush the entire cache. its the only
* way to be sure! (OB movie quote)
*/
flush_etrax_cache();
*R_DMA_CH3_FIRST = virt_to_phys(ata_descrs);
*R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start);
/* initiate a multi word dma read using DMA handshaking */
*R_ATA_TRANSFER_CNT =
IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
*R_ATA_CTRL_DATA =
IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
IO_STATE(R_ATA_CTRL_DATA, rw, read) |
IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
IO_STATE(R_ATA_CTRL_DATA, handsh, dma) |
IO_STATE(R_ATA_CTRL_DATA, multi, on) |
IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
LED_DISK_READ(1);
D(printk("dma read of %d bytes.\n", ata_tot_size));
} else {
/* writing */
RESET_DMA(ATA_TX_DMA_NBR); /* sometimes the DMA channel get stuck so we need to do this */
WAIT_DMA(ATA_TX_DMA_NBR);
/* set up the Etrax DMA descriptors */
if(e100_ide_build_dmatable (drive))
return 1;
if(!atapi) {
/* set the irq handler which will finish the request when DMA is done */
ide_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL);
/* issue cmd to drive */
if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&
(drive->addressing == 1)) {
ide_task_t *args = HWGROUP(drive)->rq->special;
etrax100_ide_outb(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);
} else if (drive->addressing) {
etrax100_ide_outb(WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
} else {
etrax100_ide_outb(WIN_WRITEDMA, IDE_COMMAND_REG);
}
}
/* begin DMA */
*R_DMA_CH2_FIRST = virt_to_phys(ata_descrs);
*R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, start);
/* initiate a multi word dma write using DMA handshaking */
*R_ATA_TRANSFER_CNT =
IO_FIELD(R_ATA_TRANSFER_CNT, count, ata_tot_size >> 1);
*R_ATA_CTRL_DATA =
IO_FIELD(R_ATA_CTRL_DATA, data, IDE_DATA_REG) |
IO_STATE(R_ATA_CTRL_DATA, rw, write) |
IO_STATE(R_ATA_CTRL_DATA, src_dst, dma) |
IO_STATE(R_ATA_CTRL_DATA, handsh, dma) |
IO_STATE(R_ATA_CTRL_DATA, multi, on) |
IO_STATE(R_ATA_CTRL_DATA, dma_size, word);
LED_DISK_WRITE(1);
D(printk("dma write of %d bytes.\n", ata_tot_size));
}
return 0;
}
static int e100_dma_write(ide_drive_t *drive)
{
e100_read_command = 0;
/* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
* then they call ide_dma_begin after they have issued the appropriate drive command
* themselves to actually start the chipset DMA. so we just return here if we're
* not a diskdrive.
*/
if (drive->media != ide_disk)
return 0;
return e100_start_dma(drive, 0, 0);
}
static int e100_dma_read(ide_drive_t *drive)
{
e100_read_command = 1;
/* ATAPI-devices (not disks) first call ide_dma_read/write to set the direction
* then they call ide_dma_begin after they have issued the appropriate drive command
* themselves to actually start the chipset DMA. so we just return here if we're
* not a diskdrive.
*/
if (drive->media != ide_disk)
return 0;
return e100_start_dma(drive, 0, 1);
}
static int e100_dma_begin(ide_drive_t *drive)
{
/* begin DMA, used by ATAPI devices which want to issue the
* appropriate IDE command themselves.
*
* they have already called ide_dma_read/write to set the
* static reading flag, now they call ide_dma_begin to do
* the real stuff. we tell our code below not to issue
* any IDE commands itself and jump into it.
*/
return e100_start_dma(drive, 1, e100_read_command);
}
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Author: Tobias Anderberg <tobiasa@axis.com>. * Author: Tobias Anderberg <tobiasa@axis.com>.
* *
* $Id: pcf8563.c,v 1.1 2002/12/12 08:27:26 starvik Exp $ * $Id: pcf8563.c,v 1.4 2004/05/28 09:26:59 starvik Exp $
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/bcd.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -39,7 +40,7 @@ ...@@ -39,7 +40,7 @@
#define PCF8563_MAJOR 121 /* Local major number. */ #define PCF8563_MAJOR 121 /* Local major number. */
#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */
#define PCF8563_NAME "PCF8563" #define PCF8563_NAME "PCF8563"
#define DRIVER_VERSION "$Revision: 1.1 $" #define DRIVER_VERSION "$Revision: 1.4 $"
/* I2C bus slave registers. */ /* I2C bus slave registers. */
#define RTC_I2C_READ 0xa3 #define RTC_I2C_READ 0xa3
...@@ -85,7 +86,12 @@ pcf8563_readreg(int reg) ...@@ -85,7 +86,12 @@ pcf8563_readreg(int reg)
void void
pcf8563_writereg(int reg, unsigned char val) pcf8563_writereg(int reg, unsigned char val)
{ {
i2c_writereg(RTC_I2C_WRITE,reg,val); #ifdef CONFIG_ETRAX_RTC_READONLY
if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR))
return;
#endif
rtc_write(reg, val);
} }
void void
...@@ -120,6 +126,9 @@ int __init ...@@ -120,6 +126,9 @@ int __init
pcf8563_init(void) pcf8563_init(void)
{ {
unsigned char ret; unsigned char ret;
i2c_init();
/* /*
* First of all we need to reset the chip. This is done by * First of all we need to reset the chip. This is done by
* clearing control1, control2 and clk freq, clear the * clearing control1, control2 and clk freq, clear the
...@@ -152,14 +161,6 @@ pcf8563_init(void) ...@@ -152,14 +161,6 @@ pcf8563_init(void)
if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0) if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0)
goto err; goto err;
if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
printk(KERN_INFO "%s: Unable to get major numer %d for RTC device.\n",
PCF8563_NAME, PCF8563_MAJOR);
return -1;
}
printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
/* Check for low voltage, and warn about it.. */ /* Check for low voltage, and warn about it.. */
if (rtc_read(RTC_SECONDS) & 0x80) if (rtc_read(RTC_SECONDS) & 0x80)
...@@ -210,9 +211,11 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned ...@@ -210,9 +211,11 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
break; break;
case RTC_SET_TIME: case RTC_SET_TIME:
{ {
#ifdef CONFIG_ETRAX_RTC_READONLY
return -EPERM;
#else
int leap; int leap;
int century; int century;
unsigned long flags;
struct rtc_time tm; struct rtc_time tm;
memset(&tm, 0, sizeof (struct rtc_time)); memset(&tm, 0, sizeof (struct rtc_time));
...@@ -256,8 +259,35 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned ...@@ -256,8 +259,35 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
rtc_write(RTC_SECONDS, tm.tm_sec); rtc_write(RTC_SECONDS, tm.tm_sec);
return 0; return 0;
#endif /* !CONFIG_ETRAX_RTC_READONLY */
} }
break;
case RTC_VLOW_RD:
{
int vl_bit = 0;
if (rtc_read(RTC_SECONDS) & 0x80) {
vl_bit = 1;
printk(KERN_WARNING "%s: RTC Voltage Low - reliable "
"date/time information is no longer guaranteed!\n",
PCF8563_NAME);
}
if (copy_to_user((int *) arg, &vl_bit, sizeof(int)))
return -EFAULT;
return 0;
}
case RTC_VLOW_SET:
{
/* Clear the VL bit in the seconds register */
int ret = rtc_read(RTC_SECONDS);
rtc_write(RTC_SECONDS, (ret & 0x7F));
return 0;
}
default: default:
return -ENOTTY; return -ENOTTY;
} }
...@@ -265,5 +295,19 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned ...@@ -265,5 +295,19 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned
return 0; return 0;
} }
module_init(pcf8563_init); static int __init
pcf8563_register(void)
{
pcf8563_init();
if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) {
printk(KERN_INFO "%s: Unable to get major numer %d for RTC device.\n",
PCF8563_NAME, PCF8563_MAJOR);
return -1;
}
printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION);
return 0;
}
module_init(pcf8563_register);
module_exit(pcf8563_exit); module_exit(pcf8563_exit);
/* $Id: serial.c,v 1.17 2003/07/04 08:27:37 starvik Exp $ /* $Id: serial.c,v 1.20 2004/05/24 12:00:20 starvik Exp $
* *
* Serial port driver for the ETRAX 100LX chip * Serial port driver for the ETRAX 100LX chip
* *
...@@ -7,6 +7,16 @@ ...@@ -7,6 +7,16 @@
* Many, many authors. Based once upon a time on serial.c for 16x50. * Many, many authors. Based once upon a time on serial.c for 16x50.
* *
* $Log: serial.c,v $ * $Log: serial.c,v $
* Revision 1.20 2004/05/24 12:00:20 starvik
* Big merge of stuff from Linux 2.4 (e.g. manual mode for the serial port).
*
* Revision 1.19 2004/05/17 13:12:15 starvik
* Kernel console hook
* Big merge from Linux 2.4 still pending.
*
* Revision 1.18 2003/10/28 07:18:30 starvik
* Compiles with debug info
*
* Revision 1.17 2003/07/04 08:27:37 starvik * Revision 1.17 2003/07/04 08:27:37 starvik
* Merge of Linux 2.5.74 * Merge of Linux 2.5.74
* *
...@@ -399,7 +409,7 @@ ...@@ -399,7 +409,7 @@
* *
*/ */
static char *serial_version = "$Revision: 1.17 $"; static char *serial_version = "$Revision: 1.20 $";
#include <linux/config.h> #include <linux/config.h>
#include <linux/version.h> #include <linux/version.h>
...@@ -447,6 +457,10 @@ static char *serial_version = "$Revision: 1.17 $"; ...@@ -447,6 +457,10 @@ static char *serial_version = "$Revision: 1.17 $";
#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" #error "RX_TIMEOUT_TICKS == 0 not allowed, use 1"
#endif #endif
#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G)
#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G"
#endif
/* /*
* All of the compatibilty code so we can compile serial.c against * All of the compatibilty code so we can compile serial.c against
* older kernels is hidden in serial_compat.h * older kernels is hidden in serial_compat.h
...@@ -473,7 +487,7 @@ struct tty_driver *serial_driver; ...@@ -473,7 +487,7 @@ struct tty_driver *serial_driver;
//#define SERIAL_DEBUG_DATA //#define SERIAL_DEBUG_DATA
//#define SERIAL_DEBUG_THROTTLE //#define SERIAL_DEBUG_THROTTLE
//#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */ //#define SERIAL_DEBUG_IO /* Debug for Extra control and status pins */
#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */ //#define SERIAL_DEBUG_LINE 0 /* What serport we want to debug */
/* Enable this to use serial interrupts to handle when you /* Enable this to use serial interrupts to handle when you
expect the first received event on the serial port to expect the first received event on the serial port to
...@@ -481,14 +495,74 @@ struct tty_driver *serial_driver; ...@@ -481,14 +495,74 @@ struct tty_driver *serial_driver;
from eLinux */ from eLinux */
#define SERIAL_HANDLE_EARLY_ERRORS #define SERIAL_HANDLE_EARLY_ERRORS
#define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) /* Defined and used in n_tty.c, but we need it here as well */
#define TTY_THRESHOLD_THROTTLE 128
/* Due to buffersizes and threshold values, our SERIAL_DESCR_BUF_SIZE
* must not be to high or flow control won't work if we leave it to the tty
* layer so we have our own throttling in flush_to_flip
* TTY_FLIPBUF_SIZE=512,
* TTY_THRESHOLD_THROTTLE/UNTHROTTLE=128
* BUF_SIZE can't be > 128
*/
/* Currently 16 descriptors x 128 bytes = 2048 bytes */
#define SERIAL_DESCR_BUF_SIZE 256 #define SERIAL_DESCR_BUF_SIZE 256
#define SERIAL_PRESCALE_BASE 3125000 /* 3.125MHz */
#define DEF_BAUD_BASE SERIAL_PRESCALE_BASE
/* We don't want to load the system with massive fast timer interrupt
* on high baudrates so limit it to 250 us (4kHz) */
#define MIN_FLUSH_TIME_USEC 250
/* Add an x here to log a lot of timer stuff */ /* Add an x here to log a lot of timer stuff */
#define TIMERD(x) #define TIMERD(x)
/* Debug details of interrupt handling */
#define DINTR1(x) /* irq on/off, errors */
#define DINTR2(x) /* tx and rx */
/* Debug flip buffer stuff */
#define DFLIP(x)
/* Debug flow control and overview of data flow */
#define DFLOW(x)
#define DBAUD(x)
#define DLOG_INT_TRIG(x)
//#define DEBUG_LOG_INCLUDED
#ifndef DEBUG_LOG_INCLUDED
#define DEBUG_LOG(line, string, value) #define DEBUG_LOG(line, string, value)
#else
struct debug_log_info
{
unsigned long time;
unsigned long timer_data;
// int line;
const char *string;
int value;
};
#define DEBUG_LOG_SIZE 4096
struct debug_log_info debug_log[DEBUG_LOG_SIZE];
int debug_log_pos = 0;
#define DEBUG_LOG(_line, _string, _value) do { \
if ((_line) == SERIAL_DEBUG_LINE) {\
debug_log_func(_line, _string, _value); \
}\
}while(0)
void debug_log_func(int line, const char *string, int value)
{
if (debug_log_pos < DEBUG_LOG_SIZE) {
debug_log[debug_log_pos].time = jiffies;
debug_log[debug_log_pos].timer_data = *R_TIMER_DATA;
// debug_log[debug_log_pos].line = line;
debug_log[debug_log_pos].string = string;
debug_log[debug_log_pos].value = value;
debug_log_pos++;
}
/*printk(string, value);*/
}
#endif
#ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS #ifndef CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS
/* Default number of timer ticks before flushing rx fifo /* Default number of timer ticks before flushing rx fifo
...@@ -498,11 +572,14 @@ struct tty_driver *serial_driver; ...@@ -498,11 +572,14 @@ struct tty_driver *serial_driver;
#define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5 #define CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS 5
#endif #endif
unsigned long timer_data_to_ns(unsigned long timer_data);
static void change_speed(struct e100_serial *info); static void change_speed(struct e100_serial *info);
static void rs_throttle(struct tty_struct * tty);
static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
static int rs_write(struct tty_struct * tty, int from_user, static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count); const unsigned char *buf, int count);
static inline int raw_write(struct tty_struct * tty, int from_user, extern _INLINE_ int rs_raw_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count); const unsigned char *buf, int count);
#ifdef CONFIG_ETRAX_RS485 #ifdef CONFIG_ETRAX_RS485
static int e100_write_rs485(struct tty_struct * tty, int from_user, static int e100_write_rs485(struct tty_struct * tty, int from_user,
...@@ -511,7 +588,7 @@ static int e100_write_rs485(struct tty_struct * tty, int from_user, ...@@ -511,7 +588,7 @@ static int e100_write_rs485(struct tty_struct * tty, int from_user,
static int get_lsr_info(struct e100_serial * info, unsigned int *value); static int get_lsr_info(struct e100_serial * info, unsigned int *value);
#define DEF_BAUD 0x99 /* 115.2 kbit/s */ #define DEF_BAUD 115200 /* 115.2 kbit/s */
#define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) #define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
#define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */ #define DEF_RX 0x20 /* or SERIAL_CTRL_W >> 8 */
/* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */ /* Default value of tx_ctrl register: has txd(bit 7)=1 (idle) as default */
...@@ -520,6 +597,7 @@ static int get_lsr_info(struct e100_serial * info, unsigned int *value); ...@@ -520,6 +597,7 @@ static int get_lsr_info(struct e100_serial * info, unsigned int *value);
/* offsets from R_SERIALx_CTRL */ /* offsets from R_SERIALx_CTRL */
#define REG_DATA 0 #define REG_DATA 0
#define REG_DATA_STATUS32 0 /* this is the 32 bit register R_SERIALx_READ */
#define REG_TR_DATA 0 #define REG_TR_DATA 0
#define REG_STATUS 1 #define REG_STATUS 1
#define REG_TR_CTRL 1 #define REG_TR_CTRL 1
...@@ -555,60 +633,162 @@ static int get_lsr_info(struct e100_serial * info, unsigned int *value); ...@@ -555,60 +633,162 @@ static int get_lsr_info(struct e100_serial * info, unsigned int *value);
*/ */
/* Mask for the irqs possibly enabled in R_IRQ_MASK1_RD etc. */
static const unsigned long e100_ser_int_mask = 0
#ifdef CONFIG_ETRAX_SERIAL_PORT0
| IO_MASK(R_IRQ_MASK1_RD, ser0_data) | IO_MASK(R_IRQ_MASK1_RD, ser0_ready)
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT1
| IO_MASK(R_IRQ_MASK1_RD, ser1_data) | IO_MASK(R_IRQ_MASK1_RD, ser1_ready)
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2
| IO_MASK(R_IRQ_MASK1_RD, ser2_data) | IO_MASK(R_IRQ_MASK1_RD, ser2_ready)
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT3
| IO_MASK(R_IRQ_MASK1_RD, ser3_data) | IO_MASK(R_IRQ_MASK1_RD, ser3_ready)
#endif
;
unsigned long r_alt_ser_baudrate_shadow = 0;
/* this is the data for the four serial ports in the etrax100 */ /* this is the data for the four serial ports in the etrax100 */
/* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */ /* DMA2(ser2), DMA4(ser3), DMA6(ser0) or DMA8(ser1) */
/* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */ /* R_DMA_CHx_CLR_INTR, R_DMA_CHx_FIRST, R_DMA_CHx_CMD */
static struct e100_serial rs_table[] = { static struct e100_serial rs_table[] = {
{ DEF_BAUD, (unsigned char *)R_SERIAL0_CTRL, 1U << 12, /* uses DMA 6 and 7 */ { .baud = DEF_BAUD,
R_DMA_CH6_CLR_INTR, R_DMA_CH6_FIRST, R_DMA_CH6_CMD, .port = (unsigned char *)R_SERIAL0_CTRL,
R_DMA_CH6_STATUS, R_DMA_CH6_HWSW, R_DMA_CH6_DESCR, .irq = 1U << 12, /* uses DMA 6 and 7 */
R_DMA_CH7_CLR_INTR, R_DMA_CH7_FIRST, R_DMA_CH7_CMD, .oclrintradr = R_DMA_CH6_CLR_INTR,
R_DMA_CH7_STATUS, R_DMA_CH7_HWSW, R_DMA_CH7_DESCR, .ofirstadr = R_DMA_CH6_FIRST,
STD_FLAGS, DEF_RX, DEF_TX, 2, .ocmdadr = R_DMA_CH6_CMD,
.ostatusadr = R_DMA_CH6_STATUS,
.iclrintradr = R_DMA_CH7_CLR_INTR,
.ifirstadr = R_DMA_CH7_FIRST,
.icmdadr = R_DMA_CH7_CMD,
.idescradr = R_DMA_CH7_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 2,
#ifdef CONFIG_ETRAX_SERIAL_PORT0 #ifdef CONFIG_ETRAX_SERIAL_PORT0
1 .enabled = 1,
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
.dma_out_enabled = 1,
#else
.dma_out_enabled = 0,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
.dma_in_enabled = 1,
#else #else
0 .dma_in_enabled = 0
#endif #endif
#else
.enabled = 0,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif
}, /* ttyS0 */ }, /* ttyS0 */
#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_SVINTO_SIM
{ DEF_BAUD, (unsigned char *)R_SERIAL1_CTRL, 1U << 16, /* uses DMA 8 and 9 */ { .baud = DEF_BAUD,
R_DMA_CH8_CLR_INTR, R_DMA_CH8_FIRST, R_DMA_CH8_CMD, .port = (unsigned char *)R_SERIAL1_CTRL,
R_DMA_CH8_STATUS, R_DMA_CH8_HWSW, R_DMA_CH8_DESCR, .irq = 1U << 16, /* uses DMA 8 and 9 */
R_DMA_CH9_CLR_INTR, R_DMA_CH9_FIRST, R_DMA_CH9_CMD, .oclrintradr = R_DMA_CH8_CLR_INTR,
R_DMA_CH9_STATUS, R_DMA_CH9_HWSW, R_DMA_CH9_DESCR, .ofirstadr = R_DMA_CH8_FIRST,
STD_FLAGS, DEF_RX, DEF_TX, 3 , .ocmdadr = R_DMA_CH8_CMD,
.ostatusadr = R_DMA_CH8_STATUS,
.iclrintradr = R_DMA_CH9_CLR_INTR,
.ifirstadr = R_DMA_CH9_FIRST,
.icmdadr = R_DMA_CH9_CMD,
.idescradr = R_DMA_CH9_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 3,
#ifdef CONFIG_ETRAX_SERIAL_PORT1 #ifdef CONFIG_ETRAX_SERIAL_PORT1
1 .enabled = 1,
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
.dma_out_enabled = 1,
#else
.dma_out_enabled = 0,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
.dma_in_enabled = 1,
#else
.dma_in_enabled = 0
#endif
#else #else
0 .enabled = 0,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif #endif
}, /* ttyS1 */ }, /* ttyS1 */
{ DEF_BAUD, (unsigned char *)R_SERIAL2_CTRL, 1U << 4, /* uses DMA 2 and 3 */ { .baud = DEF_BAUD,
R_DMA_CH2_CLR_INTR, R_DMA_CH2_FIRST, R_DMA_CH2_CMD, .port = (unsigned char *)R_SERIAL2_CTRL,
R_DMA_CH2_STATUS, R_DMA_CH2_HWSW, R_DMA_CH2_DESCR, .irq = 1U << 4, /* uses DMA 2 and 3 */
R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD, .oclrintradr = R_DMA_CH2_CLR_INTR,
R_DMA_CH3_STATUS, R_DMA_CH3_HWSW, R_DMA_CH3_DESCR, .ofirstadr = R_DMA_CH2_FIRST,
STD_FLAGS, DEF_RX, DEF_TX, 0, .ocmdadr = R_DMA_CH2_CMD,
.ostatusadr = R_DMA_CH2_STATUS,
.iclrintradr = R_DMA_CH3_CLR_INTR,
.ifirstadr = R_DMA_CH3_FIRST,
.icmdadr = R_DMA_CH3_CMD,
.idescradr = R_DMA_CH3_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 0,
#ifdef CONFIG_ETRAX_SERIAL_PORT2 #ifdef CONFIG_ETRAX_SERIAL_PORT2
1 .enabled = 1,
#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
.dma_out_enabled = 1,
#else
.dma_out_enabled = 0,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
.dma_in_enabled = 1,
#else
.dma_in_enabled = 0
#endif
#else #else
0 .enabled = 0,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif #endif
}, /* ttyS2 */ }, /* ttyS2 */
{ DEF_BAUD, (unsigned char *)R_SERIAL3_CTRL, 1U << 8, /* uses DMA 4 and 5 */ { .baud = DEF_BAUD,
R_DMA_CH4_CLR_INTR, R_DMA_CH4_FIRST, R_DMA_CH4_CMD, .port = (unsigned char *)R_SERIAL3_CTRL,
R_DMA_CH4_STATUS, R_DMA_CH4_HWSW, R_DMA_CH4_DESCR, .irq = 1U << 8, /* uses DMA 4 and 5 */
R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD, .oclrintradr = R_DMA_CH4_CLR_INTR,
R_DMA_CH5_STATUS, R_DMA_CH5_HWSW, R_DMA_CH5_DESCR, .ofirstadr = R_DMA_CH4_FIRST,
STD_FLAGS, DEF_RX, DEF_TX, 1, .ocmdadr = R_DMA_CH4_CMD,
.ostatusadr = R_DMA_CH4_STATUS,
.iclrintradr = R_DMA_CH5_CLR_INTR,
.ifirstadr = R_DMA_CH5_FIRST,
.icmdadr = R_DMA_CH5_CMD,
.idescradr = R_DMA_CH5_DESCR,
.flags = STD_FLAGS,
.rx_ctrl = DEF_RX,
.tx_ctrl = DEF_TX,
.iseteop = 1,
#ifdef CONFIG_ETRAX_SERIAL_PORT3 #ifdef CONFIG_ETRAX_SERIAL_PORT3
1 .enabled = 1,
#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
.dma_out_enabled = 1,
#else #else
0 .dma_out_enabled = 0,
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
.dma_in_enabled = 1,
#else
.dma_in_enabled = 0
#endif
#else
.enabled = 0,
.dma_out_enabled = 0,
.dma_in_enabled = 0
#endif #endif
} /* ttyS3 */ } /* ttyS3 */
#endif #endif
...@@ -616,6 +796,9 @@ static struct e100_serial rs_table[] = { ...@@ -616,6 +796,9 @@ static struct e100_serial rs_table[] = {
#define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial))
static struct termios *serial_termios[NR_PORTS];
static struct termios *serial_termios_locked[NR_PORTS];
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
static struct fast_timer fast_timers[NR_PORTS]; static struct fast_timer fast_timers[NR_PORTS];
#endif #endif
...@@ -652,6 +835,9 @@ static struct fast_timer fast_timers_rs485[NR_PORTS]; ...@@ -652,6 +835,9 @@ static struct fast_timer fast_timers_rs485[NR_PORTS];
#if defined(CONFIG_ETRAX_RS485_ON_PA) #if defined(CONFIG_ETRAX_RS485_ON_PA)
static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT;
#endif #endif
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT;
#endif
#endif #endif
/* Info and macros needed for each ports extra control/status signals. */ /* Info and macros needed for each ports extra control/status signals. */
...@@ -761,7 +947,7 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF}; ...@@ -761,7 +947,7 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF};
# endif # endif
#endif #endif
#define SER0_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT) #define SER1_PB_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PB_BIT+CONFIG_ETRAX_SER1_RI_ON_PB_BIT+CONFIG_ETRAX_SER1_DSR_ON_PB_BIT+CONFIG_ETRAX_SER1_CD_ON_PB_BIT)
#if SER1_PB_BITSUM != -4 #if SER1_PB_BITSUM != -4
# if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1 # if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1
...@@ -1081,15 +1267,9 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = ...@@ -1081,15 +1267,9 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
}; };
#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ #endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */
#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_RS485_ON_PA)
unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT;
#endif
#define E100_RTS_MASK 0x20 #define E100_RTS_MASK 0x20
#define E100_CTS_MASK 0x40 #define E100_CTS_MASK 0x40
/* All serial port signals are active low: /* All serial port signals are active low:
* active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level * active = 0 -> 3.3V to RS-232 driver -> -12V on RS-232 level
* inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level * inactive = 1 -> 0V to RS-232 driver -> +12V on RS-232 level
...@@ -1151,6 +1331,10 @@ static void update_char_time(struct e100_serial * info) ...@@ -1151,6 +1331,10 @@ static void update_char_time(struct e100_serial * info)
/* calc timeout */ /* calc timeout */
info->char_time_usec = ((bits * 1000000) / info->baud) + 1; info->char_time_usec = ((bits * 1000000) / info->baud) + 1;
info->flush_time_usec = 4*info->char_time_usec;
if (info->flush_time_usec < MIN_FLUSH_TIME_USEC)
info->flush_time_usec = MIN_FLUSH_TIME_USEC;
} }
/* /*
...@@ -1250,9 +1434,13 @@ static inline void ...@@ -1250,9 +1434,13 @@ static inline void
e100_rts(struct e100_serial *info, int set) e100_rts(struct e100_serial *info, int set)
{ {
#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_SVINTO_SIM
unsigned long flags;
save_flags(flags);
cli();
info->rx_ctrl &= ~E100_RTS_MASK; info->rx_ctrl &= ~E100_RTS_MASK;
info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */
info->port[REG_REC_CTRL] = info->rx_ctrl; info->port[REG_REC_CTRL] = info->rx_ctrl;
restore_flags(flags);
#ifdef SERIAL_DEBUG_IO #ifdef SERIAL_DEBUG_IO
printk("ser%i rts %i\n", info->line, set); printk("ser%i rts %i\n", info->line, set);
#endif #endif
...@@ -1326,6 +1514,7 @@ e100_disable_rxdma_irq(struct e100_serial *info) ...@@ -1326,6 +1514,7 @@ e100_disable_rxdma_irq(struct e100_serial *info)
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
printk("rxdma_irq(%d): 0\n",info->line); printk("rxdma_irq(%d): 0\n",info->line);
#endif #endif
DINTR1(DEBUG_LOG(info->line,"IRQ disable_rxdma_irq %i\n", info->line));
*R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3); *R_IRQ_MASK2_CLR = (info->irq << 2) | (info->irq << 3);
} }
...@@ -1335,30 +1524,33 @@ e100_enable_rxdma_irq(struct e100_serial *info) ...@@ -1335,30 +1524,33 @@ e100_enable_rxdma_irq(struct e100_serial *info)
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
printk("rxdma_irq(%d): 1\n",info->line); printk("rxdma_irq(%d): 1\n",info->line);
#endif #endif
DINTR1(DEBUG_LOG(info->line,"IRQ enable_rxdma_irq %i\n", info->line));
*R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3); *R_IRQ_MASK2_SET = (info->irq << 2) | (info->irq << 3);
} }
/* the tx DMA uses only dma_descr interrupt */ /* the tx DMA uses only dma_descr interrupt */
static inline void static _INLINE_ void
e100_disable_txdma_irq(struct e100_serial *info) e100_disable_txdma_irq(struct e100_serial *info)
{ {
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
printk("txdma_irq(%d): 0\n",info->line); printk("txdma_irq(%d): 0\n",info->line);
#endif #endif
DINTR1(DEBUG_LOG(info->line,"IRQ disable_txdma_irq %i\n", info->line));
*R_IRQ_MASK2_CLR = info->irq; *R_IRQ_MASK2_CLR = info->irq;
} }
static inline void static _INLINE_ void
e100_enable_txdma_irq(struct e100_serial *info) e100_enable_txdma_irq(struct e100_serial *info)
{ {
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
printk("txdma_irq(%d): 1\n",info->line); printk("txdma_irq(%d): 1\n",info->line);
#endif #endif
DINTR1(DEBUG_LOG(info->line,"IRQ enable_txdma_irq %i\n", info->line));
*R_IRQ_MASK2_SET = info->irq; *R_IRQ_MASK2_SET = info->irq;
} }
static inline void static _INLINE_ void
e100_disable_txdma_channel(struct e100_serial *info) e100_disable_txdma_channel(struct e100_serial *info)
{ {
unsigned long flags; unsigned long flags;
...@@ -1367,32 +1559,46 @@ e100_disable_txdma_channel(struct e100_serial *info) ...@@ -1367,32 +1559,46 @@ e100_disable_txdma_channel(struct e100_serial *info)
* ( set to something other then serialX) * ( set to something other then serialX)
*/ */
save_flags(flags); save_flags(flags);
cli(); cli();
DFLOW(DEBUG_LOG(info->line, "disable_txdma_channel %i\n", info->line));
if (info->line == 0) { if (info->line == 0) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma6)) ==
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); IO_STATE(R_GEN_CONFIG, dma6, serial0)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
}
} else if (info->line == 1) { } else if (info->line == 1) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma8)) ==
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); IO_STATE(R_GEN_CONFIG, dma8, serial1)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
}
} else if (info->line == 2) { } else if (info->line == 2) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma2)) ==
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); IO_STATE(R_GEN_CONFIG, dma2, serial2)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
}
} else if (info->line == 3) { } else if (info->line == 3) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma4)) ==
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); IO_STATE(R_GEN_CONFIG, dma4, serial3)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
}
} }
*R_GEN_CONFIG = genconfig_shadow; *R_GEN_CONFIG = genconfig_shadow;
restore_flags(flags); restore_flags(flags);
} }
static inline void static _INLINE_ void
e100_enable_txdma_channel(struct e100_serial *info) e100_enable_txdma_channel(struct e100_serial *info)
{ {
unsigned long flags; unsigned long flags;
save_flags(flags); save_flags(flags);
cli(); cli();
DFLOW(DEBUG_LOG(info->line, "enable_txdma_channel %i\n", info->line));
/* Enable output DMA channel for the serial port in question */ /* Enable output DMA channel for the serial port in question */
if (info->line == 0) { if (info->line == 0) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);
...@@ -1411,6 +1617,70 @@ e100_enable_txdma_channel(struct e100_serial *info) ...@@ -1411,6 +1617,70 @@ e100_enable_txdma_channel(struct e100_serial *info)
restore_flags(flags); restore_flags(flags);
} }
static _INLINE_ void
e100_disable_rxdma_channel(struct e100_serial *info)
{
unsigned long flags;
/* Disable input DMA channel for the serial port in question
* ( set to something other then serialX)
*/
save_flags(flags);
cli();
if (info->line == 0) {
if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma7)) ==
IO_STATE(R_GEN_CONFIG, dma7, serial0)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, unused);
}
} else if (info->line == 1) {
if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma9)) ==
IO_STATE(R_GEN_CONFIG, dma9, serial1)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, usb);
}
} else if (info->line == 2) {
if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma3)) ==
IO_STATE(R_GEN_CONFIG, dma3, serial2)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0);
}
} else if (info->line == 3) {
if ((genconfig_shadow & IO_MASK(R_GEN_CONFIG, dma5)) ==
IO_STATE(R_GEN_CONFIG, dma5, serial3)) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1);
}
}
*R_GEN_CONFIG = genconfig_shadow;
restore_flags(flags);
}
static _INLINE_ void
e100_enable_rxdma_channel(struct e100_serial *info)
{
unsigned long flags;
save_flags(flags);
cli();
/* Enable input DMA channel for the serial port in question */
if (info->line == 0) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma7);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma7, serial0);
} else if (info->line == 1) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma9);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma9, serial1);
} else if (info->line == 2) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, serial2);
} else if (info->line == 3) {
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, serial3);
}
*R_GEN_CONFIG = genconfig_shadow;
restore_flags(flags);
}
#ifdef SERIAL_HANDLE_EARLY_ERRORS #ifdef SERIAL_HANDLE_EARLY_ERRORS
/* in order to detect and fix errors on the first byte /* in order to detect and fix errors on the first byte
...@@ -1422,6 +1692,7 @@ e100_disable_serial_data_irq(struct e100_serial *info) ...@@ -1422,6 +1692,7 @@ e100_disable_serial_data_irq(struct e100_serial *info)
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
printk("ser_irq(%d): 0\n",info->line); printk("ser_irq(%d): 0\n",info->line);
#endif #endif
DINTR1(DEBUG_LOG(info->line,"IRQ disable data_irq %i\n", info->line));
*R_IRQ_MASK1_CLR = (1U << (8+2*info->line)); *R_IRQ_MASK1_CLR = (1U << (8+2*info->line));
} }
...@@ -1434,10 +1705,49 @@ e100_enable_serial_data_irq(struct e100_serial *info) ...@@ -1434,10 +1705,49 @@ e100_enable_serial_data_irq(struct e100_serial *info)
(8+2*info->line), (8+2*info->line),
(1U << (8+2*info->line))); (1U << (8+2*info->line)));
#endif #endif
DINTR1(DEBUG_LOG(info->line,"IRQ enable data_irq %i\n", info->line));
*R_IRQ_MASK1_SET = (1U << (8+2*info->line)); *R_IRQ_MASK1_SET = (1U << (8+2*info->line));
} }
#endif #endif
static inline void
e100_disable_serial_tx_ready_irq(struct e100_serial *info)
{
#ifdef SERIAL_DEBUG_INTR
printk("ser_tx_irq(%d): 0\n",info->line);
#endif
DINTR1(DEBUG_LOG(info->line,"IRQ disable ready_irq %i\n", info->line));
*R_IRQ_MASK1_CLR = (1U << (8+1+2*info->line));
}
static inline void
e100_enable_serial_tx_ready_irq(struct e100_serial *info)
{
#ifdef SERIAL_DEBUG_INTR
printk("ser_tx_irq(%d): 1\n",info->line);
printk("**** %d = %d\n",
(8+1+2*info->line),
(1U << (8+1+2*info->line)));
#endif
DINTR2(DEBUG_LOG(info->line,"IRQ enable ready_irq %i\n", info->line));
*R_IRQ_MASK1_SET = (1U << (8+1+2*info->line));
}
static inline void e100_enable_rx_irq(struct e100_serial *info)
{
if (info->uses_dma_in)
e100_enable_rxdma_irq(info);
else
e100_enable_serial_data_irq(info);
}
static inline void e100_disable_rx_irq(struct e100_serial *info)
{
if (info->uses_dma_in)
e100_disable_rxdma_irq(info);
else
e100_disable_serial_data_irq(info);
}
#if defined(CONFIG_ETRAX_RS485) #if defined(CONFIG_ETRAX_RS485)
/* Enable RS-485 mode on selected port. This is UGLY. */ /* Enable RS-485 mode on selected port. This is UGLY. */
static int static int
...@@ -1448,10 +1758,23 @@ e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) ...@@ -1448,10 +1758,23 @@ e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r)
#if defined(CONFIG_ETRAX_RS485_ON_PA) #if defined(CONFIG_ETRAX_RS485_ON_PA)
*R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit);
#endif #endif
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
rs485_port_g_bit, 1);
#endif
#if defined(CONFIG_ETRAX_RS485_LTC1387)
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1);
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1);
#endif
info->rs485.rts_on_send = 0x01 & r->rts_on_send; info->rs485.rts_on_send = 0x01 & r->rts_on_send;
info->rs485.rts_after_sent = 0x01 & r->rts_after_sent; info->rs485.rts_after_sent = 0x01 & r->rts_after_sent;
info->rs485.delay_rts_before_send = r->delay_rts_before_send; if (r->delay_rts_before_send >= 1000)
info->rs485.delay_rts_before_send = 1000;
else
info->rs485.delay_rts_before_send = r->delay_rts_before_send;
info->rs485.enabled = r->enabled; info->rs485.enabled = r->enabled;
/* printk("rts: on send = %i, after = %i, enabled = %i", /* printk("rts: on send = %i, after = %i, enabled = %i",
info->rs485.rts_on_send, info->rs485.rts_on_send,
...@@ -1491,7 +1814,7 @@ static void rs485_toggle_rts_timer_function(unsigned long data) ...@@ -1491,7 +1814,7 @@ static void rs485_toggle_rts_timer_function(unsigned long data)
e100_rts(info, info->rs485.rts_after_sent); e100_rts(info, info->rs485.rts_after_sent);
#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
e100_enable_rx(info); e100_enable_rx(info);
e100_enable_rxdma_irq(info); e100_enable_rx_irq(info);
#endif #endif
} }
#endif #endif
...@@ -1513,8 +1836,12 @@ rs_stop(struct tty_struct *tty) ...@@ -1513,8 +1836,12 @@ rs_stop(struct tty_struct *tty)
if (info) { if (info) {
unsigned long flags; unsigned long flags;
unsigned long xoff; unsigned long xoff;
save_flags(flags); cli(); save_flags(flags); cli();
DFLOW(DEBUG_LOG(info->line, "XOFF rs_stop xmit %i\n",
CIRC_CNT(info->xmit.head,
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
if (tty->termios->c_iflag & IXON ) { if (tty->termios->c_iflag & IXON ) {
...@@ -1535,6 +1862,9 @@ rs_start(struct tty_struct *tty) ...@@ -1535,6 +1862,9 @@ rs_start(struct tty_struct *tty)
unsigned long xoff; unsigned long xoff;
save_flags(flags); cli(); save_flags(flags); cli();
DFLOW(DEBUG_LOG(info->line, "XOFF rs_start xmit %i\n",
CIRC_CNT(info->xmit.head,
info->xmit.tail,SERIAL_XMIT_SIZE)));
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
if (tty->termios->c_iflag & IXON ) { if (tty->termios->c_iflag & IXON ) {
...@@ -1542,6 +1872,9 @@ rs_start(struct tty_struct *tty) ...@@ -1542,6 +1872,9 @@ rs_start(struct tty_struct *tty)
} }
*((unsigned long *)&info->port[REG_XOFF]) = xoff; *((unsigned long *)&info->port[REG_XOFF]) = xoff;
if (!info->uses_dma_out &&
info->xmit.head != info->xmit.tail && info->xmit.buf)
e100_enable_serial_tx_ready_irq(info);
restore_flags(flags); restore_flags(flags);
} }
...@@ -1576,6 +1909,8 @@ static _INLINE_ void ...@@ -1576,6 +1909,8 @@ static _INLINE_ void
rs_sched_event(struct e100_serial *info, rs_sched_event(struct e100_serial *info,
int event) int event)
{ {
if (info->event & (1 << event))
return;
info->event |= 1 << event; info->event |= 1 << event;
schedule_work(&info->work); schedule_work(&info->work);
} }
...@@ -1592,7 +1927,7 @@ rs_sched_event(struct e100_serial *info, ...@@ -1592,7 +1927,7 @@ rs_sched_event(struct e100_serial *info,
*/ */
static void static void
transmit_chars(struct e100_serial *info) transmit_chars_dma(struct e100_serial *info)
{ {
unsigned int c, sentl; unsigned int c, sentl;
struct etrax_dma_descr *descr; struct etrax_dma_descr *descr;
...@@ -1600,11 +1935,11 @@ transmit_chars(struct e100_serial *info) ...@@ -1600,11 +1935,11 @@ transmit_chars(struct e100_serial *info)
#ifdef CONFIG_SVINTO_SIM #ifdef CONFIG_SVINTO_SIM
/* This will output too little if tail is not 0 always since /* This will output too little if tail is not 0 always since
* we don't reloop to send the other part. Anyway this SHOULD be a * we don't reloop to send the other part. Anyway this SHOULD be a
* no-op - transmit_chars would never really be called during sim * no-op - transmit_chars_dma would never really be called during sim
* since rs_write does not write into the xmit buffer then. * since rs_write does not write into the xmit buffer then.
*/ */
if (info->xmit.tail) if (info->xmit.tail)
printk("Error in serial.c:transmit_chars(), tail!=0\n"); printk("Error in serial.c:transmit_chars-dma(), tail!=0\n");
if (info->xmit.head != info->xmit.tail) { if (info->xmit.head != info->xmit.tail) {
SIMCOUT(info->xmit.buf + info->xmit.tail, SIMCOUT(info->xmit.buf + info->xmit.tail,
CIRC_CNT(info->xmit.head, CIRC_CNT(info->xmit.head,
...@@ -1626,7 +1961,7 @@ transmit_chars(struct e100_serial *info) ...@@ -1626,7 +1961,7 @@ transmit_chars(struct e100_serial *info)
#endif #endif
if (!info->tr_running) { if (!info->tr_running) {
/* weirdo... we shouldn't get here! */ /* weirdo... we shouldn't get here! */
printk(KERN_WARNING "Achtung: transmit_chars with !tr_running\n"); printk(KERN_WARNING "Achtung: transmit_chars_dma with !tr_running\n");
return; return;
} }
...@@ -1642,6 +1977,8 @@ transmit_chars(struct e100_serial *info) ...@@ -1642,6 +1977,8 @@ transmit_chars(struct e100_serial *info)
/* otherwise we find the amount of data sent here */ /* otherwise we find the amount of data sent here */
sentl = descr->hw_len; sentl = descr->hw_len;
DFLOW(DEBUG_LOG(info->line, "TX %i done\n", sentl));
/* update stats */ /* update stats */
info->icount.tx += sentl; info->icount.tx += sentl;
...@@ -1659,6 +1996,13 @@ transmit_chars(struct e100_serial *info) ...@@ -1659,6 +1996,13 @@ transmit_chars(struct e100_serial *info)
c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); c = CIRC_CNT_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
/* Don't send all in one DMA transfer - divide it so we wake up
* application before all is sent
*/
if (c >= 4*WAKEUP_CHARS)
c = c/2;
if (c <= 0) { if (c <= 0) {
/* our job here is done, don't schedule any new DMA transfer */ /* our job here is done, don't schedule any new DMA transfer */
info->tr_running = 0; info->tr_running = 0;
...@@ -1678,17 +2022,17 @@ transmit_chars(struct e100_serial *info) ...@@ -1678,17 +2022,17 @@ transmit_chars(struct e100_serial *info)
/* ok we can schedule a dma send of c chars starting at info->xmit.tail */ /* ok we can schedule a dma send of c chars starting at info->xmit.tail */
/* set up the descriptor correctly for output */ /* set up the descriptor correctly for output */
DFLOW(DEBUG_LOG(info->line, "TX %i\n", c));
descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */ descr->ctrl = d_int | d_eol | d_wait; /* Wait needed for tty_wait_until_sent() */
descr->sw_len = c; descr->sw_len = c;
descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail); descr->buf = virt_to_phys(info->xmit.buf + info->xmit.tail);
descr->status = 0; descr->status = 0;
*info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */ *info->ofirstadr = virt_to_phys(descr); /* write to R_DMAx_FIRST */
*info->ocmdadr = 1; /* dma command start -> R_DMAx_CMD */ *info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, start);
/* DMA is now running (hopefully) */ /* DMA is now running (hopefully) */
} /* transmit_chars */ } /* transmit_chars_dma */
static void static void
start_transmit(struct e100_serial *info) start_transmit(struct e100_serial *info)
...@@ -1702,15 +2046,17 @@ start_transmit(struct e100_serial *info) ...@@ -1702,15 +2046,17 @@ start_transmit(struct e100_serial *info)
info->tr_descr.hw_len = 0; info->tr_descr.hw_len = 0;
info->tr_descr.status = 0; info->tr_descr.status = 0;
info->tr_running = 1; info->tr_running = 1;
if (info->uses_dma_out)
transmit_chars(info); transmit_chars_dma(info);
else
e100_enable_serial_tx_ready_irq(info);
} /* start_transmit */ } /* start_transmit */
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
static int serial_fast_timer_started = 0; static int serial_fast_timer_started = 0;
static int serial_fast_timer_expired = 0; static int serial_fast_timer_expired = 0;
static void flush_timeout_function(unsigned long data); static void flush_timeout_function(unsigned long data);
#define START_FLUSH_FAST_TIMER(info, string) {\ #define START_FLUSH_FAST_TIMER_TIME(info, string, usec) {\
unsigned long timer_flags; \ unsigned long timer_flags; \
save_flags(timer_flags); \ save_flags(timer_flags); \
cli(); \ cli(); \
...@@ -1721,7 +2067,7 @@ static void flush_timeout_function(unsigned long data); ...@@ -1721,7 +2067,7 @@ static void flush_timeout_function(unsigned long data);
start_one_shot_timer(&fast_timers[info->line], \ start_one_shot_timer(&fast_timers[info->line], \
flush_timeout_function, \ flush_timeout_function, \
(unsigned long)info, \ (unsigned long)info, \
info->char_time_usec*4, \ (usec), \
string); \ string); \
} \ } \
else { \ else { \
...@@ -1729,8 +2075,10 @@ static void flush_timeout_function(unsigned long data); ...@@ -1729,8 +2075,10 @@ static void flush_timeout_function(unsigned long data);
} \ } \
restore_flags(timer_flags); \ restore_flags(timer_flags); \
} }
#define START_FLUSH_FAST_TIMER(info, string) START_FLUSH_FAST_TIMER_TIME(info, string, info->flush_time_usec)
#else #else
#define START_FLUSH_FAST_TIMER_TIME(info, string, usec)
#define START_FLUSH_FAST_TIMER(info, string) #define START_FLUSH_FAST_TIMER(info, string)
#endif #endif
...@@ -1775,17 +2123,26 @@ static int ...@@ -1775,17 +2123,26 @@ static int
add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag)
{ {
struct etrax_recv_buffer *buffer; struct etrax_recv_buffer *buffer;
if (info->uses_dma_in) {
if (!(buffer = alloc_recv_buffer(4)))
return 0;
if (!(buffer = alloc_recv_buffer(4))) buffer->length = 1;
return 0; buffer->error = flag;
buffer->buffer[0] = data;
buffer->length = 1;
buffer->error = flag;
buffer->buffer[0] = data;
append_recv_buffer(info, buffer); append_recv_buffer(info, buffer);
info->icount.rx++; info->icount.rx++;
} else {
struct tty_struct *tty = info->tty;
*tty->flip.char_buf_ptr = data;
*tty->flip.flag_buf_ptr = flag;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
info->icount.rx++;
}
return 1; return 1;
} }
...@@ -1847,7 +2204,14 @@ handle_all_descr_data(struct e100_serial *info) ...@@ -1847,7 +2204,14 @@ handle_all_descr_data(struct e100_serial *info)
/* Reset the status information */ /* Reset the status information */
descr->status = 0; descr->status = 0;
DEBUG_LOG(info->line, "recvl %lu\n", recvl); DFLOW( DEBUG_LOG(info->line, "RX %lu\n", recvl);
if (info->tty->stopped) {
unsigned char *buf = phys_to_virt(descr->buf);
DEBUG_LOG(info->line, "rx 0x%02X\n", buf[0]);
DEBUG_LOG(info->line, "rx 0x%02X\n", buf[1]);
DEBUG_LOG(info->line, "rx 0x%02X\n", buf[2]);
}
);
/* update stats */ /* update stats */
info->icount.rx += recvl; info->icount.rx += recvl;
...@@ -1859,7 +2223,7 @@ handle_all_descr_data(struct e100_serial *info) ...@@ -1859,7 +2223,7 @@ handle_all_descr_data(struct e100_serial *info)
} }
static _INLINE_ void static _INLINE_ void
receive_chars(struct e100_serial *info) receive_chars_dma(struct e100_serial *info)
{ {
struct tty_struct *tty; struct tty_struct *tty;
unsigned char rstat; unsigned char rstat;
...@@ -1881,7 +2245,8 @@ receive_chars(struct e100_serial *info) ...@@ -1881,7 +2245,8 @@ receive_chars(struct e100_serial *info)
return; return;
#ifdef SERIAL_HANDLE_EARLY_ERRORS #ifdef SERIAL_HANDLE_EARLY_ERRORS
e100_enable_serial_data_irq(info); if (info->uses_dma_in)
e100_enable_serial_data_irq(info);
#endif #endif
if (info->errorcode == ERRCODE_INSERT_BREAK) if (info->errorcode == ERRCODE_INSERT_BREAK)
...@@ -1891,6 +2256,9 @@ receive_chars(struct e100_serial *info) ...@@ -1891,6 +2256,9 @@ receive_chars(struct e100_serial *info)
/* Read the status register to detect errors */ /* Read the status register to detect errors */
rstat = info->port[REG_STATUS]; rstat = info->port[REG_STATUS];
if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
DFLOW(DEBUG_LOG(info->line, "XOFF detect stat %x\n", rstat));
}
if (rstat & SER_ERROR_MASK) { if (rstat & SER_ERROR_MASK) {
/* If we got an error, we must reset it by reading the /* If we got an error, we must reset it by reading the
...@@ -1959,16 +2327,16 @@ start_receive(struct e100_serial *info) ...@@ -1959,16 +2327,16 @@ start_receive(struct e100_serial *info)
*/ */
return; return;
#endif #endif
/* reset the input dma channel to be sure it works */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
info->tty->flip.count = 0; info->tty->flip.count = 0;
if (info->uses_dma_in) {
/* reset the input dma channel to be sure it works */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
start_recv_dma(info); start_recv_dma(info);
}
} }
...@@ -2014,27 +2382,27 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -2014,27 +2382,27 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
for (i = 0; i < NR_PORTS; i++) { for (i = 0; i < NR_PORTS; i++) {
info = rs_table + i; info = rs_table + i;
if (!info->enabled || !info->uses_dma) if (!info->enabled || !info->uses_dma_out)
continue; continue;
/* check for dma_descr (don't need to check for dma_eop in output dma for serial */ /* check for dma_descr (don't need to check for dma_eop in output dma for serial */
if (ireg & info->irq) { if (ireg & info->irq) {
handled = 1; handled = 1;
/* we can send a new dma bunch. make it so. */ /* we can send a new dma bunch. make it so. */
DEBUG_LOG(info->line, "tr_interrupt %i\n", i); DINTR2(DEBUG_LOG(info->line, "tr_interrupt %i\n", i));
/* Read jiffies_usec first, /* Read jiffies_usec first,
* we want this time to be as late as possible * we want this time to be as late as possible
*/ */
PROCSTAT(ser_stat[info->line].tx_dma_ints++); PROCSTAT(ser_stat[info->line].tx_dma_ints++);
info->last_tx_active_usec = GET_JIFFIES_USEC(); info->last_tx_active_usec = GET_JIFFIES_USEC();
info->last_tx_active = jiffies; info->last_tx_active = jiffies;
transmit_chars(info); transmit_chars_dma(info);
} }
/* FIXME: here we should really check for a change in the /* FIXME: here we should really check for a change in the
status lines and if so call status_handle(info) */ status lines and if so call status_handle(info) */
} }
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} } /* tr_interrupt */
/* dma input channel interrupt handler */ /* dma input channel interrupt handler */
...@@ -2054,7 +2422,7 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -2054,7 +2422,7 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
const char *s = "What? rec_interrupt in simulator??\n"; const char *s = "What? rec_interrupt in simulator??\n";
SIMCOUT(s,strlen(s)); SIMCOUT(s,strlen(s));
} }
return; return IRQ_HANDLED;
#endif #endif
/* find out the line that caused this irq and get it from rs_table */ /* find out the line that caused this irq and get it from rs_table */
...@@ -2063,20 +2431,20 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) ...@@ -2063,20 +2431,20 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
for (i = 0; i < NR_PORTS; i++) { for (i = 0; i < NR_PORTS; i++) {
info = rs_table + i; info = rs_table + i;
if (!info->enabled || !info->uses_dma) if (!info->enabled || !info->uses_dma_in)
continue; continue;
/* check for both dma_eop and dma_descr for the input dma channel */ /* check for both dma_eop and dma_descr for the input dma channel */
if (ireg & ((info->irq << 2) | (info->irq << 3))) { if (ireg & ((info->irq << 2) | (info->irq << 3))) {
handled = 1; handled = 1;
/* we have received something */ /* we have received something */
receive_chars(info); receive_chars_dma(info);
} }
/* FIXME: here we should really check for a change in the /* FIXME: here we should really check for a change in the
status lines and if so call status_handle(info) */ status lines and if so call status_handle(info) */
} }
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} } /* rec_interrupt */
static _INLINE_ int static _INLINE_ int
force_eop_if_needed(struct e100_serial *info) force_eop_if_needed(struct e100_serial *info)
...@@ -2116,20 +2484,21 @@ force_eop_if_needed(struct e100_serial *info) ...@@ -2116,20 +2484,21 @@ force_eop_if_needed(struct e100_serial *info)
if (!info->forced_eop) { if (!info->forced_eop) {
info->forced_eop = 1; info->forced_eop = 1;
PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); PROCSTAT(ser_stat[info->line].timeout_flush_cnt++);
DEBUG_LOG(info->line, "timeout EOP %i\n", info->line); TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line));
FORCE_EOP(info); FORCE_EOP(info);
} }
return 1; return 1;
} }
static _INLINE_ void extern _INLINE_ void
flush_to_flip_buffer(struct e100_serial *info) flush_to_flip_buffer(struct e100_serial *info)
{ {
struct tty_struct *tty; struct tty_struct *tty;
struct etrax_recv_buffer *buffer; struct etrax_recv_buffer *buffer;
unsigned int length; unsigned int length;
unsigned long flags; unsigned long flags;
int max_flip_size;
if (!info->first_recv_buffer) if (!info->first_recv_buffer)
return; return;
...@@ -2143,12 +2512,46 @@ flush_to_flip_buffer(struct e100_serial *info) ...@@ -2143,12 +2512,46 @@ flush_to_flip_buffer(struct e100_serial *info)
} }
length = tty->flip.count; length = tty->flip.count;
/* Don't flip more than the ldisc has room for.
* The return value from ldisc.receive_room(tty) - might not be up to
* date, the previous flip of up to TTY_FLIPBUF_SIZE might be on the
* processed and not accounted for yet.
* Since we use DMA, 1 SERIAL_DESCR_BUF_SIZE could be on the way.
* Lets buffer data here and let flow control take care of it.
* Since we normally flip large chunks, the ldisc don't react
* with throttle until too late if we flip to much.
*/
max_flip_size = tty->ldisc.receive_room(tty);
if (max_flip_size < 0)
max_flip_size = 0;
if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */
length + info->recv_cnt + /* We have this queued */
2*SERIAL_DESCR_BUF_SIZE + /* This could be on the way */
TTY_THRESHOLD_THROTTLE)) { /* Some slack */
/* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles room %lu\n", max_flip_size));
rs_throttle(tty);
}
#if 0
else if (max_flip_size <= (TTY_FLIPBUF_SIZE + /* Maybe not accounted for */
length + info->recv_cnt + /* We have this queued */
SERIAL_DESCR_BUF_SIZE + /* This could be on the way */
TTY_THRESHOLD_THROTTLE)) { /* Some slack */
DFLOW(DEBUG_LOG(info->line,"flush_to_flip throttles again! %lu\n", max_flip_size));
rs_throttle(tty);
}
#endif
}
while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) { if (max_flip_size > TTY_FLIPBUF_SIZE)
max_flip_size = TTY_FLIPBUF_SIZE;
while ((buffer = info->first_recv_buffer) && length < max_flip_size) {
unsigned int count = buffer->length; unsigned int count = buffer->length;
if (length + count > TTY_FLIPBUF_SIZE) if (length + count > max_flip_size)
count = TTY_FLIPBUF_SIZE - length; count = max_flip_size - length;
memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count); memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count);
memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count); memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count);
...@@ -2156,6 +2559,7 @@ flush_to_flip_buffer(struct e100_serial *info) ...@@ -2156,6 +2559,7 @@ flush_to_flip_buffer(struct e100_serial *info)
length += count; length += count;
info->recv_cnt -= count; info->recv_cnt -= count;
DFLIP(DEBUG_LOG(info->line,"flip: %i\n", length));
if (count == buffer->length) { if (count == buffer->length) {
info->first_recv_buffer = buffer->next; info->first_recv_buffer = buffer->next;
...@@ -2171,9 +2575,30 @@ flush_to_flip_buffer(struct e100_serial *info) ...@@ -2171,9 +2575,30 @@ flush_to_flip_buffer(struct e100_serial *info)
info->last_recv_buffer = NULL; info->last_recv_buffer = NULL;
tty->flip.count = length; tty->flip.count = length;
DFLIP(if (tty->ldisc.chars_in_buffer(tty) > 3500) {
DEBUG_LOG(info->line, "ldisc %lu\n",
tty->ldisc.chars_in_buffer(tty));
DEBUG_LOG(info->line, "flip.count %lu\n",
tty->flip.count);
}
);
restore_flags(flags); restore_flags(flags);
DFLIP(
if (1) {
if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
DEBUG_LOG(info->line, "*** TTY_DONT_FLIP set flip.count %i ***\n", tty->flip.count);
DEBUG_LOG(info->line, "*** recv_cnt %i\n", info->recv_cnt);
} else {
}
DEBUG_LOG(info->line, "*** rxtot %i\n", info->icount.rx);
DEBUG_LOG(info->line, "ldisc %lu\n", tty->ldisc.chars_in_buffer(tty));
DEBUG_LOG(info->line, "room %lu\n", tty->ldisc.receive_room(tty));
}
);
/* this includes a check for low-latency */ /* this includes a check for low-latency */
tty_flip_buffer_push(tty); tty_flip_buffer_push(tty);
} }
...@@ -2181,12 +2606,19 @@ flush_to_flip_buffer(struct e100_serial *info) ...@@ -2181,12 +2606,19 @@ flush_to_flip_buffer(struct e100_serial *info)
static _INLINE_ void static _INLINE_ void
check_flush_timeout(struct e100_serial *info) check_flush_timeout(struct e100_serial *info)
{ {
force_eop_if_needed(info); /* Flip what we've got (if we can) */
flush_to_flip_buffer(info); flush_to_flip_buffer(info);
/* We might need to flip later, but not to fast
* since the system is busy processing input... */
if (info->first_recv_buffer) if (info->first_recv_buffer)
START_FLUSH_FAST_TIMER(info, "flip"); START_FLUSH_FAST_TIMER_TIME(info, "flip", 2000);
/* Force eop last, since data might have come while we're processing
* and if we started the slow timer above, we won't start a fast
* below.
*/
force_eop_if_needed(info);
} }
#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
...@@ -2222,7 +2654,7 @@ timed_flush_handler(unsigned long ptr) ...@@ -2222,7 +2654,7 @@ timed_flush_handler(unsigned long ptr)
for (i = 0; i < NR_PORTS; i++) { for (i = 0; i < NR_PORTS; i++) {
info = rs_table + i; info = rs_table + i;
if (info->uses_dma) if (info->uses_dma_in)
check_flush_timeout(info); check_flush_timeout(info);
} }
...@@ -2301,14 +2733,158 @@ TODO: The break will be delayed until an F or V character is received. ...@@ -2301,14 +2733,158 @@ TODO: The break will be delayed until an F or V character is received.
*/ */
extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info) extern _INLINE_
struct e100_serial * handle_ser_rx_interrupt_no_dma(struct e100_serial *info)
{ {
unsigned char rstat = info->port[REG_STATUS]; unsigned long data_read;
struct tty_struct *tty = info->tty;
if (!tty) {
printk("!NO TTY!\n");
return info;
}
if (tty->flip.count >= TTY_FLIPBUF_SIZE - TTY_THRESHOLD_THROTTLE) {
/* check TTY_THROTTLED first so it indicates our state */
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
DFLOW(DEBUG_LOG(info->line, "rs_throttle flip.count: %i\n", tty->flip.count));
rs_throttle(tty);
}
}
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
DEBUG_LOG(info->line, "force FLIP! %i\n", tty->flip.count);
tty->flip.work.func((void *) tty);
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
DEBUG_LOG(info->line, "FLIP FULL! %i\n", tty->flip.count);
return info; /* if TTY_DONT_FLIP is set */
}
}
/* Read data and status at the same time */
data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
more_data:
if (data_read & IO_MASK(R_SERIAL0_READ, xoff_detect) ) {
DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
}
DINTR2(DEBUG_LOG(info->line, "ser_rx %c\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read)));
if (data_read & ( IO_MASK(R_SERIAL0_READ, framing_err) |
IO_MASK(R_SERIAL0_READ, par_err) |
IO_MASK(R_SERIAL0_READ, overrun) )) {
/* An error */
info->last_rx_active_usec = GET_JIFFIES_USEC();
info->last_rx_active = jiffies;
DINTR1(DEBUG_LOG(info->line, "ser_rx err stat_data %04X\n", data_read));
DLOG_INT_TRIG(
if (!log_int_trig1_pos) {
log_int_trig1_pos = log_int_pos;
log_int(rdpc(), 0, 0);
}
);
if ( ((data_read & IO_MASK(R_SERIAL0_READ, data_in)) == 0) &&
(data_read & IO_MASK(R_SERIAL0_READ, framing_err)) ) {
/* Most likely a break, but we get interrupts over and
* over again.
*/
if (!info->break_detected_cnt) {
DEBUG_LOG(info->line, "#BRK start\n", 0);
}
if (data_read & IO_MASK(R_SERIAL0_READ, rxd)) {
/* The RX pin is high now, so the break
* must be over, but....
* we can't really know if we will get another
* last byte ending the break or not.
* And we don't know if the byte (if any) will
* have an error or look valid.
*/
DEBUG_LOG(info->line, "# BL BRK\n", 0);
info->errorcode = ERRCODE_INSERT_BREAK;
}
info->break_detected_cnt++;
} else {
/* The error does not look like a break, but could be
* the end of one
*/
if (info->break_detected_cnt) {
DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
info->errorcode = ERRCODE_INSERT_BREAK;
} else {
if (info->errorcode == ERRCODE_INSERT_BREAK) {
info->icount.brk++;
*tty->flip.char_buf_ptr = 0;
*tty->flip.flag_buf_ptr = TTY_BREAK;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
info->icount.rx++;
}
*tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
if (data_read & IO_MASK(R_SERIAL0_READ, par_err)) {
info->icount.parity++;
*tty->flip.flag_buf_ptr = TTY_PARITY;
} else if (data_read & IO_MASK(R_SERIAL0_READ, overrun)) {
info->icount.overrun++;
*tty->flip.flag_buf_ptr = TTY_OVERRUN;
} else if (data_read & IO_MASK(R_SERIAL0_READ, framing_err)) {
info->icount.frame++;
*tty->flip.flag_buf_ptr = TTY_FRAME;
}
info->errorcode = 0;
}
info->break_detected_cnt = 0;
}
} else if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
/* No error */
DLOG_INT_TRIG(
if (!log_int_trig1_pos) {
if (log_int_pos >= log_int_size) {
log_int_pos = 0;
}
log_int_trig0_pos = log_int_pos;
log_int(rdpc(), 0, 0);
}
);
*tty->flip.char_buf_ptr = IO_EXTRACT(R_SERIAL0_READ, data_in, data_read);
*tty->flip.flag_buf_ptr = 0;
} else {
DEBUG_LOG(info->line, "ser_rx int but no data_avail %08lX\n", data_read);
}
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;
tty->flip.count++;
info->icount.rx++;
data_read = *((unsigned long *)&info->port[REG_DATA_STATUS32]);
if (data_read & IO_MASK(R_SERIAL0_READ, data_avail)) {
DEBUG_LOG(info->line, "ser_rx %c in loop\n", IO_EXTRACT(R_SERIAL0_READ, data_in, data_read));
goto more_data;
}
tty_flip_buffer_push(info->tty);
return info;
}
extern _INLINE_
struct e100_serial* handle_ser_rx_interrupt(struct e100_serial *info)
{
unsigned char rstat;
#ifdef SERIAL_DEBUG_INTR #ifdef SERIAL_DEBUG_INTR
printk("Interrupt from serport %d\n", i); printk("Interrupt from serport %d\n", i);
#endif #endif
/* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */ /* DEBUG_LOG(info->line, "ser_interrupt stat %03X\n", rstat | (i << 8)); */
if (!info->uses_dma_in) {
return handle_ser_rx_interrupt_no_dma(info);
}
/* DMA is used */
rstat = info->port[REG_STATUS];
if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) ) {
DFLOW(DEBUG_LOG(info->line, "XOFF detect\n", 0));
}
if (rstat & SER_ERROR_MASK) { if (rstat & SER_ERROR_MASK) {
unsigned char data; unsigned char data;
...@@ -2318,7 +2894,8 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info) ...@@ -2318,7 +2894,8 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info)
* data_in field * data_in field
*/ */
data = info->port[REG_DATA]; data = info->port[REG_DATA];
DINTR1(DEBUG_LOG(info->line, "ser_rx! %c\n", data));
DINTR1(DEBUG_LOG(info->line, "ser_rx err stat %02X\n", rstat));
if (!data && (rstat & SER_FRAMING_ERR_MASK)) { if (!data && (rstat & SER_FRAMING_ERR_MASK)) {
/* Most likely a break, but we get interrupts over and /* Most likely a break, but we get interrupts over and
* over again. * over again.
...@@ -2347,15 +2924,22 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info) ...@@ -2347,15 +2924,22 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info)
DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt); DEBUG_LOG(info->line, "EBRK %i\n", info->break_detected_cnt);
info->errorcode = ERRCODE_INSERT_BREAK; info->errorcode = ERRCODE_INSERT_BREAK;
} else { } else {
if (info->errorcode == ERRCODE_INSERT_BREAK) if (info->errorcode == ERRCODE_INSERT_BREAK) {
info->icount.brk++;
add_char_and_flag(info, '\0', TTY_BREAK); add_char_and_flag(info, '\0', TTY_BREAK);
}
if (rstat & SER_PAR_ERR_MASK) if (rstat & SER_PAR_ERR_MASK) {
info->icount.parity++;
add_char_and_flag(info, data, TTY_PARITY); add_char_and_flag(info, data, TTY_PARITY);
else if (rstat & SER_OVERRUN_MASK) } else if (rstat & SER_OVERRUN_MASK) {
info->icount.overrun++;
add_char_and_flag(info, data, TTY_OVERRUN); add_char_and_flag(info, data, TTY_OVERRUN);
else if (rstat & SER_FRAMING_ERR_MASK) } else if (rstat & SER_FRAMING_ERR_MASK) {
info->icount.frame++;
add_char_and_flag(info, data, TTY_FRAME); add_char_and_flag(info, data, TTY_FRAME);
}
info->errorcode = 0; info->errorcode = 0;
} }
info->break_detected_cnt = 0; info->break_detected_cnt = 0;
...@@ -2379,7 +2963,7 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info) ...@@ -2379,7 +2963,7 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info)
if (elapsed_usec < 2*info->char_time_usec) { if (elapsed_usec < 2*info->char_time_usec) {
DEBUG_LOG(info->line, "FBRK %i\n", info->line); DEBUG_LOG(info->line, "FBRK %i\n", info->line);
/* Report as BREAK (error) and let /* Report as BREAK (error) and let
* receive_chars() handle it * receive_chars_dma() handle it
*/ */
info->errorcode = ERRCODE_SET_BREAK; info->errorcode = ERRCODE_SET_BREAK;
} else { } else {
...@@ -2392,38 +2976,196 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info) ...@@ -2392,38 +2976,196 @@ extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info)
printk("** OK, disabling ser_interrupts\n"); printk("** OK, disabling ser_interrupts\n");
#endif #endif
e100_disable_serial_data_irq(info); e100_disable_serial_data_irq(info);
DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line));
info->break_detected_cnt = 0; info->break_detected_cnt = 0;
PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++);
DEBUG_LOG(info->line, "ser_int OK %d\n", info->line);
} }
/* Restarting the DMA never hurts */ /* Restarting the DMA never hurts */
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart);
START_FLUSH_FAST_TIMER(info, "ser_int"); START_FLUSH_FAST_TIMER(info, "ser_int");
return IRQ_HANDLED; return info;
} /* handle_ser_interrupt */ } /* handle_ser_rx_interrupt */
extern _INLINE_ void handle_ser_tx_interrupt(struct e100_serial *info)
{
unsigned long flags;
if (info->x_char) {
unsigned char rstat;
DFLOW(DEBUG_LOG(info->line, "tx_int: xchar 0x%02X\n", info->x_char));
save_flags(flags); cli();
rstat = info->port[REG_STATUS];
DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
info->port[REG_TR_DATA] = info->x_char;
info->icount.tx++;
info->x_char = 0;
/* We must enable since it is disabled in ser_interrupt */
e100_enable_serial_tx_ready_irq(info);
restore_flags(flags);
return;
}
if (info->uses_dma_out) {
unsigned char rstat;
int i;
/* We only use normal tx interrupt when sending x_char */
DFLOW(DEBUG_LOG(info->line, "tx_int: xchar sent\n", 0));
save_flags(flags); cli();
rstat = info->port[REG_STATUS];
DFLOW(DEBUG_LOG(info->line, "stat %x\n", rstat));
e100_disable_serial_tx_ready_irq(info);
if (info->tty->stopped)
rs_stop(info->tty);
/* Enable the DMA channel and tell it to continue */
e100_enable_txdma_channel(info);
/* Wait 12 cycles before doing the DMA command */
for(i = 6; i > 0; i--)
nop();
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, continue);
restore_flags(flags);
return;
}
/* Normal char-by-char interrupt */
if (info->xmit.head == info->xmit.tail
|| info->tty->stopped
|| info->tty->hw_stopped) {
DFLOW(DEBUG_LOG(info->line, "tx_int: stopped %i\n", info->tty->stopped));
e100_disable_serial_tx_ready_irq(info);
info->tr_running = 0;
return;
}
DINTR2(DEBUG_LOG(info->line, "tx_int %c\n", info->xmit.buf[info->xmit.tail]));
/* Send a byte, rs485 timing is critical so turn of ints */
save_flags(flags); cli();
info->port[REG_TR_DATA] = info->xmit.buf[info->xmit.tail];
info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
info->icount.tx++;
if (info->xmit.head == info->xmit.tail) {
#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER)
if (info->rs485.enabled) {
/* Set a short timer to toggle RTS */
start_one_shot_timer(&fast_timers_rs485[info->line],
rs485_toggle_rts_timer_function,
(unsigned long)info,
info->char_time_usec*2,
"RS-485");
}
#endif /* RS485 */
info->last_tx_active_usec = GET_JIFFIES_USEC();
info->last_tx_active = jiffies;
e100_disable_serial_tx_ready_irq(info);
info->tr_running = 0;
DFLOW(DEBUG_LOG(info->line, "tx_int: stop2\n", 0));
} else {
/* We must enable since it is disabled in ser_interrupt */
e100_enable_serial_tx_ready_irq(info);
}
restore_flags(flags);
if (CIRC_CNT(info->xmit.head,
info->xmit.tail,
SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
} /* handle_ser_tx_interrupt */
/* result of time measurements:
* RX duration 54-60 us when doing something, otherwise 6-9 us
* ser_int duration: just sending: 8-15 us normally, up to 73 us
*/
static irqreturn_t static irqreturn_t
ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{ {
static volatile int tx_started = 0;
struct e100_serial *info; struct e100_serial *info;
int i; int i;
unsigned long flags;
unsigned long irq_mask1_rd;
unsigned long data_mask = (1 << (8+2*0)); /* ser0 data_avail */
int handled = 0; int handled = 0;
static volatile unsigned long reentered_ready_mask = 0;
save_flags(flags); cli();
irq_mask1_rd = *R_IRQ_MASK1_RD;
/* First handle all rx interrupts with ints disabled */
info = rs_table;
irq_mask1_rd &= e100_ser_int_mask;
for (i = 0; i < NR_PORTS; i++) { for (i = 0; i < NR_PORTS; i++) {
info = rs_table + i; /* Which line caused the data irq? */
if (irq_mask1_rd & data_mask) {
if (!info->enabled || !info->uses_dma)
continue;
/* Which line caused the irq? */
if (*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) {
handled = 1; handled = 1;
handle_ser_interrupt(info); handle_ser_rx_interrupt(info);
}
info += 1;
data_mask <<= 2;
}
/* Handle tx interrupts with interrupts enabled so we
* can take care of new data interrupts while transmitting
* We protect the tx part with the tx_started flag.
* We disable the tr_ready interrupts we are about to handle and
* unblock the serial interrupt so new serial interrupts may come.
*
* If we get a new interrupt:
* - it migth be due to synchronous serial ports.
* - serial irq will be blocked by general irq handler.
* - async data will be handled above (sync will be ignored).
* - tx_started flag will prevent us from trying to send again and
* we will exit fast - no need to unblock serial irq.
* - Next (sync) serial interrupt handler will be runned with
* disabled interrupt due to restore_flags() at end of function,
* so sync handler will not be preempted or reentered.
*/
if (!tx_started) {
unsigned long ready_mask;
unsigned long
tx_started = 1;
/* Only the tr_ready interrupts left */
irq_mask1_rd &= (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
while (irq_mask1_rd) {
/* Disable those we are about to handle */
*R_IRQ_MASK1_CLR = irq_mask1_rd;
/* Unblock the serial interrupt */
*R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set);
sti();
ready_mask = (1 << (8+1+2*0)); /* ser0 tr_ready */
info = rs_table;
for (i = 0; i < NR_PORTS; i++) {
/* Which line caused the ready irq? */
if (irq_mask1_rd & ready_mask) {
handled = 1;
handle_ser_tx_interrupt(info);
}
info += 1;
ready_mask <<= 2;
}
/* handle_ser_tx_interrupt enables tr_ready interrupts */
cli();
/* Handle reentered TX interrupt */
irq_mask1_rd = reentered_ready_mask;
}
cli();
tx_started = 0;
} else {
unsigned long ready_mask;
ready_mask = irq_mask1_rd & (IO_MASK(R_IRQ_MASK1_RD, ser0_ready) |
IO_MASK(R_IRQ_MASK1_RD, ser1_ready) |
IO_MASK(R_IRQ_MASK1_RD, ser2_ready) |
IO_MASK(R_IRQ_MASK1_RD, ser3_ready));
if (ready_mask) {
reentered_ready_mask |= ready_mask;
/* Disable those we are about to handle */
*R_IRQ_MASK1_CLR = ready_mask;
DFLOW(DEBUG_LOG(SERIAL_DEBUG_LINE, "ser_int reentered with TX %X\n", ready_mask));
} }
} }
restore_flags(flags);
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
} /* ser_interrupt */ } /* ser_interrupt */
#endif #endif
...@@ -2489,7 +3231,7 @@ startup(struct e100_serial * info) ...@@ -2489,7 +3231,7 @@ startup(struct e100_serial * info)
info->xmit.buf = (unsigned char *) xmit_page; info->xmit.buf = (unsigned char *) xmit_page;
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("starting up ttyS%d (xmit_buf 0x%p, recv_buf 0x%p)...\n", info->line, info->xmit.buf, info->recv.buf); printk("starting up ttyS%d (xmit_buf 0x%p)...\n", info->line, info->xmit.buf);
#endif #endif
#ifdef CONFIG_SVINTO_SIM #ifdef CONFIG_SVINTO_SIM
...@@ -2520,24 +3262,39 @@ startup(struct e100_serial * info) ...@@ -2520,24 +3262,39 @@ startup(struct e100_serial * info)
* Reset the DMA channels and make sure their interrupts are cleared * Reset the DMA channels and make sure their interrupts are cleared
*/ */
info->uses_dma = 1; if (info->dma_in_enabled) {
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); info->uses_dma_in = 1;
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); e100_enable_rxdma_channel(info);
/* Wait until reset cycle is complete */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) == /* Wait until reset cycle is complete */
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->icmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
/* Make sure the irqs are cleared */ /* Make sure the irqs are cleared */
*info->iclrintradr = *info->iclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
*info->oclrintradr = } else {
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) | e100_disable_rxdma_channel(info);
IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do); }
if (info->dma_out_enabled) {
info->uses_dma_out = 1;
e100_enable_txdma_channel(info);
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) ==
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset));
/* Make sure the irqs are cleared */
*info->oclrintradr =
IO_STATE(R_DMA_CH6_CLR_INTR, clr_descr, do) |
IO_STATE(R_DMA_CH6_CLR_INTR, clr_eop, do);
} else {
e100_disable_txdma_channel(info);
}
if (info->tty) if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags); clear_bit(TTY_IO_ERROR, &info->tty->flags);
...@@ -2563,9 +3320,10 @@ startup(struct e100_serial * info) ...@@ -2563,9 +3320,10 @@ startup(struct e100_serial * info)
(void)info->port[REG_DATA]; (void)info->port[REG_DATA];
/* enable the interrupts */ /* enable the interrupts */
if (info->uses_dma_out)
e100_enable_txdma_irq(info);
e100_enable_txdma_irq(info); e100_enable_rx_irq(info);
e100_enable_rxdma_irq(info);
info->tr_running = 0; /* to be sure we don't lock up the transmitter */ info->tr_running = 0; /* to be sure we don't lock up the transmitter */
...@@ -2606,20 +3364,28 @@ shutdown(struct e100_serial * info) ...@@ -2606,20 +3364,28 @@ shutdown(struct e100_serial * info)
#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_SVINTO_SIM
/* shut down the transmitter and receiver */ /* shut down the transmitter and receiver */
DFLOW(DEBUG_LOG(info->line, "shutdown %i\n", info->line));
e100_disable_rx(info); e100_disable_rx(info);
info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40); info->port[REG_TR_CTRL] = (info->tx_ctrl &= ~0x40);
e100_disable_rxdma_irq(info); /* disable interrupts, reset dma channels */
e100_disable_txdma_irq(info); if (info->uses_dma_in) {
e100_disable_rxdma_irq(info);
info->tr_running = 0; *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
info->uses_dma_in = 0;
/* reset both dma channels */ } else {
e100_disable_serial_data_irq(info);
}
*info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); if (info->uses_dma_out) {
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset); e100_disable_txdma_irq(info);
info->uses_dma = 0; info->tr_running = 0;
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, reset);
info->uses_dma_out = 0;
} else {
e100_disable_serial_tx_ready_irq(info);
info->tr_running = 0;
}
#endif /* CONFIG_SVINTO_SIM */ #endif /* CONFIG_SVINTO_SIM */
...@@ -2667,7 +3433,7 @@ change_speed(struct e100_serial *info) ...@@ -2667,7 +3433,7 @@ change_speed(struct e100_serial *info)
{ {
unsigned int cflag; unsigned int cflag;
unsigned long xoff; unsigned long xoff;
unsigned long flags;
/* first some safety checks */ /* first some safety checks */
if (!info->tty || !info->tty->termios) if (!info->tty || !info->tty->termios)
...@@ -2676,17 +3442,80 @@ change_speed(struct e100_serial *info) ...@@ -2676,17 +3442,80 @@ change_speed(struct e100_serial *info)
return; return;
cflag = info->tty->termios->c_cflag; cflag = info->tty->termios->c_cflag;
/* possibly, the tx/rx should be disabled first to do this safely */ /* possibly, the tx/rx should be disabled first to do this safely */
/* change baud-rate and write it to the hardware */ /* change baud-rate and write it to the hardware */
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) {
info->baud = cflag_to_baud(cflag); /* Special baudrate */
u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
unsigned long alt_source =
IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
/* R_ALT_SER_BAUDRATE selects the source */
DBAUD(printk("Custom baudrate: baud_base/divisor %lu/%i\n",
(unsigned long)info->baud_base, info->custom_divisor));
if (info->baud_base == SERIAL_PRESCALE_BASE) {
/* 0, 2-65535 (0=65536) */
u16 divisor = info->custom_divisor;
/* R_SERIAL_PRESCALE (upper 16 bits of R_CLOCK_PRESCALE) */
/* baudrate is 3.125MHz/custom_divisor */
alt_source =
IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, prescale) |
IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, prescale);
alt_source = 0x11;
DBAUD(printk("Writing SERIAL_PRESCALE: divisor %i\n", divisor));
*R_SERIAL_PRESCALE = divisor;
info->baud = SERIAL_PRESCALE_BASE/divisor;
}
#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED
else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 &&
info->custom_divisor == 1) ||
(info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ &&
info->custom_divisor == 8)) {
/* ext_clk selected */
alt_source =
IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) |
IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern);
DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8));
info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8;
}
}
#endif
else
{
/* Bad baudbase, we don't support using timer0
* for baudrate.
*/
printk(KERN_WARNING "Bad baud_base/custom_divisor: %lu/%i\n",
(unsigned long)info->baud_base, info->custom_divisor);
}
r_alt_ser_baudrate_shadow &= ~mask;
r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
} else {
/* Normal baudrate */
/* Make sure we use normal baudrate */
u32 mask = 0xFF << (info->line*8); /* Each port has 8 bits */
unsigned long alt_source =
IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, normal) |
IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, normal);
r_alt_ser_baudrate_shadow &= ~mask;
r_alt_ser_baudrate_shadow |= (alt_source << (info->line*8));
#ifndef CONFIG_SVINTO_SIM
*R_ALT_SER_BAUDRATE = r_alt_ser_baudrate_shadow;
#endif /* CONFIG_SVINTO_SIM */
info->baud = cflag_to_baud(cflag);
#ifndef CONFIG_SVINTO_SIM
info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
#endif /* CONFIG_SVINTO_SIM */
}
#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_SVINTO_SIM
info->port[REG_BAUD] = cflag_to_etrax_baud(cflag);
/* start with default settings and then fill in changes */ /* start with default settings and then fill in changes */
save_flags(flags);
cli();
/* 8 bit, no/even parity */ /* 8 bit, no/even parity */
info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) | info->rx_ctrl &= ~(IO_MASK(R_SERIAL0_REC_CTRL, rec_bitnr) |
IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) | IO_MASK(R_SERIAL0_REC_CTRL, rec_par_en) |
...@@ -2717,24 +3546,19 @@ change_speed(struct e100_serial *info) ...@@ -2717,24 +3546,19 @@ change_speed(struct e100_serial *info)
} }
if (cflag & CMSPAR) { if (cflag & CMSPAR) {
/* enable stick parity */ /* enable stick parity, PARODD mean Mark which matches ETRAX */
info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick); info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, stick);
info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick); info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, stick);
if (!(cflag & PARODD)) { }
/* set mark parity */ if (cflag & PARODD) {
info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd); /* set odd parity (or Mark if CMSPAR) */
info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd); info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
} info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
} else {
if (cflag & PARODD) {
/* set odd parity */
info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd);
info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd);
}
} }
if (cflag & CRTSCTS) { if (cflag & CRTSCTS) {
/* enable automatic CTS handling */ /* enable automatic CTS handling */
DFLOW(DEBUG_LOG(info->line, "FLOW auto_cts enabled\n", 0));
info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active); info->tx_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, active);
} }
...@@ -2750,13 +3574,16 @@ change_speed(struct e100_serial *info) ...@@ -2750,13 +3574,16 @@ change_speed(struct e100_serial *info)
xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty));
xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
if (info->tty->termios->c_iflag & IXON ) { if (info->tty->termios->c_iflag & IXON ) {
DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n", STOP_CHAR(info->tty)));
xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
} }
*((unsigned long *)&info->port[REG_XOFF]) = xoff; *((unsigned long *)&info->port[REG_XOFF]) = xoff;
restore_flags(flags);
#endif /* !CONFIG_SVINTO_SIM */ #endif /* !CONFIG_SVINTO_SIM */
update_char_time(info); update_char_time(info);
} /* change_speed */ } /* change_speed */
/* start transmitting chars NOW */ /* start transmitting chars NOW */
...@@ -2786,8 +3613,8 @@ rs_flush_chars(struct tty_struct *tty) ...@@ -2786,8 +3613,8 @@ rs_flush_chars(struct tty_struct *tty)
restore_flags(flags); restore_flags(flags);
} }
extern inline int extern _INLINE_ int
raw_write(struct tty_struct * tty, int from_user, rs_raw_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count) const unsigned char *buf, int count)
{ {
int c, ret = 0; int c, ret = 0;
...@@ -2801,7 +3628,7 @@ raw_write(struct tty_struct * tty, int from_user, ...@@ -2801,7 +3628,7 @@ raw_write(struct tty_struct * tty, int from_user,
#ifdef SERIAL_DEBUG_DATA #ifdef SERIAL_DEBUG_DATA
if (info->line == SERIAL_DEBUG_LINE) if (info->line == SERIAL_DEBUG_LINE)
printk("raw_write (%d), status %d\n", printk("rs_raw_write (%d), status %d\n",
count, info->port[REG_STATUS]); count, info->port[REG_STATUS]);
#endif #endif
...@@ -2811,6 +3638,9 @@ raw_write(struct tty_struct * tty, int from_user, ...@@ -2811,6 +3638,9 @@ raw_write(struct tty_struct * tty, int from_user,
return count; return count;
#endif #endif
save_flags(flags); save_flags(flags);
DFLOW(DEBUG_LOG(info->line, "write count %i ", count));
DFLOW(DEBUG_LOG(info->line, "ldisc %i\n", tty->ldisc.chars_in_buffer(tty)));
/* the cli/restore_flags pairs below are needed because the /* the cli/restore_flags pairs below are needed because the
* DMA interrupt handler moves the info->xmit values. the memcpy * DMA interrupt handler moves the info->xmit values. the memcpy
...@@ -2878,6 +3708,7 @@ raw_write(struct tty_struct * tty, int from_user, ...@@ -2878,6 +3708,7 @@ raw_write(struct tty_struct * tty, int from_user,
* this does not need IRQ protection since if tr_running == 0 * this does not need IRQ protection since if tr_running == 0
* the IRQ's are not running anyway for this port. * the IRQ's are not running anyway for this port.
*/ */
DFLOW(DEBUG_LOG(info->line, "write ret %i\n", ret));
if (info->xmit.head != info->xmit.tail && if (info->xmit.head != info->xmit.tail &&
!tty->stopped && !tty->stopped &&
...@@ -2887,7 +3718,7 @@ raw_write(struct tty_struct * tty, int from_user, ...@@ -2887,7 +3718,7 @@ raw_write(struct tty_struct * tty, int from_user,
} }
return ret; return ret;
} /* raw_write() */ } /* raw_raw_write() */
static int static int
rs_write(struct tty_struct * tty, int from_user, rs_write(struct tty_struct * tty, int from_user,
...@@ -2909,7 +3740,7 @@ rs_write(struct tty_struct * tty, int from_user, ...@@ -2909,7 +3740,7 @@ rs_write(struct tty_struct * tty, int from_user,
e100_rts(info, info->rs485.rts_on_send); e100_rts(info, info->rs485.rts_on_send);
#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER)
e100_disable_rx(info); e100_disable_rx(info);
e100_disable_rxdma_irq(info); e100_enable_rx_irq(info);
#endif #endif
if (info->rs485.delay_rts_before_send > 0) { if (info->rs485.delay_rts_before_send > 0) {
...@@ -2919,7 +3750,7 @@ rs_write(struct tty_struct * tty, int from_user, ...@@ -2919,7 +3750,7 @@ rs_write(struct tty_struct * tty, int from_user,
} }
#endif /* CONFIG_ETRAX_RS485 */ #endif /* CONFIG_ETRAX_RS485 */
count = raw_write(tty, from_user, buf, count); count = rs_raw_write(tty, from_user, buf, count);
#if defined(CONFIG_ETRAX_RS485) #if defined(CONFIG_ETRAX_RS485)
if (info->rs485.enabled) if (info->rs485.enabled)
...@@ -3003,23 +3834,33 @@ rs_flush_buffer(struct tty_struct *tty) ...@@ -3003,23 +3834,33 @@ rs_flush_buffer(struct tty_struct *tty)
* This function is used to send a high-priority XON/XOFF character to * This function is used to send a high-priority XON/XOFF character to
* the device * the device
* *
* Since we use DMA we don't check for info->x_char in transmit_chars, * Since we use DMA we don't check for info->x_char in transmit_chars_dma(),
* just disable DMA channel and write the character when possible. * but we do it in handle_ser_tx_interrupt().
* We disable DMA channel and enable tx ready interrupt and write the
* character when possible.
*/ */
static void rs_send_xchar(struct tty_struct *tty, char ch) static void rs_send_xchar(struct tty_struct *tty, char ch)
{ {
struct e100_serial *info = (struct e100_serial *)tty->driver_data; struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned long flags;
save_flags(flags); cli();
if (info->uses_dma_out) {
/* Put the DMA on hold and disable the channel */
*info->ocmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, hold);
while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *info->ocmdadr) !=
IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, hold));
e100_disable_txdma_channel(info);
}
e100_disable_txdma_channel(info); /* Must make sure transmitter is not stopped before we can transmit */
if (tty->stopped)
/* Wait for tr_ready */ rs_start(tty);
while (!(info->port[REG_STATUS] & IO_MASK(R_SERIAL0_STATUS, tr_ready)))
/* wait */;
/* Write the XON/XOFF char */
info->port[REG_TR_DATA] = ch;
e100_enable_txdma_channel(info); /* Enable manual transmit interrupt and send from there */
DFLOW(DEBUG_LOG(info->line, "rs_send_xchar 0x%02X\n", ch));
info->x_char = ch;
e100_enable_serial_tx_ready_irq(info);
restore_flags(flags);
} }
/* /*
...@@ -3034,21 +3875,18 @@ static void ...@@ -3034,21 +3875,18 @@ static void
rs_throttle(struct tty_struct * tty) rs_throttle(struct tty_struct * tty)
{ {
struct e100_serial *info = (struct e100_serial *)tty->driver_data; struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE #ifdef SERIAL_DEBUG_THROTTLE
char buf[64]; char buf[64];
printk("throttle %s: %d....\n", _tty_name(tty, buf), printk("throttle %s: %lu....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty)); (unsigned long)tty->ldisc.chars_in_buffer(tty));
#endif #endif
DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
/* Do RTS before XOFF since XOFF might take some time */ /* Do RTS before XOFF since XOFF might take some time */
if (tty->termios->c_cflag & CRTSCTS) { if (tty->termios->c_cflag & CRTSCTS) {
/* Turn off RTS line (do this atomic) */ /* Turn off RTS line */
save_flags(flags);
cli();
e100_rts(info, 0); e100_rts(info, 0);
restore_flags(flags);
} }
if (I_IXOFF(tty)) if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty)); rs_send_xchar(tty, STOP_CHAR(tty));
...@@ -3059,21 +3897,18 @@ static void ...@@ -3059,21 +3897,18 @@ static void
rs_unthrottle(struct tty_struct * tty) rs_unthrottle(struct tty_struct * tty)
{ {
struct e100_serial *info = (struct e100_serial *)tty->driver_data; struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE #ifdef SERIAL_DEBUG_THROTTLE
char buf[64]; char buf[64];
printk("unthrottle %s: %d....\n", _tty_name(tty, buf), printk("unthrottle %s: %lu....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty)); (unsigned long)tty->ldisc.chars_in_buffer(tty));
#endif #endif
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
/* Do RTS before XOFF since XOFF might take some time */ /* Do RTS before XOFF since XOFF might take some time */
if (tty->termios->c_cflag & CRTSCTS) { if (tty->termios->c_cflag & CRTSCTS) {
/* Assert RTS line (do this atomic) */ /* Assert RTS line */
save_flags(flags);
cli();
e100_rts(info, 1); e100_rts(info, 1);
restore_flags(flags);
} }
if (I_IXOFF(tty)) { if (I_IXOFF(tty)) {
...@@ -3110,8 +3945,10 @@ get_serial_info(struct e100_serial * info, ...@@ -3110,8 +3945,10 @@ get_serial_info(struct e100_serial * info,
tmp.port = (int)info->port; tmp.port = (int)info->port;
tmp.irq = info->irq; tmp.irq = info->irq;
tmp.flags = info->flags; tmp.flags = info->flags;
tmp.baud_base = info->baud_base;
tmp.close_delay = info->close_delay; tmp.close_delay = info->close_delay;
tmp.closing_wait = info->closing_wait; tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -3149,8 +3986,10 @@ set_serial_info(struct e100_serial *info, ...@@ -3149,8 +3986,10 @@ set_serial_info(struct e100_serial *info,
* At this point, we start making changes..... * At this point, we start making changes.....
*/ */
info->baud_base = new_serial.baud_base;
info->flags = ((info->flags & ~ASYNC_FLAGS) | info->flags = ((info->flags & ~ASYNC_FLAGS) |
(new_serial.flags & ASYNC_FLAGS)); (new_serial.flags & ASYNC_FLAGS));
info->custom_divisor = new_serial.custom_divisor;
info->type = new_serial.type; info->type = new_serial.type;
info->close_delay = new_serial.close_delay; info->close_delay = new_serial.close_delay;
info->closing_wait = new_serial.closing_wait; info->closing_wait = new_serial.closing_wait;
...@@ -3418,6 +4257,7 @@ rs_set_termios(struct tty_struct *tty, struct termios *old_termios) ...@@ -3418,6 +4257,7 @@ rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
change_speed(info); change_speed(info);
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && if ((old_termios->c_cflag & CRTSCTS) &&
!(tty->termios->c_cflag & CRTSCTS)) { !(tty->termios->c_cflag & CRTSCTS)) {
tty->hw_stopped = 0; tty->hw_stopped = 0;
...@@ -3426,6 +4266,42 @@ rs_set_termios(struct tty_struct *tty, struct termios *old_termios) ...@@ -3426,6 +4266,42 @@ rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
} }
/* In debugport.c - register a console write function that uses the normal
* serial driver
*/
typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
extern debugport_write_function debug_write_function;
static int rs_debug_write_function(int i, const char *buf, unsigned int len)
{
int cnt;
struct tty_struct *tty;
static int recurse_cnt = 0;
tty = rs_table[i].tty;
if (tty) {
unsigned long flags;
if (recurse_cnt > 5) /* We skip this debug output */
return 1;
local_irq_save(flags);
recurse_cnt++;
do {
cnt = rs_write(tty, 0, buf, len);
if (cnt >= 0) {
buf += cnt;
len -= cnt;
} else
len = cnt;
} while(len > 0);
recurse_cnt--;
local_irq_restore(flags);
return 1;
}
return 0;
}
/* /*
* ------------------------------------------------------------ * ------------------------------------------------------------
* rs_close() * rs_close()
...@@ -3482,6 +4358,12 @@ rs_close(struct tty_struct *tty, struct file * filp) ...@@ -3482,6 +4358,12 @@ rs_close(struct tty_struct *tty, struct file * filp)
return; return;
} }
info->flags |= ASYNC_CLOSING; info->flags |= ASYNC_CLOSING;
/*
* Save the termios structure, since this port may have
* separate termios for callout and dialin.
*/
if (info->flags & ASYNC_NORMAL_ACTIVE)
info->normal_termios = *tty->termios;
/* /*
* Now we wait for the transmit buffer to clear; and we notify * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters. * the line discipline to only process XON/XOFF characters.
...@@ -3499,7 +4381,7 @@ rs_close(struct tty_struct *tty, struct file * filp) ...@@ -3499,7 +4381,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_SVINTO_SIM
e100_disable_rx(info); e100_disable_rx(info);
e100_disable_rxdma_irq(info); e100_disable_rx_irq(info);
if (info->flags & ASYNC_INITIALIZED) { if (info->flags & ASYNC_INITIALIZED) {
/* /*
...@@ -3537,6 +4419,16 @@ rs_close(struct tty_struct *tty, struct file * filp) ...@@ -3537,6 +4419,16 @@ rs_close(struct tty_struct *tty, struct file * filp)
info->rs485.enabled = 0; info->rs485.enabled = 0;
#if defined(CONFIG_ETRAX_RS485_ON_PA) #if defined(CONFIG_ETRAX_RS485_ON_PA)
*R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit);
#endif
#if defined(CONFIG_ETRAX_RS485_ON_PORT_G)
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
rs485_port_g_bit, 0);
#endif
#if defined(CONFIG_ETRAX_RS485_LTC1387)
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0);
REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow,
CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0);
#endif #endif
} }
#endif #endif
...@@ -3637,8 +4529,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -3637,8 +4529,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
return 0; return 0;
} }
if (tty->termios->c_cflag & CLOCAL) if (tty->termios->c_cflag & CLOCAL) {
do_clocal = 1; do_clocal = 1;
}
/* /*
* Block waiting for the carrier detect and the line to become * Block waiting for the carrier detect and the line to become
...@@ -3664,7 +4557,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -3664,7 +4557,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
while (1) { while (1) {
save_flags(flags); save_flags(flags);
cli(); cli();
/* assert RTS and DTR */ /* assert RTS and DTR */
e100_rts(info, 1); e100_rts(info, 1);
e100_dtr(info, 1); e100_dtr(info, 1);
restore_flags(flags); restore_flags(flags);
...@@ -3681,7 +4574,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, ...@@ -3681,7 +4574,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
#endif #endif
break; break;
} }
if (!(info->flags & ASYNC_CLOSING) && do_clocal) if (!(info->flags & ASYNC_CLOSING) && do_clocal)
/* && (do_clocal || DCD_IS_ASSERTED) */ /* && (do_clocal || DCD_IS_ASSERTED) */
break; break;
if (signal_pending(current)) { if (signal_pending(current)) {
...@@ -3787,10 +4680,21 @@ rs_open(struct tty_struct *tty, struct file * filp) ...@@ -3787,10 +4680,21 @@ rs_open(struct tty_struct *tty, struct file * filp)
#endif #endif
return retval; return retval;
} }
if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
*tty->termios = info->normal_termios;
change_speed(info);
}
#ifdef SERIAL_DEBUG_OPEN #ifdef SERIAL_DEBUG_OPEN
printk("rs_open ttyS%d successful...\n", info->line); printk("rs_open ttyS%d successful...\n", info->line);
#endif #endif
DLOG_INT_TRIG( log_int_pos = 0);
DFLIP( if (info->line == SERIAL_DEBUG_LINE) {
info->icount.rx = 0;
} );
return 0; return 0;
} }
...@@ -3798,10 +4702,11 @@ rs_open(struct tty_struct *tty, struct file * filp) ...@@ -3798,10 +4702,11 @@ rs_open(struct tty_struct *tty, struct file * filp)
* /proc fs routines.... * /proc fs routines....
*/ */
extern inline int line_info(char *buf, struct e100_serial *info) extern _INLINE_ int line_info(char *buf, struct e100_serial *info)
{ {
char stat_buf[30]; char stat_buf[30];
int ret; int ret;
unsigned long tmp;
ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d", ret = sprintf(buf, "%d: uart:E100 port:%lX irq:%d",
info->line, (unsigned long)info->port, info->irq); info->line, (unsigned long)info->port, info->irq);
...@@ -3831,11 +4736,39 @@ extern inline int line_info(char *buf, struct e100_serial *info) ...@@ -3831,11 +4736,39 @@ extern inline int line_info(char *buf, struct e100_serial *info)
ret += sprintf(buf+ret, " tx:%lu rx:%lu", ret += sprintf(buf+ret, " tx:%lu rx:%lu",
(unsigned long)info->icount.tx, (unsigned long)info->icount.tx,
(unsigned long)info->icount.rx); (unsigned long)info->icount.rx);
tmp = CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
if (tmp) {
ret += sprintf(buf+ret, " tx_pend:%lu/%lu",
(unsigned long)tmp,
(unsigned long)SERIAL_XMIT_SIZE);
}
ret += sprintf(buf+ret, " rx_pend:%lu/%lu", ret += sprintf(buf+ret, " rx_pend:%lu/%lu",
(unsigned long)info->recv_cnt, (unsigned long)info->recv_cnt,
(unsigned long)info->max_recv_cnt); (unsigned long)info->max_recv_cnt);
#if 1
if (info->tty) {
if (info->tty->stopped)
ret += sprintf(buf+ret, " stopped:%i",
(int)info->tty->stopped);
if (info->tty->hw_stopped)
ret += sprintf(buf+ret, " hw_stopped:%i",
(int)info->tty->hw_stopped);
}
{
unsigned char rstat = info->port[REG_STATUS];
if (rstat & IO_MASK(R_SERIAL0_STATUS, xoff_detect) )
ret += sprintf(buf+ret, " xoff_detect:1");
}
#endif
if (info->icount.frame) if (info->icount.frame)
ret += sprintf(buf+ret, " fe:%lu", ret += sprintf(buf+ret, " fe:%lu",
(unsigned long)info->icount.frame); (unsigned long)info->icount.frame);
...@@ -3879,6 +4812,22 @@ int rs_read_proc(char *page, char **start, off_t off, int count, ...@@ -3879,6 +4812,22 @@ int rs_read_proc(char *page, char **start, off_t off, int count,
len = 0; len = 0;
} }
} }
#ifdef DEBUG_LOG_INCLUDED
for (i = 0; i < debug_log_pos; i++) {
len += sprintf(page + len, "%-4i %lu.%lu ", i, debug_log[i].time, timer_data_to_ns(debug_log[i].timer_data));
len += sprintf(page + len, debug_log[i].string, debug_log[i].value);
if (len+begin > off+count)
goto done;
if (len+begin < off) {
begin += len;
len = 0;
}
}
len += sprintf(page + len, "debug_log %i/%i %li bytes\n",
i, DEBUG_LOG_SIZE, begin+len);
debug_log_pos = 0;
#endif
*eof = 1; *eof = 1;
done: done:
if (off >= len+begin) if (off >= len+begin)
...@@ -3893,7 +4842,7 @@ static void ...@@ -3893,7 +4842,7 @@ static void
show_serial_version(void) show_serial_version(void)
{ {
printk(KERN_INFO printk(KERN_INFO
"ETRAX 100LX serial-driver %s, (c) 2000-2003 Axis Communications AB\r\n", "ETRAX 100LX serial-driver %s, (c) 2000-2004 Axis Communications AB\r\n",
&serial_version[11]); /* "$Revision: x.yy" */ &serial_version[11]); /* "$Revision: x.yy" */
} }
...@@ -3952,20 +4901,25 @@ rs_init(void) ...@@ -3952,20 +4901,25 @@ rs_init(void)
driver->init_termios.c_cflag = driver->init_termios.c_cflag =
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
driver->termios = serial_termios;
driver->termios_locked = serial_termios_locked;
tty_set_operations(driver, &rs_ops); tty_set_operations(driver, &rs_ops);
serial_driver = driver;
if (tty_register_driver(driver)) if (tty_register_driver(driver))
panic("Couldn't register serial driver\n"); panic("Couldn't register serial driver\n");
serial_driver = driver;
/* do some initializing for the separate ports */ /* do some initializing for the separate ports */
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
info->uses_dma = 0; info->uses_dma_in = 0;
info->uses_dma_out = 0;
info->line = i; info->line = i;
info->tty = 0; info->tty = 0;
info->type = PORT_ETRAX; info->type = PORT_ETRAX;
info->tr_running = 0; info->tr_running = 0;
info->forced_eop = 0; info->forced_eop = 0;
info->baud_base = DEF_BAUD_BASE;
info->custom_divisor = 0;
info->flags = 0; info->flags = 0;
info->close_delay = 5*HZ/10; info->close_delay = 5*HZ/10;
info->closing_wait = 30*HZ; info->closing_wait = 30*HZ;
...@@ -3973,6 +4927,7 @@ rs_init(void) ...@@ -3973,6 +4927,7 @@ rs_init(void)
info->event = 0; info->event = 0;
info->count = 0; info->count = 0;
info->blocked_open = 0; info->blocked_open = 0;
info->normal_termios = driver->init_termios;
init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->open_wait);
init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->close_wait);
info->xmit.buf = NULL; info->xmit.buf = NULL;
...@@ -4009,39 +4964,62 @@ rs_init(void) ...@@ -4009,39 +4964,62 @@ rs_init(void)
#ifndef CONFIG_SVINTO_SIM #ifndef CONFIG_SVINTO_SIM
/* Not needed in simulator. May only complicate stuff. */ /* Not needed in simulator. May only complicate stuff. */
/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */ /* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
panic("irq8");
#ifdef CONFIG_ETRAX_SERIAL_PORT0 #ifdef CONFIG_ETRAX_SERIAL_PORT0
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL)) if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
panic("irq22"); panic("irq22");
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL)) if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
panic("irq23"); panic("irq23");
#endif #endif
#ifdef SERIAL_HANDLE_EARLY_ERRORS
if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
panic("irq8");
#endif #endif
#ifdef CONFIG_ETRAX_SERIAL_PORT1 #ifdef CONFIG_ETRAX_SERIAL_PORT1
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL)) if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
panic("irq24"); panic("irq24");
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL)) if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
panic("irq25"); panic("irq25");
#endif #endif
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2 #ifdef CONFIG_ETRAX_SERIAL_PORT2
/* DMA Shared with par0 (and SCSI0 and ATA) */ /* DMA Shared with par0 (and SCSI0 and ATA) */
if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 2 dma tr", NULL)) #ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma tr", NULL))
panic("irq18"); panic("irq18");
if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 2 dma rec", NULL)) #endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma rec", NULL))
panic("irq19"); panic("irq19");
#endif #endif
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT3 #ifdef CONFIG_ETRAX_SERIAL_PORT3
/* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */ /* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ, "serial 3 dma tr", NULL)) #ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma tr", NULL))
panic("irq20"); panic("irq20");
if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ, "serial 3 dma rec", NULL)) #endif
#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma rec", NULL))
panic("irq21"); panic("irq21");
#endif #endif
#endif
#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT,
"fast serial dma timeout", NULL)) {
printk(KERN_CRIT "err: timer1 irq\n");
}
#endif
#endif /* CONFIG_SVINTO_SIM */ #endif /* CONFIG_SVINTO_SIM */
debug_write_function = rs_debug_write_function;
return 0; return 0;
} }
......
...@@ -44,15 +44,11 @@ struct e100_serial { ...@@ -44,15 +44,11 @@ struct e100_serial {
volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */ volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST */
volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */ volatile u8 *ocmdadr; /* adr to R_DMA_CHx_CMD */
const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */ const volatile u8 *ostatusadr; /* adr to R_DMA_CHx_STATUS */
volatile u32 *ohwswadr; /* adr to R_DMA_CHx_HWSW */
volatile u32 *odescradr; /* adr to R_DMA_CHx_DESCR */
/* Input registers */ /* Input registers */
volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */ volatile u8 *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR */
volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */ volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST */
volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */ volatile u8 *icmdadr; /* adr to R_DMA_CHx_CMD */
const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS */
volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW */
volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */ volatile u32 *idescradr; /* adr to R_DMA_CHx_DESCR */
int flags; /* defined in tty.h */ int flags; /* defined in tty.h */
...@@ -60,14 +56,17 @@ struct e100_serial { ...@@ -60,14 +56,17 @@ struct e100_serial {
u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */ u8 rx_ctrl; /* shadow for R_SERIALx_REC_CTRL */
u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */ u8 tx_ctrl; /* shadow for R_SERIALx_TR_CTRL */
u8 iseteop; /* bit number for R_SET_EOP for the input dma */ u8 iseteop; /* bit number for R_SET_EOP for the input dma */
int enabled; /* Set to 1 if the port is enabled in HW config */ int enabled; /* Set to 1 if the port is enabled in HW config */
/* end of fields defined in rs_table[] in .c-file */
int uses_dma; /* Set to 1 if DMA should be used */ u8 dma_out_enabled:1; /* Set to 1 if DMA should be used */
unsigned char forced_eop; /* a fifo eop has been forced */ u8 dma_in_enabled:1; /* Set to 1 if DMA should be used */
/* end of fields defined in rs_table[] in .c-file */
u8 uses_dma_in; /* Set to 1 if DMA is used */
u8 uses_dma_out; /* Set to 1 if DMA is used */
u8 forced_eop; /* a fifo eop has been forced */
int baud_base; /* For special baudrates */
int custom_divisor; /* For special baudrates */
struct etrax_dma_descr tr_descr; struct etrax_dma_descr tr_descr;
struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS]; struct etrax_dma_descr rec_descr[SERIAL_RECV_DESCRIPTORS];
int cur_rec_descr; int cur_rec_descr;
...@@ -95,6 +94,8 @@ struct e100_serial { ...@@ -95,6 +94,8 @@ struct e100_serial {
struct work_struct work; struct work_struct work;
struct async_icount icount; /* error-statistics etc.*/ struct async_icount icount; /* error-statistics etc.*/
struct termios normal_termios;
struct termios callout_termios;
#ifdef DECLARE_WAITQUEUE #ifdef DECLARE_WAITQUEUE
wait_queue_head_t open_wait; wait_queue_head_t open_wait;
wait_queue_head_t close_wait; wait_queue_head_t close_wait;
...@@ -104,6 +105,7 @@ struct e100_serial { ...@@ -104,6 +105,7 @@ struct e100_serial {
#endif #endif
unsigned long char_time_usec; /* The time for 1 char, in usecs */ unsigned long char_time_usec; /* The time for 1 char, in usecs */
unsigned long flush_time_usec; /* How often we should flush */
unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */ unsigned long last_tx_active_usec; /* Last tx usec in the jiffies */
unsigned long last_tx_active; /* Last tx time in jiffies */ unsigned long last_tx_active; /* Last tx time in jiffies */
unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */ unsigned long last_rx_active_usec; /* Last rx usec in the jiffies */
......
...@@ -12,6 +12,15 @@ ...@@ -12,6 +12,15 @@
* init_etrax_debug() * init_etrax_debug()
* *
* $Log: debugport.c,v $ * $Log: debugport.c,v $
* Revision 1.14 2004/05/17 13:11:29 starvik
* Disable DMA until real serial driver is up
*
* Revision 1.13 2004/05/14 07:58:01 starvik
* Merge of changes from 2.4
*
* Revision 1.12 2003/09/11 07:29:49 starvik
* Merge of Linux 2.6.0-test5
*
* Revision 1.11 2003/07/07 09:53:36 starvik * Revision 1.11 2003/07/07 09:53:36 starvik
* Revert all the 2.5.74 merge changes to make the console work again * Revert all the 2.5.74 merge changes to make the console work again
* *
...@@ -59,7 +68,7 @@ ...@@ -59,7 +68,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/major.h> #include <linux/major.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/tty.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/arch/svinto.h> #include <asm/arch/svinto.h>
#include <asm/io.h> /* Get SIMCOUT. */ #include <asm/io.h> /* Get SIMCOUT. */
...@@ -124,22 +133,28 @@ ...@@ -124,22 +133,28 @@
#define MIN_SIZE 32 /* Size that triggers the FIFO to flush characters to interface */ #define MIN_SIZE 32 /* Size that triggers the FIFO to flush characters to interface */
/* Write a string of count length to the console (debug port) using DMA, polled static struct tty_driver *serial_driver;
* for completion. Interrupts are disabled during the whole process. Some
* caution needs to be taken to not interfere with ttyS business on this port. typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len);
*/
debugport_write_function debug_write_function = NULL;
static void
console_write_direct(struct console *co, const char *buf, unsigned int len)
{
int i;
/* Send data */
for (i = 0; i < len; i++) {
/* Wait until transmitter is ready and send.*/
while(!(*DEBUG_READ & IO_MASK(R_SERIAL0_READ, tr_ready)));
*DEBUG_WRITE = buf[i];
}
}
static void static void
console_write(struct console *co, const char *buf, unsigned int len) console_write(struct console *co, const char *buf, unsigned int len)
{ {
unsigned long flags;
static struct etrax_dma_descr descr;
static struct etrax_dma_descr descr2;
static char tmp_buf[MIN_SIZE];
static int tmp_size = 0;
unsigned long flags;
#ifdef CONFIG_ETRAX_DEBUG_PORT_NULL #ifdef CONFIG_ETRAX_DEBUG_PORT_NULL
/* no debug printout at all */ /* no debug printout at all */
return; return;
...@@ -150,86 +165,18 @@ console_write(struct console *co, const char *buf, unsigned int len) ...@@ -150,86 +165,18 @@ console_write(struct console *co, const char *buf, unsigned int len)
SIMCOUT(buf,len); SIMCOUT(buf,len);
return; return;
#endif #endif
local_save_flags(flags);
local_irq_disable();
#ifdef CONFIG_ETRAX_KGDB #ifdef CONFIG_ETRAX_KGDB
/* kgdb needs to output debug info using the gdb protocol */ /* kgdb needs to output debug info using the gdb protocol */
putDebugString(buf, len); putDebugString(buf, len);
local_irq_restore(flags);
return; return;
#endif #endif
/* To make this work together with the real serial port driver local_irq_save(flags);
* we have to make sure that everything is flushed when we leave if (debug_write_function)
* here. The following steps are made to assure this: if (debug_write_function(co->index, buf, len))
* 1. Wait until DMA stops, FIFO is empty and serial port pipeline empty.
* 2. Write at least half the FIFO to trigger flush to serial port.
* 3. Wait until DMA stops, FIFO is empty and serial port pipeline empty.
*/
/* Do we have enough characters to make the DMA/FIFO happy? */
if (tmp_size + len < MIN_SIZE)
{
int size = min((int)(MIN_SIZE - tmp_size),(int)len);
memcpy(&tmp_buf[tmp_size], buf, size);
tmp_size += size;
len -= size;
/* Pad with space if complete line */
if (tmp_buf[tmp_size-1] == '\n')
{
memset(&tmp_buf[tmp_size-1], ' ', MIN_SIZE - tmp_size);
tmp_buf[MIN_SIZE - 1] = '\n';
tmp_size = MIN_SIZE;
len = 0;
}
else
{
/* Wait for more characters */
local_irq_restore(flags);
return; return;
} console_write_direct(co, buf, len);
}
/* make sure the transmitter is enabled.
* NOTE: this overrides any setting done in ttySx, to 8N1, no auto-CTS.
* in the future, move the tr/rec_ctrl shadows from etrax100ser.c to
* shadows.c and use it here as well...
*/
*DEBUG_TR_CTRL = 0x40;
while(*DEBUG_OCMD & 7); /* Until DMA is not running */
while(*DEBUG_STATUS & 0x7f); /* wait until output FIFO is empty as well */
udelay(200); /* Wait for last two characters to leave the serial transmitter */
if (tmp_size)
{
descr.ctrl = len ? 0 : d_eop | d_wait | d_eol;
descr.sw_len = tmp_size;
descr.buf = virt_to_phys(tmp_buf);
descr.next = virt_to_phys(&descr2);
descr2.ctrl = d_eop | d_wait | d_eol;
descr2.sw_len = len;
descr2.buf = virt_to_phys((char*)buf);
}
else
{
descr.ctrl = d_eop | d_wait | d_eol;
descr.sw_len = len;
descr.buf = virt_to_phys((char*)buf);
}
*DEBUG_FIRST = virt_to_phys(&descr); /* write to R_DMAx_FIRST */
*DEBUG_OCMD = 1; /* dma command start -> R_DMAx_CMD */
/* wait until the output dma channel is ready again */
while(*DEBUG_OCMD & 7);
while(*DEBUG_STATUS & 0x7f);
udelay(200);
tmp_size = 0;
local_irq_restore(flags); local_irq_restore(flags);
} }
...@@ -279,10 +226,11 @@ enableDebugIRQ(void) ...@@ -279,10 +226,11 @@ enableDebugIRQ(void)
*DEBUG_REC_CTRL = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); *DEBUG_REC_CTRL = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable);
} }
static kdev_t static struct tty_driver*
console_device(struct console *c) console_device(struct console *c, int *index)
{ {
return mk_kdev(TTY_MAJOR, 64 + c->index); *index = c->index;
return serial_driver;
} }
static int __init static int __init
...@@ -311,5 +259,33 @@ static struct console sercons = { ...@@ -311,5 +259,33 @@ static struct console sercons = {
void __init void __init
init_etrax_debug(void) init_etrax_debug(void)
{ {
#if CONFIG_ETRAX_DEBUG_PORT_NULL
return;
#endif
#if DEBUG_PORT_IDX == 0
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused);
#elif DEBUG_PORT_IDX == 1
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb);
#elif DEBUG_PORT_IDX == 2
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0);
#elif DEBUG_PORT_IDX == 3
genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4);
genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1);
#endif
*R_GEN_CONFIG = genconfig_shadow;
register_console(&sercons); register_console(&sercons);
} }
int __init
init_console(void)
{
serial_driver = alloc_tty_driver(1);
if (!serial_driver)
return -ENOMEM;
return 0;
}
/* $Id: entry.S,v 1.16 2003/07/04 08:27:41 starvik Exp $ /* $Id: entry.S,v 1.18 2004/05/11 12:28:25 starvik Exp $
* *
* linux/arch/cris/entry.S * linux/arch/cris/entry.S
* *
...@@ -7,6 +7,12 @@ ...@@ -7,6 +7,12 @@
* Authors: Bjorn Wesen (bjornw@axis.com) * Authors: Bjorn Wesen (bjornw@axis.com)
* *
* $Log: entry.S,v $ * $Log: entry.S,v $
* Revision 1.18 2004/05/11 12:28:25 starvik
* Merge of Linux 2.6.6
*
* Revision 1.17 2003/09/11 07:29:49 starvik
* Merge of Linux 2.6.0-test5
*
* Revision 1.16 2003/07/04 08:27:41 starvik * Revision 1.16 2003/07/04 08:27:41 starvik
* Merge of Linux 2.5.74 * Merge of Linux 2.5.74
* *
...@@ -1060,6 +1066,19 @@ sys_call_table: ...@@ -1060,6 +1066,19 @@ sys_call_table:
.long sys_clock_nanosleep .long sys_clock_nanosleep
.long sys_statfs64 .long sys_statfs64
.long sys_fstatfs64 .long sys_fstatfs64
.long sys_tgkill /* 270 */
.long sys_utimes
.long sys_fadvise64_64
.long sys_ni_syscall /* sys_vserver */
.long sys_ni_syscall /* sys_mbind */
.long sys_ni_syscall /* 275 sys_get_mempolicy */
.long sys_ni_syscall /* sys_set_mempolicy */
.long sys_mq_open
.long sys_mq_unlink
.long sys_mq_timedsend
.long sys_mq_timedreceive /* 280 */
.long sys_mq_notify
.long sys_mq_getsetattr
/* /*
* NOTE!! This doesn't have to be exact - we just have * NOTE!! This doesn't have to be exact - we just have
......
/* $Id: fasttimer.c,v 1.4 2003/07/04 08:27:41 starvik Exp $ /* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $
* linux/arch/cris/kernel/fasttimer.c * linux/arch/cris/kernel/fasttimer.c
* *
* Fast timers for ETRAX100/ETRAX100LX * Fast timers for ETRAX100/ETRAX100LX
* This may be useful in other OS than Linux so use 2 space indentation... * This may be useful in other OS than Linux so use 2 space indentation...
* *
* $Log: fasttimer.c,v $ * $Log: fasttimer.c,v $
* Revision 1.6 2004/05/14 10:18:39 starvik
* Export fast_timer_list
*
* Revision 1.5 2004/05/14 07:58:01 starvik
* Merge of changes from 2.4
*
* Revision 1.4 2003/07/04 08:27:41 starvik * Revision 1.4 2003/07/04 08:27:41 starvik
* Merge of Linux 2.5.74 * Merge of Linux 2.5.74
* *
...@@ -130,7 +136,7 @@ static int fast_timers_deleted = 0; ...@@ -130,7 +136,7 @@ static int fast_timers_deleted = 0;
static int fast_timer_is_init = 0; static int fast_timer_is_init = 0;
static int fast_timer_ints = 0; static int fast_timer_ints = 0;
static struct fast_timer *fast_timer_list = NULL; struct fast_timer *fast_timer_list = NULL;
#ifdef DEBUG_LOG_INCLUDED #ifdef DEBUG_LOG_INCLUDED
#define DEBUG_LOG_MAX 128 #define DEBUG_LOG_MAX 128
...@@ -325,7 +331,8 @@ void start_one_shot_timer(struct fast_timer *t, ...@@ -325,7 +331,8 @@ void start_one_shot_timer(struct fast_timer *t,
{ {
if (tmp == t) if (tmp == t)
{ {
printk("timer name: %s data: 0x%08lX already in list!\n", name, data); printk(KERN_WARNING
"timer name: %s data: 0x%08lX already in list!\n", name, data);
sanity_failed++; sanity_failed++;
return; return;
} }
...@@ -784,7 +791,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len ...@@ -784,7 +791,7 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len
cli(); cli();
if (t->next != nextt) if (t->next != nextt)
{ {
printk("timer removed!\n"); printk(KERN_WARNING "timer removed!\n");
} }
t = nextt; t = nextt;
} }
...@@ -965,7 +972,7 @@ void fast_timer_init(void) ...@@ -965,7 +972,7 @@ void fast_timer_init(void)
int i; int i;
#endif #endif
printk("fast_timer_init()\n"); printk(KERN_INFO "fast_timer_init()\n");
#if 0 && defined(FAST_TIMER_TEST) #if 0 && defined(FAST_TIMER_TEST)
for (i = 0; i <= TIMER0_DIV; i++) for (i = 0; i <= TIMER0_DIV; i++)
......
/* $Id: head.S,v 1.6 2003/04/28 05:31:46 starvik Exp $ /* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $
* *
* Head of the kernel - alter with care * Head of the kernel - alter with care
* *
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
* Authors: Bjorn Wesen (bjornw@axis.com) * Authors: Bjorn Wesen (bjornw@axis.com)
* *
* $Log: head.S,v $ * $Log: head.S,v $
* Revision 1.7 2004/05/14 07:58:01 starvik
* Merge of changes from 2.4
*
* Revision 1.6 2003/04/28 05:31:46 starvik * Revision 1.6 2003/04/28 05:31:46 starvik
* Added section attributes * Added section attributes
* *
...@@ -331,7 +334,16 @@ _inflash: ...@@ -331,7 +334,16 @@ _inflash:
move.d START_ETHERNET_CLOCK, $r0 move.d START_ETHERNET_CLOCK, $r0
move.d $r0, [R_NETWORK_GEN_CONFIG] move.d $r0, [R_NETWORK_GEN_CONFIG]
#endif #endif
;; Set up waitstates etc according to kernel configuration.
#ifndef CONFIG_SVINTO_SIM
move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0
move.d $r0, [R_WAITSTATES]
move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0
move.d $r0, [R_BUS_CONFIG]
#endif
;; We need to initialze DRAM registers before we start using the DRAM ;; We need to initialze DRAM registers before we start using the DRAM
cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized?
...@@ -626,8 +638,19 @@ _start_it: ...@@ -626,8 +638,19 @@ _start_it:
| IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0 | IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0
#endif #endif
#if defined(CONFIG_BLUETOOTH) && (defined(CONFIG_BLUETOOTH_RESET_G10) || defined(CONFIG_BLUETOOTH_RESET_G11)) #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT)
or.d IO_STATE (R_GEN_CONFIG, g8_15dir, out),$r0 or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0
#endif
#if defined(CONFIG_ETRAX_DEF_R_PORT_G8_15_DIR_OUT)
or.d IO_STATE (R_GEN_CONFIG, g8_15dir, out),$r0
#endif
#if defined(CONFIG_ETRAX_DEF_R_PORT_G16_23_DIR_OUT)
or.d IO_STATE (R_GEN_CONFIG, g16_23dir, out),$r0
#endif
#if defined(CONFIG_ETRAX_DEF_R_PORT_G24_DIR_OUT)
or.d IO_STATE (R_GEN_CONFIG, g24dir, out),$r0
#endif #endif
move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
......
/* $Id: process.c,v 1.3 2003/07/04 08:27:41 starvik Exp $ /* $Id: process.c,v 1.6 2004/05/11 12:28:25 starvik Exp $
* *
* linux/arch/cris/kernel/process.c * linux/arch/cris/kernel/process.c
* *
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/arch/svinto.h>
#include <linux/init.h> #include <linux/init.h>
#ifdef CONFIG_ETRAX_GPIO #ifdef CONFIG_ETRAX_GPIO
...@@ -249,3 +250,19 @@ unsigned long get_wchan(struct task_struct *p) ...@@ -249,3 +250,19 @@ unsigned long get_wchan(struct task_struct *p)
} }
#undef last_sched #undef last_sched
#undef first_sched #undef first_sched
void show_regs(struct pt_regs * regs)
{
unsigned long usp = rdusp();
printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
regs->irp, regs->srp, regs->dccr, usp, regs->mof );
printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
regs->r0, regs->r1, regs->r2, regs->r3);
printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
regs->r4, regs->r5, regs->r6, regs->r7);
printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
regs->r8, regs->r9, regs->r10, regs->r11);
printk("r12: %08lx r13: %08lx oR10: %08lx\n",
regs->r12, regs->r13, regs->orig_r10);
}
...@@ -118,19 +118,13 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -118,19 +118,13 @@ sys_ptrace(long request, long pid, long addr, long data)
/* Read the word at location address in the USER area. */ /* Read the word at location address in the USER area. */
case PTRACE_PEEKUSR: { case PTRACE_PEEKUSR: {
unsigned long tmp; unsigned long tmp;
ret = -EIO; ret = -EIO;
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
break; break;
tmp = 0; /* Default return condition */ tmp = get_reg(child, addr >> 2);
ret = -EIO; ret = put_user(tmp, (unsigned long *)data);
if (addr < sizeof(struct pt_regs)) {
tmp = get_reg(child, addr >> 2);
ret = put_user(tmp, (unsigned long *)data);
}
break; break;
} }
...@@ -148,28 +142,21 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -148,28 +142,21 @@ sys_ptrace(long request, long pid, long addr, long data)
/* Write the word at location address in the USER area. */ /* Write the word at location address in the USER area. */
case PTRACE_POKEUSR: case PTRACE_POKEUSR:
ret = -EIO; ret = -EIO;
if ((addr & 3) || addr < 0 || addr > PT_MAX << 2)
if ((addr & 3) || addr < 0 || addr >= sizeof(struct user))
break; break;
if (addr < sizeof(struct pt_regs)) { addr >>= 2;
addr >>= 2;
if (addr == PT_DCCR) { if (addr == PT_DCCR) {
/* /* don't allow the tracing process to change stuff like
* Don't allow the tracing process to * interrupt enable, kernel/user bit, dma enables etc.
* change stuff like interrupt enable, */
* kernel/user bit, etc. data &= DCCR_MASK;
*/ data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
data &= DCCR_MASK;
data |= get_reg(child, PT_DCCR) & ~DCCR_MASK;
}
if (put_reg(child, addr, data))
break;
ret = 0;
} }
if (put_reg(child, addr, data))
break;
ret = 0;
break; break;
case PTRACE_SYSCALL: case PTRACE_SYSCALL:
...@@ -237,7 +224,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -237,7 +224,7 @@ sys_ptrace(long request, long pid, long addr, long data)
if (put_user(tmp, (unsigned long *) data)) { if (put_user(tmp, (unsigned long *) data)) {
ret = -EFAULT; ret = -EFAULT;
break; goto out_tsk;
} }
data += sizeof(long); data += sizeof(long);
...@@ -255,7 +242,7 @@ sys_ptrace(long request, long pid, long addr, long data) ...@@ -255,7 +242,7 @@ sys_ptrace(long request, long pid, long addr, long data)
for (i = 0; i <= PT_MAX; i++) { for (i = 0; i <= PT_MAX; i++) {
if (get_user(tmp, (unsigned long *) data)) { if (get_user(tmp, (unsigned long *) data)) {
ret = -EFAULT; ret = -EFAULT;
break; goto out_tsk;
} }
if (i == PT_DCCR) { if (i == PT_DCCR) {
...@@ -290,12 +277,10 @@ void do_syscall_trace(void) ...@@ -290,12 +277,10 @@ void do_syscall_trace(void)
if (!(current->ptrace & PT_PTRACED)) if (!(current->ptrace & PT_PTRACED))
return; return;
current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) /* the 0x80 provides a way for the tracing parent to distinguish
? 0x80 : 0); between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
current->state = TASK_STOPPED; ? 0x80 : 0));
notify_parent(current, SIGCHLD);
schedule();
/* /*
* This isn't the same as continuing with a signal, but it will do for * This isn't the same as continuing with a signal, but it will do for
......
/* $Id: setup.c,v 1.1 2002/12/11 15:42:02 starvik Exp $ /*
* *
* linux/arch/cris/arch-v10/kernel/setup.c * linux/arch/cris/arch-v10/kernel/setup.c
* *
...@@ -94,3 +94,10 @@ int show_cpuinfo(struct seq_file *m, void *v) ...@@ -94,3 +94,10 @@ int show_cpuinfo(struct seq_file *m, void *v)
} }
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
void
show_etrax_copyright(void)
{
printk(KERN_INFO
"Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n");
}
...@@ -180,6 +180,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) ...@@ -180,6 +180,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
unsigned int err = 0; unsigned int err = 0;
unsigned long old_usp; unsigned long old_usp;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
/* restore the regs from &sc->regs (same as sc, since regs is first) /* restore the regs from &sc->regs (same as sc, since regs is first)
* (sc is already checked for VERIFY_READ since the sigframe was * (sc is already checked for VERIFY_READ since the sigframe was
* checked in sys_sigreturn previously) * checked in sys_sigreturn previously)
...@@ -492,7 +495,6 @@ handle_signal(int canrestart, unsigned long sig, ...@@ -492,7 +495,6 @@ handle_signal(int canrestart, unsigned long sig,
/* If so, check system call restarting.. */ /* If so, check system call restarting.. */
switch (regs->r10) { switch (regs->r10) {
case -ERESTART_RESTARTBLOCK: case -ERESTART_RESTARTBLOCK:
current_thread_info()->restart_block.fn = do_no_restart_syscall;
case -ERESTARTNOHAND: case -ERESTARTNOHAND:
/* ERESTARTNOHAND means that the syscall should only be /* ERESTARTNOHAND means that the syscall should only be
restarted if there was no handler for the signal, and since restarted if there was no handler for the signal, and since
......
/* $Id: time.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ /* $Id: time.c,v 1.3 2004/06/01 05:38:42 starvik Exp $
* *
* linux/arch/cris/arch-v10/kernel/time.c * linux/arch/cris/arch-v10/kernel/time.c
* *
...@@ -277,6 +277,12 @@ time_init(void) ...@@ -277,6 +277,12 @@ time_init(void)
update_xtime_from_cmos(); update_xtime_from_cmos();
} }
/*
* Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
* tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
*/
set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
/* Setup the etrax timers /* Setup the etrax timers
* Base frequency is 25000 hz, divider 250 -> 100 HZ * Base frequency is 25000 hz, divider 250 -> 100 HZ
* In normal mode, we use timer0, so timer1 is free. In cascade * In normal mode, we use timer0, so timer1 is free. In cascade
......
/* $Id: dram_init.S,v 1.3 2003/03/31 09:38:37 starvik Exp $ /* $Id: dram_init.S,v 1.4 2003/09/22 09:21:59 starvik Exp $
* *
* DRAM/SDRAM initialization - alter with care * DRAM/SDRAM initialization - alter with care
* This file is intended to be included from other assembler files * This file is intended to be included from other assembler files
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
* Authors: Mikael Starvik (starvik@axis.com) * Authors: Mikael Starvik (starvik@axis.com)
* *
* $Log: dram_init.S,v $ * $Log: dram_init.S,v $
* Revision 1.4 2003/09/22 09:21:59 starvik
* Decompresser is linked to 0x407xxxxx and sdram commands are at 0x000xxxxx
* so we need to mask off 12 bits.
*
* Revision 1.3 2003/03/31 09:38:37 starvik * Revision 1.3 2003/03/31 09:38:37 starvik
* Corrected calculation of end of sdram init commands * Corrected calculation of end of sdram init commands
* *
...@@ -152,9 +156,9 @@ _set_timing: ...@@ -152,9 +156,9 @@ _set_timing:
; Issue initialization command sequence ; Issue initialization command sequence
move.d _sdram_commands_start, $r2 move.d _sdram_commands_start, $r2
and.d 0x00ffffff, $r2 ; Make sure commands are read from flash and.d 0x000fffff, $r2 ; Make sure commands are read from flash
move.d _sdram_commands_end, $r3 move.d _sdram_commands_end, $r3
and.d 0x00ffffff, $r3 and.d 0x000fffff, $r3
1: clear.d $r4 1: clear.d $r4
move.b [$r2+], $r4 move.b [$r2+], $r4
lslq 9, $r4 ; Command starts at bit 9 lslq 9, $r4 ; Command starts at bit 9
......
/* $Id: old_checksum.c,v 1.2 2002/11/05 06:45:12 starvik Exp $ /* $Id: old_checksum.c,v 1.3 2003/10/27 08:04:32 starvik Exp $
* *
* INET An implementation of the TCP/IP protocol suite for the LINUX * INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket * operating system. INET is implemented using the BSD Socket
...@@ -76,7 +76,7 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) ...@@ -76,7 +76,7 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
sum += *((unsigned short *)buff)++; sum += *((unsigned short *)buff)++;
} }
if(endMarker - buff > 0) { if(endMarker - buff > 0) {
sum += *buff; /* add extra byte separately */ sum += *buff; /* add extra byte seperately */
} }
BITOFF; BITOFF;
return(sum); return(sum);
......
...@@ -30,7 +30,7 @@ extern const struct exception_table_entry ...@@ -30,7 +30,7 @@ extern const struct exception_table_entry
*search_exception_tables(unsigned long addr); *search_exception_tables(unsigned long addr);
asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
int error_code); int protection, int writeaccess);
/* fast TLB-fill fault handler /* fast TLB-fill fault handler
* this is called from entry.S with interrupts disabled * this is called from entry.S with interrupts disabled
...@@ -39,8 +39,9 @@ asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, ...@@ -39,8 +39,9 @@ asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
void void
handle_mmu_bus_fault(struct pt_regs *regs) handle_mmu_bus_fault(struct pt_regs *regs)
{ {
int cause, select; int cause;
#ifdef DEBUG #ifdef DEBUG
int select;
int index; int index;
int page_id; int page_id;
int acc, inv; int acc, inv;
...@@ -48,15 +49,14 @@ handle_mmu_bus_fault(struct pt_regs *regs) ...@@ -48,15 +49,14 @@ handle_mmu_bus_fault(struct pt_regs *regs)
int miss, we, writeac; int miss, we, writeac;
pmd_t *pmd; pmd_t *pmd;
pte_t pte; pte_t pte;
int errcode;
unsigned long address; unsigned long address;
cause = *R_MMU_CAUSE; cause = *R_MMU_CAUSE;
select = *R_TLB_SELECT;
address = cause & PAGE_MASK; /* get faulting address */ address = cause & PAGE_MASK; /* get faulting address */
#ifdef DEBUG #ifdef DEBUG
select = *R_TLB_SELECT;
page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause);
acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause);
inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause);
...@@ -82,12 +82,6 @@ handle_mmu_bus_fault(struct pt_regs *regs) ...@@ -82,12 +82,6 @@ handle_mmu_bus_fault(struct pt_regs *regs)
if(writeac) if(writeac)
regs->csrinstr &= ~(1 << 5); regs->csrinstr &= ~(1 << 5);
/* Set errcode's R/W flag according to the mode which caused the
* fault
*/
errcode = writeac << 1;
D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n", D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n",
regs->irp, address, miss, inv, we, acc, index, page_id)); regs->irp, address, miss, inv, we, acc, index, page_id));
...@@ -99,16 +93,20 @@ handle_mmu_bus_fault(struct pt_regs *regs) ...@@ -99,16 +93,20 @@ handle_mmu_bus_fault(struct pt_regs *regs)
*/ */
pmd = (pmd_t *)(current_pgd + pgd_index(address)); pmd = (pmd_t *)(current_pgd + pgd_index(address));
if (pmd_none(*pmd)) if (pmd_none(*pmd)) {
goto dofault; do_page_fault(address, regs, 0, writeac);
return;
}
if (pmd_bad(*pmd)) { if (pmd_bad(*pmd)) {
printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd); printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd);
pmd_clear(pmd); pmd_clear(pmd);
return; return;
} }
pte = *pte_offset_kernel(pmd, address); pte = *pte_offset_kernel(pmd, address);
if (!pte_present(pte)) if (!pte_present(pte)) {
goto dofault; do_page_fault(address, regs, 0, writeac);
return;
}
#ifdef DEBUG #ifdef DEBUG
printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte)); printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte));
...@@ -143,14 +141,10 @@ handle_mmu_bus_fault(struct pt_regs *regs) ...@@ -143,14 +141,10 @@ handle_mmu_bus_fault(struct pt_regs *regs)
*R_TLB_LO = pte_val(pte); *R_TLB_LO = pte_val(pte);
return; return;
} }
errcode = 1 | (we << 1);
dofault: /* leave it to the MM system fault handler */
/* leave it to the MM system fault handler below */ do_page_fault(address, regs, 1, we);
D(printk("do_page_fault %lx errcode %d\n", address, errcode));
do_page_fault(address, regs, errcode);
} }
/* Called from arch/cris/mm/fault.c to find fixup code. */ /* Called from arch/cris/mm/fault.c to find fixup code. */
......
...@@ -212,7 +212,7 @@ dump_tlb_all(void) ...@@ -212,7 +212,7 @@ dump_tlb_all(void)
void void
switch_mm(struct mm_struct *prev, struct mm_struct *next, switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk, int cpu) struct task_struct *tsk)
{ {
/* make sure we have a context */ /* make sure we have a context */
......
# #
# Automatically generated make config: don't edit # Automatically generated make config: don't edit
# #
CONFIG_MMU=y
CONFIG_UID16=y CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
# #
# Code maturity level options # Code maturity level options
# #
CONFIG_EXPERIMENTAL=y CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_STANDALONE=y
CONFIG_BROKEN_ON_SMP=y
# #
# General setup # General setup
# #
CONFIG_NET=y CONFIG_SWAP=y
CONFIG_SYSVIPC=y # CONFIG_SYSVIPC is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_SYSCTL is not set CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
CONFIG_EMBEDDED=y
# CONFIG_KALLSYMS is not set
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
#
# Loadable module support
#
# CONFIG_MODULES is not set
#
# General setup
#
CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF=y
# CONFIG_ETRAX_KGDB is not set # CONFIG_BINFMT_MISC is not set
# CONFIG_ETRAX_WATCHDOG is not set CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock3 init=/linuxrc"
CONFIG_ETRAX_WATCHDOG=y
CONFIG_ETRAX_WATCHDOG_NICE_DOGGY=y
CONFIG_ETRAX_FAST_TIMER=y
# CONFIG_PREEMPT is not set
# #
# Hardware setup # Hardware setup
...@@ -27,74 +57,170 @@ CONFIG_BINFMT_ELF=y ...@@ -27,74 +57,170 @@ CONFIG_BINFMT_ELF=y
CONFIG_ETRAX100LX=y CONFIG_ETRAX100LX=y
# CONFIG_ETRAX100LX_V2 is not set # CONFIG_ETRAX100LX_V2 is not set
# CONFIG_SVINTO_SIM is not set # CONFIG_SVINTO_SIM is not set
CONFIG_ETRAX_DRAM_SIZE=8 CONFIG_ETRAX_ARCH_V10=y
CONFIG_ETRAX_DRAM_SIZE=16
CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_FLASH_BUSWIDTH=2
CONFIG_ETRAX_ROOT_DEVICE="/dev/mtdblock3" CONFIG_CRIS_LOW_MAP=y
CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000
CONFIG_ETRAX_PA_LEDS=y
# CONFIG_ETRAX_PB_LEDS is not set
# CONFIG_ETRAX_CSP0_LEDS is not set
# CONFIG_ETRAX_NO_LEDS is not set
CONFIG_ETRAX_LED1G=2
CONFIG_ETRAX_LED1R=2
CONFIG_ETRAX_LED2G=3
CONFIG_ETRAX_LED2R=3
CONFIG_ETRAX_LED3G=2
CONFIG_ETRAX_LED3R=2
CONFIG_ETRAX_DEBUG_PORT0=y
# CONFIG_ETRAX_DEBUG_PORT1 is not set
# CONFIG_ETRAX_DEBUG_PORT2 is not set
# CONFIG_ETRAX_DEBUG_PORT3 is not set
# CONFIG_ETRAX_DEBUG_PORT_NULL is not set
CONFIG_ETRAX_RESCUE_SER0=y
# CONFIG_ETRAX_RESCUE_SER1 is not set
# CONFIG_ETRAX_RESCUE_SER2 is not set
# CONFIG_ETRAX_RESCUE_SER3 is not set
CONFIG_ETRAX_DEF_R_WAITSTATES=0x95f8
CONFIG_ETRAX_DEF_R_BUS_CONFIG=0x104
CONFIG_ETRAX_SDRAM=y
CONFIG_ETRAX_DEF_R_SDRAM_CONFIG=0x00e03636
CONFIG_ETRAX_DEF_R_SDRAM_TIMING=0x80008002
CONFIG_ETRAX_DEF_R_PORT_PA_DIR=0x1d
CONFIG_ETRAX_DEF_R_PORT_PA_DATA=0xf0
CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=0x00
CONFIG_ETRAX_DEF_R_PORT_PB_DIR=0x1e
CONFIG_ETRAX_DEF_R_PORT_PB_DATA=0xf3
# CONFIG_ETRAX_SOFT_SHUTDOWN is not set
#
# Drivers for built-in interfaces
#
CONFIG_ETRAX_ETHERNET=y
CONFIG_NET_ETHERNET=y
# CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set
CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y
CONFIG_ETRAX_SERIAL=y
CONFIG_ETRAX_SERIAL_FAST_TIMER=y
CONFIG_ETRAX_SERIAL_PORT0=y
# CONFIG_CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT is not set
CONFIG_CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT=y
# CONFIG_CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN is not set
CONFIG_CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN=y
CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE=y
# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA is not set
# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set
# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED is not set
CONFIG_ETRAX_SER0_DTR_ON_PA_BIT=-1
CONFIG_ETRAX_SER0_RI_ON_PA_BIT=-1
CONFIG_ETRAX_SER0_DSR_ON_PA_BIT=-1
CONFIG_ETRAX_SER0_CD_ON_PA_BIT=-1
CONFIG_ETRAX_SER0_DTR_ON_PB_BIT=-1
CONFIG_ETRAX_SER0_RI_ON_PB_BIT=-1
CONFIG_ETRAX_SER0_DSR_ON_PB_BIT=-1
CONFIG_ETRAX_SER0_CD_ON_PB_BIT=-1
# CONFIG_ETRAX_SERIAL_PORT1 is not set
CONFIG_ETRAX_SERIAL_PORT2=y
# CONFIG_CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT is not set
CONFIG_CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT=y
# CONFIG_CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN is not set
CONFIG_CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN=y
CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE=y
# CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA is not set
# CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB is not set
# CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED is not set
CONFIG_ETRAX_SER2_DTR_ON_PA_BIT=-1
CONFIG_ETRAX_SER2_RI_ON_PA_BIT=-1
CONFIG_ETRAX_SER2_DSR_ON_PA_BIT=-1
CONFIG_ETRAX_SER2_CD_ON_PA_BIT=-1
CONFIG_ETRAX_SER2_DTR_ON_PB_BIT=-1
CONFIG_ETRAX_SER2_RI_ON_PB_BIT=-1
CONFIG_ETRAX_SER2_DSR_ON_PB_BIT=-1
CONFIG_ETRAX_SER2_CD_ON_PB_BIT=-1
# CONFIG_ETRAX_SERIAL_PORT3 is not set
# CONFIG_ETRAX_RS485 is not set
# CONFIG_ETRAX_IDE is not set
# CONFIG_IDE is not set
# CONFIG_ETRAX_USB_HOST is not set
CONFIG_ETRAX_AXISFLASHMAP=y
CONFIG_ETRAX_PTABLE_SECTOR=65536
CONFIG_MTD=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_OBSOLETE_CHIPS=y
CONFIG_MTD_AMDSTD=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_PARTITIONS=y
CONFIG_MTD_CONCAT=y
# CONFIG_ETRAX_I2C is not set
CONFIG_ETRAX_GPIO=y
CONFIG_ETRAX_PA_BUTTON_BITMASK=0x02
CONFIG_ETRAX_PA_CHANGEABLE_DIR=0x00
CONFIG_ETRAX_PA_CHANGEABLE_BITS=0xFF
CONFIG_ETRAX_PB_CHANGEABLE_DIR=0x00
CONFIG_ETRAX_PB_CHANGEABLE_BITS=0xFF
# CONFIG_ETRAX_RTC is not set
# #
# Drivers for ETRAX 100LX built-in interfaces # Generic Driver Options
# #
# #
# Memory Technology Devices (MTD) # Memory Technology Devices (MTD)
# #
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set # CONFIG_MTD_DEBUG is not set
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
# #
# Disk-On-Chip Device Drivers # User Modules And Translation Layers
# #
# CONFIG_MTD_DOC1000 is not set # CONFIG_FTL is not set
# CONFIG_MTD_DOC2000 is not set # CONFIG_NFTL is not set
# CONFIG_MTD_DOC2001 is not set # CONFIG_INFTL is not set
# CONFIG_MTD_DOCPROBE is not set
# #
# RAM/ROM Device Drivers # RAM/ROM/Flash chip drivers
# #
# CONFIG_MTD_PMC551 is not set # CONFIG_MTD_JEDECPROBE is not set
# CONFIG_MTD_SLRAM is not set CONFIG_MTD_GEN_PROBE=y
# CONFIG_MTD_RAM is not set # CONFIG_MTD_CFI_ADV_OPTIONS is not set
# CONFIG_MTD_CFI_INTELEXT is not set
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_RAM=y
# CONFIG_MTD_ROM is not set # CONFIG_MTD_ROM is not set
# CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_ABSENT is not set
# CONFIG_MTD_SHARP is not set
# CONFIG_MTD_JEDEC is not set
# #
# Linearly Mapped Flash Device Drivers # Mapping drivers for chip access
# #
CONFIG_MTD_CFI=y CONFIG_MTD_COMPLEX_MAPPINGS=y
# CONFIG_MTD_CFI_GEOMETRY is not set
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_AMDSTD=y
# CONFIG_MTD_SHARP is not set
# CONFIG_MTD_PHYSMAP is not set # CONFIG_MTD_PHYSMAP is not set
# CONFIG_MTD_NORA is not set
# CONFIG_MTD_PNC2000 is not set
# CONFIG_MTD_RPXLITE is not set
# CONFIG_MTD_SC520CDP is not set
# CONFIG_MTD_SBC_MEDIAGX is not set
# CONFIG_MTD_ELAN_104NC is not set
# CONFIG_MTD_SA1100 is not set
# CONFIG_MTD_DC21285 is not set
# CONFIG_MTD_CSTM_CFI_JEDEC is not set
# CONFIG_MTD_JEDEC is not set
# CONFIG_MTD_MIXMEM is not set
# CONFIG_MTD_OCTAGON is not set
# CONFIG_MTD_VMAX is not set
# #
# NAND Flash Device Drivers # Self-contained MTD device drivers
# #
# CONFIG_MTD_NAND is not set # CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_NAND_SPIA is not set CONFIG_MTD_MTDRAM=y
CONFIG_MTDRAM_TOTAL_SIZE=0
CONFIG_MTDRAM_ERASE_SIZE=64
CONFIG_MTDRAM_ABS_POS=0x0
# CONFIG_MTD_BLKMTD is not set
# #
# User Modules And Translation Layers # Disk-On-Chip Device Drivers
# #
CONFIG_MTD_CHAR=y # CONFIG_MTD_DOC2000 is not set
CONFIG_MTD_BLOCK=y # CONFIG_MTD_DOC2001 is not set
# CONFIG_FTL is not set # CONFIG_MTD_DOC2001PLUS is not set
# CONFIG_NFTL is not set
#
# NAND Flash Device Drivers
#
# CONFIG_MTD_NAND is not set
# #
# Parallel port support # Parallel port support
...@@ -102,51 +228,98 @@ CONFIG_MTD_BLOCK=y ...@@ -102,51 +228,98 @@ CONFIG_MTD_BLOCK=y
# CONFIG_PARPORT is not set # CONFIG_PARPORT is not set
# #
# Plug and Play configuration # Plug and Play support
# #
# CONFIG_PNP is not set
# CONFIG_ISAPNP is not set
# #
# Block devices # Block devices
# #
# CONFIG_BLK_DEV_FD is not set # CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_XD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=4096
# CONFIG_BLK_DEV_INITRD is not set # CONFIG_BLK_DEV_INITRD is not set
#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
#
# ATA/ATAPI/MFM/RLL support
#
#
# SCSI device support
#
# CONFIG_SCSI is not set
#
# IEEE 1394 (FireWire) support
#
# CONFIG_IEEE1394 is not set
#
# I2O device support
#
#
# Networking support
#
CONFIG_NET=y
# #
# Networking options # Networking options
# #
# CONFIG_PACKET is not set CONFIG_PACKET=y
# CONFIG_NETLINK is not set # CONFIG_PACKET_MMAP is not set
# CONFIG_NETFILTER is not set # CONFIG_NETLINK_DEV is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set # CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set # CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set # CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set # CONFIG_NET_IPGRE is not set
# CONFIG_INET_ECN is not set # CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set # CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
#
# IP: Virtual Server Configuration
#
# CONFIG_IP_VS is not set
# CONFIG_IPV6 is not set # CONFIG_IPV6 is not set
# CONFIG_KHTTPD is not set CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
#
# IP: Netfilter Configuration
#
# CONFIG_IP_NF_CONNTRACK is not set
# CONFIG_IP_NF_QUEUE is not set
# CONFIG_IP_NF_IPTABLES is not set
# CONFIG_IP_NF_ARPTABLES is not set
# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
# CONFIG_IP_NF_COMPAT_IPFWADM is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set # CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set # CONFIG_IPX is not set
# CONFIG_ATALK is not set # CONFIG_ATALK is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set # CONFIG_X25 is not set
# CONFIG_LAPB is not set # CONFIG_LAPB is not set
# CONFIG_LLC is not set
# CONFIG_NET_DIVERT is not set # CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set # CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set # CONFIG_WAN_ROUTER is not set
...@@ -159,167 +332,114 @@ CONFIG_INET=y ...@@ -159,167 +332,114 @@ CONFIG_INET=y
# CONFIG_NET_SCHED is not set # CONFIG_NET_SCHED is not set
# #
# Telephony Support # Network testing
#
# CONFIG_PHONE is not set
# CONFIG_PHONE_IXJ is not set
#
# ATA/IDE/MFM/RLL support
#
# CONFIG_IDE is not set
#
# IDE, ATA and ATAPI Block devices
#
# CONFIG_BLK_DEV_IDE is not set
# CONFIG_BLK_DEV_HD_IDE is not set
# CONFIG_BLK_DEV_HD is not set
# CONFIG_BLK_DEV_IDEDISK is not set
# CONFIG_IDEDISK_MULTI_MODE is not set
# CONFIG_BLK_DEV_IDECS is not set
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
# CONFIG_BLK_DEV_IDESCSI is not set
# CONFIG_BLK_DEV_CMD640 is not set
# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
# CONFIG_BLK_DEV_ISAPNP is not set
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_IDEDMA_AUTO is not set
#
# SCSI support
#
# CONFIG_SCSI is not set
#
# I2O device support
#
# CONFIG_I2O is not set
# CONFIG_I2O_BLOCK is not set
# CONFIG_I2O_LAN is not set
# CONFIG_I2O_SCSI is not set
# CONFIG_I2O_PROC is not set
#
# Network device support
# #
# CONFIG_NET_PKTGEN is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
CONFIG_NETDEVICES=y CONFIG_NETDEVICES=y
#
# ARCnet devices
#
# CONFIG_ARCNET is not set
# CONFIG_DUMMY is not set # CONFIG_DUMMY is not set
# CONFIG_BONDING is not set # CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set # CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set # CONFIG_TUN is not set
# CONFIG_NET_SB1000 is not set
# #
# Ethernet (10 or 100Mbit) # Ethernet (10 or 100Mbit)
# #
CONFIG_NET_ETHERNET=y # CONFIG_MII is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_AT1700 is not set
# CONFIG_DEPCA is not set
# CONFIG_NET_ISA is not set
# CONFIG_NET_PCI is not set
# CONFIG_NET_POCKET is not set
# #
# Ethernet (1000 Mbit) # Ethernet (1000 Mbit)
# #
# CONFIG_ACENIC is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_SK98LIN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# #
# Wireless LAN (non-hamradio) # Ethernet (10000 Mbit)
# #
# CONFIG_NET_RADIO is not set
# #
# Token Ring devices # Token Ring devices
# #
# CONFIG_TR is not set
# CONFIG_NET_FC is not set #
# CONFIG_RCPCI is not set # Wireless LAN (non-hamradio)
# CONFIG_SHAPER is not set #
# CONFIG_NET_RADIO is not set
# #
# Wan interfaces # Wan interfaces
# #
# CONFIG_WAN is not set # CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# #
# Amateur Radio support # ISDN subsystem
# #
# CONFIG_HAMRADIO is not set # CONFIG_ISDN is not set
# #
# IrDA (infrared) support # Telephony Support
# #
# CONFIG_IRDA is not set # CONFIG_PHONE is not set
# #
# ISDN subsystem # Input device support
# #
# CONFIG_ISDN is not set # CONFIG_INPUT is not set
# #
# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) # Userland interfaces
# #
# CONFIG_CD_NO_IDESCSI is not set
# #
# Input core support # Input I/O drivers
#
# CONFIG_GAMEPORT is not set
CONFIG_SOUND_GAMEPORT=y
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
# CONFIG_SERIO_CT82C710 is not set
#
# Input Device Drivers
# #
# CONFIG_INPUT is not set
# #
# Character devices # Character devices
# #
# CONFIG_VT is not set # CONFIG_VT is not set
# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set # CONFIG_SERIAL_NONSTANDARD is not set
# CONFIG_UNIX98_PTYS is not set
# #
# I2C support # Serial drivers
# #
# CONFIG_I2C is not set # CONFIG_SERIAL_8250 is not set
# #
# Mice # Non-8250 serial port support
# #
# CONFIG_BUSMOUSE is not set CONFIG_UNIX98_PTYS=y
# CONFIG_MOUSE is not set CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_QIC02_TAPE is not set
# #
# Joysticks # IPMI
# #
# CONFIG_JOYSTICK is not set # CONFIG_IPMI_HANDLER is not set
# CONFIG_QIC02_TAPE is not set
# #
# Watchdog Cards # Watchdog Cards
# #
# CONFIG_WATCHDOG is not set # CONFIG_WATCHDOG is not set
# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set # CONFIG_RTC is not set
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set # CONFIG_DTLK is not set
# CONFIG_R3964 is not set # CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set # CONFIG_APPLICOM is not set
...@@ -330,83 +450,106 @@ CONFIG_NET_ETHERNET=y ...@@ -330,83 +450,106 @@ CONFIG_NET_ETHERNET=y
# CONFIG_FTAPE is not set # CONFIG_FTAPE is not set
# CONFIG_AGP is not set # CONFIG_AGP is not set
# CONFIG_DRM is not set # CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
# #
# Multimedia devices # Multimedia devices
# #
# CONFIG_VIDEO_DEV is not set # CONFIG_VIDEO_DEV is not set
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
# #
# File systems # File systems
# #
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_QUOTA is not set # CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set # CONFIG_AUTOFS4_FS is not set
#
# CD-ROM/DVD Filesystems
#
# CONFIG_ISO9660_FS is not set
# CONFIG_UDF_FS is not set
#
# DOS/FAT/NT Filesystems
#
# CONFIG_FAT_FS is not set
# CONFIG_NTFS_FS is not set
#
# Pseudo filesystems
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set # CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set # CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set # CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set # CONFIG_BFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set # CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set CONFIG_JFFS_FS=y
CONFIG_JFFS_FS_VERBOSE=0
# CONFIG_JFFS2_FS is not set
CONFIG_CRAMFS=y CONFIG_CRAMFS=y
CONFIG_RAMFS=y # CONFIG_VXFS_FS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS_DEBUG is not set
# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set # CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set # CONFIG_QNX4FS_FS is not set
# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
# CONFIG_EXT2_FS is not set
# CONFIG_SYSV_FS is not set # CONFIG_SYSV_FS is not set
# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set # CONFIG_UFS_FS is not set
# CONFIG_UFS_FS_WRITE is not set
# #
# Network File Systems # Network File Systems
# #
# CONFIG_CODA_FS is not set CONFIG_NFS_FS=y
# CONFIG_NFS_FS is not set CONFIG_NFS_V3=y
# CONFIG_NFS_V3 is not set # CONFIG_NFS_V4 is not set
# CONFIG_ROOT_NFS is not set # CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set # CONFIG_NFSD is not set
# CONFIG_NFSD_V3 is not set CONFIG_LOCKD=y
# CONFIG_SUNRPC is not set CONFIG_LOCKD_V4=y
# CONFIG_LOCKD is not set # CONFIG_EXPORTFS is not set
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_SMB_FS is not set # CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set # CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set # CONFIG_CODA_FS is not set
# CONFIG_NCPFS_IOCTL_LOCKING is not set # CONFIG_INTERMEZZO_FS is not set
# CONFIG_NCPFS_STRONG is not set # CONFIG_AFS_FS is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
# CONFIG_NCPFS_MOUNT_SUBDIR is not set
# CONFIG_NCPFS_NDS_DOMAINS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
# #
# Partition Types # Partition Types
# #
# CONFIG_PARTITION_ADVANCED is not set # CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y CONFIG_MSDOS_PARTITION=y
#
# Native Language Support
#
# CONFIG_NLS is not set # CONFIG_NLS is not set
# #
...@@ -417,9 +560,33 @@ CONFIG_MSDOS_PARTITION=y ...@@ -417,9 +560,33 @@ CONFIG_MSDOS_PARTITION=y
# #
# USB support # USB support
# #
# CONFIG_USB is not set
#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
# #
# Kernel hacking # Kernel hacking
# #
# CONFIG_PROFILE is not set # CONFIG_PROFILE is not set
# CONFIG_ETRAX_KGDB is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_FRAME_POINTER is not set
#
# Security options
#
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
# CONFIG_CRYPTO is not set
#
# Library routines
#
# CONFIG_CRC32 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
# $Id: Makefile,v 1.8 2003/04/09 05:20:47 starvik Exp $ # $Id: Makefile,v 1.10 2004/05/14 10:18:12 starvik Exp $
# #
# Makefile for the linux kernel. # Makefile for the linux kernel.
# #
extra-y := vmlinux.lds.s extra-y := vmlinux.lds.s
obj-y := process.o traps.o irq.o ptrace.o setup.o \ obj-y := process.o traps.o irq.o ptrace.o setup.o \
time.o sys_cris.o semaphore.o time.o sys_cris.o semaphore.o
obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_MODULES) += crisksyms.o
obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULES) += module.o
clean: clean:
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/fasttimer.h>
extern void dump_thread(struct pt_regs *, struct user *); extern void dump_thread(struct pt_regs *, struct user *);
extern unsigned long get_cmos_time(void); extern unsigned long get_cmos_time(void);
...@@ -93,4 +94,11 @@ extern void * memcpy(void *, const void *, __kernel_size_t); ...@@ -93,4 +94,11 @@ extern void * memcpy(void *, const void *, __kernel_size_t);
EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL_NOVERS(memcpy);
EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memset);
#ifdef CONFIG_ETRAX_FAST_TIMER
/* Fast timer functions */
EXPORT_SYMBOL(fast_timer_list);
EXPORT_SYMBOL(start_one_shot_timer);
EXPORT_SYMBOL(del_fast_timer);
EXPORT_SYMBOL(schedule_usleep);
#endif
#include <stdio.h>
void main()
{
int c;
int comma=0;
int count=0;
while((c=getchar())!=EOF)
{
unsigned char x=c;
if(comma)
printf(",");
else
comma=1;
if(count==8)
{
count=0;
printf("\n");
}
if(count==0)
printf("\t");
printf("0x%02X",c);
count++;
}
if(count)
printf("\n");
exit(0);
}
/* $Id: irq.c,v 1.8 2003/07/04 08:27:52 starvik Exp $ /*
* *
* linux/arch/cris/kernel/irq.c * linux/arch/cris/kernel/irq.c
* *
...@@ -99,7 +99,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -99,7 +99,7 @@ int show_interrupts(struct seq_file *p, void *v)
if (!action) if (!action)
goto skip; goto skip;
seq_printf(p, "%2d: %10u %c %s", seq_printf(p, "%2d: %10u %c %s",
i, kstat_cpu(0).irqs[i], i, kstat_this_cpu.irqs[i],
(action->flags & SA_INTERRUPT) ? '+' : ' ', (action->flags & SA_INTERRUPT) ? '+' : ' ',
action->name); action->name);
for (action = action->next; action; action = action->next) { for (action = action->next; action; action = action->next) {
...@@ -129,13 +129,12 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) ...@@ -129,13 +129,12 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
cpu = smp_processor_id(); cpu = smp_processor_id();
irq_enter(); irq_enter();
kstat_cpu(cpu).irqs[irq]++; kstat_cpu(cpu).irqs[irq - FIRST_IRQ]++;
action = irq_action[irq - FIRST_IRQ];
action = irq_action[irq];
if (action) { if (action) {
if (!(action->flags & SA_INTERRUPT)) if (!(action->flags & SA_INTERRUPT))
local_irq_enable(); local_irq_enable();
action = irq_action[irq];
do_random = 0; do_random = 0;
do { do {
do_random |= action->flags; do_random |= action->flags;
...@@ -175,7 +174,7 @@ int setup_irq(int irq, struct irqaction * new) ...@@ -175,7 +174,7 @@ int setup_irq(int irq, struct irqaction * new)
struct irqaction *old, **p; struct irqaction *old, **p;
unsigned long flags; unsigned long flags;
p = irq_action + irq; p = irq_action + irq - FIRST_IRQ;
if ((old = *p) != NULL) { if ((old = *p) != NULL) {
/* Can't share interrupts unless both agree to */ /* Can't share interrupts unless both agree to */
if (!(old->flags & new->flags & SA_SHIRQ)) if (!(old->flags & new->flags & SA_SHIRQ))
...@@ -230,12 +229,6 @@ int request_irq(unsigned int irq, ...@@ -230,12 +229,6 @@ int request_irq(unsigned int irq,
int retval; int retval;
struct irqaction * action; struct irqaction * action;
/* interrupts 0 and 1 are hardware breakpoint and NMI and we can't support
these yet. interrupt 15 is the multiple irq, it's special. */
if(irq < 2 || irq == 15 || irq >= NR_IRQS)
return -EINVAL;
if(!handler) if(!handler)
return -EINVAL; return -EINVAL;
...@@ -270,7 +263,7 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -270,7 +263,7 @@ void free_irq(unsigned int irq, void *dev_id)
printk("Trying to free IRQ%d\n",irq); printk("Trying to free IRQ%d\n",irq);
return; return;
} }
for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { for (p = irq - FIRST_IRQ + irq_action; (action = *p) != NULL; p = &action->next) {
if (action->dev_id != dev_id) if (action->dev_id != dev_id)
continue; continue;
...@@ -278,7 +271,7 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -278,7 +271,7 @@ void free_irq(unsigned int irq, void *dev_id)
local_save_flags(flags); local_save_flags(flags);
local_irq_disable(); local_irq_disable();
*p = action->next; *p = action->next;
if (!irq_action[irq]) { if (!irq_action[irq - FIRST_IRQ]) {
mask_irq(irq); mask_irq(irq);
arch_free_irq(irq); arch_free_irq(irq);
} }
......
...@@ -75,8 +75,6 @@ int apply_relocate(Elf32_Shdr *sechdrs, ...@@ -75,8 +75,6 @@ int apply_relocate(Elf32_Shdr *sechdrs,
sym = (Elf32_Sym *)sechdrs[symindex].sh_addr sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rel[i].r_info); + ELF32_R_SYM(rel[i].r_info);
/* TODO: This is probably not correct */
printk("Beware: untested code in module.c!\n");
/* We add the value into the location given */ /* We add the value into the location given */
*location += sym->st_value; *location += sym->st_value;
} }
...@@ -89,9 +87,26 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, ...@@ -89,9 +87,26 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
unsigned int relsec, unsigned int relsec,
struct module *me) struct module *me)
{ {
printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", unsigned int i;
me->name); Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
return -ENOEXEC;
DEBUGP ("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) {
/* This is where to make the change */
uint32_t *loc
= ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rela[i].r_offset);
/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
Elf32_Sym *sym
= ((Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM (rela[i].r_info));
*loc = sym->st_value + rela[i].r_addend;
}
return 0;
} }
int module_finalize(const Elf_Ehdr *hdr, int module_finalize(const Elf_Ehdr *hdr,
......
/* $Id: process.c,v 1.14 2003/06/10 10:21:12 johana Exp $ /* $Id: process.c,v 1.17 2004/04/05 13:53:48 starvik Exp $
* *
* linux/arch/cris/kernel/process.c * linux/arch/cris/kernel/process.c
* *
...@@ -8,9 +8,18 @@ ...@@ -8,9 +8,18 @@
* Authors: Bjorn Wesen (bjornw@axis.com) * Authors: Bjorn Wesen (bjornw@axis.com)
* *
* $Log: process.c,v $ * $Log: process.c,v $
* Revision 1.17 2004/04/05 13:53:48 starvik
* Merge of Linux 2.6.5
*
* Revision 1.16 2003/10/27 08:04:33 starvik
* Merge of Linux 2.6.0-test9
*
* Revision 1.15 2003/09/11 07:29:52 starvik
* Merge of Linux 2.6.0-test5
*
* Revision 1.14 2003/06/10 10:21:12 johana * Revision 1.14 2003/06/10 10:21:12 johana
* Moved thread_saved_pc() from arch/cris/kernel/process.c to * Moved thread_saved_pc() from arch/cris/kernel/process.c to
* subarch specific process.c. * subarch specific process.c. arch-v32 has an erp, no irp.
* *
* Revision 1.13 2003/04/09 05:20:47 starvik * Revision 1.13 2003/04/09 05:20:47 starvik
* Merge of Linux 2.5.67 * Merge of Linux 2.5.67
...@@ -94,6 +103,7 @@ ...@@ -94,6 +103,7 @@
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/fs_struct.h> #include <linux/fs_struct.h>
...@@ -182,13 +192,17 @@ void cpu_idle (void) ...@@ -182,13 +192,17 @@ void cpu_idle (void)
{ {
/* endless idle loop with no priority at all */ /* endless idle loop with no priority at all */
while (1) { while (1) {
void (*idle)(void) = pm_idle; while (!need_resched()) {
if (!idle) void (*idle)(void) = pm_idle;
idle = default_idle;
while (!need_resched()) if (!idle)
idle = default_idle;
idle(); idle();
}
schedule(); schedule();
} }
} }
void hard_reset_now (void); void hard_reset_now (void);
......
/* $Id: setup.c,v 1.7 2003/07/04 08:27:52 starvik Exp $ /*
* *
* linux/arch/cris/kernel/setup.c * linux/arch/cris/kernel/setup.c
* *
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
* This file handles the architecture-dependent parts of initialization * This file handles the architecture-dependent parts of initialization
*/ */
#include <linux/config.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
...@@ -38,6 +39,8 @@ extern unsigned long dram_start, dram_end; ...@@ -38,6 +39,8 @@ extern unsigned long dram_start, dram_end;
extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */ extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */
extern void show_etrax_copyright(void); /* arch-vX/kernel/setup.c */
/* This mainly sets up the memory area, and can be really confusing. /* This mainly sets up the memory area, and can be really confusing.
* *
* The physical DRAM is virtually mapped into dram_start to dram_end * The physical DRAM is virtually mapped into dram_start to dram_end
...@@ -153,18 +156,16 @@ setup_arch(char **cmdline_p) ...@@ -153,18 +156,16 @@ setup_arch(char **cmdline_p)
*cmdline_p = command_line; *cmdline_p = command_line;
#ifdef CONFIG_ETRAX_CMDLINE #ifdef CONFIG_ETRAX_CMDLINE
strlcpy(command_line, CONFIG_ETRAX_CMDLINE, sizeof(command_line)); strlcpy(command_line, CONFIG_ETRAX_CMDLINE, COMMAND_LINE_SIZE);
#elif defined(CONFIG_ETRAX_ROOT_DEVICE)
strlcpy(command_line, "root=", sizeof(command_line));
strlcat(command_line, CONFIG_ETRAX_ROOT_DEVICE,
sizeof(command_line));
#endif
command_line[COMMAND_LINE_SIZE - 1] = '\0'; command_line[COMMAND_LINE_SIZE - 1] = '\0';
/* give credit for the CRIS port */ /* Save command line for future references. */
memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
printk("Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n"); saved_command_line[COMMAND_LINE_SIZE - 1] = '\0';
#endif
/* give credit for the CRIS port */
show_etrax_copyright();
} }
static void *c_start(struct seq_file *m, loff_t *pos) static void *c_start(struct seq_file *m, loff_t *pos)
......
/* $Id: sys_cris.c,v 1.5 2003/07/04 08:27:52 starvik Exp $ /* $Id: sys_cris.c,v 1.6 2004/03/11 11:38:40 starvik Exp $
* *
* linux/arch/cris/kernel/sys_cris.c * linux/arch/cris/kernel/sys_cris.c
* *
......
/* $Id: time.c,v 1.9 2003/07/04 08:27:52 starvik Exp $ /* $Id: time.c,v 1.14 2004/06/01 05:38:11 starvik Exp $
* *
* linux/arch/cris/kernel/time.c * linux/arch/cris/kernel/time.c
* *
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/timex.h> #include <linux/timex.h>
#include <linux/init.h>
u64 jiffies_64 = INITIAL_JIFFIES; u64 jiffies_64 = INITIAL_JIFFIES;
...@@ -39,6 +40,8 @@ int have_rtc; /* used to remember if we have an RTC or not */; ...@@ -39,6 +40,8 @@ int have_rtc; /* used to remember if we have an RTC or not */;
#define TICK_SIZE tick #define TICK_SIZE tick
extern unsigned long wall_jiffies; extern unsigned long wall_jiffies;
extern unsigned long loops_per_jiffy; /* init/main.c */
unsigned long loops_per_usec;
extern unsigned long do_slow_gettimeoffset(void); extern unsigned long do_slow_gettimeoffset(void);
static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
...@@ -62,6 +65,15 @@ void do_gettimeofday(struct timeval *tv) ...@@ -62,6 +65,15 @@ void do_gettimeofday(struct timeval *tv)
if (lost) if (lost)
usec += lost * (1000000 / HZ); usec += lost * (1000000 / HZ);
} }
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
if (unlikely(time_adjust < 0) && usec > tickadj)
usec = tickadj;
sec = xtime.tv_sec; sec = xtime.tv_sec;
usec += xtime.tv_nsec / 1000; usec += xtime.tv_nsec / 1000;
local_irq_restore(flags); local_irq_restore(flags);
...@@ -79,35 +91,33 @@ EXPORT_SYMBOL(do_gettimeofday); ...@@ -79,35 +91,33 @@ EXPORT_SYMBOL(do_gettimeofday);
int do_settimeofday(struct timespec *tv) int do_settimeofday(struct timespec *tv)
{ {
unsigned long flags; time_t wtm_sec, sec = tv->tv_sec;
long wtm_nsec, nsec = tv->tv_nsec;
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL; return -EINVAL;
local_irq_save(flags); write_seqlock_irq(&xtime_lock);
local_irq_disable(); /*
* This is revolting. We need to set "xtime" correctly. However, the
/* This is revolting. We need to set the xtime.tv_usec * value in this location is the value at the most recent update of
* correctly. However, the value in this location is * wall time. Discover what correction gettimeofday() would have
* is value at the last tick. * made, and then undo it!
* Discover what correction gettimeofday
* would have done, and then undo it!
*/ */
tv->tv_nsec -= do_gettimeoffset() * 1000; nsec -= do_gettimeoffset() * NSEC_PER_USEC;
tv->tv_nsec -= (jiffies - wall_jiffies) * TICK_NSEC; nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
while (tv->tv_nsec < 0) {
tv->tv_nsec += NSEC_PER_SEC;
tv->tv_sec--;
}
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_nsec;
time_adjust = 0; /* stop active adjtime() */ time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC; time_status |= STA_UNSYNC;
time_state = TIME_ERROR; /* p. 24, (a) */
time_maxerror = NTP_PHASE_LIMIT; time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT;
local_irq_restore(flags); write_sequnlock_irq(&xtime_lock);
clock_was_set(); clock_was_set();
return 0; return 0;
} }
...@@ -125,7 +135,7 @@ int set_rtc_mmss(unsigned long nowtime) ...@@ -125,7 +135,7 @@ int set_rtc_mmss(unsigned long nowtime)
int retval = 0; int retval = 0;
int real_seconds, real_minutes, cmos_minutes; int real_seconds, real_minutes, cmos_minutes;
printk("set_rtc_mmss(%lu)\n", nowtime); printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime);
if(!have_rtc) if(!have_rtc)
return 0; return 0;
...@@ -174,7 +184,8 @@ get_cmos_time(void) ...@@ -174,7 +184,8 @@ get_cmos_time(void)
mon = CMOS_READ(RTC_MONTH); mon = CMOS_READ(RTC_MONTH);
year = CMOS_READ(RTC_YEAR); year = CMOS_READ(RTC_YEAR);
printk("rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n", printk(KERN_DEBUG
"rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n",
sec, min, hour, day, mon, year); sec, min, hour, day, mon, year);
BCD_TO_BIN(sec); BCD_TO_BIN(sec);
...@@ -202,3 +213,20 @@ update_xtime_from_cmos(void) ...@@ -202,3 +213,20 @@ update_xtime_from_cmos(void)
xtime.tv_nsec = 0; xtime.tv_nsec = 0;
} }
} }
/*
* Scheduler clock - returns current time in nanosec units.
*/
unsigned long long sched_clock(void)
{
return (unsigned long long)jiffies * (1000000000 / HZ);
}
static int
__init init_udelay(void)
{
loops_per_usec = (loops_per_jiffy * HZ) / 1000000;
return 0;
}
__initcall(init_udelay);
/* $Id: traps.c,v 1.7 2003/07/04 08:27:52 starvik Exp $ /* $Id: traps.c,v 1.9 2004/05/11 12:28:26 starvik Exp $
* *
* linux/arch/cris/traps.c * linux/arch/cris/traps.c
* *
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
...@@ -6,9 +6,18 @@ ...@@ -6,9 +6,18 @@
* Authors: Bjorn Wesen * Authors: Bjorn Wesen
* *
* $Log: fault.c,v $ * $Log: fault.c,v $
* Revision 1.11 2004/05/14 07:58:05 starvik
* Merge of changes from 2.4
*
* Revision 1.10 2003/10/27 14:51:24 starvik
* Removed debugcode
*
* Revision 1.9 2003/10/27 14:50:42 starvik
* Changed do_page_fault signature
*
* Revision 1.8 2003/07/04 13:02:48 tobiasa * Revision 1.8 2003/07/04 13:02:48 tobiasa
* Moved code snippet from arch/cris/mm/fault.c that searches for fixup code * Moved code snippet from arch/cris/mm/fault.c that searches for fixup code
* to separate function in arch-specific files. * to seperate function in arch-specific files.
* *
* Revision 1.7 2003/01/22 06:48:38 starvik * Revision 1.7 2003/01/22 06:48:38 starvik
* Fixed warnings issued by GCC 3.2.1 * Fixed warnings issued by GCC 3.2.1
...@@ -95,10 +104,6 @@ ...@@ -95,10 +104,6 @@
extern int find_fixup_code(struct pt_regs *); extern int find_fixup_code(struct pt_regs *);
extern void die_if_kernel(const char *, struct pt_regs *, long); extern void die_if_kernel(const char *, struct pt_regs *, long);
asmlinkage void do_invalid_op (struct pt_regs *, unsigned long);
asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
int error_code);
/* debug of low-level TLB reload */ /* debug of low-level TLB reload */
#undef DEBUG #undef DEBUG
...@@ -134,14 +139,16 @@ volatile pgd_t *current_pgd; ...@@ -134,14 +139,16 @@ volatile pgd_t *current_pgd;
asmlinkage void asmlinkage void
do_page_fault(unsigned long address, struct pt_regs *regs, do_page_fault(unsigned long address, struct pt_regs *regs,
int error_code) int protection, int writeaccess)
{ {
struct task_struct *tsk; struct task_struct *tsk;
struct mm_struct *mm; struct mm_struct *mm;
struct vm_area_struct * vma; struct vm_area_struct * vma;
int writeaccess;
siginfo_t info; siginfo_t info;
D(printk("Page fault for %X at %X, prot %d write %d\n",
address, regs->erp, protection, writeaccess));
tsk = current; tsk = current;
/* /*
...@@ -164,7 +171,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs, ...@@ -164,7 +171,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
*/ */
if (address >= VMALLOC_START && if (address >= VMALLOC_START &&
!(error_code & 1) && !protection &&
!user_mode(regs)) !user_mode(regs))
goto vmalloc_fault; goto vmalloc_fault;
...@@ -172,7 +179,6 @@ do_page_fault(unsigned long address, struct pt_regs *regs, ...@@ -172,7 +179,6 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
sti(); sti();
mm = tsk->mm; mm = tsk->mm;
writeaccess = error_code & 2;
info.si_code = SEGV_MAPERR; info.si_code = SEGV_MAPERR;
/* /*
...@@ -291,7 +297,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs, ...@@ -291,7 +297,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
printk(KERN_ALERT "Unable to handle kernel access"); printk(KERN_ALERT "Unable to handle kernel access");
printk(" at virtual address %08lx\n",address); printk(" at virtual address %08lx\n",address);
die_if_kernel("Oops", regs, error_code); die_if_kernel("Oops", regs, (writeaccess << 1) | protection);
do_exit(SIGKILL); do_exit(SIGKILL);
......
...@@ -7,6 +7,13 @@ ...@@ -7,6 +7,13 @@
* Authors: Bjorn Wesen (bjornw@axis.com) * Authors: Bjorn Wesen (bjornw@axis.com)
* *
* $Log: init.c,v $ * $Log: init.c,v $
* Revision 1.11 2004/05/28 09:28:56 starvik
* Calculation of loops_per_usec moved because initalization order has changed
* in Linux 2.6.
*
* Revision 1.10 2004/05/14 07:58:05 starvik
* Merge of changes from 2.4
*
* Revision 1.9 2003/07/04 08:27:54 starvik * Revision 1.9 2003/07/04 08:27:54 starvik
* Merge of Linux 2.5.74 * Merge of Linux 2.5.74
* *
...@@ -120,9 +127,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); ...@@ -120,9 +127,6 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
unsigned long empty_zero_page; unsigned long empty_zero_page;
extern unsigned long loops_per_jiffy; /* init/main.c */
unsigned long loops_per_usec;
extern char _stext, _edata, _etext; /* From linkerscript */ extern char _stext, _edata, _etext; /* From linkerscript */
extern char __init_begin, __init_end; extern char __init_begin, __init_end;
...@@ -190,7 +194,8 @@ mem_init(void) ...@@ -190,7 +194,8 @@ mem_init(void)
datasize = (unsigned long) &_edata - (unsigned long) &_etext; datasize = (unsigned long) &_edata - (unsigned long) &_etext;
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, " printk(KERN_INFO
"Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, "
"%dk init)\n" , "%dk init)\n" ,
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10), (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10), max_mapnr << (PAGE_SHIFT-10),
...@@ -199,16 +204,6 @@ mem_init(void) ...@@ -199,16 +204,6 @@ mem_init(void)
datasize >> 10, datasize >> 10,
initsize >> 10 initsize >> 10
); );
/* HACK alert - calculate a loops_per_usec for asm/delay.h here
* since this is called just after calibrate_delay in init/main.c
* but before places which use udelay. cannot be in time.c since
* that is called _before_ calibrate_delay
*/
loops_per_usec = (loops_per_jiffy * HZ) / 1000000;
return;
} }
/* free the pages occupied by initialization code */ /* free the pages occupied by initialization code */
...@@ -225,6 +220,6 @@ free_initmem(void) ...@@ -225,6 +220,6 @@ free_initmem(void)
free_page(addr); free_page(addr);
totalram_pages++; totalram_pages++;
} }
printk ("Freeing unused kernel memory: %luk freed\n", printk (KERN_INFO "Freeing unused kernel memory: %luk freed\n",
(unsigned long)((&__init_end - &__init_begin) >> 10)); (unsigned long)((&__init_end - &__init_begin) >> 10));
} }
...@@ -118,31 +118,6 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag ...@@ -118,31 +118,6 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag
if (!size || last_addr < phys_addr) if (!size || last_addr < phys_addr)
return NULL; return NULL;
#if 0
/* TODO: Here we can put checks for driver-writer abuse... */
/*
* Don't remap the low PCI/ISA area, it's always mapped..
*/
if (phys_addr >= 0xA0000 && last_addr < 0x100000)
return phys_to_virt(phys_addr);
/*
* Don't allow anybody to remap normal RAM that we're using..
*/
if (phys_addr < virt_to_phys(high_memory)) {
char *t_addr, *t_end;
struct page *page;
t_addr = __va(phys_addr);
t_end = t_addr + (size - 1);
for(page = virt_to_page(t_addr); page <= virt_to_page(t_end); page++)
if(!PageReserved(page))
return NULL;
}
#endif
/* /*
* Mappings have to be page-aligned * Mappings have to be page-aligned
*/ */
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
/* Etrax 100LX have 32-byte cache-lines. */ /* Etrax 100LX have 32-byte cache-lines. */
#define L1_CACHE_BYTES 32 #define L1_CACHE_BYTES 32
#define L1_CACHE_SHIFT 5
#define L1_CACHE_SHIFT_MAX 5 #define L1_CACHE_SHIFT_MAX 5
#endif /* _ASM_ARCH_CACHE_H */ #endif /* _ASM_ARCH_CACHE_H */
...@@ -8,6 +8,11 @@ ...@@ -8,6 +8,11 @@
#include <asm/arch/sv_addr_ag.h> #include <asm/arch/sv_addr_ag.h>
#define NR_IRQS 32 #define NR_IRQS 32
/* The first vector number used for IRQs in v10 is really 0x20 */
/* but all the code and constants are offseted to make 0 the first */
#define FIRST_IRQ 0
#define SOME_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, some) /* 0 ? */ #define SOME_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, some) /* 0 ? */
#define NMI_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, nmi) /* 1 */ #define NMI_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, nmi) /* 1 */
#define TIMER0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */ #define TIMER0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#define THREAD_usp 4 /* offsetof(struct thread_struct, usp) */ #define THREAD_usp 4 /* offsetof(struct thread_struct, usp) */
#define THREAD_dccr 8 /* offsetof(struct thread_struct, dccr) */ #define THREAD_dccr 8 /* offsetof(struct thread_struct, dccr) */
#define TASK_pid 121 /* offsetof(struct task_struct, pid) */ #define TASK_pid 133 /* offsetof(struct task_struct, pid) */
#define LCLONE_VM 256 /* CLONE_VM */ #define LCLONE_VM 256 /* CLONE_VM */
#define LCLONE_UNTRACED 8388608 /* CLONE_UNTRACED */ #define LCLONE_UNTRACED 8388608 /* CLONE_UNTRACED */
......
...@@ -295,6 +295,50 @@ extern inline int find_next_zero_bit (void * addr, int size, int offset) ...@@ -295,6 +295,50 @@ extern inline int find_next_zero_bit (void * addr, int size, int offset)
return result + ffz(tmp); return result + ffz(tmp);
} }
/**
* find_next_bit - find the first set bit in a memory region
* @addr: The address to base the search on
* @offset: The bitnumber to start searching at
* @size: The maximum size to search
*/
static __inline__ int find_next_bit(void *addr, int size, int offset)
{
unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
unsigned long result = offset & ~31UL;
unsigned long tmp;
if (offset >= size)
return size;
size -= result;
offset &= 31UL;
if (offset) {
tmp = *(p++);
tmp &= (~0UL << offset);
if (size < 32)
goto found_first;
if (tmp)
goto found_middle;
size -= 32;
result += 32;
}
while (size & ~31UL) {
if ((tmp = *(p++)))
goto found_middle;
result += 32;
size -= 32;
}
if (!size)
return result;
tmp = *p;
found_first:
tmp &= (~0UL >> (32 - size));
if (tmp == 0UL) /* Are any bits set? */
return result + size; /* Nope. */
found_middle:
return result + __ffs(tmp);
}
/** /**
* find_first_zero_bit - find the first zero bit in a memory region * find_first_zero_bit - find the first zero bit in a memory region
* @addr: The address to start the search at * @addr: The address to start the search at
...@@ -306,6 +350,8 @@ extern inline int find_next_zero_bit (void * addr, int size, int offset) ...@@ -306,6 +350,8 @@ extern inline int find_next_zero_bit (void * addr, int size, int offset)
#define find_first_zero_bit(addr, size) \ #define find_first_zero_bit(addr, size) \
find_next_zero_bit((addr), (size), 0) find_next_zero_bit((addr), (size), 0)
#define find_first_bit(addr, size) \
find_next_bit((addr), (size), 0)
#define ext2_set_bit test_and_set_bit #define ext2_set_bit test_and_set_bit
#define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) #define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a)
......
#include <asm-generic/dma-mapping.h> #ifndef _ASM_CRIS_DMA_MAPPING_H
#define _ASM_CRIS_DMA_MAPPING_H
#include "scatterlist.h"
static inline int
dma_supported(struct device *dev, u64 mask)
{
BUG();
return 0;
}
static inline int
dma_set_mask(struct device *dev, u64 dma_mask)
{
BUG();
return 1;
}
static inline void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
int flag)
{
BUG();
return NULL;
}
static inline void
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t dma_handle)
{
BUG();
}
static inline dma_addr_t
dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction direction)
{
BUG();
return 0;
}
static inline void
dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction direction)
{
BUG();
}
static inline dma_addr_t
dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction direction)
{
BUG();
return 0;
}
static inline void
dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
enum dma_data_direction direction)
{
BUG();
}
static inline int
dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
enum dma_data_direction direction)
{
BUG();
return 1;
}
static inline void
dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
enum dma_data_direction direction)
{
BUG();
}
static inline void
dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size,
enum dma_data_direction direction)
{
BUG();
}
static inline void
dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems,
enum dma_data_direction direction)
{
BUG();
}
/* Now for the API extensions over the pci_ one */
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
#define dma_is_consistent(d) (1)
static inline int
dma_get_cache_alignment(void)
{
/* no easy way to get cache size on all processors, so return
* the maximum possible, to be safe */
return (1 << L1_CACHE_SHIFT_MAX);
}
static inline void
dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
unsigned long offset, size_t size,
enum dma_data_direction direction)
{
BUG();
}
static inline void
dma_cache_sync(void *vaddr, size_t size,
enum dma_data_direction direction)
{
BUG();
}
#endif
/* $Id: fasttimer.h,v 1.2 2002/12/11 13:03:43 starvik Exp $ /* $Id: fasttimer.h,v 1.3 2004/05/14 10:19:19 starvik Exp $
* linux/include/asm-cris/fasttimer.h * linux/include/asm-cris/fasttimer.h
* *
* Fast timers for ETRAX100LX * Fast timers for ETRAX100LX
...@@ -24,6 +24,8 @@ struct fast_timer{ /* Close to timer_list */ ...@@ -24,6 +24,8 @@ struct fast_timer{ /* Close to timer_list */
const char *name; const char *name;
}; };
extern struct fast_timer *fast_timer_list;
void start_one_shot_timer(struct fast_timer *t, void start_one_shot_timer(struct fast_timer *t,
fast_timer_function_type *function, fast_timer_function_type *function,
unsigned long data, unsigned long data,
......
...@@ -72,6 +72,8 @@ extern void iounmap(void *addr); ...@@ -72,6 +72,8 @@ extern void iounmap(void *addr);
#define IO_SPACE_LIMIT 0xffff #define IO_SPACE_LIMIT 0xffff
#define inb(x) (0) #define inb(x) (0)
#define inw(x) (0)
#define inl(x) (0)
#define outb(x,y) #define outb(x,y)
#define outw(x,y) #define outw(x,y)
#define outl(x,y) #define outl(x,y)
......
...@@ -53,11 +53,18 @@ ...@@ -53,11 +53,18 @@
((nr) << _IOC_NRSHIFT) | \ ((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT)) ((size) << _IOC_SIZESHIFT))
/* provoke compile error for invalid uses of size argument */
extern int __invalid_size_argument_for_IOC;
#define _IOC_TYPECHECK(t) \
((sizeof(t) == sizeof(t[1]) && \
sizeof(t) < (1 << _IOC_SIZEBITS)) ? \
sizeof(t) : __invalid_size_argument_for_IOC)
/* used to create numbers */ /* used to create numbers */
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
/* used to decode ioctl numbers.. */ /* used to decode ioctl numbers.. */
#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) #define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
......
#include <asm-generic/local.h>
...@@ -6,7 +6,11 @@ ...@@ -6,7 +6,11 @@
/* PAGE_SHIFT determines the page size */ /* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 13 #define PAGE_SHIFT 13
#ifndef __ASSEMBLY__
#define PAGE_SIZE (1UL << PAGE_SHIFT) #define PAGE_SIZE (1UL << PAGE_SHIFT)
#else
#define PAGE_SIZE (1 << PAGE_SHIFT)
#endif
#define PAGE_MASK (~(PAGE_SIZE-1)) #define PAGE_MASK (~(PAGE_SIZE-1))
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -20,10 +24,12 @@ ...@@ -20,10 +24,12 @@
/* /*
* These are used to make use of C type-checking.. * These are used to make use of C type-checking..
*/ */
#ifndef __ASSEMBLY__
typedef struct { unsigned long pte; } pte_t; typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t; typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t; typedef struct { unsigned long pgprot; } pgprot_t;
#endif
#define pte_val(x) ((x).pte) #define pte_val(x) ((x).pte)
#define pmd_val(x) ((x).pmd) #define pmd_val(x) ((x).pmd)
...@@ -51,7 +57,7 @@ typedef struct { unsigned long pgprot; } pgprot_t; ...@@ -51,7 +57,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT)) #define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT))
#define VALID_PAGE(page) (((page) - mem_map) < max_mapnr) #define VALID_PAGE(page) (((page) - mem_map) < max_mapnr)
#define virt_addr_valid(kaddr) pfn_valid((kaddr) >> PAGE_SHIFT) #define virt_addr_valid(kaddr) pfn_valid((unsigned)(kaddr) >> PAGE_SHIFT)
/* convert a page (based on mem_map and forward) to a physical address /* convert a page (based on mem_map and forward) to a physical address
* do this by figuring out the virtual address and then use __pa * do this by figuring out the virtual address and then use __pa
...@@ -72,8 +78,6 @@ typedef struct { unsigned long pgprot; } pgprot_t; ...@@ -72,8 +78,6 @@ typedef struct { unsigned long pgprot; } pgprot_t;
BUG(); \ BUG(); \
} while (0) } while (0)
#endif /* __ASSEMBLY__ */
/* Pure 2^n version of get_order */ /* Pure 2^n version of get_order */
static inline int get_order(unsigned long size) static inline int get_order(unsigned long size)
{ {
...@@ -87,6 +91,7 @@ static inline int get_order(unsigned long size) ...@@ -87,6 +91,7 @@ static inline int get_order(unsigned long size)
} while (size); } while (size);
return order; return order;
} }
#endif /* __ASSEMBLY__ */
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
......
#ifndef __ASM_CRIS_PCI_H #ifndef __ASM_CRIS_PCI_H
#define __ASM_CRIS_PCI_H #define __ASM_CRIS_PCI_H
#include <asm/scatterlist.h>
#include <asm-generic/pci-dma-compat.h>
/* ETRAX chips don't have a PCI bus. This file is just here because some stupid .c code /* ETRAX chips don't have a PCI bus. This file is just here because some stupid .c code
* includes it even if CONFIG_PCI is not set. * includes it even if CONFIG_PCI is not set.
*/ */
#define PCI_DMA_BUS_IS_PHYS (1)
#endif /* __ASM_CRIS_PCI_H */ #endif /* __ASM_CRIS_PCI_H */
...@@ -5,9 +5,11 @@ ...@@ -5,9 +5,11 @@
#ifndef _CRIS_PGTABLE_H #ifndef _CRIS_PGTABLE_H
#define _CRIS_PGTABLE_H #define _CRIS_PGTABLE_H
#ifndef __ASSEMBLY__
#include <linux/config.h> #include <linux/config.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#endif
#include <asm/arch/pgtable.h> #include <asm/arch/pgtable.h>
/* /*
...@@ -21,8 +23,9 @@ ...@@ -21,8 +23,9 @@
* This file contains the functions and defines necessary to modify and use * This file contains the functions and defines necessary to modify and use
* the CRIS page table tree. * the CRIS page table tree.
*/ */
#ifndef __ASSEMBLY__
extern void paging_init(void); extern void paging_init(void);
#endif
/* Certain architectures need to do special things when pte's /* Certain architectures need to do special things when pte's
* within a page table are directly modified. Thus, the following * within a page table are directly modified. Thus, the following
...@@ -72,8 +75,10 @@ extern void paging_init(void); ...@@ -72,8 +75,10 @@ extern void paging_init(void);
#define FIRST_USER_PGD_NR 0 #define FIRST_USER_PGD_NR 0
/* zero page used for uninitialized stuff */ /* zero page used for uninitialized stuff */
#ifndef __ASSEMBLY__
extern unsigned long empty_zero_page; extern unsigned long empty_zero_page;
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
#endif
/* number of bits that fit into a memory pointer */ /* number of bits that fit into a memory pointer */
#define BITS_PER_PTR (8*sizeof(unsigned long)) #define BITS_PER_PTR (8*sizeof(unsigned long))
...@@ -104,6 +109,8 @@ extern unsigned long empty_zero_page; ...@@ -104,6 +109,8 @@ extern unsigned long empty_zero_page;
#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) #define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT)
#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) #define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0)
#ifndef __ASSEMBLY__
/* /*
* The "pgd_xxx()" functions here are trivial for a folded two-level * The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pgd is never bad, and a pmd always exists (as it's folded * setup: the pgd is never bad, and a pmd always exists (as it's folded
...@@ -337,4 +344,5 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma, ...@@ -337,4 +344,5 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma,
#define pte_to_pgoff(x) (pte_val(x) >> 6) #define pte_to_pgoff(x) (pte_val(x) >> 6)
#define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE) #define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE)
#endif /* __ASSEMBLY__ */
#endif /* _CRIS_PGTABLE_H */ #endif /* _CRIS_PGTABLE_H */
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
#include <asm/arch/ptrace.h> #include <asm/arch/ptrace.h>
#ifdef __KERNEL__
/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
#define PTRACE_GETREGS 12 #define PTRACE_GETREGS 12
#define PTRACE_SETREGS 13 #define PTRACE_SETREGS 13
#endif
#endif /* _CRIS_PTRACE_H */ #endif /* _CRIS_PTRACE_H */
...@@ -100,6 +100,8 @@ struct rtc_time { ...@@ -100,6 +100,8 @@ struct rtc_time {
#define RTC_RD_TIME _IOR(RTC_MAGIC, 0x09, struct rtc_time) /* Read RTC time. */ #define RTC_RD_TIME _IOR(RTC_MAGIC, 0x09, struct rtc_time) /* Read RTC time. */
#define RTC_SET_TIME _IOW(RTC_MAGIC, 0x0a, struct rtc_time) /* Set RTC time. */ #define RTC_SET_TIME _IOW(RTC_MAGIC, 0x0a, struct rtc_time) /* Set RTC time. */
#define RTC_SET_CHARGE _IOW(RTC_MAGIC, 0x0b, int) #define RTC_SET_CHARGE _IOW(RTC_MAGIC, 0x0b, int)
#define RTC_MAX_IOCTL 0x0b #define RTC_VLOW_RD _IOR(RTC_MAGIC, 0x11, int) /* Voltage Low detector */
#define RTC_VLOW_SET _IO(RTC_MAGIC, 0x12) /* Clear voltage low information */
#define RTC_MAX_IOCTL 0x12
#endif /* __RTC_H__ */ #endif /* __RTC_H__ */
#ifndef _CRIS_SECTIONS_H
#define _CRIS_SECTIONS_H
/* nothing to see, move along */
#include <asm-generic/sections.h>
#endif
...@@ -52,7 +52,7 @@ extern inline int waking_non_zero_interruptible(struct semaphore *sem, ...@@ -52,7 +52,7 @@ extern inline int waking_non_zero_interruptible(struct semaphore *sem,
dec(&sem->waking); dec(&sem->waking);
ret = 1; ret = 1;
} else if (signal_pending(tsk)) { } else if (signal_pending(tsk)) {
count_inc(&sem->count); inc(&sem->count);
ret = -EINTR; ret = -EINTR;
} }
local_irq_restore(flags); local_irq_restore(flags);
...@@ -67,7 +67,7 @@ extern inline int waking_non_zero_trylock(struct semaphore *sem) ...@@ -67,7 +67,7 @@ extern inline int waking_non_zero_trylock(struct semaphore *sem)
local_save_flags(flags); local_save_flags(flags);
local_irq_disable(); local_irq_disable();
if (read(&sem->waking) <= 0) if (read(&sem->waking) <= 0)
count_inc(&sem->count); inc(&sem->count);
else { else {
dec(&sem->waking); dec(&sem->waking);
ret = 0; ret = 0;
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
int printk(const char *fmt, ...); int printk(const char *fmt, ...);
struct semaphore { struct semaphore {
int count; /* not atomic_t since we do the atomicity here already */ atomic_t count;
atomic_t waking; atomic_t waking;
wait_queue_head_t wait; wait_queue_head_t wait;
#if WAITQUEUE_DEBUG #if WAITQUEUE_DEBUG
...@@ -36,7 +36,7 @@ struct semaphore { ...@@ -36,7 +36,7 @@ struct semaphore {
#endif #endif
#define __SEMAPHORE_INITIALIZER(name,count) \ #define __SEMAPHORE_INITIALIZER(name,count) \
{ count, ATOMIC_INIT(0), \ { ATOMIC_INIT(count), ATOMIC_INIT(0), \
__WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
__SEM_DEBUG_INIT(name) } __SEM_DEBUG_INIT(name) }
...@@ -84,7 +84,7 @@ extern inline void down(struct semaphore * sem) ...@@ -84,7 +84,7 @@ extern inline void down(struct semaphore * sem)
/* atomically decrement the semaphores count, and if its negative, we wait */ /* atomically decrement the semaphores count, and if its negative, we wait */
local_save_flags(flags); local_save_flags(flags);
local_irq_disable(); local_irq_disable();
failed = --(sem->count) < 0; failed = --(sem->count.counter) < 0;
local_irq_restore(flags); local_irq_restore(flags);
if(failed) { if(failed) {
__down(sem); __down(sem);
...@@ -110,7 +110,7 @@ extern inline int down_interruptible(struct semaphore * sem) ...@@ -110,7 +110,7 @@ extern inline int down_interruptible(struct semaphore * sem)
/* atomically decrement the semaphores count, and if its negative, we wait */ /* atomically decrement the semaphores count, and if its negative, we wait */
local_save_flags(flags); local_save_flags(flags);
local_irq_disable(); local_irq_disable();
failed = --(sem->count) < 0; failed = --(sem->count.counter) < 0;
local_irq_restore(flags); local_irq_restore(flags);
if(failed) if(failed)
failed = __down_interruptible(sem); failed = __down_interruptible(sem);
...@@ -128,7 +128,7 @@ extern inline int down_trylock(struct semaphore * sem) ...@@ -128,7 +128,7 @@ extern inline int down_trylock(struct semaphore * sem)
local_save_flags(flags); local_save_flags(flags);
local_irq_disable(); local_irq_disable();
failed = --(sem->count) < 0; failed = --(sem->count.counter) < 0;
local_irq_restore(flags); local_irq_restore(flags);
if(failed) if(failed)
failed = __down_trylock(sem); failed = __down_trylock(sem);
...@@ -153,7 +153,7 @@ extern inline void up(struct semaphore * sem) ...@@ -153,7 +153,7 @@ extern inline void up(struct semaphore * sem)
/* atomically increment the semaphores count, and if it was negative, we wake people */ /* atomically increment the semaphores count, and if it was negative, we wake people */
local_save_flags(flags); local_save_flags(flags);
local_irq_disable(); local_irq_disable();
wakeup = ++(sem->count) <= 0; wakeup = ++(sem->count.counter) <= 0;
local_irq_restore(flags); local_irq_restore(flags);
if(wakeup) { if(wakeup) {
__up(sem); __up(sem);
......
...@@ -154,7 +154,7 @@ struct termios { ...@@ -154,7 +154,7 @@ struct termios {
#define B6250000 0010007 #define B6250000 0010007
/* etrax 200 supports this as well */ /* etrax 200 supports this as well */
#define B12500000 0010010 #define B12500000 0010010
#define CIBAUD 002003600000 /* input baud rate */ #define CIBAUD 002003600000 /* input baud rate (used in v32) */
/* The values for CIBAUD bits are the same as the values for CBAUD and CBAUDEX /* The values for CIBAUD bits are the same as the values for CBAUD and CBAUDEX
* shifted left IBSHIFT bits. * shifted left IBSHIFT bits.
*/ */
......
...@@ -50,6 +50,7 @@ typedef unsigned long long u64; ...@@ -50,6 +50,7 @@ typedef unsigned long long u64;
/* Dma addresses are 32-bits wide, just like our other addresses. */ /* Dma addresses are 32-bits wide, just like our other addresses. */
typedef u32 dma_addr_t; typedef u32 dma_addr_t;
typedef u32 dma64_addr_t;
typedef unsigned int kmem_bufctl_t; typedef unsigned int kmem_bufctl_t;
......
...@@ -275,8 +275,21 @@ ...@@ -275,8 +275,21 @@
#define __NR_clock_nanosleep (__NR_timer_create+8) #define __NR_clock_nanosleep (__NR_timer_create+8)
#define __NR_statfs64 268 #define __NR_statfs64 268
#define __NR_fstatfs64 269 #define __NR_fstatfs64 269
#define __NR_tgkill 270
#define __NR_utimes 271
#define __NR_fadvise64_64 272
#define __NR_vserver 273
#define __NR_mbind 274
#define __NR_get_mempolicy 275
#define __NR_set_mempolicy 276
#define __NR_mq_open 277
#define __NR_mq_unlink (__NR_mq_open+1)
#define __NR_mq_timedsend (__NR_mq_open+2)
#define __NR_mq_timedreceive (__NR_mq_open+3)
#define __NR_mq_notify (__NR_mq_open+4)
#define __NR_mq_getsetattr (__NR_mq_open+5)
#define NR_syscalls 270 #define NR_syscalls 283
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -307,6 +320,7 @@ ...@@ -307,6 +320,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/linkage.h>
/* /*
* we need this inline - forking from kernel space will result * we need this inline - forking from kernel space will result
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment