diff options
172 files changed, 12012 insertions, 15132 deletions
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index b092fb53d4cb..05fb1fe7620f 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -42,9 +42,9 @@ config ETRAX_KGDB this option is turned on! config ETRAX_WATCHDOG - bool "Enable Etrax100 watchdog" + bool "Enable ETRAX watchdog" help - Enable the built-in watchdog timer support on Etrax100 embedded + Enable the built-in watchdog timer support on ETRAX based embedded network computers. config ETRAX_WATCHDOG_NICE_DOGGY @@ -55,6 +55,26 @@ config ETRAX_WATCHDOG_NICE_DOGGY printing oopses. Recommended for development systems but not for production releases. +config ETRAX_FAST_TIMER + bool "Enable ETRAX fast timer API" + help + This options enables the API to a fast timer implementation using + timer1 to get sub jiffie resolution timers (primarily one-shot + timers). + This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled. + +config PREEMPT + bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + endmenu @@ -65,32 +85,36 @@ choice default ETRAX100LX config ETRAX100LX - bool "Etrax-100-LX-v1" + bool "ETRAX-100LX-v1" help - Support version 1 of the Etrax 100LX. + Support version 1 of the ETRAX 100LX. config ETRAX100LX_V2 - bool "Etrax-100-LX-v2" + bool "ETRAX-100LX-v2" help - Support version 2 of the Etrax 100LX. + Support version 2 of the ETRAX 100LX. config SVINTO_SIM - bool "Etrax-100-LX-for-xsim-simulator" + bool "ETRAX-100LX-for-xsim-simulator" help Support the xsim ETRAX Simulator. +config ETRAX200LX + bool "ETRAX-200LX-V32" + help + Support CRIS V32. + endchoice -# Etrax100 LX v1 has a MMU "feature" requiring a low mapping -config CRIS_LOW_MAP - bool - depends on ETRAX100LX - default y +config ETRAX_ARCH_V10 + bool + default y if ETRAX100LX || ETRAX100LX_V2 + default n if !(ETRAX100LX || ETRAX100LX_V2) -config ETRAX_DRAM_VIRTUAL_BASE - hex - default "c0000000" if !ETRAX100LX - default "60000000" if ETRAX100LX +config ETRAX_ARCH_V32 + bool + default y if ETRAX200LX + default n if !(ETRAX200LX) config ETRAX_DRAM_SIZE int "DRAM size (dec, in MB)" @@ -114,404 +138,17 @@ config ETRAX_ROOT_DEVICE should normally be the mtdblock device for the partition after the last partition in the partition table. -choice - prompt "Product LED port" - default ETRAX_PA_LEDS - -config ETRAX_PA_LEDS - bool "Port-PA-LEDs" - help - The Etrax network driver is responsible for flashing LED's when - packets arrive and are sent. It uses macros defined in - <file:include/asm-cris/io.h>, and those macros are defined after what - YOU choose in this option. The actual bits used are configured - separately. Select this if the LEDs are on port PA. Some products - put the leds on PB or a memory-mapped latch (CSP0) instead. - -config ETRAX_PB_LEDS - bool "Port-PB-LEDs" - help - The Etrax network driver is responsible for flashing LED's when - packets arrive and are sent. It uses macros defined in - <file:include/asm-cris/io.h>, and those macros are defined after what - YOU choose in this option. The actual bits used are configured - separately. Select this if the LEDs are on port PB. Some products - put the leds on PA or a memory-mapped latch (CSP0) instead. - -config ETRAX_CSP0_LEDS - bool "Port-CSP0-LEDs" - help - The Etrax network driver is responsible for flashing LED's when - packets arrive and are sent. It uses macros defined in - <file:include/asm-cris/io.h>, and those macros are defined after what - YOU choose in this option. The actual bits used are configured - separately. Select this if the LEDs are on a memory-mapped latch - using chip select CSP0, this is mapped at 0x90000000. - Some products put the leds on PA or PB instead. - -config ETRAX_NO_LEDS - bool "None" - help - Select this option if you don't have any LED at all. - -endchoice - -config ETRAX_LED1G - int "First green LED bit" - depends on !ETRAX_NO_LEDS - default "2" - help - Bit to use for the first green LED. - Most Axis products use bit 2 here. - -config ETRAX_LED1R - int "First red LED bit" - depends on !ETRAX_NO_LEDS - default "3" - help - Bit to use for the first red LED. - Most Axis products use bit 3 here. - For products with only one controllable LED, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED2G - int "Second green LED bit" - depends on !ETRAX_NO_LEDS - default "4" - help - Bit to use for the second green LED. The "Active" LED. - Most Axis products use bit 4 here. - For products with only one controllable LED, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED2R - int "Second red LED bit" - depends on !ETRAX_NO_LEDS - default "5" - help - Bit to use for the second red LED. - Most Axis products use bit 5 here. - For products with only one controllable LED, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED3G - int "Third green LED bit" - depends on !ETRAX_NO_LEDS - default "2" - help - Bit to use for the third green LED. The "Drive" LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED3R - int "Third red LED bit" - depends on !ETRAX_NO_LEDS - default "2" - help - Bit to use for the third red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED4R - int "Fourth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fourth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED4G - int "Fourth green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fourth green LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). +# duplicate choice configs are not yet supported, so the followinguse +# doesn't work: -config ETRAX_LED5R - int "Fifth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fifth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). +source arch/cris/arch-v10/Kconfig -config ETRAX_LED5G - int "Fifth green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the fifth green LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED6R - int "Sixth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the sixth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED6G - int "Sixth green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the sixth green LED. The "Drive" LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED7R - int "Seventh red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the seventh red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED7G - int "Seventh green LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the seventh green LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED8Y - int "Eigth yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the eighth yellow LED. The "Drive" LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED9Y - int "Ninth yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the ninth yellow LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED10Y - int "Tenth yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the tenth yellow LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED11Y - int "Eleventh yellow LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the eleventh yellow LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -config ETRAX_LED12R - int "Twelfth red LED bit" - depends on ETRAX_CSP0_LEDS - default "2" - help - Bit to use for the twelfth red LED. - For products with only one or two controllable LEDs, - set this to same as CONFIG_ETRAX_LED1G (normally 2). - -choice - prompt "Product debug-port" - default ETRAX_DEBUG_PORT0 - -config ETRAX_DEBUG_PORT0 - bool "Serial-0" - help - Choose a serial port for the ETRAX debug console. Default to - port 0. - -config ETRAX_DEBUG_PORT1 - bool "Serial-1" - help - Use serial port 1 for the console. - -config ETRAX_DEBUG_PORT2 - bool "Serial-2" - help - Use serial port 2 for the console. - -config ETRAX_DEBUG_PORT3 - bool "Serial-3" - help - Use serial port 3 for the console. - -config ETRAX_DEBUG_PORT_NULL - bool "disabled" - help - Disable serial-port debugging. - -endchoice - -choice - prompt "Product rescue-port" - default ETRAX_RESCUE_SER0 - -config ETRAX_RESCUE_SER0 - bool "Serial-0" - help - Select one of the four serial ports as a rescue port. The default - is port 0. - -config ETRAX_RESCUE_SER1 - bool "Serial-1" - help - Use serial port 1 as the rescue port. - -config ETRAX_RESCUE_SER2 - bool "Serial-2" - help - Use serial port 2 as the rescue port. - -config ETRAX_RESCUE_SER3 - bool "Serial-3" - help - Use serial port 3 as the rescue port. - -endchoice - -config ETRAX_DEF_R_WAITSTATES - hex "R_WAITSTATES" - default "95a6" - help - Waitstates for SRAM, Flash and peripherials (not DRAM). 95f8 is a - good choice for most Axis products... - -config ETRAX_DEF_R_BUS_CONFIG - hex "R_BUS_CONFIG" - default "104" - help - Assorted bits controlling write mode, DMA burst length etc. 104 is - a good choice for most Axis products... - -config ETRAX_SDRAM - bool "SDRAM support" - help - Enable this if you use SDRAM chips and configure - R_SDRAM_CONFIG and R_SDRAM_TIMING as well. - -config ETRAX_DEF_R_DRAM_CONFIG - hex "R_DRAM_CONFIG" - depends on !ETRAX_SDRAM - default "1a200040" - help - The R_DRAM_CONFIG register specifies everything on how the DRAM - chips in the system are connected to the Etrax CPU. This is - different depending on the manufacturer, chip type and number of - chips. So this value often needs to be different for each Axis - product. - -config ETRAX_DEF_R_DRAM_TIMING - hex "R_DRAM_TIMING" - depends on !ETRAX_SDRAM - default "5611" - help - Different DRAM chips have different speeds. Current Axis products - use 50ns DRAM chips which can use the timing: 5611. - -config ETRAX_DEF_R_SDRAM_CONFIG - hex "R_SDRAM_CONFIG" - depends on ETRAX_SDRAM - default "d2fa7878" - help - The R_SDRAM_CONFIG register specifies everything on how the SDRAM - chips in the system are connected to the Etrax CPU. This is - different depending on the manufacturer, chip type and number of - chips. So this value often needs to be different for each Axis - product. - -config ETRAX_DEF_R_SDRAM_TIMING - hex "R_SDRAM_TIMING" - depends on ETRAX_SDRAM - default "80004801" - help - Different SDRAM chips have different timing. - -config ETRAX_DEF_R_PORT_PA_DIR - hex "R_PORT_PA_DIR" - default "1c" - help - Configures the direction of general port A bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_R_PORT_PA_DATA - hex "R_PORT_PA_DATA" - default "00" - help - Configures the initial data for the general port A bits. Most - products should use 00 here. - -config ETRAX_DEF_R_PORT_PB_CONFIG - hex "R_PORT_PB_CONFIG" - default "00" - help - Configures the type of the general port B bits. 1 is chip select, - 0 is port. Most products should use 00 here. +endmenu -config ETRAX_DEF_R_PORT_PB_DIR - hex "R_PORT_PB_DIR" - default "00" - help - Configures the direction of general port B bits. 1 is out, 0 is in. - This is often totally different depending on the product used. Bits - 0 and 1 on port PB are usually used for I2C communication, but the - kernel I2C driver sets the appropriate directions itself so you - don't need to take that into consideration when setting this option. - If you don't know what to use, it is always safe to put all as - inputs. - -config ETRAX_DEF_R_PORT_PB_DATA - hex "R_PORT_PB_DATA" - default "ff" - help - Configures the initial data for the general port A bits. Most - products should use FF here. +# bring in ETRAX built-in drivers +menu "Drivers for built-in interfaces" -config ETRAX_SOFT_SHUTDOWN - bool "Software Shutdown Support" - help - Enable this if Etrax is used with a power-supply that can be turned - off and on with PS_ON signal. Gives the possibility to detect - powerbutton and then do a power off after unmounting disks. - -config ETRAX_SHUTDOWN_BIT - int "Shutdown bit on port CSP0" - depends on ETRAX_SOFT_SHUTDOWN - default "12" - help - Configure what pin on CSPO-port that is used for controlling power - supply. - -config ETRAX_POWERBUTTON_BIT - int "Power button bit on port G" - depends on ETRAX_SOFT_SHUTDOWN - default "25" - help - Configure where power button is connected. +source arch/cris/arch-v10/drivers/Kconfig endmenu diff --git a/arch/cris/Makefile b/arch/cris/Makefile index 94c3671bdf5c..3a1a7d919725 100644 --- a/arch/cris/Makefile +++ b/arch/cris/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.3 2002/01/21 15:21:23 bjornw Exp $ +# $Id: Makefile,v 1.15 2003/07/04 12:47:53 tobiasa Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -13,37 +13,40 @@ # A bug in ld prevents us from having a (constant-value) symbol in a # "ORIGIN =" or "LENGTH =" expression. -LD = $(CROSS_COMPILE)ld -mcrislinux +arch-y := v10 +arch-$(CONFIG_ETRAX_ARCH_V10) := v10 + +# No config avaiable for make clean etc +ifneq ($(arch-y),) +SARCH := arch-$(arch-y) +else +SARCH := +endif -# objcopy is used to make binary images from the resulting linked file +LD = $(CROSS_COMPILE)ld -mcrislinux +LDFLAGS_BLOB := --format binary --oformat elf32-cris \ + -T arch/cris/$(SARCH)/output_arch.ld OBJCOPYFLAGS := -O binary -R .note -R .comment -S -# -mlinux enables -march=v10, -fno-underscores, -D__linux__ among others +AFLAGS_vmlinux.lds.o = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) +AFLAGS += -mlinux -CFLAGS := $(CFLAGS) -mlinux -pipe +CFLAGS := $(CFLAGS) -mlinux -march=$(arch-y) -pipe ifdef CONFIG_ETRAX_KGDB CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g CFLAGS += -fno-omit-frame-pointer endif -AFLAGS += -mlinux +HEAD := arch/$(ARCH)/$(SARCH)/kernel/head.o -HEAD := arch/cris/kernel/head.o - -ifdef CONFIG_ETRAX_AXISFLASHMAP -# only build this if axis flash map is used, because they depend on -# each others config options -SUBDIRS += arch/cris/boot/rescue -endif LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) -core-y += arch/cris/kernel/ arch/cris/mm/ -drivers-y += arch/cris/drivers/ -libs-y += arch/cris/lib/lib.a $(LIBGCC) - -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot +core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ +core-y += arch/$(ARCH)/$(SARCH)/kernel/ arch/$(ARCH)/$(SARCH)/mm/ +drivers-y += arch/$(ARCH)/$(SARCH)/drivers/ +libs-y += arch/$(ARCH)/$(SARCH)/lib/ $(LIBGCC) vmlinux.bin: vmlinux $(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin @@ -65,20 +68,43 @@ cramfs: clinux: vmlinux.bin decompress.bin rescue.bin decompress.bin: FORCE - @make -C arch/cris/boot/compressed decompress.bin + @make -C arch/$(ARCH)/boot/compressed decompress.bin rescue.bin: FORCE - @make -C arch/cris/boot/rescue rescue.bin + @make -C arch/$(ARCH)/boot/rescue rescue.bin -zImage: vmlinux.bin +zImage: vmlinux.bin rescue.bin ## zImage - Compressed kernel (gzip) - @$(MAKEBOOT) zImage + @make -C arch/$(ARCH)/boot/ zImage compressed: zImage +archmrproper: archclean: - @$(MAKEBOOT) clean + $(Q)$(MAKE) -f scripts/Makefile.clean obj=arch/$(ARCH)/boot rm -f timage vmlinux.bin cramfs.img rm -rf $(LD_SCRIPT).tmp -archmrproper: +prepare: arch/$(ARCH)/.links include/asm-$(ARCH)/.arch \ + include/asm-$(ARCH)/$(SARCH)/offset.h + +# Create some links to make all tools happy +arch/$(ARCH)/.links: + @ln -sfn $(SARCH)/drivers arch/$(ARCH)/drivers + @ln -sfn $(SARCH)/boot arch/$(ARCH)/boot + @ln -sfn $(SARCH)/lib arch/$(ARCH)/lib + @ln -sfn $(SARCH)/vmlinux.lds.S arch/$(ARCH)/vmlinux.lds.S + @touch $@ + +# Create link to sub arch includes +include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h) + @echo ' Making asm-$(ARCH)/arch -> asm-$(ARCH)/$(SARCH) symlink' + @rm -f include/asm-$(ARCH)/arch + @ln -sf $(SARCH) include/asm-$(ARCH)/arch + @touch $@ + +arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ + include/config/MARKER + +include/asm-$(ARCH)/$(SARCH)/offset.h: arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s + $(call filechk,gen-asm-offsets) diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig new file mode 100644 index 000000000000..2ca64cc40c63 --- /dev/null +++ b/arch/cris/arch-v10/Kconfig @@ -0,0 +1,422 @@ +# ETRAX 100LX v1 has a MMU "feature" requiring a low mapping +config CRIS_LOW_MAP + bool + depends on ETRAX_ARCH_V10 && ETRAX100LX + default y + +config ETRAX_DRAM_VIRTUAL_BASE + hex + depends on ETRAX_ARCH_V10 + default "c0000000" if !ETRAX100LX + default "60000000" if ETRAX100LX + +choice + prompt "Product LED port" + depends on ETRAX_ARCH_V10 + default ETRAX_PA_LEDS + +config ETRAX_PA_LEDS + bool "Port-PA-LEDs" + help + The ETRAX network driver is responsible for flashing LED's when + packets arrive and are sent. It uses macros defined in + <file:include/asm-cris/io.h>, and those macros are defined after what + YOU choose in this option. The actual bits used are configured + separately. Select this if the LEDs are on port PA. Some products + put the leds on PB or a memory-mapped latch (CSP0) instead. + +config ETRAX_PB_LEDS + bool "Port-PB-LEDs" + help + The ETRAX network driver is responsible for flashing LED's when + packets arrive and are sent. It uses macros defined in + <file:include/asm-cris/io.h>, and those macros are defined after what + YOU choose in this option. The actual bits used are configured + separately. Select this if the LEDs are on port PB. Some products + put the leds on PA or a memory-mapped latch (CSP0) instead. + +config ETRAX_CSP0_LEDS + bool "Port-CSP0-LEDs" + help + The ETRAX network driver is responsible for flashing LED's when + packets arrive and are sent. It uses macros defined in + <file:include/asm-cris/io.h>, and those macros are defined after what + YOU choose in this option. The actual bits used are configured + separately. Select this if the LEDs are on a memory-mapped latch + using chip select CSP0, this is mapped at 0x90000000. + Some products put the leds on PA or PB instead. + +config ETRAX_NO_LEDS + bool "None" + help + Select this option if you don't have any LED at all. + +endchoice + +config ETRAX_LED1G + int "First green LED bit" + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS + default "2" + help + Bit to use for the first green LED. + Most Axis products use bit 2 here. + +config ETRAX_LED1R + int "First red LED bit" + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS + default "3" + help + Bit to use for the first red LED. + Most Axis products use bit 3 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED2G + int "Second green LED bit" + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS + default "4" + help + Bit to use for the second green LED. The "Active" LED. + Most Axis products use bit 4 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED2R + int "Second red LED bit" + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS + default "5" + help + Bit to use for the second red LED. + Most Axis products use bit 5 here. + For products with only one controllable LED, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED3G + int "Third green LED bit" + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS + default "2" + help + Bit to use for the third green LED. The "Drive" LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED3R + int "Third red LED bit" + depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS + default "2" + help + Bit to use for the third red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED4R + int "Fourth red LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the fourth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED4G + int "Fourth green LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the fourth green LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED5R + int "Fifth red LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the fifth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED5G + int "Fifth green LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the fifth green LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED6R + int "Sixth red LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the sixth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED6G + int "Sixth green LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the sixth green LED. The "Drive" LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED7R + int "Seventh red LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the seventh red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED7G + int "Seventh green LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the seventh green LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED8Y + int "Eigth yellow LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the eighth yellow LED. The "Drive" LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED9Y + int "Ninth yellow LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the ninth yellow LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED10Y + int "Tenth yellow LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the tenth yellow LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED11Y + int "Eleventh yellow LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the eleventh yellow LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +config ETRAX_LED12R + int "Twelfth red LED bit" + depends on ETRAX_CSP0_LEDS + default "2" + help + Bit to use for the twelfth red LED. + For products with only one or two controllable LEDs, + set this to same as CONFIG_ETRAX_LED1G (normally 2). + +choice + prompt "Product debug-port" + depends on ETRAX_ARCH_V10 + default ETRAX_DEBUG_PORT0 + +config ETRAX_DEBUG_PORT0 + bool "Serial-0" + help + Choose a serial port for the ETRAX debug console. Default to + port 0. + +config ETRAX_DEBUG_PORT1 + bool "Serial-1" + help + Use serial port 1 for the console. + +config ETRAX_DEBUG_PORT2 + bool "Serial-2" + help + Use serial port 2 for the console. + +config ETRAX_DEBUG_PORT3 + bool "Serial-3" + help + Use serial port 3 for the console. + +config ETRAX_DEBUG_PORT_NULL + bool "disabled" + help + Disable serial-port debugging. + +endchoice + +choice + prompt "Product rescue-port" + depends on ETRAX_ARCH_V10 + default ETRAX_RESCUE_SER0 + +config ETRAX_RESCUE_SER0 + bool "Serial-0" + help + Select one of the four serial ports as a rescue port. The default + is port 0. + +config ETRAX_RESCUE_SER1 + bool "Serial-1" + help + Use serial port 1 as the rescue port. + +config ETRAX_RESCUE_SER2 + bool "Serial-2" + help + Use serial port 2 as the rescue port. + +config ETRAX_RESCUE_SER3 + bool "Serial-3" + help + Use serial port 3 as the rescue port. + +endchoice + +config ETRAX_DEF_R_WAITSTATES + hex "R_WAITSTATES" + depends on ETRAX_ARCH_V10 + default "95a6" + help + Waitstates for SRAM, Flash and peripherials (not DRAM). 95f8 is a + good choice for most Axis products... + +config ETRAX_DEF_R_BUS_CONFIG + hex "R_BUS_CONFIG" + depends on ETRAX_ARCH_V10 + default "104" + help + Assorted bits controlling write mode, DMA burst length etc. 104 is + a good choice for most Axis products... + +config ETRAX_SDRAM + bool "SDRAM support" + depends on ETRAX_ARCH_V10 + help + Enable this if you use SDRAM chips and configure + R_SDRAM_CONFIG and R_SDRAM_TIMING as well. + +config ETRAX_DEF_R_DRAM_CONFIG + hex "R_DRAM_CONFIG" + depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM + default "1a200040" + help + The R_DRAM_CONFIG register specifies everything on how the DRAM + chips in the system are connected to the ETRAX CPU. This is + different depending on the manufacturer, chip type and number of + chips. So this value often needs to be different for each Axis + product. + +config ETRAX_DEF_R_DRAM_TIMING + hex "R_DRAM_TIMING" + depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM + default "5611" + help + Different DRAM chips have different speeds. Current Axis products + use 50ns DRAM chips which can use the timing: 5611. + +config ETRAX_DEF_R_SDRAM_CONFIG + hex "R_SDRAM_CONFIG" + depends on ETRAX_ARCH_V10 && ETRAX_SDRAM + default "d2fa7878" + help + The R_SDRAM_CONFIG register specifies everything on how the SDRAM + chips in the system are connected to the ETRAX CPU. This is + different depending on the manufacturer, chip type and number of + chips. So this value often needs to be different for each Axis + product. + +config ETRAX_DEF_R_SDRAM_TIMING + hex "R_SDRAM_TIMING" + depends on ETRAX_ARCH_V10 && ETRAX_SDRAM + default "80004801" + help + Different SDRAM chips have different timing. + +config ETRAX_DEF_R_PORT_PA_DIR + hex "R_PORT_PA_DIR" + depends on ETRAX_ARCH_V10 + default "1c" + help + Configures the direction of general port A bits. 1 is out, 0 is in. + This is often totally different depending on the product used. + There are some guidelines though - if you know that only LED's are + connected to port PA, then they are usually connected to bits 2-4 + and you can therefore use 1c. On other boards which don't have the + LED's at the general ports, these bits are used for all kinds of + stuff. If you don't know what to use, it is always safe to put all + as inputs, although floating inputs isn't good. + +config ETRAX_DEF_R_PORT_PA_DATA + hex "R_PORT_PA_DATA" + depends on ETRAX_ARCH_V10 + default "00" + help + Configures the initial data for the general port A bits. Most + products should use 00 here. + +config ETRAX_DEF_R_PORT_PB_CONFIG + hex "R_PORT_PB_CONFIG" + depends on ETRAX_ARCH_V10 + default "00" + help + Configures the type of the general port B bits. 1 is chip select, + 0 is port. Most products should use 00 here. + +config ETRAX_DEF_R_PORT_PB_DIR + hex "R_PORT_PB_DIR" + depends on ETRAX_ARCH_V10 + default "00" + help + Configures the direction of general port B bits. 1 is out, 0 is in. + This is often totally different depending on the product used. Bits + 0 and 1 on port PB are usually used for I2C communication, but the + kernel I2C driver sets the appropriate directions itself so you + don't need to take that into consideration when setting this option. + If you don't know what to use, it is always safe to put all as + inputs. + +config ETRAX_DEF_R_PORT_PB_DATA + hex "R_PORT_PB_DATA" + depends on ETRAX_ARCH_V10 + default "ff" + help + Configures the initial data for the general port A bits. Most + products should use FF here. + +config ETRAX_SOFT_SHUTDOWN + bool "Software Shutdown Support" + depends on ETRAX_ARCH_V10 + help + Enable this if ETRAX is used with a power-supply that can be turned + off and on with PS_ON signal. Gives the possibility to detect + powerbutton and then do a power off after unmounting disks. + +config ETRAX_SHUTDOWN_BIT + int "Shutdown bit on port CSP0" + depends on ETRAX_SOFT_SHUTDOWN + default "12" + help + Configure what pin on CSPO-port that is used for controlling power + supply. + +config ETRAX_POWERBUTTON_BIT + int "Power button bit on port G" + depends on ETRAX_SOFT_SHUTDOWN + default "25" + help + Configure where power button is connected. diff --git a/arch/cris/README.mm b/arch/cris/arch-v10/README.mm index 195ca898b55b..6f08903f3139 100644 --- a/arch/cris/README.mm +++ b/arch/cris/arch-v10/README.mm @@ -3,8 +3,8 @@ Memory management for CRIS/MMU HISTORY: $Log: README.mm,v $ -Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -Import of Linux 2.5.1 +Revision 1.1 2001/12/17 13:59:27 bjornw +Initial revision Revision 1.1 2000/07/10 16:25:21 bjornw Initial revision diff --git a/arch/cris/boot/Makefile b/arch/cris/arch-v10/boot/Makefile index fe6650368e6a..fe6650368e6a 100644 --- a/arch/cris/boot/Makefile +++ b/arch/cris/arch-v10/boot/Makefile diff --git a/arch/cris/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile index 5f71c2c819e6..5f71c2c819e6 100644 --- a/arch/cris/boot/compressed/Makefile +++ b/arch/cris/arch-v10/boot/compressed/Makefile diff --git a/arch/cris/boot/compressed/README b/arch/cris/arch-v10/boot/compressed/README index 349eb2ab4663..48b3db9924b9 100644 --- a/arch/cris/boot/compressed/README +++ b/arch/cris/arch-v10/boot/compressed/README @@ -1,6 +1,6 @@ Creation of the self-extracting compressed kernel image (vmlinuz) ----------------------------------------------------------------- -$Id: README,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +$Id: README,v 1.1 2001/12/17 13:59:27 bjornw Exp $ This can be slightly confusing because it's a process with many steps. diff --git a/arch/cris/boot/compressed/decompress.ld b/arch/cris/arch-v10/boot/compressed/decompress.ld index 24be54924970..0b0a14fe6177 100644 --- a/arch/cris/boot/compressed/decompress.ld +++ b/arch/cris/arch-v10/boot/compressed/decompress.ld @@ -13,6 +13,7 @@ SECTIONS _stext = . ; *(.text) *(.rodata) + *(.rodata.*) _etext = . ; } > dram .data : diff --git a/arch/cris/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S index 84719ff14401..4cbdd4b1d9d6 100644 --- a/arch/cris/boot/compressed/head.S +++ b/arch/cris/arch-v10/boot/compressed/head.S @@ -10,7 +10,7 @@ #include <linux/config.h> #define ASSEMBLER_MACROS_ONLY -#include <asm/sv_addr_ag.h> +#include <asm/arch/sv_addr_ag.h> #define RAM_INIT_MAGIC 0x56902387 diff --git a/arch/cris/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c index 906610b45625..9969c6242f75 100644 --- a/arch/cris/boot/compressed/misc.c +++ b/arch/cris/arch-v10/boot/compressed/misc.c @@ -1,7 +1,7 @@ /* * misc.c * - * $Id: misc.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ + * $Id: misc.c,v 1.4 2003/04/09 05:20:45 starvik Exp $ * * This is a collection of several routines from gzip-1.0.3 * adapted for Linux. @@ -15,7 +15,7 @@ /* where the piggybacked kernel image expects itself to live. * it is the same address we use when we network load an uncompressed * image into DRAM, and it is the address the kernel is linked to live - * at by etrax100.ld. + * at by vmlinux.lds.S */ #define KERNEL_LOAD_ADR 0x40004000 @@ -23,7 +23,7 @@ #include <linux/config.h> #include <linux/types.h> -#include <asm/svinto.h> +#include <asm/arch/svinto.h> /* * gzip declarations @@ -109,7 +109,7 @@ static void puts(const char *); extern int end; static long free_mem_ptr = (long)&end; -#include "../../../../lib/inflate.c" +#include "../../../../../lib/inflate.c" static void *malloc(int size) { diff --git a/arch/cris/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile index e9f2ba2ad02c..e9f2ba2ad02c 100644 --- a/arch/cris/boot/rescue/Makefile +++ b/arch/cris/arch-v10/boot/rescue/Makefile diff --git a/arch/cris/boot/rescue/head.S b/arch/cris/arch-v10/boot/rescue/head.S index 52881742da43..8689ea972c46 100644 --- a/arch/cris/boot/rescue/head.S +++ b/arch/cris/arch-v10/boot/rescue/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.2 2001/12/18 13:35:12 bjornw Exp $ +/* $Id: head.S,v 1.6 2003/04/09 08:12:43 pkj Exp $ * * Rescue code, made to reside at the beginning of the * flash-memory. when it starts, it checks a partition @@ -52,7 +52,7 @@ * * Bit 0 in flags signifies RW or RO. The rescue code only bothers * to check the checksum for RO partitions, since the others will - * change its data without updating the checksums. A 1 in bit 0 + * change their data without updating the checksums. A 1 in bit 0 * means RO, 0 means RW. That way, it is possible to set a partition * in RO mode initially, and later mark it as RW, since you can always * write 0's to the flash. @@ -60,12 +60,12 @@ * During the wait for serial input, the status LED will flash so the * user knows something went wrong. * - * Copyright (C) 1999,2001 Axis Communications AB + * Copyright (C) 1999, 2000, 2001, 2002, 2003 Axis Communications AB */ #include <linux/config.h> #define ASSEMBLER_MACROS_ONLY -#include <asm/sv_addr_ag.h> +#include <asm/arch/sv_addr_ag.h> ;; The partitiontable is looked for at the first sector after the boot ;; sector. Sector size is 65536 bytes in all flashes we use. @@ -192,7 +192,7 @@ no_newjump: moveq -1, $r7 ploop: move.d [$r3+], $r1 ; partition offset (from ptable start) - bne notfirst ; check if its the partition containing ptable + bne notfirst ; check if it is the partition containing ptable nop ; yes.. move.d $r8, $r1 ; for its checksum check, skip the ptable move.d [$r3+], $r2 ; partition length diff --git a/arch/cris/boot/rescue/kimagerescue.S b/arch/cris/arch-v10/boot/rescue/kimagerescue.S index 270774108b7e..264bf7afc9ad 100644 --- a/arch/cris/boot/rescue/kimagerescue.S +++ b/arch/cris/arch-v10/boot/rescue/kimagerescue.S @@ -1,4 +1,4 @@ -/* $Id: kimagerescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: kimagerescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * Rescue code to be prepended on a kimage and copied to the * rescue serial port. diff --git a/arch/cris/boot/rescue/rescue.ld b/arch/cris/arch-v10/boot/rescue/rescue.ld index 0b52a9490db6..0b52a9490db6 100644 --- a/arch/cris/boot/rescue/rescue.ld +++ b/arch/cris/arch-v10/boot/rescue/rescue.ld diff --git a/arch/cris/boot/rescue/testrescue.S b/arch/cris/arch-v10/boot/rescue/testrescue.S index f39c69e26483..566a9f341254 100644 --- a/arch/cris/boot/rescue/testrescue.S +++ b/arch/cris/arch-v10/boot/rescue/testrescue.S @@ -1,4 +1,4 @@ -/* $Id: testrescue.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: testrescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * Simple testcode to download by the rescue block. * Just lits some LEDs to show it was downloaded correctly. diff --git a/arch/cris/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c index 2f9bbb26d603..2f9bbb26d603 100644 --- a/arch/cris/boot/tools/build.c +++ b/arch/cris/arch-v10/boot/tools/build.c diff --git a/arch/cris/arch-v10/defconfig b/arch/cris/arch-v10/defconfig new file mode 100644 index 000000000000..9d40dd316576 --- /dev/null +++ b/arch/cris/arch-v10/defconfig @@ -0,0 +1,506 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# General setup +# +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set +CONFIG_BINFMT_ELF=y +# CONFIG_ETRAX_KGDB is not set +# CONFIG_ETRAX_WATCHDOG is not set + +# +# Hardware setup +# +CONFIG_ETRAX100LX=y +# CONFIG_ETRAX100LX_V2 is not set +# CONFIG_SVINTO_SIM is not set +CONFIG_CRIS_LOW_MAP=y +CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 +CONFIG_ETRAX_DRAM_SIZE=8 +CONFIG_ETRAX_FLASH_BUSWIDTH=2 +CONFIG_ETRAX_ROOT_DEVICE="/dev/mtdblock3" +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=2 +CONFIG_ETRAX_LED2R=2 +CONFIG_ETRAX_LED3R=2 +CONFIG_ETRAX_LED3G=2 +CONFIG_ETRAX_LED4R=2 +CONFIG_ETRAX_LED4G=2 +CONFIG_ETRAX_LED5R=2 +CONFIG_ETRAX_LED5G=2 +CONFIG_ETRAX_LED6R=2 +CONFIG_ETRAX_LED6G=2 +CONFIG_ETRAX_LED7R=2 +CONFIG_ETRAX_LED7G=2 +CONFIG_ETRAX_LED8Y=2 +CONFIG_ETRAX_LED9Y=2 +CONFIG_ETRAX_LED10Y=2 +CONFIG_ETRAX_LED11Y=2 +CONFIG_ETRAX_LED12R=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_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=95a6 +CONFIG_ETRAX_DEF_R_BUS_CONFIG=104 +# CONFIG_ETRAX_SDRAM is not set +CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040 +CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611 +CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d +CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0 +CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 +CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e +CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 +# CONFIG_ETRAX_SOFT_SHUTDOWN is not set + +# +# Drivers for ETRAX 100LX 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_ETHERNET_LPSLAVE is not set +CONFIG_ETRAX_SERIAL=y +CONFIG_ETRAX_SERIAL_PORT0=y +# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set +CONFIG_ETRAX_SERIAL_PORT1=y +# CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set +# CONFIG_ETRAX_SERIAL_PORT2 is not set +# CONFIG_ETRAX_SERIAL_PORT3 is not set +# CONFIG_ETRAX_RS485 is not set +# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set +# CONFIG_ETRAX_IDE is not set +CONFIG_ETRAX_AXISFLASHMAP=y +CONFIG_ETRAX_PTABLE_SECTOR=65536 +CONFIG_MTD=y +CONFIG_MTD_CFI=y +# CONFIG_MTD_CFI_INTELEXT is not set +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_AMDSTD=y +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +CONFIG_ETRAX_I2C=y +CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y +# CONFIG_ETRAX_I2C_EEPROM is not set +CONFIG_ETRAX_GPIO=y +CONFIG_ETRAX_PA_BUTTON_BITMASK=02 +CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF +CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 +CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF +# CONFIG_ETRAX_USB_HOST is not set +# CONFIG_USB is not set +# CONFIG_ETRAX_DS1302 is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# RAM/ROM Device Drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_MTDRAM is not set + +# +# Linearly Mapped Flash Device Drivers +# +CONFIG_MTD_CFI=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_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 +# +# CONFIG_MTD_NAND is not set +# CONFIG_MTD_NAND_SPIA is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# 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_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Networking options +# +# CONFIG_PACKET is not set +# CONFIG_NETLINK is not set +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Telephony Support +# +# 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 +# CONFIG_BLK_DEV_IDE_MODES 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_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_NET_SB1000 is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# 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) +# +# 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) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# CD-ROM drivers (not for SCSI or IDE/ATAPI drives) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Input core support +# +# CONFIG_INPUT is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_JOYSTICK is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_INTEL_RNG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_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_JFFS_FS is not set +CONFIG_CRAMFS=y +CONFIG_RAMFS=y +# 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_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_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_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_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG 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 +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_PROFILE is not set diff --git a/arch/cris/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig index fef010d37227..7b0684d07fcf 100644 --- a/arch/cris/drivers/Kconfig +++ b/arch/cris/arch-v10/drivers/Kconfig @@ -1,8 +1,6 @@ - -menu "Drivers for ETRAX 100LX built-in interfaces" - config ETRAX_ETHERNET bool "Ethernet support" + depends on ETRAX_ARCH_V10 help This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet controller. @@ -45,51 +43,39 @@ choice config ETRAX_NETWORK_LED_ON_WHEN_LINK bool "LED_on_when_link" help - Selecting LED_on_when_link will light the LED when there is a - connection and will flash off when there is activity. + Selecting LED_on_when_link will light the LED when there is a + connection and will flash off when there is activity. - Selecting LED_on_when_activity will light the LED only when + Selecting LED_on_when_activity will light the LED only when there is activity. - This setting will also affect the behaviour of other activity LEDs - e.g. Bluetooth. + This setting will also affect the behaviour of other activity LEDs + e.g. Bluetooth. config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY bool "LED_on_when_activity" help - Selecting LED_on_when_link will light the LED when there is a - connection and will flash off when there is activity. + Selecting LED_on_when_link will light the LED when there is a + connection and will flash off when there is activity. - Selecting LED_on_when_activity will light the LED only when + Selecting LED_on_when_activity will light the LED only when there is activity. - This setting will also affect the behaviour of other activity LEDs - e.g. Bluetooth. + This setting will also affect the behaviour of other activity LEDs + e.g. Bluetooth. endchoice -config ETRAX_ETHERNET_LPSLAVE - bool "Etrax Ethernet slave support (over lp0/1)" - help - This option enables a slave ETRAX 100 or ETRAX 100LX, connected to a - master ETRAX 100 or ETRAX 100LX through par0 and par1, to act as an - Ethernet controller. - -config ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - bool "Slave has its own LEDs" - depends on ETRAX_ETHERNET_LPSLAVE - help - Enable if the slave has it's own LEDs. - config ETRAX_SERIAL bool "Serial-port support" + depends on ETRAX_ARCH_V10 help Enables the ETRAX 100 serial driver for ser0 (ttyS0) You probably want this enabled. -# bool ' Use fast timers for DMA flush and RS-485 timing' CONFIG_ETRAX_SERIAL_FAST_TIMER n config ETRAX_SERIAL_FAST_TIMER - bool + bool "Use fast timers for serial DMA flush (experimental)" + depends on ETRAX_SERIAL help Select this to have the serial DMAs flushed at a higher rate than normally, possible by using the fast timer API, the timeout is @@ -107,7 +93,7 @@ config ETRAX_SERIAL_FLUSH_DMA_FAST config ETRAX_SERIAL_RX_TIMEOUT_TICKS int "Receive flush timeout (ticks) " - depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER && !ETRAX100_SERIAL_FLUSH_DMA_FAST + depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER && !ETRAX_SERIAL_FLUSH_DMA_FAST default "5" help Number of timer ticks between flush of receive fifo (1 tick = 10ms). @@ -123,41 +109,84 @@ config ETRAX_SERIAL_PORT0 Normally you want this on, unless you use external DMA 1 that uses the same DMA channels. -config ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - bool "Ser0 DTR, RI, DSR, CD on PB" +choice + prompt "Ser0 DTR, RI, DSR and CD assignment" depends on ETRAX_SERIAL_PORT0 + default ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER0_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" + +config ETRAX_SER0_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" help Enables the status and control signals DTR, RI, DSR and CD on PB for ser0. +config ETRAX_SER0_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + +config ETRAX_SER0_DTR_ON_PA_BIT + int "Ser0 DTR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER0_RI_ON_PA_BIT + int "Ser0 RI on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER0_DSR_ON_PA_BIT + int "Ser0 DSR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER0_CD_ON_PA_BIT + int "Ser0 CD on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + config ETRAX_SER0_DTR_ON_PB_BIT - int "Ser0 DTR on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "4" + int "Ser0 DTR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DTR signal for serial port 0. config ETRAX_SER0_RI_ON_PB_BIT - int "Ser0 RI on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "5" + int "Ser0 RI on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the RI signal for serial port 0. config ETRAX_SER0_DSR_ON_PB_BIT - int "Ser0 DSR on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "6" + int "Ser0 DSR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DSR signal for serial port 0. config ETRAX_SER0_CD_ON_PB_BIT - int "Ser0 CD on PB bit" - depends on ETRAX_SER0_DTR_RI_DSR_CD_ON_PB - default "7" + int "Ser0 CD on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT0 + default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the CD signal for serial port 0. @@ -168,41 +197,84 @@ config ETRAX_SERIAL_PORT1 help Enables the ETRAX 100 serial driver for ser1 (ttyS1). -config ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - bool "Ser1 DTR, RI, DSR, CD on PB" +choice + prompt "Ser1 DTR, RI, DSR and CD assignment" depends on ETRAX_SERIAL_PORT1 + default ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER1_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" + +config ETRAX_SER1_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" help Enables the status and control signals DTR, RI, DSR and CD on PB for ser1. +config ETRAX_SER1_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + +config ETRAX_SER1_DTR_ON_PA_BIT + int "Ser1 DTR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER1_RI_ON_PA_BIT + int "Ser1 RI on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER1_DSR_ON_PA_BIT + int "Ser1 DSR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER1_CD_ON_PA_BIT + int "Ser1 CD on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + config ETRAX_SER1_DTR_ON_PB_BIT - int "Ser1 DTR on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "4" + int "Ser1 DTR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DTR signal for serial port 1. config ETRAX_SER1_RI_ON_PB_BIT - int "Ser1 RI on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "5" + int "Ser1 RI on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the RI signal for serial port 1. config ETRAX_SER1_DSR_ON_PB_BIT - int "Ser1 DSR on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "6" + int "Ser1 DSR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the DSR signal for serial port 1. config ETRAX_SER1_CD_ON_PB_BIT - int "Ser1 CD on PB bit" - depends on ETRAX_SER1_DTR_RI_DSR_CD_ON_PB - default "7" + int "Ser1 CD on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT1 + default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED help Specify the pin of the PB port to carry the CD signal for serial port 1. @@ -216,51 +288,153 @@ config ETRAX_SERIAL_PORT2 help Enables the ETRAX 100 serial driver for ser2 (ttyS2). -config ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - bool "Ser2 DTR, RI, DSR, CD on PA" +choice + prompt "Ser2 DTR, RI, DSR and CD assignment" depends on ETRAX_SERIAL_PORT2 + default ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER2_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" help Enables the status and control signals DTR, RI, DSR and CD on PA for ser2. +config ETRAX_SER2_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" + +config ETRAX_SER2_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + config ETRAX_SER2_DTR_ON_PA_BIT - int "Ser2 DTR on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "4" + int "Ser2 DTR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the DTR signal for serial port 2. config ETRAX_SER2_RI_ON_PA_BIT - int "Ser2 RI on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "5" + int "Ser2 RI on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the RI signal for serial port 2. config ETRAX_SER2_DSR_ON_PA_BIT - int "Ser2 DSR on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "6" + int "Ser2 DSR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the DTR signal for serial port 2. config ETRAX_SER2_CD_ON_PA_BIT - int "Ser2 CD on PA bit" - depends on ETRAX_SER2_DTR_RI_DSR_CD_ON_PA - default "7" + int "Ser2 CD on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED help Specify the pin of the PA port to carry the CD signal for serial port 2. +config ETRAX_SER2_DTR_ON_PB_BIT + int "Ser2 DTR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER2_RI_ON_PB_BIT + int "Ser2 RI on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER2_DSR_ON_PB_BIT + int "Ser2 DSR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + +config ETRAX_SER2_CD_ON_PB_BIT + int "Ser2 CD on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT2 + default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED + default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED + config ETRAX_SERIAL_PORT3 bool "Serial port 3 enabled" depends on ETRAX_SERIAL help Enables the ETRAX 100 serial driver for ser3 (ttyS3). +choice + prompt "Ser3 DTR, RI, DSR and CD assignment" + depends on ETRAX_SERIAL_PORT3 + default ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE + +config ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE + bool "No_DTR_RI_DSR_CD" + +config ETRAX_SER3_DTR_RI_DSR_CD_ON_PA + bool "DTR_RI_DSR_CD_on_PA" + +config ETRAX_SER3_DTR_RI_DSR_CD_ON_PB + bool "DTR_RI_DSR_CD_on_PB" + +config ETRAX_SER3_DTR_RI_DSR_CD_MIXED + bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" + +endchoice + +config ETRAX_SER3_DTR_ON_PA_BIT + int "Ser3 DTR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_RI_ON_PA_BIT + int "Ser3 RI on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_DSR_ON_PA_BIT + int "Ser3 DSR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_CD_ON_PA_BIT + int "Ser3 CD on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_DTR_ON_PB_BIT + int "Ser3 DTR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_RI_ON_PB_BIT + int "Ser3 RI on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_DSR_ON_PB_BIT + int "Ser3 DSR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + +config ETRAX_SER3_CD_ON_PB_BIT + int "Ser3 CD on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED + depends on ETRAX_SERIAL_PORT3 + default "-1" + config ETRAX_RS485 bool "RS-485 support" depends on ETRAX_SERIAL @@ -272,7 +446,7 @@ config ETRAX_RS485_ON_PA bool "RS-485 mode on PA" depends on ETRAX_RS485 help - Control Driver Output Enable on RS485 tranceiver using a pin on PA + Control Driver Output Enable on RS485 transceiver using a pin on PA port: Axis 2400/2401 uses PA 3. @@ -281,7 +455,7 @@ config ETRAX_RS485_ON_PA_BIT depends on ETRAX_RS485_ON_PA default "3" help - Control Driver Output Enable on RS485 tranceiver using a this bit + Control Driver Output Enable on RS485 transceiver using a this bit on PA port. config ETRAX_RS485_DISABLE_RECEIVER @@ -292,299 +466,9 @@ config ETRAX_RS485_DISABLE_RECEIVER loopback. Not all products are able to do this in software only. Axis 2400/2401 must disable receiver. -config ETRAX_SYNCHRONOUS_SERIAL - bool "Synchronous serial port support" - help - This option enables support for the ETRAX 100LX built-in - synchronous serial ports. These ports are used for continuous - streamed data like audio. The default setting is compatible - with the STA 013 MP3 decoder, but can easily be tuned to fit - any other audio encoder/decoder and SPI. - -config ETRAX_SYNCHRONOUS_SERIAL_PORT0 - bool "Synchronous serial port 0 enabled" - depends on ETRAX_SYNCHRONOUS_SERIAL - help - Enables the ETRAX 100LX synchronous serial port 0 (syncser0). - -config ETRAX_SYNCHRONOUS_SERIAL0_DMA - bool "Synchronous serial port 0 uses DMA" - depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0 - help - Makes synchronous serial port 0 use DMA. - -config ETRAX_SYNCHRONOUS_SERIAL_PORT1 - bool "Synchronous serial port 1 enabled" - depends on ETRAX_SYNCHRONOUS_SERIAL - help - Enables the ETRAX 100LX synchronous serial port 1 (syncser1). - -config ETRAX_SYNCHRONOUS_SERIAL1_DMA - bool "Synchronous serial port 1 uses DMA" - depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1 - help - Makes synchronous serial port 1 use DMA. - -config ETRAX_PARPORT - bool "Parallel port support" - help - Say Y here to enable the ETRAX on-board parallel ports. - -config ETRAX_PARALLEL_PORT0 - bool "Parallel port 0 enabled" - depends on ETRAX_PARPORT - help - Say Y here to enable parallel port 0. - -config ETRAX_PARALLEL_PORT1 - bool "Parallel port 1 enabled" - depends on ETRAX_PARPORT - help - Say Y here to enable parallel port 1. - -# here we define the CONFIG_'s necessary to enable parallel port support -config PARPORT - tristate - depends on ETRAX_PARPORT - default y - ---help--- - If you want to use devices connected to your machine's parallel port - (the connector at the computer with 25 holes), e.g. printer, ZIP - drive, PLIP link (Parallel Line Internet Protocol is mainly used to - create a mini network by connecting the parallel ports of two local - machines) etc., then you need to say Y here; please read - <file:Documentation/parport.txt> and - <file:drivers/parport/BUGS-parport>. - - For extensive information about drivers for many devices attaching - to the parallel port see <http://www.torque.net/linux-pp.html> on - the WWW. - - It is possible to share a single parallel port among several devices - and it is safe to compile all the corresponding drivers into the - kernel. If you want to compile parallel port support as a module - ( = code which can be inserted in and removed from the running - kernel whenever you want), say M here and read - <file:Documentation/modules.txt>. The module will be called - parport. If you have more than one parallel port and want to - specify which port and IRQ to be used by this driver at module load - time, take a look at <file:Documentation/parport.txt>. - - If unsure, say Y. - -config PARPORT_1284 - bool - depends on ETRAX_PARPORT - default y - help - If you have a printer that supports status readback or device ID, or - want to use a device that uses enhanced parallel port transfer modes - such as EPP and ECP, say Y here to enable advanced IEEE 1284 - transfer modes. Also say Y if you want device ID information to - appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N. - -config PRINTER - tristate - depends on ETRAX_PARPORT - default y - ---help--- - If you intend to attach a printer to the parallel port of your Linux - box (as opposed to using a serial printer; if the connector at the - printer has 9 or 25 holes ["female"], then it's serial), say Y. - Also read the Printing-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - It is possible to share one parallel port among several devices - (e.g. printer and ZIP drive) and it is safe to compile the - corresponding drivers into the kernel. If you want to compile this - driver as a module however ( = code which can be inserted in and - removed from the running kernel whenever you want), say M here and - read <file:Documentation/modules.txt> and - <file:Documentation/parport.txt>. The module will be called lp. - - If you have several parallel ports, you can specify which ports to - use with the "lp" kernel command line option. (Try "man bootparam" - or see the documentation of your boot loader (lilo or loadlin) about - how to pass options to the kernel at boot time.) The syntax of the - "lp" command line option can be found in <file:drivers/char/lp.c>. - - If you have more than 8 printers, you need to increase the LP_NO - macro in lp.c and the PARPORT_MAX macro in parport.h. - -config ETRAX_IDE - bool "ATA/IDE support" - help - Enable this to get support for ATA/IDE. You can't use parallel - 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 - ---help--- - If you say Y here, your kernel will be able to manage low cost mass - storage units such as ATA/(E)IDE and ATAPI units. The most common - cases are IDE hard drives and ATAPI CD-ROM drives. - - If your system is pure SCSI and doesn't use these interfaces, you - can say N here. - - Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard - for mass storage units such as hard disks. It was designed by - Western Digital and Compaq Computer in 1984. It was then named - ST506. Quite a number of disks use the IDE interface. - - AT Attachment (ATA) is the superset of the IDE specifications. - ST506 was also called ATA-1. - - Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is - ATA-3. It provides support for larger disks (up to 8.4GB by means of - the LBA standard), more disks (4 instead of 2) and for other mass - storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is - ATA-4 and provides faster (and more CPU friendly) transfer modes - than previous PIO (Programmed processor Input/Output) from previous - ATA/IDE standards by means of fast DMA controllers. - - ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and - CD-ROM drives, similar in many respects to the SCSI protocol. - - SMART IDE (Self Monitoring, Analysis and Reporting Technology) was - designed in order to prevent data corruption and disk crash by - detecting pre hardware failure conditions (heat, access time, and - the like...). Disks built since June 1995 may follow this standard. - The kernel itself don't manage this; however there are quite a - number of user programs such as smart that can query the status of - SMART parameters disk. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called ide. - - For further information, please read <file:Documentation/ide.txt>. - - If unsure, say Y. - -config BLK_DEV_IDE - tristate - depends on ETRAX_IDE - default y - ---help--- - If you say Y here, you will use the full-featured IDE driver to - control up to ten ATA/IDE interfaces, each being able to serve a - "master" and a "slave" device, for a total of up to twenty ATA/IDE - disk/cdrom/tape/floppy drives. - - Useful information about large (>540 MB) IDE disks, multiple - interfaces, what to do if ATA/IDE devices are not automatically - detected, sound card ATA/IDE ports, module support, and other - topics, is contained in <file:Documentation/ide.txt>. For detailed - information about hard drives, consult the Disk-HOWTO and the - Multi-Disk-HOWTO, available from - <http://www.tldp.org/docs.html#howto>. - - To fine-tune ATA/IDE drive/interface parameters for improved - performance, look for the hdparm package at - <ftp://ibiblio.org/pub/Linux/system/hardware/>. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt> and - <file:Documentation/ide.txt>. The module will be called ide-mod. - Do not compile this driver as a module if your root file system (the - one containing the directory /) is located on an IDE device. - - If you have one or more IDE drives, say Y or M here. If your system - has no IDE drives, or if memory requirements are really tight, you - could say N here, and select the "Old hard disk driver" below - instead to save about 13 KB of memory in the kernel. - -config BLK_DEV_IDEDISK - tristate - depends on ETRAX_IDE - default y - ---help--- - This will include enhanced support for MFM/RLL/IDE hard disks. If - you have a MFM/RLL/IDE disk, and there is no special reason to use - the old hard disk driver instead, say Y. If you have an SCSI-only - system, you can say N here. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called ide-disk. Do not compile this driver as a module - if your root file system (the one containing the directory /) is - located on the IDE disk. If unsure, say Y. - -config BLK_DEV_IDECD - tristate - depends on ETRAX_IDE - default y - ---help--- - If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is - a newer protocol used by IDE CD-ROM and TAPE drives, similar to the - SCSI protocol. Most new CD-ROM drives use ATAPI, including the - NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI - double(2X) or better speed drives. - - If you say Y here, the CD-ROM drive will be identified at boot time - along with other IDE devices, as "hdb" or "hdc", or something - similar (check the boot messages with dmesg). If this is your only - CD-ROM drive, you can say N to all other CD-ROM options, but be sure - to say Y or M to "ISO 9660 CD-ROM file system support". - - Note that older versions of LILO (LInux LOader) cannot properly deal - with IDE/ATAPI CD-ROMs, so install LILO 16 or higher, available from - <ftp://brun.dyndns.org/pub/linux/lilo/>. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read <file:Documentation/modules.txt>. The module - will be called ide-cd. - -config BLK_DEV_IDEDMA - 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 - Sets the time to wait for disks to regain consciousness after 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 - Configures the pin used to reset the IDE bus. - -config ETRAX_IDE_G27_RESET - bool "Port_G_Bit_27" - help - Configures the pin used to reset the IDE bus. - -config ETRAX_IDE_CSE1_16_RESET - bool "Port_CSE1_Bit_16" - -config ETRAX_IDE_CSP0_8_RESET - bool "Port_CSP0_Bit_08" - help - Configures the pin used to reset the IDE bus. - -endchoice - config ETRAX_AXISFLASHMAP bool "Axis flash-map support" + depends on ETRAX_ARCH_V10 help This option enables MTD mapping of flash devices. Needed to use flash memories. If unsure, say Y. @@ -637,6 +521,19 @@ config MTD_CFI_AMDSTD provides support for one of those command sets, used on chips chips including the AMD Am29LV320. +config MTD_OBSOLETE_CHIPS + bool + depends on ETRAX_AXISFLASHMAP + default y + help + This option does not enable any code directly, but will allow you to + select some other chip drivers which are now considered obsolete, + because the generic CONFIG_JEDEC_PROBE code above should now detect + the chips which are supported by these drivers, and allow the generic + CFI-compatible drivers to drive the chips. Say 'N' here unless you have + already tried the CONFIG_JEDEC_PROBE method and reported its failure + to the MTD mailing list at <linux-mtd@lists.infradead.org> + config MTD_AMDSTD tristate depends on ETRAX_AXISFLASHMAP @@ -695,10 +592,16 @@ config MTD_PARTITIONS devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. +config MTD_CONCAT + tristate + depends on ETRAX_AXISFLASHMAP + default y + config ETRAX_I2C bool "I2C support" + depends on ETRAX_ARCH_V10 help - Enables an I2C driver on PB0 and PB1 on ETRAX100. + Enables an I2C driver on ETRAX100. EXAMPLE usage: i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); @@ -717,8 +620,23 @@ config ETRAX_I2C_USES_PB_NOT_PB_I2C I2C driver, like the DS1302 realtime-clock driver. If you are uncertain, choose Y here. +config ETRAX_I2C_DATA_PORT + int "I2C SDA bit number" + depends on ETRAX_I2C_USES_PB_NOT_PB_I2C + default "0" + help + Selects the pin on Port B where the data pin is connected + +config ETRAX_I2C_CLK_PORT + int "I2C SCL bit number" + depends on ETRAX_I2C_USES_PB_NOT_PB_I2C + default "1" + help + Select the pin on Port B where the clock pin is connected + config ETRAX_I2C_EEPROM bool "I2C EEPROM (non-volatile RAM) support" + depends on ETRAX_I2C help Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C driver. Select size option: Probed, 2k, 8k, 16k. @@ -755,8 +673,9 @@ endchoice config ETRAX_GPIO bool "GPIO support" + depends on ETRAX_ARCH_V10 ---help--- - Enables the Etrax general port device (major 120, minors 0 and 1). + Enables the ETRAX general port device (major 120, minors 0 and 1). You can use this driver to access the general port bits. It supports these ioctl's: #include <linux/etraxgpio.h> @@ -778,7 +697,7 @@ config ETRAX_PA_BUTTON_BITMASK use 02 here. Use 00 if there are no buttons on PA. If the bitmask is <> 00 a button driver will be included in the gpio - driver. Etrax general I/O support must be enabled. + driver. ETRAX general I/O support must be enabled. config ETRAX_PA_CHANGEABLE_DIR hex "PA user changeable dir mask" @@ -820,71 +739,37 @@ config ETRAX_PB_CHANGEABLE_BITS Bit set = changeable. You probably want 00 here. -#bool 'ARTPEC-1 support' CONFIG_JULIETTE -# -#if [ "$CONFIG_JULIETTE" = "y" ]; then -# source arch/cris/drivers/juliette/Config.in -#fi -config ETRAX_USB_HOST - bool "USB host" +config ETRAX_RTC + bool "Real Time Clock support" + depends on ETRAX_ARCH_V10 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 - ---help--- - Universal Serial Bus (USB) is a specification for a serial bus - subsystem which offers higher speeds and more features than the - traditional PC serial port. The bus supplies power to peripherals - and allows for hot swapping. Up to 127 USB peripherals can be - connected to a single USB port in a tree structure. The USB port is - the root of the tree, the peripherals are the leaves and the inner - nodes are special USB devices called hubs. Many newer PC's have USB - ports and newer peripherals such as scanners, keyboards, mice, - modems, and printers support the USB protocol and can be connected - to the PC via those ports. - - Say Y here if your computer has a USB port and you want to use USB - devices. You then need to say Y to at least one of "UHCI support" - or "OHCI support" below (the type of interface that the USB hardware - in your computer provides to the operating system) and then choose - from among the drivers for USB peripherals. You may want to check - out the information provided in <file:Documentation/usb/> and - especially the links given in <file:Documentation/usb/usb-help.txt>. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called usbcore. If you want to compile it as a - module, say M here and read <file:Documentation/modules.txt>. - -config ETRAX_USB_HOST_PORT1 - bool "USB port 1 enabled" - depends on ETRAX_USB_HOST - help - This option enables port 1 of the ETRAX 100LX USB root hub (RH). - -config ETRAX_USB_HOST_PORT2 - bool "USB port 2 enabled" - depends on ETRAX_USB_HOST - help - This option enables port 2 of the ETRAX 100LX USB root hub (RH). - -config ETRAX_DS1302 - bool "DS1302 Real Time Clock support" - help - Enables the driver for the DS1302 Real-Time Clock battery-backed - chip on some products. The kernel reads the time when booting, and + Enables drivers for the Real-Time Clock battery-backed chips on + some products. The kernel reads the time when booting, and the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc device, major 121. You can check the time with cat /proc/rtc, but normal time reading should be done using libc function time and friends. +choice + prompt "RTC chip" + depends on ETRAX_RTC + default ETRAX_DS1302 + +config ETRAX_DS1302 + bool "DS1302" + help + Enables the driver for the DS1302 Real-Time Clock battery-backed + chip on some products. + +config ETRAX_PCF8563 + bool "PCF8563" + help + Enables the driver for the PCF8563 Real-Time Clock battery-backed + chip on some products. + +endchoice + config ETRAX_DS1302_RST_ON_GENERIC_PORT bool "DS1302 RST on Generic Port" depends on ETRAX_DS1302 @@ -919,5 +804,17 @@ config ETRAX_DS1302_SDABIT This is the bit number for the SDA signal line of the DS1302 RTC on Port PB. This is probably best left at 2. -endmenu +config ETRAX_DS1302_TRICKLE_CHARGE + int "DS1302 Trickle charger value" + depends on ETRAX_DS1302 + default "0" + help + This controls the initial value of the trickle charge register. + 0 = disabled (use this if you are unsure or have a non rechargable battery) + Otherwise the following values can be OR:ed together to control the + charge current: + 1 = 2kohm, 2 = 4kohm, 3 = 4kohm + 4 = 1 diode, 8 = 2 diodes + Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5 + diff --git a/arch/cris/drivers/Makefile b/arch/cris/arch-v10/drivers/Makefile index 50da6d18d529..7160cdd7bdd1 100644 --- a/arch/cris/drivers/Makefile +++ b/arch/cris/arch-v10/drivers/Makefile @@ -4,13 +4,11 @@ obj-$(CONFIG_ETRAX_ETHERNET) += ethernet.o obj-$(CONFIG_ETRAX_SERIAL) += serial.o -obj-$(CONFIG_ETRAX_IDE) += ide.o obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o obj-$(CONFIG_ETRAX_I2C) += i2c.o obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o obj-$(CONFIG_ETRAX_GPIO) += gpio.o -obj-$(CONFIG_ETRAX_USB_HOST) += usb-host.o -obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o -obj-$(CONFIG_ETRAX_PARPORT) += parport.o obj-$(CONFIG_ETRAX_DS1302) += ds1302.o -obj-$(CONFIG_ETRAX_ETHERNET_LPSLAVE) += lpslave +obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o + + diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c new file mode 100644 index 000000000000..c6f90bdcf07c --- /dev/null +++ b/arch/cris/arch-v10/drivers/axisflashmap.c @@ -0,0 +1,541 @@ +/* + * Physical mapping layer for MTD using the Axis partitiontable format + * + * Copyright (c) 2001, 2002 Axis Communications AB + * + * This file is under the GPL. + * + * First partition is always sector 0 regardless of if we find a partitiontable + * or not. In the start of the next sector, there can be a partitiontable that + * tells us what other partitions to define. If there isn't, we use a default + * partition split defined below. + * + * $Log: axisflashmap.c,v $ + * Revision 1.6 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.5 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.4 2002/11/20 11:56:10 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.3 2002/11/13 14:54:13 starvik + * Copied from linux 2.4 + * + * Revision 1.28 2002/10/01 08:08:43 jonashg + * The first partition ends at the start of the partition table. + * + * Revision 1.27 2002/08/21 09:23:13 jonashg + * Speling. + * + * Revision 1.26 2002/08/21 08:35:20 jonashg + * Cosmetic change to printouts. + * + * Revision 1.25 2002/08/21 08:15:42 jonashg + * Made it compile even without CONFIG_MTD_CONCAT defined. + * + * Revision 1.24 2002/08/20 13:12:35 jonashg + * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat + * the results. + * * Removed compile time tests concerning how the mtdram driver has been + * configured. The user will know about the misconfiguration at runtime + * instead. (The old approach made it impossible to use mtdram for anything + * else than RAM boot). + * + * Revision 1.23 2002/05/13 12:12:28 johana + * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and + * be informative at runtime. + * + * Revision 1.22 2002/05/13 10:24:44 johana + * Added #if checks on MTDRAM CONFIG + * + * Revision 1.21 2002/05/06 16:05:20 johana + * Removed debug printout. + * + * Revision 1.20 2002/05/06 16:03:00 johana + * No more cramfs as root hack in generic code. + * It's handled by axisflashmap using mtdram. + * + * Revision 1.19 2002/03/15 17:10:28 bjornw + * Changed comment about cached access since we changed this before + * + * Revision 1.18 2002/03/05 17:06:15 jonashg + * Try amd_flash probe before cfi_probe since amd_flash driver can handle two + * (or more) flash chips of different model and the cfi driver cannot. + * + * Revision 1.17 2001/11/12 19:42:38 pkj + * Fixed compiler warnings. + * + * Revision 1.16 2001/11/08 11:18:58 jonashg + * Always read from uncached address to avoid problems with flushing + * cachelines after write and MTD-erase. No performance loss have been + * seen yet. + * + * Revision 1.15 2001/10/19 12:41:04 jonashg + * Name of probe has changed in MTD. + * + * Revision 1.14 2001/09/21 07:14:10 jonashg + * Made root filesystem (cramfs) use mtdblock driver when booting from flash. + * + * Revision 1.13 2001/08/15 13:57:35 jonashg + * Entire MTD updated to the linux 2.4.7 version. + * + * Revision 1.12 2001/06/11 09:50:30 jonashg + * Oops, 2MB is 0x200000 bytes. + * + * Revision 1.11 2001/06/08 11:39:44 jonashg + * Changed sizes and offsets in axis_default_partitions to use + * CONFIG_ETRAX_PTABLE_SECTOR. + * + * Revision 1.10 2001/05/29 09:42:03 jonashg + * Use macro for end marker length instead of sizeof. + * + * Revision 1.9 2001/05/29 08:52:52 jonashg + * Gave names to the magic fours (size of the ptable end marker). + * + * Revision 1.8 2001/05/28 15:36:20 jonashg + * * Removed old comment about ptable location in flash (it's a CONFIG_ option). + * * Variable ptable was initialized twice to the same value. + * + * Revision 1.7 2001/04/05 13:41:46 markusl + * Updated according to review remarks + * + * Revision 1.6 2001/03/07 09:21:21 bjornw + * No need to waste .data + * + * Revision 1.5 2001/03/06 16:27:01 jonashg + * Probe the entire flash area for flash devices. + * + * Revision 1.4 2001/02/23 12:47:15 bjornw + * Uncached flash in LOW_MAP moved from 0xe to 0x8 + * + * Revision 1.3 2001/02/16 12:11:45 jonashg + * MTD driver amd_flash is now included in MTD CVS repository. + * (It's now in drivers/mtd). + * + * Revision 1.2 2001/02/09 11:12:22 jonashg + * Support for AMD compatible non-CFI flash chips. + * Only tested with Toshiba TC58FVT160 so far. + * + * Revision 1.1 2001/01/12 17:01:18 bjornw + * * Added axisflashmap.c, a physical mapping for MTD that reads and understands + * Axis partition-table format. + * + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/config.h> +#include <linux/init.h> + +#include <linux/mtd/concat.h> +#include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/mtdram.h> +#include <linux/mtd/partitions.h> + +#include <asm/axisflashmap.h> +#include <asm/mmu.h> +#include <asm/arch/sv_addr_ag.h> + +#ifdef CONFIG_CRIS_LOW_MAP +#define FLASH_UNCACHED_ADDR KSEG_8 +#define FLASH_CACHED_ADDR KSEG_5 +#else +#define FLASH_UNCACHED_ADDR KSEG_E +#define FLASH_CACHED_ADDR KSEG_F +#endif + +/* From head.S */ +extern unsigned long romfs_start, romfs_length, romfs_in_flash; + +/* Map driver functions. */ + +static __u8 flash_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(map->map_priv_1 + ofs); +} + +static __u16 flash_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(map->map_priv_1 + ofs); +} + +static __u32 flash_read32(struct map_info *map, unsigned long ofs) +{ + return *(volatile unsigned int *)(map->map_priv_1 + ofs); +} + +static void flash_copy_from(struct map_info *map, void *to, + unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void flash_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(map->map_priv_1 + adr) = d; +} + +static void flash_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(map->map_priv_1 + adr) = d; +} + +static void flash_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(map->map_priv_1 + adr) = d; +} + +/* + * The map for chip select e0. + * + * We run into tricky coherence situations if we mix cached with uncached + * accesses to we only use the uncached version here. + * + * The size field is the total size where the flash chips may be mapped on the + * chip select. MTD probes should find all devices there and it does not matter + * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD + * probes will ignore them. + * + * The start address in map_priv_1 is in virtual memory so we cannot use + * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start + * address of cse0. + */ +static struct map_info map_cse0 = { + .name = "cse0", + .size = MEM_CSE0_SIZE, + .buswidth = CONFIG_ETRAX_FLASH_BUSWIDTH, + .read8 = flash_read8, + .read16 = flash_read16, + .read32 = flash_read32, + .copy_from = flash_copy_from, + .write8 = flash_write8, + .write16 = flash_write16, + .write32 = flash_write32, + .map_priv_1 = FLASH_UNCACHED_ADDR +}; + +/* + * The map for chip select e1. + * + * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong + * address, but there isn't. + */ +static struct map_info map_cse1 = { + .name = "cse1", + .size = MEM_CSE1_SIZE, + .buswidth = CONFIG_ETRAX_FLASH_BUSWIDTH, + .read8 = flash_read8, + .read16 = flash_read16, + .read32 = flash_read32, + .copy_from = flash_copy_from, + .write8 = flash_write8, + .write16 = flash_write16, + .write32 = flash_write32, + .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE +}; + +/* If no partition-table was found, we use this default-set. */ +#define MAX_PARTITIONS 7 +#define NUM_DEFAULT_PARTITIONS 3 + +/* + * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the + * size of one flash block and "filesystem"-partition needs 5 blocks to be able + * to use JFFS. + */ +static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { + { + .name = "boot firmware", + .size = CONFIG_ETRAX_PTABLE_SECTOR, + .offset = 0 + }, + { + .name = "kernel", + .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), + .offset = CONFIG_ETRAX_PTABLE_SECTOR + }, + { + .name = "filesystem", + .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, + .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) + } +}; + +/* Initialize the ones normally used. */ +static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { + { + .name = "part0", + .size = CONFIG_ETRAX_PTABLE_SECTOR, + .offset = 0 + }, + { + .name = "part1", + .size = 0, + .offset = 0 + }, + { + .name = "part2", + .size = 0, + .offset = 0 + }, + { + .name = "part3", + .size = 0, + .offset = 0 + }, + { + .name = "part4", + .size = 0, + .offset = 0 + }, + { + .name = "part5", + .size = 0, + .offset = 0 + }, + { + .name = "part6", + .size = 0, + .offset = 0 + }, +}; + +/* + * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash + * chips in that order (because the amd_flash-driver is faster). + */ +static struct mtd_info *probe_cs(struct map_info *map_cs) +{ + struct mtd_info *mtd_cs = NULL; + + printk("%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n", + map_cs->name, map_cs->size, map_cs->map_priv_1); + +#ifdef CONFIG_MTD_AMDSTD + mtd_cs = do_map_probe("amd_flash", map_cs); +#endif +#ifdef CONFIG_MTD_CFI + if (!mtd_cs) { + mtd_cs = do_map_probe("cfi_probe", map_cs); + } +#endif + + return mtd_cs; +} + +/* + * Probe each chip select individually for flash chips. If there are chips on + * both cse0 and cse1, the mtd_info structs will be concatenated to one struct + * so that MTD partitions can cross chip boundries. + * + * The only known restriction to how you can mount your chips is that each + * chip select must hold similar flash chips. But you need external hardware + * to do that anyway and you can put totally different chips on cse0 and cse1 + * so it isn't really much of a restriction. + */ +static struct mtd_info *flash_probe(void) +{ + struct mtd_info *mtd_cse0; + struct mtd_info *mtd_cse1; + struct mtd_info *mtd_cse; + + mtd_cse0 = probe_cs(&map_cse0); + mtd_cse1 = probe_cs(&map_cse1); + + if (!mtd_cse0 && !mtd_cse1) { + /* No chip found. */ + return NULL; + } + + if (mtd_cse0 && mtd_cse1) { +#ifdef CONFIG_MTD_CONCAT + struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 }; + + /* Since the concatenation layer adds a small overhead we + * could try to figure out if the chips in cse0 and cse1 are + * identical and reprobe the whole cse0+cse1 window. But since + * flash chips are slow, the overhead is relatively small. + * So we use the MTD concatenation layer instead of further + * complicating the probing procedure. + */ + mtd_cse = mtd_concat_create(mtds, + sizeof(mtds) / sizeof(mtds[0]), + "cse0+cse1"); +#else + printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " + "(mis)configuration!\n", map_cse0.name, map_cse1.name); + mtd_cse = NULL; +#endif + if (!mtd_cse) { + printk(KERN_ERR "%s and %s: Concatenation failed!\n", + map_cse0.name, map_cse1.name); + + /* The best we can do now is to only use what we found + * at cse0. + */ + mtd_cse = mtd_cse0; + map_destroy(mtd_cse1); + } + } else { + mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1; + } + + return mtd_cse; +} + +/* + * Probe the flash chip(s) and, if it succeeds, read the partition-table + * and register the partitions with MTD. + */ +static int __init init_axis_flash(void) +{ + struct mtd_info *mymtd; + int err = 0; + int pidx = 0; + struct partitiontable_head *ptable_head; + struct partitiontable_entry *ptable; + int use_default_ptable = 1; /* Until proven otherwise. */ + const char *pmsg = " /dev/flash%d at 0x%08x, size 0x%08x\n"; + + if (!(mymtd = flash_probe())) { + /* There's no reason to use this module if no flash chip can + * be identified. Make sure that's understood. + */ + panic("axisflashmap found no flash chip!\n"); + } + + printk("%s: 0x%08x bytes of flash memory.\n", + mymtd->name, mymtd->size); + + mymtd->owner = THIS_MODULE; + + ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + + CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); + pidx++; /* First partition is always set to the default. */ + + if ((ptable_head->magic == PARTITION_TABLE_MAGIC) + && (ptable_head->size < + (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + + PARTITIONTABLE_END_MARKER_SIZE)) + && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + + ptable_head->size - + PARTITIONTABLE_END_MARKER_SIZE) + == PARTITIONTABLE_END_MARKER)) { + /* Looks like a start, sane length and end of a + * partition table, lets check csum etc. + */ + int ptable_ok = 0; + struct partitiontable_entry *max_addr = + (struct partitiontable_entry *) + ((unsigned long)ptable_head + sizeof(*ptable_head) + + ptable_head->size); + unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; + unsigned char *p; + unsigned long csum = 0; + + ptable = (struct partitiontable_entry *) + ((unsigned long)ptable_head + sizeof(*ptable_head)); + + /* Lets be PARANOID, and check the checksum. */ + p = (unsigned char*) ptable; + + while (p <= (unsigned char*)max_addr) { + csum += *p++; + csum += *p++; + csum += *p++; + csum += *p++; + } + ptable_ok = (csum == ptable_head->checksum); + + /* Read the entries and use/show the info. */ + printk(" Found a%s partition table at 0x%p-0x%p.\n", + (ptable_ok ? " valid" : "n invalid"), ptable_head, + max_addr); + + /* We have found a working bootblock. Now read the + * partition table. Scan the table. It ends when + * there is 0xffffffff, that is, empty flash. + */ + while (ptable_ok + && ptable->offset != 0xffffffff + && ptable < max_addr + && pidx < MAX_PARTITIONS) { + + axis_partitions[pidx].offset = offset + ptable->offset; + axis_partitions[pidx].size = ptable->size; + + printk(pmsg, pidx, axis_partitions[pidx].offset, + axis_partitions[pidx].size); + pidx++; + ptable++; + } + use_default_ptable = !ptable_ok; + } + + if (romfs_in_flash) { + /* Add an overlapping device for the root partition (romfs). */ + + axis_partitions[pidx].name = "romfs"; + axis_partitions[pidx].size = romfs_length; + axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; + axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; + + printk(" Adding readonly flash partition for romfs image:\n"); + printk(pmsg, pidx, axis_partitions[pidx].offset, + axis_partitions[pidx].size); + pidx++; + } + + if (use_default_ptable) { + printk(" Using default partition table.\n"); + err = add_mtd_partitions(mymtd, axis_default_partitions, + NUM_DEFAULT_PARTITIONS); + } else { + err = add_mtd_partitions(mymtd, axis_partitions, pidx); + } + + if (err) { + panic("axisflashmap could not add MTD partitions!\n"); + } + + if (!romfs_in_flash) { + /* Create an RAM device for the root partition (romfs). */ + +#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0) + /* No use trying to boot this kernel from RAM. Panic! */ + printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " + "device due to kernel (mis)configuration!\n"); + panic("This kernel cannot boot from RAM!\n"); +#else + struct mtd_info *mtd_ram; + + mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), + GFP_KERNEL); + if (!mtd_ram) { + panic("axisflashmap couldn't allocate memory for " + "mtd_info!\n"); + } + + printk(" Adding RAM partition for romfs image:\n"); + printk(pmsg, pidx, romfs_start, romfs_length); + + err = mtdram_init_device(mtd_ram, (void*)romfs_start, + romfs_length, "romfs"); + if (err) { + panic("axisflashmap could not initialize MTD RAM " + "device!\n"); + } +#endif + } + + return err; +} + +/* This adds the above to the kernels init-call chain. */ +module_init(init_axis_flash); diff --git a/arch/cris/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c index 23814c3843d3..175062133724 100644 --- a/arch/cris/drivers/ds1302.c +++ b/arch/cris/arch-v10/drivers/ds1302.c @@ -7,8 +7,37 @@ *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init, get_rtc_status *! *! $Log: ds1302.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.9 2003/07/04 08:27:37 starvik +*! Merge of Linux 2.5.74 +*! +*! Revision 1.8 2003/04/09 05:20:47 starvik +*! Merge of Linux 2.5.67 +*! +*! Revision 1.6 2003/01/09 14:42:51 starvik +*! Merge of Linux 2.5.55 +*! +*! Revision 1.4 2002/12/11 13:13:57 starvik +*! Added arch/ to v10 specific includes +*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) +*! +*! Revision 1.3 2002/11/20 11:56:10 starvik +*! Merge of Linux 2.5.48 +*! +*! Revision 1.2 2002/11/18 13:16:06 starvik +*! Linux 2.5 port of latest 2.4 drivers +*! +*! Revision 1.15 2002/10/11 16:14:33 johana +*! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the +*! trcklecharge register. +*! +*! Revision 1.14 2002/10/10 12:15:38 magnusmn +*! Added support for having the RST signal on bit g0 +*! +*! Revision 1.13 2002/05/29 15:16:08 johana +*! Removed unused variables. +*! +*! Revision 1.12 2002/04/10 15:35:25 johana +*! Moved probe function closer to init function and marked it __init. *! *! Revision 1.11 2001/06/14 12:35:52 jonashg *! The ATA hack is back. It is unfortunately the only way to set g27 to output. @@ -85,7 +114,7 @@ *! *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN *! -*! $Id: ds1302.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +*! $Id: ds1302.c,v 1.9 2003/07/04 08:27:37 starvik Exp $ *! *!***************************************************************************/ @@ -101,7 +130,7 @@ #include <asm/uaccess.h> #include <asm/system.h> -#include <asm/svinto.h> +#include <asm/arch/svinto.h> #include <asm/io.h> #include <asm/rtc.h> @@ -232,54 +261,6 @@ ds1302_wdisable(void) stop(); } -/* Probe for the chip by writing something to its RAM and try reading it back. */ - -#define MAGIC_PATTERN 0x42 - -static int -ds1302_probe(void) -{ - int retval, res; - - TK_RST_DIR(1); - TK_SCL_DIR(1); - TK_SDA_DIR(0); - - /* Try to talk to timekeeper. */ - - ds1302_wenable(); - start(); - out_byte(0xc0); /* write RAM byte 0 */ - out_byte(MAGIC_PATTERN); /* write something magic */ - start(); - out_byte(0xc1); /* read RAM byte 0 */ - - if((res = in_byte()) == MAGIC_PATTERN) { - char buf[100]; - stop(); - ds1302_wdisable(); - printk("%s: RTC found.\n", ds1302_name); - printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", - ds1302_name, - CONFIG_ETRAX_DS1302_SDABIT, - CONFIG_ETRAX_DS1302_SCLBIT, -#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT - "GENIO", -#else - "PB", -#endif - CONFIG_ETRAX_DS1302_RSTBIT); - get_rtc_status(buf); - printk(buf); - retval = 1; - } else { - stop(); - printk("%s: RTC not found.\n", ds1302_name); - retval = 0; - } - - return retval; -} /* Read a byte from the selected register in the DS1302. */ @@ -315,8 +296,8 @@ get_rtc_time(struct rtc_time *rtc_tm) { unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); + local_irq_disable(); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); @@ -325,7 +306,7 @@ get_rtc_time(struct rtc_time *rtc_tm) rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); rtc_tm->tm_year = CMOS_READ(RTC_YEAR); - restore_flags(flags); + local_irq_restore(flags); BCD_TO_BIN(rtc_tm->tm_sec); BCD_TO_BIN(rtc_tm->tm_min); @@ -371,7 +352,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, { struct rtc_time rtc_tm; unsigned char mon, day, hrs, min, sec, leap_yr; - unsigned char save_control, save_freq_select; unsigned int yrs; if (!capable(CAP_SYS_TIME)) @@ -414,15 +394,15 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, BIN_TO_BCD(mon); BIN_TO_BCD(yrs); - save_flags(flags); - cli(); + local_irq_save(flags); + local_irq_disable(); CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(mon, RTC_MONTH); CMOS_WRITE(day, RTC_DAY_OF_MONTH); CMOS_WRITE(hrs, RTC_HOURS); CMOS_WRITE(min, RTC_MINUTES); CMOS_WRITE(sec, RTC_SECONDS); - restore_flags(flags); + local_irq_restore(flags); /* Notice that at this point, the RTC is updated but * the kernel is still running with the old time. @@ -435,7 +415,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ { int tcs_val; - unsigned char save_control, save_freq_select; if (!capable(CAP_SYS_TIME)) return -EPERM; @@ -484,6 +463,56 @@ static struct file_operations rtc_fops = { .ioctl = rtc_ioctl, }; +/* Probe for the chip by writing something to its RAM and try reading it back. */ + +#define MAGIC_PATTERN 0x42 + +static int __init +ds1302_probe(void) +{ + int retval, res; + + TK_RST_DIR(1); + TK_SCL_DIR(1); + TK_SDA_DIR(0); + + /* Try to talk to timekeeper. */ + + ds1302_wenable(); + start(); + out_byte(0xc0); /* write RAM byte 0 */ + out_byte(MAGIC_PATTERN); /* write something magic */ + start(); + out_byte(0xc1); /* read RAM byte 0 */ + + if((res = in_byte()) == MAGIC_PATTERN) { + char buf[100]; + stop(); + ds1302_wdisable(); + printk("%s: RTC found.\n", ds1302_name); + printk("%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", + ds1302_name, + CONFIG_ETRAX_DS1302_SDABIT, + CONFIG_ETRAX_DS1302_SCLBIT, +#ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT + "GENIO", +#else + "PB", +#endif + CONFIG_ETRAX_DS1302_RSTBIT); + get_rtc_status(buf); + printk(buf); + retval = 1; + } else { + stop(); + printk("%s: RTC not found.\n", ds1302_name); + retval = 0; + } + + return retval; +} + + /* Just probe for the RTC and register the device to handle the ioctl needed. */ int __init @@ -491,27 +520,47 @@ ds1302_init(void) { if (!ds1302_probe()) { #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT +#if CONFIG_ETRAX_DS1302_RSTBIT == 27 /* * The only way to set g27 to output is to enable ATA. * * Make sure that R_GEN_CONFIG is setup correct. */ genconfig_shadow = ((genconfig_shadow & - ~IO_MASK(R_GEN_CONFIG, ata)) - | + ~IO_MASK(R_GEN_CONFIG, ata)) | (IO_STATE(R_GEN_CONFIG, ata, select))); *R_GEN_CONFIG = genconfig_shadow; - if (!ds1302_probe()) +#elif CONFIG_ETRAX_DS1302_RSTBIT == 0 + + /* Set the direction of this bit to out. */ + genconfig_shadow = ((genconfig_shadow & + ~IO_MASK(R_GEN_CONFIG, g0dir)) | + (IO_STATE(R_GEN_CONFIG, g0dir, out))); + *R_GEN_CONFIG = genconfig_shadow; +#endif + if (!ds1302_probe()) return -1; #else return -1; #endif } + /* Initialise trickle charger */ + ds1302_writereg(RTC_TRICKLECHARGER, + RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F)); + return 0; +} + +static int __init ds1302_register(void) +{ + ds1302_init(); if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { printk(KERN_INFO "%s: unable to get major %d for rtc\n", ds1302_name, RTC_MAJOR_NR); return -1; } - return 0; + return 0; + } + +module_init(ds1302_register); diff --git a/arch/cris/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c index ae3c37886721..67523549dd96 100644 --- a/arch/cris/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -20,8 +20,24 @@ *! in the spin-lock. *! *! $Log: eeprom.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.9 2003/07/04 08:27:37 starvik +*! Merge of Linux 2.5.74 +*! +*! Revision 1.8 2003/04/09 05:20:47 starvik +*! Merge of Linux 2.5.67 +*! +*! Revision 1.6 2003/02/10 07:19:28 starvik +*! Removed misplaced ; +*! +*! Revision 1.5 2002/12/11 13:13:57 starvik +*! Added arch/ to v10 specific includes +*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) +*! +*! Revision 1.4 2002/11/20 11:56:10 starvik +*! Merge of Linux 2.5.48 +*! +*! Revision 1.3 2002/11/18 13:16:06 starvik +*! Linux 2.5 port of latest 2.4 drivers *! *! Revision 1.8 2001/06/15 13:24:29 jonashg *! * Added verification of pointers from userspace in read and write. @@ -74,7 +90,7 @@ #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> -#include <linux/smp_lock.h> +#include <linux/interrupt.h> #include <asm/uaccess.h> #include "i2c.h" @@ -425,9 +441,9 @@ int __init eeprom_init(void) static int eeprom_open(struct inode * inode, struct file * file) { - if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR) + if(minor(inode->i_rdev) != EEPROM_MINOR_NR) return -ENXIO; - if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR) + if(major(inode->i_rdev) != EEPROM_MAJOR_NR) return -ENXIO; if( eeprom.size > 0 ) @@ -449,39 +465,36 @@ static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig) * orig 1: relative from current position * orig 2: position from last eeprom address */ - loff_t ret; - - lock_kernel(); + switch (orig) { case 0: - ret = file->f_pos = offset; + file->f_pos = offset; break; case 1: - ret = file->f_pos += offset; + file->f_pos += offset; break; case 2: - ret = file->f_pos = eeprom.size - offset; + file->f_pos = eeprom.size - offset; break; default: - ret = -EINVAL; + return -EINVAL; } /* truncate position */ if (file->f_pos < 0) { - file->f_pos = 0; - ret = -EOVERFLOW; + file->f_pos = 0; + return(-EOVERFLOW); } - + if (file->f_pos >= eeprom.size) { file->f_pos = eeprom.size - 1; - ret = -EOVERFLOW; + return(-EOVERFLOW); } - unlock_kernel(); - return ( ret ); + return ( file->f_pos ); } /* Reads data from eeprom. */ @@ -500,7 +513,7 @@ static int eeprom_read_buf(loff_t addr, char * buf, int count) static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) { - int i, read=0; + int read=0; unsigned long p = file->f_pos; unsigned char page; @@ -526,7 +539,7 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t if(!eeprom_address(p)) { printk(KERN_INFO "%s: Read failed to address the eeprom: " - "0x%08X (%i) page: %i\n", eeprom_name, p, p, page); + "0x%08X (%i) page: %i\n", eeprom_name, (int)p, (int)p, page); i2c_stop(); /* don't forget to wake them up */ @@ -609,7 +622,7 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, if(!eeprom_address(p)) { printk(KERN_INFO "%s: Write failed to address the eeprom: " - "0x%08X (%i) \n", eeprom_name, p, p); + "0x%08X (%i) \n", eeprom_name, (int)p, (int)p); i2c_stop(); /* don't forget to wake them up */ @@ -747,7 +760,7 @@ static int eeprom_close(struct inode * inode, struct file * file) static int eeprom_address(unsigned long addr) { - int i, j; + int i; unsigned char page, offset; page = (unsigned char) (addr >> 8); diff --git a/arch/cris/drivers/ethernet.c b/arch/cris/arch-v10/drivers/ethernet.c index 9b72037ea030..6b9b40634da9 100644 --- a/arch/cris/drivers/ethernet.c +++ b/arch/cris/arch-v10/drivers/ethernet.c @@ -1,14 +1,109 @@ -/* $Id: ethernet.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $ +/* $Id: ethernet.c,v 1.17 2003/07/04 08:27:37 starvik Exp $ * * e100net.c: A network driver for the ETRAX 100LX network controller. * - * Copyright (c) 1998-2001 Axis Communications AB. + * Copyright (c) 1998-2002 Axis Communications AB. * * The outline of this driver comes from skeleton.c. * * $Log: ethernet.c,v $ - * Revision 1.2 2001/12/18 13:35:15 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). + * Revision 1.17 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.16 2003/04/24 08:28:22 starvik + * New LED behaviour: LED off when no link + * + * Revision 1.15 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.13 2003/03/06 16:11:01 henriken + * Off by one error in group address register setting. + * + * Revision 1.12 2003/02/27 17:24:19 starvik + * Corrected Rev to Revision + * + * Revision 1.11 2003/01/24 09:53:21 starvik + * Oops. Initialize GA to 0, not to 1 + * + * Revision 1.10 2003/01/24 09:50:55 starvik + * Initialize GA_0 and GA_1 to 0 to avoid matching of unwanted packets + * + * Revision 1.9 2002/12/13 07:40:58 starvik + * Added basic ethtool interface + * Handled out of memory when allocating new buffers + * + * Revision 1.8 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.7 2002/11/26 09:41:42 starvik + * Added e100_set_config (standard interface to set media type) + * Added protection against preemptive scheduling + * Added standard MII ioctls + * + * Revision 1.6 2002/11/21 07:18:18 starvik + * Timers must be initialized in 2.5.48 + * + * Revision 1.5 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.4 2002/11/18 07:26:46 starvik + * Linux 2.5 port of latest Linux 2.4 ethernet driver + * + * Revision 1.33 2002/10/02 20:16:17 hp + * SETF, SETS: Use underscored IO_x_ macros rather than incorrect token concatenation + * + * Revision 1.32 2002/09/16 06:05:58 starvik + * Align memory returned by dev_alloc_skb + * Moved handling of sent packets to interrupt to avoid reference counting problem + * + * Revision 1.31 2002/09/10 13:28:23 larsv + * Return -EINVAL for unknown ioctls to avoid confusing tools that tests + * for supported functionality by issuing special ioctls, i.e. wireless + * extensions. + * + * Revision 1.30 2002/05/07 18:50:08 johana + * Correct spelling in comments. + * + * Revision 1.29 2002/05/06 05:38:49 starvik + * Performance improvements: + * Large packets are not copied (breakpoint set to 256 bytes) + * The cache bug workaround is delayed until half of the receive list + * has been used + * Added transmit list + * Transmit interrupts are only enabled when transmit queue is full + * + * Revision 1.28.2.1 2002/04/30 08:15:51 starvik + * Performance improvements: + * Large packets are not copied (breakpoint set to 256 bytes) + * The cache bug workaround is delayed until half of the receive list + * has been used. + * Added transmit list + * Transmit interrupts are only enabled when transmit queue is full + * + * Revision 1.28 2002/04/22 11:47:21 johana + * Fix according to 2.4.19-pre7. time_after/time_before and + * missing end of comment. + * The patch has a typo for ethernet.c in e100_clear_network_leds(), + * that is fixed here. + * + * Revision 1.27 2002/04/12 11:55:11 bjornw + * Added TODO + * + * Revision 1.26 2002/03/15 17:11:02 bjornw + * Use prepare_rx_descriptor after the CPU has touched the receiving descs + * + * Revision 1.25 2002/03/08 13:07:53 bjornw + * Unnecessary spinlock removed + * + * Revision 1.24 2002/02/20 12:57:43 fredriks + * Replaced MIN() with min(). + * + * Revision 1.23 2002/02/20 10:58:14 fredriks + * Strip the Ethernet checksum (4 bytes) before forwarding a frame to upper layers. + * + * Revision 1.22 2002/01/30 07:48:22 matsfg + * Initiate R_NETWORK_TR_CTRL * * Revision 1.21 2001/11/23 11:54:49 starvik * Added IFF_PROMISC and IFF_ALLMULTI handling in set_multicast_list @@ -112,22 +207,25 @@ #include <linux/errno.h> #include <linux/init.h> +#include <linux/if.h> +#include <linux/mii.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> +#include <linux/ethtool.h> -#include <asm/svinto.h> /* DMA and register descriptions */ +#include <asm/arch/svinto.h>/* DMA and register descriptions */ #include <asm/io.h> /* LED_* I/O functions */ #include <asm/irq.h> #include <asm/dma.h> #include <asm/system.h> #include <asm/bitops.h> #include <asm/ethernet.h> +#include <asm/cache.h> //#define ETHDEBUG #define D(x) - /* * The name of the card. Is used for messages and in the requests for * io regions, irqs and dma channels @@ -154,6 +252,11 @@ struct net_local { spinlock_t lock; }; +typedef struct etrax_eth_descr +{ + etrax_dma_descr descr; + struct sk_buff* skb; +} etrax_eth_descr; /* Duplex settings */ enum duplex @@ -165,8 +268,6 @@ enum duplex /* Dma descriptors etc. */ -#define RX_BUF_SIZE 32768 - #define MAX_MEDIA_DATA_SIZE 1518 #define MIN_PACKET_LEN 46 @@ -207,29 +308,37 @@ enum duplex #define NO_NETWORK_ACTIVITY 0 #define NETWORK_ACTIVITY 1 -#define RX_DESC_BUF_SIZE 256 -#define NBR_OF_RX_DESC (RX_BUF_SIZE / \ - RX_DESC_BUF_SIZE) +#define NBR_OF_RX_DESC 64 +#define NBR_OF_TX_DESC 256 + +/* Large packets are sent directly to upper layers while small packets are */ +/* copied (to reduce memory waste). The following constant decides the breakpoint */ +#define RX_COPYBREAK 256 + +/* Due to a chip bug we need to flush the cache when descriptors are returned */ +/* to the DMA. To decrease performance impact we return descriptors in chunks. */ +/* The following constant determines the number of descriptors to return. */ +#define RX_QUEUE_THRESHOLD NBR_OF_RX_DESC/2 #define GET_BIT(bit,val) (((val) >> (bit)) & 0x01) /* Define some macros to access ETRAX 100 registers */ -#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_FIELD(##reg##, field, val) -#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_STATE(##reg##, field, val) +#define SETF(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_FIELD_(reg##_, field##_, val) +#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_STATE_(reg##_, field##_, _##val) -static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to +static etrax_eth_descr *myNextRxDesc; /* Points to the next descriptor to to be processed */ -static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */ -static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ - -static unsigned char RxBuf[RX_BUF_SIZE]; +static etrax_eth_descr *myLastRxDesc; /* The last processed descriptor */ +static etrax_eth_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ -static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); -static etrax_dma_descr TxDesc __attribute__ ((aligned(4))); +static etrax_eth_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(32))); -static struct sk_buff *tx_skb; +static etrax_eth_descr* myFirstTxDesc; /* First packet not yet sent */ +static etrax_eth_descr* myLastTxDesc; /* End of send queue */ +static etrax_eth_descr* myNextTxDesc; /* Next descriptor to use */ +static etrax_eth_descr TxDescList[NBR_OF_TX_DESC] __attribute__ ((aligned(32))); static unsigned int network_rec_config_shadow = 0; @@ -238,27 +347,29 @@ static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0); static struct timer_list clear_led_timer = TIMER_INITIALIZER(NULL, 0, 0); static int current_speed; /* Speed read from transceiver */ static int current_speed_selection; /* Speed selected by user */ -static int led_next_time; +static unsigned long led_next_time; static int led_active; +static int rx_queue_len; /* Duplex */ -static struct timer_list duplex_timer; +static struct timer_list duplex_timer = TIMER_INITIALIZER(NULL, 0, 0); static int full_duplex; static enum duplex current_duplex; /* Index to functions, as function prototypes. */ -static int etrax_ethernet_init(struct net_device *dev); +static int etrax_ethernet_init(void); static int e100_open(struct net_device *dev); static int e100_set_mac_address(struct net_device *dev, void *addr); static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); -static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void e100_rx(struct net_device *dev); static int e100_close(struct net_device *dev); static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static int e100_ethtool_ioctl(struct net_device* dev, struct ifreq *ifr); +static int e100_set_config(struct net_device* dev, struct ifmap* map); static void e100_tx_timeout(struct net_device *dev); static struct net_device_stats *e100_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); @@ -273,6 +384,7 @@ static void e100_set_duplex(enum duplex); static void e100_negotiate(void); static unsigned short e100_get_mdio_reg(unsigned char reg_num); +static void e100_set_mdio_reg(unsigned char reg, unsigned short data); static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd); static void e100_send_mdio_bit(unsigned char bit); static unsigned char e100_receive_mdio_bit(void); @@ -296,15 +408,14 @@ etrax_ethernet_init(void) { struct net_device *dev; int i, err; - int anOffset = 0; - printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n"); + printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2003 Axis Communications AB\n"); dev = alloc_etherdev(sizeof(struct net_local)); if (!dev) return -ENOMEM; - dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ + dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ /* now setup our etrax specific stuff */ @@ -320,35 +431,55 @@ etrax_ethernet_init(void) dev->set_multicast_list = set_multicast_list; dev->set_mac_address = e100_set_mac_address; dev->do_ioctl = e100_ioctl; + dev->set_config = e100_set_config; dev->tx_timeout = e100_tx_timeout; /* Initialise the list of Etrax DMA-descriptors */ /* Initialise receive descriptors */ - for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { - RxDescList[i].ctrl = 0; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; - anOffset += RX_DESC_BUF_SIZE; + for (i = 0; i < NBR_OF_RX_DESC; i++) { + /* Allocate two extra cachelines to make sure that buffer used by DMA + * does not share cacheline with any other data (to avoid cache bug) + */ + RxDescList[i].skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); + RxDescList[i].descr.ctrl = 0; + RxDescList[i].descr.sw_len = MAX_MEDIA_DATA_SIZE; + RxDescList[i].descr.next = virt_to_phys(&RxDescList[i + 1]); + RxDescList[i].descr.buf = L1_CACHE_ALIGN(virt_to_phys(RxDescList[i].skb->data)); + RxDescList[i].descr.status = 0; + RxDescList[i].descr.hw_len = 0; + prepare_rx_descriptor(&RxDescList[i].descr); } - RxDescList[i].ctrl = d_eol; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[0]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; + RxDescList[NBR_OF_RX_DESC - 1].descr.ctrl = d_eol; + RxDescList[NBR_OF_RX_DESC - 1].descr.next = virt_to_phys(&RxDescList[0]); + rx_queue_len = 0; + + /* Initialize transmit descriptors */ + for (i = 0; i < NBR_OF_TX_DESC; i++) { + TxDescList[i].descr.ctrl = 0; + TxDescList[i].descr.sw_len = 0; + TxDescList[i].descr.next = virt_to_phys(&TxDescList[i + 1].descr); + TxDescList[i].descr.buf = 0; + TxDescList[i].descr.status = 0; + TxDescList[i].descr.hw_len = 0; + TxDescList[i].skb = 0; + } + TxDescList[NBR_OF_TX_DESC - 1].descr.ctrl = d_eol; + TxDescList[NBR_OF_TX_DESC - 1].descr.next = virt_to_phys(&TxDescList[0].descr); + /* Initialise initial pointers */ - myNextRxDesc = &RxDescList[0]; - myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myNextRxDesc = &RxDescList[0]; + myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + myFirstTxDesc = &TxDescList[0]; + myNextTxDesc = &TxDescList[0]; + myLastTxDesc = &TxDescList[NBR_OF_TX_DESC - 1]; + /* Register device */ err = register_netdev(dev); if (err) { kfree(dev); @@ -375,6 +506,10 @@ etrax_ethernet_init(void) duplex_timer.function = e100_check_duplex; add_timer(&duplex_timer); + /* Initialize group address registers to make sure that no */ + /* unwanted addresses are matched */ + *R_NETWORK_GA_0 = 0x00000000; + *R_NETWORK_GA_1 = 0x00000000; return 0; } @@ -385,9 +520,12 @@ etrax_ethernet_init(void) static int e100_set_mac_address(struct net_device *dev, void *p) { + struct net_local *np = (struct net_local *)dev->priv; struct sockaddr *addr = p; int i; + spin_lock(&np->lock); /* preemption protection */ + /* remember it */ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); @@ -412,6 +550,8 @@ e100_set_mac_address(struct net_device *dev, void *p) printk("%02X\n", dev->dev_addr[i]); + spin_unlock(&np->lock); + return 0; } @@ -462,14 +602,14 @@ e100_open(struct net_device *dev) /* allocate the irq corresponding to the receiving DMA */ - if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rx_interrupt, 0, + if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, (void *)dev)) { goto grace_exit0; } /* allocate the irq corresponding to the transmitting DMA */ - if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100tx_interrupt, 0, + if (request_irq(NETWORK_DMA_TX_IRQ_NBR, e100rxtx_interrupt, 0, cardname, (void *)dev)) { goto grace_exit1; } @@ -481,19 +621,6 @@ e100_open(struct net_device *dev) goto grace_exit2; } - /* - * Always allocate the DMA channels after the IRQ, - * and clean up on failure. - */ - - if (request_dma(NETWORK_TX_DMA_NBR, cardname)) { - goto grace_exit3; - } - - if (request_dma(NETWORK_RX_DMA_NBR, cardname)) { - goto grace_exit4; - } - /* give the HW an idea of what MAC address we want */ *R_NETWORK_SA_0 = dev->dev_addr[0] | (dev->dev_addr[1] << 8) | @@ -518,22 +645,28 @@ e100_open(struct net_device *dev) IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | IO_STATE(R_NETWORK_GEN_CONFIG, enable, on); + *R_NETWORK_TR_CTRL = + IO_STATE(R_NETWORK_TR_CTRL, clr_error, clr) | + IO_STATE(R_NETWORK_TR_CTRL, delay, none) | + IO_STATE(R_NETWORK_TR_CTRL, cancel, dont) | + IO_STATE(R_NETWORK_TR_CTRL, cd, enable) | + IO_STATE(R_NETWORK_TR_CTRL, retry, enable) | + IO_STATE(R_NETWORK_TR_CTRL, pad, enable) | + IO_STATE(R_NETWORK_TR_CTRL, crc, enable); + save_flags(flags); cli(); /* enable the irq's for ethernet DMA */ *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); + IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set); *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, overrun, set) | IO_STATE(R_IRQ_MASK0_SET, underrun, set) | IO_STATE(R_IRQ_MASK0_SET, excessive_col, set); - tx_skb = 0; - /* make sure the irqs are cleared */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); @@ -549,6 +682,11 @@ e100_open(struct net_device *dev) *R_DMA_CH1_FIRST = virt_to_phys(myNextRxDesc); *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start); + /* Set up transmit DMA channel so it can be restarted later */ + + *R_DMA_CH0_FIRST = 0; + *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); + restore_flags(flags); /* We are now ready to accept transmit requeusts from @@ -558,10 +696,6 @@ e100_open(struct net_device *dev) return 0; -grace_exit4: - free_dma(NETWORK_TX_DMA_NBR); -grace_exit3: - free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); grace_exit2: free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); grace_exit1: @@ -596,9 +730,7 @@ e100_check_speed(unsigned long dummy) static void e100_negotiate(void) { - unsigned short cmd; unsigned short data = e100_get_mdio_reg(MDIO_ADVERTISMENT_REG); - int bitCounter; /* Discard old speed and duplex settings */ data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | @@ -637,29 +769,13 @@ e100_negotiate(void) MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD; } - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | - (MDIO_ADVERTISMENT_REG<< 2); - - e100_send_mdio_cmd(cmd, 1); - - /* Data... */ - for (bitCounter=15; bitCounter>=0 ; bitCounter--) { - e100_send_mdio_bit(GET_BIT(bitCounter, data)); - } + e100_set_mdio_reg(MDIO_ADVERTISMENT_REG, data); /* Renegotiate with link partner */ data = e100_get_mdio_reg(MDIO_BASE_CONTROL_REG); data |= MDIO_BC_NEGOTIATE; - cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | - (MDIO_BASE_CONTROL_REG<< 2); - - e100_send_mdio_cmd(cmd, 1); - - /* Data... */ - for (bitCounter=15; bitCounter>=0 ; bitCounter--) { - e100_send_mdio_bit(GET_BIT(bitCounter, data)); - } + e100_set_mdio_reg(MDIO_BASE_CONTROL_REG, data); } static void @@ -727,6 +843,24 @@ e100_get_mdio_reg(unsigned char reg_num) } static void +e100_set_mdio_reg(unsigned char reg, unsigned short data) +{ + int bitCounter; + unsigned short cmd; + + cmd = (MDIO_START << 14) | (MDIO_WRITE << 12) | (MDIO_PHYS_ADDR << 7) | + (reg << 2); + + e100_send_mdio_cmd(cmd, 1); + + /* Data... */ + for (bitCounter=15; bitCounter>=0 ; bitCounter--) { + e100_send_mdio_bit(GET_BIT(bitCounter, data)); + } + +} + +static void e100_send_mdio_cmd(unsigned short cmd, int write_cmd) { int bitCounter; @@ -801,6 +935,9 @@ static void e100_tx_timeout(struct net_device *dev) { struct net_local *np = (struct net_local *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&np->lock, flags); printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ problem" : "network cable problem"); @@ -818,14 +955,22 @@ e100_tx_timeout(struct net_device *dev) e100_reset_transceiver(); - /* and get rid of the packet that never got an interrupt */ - - dev_kfree_skb(tx_skb); - tx_skb = 0; - + /* and get rid of the packets that never got an interrupt */ + while (myFirstTxDesc != myNextTxDesc) + { + dev_kfree_skb(myFirstTxDesc->skb); + myFirstTxDesc->skb = 0; + myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); + } + + /* Set up transmit DMA channel so it can be restarted later */ + *R_DMA_CH0_FIRST = 0; + *R_DMA_CH0_DESCR = virt_to_phys(myLastTxDesc); + /* tell the upper layers we're ok again */ netif_wake_queue(dev); + spin_unlock_irqrestore(&np->lock, flags); } @@ -841,25 +986,30 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) 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 long flags; #ifdef ETHDEBUG printk("send packet len %d\n", length); #endif - spin_lock_irq(&np->lock); /* protect from tx_interrupt */ + spin_lock_irqsave(&np->lock, flags); /* protect from tx_interrupt and ourself */ + + myNextTxDesc->skb = skb; - tx_skb = skb; /* remember it so we can free it in the tx irq handler later */ dev->trans_start = jiffies; e100_hardware_send_packet(buf, length); - /* this simple TX driver has only one send-descriptor so we're full - * directly. If this had a send-ring instead, we would only do this if - * the ring got full. - */ + myNextTxDesc = phys_to_virt(myNextTxDesc->descr.next); - netif_stop_queue(dev); + /* Stop queue if full */ + 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); + } - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); return 0; } @@ -869,12 +1019,14 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev) * Handle the network interface interrupts. */ -static void -e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t +e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = (struct net_device *)dev_id; + struct net_local *np = (struct net_local *)dev->priv; unsigned long irqbits = *R_IRQ_MASK2_RD; + /* Handle received packets */ if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma1_eop, active)) { /* acknowledge the eop interrupt */ @@ -899,51 +1051,31 @@ e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) so we have to loop back and check if so */ } } -} - -/* the transmit dma channel interrupt - * - * this is supposed to free the skbuff which was pending during transmission, - * and inform the kernel that we can send one more buffer - */ -static void -e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - unsigned long irqbits = *R_IRQ_MASK2_RD; - struct net_local *np = (struct net_local *)dev->priv; - - /* check for a dma0_eop interrupt */ - if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { - /* This protects us from concurrent execution of - * our dev->hard_start_xmit function above. - */ - - spin_lock(&np->lock); - - /* acknowledge the eop interrupt */ + /* Report any packets that have been sent */ + while (myFirstTxDesc != phys_to_virt(*R_DMA_CH0_FIRST) && + myFirstTxDesc != myNextTxDesc) + { + np->stats.tx_bytes += myFirstTxDesc->skb->len; + np->stats.tx_packets++; + + /* dma is ready with the transmission of the data in tx_skb, so now + we can release the skb memory */ + dev_kfree_skb_irq(myFirstTxDesc->skb); + myFirstTxDesc->skb = 0; + myFirstTxDesc = phys_to_virt(myFirstTxDesc->descr.next); + } + if (irqbits & IO_STATE(R_IRQ_MASK2_RD, dma0_eop, active)) { + /* acknowledge the eop interrupt and wake up queue */ *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do); - - if (*R_DMA_CH0_FIRST == 0 && tx_skb) { - np->stats.tx_bytes += tx_skb->len; - np->stats.tx_packets++; - /* dma is ready with the transmission of the data in tx_skb, so now - we can release the skb memory */ - dev_kfree_skb_irq(tx_skb); - tx_skb = 0; - netif_wake_queue(dev); - } else { - printk(KERN_WARNING "%s: tx weird interrupt\n", - cardname); - } - - spin_unlock(&np->lock); + *R_IRQ_MASK2_CLR = IO_STATE(R_IRQ_MASK2_CLR, dma0_eop, clr); + netif_wake_queue(dev); } + return IRQ_HANDLED; } -static void +static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct net_device *dev = (struct net_device *)dev_id; @@ -968,7 +1100,7 @@ e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs) np->stats.tx_errors++; D(printk("ethernet excessive collisions!\n")); } - + return IRQ_HANDLED; } /* We have a good packet(s), get it/them out of the buffers. */ @@ -978,7 +1110,6 @@ e100_rx(struct net_device *dev) struct sk_buff *skb; int length = 0; struct net_local *np = (struct net_local *)dev->priv; - struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; unsigned char *skb_data_ptr; #ifdef ETHDEBUG int i; @@ -994,24 +1125,13 @@ e100_rx(struct net_device *dev) mod_timer(&clear_led_timer, jiffies + HZ/10); } - /* If the packet is broken down in many small packages then merge - * count how much space we will need to alloc with skb_alloc() for - * it to fit. - */ - - while (!(myNextRxDesc->status & d_eop)) { - length += myNextRxDesc->sw_len; /* use sw_len for the first descs */ - myNextRxDesc->status = 0; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - } - - length += myNextRxDesc->hw_len; /* use hw_len for the last descr */ + length = myNextRxDesc->descr.hw_len - 4; ((struct net_local *)dev->priv)->stats.rx_bytes += length; #ifdef ETHDEBUG printk("Got a packet of length %d:\n", length); /* dump the first bytes in the packet */ - skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); + skb_data_ptr = (unsigned char *)phys_to_virt(myNextRxDesc->descr.buf); for (i = 0; i < 8; i++) { printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], @@ -1020,53 +1140,68 @@ e100_rx(struct net_device *dev) } #endif - skb = dev_alloc_skb(length - ETHER_HEAD_LEN); - if (!skb) { - np->stats.rx_errors++; - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); - return; - } + if (length < RX_COPYBREAK) { + /* Small packet, copy data */ + skb = dev_alloc_skb(length - ETHER_HEAD_LEN); + if (!skb) { + np->stats.rx_errors++; + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + return; + } - skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ - skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ + skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ + skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ #ifdef ETHDEBUG - printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", - skb->head, skb->data, skb->tail, skb->end); - printk("copying packet to 0x%x.\n", skb_data_ptr); + printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", + skb->head, skb->data, skb->tail, skb->end); + printk("copying packet to 0x%x.\n", skb_data_ptr); #endif - - /* this loop can be made using max two memcpy's if optimized */ - - while (mySaveRxDesc != myNextRxDesc) { - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->sw_len); - skb_data_ptr += mySaveRxDesc->sw_len; - mySaveRxDesc = phys_to_virt(mySaveRxDesc->next); + + memcpy(skb_data_ptr, phys_to_virt(myNextRxDesc->descr.buf), length); + } + else { + /* Large packet, send directly to upper layers and allocate new + * memory (aligned to cache line boundary to avoid bug). + * Before sending the skb to upper layers we must make sure that + * skb->data points to the aligned start of the packet. + */ + int align; + struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES); + if (!new_skb) { + np->stats.rx_errors++; + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + return; + } + skb = myNextRxDesc->skb; + align = (int)phys_to_virt(myNextRxDesc->descr.buf) - (int)skb->data; + skb_put(skb, length + align); + skb_pull(skb, align); /* Remove alignment bytes */ + myNextRxDesc->skb = new_skb; + myNextRxDesc->descr.buf = L1_CACHE_ALIGN(virt_to_phys(myNextRxDesc->skb->data)); } - - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->hw_len); skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); /* Send the packet to the upper layers */ - netif_rx(skb); /* Prepare for next packet */ - - myNextRxDesc->status = 0; + myNextRxDesc->descr.status = 0; myPrevRxDesc = myNextRxDesc; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); + myNextRxDesc = phys_to_virt(myNextRxDesc->descr.next); - myPrevRxDesc->ctrl |= d_eol; - myLastRxDesc->ctrl &= ~d_eol; - myLastRxDesc = myPrevRxDesc; + rx_queue_len++; - return; + /* Check if descriptors should be returned */ + if (rx_queue_len == RX_QUEUE_THRESHOLD) { + flush_etrax_cache(); + myPrevRxDesc->descr.ctrl |= d_eol; + myLastRxDesc->descr.ctrl &= ~d_eol; + myLastRxDesc = myPrevRxDesc; + rx_queue_len = 0; + } } /* The inverse routine to net_open(). */ @@ -1105,9 +1240,6 @@ e100_close(struct net_device *dev) free_irq(NETWORK_DMA_TX_IRQ_NBR, (void *)dev); free_irq(NETWORK_STATUS_IRQ_NBR, (void *)dev); - free_dma(NETWORK_TX_DMA_NBR); - free_dma(NETWORK_RX_DMA_NBR); - /* Update the statistics here. */ update_rx_stats(&np->stats); @@ -1119,8 +1251,24 @@ e100_close(struct net_device *dev) static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - /* Maybe default should return -EINVAL instead? */ + struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; + struct net_local *np = (struct net_local *)dev->priv; + + spin_lock(&np->lock); /* Preempt protection */ switch (cmd) { + case SIOCETHTOOL: + return e100_ethtool_ioctl(dev,ifr); + case SIOCGMIIPHY: /* Get PHY address */ + data->phy_id = MDIO_PHYS_ADDR; + break; + case SIOCGMIIREG: /* Read MII register */ + data->val_out = e100_get_mdio_reg(data->reg_num); + break; + case SIOCSMIIREG: /* Write MII register */ + e100_set_mdio_reg(data->reg_num, data->val_in); + break; + /* The ioctls below should be considered obsolete but are */ + /* still present for compatability with old scripts/apps */ case SET_ETH_SPEED_10: /* 10 Mbps */ e100_set_speed(10); break; @@ -1139,11 +1287,128 @@ e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SET_ETH_DUPLEX_AUTO: /* Autonegotiate duplex*/ e100_set_duplex(autoneg); break; - default: /* Auto neg */ + default: + return -EINVAL; + } + spin_unlock(&np->lock); + return 0; +} + +static int +e100_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr) +{ + struct ethtool_cmd ecmd; + + if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) + return -EFAULT; + + switch (ecmd.cmd) { + case ETHTOOL_GSET: + { + memset((void *) &ecmd, 0, sizeof (ecmd)); + ecmd.supported = + SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | + SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; + ecmd.port = PORT_TP; + ecmd.transceiver = XCVR_EXTERNAL; + ecmd.phy_address = MDIO_PHYS_ADDR; + ecmd.speed = current_speed; + ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF; + ecmd.advertising = ADVERTISED_TP; + if (current_duplex == autoneg && current_speed_selection == 0) + ecmd.advertising = ADVERTISED_Autoneg; + else { + ecmd.advertising |= + ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; + if (current_speed_selection == 10) + ecmd.advertising &= ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full); + else if (current_speed_selection == 100) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full); + if (current_duplex == half) + ecmd.advertising &= ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full); + else if (current_duplex == full) + ecmd.advertising &= ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half); + } + ecmd.autoneg = AUTONEG_ENABLE; + if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) + return -EFAULT; + } + break; + case ETHTOOL_SSET: + { + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + if (ecmd.autoneg == AUTONEG_ENABLE) { + e100_set_duplex(autoneg); + e100_set_speed(0); + } else { + e100_set_duplex(ecmd.duplex == DUPLEX_HALF ? half : full); + e100_set_speed(ecmd.speed == SPEED_10 ? 10: 100); + } + } + break; + case ETHTOOL_GDRVINFO: + { + struct ethtool_drvinfo info; + memset((void *) &info, 0, sizeof (info)); + strncpy(info.driver, "ETRAX 100LX", sizeof(info.driver) - 1); + strncpy(info.version, "$Revision: 1.17 $", sizeof(info.version) - 1); + strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1); + strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1); + info.regdump_len = 0; + info.eedump_len = 0; + info.testinfo_len = 0; + if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) + return -EFAULT; + } + break; + case ETHTOOL_NWAY_RST: + if (current_duplex == autoneg && current_speed_selection == 0) + e100_negotiate(); + break; + default: + return -EOPNOTSUPP; + break; + } + return 0; +} + +static int +e100_set_config(struct net_device *dev, struct ifmap *map) +{ + struct net_local *np = (struct net_local *)dev->priv; + spin_lock(&np->lock); /* Preempt protection */ + + switch(map->port) { + case IF_PORT_UNKNOWN: + /* Use autoneg */ e100_set_speed(0); e100_set_duplex(autoneg); break; + case IF_PORT_10BASET: + e100_set_speed(10); + e100_set_duplex(autoneg); + break; + case IF_PORT_100BASET: + case IF_PORT_100BASETX: + e100_set_speed(100); + e100_set_duplex(autoneg); + break; + case IF_PORT_100BASEFX: + case IF_PORT_10BASE2: + case IF_PORT_AUI: + spin_unlock(&np->lock); + return -EOPNOTSUPP; + break; + default: + printk(KERN_ERR "%s: Invalid media selected", dev->name); + spin_unlock(&np->lock); + return -EINVAL; } + spin_unlock(&np->lock); return 0; } @@ -1177,10 +1442,13 @@ static struct net_device_stats * e100_get_stats(struct net_device *dev) { struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + spin_lock_irqsave(&lp->lock, flags); update_rx_stats(&lp->stats); update_tx_stats(&lp->stats); - + + spin_unlock_irqrestore(&lp->lock, flags); return &lp->stats; } @@ -1194,9 +1462,11 @@ e100_get_stats(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { + struct net_local *lp = (struct net_local *)dev->priv; int num_addr = dev->mc_count; unsigned long int lo_bits; unsigned long int hi_bits; + spin_lock(&lp->lock); if (dev->flags & IFF_PROMISC) { /* promiscuous mode */ @@ -1255,7 +1525,7 @@ set_multicast_list(struct net_device *dev) hash_ix &= 0x3f; - if (hash_ix > 32) { + if (hash_ix >= 32) { hi_bits |= (1 << (hash_ix-32)); } else { @@ -1269,6 +1539,7 @@ set_multicast_list(struct net_device *dev) } *R_NETWORK_GA_0 = lo_bits; *R_NETWORK_GA_1 = hi_bits; + spin_unlock(&lp->lock); } void @@ -1287,15 +1558,16 @@ e100_hardware_send_packet(char *buf, int length) } /* configure the tx dma descriptor */ + myNextTxDesc->descr.sw_len = length; + myNextTxDesc->descr.ctrl = d_eop | d_eol | d_wait; + myNextTxDesc->descr.buf = virt_to_phys(buf); - TxDesc.sw_len = length; - TxDesc.ctrl = d_eop | d_eol | d_wait; - TxDesc.buf = virt_to_phys(buf); + /* Move end of list */ + myLastTxDesc->descr.ctrl &= ~d_eol; + myLastTxDesc = myNextTxDesc; - /* setup the dma channel and start it */ - - *R_DMA_CH0_FIRST = virt_to_phys(&TxDesc); - *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, start); + /* Restart DMA channel */ + *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, restart); } static void @@ -1323,7 +1595,7 @@ e100_set_network_leds(int active) if (!current_speed) { /* Make LED red, link is down */ - LED_NETWORK_SET(LED_RED); + LED_NETWORK_SET(LED_OFF); } else if (light_leds) { if (current_speed == 10) { diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c new file mode 100644 index 000000000000..a105cadaeed1 --- /dev/null +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -0,0 +1,907 @@ +/* $Id: gpio.c,v 1.8 2003/07/04 08:27:37 starvik Exp $ + * + * Etrax general port I/O device + * + * Copyright (c) 1999, 2000, 2001, 2002 Axis Communications AB + * + * Authors: Bjorn Wesen (initial version) + * Ola Knutsson (LED handling) + * Johan Adolfsson (read/set directions, write, port G) + * + * $Log: gpio.c,v $ + * Revision 1.8 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.7 2003/01/10 07:44:07 starvik + * init_ioremap is now called by kernel before drivers are initialized + * + * Revision 1.6 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.5 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.4 2002/11/18 10:10:05 starvik + * Linux 2.5 port of latest gpio.c from Linux 2.4 + * + * Revision 1.20 2002/10/16 21:16:24 johana + * Added support for PA high level interrupt. + * That gives 2ms response time with iodtest for high levels and 2-12 ms + * response time on low levels if the check is not made in + * process.c:cpu_idle() as well. + * + * Revision 1.19 2002/10/14 18:27:33 johana + * Implemented alarm handling so select() now works. + * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in + * cpu_idle(). + * Otherwise I get 15-18 ms (same as doing the poll in userspace - + * but less overhead). + * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it + * is in 2.4) as well? + * TODO? Perhaps call request_irq()/free_irq() only when needed? + * Increased version to 2.5 + * + * Revision 1.18 2002/10/11 15:02:00 johana + * Mask inverted 8 bit value in setget_input(). + * + * Revision 1.17 2002/06/17 15:53:01 johana + * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT + * that take a pointer as argument and thus can handle 32 bit ports (G) + * correctly. + * These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT. + * (especially if Port G bit 31 is used) + * + * Revision 1.16 2002/06/17 09:59:51 johana + * Returning 32 bit values in the ioctl return value doesn't work if bit + * 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF. + * A new set of ioctl's will be added. + * + * Revision 1.15 2002/05/06 13:19:13 johana + * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well. + * + * Revision 1.14 2002/04/12 12:01:53 johana + * Use global r_port_g_data_shadow. + * Moved gpio_init_port_g() closer to gpio_init() and marked it __init. + * + * Revision 1.13 2002/04/10 12:03:55 johana + * Added support for port G /dev/gpiog (minor 3). + * Changed indentation on switch cases. + * Fixed other spaces to tabs. + * + * Revision 1.12 2001/11/12 19:42:15 pkj + * * Corrected return values from gpio_leds_ioctl(). + * * Fixed compiler warnings. + * + * Revision 1.11 2001/10/30 14:39:12 johana + * Added D() around gpio_write printk. + * + * Revision 1.10 2001/10/25 10:24:42 johana + * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast + * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB + * from ~60 seconds to 4 seconds). + * Added save_flags/cli/restore_flags in ioctl. + * + * Revision 1.9 2001/05/04 14:16:07 matsfg + * Corrected spelling error + * + * Revision 1.8 2001/04/27 13:55:26 matsfg + * Moved initioremap. + * Turns off all LEDS on init. + * Added support for shutdown and powerbutton. + * + * Revision 1.7 2001/04/04 13:30:08 matsfg + * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping + * + * Revision 1.6 2001/03/26 16:03:06 bjornw + * Needs linux/config.h + * + * Revision 1.5 2001/03/26 14:22:03 bjornw + * Namechange of some config options + * + * Revision 1.4 2001/02/27 13:52:48 bjornw + * malloc.h -> slab.h + * + * Revision 1.3 2001/01/24 15:06:48 bjornw + * gpio_wq correct type + * + * Revision 1.2 2001/01/18 16:07:30 bjornw + * 2.4 port + * + * Revision 1.1 2001/01/18 15:55:16 bjornw + * Verbatim copy of etraxgpio.c from elinux 2.0 added + * + * + */ + +#include <linux/config.h> + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/poll.h> +#include <linux/init.h> +#include <linux/interrupt.h> + +#include <asm/etraxgpio.h> +#include <asm/arch/svinto.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/irq.h> + +#define GPIO_MAJOR 120 /* experimental MAJOR number */ + +#define D(x) + +#if 0 +static int dp_cnt; +#define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0) +#else +#define DP(x) +#endif + +static char gpio_name[] = "etrax gpio"; + +#if 0 +static wait_queue_head_t *gpio_wq; +#endif + +static int gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off); +static int gpio_open(struct inode *inode, struct file *filp); +static int gpio_release(struct inode *inode, struct file *filp); +static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); + +/* private data per open() of this driver */ + +struct gpio_private { + struct gpio_private *next; + /* These fields are for PA and PB only */ + volatile unsigned char *port, *shadow; + volatile unsigned char *dir, *dir_shadow; + unsigned char changeable_dir; + unsigned char changeable_bits; + unsigned char clk_mask; + unsigned char data_mask; + unsigned char write_msb; + unsigned char pad1, pad2, pad3; + /* These fields are generic */ + unsigned long highalarm, lowalarm; + wait_queue_head_t alarm_wq; + int minor; +}; + +/* linked list of alarms to check for */ + +static struct gpio_private *alarmlist = 0; + +static int gpio_some_alarms = 0; /* Set if someone uses alarm */ + +/* Port A and B use 8 bit access, but Port G is 32 bit */ +#define NUM_PORTS (GPIO_MINOR_B+1) + +static volatile unsigned char *ports[NUM_PORTS] = { + R_PORT_PA_DATA, + R_PORT_PB_DATA, +}; +static volatile unsigned char *shads[NUM_PORTS] = { + &port_pa_data_shadow, + &port_pb_data_shadow +}; + +/* What direction bits that are user changeable 1=changeable*/ +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR +#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00 +#endif +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR +#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00 +#endif + +#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS +#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF +#endif +#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS +#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF +#endif + + +static unsigned char changeable_dir[NUM_PORTS] = { + CONFIG_ETRAX_PA_CHANGEABLE_DIR, + CONFIG_ETRAX_PB_CHANGEABLE_DIR +}; +static unsigned char changeable_bits[NUM_PORTS] = { + CONFIG_ETRAX_PA_CHANGEABLE_BITS, + CONFIG_ETRAX_PB_CHANGEABLE_BITS +}; + +static volatile unsigned char *dir[NUM_PORTS] = { + R_PORT_PA_DIR, + R_PORT_PB_DIR +}; + +static volatile unsigned char *dir_shadow[NUM_PORTS] = { + &port_pa_dir_shadow, + &port_pb_dir_shadow +}; + +/* Port G is 32 bit, handle it special, some bits are both inputs + and outputs at the same time, only some of the bits can change direction + and some of them in groups of 8 bit. */ +static unsigned long changeable_dir_g; +static unsigned long dir_g_in_bits; +static unsigned long dir_g_out_bits; +static unsigned long dir_g_shadow; /* 1=output */ + +#define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B) + + + +static unsigned int +gpio_poll(struct file *file, + poll_table *wait) +{ + unsigned int mask = 0; + struct gpio_private *priv = (struct gpio_private *)file->private_data; + unsigned long data; + poll_wait(file, &priv->alarm_wq, wait); + if (priv->minor == GPIO_MINOR_A) { + unsigned long tmp; + data = *R_PORT_PA_DATA; + /* PA has support for high level interrupt - + * lets activate for those low and with highalarm set + */ + tmp = ~data & priv->highalarm & 0xFF; + *R_IRQ_MASK1_SET = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); + } else if (priv->minor == GPIO_MINOR_B) + data = *R_PORT_PB_DATA; + else if (priv->minor == GPIO_MINOR_G) + data = *R_PORT_G_DATA; + else + return 0; + + if ((data & priv->highalarm) || + (~data & priv->lowalarm)) { + mask = POLLIN|POLLRDNORM; + } + + DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); + return mask; +} + +int etrax_gpio_wake_up_check(void) +{ + struct gpio_private *priv = alarmlist; + unsigned long data = 0; + int ret = 0; + while (priv) { + if (USE_PORTS(priv)) { + data = *priv->port; + } else if (priv->minor == GPIO_MINOR_G) { + data = *R_PORT_G_DATA; + } + if ((data & priv->highalarm) || + (~data & priv->lowalarm)) { + DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor)); + wake_up_interruptible(&priv->alarm_wq); + ret = 1; + } + priv = priv->next; + } + return ret; +} + +static irqreturn_t +gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (gpio_some_alarms) { + etrax_gpio_wake_up_check(); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static irqreturn_t +gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long tmp; + /* Find what PA interrupts are active */ + tmp = (*R_IRQ_READ1 >> R_IRQ_READ1__pa0__BITNR) & 0xFF; + /* Clear them.. */ + /* NOTE: Maybe we need to be more careful here if some other + * driver uses PA interrupt as well? + */ + *R_IRQ_MASK1_CLR = (tmp << R_IRQ_MASK1_CLR__pa0__BITNR); + if (gpio_some_alarms) { + return IRQ_RETVAL(etrax_gpio_wake_up_check()); + } + return IRQ_NONE; +} + + +static ssize_t gpio_write(struct file * file, const char * buf, size_t count, + loff_t *off) +{ + struct gpio_private *priv = (struct gpio_private *)file->private_data; + unsigned char data, clk_mask, data_mask, write_msb; + unsigned long flags; + ssize_t retval = count; + if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { + return -EFAULT; + } + + if (verify_area(VERIFY_READ, buf, count)) { + return -EFAULT; + } + clk_mask = priv->clk_mask; + data_mask = priv->data_mask; + /* It must have been configured using the IO_CFG_WRITE_MODE */ + /* Perhaps a better error code? */ + if (clk_mask == 0 || data_mask == 0) { + return -EPERM; + } + write_msb = priv->write_msb; + D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); + while (count--) { + int i; + data = *buf++; + if (priv->write_msb) { + for (i = 7; i >= 0;i--) { + local_irq_save(flags); local_irq_disable(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<<i) + *priv->port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + local_irq_restore(flags); + } + } else { + for (i = 0; i <= 7;i++) { + local_irq_save(flags); local_irq_disable(); + *priv->port = *priv->shadow &= ~clk_mask; + if (data & 1<<i) + *priv->port = *priv->shadow |= data_mask; + else + *priv->port = *priv->shadow &= ~data_mask; + /* For FPGA: min 5.0ns (DCC) before CCLK high */ + *priv->port = *priv->shadow |= clk_mask; + local_irq_restore(flags); + } + } + } + return retval; +} + + + +static int +gpio_open(struct inode *inode, struct file *filp) +{ + struct gpio_private *priv; + int p = minor(inode->i_rdev); + + if (p > GPIO_MINOR_LAST) + return -EINVAL; + + priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), + GFP_KERNEL); + + if (!priv) + return -ENOMEM; + + priv->minor = p; + + /* initialize the io/alarm struct and link it into our alarmlist */ + + priv->next = alarmlist; + alarmlist = priv; + if (USE_PORTS(priv)) { /* A and B */ + priv->port = ports[p]; + priv->shadow = shads[p]; + priv->dir = dir[p]; + priv->dir_shadow = dir_shadow[p]; + priv->changeable_dir = changeable_dir[p]; + priv->changeable_bits = changeable_bits[p]; + } else { + priv->port = NULL; + priv->shadow = NULL; + priv->dir = NULL; + priv->dir_shadow = NULL; + priv->changeable_dir = 0; + priv->changeable_bits = 0; + } + + priv->highalarm = 0; + priv->lowalarm = 0; + priv->clk_mask = 0; + priv->data_mask = 0; + init_waitqueue_head(&priv->alarm_wq); + + filp->private_data = (void *)priv; + + return 0; +} + +static int +gpio_release(struct inode *inode, struct file *filp) +{ + struct gpio_private *p = alarmlist; + struct gpio_private *todel = (struct gpio_private *)filp->private_data; + + /* unlink from alarmlist and free the private structure */ + + if (p == todel) { + alarmlist = todel->next; + } else { + while (p->next != todel) + p = p->next; + p->next = todel->next; + } + + kfree(todel); + /* Check if there are still any alarms set */ + p = alarmlist; + while (p) { + if (p->highalarm | p->lowalarm) { + gpio_some_alarms = 1; + return 0; + } + p = p->next; + } + gpio_some_alarms = 0; + + return 0; +} + +/* Main device API. ioctl's to read/set/clear bits, as well as to + * set alarms to wait for using a subsequent select(). + */ + +unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) +{ + /* Set direction 0=unchanged 1=input, + * return mask with 1=input + */ + unsigned long flags; + if (USE_PORTS(priv)) { + local_irq_save(flags); local_irq_disable(); + *priv->dir = *priv->dir_shadow &= + ~((unsigned char)arg & priv->changeable_dir); + local_irq_restore(flags); + return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ + } else if (priv->minor == GPIO_MINOR_G) { + /* We must fiddle with R_GEN_CONFIG to change dir */ + if (((arg & dir_g_in_bits) != arg) && + (arg & changeable_dir_g)) { + arg &= changeable_dir_g; + /* Clear bits in genconfig to set to input */ + if (arg & (1<<0)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir); + dir_g_in_bits |= (1<<0); + dir_g_out_bits &= ~(1<<0); + } + if ((arg & 0x0000FF00) == 0x0000FF00) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir); + dir_g_in_bits |= 0x0000FF00; + dir_g_out_bits &= ~0x0000FF00; + } + if ((arg & 0x00FF0000) == 0x00FF0000) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir); + dir_g_in_bits |= 0x00FF0000; + dir_g_out_bits &= ~0x00FF0000; + } + if (arg & (1<<24)) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir); + dir_g_in_bits |= (1<<24); + dir_g_out_bits &= ~(1<<24); + } + printk("gpio: SETINPUT on port G set " + "genconfig to 0x%08lX " + "in_bits: 0x%08lX " + "out_bits: 0x%08lX\n", + (unsigned long)genconfig_shadow, + dir_g_in_bits, dir_g_out_bits); + *R_GEN_CONFIG = genconfig_shadow; + /* Must be a >120 ns delay before writing this again */ + + } + return dir_g_in_bits; + } + return 0; +} /* setget_input */ + +unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) +{ + unsigned long flags; + if (USE_PORTS(priv)) { + local_irq_save(flags); local_irq_disable(); + *priv->dir = *priv->dir_shadow |= + ((unsigned char)arg & priv->changeable_dir); + local_irq_restore(flags); + return *priv->dir_shadow; + } else if (priv->minor == GPIO_MINOR_G) { + /* We must fiddle with R_GEN_CONFIG to change dir */ + if (((arg & dir_g_out_bits) != arg) && + (arg & changeable_dir_g)) { + /* Set bits in genconfig to set to output */ + if (arg & (1<<0)) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir); + dir_g_out_bits |= (1<<0); + dir_g_in_bits &= ~(1<<0); + } + if ((arg & 0x0000FF00) == 0x0000FF00) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir); + dir_g_out_bits |= 0x0000FF00; + dir_g_in_bits &= ~0x0000FF00; + } + if ((arg & 0x00FF0000) == 0x00FF0000) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir); + dir_g_out_bits |= 0x00FF0000; + dir_g_in_bits &= ~0x00FF0000; + } + if (arg & (1<<24)) { + genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir); + dir_g_out_bits |= (1<<24); + dir_g_in_bits &= ~(1<<24); + } + printk("gpio: SETOUTPUT on port G set " + "genconfig to 0x%08lX " + "in_bits: 0x%08lX " + "out_bits: 0x%08lX\n", + (unsigned long)genconfig_shadow, + dir_g_in_bits, dir_g_out_bits); + *R_GEN_CONFIG = genconfig_shadow; + /* Must be a >120 ns delay before writing this again */ + } + return dir_g_out_bits & 0x7FFFFFFF; + } + return 0; +} /* setget_output */ + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg); + +static int +gpio_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + unsigned long val; + struct gpio_private *priv = (struct gpio_private *)file->private_data; + if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { + return -EINVAL; + } + + switch (_IOC_NR(cmd)) { + case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ + // read the port + if (USE_PORTS(priv)) { + return *priv->port; + } else if (priv->minor == GPIO_MINOR_G) { + return (*R_PORT_G_DATA) & 0x7FFFFFFF; + } + break; + case IO_SETBITS: + local_irq_save(flags); local_irq_disable(); + // set changeable bits with a 1 in arg + if (USE_PORTS(priv)) { + *priv->port = *priv->shadow |= + ((unsigned char)arg & priv->changeable_bits); + } else if (priv->minor == GPIO_MINOR_G) { + *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits); + } + local_irq_restore(flags); + break; + case IO_CLRBITS: + local_irq_save(flags); local_irq_disable(); + // clear changeable bits with a 1 in arg + if (USE_PORTS(priv)) { + *priv->port = *priv->shadow &= + ~((unsigned char)arg & priv->changeable_bits); + } else if (priv->minor == GPIO_MINOR_G) { + *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits); + } + local_irq_restore(flags); + break; + case IO_HIGHALARM: + // set alarm when bits with 1 in arg go high + priv->highalarm |= arg; + gpio_some_alarms = 1; + break; + case IO_LOWALARM: + // set alarm when bits with 1 in arg go low + priv->lowalarm |= arg; + gpio_some_alarms = 1; + break; + case IO_CLRALARM: + // clear alarm for bits with 1 in arg + priv->highalarm &= ~arg; + priv->lowalarm &= ~arg; + break; + case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ + /* Read direction 0=input 1=output */ + if (USE_PORTS(priv)) { + return *priv->dir_shadow; + } else if (priv->minor == GPIO_MINOR_G) { + /* Note: Some bits are both in and out, + * Those that are dual is set here as well. + */ + return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; + } + case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ + /* Set direction 0=unchanged 1=input, + * return mask with 1=input + */ + return setget_input(priv, arg) & 0x7FFFFFFF; + break; + case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ + /* Set direction 0=unchanged 1=output, + * return mask with 1=output + */ + return setget_output(priv, arg) & 0x7FFFFFFF; + + case IO_SHUTDOWN: + SOFT_SHUTDOWN(); + break; + case IO_GET_PWR_BT: +#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) + return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); +#else + return 0; +#endif + break; + case IO_CFG_WRITE_MODE: + priv->clk_mask = arg & 0xFF; + priv->data_mask = (arg >> 8) & 0xFF; + priv->write_msb = (arg >> 16) & 0x01; + /* Check if we're allowed to change the bits and + * the direction is correct + */ + if (!((priv->clk_mask & priv->changeable_bits) && + (priv->data_mask & priv->changeable_bits) && + (priv->clk_mask & *priv->dir_shadow) && + (priv->data_mask & *priv->dir_shadow))) + { + priv->clk_mask = 0; + priv->data_mask = 0; + return -EPERM; + } + break; + case IO_READ_INBITS: + /* *arg is result of reading the input pins */ + if (USE_PORTS(priv)) { + val = *priv->port; + } else if (priv->minor == GPIO_MINOR_G) { + val = *R_PORT_G_DATA; + } + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + return 0; + break; + case IO_READ_OUTBITS: + /* *arg is result of reading the output shadow */ + if (USE_PORTS(priv)) { + val = *priv->shadow; + } else if (priv->minor == GPIO_MINOR_G) { + val = port_g_data_shadow; + } + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + break; + case IO_SETGET_INPUT: + /* bits set in *arg is set to input, + * *arg updated with current input pins. + */ + if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) + return -EFAULT; + val = setget_input(priv, val); + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + break; + case IO_SETGET_OUTPUT: + /* bits set in *arg is set to output, + * *arg updated with current output pins. + */ + if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) + return -EFAULT; + val = setget_output(priv, val); + if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) + return -EFAULT; + break; + default: + if (priv->minor == GPIO_MINOR_LEDS) + return gpio_leds_ioctl(cmd, arg); + else + return -EINVAL; + } /* switch */ + + return 0; +} + +static int +gpio_leds_ioctl(unsigned int cmd, unsigned long arg) +{ + unsigned char green; + unsigned char red; + + switch (_IOC_NR(cmd)) { + case IO_LEDACTIVE_SET: + green = ((unsigned char) arg) & 1; + red = (((unsigned char) arg) >> 1) & 1; + LED_ACTIVE_SET_G(green); + LED_ACTIVE_SET_R(red); + break; + + case IO_LED_SETBIT: + LED_BIT_SET(arg); + break; + + case IO_LED_CLRBIT: + LED_BIT_CLR(arg); + break; + + default: + return -EINVAL; + } /* switch */ + + return 0; +} + +struct file_operations gpio_fops = { + .owner = THIS_MODULE, + .poll = gpio_poll, + .ioctl = gpio_ioctl, + .write = gpio_write, + .open = gpio_open, + .release = gpio_release, +}; + + +static void __init gpio_init_port_g(void) +{ +#define GROUPA (0x0000FF3F) +#define GROUPB (1<<6 | 1<<7) +#define GROUPC (1<<30 | 1<<31) +#define GROUPD (0x3FFF0000) +#define GROUPD_LOW (0x00FF0000) + unsigned long used_in_bits = 0; + unsigned long used_out_bits = 0; + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){ + used_in_bits |= GROUPA | GROUPB | 0 | 0; + used_out_bits |= GROUPA | GROUPB | 0 | 0; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) { + used_in_bits |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26)); + used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD; + } + + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) { + used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; + used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) { + used_in_bits |= 0 | GROUPB | 0 | 0; + used_out_bits |= 0 | GROUPB | 0 | 0; + } + /* mio same as shared RAM ? */ + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) { + used_in_bits |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW; + used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) { + used_in_bits |= 0 | 0 | GROUPC | GROUPD; + used_out_bits |= 0 | 0 | GROUPC | GROUPD; + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) { + used_in_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24); + used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26); + } + + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) { + used_in_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); + used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); + } + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) { + used_in_bits |= 0 | 0 | GROUPC | 0; + used_out_bits |= 0 | 0 | GROUPC | 0; + } + /* mio same as shared RAM-W? */ + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) { + used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW; + used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW; + } + /* TODO: USB p2, parw, sync ser3? */ + + /* Initialise the dir_g_shadow etc. depending on genconfig */ + /* 0=input 1=output */ + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out)) + dir_g_shadow |= (1 << 0); + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out)) + dir_g_shadow |= 0x0000FF00; + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out)) + dir_g_shadow |= 0x00FF0000; + if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out)) + dir_g_shadow |= (1 << 24); + + dir_g_in_bits = ~used_in_bits; + dir_g_out_bits = ~used_out_bits; + + changeable_dir_g = 0x01FFFF01; /* all that can change dir */ + changeable_dir_g &= dir_g_out_bits; + changeable_dir_g &= dir_g_in_bits; + /* Correct the bits that can change direction */ + dir_g_out_bits &= ~changeable_dir_g; + dir_g_out_bits |= dir_g_shadow; + dir_g_in_bits &= ~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", + dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); + printk("GPIO port G: dir: %08lX changeable: %08lX\n", + dir_g_shadow, changeable_dir_g); +} + +/* main driver initialization routine, called from mem.c */ + +static __init int +gpio_init(void) +{ + int res; +#if defined (CONFIG_ETRAX_CSP0_LEDS) + int i; +#endif + + /* do the formalities */ + + res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); + if (res < 0) { + printk(KERN_ERR "gpio: couldn't get a major number.\n"); + return res; + } + + /* Clear all leds */ +#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) + LED_NETWORK_SET(0); + LED_ACTIVE_SET(0); + LED_DISK_READ(0); + LED_DISK_WRITE(0); + +#if defined (CONFIG_ETRAX_CSP0_LEDS) + for (i = 0; i < 32; i++) { + LED_BIT_SET(i); + } +#endif + +#endif + gpio_init_port_g(); + printk("ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); + /* We call etrax_gpio_wake_up_check() from timer interrupt and + * from cpu_idle() in kernel/process.c + * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms + * in some tests. + */ + if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt, + SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) { + printk("err: timer0 irq for gpio\n"); + } + if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt, + SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) { + printk("err: PA irq for gpio\n"); + } + + + return res; +} + +/* this makes sure that gpio_init is called during kernel boot */ + +module_init(gpio_init); diff --git a/arch/cris/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c index 093c5d5dac13..7731f7d22f91 100644 --- a/arch/cris/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c @@ -12,8 +12,25 @@ *! don't use PB_I2C if DS1302 uses same bits, *! use PB. *! $Log: i2c.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.4 2002/12/11 13:13:57 starvik +*! Added arch/ to v10 specific includes +*! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) +*! +*! Revision 1.3 2002/11/20 11:56:11 starvik +*! Merge of Linux 2.5.48 +*! +*! Revision 1.2 2002/11/18 13:16:06 starvik +*! Linux 2.5 port of latest 2.4 drivers +*! +*! Revision 1.9 2002/10/31 15:32:26 starvik +*! Update Port B register and shadow even when running with hardware support +*! to avoid glitches when reading bits +*! Never set direction to out in i2c_inbyte +*! Removed incorrect clock togling at end of i2c_inbyte +*! +*! Revision 1.8 2002/08/13 06:31:53 starvik +*! Made SDA and SCL line configurable +*! Modified i2c_inbyte to work with PCF8563 *! *! Revision 1.7 2001/04/04 13:11:36 markusl *! Updated according to review remarks @@ -43,10 +60,11 @@ *! *! --------------------------------------------------------------------------- *! -*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! *!***************************************************************************/ -/* $Id: i2c.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */ +/* $Id: i2c.c,v 1.4 2002/12/11 13:13:57 starvik Exp $ */ + /****************** INCLUDE FILES SECTION ***********************************/ #include <linux/module.h> @@ -62,7 +80,7 @@ #include <asm/etraxi2c.h> #include <asm/system.h> -#include <asm/svinto.h> +#include <asm/arch/svinto.h> #include <asm/io.h> #include <asm/delay.h> @@ -96,8 +114,15 @@ static const char i2c_name[] = "i2c"; #ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C /* Use PB and not PB_I2C */ -#define SDABIT 0 -#define SCLBIT 1 +#ifndef CONFIG_ETRAX_I2C_DATA_PORT +#define CONFIG_ETRAX_I2C_DATA_PORT 0 +#endif +#ifndef CONFIG_ETRAX_I2C_CLK_PORT +#define CONFIG_ETRAX_I2C_CLK_PORT 1 +#endif + +#define SDABIT CONFIG_ETRAX_I2C_DATA_PORT +#define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT #define i2c_enable() #define i2c_disable() @@ -117,7 +142,7 @@ static const char i2c_name[] = "i2c"; /* read a bit from the i2c interface */ -#define i2c_getbit() (*R_PORT_PB_READ & (1 << SDABIT)) +#define i2c_getbit() (((*R_PORT_PB_READ & (1 << SDABIT))) >> SDABIT) #else /* enable or disable the i2c interface */ @@ -127,16 +152,24 @@ static const char i2c_name[] = "i2c"; /* enable or disable output-enable, to select output or input on the i2c bus */ -#define i2c_dir_out() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)) -#define i2c_dir_in() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)) +#define i2c_dir_out() \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); +#define i2c_dir_in() \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \ + REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0); /* control the i2c clock and data signals */ -#define i2c_clk(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ - ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))) +#define i2c_clk(x) \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x); -#define i2c_data(x) *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ - ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))) +#define i2c_data(x) \ + *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ + ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x); /* read a bit from the i2c interface */ @@ -209,14 +242,15 @@ void i2c_outbyte(unsigned char x) { int i; - + i2c_dir_out(); for (i = 0; i < 8; i++) { - if (x & 0x80) + if (x & 0x80) { i2c_data(I2C_DATA_HIGH); - else + } else { i2c_data(I2C_DATA_LOW); + } i2c_delay(CLOCK_LOW_TIME/2); i2c_clk(I2C_CLOCK_HIGH); @@ -241,65 +275,41 @@ i2c_inbyte(void) { unsigned char aBitByte = 0; int i; - int iaa; - /* - * enable output - */ - i2c_dir_out(); - /* - * Release data bus by setting - * data high - */ - i2c_data(I2C_DATA_HIGH); - /* - * enable input - */ + /* Switch off I2C to get bit */ + i2c_disable(); i2c_dir_in(); - /* - * Use PORT PB instead of I2C - * for input. (I2C not working) - */ - i2c_clk(1); - i2c_data(1); - /* - * get bits - */ - for (i = 0; i < 8; i++) { - i2c_delay(CLOCK_LOW_TIME/2); - /* - * low clock period - */ + i2c_delay(CLOCK_HIGH_TIME/2); + + /* Get bit */ + aBitByte |= i2c_getbit(); + + /* Enable I2C */ + i2c_enable(); + i2c_delay(CLOCK_LOW_TIME/2); + + for (i = 1; i < 8; i++) { + aBitByte <<= 1; + /* Clock pulse */ i2c_clk(I2C_CLOCK_HIGH); - /* - * switch off I2C - */ - i2c_data(1); + i2c_delay(CLOCK_HIGH_TIME); + i2c_clk(I2C_CLOCK_LOW); + i2c_delay(CLOCK_LOW_TIME); + + /* Switch off I2C to get bit */ i2c_disable(); i2c_dir_in(); - /* - * wait before getting bit - */ - i2c_delay(CLOCK_HIGH_TIME/2); - aBitByte = (aBitByte << 1); - iaa = i2c_getbit(); - aBitByte = aBitByte | iaa ; - /* - * wait - */ i2c_delay(CLOCK_HIGH_TIME/2); - /* - * end clock puls - */ + + /* Get bit */ + aBitByte |= i2c_getbit(); + + /* Enable I2C */ i2c_enable(); - i2c_dir_out(); - i2c_clk(I2C_CLOCK_LOW); - /* - * low clock period - */ i2c_delay(CLOCK_LOW_TIME/2); } - i2c_dir_out(); + i2c_clk(I2C_CLOCK_HIGH); + i2c_delay(CLOCK_HIGH_TIME); return aBitByte; } @@ -424,44 +434,25 @@ i2c_sendack(void) *# *#--------------------------------------------------------------------------*/ int -i2c_writereg(unsigned char theSlave, unsigned char theReg, +i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue) { int error, cntr = 3; unsigned long flags; - + do { error = 0; /* * we don't like to be interrupted */ - save_flags(flags); - cli(); - /* - * generate start condition - */ - i2c_start(); - /* - * dummy preamble - */ - i2c_outbyte(0x01); - i2c_data(I2C_DATA_HIGH); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ - i2c_data(I2C_DATA_LOW); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); + local_irq_save(flags); + local_irq_disable(); i2c_start(); /* * send slave address */ - i2c_outbyte(theSlave); + i2c_outbyte((theSlave & 0xfe)); /* * wait for ack */ @@ -493,10 +484,10 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, /* * enable interrupt again */ - restore_flags(flags); + local_irq_restore(flags); } while(error && cntr--); - + i2c_delay(CLOCK_LOW_TIME); return -error; @@ -515,40 +506,23 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) unsigned char b = 0; int error, cntr = 3; unsigned long flags; - + do { error = 0; /* * we don't like to be interrupted */ - save_flags(flags); - cli(); + local_irq_save(flags); + local_irq_disable(); /* * generate start condition */ i2c_start(); - /* - * dummy preamble - */ - i2c_outbyte(0x01); - i2c_data(I2C_DATA_HIGH); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_HIGH_TIME); /* Dummy Acknowledge */ - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - i2c_clk(I2C_CLOCK_HIGH); - i2c_delay(CLOCK_LOW_TIME); /* Repeated Start Condition */ - i2c_data(I2C_DATA_LOW); - i2c_delay(CLOCK_HIGH_TIME); - i2c_clk(I2C_CLOCK_LOW); - i2c_delay(CLOCK_LOW_TIME); - - i2c_start(); /* * send slave address */ - i2c_outbyte(theSlave); + i2c_outbyte((theSlave & 0xfe)); /* * wait for ack */ @@ -593,7 +567,7 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) /* * enable interrupt again */ - restore_flags(flags); + local_irq_restore(flags); } while(error && cntr--); diff --git a/arch/cris/drivers/i2c.h b/arch/cris/arch-v10/drivers/i2c.h index d789274adc71..d0caa9ff883e 100644 --- a/arch/cris/drivers/i2c.h +++ b/arch/cris/arch-v10/drivers/i2c.h @@ -1,4 +1,4 @@ -/* $Id: i2c.h,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ */ +/* $Id: i2c.h,v 1.2 2002/11/18 13:16:06 starvik Exp $ */ /* High level I2C actions */ int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c new file mode 100644 index 000000000000..6a677bce6f14 --- /dev/null +++ b/arch/cris/arch-v10/drivers/pcf8563.c @@ -0,0 +1,287 @@ +/* + * PCF8563 RTC + * + * From Phillips' datasheet: + * + * The PCF8563 is a CMOS real-time clock/calendar optimized for low power + * consumption. A programmable clock output, interupt output and voltage + * low detector are also provided. All address and data are transferred + * serially via two-line bidirectional I2C-bus. Maximum bus speed is + * 400 kbits/s. The built-in word address register is incremented + * automatically after each written or read bute. + * + * Copyright (c) 2002, Axis Communications AB + * All rights reserved. + * + * Author: Tobias Anderberg <tobiasa@axis.com>. + * + * $Id: pcf8563.c,v 1.1 2002/12/12 08:27:26 starvik Exp $ + */ + +#include <linux/config.h> +#include <linux/version.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/ioctl.h> +#include <linux/delay.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/arch/svinto.h> +#include <asm/rtc.h> +#include "i2c.h" + +#define PCF8563_MAJOR 121 /* Local major number. */ +#define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ +#define PCF8563_NAME "PCF8563" +#define DRIVER_VERSION "$Revision: 1.1 $" + +/* I2C bus slave registers. */ +#define RTC_I2C_READ 0xa3 +#define RTC_I2C_WRITE 0xa2 + +/* Two simple wrapper macros, saves a few keystrokes. */ +#define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) +#define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) + +static const unsigned char days_in_month[] = + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int pcf8563_open(struct inode *, struct file *); +int pcf8563_release(struct inode *, struct file *); + +static struct file_operations pcf8563_fops = { + owner: THIS_MODULE, + ioctl: pcf8563_ioctl, + open: pcf8563_open, + release: pcf8563_release, +}; + +unsigned char +pcf8563_readreg(int reg) +{ + unsigned char res = i2c_readreg(RTC_I2C_READ, reg); + + /* The PCF8563 does not return 0 for unimplemented bits */ + switch(reg) + { + case RTC_SECONDS: + case RTC_MINUTES: + res &= 0x7f; + break; + case RTC_HOURS: + case RTC_DAY_OF_MONTH: + res &= 0x3f; + break; + case RTC_MONTH: + res = (res & 0x1f) - 1; /* PCF8563 returns month in range 1-12 */ + break; + } + return res; +} + +void +pcf8563_writereg(int reg, unsigned char val) +{ + i2c_writereg(RTC_I2C_WRITE,reg,val); +} + +void +get_rtc_time(struct rtc_time *tm) +{ + tm->tm_sec = rtc_read(RTC_SECONDS); + tm->tm_min = rtc_read(RTC_MINUTES); + tm->tm_hour = rtc_read(RTC_HOURS); + tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH); + tm->tm_mon = rtc_read(RTC_MONTH); + tm->tm_year = rtc_read(RTC_YEAR); + + if (tm->tm_sec & 0x80) + printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); + + tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0); + tm->tm_sec &= 0x7f; + tm->tm_min &= 0x7f; + tm->tm_hour &= 0x3f; + tm->tm_mday &= 0x3f; + tm->tm_mon &= 0x1f; + + BCD_TO_BIN(tm->tm_sec); + BCD_TO_BIN(tm->tm_min); + BCD_TO_BIN(tm->tm_hour); + BCD_TO_BIN(tm->tm_mday); + BCD_TO_BIN(tm->tm_mon); + tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */ +} + +int __init +pcf8563_init(void) +{ + unsigned char ret; + /* + * First of all we need to reset the chip. This is done by + * clearing control1, control2 and clk freq, clear the + * Voltage Low bit, and resetting all alarms. + */ + if (rtc_write(RTC_CONTROL1, 0x00) < 0) + goto err; + + if (rtc_write(RTC_CONTROL2, 0x00) < 0) + goto err; + + if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0) + goto err; + + /* Clear the VL bit in the seconds register. */ + ret = rtc_read(RTC_SECONDS); + + if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0) + goto err; + + /* Reset the alarms. */ + if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0) + goto err; + + if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0) + goto err; + + if (rtc_write(RTC_DAY_ALARM, 0x00) < 0) + goto err; + + if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0) + 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.. */ + if (rtc_read(RTC_SECONDS) & 0x80) + printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); + + return 0; + +err: + printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); + return -1; +} + +void __exit +pcf8563_exit(void) +{ + if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) { + printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME); + } +} + +/* + * ioctl calls for this driver. Why return -ENOTTY upon error? Because + * POSIX says so! + */ +int +pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +{ + /* Some sanity checks. */ + if (_IOC_TYPE(cmd) != RTC_MAGIC) + return -ENOTTY; + + if (_IOC_NR(cmd) > RTC_MAX_IOCTL) + return -ENOTTY; + + switch (cmd) { + case RTC_RD_TIME: + { + struct rtc_time tm; + + get_rtc_time(&tm); + + if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { + return -EFAULT; + } + + return 0; + } + break; + case RTC_SET_TIME: + { + int leap; + int century; + unsigned long flags; + struct rtc_time tm; + + if (!capable(CAP_SYS_TIME)) + return -EPERM; + + if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time))) + return -EFAULT; + + /* Convert from struct tm to struct rtc_time. */ + tm.tm_year += 1900; + tm.tm_mon += 1; + + leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0; + + /* Perform some sanity checks. */ + if ((tm.tm_year < 1970) || + (tm.tm_mon > 12) || + (tm.tm_mday == 0) || + (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || + (tm.tm_hour >= 24) || + (tm.tm_min >= 60) || + (tm.tm_sec >= 60)) + return -EINVAL; + + century = (tm.tm_year >= 2000) ? 0x80 : 0; + tm.tm_year = tm.tm_year % 100; + + BIN_TO_BCD(tm.tm_year); + BIN_TO_BCD(tm.tm_mday); + BIN_TO_BCD(tm.tm_hour); + BIN_TO_BCD(tm.tm_min); + BIN_TO_BCD(tm.tm_sec); + tm.tm_mon |= century; + + rtc_write(RTC_YEAR, tm.tm_year); + rtc_write(RTC_MONTH, tm.tm_mon); + rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); + rtc_write(RTC_HOURS, tm.tm_hour); + rtc_write(RTC_MINUTES, tm.tm_min); + rtc_write(RTC_SECONDS, tm.tm_sec); + + return 0; + } + break; + default: + return -ENOTTY; + } + + return 0; +} + +int +pcf8563_open(struct inode *inode, struct file *filp) +{ + MOD_INC_USE_COUNT; + return 0; +} + +int +pcf8563_release(struct inode *inode, struct file *filp) +{ + MOD_DEC_USE_COUNT; + return 0; +} + +EXPORT_NO_SYMBOLS; +module_init(pcf8563_init); +module_exit(pcf8563_exit); diff --git a/arch/cris/drivers/serial.c b/arch/cris/arch-v10/drivers/serial.c index 1a47d686061f..2822ffb812cc 100644 --- a/arch/cris/drivers/serial.c +++ b/arch/cris/arch-v10/drivers/serial.c @@ -1,13 +1,129 @@ -/* $Id: serial.c,v 1.3 2001/12/19 10:32:35 johana Exp $ +/* $Id: serial.c,v 1.17 2003/07/04 08:27:37 starvik Exp $ * * Serial port driver for the ETRAX 100LX chip * - * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Axis Communications AB * - * 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 $ - * Revision 1.3 2001/12/19 10:32:35 johana + * Revision 1.17 2003/07/04 08:27:37 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.16 2003/06/13 10:05:19 johana + * Help the user to avoid trouble by: + * Forcing mixed mode for status/control lines if not all pins are used. + * + * Revision 1.15 2003/06/13 09:43:01 johana + * Merged in the following changes from os/linux/arch/cris/drivers/serial.c + * + some minor changes to reduce diff. + * + * Revision 1.49 2003/05/30 11:31:54 johana + * Merged in change-branch--serial9bit that adds CMSPAR support for sticky + * parity (mark/space) + * + * Revision 1.48 2003/05/30 11:03:57 johana + * Implemented rs_send_xchar() by disabling the DMA and writing manually. + * Added e100_disable_txdma_channel() and e100_enable_txdma_channel(). + * Fixed rs_throttle() and rs_unthrottle() to properly call rs_send_xchar + * instead of setting info->x_char and check the CRTSCTS flag before + * controlling the rts pin. + * + * Revision 1.14 2003/04/09 08:12:44 pkj + * Corrected typo changes made upstream. + * + * Revision 1.13 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.11 2003/01/22 06:48:37 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.9 2002/12/13 09:07:47 starvik + * Alert user that RX_TIMEOUT_TICKS==0 doesn't work + * + * Revision 1.8 2002/12/11 13:13:57 starvik + * Added arch/ to v10 specific includes + * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) + * + * Revision 1.7 2002/12/06 07:13:57 starvik + * Corrected work queue stuff + * Removed CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST + * + * Revision 1.6 2002/11/21 07:17:46 starvik + * Change static inline to extern inline where otherwise outlined with gcc-3.2 + * + * Revision 1.5 2002/11/14 15:59:49 starvik + * Linux 2.5 port of the latest serial driver from 2.4. The work queue stuff + * probably doesn't work yet. + * + * Revision 1.42 2002/11/05 09:08:47 johana + * Better implementation of rs_stop() and rs_start() that uses the XOFF + * register to start/stop transmission. + * change_speed() also initilises XOFF register correctly so that + * auto_xoff is enabled when IXON flag is set by user. + * This gives fast XOFF response times. + * + * Revision 1.41 2002/11/04 18:40:57 johana + * Implemented rs_stop() and rs_start(). + * Simple tests using hwtestserial indicates that this should be enough + * to make it work. + * + * Revision 1.40 2002/10/14 05:33:18 starvik + * RS-485 uses fast timers even if SERIAL_FAST_TIMER is disabled + * + * Revision 1.39 2002/09/30 21:00:57 johana + * Support for CONFIG_ETRAX_SERx_DTR_RI_DSR_CD_MIXED where the status and + * control pins can be mixed between PA and PB. + * If no serial port uses MIXED old solution is used + * (saves a few bytes and cycles). + * control_pins struct uses masks instead of bit numbers. + * Corrected dummy values and polarity in line_info() so + * /proc/tty/driver/serial is now correct. + * (the E100_xxx_GET() macros is really active low - perhaps not obvious) + * + * Revision 1.38 2002/08/23 11:01:36 starvik + * Check that serial port is enabled in all interrupt handlers to avoid + * restarts of DMA channels not assigned to serial ports + * + * Revision 1.37 2002/08/13 13:02:37 bjornw + * Removed some warnings because of unused code + * + * Revision 1.36 2002/08/08 12:50:01 starvik + * Serial interrupt is shared with synchronous serial port driver + * + * Revision 1.35 2002/06/03 10:40:49 starvik + * Increased RS-485 RTS toggle timer to 2 characters + * + * Revision 1.34 2002/05/28 18:59:36 johana + * Whitespace and comment fixing to be more like etrax100ser.c 1.71. + * + * Revision 1.33 2002/05/28 17:55:43 johana + * RS-485 uses FAST_TIMER if enabled, and starts a short (one char time) + * timer from tranismit_chars (interrupt context). + * The timer toggles RTS in interrupt context when expired giving minimum + * latencies. + * + * Revision 1.32 2002/05/22 13:58:00 johana + * Renamed rs_write() to raw_write() and made it inline. + * New rs_write() handles RS-485 if configured and enabled + * (moved code from e100_write_rs485()). + * RS-485 ioctl's uses copy_from_user() instead of verify_area(). + * + * Revision 1.31 2002/04/22 11:20:03 johana + * Updated copyright years. + * + * Revision 1.30 2002/04/22 09:39:12 johana + * RS-485 support compiles. + * + * Revision 1.29 2002/01/14 16:10:01 pkj + * Allocate the receive buffers dynamically. The static 4kB buffer was + * too small for the peaks. This means that we can get rid of the extra + * buffer and the copying to it. It also means we require less memory + * under normal operations, but can use more when needed (there is a + * cap at 64kB for safety reasons). If there is no memory available + * we panic(), and die a horrible death... + * + * Revision 1.28 2001/12/18 15:04:53 johana * Cleaned up write_rs485() - now it works correctly without padding extra * char. * Added sane default initialisation of rs485. @@ -283,7 +399,7 @@ * */ -static char *serial_version = "$Revision: 1.3 $"; +static char *serial_version = "$Revision: 1.17 $"; #include <linux/config.h> #include <linux/version.h> @@ -301,12 +417,8 @@ static char *serial_version = "$Revision: 1.3 $"; #include <linux/fcntl.h> #include <linux/mm.h> #include <linux/slab.h> -#if (LINUX_VERSION_CODE >= 131343) #include <linux/init.h> -#endif -#if (LINUX_VERSION_CODE >= 131336) #include <asm/uaccess.h> -#endif #include <linux/kernel.h> #include <asm/io.h> @@ -314,28 +426,38 @@ static char *serial_version = "$Revision: 1.3 $"; #include <asm/system.h> #include <asm/segment.h> #include <asm/bitops.h> -#include <asm/delay.h> +#include <linux/delay.h> -#include <asm/svinto.h> +#include <asm/arch/svinto.h> /* non-arch dependent serial structures are in linux/serial.h */ #include <linux/serial.h> /* while we keep our own stuff (struct e100_serial) in a local .h file */ #include "serial.h" +#include <asm/fasttimer.h> + +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +#ifndef CONFIG_ETRAX_FAST_TIMER +#error "Enable FAST_TIMER to use SERIAL_FAST_TIMER" +#endif +#endif + +#if defined(CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS) && \ + (CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS == 0) +#error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" +#endif /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h */ -#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ +#if defined(LOCAL_HEADERS) #include "serial_compat.h" #endif #define _INLINE_ inline -static DECLARE_TASK_QUEUE(tq_serial); - -static struct tty_driver *serial_driver; +struct tty_driver *serial_driver; /* serial subtype definitions */ #ifndef SERIAL_TYPE_NORMAL @@ -361,8 +483,7 @@ static struct tty_driver *serial_driver; #define TTY_THROTTLE_LIMIT (TTY_FLIPBUF_SIZE/10) -#define SERIAL_RECV_SIZE 4096 -#define SERIAL_DESCR_BUF_SIZE 512 +#define SERIAL_DESCR_BUF_SIZE 256 /* Add an x here to log a lot of timer stuff */ #define TIMERD(x) @@ -381,6 +502,14 @@ static void change_speed(struct e100_serial *info); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static int rs_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count); +static inline int raw_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count); +#ifdef CONFIG_ETRAX_RS485 +static int e100_write_rs485(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count); +#endif +static int get_lsr_info(struct e100_serial * info, unsigned int *value); + #define DEF_BAUD 0x99 /* 115.2 kbit/s */ #define STD_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) @@ -487,6 +616,9 @@ static struct e100_serial rs_table[] = { #define NR_PORTS (sizeof(rs_table)/sizeof(struct e100_serial)) +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER +static struct fast_timer fast_timers[NR_PORTS]; +#endif #ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY #define PROCSTAT(x) x @@ -506,7 +638,7 @@ struct ser_statistics_type { static struct ser_statistics_type ser_stat[NR_PORTS]; -#else +#else #define PROCSTAT(x) @@ -514,91 +646,440 @@ static struct ser_statistics_type ser_stat[NR_PORTS]; /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) +#ifdef CONFIG_ETRAX_FAST_TIMER +static struct fast_timer fast_timers_rs485[NR_PORTS]; +#endif #if defined(CONFIG_ETRAX_RS485_ON_PA) static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif #endif - -/* For now we assume that all bits are on the same port for each serial port */ +/* Info and macros needed for each ports extra control/status signals. */ +#define E100_STRUCT_PORT(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (R_PORT_PA_DATA): ( \ + (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ + (R_PORT_PB_DATA):&dummy_ser[line])) + +#define E100_STRUCT_SHADOW(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (&port_pa_data_shadow): ( \ + (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ + (&port_pb_data_shadow):&dummy_ser[line])) +#define E100_STRUCT_MASK(line, pinname) \ + ((CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT >= 0)? \ + (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PA_BIT): ( \ + (CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT >= 0)? \ + (1<<CONFIG_ETRAX_SER##line##_##pinname##_ON_PB_BIT):DUMMY_##pinname##_MASK)) + +#define DUMMY_DTR_MASK 1 +#define DUMMY_RI_MASK 2 +#define DUMMY_DSR_MASK 4 +#define DUMMY_CD_MASK 8 +static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF}; + +/* If not all status pins are used or disabled, use mixed mode */ +#ifdef CONFIG_ETRAX_SERIAL_PORT0 -/* Dummy shadow variables */ -#if !defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB) -static unsigned char dummy_ser0 = 0x00; -static unsigned char dummy_dir_ser0 = 0x00; -#endif -#if !defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB) -static unsigned char dummy_ser1 = 0x00; -static unsigned char dummy_dir_ser1 = 0x00; -#endif -#if !defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA) -static unsigned char dummy_ser2 = 0x00; -static unsigned char dummy_dir_ser2 = 0x00; -#endif +#define SER0_PA_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PA_BIT+CONFIG_ETRAX_SER0_RI_ON_PA_BIT+CONFIG_ETRAX_SER0_DSR_ON_PA_BIT+CONFIG_ETRAX_SER0_CD_ON_PA_BIT) + +#if SER0_PA_BITSUM != -4 +# if CONFIG_ETRAX_SER0_DTR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER0_RI_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER0_DSR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER0_CD_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +#endif + +#define SER0_PB_BITSUM (CONFIG_ETRAX_SER0_DTR_ON_PB_BIT+CONFIG_ETRAX_SER0_RI_ON_PB_BIT+CONFIG_ETRAX_SER0_DSR_ON_PB_BIT+CONFIG_ETRAX_SER0_CD_ON_PB_BIT) + +#if SER0_PB_BITSUM != -4 +# if CONFIG_ETRAX_SER0_DTR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER0_RI_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER0_DSR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER0_CD_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +#endif + +#endif /* PORT0 */ + + +#ifdef CONFIG_ETRAX_SERIAL_PORT1 + +#define SER1_PA_BITSUM (CONFIG_ETRAX_SER1_DTR_ON_PA_BIT+CONFIG_ETRAX_SER1_RI_ON_PA_BIT+CONFIG_ETRAX_SER1_DSR_ON_PA_BIT+CONFIG_ETRAX_SER1_CD_ON_PA_BIT) + +#if SER1_PA_BITSUM != -4 +# if CONFIG_ETRAX_SER1_DTR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER1_RI_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER1_DSR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER1_CD_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# 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) + +#if SER1_PB_BITSUM != -4 +# if CONFIG_ETRAX_SER1_DTR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER1_RI_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER1_DSR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER1_CD_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +#endif + +#endif /* PORT1 */ + +#ifdef CONFIG_ETRAX_SERIAL_PORT2 + +#define SER2_PA_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PA_BIT+CONFIG_ETRAX_SER2_RI_ON_PA_BIT+CONFIG_ETRAX_SER2_DSR_ON_PA_BIT+CONFIG_ETRAX_SER2_CD_ON_PA_BIT) + +#if SER2_PA_BITSUM != -4 +# if CONFIG_ETRAX_SER2_DTR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER2_RI_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER2_DSR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER2_CD_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +#endif + +#define SER2_PB_BITSUM (CONFIG_ETRAX_SER2_DTR_ON_PB_BIT+CONFIG_ETRAX_SER2_RI_ON_PB_BIT+CONFIG_ETRAX_SER2_DSR_ON_PB_BIT+CONFIG_ETRAX_SER2_CD_ON_PB_BIT) + +#if SER2_PB_BITSUM != -4 +# if CONFIG_ETRAX_SER2_DTR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER2_RI_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER2_DSR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER2_CD_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +#endif + +#endif /* PORT2 */ -static unsigned char dummy_ser3 = 0x00; -static unsigned char dummy_dir_ser3 = 0x00; +#ifdef CONFIG_ETRAX_SERIAL_PORT3 + +#define SER3_PA_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PA_BIT+CONFIG_ETRAX_SER3_RI_ON_PA_BIT+CONFIG_ETRAX_SER3_DSR_ON_PA_BIT+CONFIG_ETRAX_SER3_CD_ON_PA_BIT) + +#if SER3_PA_BITSUM != -4 +# if CONFIG_ETRAX_SER3_DTR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER3_RI_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER3_DSR_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER3_CD_ON_PA_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +#endif + +#define SER3_PB_BITSUM (CONFIG_ETRAX_SER3_DTR_ON_PB_BIT+CONFIG_ETRAX_SER3_RI_ON_PB_BIT+CONFIG_ETRAX_SER3_DSR_ON_PB_BIT+CONFIG_ETRAX_SER3_CD_ON_PB_BIT) + +#if SER3_PB_BITSUM != -4 +# if CONFIG_ETRAX_SER3_DTR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER3_RI_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER3_DSR_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +# if CONFIG_ETRAX_SER3_CD_ON_PB_BIT == -1 +# ifndef CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED +# define CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED 1 +# endif +# endif +#endif + +#endif /* PORT3 */ + + +#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED) || \ + defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \ + defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \ + defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED) +#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +#endif + +#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +/* The pins can be mixed on PA and PB */ +#define CONTROL_PINS_PORT_NOT_USED(line) \ + &dummy_ser[line], &dummy_ser[line], \ + &dummy_ser[line], &dummy_ser[line], \ + &dummy_ser[line], &dummy_ser[line], \ + &dummy_ser[line], &dummy_ser[line], \ + DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK + + +struct control_pins +{ + volatile unsigned char *dtr_port; + unsigned char *dtr_shadow; + volatile unsigned char *ri_port; + unsigned char *ri_shadow; + volatile unsigned char *dsr_port; + unsigned char *dsr_shadow; + volatile unsigned char *cd_port; + unsigned char *cd_shadow; + + unsigned char dtr_mask; + unsigned char ri_mask; + unsigned char dsr_mask; + unsigned char cd_mask; +}; + +static const struct control_pins e100_modem_pins[NR_PORTS] = +{ + /* Ser 0 */ + { +#ifdef CONFIG_ETRAX_SERIAL_PORT0 + E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR), + E100_STRUCT_PORT(0,RI), E100_STRUCT_SHADOW(0,RI), + E100_STRUCT_PORT(0,DSR), E100_STRUCT_SHADOW(0,DSR), + E100_STRUCT_PORT(0,CD), E100_STRUCT_SHADOW(0,CD), + E100_STRUCT_MASK(0,DTR), + E100_STRUCT_MASK(0,RI), + E100_STRUCT_MASK(0,DSR), + E100_STRUCT_MASK(0,CD) +#else + CONTROL_PINS_PORT_NOT_USED(0) +#endif + }, + + /* Ser 1 */ + { +#ifdef CONFIG_ETRAX_SERIAL_PORT1 + E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR), + E100_STRUCT_PORT(1,RI), E100_STRUCT_SHADOW(1,RI), + E100_STRUCT_PORT(1,DSR), E100_STRUCT_SHADOW(1,DSR), + E100_STRUCT_PORT(1,CD), E100_STRUCT_SHADOW(1,CD), + E100_STRUCT_MASK(1,DTR), + E100_STRUCT_MASK(1,RI), + E100_STRUCT_MASK(1,DSR), + E100_STRUCT_MASK(1,CD) +#else + CONTROL_PINS_PORT_NOT_USED(1) +#endif + }, + + /* Ser 2 */ + { +#ifdef CONFIG_ETRAX_SERIAL_PORT2 + E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR), + E100_STRUCT_PORT(2,RI), E100_STRUCT_SHADOW(2,RI), + E100_STRUCT_PORT(2,DSR), E100_STRUCT_SHADOW(2,DSR), + E100_STRUCT_PORT(2,CD), E100_STRUCT_SHADOW(2,CD), + E100_STRUCT_MASK(2,DTR), + E100_STRUCT_MASK(2,RI), + E100_STRUCT_MASK(2,DSR), + E100_STRUCT_MASK(2,CD) +#else + CONTROL_PINS_PORT_NOT_USED(2) +#endif + }, + + /* Ser 3 */ + { +#ifdef CONFIG_ETRAX_SERIAL_PORT3 + E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR), + E100_STRUCT_PORT(3,RI), E100_STRUCT_SHADOW(3,RI), + E100_STRUCT_PORT(3,DSR), E100_STRUCT_SHADOW(3,DSR), + E100_STRUCT_PORT(3,CD), E100_STRUCT_SHADOW(3,CD), + E100_STRUCT_MASK(3,DTR), + E100_STRUCT_MASK(3,RI), + E100_STRUCT_MASK(3,DSR), + E100_STRUCT_MASK(3,CD) +#else + CONTROL_PINS_PORT_NOT_USED(3) +#endif + } +}; +#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ + +/* All pins are on either PA or PB for each serial port */ +#define CONTROL_PINS_PORT_NOT_USED(line) \ + &dummy_ser[line], &dummy_ser[line], \ + DUMMY_DTR_MASK, DUMMY_RI_MASK, DUMMY_DSR_MASK, DUMMY_CD_MASK + -/* Info needed for each ports extra control/status signals. - We only supports that all pins uses same register for each port */ struct control_pins { volatile unsigned char *port; - volatile unsigned char *shadow; - volatile unsigned char *dir_shadow; - - unsigned char dtr_bit; - unsigned char ri_bit; - unsigned char dsr_bit; - unsigned char cd_bit; + unsigned char *shadow; + + unsigned char dtr_mask; + unsigned char ri_mask; + unsigned char dsr_mask; + unsigned char cd_mask; }; +#define dtr_port port +#define dtr_shadow shadow +#define ri_port port +#define ri_shadow shadow +#define dsr_port port +#define dsr_shadow shadow +#define cd_port port +#define cd_shadow shadow + static const struct control_pins e100_modem_pins[NR_PORTS] = { /* Ser 0 */ { -#if defined(CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB) - R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - CONFIG_ETRAX_SER0_DTR_ON_PB_BIT, - CONFIG_ETRAX_SER0_RI_ON_PB_BIT, - CONFIG_ETRAX_SER0_DSR_ON_PB_BIT, - CONFIG_ETRAX_SER0_CD_ON_PB_BIT +#ifdef CONFIG_ETRAX_SERIAL_PORT0 + E100_STRUCT_PORT(0,DTR), E100_STRUCT_SHADOW(0,DTR), + E100_STRUCT_MASK(0,DTR), + E100_STRUCT_MASK(0,RI), + E100_STRUCT_MASK(0,DSR), + E100_STRUCT_MASK(0,CD) #else - &dummy_ser0, &dummy_ser0, &dummy_dir_ser0, 0, 1, 2, 3 -#endif + CONTROL_PINS_PORT_NOT_USED(0) +#endif }, /* Ser 1 */ { -#if defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB) - R_PORT_PB_DATA, &port_pb_data_shadow, &port_pb_dir_shadow, - 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 +#ifdef CONFIG_ETRAX_SERIAL_PORT1 + E100_STRUCT_PORT(1,DTR), E100_STRUCT_SHADOW(1,DTR), + E100_STRUCT_MASK(1,DTR), + E100_STRUCT_MASK(1,RI), + E100_STRUCT_MASK(1,DSR), + E100_STRUCT_MASK(1,CD) #else - &dummy_ser1, &dummy_ser1, &dummy_dir_ser1, 0, 1, 2, 3 -#endif + CONTROL_PINS_PORT_NOT_USED(1) +#endif }, /* Ser 2 */ { -#if defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA) - R_PORT_PA_DATA, &port_pa_data_shadow, &port_pa_dir_shadow, - CONFIG_ETRAX_SER2_DTR_ON_PA_BIT, - CONFIG_ETRAX_SER2_RI_ON_PA_BIT, - CONFIG_ETRAX_SER2_DSR_ON_PA_BIT, - CONFIG_ETRAX_SER2_CD_ON_PA_BIT +#ifdef CONFIG_ETRAX_SERIAL_PORT2 + E100_STRUCT_PORT(2,DTR), E100_STRUCT_SHADOW(2,DTR), + E100_STRUCT_MASK(2,DTR), + E100_STRUCT_MASK(2,RI), + E100_STRUCT_MASK(2,DSR), + E100_STRUCT_MASK(2,CD) #else - &dummy_ser2, &dummy_ser2, &dummy_dir_ser2, 0, 1, 2, 3 -#endif + CONTROL_PINS_PORT_NOT_USED(2) +#endif }, /* Ser 3 */ { - &dummy_ser3, &dummy_ser3, &dummy_dir_ser3, 0, 1, 2, 3 +#ifdef CONFIG_ETRAX_SERIAL_PORT3 + E100_STRUCT_PORT(3,DTR), E100_STRUCT_SHADOW(3,DTR), + E100_STRUCT_MASK(3,DTR), + E100_STRUCT_MASK(3,RI), + E100_STRUCT_MASK(3,DSR), + E100_STRUCT_MASK(3,CD) +#else + CONTROL_PINS_PORT_NOT_USED(3) +#endif } }; +#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; @@ -623,20 +1104,16 @@ unsigned char rs485_pa_port = CONFIG_ETRAX_RS485_ON_PA_BIT; /* These are typically PA or PB and 0 means 0V, 1 means 3.3V */ /* Is an output */ -#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].shadow) & (1 << e100_modem_pins[(info)->line].dtr_bit)) +#define E100_DTR_GET(info) ((*e100_modem_pins[(info)->line].dtr_shadow) & e100_modem_pins[(info)->line].dtr_mask) /* Normally inputs */ -#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].ri_bit)) -#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].cd_bit)) +#define E100_RI_GET(info) ((*e100_modem_pins[(info)->line].ri_port) & e100_modem_pins[(info)->line].ri_mask) +#define E100_CD_GET(info) ((*e100_modem_pins[(info)->line].cd_port) & e100_modem_pins[(info)->line].cd_mask) /* Input */ -#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].port) & (1 << e100_modem_pins[(info)->line].dsr_bit)) +#define E100_DSR_GET(info) ((*e100_modem_pins[(info)->line].dsr_port) & e100_modem_pins[(info)->line].dsr_mask) -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* * tmp_buf is used as a temporary buffer by serial_write. We need to * lock it in case the memcpy_fromfs blocks while swapping in a page, @@ -653,43 +1130,6 @@ static DECLARE_MUTEX(tmp_buf_sem); static struct semaphore tmp_buf_sem = MUTEX; #endif -#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST - -/* clock select 10 for timer 1 gives 230400 Hz */ -#define FASTTIMER_SELECT (10) -/* we use a source of 230400 Hz and a divider of 15 => 15360 Hz */ -#define FASTTIMER_DIV (15) - -/* fast flush timer stuff */ -static int fast_timer_started = 0; -static unsigned long int fast_timer_ints = 0; - -static void _INLINE_ start_flush_timer(void) -{ - if (fast_timer_started) - return; - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - (r_timer_ctrl_shadow & - ~IO_MASK(R_TIMER_CTRL, timerdiv1) & - ~IO_MASK(R_TIMER_CTRL, tm1) & - ~IO_MASK(R_TIMER_CTRL, clksel1)) | - IO_FIELD(R_TIMER_CTRL, timerdiv1, FASTTIMER_DIV) | - IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | - IO_FIELD(R_TIMER_CTRL, clksel1, FASTTIMER_SELECT); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | - IO_STATE(R_TIMER_CTRL, tm1, run); - - /* enable timer1 irq */ - - *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); - - fast_timer_started = 1; -} -#endif /* CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST */ - /* Calculate the chartime depending on baudrate, numbor of bits etc. */ static void update_char_time(struct e100_serial * info) { @@ -754,7 +1194,7 @@ cflag_to_etrax_baud(unsigned int cflag) retval = baud_table[cflag & CBAUD]; if (retval < 0) { - printk("serdriver tried setting invalid baud rate, flags %x.\n", cflag); + printk(KERN_WARNING "serdriver tried setting invalid baud rate, flags %x.\n", cflag); retval = 5; /* choose default 9600 instead */ } @@ -770,16 +1210,17 @@ cflag_to_etrax_baud(unsigned int cflag) * any general port. */ + static inline void e100_dtr(struct e100_serial *info, int set) { #ifndef CONFIG_SVINTO_SIM - unsigned char mask = (1 << e100_modem_pins[info->line].dtr_bit); + unsigned char mask = e100_modem_pins[info->line].dtr_mask; #ifdef SERIAL_DEBUG_IO printk("ser%i dtr %i mask: 0x%02X\n", info->line, set, mask); printk("ser%i shadow before 0x%02X get: %i\n", - info->line, *e100_modem_pins[info->line].shadow, + info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info)); #endif /* DTR is active low */ @@ -788,20 +1229,15 @@ e100_dtr(struct e100_serial *info, int set) save_flags(flags); cli(); - *e100_modem_pins[info->line].shadow &= ~mask; - *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + *e100_modem_pins[info->line].dtr_shadow &= ~mask; + *e100_modem_pins[info->line].dtr_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].dtr_port = *e100_modem_pins[info->line].dtr_shadow; restore_flags(flags); } -#if 0 - REG_SHADOW_SET(e100_modem_pins[info->line].port, - *e100_modem_pins[info->line].shadow, - e100_modem_pins[info->line].dtr_bit, !set); -#endif #ifdef SERIAL_DEBUG_IO printk("ser%i shadow after 0x%02X get: %i\n", - info->line, *e100_modem_pins[info->line].shadow, + info->line, *e100_modem_pins[info->line].dtr_shadow, E100_DTR_GET(info)); #endif #endif @@ -814,15 +1250,16 @@ static inline void e100_rts(struct e100_serial *info, int set) { #ifndef CONFIG_SVINTO_SIM -#ifdef SERIAL_DEBUG_IO - printk("ser%i rts %i\n", info->line, set); -#endif info->rx_ctrl &= ~E100_RTS_MASK; info->rx_ctrl |= (set ? 0 : E100_RTS_MASK); /* RTS is active low */ info->port[REG_REC_CTRL] = info->rx_ctrl; +#ifdef SERIAL_DEBUG_IO + printk("ser%i rts %i\n", info->line, set); +#endif #endif } + /* If this behaves as a modem, RI and CD is an output */ static inline void e100_ri_out(struct e100_serial *info, int set) @@ -830,21 +1267,16 @@ e100_ri_out(struct e100_serial *info, int set) #ifndef CONFIG_SVINTO_SIM /* RI is active low */ { - unsigned char mask = (1 << e100_modem_pins[info->line].ri_bit); + unsigned char mask = e100_modem_pins[info->line].ri_mask; unsigned long flags; save_flags(flags); cli(); - *e100_modem_pins[info->line].shadow &= ~mask; - *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + *e100_modem_pins[info->line].ri_shadow &= ~mask; + *e100_modem_pins[info->line].ri_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].ri_port = *e100_modem_pins[info->line].ri_shadow; restore_flags(flags); } -#if 0 - REG_SHADOW_SET(e100_modem_pins[info->line].port, - *e100_modem_pins[info->line].shadow, - e100_modem_pins[info->line].ri_bit, !set); -#endif #endif } static inline void @@ -853,21 +1285,16 @@ e100_cd_out(struct e100_serial *info, int set) #ifndef CONFIG_SVINTO_SIM /* CD is active low */ { - unsigned char mask = (1 << e100_modem_pins[info->line].cd_bit); + unsigned char mask = e100_modem_pins[info->line].cd_mask; unsigned long flags; save_flags(flags); cli(); - *e100_modem_pins[info->line].shadow &= ~mask; - *e100_modem_pins[info->line].shadow |= (set ? 0 : mask); - *e100_modem_pins[info->line].port = *e100_modem_pins[info->line].shadow; + *e100_modem_pins[info->line].cd_shadow &= ~mask; + *e100_modem_pins[info->line].cd_shadow |= (set ? 0 : mask); + *e100_modem_pins[info->line].cd_port = *e100_modem_pins[info->line].cd_shadow; restore_flags(flags); } -#if 0 - REG_SHADOW_SET(e100_modem_pins[info->line].port, - *e100_modem_pins[info->line].shadow, - e100_modem_pins[info->line].cd_bit, !set); -#endif #endif } @@ -931,6 +1358,60 @@ e100_enable_txdma_irq(struct e100_serial *info) *R_IRQ_MASK2_SET = info->irq; } +static inline void +e100_disable_txdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + /* Disable output DMA channel for the serial port in question + * ( set to something other then serialX) + */ + save_flags(flags); + cli(); + if (info->line == 0) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); + } else if (info->line == 1) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); + } else if (info->line == 2) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); + } else if (info->line == 3) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); + } + *R_GEN_CONFIG = genconfig_shadow; + restore_flags(flags); +} + + +static inline void +e100_enable_txdma_channel(struct e100_serial *info) +{ + unsigned long flags; + + save_flags(flags); + cli(); + /* Enable output DMA channel for the serial port in question */ + if (info->line == 0) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, serial0); + } else if (info->line == 1) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, serial1); + } else if (info->line == 2) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, serial2); + } else if (info->line == 3) { + genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); + genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, serial3); + } + *R_GEN_CONFIG = genconfig_shadow; + restore_flags(flags); +} + + #ifdef SERIAL_HANDLE_EARLY_ERRORS /* in order to detect and fix errors on the first byte we have to use the serial interrupts as well. */ @@ -972,88 +1453,98 @@ e100_enable_rs485(struct tty_struct *tty,struct rs485_control *r) info->rs485.rts_after_sent = 0x01 & r->rts_after_sent; info->rs485.delay_rts_before_send = r->delay_rts_before_send; info->rs485.enabled = r->enabled; - +/* printk("rts: on send = %i, after = %i, enabled = %i", + info->rs485.rts_on_send, + info->rs485.rts_after_sent, + info->rs485.enabled + ); +*/ return 0; } static int -e100_write_rs485(struct tty_struct *tty,struct rs485_write *r) +e100_write_rs485(struct tty_struct *tty, int from_user, + const unsigned char *buf, int count) { - int total; struct e100_serial * info = (struct e100_serial *)tty->driver_data; + int old_enabled = info->rs485.enabled; - /* If we are in RS-485 mode, we need to toggle RTS and disable - * the receiver before initiating a DMA transfer + /* rs485 is always implicitly enabled if we're using the ioctl() + * but it doesn't have to be set in the rs485_control + * (to be backward compatible with old apps) + * So we store, set and restore it. */ - e100_rts(info, info->rs485.rts_on_send); -#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) - e100_disable_rx(info); - e100_disable_rxdma_irq(info); -#endif - - if (info->rs485.delay_rts_before_send > 0) { - current->timeout = jiffies + (info->rs485.delay_rts_before_send * HZ)/1000; - current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; - } - total = rs_write(tty, 1, (*r).outc, (*r).outc_size); - - /* If we are in RS-485 mode the following things has to be done: - * wait until DMA is ready - * wait on transmit shift register - * wait to toggle RTS - * enable the receiver - */ + info->rs485.enabled = 1; + /* rs_write now deals with RS485 if enabled */ + count = rs_write(tty, from_user, buf, count); + info->rs485.enabled = old_enabled; + return count; +} - /* Sleep until all sent */ - tty_wait_until_sent(tty, 0); -#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER - /* Now sleep a little more so that shift register is empty */ - schedule_usleep(info->char_time_usec * 2); -#else - { - unsigned int val; - /* wait on transmit shift register */ - do{ - get_lsr_info(info, &val); - }while (!(val & TIOCSER_TEMT)); - } -#endif +#ifdef CONFIG_ETRAX_FAST_TIMER +/* Timer function to toggle RTS when using FAST_TIMER */ +static void rs485_toggle_rts_timer_function(unsigned long data) +{ + struct e100_serial *info = (struct e100_serial *)data; + fast_timers_rs485[info->line].function = NULL; e100_rts(info, info->rs485.rts_after_sent); - #if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) e100_enable_rx(info); e100_enable_rxdma_irq(info); #endif - - return total; } #endif +#endif /* CONFIG_ETRAX_RS485 */ /* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. + * They enable or disable transmitter using the XOFF registers, as necessary. * ------------------------------------------------------------ */ -/* FIXME - when are these used and what is the purpose ? - * In rs_stop we probably just can block the transmit DMA ready irq - * and in rs_start we re-enable it (and then the old one will come). - */ - static void rs_stop(struct tty_struct *tty) { + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + if (info) { + unsigned long flags; + unsigned long xoff; + + save_flags(flags); cli(); + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); + xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop); + if (tty->termios->c_iflag & IXON ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->port[REG_XOFF]) = xoff; + restore_flags(flags); + } } static void rs_start(struct tty_struct *tty) { + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + if (info) { + unsigned long flags; + unsigned long xoff; + + save_flags(flags); cli(); + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty)); + xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); + if (tty->termios->c_iflag & IXON ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->port[REG_XOFF]) = xoff; + + restore_flags(flags); + } } /* @@ -1086,8 +1577,7 @@ rs_sched_event(struct e100_serial *info, int event) { info->event |= 1 << event; - queue_task(&info->tqueue, &tq_serial); - mark_bh(SERIAL_BH); + schedule_work(&info->work); } /* The output DMA channel is free - use it to send as many chars as possible @@ -1136,7 +1626,7 @@ transmit_chars(struct e100_serial *info) #endif if (!info->tr_running) { /* weirdo... we shouldn't get here! */ - printk("Achtung: transmit_chars with !tr_running\n"); + printk(KERN_WARNING "Achtung: transmit_chars with !tr_running\n"); return; } @@ -1173,26 +1663,16 @@ transmit_chars(struct e100_serial *info) /* our job here is done, don't schedule any new DMA transfer */ info->tr_running = 0; -#if defined(CONFIG_ETRAX_RS485) - /* Check if we should toggle RTS now */ +#if defined(CONFIG_ETRAX_RS485) && defined(CONFIG_ETRAX_FAST_TIMER) if (info->rs485.enabled) { - /* Make sure fifo is empty */ - int in_fifo = 0; - - do { - in_fifo = IO_EXTRACT(R_DMA_CH6_STATUS, avail, - *info->ostatusadr); - } while (in_fifo > 0); - /* Any way to really check transmitter empty? (TEMT) */ - /* Control RTS to set to RX mode */ - e100_rts(info, info->rs485.rts_after_sent); -#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) - e100_enable_rx(info); - e100_enable_rxdma_irq(info); -#endif + /* 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 */ - return; } @@ -1208,7 +1688,7 @@ transmit_chars(struct e100_serial *info) *info->ocmdadr = 1; /* dma command start -> R_DMAx_CMD */ /* DMA is now running (hopefully) */ -} +} /* transmit_chars */ static void start_transmit(struct e100_serial *info) @@ -1224,7 +1704,7 @@ start_transmit(struct e100_serial *info) info->tr_running = 1; transmit_chars(info); -} +} /* start_transmit */ #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER static int serial_fast_timer_started = 0; @@ -1254,49 +1734,91 @@ static void flush_timeout_function(unsigned long data); #define START_FLUSH_FAST_TIMER(info, string) #endif +static struct etrax_recv_buffer * +alloc_recv_buffer(unsigned int size) +{ + struct etrax_recv_buffer *buffer; + + if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + return NULL; + + buffer->next = NULL; + buffer->length = 0; + buffer->error = TTY_NORMAL; + + return buffer; +} + +static void +append_recv_buffer(struct e100_serial *info, struct etrax_recv_buffer *buffer) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + if (!info->first_recv_buffer) + info->first_recv_buffer = buffer; + else + info->last_recv_buffer->next = buffer; + + info->last_recv_buffer = buffer; + + info->recv_cnt += buffer->length; + if (info->recv_cnt > info->max_recv_cnt) + info->max_recv_cnt = info->recv_cnt; + + restore_flags(flags); +} + static int add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char flag) { - if (!CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + struct etrax_recv_buffer *buffer; + + if (!(buffer = alloc_recv_buffer(4))) return 0; - info->recv.buf[info->recv.head] = data; - info->flag_buf[info->recv.head] = flag; - info->recv.head = (info->recv.head + 1) & (SERIAL_RECV_SIZE - 1); + buffer->length = 1; + buffer->error = flag; + buffer->buffer[0] = data; + + append_recv_buffer(info, buffer); info->icount.rx++; return 1; } -static _INLINE_ unsigned int -copy_descr_data(struct e100_serial *info, unsigned int recvl, unsigned char *buf) +extern _INLINE_ unsigned int +handle_descr_data(struct e100_serial *info, struct etrax_dma_descr *descr, unsigned int recvl) { - unsigned int count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); - unsigned int length = 0; + struct etrax_recv_buffer *buffer = phys_to_virt(descr->buf) - sizeof *buffer; - while (length < recvl && count) { - if (length + count > recvl) - count = recvl - length; + if (info->recv_cnt + recvl > 65536) { + printk(KERN_CRIT + "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl); + return 0; + } - memcpy(info->recv.buf + info->recv.head, buf + length, count); - memset(info->flag_buf + info->recv.head, '\0', count); - info->recv.head = (info->recv.head + count) & (SERIAL_RECV_SIZE - 1); - length += count; + buffer->length = recvl; - count = CIRC_SPACE_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); - } + if (info->errorcode == ERRCODE_SET_BREAK) + buffer->error = TTY_BREAK; + info->errorcode = 0; - if (length != recvl) { - printk(__FUNCTION__ ": Buffer overflow! %d byte(s) did not fit.\n", recvl - length); - PROCSTAT(ser_stat[info->line].overrun_cnt += recvl - length); - } + append_recv_buffer(info, buffer); - return length; + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__); + + descr->buf = virt_to_phys(buffer->buffer); + + return recvl; } static _INLINE_ unsigned int -copy_all_descr_data(struct e100_serial *info) +handle_all_descr_data(struct e100_serial *info) { struct etrax_dma_descr *descr; unsigned int recvl; @@ -1330,7 +1852,7 @@ copy_all_descr_data(struct e100_serial *info) /* update stats */ info->icount.rx += recvl; - ret += copy_descr_data(info, recvl, phys_to_virt(descr->buf)); + ret += handle_descr_data(info, descr, recvl); } return ret; @@ -1341,7 +1863,6 @@ receive_chars(struct e100_serial *info) { struct tty_struct *tty; unsigned char rstat; - unsigned int old_head; #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of @@ -1366,12 +1887,7 @@ receive_chars(struct e100_serial *info) if (info->errorcode == ERRCODE_INSERT_BREAK) add_char_and_flag(info, '\0', TTY_BREAK); - old_head = info->recv.head; - - if (copy_all_descr_data(info) && info->errorcode == ERRCODE_SET_BREAK) - info->flag_buf[old_head] = TTY_BREAK; - - info->errorcode = 0; + handle_all_descr_data(info); /* Read the status register to detect errors */ rstat = info->port[REG_STATUS]; @@ -1394,10 +1910,6 @@ receive_chars(struct e100_serial *info) add_char_and_flag(info, data, TTY_FRAME); } - if (!E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) < TTY_THROTTLE_LIMIT) - info->tty->driver->throttle(info->tty); - START_FLUSH_FAST_TIMER(info, "receive_chars"); /* Restart the receiving DMA */ @@ -1408,19 +1920,20 @@ static _INLINE_ int start_recv_dma(struct e100_serial *info) { struct etrax_dma_descr *descr = info->rec_descr; - unsigned char *buf = info->recv.buf + 2*SERIAL_RECV_SIZE; + struct etrax_recv_buffer *buffer; int i; /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { + if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__); + descr[i].ctrl = d_int; - descr[i].buf = virt_to_phys(buf); + descr[i].buf = virt_to_phys(buffer->buffer); descr[i].sw_len = SERIAL_DESCR_BUF_SIZE; descr[i].hw_len = 0; descr[i].status = 0; descr[i].next = virt_to_phys(&descr[i+1]); - - buf += SERIAL_DESCR_BUF_SIZE; } /* Link the last descriptor to the first */ @@ -1448,7 +1961,7 @@ start_receive(struct e100_serial *info) #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)); @@ -1456,10 +1969,6 @@ start_receive(struct e100_serial *info) info->tty->flip.count = 0; start_recv_dma(info); - -#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST - start_flush_timer(); -#endif } @@ -1480,13 +1989,14 @@ status_handle(struct e100_serial *info, unsigned short status) DMA8(ser1) when they have finished a descriptor with the intr flag set. */ -static void +static irqreturn_t tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct e100_serial *info; unsigned long ireg; int i; - + int handled = 0; + #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of * the serial interface works, and this piece will just be removed. @@ -1495,7 +2005,7 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) const char *s = "What? tr_interrupt in simulator??\n"; SIMCOUT(s,strlen(s)); } - return; + return IRQ_HANDLED; #endif /* find out the line that caused this irq and get it from rs_table */ @@ -1504,10 +2014,11 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if (!info->uses_dma) + if (!info->enabled || !info->uses_dma) continue; /* check for dma_descr (don't need to check for dma_eop in output dma for serial */ if (ireg & info->irq) { + handled = 1; /* we can send a new dma bunch. make it so. */ DEBUG_LOG(info->line, "tr_interrupt %i\n", i); /* Read jiffies_usec first, @@ -1522,16 +2033,18 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* FIXME: here we should really check for a change in the status lines and if so call status_handle(info) */ } + return IRQ_RETVAL(handled); } /* dma input channel interrupt handler */ -static void +static irqreturn_t rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct e100_serial *info; unsigned long ireg; int i; + int handled = 0; #ifdef CONFIG_SVINTO_SIM /* No receive in the simulator. Will probably be when the rest of @@ -1550,10 +2063,11 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if (!info->uses_dma) + if (!info->enabled || !info->uses_dma) continue; /* check for both dma_eop and dma_descr for the input dma channel */ if (ireg & ((info->irq << 2) | (info->irq << 3))) { + handled = 1; /* we have received something */ receive_chars(info); } @@ -1561,6 +2075,7 @@ rec_interrupt(int irq, void *dev_id, struct pt_regs * regs) /* FIXME: here we should really check for a change in the status lines and if so call status_handle(info) */ } + return IRQ_RETVAL(handled); } static _INLINE_ int @@ -1611,48 +2126,56 @@ force_eop_if_needed(struct e100_serial *info) static _INLINE_ void flush_to_flip_buffer(struct e100_serial *info) { - struct tty_struct *tty = info->tty; - unsigned int count = CIRC_CNT_TO_END(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE); + struct tty_struct *tty; + struct etrax_recv_buffer *buffer; unsigned int length; unsigned long flags; - if (!count) + if (!info->first_recv_buffer) return; save_flags(flags); cli(); + if (!(tty = info->tty)) { + restore_flags(flags); + return; + } + length = tty->flip.count; - - do { + + while ((buffer = info->first_recv_buffer) && length < TTY_FLIPBUF_SIZE) { + unsigned int count = buffer->length; + if (length + count > TTY_FLIPBUF_SIZE) count = TTY_FLIPBUF_SIZE - length; - memcpy(tty->flip.char_buf_ptr + length, info->recv.buf + info->recv.tail, count); - memcpy(tty->flip.flag_buf_ptr + length, info->flag_buf + info->recv.tail, count); - info->recv.tail = ((info->recv.tail + count) & (SERIAL_RECV_SIZE-1)); + memcpy(tty->flip.char_buf_ptr + length, buffer->buffer, count); + memset(tty->flip.flag_buf_ptr + length, TTY_NORMAL, count); + tty->flip.flag_buf_ptr[length] = buffer->error; + length += count; - - count = CIRC_CNT_TO_END(info->recv.head, - info->recv.tail, - SERIAL_RECV_SIZE); - } while (length < TTY_FLIPBUF_SIZE && count); + info->recv_cnt -= count; + + if (count == buffer->length) { + info->first_recv_buffer = buffer->next; + kfree(buffer); + } else { + buffer->length -= count; + memmove(buffer->buffer, buffer->buffer + count, buffer->length); + buffer->error = TTY_NORMAL; + } + } + + if (!info->first_recv_buffer) + info->last_recv_buffer = NULL; tty->flip.count = length; restore_flags(flags); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,66) /* this includes a check for low-latency */ tty_flip_buffer_push(tty); -#else - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); -#endif - - /* unthrottle if we have throttled */ - if (E100_RTS_GET(info) && - CIRC_SPACE(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE) > TTY_THROTTLE_LIMIT) - tty->driver->unthrottle(info->tty); } static _INLINE_ void @@ -1662,7 +2185,7 @@ check_flush_timeout(struct e100_serial *info) flush_to_flip_buffer(info); - if (CIRC_CNT(info->recv.head, info->recv.tail, SERIAL_RECV_SIZE)) + if (info->first_recv_buffer) START_FLUSH_FAST_TIMER(info, "flip"); } @@ -1678,43 +2201,11 @@ static void flush_timeout_function(unsigned long data) check_flush_timeout(info); } -#elif defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) - -static void -timeout_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct e100_serial *info; - int i; - -#ifdef CONFIG_SVINTO_SIM - /* No receive in the simulator. Will probably be when the rest of - * the serial interface works, and this piece will just be removed. - */ - { - const char *s = "What? timeout_interrupt in simulator??\n"; - SIMCOUT(s,strlen(s)); - } - return; -#endif - - /* acknowledge the timer1 irq */ - *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); - PROCSTAT(fast_timer_ints++); - - for (i = 0; i < NR_PORTS; i++) { - info = rs_table + i; - if (info->uses_dma) - check_flush_timeout(info); - } -} /* timeout_interrupt */ - #else /* dma fifo/buffer timeout handler forces an end-of-packet for the dma input channel if no chars have been received for CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS/100 s. - If CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST is configured then this - handler is instead run at 15360 Hz. */ static struct timer_list flush_timer; @@ -1810,7 +2301,7 @@ TODO: The break will be delayed until an F or V character is received. */ -static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) +extern irqreturn_t _INLINE_ handle_ser_interrupt(struct e100_serial *info) { unsigned char rstat = info->port[REG_STATUS]; @@ -1869,7 +2360,7 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) } info->break_detected_cnt = 0; DEBUG_LOG(info->line, "#iERR s d %04X\n", - ((rstat & SER_ERROR_MASK) << 8) | data); + ((rstat & SER_ERROR_MASK) << 8) | data); } PROCSTAT(ser_stat[info->line].early_errors_cnt++); } else { /* It was a valid byte, now let the DMA do the rest */ @@ -1883,8 +2374,8 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) * previous interrupt we should discard it. */ long elapsed_usec = - (curr_time - info->last_rx_active) * (1000000/HZ) + - curr_time_u - info->last_rx_active_usec; + (curr_time - info->last_rx_active) * (1000000/HZ) + + curr_time_u - info->last_rx_active_usec; if (elapsed_usec < 2*info->char_time_usec) { DEBUG_LOG(info->line, "FBRK %i\n", info->line); /* Report as BREAK (error) and let @@ -1911,25 +2402,29 @@ static void _INLINE_ handle_ser_interrupt(struct e100_serial *info) /* Restarting the DMA never hurts */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); START_FLUSH_FAST_TIMER(info, "ser_int"); + return IRQ_HANDLED; } /* handle_ser_interrupt */ -static void +static irqreturn_t ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct e100_serial *info; int i; + int handled = 0; for (i = 0; i < NR_PORTS; i++) { info = rs_table + i; - if (!info->uses_dma) + if (!info->enabled || !info->uses_dma) continue; /* Which line caused the irq? */ if (*R_IRQ_MASK1_RD & (1U << (8+2*info->line))) { + handled = 1; handle_ser_interrupt(info); } } + return IRQ_RETVAL(handled); } /* ser_interrupt */ #endif @@ -1949,12 +2444,6 @@ ser_interrupt(int irq, void *dev_id, struct pt_regs *regs) * them using rs_sched_event(), and they get done here. */ static void -do_serial_bh(void) -{ - run_task_queue(&tq_serial); -} - -static void do_softint(void *private_) { struct e100_serial *info = (struct e100_serial *) private_; @@ -1972,53 +2461,25 @@ do_softint(void *private_) } } -/* - * This routine is called from the scheduler tqueue when the interrupt - * routine has signalled that a hangup has occurred. The path of - * hangup processing is: - * - * serial interrupt routine -> (scheduler tqueue) -> - * do_serial_hangup() -> tty->hangup() -> rs_hangup() - * - */ -static void -do_serial_hangup(void *private_) -{ - struct e100_serial *info = (struct e100_serial *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - tty_hangup(tty); -} - static int startup(struct e100_serial * info) { unsigned long flags; unsigned long xmit_page; - unsigned char *recv_page; + int i; xmit_page = get_zeroed_page(GFP_KERNEL); if (!xmit_page) return -ENOMEM; - recv_page = kmalloc(2 * SERIAL_RECV_SIZE + SERIAL_RECV_DESCRIPTORS * SERIAL_DESCR_BUF_SIZE, GFP_KERNEL); - if (!recv_page) { - free_page(xmit_page); - return -ENOMEM; - } - - save_flags(flags); cli(); + save_flags(flags); + cli(); /* if it was already initialized, skip this */ if (info->flags & ASYNC_INITIALIZED) { restore_flags(flags); free_page(xmit_page); - kfree(recv_page); return 0; } @@ -2027,13 +2488,6 @@ startup(struct e100_serial * info) else info->xmit.buf = (unsigned char *) xmit_page; - if (info->recv.buf) - kfree(recv_page); - else { - info->recv.buf = (unsigned char *) recv_page; - info->flag_buf = info->recv.buf + SERIAL_RECV_SIZE; - } - #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); #endif @@ -2044,8 +2498,13 @@ startup(struct e100_serial * info) right? */ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = NULL; /* No real action in the simulator, but may set info important to ioctl. */ @@ -2084,8 +2543,12 @@ startup(struct e100_serial * info) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0; - info->recv.head = info->recv.tail = 0; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + info->rec_descr[i].buf = 0; + /* * and set the speed and other flags of the serial port * this will start the rx/tx as well @@ -2137,6 +2600,9 @@ static void shutdown(struct e100_serial * info) { unsigned long flags; + struct etrax_dma_descr *descr = info->rec_descr; + struct etrax_recv_buffer *buffer; + int i; #ifndef CONFIG_SVINTO_SIM /* shut down the transmitter and receiver */ @@ -2173,11 +2639,12 @@ shutdown(struct e100_serial * info) info->xmit.buf = NULL; } - if (info->recv.buf) { - kfree(info->recv.buf); - info->recv.buf = NULL; - info->flag_buf = NULL; - } + for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) + if (descr[i].buf) { + buffer = phys_to_virt(descr[i].buf) - sizeof *buffer; + kfree(buffer); + descr[i].buf = 0; + } if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) { /* hang up DTR and RTS if HUPCL is enabled */ @@ -2199,6 +2666,7 @@ static void change_speed(struct e100_serial *info) { unsigned int cflag; + unsigned long xoff; /* first some safety checks */ @@ -2248,10 +2716,21 @@ change_speed(struct e100_serial *info) info->rx_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); } - 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 & CMSPAR) { + /* enable stick parity */ + 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); + if (!(cflag & PARODD)) { + /* set mark 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); + } + } 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) { @@ -2268,7 +2747,13 @@ change_speed(struct e100_serial *info) info->port[REG_TR_CTRL] = info->tx_ctrl; info->port[REG_REC_CTRL] = info->rx_ctrl; - *((unsigned long *)&info->port[REG_XOFF]) = 0; + xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->tty)); + xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable); + if (info->tty->termios->c_iflag & IXON ) { + xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable); + } + + *((unsigned long *)&info->port[REG_XOFF]) = xoff; #endif /* !CONFIG_SVINTO_SIM */ update_char_time(info); @@ -2301,9 +2786,9 @@ rs_flush_chars(struct tty_struct *tty) restore_flags(flags); } -static int -rs_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) +extern inline int +raw_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) { int c, ret = 0; struct e100_serial *info = (struct e100_serial *)tty->driver_data; @@ -2316,7 +2801,7 @@ rs_write(struct tty_struct * tty, int from_user, #ifdef SERIAL_DEBUG_DATA if (info->line == SERIAL_DEBUG_LINE) - printk("rs_write (%d), status %d\n", + printk("raw_write (%d), status %d\n", count, info->port[REG_STATUS]); #endif @@ -2402,7 +2887,74 @@ rs_write(struct tty_struct * tty, int from_user, } return ret; -} +} /* raw_write() */ + +static int +rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ +#if defined(CONFIG_ETRAX_RS485) + struct e100_serial *info = (struct e100_serial *)tty->driver_data; + + if (info->rs485.enabled) + { + /* If we are in RS-485 mode, we need to toggle RTS and disable + * the receiver before initiating a DMA transfer + */ +#ifdef CONFIG_ETRAX_FAST_TIMER + /* Abort any started timer */ + fast_timers_rs485[info->line].function = NULL; + del_fast_timer(&fast_timers_rs485[info->line]); +#endif + e100_rts(info, info->rs485.rts_on_send); +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) + e100_disable_rx(info); + e100_disable_rxdma_irq(info); +#endif + + if (info->rs485.delay_rts_before_send > 0) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout((info->rs485.delay_rts_before_send * HZ)/1000); + } + } +#endif /* CONFIG_ETRAX_RS485 */ + + count = raw_write(tty, from_user, buf, count); + +#if defined(CONFIG_ETRAX_RS485) + if (info->rs485.enabled) + { + unsigned int val; + /* If we are in RS-485 mode the following has to be done: + * wait until DMA is ready + * wait on transmit shift register + * toggle RTS + * enable the receiver + */ + + /* Sleep until all sent */ + tty_wait_until_sent(tty, 0); +#ifdef CONFIG_ETRAX_FAST_TIMER + /* Now sleep a little more so that shift register is empty */ + schedule_usleep(info->char_time_usec * 2); +#endif + /* wait on transmit shift register */ + do{ + get_lsr_info(info, &val); + }while (!(val & TIOCSER_TEMT)); + + e100_rts(info, info->rs485.rts_after_sent); + +#if defined(CONFIG_ETRAX_RS485_DISABLE_RECEIVER) + e100_enable_rx(info); + e100_enable_rxdma_irq(info); +#endif + } +#endif /* CONFIG_ETRAX_RS485 */ + + return count; +} /* rs_write */ + /* how much space is available in the xmit buffer? */ @@ -2451,20 +3003,23 @@ rs_flush_buffer(struct tty_struct *tty) * This function is used to send a high-priority XON/XOFF character to * the device * - * Since we don't bother to check for info->x_char in transmit_chars yet, - * we don't really implement this function yet. + * Since we use DMA we don't check for info->x_char in transmit_chars, + * just disable DMA channel and write the character when possible. */ static void rs_send_xchar(struct tty_struct *tty, char ch) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; - printk("serial.c:rs_send_xchar not implemented!\n"); + e100_disable_txdma_channel(info); - info->x_char = ch; - if (ch) { - /* Make sure transmit interrupts are on */ - /* TODO. */ - } + /* Wait for tr_ready */ + 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); } /* @@ -2482,20 +3037,22 @@ rs_throttle(struct tty_struct * tty) unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - + printk("throttle %s: %d....\n", _tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - + + /* Do RTS before XOFF since XOFF might take some time */ + if (tty->termios->c_cflag & CRTSCTS) { + /* Turn off RTS line (do this atomic) */ + save_flags(flags); + cli(); + e100_rts(info, 0); + restore_flags(flags); + } if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - - /* Turn off RTS line (do this atomic) should here be an else ?? */ - - save_flags(flags); - cli(); - e100_rts(info, 0); - restore_flags(flags); + rs_send_xchar(tty, STOP_CHAR(tty)); + } static void @@ -2505,24 +3062,27 @@ rs_unthrottle(struct tty_struct * tty) unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - + + /* Do RTS before XOFF since XOFF might take some time */ + if (tty->termios->c_cflag & CRTSCTS) { + /* Assert RTS line (do this atomic) */ + save_flags(flags); + cli(); + e100_rts(info, 1); + restore_flags(flags); + } + if (I_IXOFF(tty)) { if (info->x_char) info->x_char = 0; else - info->x_char = START_CHAR(tty); + rs_send_xchar(tty, START_CHAR(tty)); } - - /* Assert RTS line (do this atomic) */ - - save_flags(flags); - cli(); - e100_rts(info, 1); - restore_flags(flags); + } /* @@ -2594,9 +3154,7 @@ set_serial_info(struct e100_serial *info, info->type = new_serial.type; info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; -#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif check_and_exit: if (info->flags & ASYNC_INITIALIZED) { @@ -2641,8 +3199,8 @@ get_lsr_info(struct e100_serial * info, unsigned int *value) #ifdef SERIAL_DEBUG_IO struct state_str { - int state; - const char *str; + int state; + const char *str; }; const struct state_str control_state_str[] = { @@ -2690,14 +3248,15 @@ get_modem_info(struct e100_serial * info, unsigned int *value) E100_DSR_GET(info), E100_CTS_GET(info)); #endif + result = (!E100_RTS_GET(info) ? TIOCM_RTS : 0) | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) - | (!E100_CD_GET(info) ? TIOCM_CAR : 0) | (!E100_RI_GET(info) ? TIOCM_RNG : 0) | (!E100_DSR_GET(info) ? TIOCM_DSR : 0) + | (!E100_CD_GET(info) ? TIOCM_CAR : 0) | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); - + #ifdef SERIAL_DEBUG_IO printk("e100ser: modem state: %i 0x%08X\n", result, result); { @@ -2766,44 +3325,7 @@ set_modem_info(struct e100_serial * info, unsigned int cmd, return 0; } -/* - * This routine sends a break character out the serial port. - */ -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ -static void -send_break(struct e100_serial * info, int duration) -{ - unsigned long flags; - - if (!info->port) - return; - - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; - - save_flags(flags); - cli(); - - /* Go to manual mode and set the txd pin to 0 */ - - info->tx_ctrl &= 0x3F; /* Clear bit 7 (txd) and 6 (tr_enable) */ - info->port[REG_TR_CTRL] = info->tx_ctrl; - - /* wait for "duration" jiffies */ - - schedule(); - - info->tx_ctrl |= (0x80 | 0x40); /* Set bit 7 (txd) and 6 (tr_enable) */ - info->port[REG_TR_CTRL] = info->tx_ctrl; - - /* the DMA gets awfully confused if we toggle the transceiver like this - * so we need to reset it - */ - *info->ocmdadr = 4; - restore_flags(flags); -} -#else static void rs_break(struct tty_struct *tty, int break_state) { @@ -2824,19 +3346,12 @@ rs_break(struct tty_struct *tty, int break_state) info->port[REG_TR_CTRL] = info->tx_ctrl; restore_flags(flags); } -#endif static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct e100_serial * info = (struct e100_serial *)tty->driver_data; -#if defined(CONFIG_ETRAX_RS485) || (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - int error; -#endif -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - int retval; -#endif if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && @@ -2846,45 +3361,6 @@ rs_ioctl(struct tty_struct *tty, struct file * file, } switch (cmd) { -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, HZ/4); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*(HZ/10) : HZ/4); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCGSOFTCAR: - error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); - if (error) - return error; - put_fs_long(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg); - return 0; - case TIOCSSOFTCAR: - arg = get_fs_long((unsigned long *) arg); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; -#endif case TIOCMGET: return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: @@ -2908,22 +3384,22 @@ rs_ioctl(struct tty_struct *tty, struct file * file, #if defined(CONFIG_ETRAX_RS485) case TIOCSERSETRS485: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct rs485_control)); - - if (error) - return error; - - return e100_enable_rs485(tty, (struct rs485_control *) arg); + { + struct rs485_control rs485ctrl; + if (copy_from_user(&rs485ctrl, (struct rs485_control*)arg, sizeof(rs485ctrl))) + return -EFAULT; + + return e100_enable_rs485(tty, &rs485ctrl); + } case TIOCSERWRRS485: - error = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct rs485_write)); - - if (error) - return error; - - return e100_write_rs485(tty, (struct rs485_write *) arg); + { + struct rs485_write rs485wr; + if (copy_from_user(&rs485wr, (struct rs485_write*)arg, sizeof(rs485wr))) + return -EFAULT; + + return e100_write_rs485(tty, 1, rs485wr.outc, rs485wr.outc_size); + } #endif default: @@ -2991,12 +3467,13 @@ rs_close(struct tty_struct *tty, struct file * filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("rs_close: bad serial port count; tty->count is 1, " + printk(KERN_CRIT + "rs_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { - printk("rs_close: bad serial port count for ttyS%d: %d\n", + printk(KERN_CRIT "rs_close: bad serial port count for ttyS%d: %d\n", info->line, info->count); info->count = 0; } @@ -3149,7 +3626,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, return -EAGAIN; #endif } - + /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -3162,7 +3639,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; - + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3187,7 +3664,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, while (1) { save_flags(flags); cli(); - /* assert RTS and DTR */ + /* assert RTS and DTR */ e100_rts(info, 1); e100_dtr(info, 1); restore_flags(flags); @@ -3204,7 +3681,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(info->flags & ASYNC_CLOSING) && do_clocal) + if (!(info->flags & ASYNC_CLOSING) && do_clocal) /* && (do_clocal || DCD_IS_ASSERTED) */ break; if (signal_pending(current)) { @@ -3258,17 +3735,15 @@ rs_open(struct tty_struct *tty, struct file * filp) return -ENODEV; #ifdef SERIAL_DEBUG_OPEN - printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, - info->count); + printk("[%d] rs_open %s, count = %d\n", current->pid, tty->name, + info->count); #endif info->count++; tty->driver_data = info; info->tty = tty; -#if (LINUX_VERSION_CODE > 0x20100) info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); @@ -3312,7 +3787,7 @@ rs_open(struct tty_struct *tty, struct file * filp) #endif return retval; } - + #ifdef SERIAL_DEBUG_OPEN printk("rs_open ttyS%d successful...\n", info->line); #endif @@ -3323,7 +3798,7 @@ rs_open(struct tty_struct *tty, struct file * filp) * /proc fs routines.... */ -static 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]; int ret; @@ -3338,17 +3813,17 @@ static inline int line_info(char *buf, struct e100_serial *info) stat_buf[0] = 0; stat_buf[1] = 0; - if (E100_RTS_GET(info)) + if (!E100_RTS_GET(info)) strcat(stat_buf, "|RTS"); - if (E100_CTS_GET(info)) + if (!E100_CTS_GET(info)) strcat(stat_buf, "|CTS"); - if (E100_DTR_GET(info)) + if (!E100_DTR_GET(info)) strcat(stat_buf, "|DTR"); - if (E100_DSR_GET(info)) + if (!E100_DSR_GET(info)) strcat(stat_buf, "|DSR"); - if (E100_CD_GET(info)) + if (!E100_CD_GET(info)) strcat(stat_buf, "|CD"); - if (E100_RI_GET(info)) + if (!E100_RI_GET(info)) strcat(stat_buf, "|RI"); ret += sprintf(buf+ret, " baud:%d", info->baud); @@ -3357,6 +3832,10 @@ static inline int line_info(char *buf, struct e100_serial *info) (unsigned long)info->icount.tx, (unsigned long)info->icount.rx); + ret += sprintf(buf+ret, " rx_pend:%lu/%lu", + (unsigned long)info->recv_cnt, + (unsigned long)info->max_recv_cnt); + if (info->icount.frame) ret += sprintf(buf+ret, " fe:%lu", (unsigned long)info->icount.frame); @@ -3413,12 +3892,13 @@ done: static void show_serial_version(void) { - printk("ETRAX 100LX serial-driver %s, (c) 2000 Axis Communications AB\r\n", - serial_version); + printk(KERN_INFO + "ETRAX 100LX serial-driver %s, (c) 2000-2003 Axis Communications AB\r\n", + &serial_version[11]); /* "$Revision: x.yy" */ } /* rs_init inits the driver at boot (using the module_init chain) */ - + static struct tty_operations rs_ops = { .open = rs_open, .close = rs_close, @@ -3428,8 +3908,8 @@ static struct tty_operations rs_ops = { .chars_in_buffer = rs_chars_in_buffer, .flush_buffer = rs_flush_buffer, .ioctl = rs_ioctl, - .throttle = rs_throttle, - .unthrottle = rs_unthrottle, + .throttle = rs_throttle, + .unthrottle = rs_unthrottle, .set_termios = rs_set_termios, .stop = rs_stop, .start = rs_start, @@ -3451,12 +3931,10 @@ rs_init(void) return -ENOMEM; show_serial_version(); - - init_bh(SERIAL_BH, do_serial_bh); /* Setup the timed flush handler system */ -#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) && !defined(CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST) +#if !defined(CONFIG_ETRAX_SERIAL_FAST_TIMER) init_timer(&flush_timer); flush_timer.function = timed_flush_handler; mod_timer(&flush_timer, jiffies + CONFIG_ETRAX_SERIAL_RX_TIMEOUT_TICKS); @@ -3477,7 +3955,7 @@ rs_init(void) tty_set_operations(driver, &rs_ops); if (tty_register_driver(driver)) panic("Couldn't register serial driver\n"); - serial_driver = driver; + serial_driver = driver; /* do some initializing for the separate ports */ @@ -3495,15 +3973,12 @@ rs_init(void) info->event = 0; info->count = 0; info->blocked_open = 0; - info->tqueue.routine = do_softint; - info->tqueue.data = info; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); info->xmit.buf = NULL; info->xmit.tail = info->xmit.head = 0; - info->recv.buf = NULL; - info->recv.tail = info->recv.head = 0; - info->flag_buf = NULL; + info->first_recv_buffer = info->last_recv_buffer = NULL; + info->recv_cnt = info->max_recv_cnt = 0; info->last_tx_active_usec = 0; info->last_tx_active = 0; @@ -3514,12 +3989,22 @@ rs_init(void) info->rs485.delay_rts_before_send = 0; info->rs485.enabled = 0; #endif + INIT_WORK(&info->work, do_softint, info); if (info->enabled) { printk(KERN_INFO "%s%d at 0x%x is a builtin UART with DMA\n", serial_driver->name, info->line, (unsigned int)info->port); } } +#ifdef CONFIG_ETRAX_FAST_TIMER +#ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER + memset(fast_timers, 0, sizeof(fast_timers)); +#endif +#ifdef CONFIG_ETRAX_RS485 + memset(fast_timers_rs485, 0, sizeof(fast_timers_rs485)); +#endif + fast_timer_init(); +#endif #ifndef CONFIG_SVINTO_SIM /* Not needed in simulator. May only complicate stuff. */ @@ -3531,7 +4016,7 @@ rs_init(void) panic("irq23"); #endif #ifdef SERIAL_HANDLE_EARLY_ERRORS - if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_INTERRUPT, "serial ", NULL)) + if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL)) panic("irq8"); #endif #ifdef CONFIG_ETRAX_SERIAL_PORT1 @@ -3555,12 +4040,6 @@ rs_init(void) panic("irq21"); #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("err: timer1 irq\n"); - } -#endif #endif /* CONFIG_SVINTO_SIM */ return 0; diff --git a/arch/cris/drivers/serial.h b/arch/cris/arch-v10/drivers/serial.h index 1994228fa102..45813c657aaf 100644 --- a/arch/cris/drivers/serial.h +++ b/arch/cris/arch-v10/drivers/serial.h @@ -25,6 +25,15 @@ #define SERIAL_RECV_DESCRIPTORS 8 +struct etrax_recv_buffer { + struct etrax_recv_buffer *next; + unsigned short length; + unsigned char error; + unsigned char pad; + + unsigned char buffer[0]; +}; + struct e100_serial { int baud; volatile u8 *port; /* R_SERIALx_CTRL */ @@ -79,10 +88,12 @@ struct e100_serial { int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ struct circ_buf xmit; - struct circ_buf recv; - unsigned char *flag_buf; + struct etrax_recv_buffer *first_recv_buffer; + struct etrax_recv_buffer *last_recv_buffer; + unsigned int recv_cnt; + unsigned int max_recv_cnt; - struct tq_struct tqueue; + struct work_struct work; struct async_icount icount; /* error-statistics etc.*/ #ifdef DECLARE_WAITQUEUE wait_queue_head_t open_wait; @@ -101,7 +112,7 @@ struct e100_serial { int break_detected_cnt; int errorcode; -#ifdef CONFIG_RS485 +#ifdef CONFIG_ETRAX_RS485 struct rs485_control rs485; /* RS-485 support */ #endif }; diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile new file mode 100644 index 000000000000..20a56080a8f0 --- /dev/null +++ b/arch/cris/arch-v10/kernel/Makefile @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.4 2003/07/04 12:57:13 tobiasa Exp $ +# +# Makefile for the linux kernel. +# + +extra-y := head.o + + +obj-y := entry.o traps.o shadows.o debugport.o irq.o \ + process.o setup.o signal.o traps.o time.o ptrace.o + +obj-$(CONFIG_ETRAX_KGDB) += kgdb.o +obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o + +clean: + diff --git a/arch/cris/arch-v10/kernel/asm-offsets.c b/arch/cris/arch-v10/kernel/asm-offsets.c new file mode 100644 index 000000000000..1aa3cc4e7107 --- /dev/null +++ b/arch/cris/arch-v10/kernel/asm-offsets.c @@ -0,0 +1,47 @@ +#include <linux/sched.h> +#include <asm/thread_info.h> + +/* + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed to extract + * and format the required data. + */ + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ +#define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry)) + ENTRY(orig_r10); + ENTRY(r13); + ENTRY(r12); + ENTRY(r11); + ENTRY(r10); + ENTRY(r9); + ENTRY(mof); + ENTRY(dccr); + ENTRY(srp); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry)) + ENTRY(task); + ENTRY(flags); + ENTRY(preempt_count); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry)) + ENTRY(ksp); + ENTRY(usp); + ENTRY(dccr); + BLANK(); +#undef ENTRY +#define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry)) + ENTRY(pid); + BLANK(); + DEFINE(LCLONE_VM, CLONE_VM); + DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED); + return 0; +} diff --git a/arch/cris/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index fa20b2146adf..012c3028e5f6 100644 --- a/arch/cris/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -12,6 +12,33 @@ * init_etrax_debug() * * $Log: debugport.c,v $ + * Revision 1.11 2003/07/07 09:53:36 starvik + * Revert all the 2.5.74 merge changes to make the console work again + * + * Revision 1.9 2003/02/17 17:07:23 starvik + * Solved the problem with corrupted debug output (from Linux 2.4) + * * Wait until DMA, FIFO and pipe is empty before and after transmissions + * * Buffer data until a FIFO flush can be triggered. + * + * Revision 1.8 2003/01/22 06:48:36 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.7 2002/12/12 08:26:32 starvik + * Don't use C-comments inside CVS comments + * + * Revision 1.6 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ + * + * Revision 1.5 2002/11/20 06:58:03 starvik + * Compiles with kgdb + * + * Revision 1.4 2002/11/19 14:35:24 starvik + * Changes from linux 2.4 + * Changed struct initializer syntax to the currently prefered notation + * + * Revision 1.3 2002/11/06 09:47:03 starvik + * Modified for new interrupt macros + * * Revision 1.2 2002/01/21 15:21:50 bjornw * Update for kdev_t changes * @@ -31,9 +58,10 @@ #include <linux/console.h> #include <linux/init.h> #include <linux/major.h> +#include <linux/delay.h> #include <asm/system.h> -#include <asm/svinto.h> +#include <asm/arch/svinto.h> #include <asm/io.h> /* Get SIMCOUT. */ /* Which serial-port is our debug port ? */ @@ -94,6 +122,8 @@ #define DEBUG_DMA_IRQ_CLR IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr) #endif +#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 * for completion. Interrupts are disabled during the whole process. Some * caution needs to be taken to not interfere with ttyS business on this port. @@ -102,9 +132,13 @@ static void console_write(struct console *co, const char *buf, unsigned int len) { + 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; - int in_progress; #ifdef CONFIG_ETRAX_DEBUG_PORT_NULL /* no debug printout at all */ @@ -117,16 +151,48 @@ console_write(struct console *co, const char *buf, unsigned int len) return; #endif - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); #ifdef CONFIG_ETRAX_KGDB /* kgdb needs to output debug info using the gdb protocol */ putDebugString(buf, len); - restore_flags(flags); + local_irq_restore(flags); return; #endif + /* To make this work together with the real serial port driver + * we have to make sure that everything is flushed when we leave + * here. The following steps are made to assure this: + * 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; + } + } + /* 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 @@ -134,38 +200,37 @@ console_write(struct console *co, const char *buf, unsigned int len) */ *DEBUG_TR_CTRL = 0x40; - - /* if the tty has some ongoing business, remember it */ - - in_progress = *DEBUG_OCMD & 7; - - if(in_progress) { - /* wait until the output dma channel is ready */ - - while(*DEBUG_OCMD & 7) /* nothing */ ; + 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); } - descr.ctrl = d_eol; - descr.sw_len = len; - descr.buf = __pa(buf); - - *DEBUG_FIRST = __pa(&descr); /* write to R_DMAx_FIRST */ + *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); - while(*DEBUG_OCMD & 7) /* nothing */; - - /* clear pending interrupts so we don't get a surprise below */ - - if(in_progress) - *DEBUG_OCLRINT = 2; /* only clear EOP, leave DESCR for the tty */ - else - *DEBUG_OCLRINT = 3; /* clear both EOP and DESCR */ - - while(*DEBUG_STATUS & 0x7f); /* wait until output FIFO is empty as well */ - - restore_flags(flags); + tmp_size = 0; + local_irq_restore(flags); } /* legacy function */ @@ -227,11 +292,11 @@ console_setup(struct console *co, char *options) } static struct console sercons = { - .name = "ttyS", - .write = console_write, - .read = NULL, - .device = console_device, - .unblank = NULL, + .name = "ttyS", + .write = console_write, + .read = NULL, + .device = console_device, + .unblank = NULL, .setup = console_setup, .flags = CON_PRINTBUFFER, .index = DEBUG_PORT_IDX, diff --git a/arch/cris/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 2c0477bcdd50..5e5f5be7e139 100644 --- a/arch/cris/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -1,12 +1,55 @@ -/* $Id: entry.S,v 1.3 2002/01/21 15:22:20 bjornw Exp $ +/* $Id: entry.S,v 1.16 2003/07/04 08:27:41 starvik Exp $ * * linux/arch/cris/entry.S * - * Copyright (C) 2000, 2001 Axis Communications AB + * Copyright (C) 2000, 2001, 2002 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.16 2003/07/04 08:27:41 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.15 2003/04/09 07:32:55 starvik + * resume should return task_struct, not thread_info + * + * Revision 1.14 2003/04/09 05:20:44 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.13 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c + * + * Revision 1.12 2002/12/10 09:00:10 starvik + * Merge of Linux 2.5.51 + * + * Revision 1.11 2002/12/05 07:53:10 starvik + * Corrected constants used with btstq + * + * Revision 1.10 2002/11/27 08:45:10 starvik + * pid is in task_struct, not thread_info + * + * Revision 1.9 2002/11/26 09:52:05 starvik + * Added preemptive kernel scheduling (if CONFIG_PREEMPT) + * + * Revision 1.8 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.7 2002/11/18 13:02:42 starvik + * Added fourth parameter to do_notify_resume + * Minor cleanup + * + * Revision 1.6 2002/11/11 10:37:50 starvik + * Use new asm-offset defines + * Modified for new location of current->work etc + * Removed SYMBOL_NAME from syscalls + * Added some new syscalls + * + * Revision 1.5 2002/11/05 06:45:11 starvik + * Merge of Linux 2.5.45 + * + * Revision 1.4 2002/02/05 15:41:31 bjornw + * Rewritten to conform better to current 2.5 code (similar to arch/i386) + * * Revision 1.3 2002/01/21 15:22:20 bjornw * NICE_DOGGY fix from 2.4 arch/cris * @@ -185,75 +228,88 @@ #include <linux/linkage.h> #include <linux/sys.h> #include <asm/unistd.h> -#include <asm/sv_addr_ag.h> +#include <asm/arch/sv_addr_ag.h> #include <asm/errno.h> - +#include <asm/thread_info.h> +#include <asm/arch/offset.h> + ;; functions exported from this file .globl system_call .globl ret_from_intr - .globl ret_from_sys_call + .globl ret_from_fork .globl resume .globl multiple_interrupt .globl hwbreakpoint .globl IRQ1_interrupt - .globl timer_interrupt - .globl timer_shortcut .globl spurious_interrupt .globl hw_bp_trigs .globl mmu_bus_fault .globl do_sigtrap .globl gdb_handle_breakpoint - .globl sys_call_table - ;; Get values and offsets into various structs. The file isn't - ;; suitable for consumption by the preprocessor, so don't use - ;; #include. - .include "entryoffsets.s" - - ;; process bits for ptrace. FIXME: Should be in a header file. - -PT_TRACESYS_BIT = 1 - ;; below are various parts of system_call which are not in the fast-path - ;; handle software irqs - -_handle_softirq: - move.d $r9, $r1 - jsr do_softirq ; call the C routine for softirq handling - move.d $r1, $r9 - - ;; fall-through - +#ifdef CONFIG_PREEMPT + ; Check if preemptive kernel scheduling should be done +_resume_kernel: + ; Load current task struct + movs.w -8192, $r0 ; THREAD_SIZE = 8192 + and.d $sp, $r0 + move.d [$r0+TI_preempt_count], $r10 ; Preemption disabled? + bne _Rexit + nop +_need_resched: + move.d [$r0+TI_flags], $r10 + btstq TIF_NEED_RESCHED, $r10 ; Check if need_resched is set + bpl _Rexit + nop + ; Ok, lets's do some preemptive kernel scheduling + move.d PREEMPT_ACTIVE, $r10 + move.d $r10, [$r0+TI_preempt_count] ; Mark as active + ei + jsr schedule + clear.d [$r0+TI_preempt_count] ; Mark as inactive + di + ; Load new task struct + movs.w -8192, $r0 ; THREAD_SIZE = 8192 + and.d $sp, $r0 + ; One more time (with new task) + ba _need_resched + nop +#else +#define _resume_kernel _Rexit +#endif + + ; Called at exit from fork. schedule_tail must be called to drop + ; spinlock if CONFIG_PREEMPT +ret_from_fork: + jsr schedule_tail + ba ret_from_sys_call + nop + ret_from_intr: - ;; check for resched only if we're going back to user-mode + ;; check for resched if preemptive kernel or if we're going back to user-mode ;; this test matches the user_regs(regs) macro ;; we cannot simply test $dccr, because that does not necessarily ;; reflect what mode we'll return into. - move.d [$sp + LDCCR], $r0; regs->dccr + move.d [$sp + PT_dccr], $r0; regs->dccr btstq 8, $r0 ; U-flag - bpl _Rexit ; go back directly - nop - ba _ret_with_reschedule ; go back but check schedule and signals first - nop + bpl _resume_kernel + ; Note that di below is in delay slot + +_resume_userspace: + di ; so need_resched and sigpending don't change -_reschedule: - ;; keep r9 intact - move.d $r9, $r1 - jsr schedule - ba ret_from_sys_call - move.d $r1, $r9 + movs.w -8192, $r0 ; THREAD_SIZE == 8192 + and.d $sp, $r0 - ;; return but call do_signal first -_signal_return: - ei ; we can get here from an interrupt - move.d $r9, $r10 ; do_signals syscall/irq param - moveq 0, $r11 ; oldset param - 0 in this case - move.d $sp, $r12 ; another argument to do_signal (the regs param) - jsr do_signal ; arch/cris/kernel/signal.c + move.d [$r0+TI_flags], $r10 ; current->work + and.d _TIF_WORK_MASK, $r10 ; is there any work to be done on return + bne _work_pending + nop ba _Rexit nop @@ -285,18 +341,20 @@ system_call: clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe movs.w -ENOSYS, $r0 - move.d $r0, [$sp+LR10] ; put the default return value in r10 in the frame + move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame ;; check if this process is syscall-traced movs.w -8192, $r0 ; THREAD_SIZE == 8192 and.d $sp, $r0 - move.d [$r0+LTASK_PTRACE], $r0 - btstq PT_TRACESYS_BIT, $r0 - bmi _tracesys + move.d [$r0+TI_flags], $r0 + btstq TIF_SYSCALL_TRACE, $r0 + bmi _syscall_trace_entry nop +_syscall_traced: + ;; check for sanity in the requested syscall number cmpu.w NR_syscalls, $r9 @@ -317,39 +375,26 @@ system_call: jsr [$r9+sys_call_table] ; actually do the system call addq 3*4, $sp ; pop the mof, srp and regs parameters - move.d $r10, [$sp+LR10] ; save the return value + move.d $r10, [$sp+PT_r10] ; save the return value moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call ;; fall through into ret_from_sys_call to return ret_from_sys_call: - ;; r9 is a parameter - if 1, we came from a syscall, if 0, from an irq + ;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq - ;; check if any bottom halves need service - - test.d [irq_stat] ; softirq_pending - bne _handle_softirq - nop + ;; get the current task-struct pointer (see top for defs) -_ret_with_reschedule: - ;; first get the current task-struct pointer (see top for defs) + movs.w -8192, $r0 ; THREAD_SIZE == 8192 + and.d $sp, $r0 - move.d $sp, $r0 - and.d -8192, $r0 ; THREAD_SIZE == 8192 - - ;; see if we want to reschedule into another process - - test.d [$r0+LTASK_NEEDRESCHED] - bne _reschedule + di ; make sure need_resched and sigpending don't change + move.d [$r0+TI_flags],$r1 + and.d _TIF_ALLWORK_MASK, $r1 + bne _syscall_exit_work nop - ;; see if we need to run signal checks (important that r9 is intact here) - - test.d [$r0+LTASK_SIGPENDING] - bne _signal_return - nop - _Rexit: ;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h pop $r10 ; frametype @@ -375,63 +420,82 @@ _RBFexit: pop $srp ; subroutine return pointer rbf [$sp+] ; return by popping the CPU status -_tracesys: - ;; this first invocation of syscall_trace _requires_ that - ;; LR10 in the frame contains -ENOSYS (as is set in the beginning - ;; of system_call). - - jsr syscall_trace - - ;; now we should more or less do the same things as in the system_call - ;; but since our argument regs got clobbered during syscall_trace and - ;; because syscall_trace might want to alter them, we need to reload them - ;; from the stack-frame as we use them. - - ;; check for sanity in the requested syscall number - - move.d [$sp+LR9], $r9 - movs.w -ENOSYS, $r10 - cmpu.w NR_syscalls, $r9 - bcc 1f - lslq 2, $r9 ; multiply by 4, in the delay slot - - ;; read the system call vector entry into r9 + ;; We get here after doing a syscall if extra work might need to be done + ;; perform syscall exit tracing if needed - move.d [$r9+sys_call_table], $r9 - - ;; restore r10, r11, r12, r13, mof and srp into the needed registers - - move.d [$sp+LORIG_R10], $r10 ; LR10 is already filled with -ENOSYS. - move.d [$sp+LR11], $r11 - move.d [$sp+LR12], $r12 - move.d [$sp+LR13], $r13 - move [$sp+LMOF], $mof - move [$sp+LSRP], $srp - - ;; as a bonus 7th parameter, we give the location on the stack - ;; of the register structure itself. some syscalls need this. +_syscall_exit_work: + ;; $r0 contains current at this point and irq's are disabled - push $sp + move.d [$r0+TI_flags], $r1 + btstq TIF_SYSCALL_TRACE, $r1 + bpl _work_pending + nop - ;; the fifth and sixth parameters needs to be put on the stack for - ;; the system call to find them + ei - push $srp - push $mof + move.d $r9, $r1 ; preserve r9 + jsr do_syscall_trace + move.d $r1, $r9 + + ba _resume_userspace + nop + +_work_pending: + move.d [$r0+TI_flags], $r1 + btstq TIF_NEED_RESCHED, $r1 + bpl _work_notifysig ; was neither trace nor sched, must be signal/notify + nop + +_work_resched: + move.d $r9, $r1 ; preserve r9 + jsr schedule + move.d $r1, $r9 + di - jsr $r9 ; actually call the system-call - addq 3*4, $sp ; pop the srp, mof and regs parameters + move.d [$r0+TI_flags], $r1 + and.d _TIF_WORK_MASK, $r1; ignore the syscall trace counter + beq _Rexit + nop + btstq TIF_NEED_RESCHED, $r1 + bmi _work_resched ; current->work.need_resched + nop -1: move.d $r10, [$sp+LR10]; save the return value +_work_notifysig: + ;; deal with pending signals and notify-resume requests - ;; second call of syscall_trace, to let it grab the results - - jsr syscall_trace + move.d $r9, $r10 ; do_notify_resume syscall/irq param + moveq 0, $r11 ; oldset param - 0 in this case + move.d $sp, $r12 ; the regs param + move.d $r1, $r13 ; the thread_info_flags parameter + jsr do_notify_resume + + ba _Rexit + nop - moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call - ba ret_from_sys_call + ;; We get here as a sidetrack when we've entered a syscall with the + ;; trace-bit set. We need to call do_syscall_trace and then continue + ;; with the call. + +_syscall_trace_entry: + ;; PT_r10 in the frame contains -ENOSYS as required, at this point + + jsr do_syscall_trace + + ;; now re-enter the syscall code to do the syscall itself + ;; we need to restore $r9 here to contain the wanted syscall, and + ;; the other parameter-bearing registers + + move.d [$sp+PT_r9], $r9 + move.d [$sp+PT_orig_r10], $r10 ; PT_r10 is already filled with -ENOSYS. + move.d [$sp+PT_r11], $r11 + move.d [$sp+PT_r12], $r12 + move.d [$sp+PT_r13], $r13 + move [$sp+PT_mof], $mof + move [$sp+PT_srp], $srp + + ba _syscall_traced nop - + ;; resume performs the actual task-switching, by switching stack pointers ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct ;; returns old current in r10 @@ -442,26 +506,27 @@ _tracesys: resume: push $srp ; we keep the old/new PC on the stack add.d $r12, $r10 ; r10 = current tasks tss - move $dccr, [$r10+LTHREAD_DCCR] ; save irq enable state + move $dccr, [$r10+THREAD_dccr]; save irq enable state di - move $usp, [$r10+LTHREAD_USP] ; save user-mode stackpointer + move $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer ;; See copy_thread for the reason why register R9 is saved. subq 10*4, $sp movem $r9, [$sp] ; save non-scratch registers and R9. - move.d $sp, [$r10+LTHREAD_KSP] ; save the kernel stack pointer for the old task + move.d $sp, [$r10+THREAD_ksp] ; save the kernel stack pointer for the old task move.d $sp, $r10 ; return last running task in r10 - and.d -8192, $r10 ; get task ptr from stackpointer + and.d -8192, $r10 ; get thread_info from stackpointer + move.d [$r10+TI_task], $r10 ; get task add.d $r12, $r11 ; find the new tasks tss - move.d [$r11+LTHREAD_KSP], $sp ; switch into the new stackframe by restoring kernel sp + move.d [$r11+THREAD_ksp], $sp ; switch into the new stackframe by restoring kernel sp movem [$sp+], $r9 ; restore non-scratch registers and R9. - move [$r11+LTHREAD_USP], $usp ; restore user-mode stackpointer + move [$r11+THREAD_usp], $usp ; restore user-mode stackpointer - move [$r11+LTHREAD_DCCR], $dccr ; restore irq enable status + move [$r11+THREAD_dccr], $dccr ; restore irq enable status jump [$sp+] ; restore PC ;; This is the MMU bus fault handler. @@ -689,7 +754,8 @@ do_sigtrap: movs.w -8192,$r9 ; THREAD_SIZE == 8192 and.d $sp, $r9 - move.d [$r9+LTASK_PID], $r10 ; current->pid as arg1. + move.d [$r9+TI_task], $r10 + move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. moveq 5, $r11 ; SIGTRAP as arg2. jsr sys_kill jump ret_from_intr ; Use the return routine for interrupts. @@ -722,75 +788,9 @@ hw_bp_trigs: hw_bp_trig_ptr: .dword hw_bp_trigs -/* - * This is the mechanism for creating a new kernel thread. - * - * NOTE! Only a kernel-only process (i.e. the swapper or direct descendants - * who haven't done an "execve()") should use this: it will work within - * a system call from a "real" process, but the process memory space will - * not be free'd until both the parent and the child have exited. - * - * This *can* be done in C with an single-asm-wrapped-in-a-function, but you - * get more or less gross code. The safer you make the asm-constraints, - * the grosser the code, at least with the gcc version in cris-dist-1.13. - */ - -/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */ -/* r10 r11 r12 */ - - .text - .global kernel_thread -kernel_thread: - - /* Save ARG for later. */ - move.d $r11, $r13 - - /* r11 is argument 2 to clone, the flags */ - move.d $r12, $r11 - or.w LCLONE_VM, $r11 - or.w LCLONE_UNTRACED, $r11 - - /* Save FN for later. */ - move.d $r10, $r12 - - /* r9 contains syscall number, to sys_clone */ - movu.w __NR_clone, $r9 - - /* r10 is argument 1 to clone */ - clear.d $r10 - - /* call sys_clone, this will fork */ - break 13 - - /* parent or child? child returns 0 here. */ - test.d $r10 - - /* jump if parent */ - bne 1f - nop /* delay slot */ - - /* set argument to function to call */ - move.d $r13, $r10 - - /* call specified function */ - jsr $r12 - /* If we ever return from the function, something bad has happened. */ - - /* r9 is sys_exit syscall number */ - movu.w __NR_exit, $r9 - - /* Give a really bad exit-value */ - moveq -1, $r10 - - /* call sys_exit, killing the child */ - break 13 -1: - ret - nop /* delay slot */ - .section .rodata,"a" sys_call_table: - .long sys_ni_syscall /* 0 - old "setup()" system call*/ + .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit .long sys_fork .long sys_read @@ -842,7 +842,7 @@ sys_call_table: .long sys_geteuid16 .long sys_getegid16 /* 50 */ .long sys_acct - .long sys_umount /* recycled never used phys() */ + .long sys_umount /* recycled never used phys( */ .long sys_ni_syscall /* old lock syscall holder */ .long sys_ioctl .long sys_fcntl /* 55 */ @@ -913,14 +913,14 @@ sys_call_table: .long sys_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_ni_syscall /* TODO sys_modify_ldt - do something ?*/ + .long sys_ni_syscall /* sys_modify_ldt */ .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask - .long sys_create_module + .long sys_ni_syscall /* old "create_module" */ .long sys_init_module .long sys_delete_module - .long sys_get_kernel_syms /* 130 */ + .long sys_ni_syscall /* 130: old "get_kernel_syms" */ .long sys_quotactl .long sys_getpgid .long sys_fchdir @@ -945,19 +945,19 @@ sys_call_table: .long sys_mlockall .long sys_munlockall .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ + .long sys_sched_getparam /* 155 */ .long sys_sched_setscheduler .long sys_sched_getscheduler .long sys_sched_yield .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ + .long sys_sched_get_priority_min /* 160 */ .long sys_sched_rr_get_interval .long sys_nanosleep .long sys_mremap .long sys_setresuid16 .long sys_getresuid16 /* 165 */ .long sys_ni_syscall /* sys_vm86 */ - .long sys_query_module + .long sys_ni_syscall /* Old sys_query_module */ .long sys_poll .long sys_nfsservctl .long sys_setresgid16 /* 170 */ @@ -970,8 +970,8 @@ sys_call_table: .long sys_rt_sigtimedwait .long sys_rt_sigqueueinfo .long sys_rt_sigsuspend - .long sys_pread /* 180 */ - .long sys_pwrite + .long sys_pread64 /* 180 */ + .long sys_pwrite64 .long sys_chown16 .long sys_getcwd .long sys_capget @@ -1013,11 +1013,54 @@ sys_call_table: .long sys_getdents64 /* 220 */ .long sys_fcntl64 .long sys_ni_syscall /* reserved for TUX */ - .long sys_ni_syscall /* Reserved for Security */ + .long sys_ni_syscall .long sys_gettid .long sys_readahead /* 225 */ + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr + .long sys_lgetxattr /* 230 */ + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr + .long sys_removexattr /* 235 */ + .long sys_lremovexattr + .long sys_fremovexattr .long sys_tkill - + .long sys_sendfile64 + .long sys_futex /* 240 */ + .long sys_sched_setaffinity + .long sys_sched_getaffinity + .long sys_ni_syscall /* sys_set_thread_area */ + .long sys_ni_syscall /* sys_get_thread_area */ + .long sys_io_setup /* 245 */ + .long sys_io_destroy + .long sys_io_getevents + .long sys_io_submit + .long sys_io_cancel + .long sys_fadvise64 /* 250 */ + .long sys_ni_syscall + .long sys_exit_group + .long sys_lookup_dcookie + .long sys_epoll_create + .long sys_epoll_ctl /* 255 */ + .long sys_epoll_wait + .long sys_remap_file_pages + .long sys_set_tid_address + .long sys_timer_create + .long sys_timer_settime /* 260 */ + .long sys_timer_gettime + .long sys_timer_getoverrun + .long sys_timer_delete + .long sys_clock_settime + .long sys_clock_gettime /* 265 */ + .long sys_clock_getres + .long sys_clock_nanosleep + .long sys_statfs64 + .long sys_fstatfs64 + /* * NOTE!! This doesn't have to be exact - we just have * to make sure we have _enough_ of the "sys_ni_syscall" diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c new file mode 100644 index 000000000000..2c2cb60c4710 --- /dev/null +++ b/arch/cris/arch-v10/kernel/fasttimer.c @@ -0,0 +1,996 @@ +/* $Id: fasttimer.c,v 1.4 2003/07/04 08:27:41 starvik Exp $ + * linux/arch/cris/kernel/fasttimer.c + * + * Fast timers for ETRAX100/ETRAX100LX + * This may be useful in other OS than Linux so use 2 space indentation... + * + * $Log: fasttimer.c,v $ + * Revision 1.4 2003/07/04 08:27:41 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.3 2002/12/12 08:26:32 starvik + * Don't use C-comments inside CVS comments + * + * Revision 1.2 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ + * + * Revision 1.1 2002/11/18 07:58:06 starvik + * Fast timers (from Linux 2.4) + * + * Revision 1.5 2002/10/15 06:21:39 starvik + * Added call to init_waitqueue_head + * + * Revision 1.4 2002/05/28 17:47:59 johana + * Added del_fast_timer() + * + * Revision 1.3 2002/05/28 16:16:07 johana + * Handle empty fast_timer_list + * + * Revision 1.2 2002/05/27 15:38:42 johana + * Made it compile without warnings on Linux 2.4. + * (includes, wait_queue, PROC_FS and snprintf) + * + * Revision 1.1 2002/05/27 15:32:25 johana + * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree. + * + * Revision 1.8 2001/11/27 13:50:40 pkj + * Disable interrupts while stopping the timer and while modifying the + * list of active timers in timer1_handler() as it may be interrupted + * by other interrupts (e.g., the serial interrupt) which may add fast + * timers. + * + * Revision 1.7 2001/11/22 11:50:32 pkj + * * Only store information about the last 16 timers. + * * proc_fasttimer_read() now uses an allocated buffer, since it + * requires more space than just a page even for only writing the + * last 16 timers. The buffer is only allocated on request, so + * unless /proc/fasttimer is read, it is never allocated. + * * Renamed fast_timer_started to fast_timers_started to match + * fast_timers_added and fast_timers_expired. + * * Some clean-up. + * + * Revision 1.6 2000/12/13 14:02:08 johana + * Removed volatile for fast_timer_list + * + * Revision 1.5 2000/12/13 13:55:35 johana + * Added DEBUG_LOG, added som cli() and cleanup + * + * Revision 1.4 2000/12/05 13:48:50 johana + * Added range check when writing proc file, modified timer int handling + * + * Revision 1.3 2000/11/23 10:10:20 johana + * More debug/logging possibilities. + * Moved GET_JIFFIES_USEC() to timex.h and time.c + * + * Revision 1.2 2000/11/01 13:41:04 johana + * Clean up and bugfixes. + * Created new do_gettimeofday_fast() that gets a timeval struct + * with time based on jiffies and *R_TIMER0_DATA, uses a table + * for fast conversion of timer value to microseconds. + * (Much faster the standard do_gettimeofday() and we don't really + * wan't to use the true time - we wan't the "uptime" so timers don't screw up + * when we change the time. + * TODO: Add efficient support for continuous timers as well. + * + * Revision 1.1 2000/10/26 15:49:16 johana + * Added fasttimer, highresolution timers. + * + * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden + */ + +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/delay.h> + +#include <asm/segment.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/delay.h> +#include <asm/rtc.h> + +#include <linux/config.h> +#include <linux/version.h> + +#include <asm/arch/svinto.h> +#include <asm/fasttimer.h> +#include <linux/proc_fs.h> + + +#define DEBUG_LOG_INCLUDED +#define FAST_TIMER_LOG +//#define FAST_TIMER_TEST + +#define FAST_TIMER_SANITY_CHECKS + +#ifdef FAST_TIMER_SANITY_CHECKS +#define SANITYCHECK(x) x +static int sanity_failed = 0; +#else +#define SANITYCHECK(x) +#endif + +#define D1(x) +#define D2(x) +#define DP(x) + +#define __INLINE__ inline + +static int fast_timer_running = 0; +static int fast_timers_added = 0; +static int fast_timers_started = 0; +static int fast_timers_expired = 0; +static int fast_timers_deleted = 0; +static int fast_timer_is_init = 0; +static int fast_timer_ints = 0; + +static struct fast_timer *fast_timer_list = NULL; + +#ifdef DEBUG_LOG_INCLUDED +#define DEBUG_LOG_MAX 128 +static const char * debug_log_string[DEBUG_LOG_MAX]; +static unsigned long debug_log_value[DEBUG_LOG_MAX]; +static int debug_log_cnt = 0; +static int debug_log_cnt_wrapped = 0; + +#define DEBUG_LOG(string, value) \ +{ \ + unsigned long log_flags; \ + save_flags(log_flags); \ + cli(); \ + debug_log_string[debug_log_cnt] = (string); \ + debug_log_value[debug_log_cnt] = (unsigned long)(value); \ + if (++debug_log_cnt >= DEBUG_LOG_MAX) \ + { \ + debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ + debug_log_cnt_wrapped = 1; \ + } \ + restore_flags(log_flags); \ +} +#else +#define DEBUG_LOG(string, value) +#endif + + +/* The frequencies for index = clkselx number in R_TIMER_CTRL */ +#define NUM_TIMER_FREQ 15 +#define MAX_USABLE_TIMER_FREQ 7 +#define MAX_DELAY_US 853333L +const unsigned long timer_freq_100[NUM_TIMER_FREQ] = +{ + 3, /* 0 3333 - 853333 us */ + 6, /* 1 1666 - 426666 us */ + 12, /* 2 833 - 213333 us */ + 24, /* 3 416 - 106666 us */ + 48, /* 4 208 - 53333 us */ + 96, /* 5 104 - 26666 us */ + 192, /* 6 52 - 13333 us */ + 384, /* 7 26 - 6666 us */ + 576, + 1152, + 2304, + 4608, + 9216, + 18432, + 62500, + /* 15 = cascade */ +}; +#define NUM_TIMER_STATS 16 +#ifdef FAST_TIMER_LOG +struct fast_timer timer_added_log[NUM_TIMER_STATS]; +struct fast_timer timer_started_log[NUM_TIMER_STATS]; +struct fast_timer timer_expired_log[NUM_TIMER_STATS]; +#endif + +int timer_div_settings[NUM_TIMER_STATS]; +int timer_freq_settings[NUM_TIMER_STATS]; +int timer_delay_settings[NUM_TIMER_STATS]; + +/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ +void __INLINE__ do_gettimeofday_fast(struct timeval *tv) +{ + unsigned long sec = jiffies; + unsigned long usec = GET_JIFFIES_USEC(); + + usec += (sec % HZ) * (1000000 / HZ); + sec = sec / HZ; + + if (usec > 1000000) + { + usec -= 1000000; + sec++; + } + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1) +{ + if (t0->tv_sec < t1->tv_sec) + { + return -1; + } + else if (t0->tv_sec > t1->tv_sec) + { + return 1; + } + if (t0->tv_usec < t1->tv_usec) + { + return -1; + } + else if (t0->tv_usec > t1->tv_usec) + { + return 1; + } + return 0; +} + +void __INLINE__ start_timer1(unsigned long delay_us) +{ + int freq_index = 0; /* This is the lowest resolution */ + unsigned long upper_limit = MAX_DELAY_US; + + unsigned long div; + /* Start/Restart the timer to the new shorter value */ + /* t = 1/freq = 1/19200 = 53us + * T=div*t, div = T/t = delay_us*freq/1000000 + */ +#if 1 /* Adaptive timer settings */ + while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ) + { + freq_index++; + upper_limit >>= 1; /* Divide by 2 using shift */ + } + if (freq_index > 0) + { + freq_index--; + } +#else + freq_index = 6; +#endif + div = delay_us * timer_freq_100[freq_index]/10000; + if (div < 2) + { + /* Maybe increase timer freq? */ + div = 2; + } + if (div > 255) + { + div = 0; /* This means 256, the max the timer takes */ + /* If a longer timeout than the timer can handle is used, + * then we must restart it when it goes off. + */ + } + + timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div; + timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index; + timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; + + D1(printk("start_timer1 : %d us freq: %i div: %i\n", + delay_us, freq_index, div)); + /* Clear timer1 irq */ + *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); + + /* Set timer values */ + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & + ~IO_MASK(R_TIMER_CTRL, timerdiv1) & + ~IO_MASK(R_TIMER_CTRL, tm1) & + ~IO_MASK(R_TIMER_CTRL, clksel1)) | + IO_FIELD(R_TIMER_CTRL, timerdiv1, div) | + IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | + IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */ + + /* Ack interrupt */ + *R_TIMER_CTRL = r_timer_ctrl_shadow | + IO_STATE(R_TIMER_CTRL, i1, clr); + + /* Start timer */ + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | + IO_STATE(R_TIMER_CTRL, tm1, run); + + /* Enable timer1 irq */ + *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); + fast_timers_started++; + fast_timer_running = 1; +} + +/* In version 1.4 this function takes 27 - 50 us */ +void start_one_shot_timer(struct fast_timer *t, + fast_timer_function_type *function, + unsigned long data, + unsigned long delay_us, + const char *name) +{ + unsigned long flags; + struct fast_timer *tmp; + + D1(printk("sft %s %d us\n", name, delay_us)); + + save_flags(flags); + cli(); + + do_gettimeofday_fast(&t->tv_set); + tmp = fast_timer_list; + + SANITYCHECK({ /* Check so this is not in the list already... */ + while (tmp != NULL) + { + if (tmp == t) + { + printk("timer name: %s data: 0x%08lX already in list!\n", name, data); + sanity_failed++; + return; + } + else + { + tmp = tmp->next; + } + } + tmp = fast_timer_list; + }); + + t->delay_us = delay_us; + t->function = function; + t->data = data; + t->name = name; + + t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; + t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000; + if (t->tv_expires.tv_usec > 1000000) + { + t->tv_expires.tv_usec -= 1000000; + t->tv_expires.tv_sec++; + } +#ifdef FAST_TIMER_LOG + timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; +#endif + fast_timers_added++; + + /* Check if this should timeout before anything else */ + if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0) + { + /* Put first in list and modify the timer value */ + t->prev = NULL; + t->next = fast_timer_list; + if (fast_timer_list) + { + fast_timer_list->prev = t; + } + fast_timer_list = t; +#ifdef FAST_TIMER_LOG + timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; +#endif + start_timer1(delay_us); + } else { + /* Put in correct place in list */ + while (tmp->next && + timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) + { + tmp = tmp->next; + } + /* Insert t after tmp */ + t->prev = tmp; + t->next = tmp->next; + if (tmp->next) + { + tmp->next->prev = t; + } + tmp->next = t; + } + + D2(printk("start_one_shot_timer: %d us done\n", delay_us)); + + restore_flags(flags); +} /* start_one_shot_timer */ + +static inline int fast_timer_pending (const struct fast_timer * t) +{ + return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list); +} + +static inline int detach_fast_timer (struct fast_timer *t) +{ + struct fast_timer *next, *prev; + if (!fast_timer_pending(t)) + return 0; + next = t->next; + prev = t->prev; + if (next) + next->prev = prev; + if (prev) + prev->next = next; + else + fast_timer_list = next; + fast_timers_deleted++; + return 1; +} + +int del_fast_timer(struct fast_timer * t) +{ + unsigned long flags; + int ret; + + save_flags(flags); + cli(); + ret = detach_fast_timer(t); + t->next = t->prev = NULL; + restore_flags(flags); + return ret; +} /* del_fast_timer */ + + +/* Interrupt routines or functions called in interrupt context */ + +/* Timer 1 interrupt handler */ + +static irqreturn_t +timer1_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct fast_timer *t; + unsigned long flags; + + save_flags(flags); + cli(); + + /* Clear timer1 irq */ + *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); + + /* First stop timer, then ack interrupt */ + /* Stop timer */ + *R_TIMER_CTRL = r_timer_ctrl_shadow = + (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | + IO_STATE(R_TIMER_CTRL, tm1, stop_ld); + + /* Ack interrupt */ + *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); + + fast_timer_running = 0; + fast_timer_ints++; + + restore_flags(flags); + + t = fast_timer_list; + while (t) + { + struct timeval tv; + + /* Has it really expired? */ + do_gettimeofday_fast(&tv); + D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec)); + + if (timeval_cmp(&t->tv_expires, &tv) <= 0) + { + /* Yes it has expired */ +#ifdef FAST_TIMER_LOG + timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; +#endif + fast_timers_expired++; + + /* Remove this timer before call, since it may reuse the timer */ + save_flags(flags); + cli(); + if (t->prev) + { + t->prev->next = t->next; + } + else + { + fast_timer_list = t->next; + } + if (t->next) + { + t->next->prev = t->prev; + } + t->prev = NULL; + t->next = NULL; + restore_flags(flags); + + if (t->function != NULL) + { + t->function(t->data); + } + else + { + DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints); + } + } + else + { + /* Timer is to early, let's set it again using the normal routines */ + D1(printk(".\n")); + } + + save_flags(flags); + cli(); + if ((t = fast_timer_list) != NULL) + { + /* Start next timer.. */ + long us; + struct timeval tv; + + do_gettimeofday_fast(&tv); + us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 + + t->tv_expires.tv_usec - tv.tv_usec); + if (us > 0) + { + if (!fast_timer_running) + { +#ifdef FAST_TIMER_LOG + timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; +#endif + start_timer1(us); + } + restore_flags(flags); + break; + } + else + { + /* Timer already expired, let's handle it better late than never. + * The normal loop handles it + */ + D1(printk("e! %d\n", us)); + } + } + restore_flags(flags); + } + + if (!t) + { + D1(printk("t1 stop!\n")); + } + + return IRQ_HANDLED; +} + +static void wake_up_func(unsigned long data) +{ +#ifdef DECLARE_WAITQUEUE + wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; +#else + struct wait_queue **sleep_wait_p = (struct wait_queue **)data; +#endif + wake_up(sleep_wait_p); +} + + +/* Useful API */ + +void schedule_usleep(unsigned long us) +{ + struct fast_timer t; +#ifdef DECLARE_WAITQUEUE + wait_queue_head_t sleep_wait; + init_waitqueue_head(&sleep_wait); + { + DECLARE_WAITQUEUE(wait, current); +#else + struct wait_queue *sleep_wait = NULL; + struct wait_queue wait = { current, NULL }; +#endif + + D1(printk("schedule_usleep(%d)\n", us)); + add_wait_queue(&sleep_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, + "usleep"); + schedule(); + set_current_state(TASK_RUNNING); + remove_wait_queue(&sleep_wait, &wait); + D1(printk("done schedule_usleep(%d)\n", us)); +#ifdef DECLARE_WAITQUEUE + } +#endif +} + +#ifdef CONFIG_PROC_FS +static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + ,int *eof, void *data_unused +#else + ,int unused +#endif + ); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) +static struct proc_dir_entry *fasttimer_proc_entry; +#else +static struct proc_dir_entry fasttimer_proc_entry = +{ + 0, 9, "fasttimer", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, NULL /* ops -- default to array */, + &proc_fasttimer_read /* get_info */, +}; +#endif +#endif /* CONFIG_PROC_FS */ + +#ifdef CONFIG_PROC_FS + +/* This value is very much based on testing */ +#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300) + +static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + ,int *eof, void *data_unused +#else + ,int unused +#endif + ) +{ + unsigned long flags; + int i = 0; + int num_to_show; + struct timeval tv; + struct fast_timer *t, *nextt; + static char *bigbuf = NULL; + static unsigned long used; + + if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) + { + used = 0; + bigbuf[0] = '\0'; + return 0; + } + + if (!offset || !used) + { + do_gettimeofday_fast(&tv); + + used = 0; + used += sprintf(bigbuf + used, "Fast timers added: %i\n", + fast_timers_added); + used += sprintf(bigbuf + used, "Fast timers started: %i\n", + fast_timers_started); + used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n", + fast_timer_ints); + used += sprintf(bigbuf + used, "Fast timers expired: %i\n", + fast_timers_expired); + used += sprintf(bigbuf + used, "Fast timers deleted: %i\n", + fast_timers_deleted); + used += sprintf(bigbuf + used, "Fast timer running: %s\n", + fast_timer_running ? "yes" : "no"); + used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", + (unsigned long)tv.tv_sec, + (unsigned long)tv.tv_usec); +#ifdef FAST_TIMER_SANITY_CHECKS + used += sprintf(bigbuf + used, "Sanity failed: %i\n", + sanity_failed); +#endif + used += sprintf(bigbuf + used, "\n"); + +#ifdef DEBUG_LOG_INCLUDED + { + int end_i = debug_log_cnt; + i = 0; + + if (debug_log_cnt_wrapped) + { + i = debug_log_cnt; + } + + while ((i != end_i || (debug_log_cnt_wrapped && !used)) && + used+100 < BIG_BUF_SIZE) + { + used += sprintf(bigbuf + used, debug_log_string[i], + debug_log_value[i]); + i = (i+1) % DEBUG_LOG_MAX; + } + } + used += sprintf(bigbuf + used, "\n"); +#endif + + num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started: + NUM_TIMER_STATS); + used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started); + for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++) + { + int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS; + +#if 1 //ndef FAST_TIMER_LOG + used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i" + "\n", + timer_div_settings[cur], + timer_freq_settings[cur], + timer_delay_settings[cur] + ); +#endif +#ifdef FAST_TIMER_LOG + t = &timer_started_log[cur]; + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data + ); +#endif + } + used += sprintf(bigbuf + used, "\n"); + +#ifdef FAST_TIMER_LOG + num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added: + NUM_TIMER_STATS); + used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added); + for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) + { + t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS]; + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data + ); + } + used += sprintf(bigbuf + used, "\n"); + + num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired: + NUM_TIMER_STATS); + used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired); + for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) + { + t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS]; + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data + ); + } + used += sprintf(bigbuf + used, "\n"); +#endif + + used += sprintf(bigbuf + used, "Active timers:\n"); + save_flags(flags); + cli(); + t = fast_timer_list; + while (t != NULL && (used+100 < BIG_BUF_SIZE)) + { + nextt = t->next; + restore_flags(flags); + used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " + "d: %6li us data: 0x%08lX" +/* " func: 0x%08lX" */ + "\n", + t->name, + (unsigned long)t->tv_set.tv_sec, + (unsigned long)t->tv_set.tv_usec, + (unsigned long)t->tv_expires.tv_sec, + (unsigned long)t->tv_expires.tv_usec, + t->delay_us, + t->data +/* , t->function */ + ); + cli(); + if (t->next != nextt) + { + printk("timer removed!\n"); + } + t = nextt; + } + restore_flags(flags); + } + + if (used - offset < len) + { + len = used - offset; + } + + memcpy(buf, bigbuf + offset, len); + *start = buf; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + *eof = 1; +#endif + + return len; +} +#endif /* PROC_FS */ + +#ifdef FAST_TIMER_TEST +static volatile unsigned long i = 0; +static volatile int num_test_timeout = 0; +static struct fast_timer tr[10]; +static int exp_num[10]; + +static struct timeval tv_exp[100]; + +static void test_timeout(unsigned long data) +{ + do_gettimeofday_fast(&tv_exp[data]); + exp_num[data] = num_test_timeout; + + num_test_timeout++; +} + +static void test_timeout1(unsigned long data) +{ + do_gettimeofday_fast(&tv_exp[data]); + exp_num[data] = num_test_timeout; + if (data < 7) + { + start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1"); + i++; + } + num_test_timeout++; +} + +DP( +static char buf0[2000]; +static char buf1[2000]; +static char buf2[2000]; +static char buf3[2000]; +static char buf4[2000]; +); + +static char buf5[6000]; +static int j_u[1000]; + +static void fast_timer_test(void) +{ + int prev_num; + int j; + + struct timeval tv, tv0, tv1, tv2; + + printk("fast_timer_test() start\n"); + do_gettimeofday_fast(&tv); + + for (j = 0; j < 1000; j++) + { + j_u[j] = GET_JIFFIES_USEC(); + } + for (j = 0; j < 100; j++) + { + do_gettimeofday_fast(&tv_exp[j]); + } + printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec); + + for (j = 0; j < 1000; j++) + { + printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); + j += 4; + } + for (j = 0; j < 100; j++) + { + printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n", + tv_exp[j].tv_sec,tv_exp[j].tv_usec, + tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec, + tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec, + tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec, + tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec); + j += 4; + } + do_gettimeofday_fast(&tv0); + start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0"); + DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1"); + DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2"); + DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3"); + DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0)); + i++; + start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx"); + DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0)); + i++; + do_gettimeofday_fast(&tv1); + + proc_fasttimer_read(buf5, NULL, 0, 0, 0); + + prev_num = num_test_timeout; + while (num_test_timeout < i) + { + if (num_test_timeout != prev_num) + { + prev_num = num_test_timeout; + } + } + do_gettimeofday_fast(&tv2); + printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec); + printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec); + printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec); + DP(printk("buf0:\n"); + printk(buf0); + printk("buf1:\n"); + printk(buf1); + printk("buf2:\n"); + printk(buf2); + printk("buf3:\n"); + printk(buf3); + printk("buf4:\n"); + printk(buf4); + ); + printk("buf5:\n"); + printk(buf5); + + printk("timers set:\n"); + for(j = 0; j<i; j++) + { + struct fast_timer *t = &tr[j]; + printk("%-10s set: %6is %06ius exp: %6is %06ius " + "data: 0x%08X func: 0x%08X\n", + t->name, + t->tv_set.tv_sec, + t->tv_set.tv_usec, + t->tv_expires.tv_sec, + t->tv_expires.tv_usec, + t->data, + t->function + ); + + printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", + t->delay_us, + tv_exp[j].tv_sec, + tv_exp[j].tv_usec, + exp_num[j], + (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec); + } + proc_fasttimer_read(buf5, NULL, 0, 0, 0); + printk("buf5 after all done:\n"); + printk(buf5); + printk("fast_timer_test() done\n"); +} +#endif + + +void fast_timer_init(void) +{ + /* For some reason, request_irq() hangs when called froom time_init() */ + if (!fast_timer_is_init) + { +#if 0 && defined(FAST_TIMER_TEST) + int i; +#endif + + printk("fast_timer_init()\n"); + +#if 0 && defined(FAST_TIMER_TEST) + for (i = 0; i <= TIMER0_DIV; i++) + { + /* We must be careful not to get overflow... */ + printk("%3i %6u\n", i, timer0_value_us[i]); + } +#endif +#ifdef CONFIG_PROC_FS +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) + if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) + fasttimer_proc_entry->read_proc = proc_fasttimer_read; +#else + proc_register_dynamic(&proc_root, &fasttimer_proc_entry); +#endif +#endif /* PROC_FS */ + if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, + "fast timer int", NULL)) + { + printk("err: timer1 irq\n"); + } + fast_timer_is_init = 1; +#ifdef FAST_TIMER_TEST + printk("do test\n"); + fast_timer_test(); +#endif + } +} diff --git a/arch/cris/kernel/head.S b/arch/cris/arch-v10/kernel/head.S index bbd4eb3dd936..8192cd758b4f 100644 --- a/arch/cris/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.2 2001/12/18 13:35:19 bjornw Exp $ +/* $Id: head.S,v 1.6 2003/04/28 05:31:46 starvik Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,19 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.6 2003/04/28 05:31:46 starvik + * Added section attributes + * + * Revision 1.5 2002/12/11 15:42:02 starvik + * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c + * + * Revision 1.4 2002/11/07 09:00:44 starvik + * Names changed for init sections + * init_task_union -> init_thread_union + * + * Revision 1.3 2002/02/05 15:38:23 bjornw + * Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it... + * * Revision 1.2 2001/12/18 13:35:19 bjornw * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). * @@ -161,7 +174,7 @@ #define ASSEMBLER_MACROS_ONLY /* The IO_* macros use the ## token concatenation operator, so -traditional must not be used when assembling this file. */ -#include <asm/sv_addr_ag.h> +#include <asm/arch/sv_addr_ag.h> #define CRAMFS_MAGIC 0x28cd3d45 #define RAM_INIT_MAGIC 0x56902387 @@ -294,7 +307,7 @@ ;; ;; arch/etrax100/etrax100.ld sets some symbols that define the start ;; and end of each segment. - + ;; Check if we start from DRAM or FLASH by testing PC move.d $pc,$r0 @@ -311,7 +324,7 @@ _inflash0: ;; Put this in a suitable section where we can reclaim storage ;; after init. - .section ".text.init" + .section ".init.text", "ax" _inflash: #ifdef CONFIG_ETRAX_ETHERNET ;; Start MII clock to make sure it is running when tranceiver is reset @@ -379,7 +392,7 @@ _dram_init_finished: _inram: ;; Move the ROM fs to after BSS end. This assumes that the cramfs ;; second longword contains the length of the cramfs - + moveq 0, $r0 move.d $r0, [romfs_length] ; default if there is no cramfs @@ -411,19 +424,20 @@ _inram: moveq 1, $r0 move.d $r0, [romfs_in_flash] - + jump _start_it ; enter code, cached this time _no_romfs_in_flash: + ;; Check if there is a cramfs (magic value). ;; Notice that we check for cramfs magic value - which is ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does ;; not need this mechanism anyway) - + move.d __vmlinux_end, $r0; the image will be after the vmlinux end address move.d [$r0], $r1 ; cramfs assumes same endian on host/target cmp.d CRAMFS_MAGIC, $r1; magic value in cramfs superblock - bne 1f + bne 2f nop ;; Ok. What is its size ? @@ -453,7 +467,8 @@ _no_romfs_in_flash: subq 1, $r2 bne 1b nop - + +2: ;; Dont worry that the BSS is tainted. It will be cleared later. moveq 0, $r0 @@ -462,14 +477,15 @@ _no_romfs_in_flash: jump _start_it ; better skip the additional cramfs check below _start_it: + ;; the kernel stack is overlayed with the task structure for each ;; task. thus the initial kernel stack is in the same page as the ;; init_task (but starts in the top of the page, size 8192) - move.d init_task_union + 8192, $sp + move.d init_thread_union + 8192, $sp move.d ibr_start,$r0 ; this symbol is set by the linker script move $r0,$ibr move.d $r0,[etrax_irv] ; set the interrupt base register and pointer - + ;; Clear BSS region, from _bss_start to _end move.d __bss_start, $r0 @@ -839,5 +855,5 @@ swapper_pg_dir = 0x60002000 swapper_pg_dir = 0xc0002000 #endif - .section ".data.init" + .section ".init.data", "aw" #include "../lib/hw_settings.S" diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c new file mode 100644 index 000000000000..c5e6348aba1f --- /dev/null +++ b/arch/cris/arch-v10/kernel/irq.c @@ -0,0 +1,219 @@ +/* $Id: irq.c,v 1.1 2002/12/11 15:42:02 starvik Exp $ + * + * linux/arch/cris/kernel/irq.c + * + * Copyright (c) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + * This file contains the interrupt vectors and some + * helper functions + * + */ + +#include <asm/irq.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/config.h> + +irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ + +/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is + * global just so that the kernel gdb can use it. + */ + +void +set_int_vector(int n, irqvectptr addr, irqvectptr saddr) +{ + /* remember the shortcut entry point, after the prologue */ + + irq_shortcuts[n] = saddr; + + etrax_irv->v[n + 0x20] = (irqvectptr)addr; +} + +/* the breakpoint vector is obviously not made just like the normal irq handlers + * but needs to contain _code_ to jump to addr. + * + * the BREAK n instruction jumps to IBR + n * 8 + */ + +void +set_break_vector(int n, irqvectptr addr) +{ + unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2]; + unsigned long *jaddr = (unsigned long *)(jinstr + 1); + + /* if you don't know what this does, do not touch it! */ + + *jinstr = 0x0d3f; + *jaddr = (unsigned long)addr; + + /* 00000026 <clrlop+1a> 3f0d82000000 jump 0x82 */ +} + +/* + * This builds up the IRQ handler stubs using some ugly macros in irq.h + * + * These macros create the low-level assembly IRQ routines that do all + * the operations that are needed. They are also written to be fast - and to + * disable interrupts as little as humanly possible. + * + */ + +/* IRQ0 and 1 are special traps */ +void hwbreakpoint(void); +void IRQ1_interrupt(void); +BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */ +BUILD_IRQ(3, 0x08) +BUILD_IRQ(4, 0x10) +BUILD_IRQ(5, 0x20) +BUILD_IRQ(6, 0x40) +BUILD_IRQ(7, 0x80) +BUILD_IRQ(8, 0x100) +BUILD_IRQ(9, 0x200) +BUILD_IRQ(10, 0x400) +BUILD_IRQ(11, 0x800) +BUILD_IRQ(12, 0x1000) +BUILD_IRQ(13, 0x2000) +void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ +void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ +BUILD_IRQ(16, 0x10000) +BUILD_IRQ(17, 0x20000) +BUILD_IRQ(18, 0x40000) +BUILD_IRQ(19, 0x80000) +BUILD_IRQ(20, 0x100000) +BUILD_IRQ(21, 0x200000) +BUILD_IRQ(22, 0x400000) +BUILD_IRQ(23, 0x800000) +BUILD_IRQ(24, 0x1000000) +BUILD_IRQ(25, 0x2000000) +/* IRQ 26-30 are reserved */ +BUILD_IRQ(31, 0x80000000) + +/* + * Pointers to the low-level handlers + */ + +static void (*interrupt[NR_IRQS])(void) = { + NULL, NULL, IRQ2_interrupt, IRQ3_interrupt, + IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, + IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, + IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, + IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, + IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, + IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + IRQ31_interrupt +}; + +static void (*sinterrupt[NR_IRQS])(void) = { + NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt, + sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt, + sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt, + sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, + sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, + sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, + sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, + sIRQ31_interrupt +}; + +static void (*bad_interrupt[NR_IRQS])(void) = { + NULL, NULL, + NULL, bad_IRQ3_interrupt, + bad_IRQ4_interrupt, bad_IRQ5_interrupt, + bad_IRQ6_interrupt, bad_IRQ7_interrupt, + bad_IRQ8_interrupt, bad_IRQ9_interrupt, + bad_IRQ10_interrupt, bad_IRQ11_interrupt, + bad_IRQ12_interrupt, bad_IRQ13_interrupt, + NULL, NULL, + bad_IRQ16_interrupt, bad_IRQ17_interrupt, + bad_IRQ18_interrupt, bad_IRQ19_interrupt, + bad_IRQ20_interrupt, bad_IRQ21_interrupt, + bad_IRQ22_interrupt, bad_IRQ23_interrupt, + bad_IRQ24_interrupt, bad_IRQ25_interrupt, + NULL, NULL, NULL, NULL, NULL, + bad_IRQ31_interrupt +}; + +void arch_setup_irq(int irq) +{ + set_int_vector(irq, interrupt[irq], sinterrupt[irq]); +} + +void arch_free_irq(int irq) +{ + set_int_vector(irq, bad_interrupt[irq], 0); +} + +void weird_irq(void); +void system_call(void); /* from entry.S */ +void do_sigtrap(void); /* from entry.S */ +void gdb_handle_breakpoint(void); /* from entry.S */ + +/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and + setting the irq vector table to point to bad_interrupt ptrs. +*/ + +void __init +init_IRQ(void) +{ + int i; + + /* clear all interrupt masks */ + +#ifndef CONFIG_SVINTO_SIM + *R_IRQ_MASK0_CLR = 0xffffffff; + *R_IRQ_MASK1_CLR = 0xffffffff; + *R_IRQ_MASK2_CLR = 0xffffffff; +#endif + + *R_VECT_MASK_CLR = 0xffffffff; + + /* clear the shortcut entry points */ + + for(i = 0; i < NR_IRQS; i++) + irq_shortcuts[i] = NULL; + + for (i = 0; i < 256; i++) + etrax_irv->v[i] = weird_irq; + + /* the entries in the break vector contain actual code to be + executed by the associated break handler, rather than just a jump + address. therefore we need to setup a default breakpoint handler + for all breakpoints */ + + for (i = 0; i < 16; i++) + set_break_vector(i, do_sigtrap); + + /* set all etrax irq's to the bad handlers */ + for (i = 2; i < NR_IRQS; i++) + set_int_vector(i, bad_interrupt[i], 0); + + /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ + + set_int_vector(15, multiple_interrupt, 0); + + /* 0 and 1 which are special breakpoint/NMI traps */ + + set_int_vector(0, hwbreakpoint, 0); + set_int_vector(1, IRQ1_interrupt, 0); + + /* and irq 14 which is the mmu bus fault handler */ + + set_int_vector(14, mmu_bus_fault, 0); + + /* setup the system-call trap, which is reached by BREAK 13 */ + + set_break_vector(13, system_call); + + /* setup a breakpoint handler for debugging used for both user and + kernel mode debugging (which is why it is not inside an ifdef + CONFIG_ETRAX_KGDB) */ + set_break_vector(8, gdb_handle_breakpoint); + +#ifdef CONFIG_ETRAX_KGDB + /* setup kgdb if its enabled, and break into the debugger */ + kgdb_init(); + breakpoint(); +#endif +} diff --git a/arch/cris/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c index 793c77575c8e..4e5d50d28de5 100644 --- a/arch/cris/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -18,8 +18,18 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ -*! Revision 1.1.1.1 2001/12/17 13:59:27 bjornw -*! Import of Linux 2.5.1 +*! Revision 1.4 2003/04/09 05:20:44 starvik +*! Merge of Linux 2.5.67 +*! +*! Revision 1.3 2003/01/21 19:11:08 starvik +*! Modified include path for new dir layout +*! +*! Revision 1.2 2002/11/19 14:35:24 starvik +*! Changes from linux 2.4 +*! Changed struct initializer syntax to the currently prefered notation +*! +*! Revision 1.1 2001/12/17 13:59:27 bjornw +*! Initial revision *! *! Revision 1.6 2001/10/09 13:10:03 matsfg *! Added $ on registers and removed some underscores @@ -58,7 +68,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +*! $Id: kgdb.c,v 1.4 2003/04/09 05:20:44 starvik Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -216,7 +226,7 @@ #include <asm/setup.h> #include <asm/ptrace.h> -#include <asm/svinto.h> +#include <asm/arch/svinto.h> #include <asm/irq.h> static int kgdb_started = 0; @@ -1067,7 +1077,7 @@ handle_exception (int sigval) int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16); int status; #ifdef PROCESS_SUPPORT - if (current_thread_g =! executing_task) + if (current_thread_g != executing_task) status = write_stack_register (current_thread_g, regno, suffix+1); else #endif diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c new file mode 100644 index 000000000000..62e3a4fbf33a --- /dev/null +++ b/arch/cris/arch-v10/kernel/process.c @@ -0,0 +1,252 @@ +/* $Id: process.c,v 1.3 2003/07/04 08:27:41 starvik Exp $ + * + * linux/arch/cris/kernel/process.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (C) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * Mikael Starvik (starvik@axis.com) + * + * This file handles the architecture-dependent parts of process handling.. + */ + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/err.h> +#include <linux/fs.h> +#include <linux/slab.h> + +#ifdef CONFIG_ETRAX_GPIO +void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ +#endif + +/* + * We use this if we don't have any better + * idle routine.. + */ +void default_idle(void) +{ +#ifdef CONFIG_ETRAX_GPIO + etrax_gpio_wake_up_check(); +#endif +} + +/* if the watchdog is enabled, we can simply disable interrupts and go + * into an eternal loop, and the watchdog will reset the CPU after 0.1s + * if on the other hand the watchdog wasn't enabled, we just enable it and wait + */ + +void hard_reset_now (void) +{ + /* + * Don't declare this variable elsewhere. We don't want any other + * code to know about it than the watchdog handler in entry.S and + * this code, implementing hard reset through the watchdog. + */ +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + extern int cause_of_death; +#endif + + printk("*** HARD RESET ***\n"); + local_irq_disable(); + +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + cause_of_death = 0xbedead; +#else + /* Since we dont plan to keep on reseting the watchdog, + the key can be arbitrary hence three */ + *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) | + IO_STATE(R_WATCHDOG, enable, start); +#endif + + while(1) /* waiting for RETRIBUTION! */ ; +} + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *t) +{ + return (unsigned long)user_regs(t->thread_info)->irp; +} + +static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) +{ + fn(arg); + do_exit(-1); /* Should never be called, return bad exit value */ +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + struct pt_regs regs; + + memset(®s, 0, sizeof(regs)); + + /* Don't use r10 since that is set to 0 in copy_thread */ + regs.r11 = (unsigned long)fn; + regs.r12 = (unsigned long)arg; + regs.irp = (unsigned long)kernel_thread_helper; + + /* Ok, create the new process.. */ + return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); +} + +/* setup the child's kernel stack with a pt_regs and switch_stack on it. + * it will be un-nested during _resume and _ret_from_sys_call when the + * new thread is scheduled. + * + * also setup the thread switching structure which is used to keep + * thread-specific data during _resumes. + * + */ +asmlinkage void ret_from_fork(void); + +int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct *p, struct pt_regs *regs) +{ + struct pt_regs * childregs; + struct switch_stack *swstack; + + /* put the pt_regs structure at the end of the new kernel stack page and fix it up + * remember that the task_struct doubles as the kernel stack for the task + */ + + childregs = user_regs(p->thread_info); + + *childregs = *regs; /* struct copy of pt_regs */ + + p->set_child_tid = p->clear_child_tid = NULL; + + childregs->r10 = 0; /* child returns 0 after a fork/clone */ + + /* put the switch stack right below the pt_regs */ + + swstack = ((struct switch_stack *)childregs) - 1; + + swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ + + /* we want to return into ret_from_sys_call after the _resume */ + + swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */ + + /* fix the user-mode stackpointer */ + + p->thread.usp = usp; + + /* and the kernel-mode one */ + + p->thread.ksp = (unsigned long) swstack; + +#ifdef DEBUG + printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); + show_registers(childregs); +#endif + + return 0; +} + +/* + * Be aware of the "magic" 7th argument in the four system-calls below. + * They need the latest stackframe, which is put as the 7th argument by + * entry.S. The previous arguments are dummies or actually used, but need + * to be defined to reach the 7th argument. + * + * N.B.: Another method to get the stackframe is to use current_regs(). But + * it returns the latest stack-frame stacked when going from _user mode_ and + * some of these (at least sys_clone) are called from kernel-mode sometimes + * (for example during kernel_thread, above) and thus cannot use it. Thus, + * to be sure not to get any surprises, we use the method for the other calls + * as well. + */ + +asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) +{ + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); +} + +/* if newusp is 0, we just grab the old usp */ +/* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ +asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, + int* parent_tid, int* child_tid, long mof, long srp, + struct pt_regs *regs) +{ + if (!newusp) + newusp = rdusp(); + return do_fork(flags & ~CLONE_IDLETASK, newusp, regs, 0, parent_tid, child_tid); +} + +/* vfork is a system call in i386 because of register-pressure - maybe + * we can remove it and handle it in libc but we put it here until then. + */ + +asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, + struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(const char *fname, char **argv, char **envp, + long r13, long mof, long srp, + struct pt_regs *regs) +{ + int error; + char *filename; + + filename = getname(fname); + error = PTR_ERR(filename); + + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); + out: + return error; +} + +/* + * These bracket the sleeping functions.. + */ + +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ +#if 0 + /* YURGH. TODO. */ + + unsigned long ebp, esp, eip; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = (unsigned long)p; + esp = p->thread.esp; + if (!stack_page || esp < stack_page || esp > 8188+stack_page) + return 0; + /* include/asm-i386/system.h:switch_to() pushes ebp last. */ + ebp = *(unsigned long *) esp; + do { + if (ebp < stack_page || ebp > 8184+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if (eip < first_sched || eip >= last_sched) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); +#endif + return 0; +} +#undef last_sched +#undef first_sched diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c new file mode 100644 index 000000000000..c83eba5d6d04 --- /dev/null +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2000-2003, Axis Communications AB. + */ + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/user.h> + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/processor.h> + +/* + * Determines which bits in DCCR the user has access to. + * 1 = access, 0 = no access. + */ +#define DCCR_MASK 0x0000001f /* XNZVC */ + +extern inline long get_reg(struct task_struct *, unsigned int); +extern inline long put_reg(struct task_struct *, unsigned int, unsigned long); + +/* + * Called by kernel/ptrace.c when detaching. + * + * Make sure the single step bit is not set. + */ +void +ptrace_disable(struct task_struct *child) +{ + /* Todo - pending singlesteps? */ +} + +/* + * Note that this implementation of ptrace behaves differently from vanilla + * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, + * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not + * ignored. Instead, the data variable is expected to point at a location + * (in user space) where the result of the ptrace call is written (instead of + * being returned). + */ +asmlinkage int +sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + + if (request == PTRACE_TRACEME) { + if (current->ptrace & PT_PTRACED) + goto out; + + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + + if (child) + get_task_struct(child); + + read_unlock(&tasklist_lock); + + if (!child) + goto out; + + ret = -EPERM; + + if (pid == 1) /* Leave the init process alone! */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } + + ret = -ESRCH; + + if (!(child->ptrace & PT_PTRACED)) + goto out_tsk; + + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + goto out_tsk; + } + + if (child->parent != current) + goto out_tsk; + + switch (request) { + /* Read word at location address. */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: { + unsigned long tmp; + int copied; + + copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + ret = -EIO; + + if (copied != sizeof(tmp)) + break; + + ret = put_user(tmp,(unsigned long *) data); + break; + } + + /* Read the word at location address in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + break; + + tmp = 0; /* Default return condition */ + ret = -EIO; + + if (addr < sizeof(struct pt_regs)) { + tmp = get_reg(child, addr >> 2); + ret = put_user(tmp, (unsigned long *)data); + } + + break; + } + + /* Write the word at location address. */ + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + ret = 0; + + if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) + break; + + ret = -EIO; + break; + + /* Write the word at location address in the USER area. */ + case PTRACE_POKEUSR: + ret = -EIO; + + if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) + break; + + if (addr < sizeof(struct pt_regs)) { + addr >>= 2; + + if (addr == PT_DCCR) { + /* + * Don't allow the tracing process to + * change stuff like interrupt enable, + * kernel/user bit, etc. + */ + data &= DCCR_MASK; + data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; + } + + if (put_reg(child, addr, data)) + break; + + ret = 0; + } + break; + + case PTRACE_SYSCALL: + case PTRACE_CONT: + ret = -EIO; + + if ((unsigned long) data > _NSIG) + break; + + if (request == PTRACE_SYSCALL) { + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } + else { + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + } + + child->exit_code = data; + + /* TODO: make sure any pending breakpoint is killed */ + wake_up_process(child); + ret = 0; + + break; + + /* Make the child exit by sending it a sigkill. */ + case PTRACE_KILL: + ret = 0; + + if (child->state == TASK_ZOMBIE) + break; + + child->exit_code = SIGKILL; + + /* TODO: make sure any pending breakpoint is killed */ + wake_up_process(child); + break; + + /* Set the trap flag. */ + case PTRACE_SINGLESTEP: + ret = -EIO; + + if ((unsigned long) data > _NSIG) + break; + + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + + /* TODO: set some clever breakpoint mechanism... */ + + child->exit_code = data; + wake_up_process(child); + ret = 0; + break; + + case PTRACE_DETACH: + ret = ptrace_detach(child, data); + break; + + /* Get all GP registers from the child. */ + case PTRACE_GETREGS: { + int i; + unsigned long tmp; + + for (i = 0; i <= PT_MAX; i++) { + tmp = get_reg(child, i); + + if (put_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + + data += sizeof(long); + } + + ret = 0; + break; + } + + /* Set all GP registers in the child. */ + case PTRACE_SETREGS: { + int i; + unsigned long tmp; + + for (i = 0; i <= PT_MAX; i++) { + if (get_user(tmp, (unsigned long *) data)) { + ret = -EFAULT; + break; + } + + if (i == PT_DCCR) { + tmp &= DCCR_MASK; + tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK; + } + + put_reg(child, i, tmp); + data += sizeof(long); + } + + ret = 0; + break; + } + + default: + ret = ptrace_request(child, request, addr, data); + break; + } +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + return ret; +} + +void do_syscall_trace(void) +{ + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + + if (!(current->ptrace & PT_PTRACED)) + return; + + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); + + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + + /* + * This isn't the same as continuing with a signal, but it will do for + * normal use. + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c new file mode 100644 index 000000000000..d95930270a9b --- /dev/null +++ b/arch/cris/arch-v10/kernel/setup.c @@ -0,0 +1,96 @@ +/* $Id: setup.c,v 1.1 2002/12/11 15:42:02 starvik Exp $ + * + * linux/arch/cris/arch-v10/kernel/setup.c + * + * Copyright (C) 1995 Linus Torvalds + * Copyright (c) 2001-2002 Axis Communications AB + */ + +/* + * This file handles the architecture-dependent parts of initialization + */ + +#include <linux/config.h> +#include <linux/seq_file.h> +#include <linux/proc_fs.h> +#include <linux/delay.h> + +#ifdef CONFIG_PROC_FS +#define HAS_FPU 0x0001 +#define HAS_MMU 0x0002 +#define HAS_ETHERNET100 0x0004 +#define HAS_TOKENRING 0x0008 +#define HAS_SCSI 0x0010 +#define HAS_ATA 0x0020 +#define HAS_USB 0x0040 +#define HAS_IRQ_BUG 0x0080 +#define HAS_MMU_BUG 0x0100 + +static struct cpu_info { + char *model; + unsigned short cache; + unsigned short flags; +} cpu_info[] = { + /* The first four models will never ever run this code and are + only here for display. */ + { "ETRAX 1", 0, 0 }, + { "ETRAX 2", 0, 0 }, + { "ETRAX 3", 0, HAS_TOKENRING }, + { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Unknown", 0, 0 }, + { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, + { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, + { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, + { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, + { "Unknown", 0, 0 } /* This entry MUST be the last */ +}; + +int show_cpuinfo(struct seq_file *m, void *v) +{ + unsigned long revision; + struct cpu_info *info; + + /* read the version register in the CPU and print some stuff */ + + revision = rdvr(); + + if (revision >= sizeof cpu_info/sizeof *cpu_info) + info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; + else + info = &cpu_info[revision]; + + return seq_printf(m, + "processor\t: 0\n" + "cpu\t\t: CRIS\n" + "cpu revision\t: %lu\n" + "cpu model\t: %s\n" + "cache size\t: %d kB\n" + "fpu\t\t: %s\n" + "mmu\t\t: %s\n" + "mmu DMA bug\t: %s\n" + "ethernet\t: %s Mbps\n" + "token ring\t: %s\n" + "scsi\t\t: %s\n" + "ata\t\t: %s\n" + "usb\t\t: %s\n" + "bogomips\t: %lu.%02lu\n", + + revision, + info->model, + info->cache, + info->flags & HAS_FPU ? "yes" : "no", + info->flags & HAS_MMU ? "yes" : "no", + info->flags & HAS_MMU_BUG ? "yes" : "no", + info->flags & HAS_ETHERNET100 ? "10/100" : "10", + info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", + info->flags & HAS_SCSI ? "yes" : "no", + info->flags & HAS_ATA ? "yes" : "no", + info->flags & HAS_USB ? "yes" : "no", + (loops_per_jiffy * HZ + 500) / 500000, + ((loops_per_jiffy * HZ + 500) / 5000) % 100); +} + +#endif /* CONFIG_PROC_FS */ diff --git a/arch/cris/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c index 25fac64945e4..561a890a8e4c 100644 --- a/arch/cris/kernel/shadows.c +++ b/arch/cris/arch-v10/kernel/shadows.c @@ -1,4 +1,4 @@ -/* $Id: shadows.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * Various shadow registers. Defines for these are in include/asm-etrax100/io.h */ diff --git a/arch/cris/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 678281dae205..6698054a576c 100644 --- a/arch/cris/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -55,11 +55,11 @@ sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, sigset_t saveset; mask &= _BLOCKABLE; - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; siginitset(¤t->blocked, mask); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); regs->r10 = -EINTR; while (1) { @@ -94,11 +94,11 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, return -EFAULT; sigdelsetmask(&newset, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); saveset = current->blocked; current->blocked = newset; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); regs->r10 = -EINTR; while (1) { @@ -117,7 +117,7 @@ sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, } int -sys_sigaction(int sig, const struct old_sigaction *act, +sys_sigaction(int sig, const struct old_sigaction __user *act, struct old_sigaction *oact) { struct k_sigaction new_ka, old_ka; @@ -149,7 +149,7 @@ sys_sigaction(int sig, const struct old_sigaction *act, } int -sys_sigaltstack(const stack_t *uss, stack_t *uoss) +sys_sigaltstack(const stack_t *uss, stack_t __user *uoss) { return do_sigaltstack(uss, uoss, rdusp()); } @@ -175,7 +175,7 @@ struct rt_sigframe { static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { unsigned int err = 0; unsigned long old_usp; @@ -217,7 +217,7 @@ badframe: asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, struct pt_regs *regs) { - struct sigframe *frame = (struct sigframe *)rdusp(); + struct sigframe __user *frame = (struct sigframe *)rdusp(); sigset_t set; /* @@ -232,15 +232,15 @@ asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) || (_NSIG_WORDS > 1 - && __copy_from_user(&set.sig[1], &frame->extramask, + && __copy_from_user(&set.sig[1], frame->extramask, sizeof(frame->extramask)))) goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->sc)) goto badframe; @@ -259,7 +259,7 @@ badframe: asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, long mof, long srp, struct pt_regs *regs) { - struct rt_sigframe *frame = (struct rt_sigframe *)rdusp(); + struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp(); sigset_t set; stack_t st; @@ -277,10 +277,10 @@ asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, goto badframe; sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) goto badframe; @@ -303,7 +303,7 @@ badframe: */ static int -setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask) +setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) { int err = 0; unsigned long usp = rdusp(); @@ -328,7 +328,7 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, unsigned long mask /* figure out where we want to put the new signal frame - usually on the stack */ -static inline void * +static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long sp = rdusp(); @@ -343,7 +343,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) sp &= ~3; - return (void *)(sp - frame_size); + return (void __user*)(sp - frame_size); } /* grab and setup a signal frame. @@ -357,7 +357,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { - struct sigframe *frame; + struct sigframe __user *frame; unsigned long return_ip; int err = 0; @@ -414,7 +414,7 @@ give_sigsegv: static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { - struct rt_sigframe *frame; + struct rt_sigframe __user *frame; unsigned long return_ip; int err = 0; @@ -481,16 +481,18 @@ give_sigsegv: * OK, we're invoking a handler */ -static inline void +extern inline void handle_signal(int canrestart, unsigned long sig, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { - struct k_sigaction *ka = ¤t->sig->action[sig-1]; + struct k_sigaction *ka = ¤t->sighand->action[sig-1]; /* Are we from a system call? */ if (canrestart) { /* If so, check system call restarting.. */ switch (regs->r10) { + case -ERESTART_RESTARTBLOCK: + current_thread_info()->restart_block.fn = do_no_restart_syscall; case -ERESTARTNOHAND: /* ERESTARTNOHAND means that the syscall should only be restarted if there was no handler for the signal, and since @@ -523,11 +525,11 @@ handle_signal(int canrestart, unsigned long sig, ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { - spin_lock_irq(¤t->sigmask_lock); + spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(); - spin_unlock_irq(¤t->sigmask_lock); + spin_unlock_irq(¤t->sighand->siglock); } } @@ -575,6 +577,10 @@ int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) regs->r10 == -ERESTARTNOINTR) { RESTART_CRIS_SYS(regs); } + if (regs->r10 == -ERESTART_RESTARTBLOCK){ + regs->r10 = __NR_restart_syscall; + regs->irp -= 2; + } } return 0; } diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c new file mode 100644 index 000000000000..31e83a84e4a6 --- /dev/null +++ b/arch/cris/arch-v10/kernel/time.c @@ -0,0 +1,359 @@ +/* $Id: time.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ + * + * linux/arch/cris/arch-v10/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Copyright (C) 1999-2002 Axis Communications AB + * + */ + +#include <linux/config.h> +#include <linux/timex.h> +#include <linux/time.h> +#include <linux/jiffies.h> +#include <linux/interrupt.h> +#include <linux/swap.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <asm/arch/svinto.h> +#include <asm/types.h> +#include <asm/signal.h> +#include <asm/io.h> +#include <asm/delay.h> +#include <asm/rtc.h> + +/* define this if you need to use print_timestamp */ +/* it will make jiffies at 96 hz instead of 100 hz though */ +#undef USE_CASCADE_TIMERS + +extern void update_xtime_from_cmos(void); +extern int set_rtc_mmss(unsigned long nowtime); +extern int setup_irq(int, struct irqaction *); +extern int have_rtc; + +unsigned long get_ns_in_jiffie(void) +{ + unsigned char timer_count, t1; + unsigned short presc_count; + unsigned long ns; + unsigned long flags; + + local_irq_save(flags); + local_irq_disable(); + timer_count = *R_TIMER0_DATA; + presc_count = *R_TIM_PRESC_STATUS; + /* presc_count might be wrapped */ + t1 = *R_TIMER0_DATA; + + if (timer_count != t1){ + /* it wrapped, read prescaler again... */ + presc_count = *R_TIM_PRESC_STATUS; + timer_count = t1; + } + local_irq_restore(flags); + if (presc_count >= PRESCALE_VALUE/2 ){ + presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; + } else { + presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; + } + + ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + + ( (presc_count) * (1000000000/PRESCALE_FREQ)); + return ns; +} + +unsigned long do_slow_gettimeoffset(void) +{ + unsigned long count, t1; + unsigned long usec_count = 0; + unsigned short presc_count; + + static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ + static unsigned long jiffies_p = 0; + + /* + * cache volatile jiffies temporarily; we have IRQs turned off. + */ + unsigned long jiffies_t; + + /* The timer interrupt comes from Etrax timer 0. In order to get + * better precision, we check the current value. It might have + * underflowed already though. + */ + +#ifndef CONFIG_SVINTO_SIM + /* Not available in the xsim simulator. */ + count = *R_TIMER0_DATA; + presc_count = *R_TIM_PRESC_STATUS; + /* presc_count might be wrapped */ + t1 = *R_TIMER0_DATA; + if (count != t1){ + /* it wrapped, read prescaler again... */ + presc_count = *R_TIM_PRESC_STATUS; + count = t1; + } +#else + count = 0; + presc_count = 0; +#endif + + jiffies_t = jiffies; + + /* + * avoiding timer inconsistencies (they are rare, but they happen)... + * there are one problem that must be avoided here: + * 1. the timer counter underflows + */ + if( jiffies_t == jiffies_p ) { + if( count > count_p ) { + /* Timer wrapped, use new count and prescale + * increase the time corresponding to one jiffie + */ + usec_count = 1000000/HZ; + } + } else + jiffies_p = jiffies_t; + count_p = count; + if (presc_count >= PRESCALE_VALUE/2 ){ + presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; + } else { + presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; + } + /* Convert timer value to usec */ + usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) + + (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000); + + return usec_count; +} + +/* Excerpt from the Etrax100 HSDD about the built-in watchdog: + * + * 3.10.4 Watchdog timer + + * When the watchdog timer is started, it generates an NMI if the watchdog + * isn't restarted or stopped within 0.1 s. If it still isn't restarted or + * stopped after an additional 3.3 ms, the watchdog resets the chip. + * The watchdog timer is stopped after reset. The watchdog timer is controlled + * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit + * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is + * described in the table below: + * + * Watchdog Value written: + * state: To enable: To key: Operation: + * -------- ---------- ------- ---------- + * stopped 0 X No effect. + * stopped 1 key_val Start watchdog with key = key_val. + * started 0 ~key Stop watchdog + * started 1 ~key Restart watchdog with key = ~key. + * started X new_key_val Change key to new_key_val. + * + * Note: '~' is the bitwise NOT operator. + * + */ + +/* right now, starting the watchdog is the same as resetting it */ +#define start_watchdog reset_watchdog + +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +static int watchdog_key = 0; /* arbitrary number */ +#endif + +/* number of pages to consider "out of memory". it is normal that the memory + * is used though, so put this really low. + */ + +#define WATCHDOG_MIN_FREE_PAGES 8 + +void +reset_watchdog(void) +{ +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + /* only keep watchdog happy as long as we have memory left! */ + if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { + /* reset the watchdog with the inverse of the old key */ + watchdog_key ^= 0x7; /* invert key, which is 3 bits */ + *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | + IO_STATE(R_WATCHDOG, enable, start); + } +#endif +} + +/* stop the watchdog - we still need the correct key */ + +void +stop_watchdog(void) +{ +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + watchdog_key ^= 0x7; /* invert key, which is 3 bits */ + *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | + IO_STATE(R_WATCHDOG, enable, stop); +#endif +} + +/* last time the cmos clock got updated */ +static long last_rtc_update = 0; + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "do_timer()" routine every clocktick + */ + +//static unsigned short myjiff; /* used by our debug routine print_timestamp */ + +static inline irqreturn_t +timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* acknowledge the timer irq */ + +#ifdef USE_CASCADE_TIMERS + *R_TIMER_CTRL = + IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | + IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | + IO_STATE( R_TIMER_CTRL, i1, clr) | + IO_STATE( R_TIMER_CTRL, tm1, run) | + IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | + IO_STATE( R_TIMER_CTRL, i0, clr) | + IO_STATE( R_TIMER_CTRL, tm0, run) | + IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); +#else + *R_TIMER_CTRL = r_timer_ctrl_shadow | + IO_STATE(R_TIMER_CTRL, i0, clr); +#endif + + /* reset watchdog otherwise it resets us! */ + + reset_watchdog(); + + /* call the real timer interrupt handler */ + + do_timer(regs); + + /* + * If we have an externally synchronized Linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + * + * The division here is not time critical since it will run once in + * 11 minutes + */ + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 && + (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) { + if (set_rtc_mmss(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } + return IRQ_HANDLED; +} + +/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain + * it needs to be SA_INTERRUPT to make the jiffies update work properly + */ + +static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, + 0, "timer", NULL, NULL}; + +void __init +time_init(void) +{ + /* probe for the RTC and read it if it exists + * Before the RTC can be probed the loops_per_usec variable needs + * to be initialized to make usleep work. A better value for + * loops_per_usec is calculated by the kernel later once the + * clock has started. + */ + loops_per_usec = 50; + + if(RTC_INIT() < 0) { + /* no RTC, start at 1980 */ + xtime.tv_sec = 0; + xtime.tv_nsec = 0; + have_rtc = 0; + } else { + /* get the current time */ + have_rtc = 1; + update_xtime_from_cmos(); + } + + /* Setup the etrax timers + * Base frequency is 25000 hz, divider 250 -> 100 HZ + * In normal mode, we use timer0, so timer1 is free. In cascade + * mode (which we sometimes use for debugging) both timers are used. + * Remember that linux/timex.h contains #defines that rely on the + * timer settings below (hz and divide factor) !!! + */ + +#ifdef USE_CASCADE_TIMERS + *R_TIMER_CTRL = + IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | + IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | + IO_STATE( R_TIMER_CTRL, i1, nop) | + IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | + IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | + IO_STATE( R_TIMER_CTRL, i0, nop) | + IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | + IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); + + *R_TIMER_CTRL = r_timer_ctrl_shadow = + IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | + IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | + IO_STATE( R_TIMER_CTRL, i1, nop) | + IO_STATE( R_TIMER_CTRL, tm1, run) | + IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | + IO_STATE( R_TIMER_CTRL, i0, nop) | + IO_STATE( R_TIMER_CTRL, tm0, run) | + IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); +#else + *R_TIMER_CTRL = + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | + IO_STATE(R_TIMER_CTRL, i1, nop) | + IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | + IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | + IO_STATE(R_TIMER_CTRL, i0, nop) | + IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | + IO_STATE(R_TIMER_CTRL, clksel0, flexible); + + *R_TIMER_CTRL = r_timer_ctrl_shadow = + IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | + IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | + IO_STATE(R_TIMER_CTRL, i1, nop) | + IO_STATE(R_TIMER_CTRL, tm1, run) | + IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | + IO_STATE(R_TIMER_CTRL, i0, nop) | + IO_STATE(R_TIMER_CTRL, tm0, run) | + IO_STATE(R_TIMER_CTRL, clksel0, flexible); + + *R_TIMER_PRESCALE = PRESCALE_VALUE; +#endif + + *R_IRQ_MASK0_SET = + IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ + + /* now actually register the timer irq handler that calls timer_interrupt() */ + + setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ + + /* enable watchdog if we should use one */ + +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + printk("Enabling watchdog...\n"); + start_watchdog(); + + /* If we use the hardware watchdog, we want to trap it as an NMI + and dump registers before it resets us. For this to happen, we + must set the "m" NMI enable flag (which once set, is unset only + when an NMI is taken). + + The same goes for the external NMI, but that doesn't have any + driver or infrastructure support yet. */ + asm ("setf m"); + + *R_IRQ_MASK0_SET = + IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); + *R_VECT_MASK_SET = + IO_STATE(R_VECT_MASK_SET, nmi, set); +#endif +} diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c new file mode 100644 index 000000000000..da491f438a6e --- /dev/null +++ b/arch/cris/arch-v10/kernel/traps.c @@ -0,0 +1,132 @@ +/* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ + * + * linux/arch/cris/arch-v10/traps.c + * + * Heler functions for trap handlers + * + * Copyright (C) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen + * Hans-Peter Nilsson + * + */ + +#include <linux/config.h> +#include <linux/ptrace.h> +#include <asm/uaccess.h> +#include <asm/arch/sv_addr_ag.h> + +void +show_registers(struct pt_regs * regs) +{ + /* We either use rdusp() - the USP register, which might not + correspond to the current process for all cases we're called, + or we use the current->thread.usp, which is not up to date for + the current process. Experience shows we want the USP + register. */ + 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); + printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); + printk("Process %s (pid: %d, stackpage=%08lx)\n", + current->comm, current->pid, (unsigned long)current); + + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (! user_mode(regs)) { + int i; + + show_stack(NULL, (unsigned long*)usp); + + /* Dump kernel stack if the previous dump wasn't one. */ + if (usp != 0) + show_stack (NULL, NULL); + + printk("\nCode: "); + if(regs->irp < PAGE_OFFSET) + goto bad; + + /* Often enough the value at regs->irp does not point to + the interesting instruction, which is most often the + _previous_ instruction. So we dump at an offset large + enough that instruction decoding should be in sync at + the interesting point, but small enough to fit on a row + (sort of). We point out the regs->irp location in a + ksymoops-friendly way by wrapping the byte for that + address in parentheses. */ + for(i = -12; i < 12; i++) + { + unsigned char c; + if(__get_user(c, &((unsigned char*)regs->irp)[i])) { +bad: + printk(" Bad IP value."); + break; + } + + if (i == 0) + printk("(%02x) ", c); + else + printk("%02x ", c); + } + printk("\n"); + } +} + +/* Called from entry.S when the watchdog has bitten + * We print out something resembling an oops dump, and if + * we have the nice doggy development flag set, we halt here + * instead of rebooting. + */ + +extern void reset_watchdog(void); +extern void stop_watchdog(void); + + +void +watchdog_bite_hook(struct pt_regs *regs) +{ +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + local_irq_disable(); + stop_watchdog(); + show_registers(regs); + while(1) /* nothing */; +#else + show_registers(regs); +#endif +} + +/* This is normally the 'Oops' routine */ +void +die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if(user_mode(regs)) + return; + +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + /* This printout might take too long and trigger the + * watchdog normally. If we're in the nice doggy + * development mode, stop the watchdog during printout. + */ + stop_watchdog(); +#endif + + printk("%s: %04lx\n", str, err & 0xffff); + + show_registers(regs); + +#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY + reset_watchdog(); +#endif + do_exit(SIGSEGV); +} diff --git a/arch/cris/lib/Makefile b/arch/cris/arch-v10/lib/Makefile index 568496a8884e..36e9a9c5239b 100644 --- a/arch/cris/lib/Makefile +++ b/arch/cris/arch-v10/lib/Makefile @@ -2,6 +2,8 @@ # Makefile for Etrax-specific library files.. # + EXTRA_AFLAGS := -traditional lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o + diff --git a/arch/cris/lib/checksum.S b/arch/cris/arch-v10/lib/checksum.S index fd15a76f78d6..85c48f0a9ec2 100644 --- a/arch/cris/lib/checksum.S +++ b/arch/cris/arch-v10/lib/checksum.S @@ -1,4 +1,4 @@ -/* $Id: checksum.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: checksum.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * A fast checksum routine using movem * Copyright (c) 1998-2001 Axis Communications AB * diff --git a/arch/cris/lib/checksumcopy.S b/arch/cris/arch-v10/lib/checksumcopy.S index 4d8bc348da39..35cbffb306fd 100644 --- a/arch/cris/lib/checksumcopy.S +++ b/arch/cris/arch-v10/lib/checksumcopy.S @@ -1,4 +1,4 @@ -/* $Id: checksumcopy.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: checksumcopy.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * A fast checksum+copy routine using movem * Copyright (c) 1998, 2001 Axis Communications AB * diff --git a/arch/cris/lib/csumcpfruser.S b/arch/cris/arch-v10/lib/csumcpfruser.S index 5f41ccd62754..5f41ccd62754 100644 --- a/arch/cris/lib/csumcpfruser.S +++ b/arch/cris/arch-v10/lib/csumcpfruser.S diff --git a/arch/cris/lib/dmacopy.c b/arch/cris/arch-v10/lib/dmacopy.c index fe8f091ed09c..e5fb44f505c5 100644 --- a/arch/cris/lib/dmacopy.c +++ b/arch/cris/arch-v10/lib/dmacopy.c @@ -1,4 +1,4 @@ -/* $Id: dmacopy.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: dmacopy.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax */ diff --git a/arch/cris/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S index d46efd1aef1f..4852709dc7aa 100644 --- a/arch/cris/lib/dram_init.S +++ b/arch/cris/arch-v10/lib/dram_init.S @@ -1,4 +1,4 @@ -/* $Id: dram_init.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: dram_init.S,v 1.3 2003/03/31 09:38:37 starvik Exp $ * * DRAM/SDRAM initialization - alter with care * This file is intended to be included from other assembler files @@ -11,8 +11,20 @@ * Authors: Mikael Starvik (starvik@axis.com) * * $Log: dram_init.S,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 + * Revision 1.3 2003/03/31 09:38:37 starvik + * Corrected calculation of end of sdram init commands + * + * Revision 1.2 2002/11/19 13:33:29 starvik + * Changes from Linux 2.4 + * + * Revision 1.13 2002/10/30 07:42:28 starvik + * Always read SDRAM command sequence from flash + * + * Revision 1.12 2002/08/09 11:37:37 orjanf + * Added double initialization work-around for Samsung SDRAMs. + * + * Revision 1.11 2002/06/04 11:43:21 starvik + * Check if mrs_data is specified in kernelconfig (necessary for MCM) * * Revision 1.10 2001/10/04 12:00:21 martinnn * Added missing underscores. @@ -73,7 +85,11 @@ move.d CONFIG_ETRAX_DEF_R_DRAM_TIMING, $r0 move.d $r0, [R_DRAM_TIMING] -#else +#else + ;; Samsung SDRAMs seem to require to be initialized twice to work properly. + moveq 2, $r6 +_sdram_init: + ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization ; Bank configuration @@ -85,6 +101,12 @@ ; CAS latency = 3 && bus_width = 32 => 0x60 ; CAS latency = 2 && bus_width = 16 => 0x20 ; CAS latency = 3 && bus_width = 16 => 0x30 + + ; Check if value is already supplied in kernel config + move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r2 + and.d 0x00ff0000, $r2 + bne _set_timing + lsrq 16, $r2 move.d 0x40, $r2 ; Assume 32 bits and CAS latency = 2 move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 @@ -130,7 +152,9 @@ _set_timing: ; Issue initialization command sequence move.d _sdram_commands_start, $r2 + and.d 0x00ffffff, $r2 ; Make sure commands are read from flash move.d _sdram_commands_end, $r3 + and.d 0x00ffffff, $r3 1: clear.d $r4 move.b [$r2+], $r4 lslq 9, $r4 ; Command starts at bit 9 @@ -145,6 +169,9 @@ _set_timing: bne 1b nop move.d $r5, [R_SDRAM_TIMING] + subq 1, $r6 + bne _sdram_init + nop ba _sdram_commands_end nop diff --git a/arch/cris/lib/hw_settings.S b/arch/cris/arch-v10/lib/hw_settings.S index b35bb3baa5aa..56905aaa7b6e 100644 --- a/arch/cris/lib/hw_settings.S +++ b/arch/cris/arch-v10/lib/hw_settings.S @@ -1,5 +1,5 @@ /* - * $Id: hw_settings.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ + * $Id: hw_settings.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ * * This table is used by some tools to extract hardware parameters. * The table should be included in the kernel and the decompressor. diff --git a/arch/cris/lib/memset.c b/arch/cris/arch-v10/lib/memset.c index 82bb66839171..82bb66839171 100644 --- a/arch/cris/lib/memset.c +++ b/arch/cris/arch-v10/lib/memset.c diff --git a/arch/cris/lib/old_checksum.c b/arch/cris/arch-v10/lib/old_checksum.c index 5d4d9bc4b057..3b68d1a60a0a 100644 --- a/arch/cris/lib/old_checksum.c +++ b/arch/cris/arch-v10/lib/old_checksum.c @@ -1,4 +1,4 @@ -/* $Id: old_checksum.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: old_checksum.c,v 1.2 2002/11/05 06:45:12 starvik Exp $ * * INET An implementation of the TCP/IP protocol suite for the LINUX * operating system. INET is implemented using the BSD Socket @@ -75,7 +75,7 @@ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) sum += *((unsigned short *)buff)++; } if(endMarker - buff > 0) { - sum += *buff; /* add extra byte separately */ + sum += *buff; /* add extra byte seperately */ } BITOFF; return(sum); diff --git a/arch/cris/lib/string.c b/arch/cris/arch-v10/lib/string.c index 8ffde4901b57..8ffde4901b57 100644 --- a/arch/cris/lib/string.c +++ b/arch/cris/arch-v10/lib/string.c diff --git a/arch/cris/lib/usercopy.c b/arch/cris/arch-v10/lib/usercopy.c index fc0b89cc57fe..43778d53c254 100644 --- a/arch/cris/lib/usercopy.c +++ b/arch/cris/arch-v10/lib/usercopy.c @@ -31,7 +31,7 @@ kernel-to-kernel copying; see "string.c". */ unsigned long -__copy_user (void *pdst, const void *psrc, unsigned long pn) +__copy_user (void __user *pdst, const void *psrc, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -88,11 +88,11 @@ __copy_user (void *pdst, const void *psrc, unsigned long pn) If you want to check that the allocation was right; then check the equalities in the first comment. It should say "r13=r13, r11=r11, r12=r12". */ - __asm__ volatile (" - ;; Check that the following is true (same register names on - ;; both sides of equal sign, as in r8=r8): - ;; %0=r13, %1=r11, %2=r12 %3=r10 - ;; + __asm__ volatile ("\ + .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ + .err \n\ + .endif \n\ + ;; Save the registers we'll use in the movem process ;; on the stack. subq 11*4,$sp @@ -189,10 +189,11 @@ __copy_user (void *pdst, const void *psrc, unsigned long pn) } /* Copy from user to kernel, zeroing the bytes that were inaccessible in - userland. */ + userland. The return-value is the number of bytes that were + inaccessible. */ unsigned long -__copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) +__copy_user_zeroing (void __user *pdst, const void *psrc, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -207,30 +208,34 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) register int n __asm__ ("r12") = pn; register int retn __asm__ ("r10") = 0; - /* When src is aligned but not dst, this makes a few extra needless - cycles. I believe it would take as many to check that the - re-alignment was unnecessary. */ - if (((unsigned long) dst & 3) != 0 - /* Don't align if we wouldn't copy more than a few bytes; so we - don't have to check further for overflows. */ - && n >= 3) + /* The best reason to align src is that we then know that a read-fault + was for aligned bytes; there's no 1..3 remaining good bytes to + pickle. */ + if (((unsigned long) src & 3) != 0) { - if ((unsigned long) dst & 1) + if (((unsigned long) src & 1) && n != 0) { __asm_copy_from_user_1 (dst, src, retn); n--; } - if ((unsigned long) dst & 2) + if (((unsigned long) src & 2) && n >= 2) { __asm_copy_from_user_2 (dst, src, retn); n -= 2; } + + /* We only need one check after the unalignment-adjustments, because + if both adjustments were done, either both or neither reference + had an exception. */ + if (retn != 0) + goto copy_exception_bytes; } /* Decide which copying method to use. */ if (n >= 44*2) /* Break even between movem and - move16 is at 38.7*2, but modulo 44. */ + move16 is at 38.7*2, but modulo 44. + FIXME: We use move4 now. */ { /* For large copies we use 'movem' */ @@ -249,10 +254,10 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) check the equalities in the first comment. It should say "r13=r13, r11=r11, r12=r12" */ __asm__ volatile (" - ;; Check that the following is true (same register names on - ;; both sides of equal sign, as in r8=r8): - ;; %0=r13, %1=r11, %2=r12 %3=r10 - ;; + .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ + .err \n\ + .endif \n\ + ;; Save the registers we'll use in the movem process ;; on the stack. subq 11*4,$sp @@ -273,73 +278,30 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) movem $r10,[$r13+] addq 44,$r12 ;; compensate for last loop underflowing n -8: + ;; Restore registers from stack movem [$sp+],$r10 - +4: .section .fixup,\"ax\" ;; Do not jump back into the loop if we fail. For some uses, we get a -;; page fault but for performance reasons we care to not get further -;; faults. For example, fs/super.c at one time did +;; page fault somewhere on the line. Without checking for page limits, +;; we don't know where, but we need to copy accurately and keep an +;; accurate count; not just clear the whole line. To do that, we fall +;; down in the code below, proceeding with smaller amounts. It should +;; be kept in mind that we have to cater to code like what at one time +;; was in fs/super.c: ;; i = size - copy_from_user((void *)page, data, size); ;; which would cause repeated faults while clearing the remainder of ;; the SIZE bytes at PAGE after the first fault. +;; A caveat here is that we must not fall through from a failing page +;; to a valid page. 3: - move.d [$sp],$r10 - -;; Number of remaining bytes, cleared but not copied, is r12 + 44. - - add.d $r12,$r10 - addq 44,$r10 - - move.d $r10,[$sp] - clear.d $r0 - clear.d $r1 - clear.d $r2 - clear.d $r3 - clear.d $r4 - clear.d $r5 - clear.d $r6 - clear.d $r7 - clear.d $r8 - clear.d $r9 - clear.d $r10 - -;; Perform clear similar to the copy-loop. - -4: - subq 44,$r12 - bge 4b - movem $r10,[$r13+] - -;; Clear by four for the remaining multiples. - - addq 40,$r12 - bmi 6f - nop -5: - subq 4,$r12 - bpl 5b - clear.d [$r13+] -6: - addq 4,$r12 - beq 7f - nop - - subq 1,$r12 - beq 7f - clear.b [$r13+] - - subq 1,$r12 - beq 7f - clear.b [$r13+] - - clear.d $r12 - clear.b [$r13+] -7: - jump 8b + movem [$sp+],$r10 + addq 44,$r12 ;; Get back count before faulting point. + subq 44,$r11 ;; Get back pointer to faulting movem-line. + jump 4b ;; Fall through, pretending the fault didn't happen. .previous .section __ex_table,\"a\" @@ -354,25 +316,30 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) /* Either we directly start copying here, using dword copying in a loop, or we copy as much as possible with 'movem' and then the last block (<44 bytes) is copied here. This will work since 'movem' will have - updated src, dst and n. */ + updated src, dst and n. (Except with failing src.) - while (n >= 16) - { - __asm_copy_from_user_16 (dst, src, retn); - n -= 16; - } + Since we want to keep src accurate, we can't use + __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and + retn, but not src (by design; it's value is ignored elsewhere). */ - /* Having a separate by-four loops cuts down on cache footprint. - FIXME: Test with and without; increasing switch to be 0..15. */ while (n >= 4) { __asm_copy_from_user_4 (dst, src, retn); n -= 4; + + if (retn) + goto copy_exception_bytes; } + /* If we get here, there were no memory read faults. */ switch (n) { + /* These copies are at least "naturally aligned" (so we don't have + to check each byte), due to the src alignment code before the + movem loop. The *_3 case *will* get the correct count for retn. */ case 0: + /* This case deliberately left in (if you have doubts check the + generated assembly code). */ break; case 1: __asm_copy_from_user_1 (dst, src, retn); @@ -385,13 +352,28 @@ __copy_user_zeroing (void *pdst, const void *psrc, unsigned long pn) break; } + /* If we get here, retn correctly reflects the number of failing + bytes. */ return retn; + +copy_exception_bytes: + /* We already have "retn" bytes cleared, and need to clear the + remaining "n" bytes. A non-optimized simple byte-for-byte in-line + memset is preferred here, since this isn't speed-critical code and + we'd rather have this a leaf-function than calling memset. */ + { + char *endp; + for (endp = dst + n; dst < endp; dst++) + *dst = 0; + } + + return retn + n; } /* Zero userspace. */ unsigned long -__do_clear_user (void *pto, unsigned long pn) +__do_clear_user (void __user *pto, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -444,10 +426,10 @@ __do_clear_user (void *pto, unsigned long pn) check the equalities in the first comment. It should say something like "r13=r13, r11=r11, r12=r12". */ __asm__ volatile (" - ;; Check that the following is true (same register names on - ;; both sides of equal sign, as in r8=r8): - ;; %0=r13, %1=r12 %2=r10 - ;; + .ifnc %0%1%2,$r13$r12$r10 \n\ + .err \n\ + .endif \n\ + ;; Save the registers we'll clobber in the movem process ;; on the stack. Don't mention them to gcc, it will only be ;; upset. diff --git a/arch/cris/arch-v10/mm/Makefile b/arch/cris/arch-v10/mm/Makefile new file mode 100644 index 000000000000..588b4baee85e --- /dev/null +++ b/arch/cris/arch-v10/mm/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the linux cris-specific parts of the memory manager. +# + +obj-y := fault.o init.o tlb.o + diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c new file mode 100644 index 000000000000..7a012adc1579 --- /dev/null +++ b/arch/cris/arch-v10/mm/fault.c @@ -0,0 +1,175 @@ +/* + * linux/arch/cris/mm/fault.c + * + * Low level bus fault handler + * + * + * Copyright (C) 2000, 2001 Axis Communications AB + * + * Authors: Bjorn Wesen + * + */ + +#include <linux/mm.h> +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/arch/svinto.h> + +/* debug of low-level TLB reload */ +#undef DEBUG + +#ifdef DEBUG +#define D(x) x +#else +#define D(x) +#endif + +extern volatile pgd_t *current_pgd; + +extern const struct exception_table_entry + *search_exception_tables(unsigned long addr); + +asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, + int error_code); + +/* fast TLB-fill fault handler + * this is called from entry.S with interrupts disabled + */ + +void +handle_mmu_bus_fault(struct pt_regs *regs) +{ + int cause, select; +#ifdef DEBUG + int index; + int page_id; + int acc, inv; +#endif + int miss, we, writeac; + pmd_t *pmd; + pte_t pte; + int errcode; + unsigned long address; + + cause = *R_MMU_CAUSE; + select = *R_TLB_SELECT; + + address = cause & PAGE_MASK; /* get faulting address */ + +#ifdef DEBUG + page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); + acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); + inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); + index = IO_EXTRACT(R_TLB_SELECT, index, select); +#endif + miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); + we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); + writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); + + /* ETRAX 100LX TR89 bugfix: if the second half of an unaligned + * write causes a MMU-fault, it will not be restarted correctly. + * This could happen if a write crosses a page-boundary and the + * second page is not yet COW'ed or even loaded. The workaround + * is to clear the unaligned bit in the CPU status record, so + * that the CPU will rerun both the first and second halves of + * the instruction. This will not have any sideeffects unless + * the first half goes to any device or memory that can't be + * written twice, and which is mapped through the MMU. + * + * We only need to do this for writes. + */ + + if(writeac) + 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", + regs->irp, address, miss, inv, we, acc, index, page_id)); + + /* for a miss, we need to reload the TLB entry */ + + if (miss) { + /* see if the pte exists at all + * refer through current_pgd, dont use mm->pgd + */ + + pmd = (pmd_t *)(current_pgd + pgd_index(address)); + if (pmd_none(*pmd)) + goto dofault; + if (pmd_bad(*pmd)) { + printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd); + pmd_clear(pmd); + return; + } + pte = *pte_offset_kernel(pmd, address); + if (!pte_present(pte)) + goto dofault; + +#ifdef DEBUG + printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte)); + if (pte_val(pte) & _PAGE_SILENT_WRITE) + printk("Silent-W "); + if (pte_val(pte) & _PAGE_KERNEL) + printk("Kernel "); + if (pte_val(pte) & _PAGE_SILENT_READ) + printk("Silent-R "); + if (pte_val(pte) & _PAGE_GLOBAL) + printk("Global "); + if (pte_val(pte) & _PAGE_PRESENT) + printk("Present "); + if (pte_val(pte) & _PAGE_ACCESSED) + printk("Accessed "); + if (pte_val(pte) & _PAGE_MODIFIED) + printk("Modified "); + if (pte_val(pte) & _PAGE_READ) + printk("Readable "); + if (pte_val(pte) & _PAGE_WRITE) + printk("Writeable "); + printk("\n"); +#endif + + /* load up the chosen TLB entry + * this assumes the pte format is the same as the TLB_LO layout. + * + * the write to R_TLB_LO also writes the vpn and page_id fields from + * R_MMU_CAUSE, which we in this case obviously want to keep + */ + + *R_TLB_LO = pte_val(pte); + + return; + } + + errcode = 1 | (we << 1); + + dofault: + /* leave it to the MM system fault handler below */ + 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. */ +int +find_fixup_code(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + if ((fixup = search_exception_tables(regs->irp)) != 0) { + /* Adjust the instruction pointer in the stackframe. */ + regs->irp = fixup->fixup; + + /* + * Don't return by restoring the CPU state, so switch + * frame-type. + */ + regs->frametype = CRIS_FRAME_NORMAL; + return 1; + } + + return 0; +} diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c new file mode 100644 index 000000000000..df03dea5bae4 --- /dev/null +++ b/arch/cris/arch-v10/mm/init.c @@ -0,0 +1,265 @@ +/* + * linux/arch/cris/arch-v10/mm/init.c + * + */ +#include <linux/config.h> +#include <linux/mmzone.h> +#include <linux/init.h> +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/types.h> +#include <asm/mmu.h> +#include <asm/io.h> +#include <asm/mmu_context.h> +#include <asm/arch/svinto.h> + +extern void tlb_init(void); + +/* + * The kernel is already mapped with a kernel segment at kseg_c so + * we don't need to map it with a page table. However head.S also + * temporarily mapped it at kseg_4 so we should set up the ksegs again, + * clear the TLB and do some other paging setup stuff. + */ + +void __init +paging_init(void) +{ + int i; + unsigned long zones_size[MAX_NR_ZONES]; + + printk("Setting up paging and the MMU.\n"); + + /* clear out the init_mm.pgd that will contain the kernel's mappings */ + + for(i = 0; i < PTRS_PER_PGD; i++) + swapper_pg_dir[i] = __pgd(0); + + /* make sure the current pgd table points to something sane + * (even if it is most probably not used until the next + * switch_mm) + */ + + current_pgd = init_mm.pgd; + + /* initialise the TLB (tlb.c) */ + + tlb_init(); + + /* see README.mm for details on the KSEG setup */ + +#ifdef CONFIG_CRIS_LOW_MAP + /* Etrax-100 LX version 1 has a bug so that we cannot map anything + * across the 0x80000000 boundary, so we need to shrink the user-virtual + * area to 0x50000000 instead of 0xb0000000 and map things slightly + * different. The unused areas are marked as paged so that we can catch + * freak kernel accesses there. + * + * The ARTPEC chip is mapped at 0xa so we pass that segment straight + * through. We cannot vremap it because the vmalloc area is below 0x8 + * and Juliette needs an uncached area above 0x8. + * + * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards. + * We map them straight over in LOW_MAP, but use vremap in LX version 2. + */ + +#define CACHED_BOOTROM (KSEG_F | 0x08000000UL) + + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* bootrom */ + IO_STATE(R_MMU_KSEG, seg_e, page ) | + IO_STATE(R_MMU_KSEG, seg_d, page ) | + IO_STATE(R_MMU_KSEG, seg_c, page ) | + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ +#ifdef CONFIG_JULIETTE + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ +#else + IO_STATE(R_MMU_KSEG, seg_a, page ) | +#endif + IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ + IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ + IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ + IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_4, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_3, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_2, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_1, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x3 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | +#ifdef CONFIG_JULIETTE + IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | +#else + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | +#endif + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#else + /* This code is for the corrected Etrax-100 LX version 2... */ + +#define CACHED_BOOTROM (KSEG_A | 0x08000000UL) + + *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ + IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ + IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ + IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ + IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ + IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* bootrom */ + IO_STATE(R_MMU_KSEG, seg_9, page ) | /* user area */ + IO_STATE(R_MMU_KSEG, seg_8, page ) | + IO_STATE(R_MMU_KSEG, seg_7, page ) | + IO_STATE(R_MMU_KSEG, seg_6, page ) | + IO_STATE(R_MMU_KSEG, seg_5, page ) | + IO_STATE(R_MMU_KSEG, seg_4, page ) | + IO_STATE(R_MMU_KSEG, seg_3, page ) | + IO_STATE(R_MMU_KSEG, seg_2, page ) | + IO_STATE(R_MMU_KSEG, seg_1, page ) | + IO_STATE(R_MMU_KSEG, seg_0, page ) ); + + *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | + IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | + IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | + IO_FIELD(R_MMU_KBASE_HI, base_a, 0x3 ) | + IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | + IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); + + *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | + IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); +#endif + + *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); + + /* The MMU has been enabled ever since head.S but just to make + * it totally obvious we do it here as well. + */ + + *R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) | + IO_STATE(R_MMU_CTRL, acc_excp, enable ) | + IO_STATE(R_MMU_CTRL, we_excp, enable ) ); + + *R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable); + + /* + * initialize the bad page table and bad page to point + * to a couple of allocated pages + */ + + empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); + memset((void *)empty_zero_page, 0, PAGE_SIZE); + + /* All pages are DMA'able in Etrax, so put all in the DMA'able zone */ + + zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT; + + for (i = 1; i < MAX_NR_ZONES; i++) + zones_size[i] = 0; + + /* Use free_area_init_node instead of free_area_init, because the former + * is designed for systems where the DRAM starts at an address substantially + * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the + * mem_map page array. + */ + + free_area_init_node(0, &contig_page_data, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); + mem_map = contig_page_data.node_mem_map; +} + +/* Initialize remaps of some I/O-ports. It is important that this + * is called before any driver is initialized. + */ + +static int +__init init_ioremap(void) +{ + + /* Give the external I/O-port addresses their values */ + +#ifdef CONFIG_CRIS_LOW_MAP + /* Simply a linear map (see the KSEG map above in paging_init) */ + port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | + MEM_NON_CACHEABLE); + port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | + MEM_NON_CACHEABLE); + port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | + MEM_NON_CACHEABLE); +#else + /* Note that nothing blows up just because we do this remapping + * it's ok even if the ports are not used or connected + * to anything (or connected to a non-I/O thing) */ + port_cse1_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSE1_START | MEM_NON_CACHEABLE), 16); + port_csp0_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP0_START | MEM_NON_CACHEABLE), 16); + port_csp4_addr = (volatile unsigned long *) + ioremap((unsigned long)(MEM_CSP4_START | MEM_NON_CACHEABLE), 16); +#endif + return 0; +} + +__initcall(init_ioremap); + +/* Helper function for the two below */ + +static inline void +flush_etrax_cacherange(void *startadr, int length) +{ + /* CACHED_BOOTROM is mapped to the boot-rom area (cached) which + * we can use to get fast dummy-reads of cachelines + */ + + volatile short *flushadr = (volatile short *)(((unsigned long)startadr & ~PAGE_MASK) | + CACHED_BOOTROM); + + length = length > 8192 ? 8192 : length; /* No need to flush more than cache size */ + + while(length > 0) { + *flushadr; /* dummy read to flush */ + flushadr += (32/sizeof(short)); /* a cacheline is 32 bytes */ + length -= 32; + } +} + +/* Due to a bug in Etrax100(LX) all versions, receiving DMA buffers + * will occationally corrupt certain CPU writes if the DMA buffers + * happen to be hot in the cache. + * + * As a workaround, we have to flush the relevant parts of the cache + * before (re) inserting any receiving descriptor into the DMA HW. + */ + +void +prepare_rx_descriptor(struct etrax_dma_descr *desc) +{ + flush_etrax_cacherange((void *)desc->buf, desc->sw_len ? desc->sw_len : 65536); +} + +/* Do the same thing but flush the entire cache */ + +void +flush_etrax_cache(void) +{ + flush_etrax_cacherange(0, 8192); +} diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c new file mode 100644 index 000000000000..2ddb0a61cdbf --- /dev/null +++ b/arch/cris/arch-v10/mm/tlb.c @@ -0,0 +1,236 @@ +/* + * linux/arch/cris/arch-v10/mm/tlb.c + * + * Low level TLB handling + * + * + * Copyright (C) 2000-2002 Axis Communications AB + * + * Authors: Bjorn Wesen (bjornw@axis.com) + * + */ + +#include <asm/tlb.h> +#include <asm/mmu_context.h> +#include <asm/arch/svinto.h> + +#define D(x) + +/* The TLB can host up to 64 different mm contexts at the same time. + * The running context is R_MMU_CONTEXT, and each TLB entry contains a + * page_id that has to match to give a hit. In page_id_map, we keep track + * of which mm's we have assigned which page_id's, so that we know when + * to invalidate TLB entries. + * + * The last page_id is never running - it is used as an invalid page_id + * so we can make TLB entries that will never match. + * + * Notice that we need to make the flushes atomic, otherwise an interrupt + * handler that uses vmalloced memory might cause a TLB load in the middle + * of a flush causing. + */ + +/* invalidate all TLB entries */ + +void +flush_tlb_all(void) +{ + int i; + unsigned long flags; + + /* the vpn of i & 0xf is so we dont write similar TLB entries + * in the same 4-way entry group. details.. + */ + + local_save_flags(flags); + local_irq_disable(); + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); + *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + local_irq_restore(flags); + D(printk("tlb: flushed all\n")); +} + +/* invalidate the selected mm context only */ + +void +flush_tlb_mm(struct mm_struct *mm) +{ + int i; + int page_id = mm->context; + unsigned long flags; + + D(printk("tlb: flush mm context %d (%p)\n", page_id, mm)); + + if(page_id == NO_CONTEXT) + return; + + /* mark the TLB entries that match the page_id as invalid. + * here we could also check the _PAGE_GLOBAL bit and NOT flush + * global pages. is it worth the extra I/O ? + */ + + local_save_flags(flags); + local_irq_disable(); + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); + if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { + *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + } + local_irq_restore(flags); +} + +/* invalidate a single page */ + +void +flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr) +{ + struct mm_struct *mm = vma->vm_mm; + int page_id = mm->context; + int i; + unsigned long flags; + + D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm)); + + if(page_id == NO_CONTEXT) + return; + + addr &= PAGE_MASK; /* perhaps not necessary */ + + /* invalidate those TLB entries that match both the mm context + * and the virtual address requested + */ + + local_save_flags(flags); + local_irq_disable(); + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + unsigned long tlb_hi; + *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); + tlb_hi = *R_TLB_HI; + if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && + (tlb_hi & PAGE_MASK) == addr) { + *R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + addr; /* same addr as before works. */ + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + } + local_irq_restore(flags); +} + +/* invalidate a page range */ + +void +flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, + unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + int page_id = mm->context; + int i; + unsigned long flags; + + D(printk("tlb: flush range %p<->%p in context %d (%p)\n", + start, end, page_id, mm)); + + if(page_id == NO_CONTEXT) + return; + + start &= PAGE_MASK; /* probably not necessary */ + end &= PAGE_MASK; /* dito */ + + /* invalidate those TLB entries that match both the mm context + * and the virtual address range + */ + + local_save_flags(flags); + local_irq_disable(); + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + unsigned long tlb_hi, vpn; + *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); + tlb_hi = *R_TLB_HI; + vpn = tlb_hi & PAGE_MASK; + if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && + vpn >= start && vpn < end) { + *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | + IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); + + *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | + IO_STATE(R_TLB_LO, valid, no ) | + IO_STATE(R_TLB_LO, kernel,no ) | + IO_STATE(R_TLB_LO, we, no ) | + IO_FIELD(R_TLB_LO, pfn, 0 ) ); + } + } + local_irq_restore(flags); +} + +/* dump the entire TLB for debug purposes */ + +#if 0 +void +dump_tlb_all(void) +{ + int i; + unsigned long flags; + + printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n"); + + local_save_flags(flags); + local_irq_disable(); + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); + printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n", + i, *R_TLB_HI, *R_TLB_LO); + } + local_irq_restore(flags); +} +#endif + +/* called in schedule() just before actually doing the switch_to */ + +void +switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk, int cpu) +{ + /* make sure we have a context */ + + get_mmu_context(next); + + /* remember the pgd for the fault handlers + * this is similar to the pgd register in some other CPU's. + * we need our own copy of it because current and active_mm + * might be invalid at points where we still need to derefer + * the pgd. + */ + + current_pgd = next->pgd; + + /* switch context in the MMU */ + + D(printk("switching mmu_context to %d (%p)\n", next->context, next)); + + *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context); +} + diff --git a/arch/cris/arch-v10/output_arch.ld b/arch/cris/arch-v10/output_arch.ld new file mode 100644 index 000000000000..2f3288006991 --- /dev/null +++ b/arch/cris/arch-v10/output_arch.ld @@ -0,0 +1,2 @@ +/* At the time of this writing, there's no equivalent ld option. */ +OUTPUT_ARCH (cris) diff --git a/arch/cris/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S index 3a5f1a36da38..b2c27e147f29 100644 --- a/arch/cris/vmlinux.lds.S +++ b/arch/cris/arch-v10/vmlinux.lds.S @@ -10,11 +10,11 @@ #include <linux/config.h> #include <asm-generic/vmlinux.lds.h> - + jiffies = jiffies_64; SECTIONS { - . = 0x ## CONFIG_ETRAX_DRAM_VIRTUAL_BASE; + . = DRAM_VIRTUAL_BASE; dram_start = .; ibr_start = .; . = . + 0x4000; /* see head.S and pages reserved at the start */ @@ -53,12 +53,19 @@ SECTIONS . = ALIGN(8192); /* Init code and data */ __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } + .init.text : { + _sinittext = .; + *(.init.text) + _einittext = .; + } + .init.data : { *(.init.data) } . = ALIGN(16); __setup_start = .; - .setup.init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; + __start___param = .; + __param : { *(__param) } + __stop___param = .; .initcall.init : { __initcall_start = .; *(.initcall1.init); @@ -68,24 +75,27 @@ SECTIONS *(.initcall5.init); *(.initcall6.init); *(.initcall7.init); - __initcall_end = .; + __initcall_end = .; } + .con_initcall.init : { __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; - } - .security_initcall.init : { - __security_initcall_start = .; - *(.security_initcall.init) - __security_initcall_end = .; - + } + SECURITY_INIT + + .init.ramfs : { + __initramfs_start = .; + *(.init.ramfs) + __initramfs_end = .; /* We fill to the next page, so we can discard all init pages without needing to consider what payload might be appended to the kernel image. */ - FILL (0); + FILL (0); . = ALIGN (8192); } + __vmlinux_end = .; /* last address of the physical file */ __init_end = .; diff --git a/arch/cris/defconfig b/arch/cris/defconfig index 9d40dd316576..7af178b78328 100644 --- a/arch/cris/defconfig +++ b/arch/cris/defconfig @@ -27,93 +27,13 @@ CONFIG_BINFMT_ELF=y CONFIG_ETRAX100LX=y # CONFIG_ETRAX100LX_V2 is not set # CONFIG_SVINTO_SIM is not set -CONFIG_CRIS_LOW_MAP=y -CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 CONFIG_ETRAX_DRAM_SIZE=8 CONFIG_ETRAX_FLASH_BUSWIDTH=2 CONFIG_ETRAX_ROOT_DEVICE="/dev/mtdblock3" -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=2 -CONFIG_ETRAX_LED2R=2 -CONFIG_ETRAX_LED3R=2 -CONFIG_ETRAX_LED3G=2 -CONFIG_ETRAX_LED4R=2 -CONFIG_ETRAX_LED4G=2 -CONFIG_ETRAX_LED5R=2 -CONFIG_ETRAX_LED5G=2 -CONFIG_ETRAX_LED6R=2 -CONFIG_ETRAX_LED6G=2 -CONFIG_ETRAX_LED7R=2 -CONFIG_ETRAX_LED7G=2 -CONFIG_ETRAX_LED8Y=2 -CONFIG_ETRAX_LED9Y=2 -CONFIG_ETRAX_LED10Y=2 -CONFIG_ETRAX_LED11Y=2 -CONFIG_ETRAX_LED12R=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_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=95a6 -CONFIG_ETRAX_DEF_R_BUS_CONFIG=104 -# CONFIG_ETRAX_SDRAM is not set -CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040 -CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611 -CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d -CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0 -CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 -CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e -CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 -# CONFIG_ETRAX_SOFT_SHUTDOWN is not set # # Drivers for ETRAX 100LX 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_ETHERNET_LPSLAVE is not set -CONFIG_ETRAX_SERIAL=y -CONFIG_ETRAX_SERIAL_PORT0=y -# CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set -CONFIG_ETRAX_SERIAL_PORT1=y -# CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set -# CONFIG_ETRAX_SERIAL_PORT2 is not set -# CONFIG_ETRAX_SERIAL_PORT3 is not set -# CONFIG_ETRAX_RS485 is not set -# CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set -# CONFIG_ETRAX_IDE is not set -CONFIG_ETRAX_AXISFLASHMAP=y -CONFIG_ETRAX_PTABLE_SECTOR=65536 -CONFIG_MTD=y -CONFIG_MTD_CFI=y -# CONFIG_MTD_CFI_INTELEXT is not set -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_AMDSTD=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_ETRAX_I2C=y -CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y -# CONFIG_ETRAX_I2C_EEPROM is not set -CONFIG_ETRAX_GPIO=y -CONFIG_ETRAX_PA_BUTTON_BITMASK=02 -CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 -CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF -CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 -CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF -# CONFIG_ETRAX_USB_HOST is not set -# CONFIG_USB is not set -# CONFIG_ETRAX_DS1302 is not set # # Memory Technology Devices (MTD) diff --git a/arch/cris/drivers/axisflashmap.c b/arch/cris/drivers/axisflashmap.c deleted file mode 100644 index 6db4078e068b..000000000000 --- a/arch/cris/drivers/axisflashmap.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Physical mapping layer for MTD using the Axis partitiontable format - * - * Copyright (c) 2001 Axis Communications AB - * - * This file is under the GPL. - * - * First partition is always sector 0 regardless of if we find a partitiontable - * or not. In the start of the next sector, there can be a partitiontable that - * tells us what other partitions to define. If there isn't, we use a default - * partition split defined below. - * - * $Log: axisflashmap.c,v $ - * Revision 1.2 2001/12/18 13:35:15 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). - * - * Revision 1.17 2001/11/12 19:42:38 pkj - * Fixed compiler warnings. - * - * Revision 1.16 2001/11/08 11:18:58 jonashg - * Always read from uncached address to avoid problems with flushing - * cachelines after write and MTD-erase. No performance loss have been - * seen yet. - * - * Revision 1.15 2001/10/19 12:41:04 jonashg - * Name of probe has changed in MTD. - * - * Revision 1.14 2001/09/21 07:14:10 jonashg - * Made root filesystem (cramfs) use mtdblock driver when booting from flash. - * - * Revision 1.13 2001/08/15 13:57:35 jonashg - * Entire MTD updated to the linux 2.4.7 version. - * - * Revision 1.12 2001/06/11 09:50:30 jonashg - * Oops, 2MB is 0x200000 bytes. - * - * Revision 1.11 2001/06/08 11:39:44 jonashg - * Changed sizes and offsets in axis_default_partitions to use - * CONFIG_ETRAX_PTABLE_SECTOR. - * - * Revision 1.10 2001/05/29 09:42:03 jonashg - * Use macro for end marker length instead of sizeof. - * - * Revision 1.9 2001/05/29 08:52:52 jonashg - * Gave names to the magic fours (size of the ptable end marker). - * - * Revision 1.8 2001/05/28 15:36:20 jonashg - * * Removed old comment about ptable location in flash (it's a CONFIG_ option). - * * Variable ptable was initialized twice to the same value. - * - * Revision 1.7 2001/04/05 13:41:46 markusl - * Updated according to review remarks - * - * Revision 1.6 2001/03/07 09:21:21 bjornw - * No need to waste .data - * - * Revision 1.5 2001/03/06 16:27:01 jonashg - * Probe the entire flash area for flash devices. - * - * Revision 1.4 2001/02/23 12:47:15 bjornw - * Uncached flash in LOW_MAP moved from 0xe to 0x8 - * - * Revision 1.3 2001/02/16 12:11:45 jonashg - * MTD driver amd_flash is now included in MTD CVS repository. - * (It's now in drivers/mtd). - * - * Revision 1.2 2001/02/09 11:12:22 jonashg - * Support for AMD compatible non-CFI flash chips. - * Only tested with Toshiba TC58FVT160 so far. - * - * Revision 1.1 2001/01/12 17:01:18 bjornw - * * Added axisflashmap.c, a physical mapping for MTD that reads and understands - * Axis partition-table format. - * - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/config.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#include <asm/axisflashmap.h> -#include <asm/mmu.h> - -#ifdef CONFIG_CRIS_LOW_MAP -#define FLASH_UNCACHED_ADDR KSEG_8 -#define FLASH_CACHED_ADDR KSEG_5 -#else -#define FLASH_UNCACHED_ADDR KSEG_E -#define FLASH_CACHED_ADDR KSEG_F -#endif - -/* - * WINDOW_SIZE is the total size where the flash chips may be mapped. - * MTD probes should find all devices there and it does not matter - * if there are unmapped gaps or aliases (mirrors of flash devices). - * The MTD probes will ignore them. - */ - -#define WINDOW_SIZE (128 * 1024 * 1024) - -extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* From head.S */ - -/* - * Map driver - * - * Ok this is the scoop - we need to access the flash both with and without - * the cache - without when doing all the fancy flash interfacing, and with - * when we do actual copying because otherwise it will be slow like molasses. - */ - -static __u8 flash_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(FLASH_UNCACHED_ADDR + ofs); -} - -static __u16 flash_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(FLASH_UNCACHED_ADDR + ofs); -} - -static __u32 flash_read32(struct map_info *map, unsigned long ofs) -{ - return *(volatile unsigned int *)(FLASH_UNCACHED_ADDR + ofs); -} - -static void flash_copy_from(struct map_info *map, void *to, - unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(FLASH_UNCACHED_ADDR + from), len); -} - -static void flash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(FLASH_UNCACHED_ADDR + adr) = d; -} - -static void flash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(FLASH_UNCACHED_ADDR + adr) = d; -} - -static void flash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(FLASH_UNCACHED_ADDR + adr) = d; -} - -static struct map_info axis_map = { - .name = "Axis flash", - .size = WINDOW_SIZE, - .buswidth = CONFIG_ETRAX_FLASH_BUSWIDTH, - .read8 = flash_read8, - .read16 = flash_read16, - .read32 = flash_read32, - .copy_from = flash_copy_from, - .write8 = flash_write8, - .write16 = flash_write16, - .write32 = flash_write32, -}; - -/* If no partition-table was found, we use this default-set. - */ - -#define MAX_PARTITIONS 7 -#define NUM_DEFAULT_PARTITIONS 3 - -/* Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the - * size of one flash block and "filesystem"-partition needs 5 blocks to be able - * to use JFFS. - */ -static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { - { - .name = "boot firmware", - .size = CONFIG_ETRAX_PTABLE_SECTOR, - .offset = 0 - }, - { - .name = "kernel", - .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), - .offset = CONFIG_ETRAX_PTABLE_SECTOR - }, - { - .name = "filesystem", - .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, - .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) - } -}; - -static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { - { - .name = "part0", - .size = 0, - .offset = 0 - }, - { - .name = "part1", - .size = 0, - .offset = 0 - }, - { - .name = "part2", - .size = 0, - .offset = 0 - }, - { - .name = "part3", - .size = 0, - .offset = 0 - }, - { - .name = "part4", - .size = 0, - .offset = 0 - }, - { - .name = "part5", - .size = 0, - .offset = 0 - }, - { - .name = "part6", - .size = 0, - .offset = 0 - }, -}; - -/* - * This is the master MTD device for which all the others are just - * auto-relocating aliases. - */ -static struct mtd_info *mymtd; - -/* CFI-scan the flash, and if there was a chip, read the partition-table - * and register the partitions with MTD. - */ - -static int __init -init_axis_flash(void) -{ - int pidx = 0; - struct partitiontable_head *ptable_head; - struct partitiontable_entry *ptable; - int use_default_ptable = 1; /* Until proven otherwise */ - const char *pmsg = " /dev/flash%d at 0x%x, size 0x%x\n"; - - printk(KERN_NOTICE "Axis flash mapping: %x at %lx\n", - WINDOW_SIZE, FLASH_CACHED_ADDR); - -#ifdef CONFIG_MTD_CFI - mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &axis_map); -#endif - -#ifdef CONFIG_MTD_AMDSTD - if (!mymtd) { - mymtd = (struct mtd_info *)do_map_probe("amd_flash", &axis_map); - } -#endif - - if(!mymtd) { - printk("%s: No flash chip found!\n", axis_map.name); - return -ENXIO; - } - - mymtd->module = THIS_MODULE; - - ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + - CONFIG_ETRAX_PTABLE_SECTOR + PARTITION_TABLE_OFFSET); - pidx++; /* first partition is always set to the default */ - - if ((ptable_head->magic == PARTITION_TABLE_MAGIC) - && (ptable_head->size < - (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + - PARTITIONTABLE_END_MARKER_SIZE)) - && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + - ptable_head->size - - PARTITIONTABLE_END_MARKER_SIZE) - == PARTITIONTABLE_END_MARKER)) { - /* Looks like a start, sane length and end of a - * partition table, lets check csum etc. - */ - int ptable_ok = 0; - struct partitiontable_entry *max_addr = - (struct partitiontable_entry *) - ((unsigned long)ptable_head + sizeof(*ptable_head) + - ptable_head->size); - unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; - unsigned char *p; - unsigned long csum = 0; - - ptable = (struct partitiontable_entry *) - ((unsigned long)ptable_head + sizeof(*ptable_head)); - - /* Lets be PARANOID, and check the checksum. */ - p = (unsigned char*) ptable; - - while (p <= (unsigned char*)max_addr) { - csum += *p++; - csum += *p++; - csum += *p++; - csum += *p++; - } - /* printk(" total csum: 0x%08X 0x%08X\n", - csum, ptable_head->checksum); */ - ptable_ok = (csum == ptable_head->checksum); - - /* Read the entries and use/show the info. */ - printk(" Found %s partition table at 0x%08lX-0x%08lX.\n", - (ptable_ok ? "valid" : "invalid"), - (unsigned long)ptable_head, - (unsigned long)max_addr); - - /* We have found a working bootblock. Now read the - partition table. Scan the table. It ends when - there is 0xffffffff, that is, empty flash. */ - - while (ptable_ok - && ptable->offset != 0xffffffff - && ptable < max_addr - && pidx < MAX_PARTITIONS) { - - axis_partitions[pidx].offset = offset + ptable->offset; - axis_partitions[pidx].size = ptable->size; - - printk(pmsg, pidx, axis_partitions[pidx].offset, - axis_partitions[pidx].size); - pidx++; - ptable++; - } - use_default_ptable = !ptable_ok; - } - - if (use_default_ptable) { - printk(" Using default partition table\n"); - return add_mtd_partitions(mymtd, axis_default_partitions, - NUM_DEFAULT_PARTITIONS); - } else { - if (romfs_in_flash) { - axis_partitions[pidx].name = "romfs"; - axis_partitions[pidx].size = romfs_length; - axis_partitions[pidx].offset = romfs_start - - FLASH_CACHED_ADDR; - axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; - - printk(" Adding readonly partition for romfs image:\n"); - printk(pmsg, pidx, axis_partitions[pidx].offset, - axis_partitions[pidx].size); - pidx++; - } - return add_mtd_partitions(mymtd, axis_partitions, pidx); - } -} - -/* This adds the above to the kernels init-call chain */ - -module_init(init_axis_flash); - diff --git a/arch/cris/drivers/bluetooth/Makefile b/arch/cris/drivers/bluetooth/Makefile deleted file mode 100644 index b3cbffc6c1a4..000000000000 --- a/arch/cris/drivers/bluetooth/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -include $(APPS)/Rules.elinux - -all: - -install: src/bluetooth.c include/btcommon.h - ln -sfn ../../arch/cris/drivers/bluetooth/include ../../../../include/linux/bluetooth - if ! grep arch/cris/drivers/bluetooth/src/Config.in ../Config.in; then \ - echo '' >> ../Config.in; \ - echo 'if [ "$$CONFIG_ETRAX_SERIAL" = "y" ]; then' >> ../Config.in; \ - echo ' source arch/cris/drivers/bluetooth/src/Config.in' >> ../Config.in; \ - echo 'fi' >> ../Config.in; \ - fi - if ! grep bluetooth/src/bt.o ../Makefile; then \ - perl -pi -e "s:include:obj-\\\$$(CONFIG_BLUETOOTH) += bluetooth/src/bt.o\nsubdir-\\\$$(CONFIG_BLUETOOTH) += bluetooth/src\n\ninclude:" ../Makefile; \ - fi - -clean: - -src/bluetooth.c: - @echo "You must install the OpenBT src directory before install can be done here!" - @exit 1 - -include/btcommon.h: - @echo "You must install the OpenBT include directory before install can be done here!" - @exit 1 diff --git a/arch/cris/drivers/gpio.c b/arch/cris/drivers/gpio.c deleted file mode 100644 index 533e2738c46f..000000000000 --- a/arch/cris/drivers/gpio.c +++ /dev/null @@ -1,460 +0,0 @@ -/* $Id: gpio.c,v 1.2 2001/12/18 13:35:15 bjornw Exp $ - * - * Etrax general port I/O device - * - * Copyright (c) 1999, 2000, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Ola Knutsson (LED handling) - * Johan Adolfsson (read/set directions, write) - * - * $Log: gpio.c,v $ - * Revision 1.2 2001/12/18 13:35:15 bjornw - * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). - * - * Revision 1.12 2001/11/12 19:42:15 pkj - * * Corrected return values from gpio_leds_ioctl(). - * * Fixed compiler warnings. - * - * Revision 1.11 2001/10/30 14:39:12 johana - * Added D() around gpio_write printk. - * - * Revision 1.10 2001/10/25 10:24:42 johana - * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast - * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB - * from ~60 seconds to 4 seconds). - * Added save_flags/cli/restore_flags in ioctl. - * - * Revision 1.9 2001/05/04 14:16:07 matsfg - * Corrected spelling error - * - * Revision 1.8 2001/04/27 13:55:26 matsfg - * Moved initioremap. - * Turns off all LEDS on init. - * Added support for shutdown and powerbutton. - * - * Revision 1.7 2001/04/04 13:30:08 matsfg - * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping - * - * Revision 1.6 2001/03/26 16:03:06 bjornw - * Needs linux/config.h - * - * Revision 1.5 2001/03/26 14:22:03 bjornw - * Namechange of some config options - * - * Revision 1.4 2001/02/27 13:52:48 bjornw - * malloc.h -> slab.h - * - * Revision 1.3 2001/01/24 15:06:48 bjornw - * gpio_wq correct type - * - * Revision 1.2 2001/01/18 16:07:30 bjornw - * 2.4 port - * - * Revision 1.1 2001/01/18 15:55:16 bjornw - * Verbatim copy of etraxgpio.c from elinux 2.0 added - * - * - */ - -#include <linux/config.h> - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/string.h> -#include <linux/poll.h> -#include <linux/init.h> - -#include <asm/etraxgpio.h> -#include <asm/svinto.h> -#include <asm/io.h> -#include <asm/system.h> - -#define GPIO_MAJOR 120 /* experimental MAJOR number */ - -#define D(x) - -static char gpio_name[] = "etrax gpio"; - -#if 0 -static wait_queue_head_t *gpio_wq; -#endif - -static int gpio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static ssize_t gpio_write(struct file * file, const char * buf, size_t count, - loff_t *off); -static int gpio_open(struct inode *inode, struct file *filp); -static int gpio_release(struct inode *inode, struct file *filp); -static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); - -/* private data per open() of this driver */ - -struct gpio_private { - struct gpio_private *next; - volatile unsigned char *port, *shadow; - volatile unsigned char *dir, *dir_shadow; - unsigned char changeable_dir; - unsigned char changeable_bits; - unsigned char highalarm, lowalarm; - unsigned char clk_mask; - unsigned char data_mask; - unsigned char write_msb; - wait_queue_head_t alarm_wq; - int minor; -}; - -/* linked list of alarms to check for */ - -static struct gpio_private *alarmlist = 0; - -#define NUM_PORTS 2 -static volatile unsigned char *ports[2] = { R_PORT_PA_DATA, R_PORT_PB_DATA }; -static volatile unsigned char *shads[2] = { - &port_pa_data_shadow, &port_pb_data_shadow }; - -/* What direction bits that are user changeable 1=changeable*/ -#ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR -#define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00 -#endif -#ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR -#define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00 -#endif - -#ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS -#define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF -#endif -#ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS -#define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF -#endif - - -static unsigned char changeable_dir[2] = { CONFIG_ETRAX_PA_CHANGEABLE_DIR, - CONFIG_ETRAX_PB_CHANGEABLE_DIR }; -static unsigned char changeable_bits[2] = { CONFIG_ETRAX_PA_CHANGEABLE_BITS, - CONFIG_ETRAX_PB_CHANGEABLE_BITS }; - -static volatile unsigned char *dir[2] = { R_PORT_PA_DIR, R_PORT_PB_DIR }; - -static volatile unsigned char *dir_shadow[2] = { - &port_pa_dir_shadow, &port_pb_dir_shadow }; - -#define LEDS 2 - -static unsigned int -gpio_poll(struct file *filp, - struct poll_table_struct *wait) -{ - /* TODO poll on alarms! */ -#if 0 - if (!ANYTHING_WANTED) { - D(printk("gpio_select sleeping task\n")); - select_wait(&gpio_wq, table); - return 0; - } - D(printk("gpio_select ready\n")); -#endif - return 1; -} - -static ssize_t gpio_write(struct file * file, const char * buf, size_t count, - loff_t *off) -{ - struct gpio_private *priv = (struct gpio_private *)file->private_data; - unsigned char data, clk_mask, data_mask, write_msb; - unsigned long flags; - ssize_t retval = count; - if (verify_area(VERIFY_READ, buf, count)) { - return -EFAULT; - } - clk_mask = priv->clk_mask; - data_mask = priv->data_mask; - /* It must have been configured using the IO_CFG_WRITE_MODE */ - /* Perhaps a better error code? */ - if (clk_mask == 0 || data_mask == 0) { - return -EPERM; - } - write_msb = priv->write_msb; - D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); - while (count--) { - int i; - data = *buf++; - if (priv->write_msb) { - for (i = 7; i >= 0;i--) { - save_flags(flags); cli(); - *priv->port = *priv->shadow &= ~clk_mask; - if (data & 1<<i) - *priv->port = *priv->shadow |= data_mask; - else - *priv->port = *priv->shadow &= ~data_mask; - /* For FPGA: min 5.0ns (DCC) before CCLK high */ - *priv->port = *priv->shadow |= clk_mask; - restore_flags(flags); - } - } else { - for (i = 0; i <= 7;i++) { - save_flags(flags); cli(); - *priv->port = *priv->shadow &= ~clk_mask; - if (data & 1<<i) - *priv->port = *priv->shadow |= data_mask; - else - *priv->port = *priv->shadow &= ~data_mask; - /* For FPGA: min 5.0ns (DCC) before CCLK high */ - *priv->port = *priv->shadow |= clk_mask; - restore_flags(flags); - } - } - } - return retval; -} - -static int -gpio_open(struct inode *inode, struct file *filp) -{ - struct gpio_private *priv; - int p = minor(inode->i_rdev); - - if (p >= NUM_PORTS && p != LEDS) - return -EINVAL; - - priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), - GFP_KERNEL); - - if (!priv) - return -ENOMEM; - - priv->minor = p; - - /* initialize the io/alarm struct and link it into our alarmlist */ - - priv->next = alarmlist; - alarmlist = priv; - priv->port = ports[p]; - priv->shadow = shads[p]; - - priv->changeable_dir = changeable_dir[p]; - priv->changeable_bits = changeable_bits[p]; - priv->dir = dir[p]; - priv->dir_shadow = dir_shadow[p]; - - priv->highalarm = 0; - priv->lowalarm = 0; - priv->clk_mask = 0; - priv->data_mask = 0; - init_waitqueue_head(&priv->alarm_wq); - - filp->private_data = (void *)priv; - - return 0; -} - -static int -gpio_release(struct inode *inode, struct file *filp) -{ - struct gpio_private *p = alarmlist; - struct gpio_private *todel = (struct gpio_private *)filp->private_data; - - /* unlink from alarmlist and free the private structure */ - - if (p == todel) { - alarmlist = todel->next; - } else { - while (p->next != todel) - p = p->next; - p->next = todel->next; - } - - kfree(todel); - - return 0; -} - -/* Main device API. ioctl's to read/set/clear bits, as well as to - * set alarms to wait for using a subsequent select(). - */ - -static int -gpio_leds_ioctl(unsigned int cmd, unsigned long arg); - -static int -gpio_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - unsigned long flags; - struct gpio_private *priv = (struct gpio_private *)file->private_data; - if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { - return -EINVAL; - } - - switch (_IOC_NR(cmd)) { - case IO_READBITS: - // read the port - return *priv->port; - case IO_SETBITS: - save_flags(flags); cli(); - // set changeable bits with a 1 in arg - *priv->port = *priv->shadow |= - ((unsigned char)arg & priv->changeable_bits); - restore_flags(flags); - break; - case IO_CLRBITS: - save_flags(flags); cli(); - // clear changeable bits with a 1 in arg - *priv->port = *priv->shadow &= - ~((unsigned char)arg & priv->changeable_bits); - restore_flags(flags); - break; - case IO_HIGHALARM: - // set alarm when bits with 1 in arg go high - priv->highalarm |= (unsigned char)arg; - break; - case IO_LOWALARM: - // set alarm when bits with 1 in arg go low - priv->lowalarm |= (unsigned char)arg; - break; - case IO_CLRALARM: - // clear alarm for bits with 1 in arg - priv->highalarm &= ~(unsigned char)arg; - priv->lowalarm &= ~(unsigned char)arg; - break; - case IO_READDIR: - /* Read direction 0=input 1=output */ - return *priv->dir_shadow; - case IO_SETINPUT: - save_flags(flags); cli(); - /* Set direction 0=unchanged 1=input */ - *priv->dir = *priv->dir_shadow &= - ~((unsigned char)arg & priv->changeable_dir); - restore_flags(flags); - return *priv->dir_shadow; - case IO_SETOUTPUT: - save_flags(flags); cli(); - /* Set direction 0=unchanged 1=output */ - *priv->dir = *priv->dir_shadow |= - ((unsigned char)arg & priv->changeable_dir); - restore_flags(flags); - return *priv->dir_shadow; - case IO_SHUTDOWN: - SOFT_SHUTDOWN(); - break; - case IO_GET_PWR_BT: -#if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) - return (*R_PORT_G_DATA & - ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); -#else - return 0; -#endif - break; - case IO_CFG_WRITE_MODE: - priv->clk_mask = arg & 0xFF; - priv->data_mask = (arg >> 8) & 0xFF; - priv->write_msb = (arg >> 16) & 0x01; - /* Check if we're allowed to change the bits and - * the direction is correct - */ - if (!((priv->clk_mask & priv->changeable_bits) && - (priv->data_mask & priv->changeable_bits) && - (priv->clk_mask & *priv->dir_shadow) && - (priv->data_mask & *priv->dir_shadow))) - { - priv->clk_mask = 0; - priv->data_mask = 0; - return -EPERM; - } - break; - default: - if (priv->minor == LEDS) - return gpio_leds_ioctl(cmd, arg); - else - return -EINVAL; - } - - return 0; -} - -static int -gpio_leds_ioctl(unsigned int cmd, unsigned long arg) -{ - unsigned char green; - unsigned char red; - - switch (_IOC_NR(cmd)) { - case IO_LEDACTIVE_SET: - green = ((unsigned char) arg) & 1; - red = (((unsigned char) arg) >> 1) & 1; - LED_ACTIVE_SET_G(green); - LED_ACTIVE_SET_R(red); - break; - - case IO_LED_SETBIT: - LED_BIT_SET(arg); - break; - - case IO_LED_CLRBIT: - LED_BIT_CLR(arg); - break; - - default: - return -EINVAL; - } - - return 0; -} - -struct file_operations gpio_fops = { - .owner = THIS_MODULE, - .poll = gpio_poll, - .ioctl = gpio_ioctl, - .write = gpio_write, - .open = gpio_open, - .release = gpio_release, -}; - -/* main driver initialization routine, called from mem.c */ - -static __init int -gpio_init(void) -{ - extern void init_ioremap(void); - int res; -#if defined (CONFIG_ETRAX_CSP0_LEDS) - int i; -#endif - - /* do the formalities */ - - res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); - if (res < 0) { - printk(KERN_ERR "gpio: couldn't get a major number.\n"); - return res; - } - - /* Clear all leds */ -#if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) - init_ioremap(); - LED_NETWORK_SET(0); - LED_ACTIVE_SET(0); - LED_DISK_READ(0); - LED_DISK_WRITE(0); - -#if defined (CONFIG_ETRAX_CSP0_LEDS) - for (i = 0; i < 32; i++) { - LED_BIT_SET(i); - } -#endif - -#endif - - printk("ETRAX 100LX GPIO driver v2.2, (c) 2001 Axis Communications AB\n"); - - return res; -} - -/* this makes sure that gpio_init is called during kernel boot */ - -module_init(gpio_init); diff --git a/arch/cris/drivers/ide.c b/arch/cris/drivers/ide.c deleted file mode 100644 index 89ae840968e8..000000000000 --- a/arch/cris/drivers/ide.c +++ /dev/null @@ -1,877 +0,0 @@ -/* $Id: ide.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw 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, 2001 Axis Communications AB - * - * Authors: Bjorn Wesen (initial version) - * Mikael Starvik (pio setup stuff) - * - * $Log: ide.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 - * - * Revision 1.19 2001/05/09 12:53:16 johana - * Added #include <asm/dma.h> - * - * Revision 1.18 2001/05/09 12:37:00 johana - * Use DMA_NBR macros from dma.h. - * - * Revision 1.17 2001/04/23 13:36:30 matsfg - * Changed CONFIG_IDE_DELAY to CONFIG_ETRAX_IDE_DELAY - * - * Revision 1.16 2001/04/05 08:30:07 matsfg - * Corrected cse1 and csp0 reset. - * - * Revision 1.15 2001/04/04 14:34:06 bjornw - * Re-instated code that mysteriously disappeared during review updates. - * - * Revision 1.14 2001/04/04 13:45:12 matsfg - * Calls REG_SHADOW_SET for cse1 reset so only the resetbit is affected - * - * Revision 1.13 2001/04/04 13:26:40 matsfg - * memmapping is done in init.c - * - * Revision 1.12 2001/04/04 11:37:56 markusl - * Updated according to review remarks - * - * Revision 1.11 2001/03/29 12:49:14 matsfg - * Changed check for ata_tot_size from >= to >. - * Sets sw_len to 0 if size is exactly 65536. - * - * Revision 1.10 2001/03/16 09:39:30 matsfg - * Support for reset on port CSP0 - * - * Revision 1.9 2001/03/01 13:11:18 bjornw - * 100 -> HZ - * - * Revision 1.8 2001/03/01 09:32:56 matsfg - * Moved IDE delay to a CONFIG-parameter instead - * - * Revision 1.7 2001/02/23 13:46:38 bjornw - * Spellling check - * - * Revision 1.6 2001/02/22 15:44:30 bjornw - * * Use ioremap when mapping the CSE1 memory-mapped reset-line for LX v2 - * * sw_len for a 65536 descriptor is 0, not 65536 - * * Express concern for G27 reset code - * - * Revision 1.5 2001/02/16 07:35:38 matsfg - * Now handles DMA request blocks between 64k and 128k by split into two descriptors. - * - * Revision 1.4 2001/01/10 21:14:32 bjornw - * Initialize hwif->ideproc, for the new way of handling ide_xxx_data - * - * Revision 1.3 2000/12/01 17:48:18 bjornw - * - atapi_output_bytes now uses DMA - * - dma_active check removed - the kernel does proper serializing and it had - * a race-condition anyway - * - ide_build_dmatable had a nameclash - * - re-added the RESET_DMA thingys because sometimes the interface can get - * stuck apparently - * - added ide_release_dma - * - * Revision 1.2 2000/11/29 17:31:29 bjornw - * 2.4 port - * - * - The "register addresses" stored in the hwif are now 32-bit fields that - * don't need to be shifted into correct positions in R_ATA_CTRL_DATA - * - PIO-mode detection temporarily disabled since ide-modes.c is not compiled - * - All DMA uses virt_to_phys conversions for DMA buffers and descriptor ptrs - * - Probably correct ide_dma_begin semantics in dmaproc now for ATAPI devices - * - Removed RESET_DMA when starting a new transfer - why was this necessary ? - * - Indentation fix - * - * - */ - -/* 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. - */ - -#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/svinto.h> -#include <asm/dma.h> - -/* number of Etrax DMA descriptors */ -#define MAX_DMA_DESCRS 64 - -#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 - -#define LOWDB(x) -#define D(x) - -void OUT_BYTE(unsigned char data, ide_ioreg_t reg) { - LOWDB(printk("ob: data 0x%x, reg 0x%x\n", data, reg)); - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ - *R_ATA_CTRL_DATA = reg | data; /* write data to the drive's register */ - while(!(*R_ATA_STATUS_DATA & - IO_MASK(R_ATA_STATUS_DATA, tr_rdy))); /* wait for transmitter ready */ -} - -unsigned char IN_BYTE(ide_ioreg_t reg) { - int status; - while(*R_ATA_STATUS_DATA & IO_MASK(R_ATA_STATUS_DATA, busy)); /* wait for busy flag */ - *R_ATA_CTRL_DATA = reg | IO_STATE(R_ATA_CTRL_DATA, rw, read); /* read data */ - while(!((status = *R_ATA_STATUS_DATA) & - IO_MASK(R_ATA_STATUS_DATA, dav))); /* wait for available */ - LOWDB(printk("inb: 0x%x from reg 0x%x\n", status & 0xff, reg)); - return (unsigned char)status; /* data was in the lower 16 bits in the status 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_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq); -static void e100_ideproc (ide_ide_action_t func, struct ata_device *drive, - void *buffer, unsigned int length); - -/* - * 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(struct ata_device *drive, byte pio) -{ - unsigned long flags; - - pio = 4; - /* pio = ide_get_best_pio_mode(drive, pio, 4, NULL); */ - - save_flags(flags); - cli(); - - /* 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; - } - restore_flags(flags); -} - -void __init -init_e100_ide (void) -{ - volatile unsigned int dummy; - int h; - - printk("ide: ETRAX 100LX built-in ATA DMA controller\n"); - - /* first initialize the channel interface data */ - - for(h = 0; h < MAX_HWIFS; h++) { - struct ata_channel *hwif = &ide_hwifs[h]; - - hwif->chipset = ide_etrax100; - hwif->tuneproc = &tune_e100_ide; - hwif->udma = &e100_dmaproc; - hwif->ata_read = e100_ide_input_data; - hwif->ata_write = e100_ide_output_data; - hwif->atapi_read = e100_atapi_read; - hwif->atapi_write = e100_atapi_write; - } - /* actually reset and configure the etrax100 ide/ata interface */ - - /* This is mystifying; why is not G27 SET anywhere ? It's just reset here twice. */ - - /* de-assert bus-reset */ -#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 -#ifdef CONFIG_ETRAX_IDE_G27_RESET - *R_PORT_G_DATA = 0; -#endif - - *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; - -#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET - init_ioremap(); - REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, 0); -#endif - -#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET - init_ioremap(); - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, 0); -#endif - - /* wait some */ - udelay(25); - -#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 - *R_PORT_G_DATA = 0; /* de-assert bus-reset */ -#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)) ; - - /* 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 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_read(struct ata_device *drive, void *buffer, unsigned int bytecount) -{ - ide_ioreg_t data_reg = IDE_DATA_REG; - - D(printk("atapi_read, 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_write(struct ata_device *drive, void *buffer, unsigned int bytecount) -{ - ide_ioreg_t data_reg = IDE_DATA_REG; - - D(printk("atapi_write, 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 succesful 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 (struct ata_device *drive, void *buffer, unsigned int wcount) -{ - e100_atapi_read(drive, buffer, wcount << 2); -} - -/* - * This is used for most PIO data transfers *to* the IDE interface - */ -static void -e100_ide_output_data (struct ata_device *drive, void *buffer, unsigned int wcount) -{ - e100_atapi_write(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; - - -/* - * This prepares a dma request. Returns 0 if all went okay, returns 1 - * otherwise. - */ - -static int e100_udma_new_table(struct ata_channel *ch, struct request *rq) -{ - struct buffer_head *bh = rq->bh; - unsigned long size, addr; - unsigned int count = 0; - - ata_tot_size = 0; - - do { - /* - * 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. - */ - if (bh == NULL) { /* paging and tape requests have (rq->bh == NULL) */ - addr = virt_to_phys (rq->buffer); - size = rq->nr_sectors << 9; - } else { - /* group sequential buffers into one large buffer */ - addr = virt_to_phys (bh->b_data); - size = bh->b_size; - while ((bh = bh->b_reqnext) != NULL) { - if ((addr + size) != virt_to_phys (bh->b_data)) - break; - size += bh->b_size; - } - } - - /* did we run out of descriptors? */ - - if(count >= MAX_DMA_DESCRS) { - printk("%s: too few DMA descriptors\n", ch->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, 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; - - } while (bh != NULL); - - 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", ch->name); - return 1; /* let the PIO routines handle this weirdness */ -} - -static int config_drive_for_dma (struct ata_device *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(struct ata_device *drive, struct request *rq) -{ - int i, dma_stat; - - LED_DISK_READ(0); - LED_DISK_WRITE(0); - - dma_stat = drive->channel->udma(ide_dma_end, drive, rq); - /* get drive status */ - if (ata_status(drive, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) { - if (!dma_stat) { - for (i = rq->nr_sectors; i > 0;) { - i -= rq->current_nr_sectors; - ide_end_request(drive, rq, 1); - } - return ATA_OP_FINISHED; - } - printk("%s: bad DMA status\n", drive->name); - } - return ata_error(drive, rq, __FUNCTION__); -} - -/* - * e100_dmaproc() 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_dmaproc(ide_dma_action_t func, struct ata_device *drive, struct request *rq) -{ - static unsigned int reading; /* static to support ide_dma_begin semantics */ - int atapi = 0; - - D(printk("e100_dmaproc func %d\n", func)); - - switch (func) { - case ide_dma_verbose: - return 0; - case ide_dma_check: - return config_drive_for_dma (drive); - case ide_dma_off: - case ide_dma_off_quietly: - /* ok.. we don't really need to do anything I think. */ - return 0; - case ide_dma_write: - reading = 0; - break; - case ide_dma_read: - reading = 1; - break; - case ide_dma_begin: - /* 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. - */ - atapi++; - goto dma_begin; - case ide_dma_end: /* returns 1 on error, 0 otherwise */ - /* TODO: check if something went wrong with the DMA */ - return 0; - - default: - printk("e100_dmaproc: unsupported func %d\n", func); - return 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->type != ATA_DISK) - return 0; - - dma_begin: - - 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_udma_new_table(drive->channel, rq)) - return 1; - - if(!atapi) { - /* set the irq handler which will finish the request when DMA is done */ - ata_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); - - /* issue cmd to drive */ - OUT_BYTE(WIN_READDMA, IDE_COMMAND_REG); - } - - /* begin DMA */ - *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_udma_new_table(drive->channel, rq)) - return 1; - - if(!atapi) { - /* set the irq handler which will finish the request when DMA is done */ - ata_set_handler(drive, &etrax_dma_intr, WAIT_CMD, NULL); - - /* issue cmd to drive */ - OUT_BYTE(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)); - } - - /* DMA started successfully */ - return 0; -} - -/* ide.c calls this, but we don't need to do anything particular */ - -/* Dear maintainer of this architecture please note that it would be a little - * more clever :-) to put this up into some header as static inline, so the - * spurious code below would just vanish. - * - * --- Marcin Dalecki - */ - -void ide_release_dma(struct ata_channel *ch) -{ - /* empty */ -} diff --git a/arch/cris/drivers/lpslave/Makefile b/arch/cris/drivers/lpslave/Makefile deleted file mode 100644 index 6d7982db01e8..000000000000 --- a/arch/cris/drivers/lpslave/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Makefile for parallel port slave drivers -# - -obj-y = e100lpslavenet.o e100lpslave_code.o - -e100lpslave_code.o: e100lpslave.o e100lpslaveld - $(CROSS_COMPILE)ld -qmagic -Te100lpslaveld e100lpslave.o -o e100lpslave - $(CROSS_COMPILE)objcopy -O binary --remove-section=.data --remove-section=.bss e100lpslave e100lpslave.text - $(CROSS_COMPILE)objcopy -O binary --remove-section=.text --remove-section=.bss e100lpslave e100lpslave.data - cat e100lpslave.text e100lpslave.data |\ - ./bintocarr.pl e100lpslaveprog |\ - $(CC) $(CFLAGS) -pipe -o e100lpslave_code.o -c -x c - - ls -l e100lpslave.text e100lpslave.data - rm -f e100lpslave e100lpslave.text e100lpslave.data diff --git a/arch/cris/drivers/lpslave/bintocarr.pl b/arch/cris/drivers/lpslave/bintocarr.pl deleted file mode 100644 index c03dd8b718b7..000000000000 --- a/arch/cris/drivers/lpslave/bintocarr.pl +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/perl -w -# $Id: bintocarr.pl,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ -# Copy of mkjulbin.pl made by Olof -# convert a binary stdin to a C-file containing a char array of the input -# first argument is the symbol name - -$symbol = shift @ARGV; - -print "#include <linux/init.h>\n\n"; -#print "unsigned char $symbol", "[] __initdata = {\n"; -print "unsigned char $symbol", "[] = {\n"; - -my $char; - -$bcount = 0; - -while(read STDIN, $char, 1) { - printf("0x%x, ", ord($char)); - $bcount++; - if(!($bcount % 16)) { - print "\n"; - } -} - -print "\n};\n"; - -$lensymb = ("_" . ($symbol . "_length")); - -print "__asm__(\"\\t.globl $lensymb\\n$lensymb = $bcount\\n\");\n"; - diff --git a/arch/cris/drivers/lpslave/e100lpslave.README b/arch/cris/drivers/lpslave/e100lpslave.README deleted file mode 100644 index eb580a9d2dac..000000000000 --- a/arch/cris/drivers/lpslave/e100lpslave.README +++ /dev/null @@ -1,54 +0,0 @@ -***** MODIFICATIONS -To use a 5600 as a slave device it has to somewhat modified. -This has to be done on a 5600 (art no 16144 R2) to automatically set it to parallel port boot mode: - -1) -Close to the LPT1 connector there are two resistors, between the "Pulse" inductor and -the LS245. The one closest to the LS245 is a 4k7 pull up (R105). Remove it. - -2) -Between the other "Pulse" inductor and Etrax there is a black 5-pin inverter -(D15). Short connectors 2 and 3 with a solder blob. - - -***** PINOUT -To use this driver use cables connected like this: -DSUB25-Male DSUB25Male - -1 10 -2-9 2-9 -10 1 -11 14 -12 18 -13 NC -14 11 -15 NC -16 NC -17 NC -18 12 -19 NC -20-25 20-25 - -Thus the cables are symmetrical with most cables straight through, -some crossed (1-10, 11-14 and 12-18) -and some Not connected (NC 13,15,16,17 and 19). - - -******* Only for reference -To ease the use of flat-cable connectors, here are the notes of wich wires to cross and cut with pin 1 being cable 1: -Cross: -1 19 -2 21 -10 23 -Cut: -4 -6 -8 -12 -25 - -jonas.dellenvall@axis.com - - - - diff --git a/arch/cris/drivers/lpslave/e100lpslave.S b/arch/cris/drivers/lpslave/e100lpslave.S deleted file mode 100644 index 44efe0771fc2..000000000000 --- a/arch/cris/drivers/lpslave/e100lpslave.S +++ /dev/null @@ -1,429 +0,0 @@ - ;; $Id: e100lpslave.S,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ - ;; - ;; Etrax100 slave network<->parport forwarder - ;; - ;; Copyright (c) 1999 Bjorn Wesen, Axis Communications AB - ;; - ;; We got 784 bytes (par loader size) to do DMA forwarding - ;; between DMA0/1 (ethernet) and DMA3/4 (par port 0 RX/1 TX) - ;; - -#include <linux/config.h> -#if 0 -#define ASSEMBLER_MACROS_ONLY -#endif -#include <asm/sv_addr_ag.h> - -#define BUFSIZE 0x600 - - ;; R_IRQ_READ2 - -#define DMA1EOPBIT 3 -#define DMA0EOPBIT 1 -#define DMA3EOPBIT 7 -#define DMA4DESCBIT 8 - - ;; R_IRQ_READ0 - -#define PAR0ECPCMDBIT 11 - - ;; get host CMDs - -#include "e100lpslave.h" - -start: - ;; disable interrupts. we are not going to use them at all. - - di - - ;; setup DMA connections and port configuration - - movu.w 0x84, r0 ; DMA2/3/4/5 to par ports - move.d r0, [R_GEN_CONFIG] - - ;; setup port PA dirs and turn on the LED to show were alive - - movu.w 0x0cfb, r0 ; PA2-PA3 out, PA2 inactive - move.d r0, [R_PORT_PA_SET] - - ;; enable MDIO output pin - moveq IO_STATE(R_NETWORK_MGM_CTRL, mdoe, enable), r0 - move.d r0, [R_NETWORK_MGM_CTRL] - - ;; accept broadcast frames, and enable station address 0 - moveq IO_STATE(R_NETWORK_REC_CONFIG, broadcast, receive) | \ - IO_STATE(R_NETWORK_REC_CONFIG, ma0, enable), r0 - move.d r0, [R_NETWORK_REC_CONFIG] - - ;; use MII CLK mode, and enable the controller - moveq IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | \ - IO_STATE(R_NETWORK_GEN_CONFIG, enable, on), r0 - move.d r0, [R_NETWORK_GEN_CONFIG] - - move.d IO_STATE(R_PAR0_CONFIG, ioe, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iseli, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | \ - IO_STATE(R_PAR0_CONFIG, istrb, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iinit, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iperr, noninv) | \ - IO_STATE(R_PAR0_CONFIG, iack, noninv) | \ - IO_STATE(R_PAR0_CONFIG, ibusy, noninv) | \ - IO_STATE(R_PAR0_CONFIG, ifault, noninv) | \ - IO_STATE(R_PAR0_CONFIG, isel, noninv) | \ - IO_STATE(R_PAR0_CONFIG, dma, enable) | \ - IO_STATE(R_PAR0_CONFIG, rle_in, disable) | \ - IO_STATE(R_PAR0_CONFIG, rle_out, disable) | \ - IO_STATE(R_PAR0_CONFIG, enable, on) | \ - IO_STATE(R_PAR0_CONFIG, force, on) | \ - IO_STATE(R_PAR0_CONFIG, mode, ecp_rev), r0 ; Reverse ECP - PAR0 is RX - - move.d r0, [R_PAR0_CONFIG] - - move.d IO_STATE(R_PAR1_CONFIG, ioe, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iseli, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iautofd, noninv) | \ - IO_STATE(R_PAR1_CONFIG, istrb, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iinit, noninv) | \ - IO_STATE(R_PAR1_CONFIG, iperr, inv) | \ - IO_STATE(R_PAR1_CONFIG, iack, noninv) | \ - IO_STATE(R_PAR1_CONFIG, ibusy, noninv) | \ - IO_STATE(R_PAR1_CONFIG, ifault, noninv) | \ - IO_STATE(R_PAR1_CONFIG, isel, noninv) | \ - IO_STATE(R_PAR1_CONFIG, dma, enable) | \ - IO_STATE(R_PAR1_CONFIG, rle_in, disable) | \ - IO_STATE(R_PAR1_CONFIG, rle_out, disable) | \ - IO_STATE(R_PAR1_CONFIG, enable, on) | \ - IO_STATE(R_PAR1_CONFIG, force, on) | \ - IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd), r0 ; Forward ECP - PAR1 is TX - - move.d r0, [R_PAR1_CONFIG] - - moveq IO_FIELD(R_PAR1_DELAY, setup, 0), r0 ; setup time of value * 160 + 20 == 20 ns - move.d r0, [R_PAR1_DELAY] - - ;; we got four descriptors, that can be active at the same time: - ;; 1) from network - ;; 2) to parport - ;; 3) from parport - ;; 4) to network - ;; - ;; we got four buffers, each can hold a max packet (we use 1536 bytes) - ;; buffers 1 and 2 are used from network to parport, while - ;; buffers 3 and 4 are used from parport to network. - ;; - ;; a double buffering scheme is used, so that new data can be read - ;; into a buffer pair while the last data is written out from the - ;; last buffer. if the read buffer is done before the write buffer, - ;; the reading will halt until the writing is done, at which point - ;; writing starts from the newly read and reading can start with - ;; the newly written. - ;; - - move.d R_DMA_CH0_FIRST, r1 ; we use this as base for subsequent DMA ops - moveq IO_STATE(R_DMA_CH1_CMD, cmd, start), r6 - move.d FN1desc, r7 - move.d R_IRQ_READ0, r9 - - ;; start receiving from network - - jsr startdmaFPTN - jsr startdmaFNTP - - - - ;; ------------------- MAIN LOOP - - ;; IRQ bits: parport rcv is par0_ecp_cmd, then dma3_eop - ;; network rcv is dma1_eop - ;; parport tx is dma4_desc - ;; network tx is dma0_eop - -mainloop: - - ;; ------- first handle the parport -> network link - - ;; check if we got something from the parport - - move.d [r9], r0 ; r0 <- *R_IRQ_READ0 - btstq PAR0ECPCMDBIT, r0 - bpl noparecp - nop - - ;; ack it by reading PAR0_STATUS_DATA - - move.d [R_PAR0_STATUS_DATA], r0 - - ;; trigger EOP on DMA3 (par0 incoming channel) - - moveq IO_STATE(R_SET_EOP, ch3_eop, set), r0 - move.d r0, [R_SET_EOP] - -noparecp: - - ;; if we simultaneously have parport rx EOP and - ;; network TX eop, we can swap buffers and start a new RX/TX - - move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0 - btstq DMA3EOPBIT, r0 ; check parport rx - bpl noswap1 - btstq DMA0EOPBIT, r0 ; check network tx - bpl noswap1 - nop - - ;; prepare to swap buffer ptrs (FN3b <-> TN4b) - - move.d [r4 = r7 + 56], r0; FP3b - move.d [r3 = r7 + 72], r2; TN4b - - ;; but first check if this was a Host Command Packet - - move.d [r0], r5 ; r5 <- first 4 bytes in PAR-received packet - bne handle_command ; if non-zero, it was a host command - addq 4, r0 ; skip command (in delay slot - handle_command requires this) - move.d r0, [r3] ; write to To Network descriptor - subq 4, r2 ; undo the skipping done last swap - move.d r2, [r4] ; write to From Parport descriptor - - ;; clear the interrupts - - moveq IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do), r0 - move.b r0, [r1 + (R_DMA_CH0_CLR_INTR - R_DMA_CH0_FIRST)] - move.b r0, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)] - - ;; copy received length to outgoing network length - - move.w [r7 + 60], r0 ; FPhlen - subq 4, r0 ; skip command - move.w r0, [r7 + 64] ; TN4desc - - ;; restart DMAs - - jsr startdmaFPTN - -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS -#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) - ;; Turn off the LED signaling an outgoing network packet - movu.b [LEDOff], r0 -#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) - ;; Light the LED signaling an outgoing network packet - movu.b [LEDAmber], r0 -#else -#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" -#endif - move.b r0, [R_PORT_PA_DATA] - move.d 0x00011000, r0 - move.d r0,[LEDCount] -#endif - -noswap1: - ;; ----- now check the network -> parport link - - - ;; if we simultaneously have network rx EOP and - ;; parport TX desc, we can swap buffers and start a new RX/TX - - move.d [r9 + (R_IRQ_READ2 - R_IRQ_READ0)], r0 - btstq DMA1EOPBIT, r0 ; check network rx - bpl noswap2 - btstq DMA4DESCBIT, r0 ; check parport tx - bpl noswap2 - nop - - ;; prepare to swap buffer ptrs (FP1b <-> TP2b) - - move.d [r4 = r7 + 8], r0; FN1b - move.d [r3 = r7 + 24], r2; TP2b - move.d r0, [r3] ; write to To Parport descriptor - move.d r2, [r4] ; write to From Network descriptor - - ;; clear the interrupts - - moveq IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do) | \ - IO_STATE(R_DMA_CH1_CLR_INTR, clr_descr, do), r0 - move.b r0, [r1 + (R_DMA_CH1_CLR_INTR - R_DMA_CH0_FIRST)] - move.b r0, [r1 + (R_DMA_CH4_CLR_INTR - R_DMA_CH0_FIRST)] - - ;; copy received network length to outgoing parport length - - move.w [r7 + 12], r0 ; FNhlen - move.w r0, [r7 + 16] ; TP2desc - - ;; restart DMAs - - jsr startdmaFNTP -#if 0 -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - ;; Light the LED signaling an incoming networkpacket - movu.b 0xFB, r0 - move.b r0, [R_PORT_PA_DATA] - move.d 0x00010000, r0 - move.d r0,[LEDCount] -#endif -#endif - -noswap2: -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS - - ;; Count down LED counter, and turn off the network LED if required - move.d [LEDCount], r0 - beq mainloop - nop - - subq 1, r0 - move.d r0, [LEDCount] - bne mainloop - nop - -#if defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK) - ;; Light the network LED , and start over the main loop - movu.b [LEDAmber], r0 -#elif defined(CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY) - ;; Turn off the network LED, and start over the main loop - movu.b [LEDOff], r0 -#else -#error "Define either CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK or CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY" -#endif - move.b r0, [R_PORT_PA_DATA] -#endif - - ba mainloop - nop - - ;; --- some useful subroutines. - -handle_command: - ;; handle command. we also need to clear the PAR0 RX EOP IRQ, and - ;; restart the PAR0 dma. command is in R5, packet after cmd is in R0 - - moveq IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do), r2 - move.b r2, [r1 + (R_DMA_CH3_CLR_INTR - R_DMA_CH0_FIRST)] - - cmpq HOST_CMD_SETMAC, r5 - bne no_setmac - nop - - ;; copy station address (6 bytes) from packet to hardware - - move.d [r0+], r2 - move.d R_NETWORK_SA_0, r3 - move.d r2, [r3] - move.w [r0], r2 - move.w r2, [r3 + 4] - -no_setmac: - move noswap1, SRP - ba startdmaFP - nop - - ;; start DMAs, from parport and to network - -startdmaFPTN: - - ;; start transmitting to the network (CH0) - - move.d TN4desc, r8 - move.d r8, [r1] ; TN4desc -> FIRST0 - move.b r6, [r1 + (R_DMA_CH0_CMD - R_DMA_CH0_FIRST)] ; start -> CMD0 - -startdmaFP: - - ;; start receiving from parport (CH3) - - move.d FP3desc, r8 - move.d r8, [r1 + (R_DMA_CH3_FIRST - R_DMA_CH0_FIRST)] ; FP3desc -> FIRST3 - move.b r6, [r1 + (R_DMA_CH3_CMD - R_DMA_CH0_FIRST)] ; start -> CMD3 - - ret - nop - - ;; start DMAs, from network and to parport - -startdmaFNTP: - - ;; start transmitting to the parport (CH4) - - move.d TP2desc, r8 - move.d r8, [r1 + (R_DMA_CH4_FIRST - R_DMA_CH0_FIRST)] ; TP2desc -> FIRST4 - move.b r6, [r1 + (R_DMA_CH4_CMD - R_DMA_CH0_FIRST)] ; start -> CMD4 - - ;; start receiving from network (CH1) (r7 already contains FN1desc) - - move.d r7, [r1 + (R_DMA_CH1_FIRST - R_DMA_CH0_FIRST)] ; FN1desc -> FIRST1 - move.b r6, [r1 + (R_DMA_CH1_CMD - R_DMA_CH0_FIRST)] ; start -> CMD1 - - ret - nop - - ;; --- DMA descriptors - each descriptor is 4 longwords (16 bytes) - ;; DONT MOVE THESE AROUND. Due to the as/ld "hole-in-the-head", - ;; we cant write stuff like (TP2b - TP2desc) but the offsets - ;; have to be hardcoded. - - .data - - ;; 0 from network -FN1desc: - .word BUFSIZE ; sw_len - .word 0x0001 ; ctrl, d_eol is only flag we need - .dword 0 ; next -FN1b: .dword buffers ; buffer 1 8 - .word 0 ; hw_len - .word 0 ; status - - ;; 16 to parport -TP2desc: - .word 2 ; sw_len, filled in by code - .word 0x0004 ; ctrl, d_wait because ecp cmd in next - .dword TP2desc2 ; next -TP2b: .dword buffers + BUFSIZE ; buffer 2 24 - .word 0 ; hw_len - .word 0 ; status - - ;; 32 to parport second descriptor, for the ECP command -TP2desc2: - .word 0x0001 ; sw_len, 1 byte (ecp command) - .word 0x0019 ; ctrl, d_ecp | d_eol | d_int - .dword 0 ; next - .dword TP2desc2 ; buffer, dont care - .word 0 ; hw_len - .word 0 ; status - - ;; 48 from parport -FP3desc: - .word BUFSIZE ; sw_len - .word 0x0001 ; ctrl, d_eol is only flag we need - .dword 0 ; next -FP3b: .dword buffers + BUFSIZE * 2 ; 56 buffer 3 -FPhlen: .word 0 ; 60 hw_len - .word 0 ; status - - ;; 64 to network -TN4desc: - .word 2 ; sw_len, filled in by code - .word 0x0007 ; ctrl, d_eop | d_eol | d_wait - .dword 0 ; next -TN4b: .dword buffers + BUFSIZE * 3 + 4 ; 72 buffer 4 (the +4 is to offset the anti-skipping) - .word 0 ; hw_len - .word 0 ; status - -#ifdef CONFIG_ETRAX_ETHERNET_LPSLAVE_HAS_LEDS -LEDCount: - .dword 0 -LEDOff: - .word 0xff -LEDGreen: - .word 0xfb -LEDRed: - .word 0xf7 -LEDAmber: - .word 0xf3 -LED: - .word 0xf7 -#endif - - ;; after the prog we put the buffers. not in the asm program, we just use - ;; the address generated - -buffers: - - ;; END diff --git a/arch/cris/drivers/lpslave/e100lpslave.h b/arch/cris/drivers/lpslave/e100lpslave.h deleted file mode 100644 index 7c9cfd91e365..000000000000 --- a/arch/cris/drivers/lpslave/e100lpslave.h +++ /dev/null @@ -1,2 +0,0 @@ -#define HOST_CMD_SENDPACK 0 -#define HOST_CMD_SETMAC 1 diff --git a/arch/cris/drivers/lpslave/e100lpslaveld b/arch/cris/drivers/lpslave/e100lpslaveld deleted file mode 100644 index 4d51ff40ef65..000000000000 --- a/arch/cris/drivers/lpslave/e100lpslaveld +++ /dev/null @@ -1,22 +0,0 @@ -MEMORY - { - cache : ORIGIN = 0x380000f0, - LENGTH = 784 - } - -SECTIONS -{ - .text : - { - *(.text) - } > cache - .data : - { - *(.data) - *(COMMON) - } > cache - .bss : - { - *(.bss) - } > cache -} diff --git a/arch/cris/drivers/lpslave/e100lpslavenet.c b/arch/cris/drivers/lpslave/e100lpslavenet.c deleted file mode 100644 index 29e98e46c321..000000000000 --- a/arch/cris/drivers/lpslave/e100lpslavenet.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* $Id: e100lpslavenet.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ - * - * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller. - * - * Copyright (c) 1998-2001 Axis Communications AB. - * - * The outline of this driver comes from skeleton.c. - * - * $Log: e100lpslavenet.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 - * - * Revision 1.4 2001/06/21 16:55:26 olof - * Minimized par port setup time to gain bandwidth - * - * Revision 1.3 2001/06/21 15:49:02 olof - * Removed setting of default MAC address - * - * Revision 1.2 2001/06/11 15:39:52 olof - * Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave. - * - * Revision 1.1 2001/06/06 08:56:26 olof - * Added support for slave Etrax defined by CONFIG_ETRAX_ETHERNET_LPSLAVE - * - */ - -#include <linux/config.h> - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/interrupt.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/spinlock.h> -#include <linux/errno.h> -#include <linux/init.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#include <asm/svinto.h> /* DMA and register descriptions */ -#include <asm/io.h> /* LED_* I/O functions */ -#include <asm/irq.h> -#include <asm/dma.h> -#include <asm/system.h> -#include <asm/bitops.h> - -#include "e100lpslave.h" - -/* #define ETHDEBUG */ -#define D(x) - -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ - -static const char* cardname = "Etrax 100LX ethernet slave controller"; - -/* A default ethernet address. Highlevel SW will set the real one later */ - -static struct sockaddr default_mac = { - 0, - { 0x00, 0x40, 0x8C, 0xCD, 0x00, 0x00 } -}; - -/* Information that need to be kept for each board. */ -struct net_local { - struct net_device_stats stats; - - /* Tx control lock. This protects the transmit buffer ring - * state along with the "tx full" state of the driver. This - * means all netif_queue flow control actions are protected - * by this lock as well. - */ - spinlock_t lock; -}; - -/* Dma descriptors etc. */ - -#define RX_BUF_SIZE 32768 -#define ETHER_HEAD_LEN 14 - -#define PAR0_ECP_IRQ_NBR 4 - -#define RX_DESC_BUF_SIZE 256 -#define NBR_OF_RX_DESC (RX_BUF_SIZE / \ - RX_DESC_BUF_SIZE) - -/* Size of slave etrax boot image */ -#define ETRAX_PAR_BOOT_LENGTH 784 - -static etrax_dma_descr *myNextRxDesc; /* Points to the next descriptor to - to be processed */ -static etrax_dma_descr *myLastRxDesc; /* The last processed descriptor */ -static etrax_dma_descr *myPrevRxDesc; /* The descriptor right before myNextRxDesc */ - -static unsigned char RxBuf[RX_BUF_SIZE]; - -static etrax_dma_descr RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned(4))); -static etrax_dma_descr TxDescList[3] __attribute__ ((aligned(4))); - /* host command, data, bogus ECP command */ - -static struct sk_buff *tx_skb; - -/* Index to functions, as function prototypes. */ - -static int etrax_ethernet_lpslave_init(struct net_device *dev); - -static int e100_open(struct net_device *dev); -static int e100_set_mac_address(struct net_device *dev, void *addr); -static int e100_send_packet(struct sk_buff *skb, struct net_device *dev); -static void e100rx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100tx_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void ecp_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static void e100_rx(struct net_device *dev); -static int e100_close(struct net_device *dev); -static struct net_device_stats *e100_get_stats(struct net_device *dev); -static void set_multicast_list(struct net_device *dev); -static void e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length); -static void update_rx_stats(struct net_device_stats *); -static void update_tx_stats(struct net_device_stats *); -static void e100_reset_transceiver(void); - -static void boot_slave(unsigned char *code); - -#ifdef ETHDEBUG -static void dump_parport_status(void); -#endif - -#define tx_done(dev) (*R_DMA_CH0_CMD == 0) - -static unsigned long host_command; -extern unsigned char e100lpslaveprog; - -/* - * This driver uses PAR0 to recevice data from slave ETRAX and PAR1 to boot - * and send data to slave ETRAX. - * Used ETRAX100 DMAchannels with corresponding IRQ: - * PAR0 RX : DMA3 - IRQ 19 - * PAR1 TX : DMA4 - IRQ 20 - * IRQ 4 is used to detect ECP commands from slave ETRAX - * - * NOTE! PAR0 and PAR1 shares DMA and IRQ numbers with SER2 and SER3 - */ - - -/* - * Check for a network adaptor of this type, and return '0' if one exists. - * If dev->base_addr == 0, probe all likely locations. - * If dev->base_addr == 1, always return failure. - * If dev->base_addr == 2, allocate space for the device and return success - * (detachable devices only). - */ -static int __init -etrax_ethernet_lpslave_init(void) -{ - struct net_device *dev; - int i, err; - int anOffset = 0; - - printk("Etrax/100 lpslave ethernet driver v0.3, (c) 1999 Axis Communications AB\n"); - - dev = alloc_etherdev(sizeof(struct net_lock)); - if (!dev) - return -ENOMEM; - - dev->base_addr = 2; - - /* now setup our etrax specific stuff */ - - dev->irq = DMA3_RX_IRQ_NBR; /* we really use DMATX as well... */ - dev->dma = PAR0_RX_DMA_NBR; - - /* fill in our handlers so the network layer can talk to us in the future */ - - dev->open = e100_open; - dev->hard_start_xmit = e100_send_packet; - dev->stop = e100_close; - dev->get_stats = e100_get_stats; - dev->set_multicast_list = set_multicast_list; - dev->set_mac_address = e100_set_mac_address; - - /* Initialise the list of Etrax DMA-descriptors */ - - /* Initialise receive descriptors */ - - for(i = 0; i < (NBR_OF_RX_DESC - 1); i++) { - RxDescList[i].ctrl = 0; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; - anOffset += RX_DESC_BUF_SIZE; - } - - RxDescList[i].ctrl = d_eol; - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].next = virt_to_phys(&RxDescList[0]); - RxDescList[i].buf = virt_to_phys(RxBuf + anOffset); - RxDescList[i].status = 0; - RxDescList[i].hw_len = 0; - - /* Initialise initial pointers */ - - myNextRxDesc = &RxDescList[0]; - myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - - /* setup some TX descriptor data */ - - TxDescList[0].sw_len = 4; - TxDescList[0].ctrl = 0; - TxDescList[0].buf = virt_to_phys(&host_command); - TxDescList[0].next = virt_to_phys(&TxDescList[1]); - - err = register_netdev(dev); - if (err) - kfree(dev); - - return err; -} - -/* set MAC address of the interface. called from the core after a - * SIOCSIFADDR ioctl, and from the bootup above. - */ - -static int -e100_set_mac_address(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - int i; - - /* remember it */ - - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - - /* Write it to the hardware. - * Note the way the address is wrapped: - * *R_NETWORK_SA_0 = a0_0 | (a0_1 << 8) | (a0_2 << 16) | (a0_3 << 24); - * *R_NETWORK_SA_1 = a0_4 | (a0_5 << 8); - */ - - tx_skb = 0; - e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6); - - /* show it in the log as well */ - - printk("%s: changed MAC to ", dev->name); - - for (i = 0; i < 5; i++) - printk("%02X:", dev->dev_addr[i]); - - printk("%02X\n", dev->dev_addr[i]); - - return 0; -} - -/* - * Open/initialize the board. This is called (in the current kernel) - * sometime after booting when the 'ifconfig' program is run. - * - * This routine should set everything up anew at each open, even - * registers that "should" only need to be set once at boot, so that - * there is non-reboot way to recover if something goes wrong. - */ - -static int -e100_open(struct net_device *dev) -{ - unsigned long flags; - - /* configure the PAR0 (RX) and PAR1 (TX) ports - * - * perror is nAckReverse, which must be 1 at the TX side, - * and 0 at the RX side - * - * select is XFlag, which must be 1 at both sides - */ -#ifdef ETHDEBUG - printk("Setting up PAR ports\n"); -#endif - *R_PAR0_CONFIG = - /* We do not have an external buffer, don't care */ - IO_STATE(R_PAR0_CONFIG, ioe, noninv) | - /* Not connected, don't care */ - IO_STATE(R_PAR0_CONFIG, iseli, noninv) | - /* iautofd is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, iautofd, noninv) | - /* Not used in reverse direction, don't care */ - IO_STATE(R_PAR0_CONFIG, istrb, noninv) | - /* Not connected, don't care */ - IO_STATE(R_PAR0_CONFIG, iinit, noninv) | - /* perror is GND and reverse wants 0, noninv */ - IO_STATE(R_PAR0_CONFIG, iperr, noninv) | - /* ack is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, iack, noninv) | - /* busy is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, ibusy, noninv) | - /* fault is not inverted, noninv */ - IO_STATE(R_PAR0_CONFIG, ifault, noninv) | - /* select is Vcc and we want 1, noninv */ - IO_STATE(R_PAR0_CONFIG, isel, noninv) | - /* We will run dma, enable */ - IO_STATE(R_PAR0_CONFIG, dma, enable) | - /* No run length encoding, disable */ - IO_STATE(R_PAR0_CONFIG, rle_in, disable) | - /* No run length encoding, disable */ - IO_STATE(R_PAR0_CONFIG, rle_out, disable) | - /* Enable parallel port */ - IO_STATE(R_PAR0_CONFIG, enable, on) | - /* Force mode regardless of pin status */ - IO_STATE(R_PAR0_CONFIG, force, on) | - /* We want ECP forward mode since PAR0 is RX */ - IO_STATE(R_PAR0_CONFIG, mode, ecp_rev); - - *R_PAR1_CONFIG = - /* We do not have an external buffer, don't care */ - IO_STATE(R_PAR1_CONFIG, ioe, noninv) | - - /* Not connected, don't care */ - IO_STATE(R_PAR1_CONFIG, iseli, noninv) | - - /* HostAck must indicate data cycle, noninv */ - IO_STATE(R_PAR1_CONFIG, iautofd, noninv) | - - /* HostClk has no external inverter, noninv */ - IO_STATE(R_PAR1_CONFIG, istrb, noninv) | - - /* Not connected, don't care */ - IO_STATE(R_PAR1_CONFIG, iinit, noninv) | - - /* nAckReverse must be 1 in forward mode but is grounded, inv */ - IO_STATE(R_PAR1_CONFIG, iperr, inv) | - - /* PeriphClk must be 1 in forward mode, noninv */ - IO_STATE(R_PAR1_CONFIG, iack, noninv) | - - /* PeriphAck has no external inverter, noninv */ - IO_STATE(R_PAR1_CONFIG, ibusy, noninv) | - - /* nPerihpRequest has no external inverter, noniv */ - IO_STATE(R_PAR1_CONFIG, ifault, noninv) | - - /* Select is VCC and we want 1, noninv */ - IO_STATE(R_PAR1_CONFIG, isel, noninv) | - - /* No EPP mode, disable */ - IO_STATE(R_PAR1_CONFIG, ext_mode, disable) | - - /* We will run dma, enable */ - IO_STATE(R_PAR1_CONFIG, dma, enable) | - - /* No run length encoding, disable */ - IO_STATE(R_PAR1_CONFIG, rle_in, disable) | - - /* No run length encoding, disable */ - IO_STATE(R_PAR1_CONFIG, rle_out, disable) | - - /* Enable parallel port */ - IO_STATE(R_PAR1_CONFIG, enable, on) | - - /* Force mode regardless of pin status */ - IO_STATE(R_PAR1_CONFIG, force, on) | - - /* We want ECP forward mode since PAR1 is TX */ - IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd); - - /* Setup time of value * 160 + 20 ns == 20 ns below */ - *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 0); - - *R_PAR1_CTRL = 0; - - while ((((*R_PAR1_STATUS)&0xE000) >> 13) != 5); /* Wait for ECP_FWD mode */ -#ifdef ETHDEBUG - dump_parport_status(); -#endif - - /* make sure ECP irq is acked when we enable it below */ - - (void)*R_PAR0_STATUS_DATA; - (void)*R_PAR1_STATUS_DATA; - - /* Reset and wait for the DMA channels */ - - RESET_DMA(4); /* PAR1_TX_DMA_NBR */ - RESET_DMA(3); /* PAR0_RX_DMA_NBR */ - WAIT_DMA(4); - WAIT_DMA(3); - - /* boot the slave Etrax, by sending code on PAR1. - * do this before we start up the IRQ handlers and stuff, - * beacuse we simply poll for completion in boot_slave. - */ - - boot_slave(&e100lpslaveprog); - - /* allocate the irq corresponding to the receiving DMA */ - - if (request_irq(DMA3_RX_IRQ_NBR, e100rx_interrupt, 0, - cardname, (void *)dev)) { - printk("Failed to allocate DMA3_RX_IRQ_NBR\n"); - goto grace_exit; - } - - /* allocate the irq corresponding to the transmitting DMA */ - - if (request_irq(DMA4_TX_IRQ_NBR, e100tx_interrupt, 0, - cardname, (void *)dev)) { - printk("Failed to allocate DMA4_TX_IRQ_NBR\n"); - goto grace_exit; - } - - /* allocate the irq used for detecting ECP commands on the RX port (PAR0) */ - - if (request_irq(PAR0_ECP_IRQ_NBR, ecp_interrupt, 0, - cardname, (void *)dev)) { - printk("Failed to allocate PAR0_ECP_IRQ_NBR\n"); - grace_exit: - free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); - free_irq(DMA4_TX_IRQ_NBR, (void *)dev); - free_irq(DMA3_RX_IRQ_NBR, (void *)dev); - - return -EAGAIN; - } - -#if 0 - /* We are not allocating DMA since DMA4 is reserved for 'cascading' - * and will always fail with the current dma.c - */ - - /* - * Always allocate the DMA channels after the IRQ, - * and clean up on failure. - */ - - if(request_dma(PAR0_RX_DMA_NBR, cardname)) { - printk("Failed to allocate PAR0_RX_DMA_NBR\n"); - goto grace_exit; - } - - if(request_dma(PAR1_TX_DMA_NBR, cardname)) { - printk("Failed to allocate PAR1_TX_DMA_NBR\n"); - grace_exit: - /* this will cause some 'trying to free free irq' but what the heck... */ - - free_dma(PAR1_TX_DMA_NBR); - free_dma(PAR0_RX_DMA_NBR); - free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); - free_irq(DMA4_TX_IRQ_NBR, (void *)dev); - free_irq(DMA3_RX_IRQ_NBR, (void *)dev); - - return -EAGAIN; - } -#endif - -#ifdef ETHDEBUG - printk("Par port IRQ and DMA allocated\n"); -#endif - save_flags(flags); - cli(); - - /* enable the irq's for PAR0/1 DMA */ - - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma3_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set); - - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, par0_ecp_cmd, set); - - tx_skb = 0; - - /* make sure the irqs are cleared */ - - *R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do); - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - - /* Write the MAC address to the slave HW */ - udelay(5000); - e100_hardware_send_packet(HOST_CMD_SETMAC, dev->dev_addr, 6); - - /* make sure the rec and transmit error counters are cleared */ - - (void)*R_REC_COUNTERS; /* dummy read */ - (void)*R_TR_COUNTERS; /* dummy read */ - - /* start the receiving DMA channel so we can receive packets from now on */ - - *R_DMA_CH3_FIRST = virt_to_phys(myNextRxDesc); - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, start); - - restore_flags(flags); - - /* We are now ready to accept transmit requeusts from - * the queueing layer of the networking. - */ -#ifdef ETHDEBUG - printk("Starting slave network transmit queue\n"); -#endif - netif_start_queue(dev); - - return 0; -} - -static void -e100_reset_transceiver(void) -{ - /* To do: Reboot and setup slave Etrax */ -} - -/* Called by upper layers if they decide it took too long to complete - * sending a packet - we need to reset and stuff. - */ - -static void -e100_tx_timeout(struct net_device *dev) -{ - struct net_local *np = (struct net_local *)dev->priv; - - printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - tx_done(dev) ? "IRQ problem" : "network cable problem"); - - /* remember we got an error */ - - np->stats.tx_errors++; - - /* reset the TX DMA in case it has hung on something */ - - RESET_DMA(4); - WAIT_DMA(4); - - /* Reset the transceiver. */ - - e100_reset_transceiver(); - - /* and get rid of the packet that never got an interrupt */ - - dev_kfree_skb(tx_skb); - tx_skb = 0; - - /* tell the upper layers we're ok again */ - - netif_wake_queue(dev); -} - - -/* This will only be invoked if the driver is _not_ in XOFF state. - * What this means is that we need not check it, and that this - * invariant will hold if we make sure that the netif_*_queue() - * calls are done at the proper times. - */ - -static int -e100_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *np = (struct net_local *)dev->priv; - int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = skb->data; - -#ifdef ETHDEBUG - unsigned char *temp_data_ptr = buf; - int i; - - printk("Sending a packet of length %d:\n", length); - /* dump the first bytes in the packet */ - for(i = 0; i < 8; i++) { - printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, - temp_data_ptr[0],temp_data_ptr[1],temp_data_ptr[2], - temp_data_ptr[3],temp_data_ptr[4],temp_data_ptr[5], - temp_data_ptr[6],temp_data_ptr[7]); - temp_data_ptr += 8; - } -#endif - spin_lock_irq(&np->lock); /* protect from tx_interrupt */ - - tx_skb = skb; /* remember it so we can free it in the tx irq handler later */ - dev->trans_start = jiffies; - - e100_hardware_send_packet(HOST_CMD_SENDPACK, buf, length); - - /* this simple TX driver has only one send-descriptor so we're full - * directly. If this had a send-ring instead, we would only do this if - * the ring got full. - */ - - netif_stop_queue(dev); - - spin_unlock_irq(&np->lock); - - return 0; -} - -/* - * The typical workload of the driver: - * Handle the network interface interrupts. - */ - -static void -e100rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - unsigned long irqbits = *R_IRQ_MASK2_RD; - - if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma3_eop, active)) { - - /* acknowledge the eop interrupt */ - - *R_DMA_CH3_CLR_INTR = IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do); - - /* check if one or more complete packets were indeed received */ - - while(*R_DMA_CH3_FIRST != virt_to_phys(myNextRxDesc)) { - /* Take out the buffer and give it to the OS, then - * allocate a new buffer to put a packet in. - */ - e100_rx(dev); - ((struct net_local *)dev->priv)->stats.rx_packets++; - /* restart/continue on the channel, for safety */ - *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, restart); - /* clear dma channel 3 eop/descr irq bits */ - *R_DMA_CH3_CLR_INTR = - IO_STATE(R_DMA_CH3_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH3_CLR_INTR, clr_descr, do); - - /* now, we might have gotten another packet - so we have to loop back and check if so */ - } - } -} - -/* the transmit dma channel interrupt - * - * this is supposed to free the skbuff which was pending during transmission, - * and inform the kernel that we can send one more buffer - */ - -static void -e100tx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - unsigned long irqbits = *R_IRQ_MASK2_RD; - struct net_local *np = (struct net_local *)dev->priv; - -#ifdef ETHDEBUG - printk("We got tx interrupt\n"); -#endif - /* check for a dma4_eop interrupt */ - if(irqbits & IO_STATE(R_IRQ_MASK2_RD, dma4_descr, active)) { - /* This protects us from concurrent execution of - * our dev->hard_start_xmit function above. - */ - - spin_lock(&np->lock); - - /* acknowledge the eop interrupt */ - - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - - /* skip *R_DMA_CH4_FIRST == 0 test since we use d_wait... */ - if(tx_skb) { - - np->stats.tx_bytes += tx_skb->len; - np->stats.tx_packets++; - /* dma is ready with the transmission of the data in tx_skb, so now we can release the skb memory */ - dev_kfree_skb_irq(tx_skb); - tx_skb = 0; - netif_wake_queue(dev); - } else { - printk(KERN_WARNING "%s: tx weird interrupt\n", - cardname); - } - - spin_unlock(&np->lock); - } -} - -static void -ecp_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - struct net_device *dev = (struct net_device *)dev_id; - struct net_local *lp = (struct net_local *)dev->priv; - unsigned long temp, irqbits = *R_IRQ_MASK0_RD; - - /* check for ecp irq */ - if(irqbits & IO_MASK(R_IRQ_MASK0_RD, par0_ecp_cmd)) { - /* acknowledge by reading the bit */ - temp = *R_PAR0_STATUS_DATA; - /* force an EOP on the incoming channel, so we'll get an rx interrupt */ - *R_SET_EOP = IO_STATE(R_SET_EOP, ch3_eop, set); - } -} - -/* We have a good packet(s), get it/them out of the buffers. */ -static void -e100_rx(struct net_device *dev) -{ - struct sk_buff *skb; - int length=0; - int i; - struct net_local *np = (struct net_local *)dev->priv; - struct etrax_dma_descr *mySaveRxDesc = myNextRxDesc; - unsigned char *skb_data_ptr; - - /* If the packet is broken down in many small packages then merge - * count how much space we will need to alloc with skb_alloc() for - * it to fit. - */ - - while (!(myNextRxDesc->status & d_eop)) { - length += myNextRxDesc->sw_len; /* use sw_len for the first descs */ - myNextRxDesc->status = 0; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - } - - length += myNextRxDesc->hw_len; /* use hw_len for the last descr */ - -#ifdef ETHDEBUG - printk("Got a packet of length %d:\n", length); - /* dump the first bytes in the packet */ - skb_data_ptr = (unsigned char *)phys_to_virt(mySaveRxDesc->buf); - for(i = 0; i < 8; i++) { - printk("%d: %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", i * 8, - skb_data_ptr[0],skb_data_ptr[1],skb_data_ptr[2],skb_data_ptr[3], - skb_data_ptr[4],skb_data_ptr[5],skb_data_ptr[6],skb_data_ptr[7]); - skb_data_ptr += 8; - } -#endif - - skb = dev_alloc_skb(length - ETHER_HEAD_LEN); - if (!skb) { - np->stats.rx_errors++; - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); - return; - } - - skb_put(skb, length - ETHER_HEAD_LEN); /* allocate room for the packet body */ - skb_data_ptr = skb_push(skb, ETHER_HEAD_LEN); /* allocate room for the header */ - -#ifdef ETHDEBUG - printk("head = 0x%x, data = 0x%x, tail = 0x%x, end = 0x%x\n", - skb->head, skb->data, skb->tail, skb->end); - printk("copying packet to 0x%x.\n", skb_data_ptr); -#endif - - /* this loop can be made using max two memcpy's if optimized */ - - while(mySaveRxDesc != myNextRxDesc) { - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->sw_len); - skb_data_ptr += mySaveRxDesc->sw_len; - mySaveRxDesc = phys_to_virt(mySaveRxDesc->next); - } - - memcpy(skb_data_ptr, phys_to_virt(mySaveRxDesc->buf), - mySaveRxDesc->hw_len); - - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - - /* Send the packet to the upper layers */ - - netif_rx(skb); - - /* Prepare for next packet */ - - myNextRxDesc->status = 0; - myPrevRxDesc = myNextRxDesc; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - - myPrevRxDesc->ctrl |= d_eol; - myLastRxDesc->ctrl &= ~d_eol; - myLastRxDesc = myPrevRxDesc; - - return; -} - -/* The inverse routine to net_open(). */ -static int -e100_close(struct net_device *dev) -{ - struct net_local *np = (struct net_local *)dev->priv; - - printk("Closing %s.\n", dev->name); - - netif_stop_queue(dev); - - *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, par0_ecp_cmd, clr); - - *R_IRQ_MASK2_CLR = - IO_STATE(R_IRQ_MASK2_CLR, dma3_eop, clr) | - IO_STATE(R_IRQ_MASK2_CLR, dma4_descr, clr); - - /* Stop the receiver and the transmitter */ - - RESET_DMA(3); - RESET_DMA(4); - - /* Flush the Tx and disable Rx here. */ - - free_irq(DMA3_RX_IRQ_NBR, (void *)dev); - free_irq(DMA4_TX_IRQ_NBR, (void *)dev); - free_irq(PAR0_ECP_IRQ_NBR, (void *)dev); - - free_dma(PAR1_TX_DMA_NBR); - free_dma(PAR0_RX_DMA_NBR); - - /* Update the statistics here. */ - - update_rx_stats(&np->stats); - update_tx_stats(&np->stats); - - return 0; -} - -static void -update_rx_stats(struct net_device_stats *es) -{ - unsigned long r = *R_REC_COUNTERS; - /* update stats relevant to reception errors */ - es->rx_fifo_errors += r >> 24; /* fifo overrun */ - es->rx_crc_errors += r & 0xff; /* crc error */ - es->rx_frame_errors += (r >> 8) & 0xff; /* alignment error */ - es->rx_length_errors += (r >> 16) & 0xff; /* oversized frames */ -} - -static void -update_tx_stats(struct net_device_stats *es) -{ - unsigned long r = *R_TR_COUNTERS; - /* update stats relevant to transmission errors */ - es->collisions += (r & 0xff) + ((r >> 8) & 0xff); /* single_col + multiple_col */ - es->tx_errors += (r >> 24) & 0xff; /* deferred transmit frames */ -} - -/* - * Get the current statistics. - * This may be called with the card open or closed. - */ -static struct net_device_stats * -e100_get_stats(struct net_device *dev) -{ - struct net_local *lp = (struct net_local *)dev->priv; - - update_rx_stats(&lp->stats); - update_tx_stats(&lp->stats); - - return &lp->stats; -} - -/* - * Set or clear the multicast filter for this adaptor. - * num_addrs == -1 Promiscuous mode, receive all packets - * num_addrs == 0 Normal mode, clear multicast list - * num_addrs > 0 Multicast mode, receive normal and MC packets, - * and do best-effort filtering. - */ -static void -set_multicast_list(struct net_device *dev) -{ - /* To do */ -} - -void -e100_hardware_send_packet(unsigned long hostcmd, char *buf, int length) -{ - static char bogus_ecp[] = { 42, 42 }; - int i; - - -#ifdef ETHDEBUG - printk("e100 send pack, buf 0x%x len %d\n", buf, length); -#endif - - host_command = hostcmd; - - /* Configure the tx dma descriptor. Desc 0 is already configured.*/ - - TxDescList[1].sw_len = length; - /* bug workaround - etrax100 needs d_wait on the descriptor _before_ - * a descriptor containing an ECP command - */ - TxDescList[1].ctrl = d_wait; - TxDescList[1].buf = virt_to_phys(buf); - TxDescList[1].next = virt_to_phys(&TxDescList[2]); - - /* append the ecp dummy descriptor - its only purpose is to - * make the receiver generate an irq due to the ecp command - * so the receiver knows where packets end - */ - - TxDescList[2].sw_len = 1; - TxDescList[2].ctrl = d_ecp | d_eol | d_int; - TxDescList[2].buf = virt_to_phys(bogus_ecp); - - - /* setup the dma channel and start it */ - - *R_DMA_CH4_FIRST = virt_to_phys(TxDescList); - *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start); - -#ifdef ETHDEBUG - printk("done\n"); -#endif -} - -/* send a chunk of code to the slave chip to boot it. */ - -static void -boot_slave(unsigned char *code) -{ - int i; - -#ifdef ETHDEBUG - printk(" booting slave ETRAX...\n"); -#endif - *R_PORT_PB_DATA = 0x7F; /* Reset slave */ - udelay(15); /* Time enough to reset WAN tranciever */ - *R_PORT_PB_DATA = 0xFF; /* Reset slave */ - - /* configure the tx dma data descriptor */ - - TxDescList[1].sw_len = ETRAX_PAR_BOOT_LENGTH; - TxDescList[1].ctrl = d_eol | d_int; - - TxDescList[1].buf = virt_to_phys(code); - TxDescList[1].next = 0; - - /* setup the dma channel and start it */ - *R_DMA_CH4_FIRST = virt_to_phys(&TxDescList[1]); - *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start); - - /* wait for completion */ - while(!(*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma4_descr))); - - /* ack the irq */ - - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - -#if 0 - /* manual transfer of boot code - requires dma turned off */ - for (i=0; i<ETRAX_PAR_BOOT_LENGTH; i++) - { - printk(" sending byte: %u value: %x\n",i,code[i]); - while (((*R_PAR1_STATUS)&0x02) == 0); /* Wait while tr_rdy is busy*/ - *R_PAR1_CTRL_DATA = code[i]; - } -#endif - -#ifdef ETHDEBUG - printk(" done\n"); -#endif -} - -#ifdef ETHDEBUG -/* debug code to check the current status of PAR1 */ -static void -dump_parport_status(void) -{ - unsigned long temp; - - printk("Parport1 status:\n"); - - temp = (*R_PAR1_STATUS)&0xE000; - temp = temp >> 13; - printk("Reg mode: %u (ecp_fwd(5), ecp_rev(6))\n", temp); - - temp = (*R_PAR1_STATUS)&0x1000; - temp = temp >> 12; - printk("Reg perr: %u (ecp_rev(0))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0800; - temp = temp >> 11; - printk("Reg ack: %u (inactive (1), active (0))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0400; - temp = temp >> 10; - printk("Reg busy: %u (inactive (0), active (1))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0200; - temp = temp >> 9; - printk("Reg fault: %u (inactive (1), active (0))\n", temp); - - temp = (*R_PAR1_STATUS)&0x0100; - temp = temp >> 8; - printk("Reg sel: %u (inactive (0), active (1), xflag(1))\n", temp); - - temp = (*R_PAR1_STATUS)&0x02; - temp = temp >> 1; - printk("Reg tr_rdy: %u (busy (0), ready (1))\n", temp); - -} -#endif /* ETHDEBUG */ - -static int -etrax_init_module(void) -{ - return etrax_ethernet_lpslave_init(); -} - -module_init(etrax_init_module); diff --git a/arch/cris/drivers/parport.c b/arch/cris/drivers/parport.c deleted file mode 100644 index 443e51a111b8..000000000000 --- a/arch/cris/drivers/parport.c +++ /dev/null @@ -1,572 +0,0 @@ -/* $Id: parport.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ - * - * Elinux parallel port driver - * NOTE! - * Since par0 shares DMA with ser2 and par 1 shares DMA with ser3 - * this should be handled if both are enabled at the same time. - * THIS IS NOT HANDLED YET! - * - * Copyright (c) 2001 Axis Communications AB - * - * Author: Fredrik Hugosson - * - */ - - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/parport.h> -#include <linux/ioport.h> -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/sched.h> - -#include <linux/slab.h> -#include <linux/interrupt.h> - -#include <asm/setup.h> -#include <asm/irq.h> -#include <asm/io.h> - -#include <asm/segment.h> -#include <asm/system.h> - -#include <asm/svinto.h> - - -#undef DEBUG -#ifdef DEBUG -#define DPRINTK printk -#else -static inline int DPRINTK(void *nothing, ...) {return 0;} -#endif - -/* - * Etrax100 DMAchannels: - * Par0 out : DMA2 - * Par0 in : DMA3 - * Par1 out : DMA4 - * Par1 in : DMA5 - * NOTE! par0 is shared with ser2 and par1 is shared with ser3 regarding - * DMA and DMA irq - */ - -//#define CONFIG_PAR0_INT 1 -//#define CONFIG_PAR1_INT 1 - -#define SETF(var, reg, field, val) \ - var = (var & ~IO_MASK(##reg##, field)) | IO_FIELD(##reg##, field, val) - -#define SETS(var, reg, field, val) \ - var = (var & ~IO_MASK(##reg##, field)) | IO_STATE(##reg##, field, val) - -struct etrax100par_struct { - /* parallell port control */ - volatile u32 *reg_ctrl_data; /* R_PARx_CTRL_DATA */ - const volatile u32 *reg_status_data; /* R_PARx_STATUS_DATA */ - volatile u32 *reg_config; /* R_PARx_CONFIG */ - volatile u32 *reg_delay; /* R_PARx_DELAY */ - - /* DMA control */ - int odma; - unsigned long dma_irq; /* bitnr in R_IRQ_MASK2 for dmaX_descr */ - - volatile char *oclrintradr; /* adr to R_DMA_CHx_CLR_INTR, output */ - volatile u32 *ofirstadr; /* adr to R_DMA_CHx_FIRST, output */ - volatile char *ocmdadr; /* adr to R_DMA_CHx_CMD, output */ - - volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ - volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ - volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ - - /* Non DMA interrupt stuff */ - unsigned long int_irq; /* R_VECT_MASK_RD */ - const volatile u32 *irq_mask_rd; /* R_IRQ_MASKX_RD */ - volatile u32 *irq_mask_clr; /* R_IRQ_MASKX_RD */ - const volatile u32 *irq_read; /* R_IRQ_READX */ - volatile u32 *irq_mask_set; /* R_IRQ_MASKX_SET */ - unsigned long irq_mask_tx; /* bitmask in R_IRQ_ for tx (ready) int */ - unsigned long irq_mask_rx; /* bitmask in R_IRQ_ for rx (data) int */ - unsigned long irq_mask_ecp_cmd; /* mask in R_IRQ_ for ecp_cmd int */ - unsigned long irq_mask_peri; /* bitmask in R_IRQ_ for peri int */ - int portnr; - - /* ----- end of fields initialised in port_table[] below ----- */ - - struct parport *port; - - /* Shadow registers */ - volatile unsigned long reg_ctrl_data_shadow; /* for R_PARx_CTRL_DATA */ - volatile unsigned long reg_config_shadow; /* for R_PARx_CONFIG */ - volatile unsigned long reg_delay_shadow; /* for R_PARx_DELAY */ -}; - -/* Always have the complete structs here, even if the port is not used! - * (that way we can index this by the port number) - */ -static struct etrax100par_struct port_table[] = { - { - R_PAR0_CTRL_DATA, - R_PAR0_STATUS_DATA, - R_PAR0_CONFIG, - R_PAR0_DELAY, - /* DMA interrupt stuff */ - 2, - 1U << 4, /* uses DMA 2 and 3 */ - R_DMA_CH2_CLR_INTR, - R_DMA_CH2_FIRST, - R_DMA_CH2_CMD, - R_DMA_CH3_CLR_INTR, - R_DMA_CH3_FIRST, - R_DMA_CH3_CMD, - /* Non DMA interrupt stuff */ - IO_BITNR(R_VECT_MASK_RD, par0), - R_IRQ_MASK0_RD, - R_IRQ_MASK0_CLR, - R_IRQ_READ0, - R_IRQ_MASK0_SET, - IO_FIELD(R_IRQ_MASK0_RD, par0_ready, 1U), /* tx (ready)*/ - IO_FIELD(R_IRQ_MASK0_RD, par0_data, 1U), /* rx (data)*/ - IO_FIELD(R_IRQ_MASK0_RD, par0_ecp_cmd, 1U), /* ecp_cmd */ - IO_FIELD(R_IRQ_MASK0_RD, par0_peri, 1U), /* peri */ - 0 - }, - { - R_PAR1_CTRL_DATA, - R_PAR1_STATUS_DATA, - R_PAR1_CONFIG, - R_PAR1_DELAY, - /* DMA interrupt stuff */ - 4, - 1U << 8, /* uses DMA 4 and 5 */ - - R_DMA_CH4_CLR_INTR, - R_DMA_CH4_FIRST, - R_DMA_CH4_CMD, - R_DMA_CH5_CLR_INTR, - R_DMA_CH5_FIRST, - R_DMA_CH5_CMD, - /* Non DMA interrupt stuff */ - IO_BITNR(R_VECT_MASK_RD, par1), - R_IRQ_MASK1_RD, - R_IRQ_MASK1_CLR, - R_IRQ_READ1, - R_IRQ_MASK1_SET, - IO_FIELD(R_IRQ_MASK1_RD, par1_ready, 1U), /* tx (ready)*/ - IO_FIELD(R_IRQ_MASK1_RD, par1_data, 1U), /* rx (data)*/ - IO_FIELD(R_IRQ_MASK1_RD, par1_ecp_cmd, 1U), /* ecp_cmd */ - IO_FIELD(R_IRQ_MASK1_RD, par1_peri, 1U), /* peri */ - 1 - } -}; - - -#define NR_PORTS (sizeof(port_table)/sizeof(struct etrax100par_struct)) - -static void -parport_etrax_write_data(struct parport *p, unsigned char value) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: etrax_write_data %02X\n", p->portnum, value); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, data, value); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static unsigned char -parport_etrax_read_data(struct parport *p) -{ - unsigned char ret; - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - ret = IO_EXTRACT(R_PAR0_STATUS_DATA, data, *info->reg_status_data); - - DPRINTK("* E100 PP %d: etrax_read_data %02X\n", p->portnum, ret); - return ret; -} - - -static void -parport_etrax_write_control(struct parport *p, unsigned char control) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: etrax_write_control %02x\n", p->portnum, control); - - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, strb, - (control & PARPORT_CONTROL_STROBE) > 0); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, autofd, - (control & PARPORT_CONTROL_AUTOFD) > 0); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, init, - (control & PARPORT_CONTROL_INIT) > 0); - SETF(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, seli, - (control & PARPORT_CONTROL_SELECT) > 0); - - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static unsigned char -parport_etrax_read_control( struct parport *p) -{ - unsigned char ret = 0; - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - if (IO_EXTRACT(R_PAR0_CTRL_DATA, strb, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_STROBE; - if (IO_EXTRACT(R_PAR0_CTRL_DATA, autofd, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_AUTOFD; - if (IO_EXTRACT(R_PAR0_CTRL_DATA, init, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_INIT; - if (IO_EXTRACT(R_PAR0_CTRL_DATA, seli, info->reg_ctrl_data_shadow)) - ret |= PARPORT_CONTROL_SELECT; - - DPRINTK("* E100 PP %d: etrax_read_control %02x\n", p->portnum, ret); - return ret; -} - - -static unsigned char -parport_etrax_frob_control(struct parport *p, unsigned char mask, - unsigned char val) -{ - unsigned char old; - - DPRINTK("* E100 PP %d: frob_control mask %02x, value %02x\n", - p->portnum, mask, val); - old = parport_etrax_read_control(p); - parport_etrax_write_control(p, (old & ~mask) ^ val); - return old; -} - - -static unsigned char -parport_etrax_read_status(struct parport *p) -{ - unsigned char ret = 0; - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - if (IO_EXTRACT(R_PAR0_STATUS_DATA, fault, *info->reg_status_data)) - ret |= PARPORT_STATUS_ERROR; - if (IO_EXTRACT(R_PAR0_STATUS_DATA, sel, *info->reg_status_data)) - ret |= PARPORT_STATUS_SELECT; - if (!IO_EXTRACT(R_PAR0_STATUS_DATA, perr, *info->reg_status_data)) - ret |= PARPORT_STATUS_PAPEROUT; - if (IO_EXTRACT(R_PAR0_STATUS_DATA, ack, *info->reg_status_data)) - ret |= PARPORT_STATUS_ACK; - if (!IO_EXTRACT(R_PAR0_STATUS_DATA, busy, *info->reg_status_data)) - ret |= PARPORT_STATUS_BUSY; - - DPRINTK("* E100 PP %d: status register %04x\n", - p->portnum, *info->reg_status_data); - DPRINTK("* E100 PP %d: read_status %02x\n", p->portnum, ret); - return ret; -} - - -static void -parport_etrax_enable_irq(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - *info->irq_mask_set = info->irq_mask_tx; - DPRINTK("* E100 PP %d: enable irq\n", p->portnum); -} - - -static void -parport_etrax_disable_irq(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - *info->irq_mask_clr = info->irq_mask_tx; - DPRINTK("* E100 PP %d: disable irq\n", p->portnum); -} - - -static void -parport_etrax_data_forward(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: forward mode\n", p->portnum); - SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, enable); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static void -parport_etrax_data_reverse(struct parport *p) -{ - struct etrax100par_struct *info = - (struct etrax100par_struct *)p->private_data; - - DPRINTK("* E100 PP %d: reverse mode\n", p->portnum); - SETS(info->reg_ctrl_data_shadow, R_PAR0_CTRL_DATA, oe, disable); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; -} - - -static void -parport_etrax_init_state(struct pardevice *dev, struct parport_state *s) -{ - DPRINTK("* E100 PP: parport_etrax_init_state\n"); -} - - -static void -parport_etrax_save_state(struct parport *p, struct parport_state *s) -{ - DPRINTK("* E100 PP: parport_etrax_save_state\n"); -} - - -static void -parport_etrax_restore_state(struct parport *p, struct parport_state *s) -{ - DPRINTK("* E100 PP: parport_etrax_restore_state\n"); -} - - -static void -parport_etrax_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - - -static void -parport_etrax_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - - -static struct -parport_operations pp_etrax_ops = { - parport_etrax_write_data, - parport_etrax_read_data, - - parport_etrax_write_control, - parport_etrax_read_control, - parport_etrax_frob_control, - - parport_etrax_read_status, - - parport_etrax_enable_irq, - parport_etrax_disable_irq, - - parport_etrax_data_forward, - parport_etrax_data_reverse, - - parport_etrax_init_state, - parport_etrax_save_state, - parport_etrax_restore_state, - - parport_etrax_inc_use_count, - parport_etrax_dec_use_count, - - parport_ieee1284_epp_write_data, - parport_ieee1284_epp_read_data, - parport_ieee1284_epp_write_addr, - parport_ieee1284_epp_read_addr, - - parport_ieee1284_ecp_write_data, - parport_ieee1284_ecp_read_data, - parport_ieee1284_ecp_write_addr, - - parport_ieee1284_write_compat, - parport_ieee1284_read_nibble, - parport_ieee1284_read_byte, -}; - - -static void -parport_etrax_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct etrax100par_struct *info = (struct etrax100par_struct *) - ((struct parport *)dev_id)->private_data; - DPRINTK("* E100 PP %d: Interrupt received\n", - ((struct parport *)dev_id)->portnum); - *info->irq_mask_clr = info->irq_mask_tx; - parport_generic_irq(irq, (struct parport *)dev_id, regs); -} - -/* ----------- Initialisation code --------------------------------- */ - -static void __init -parport_etrax_show_parallel_version(void) -{ - printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n"); -} - -#ifdef CONFIG_ETRAX_PAR0_DMA -#define PAR0_USE_DMA 1 -#else -#define PAR0_USE_DMA 0 -#endif - -#ifdef CONFIG_ETRAX_PAR1_DMA -#define PAR1_USE_DMA 1 -#else -#define PAR1_USE_DMA 0 -#endif - -static void __init -parport_etrax_init_registers(void) -{ - struct etrax100par_struct *info; - int i; - - for (i = 0, info = port_table; i < 2; i++, info++) { -#ifndef CONFIG_ETRAX_PARALLEL_PORT0 - if (i == 0) - continue; -#endif -#ifndef CONFIG_ETRAX_PARALLEL_PORT1 - if (i == 1) - continue; -#endif - info->reg_config_shadow = - IO_STATE(R_PAR0_CONFIG, iseli, inv) | - IO_STATE(R_PAR0_CONFIG, iautofd, inv) | - IO_STATE(R_PAR0_CONFIG, istrb, inv) | - IO_STATE(R_PAR0_CONFIG, iinit, inv) | - IO_STATE(R_PAR0_CONFIG, rle_in, disable) | - IO_STATE(R_PAR0_CONFIG, rle_out, disable) | - IO_STATE(R_PAR0_CONFIG, enable, on) | - IO_STATE(R_PAR0_CONFIG, force, off) | - IO_STATE(R_PAR0_CONFIG, ign_ack, wait) | - IO_STATE(R_PAR0_CONFIG, oe_ack, wait_oe) | - IO_STATE(R_PAR0_CONFIG, mode, manual); - - if ((i == 0 && PAR0_USE_DMA) || (i == 1 && PAR1_USE_DMA)) - info->reg_config_shadow |= - IO_STATE(R_PAR0_CONFIG, dma, enable); - else - info->reg_config_shadow |= - IO_STATE(R_PAR0_CONFIG, dma, disable); - - *info->reg_config = info->reg_config_shadow; - - info->reg_ctrl_data_shadow = - IO_STATE(R_PAR0_CTRL_DATA, peri_int, nop) | - IO_STATE(R_PAR0_CTRL_DATA, oe, enable) | - IO_STATE(R_PAR0_CTRL_DATA, seli, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, autofd, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, strb, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, init, inactive) | - IO_STATE(R_PAR0_CTRL_DATA, ecp_cmd, data) | - IO_FIELD(R_PAR0_CTRL_DATA, data, 0); - *info->reg_ctrl_data = info->reg_ctrl_data_shadow; - - /* Clear peri int without setting shadow */ - *info->reg_ctrl_data = info->reg_ctrl_data_shadow | - IO_STATE(R_PAR0_CTRL_DATA, peri_int, ack); - - info->reg_delay_shadow = - IO_FIELD(R_PAR0_DELAY, setup, 5) | - IO_FIELD(R_PAR0_DELAY, strobe, 5) | - IO_FIELD(R_PAR0_DELAY, hold, 5); - *info->reg_delay = info->reg_delay_shadow; - } - -#ifdef CONFIG_ETRAX_PARALLEL_PORT0 -#ifdef CONFIG_ETRAX_PAR0_DMA - RESET_DMA(PAR0_TX_DMA_NBR); - WAIT_DMA(PAR0_TX_DMA_NBR); -#ifdef CONFIG_ETRAX_SERIAL_PORT2 - printk(" Warning - DMA clash with ser2!\n"); -#endif /* SERIAL_PORT2 */ -#endif /* DMA */ -#endif /* PORT0 */ - -#ifdef CONFIG_ETRAX_PARALLEL_PORT1 -#ifdef CONFIG_ETRAX_PAR1_DMA - RESET_DMA(PAR1_TX_DMA_NBR); - WAIT_DMA(PAR1_TX_DMA_NBR); -#ifdef CONFIG_ETRAX_SERIAL_PORT3 - printk(" Warning - DMA clash with ser3!\n"); -#endif /* SERIAL_PORT3 */ -#endif /* DMA */ -#endif /* PORT1 */ -} - - -int __init -parport_etrax_init(void) -{ - struct parport *p; - int port_exists = 0; - int i; - struct etrax100par_struct *info; - const char *names[] = { "parallel 0 tx+rx", "parallel 1 tx+rx" }; - - parport_etrax_show_parallel_version(); - parport_etrax_init_registers(); - - for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { -#ifndef CONFIG_ETRAX_PARALLEL_PORT0 - if (i == 0) - continue; -#endif -#ifndef CONFIG_ETRAX_PARALLEL_PORT1 - if (i == 1) - continue; -#endif - p = parport_register_port((unsigned long)0, info->int_irq, - PARPORT_DMA_NONE, &pp_etrax_ops); - if (!p) - continue; - - info->port = p; - p->private_data = info; - /* Axis FIXME: Set mode flags. */ - /* p->modes = PARPORT_MODE_TRISTATE | PARPORT_MODE_SAFEININT; */ - - if(request_irq(info->int_irq, parport_etrax_interrupt, - SA_SHIRQ, names[i], p)) { - parport_unregister_port (p); - continue; - } - - printk(KERN_INFO "%s: ETRAX 100LX port %d using irq\n", - p->name, i); - parport_proc_register(p); - parport_announce_port(p); - port_exists = 1; - } - - return port_exists; -} - -void __exit -parport_etrax_exit(void) -{ - int i; - struct etrax100par_struct *info; - - for (i = 0, info = port_table; i < NR_PORTS; i++, info++) { -#ifndef CONFIG_ETRAX_PARALLEL_PORT0 - if (i == 0) - continue; -#endif -#ifndef CONFIG_ETRAX_PARALLEL_PORT1 - if (i == 1) - continue; -#endif - if (info->int_irq != PARPORT_IRQ_NONE) - free_irq(info->int_irq, info->port); - parport_proc_unregister(info->port); - parport_unregister_port(info->port); - } -} diff --git a/arch/cris/drivers/sync_serial.c b/arch/cris/drivers/sync_serial.c deleted file mode 100644 index 59d62e01c731..000000000000 --- a/arch/cris/drivers/sync_serial.c +++ /dev/null @@ -1,900 +0,0 @@ -/* - * Simple synchronous serial port driver for ETRAX 100LX. - * - * Synchronous serial ports are used for continous streamed data like audio. - * The default setting for this driver is compatible with the STA 013 MP3 - * decoder. The driver can easily be tuned to fit other audio encoder/decoders - * and SPI - * - * Copyright (c) 2001 Axis Communications AB - * - * Author: Mikael Starvik - * - */ -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/config.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/major.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <asm/irq.h> -#include <asm/io.h> -#include <asm/svinto.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/sync_serial.h> - -/* The receiver is a bit tricky beacuse of the continous stream of data. */ -/* */ -/* Two DMA descriptors are linked together. Each DMA descriptor is */ -/* responsible for one half of a common buffer. */ -/* */ -/* ------------------------------ */ -/* | ---------- ---------- | */ -/* --> | Descr1 |-->| Descr2 |--- */ -/* ---------- ---------- */ -/* | | */ -/* v v */ -/* ----------------------------- */ -/* | BUFFER | */ -/* ----------------------------- */ -/* | | */ -/* readp writep */ -/* */ -/* If the application keeps up the pace readp will be right after writep.*/ -/* If the application can't keep the pace we have to throw away data. */ -/* The idea is that readp should be ready with the data pointed out by */ -/* Descr1 when the DMA has filled in Descr2. Otherwise we will discard */ -/* the rest of the data pointed out by Descr1 and set readp to the start */ -/* of Descr2 */ - -#define SYNC_SERIAL_MAJOR 125 - -/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ -/* words can be handled */ - -#define IN_BUFFER_SIZE 12288 -#define OUT_BUFFER_SIZE 4096 - -#define DEFAULT_FRAME_RATE 0 -#define DEFAULT_WORD_RATE 7 - -#define DEBUG(x) - -/* Define some macros to access ETRAX 100 registers */ -#define SETF(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_FIELD(##reg##, field, val) -#define SETS(var, reg, field, val) var = (var & ~IO_MASK(##reg##, field)) | \ - IO_STATE(##reg##, field, val) - -typedef struct sync_port -{ - /* Etrax registers and bits*/ - volatile unsigned * const status; - volatile unsigned * const ctrl_data; - volatile unsigned * const output_dma_first; - volatile unsigned char * const output_dma_cmd; - volatile unsigned char * const output_dma_clr_irq; - volatile unsigned * const input_dma_first; - volatile unsigned char * const input_dma_cmd; - volatile unsigned char * const input_dma_clr_irq; - volatile unsigned * const data_out; - volatile unsigned * const data_in; - char data_avail_bit; /* In R_IRQ_MASK1_RD */ - char transmitter_ready_bit; /* In R_IRQ_MASK1_RD */ - char ready_irq_bit; /* In R_IRQ_MASK1_SET and R_IRQ_MASK1_CLR */ - char input_dma_descr_bit; /* In R_IRQ_MASK2_RD */ - char output_dma_bit; /* In R_IRQ_MASK2_RD */ - - int enabled; /* 1 if port is enabled */ - int use_dma; /* 1 if port uses dma */ - int port_nbr; /* Port 0 or 1 */ - unsigned ctrl_data_shadow; /* Register shadow */ - char busy; /* 1 if port is busy */ - wait_queue_head_t out_wait_q; - wait_queue_head_t in_wait_q; - struct etrax_dma_descr out_descr; - struct etrax_dma_descr in_descr1; - struct etrax_dma_descr in_descr2; - char out_buffer[OUT_BUFFER_SIZE]; - int out_count; /* Remaining bytes for current transfer */ - char* outp; /* Current position in out_buffer */ - char in_buffer[IN_BUFFER_SIZE]; - volatile char* readp; /* Next byte to be read by application */ - volatile char* writep; /* Next byte to be written by etrax */ - int odd_output; /* 1 if writing odd nible in 12 bit mode */ - int odd_input; /* 1 if reading odd nible in 12 bit mode */ -} sync_port; - - -static int etrax_sync_serial_init(void); -static void initialize_port(int portnbr); -static int sync_serial_open(struct inode *, struct file*); -static int sync_serial_release(struct inode*, struct file*); -static int sync_serial_ioctl(struct inode*, struct file*, - unsigned int cmd, unsigned long arg); -static ssize_t sync_serial_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t sync_serial_manual_write(struct file * file, const char * buf, - size_t count, loff_t *ppos); -static ssize_t sync_serial_read(struct file *file, char *buf, - size_t count, loff_t *ppos); -static void send_word(sync_port* port); -static void start_dma(struct sync_port *port, const char* data, int count); -static void start_dma_in(sync_port* port); -static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs); -static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs); - -/* The ports */ -static struct sync_port ports[]= -{ - { - R_SYNC_SERIAL1_STATUS, /* status */ - R_SYNC_SERIAL1_CTRL, /* ctrl_data */ - R_DMA_CH8_FIRST, /* output_dma_first */ - R_DMA_CH8_CMD, /* output_dma_cmd */ - R_DMA_CH8_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH9_FIRST, /* input_dma_first */ - R_DMA_CH9_CMD, /* input_dma_cmd */ - R_DMA_CH9_CLR_INTR, /* input_dma_clr_irq */ - R_SYNC_SERIAL1_TR_DATA, /* data_out */ - R_SYNC_SERIAL1_REC_DATA,/* data in */ - IO_BITNR(R_IRQ_MASK1_RD, ser1_data), /* data_avail_bit */ - IO_BITNR(R_IRQ_MASK1_RD, ser1_ready), /* transmitter_ready_bit */ - IO_BITNR(R_IRQ_MASK1_SET, ser1_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma9_descr), /* input_dma_descr_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma8_eop), /* output_dma_bit */ - }, - { - R_SYNC_SERIAL3_STATUS, /* status */ - R_SYNC_SERIAL3_CTRL, /* ctrl_data */ - R_DMA_CH4_FIRST, /* output_dma_first */ - R_DMA_CH4_CMD, /* output_dma_cmd */ - R_DMA_CH4_CLR_INTR, /* output_dma_clr_irq */ - R_DMA_CH5_FIRST, /* input_dma_first */ - R_DMA_CH5_CMD, /* input_dma_cmd */ - R_DMA_CH5_CLR_INTR, /* input_dma_clr_irq */ - R_SYNC_SERIAL3_TR_DATA, /* data_out */ - R_SYNC_SERIAL3_REC_DATA,/* data in */ - IO_BITNR(R_IRQ_MASK1_RD, ser3_data), /* data_avail_bit */ - IO_BITNR(R_IRQ_MASK1_RD, ser3_ready), /* transmitter_ready_bit */ - IO_BITNR(R_IRQ_MASK1_SET, ser3_ready), /* ready_irq_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma5_descr), /* input_dma_descr_bit */ - IO_BITNR(R_IRQ_MASK2_RD, dma4_eop), /* output_dma_bit */ - } -}; - -/* Register shadows */ -static unsigned sync_serial_prescale_shadow = 0; -static unsigned gen_config_ii_shadow = 0; - -#define NUMBER_OF_PORTS (sizeof(ports)/sizeof(sync_port)) - -static struct file_operations sync_serial_fops = { - .owner = THIS_MODULE, - .write = sync_serial_write, - .read = sync_serial_read, - .ioctl = sync_serial_ioctl, - .open = sync_serial_open, - .release = sync_serial_release -}; - -static int __init etrax_sync_serial_init(void) -{ - ports[0].enabled = 0; - ports[1].enabled = 0; - - if (register_chrdev(SYNC_SERIAL_MAJOR,"sync serial", &sync_serial_fops) <0 ) - { - printk("unable to get major for synchronous serial port\n"); - return -EBUSY; - } - - /* Deselect synchronous serial ports */ - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, ser3, select); - *R_GEN_CONFIG_II = gen_config_ii_shadow; - - /* Initialize Ports */ -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) - ports[0].enabled = 1; - SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser1, ss1extra); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) - ports[0].use_dma = 1; - initialize_port(0); - if(request_irq(24, tr_interrupt, 0, "synchronous serial 1 dma tr", &ports[0])) - panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(25, rx_interrupt, 0, "synchronous serial 1 dma rx", &ports[0])) - panic("Can't allocate sync serial port 1 IRQ"); - RESET_DMA(8); WAIT_DMA(8); - RESET_DMA(9); WAIT_DMA(9); - *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); - *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH9_CLR_INTR, clr_descr, do); - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma8_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); - start_dma_in(&ports[0]); -#else - ports[0].use_dma = 0; - initialize_port(0); - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[0])) - panic("Can't allocate sync serial manual irq"); - *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser1_data, set); -#endif -#endif - -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) - ports[1].enabled = 1; - SETS(port_pb_i2c_shadow, R_PORT_PB_I2C, syncser3, ss3extra); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) - ports[1].use_dma = 1; - initialize_port(1); - if(request_irq(20, tr_interrupt, 0, "synchronous serial 3 dma tr", &ports[1])) - panic("Can't allocate sync serial port 1 IRQ"); - if(request_irq(21, rx_interrupt, 0, "synchronous serial 3 dma rx", &ports[1])) - panic("Can't allocate sync serial port 1 IRQ"); - RESET_DMA(4); WAIT_DMA(4); - RESET_DMA(5); WAIT_DMA(5); - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - *R_DMA_CH5_CLR_INTR = IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do); - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma4_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set); - start_dma_in(&ports[1]); -#else - ports[1].use_dma = 0; - initialize_port(1); - if (port[0].use_dma) /* Port 0 uses dma, we must manual allocate IRQ */ - { - if (request_irq(8, manual_interrupt, SA_SHIRQ, "synchronous serial manual irq", &ports[1])) - panic("Can't allocate sync serial manual irq"); - } - *R_IRQ_MASK1_SET = IO_STATE(R_IRQ_MASK1_SET, ser3_data, set); -#endif -#endif - - *R_PORT_PB_I2C = port_pb_i2c_shadow; /* Use PB4/PB7 */ - - /* Set up timing */ - *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow = ( - IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u1, external) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, word_stb_sel_u3, external) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, prescaler, div4) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, frame_rate, DEFAULT_FRAME_RATE) | - IO_FIELD(R_SYNC_SERIAL_PRESCALE, word_rate, DEFAULT_WORD_RATE) | - IO_STATE(R_SYNC_SERIAL_PRESCALE, warp_mode, normal)); - - /* Select synchronous ports */ - *R_GEN_CONFIG_II = gen_config_ii_shadow; - - printk("ETRAX 100LX synchronous serial port driver\n"); - return 0; -} - -static void initialize_port(int portnbr) -{ - struct sync_port* port = &ports[portnbr]; - - DEBUG(printk("Init sync serial port %d\n", portnbr)); - - port->port_nbr = portnbr; - port->busy = 0; - port->readp = port->in_buffer; - port->writep = port->in_buffer + IN_BUFFER_SIZE/2; - port->odd_input = 0; - - init_waitqueue_head(&port->out_wait_q); - init_waitqueue_head(&port->in_wait_q); - - port->ctrl_data_shadow = - IO_STATE(R_SYNC_SERIAL1_CTRL, tr_baud, c115k2Hz) | - IO_STATE(R_SYNC_SERIAL1_CTRL, mode, master_output) | - IO_STATE(R_SYNC_SERIAL1_CTRL, error, ignore) | - IO_STATE(R_SYNC_SERIAL1_CTRL, rec_enable, disable) | - IO_STATE(R_SYNC_SERIAL1_CTRL, f_synctype, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, f_syncsize, word) | - IO_STATE(R_SYNC_SERIAL1_CTRL, f_sync, on) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_mode, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_halt, stopped) | - IO_STATE(R_SYNC_SERIAL1_CTRL, bitorder, msb) | - IO_STATE(R_SYNC_SERIAL1_CTRL, tr_enable, disable) | - IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit) | - IO_STATE(R_SYNC_SERIAL1_CTRL, buf_empty, lmt_8) | - IO_STATE(R_SYNC_SERIAL1_CTRL, buf_full, lmt_8) | - IO_STATE(R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled) | - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_polarity, neg) | - IO_STATE(R_SYNC_SERIAL1_CTRL, frame_polarity, normal)| - IO_STATE(R_SYNC_SERIAL1_CTRL, status_polarity, inverted)| - IO_STATE(R_SYNC_SERIAL1_CTRL, clk_driver, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, frame_driver, normal) | - IO_STATE(R_SYNC_SERIAL1_CTRL, status_driver, normal)| - IO_STATE(R_SYNC_SERIAL1_CTRL, def_out0, high); - - if (port->use_dma) - port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, on); - else - port->ctrl_data_shadow |= IO_STATE(R_SYNC_SERIAL1_CTRL, dma_enable, off); - - *port->ctrl_data = port->ctrl_data_shadow; -} - -static int sync_serial_open(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev); - DEBUG(printk("Open sync serial port %d\n", dev)); - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - if (ports[dev].busy) - { - DEBUG(printk("Device is busy.. \n")); - return -EBUSY; - } - ports[dev].busy = 1; - return 0; -} - -static int sync_serial_release(struct inode *inode, struct file *file) -{ - int dev = MINOR(inode->i_rdev); - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - ports[dev].busy = 0; - return 0; -} - -static int sync_serial_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int return_val = 0; - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - sync_port* port; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -1; - } - port = &ports[dev]; - - /* Disable port while changing config */ - if (dev) - { - RESET_DMA(4); WAIT_DMA(4); - *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH4_CLR_INTR, clr_descr, do); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, async); - } - else - { - RESET_DMA(8); WAIT_DMA(8); - *R_DMA_CH8_CLR_INTR = IO_STATE(R_DMA_CH8_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH8_CLR_INTR, clr_descr, do); - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, async); - } - *R_GEN_CONFIG_II = gen_config_ii_shadow; - - switch(cmd) - { - case SSP_SPEED: - if (GET_SPEED(arg) == CODEC) - { - if (dev) - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, codec); - else - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, codec); - - SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, prescaler, GET_FREQ(arg)); - SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, frame_rate, GET_FRAME_RATE(arg)); - SETF(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, word_rate, GET_WORD_RATE(arg)); - } - else - { - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_baud, GET_SPEED(arg)); - if (dev) - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u3, baudrate); - else - SETS(sync_serial_prescale_shadow, R_SYNC_SERIAL_PRESCALE, clk_sel_u1, baudrate); - } - break; - case SSP_MODE: - if (arg > 5) - return -EINVAL; - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, arg); - break; - case SSP_FRAME_SYNC: - if (arg & NORMAL_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); - else if (arg & EARLY_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, early); - - if (arg & BIT_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, bit); - else if (arg & WORD_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); - else if (arg & EXTENDED_SYNC) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, extended); - - if (arg & SYNC_ON) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); - else if (arg & SYNC_OFF) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, off); - - if (arg & WORD_SIZE_8) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); - else if (arg & WORD_SIZE_12) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size12bit); - else if (arg & WORD_SIZE_16) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size16bit); - else if (arg & WORD_SIZE_24) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size24bit); - else if (arg & WORD_SIZE_32) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size32bit); - - if (arg & BIT_ORDER_MSB) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); - else if (arg & BIT_ORDER_LSB) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, lsb); - - if (arg & FLOW_CONTROL_ENABLE) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, enabled); - else if (arg & FLOW_CONTROL_DISABLE) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); - - if (arg & CLOCK_NOT_GATED) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, normal); - else if (arg & CLOCK_GATED) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_mode, gated); - - break; - case SSP_IPOLARITY: - if (arg & CLOCK_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); - else if (arg & CLOCK_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, pos); - - if (arg & FRAME_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, normal); - else if (arg & FRAME_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); - - if (arg & STATUS_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, normal); - else if (arg & STATUS_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_polarity, inverted); - break; - case SSP_OPOLARITY: - if (arg & CLOCK_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, normal); - else if (arg & CLOCK_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); - - if (arg & FRAME_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, normal); - else if (arg & FRAME_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); - - if (arg & STATUS_NORMAL) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, normal); - else if (arg & STATUS_INVERT) - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, status_driver, inverted); - break; - case SSP_SPI: - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, flow_ctrl, disabled); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, bitorder, msb); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, wordsize, size8bit); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_sync, on); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_syncsize, word); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, f_synctype, normal); - if (arg & SPI_SLAVE) - { - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_polarity, inverted); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_polarity, neg); - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, SLAVE_INPUT); - } - else - { - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, frame_driver, inverted); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_driver, inverted); - SETF(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, mode, MASTER_OUTPUT); - } - break; - default: - return_val = -1; - } - /* Set config and enable port */ - *port->ctrl_data = port->ctrl_data_shadow; - *R_SYNC_SERIAL_PRESCALE = sync_serial_prescale_shadow; - if (dev) - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode3, sync); - else - SETS(gen_config_ii_shadow, R_GEN_CONFIG_II, sermode1, sync); - - *R_GEN_CONFIG_II = gen_config_ii_shadow; - return return_val; -} - -static ssize_t sync_serial_manual_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - DECLARE_WAITQUEUE(wait, current); - sync_port* port; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - - port = &ports[dev]; - if (copy_from_user(port->out_buffer, buf, count)) - return -EFAULT; - port->outp = port->out_buffer; - port->out_count = count; - port->odd_output = 1; - add_wait_queue(&port->out_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - *R_IRQ_MASK1_SET = 1 << port->ready_irq_bit; /* transmitter ready IRQ on */ - send_word(port); /* Start sender by sending first word */ - schedule(); - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->out_wait_q, &wait); - if (signal_pending(current)) - { - return -EINTR; - } - return count; -} - -static ssize_t sync_serial_write(struct file * file, const char * buf, - size_t count, loff_t *ppos) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - DECLARE_WAITQUEUE(wait, current); - sync_port *port; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - - DEBUG(printk("Write dev %d count %d\n", port->port_nbr, count)); - - count = count > OUT_BUFFER_SIZE ? OUT_BUFFER_SIZE : count; - - /* Make sure transmitter is running */ - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, tr_enable, enable); - *port->ctrl_data = port->ctrl_data_shadow; - - if (!port->use_dma) - { - return sync_serial_manual_write(file, buf, count, ppos); - } - - if (copy_from_user(port->out_buffer, buf, count)) - return -EFAULT; - add_wait_queue(&port->out_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - start_dma(port, buf, count); - schedule(); - set_current_state(TASK_RUNNING); - remove_wait_queue(&port->out_wait_q, &wait); - if (signal_pending(current)) - { - return -EINTR; - } - return count; -} - -static ssize_t sync_serial_read(struct file * file, char * buf, - size_t count, loff_t *ppos) -{ - int dev = MINOR(file->f_dentry->d_inode->i_rdev); - int avail; - sync_port *port; - char* start; - char* end; - unsigned long flags; - - if (dev < 0 || dev >= NUMBER_OF_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - - DEBUG(printk("Read dev %d count %d\n", dev, count)); - - /* Make sure receiver is running */ - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, clk_halt, running); - SETS(port->ctrl_data_shadow, R_SYNC_SERIAL1_CTRL, rec_enable, enable); - *port->ctrl_data = port->ctrl_data_shadow; - - /* Calculate number of available bytes */ - while (port->readp == port->writep) /* No data */ - { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - interruptible_sleep_on(&port->in_wait_q); - if (signal_pending(current)) - { - return -EINTR; - } - } - - /* Save pointers to avoid that they are modified by interrupt */ - start = port->readp; - end = port->writep; - - /* Lazy read, never return wrapped data. */ - if (end > start) - avail = end - start; - else - avail = port->in_buffer + IN_BUFFER_SIZE - start; - - count = count > avail ? avail : count; - if (copy_to_user(buf, start, count)) - return -EFAULT; - - /* Disable interrupts while updating readp */ - save_flags(flags); - cli(); - port->readp += count; - if (port->readp == port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ - port->readp = port->in_buffer; - restore_flags(flags); - - DEBUG(printk("%d bytes read\n", count)); - return count; -} - -static void send_word(sync_port* port) -{ - switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) - { - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): - port->out_count--; - *port->data_out = *port->outp++; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): - port->out_count--; - if (port->odd_output) - *port->data_out = ((*port->outp) << 16) | (*(unsigned short *)(port->outp + 1)); - else - *port->data_out = ((*(unsigned short *)port->outp) << 8) | (*(port->outp + 1)); - port->odd_output = !port->odd_output; - port->outp++; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): - port->out_count-=2; - *port->data_out = *(unsigned short *)port->outp; - port->outp+=2; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): - port->out_count-=3; - *port->data_out = *(unsigned int *)port->outp; - port->outp+=3; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): - port->out_count-=4; - *port->data_out = *(unsigned int *)port->outp; - port->outp+=4; - break; - } -} - -static void start_dma(struct sync_port* port, const char* data, int count) -{ - port->out_descr.hw_len = 0; - port->out_descr.next = 0; - port->out_descr.ctrl = d_int | d_eol | d_eop | d_wait; - port->out_descr.sw_len = count; - port->out_descr.buf = virt_to_phys(port->out_buffer); - port->out_descr.status = 0; - - *port->output_dma_first = virt_to_phys(&port->out_descr); - *port->output_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); -} - -static void start_dma_in(sync_port* port) -{ - if (port->writep > port->in_buffer + IN_BUFFER_SIZE) - { - panic("Offset too large in sync serial driver\n"); - return; - } - port->in_descr1.hw_len = 0; - port->in_descr1.ctrl = d_int; - port->in_descr1.status = 0; - port->in_descr1.next = virt_to_phys(&port->in_descr2); - port->in_descr2.hw_len = 0; - port->in_descr2.next = virt_to_phys(&port->in_descr1); - port->in_descr2.ctrl = d_int; - port->in_descr2.status = 0; - - /* Find out which descriptor to start */ - if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) - { - /* Start descriptor 2 */ - port->in_descr1.sw_len = IN_BUFFER_SIZE/2; /* All data available in 1 */ - port->in_descr1.buf = virt_to_phys(port->in_buffer); - port->in_descr2.sw_len = port->in_buffer + IN_BUFFER_SIZE - port->writep; - port->in_descr2.buf = virt_to_phys(port->writep); - *port->input_dma_first = virt_to_phys(&port->in_descr2); - } - else - { - /* Start descriptor 1 */ - port->in_descr1.sw_len = port->in_buffer + IN_BUFFER_SIZE/2 - port->writep; - port->in_descr1.buf = virt_to_phys(port->writep); - port->in_descr2.sw_len = IN_BUFFER_SIZE/2; - port->in_descr2.buf = virt_to_phys(port->in_buffer + IN_BUFFER_SIZE / 2); - *port->input_dma_first = virt_to_phys(&port->in_descr1); - } - *port->input_dma_cmd = IO_STATE(R_DMA_CH0_CMD, cmd, start); -} - -static void tr_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - unsigned long ireg = *R_IRQ_MASK2_RD; - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - sync_port *port = &ports[i]; - if (ireg & (1 << port->output_dma_bit)) /* IRQ active for the port? */ - { - /* Clear IRQ */ - *port->output_dma_clr_irq = - IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); - wake_up_interruptible(&port->out_wait_q); /* wake up the waiting process */ - } - } -} - -static void rx_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - unsigned long ireg = *R_IRQ_MASK2_RD; - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - int update = 0; - sync_port *port = &ports[i]; - - if (!port->enabled) - { - continue; - } - - if (ireg & (1 << port->input_dma_descr_bit)) /* Descriptor interrupt */ - { - /* DMA has reached end of descriptor */ - *port->input_dma_clr_irq = - IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do) | - IO_STATE(R_DMA_CH0_CLR_INTR, clr_descr, do); - - /* Find out which descriptor that is ready */ - if (port->writep >= port->in_buffer + IN_BUFFER_SIZE/2) - { - /* Descr 2 was ready. Restart DMA at descriptor 1 */ - port->writep = port->in_buffer; - - /* Throw away data? */ - if (port->readp < port->in_buffer + IN_BUFFER_SIZE/2) - port->readp = port->in_buffer + IN_BUFFER_SIZE/2; - } - else - { - /* Descr 1 was ready. Restart DMA at descriptor 2 */ - port->writep = port->in_buffer + IN_BUFFER_SIZE/2; - - /* Throw away data? */ - if (port->readp >= port->in_buffer + IN_BUFFER_SIZE/2) - port->readp = port->in_buffer; - } - start_dma_in(port); - wake_up_interruptible(&port->in_wait_q); /* wake up the waiting process */ - } - } -} - -static void manual_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - int i; - - for (i = 0; i < NUMBER_OF_PORTS; i++) - { - sync_port* port = &ports[i]; - - if (!port->enabled) - { - continue; - } - - if (*R_IRQ_MASK1_RD & (1 << port->data_avail_bit)) /* Data received? */ - { - /* Read data */ - switch(port->ctrl_data_shadow & IO_MASK(R_SYNC_SERIAL1_CTRL, wordsize)) - { - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size8bit): - *port->writep++ = *(volatile char *)port->data_in; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size12bit): - { - int data = *(unsigned short *)port->data_in; - if (port->odd_input) - { - *port->writep |= (data & 0x0f00) >> 8; - *(port->writep + 1) = data & 0xff; - } - else - { - *port->writep = (data & 0x0ff0) >> 4; - *(port->writep + 1) = (data & 0x0f) << 4; - } - port->odd_input = !port->odd_input; - port->writep+=1; - } - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size16bit): - *(unsigned short*)port->writep = *(volatile unsigned short *)port->data_in; - port->writep+=2; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size24bit): - *(unsigned int*)port->writep = *port->data_in; - port->writep+=3; - break; - case IO_STATE(R_SYNC_SERIAL1_CTRL, wordsize, size32bit): - *(unsigned int*)port->writep = *port->data_in; - port->writep+=4; - break; - } - - if (port->writep > port->in_buffer + IN_BUFFER_SIZE) /* Wrap? */ - port->writep = port->in_buffer; - wake_up_interruptible(&port->in_wait_q); /* Wake up application */ - } - - if (*R_IRQ_MASK1_RD & (1 << port->transmitter_ready_bit)) /* Transmitter ready? */ - { - if (port->out_count) /* More data to send */ - send_word(port); - else /* transmission finished */ - { - *R_IRQ_MASK1_CLR = 1 << port->ready_irq_bit; /* Turn off IRQ */ - wake_up_interruptible(&port->out_wait_q); /* Wake up application */ - } - } - } -} - -module_init(etrax_sync_serial_init); diff --git a/arch/cris/drivers/usb-host.c b/arch/cris/drivers/usb-host.c deleted file mode 100644 index 3a6326f735ae..000000000000 --- a/arch/cris/drivers/usb-host.c +++ /dev/null @@ -1,2516 +0,0 @@ -/* - * usb-host.c: ETRAX 100LX USB Host Controller Driver (HCD) - * - * Copyright (c) 2001 Axis Communications AB. - * - * $Id: usb-host.c,v 1.11 2001/09/26 11:52:16 bjornw Exp $ - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/unistd.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/version.h> -#include <linux/list.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/dma.h> -#include <asm/system.h> -#include <asm/svinto.h> - -#include <linux/usb.h> -#include "usb-host.h" - -#define ETRAX_USB_HC_IRQ USB_HC_IRQ_NBR -#define ETRAX_USB_RX_IRQ USB_DMA_RX_IRQ_NBR -#define ETRAX_USB_TX_IRQ USB_DMA_TX_IRQ_NBR - -static const char *usb_hcd_version = "$Revision: 1.11 $"; - -#undef KERN_DEBUG -#define KERN_DEBUG "" - -#undef USB_DEBUG_RH -#undef USB_DEBUG_EP -#undef USB_DEBUG_DESC -#undef USB_DEBUG_TRACE -#undef USB_DEBUG_CTRL -#undef USB_DEBUG_BULK -#undef USB_DEBUG_INTR - -#ifdef USB_DEBUG_RH -#define dbg_rh(format, arg...) printk(KERN_DEBUG __FILE__ ": (RH) " format "\n" , ## arg) -#else -#define dbg_rh(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_EP -#define dbg_ep(format, arg...) printk(KERN_DEBUG __FILE__ ": (EP) " format "\n" , ## arg) -#else -#define dbg_ep(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_CTRL -#define dbg_ctrl(format, arg...) printk(KERN_DEBUG __FILE__ ": (CTRL) " format "\n" , ## arg) -#else -#define dbg_ctrl(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_BULK -#define dbg_bulk(format, arg...) printk(KERN_DEBUG __FILE__ ": (BULK) " format "\n" , ## arg) -#else -#define dbg_bulk(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_INTR -#define dbg_intr(format, arg...) printk(KERN_DEBUG __FILE__ ": (INTR) " format "\n" , ## arg) -#else -#define dbg_intr(format, arg...) do {} while (0) -#endif - -#ifdef USB_DEBUG_TRACE -#define DBFENTER (printk(KERN_DEBUG __FILE__ ": Entering : " __FUNCTION__ "\n")) -#define DBFEXIT (printk(KERN_DEBUG __FILE__ ": Exiting : " __FUNCTION__ "\n")) -#else -#define DBFENTER (NULL) -#define DBFEXIT (NULL) -#endif - -/*------------------------------------------------------------------- - Virtual Root Hub - -------------------------------------------------------------------*/ - -static __u8 root_hub_dev_des[] = -{ - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x00, /* __u16 bcdUSB; v1.0 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; Bit 7: Bus-powered */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static __u8 root_hub_hub_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x29, /* __u8 bDescriptorType; Hub-descriptor */ - 0x02, /* __u8 bNbrPorts; */ - 0x00, /* __u16 wHubCharacteristics; */ - 0x00, - 0x01, /* __u8 bPwrOn2pwrGood; 2ms */ - 0x00, /* __u8 bHubContrCurrent; 0 mA */ - 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */ - 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */ -}; - - -#define OK(x) len = (x); dbg_rh("OK(%d): line: %d", x, __LINE__); break -#define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ -{panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} - -static submit_urb_count = 0; - -//#define ETRAX_USB_INTR_IRQ -//#define ETRAX_USB_INTR_ERROR_FATAL - -#define RX_BUF_SIZE 32768 -#define RX_DESC_BUF_SIZE 64 -#define NBR_OF_RX_DESC (RX_BUF_SIZE / RX_DESC_BUF_SIZE) - -#define NBR_OF_EP_DESC 32 - -#define MAX_INTR_INTERVAL 128 - -static __u32 ep_usage_bitmask; -static __u32 ep_really_active; - -static unsigned char RxBuf[RX_BUF_SIZE]; -static USB_IN_Desc_t RxDescList[NBR_OF_RX_DESC] __attribute__ ((aligned (4))); - -static volatile USB_IN_Desc_t *myNextRxDesc; -static volatile USB_IN_Desc_t *myLastRxDesc; -static volatile USB_IN_Desc_t *myPrevRxDesc; - -static USB_EP_Desc_t TxCtrlEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); -static USB_EP_Desc_t TxBulkEPList[NBR_OF_EP_DESC] __attribute__ ((aligned (4))); - -static USB_EP_Desc_t TxIntrEPList[MAX_INTR_INTERVAL] __attribute__ ((aligned (4))); -static USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4))); - -static struct urb *URB_List[NBR_OF_EP_DESC]; -static kmem_cache_t *usb_desc_cache; -static struct usb_bus *etrax_usb_bus; - -static void dump_urb (struct urb *urb); -static void init_rx_buffers(void); -static int etrax_rh_unlink_urb (struct urb *urb); -static void etrax_rh_send_irq(struct urb *urb); -static void etrax_rh_init_int_timer(struct urb *urb); -static void etrax_rh_int_timer_do(unsigned long ptr); - -static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, - char packsize, char slow); -static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp); -static int etrax_usb_allocate_epid(void); -static void etrax_usb_free_epid(char epid); -static void cleanup_sb(USB_SB_Desc_t *sb); - -static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags); -static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags); - -static int etrax_usb_submit_ctrl_urb(struct urb *urb, int mem_flags); - -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags); -static int etrax_usb_unlink_urb(struct urb *urb); -static int etrax_usb_get_frame_number(struct usb_device *usb_dev); -static int etrax_usb_allocate_dev(struct usb_device *usb_dev); -static int etrax_usb_deallocate_dev(struct usb_device *usb_dev); - -static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs); -static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs); -static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs); - -static int etrax_rh_submit_urb (struct urb *urb); - -static int etrax_usb_hc_init(void); -static void etrax_usb_hc_cleanup(void); - -static struct usb_operations etrax_usb_device_operations = -{ - etrax_usb_allocate_dev, - etrax_usb_deallocate_dev, - etrax_usb_get_frame_number, - etrax_usb_submit_urb, - etrax_usb_unlink_urb -}; - -#ifdef USB_DEBUG_DESC -static void dump_urb(struct urb *urb) -{ - printk("\nurb :0x%08X\n", urb); - printk("next :0x%08X\n", urb->next); - printk("dev :0x%08X\n", urb->dev); - printk("pipe :0x%08X\n", urb->pipe); - printk("status :%d\n", urb->status); - printk("transfer_flags :0x%08X\n", urb->transfer_flags); - printk("transfer_buffer :0x%08X\n", urb->transfer_buffer); - printk("transfer_buffer_length:%d\n", urb->transfer_buffer_length); - printk("actual_length :%d\n", urb->actual_length); - printk("setup_packet :0x%08X\n", urb->setup_packet); - printk("start_frame :%d\n", urb->start_frame); - printk("number_of_packets :%d\n", urb->number_of_packets); - printk("interval :%d\n", urb->interval); - printk("error_count :%d\n", urb->error_count); - printk("context :0x%08X\n", urb->context); - printk("complete :0x%08X\n\n", urb->complete); -} - -static void dump_in_desc(USB_IN_Desc_t *in) -{ - printk("\nUSB_IN_Desc at 0x%08X\n", in); - printk(" sw_len : 0x%04X (%d)\n", in->sw_len, in->sw_len); - printk(" command : 0x%04X\n", in->command); - printk(" next : 0x%08X\n", in->next); - printk(" buf : 0x%08X\n", in->buf); - printk(" hw_len : 0x%04X (%d)\n", in->hw_len, in->hw_len); - printk(" status : 0x%04X\n\n", in->status); -} - -static void dump_sb_desc(USB_SB_Desc_t *sb) -{ - printk("\nUSB_SB_Desc at 0x%08X\n", sb); - printk(" sw_len : 0x%04X (%d)\n", sb->sw_len, sb->sw_len); - printk(" command : 0x%04X\n", sb->command); - printk(" next : 0x%08X\n", sb->next); - printk(" buf : 0x%08X\n\n", sb->buf); -} - - -static void dump_ep_desc(USB_EP_Desc_t *ep) -{ - printk("\nUSB_EP_Desc at 0x%08X\n", ep); - printk(" hw_len : 0x%04X (%d)\n", ep->hw_len, ep->hw_len); - printk(" command : 0x%08X\n", ep->command); - printk(" sub : 0x%08X\n", ep->sub); - printk(" nep : 0x%08X\n\n", ep->nep); -} - - -#else -#define dump_urb(...) (NULL) -#define dump_ep_desc(...) (NULL) -#define dump_sb_desc(...) (NULL) -#define dump_in_desc(...) (NULL) -#endif - -static void init_rx_buffers(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < (NBR_OF_RX_DESC - 1); i++) { - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].command = 0; - RxDescList[i].next = virt_to_phys(&RxDescList[i + 1]); - RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); - RxDescList[i].hw_len = 0; - RxDescList[i].status = 0; - } - - RxDescList[i].sw_len = RX_DESC_BUF_SIZE; - RxDescList[i].command = IO_STATE(USB_IN_command, eol, yes); - RxDescList[i].next = virt_to_phys(&RxDescList[0]); - RxDescList[i].buf = virt_to_phys(RxBuf + (i * RX_DESC_BUF_SIZE)); - RxDescList[i].hw_len = 0; - RxDescList[i].status = 0; - - myNextRxDesc = &RxDescList[0]; - myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; - - *R_DMA_CH9_FIRST = virt_to_phys(myNextRxDesc); - *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, start); - - DBFEXIT; -} - -static void init_tx_ctrl_ep(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { - TxCtrlEPList[i].hw_len = 0; - TxCtrlEPList[i].command = IO_FIELD(USB_EP_command, epid, i); - TxCtrlEPList[i].sub = 0; - TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[i + 1]); - } - - TxCtrlEPList[i].hw_len = 0; - TxCtrlEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | - IO_FIELD(USB_EP_command, epid, i); - - TxCtrlEPList[i].sub = 0; - TxCtrlEPList[i].nep = virt_to_phys(&TxCtrlEPList[0]); - - *R_DMA_CH8_SUB1_EP = virt_to_phys(&TxCtrlEPList[0]); - *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); - - DBFEXIT; -} - -static void init_tx_bulk_ep(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < (NBR_OF_EP_DESC - 1); i++) { - TxBulkEPList[i].hw_len = 0; - TxBulkEPList[i].command = IO_FIELD(USB_EP_command, epid, i); - TxBulkEPList[i].sub = 0; - TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[i + 1]); - } - - TxBulkEPList[i].hw_len = 0; - TxBulkEPList[i].command = IO_STATE(USB_EP_command, eol, yes) | - IO_FIELD(USB_EP_command, epid, i); - - TxBulkEPList[i].sub = 0; - TxBulkEPList[i].nep = virt_to_phys(&TxBulkEPList[0]); - - *R_DMA_CH8_SUB0_EP = virt_to_phys(&TxBulkEPList[0]); - *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); - - DBFEXIT; -} - -static void init_tx_intr_ep(void) -{ - int i; - - DBFENTER; - - TxIntrSB_zout.sw_len = 0; - TxIntrSB_zout.next = 0; - TxIntrSB_zout.buf = 0; - TxIntrSB_zout.command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, zout) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { - TxIntrEPList[i].hw_len = 0; - TxIntrEPList[i].command = IO_STATE(USB_EP_command, eof, yes) | - IO_STATE(USB_EP_command, enable, yes) | - IO_FIELD(USB_EP_command, epid, 0); - TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); - TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[i + 1]); - } - - TxIntrEPList[i].hw_len = 0; - TxIntrEPList[i].command = - IO_STATE(USB_EP_command, eof, yes) | - IO_STATE(USB_EP_command, enable, yes) | - IO_FIELD(USB_EP_command, epid, 0); - TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); - TxIntrEPList[i].nep = virt_to_phys(&TxIntrEPList[0]); - - *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); - - DBFEXIT; -} - - -static int etrax_usb_unlink_intr_urb(struct urb *urb) -{ - struct usb_device *usb_dev = urb->dev; - etrax_hc_t *hc = usb_dev->bus->hcpriv; - - USB_EP_Desc_t *tmp_ep; - USB_EP_Desc_t *first_ep; - - USB_EP_Desc_t *ep_desc; - USB_SB_Desc_t *sb_desc; - - char epid; - char devnum; - char endpoint; - char slow; - int maxlen; - int i; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - slow = usb_pipeslow(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - err("Trying to unlink urb that is not in traffic queue!!"); - return -1; /* fix this */ - } - - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, stop); - /* Somehow wait for the DMA to finish current activities */ - i = jiffies + 100; - while (time_before(jiffies, i)) - ; - - first_ep = &TxIntrEPList[0]; - tmp_ep = first_ep; - - do { - if (IO_EXTRACT(USB_EP_command, epid, ((USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep))->command) - == epid) { - /* Unlink it !!! */ - dbg_intr("Found urb to unlink for epid %d", epid); - - ep_desc = phys_to_virt(tmp_ep->nep); - tmp_ep->nep = ep_desc->nep; - kmem_cache_free(usb_desc_cache, phys_to_virt(ep_desc->sub)); - kmem_cache_free(usb_desc_cache, ep_desc); - } - - tmp_ep = phys_to_virt(tmp_ep->nep); - - } while (tmp_ep != first_ep); - - /* We should really try to move the EP register to an EP that is not removed - instead of restarting, but this will work too */ - *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); - - clear_bit(epid, (void *)&ep_really_active); - URB_List[epid] = NULL; - etrax_usb_free_epid(epid); - - DBFEXIT; - - return 0; -} - -void etrax_usb_do_intr_recover(int epid) -{ - USB_EP_Desc_t *first_ep, *tmp_ep; - - first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); - tmp_ep = first_ep; - - do { - if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid && - !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) { - tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes); - } - - tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); - - } while (tmp_ep != first_ep); -} - -static int etrax_usb_submit_intr_urb(struct urb *urb, mem_flags) -{ - USB_EP_Desc_t *tmp_ep; - USB_EP_Desc_t *first_ep; - - USB_SB_Desc_t *sb_desc; - - char epid; - char devnum; - char endpoint; - char maxlen; - char slow; - int interval; - int i; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - - slow = usb_pipeslow(urb->pipe); - interval = urb->interval; - - dbg_intr("Intr traffic for dev %d, endpoint %d, maxlen %d, slow %d", - devnum, endpoint, maxlen, slow); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - epid = etrax_usb_allocate_epid(); - if (epid == -1) { - /* We're out of endpoints, return some error */ - err("We're out of endpoints"); - return -ENOMEM; - } - /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); - } - /* Ok, now we got valid endpoint, lets insert some traffic */ - - urb_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), mem_flags); - urb_priv->first_sb = 0; - urb_priv->rx_offset = 0; - urb_priv->eot = 0; - INIT_LIST_HEAD(&urb_priv->ep_in_list); - urb->hcpriv = urb_priv; - - /* This is safe since there cannot be any other URB's for this epid */ - URB_List[epid] = urb; -#if 0 - first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); -#else - first_ep = &TxIntrEPList[0]; -#endif - - /* Round of the interval to 2^n, it is obvious that this code favours - smaller numbers, but that is actually a good thing */ - for (i = 0; interval; i++) { - interval = interval >> 1; - } - - urb->interval = interval = 1 << (i - 1); - - dbg_intr("Interval rounded to %d", interval); - - tmp_ep = first_ep; - i = 0; - do { - if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) { - if ((i % interval) == 0) { - /* Insert the traffic ep after tmp_ep */ - USB_EP_Desc_t *traffic_ep; - USB_SB_Desc_t *traffic_sb; - - traffic_ep = (USB_EP_Desc_t *) - kmem_cache_alloc(usb_desc_cache, mem_flags); - traffic_sb = (USB_SB_Desc_t *) - kmem_cache_alloc(usb_desc_cache, mem_flags); - - traffic_ep->hw_len = 0; - traffic_ep->command = IO_FIELD(USB_EP_command, epid, epid) | - IO_STATE(USB_EP_command, enable, yes); - traffic_ep->sub = virt_to_phys(traffic_sb); - - if (usb_pipein(urb->pipe)) { - traffic_sb->sw_len = urb->transfer_buffer_length ? - (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; - traffic_sb->next = 0; - traffic_sb->buf = 0; - traffic_sb->command = IO_FIELD(USB_SB_command, rem, - urb->transfer_buffer_length % maxlen) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - } else if (usb_pipeout(urb->pipe)) { - traffic_sb->sw_len = urb->transfer_buffer_length; - traffic_sb->next = 0; - traffic_sb->buf = virt_to_phys(urb->transfer_buffer); - traffic_sb->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, out) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes) | - IO_STATE(USB_SB_command, full, yes); - } - - traffic_ep->nep = tmp_ep->nep; - tmp_ep->nep = virt_to_phys(traffic_ep); - dbg_intr("One ep sucessfully inserted"); - } - i++; - } - tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); - } while (tmp_ep != first_ep); - - set_bit(epid, (void *)&ep_really_active); - - *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); - - DBFEXIT; - - return 0; -} - - -static int handle_intr_transfer_attn(char epid, int status) -{ - struct urb *old_urb; - - DBFENTER; - - old_urb = URB_List[epid]; - - /* if (status == 0 && IN) find data and copy to urb */ - if (status == 0 && usb_pipein(old_urb->pipe)) { - unsigned long flags; - etrax_urb_priv_t *urb_priv; - struct list_head *entry; - struct in_chunk *in; - - urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - - save_flags(flags); - cli(); - - list_for_each(entry, &urb_priv->ep_in_list) { - in = list_entry(entry, struct in_chunk, list); - memcpy(old_urb->transfer_buffer, in->data, in->length); - old_urb->actual_length = in->length; - old_urb->status = status; - - if (old_urb->complete) { - old_urb->complete(old_urb); - } - - list_del(entry); - kfree(in->data); - kfree(in); - } - - restore_flags(flags); - - } else if (status != 0) { - warn("Some sort of error for INTR EP !!!!"); -#ifdef ETRAX_USB_INTR_ERROR_FATAL - /* This means that an INTR error is fatal for that endpoint */ - etrax_usb_unlink_intr_urb(old_urb); - old_urb->status = status; - if (old_urb->complete) { - old_urb->complete(old_urb); - } -#else - /* In this case we reenable the disabled endpoint(s) */ - etrax_usb_do_intr_recover(epid); -#endif - } - - DBFEXIT; -} - -static int etrax_rh_unlink_urb (struct urb *urb) -{ - etrax_hc_t *hc; - - DBFENTER; - - hc = urb->dev->bus->hcpriv; - - if (hc->rh.urb == urb) { - hc->rh.send = 0; - del_timer(&hc->rh.rh_int_timer); - } - - DBFEXIT; - return 0; -} - -static void etrax_rh_send_irq(struct urb *urb) -{ - __u16 data = 0; - etrax_hc_t *hc = urb->dev->bus->hcpriv; -// static prev_wPortStatus_1 = 0; -// static prev_wPortStatus_2 = 0; - -/* DBFENTER; */ - - -/* - dbg_rh("R_USB_FM_NUMBER : 0x%08X", *R_USB_FM_NUMBER); - dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING); -*/ - - data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0; - data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0; - - *((__u16 *)urb->transfer_buffer) = cpu_to_le16(data); - urb->actual_length = 1; - urb->status = 0; - - - if (data && hc->rh.send && urb->complete) { - dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1); - dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2); - - urb->complete(urb); - } - -/* DBFEXIT; */ -} - -static void etrax_rh_init_int_timer(struct urb *urb) -{ - etrax_hc_t *hc; - -/* DBFENTER; */ - - hc = urb->dev->bus->hcpriv; - hc->rh.interval = urb->interval; - init_timer(&hc->rh.rh_int_timer); - hc->rh.rh_int_timer.function = etrax_rh_int_timer_do; - hc->rh.rh_int_timer.data = (unsigned long)urb; - hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000); - add_timer(&hc->rh.rh_int_timer); - -/* DBFEXIT; */ -} - -static void etrax_rh_int_timer_do(unsigned long ptr) -{ - struct urb *urb; - etrax_hc_t *hc; - -/* DBFENTER; */ - - urb = (struct urb *)ptr; - hc = urb->dev->bus->hcpriv; - - if (hc->rh.send) { - etrax_rh_send_irq(urb); - } - - etrax_rh_init_int_timer(urb); - -/* DBFEXIT; */ -} - -static void etrax_usb_setup_epid(char epid, char devnum, char endpoint, char packsize, char slow) -{ - unsigned long flags; - - DBFENTER; - - save_flags(flags); - cli(); - - if (test_bit(epid, (void *)&ep_usage_bitmask)) { - restore_flags(flags); - - warn("Trying to setup used epid %d", epid); - DBFEXIT; - return; - } - - set_bit(epid, (void *)&ep_usage_bitmask); - dbg_ep("Setting up ep_id %d with devnum %d, endpoint %d and max_len %d", - epid, devnum, endpoint, packsize); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); - nop(); - *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) | - IO_FIELD(R_USB_EPT_DATA, ep, endpoint) | - IO_FIELD(R_USB_EPT_DATA, dev, devnum) | - IO_FIELD(R_USB_EPT_DATA, max_len, packsize) | - IO_FIELD(R_USB_EPT_DATA, low_speed, slow); - - restore_flags(flags); - - DBFEXIT; -} - -static void etrax_usb_free_epid(char epid) -{ - unsigned long flags; - - DBFENTER; - - if (!test_bit(epid, (void *)&ep_usage_bitmask)) { - warn("Trying to free unused epid %d", epid); - DBFEXIT; - return; - } - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); - nop(); - while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) - printk("+"); - *R_USB_EPT_DATA = 0; - clear_bit(epid, (void *)&ep_usage_bitmask); - - restore_flags(flags); - - dbg_ep("epid: %d freed", epid); - - DBFEXIT; -} - - -static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp) -{ - int i; - unsigned long flags; - __u32 data; - - DBFENTER; - - save_flags(flags); - - /* Skip first ep_id since it is reserved when intr. or iso traffic is used */ - for (i = 0; i < NBR_OF_EP_DESC; i++) { - if (test_bit(i, (void *)&ep_usage_bitmask)) { - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i); - nop(); - data = *R_USB_EPT_DATA; - if ((IO_MASK(R_USB_EPT_DATA, valid) & data) && - (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) && - (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) && - (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) && - (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxp)) { - restore_flags(flags); - - dbg_ep("Found ep_id %d for devnum %d, endpoint %d", - i, devnum, endpoint); - DBFEXIT; - return i; - } - } - } - - restore_flags(flags); - - dbg_ep("Found no ep_id for devnum %d, endpoint %d", - devnum, endpoint); - DBFEXIT; - return -1; -} - -static int etrax_usb_allocate_epid(void) -{ - int i; - - DBFENTER; - - for (i = 0; i < NBR_OF_EP_DESC; i++) { - if (!test_bit(i, (void *)&ep_usage_bitmask)) { - dbg_ep("Found free ep_id at %d", i); - DBFEXIT; - return i; - } - } - - dbg_ep("Found no free ep_id's"); - DBFEXIT; - return -1; -} - -static int etrax_usb_submit_bulk_urb(struct urb *urb, int mem_flags) -{ - char epid; - char devnum; - char endpoint; - char maxlen; - char slow; - - struct urb *tmp_urb; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - slow = usb_pipeslow(urb->pipe); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - epid = etrax_usb_allocate_epid(); - if (epid == -1) { - /* We're out of endpoints, return some error */ - err("We're out of endpoints"); - return -ENOMEM; - } - /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); - } - /* Ok, now we got valid endpoint, lets insert some traffic */ - - urb->status = -EINPROGRESS; - - save_flags(flags); - cli(); - - if (URB_List[epid]) { - /* Find end of list and add */ - for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) - dump_urb(tmp_urb); - - tmp_urb->next = urb; - restore_flags(flags); - } else { - /* If this is the first URB, add the URB and do HW add */ - URB_List[epid] = urb; - restore_flags(flags); - etrax_usb_do_bulk_hw_add(urb, epid, maxlen, mem_flags); - } - - DBFEXIT; - - return 0; -} - -static int etrax_usb_do_bulk_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags) -{ - USB_SB_Desc_t *sb_desc_1; - - etrax_urb_priv_t *urb_priv; - - unsigned long flags; - __u32 r_usb_ept_data; - - DBFENTER; - - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), mem_flags); - sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - if (usb_pipeout(urb->pipe)) { - - dbg_bulk("Bulk transfer for epid %d is OUT", epid); - dbg_bulk("transfer_buffer_length == %d", urb->transfer_buffer_length); - dbg_bulk("actual_length == %d", urb->actual_length); - - if (urb->transfer_buffer_length > 0xffff) { - panic(__FILE__ __FUNCTION__ ":urb->transfer_buffer_length > 0xffff\n"); - } - - sb_desc_1->sw_len = urb->transfer_buffer_length; /* was actual_length */ - sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, out) | - -#if 0 - IO_STATE(USB_SB_command, full, no) | -#else - IO_STATE(USB_SB_command, full, yes) | -#endif - - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); - - sb_desc_1->buf = virt_to_phys(urb->transfer_buffer); - sb_desc_1->next = 0; - - } else if (usb_pipein(urb->pipe)) { - - dbg_bulk("Transfer for epid %d is IN", epid); - dbg_bulk("transfer_buffer_length = %d", urb->transfer_buffer_length); - dbg_bulk("rem is calculated to %d", urb->transfer_buffer_length % maxlen); - - sb_desc_1->sw_len = urb->transfer_buffer_length ? - (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; - dbg_bulk("sw_len got %d", sb_desc_1->sw_len); - dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); - - sb_desc_1->command = - IO_FIELD(USB_SB_command, rem, - urb->transfer_buffer_length % maxlen) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - sb_desc_1->buf = 0; - sb_desc_1->next = 0; - - urb_priv->rx_offset = 0; - urb_priv->eot = 0; - } - - urb_priv->first_sb = sb_desc_1; - - urb->hcpriv = (void *)urb_priv; - - /* Reset toggle bits and reset error count, remeber to di and ei */ - /* Warning: it is possible that this locking doesn't work with bottom-halves */ - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { - panic("Hold was set in %s\n", __FUNCTION__); - } - - *R_USB_EPT_DATA &= - ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | - IO_MASK(R_USB_EPT_DATA, error_count_out)); - - if (usb_pipeout(urb->pipe)) { - char toggle = - usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); - *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out); - *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle); - } else { - char toggle = - usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); - *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in); - *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle); - } - - /* Enable the EP descr. */ - - set_bit(epid, (void *)&ep_really_active); - - TxBulkEPList[epid].sub = virt_to_phys(sb_desc_1); - TxBulkEPList[epid].hw_len = 0; - TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); - - restore_flags(flags); - - if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) { - *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); - - } - - DBFEXIT; -} - -static int handle_bulk_transfer_attn(char epid, int status) -{ - struct urb *old_urb; - etrax_urb_priv_t *hc_priv; - unsigned long flags; - - DBFENTER; - - clear_bit(epid, (void *)&ep_really_active); - - old_urb = URB_List[epid]; - URB_List[epid] = old_urb->next; - - /* if (status == 0 && IN) find data and copy to urb */ - if (status == 0 && usb_pipein(old_urb->pipe)) { - etrax_urb_priv_t *urb_priv; - - urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - save_flags(flags); - cli(); - if (urb_priv->eot == 1) { - old_urb->actual_length = urb_priv->rx_offset; - } else { - if (urb_priv->rx_offset == 0) { - status = 0; - } else { - status = -EPROTO; - } - - old_urb->actual_length = 0; - err("(BULK) No eot set in IN data!!! rx_offset is: %d", urb_priv->rx_offset); - } - - restore_flags(flags); - } - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - if (usb_pipeout(old_urb->pipe)) { - char toggle = - IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA); - usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), - usb_pipeout(old_urb->pipe), toggle); - } else { - char toggle = - IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA); - usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), - usb_pipeout(old_urb->pipe), toggle); - } - restore_flags(flags); - - /* If there are any more URB's in the list we'd better start sending */ - if (URB_List[epid]) { - etrax_usb_do_bulk_hw_add(URB_List[epid], epid, - usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, - usb_pipeout(URB_List[epid]->pipe)), - GFP_KERNEL); - } -#if 1 - else { - /* This means that this EP is now free, deconfigure it */ - etrax_usb_free_epid(epid); - } -#endif - - /* Remember to free the SB's */ - hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - cleanup_sb(hc_priv->first_sb); - kfree(hc_priv); - - old_urb->status = status; - if (old_urb->complete) { - old_urb->complete(old_urb); - } - - DBFEXIT; -} - -/* ---------------------------------------------------------------------------- */ - -static int etrax_usb_submit_ctrl_urb(struct urb *urb, int mem_flags) -{ - char epid; - char devnum; - char endpoint; - char maxlen; - char slow; - - struct urb *tmp_urb; - - etrax_urb_priv_t *urb_priv; - unsigned long flags; - - DBFENTER; - - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - slow = usb_pipeslow(urb->pipe); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - if (epid == -1) { - epid = etrax_usb_allocate_epid(); - if (epid == -1) { - /* We're out of endpoints, return some error */ - err("We're out of endpoints"); - return -ENOMEM; - } - /* Now we have to fill in this ep */ - etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow); - } - /* Ok, now we got valid endpoint, lets insert some traffic */ - - urb->status = -EINPROGRESS; - - save_flags(flags); - cli(); - - if (URB_List[epid]) { - /* Find end of list and add */ - for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) - dump_urb(tmp_urb); - - tmp_urb->next = urb; - restore_flags(flags); - } else { - /* If this is the first URB, add the URB and do HW add */ - URB_List[epid] = urb; - restore_flags(flags); - etrax_usb_do_ctrl_hw_add(urb, epid, maxlen, mem_flags); - } - - DBFEXIT; - - return 0; -} - -static int etrax_usb_do_ctrl_hw_add(struct urb *urb, char epid, char maxlen, int mem_flags) -{ - USB_SB_Desc_t *sb_desc_1; - USB_SB_Desc_t *sb_desc_2; - USB_SB_Desc_t *sb_desc_3; - - etrax_urb_priv_t *urb_priv; - - unsigned long flags; - __u32 r_usb_ept_data; - - - DBFENTER; - - urb_priv = kmalloc(sizeof(etrax_urb_priv_t), mem_flags); - sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - if (!(sb_desc_1 && sb_desc_2)) { - panic("kmem_cache_alloc in ctrl_hw_add gave NULL pointers !!!\n"); - } - - sb_desc_1->sw_len = 8; - sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, setup) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes); - - sb_desc_1->buf = virt_to_phys(urb->setup_packet); - sb_desc_1->next = virt_to_phys(sb_desc_2); - dump_sb_desc(sb_desc_1); - - if (usb_pipeout(urb->pipe)) { - dbg_ctrl("Transfer for epid %d is OUT", epid); - - /* If this Control OUT transfer has an optional data stage we add an OUT token - before the mandatory IN (status) token, hence the reordered SB list */ - - if (urb->transfer_buffer) { - dbg_ctrl("This OUT transfer has an extra data stage"); - sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - sb_desc_1->next = virt_to_phys(sb_desc_3); - - sb_desc_3->sw_len = urb->transfer_buffer_length; - sb_desc_3->command = IO_STATE(USB_SB_command, tt, out) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes); - sb_desc_3->buf = virt_to_phys(urb->transfer_buffer); - sb_desc_3->next = virt_to_phys(sb_desc_2); - } - - sb_desc_2->sw_len = 1; - sb_desc_2->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - sb_desc_2->buf = 0; - sb_desc_2->next = 0; - dump_sb_desc(sb_desc_2); - - } else if (usb_pipein(urb->pipe)) { - - dbg_ctrl("Transfer for epid %d is IN", epid); - dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length); - dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen); - - sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, mem_flags); - - sb_desc_2->sw_len = urb->transfer_buffer_length ? - (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; - dbg_ctrl("sw_len got %d", sb_desc_2->sw_len); - - sb_desc_2->command = - IO_FIELD(USB_SB_command, rem, - urb->transfer_buffer_length % maxlen) | - IO_STATE(USB_SB_command, tt, in) | - IO_STATE(USB_SB_command, eot, yes); - - sb_desc_2->buf = 0; - sb_desc_2->next = virt_to_phys(sb_desc_3); - dump_sb_desc(sb_desc_2); - - sb_desc_3->sw_len = 1; - sb_desc_3->command = IO_FIELD(USB_SB_command, rem, 0) | - IO_STATE(USB_SB_command, tt, zout) | - IO_STATE(USB_SB_command, full, yes) | - IO_STATE(USB_SB_command, eot, yes) | - IO_STATE(USB_SB_command, eol, yes); - - sb_desc_3->buf = 0; - sb_desc_3->next = 0; - dump_sb_desc(sb_desc_3); - - urb_priv->rx_offset = 0; - urb_priv->eot = 0; - } - - urb_priv->first_sb = sb_desc_1; - - urb->hcpriv = (void *)urb_priv; - - /* Reset toggle bits and reset error count, remeber to di and ei */ - /* Warning: it is possible that this locking doesn't work with bottom-halves */ - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { - panic("Hold was set in %s\n", __FUNCTION__); - } - - - *R_USB_EPT_DATA &= - ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | - IO_MASK(R_USB_EPT_DATA, error_count_out) | - IO_MASK(R_USB_EPT_DATA, t_in) | - IO_MASK(R_USB_EPT_DATA, t_out)); - - /* Enable the EP descr. */ - - set_bit(epid, (void *)&ep_really_active); - - TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_1); - TxCtrlEPList[epid].hw_len = 0; - TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); - - restore_flags(flags); - - dump_ep_desc(&TxCtrlEPList[epid]); - - if (!(*R_DMA_CH8_SUB1_CMD & IO_MASK(R_DMA_CH8_SUB1_CMD, cmd))) { - *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); - - } - - DBFEXIT; -} - -static int etrax_usb_submit_urb(struct urb *urb, int mem_flags) -{ - etrax_hc_t *hc; - int rval = -EINVAL; - - DBFENTER; - - dump_urb(urb); - submit_urb_count++; - - hc = (etrax_hc_t*) urb->dev->bus->hcpriv; - - if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { - /* This request if for the Virtual Root Hub */ - rval = etrax_rh_submit_urb(urb); - - } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { - rval = etrax_usb_submit_ctrl_urb(urb, mem_flags); - - } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { - rval = etrax_usb_submit_bulk_urb(urb, mem_flags); - - } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - int bustime; - - if (urb->bandwidth == 0) { - bustime = usb_check_bandwidth(urb->dev, urb); - if (bustime < 0) { - rval = bustime; - } else { - usb_claim_bandwidth(urb->dev, urb, bustime, 0); - rval = etrax_usb_submit_intr_urb(urb, mem_flags); - } - - } - } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - warn("Isochronous traffic is not supported !!!"); - rval = -EINVAL; - } - - DBFEXIT; - - return rval; -} - -static int etrax_usb_unlink_urb(struct urb *urb) -{ - etrax_hc_t *hc = urb->dev->bus->hcpriv; - int epid; - int pos; - int devnum, endpoint, slow, maxlen; - etrax_urb_priv_t *hc_priv; - unsigned long flags; - - DBFENTER; - dump_urb(urb); - devnum = usb_pipedevice(urb->pipe); - endpoint = usb_pipeendpoint(urb->pipe); - slow = usb_pipeslow(urb->pipe); - maxlen = usb_maxpacket(urb->dev, urb->pipe, - usb_pipeout(urb->pipe)); - - epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen); - - if (epid == -1) - return 0; - - - if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { - int ret; - ret = etrax_rh_unlink_urb(urb); - DBFEXIT; - return ret; - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - int ret; - ret = etrax_usb_unlink_intr_urb(urb); - urb->status = -ENOENT; - if (urb->complete) { - urb->complete(urb); - } - DBFEXIT; - return ret; - } - - info("Unlink of BULK or CTRL"); - - save_flags(flags); - cli(); - - for (epid = 0; epid < 32; epid++) { - struct urb *u = URB_List[epid]; - pos = 0; - - for (; u; u = u->next) { - pos++; - if (u == urb) { - info("Found urb at epid %d, pos %d", epid, pos); - - if (pos == 1) { - if (usb_pipetype(u->pipe) == PIPE_CONTROL) { - if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) { - /* The EP was enabled, disable it and wait */ - TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); - while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid])); - } - - } else if (usb_pipetype(u->pipe) == PIPE_BULK) { - if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) { - TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); - while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid])); - } - } - - URB_List[epid] = u->next; - - } else { - struct urb *up; - for (up = URB_List[epid]; up->next != u; up = up->next); - up->next = u->next; - } - u->status = -ENOENT; - if (u->complete) { - u->complete(u); - } - - hc_priv = (etrax_urb_priv_t *)u->hcpriv; - cleanup_sb(hc_priv->first_sb); - kfree(hc_priv); - } - } - } - - restore_flags(flags); - - DBFEXIT; - return 0; -} - -static int etrax_usb_get_frame_number(struct usb_device *usb_dev) -{ - DBFENTER; - DBFEXIT; - return (*R_USB_FM_NUMBER); -} - -static int etrax_usb_allocate_dev(struct usb_device *usb_dev) -{ - DBFENTER; - DBFEXIT; - return 0; -} - -static int etrax_usb_deallocate_dev(struct usb_device *usb_dev) -{ - DBFENTER; - DBFEXIT; - return 0; -} - -static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs) -{ - etrax_hc_t *hc = (etrax_hc_t *)vhc; - int epid; - char eol; - struct urb *urb; - USB_EP_Desc_t *tmp_ep; - USB_SB_Desc_t *tmp_sb; - - DBFENTER; - - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) { - info("dma8_sub0_descr (BULK) intr."); - *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do); - } - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) { - info("dma8_sub1_descr (CTRL) intr."); - *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do); - } - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) { - info("dma8_sub2_descr (INT) intr."); - *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do); - } - if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) { - info("dma8_sub3_descr (ISO) intr."); - *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); - } - - DBFEXIT; -} - -static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs) -{ - int epid = 0; - struct urb *urb; - etrax_urb_priv_t *urb_priv; - - *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do); - - while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) { - if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { - - goto skip_out; - } - - if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) { - - goto skip_out; - } - - epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status); - - urb = URB_List[epid]; - - if (urb && usb_pipein(urb->pipe)) { - urb_priv = (etrax_urb_priv_t *)urb->hcpriv; - - if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - struct in_chunk *in; - dbg_intr("Packet for epid %d in rx buffers", epid); - in = kmalloc(sizeof(struct in_chunk), GFP_ATOMIC); - in->length = myNextRxDesc->hw_len; - in->data = kmalloc(in->length, GFP_ATOMIC); - memcpy(in->data, phys_to_virt(myNextRxDesc->buf), in->length); - list_add_tail(&in->list, &urb_priv->ep_in_list); -#ifndef ETRAX_USB_INTR_IRQ - etrax_usb_hc_intr_top_half(irq, vhc, regs); -#endif - - } else { - if ((urb_priv->rx_offset + myNextRxDesc->hw_len) > - urb->transfer_buffer_length) { - err("Packet (epid: %d) in RX buffer was bigger " - "than the URB has room for !!!", epid); - goto skip_out; - } - - memcpy(urb->transfer_buffer + urb_priv->rx_offset, - phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len); - - urb_priv->rx_offset += myNextRxDesc->hw_len; - } - - if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) { - urb_priv->eot = 1; - } - - } else { - err("This is almost fatal, inpacket for epid %d which does not exist " - " or is out !!!\nURB was at 0x%08X", epid, urb); - - goto skip_out; - } - - skip_out: - myPrevRxDesc = myNextRxDesc; - myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol); - myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol); - myLastRxDesc = myPrevRxDesc; - - myNextRxDesc->status = 0; - myNextRxDesc = phys_to_virt(myNextRxDesc->next); - } -} - - - -static void cleanup_sb(USB_SB_Desc_t *sb) -{ - USB_SB_Desc_t *next_sb; - - DBFENTER; - - if (sb == NULL) { - err("cleanup_sb was given a NULL pointer"); - return; - } - - while (!(sb->command & IO_MASK(USB_SB_command, eol))) { - next_sb = (USB_SB_Desc_t *)phys_to_virt(sb->next); - kmem_cache_free(usb_desc_cache, sb); - sb = next_sb; - } - - kmem_cache_free(usb_desc_cache, sb); - - DBFEXIT; - -} - -static int handle_control_transfer_attn(char epid, int status) -{ - struct urb *old_urb; - etrax_urb_priv_t *hc_priv; - - DBFENTER; - - clear_bit(epid, (void *)&ep_really_active); - - old_urb = URB_List[epid]; - URB_List[epid] = old_urb->next; - - /* if (status == 0 && IN) find data and copy to urb */ - if (status == 0 && usb_pipein(old_urb->pipe)) { - unsigned long flags; - etrax_urb_priv_t *urb_priv; - - urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - save_flags(flags); - cli(); - if (urb_priv->eot == 1) { - old_urb->actual_length = urb_priv->rx_offset; - dbg_ctrl("urb_priv->rx_offset: %d in handle_control_attn", urb_priv->rx_offset); - } else { - status = -EPROTO; - old_urb->actual_length = 0; - err("(CTRL) No eot set in IN data!!! rx_offset: %d", urb_priv->rx_offset); - } - - restore_flags(flags); - } - - /* If there are any more URB's in the list we'd better start sending */ - if (URB_List[epid]) { - etrax_usb_do_ctrl_hw_add(URB_List[epid], epid, - usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, - usb_pipeout(URB_List[epid]->pipe)), - GFP_KERNEL); - } -#if 1 - else { - /* This means that this EP is now free, deconfigure it */ - etrax_usb_free_epid(epid); - } -#endif - - /* Remember to free the SB's */ - hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; - cleanup_sb(hc_priv->first_sb); - kfree(hc_priv); - - old_urb->status = status; - if (old_urb->complete) { - old_urb->complete(old_urb); - } - - DBFEXIT; -} - - - -static void etrax_usb_hc_intr_bottom_half(void *data) -{ - struct usb_reg_context *reg = (struct usb_reg_context *)data; - struct urb *old_urb; - - int error_code; - int epid; - - __u32 r_usb_ept_data; - - etrax_hc_t *hc = reg->hc; - __u16 r_usb_rh_port_status_1; - __u16 r_usb_rh_port_status_2; - - DBFENTER; - - if (reg->r_usb_irq_mask_read & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) { - - /* - The Etrax RH does not include a wPortChange register, so this has - to be handled in software. See section 11.16.2.6.2 in USB 1.1 spec - for details. - */ - - r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1; - r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2; - - dbg_rh("port_status pending"); - dbg_rh("r_usb_rh_port_status_1: 0x%04X", r_usb_rh_port_status_1); - dbg_rh("r_usb_rh_port_status_2: 0x%04X", r_usb_rh_port_status_2); - - /* C_PORT_CONNECTION is set on any transition */ - hc->rh.wPortChange_1 |= - ((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) != - (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ? - (1 << RH_PORT_CONNECTION) : 0; - - hc->rh.wPortChange_2 |= - ((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) != - (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ? - (1 << RH_PORT_CONNECTION) : 0; - - /* C_PORT_ENABLE is _only_ set on a one to zero transition */ - hc->rh.wPortChange_1 |= - ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE)) - && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_ENABLE) : 0; - - hc->rh.wPortChange_2 |= - ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE)) - && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_ENABLE) : 0; - - /* C_PORT_SUSPEND seems difficult, lets ignore it.. (for now) */ - - /* C_PORT_RESET is _only_ set on a transition from the resetting state - to the enabled state */ - hc->rh.wPortChange_1 |= - ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET)) - && (r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_RESET) : 0; - - hc->rh.wPortChange_2 |= - ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET)) - && (r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? - (1 << RH_PORT_RESET) : 0; - - hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1; - hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2; - } - - for (epid = 0; epid < 32; epid++) { - - unsigned long flags; - - save_flags(flags); - cli(); - - *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); - r_usb_ept_data = *R_USB_EPT_DATA; - - restore_flags(flags); - - if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) { - warn("Was hold for epid %d", epid); - continue; - } - - if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) { - continue; - } - - - if (test_bit(epid, (void *)®->r_usb_epid_attn)) { - - if (URB_List[epid] == NULL) { - err("R_USB_EPT_DATA is 0x%08X", r_usb_ept_data); - err("submit urb has been called %d times..", submit_urb_count); - err("EPID_ATTN for epid %d, with NULL entry in list", epid); - return; - } - - dbg_ep("r_usb_ept_data [%d] == 0x%08X", epid, - r_usb_ept_data); - - error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, - r_usb_ept_data); - - if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* no_error means that this urb was sucessfully sent or that we have - some undefinde error*/ - - if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 || - IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3) { - /* Actually there were transmission errors */ - warn("Undefined error for endpoint %d", epid); - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - handle_control_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - handle_bulk_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, -EPROTO); - } - - } else { - - if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - etrax_usb_do_intr_recover(epid); - } else { - panic("Epid attention for epid %d (none INTR), with no errors and no " - "exessive retry r_usb_status is 0x%02X\n", - epid, reg->r_usb_status); - } - - } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { - panic("Epid attention for epid %d, with no errors and no " - "exessive retry r_usb_status is 0x%02X\n", - epid, reg->r_usb_status); - - } - - warn("Epid attention for epid %d, with no errors and no " - "exessive retry r_usb_status is 0x%02X", - epid, reg->r_usb_status); - warn("OUT error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_out, - r_usb_ept_data)); - warn("IN error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_in, - r_usb_ept_data)); - - - } - - } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) { - warn("Stall for endpoint %d", epid); - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - handle_control_transfer_attn(epid, -EPIPE); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - handle_bulk_transfer_attn(epid, -EPIPE); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, -EPIPE); - } - - - } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) { - panic("USB bus error for endpoint %d\n", epid); - - } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) { - warn("Buffer error for endpoint %d", epid); - - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - handle_control_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - handle_bulk_transfer_attn(epid, -EPROTO); - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, -EPROTO); - } - - } - } else if (test_bit(epid, (void *)&ep_really_active)) { - /* Should really be else if (testbit(really active)) */ - - if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { - - if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))) { - /* Now we have to verify that this CTRL endpoint got disabled - cause it reached end of list with no error */ - - if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == - IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* - This means that the endpoint has no error, is disabled - and had inserted traffic, - i.e. transfer sucessfully completed - */ - dbg_ctrl("Last SB for CTRL %d sent sucessfully", epid); - handle_control_transfer_attn(epid, 0); - } - } - - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { - if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))) { - /* Now we have to verify that this BULK endpoint go disabled - cause it reached end of list with no error */ - - if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == - IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { - /* - This means that the endpoint has no error, is disabled - and had inserted traffic, - i.e. transfer sucessfully completed - */ - dbg_bulk("Last SB for BULK %d sent sucessfully", epid); - handle_bulk_transfer_attn(epid, 0); - } - } - } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { - handle_intr_transfer_attn(epid, 0); - } - } - - } - - kfree(reg); - - DBFEXIT; -} - - -static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs) -{ - struct usb_reg_context *reg; - - DBFENTER; - - reg = (struct usb_reg_context *)kmalloc(sizeof(struct usb_reg_context), GFP_ATOMIC); - - if (!(reg)) { - panic("kmalloc failed in top_half\n"); - } - - reg->hc = (etrax_hc_t *)vhc; - reg->r_usb_irq_mask_read = *R_USB_IRQ_MASK_READ; - reg->r_usb_status = *R_USB_STATUS; - -#if 0 - if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { - panic("r_usb_status said perror\n"); - } - if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { - panic("r_usb_status said ourun !!!\n"); - } -#endif - - reg->r_usb_epid_attn = *R_USB_EPID_ATTN; - - reg->r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1; - reg->r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2; - - reg->usb_bh.sync = 0; - reg->usb_bh.routine = etrax_usb_hc_intr_bottom_half; - reg->usb_bh.data = reg; - - queue_task(®->usb_bh, &tq_immediate); - mark_bh(IMMEDIATE_BH); - - DBFEXIT; -} - -static int etrax_rh_submit_urb(struct urb *urb) -{ - struct usb_device *usb_dev = urb->dev; - etrax_hc_t *hc = usb_dev->bus->hcpriv; - unsigned int pipe = urb->pipe; - struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; - void *data = urb->transfer_buffer; - int leni = urb->transfer_buffer_length; - int len = 0; - int status = 0; - int stat = 0; - int i; - - __u16 cstatus; - - __u16 bmRType_bReq; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - - DBFENTER; - - if (usb_pipetype (pipe) == PIPE_INTERRUPT) { - dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval); - hc->rh.urb = urb; - hc->rh.send = 1; - hc->rh.interval = urb->interval; - etrax_rh_init_int_timer(urb); - DBFEXIT; - - return 0; - } - - bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8; - wValue = le16_to_cpu(cmd->wValue); - wIndex = le16_to_cpu(cmd->wIndex); - wLength = le16_to_cpu(cmd->wLength); - - dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq); - dbg_rh("wValue : 0x%04X (%d)", wValue, wValue); - dbg_rh("wIndex : 0x%04X (%d)", wIndex, wIndex); - dbg_rh("wLength : 0x%04X (%d)", wLength, wLength); - - switch (bmRType_bReq) { - - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ - - case RH_GET_STATUS: - *(__u16 *) data = cpu_to_le16 (1); - OK (2); - - case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *) data = cpu_to_le16 (0); - OK (2); - - case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *) data = cpu_to_le16 (0); - OK (2); - - case RH_GET_STATUS | RH_CLASS: - *(__u32 *) data = cpu_to_le32 (0); - OK (4); /* hub power ** */ - - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - if (wIndex == 1) { - *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1); - *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1); - } - else if (wIndex == 2) { - *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2); - *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2); - } - else { - dbg_rh("RH_GET_STATUS whith invalid wIndex !!"); - OK(0); - } - - OK(4); - - case RH_CLEAR_FEATURE | RH_ENDPOINT: - switch (wValue) { - case (RH_ENDPOINT_STALL): - OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_CLASS: - switch (wValue) { - case (RH_C_HUB_OVER_CURRENT): - OK (0); /* hub power over current ** */ - } - break; - - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_ENABLE): - if (wIndex == 1) { - - dbg_rh("trying to do disable of port 1"); - - *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes); - while (hc->rh.prev_wPortStatus_1 & - IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)); - *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); - dbg_rh("Port 1 is disabled"); - - } else if (wIndex == 2) { - - dbg_rh("trying to do disable of port 2"); - - *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes); - while (hc->rh.prev_wPortStatus_2 & - IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes)); - *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); - dbg_rh("Port 2 is disabled"); - - } else { - dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_PORT_SUSPEND): - /* Opposite to suspend should be resume, so well do a resume */ - if (wIndex == 1) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port1) | - IO_STATE(R_USB_COMMAND, port_cmd, resume)| - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else if (wIndex == 2) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port2) | - IO_STATE(R_USB_COMMAND, port_cmd, resume)| - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else { - dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_PORT_POWER): - OK (0); /* port power ** */ - case (RH_C_PORT_CONNECTION): - - if (wIndex == 1) { - hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION); - } - else if (wIndex == 2) { - hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION); - } - else { - dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_C_PORT_ENABLE): - if (wIndex == 1) { - hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE); - } - else if (wIndex == 2) { - hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE); - } - else { - dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE " - "with invalid wIndex == %d!!", wIndex); - } - OK (0); - case (RH_C_PORT_SUSPEND): -/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ - OK (0); - case (RH_C_PORT_OVER_CURRENT): - OK (0); /* port power over current ** */ - case (RH_C_PORT_RESET): - if (wIndex == 1) { - hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET); - } - else if (wIndex == 2) { - dbg_rh("This is wPortChange before clear: 0x%04X", hc->rh.wPortChange_2); - - hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET); - dbg_rh("This is wPortChange after clear: 0x%04X", hc->rh.wPortChange_2); - } else { - dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET " - "with invalid index == %d!!", wIndex); - } - - OK (0); - - } - break; - - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_SUSPEND): - if (wIndex == 1) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port1) | - IO_STATE(R_USB_COMMAND, port_cmd, suspend) | - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else if (wIndex == 2) { - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port2) | - IO_STATE(R_USB_COMMAND, port_cmd, suspend) | - IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); - } else { - dbg_rh("RH_SET_FEATURE->RH_C_PORT_SUSPEND " - "with invalid wIndex == %d!!", wIndex); - } - - OK (0); - case (RH_PORT_RESET): - if (wIndex == 1) { - int port1_retry; - - port1_redo: - dbg_rh("Doing reset of port 1"); - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_cmd, reset) | - IO_STATE(R_USB_COMMAND, port_sel, port1); - - /* We must once again wait at least 10ms for the device to recover */ - - port1_retry = 0; - while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_1)) & - IO_STATE(R_USB_RH_PORT_STATUS_1, - enabled, yes))) { - printk(""); if (port1_retry++ >= 10000) {goto port1_redo;} - } - - /* This only seems to work if we use printk, - not even schedule() works !!! WHY ?? */ - - udelay(15000); - } - else if (wIndex == 2) { - int port2_retry; - - port2_redo: - dbg_rh("Doing reset of port 2"); - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_cmd, reset) | - IO_STATE(R_USB_COMMAND, port_sel, port2); - - /* We must once again wait at least 10ms for the device to recover */ - - port2_retry = 0; - while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_2)) & - IO_STATE(R_USB_RH_PORT_STATUS_2, - enabled, yes))) { - printk(""); if (port2_retry++ >= 10000) {goto port2_redo;} - } - - /* This only seems to work if we use printk, - not even schedule() works !!! WHY ?? */ - - udelay(15000); - } - - /* Try to bring the HC into running state */ - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - dbg_rh("...Done"); - OK(0); - - case (RH_PORT_POWER): - OK (0); /* port power ** */ - case (RH_PORT_ENABLE): - /* There is no rh port enable command in the Etrax USB interface!!!! */ - OK (0); - - } - break; - - case RH_SET_ADDRESS: - hc->rh.devnum = wValue; - dbg_rh("RH address set to: %d", hc->rh.devnum); - OK (0); - - case RH_GET_DESCRIPTOR: - switch ((wValue & 0xff00) >> 8) { - case (0x01): /* device descriptor */ - len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength)); - memcpy (data, root_hub_dev_des, len); - OK (len); - case (0x02): /* configuration descriptor */ - len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength)); - memcpy (data, root_hub_config_des, len); - OK (len); - case (0x03): /* string descriptors */ - len = usb_root_hub_string (wValue & 0xff, - 0xff, "ETRAX 100LX", - data, wLength); - if (len > 0) { - OK(min_t(int, leni, len)); - } else - stat = -EPIPE; - } - break; - - case RH_GET_DESCRIPTOR | RH_CLASS: - root_hub_hub_des[2] = hc->rh.numports; - len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength)); - memcpy (data, root_hub_hub_des, len); - OK (len); - - case RH_GET_CONFIGURATION: - *(__u8 *) data = 0x01; - OK (1); - - case RH_SET_CONFIGURATION: - OK (0); - - default: - stat = -EPIPE; - } - - urb->actual_length = len; - urb->status = stat; - urb->dev=NULL; - if (urb->complete) { - urb->complete (urb); - } - DBFEXIT; - - return 0; -} - -static int __init etrax_usb_hc_init(void) -{ - static etrax_hc_t *hc; - struct usb_bus *bus; - struct usb_device *usb_rh; - - DBFENTER; - - info("ETRAX 100LX USB-HCD %s (c) 2001 Axis Communications AB\n", usb_hcd_version); - - hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL); - - /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */ - usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0, 0, 0, 0); - if (!usb_desc_cache) { - panic("USB Desc Cache allocation failed !!!\n"); - } - - etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations); - hc->bus = bus; - bus->hcpriv = hc; - - /* Initalize RH to the default address. - And make sure that we have no status change indication */ - hc->rh.numports = 2; /* The RH has two ports */ - hc->rh.devnum = 0; - hc->rh.wPortChange_1 = 0; - hc->rh.wPortChange_2 = 0; - - /* Also initate the previous values to zero */ - hc->rh.prev_wPortStatus_1 = 0; - hc->rh.prev_wPortStatus_2 = 0; - - /* Initialize the intr-traffic flags */ - hc->intr.sleeping = 0; - hc->intr.wq = NULL; - - /* Initially all ep's are free except ep 0 */ - ep_usage_bitmask = 0; - set_bit(0, (void *)&ep_usage_bitmask); - ep_really_active = 0; - - memset(URB_List, 0, sizeof(URB_List)); - - /* This code should really be moved */ - - if (request_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)")) { - err("Could not allocate DMA ch 8 for USB"); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - if (request_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)")) { - err("Could not allocate DMA ch 9 for USB"); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } -#if 0 /* Moved to head.S */ - *R_GEN_CONFIG = genconfig_shadow = - (genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) | - IO_MASK(R_GEN_CONFIG, usb2) | - IO_MASK(R_GEN_CONFIG, dma8) | - IO_MASK(R_GEN_CONFIG, dma9))) | - IO_STATE(R_GEN_CONFIG, dma8, usb) | - IO_STATE(R_GEN_CONFIG, dma9, usb) -#ifdef CONFIG_ETRAX_USB_HOST_PORT1 - | IO_STATE(R_GEN_CONFIG, usb1, select) -#endif -#ifdef CONFIG_ETRAX_USB_HOST_PORT2 - | IO_STATE(R_GEN_CONFIG, usb2, select) -#endif - ; -#endif - - usb_register_bus(hc->bus); - - /* We may have to set more bits, but these are the obvious ones */ - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) | - IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set); - - *R_IRQ_MASK2_SET = - IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | - IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); - - *R_USB_IRQ_MASK_SET = - IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set) | - IO_STATE(R_USB_IRQ_MASK_SET, ctl_eot, set) | - IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) | -#ifdef ETRAX_USB_INTR_IRQ - IO_STATE(R_USB_IRQ_MASK_SET, intr_eot, set) | -#endif - IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) | - IO_STATE(R_USB_IRQ_MASK_SET, port_status, set); - - if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_intr_top_half, 0, - "ETRAX 100LX built-in USB (HC)", hc)) { - err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0, - "ETRAX 100LX built-in USB (Rx)", hc)) { - err("Could not allocate IRQ %d for USB", ETRAX_USB_RX_IRQ); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - if (request_irq(ETRAX_USB_TX_IRQ, etrax_usb_tx_interrupt, 0, - "ETRAX 100LX built-in USB (Tx)", hc)) { - err("Could not allocate IRQ %d for USB", ETRAX_USB_TX_IRQ); - etrax_usb_hc_cleanup(); - DBFEXIT; - return -1; - } - - /* Reset the USB interface (configures as HC) */ - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, reset) | - IO_STATE(R_USB_COMMAND, port_cmd, reset); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); -#if 1 - /* Initate PSTART to all unallocatable bit times */ - *R_USB_FM_PSTART = IO_FIELD(R_USB_FM_PSTART, value, 10000); -#endif - -#ifdef CONFIG_ETRAX_USB_HOST_PORT1 - *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); -#endif - -#ifdef CONFIG_ETRAX_USB_HOST_PORT2 - *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); -#endif - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, host_config) | - IO_STATE(R_USB_COMMAND, port_cmd, reset); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, port_sel, port1) | - IO_STATE(R_USB_COMMAND, port_cmd, reset); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - /* Here we must wait at least 10ms so the device has time to recover */ - udelay(15000); - - init_rx_buffers(); - init_tx_bulk_ep(); - init_tx_ctrl_ep(); - init_tx_intr_ep(); - - /* This works. It seems like the host_run command only has effect when a device is connected, - i.e. it has to be done when a interrup */ - *R_USB_COMMAND = - IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); - - nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); - - usb_rh = usb_alloc_dev(NULL, hc->bus); - hc->bus->root_hub = usb_rh; - usb_connect(usb_rh); - usb_new_device(usb_rh); - - DBFEXIT; - - return 0; -} - -static void etrax_usb_hc_cleanup(void) -{ - DBFENTER; - - free_irq(ETRAX_USB_HC_IRQ, NULL); - free_irq(ETRAX_USB_RX_IRQ, NULL); - free_irq(ETRAX_USB_TX_IRQ, NULL); - - free_dma(USB_TX_DMA_NBR); - free_dma(USB_RX_DMA_NBR); - usb_deregister_bus(etrax_usb_bus); - - DBFEXIT; -} - -module_init(etrax_usb_hc_init); -module_exit(etrax_usb_hc_cleanup); diff --git a/arch/cris/drivers/usb-host.h b/arch/cris/drivers/usb-host.h deleted file mode 100644 index 434d50b26021..000000000000 --- a/arch/cris/drivers/usb-host.h +++ /dev/null @@ -1,243 +0,0 @@ -#ifndef __LINUX_ETRAX_USB_H -#define __LINUX_ETRAX_USB_H - -#include <linux/types.h> -#include <linux/list.h> - -typedef struct USB_IN_Desc { - __u16 sw_len; - __u16 command; - unsigned long next; - unsigned long buf; - __u16 hw_len; - __u16 status; -} USB_IN_Desc_t; - -typedef struct USB_SB_Desc { - __u16 sw_len; - __u16 command; - unsigned long next; - unsigned long buf; - __u32 dummy; -} USB_SB_Desc_t; - -typedef struct USB_EP_Desc { - __u16 hw_len; - __u16 command; - unsigned long sub; - unsigned long nep; - __u32 dummy; -} USB_EP_Desc_t; - -struct virt_root_hub { - int devnum; - void *urb; - void *int_addr; - int send; - int interval; - int numports; - struct timer_list rh_int_timer; - __u16 wPortChange_1; - __u16 wPortChange_2; - __u16 prev_wPortStatus_1; - __u16 prev_wPortStatus_2; -}; - -struct etrax_usb_intr_traffic { - int sleeping; - int error; - struct wait_queue *wq; -}; - -typedef struct etrax_usb_hc { - struct usb_bus *bus; - struct virt_root_hub rh; - struct etrax_usb_intr_traffic intr; -} etrax_hc_t; - -typedef enum {idle, eot, nodata} etrax_usb_rx_state_t; - -typedef struct etrax_usb_urb_priv { - USB_SB_Desc_t *first_sb; - __u32 rx_offset; - etrax_usb_rx_state_t rx_state; - __u8 eot; - struct list_head ep_in_list; -} etrax_urb_priv_t; - - -struct usb_reg_context -{ - etrax_hc_t *hc; - __u32 r_usb_epid_attn; - __u8 r_usb_status; - __u32 r_usb_rh_port_status_1; - __u32 r_usb_rh_port_status_2; - __u32 r_usb_irq_mask_read; - struct tq_struct usb_bh; -#if 0 - __u32 r_usb_ept_data[32]; -#endif -}; - -struct in_chunk -{ - void *data; - int length; - char epid; - struct list_head list; -}; - - -/* --------------------------------------------------------------------------- - Virtual Root HUB - ------------------------------------------------------------------------- */ -/* destination of request */ -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 - -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -/* Our Vendor Specific feature */ -#define RH_REMOVE_EP 0x00 - - -#define RH_ACK 0x01 -#define RH_REQ_ERR -1 -#define RH_NACK 0x00 - -/* Field definitions for */ - -#define USB_IN_command__eol__BITNR 0 /* command macros */ -#define USB_IN_command__eol__WIDTH 1 -#define USB_IN_command__eol__no 0 -#define USB_IN_command__eol__yes 1 - -#define USB_IN_command__intr__BITNR 3 -#define USB_IN_command__intr__WIDTH 1 -#define USB_IN_command__intr__no 0 -#define USB_IN_command__intr__yes 1 - -#define USB_IN_status__eop__BITNR 1 /* status macros. */ -#define USB_IN_status__eop__WIDTH 1 -#define USB_IN_status__eop__no 0 -#define USB_IN_status__eop__yes 1 - -#define USB_IN_status__eot__BITNR 5 -#define USB_IN_status__eot__WIDTH 1 -#define USB_IN_status__eot__no 0 -#define USB_IN_status__eot__yes 1 - -#define USB_IN_status__error__BITNR 6 -#define USB_IN_status__error__WIDTH 1 -#define USB_IN_status__error__no 0 -#define USB_IN_status__error__yes 1 - -#define USB_IN_status__nodata__BITNR 7 -#define USB_IN_status__nodata__WIDTH 1 -#define USB_IN_status__nodata__no 0 -#define USB_IN_status__nodata__yes 1 - -#define USB_IN_status__epid__BITNR 8 -#define USB_IN_status__epid__WIDTH 5 - -#define USB_EP_command__eol__BITNR 0 -#define USB_EP_command__eol__WIDTH 1 -#define USB_EP_command__eol__no 0 -#define USB_EP_command__eol__yes 1 - -#define USB_EP_command__eof__BITNR 1 -#define USB_EP_command__eof__WIDTH 1 -#define USB_EP_command__eof__no 0 -#define USB_EP_command__eof__yes 1 - -#define USB_EP_command__intr__BITNR 3 -#define USB_EP_command__intr__WIDTH 1 -#define USB_EP_command__intr__no 0 -#define USB_EP_command__intr__yes 1 - -#define USB_EP_command__enable__BITNR 4 -#define USB_EP_command__enable__WIDTH 1 -#define USB_EP_command__enable__no 0 -#define USB_EP_command__enable__yes 1 - -#define USB_EP_command__hw_valid__BITNR 5 -#define USB_EP_command__hw_valid__WIDTH 1 -#define USB_EP_command__hw_valid__no 0 -#define USB_EP_command__hw_valid__yes 1 - -#define USB_EP_command__epid__BITNR 8 -#define USB_EP_command__epid__WIDTH 5 - -#define USB_SB_command__eol__BITNR 0 /* command macros. */ -#define USB_SB_command__eol__WIDTH 1 -#define USB_SB_command__eol__no 0 -#define USB_SB_command__eol__yes 1 - -#define USB_SB_command__eot__BITNR 1 -#define USB_SB_command__eot__WIDTH 1 -#define USB_SB_command__eot__no 0 -#define USB_SB_command__eot__yes 1 - -#define USB_SB_command__intr__BITNR 3 -#define USB_SB_command__intr__WIDTH 1 -#define USB_SB_command__intr__no 0 -#define USB_SB_command__intr__yes 1 - -#define USB_SB_command__tt__BITNR 4 -#define USB_SB_command__tt__WIDTH 2 -#define USB_SB_command__tt__zout 0 -#define USB_SB_command__tt__in 1 -#define USB_SB_command__tt__out 2 -#define USB_SB_command__tt__setup 3 - - -#define USB_SB_command__rem__BITNR 8 -#define USB_SB_command__rem__WIDTH 6 - -#define USB_SB_command__full__BITNR 6 -#define USB_SB_command__full__WIDTH 1 -#define USB_SB_command__full__no 0 -#define USB_SB_command__full__yes 1 - -#endif diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile index a340c8fb59fa..7f6d9b43cf1f 100644 --- a/arch/cris/kernel/Makefile +++ b/arch/cris/kernel/Makefile @@ -1,21 +1,13 @@ -# $Id: Makefile,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +# $Id: Makefile,v 1.8 2003/04/09 05:20:47 starvik Exp $ # # Makefile for the linux kernel. # -extra-y := head.o - -obj-y := process.o signal.o entry.o traps.o irq.o \ - ptrace.o setup.o time.o sys_cris.o shadows.o \ - debugport.o semaphore.o +obj-y := process.o traps.o irq.o ptrace.o setup.o \ + time.o sys_cris.o semaphore.o obj-$(CONFIG_MODULES) += ksyms.o -obj-$(CONFIG_ETRAX_KGDB) += kgdb.o - -# This dependency isn't caught by mkdep. See entry.S. -entry.o: entryoffsets.s - -entryoffsets.s: entryoffsets.c - $(CC) $(CFLAGS) -S -c $< +obj-$(CONFIG_MODULES) += module.o clean: + diff --git a/arch/cris/kernel/entryoffsets.c b/arch/cris/kernel/entryoffsets.c deleted file mode 100644 index f1480acd1047..000000000000 --- a/arch/cris/kernel/entryoffsets.c +++ /dev/null @@ -1,62 +0,0 @@ -/* linux/arch/cris/entryoffsets.c - * - * Copyright (C) 2001 Axis Communications AB - * - * Generate structure offsets for use in entry.S. No extra processing - * needed more than compiling this file to assembly code. Horrendous - * assembly code will be generated, so don't look at that. - * - * Authors: Hans-Peter Nilsson (hp@axis.com) - */ - -/* There can be string constants fallout from inline functions, so we'd - better make sure we don't assemble anything emitted from inclusions. */ -__asm__ (".if 0"); - -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <asm/processor.h> - -/* Exclude everything except the assembly by wrapping it in ".if 0". */ -#undef VAL -#define VAL(NAME, VALUE) \ -void NAME ## _fun (void) \ - { \ - __asm__ (".endif \n" \ - #NAME " = %0 \n" \ - ".if 0\n" \ - : : "i" (VALUE)); \ - } - -#undef OF -#define OF(NAME, TYPE, MEMBER) \ - VAL (NAME, offsetof (TYPE, MEMBER)) - -/* task_struct offsets. */ -#error OF (LTASK_SIGPENDING, struct task_struct, sigpending) -#error OF (LTASK_NEEDRESCHED, struct task_struct, need_resched) -#error OF (LTASK_PTRACE, struct task_struct, ptrace) -OF (LTASK_PID, struct task_struct, pid) - -/* pt_regs offsets. */ -OF (LORIG_R10, struct pt_regs, orig_r10) -OF (LR13, struct pt_regs, r13) -OF (LR12, struct pt_regs, r12) -OF (LR11, struct pt_regs, r11) -OF (LR10, struct pt_regs, r10) -OF (LR9, struct pt_regs, r9) -OF (LMOF, struct pt_regs, mof) -OF (LDCCR, struct pt_regs, dccr) -OF (LSRP, struct pt_regs, srp) -OF (LIRP, struct pt_regs, irp) - -/* thread_struct offsets. */ -OF (LTHREAD_KSP, struct thread_struct, ksp) -OF (LTHREAD_USP, struct thread_struct, usp) -OF (LTHREAD_DCCR, struct thread_struct, dccr) - -/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these. */ -VAL (LCLONE_VM, CLONE_VM) -VAL (LCLONE_UNTRACED, CLONE_UNTRACED) - -__asm__ (".endif"); diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index c63a5f02b00d..934f8715b5af 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: irq.c,v 1.8 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/kernel/irq.c * @@ -23,7 +23,7 @@ #include <linux/config.h> #include <linux/ptrace.h> -#include <linux/errno.h> + #include <linux/kernel_stat.h> #include <linux/signal.h> #include <linux/sched.h> @@ -34,47 +34,34 @@ #include <linux/random.h> #include <linux/init.h> #include <linux/seq_file.h> +#include <linux/errno.h> -#include <asm/system.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/bitops.h> -#include <asm/svinto.h> - -char *hw_bp_msg = "BP 0x%x\n"; - -static inline void -mask_irq(unsigned int irq_nr) -{ - *R_VECT_MASK_CLR = 1 << irq_nr; -} - -static inline void -unmask_irq(unsigned int irq_nr) -{ - *R_VECT_MASK_SET = 1 << irq_nr; -} +/* Defined in arch specific irq.c */ +extern void arch_setup_irq(int irq); +extern void arch_free_irq(int irq); void disable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); mask_irq(irq_nr); - restore_flags(flags); + local_irq_restore(flags); } void enable_irq(unsigned int irq_nr) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); unmask_irq(irq_nr); - restore_flags(flags); + local_irq_restore(flags); } unsigned long @@ -89,140 +76,11 @@ probe_irq_off(unsigned long x) return 0; } -irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ - -/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is - * global just so that the kernel gdb can use it. - */ - -void -set_int_vector(int n, irqvectptr addr, irqvectptr saddr) -{ - /* remember the shortcut entry point, after the prologue */ - - irq_shortcuts[n] = saddr; - - etrax_irv->v[n + 0x20] = (irqvectptr)addr; -} - -/* the breakpoint vector is obviously not made just like the normal irq handlers - * but needs to contain _code_ to jump to addr. - * - * the BREAK n instruction jumps to IBR + n * 8 - */ - -void -set_break_vector(int n, irqvectptr addr) -{ - unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2]; - unsigned long *jaddr = (unsigned long *)(jinstr + 1); - - /* if you don't know what this does, do not touch it! */ - - *jinstr = 0x0d3f; - *jaddr = (unsigned long)addr; - - /* 00000026 <clrlop+1a> 3f0d82000000 jump 0x82 */ -} - - -/* - * This builds up the IRQ handler stubs using some ugly macros in irq.h - * - * These macros create the low-level assembly IRQ routines that do all - * the operations that are needed. They are also written to be fast - and to - * disable interrupts as little as humanly possible. - * - */ - -/* IRQ0 and 1 are special traps */ -void hwbreakpoint(void); -void IRQ1_interrupt(void); -BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */ -BUILD_IRQ(3, 0x08) -BUILD_IRQ(4, 0x10) -BUILD_IRQ(5, 0x20) -BUILD_IRQ(6, 0x40) -BUILD_IRQ(7, 0x80) -BUILD_IRQ(8, 0x100) -BUILD_IRQ(9, 0x200) -BUILD_IRQ(10, 0x400) -BUILD_IRQ(11, 0x800) -BUILD_IRQ(12, 0x1000) -BUILD_IRQ(13, 0x2000) -void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ -void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ -BUILD_IRQ(16, 0x10000) -BUILD_IRQ(17, 0x20000) -BUILD_IRQ(18, 0x40000) -BUILD_IRQ(19, 0x80000) -BUILD_IRQ(20, 0x100000) -BUILD_IRQ(21, 0x200000) -BUILD_IRQ(22, 0x400000) -BUILD_IRQ(23, 0x800000) -BUILD_IRQ(24, 0x1000000) -BUILD_IRQ(25, 0x2000000) -/* IRQ 26-30 are reserved */ -BUILD_IRQ(31, 0x80000000) - -/* - * Pointers to the low-level handlers - */ - -static void (*interrupt[NR_IRQS])(void) = { - NULL, NULL, IRQ2_interrupt, IRQ3_interrupt, - IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, - IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, - IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, - IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, - IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, - IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, - IRQ31_interrupt -}; - -static void (*sinterrupt[NR_IRQS])(void) = { - NULL, NULL, sIRQ2_interrupt, sIRQ3_interrupt, - sIRQ4_interrupt, sIRQ5_interrupt, sIRQ6_interrupt, sIRQ7_interrupt, - sIRQ8_interrupt, sIRQ9_interrupt, sIRQ10_interrupt, sIRQ11_interrupt, - sIRQ12_interrupt, sIRQ13_interrupt, NULL, NULL, - sIRQ16_interrupt, sIRQ17_interrupt, sIRQ18_interrupt, sIRQ19_interrupt, - sIRQ20_interrupt, sIRQ21_interrupt, sIRQ22_interrupt, sIRQ23_interrupt, - sIRQ24_interrupt, sIRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, - sIRQ31_interrupt -}; - -static void (*bad_interrupt[NR_IRQS])(void) = { - NULL, NULL, - NULL, bad_IRQ3_interrupt, - bad_IRQ4_interrupt, bad_IRQ5_interrupt, - bad_IRQ6_interrupt, bad_IRQ7_interrupt, - bad_IRQ8_interrupt, bad_IRQ9_interrupt, - bad_IRQ10_interrupt, bad_IRQ11_interrupt, - bad_IRQ12_interrupt, bad_IRQ13_interrupt, - NULL, NULL, - bad_IRQ16_interrupt, bad_IRQ17_interrupt, - bad_IRQ18_interrupt, bad_IRQ19_interrupt, - bad_IRQ20_interrupt, bad_IRQ21_interrupt, - bad_IRQ22_interrupt, bad_IRQ23_interrupt, - bad_IRQ24_interrupt, bad_IRQ25_interrupt, - NULL, NULL, NULL, NULL, NULL, - bad_IRQ31_interrupt -}; - /* * Initial irq handlers. */ -static struct irqaction *irq_action[NR_IRQS] = { - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL -}; +static struct irqaction *irq_action[NR_IRQS]; int show_interrupts(struct seq_file *p, void *v) { @@ -262,9 +120,10 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction *action; int do_random, cpu; + int retval = 0; cpu = smp_processor_id(); - irq_enter(cpu); + irq_enter(); kstat_cpu(cpu).irqs[irq]++; action = irq_action[irq]; @@ -275,14 +134,24 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) do_random = 0; do { do_random |= action->flags; - action->handler(irq, action->dev_id, regs); + retval |= action->handler(irq, action->dev_id, regs); action = action->next; } while (action); + + if (retval != 1) { + if (retval) { + printk("irq event %d: bogus retval mask %x\n", + irq, retval); + } else { + printk("irq %d: nobody cared\n", irq); + } + } + if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - local_irq_disable(); + local_irq_disable(); } - irq_exit(cpu); + irq_exit(); if (softirq_pending(cpu)) do_softirq(); @@ -295,7 +164,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) handler is entered into the interrupt vector */ -int setup_etrax_irq(int irq, struct irqaction * new) +int setup_irq(int irq, struct irqaction * new) { int shared = 0; struct irqaction *old, **p; @@ -322,19 +191,19 @@ int setup_etrax_irq(int irq, struct irqaction * new) if (new->flags & SA_SAMPLE_RANDOM) rand_initialize_irq(irq); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); *p = new; if (!shared) { /* if the irq wasn't registred before, enter it into the vector table and unmask it physically */ - set_int_vector(irq, interrupt[irq], sinterrupt[irq]); + arch_setup_irq(irq); unmask_irq(irq); } - restore_flags(flags); + local_irq_restore(flags); return 0; } @@ -348,7 +217,7 @@ int setup_etrax_irq(int irq, struct irqaction * new) */ int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) @@ -378,7 +247,7 @@ int request_irq(unsigned int irq, action->next = NULL; action->dev_id = dev_id; - retval = setup_etrax_irq(irq, action); + retval = setup_irq(irq, action); if (retval) kfree(action); @@ -399,14 +268,14 @@ void free_irq(unsigned int irq, void *dev_id) continue; /* Found it - now free it */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); *p = action->next; if (!irq_action[irq]) { mask_irq(irq); - set_int_vector(irq, bad_interrupt[irq], 0); + arch_free_irq(irq); } - restore_flags(flags); + local_irq_restore(flags); kfree(action); return; } @@ -415,84 +284,11 @@ void free_irq(unsigned int irq, void *dev_id) void weird_irq(void) { - __asm__("di"); + local_irq_disable(); printk("weird irq\n"); while(1); } -/* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and - setting the irq vector table to point to bad_interrupt ptrs. -*/ - -void system_call(void); /* from entry.S */ -void do_sigtrap(void); /* from entry.S */ -void gdb_handle_breakpoint(void); /* from entry.S */ - -void __init -init_IRQ(void) -{ - int i; - - /* clear all interrupt masks */ - -#ifndef CONFIG_SVINTO_SIM - *R_IRQ_MASK0_CLR = 0xffffffff; - *R_IRQ_MASK1_CLR = 0xffffffff; - *R_IRQ_MASK2_CLR = 0xffffffff; -#endif - - *R_VECT_MASK_CLR = 0xffffffff; - - /* clear the shortcut entry points */ - - for(i = 0; i < NR_IRQS; i++) - irq_shortcuts[i] = NULL; - - for (i = 0; i < 256; i++) - etrax_irv->v[i] = weird_irq; - - /* the entries in the break vector contain actual code to be - executed by the associated break handler, rather than just a jump - address. therefore we need to setup a default breakpoint handler - for all breakpoints */ - - for (i = 0; i < 16; i++) - set_break_vector(i, do_sigtrap); - - /* set all etrax irq's to the bad handlers */ - for (i = 2; i < NR_IRQS; i++) - set_int_vector(i, bad_interrupt[i], 0); - - /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ - - set_int_vector(15, multiple_interrupt, 0); - - /* 0 and 1 which are special breakpoint/NMI traps */ - - set_int_vector(0, hwbreakpoint, 0); - set_int_vector(1, IRQ1_interrupt, 0); - - /* and irq 14 which is the mmu bus fault handler */ - - set_int_vector(14, mmu_bus_fault, 0); - - /* setup the system-call trap, which is reached by BREAK 13 */ - - set_break_vector(13, system_call); - - /* setup a breakpoint handler for debugging used for both user and - kernel mode debugging (which is why it is not inside an ifdef - CONFIG_ETRAX_KGDB) */ - set_break_vector(8, gdb_handle_breakpoint); - -#ifdef CONFIG_ETRAX_KGDB - /* setup kgdb if its enabled, and break into the debugger */ - kgdb_init(); - breakpoint(); -#endif - -} - #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) /* Used by other archs to show/control IRQ steering during SMP */ void __init diff --git a/arch/cris/kernel/ksyms.c b/arch/cris/kernel/ksyms.c index 4d2cbc18c6a8..1161a2525254 100644 --- a/arch/cris/kernel/ksyms.c +++ b/arch/cris/kernel/ksyms.c @@ -24,6 +24,9 @@ extern void dump_thread(struct pt_regs *, struct user *); extern unsigned long get_cmos_time(void); extern void __Udiv(void); +extern void __Umod(void); +extern void __Div(void); +extern void __Mod(void); extern void __ashrdi3(void); extern void iounmap(void *addr); @@ -44,11 +47,16 @@ EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strlen); +EXPORT_SYMBOL(strcat); EXPORT_SYMBOL(strncat); EXPORT_SYMBOL(strncmp); +EXPORT_SYMBOL(strncpy); /* Math functions */ EXPORT_SYMBOL(__Udiv); +EXPORT_SYMBOL(__Umod); +EXPORT_SYMBOL(__Div); +EXPORT_SYMBOL(__Mod); EXPORT_SYMBOL(__ashrdi3); /* Memory functions */ @@ -58,6 +66,8 @@ EXPORT_SYMBOL(iounmap); /* Semaphore functions */ EXPORT_SYMBOL(__up); EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); /* Export shadow registers for the CPU I/O pins */ EXPORT_SYMBOL(genconfig_shadow); @@ -69,14 +79,13 @@ EXPORT_SYMBOL(port_pb_config_shadow); EXPORT_SYMBOL(port_g_data_shadow); /* Userspace access functions */ -EXPORT_SYMBOL(strncpy_from_user); -EXPORT_SYMBOL(__strncpy_from_user); -EXPORT_SYMBOL(__generic_copy_from_user); -EXPORT_SYMBOL(__generic_copy_to_user); -EXPORT_SYMBOL(strnlen_user); EXPORT_SYMBOL(__copy_user_zeroing); EXPORT_SYMBOL(__copy_user); +/* Cache flush functions */ +EXPORT_SYMBOL(flush_etrax_cache); +EXPORT_SYMBOL(prepare_rx_descriptor); + #undef memcpy #undef memset extern void * memset(void *, int, __kernel_size_t); diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c new file mode 100644 index 000000000000..052c0031fa29 --- /dev/null +++ b/arch/cris/kernel/module.c @@ -0,0 +1,106 @@ +/* Kernel module help for i386. + Copyright (C) 2001 Rusty Russell. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#include <linux/moduleloader.h> +#include <linux/elf.h> +#include <linux/vmalloc.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/kernel.h> + +#if 0 +#define DEBUGP printk +#else +#define DEBUGP(fmt , ...) +#endif + +void *module_alloc(unsigned long size) +{ + if (size == 0) + return NULL; + return vmalloc(size); +} + + +/* Free memory returned from module_alloc */ +void module_free(struct module *mod, void *module_region) +{ + vfree(module_region); + /* FIXME: If module_region == mod->init_region, trim exception + table entries. */ +} + +/* We don't need anything special. */ +int module_frob_arch_sections(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + char *secstrings, + struct module *mod) +{ + return 0; +} + +int apply_relocate(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + unsigned int i; + Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; + Elf32_Sym *sym; + uint32_t *location; + + DEBUGP("Applying relocate section %u to %u\n", relsec, + sechdrs[relsec].sh_info); + for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { + /* This is where to make the change */ + location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset + + rel[i].r_offset; + /* This is the symbol it is referring to. Note that all + undefined symbols have been resolved. */ + sym = (Elf32_Sym *)sechdrs[symindex].sh_addr + + 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 */ + *location += sym->st_value; + } + return 0; +} + +int apply_relocate_add(Elf32_Shdr *sechdrs, + const char *strtab, + unsigned int symindex, + unsigned int relsec, + struct module *me) +{ + printk(KERN_ERR "module %s: ADD RELOCATION unsupported\n", + me->name); + return -ENOEXEC; +} + +int module_finalize(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs, + struct module *me) +{ + return 0; +} + +void module_arch_cleanup(struct module *mod) +{ +} diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c index 60441877ef2f..23a5d13c18ea 100644 --- a/arch/cris/kernel/process.c +++ b/arch/cris/kernel/process.c @@ -1,13 +1,51 @@ -/* $Id: process.c,v 1.3 2002/01/21 15:22:49 bjornw Exp $ +/* $Id: process.c,v 1.14 2003/06/10 10:21:12 johana Exp $ * * linux/arch/cris/kernel/process.c * * Copyright (C) 1995 Linus Torvalds - * Copyright (C) 2000, 2001 Axis Communications AB + * Copyright (C) 2000-2002 Axis Communications AB * * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: process.c,v $ + * Revision 1.14 2003/06/10 10:21:12 johana + * Moved thread_saved_pc() from arch/cris/kernel/process.c to + * subarch specific process.c. + * + * Revision 1.13 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.12 2002/12/11 15:41:11 starvik + * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/kernel + * + * Revision 1.11 2002/12/10 09:00:10 starvik + * Merge of Linux 2.5.51 + * + * Revision 1.10 2002/11/27 08:42:34 starvik + * Argument to user_regs() is thread_info* + * + * Revision 1.9 2002/11/26 09:44:21 starvik + * New threads exits through ret_from_fork (necessary for preemptive scheduling) + * + * Revision 1.8 2002/11/19 14:35:24 starvik + * Changes from linux 2.4 + * Changed struct initializer syntax to the currently prefered notation + * + * Revision 1.7 2002/11/18 07:39:42 starvik + * thread_saved_pc moved here from processor.h + * + * Revision 1.6 2002/11/14 06:51:27 starvik + * Made cpu_idle more similar with other archs + * init_task_union -> init_thread_union + * Updated for new interrupt macros + * sys_clone and do_fork have a new argument, user_tid + * + * Revision 1.5 2002/11/05 06:45:11 starvik + * Merge of Linux 2.5.45 + * + * Revision 1.4 2002/02/05 15:37:44 bjornw + * Need init_task.h + * * Revision 1.3 2002/01/21 15:22:49 bjornw * current->counter is gone * @@ -54,29 +92,17 @@ */ #define __KERNEL_SYSCALLS__ -#include <stdarg.h> -#include <linux/errno.h> +#include <asm/atomic.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> +#include <linux/spinlock.h> +#include <linux/fs_struct.h> +#include <linux/init_task.h> #include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> +#include <linux/fs.h> #include <linux/user.h> -#include <linux/a.out.h> #include <linux/elfcore.h> -#include <linux/interrupt.h> -#include <linux/delay.h> - -#include <asm/uaccess.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/processor.h> - -#include <linux/smp.h> //#define DEBUG @@ -89,20 +115,29 @@ static struct fs_struct init_fs = INIT_FS; static struct files_struct init_files = INIT_FILES; -static struct signal_struct init_signals = INIT_SIGNALS; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); struct mm_struct init_mm = INIT_MM(init_mm); /* - * Initial task structure. + * Initial thread structure. * * We need to make sure that this is 8192-byte aligned due to the * way process stacks are handled. This is done by having a special * "init_task" linker map entry.. */ +union thread_union init_thread_union + __attribute__((__section__(".data.init_task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); + -union task_union init_task_union - __attribute__((__section__(".data.init_task"))) = - { INIT_TASK(init_task_union.task) }; /* * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if @@ -125,44 +160,34 @@ void enable_hlt(void) hlt_counter--; } -int cpu_idle(void *unused) -{ - while(1) { - schedule(); - } -} - -/* if the watchdog is enabled, we can simply disable interrupts and go - * into an eternal loop, and the watchdog will reset the CPU after 0.1s - * if on the other hand the watchdog wasn't enabled, we just enable it and wait +/* + * The following aren't currently used. */ +void (*pm_idle)(void); -void hard_reset_now (void) -{ - /* - * Don't declare this variable elsewhere. We don't want any other - * code to know about it than the watchdog handler in entry.S and - * this code, implementing hard reset through the watchdog. - */ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - extern int cause_of_death; -#endif - - printk("*** HARD RESET ***\n"); - cli(); +extern void default_idle(void); -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - cause_of_death = 0xbedead; -#else - /* Since we don't plan to keep on reseting the watchdog, - the key can be arbitrary hence three */ - *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) | - IO_STATE(R_WATCHDOG, enable, start); -#endif - - while(1) /* waiting for RETRIBUTION! */ ; +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle (void) +{ + /* endless idle loop with no priority at all */ + while (1) { + void (*idle)(void) = pm_idle; + if (!idle) + idle = default_idle; + while (!need_resched()) + idle(); + schedule(); + } } +void hard_reset_now (void); + void machine_restart(void) { hard_reset_now(); @@ -194,60 +219,6 @@ void flush_thread(void) { } -asmlinkage void ret_from_sys_call(void); - -/* setup the child's kernel stack with a pt_regs and switch_stack on it. - * it will be un-nested during _resume and _ret_from_sys_call when the - * new thread is scheduled. - * - * also setup the thread switching structure which is used to keep - * thread-specific data during _resumes. - * - */ - -int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, - unsigned long unused, - struct task_struct *p, struct pt_regs *regs) -{ - struct pt_regs * childregs; - struct switch_stack *swstack; - - /* put the pt_regs structure at the end of the new kernel stack page and fix it up - * remember that the task_struct doubles as the kernel stack for the task - */ - - childregs = user_regs(p); - - *childregs = *regs; /* struct copy of pt_regs */ - - childregs->r10 = 0; /* child returns 0 after a fork/clone */ - - /* put the switch stack right below the pt_regs */ - - swstack = ((struct switch_stack *)childregs) - 1; - - swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == don't restart the syscall */ - - /* we want to return into ret_from_sys_call after the _resume */ - - swstack->return_ip = (unsigned long) ret_from_sys_call; - - /* fix the user-mode stackpointer */ - - p->thread.usp = usp; - - /* and the kernel-mode one */ - - p->thread.ksp = (unsigned long) swstack; - -#ifdef DEBUG - printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); - show_registers(childregs); -#endif - - return 0; -} - /* * fill in the user structure for a core dump.. */ @@ -281,110 +252,3 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) { return 0; } - -/* - * Be aware of the "magic" 7th argument in the four system-calls below. - * They need the latest stackframe, which is put as the 7th argument by - * entry.S. The previous arguments are dummies or actually used, but need - * to be defined to reach the 7th argument. - * - * N.B.: Another method to get the stackframe is to use current_regs(). But - * it returns the latest stack-frame stacked when going from _user mode_ and - * some of these (at least sys_clone) are called from kernel-mode sometimes - * (for example during kernel_thread, above) and thus cannot use it. Thus, - * to be sure not to get any surprises, we use the method for the other calls - * as well. - */ - -asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, - struct pt_regs *regs) -{ - struct task_struct *p; - p = do_fork(SIGCHLD, rdusp(), regs, 0); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; -} - -/* if newusp is 0, we just grab the old usp */ - -asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, - long r12, long r13, long mof, long srp, - struct pt_regs *regs) -{ - struct task_struct *p; - if (!newusp) - newusp = rdusp(); - p = do_fork(flags & ~CLONE_IDLETASK, newusp, regs, 0); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; -} - -/* vfork is a system call in i386 because of register-pressure - maybe - * we can remove it and handle it in libc but we put it here until then. - */ - -asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, - struct pt_regs *regs) -{ - struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; -} - -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char *fname, char **argv, char **envp, - long r13, long mof, long srp, - struct pt_regs *regs) -{ - int error; - char *filename; - - filename = getname(fname); - error = PTR_ERR(filename); - - if (IS_ERR(filename)) - goto out; - error = do_execve(filename, argv, envp, regs); - putname(filename); - out: - return error; -} - -/* - * These bracket the sleeping functions.. - */ - -extern void scheduling_functions_start_here(void); -extern void scheduling_functions_end_here(void); -#define first_sched ((unsigned long) scheduling_functions_start_here) -#define last_sched ((unsigned long) scheduling_functions_end_here) - -unsigned long get_wchan(struct task_struct *p) -{ -#if 0 - /* YURGH. TODO. */ - - unsigned long ebp, esp, eip; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - stack_page = (unsigned long)p; - esp = p->thread.esp; - if (!stack_page || esp < stack_page || esp > 8188+stack_page) - return 0; - /* include/asm-i386/system.h:switch_to() pushes ebp last. */ - ebp = *(unsigned long *) esp; - do { - if (ebp < stack_page || ebp > 8184+stack_page) - return 0; - eip = *(unsigned long *) (ebp+4); - if (eip < first_sched || eip >= last_sched) - return eip; - ebp = *(unsigned long *) ebp; - } while (count++ < 16); -#endif - return 0; -} -#undef last_sched -#undef first_sched diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index c8a066c4ee4c..e85a2fdd9acf 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c @@ -3,11 +3,35 @@ * * Parts taken from the m68k port. * - * Copyright (c) 2000, 2001 Axis Communications AB + * Copyright (c) 2000, 2001, 2002 Axis Communications AB * * Authors: Bjorn Wesen * * $Log: ptrace.c,v $ + * Revision 1.9 2003/07/04 12:56:11 tobiasa + * Moved arch-specific code to arch-specific files. + * + * Revision 1.8 2003/04/09 05:20:47 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.7 2002/11/27 08:42:34 starvik + * Argument to user_regs() is thread_info* + * + * Revision 1.6 2002/11/20 11:56:11 starvik + * Merge of Linux 2.5.48 + * + * Revision 1.5 2002/11/18 07:41:19 starvik + * Removed warning + * + * Revision 1.4 2002/11/11 12:47:28 starvik + * SYSCALL_TRACE has been moved to thread flags + * + * Revision 1.3 2002/02/05 15:37:18 bjornw + * * Add do_notify_resume (replaces do_signal in the callchain) + * * syscall_trace is now do_syscall_trace + * * current->ptrace flag PT_TRACESYS -> PT_SYSCALLTRACE + * * Keep track of the current->work.syscall_trace counter + * * Revision 1.2 2001/12/18 13:35:20 bjornw * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). * @@ -49,18 +73,9 @@ #include <asm/processor.h> /* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* determines which bits in DCCR the user has access to. */ -/* 1 = access 0 = no access */ -#define DCCR_MASK 0x0000001f /* XNZVC */ - -/* * Get contents of register REGNO in task TASK. */ -static inline long get_reg(struct task_struct *task, unsigned int regno) +inline long get_reg(struct task_struct *task, unsigned int regno) { /* USP is a special case, it's not in the pt_regs struct but * in the tasks thread struct @@ -69,7 +84,7 @@ static inline long get_reg(struct task_struct *task, unsigned int regno) if (regno == PT_USP) return task->thread.usp; else if (regno < PT_MAX) - return ((unsigned long *)user_regs(task))[regno]; + return ((unsigned long *)user_regs(task->thread_info))[regno]; else return 0; } @@ -77,248 +92,28 @@ static inline long get_reg(struct task_struct *task, unsigned int regno) /* * Write contents of register REGNO in task TASK. */ -static inline int put_reg(struct task_struct *task, unsigned int regno, +inline int put_reg(struct task_struct *task, unsigned int regno, unsigned long data) { if (regno == PT_USP) task->thread.usp = data; else if (regno < PT_MAX) - ((unsigned long *)user_regs(task))[regno] = data; + ((unsigned long *)user_regs(task->thread_info))[regno] = data; else return -1; return 0; } -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. +/* notification of userspace execution resumption + * - triggered by current->work.notify_resume */ -void ptrace_disable(struct task_struct *child) -{ - /* Todo - pending singlesteps? */ -} +extern int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); -/* Note that this implementation of ptrace behaves differently from vanilla - * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, - * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not - * ignored. Instead, the data variable is expected to point at a location - * (in user space) where the result of the ptrace call is written (instead of - * being returned). - */ -asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +void do_notify_resume(int canrestart, sigset_t *oldset, struct pt_regs *regs, + __u32 thread_info_flags ) { - struct task_struct *child; - int ret; - - lock_kernel(); - ret = -EPERM; - if (request == PTRACE_TRACEME) { - /* are we already being traced? */ - if (current->ptrace & PT_PTRACED) - goto out; - /* set the ptrace bit in the process flags. */ - current->ptrace |= PT_PTRACED; - ret = 0; - goto out; - } - ret = -ESRCH; - read_lock(&tasklist_lock); - child = find_task_by_pid(pid); - if (child) - get_task_struct(child); - read_unlock(&tasklist_lock); - if (!child) - goto out; - ret = -EPERM; - if (pid == 1) /* you may not mess with init */ - goto out_tsk; - if (request == PTRACE_ATTACH) { - ret = ptrace_attach(child); - goto out_tsk; - } - ret = -ESRCH; - if (!(child->ptrace & PT_PTRACED)) - goto out_tsk; - if (child->state != TASK_STOPPED) { - if (request != PTRACE_KILL) - goto out_tsk; - } - if (child->p_pptr != current) - goto out_tsk; - - switch (request) { - /* when I and D space are separate, these will need to be fixed. */ - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); - ret = -EIO; - if (copied != sizeof(tmp)) - break; - ret = put_user(tmp,(unsigned long *) data); - break; - } - - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - break; - - tmp = 0; /* Default return condition */ - ret = -EIO; - if (addr < sizeof(struct pt_regs)) { - tmp = get_reg(child, addr >> 2); - ret = put_user(tmp, (unsigned long *)data); - } - break; - } - - /* when I and D space are separate, this will have to be fixed. */ - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: - ret = 0; - if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) - break; - ret = -EIO; - break; - - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || addr < 0 || addr >= sizeof(struct user)) - break; - - if (addr < sizeof(struct pt_regs)) { - addr >>= 2; - - if (addr == PT_DCCR) { - /* don't allow the tracing process to change stuff like - * interrupt enable, kernel/user bit, dma enables etc. - */ - data &= DCCR_MASK; - data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; - } - if (put_reg(child, addr, data)) - break; - ret = 0; - } - break; - - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - break; - if (request == PTRACE_SYSCALL) - child->ptrace |= PT_TRACESYS; - else - child->ptrace &= ~PT_TRACESYS; - child->exit_code = data; - /* TODO: make sure any pending breakpoint is killed */ - wake_up_process(child); - ret = 0; - break; - -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: - ret = 0; - if (child->state == TASK_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - /* TODO: make sure any pending breakpoint is killed */ - wake_up_process(child); - break; - - case PTRACE_SINGLESTEP: /* set the trap flag. */ - ret = -EIO; - if ((unsigned long) data > _NSIG) - break; - child->ptrace &= ~PT_TRACESYS; - - /* TODO: set some clever breakpoint mechanism... */ - - child->exit_code = data; - /* give it a chance to run. */ - wake_up_process(child); - ret = 0; - break; - - case PTRACE_DETACH: - ret = ptrace_detach(child, data); - break; - - case PTRACE_GETREGS: { /* Get all gp regs from the child. */ - int i; - unsigned long tmp; - for (i = 0; i <= PT_MAX; i++) { - tmp = get_reg(child, i); - if (put_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; - break; - } - data += sizeof(long); - } - ret = 0; - break; - } - - case PTRACE_SETREGS: { /* Set all gp regs in the child. */ - int i; - unsigned long tmp; - for (i = 0; i <= PT_MAX; i++) { - if (get_user(tmp, (unsigned long *) data)) { - ret = -EFAULT; - break; - } - if (i == PT_DCCR) { - tmp &= DCCR_MASK; - tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK; - } - put_reg(child, i, tmp); - data += sizeof(long); - } - ret = 0; - break; - } - - default: - ret = ptrace_request(child, request, addr, data); - break; - } -out_tsk: - free_task_struct(child); -out: - unlock_kernel(); - return ret; -} - -asmlinkage void syscall_trace(void) -{ - if ((current->ptrace & (PT_PTRACED | PT_TRACESYS)) != - (PT_PTRACED | PT_TRACESYS)) - return; - current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); - current->state = TASK_STOPPED; - notify_parent(current, SIGCHLD); - schedule(); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + /* deal with pending signal delivery */ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal(canrestart,oldset,regs); } diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c index 3232548a639c..fc989d2c7735 100644 --- a/arch/cris/kernel/setup.c +++ b/arch/cris/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: setup.c,v 1.7 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/kernel/setup.c * @@ -10,30 +10,12 @@ * This file handles the architecture-dependent parts of initialization */ -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/tty.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/config.h> #include <linux/init.h> +#include <linux/mm.h> #include <linux/bootmem.h> -#include <linux/seq_file.h> - -#include <asm/segment.h> -#include <asm/system.h> -#include <asm/smp.h> #include <asm/pgtable.h> -#include <asm/types.h> -#include <asm/svinto.h> +#include <linux/seq_file.h> +#include <linux/tty.h> /* * Setup options @@ -52,6 +34,7 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, }; char saved_command_line[COMMAND_LINE_SIZE]; extern const unsigned long text_start, edata; /* set by the linker script */ +extern unsigned long dram_start, dram_end; extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */ @@ -169,14 +152,14 @@ setup_arch(char **cmdline_p) *cmdline_p = command_line; - if (romfs_in_flash) { - strlcpy(command_line, "root=", sizeof(command_line)); - strlcat(command_line, CONFIG_ETRAX_ROOT_DEVICE, - sizeof(command_line)); - - /* Save command line copy for /proc/cmdline */ - strlcpy(saved_command_line, command_line, sizeof(saved_command_line)); - } +#ifdef CONFIG_ETRAX_CMDLINE + strlcpy(command_line, CONFIG_ETRAX_CMDLINE, sizeof(command_line)); +#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'; /* give credit for the CRIS port */ @@ -184,83 +167,6 @@ setup_arch(char **cmdline_p) } -#ifdef CONFIG_PROC_FS -#define HAS_FPU 0x0001 -#define HAS_MMU 0x0002 -#define HAS_ETHERNET100 0x0004 -#define HAS_TOKENRING 0x0008 -#define HAS_SCSI 0x0010 -#define HAS_ATA 0x0020 -#define HAS_USB 0x0040 -#define HAS_IRQ_BUG 0x0080 -#define HAS_MMU_BUG 0x0100 - -static struct cpu_info { - char *model; - unsigned short cache; - unsigned short flags; -} cpu_info[] = { - /* The first four models will never ever run this code and are - only here for display. */ - { "ETRAX 1", 0, 0 }, - { "ETRAX 2", 0, 0 }, - { "ETRAX 3", 0, HAS_TOKENRING }, - { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Unknown", 0, 0 }, - { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, - { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, - { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, - { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, - { "Unknown", 0, 0 } /* This entry MUST be the last */ -}; - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - unsigned long revision; - struct cpu_info *info; - - /* read the version register in the CPU and print some stuff */ - - revision = rdvr(); - - if (revision >= sizeof cpu_info/sizeof *cpu_info) - info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; - else - info = &cpu_info[revision]; - - return seq_printf(m, - "cpu\t\t: CRIS\n" - "cpu revision\t: %lu\n" - "cpu model\t: %s\n" - "cache size\t: %d kB\n" - "fpu\t\t: %s\n" - "mmu\t\t: %s\n" - "mmu DMA bug\t: %s\n" - "ethernet\t: %s Mbps\n" - "token ring\t: %s\n" - "scsi\t\t: %s\n" - "ata\t\t: %s\n" - "usb\t\t: %s\n" - "bogomips\t: %lu.%02lu\n", - - revision, - info->model, - info->cache, - info->flags & HAS_FPU ? "yes" : "no", - info->flags & HAS_MMU ? "yes" : "no", - info->flags & HAS_MMU_BUG ? "yes" : "no", - info->flags & HAS_ETHERNET100 ? "10/100" : "10", - info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", - info->flags & HAS_SCSI ? "yes" : "no", - info->flags & HAS_ATA ? "yes" : "no", - info->flags & HAS_USB ? "yes" : "no", - (loops_per_jiffy * HZ + 500) / 500000, - ((loops_per_jiffy * HZ + 500) / 5000) % 100); -} - static void *c_start(struct seq_file *m, loff_t *pos) { /* We only got one CPU... */ @@ -277,11 +183,13 @@ static void c_stop(struct seq_file *m, void *v) { } +extern int show_cpuinfo(struct seq_file *m, void *v); + struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, }; -#endif /* CONFIG_PROC_FS */ + diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c index 31917ab11982..e7e5c04071e5 100644 --- a/arch/cris/kernel/sys_cris.c +++ b/arch/cris/kernel/sys_cris.c @@ -1,4 +1,4 @@ -/* $Id: sys_cris.c,v 1.1.1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: sys_cris.c,v 1.5 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/kernel/sys_cris.c * @@ -29,7 +29,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way Unix traditionally does this, though. */ -asmlinkage int sys_pipe(unsigned long * fildes) +asmlinkage int sys_pipe(unsigned long __user * fildes) { int fd[2]; int error; @@ -69,7 +69,7 @@ out: return error; } -asmlinkage unsigned long old_mmap(unsigned long *args) +asmlinkage unsigned long old_mmap(unsigned long __user *args) { unsigned long buffer[6]; int err = -EFAULT; @@ -101,7 +101,7 @@ sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, */ asmlinkage int sys_ipc (uint call, int first, int second, - int third, void *ptr, long fifth) + int third, void __user *ptr, long fifth) { int version, ret; @@ -110,20 +110,24 @@ asmlinkage int sys_ipc (uint call, int first, int second, switch (call) { case SEMOP: - return sys_semop (first, (struct sembuf *)ptr, second); + return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); + case SEMTIMEDOP: + return sys_semtimedop(first, (struct sembuf __user *)ptr, second, + (const struct timespec __user *)fifth); + case SEMGET: return sys_semget (first, second, third); case SEMCTL: { union semun fourth; if (!ptr) return -EINVAL; - if (get_user(fourth.__pad, (void **) ptr)) + if (get_user(fourth.__pad, (void * __user *) ptr)) return -EFAULT; return sys_semctl (first, second, third, fourth); } case MSGSND: - return sys_msgsnd (first, (struct msgbuf *) ptr, + return sys_msgsnd (first, (struct msgbuf __user *) ptr, second, third); case MSGRCV: switch (version) { @@ -133,7 +137,7 @@ asmlinkage int sys_ipc (uint call, int first, int second, return -EINVAL; if (copy_from_user(&tmp, - (struct ipc_kludge *) ptr, + (struct ipc_kludge __user *) ptr, sizeof (tmp))) return -EFAULT; return sys_msgrcv (first, tmp.msgp, second, @@ -141,29 +145,29 @@ asmlinkage int sys_ipc (uint call, int first, int second, } default: return sys_msgrcv (first, - (struct msgbuf *) ptr, + (struct msgbuf __user *) ptr, second, fifth, third); } case MSGGET: return sys_msgget ((key_t) first, second); case MSGCTL: - return sys_msgctl (first, second, (struct msqid_ds *) ptr); + return sys_msgctl (first, second, (struct msqid_ds __user *) ptr); case SHMAT: { ulong raddr; - ret = sys_shmat (first, (char *) ptr, second, &raddr); + ret = sys_shmat (first, (char __user *) ptr, second, &raddr); if (ret) return ret; - return put_user (raddr, (ulong *) third); + return put_user (raddr, (ulong __user *) third); } case SHMDT: - return sys_shmdt ((char *)ptr); + return sys_shmdt ((char __user *)ptr); case SHMGET: return sys_shmget (first, second, third); case SHMCTL: return sys_shmctl (first, second, - (struct shmid_ds *) ptr); + (struct shmid_ds __user *) ptr); default: - return -EINVAL; + return -ENOSYS; } } diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c index 81f91df573af..caee8e4fd39b 100644 --- a/arch/cris/kernel/time.c +++ b/arch/cris/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: time.c,v 1.9 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/kernel/time.c * @@ -22,124 +22,66 @@ * */ +#include <asm/rtc.h> #include <linux/errno.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/kernel.h> #include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/delay.h> +#include <linux/jiffies.h> #include <linux/bcd.h> - -#include <asm/segment.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/delay.h> -#include <asm/rtc.h> - #include <linux/timex.h> -#include <linux/config.h> - -#include <asm/svinto.h> u64 jiffies_64 = INITIAL_JIFFIES; -static int have_rtc; /* used to remember if we have an RTC or not */ - -/* define this if you need to use print_timestamp */ -/* it will make jiffies at 96 hz instead of 100 hz though */ -#undef USE_CASCADE_TIMERS - -extern int setup_etrax_irq(int, struct irqaction *); - -/* Lookup table to convert *R_TIMER0 to microseconds (us) - * Timer goes from TIMER0_DIV down to 1 meaning 0-10000us in step of approx 52us - */ -unsigned short cris_timer0_value_us[TIMER0_DIV+1]; +int have_rtc; /* used to remember if we have an RTC or not */; #define TICK_SIZE tick -static unsigned long do_slow_gettimeoffset(void) -{ - unsigned long count; - unsigned long usec_count = 0; - - static unsigned long count_p = LATCH; /* for the first call after boot */ - static unsigned long jiffies_p = 0; - - /* - * cache volatile jiffies temporarily; we have IRQs turned off. - */ - unsigned long jiffies_t; - - /* The timer interrupt comes from Etrax timer 0. In order to get - * better precision, we check the current value. It might have - * underflowed already though. - */ - -#ifndef CONFIG_SVINTO_SIM - /* Not available in the xsim simulator. */ - count = *R_TIMER0_DATA; -#else - count = 0; -#endif - - jiffies_t = jiffies; - - /* - * avoiding timer inconsistencies (they are rare, but they happen)... - * there are three kinds of problems that must be avoided here: - * 1. the timer counter underflows - * 2. we are after the timer interrupt, but the bottom half handler - * hasn't executed yet. - */ - if( jiffies_t == jiffies_p ) { - if( count > count_p ) { - /* Timer wrapped */ - count = count_p; - usec_count = 1000000/CLOCK_TICK_RATE/2; - } - } else - jiffies_p = jiffies_t; - count_p = count; - /* Convert timer value to usec using table lookup */ - usec_count += cris_timer0_value_us[count]; -#if 0 - count = ((LATCH-1) - count) * TICK_SIZE; - count = (count + LATCH/2) / LATCH; -#endif - return usec_count; -} +extern unsigned long wall_jiffies; +extern unsigned long do_slow_gettimeoffset(void); static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; /* * This version of gettimeofday has near microsecond resolution. + * + * Note: Division is quite slow on CRIS and do_gettimeofday is called + * rather often. Maybe we should do some kind of approximation here + * (a naive approximation would be to divide by 1024). */ void do_gettimeofday(struct timeval *tv) { unsigned long flags; + signed long usec, sec; + local_irq_save(flags); + local_irq_disable(); + usec = do_gettimeoffset(); + { + unsigned long lost = jiffies - wall_jiffies; + if (lost) + usec += lost * (1000000 / HZ); + } + sec = xtime.tv_sec; + usec += xtime.tv_nsec / 1000; + local_irq_restore(flags); - save_flags(flags); - cli(); - *tv = xtime; - tv->tv_usec += do_gettimeoffset(); - if (tv->tv_usec >= 1000000) { - tv->tv_usec -= 1000000; - tv->tv_sec++; + while (usec >= 1000000) { + usec -= 1000000; + sec++; } - restore_flags(flags); + + tv->tv_sec = sec; + tv->tv_usec = usec; } int do_settimeofday(struct timespec *tv) { - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) + unsigned long flags; + + if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; - cli(); + local_irq_save(flags); + local_irq_disable(); + /* This is revolting. We need to set the xtime.tv_usec * correctly. However, the value in this location is * is value at the last tick. @@ -147,19 +89,20 @@ int do_settimeofday(struct timespec *tv) * would have done, and then undo it! */ tv->tv_nsec -= do_gettimeoffset() * 1000; + tv->tv_nsec -= (jiffies - wall_jiffies) * TICK_NSEC; - if (tv->tv_nsec < 0) { + while (tv->tv_nsec < 0) { tv->tv_nsec += NSEC_PER_SEC; tv->tv_sec--; } - - xtime = *tv; + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = tv->tv_nsec; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; - sti(); + local_irq_restore(flags); return 0; } @@ -169,7 +112,7 @@ int do_settimeofday(struct timespec *tv) * sets the minutes. Usually you'll only notice that after reboot! */ -static int set_rtc_mmss(unsigned long nowtime) +int set_rtc_mmss(unsigned long nowtime) { int retval = 0; int real_seconds, real_minutes, cmos_minutes; @@ -209,143 +152,6 @@ static int set_rtc_mmss(unsigned long nowtime) return retval; } -/* Excerpt from the Etrax100 HSDD about the built-in watchdog: - * - * 3.10.4 Watchdog timer - - * When the watchdog timer is started, it generates an NMI if the watchdog - * isn't restarted or stopped within 0.1 s. If it still isn't restarted or - * stopped after an additional 3.3 ms, the watchdog resets the chip. - * The watchdog timer is stopped after reset. The watchdog timer is controlled - * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit - * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is - * described in the table below: - * - * Watchdog Value written: - * state: To enable: To key: Operation: - * -------- ---------- ------- ---------- - * stopped 0 X No effect. - * stopped 1 key_val Start watchdog with key = key_val. - * started 0 ~key Stop watchdog - * started 1 ~key Restart watchdog with key = ~key. - * started X new_key_val Change key to new_key_val. - * - * Note: '~' is the bitwise NOT operator. - * - */ - -/* right now, starting the watchdog is the same as resetting it */ -#define start_watchdog reset_watchdog - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) -static int watchdog_key = 0; /* arbitrary number */ -#endif - -/* number of pages to consider "out of memory". it is normal that the memory - * is used though, so put this really low. - */ - -#define WATCHDOG_MIN_FREE_PAGES 8 - -void -reset_watchdog(void) -{ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - /* only keep watchdog happy as long as we have memory left! */ - if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { - /* reset the watchdog with the inverse of the old key */ - watchdog_key ^= 0x7; /* invert key, which is 3 bits */ - *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | - IO_STATE(R_WATCHDOG, enable, start); - } -#endif -} - -/* stop the watchdog - we still need the correct key */ - -void -stop_watchdog(void) -{ -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - watchdog_key ^= 0x7; /* invert key, which is 3 bits */ - *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | - IO_STATE(R_WATCHDOG, enable, stop); -#endif -} - -/* last time the cmos clock got updated */ -static long last_rtc_update = 0; - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick - */ - -//static unsigned short myjiff; /* used by our debug routine print_timestamp */ - -static inline void -timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - /* acknowledge the timer irq */ - -#ifdef USE_CASCADE_TIMERS - *R_TIMER_CTRL = - IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | - IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | - IO_STATE( R_TIMER_CTRL, i1, clr) | - IO_STATE( R_TIMER_CTRL, tm1, run) | - IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | - IO_STATE( R_TIMER_CTRL, i0, clr) | - IO_STATE( R_TIMER_CTRL, tm0, run) | - IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); -#else - *R_TIMER_CTRL = r_timer_ctrl_shadow | - IO_STATE(R_TIMER_CTRL, i0, clr); -#endif - - /* reset watchdog otherwise it resets us! */ - - reset_watchdog(); - - /* call the real timer interrupt handler */ - - do_timer(regs); - - /* - * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - */ - - if ((time_status & STA_UNSYNC) == 0 && - xtime.tv_sec > last_rtc_update + 660 && - xtime.tv_usec > 500000 - (tick >> 1) && - xtime.tv_usec < 500000 + (tick >> 1)) { - if (set_rtc_mmss(xtime.tv_sec) == 0) - last_rtc_update = xtime.tv_sec; - else - last_rtc_update = xtime.tv_sec - 600; - } -} - -#if 0 -/* some old debug code for testing the microsecond timing of packets */ -static unsigned int lastjiff; - -void print_timestamp(const char *s) -{ - unsigned long flags; - unsigned int newjiff; - - save_flags(flags); - cli(); - newjiff = (myjiff << 16) | (unsigned short)(-*R_TIMER01_DATA); - printk("%s: %x (%x)\n", s, newjiff, newjiff - lastjiff); - lastjiff = newjiff; - restore_flags(flags); -} -#endif - /* grab the time from the RTC chip */ unsigned long @@ -385,116 +191,6 @@ update_xtime_from_cmos(void) { if(have_rtc) { xtime.tv_sec = get_cmos_time(); - xtime.tv_usec = 0; - } -} - -/* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain - * it needs to be SA_INTERRUPT to make the jiffies update work properly - */ - -static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, - 0, "timer", NULL, NULL}; - -void __init -time_init(void) -{ - int i; - /* probe for the RTC and read it if it exists */ - - if(RTC_INIT() < 0) { - /* no RTC, start at 1980 */ - xtime.tv_sec = 0; - xtime.tv_usec = 0; - have_rtc = 0; - } else { - /* get the current time */ - have_rtc = 1; - update_xtime_from_cmos(); - } - - /* Setup the etrax timers - * Base frequency is 19200 hz, divider 192 -> 100 hz as Linux wants - * In normal mode, we use timer0, so timer1 is free. In cascade - * mode (which we sometimes use for debugging) both timers are used. - * Remember that linux/timex.h contains #defines that rely on the - * timer settings below (hz and divide factor) !!! - */ - -#ifdef USE_CASCADE_TIMERS - *R_TIMER_CTRL = - IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | - IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | - IO_STATE( R_TIMER_CTRL, i1, nop) | - IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | - IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | - IO_STATE( R_TIMER_CTRL, i0, nop) | - IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | - IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | - IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | - IO_STATE( R_TIMER_CTRL, i1, nop) | - IO_STATE( R_TIMER_CTRL, tm1, run) | - IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | - IO_STATE( R_TIMER_CTRL, i0, nop) | - IO_STATE( R_TIMER_CTRL, tm0, run) | - IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); -#else - *R_TIMER_CTRL = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | - IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | - IO_STATE(R_TIMER_CTRL, i1, nop) | - IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | - IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | - IO_STATE(R_TIMER_CTRL, i0, nop) | - IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | - IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); - - *R_TIMER_CTRL = r_timer_ctrl_shadow = - IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | - IO_FIELD(R_TIMER_CTRL, timerdiv0, 192) | - IO_STATE(R_TIMER_CTRL, i1, nop) | - IO_STATE(R_TIMER_CTRL, tm1, run) | - IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | - IO_STATE(R_TIMER_CTRL, i0, nop) | - IO_STATE(R_TIMER_CTRL, tm0, run) | - IO_STATE(R_TIMER_CTRL, clksel0, c19k2Hz); -#endif - - for (i=0; i <= TIMER0_DIV; i++) { - /* We must be careful not to get overflow... */ - cris_timer0_value_us[TIMER0_DIV-i] = - (unsigned short)((unsigned long) - ((i*(1000000/HZ))/TIMER0_DIV)&0x0000FFFFL); + xtime.tv_nsec = 0; } - - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ - - /* now actually register the timer irq handler that calls timer_interrupt() */ - - setup_etrax_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ - - /* enable watchdog if we should use one */ - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) - printk("Enabling watchdog...\n"); - start_watchdog(); - - /* If we use the hardware watchdog, we want to trap it as an NMI - and dump registers before it resets us. For this to happen, we - must set the "m" NMI enable flag (which once set, is unset only - when an NMI is taken). - - The same goes for the external NMI, but that doesn't have any - driver or infrastructure support yet. */ - asm ("setf m"); - - *R_IRQ_MASK0_SET = - IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); - *R_VECT_MASK_SET = - IO_STATE(R_VECT_MASK_SET, nmi, set); -#endif } diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c index 9666d32af626..5273241e072d 100644 --- a/arch/cris/kernel/traps.c +++ b/arch/cris/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.2 2001/12/18 13:35:20 bjornw Exp $ +/* $Id: traps.c,v 1.7 2003/07/04 08:27:52 starvik Exp $ * * linux/arch/cris/traps.c * @@ -6,7 +6,7 @@ * mechanism, as well as some general stack/register dumping * things. * - * Copyright (C) 2000,2001 Axis Communications AB + * Copyright (C) 2000-2002 Axis Communications AB * * Authors: Bjorn Wesen * Hans-Peter Nilsson @@ -14,19 +14,8 @@ */ #include <linux/init.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/timer.h> -#include <linux/mm.h> -#include <asm/uaccess.h> - -#include <asm/system.h> -#include <asm/segment.h> -#include <asm/io.h> #include <asm/pgtable.h> +#include <asm/uaccess.h> static int kstack_depth_to_print = 24; @@ -95,7 +84,7 @@ void show_trace_task(struct task_struct *tsk) */ void -show_stack(unsigned long *sp) +show_stack(struct task_struct *task, unsigned long *sp) { unsigned long *stack, addr; int i; @@ -105,8 +94,12 @@ show_stack(unsigned long *sp) * back trace. */ - if(sp == NULL) - sp = (unsigned long*)rdsp(); + if(sp == NULL) { + if (task) + sp = (unsigned long*)task->thread.ksp; + else + sp = (unsigned long*)rdsp(); + } stack = sp; @@ -144,123 +137,9 @@ show_stack() } #endif -void -show_registers(struct pt_regs * regs) -{ - /* We either use rdusp() - the USP register, which might not - correspond to the current process for all cases we're called, - or we use the current->thread.usp, which is not up to date for - the current process. Experience shows we want the USP - register. */ - 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); - printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); - printk("Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, (unsigned long)current); - - /* - * When in-kernel, we also print out the stack and code at the - * time of the fault.. - */ - if (! user_mode(regs)) { - int i; - - show_stack((unsigned long*)usp); - - /* Dump kernel stack if the previous dump wasn't one. */ - if (usp != 0) - show_stack (NULL); - - printk("\nCode: "); - if(regs->irp < PAGE_OFFSET) - goto bad; - - /* Often enough the value at regs->irp does not point to - the interesting instruction, which is most often the - _previous_ instruction. So we dump at an offset large - enough that instruction decoding should be in sync at - the interesting point, but small enough to fit on a row - (sort of). We point out the regs->irp location in a - ksymoops-friendly way by wrapping the byte for that - address in parentheses. */ - for(i = -12; i < 12; i++) - { - unsigned char c; - if(__get_user(c, &((unsigned char*)regs->irp)[i])) { -bad: - printk(" Bad IP value."); - break; - } - - if (i == 0) - printk("(%02x) ", c); - else - printk("%02x ", c); - } - printk("\n"); - } -} - -/* Called from entry.S when the watchdog has bitten - * We print out something resembling an oops dump, and if - * we have the nice doggy development flag set, we halt here - * instead of rebooting. - */ - -void -watchdog_bite_hook(struct pt_regs *regs) -{ -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - cli(); - stop_watchdog(); - show_registers(regs); - while(1) /* nothing */; -#else - show_registers(regs); -#endif -} - void dump_stack(void) { - show_stack(NULL); -} - -/* This is normally the 'Oops' routine */ -void -die_if_kernel(const char * str, struct pt_regs * regs, long err) -{ - extern void reset_watchdog(void); - extern void stop_watchdog(void); - - if(user_mode(regs)) - return; - -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - /* This printout might take too long and trigger the - * watchdog normally. If we're in the nice doggy - * development mode, stop the watchdog during printout. - */ - stop_watchdog(); -#endif - - printk("%s: %04lx\n", str, err & 0xffff); - - show_registers(regs); - -#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - reset_watchdog(); -#endif - do_exit(SIGSEGV); + show_stack(NULL, NULL); } void __init diff --git a/arch/cris/mm/Makefile b/arch/cris/mm/Makefile index 5a92ec53ca3d..f3790c7e41ae 100644 --- a/arch/cris/mm/Makefile +++ b/arch/cris/mm/Makefile @@ -3,3 +3,4 @@ # obj-y := init.o fault.o tlb.o extable.o ioremap.o + diff --git a/arch/cris/mm/extable.c b/arch/cris/mm/extable.c index 7351f59f8bb9..7992bdb4fea1 100644 --- a/arch/cris/mm/extable.c +++ b/arch/cris/mm/extable.c @@ -2,8 +2,18 @@ * linux/arch/cris/mm/extable.c * * $Log: extable.c,v $ - * Revision 1.1.1.1 2001/12/17 13:59:27 bjornw - * Import of Linux 2.5.1 + * Revision 1.4 2003/01/09 14:42:52 starvik + * Merge of Linux 2.5.55 + * + * Revision 1.3 2002/11/21 07:24:54 starvik + * Made search_exception_table similar to implementation for other archs + * (now compiles with CONFIG_MODULES) + * + * Revision 1.2 2002/11/18 07:36:55 starvik + * Removed warning + * + * Revision 1.1 2001/12/17 13:59:27 bjornw + * Initial revision * * Revision 1.3 2001/09/27 13:52:40 bjornw * Harmonize underscore-ness with other parts @@ -15,13 +25,11 @@ #include <linux/module.h> #include <asm/uaccess.h> -extern const struct exception_table_entry __start___ex_table[]; -extern const struct exception_table_entry __stop___ex_table[]; - -static inline unsigned long -search_one_table(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) +/* Simple binary search */ +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) { while (first <= last) { const struct exception_table_entry *mid; @@ -30,34 +38,11 @@ search_one_table(const struct exception_table_entry *first, mid = (last - first) / 2 + first; diff = mid->insn - value; if (diff == 0) - return mid->fixup; + return mid; else if (diff < 0) first = mid+1; else last = mid-1; } - return 0; -} - -unsigned long -search_exception_table(unsigned long addr) -{ - unsigned long ret; - -#ifndef CONFIG_MODULES - /* There is only the kernel to search. */ - return search_one_table(__start___ex_table, __stop___ex_table-1, addr); -#else - /* The kernel is the last "module" -- no need to treat it special. */ - struct module *mp; - for (mp = module_list; mp != NULL; mp = mp->next) { - if (mp->ex_table_start == NULL) - continue; - ret = search_one_table(mp->ex_table_start, - mp->ex_table_end - 1, addr); - if (ret) return ret; - } -#endif - - return 0; + return NULL; } diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c index 2e4d91e40cf9..1af6f3a49dad 100644 --- a/arch/cris/mm/fault.c +++ b/arch/cris/mm/fault.c @@ -6,6 +6,25 @@ * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.8 2003/07/04 13:02:48 tobiasa + * Moved code snippet from arch/cris/mm/fault.c that searches for fixup code + * to seperate function in arch-specific files. + * + * Revision 1.7 2003/01/22 06:48:38 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.6 2003/01/09 14:42:52 starvik + * Merge of Linux 2.5.55 + * + * Revision 1.5 2002/12/11 14:44:48 starvik + * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm + * + * Revision 1.4 2002/11/13 15:10:28 starvik + * pte_offset has been renamed to pte_offset_kernel + * + * Revision 1.3 2002/11/05 06:45:13 starvik + * Merge of Linux 2.5.45 + * * Revision 1.2 2001/12/18 13:35:22 bjornw * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). * @@ -68,24 +87,13 @@ * */ -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> #include <linux/mm.h> #include <linux/interrupt.h> - -#include <asm/system.h> -#include <asm/segment.h> -#include <asm/pgtable.h> +#include <linux/module.h> #include <asm/uaccess.h> -#include <asm/svinto.h> -extern void die_if_kernel(const char *,struct pt_regs *,long); +extern int find_fixup_code(struct pt_regs *); +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, @@ -107,127 +115,6 @@ asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, volatile pgd_t *current_pgd; -/* fast TLB-fill fault handler - * this is called from entry.S with interrupts disabled - */ - -void -handle_mmu_bus_fault(struct pt_regs *regs) -{ - int cause, select; -#ifdef DEBUG - int index; - int page_id; - int acc, inv; -#endif - int miss, we, writeac; - pmd_t *pmd; - pte_t pte; - int errcode; - unsigned long address; - - cause = *R_MMU_CAUSE; - select = *R_TLB_SELECT; - - address = cause & PAGE_MASK; /* get faulting address */ - -#ifdef DEBUG - page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); - acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); - inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); - index = IO_EXTRACT(R_TLB_SELECT, index, select); -#endif - miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); - we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); - writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); - - /* ETRAX 100LX TR89 bugfix: if the second half of an unaligned - * write causes a MMU-fault, it will not be restarted correctly. - * This could happen if a write crosses a page-boundary and the - * second page is not yet COW'ed or even loaded. The workaround - * is to clear the unaligned bit in the CPU status record, so - * that the CPU will rerun both the first and second halves of - * the instruction. This will not have any sideeffects unless - * the first half goes to any device or memory that can't be - * written twice, and which is mapped through the MMU. - * - * We only need to do this for writes. - */ - - if(writeac) - 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", - regs->irp, address, miss, inv, we, acc, index, page_id)); - - /* for a miss, we need to reload the TLB entry */ - - if (miss) { - /* see if the pte exists at all - * refer through current_pgd, don't use mm->pgd - */ - - pmd = (pmd_t *)(current_pgd + pgd_index(address)); - if (pmd_none(*pmd)) - goto dofault; - if (pmd_bad(*pmd)) { - printk("bad pgdir entry 0x%lx at 0x%p\n", *(unsigned long*)pmd, pmd); - pmd_clear(pmd); - return; - } - pte = *pte_offset(pmd, address); - if (!pte_present(pte)) - goto dofault; - -#ifdef DEBUG - printk(" found pte %lx pg %p ", pte_val(pte), pte_page(pte)); - if (pte_val(pte) & _PAGE_SILENT_WRITE) - printk("Silent-W "); - if (pte_val(pte) & _PAGE_KERNEL) - printk("Kernel "); - if (pte_val(pte) & _PAGE_SILENT_READ) - printk("Silent-R "); - if (pte_val(pte) & _PAGE_GLOBAL) - printk("Global "); - if (pte_val(pte) & _PAGE_PRESENT) - printk("Present "); - if (pte_val(pte) & _PAGE_ACCESSED) - printk("Accessed "); - if (pte_val(pte) & _PAGE_MODIFIED) - printk("Modified "); - if (pte_val(pte) & _PAGE_READ) - printk("Readable "); - if (pte_val(pte) & _PAGE_WRITE) - printk("Writeable "); - printk("\n"); -#endif - - /* load up the chosen TLB entry - * this assumes the pte format is the same as the TLB_LO layout. - * - * the write to R_TLB_LO also writes the vpn and page_id fields from - * R_MMU_CAUSE, which we in this case obviously want to keep - */ - - *R_TLB_LO = pte_val(pte); - - return; - } - - errcode = 1 | (we << 1); - - dofault: - /* leave it to the MM system fault handler below */ - D(printk("do_page_fault %lx errcode %d\n", address, errcode)); - do_page_fault(address, regs, errcode); -} - /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -253,7 +140,6 @@ do_page_fault(unsigned long address, struct pt_regs *regs, struct mm_struct *mm; struct vm_area_struct * vma; int writeaccess; - unsigned long fixup; siginfo_t info; tsk = current; @@ -391,20 +277,8 @@ do_page_fault(unsigned long address, struct pt_regs *regs, * code) */ - if ((fixup = search_exception_table(regs->irp)) != 0) { - /* Adjust the instruction pointer in the stackframe */ - - regs->irp = fixup; - - /* We do not want to return by restoring the CPU-state - * anymore, so switch frame-types (see ptrace.h) - */ - - regs->frametype = CRIS_FRAME_NORMAL; - - D(printk("doing fixup to 0x%lx\n", fixup)); + if (find_fixup_code(regs)) return; - } /* * Oops. The kernel tried to access some bad page. We'll have to @@ -498,7 +372,7 @@ vmalloc_fault: * silently loop forever. */ - pte_k = pte_offset(pmd_k, address); + pte_k = pte_offset_kernel(pmd_k, address); if (!pte_present(*pte_k)) goto no_context; diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c index d9ab23bacb2b..3ff9bfcb8194 100644 --- a/arch/cris/mm/init.c +++ b/arch/cris/mm/init.c @@ -7,6 +7,27 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.9 2003/07/04 08:27:54 starvik + * Merge of Linux 2.5.74 + * + * Revision 1.8 2003/04/09 05:20:48 starvik + * Merge of Linux 2.5.67 + * + * Revision 1.7 2003/01/22 06:48:38 starvik + * Fixed warnings issued by GCC 3.2.1 + * + * Revision 1.6 2002/12/11 14:44:48 starvik + * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm + * + * Revision 1.5 2002/11/18 07:37:37 starvik + * Added cache bug workaround (from Linux 2.4) + * + * Revision 1.4 2002/11/13 15:40:24 starvik + * Removed the page table cache stuff (as done in other archs) + * + * Revision 1.3 2002/11/05 06:45:13 starvik + * Merge of Linux 2.5.45 + * * Revision 1.2 2001/12/18 13:35:22 bjornw * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). * @@ -91,65 +112,19 @@ * */ -#include <linux/config.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/swap.h> -#include <linux/smp.h> +#include <linux/init.h> #include <linux/bootmem.h> +#include <asm/tlb.h> -#include <asm/system.h> -#include <asm/segment.h> -#include <asm/pgalloc.h> -#include <asm/pgtable.h> -#include <asm/dma.h> -#include <asm/svinto.h> -#include <asm/io.h> -#include <asm/mmu_context.h> - -struct pgtable_cache_struct quicklists; /* see asm/pgalloc.h */ - -const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; - -extern void die_if_kernel(char *,struct pt_regs *,long); -extern void show_net_buffers(void); -extern void tlb_init(void); - +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); unsigned long empty_zero_page; -/* trim the page-table cache if necessary */ - -int -do_check_pgt_cache(int low, int high) -{ - int freed = 0; +extern unsigned long loops_per_jiffy; /* init/main.c */ +unsigned long loops_per_usec; - if(pgtable_cache_size > high) { - do { - if(pgd_quicklist) { - free_pgd_slow(get_pgd_fast()); - freed++; - } - if(pmd_quicklist) { - pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); - freed++; - } - if(pte_quicklist) { - pte_free_slow(pte_alloc_one_fast(NULL, 0)); - freed++; - } - } while(pgtable_cache_size > low); - } - return freed; -} +extern char _stext, _edata, _etext; /* From linkerscript */ +extern char __init_begin, __init_end; void show_mem(void) @@ -180,181 +155,8 @@ show_mem(void) printk("%d pages nonshared\n",nonshared); printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); - printk("%ld pages in page table cache\n",pgtable_cache_size); } -/* - * The kernel is already mapped with a kernel segment at kseg_c so - * we don't need to map it with a page table. However head.S also - * temporarily mapped it at kseg_4 so we should set up the ksegs again, - * clear the TLB and do some other paging setup stuff. - */ - -void __init -paging_init(void) -{ - int i; - unsigned long zones_size[MAX_NR_ZONES]; - - printk("Setting up paging and the MMU.\n"); - - /* clear out the init_mm.pgd that will contain the kernel's mappings */ - - for(i = 0; i < PTRS_PER_PGD; i++) - swapper_pg_dir[i] = __pgd(0); - - /* make sure the current pgd table points to something sane - * (even if it is most probably not used until the next - * switch_mm) - */ - - current_pgd = init_mm.pgd; - - /* initialise the TLB (tlb.c) */ - - tlb_init(); - - /* see README.mm for details on the KSEG setup */ - -#ifndef CONFIG_CRIS_LOW_MAP - /* This code is for the corrected Etrax-100 LX version 2... */ - - *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ - IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ - IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ - IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ - IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ - IO_STATE(R_MMU_KSEG, seg_a, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_9, page ) | - IO_STATE(R_MMU_KSEG, seg_8, page ) | - IO_STATE(R_MMU_KSEG, seg_7, page ) | - IO_STATE(R_MMU_KSEG, seg_6, page ) | - IO_STATE(R_MMU_KSEG, seg_5, page ) | - IO_STATE(R_MMU_KSEG, seg_4, page ) | - IO_STATE(R_MMU_KSEG, seg_3, page ) | - IO_STATE(R_MMU_KSEG, seg_2, page ) | - IO_STATE(R_MMU_KSEG, seg_1, page ) | - IO_STATE(R_MMU_KSEG, seg_0, page ) ); - - *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | - IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | - IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | - IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); - - *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#else - /* Etrax-100 LX version 1 has a bug so that we cannot map anything - * across the 0x80000000 boundary, so we need to shrink the user-virtual - * area to 0x50000000 instead of 0xb0000000 and map things slightly - * different. The unused areas are marked as paged so that we can catch - * freak kernel accesses there. - * - * The ARTPEC chip is mapped at 0xa so we pass that segment straight - * through. We cannot vremap it because the vmalloc area is below 0x8 - * and Juliette needs an uncached area above 0x8. - * - * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards. - * We map them straight over in LOW_MAP, but use vremap in LX version 2. - */ - - *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, page ) | - IO_STATE(R_MMU_KSEG, seg_e, page ) | - IO_STATE(R_MMU_KSEG, seg_d, page ) | - IO_STATE(R_MMU_KSEG, seg_c, page ) | - IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ -#ifdef CONFIG_JULIETTE - IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ -#else - IO_STATE(R_MMU_KSEG, seg_a, page ) | -#endif - IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ - IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ - IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ - IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ - IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ - IO_STATE(R_MMU_KSEG, seg_4, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_3, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_2, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_1, page ) | /* user area */ - IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ - - *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | - IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | -#ifdef CONFIG_JULIETTE - IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | -#else - IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | -#endif - IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | - IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); - - *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | - IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | - IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); -#endif - - *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); - - /* The MMU has been enabled ever since head.S but just to make - * it totally obvious we do it here as well. - */ - - *R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) | - IO_STATE(R_MMU_CTRL, acc_excp, enable ) | - IO_STATE(R_MMU_CTRL, we_excp, enable ) ); - - *R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable); - - /* - * initialize the bad page table and bad page to point - * to a couple of allocated pages - */ - - empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); - memset((void *)empty_zero_page, 0, PAGE_SIZE); - - /* All pages are DMA'able in Etrax, so put all in the DMA'able zone */ - - zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT; - - for (i = 1; i < MAX_NR_ZONES; i++) - zones_size[i] = 0; - - /* Use free_area_init_node instead of free_area_init, because the former - * is designed for systems where the DRAM starts at an address substantially - * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the - * mem_map page array. - */ - - free_area_init_node(0, &contig_page_data, 0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); - mem_map = contig_page_data.node_mem_map; -} - -extern unsigned long loops_per_jiffy; /* init/main.c */ -unsigned long loops_per_usec; - -extern char _stext, _edata, _etext; -extern char __init_begin, __init_end; - void __init mem_init(void) { @@ -409,48 +211,6 @@ mem_init(void) return; } -/* Initialize remaps of some I/O-ports. This is designed to be callable - * multiple times from the drivers init-sections, because we don't know - * beforehand which driver will get initialized first. - */ - -void -init_ioremap(void) -{ - - /* Give the external I/O-port addresses their values */ - - static int initialized = 0; - - if( !initialized ) { - initialized++; - -#ifdef CONFIG_CRIS_LOW_MAP - /* Simply a linear map (see the KSEG map above in paging_init) */ - port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | - MEM_NON_CACHEABLE); - port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | - MEM_NON_CACHEABLE); - port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | - MEM_NON_CACHEABLE); -#else - /* Note that nothing blows up just because we do this remapping - * it's ok even if the ports are not used or connected - * to anything (or connected to a non-I/O thing) */ - port_cse1_addr = (volatile unsigned long *) - ioremap((unsigned long)(MEM_CSE1_START | - MEM_NON_CACHEABLE), 16); - port_csp0_addr = (volatile unsigned long *) - ioremap((unsigned long)(MEM_CSP0_START | - MEM_NON_CACHEABLE), 16); - port_csp4_addr = (volatile unsigned long *) - ioremap((unsigned long)(MEM_CSP4_START | - MEM_NON_CACHEABLE), 16); -#endif - } -} - - /* free the pages occupied by initialization code */ void @@ -466,5 +226,5 @@ free_initmem(void) totalram_pages++; } printk ("Freeing unused kernel memory: %luk freed\n", - (&__init_end - &__init_begin) >> 10); + (unsigned long)((&__init_end - &__init_begin) >> 10)); } diff --git a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c index 53656f9c5dc4..14216d9668f9 100644 --- a/arch/cris/mm/ioremap.c +++ b/arch/cris/mm/ioremap.c @@ -12,12 +12,13 @@ #include <linux/vmalloc.h> #include <asm/io.h> #include <asm/pgalloc.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> -static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, +extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, unsigned long phys_addr, unsigned long flags) { unsigned long end; - unsigned long pfn; address &= ~PMD_MASK; end = address + size; @@ -25,17 +26,16 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned l end = PMD_SIZE; if (address >= end) BUG(); - pfn = phys_addr >> PAGE_SHIFT; do { if (!pte_none(*pte)) { printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | __READABLE | - __WRITEABLE | _PAGE_GLOBAL | - _PAGE_KERNEL | flags))); + set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE | + __WRITEABLE | _PAGE_GLOBAL | + _PAGE_KERNEL | flags))); address += PAGE_SIZE; - pfn++; + phys_addr += PAGE_SIZE; pte++; } while (address && (address < end)); } @@ -53,7 +53,7 @@ static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned lo if (address >= end) BUG(); do { - pte_t * pte = pte_alloc(&init_mm, pmd, address); + pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); if (!pte) return -ENOMEM; remap_area_pte(pte, address, end - address, address + phys_addr, flags); @@ -148,7 +148,7 @@ void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flag */ offset = phys_addr & ~PAGE_MASK; phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(last_addr) - phys_addr; + size = PAGE_ALIGN(last_addr+1) - phys_addr; /* * Ok, go for it.. diff --git a/arch/cris/mm/tlb.c b/arch/cris/mm/tlb.c index f5a97c9799fd..23eca5ad7389 100644 --- a/arch/cris/mm/tlb.c +++ b/arch/cris/mm/tlb.c @@ -7,31 +7,11 @@ * */ -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> #include <linux/init.h> - -#include <asm/system.h> -#include <asm/segment.h> -#include <asm/pgtable.h> -#include <asm/svinto.h> -#include <asm/mmu_context.h> +#include <asm/tlb.h> #define D(x) -/* CRIS in Etrax100LX TLB */ - -#define NUM_TLB_ENTRIES 64 -#define NUM_PAGEID 64 -#define INVALID_PAGEID 63 -#define NO_CONTEXT -1 - /* The TLB can host up to 64 different mm contexts at the same time. * The running context is R_MMU_CONTEXT, and each TLB entry contains a * page_id that has to match to give a hit. In page_id_map, we keep track @@ -47,182 +27,8 @@ */ struct mm_struct *page_id_map[NUM_PAGEID]; - static int map_replace_ptr = 1; /* which page_id_map entry to replace next */ -/* invalidate all TLB entries */ - -void -flush_tlb_all(void) -{ - int i; - unsigned long flags; - - /* the vpn of i & 0xf is so we don't write similar TLB entries - * in the same 4-way entry group. details.. - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); - *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - restore_flags(flags); - D(printk("tlb: flushed all\n")); -} - -/* invalidate the selected mm context only */ - -void -flush_tlb_mm(struct mm_struct *mm) -{ - int i; - int page_id = mm->context; - unsigned long flags; - - D(printk("tlb: flush mm context %d (%p)\n", page_id, mm)); - - if(page_id == NO_CONTEXT) - return; - - /* mark the TLB entries that match the page_id as invalid. - * here we could also check the _PAGE_GLOBAL bit and NOT flush - * global pages. is it worth the extra I/O ? - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); - if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { - *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - } - restore_flags(flags); -} - -/* invalidate a single page */ - -void -flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr) -{ - struct mm_struct *mm = vma->vm_mm; - int page_id = mm->context; - int i; - unsigned long flags; - - D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm)); - - if(page_id == NO_CONTEXT) - return; - - addr &= PAGE_MASK; /* perhaps not necessary */ - - /* invalidate those TLB entries that match both the mm context - * and the virtual address requested - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - unsigned long tlb_hi; - *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); - tlb_hi = *R_TLB_HI; - if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && - (tlb_hi & PAGE_MASK) == addr) { - *R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - addr; /* same addr as before works. */ - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - } - restore_flags(flags); -} - -/* invalidate a page range */ - -void -flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, - unsigned long end) -{ - struct mm_struct *mm = vma->vm_mm; - int page_id = mm->context; - int i; - unsigned long flags; - - D(printk("tlb: flush range %p<->%p in context %d (%p)\n", - start, end, page_id, mm)); - - if(page_id == NO_CONTEXT) - return; - - start &= PAGE_MASK; /* probably not necessary */ - end &= PAGE_MASK; /* dito */ - - /* invalidate those TLB entries that match both the mm context - * and the virtual address range - */ - - save_and_cli(flags); /* flush needs to be atomic */ - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - unsigned long tlb_hi, vpn; - *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); - tlb_hi = *R_TLB_HI; - vpn = tlb_hi & PAGE_MASK; - if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && - vpn >= start && vpn < end) { - *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | - IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); - - *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | - IO_STATE(R_TLB_LO, valid, no ) | - IO_STATE(R_TLB_LO, kernel,no ) | - IO_STATE(R_TLB_LO, we, no ) | - IO_FIELD(R_TLB_LO, pfn, 0 ) ); - } - } - restore_flags(flags); -} - -/* dump the entire TLB for debug purposes */ - -#if 0 -void -dump_tlb_all(void) -{ - int i; - unsigned long flags; - - printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n"); - - save_and_cli(flags); - for(i = 0; i < NUM_TLB_ENTRIES; i++) { - *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); - printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n", - i, *R_TLB_HI, *R_TLB_LO); - } - restore_flags(flags); -} -#endif - /* * Initialize the context related info for a new mm_struct * instance. @@ -279,33 +85,6 @@ get_mmu_context(struct mm_struct *mm) alloc_context(mm); } -/* called in schedule() just before actually doing the switch_to */ - -void -switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk, int cpu) -{ - /* make sure we have a context */ - - get_mmu_context(next); - - /* remember the pgd for the fault handlers - * this is similar to the pgd register in some other CPU's. - * we need our own copy of it because current and active_mm - * might be invalid at points where we still need to derefer - * the pgd. - */ - - current_pgd = next->pgd; - - /* switch context in the MMU */ - - D(printk("switching mmu_context to %d (%p)\n", next->context, next)); - - *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context); -} - - /* called by __exit_mm to destroy the used MMU context if any before * destroying the mm itself. this is only called when the last user of the mm * drops it. diff --git a/include/asm-cris/arch-v10/bitops.h b/include/asm-cris/arch-v10/bitops.h new file mode 100644 index 000000000000..21b7ae8c9bb3 --- /dev/null +++ b/include/asm-cris/arch-v10/bitops.h @@ -0,0 +1,73 @@ +/* asm/arch/bitops.h for Linux/CRISv10 */ + +#ifndef _CRIS_ARCH_BITOPS_H +#define _CRIS_ARCH_BITOPS_H + +/* + * Helper functions for the core of the ff[sz] functions, wrapping the + * syntactically awkward asms. The asms compute the number of leading + * zeroes of a bits-in-byte and byte-in-word and word-in-dword-swapped + * number. They differ in that the first function also inverts all bits + * in the input. + */ +extern inline unsigned long cris_swapnwbrlz(unsigned long w) +{ + /* Let's just say we return the result in the same register as the + input. Saying we clobber the input but can return the result + in another register: + ! __asm__ ("swapnwbr %2\n\tlz %2,%0" + ! : "=r,r" (res), "=r,X" (dummy) : "1,0" (w)); + confuses gcc (sched.c, gcc from cris-dist-1.14). */ + + unsigned long res; + __asm__ ("swapnwbr %0 \n\t" + "lz %0,%0" + : "=r" (res) : "0" (w)); + return res; +} + +extern inline unsigned long cris_swapwbrlz(unsigned long w) +{ + unsigned res; + __asm__ ("swapwbr %0 \n\t" + "lz %0,%0" + : "=r" (res) + : "0" (w)); + return res; +} + +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +extern inline unsigned long ffz(unsigned long w) +{ + return cris_swapnwbrlz(w); +} + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +extern __inline__ unsigned long __ffs(unsigned long word) +{ + return cris_swapnwbrlz(~word); +} + +/** + * ffs - find first bit set + * @x: the word to search + * + * This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +extern inline unsigned long kernel_ffs(unsigned long w) +{ + return w ? cris_swapwbrlz (w) + 1 : 0; +} + +#endif diff --git a/include/asm-cris/arch-v10/byteorder.h b/include/asm-cris/arch-v10/byteorder.h new file mode 100644 index 000000000000..bac946459b81 --- /dev/null +++ b/include/asm-cris/arch-v10/byteorder.h @@ -0,0 +1,25 @@ +#ifndef _CRIS_ARCH_BYTEORDER_H +#define _CRIS_ARCH_BYTEORDER_H + +#include <asm/types.h> + +/* we just define these two (as we can do the swap in a single + * asm instruction in CRIS) and the arch-independent files will put + * them together into ntohl etc. + */ + +extern __inline__ __const__ __u32 ___arch__swab32(__u32 x) +{ + __asm__ ("swapwb %0" : "=r" (x) : "0" (x)); + + return(x); +} + +extern __inline__ __const__ __u16 ___arch__swab16(__u16 x) +{ + __asm__ ("swapb %0" : "=r" (x) : "0" (x)); + + return(x); +} + +#endif diff --git a/include/asm-cris/arch-v10/cache.h b/include/asm-cris/arch-v10/cache.h new file mode 100644 index 000000000000..1e796271ea5e --- /dev/null +++ b/include/asm-cris/arch-v10/cache.h @@ -0,0 +1,8 @@ +#ifndef _ASM_ARCH_CACHE_H +#define _ASM_ARCH_CACHE_H + +/* Etrax 100LX have 32-byte cache-lines. */ +#define L1_CACHE_BYTES 32 +#define L1_CACHE_SHIFT_MAX 5 + +#endif /* _ASM_ARCH_CACHE_H */ diff --git a/include/asm-cris/arch-v10/checksum.h b/include/asm-cris/arch-v10/checksum.h new file mode 100644 index 000000000000..fde1d00aaa90 --- /dev/null +++ b/include/asm-cris/arch-v10/checksum.h @@ -0,0 +1,29 @@ +#ifndef _CRIS_ARCH_CHECKSUM_H +#define _CRIS_ARCH_CHECKSUM_H + +/* Checksum some values used in TCP/UDP headers. + * + * The gain by doing this in asm is that C will not generate carry-additions + * for the 32-bit components of the checksum, so otherwise we would have had + * to split all of those into 16-bit components, then add. + */ + +extern inline unsigned int +csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned short proto, unsigned int sum) +{ + int res; + __asm__ ("add.d %2, %0\n\t" + "ax\n\t" + "add.d %3, %0\n\t" + "ax\n\t" + "add.d %4, %0\n\t" + "ax\n\t" + "addq 0, %0\n" + : "=r" (res) + : "0" (sum), "r" (daddr), "r" (saddr), "r" ((ntohs(len) << 16) + (proto << 8))); + + return res; +} + +#endif diff --git a/include/asm-cris/arch-v10/delay.h b/include/asm-cris/arch-v10/delay.h new file mode 100644 index 000000000000..cfedae0d2f53 --- /dev/null +++ b/include/asm-cris/arch-v10/delay.h @@ -0,0 +1,20 @@ +#ifndef _CRIS_ARCH_DELAY_H +#define _CRIS_ARCH_DELAY_H + +extern __inline__ void __delay(int loops) +{ + __asm__ __volatile__ ( + "move.d %0,$r9\n\t" + "beq 2f\n\t" + "subq 1,$r9\n\t" + "1:\n\t" + "bne 1b\n\t" + "subq 1,$r9\n" + "2:" + : : "g" (loops) : "r9"); +} + +#endif /* defined(_CRIS_ARCH_DELAY_H) */ + + + diff --git a/include/asm-cris/arch-v10/dma.h b/include/asm-cris/arch-v10/dma.h new file mode 100644 index 000000000000..9e078b9bc934 --- /dev/null +++ b/include/asm-cris/arch-v10/dma.h @@ -0,0 +1,46 @@ +/* Defines for using and allocating dma channels. */ + +#ifndef _ASM_ARCH_DMA_H +#define _ASM_ARCH_DMA_H + +#define MAX_DMA_CHANNELS 10 + +/* dma0 and dma1 used for network (ethernet) */ +#define NETWORK_TX_DMA_NBR 0 +#define NETWORK_RX_DMA_NBR 1 + +/* dma2 and dma3 shared by par0, scsi0, ser2 and ata */ +#define PAR0_TX_DMA_NBR 2 +#define PAR0_RX_DMA_NBR 3 +#define SCSI0_TX_DMA_NBR 2 +#define SCSI0_RX_DMA_NBR 3 +#define SER2_TX_DMA_NBR 2 +#define SER2_RX_DMA_NBR 3 +#define ATA_TX_DMA_NBR 2 +#define ATA_RX_DMA_NBR 3 + +/* dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ +#define PAR1_TX_DMA_NBR 4 +#define PAR1_RX_DMA_NBR 5 +#define SCSI1_TX_DMA_NBR 4 +#define SCSI1_RX_DMA_NBR 5 +#define SER3_TX_DMA_NBR 4 +#define SER3_RX_DMA_NBR 5 +#define EXTDMA0_TX_DMA_NBR 4 +#define EXTDMA0_RX_DMA_NBR 5 + +/* dma6 and dma7 shared by ser0, extdma1 and mem2mem */ +#define SER0_TX_DMA_NBR 6 +#define SER0_RX_DMA_NBR 7 +#define EXTDMA1_TX_DMA_NBR 6 +#define EXTDMA1_RX_DMA_NBR 7 +#define MEM2MEM_TX_DMA_NBR 6 +#define MEM2MEM_RX_DMA_NBR 7 + +/* dma8 and dma9 shared by ser1 and usb */ +#define SER1_TX_DMA_NBR 8 +#define SER1_RX_DMA_NBR 9 +#define USB_TX_DMA_NBR 8 +#define USB_RX_DMA_NBR 9 + +#endif diff --git a/include/asm-cris/arch-v10/elf.h b/include/asm-cris/arch-v10/elf.h new file mode 100644 index 000000000000..2a2201ca538e --- /dev/null +++ b/include/asm-cris/arch-v10/elf.h @@ -0,0 +1,71 @@ +#ifndef __ASMCRIS_ARCH_ELF_H +#define __ASMCRIS_ARCH_ELF_H + +/* + * ELF register definitions.. + */ + +#include <asm/ptrace.h> + +/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts (a register; assume first param register for CRIS) + contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ + +/* Explicitly set registers to 0 to increase determinism. */ +#define ELF_PLAT_INIT(_r, load_addr) do { \ + (_r)->r13 = 0; (_r)->r12 = 0; (_r)->r11 = 0; (_r)->r10 = 0; \ + (_r)->r9 = 0; (_r)->r8 = 0; (_r)->r7 = 0; (_r)->r6 = 0; \ + (_r)->r5 = 0; (_r)->r4 = 0; (_r)->r3 = 0; (_r)->r2 = 0; \ + (_r)->r1 = 0; (_r)->r0 = 0; (_r)->mof = 0; (_r)->srp = 0; \ +} while (0) + +/* The additional layer below is because the stack pointer is missing in + the pt_regs struct, but needed in a core dump. pr_reg is a elf_gregset_t, + and should be filled in according to the layout of the user_regs_struct + struct; regs is a pt_regs struct. We dump all registers, though several are + obviously unnecessary. That way there's less need for intelligence at + the receiving end (i.e. gdb). */ +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + pr_reg[0] = regs->r0; \ + pr_reg[1] = regs->r1; \ + pr_reg[2] = regs->r2; \ + pr_reg[3] = regs->r3; \ + pr_reg[4] = regs->r4; \ + pr_reg[5] = regs->r5; \ + pr_reg[6] = regs->r6; \ + pr_reg[7] = regs->r7; \ + pr_reg[8] = regs->r8; \ + pr_reg[9] = regs->r9; \ + pr_reg[10] = regs->r10; \ + pr_reg[11] = regs->r11; \ + pr_reg[12] = regs->r12; \ + pr_reg[13] = regs->r13; \ + pr_reg[14] = rdusp(); /* sp */ \ + pr_reg[15] = regs->irp; /* pc */ \ + pr_reg[16] = 0; /* p0 */ \ + pr_reg[17] = rdvr(); /* vr */ \ + pr_reg[18] = 0; /* p2 */ \ + pr_reg[19] = 0; /* p3 */ \ + pr_reg[20] = 0; /* p4 */ \ + pr_reg[21] = (regs->dccr & 0xffff); /* ccr */ \ + pr_reg[22] = 0; /* p6 */ \ + pr_reg[23] = regs->mof; /* mof */ \ + pr_reg[24] = 0; /* p8 */ \ + pr_reg[25] = 0; /* ibr */ \ + pr_reg[26] = 0; /* irp */ \ + pr_reg[27] = regs->srp; /* srp */ \ + pr_reg[28] = 0; /* bar */ \ + pr_reg[29] = regs->dccr; /* dccr */ \ + pr_reg[30] = 0; /* brp */ \ + pr_reg[31] = rdusp(); /* usp */ \ + pr_reg[32] = 0; /* csrinstr */ \ + pr_reg[33] = 0; /* csraddr */ \ + pr_reg[34] = 0; /* csrdata */ + + +#endif diff --git a/include/asm-cris/arch-v10/io.h b/include/asm-cris/arch-v10/io.h new file mode 100644 index 000000000000..0bc38a0313c1 --- /dev/null +++ b/include/asm-cris/arch-v10/io.h @@ -0,0 +1,193 @@ +#ifndef _ASM_ARCH_CRIS_IO_H +#define _ASM_ARCH_CRIS_IO_H + +#include <asm/arch/svinto.h> +#include <linux/config.h> + +/* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */ + +extern unsigned long port_g_data_shadow; +extern unsigned char port_pa_dir_shadow; +extern unsigned char port_pa_data_shadow; +extern unsigned char port_pb_i2c_shadow; +extern unsigned char port_pb_config_shadow; +extern unsigned char port_pb_dir_shadow; +extern unsigned char port_pb_data_shadow; +extern unsigned long r_timer_ctrl_shadow; + +extern unsigned long port_cse1_shadow; +extern unsigned long port_csp0_shadow; +extern unsigned long port_csp4_shadow; + +extern volatile unsigned long *port_cse1_addr; +extern volatile unsigned long *port_csp0_addr; +extern volatile unsigned long *port_csp4_addr; + +/* macro for setting regs through a shadow - + * r = register name (like R_PORT_PA_DATA) + * s = shadow name (like port_pa_data_shadow) + * b = bit number + * v = value (0 or 1) + */ + +#define REG_SHADOW_SET(r,s,b,v) *r = s = (s & ~(1 << (b))) | ((v) << (b)) + +/* The LED's on various Etrax-based products are set differently. */ + +#if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM) +#undef CONFIG_ETRAX_PA_LEDS +#undef CONFIG_ETRAX_PB_LEDS +#undef CONFIG_ETRAX_CSP0_LEDS +#define LED_NETWORK_SET_G(x) +#define LED_NETWORK_SET_R(x) +#define LED_ACTIVE_SET_G(x) +#define LED_ACTIVE_SET_R(x) +#define LED_DISK_WRITE(x) +#define LED_DISK_READ(x) +#endif + +#if !defined(CONFIG_ETRAX_CSP0_LEDS) +#define LED_BIT_SET(x) +#define LED_BIT_CLR(x) +#endif + +#define LED_OFF 0x00 +#define LED_GREEN 0x01 +#define LED_RED 0x02 +#define LED_ORANGE (LED_GREEN | LED_RED) + +#if CONFIG_ETRAX_LED1G == CONFIG_ETRAX_LED1R +#define LED_NETWORK_SET(x) \ + do { \ + LED_NETWORK_SET_G((x) & LED_GREEN); \ + } while (0) +#else +#define LED_NETWORK_SET(x) \ + do { \ + LED_NETWORK_SET_G((x) & LED_GREEN); \ + LED_NETWORK_SET_R((x) & LED_RED); \ + } while (0) +#endif +#if CONFIG_ETRAX_LED2G == CONFIG_ETRAX_LED2R +#define LED_ACTIVE_SET(x) \ + do { \ + LED_ACTIVE_SET_G((x) & LED_GREEN); \ + } while (0) +#else +#define LED_ACTIVE_SET(x) \ + do { \ + LED_ACTIVE_SET_G((x) & LED_GREEN); \ + LED_ACTIVE_SET_R((x) & LED_RED); \ + } while (0) +#endif + +#ifdef CONFIG_ETRAX_PA_LEDS +#define LED_NETWORK_SET_G(x) \ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1G, !(x)) +#define LED_NETWORK_SET_R(x) \ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1R, !(x)) +#define LED_ACTIVE_SET_G(x) \ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !(x)) +#define LED_ACTIVE_SET_R(x) \ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x)) +#define LED_DISK_WRITE(x) \ + do{\ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x));\ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x));\ + }while(0) +#define LED_DISK_READ(x) \ + REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) +#endif + +#ifdef CONFIG_ETRAX_PB_LEDS +#define LED_NETWORK_SET_G(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1G, !(x)) +#define LED_NETWORK_SET_R(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1R, !(x)) +#define LED_ACTIVE_SET_G(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !(x)) +#define LED_ACTIVE_SET_R(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x)) +#define LED_DISK_WRITE(x) \ + do{\ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x));\ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x));\ + }while(0) +#define LED_DISK_READ(x) \ + REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x)) +#endif + +#ifdef CONFIG_ETRAX_CSP0_LEDS +#define CONFIGURABLE_LEDS\ + ((1 << CONFIG_ETRAX_LED1G ) | (1 << CONFIG_ETRAX_LED1R ) |\ + (1 << CONFIG_ETRAX_LED2G ) | (1 << CONFIG_ETRAX_LED2R ) |\ + (1 << CONFIG_ETRAX_LED3G ) | (1 << CONFIG_ETRAX_LED3R ) |\ + (1 << CONFIG_ETRAX_LED4G ) | (1 << CONFIG_ETRAX_LED4R ) |\ + (1 << CONFIG_ETRAX_LED5G ) | (1 << CONFIG_ETRAX_LED5R ) |\ + (1 << CONFIG_ETRAX_LED6G ) | (1 << CONFIG_ETRAX_LED6R ) |\ + (1 << CONFIG_ETRAX_LED7G ) | (1 << CONFIG_ETRAX_LED7R ) |\ + (1 << CONFIG_ETRAX_LED8Y ) | (1 << CONFIG_ETRAX_LED9Y ) |\ + (1 << CONFIG_ETRAX_LED10Y ) |(1 << CONFIG_ETRAX_LED11Y )|\ + (1 << CONFIG_ETRAX_LED12R )) + +#define LED_NETWORK_SET_G(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1G, !(x)) +#define LED_NETWORK_SET_R(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1R, !(x)) +#define LED_ACTIVE_SET_G(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2G, !(x)) +#define LED_ACTIVE_SET_R(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x)) +#define LED_DISK_WRITE(x) \ + do{\ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x));\ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x));\ + }while(0) +#define LED_DISK_READ(x) \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x)) +#define LED_BIT_SET(x)\ + do{\ + if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1);\ + }while(0) +#define LED_BIT_CLR(x)\ + do{\ + if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0);\ + }while(0) +#endif + +# +#ifdef CONFIG_ETRAX_SOFT_SHUTDOWN +#define SOFT_SHUTDOWN() \ + REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_SHUTDOWN_BIT, 1) +#else +#define SOFT_SHUTDOWN() +#endif + +/* Console I/O for simulated etrax100. Use #ifdef so erroneous + use will be evident. */ +#ifdef CONFIG_SVINTO_SIM + /* Let's use the ucsim interface since it lets us do write(2, ...) */ +#define SIMCOUT(s,len) \ + asm ("moveq 4,$r9 \n\t" \ + "moveq 2,$r10 \n\t" \ + "move.d %0,$r11 \n\t" \ + "move.d %1,$r12 \n\t" \ + "push $irp \n\t" \ + "move 0f,$irp \n\t" \ + "jump -6809 \n" \ + "0: \n\t" \ + "pop $irp" \ + : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") +#define TRACE_ON() __extension__ \ + ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ + (255)); _Foofoo; }) + +#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0) +#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0) +#define CRIS_CYCLES() __extension__ \ + ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;}) +#endif /* ! defined CONFIG_SVINTO_SIM */ + +#endif diff --git a/include/asm-cris/arch-v10/irq.h b/include/asm-cris/arch-v10/irq.h new file mode 100644 index 000000000000..f657c75ddcfa --- /dev/null +++ b/include/asm-cris/arch-v10/irq.h @@ -0,0 +1,176 @@ +/* + * Interrupt handling assembler and defines for Linux/CRISv10 + */ + +#ifndef _ASM_ARCH_IRQ_H +#define _ASM_ARCH_IRQ_H + +#include <asm/arch/sv_addr_ag.h> + +#define NR_IRQS 32 +#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 TIMER0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */ +#define TIMER1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer1) /* 3 */ +/* mio, ata, par0, scsi0 on 4 */ +/* par1, scsi1 on 5 */ +#define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */ + +#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, serial) /* 8 */ +#define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */ +/* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */ +#define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0) +#define EXTDMA1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma1) + +/* dma0-9 is irq 16..25 */ +/* 16,17: network */ +#define DMA0_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma0) +#define DMA1_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma1) +#define NETWORK_DMA_TX_IRQ_NBR DMA0_TX_IRQ_NBR +#define NETWORK_DMA_RX_IRQ_NBR DMA1_RX_IRQ_NBR + +/* 18,19: dma2 and dma3 shared by par0, scsi0, ser2 and ata */ +#define DMA2_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma2) +#define DMA3_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma3) +#define SER2_DMA_TX_IRQ_NBR DMA2_TX_IRQ_NBR +#define SER2_DMA_RX_IRQ_NBR DMA3_RX_IRQ_NBR + +/* 20,21: dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ +#define DMA4_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma4) +#define DMA5_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma5) +#define SER3_DMA_TX_IRQ_NBR DMA4_TX_IRQ_NBR +#define SER3_DMA_RX_IRQ_NBR DMA5_RX_IRQ_NBR + +/* 22,23: dma6 and dma7 shared by ser0, extdma1 and mem2mem */ +#define DMA6_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma6) +#define DMA7_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma7) +#define SER0_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR +#define SER0_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR +#define MEM2MEM_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR +#define MEM2MEM_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR + +/* 24,25: dma8 and dma9 shared by ser1 and usb */ +#define DMA8_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma8) +#define DMA9_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma9) +#define SER1_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR +#define SER1_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR +#define USB_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR +#define USB_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR + +/* usb: controller at irq 31 + uses DMA8 and DMA9 */ +#define USB_HC_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, usb) + +/* our fine, global, etrax irq vector! the pointer lives in the head.S file. */ + +typedef void (*irqvectptr)(void); + +struct etrax_interrupt_vector { + irqvectptr v[256]; +}; + +extern struct etrax_interrupt_vector *etrax_irv; +void set_int_vector(int n, irqvectptr addr, irqvectptr saddr); +void set_break_vector(int n, irqvectptr addr); + +#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); +#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); + +#define __STR(x) #x +#define STR(x) __STR(x) + +/* SAVE_ALL saves registers so they match pt_regs */ + +#define SAVE_ALL \ + "move $irp,[$sp=$sp-16]\n\t" /* push instruction pointer and fake SBFS struct */ \ + "push $srp\n\t" /* push subroutine return pointer */ \ + "push $dccr\n\t" /* push condition codes */ \ + "push $mof\n\t" /* push multiply overflow reg */ \ + "di\n\t" /* need to disable irq's at this point */\ + "subq 14*4,$sp\n\t" /* make room for r0-r13 */ \ + "movem $r13,[$sp]\n\t" /* push the r0-r13 registers */ \ + "push $r10\n\t" /* push orig_r10 */ \ + "clear.d [$sp=$sp-4]\n\t" /* frametype - this is a normal stackframe */ + + /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq */ + +#define BLOCK_IRQ(mask,nr) \ + "move.d " #mask ",$r0\n\t" \ + "move.d $r0,[0xb00000d8]\n\t" + +#define UNBLOCK_IRQ(mask) \ + "move.d " #mask ",$r0\n\t" \ + "move.d $r0,[0xb00000dc]\n\t" + +#define IRQ_NAME2(nr) nr##_interrupt(void) +#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) +#define sIRQ_NAME(nr) IRQ_NAME2(sIRQ##nr) +#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) + + /* the asm IRQ handler makes sure the causing IRQ is blocked, then it calls + * do_IRQ (with irq disabled still). after that it unblocks and jumps to + * ret_from_intr (entry.S) + * + * The reason the IRQ is blocked is to allow an sti() before the handler which + * will acknowledge the interrupt is run. + */ + +#define BUILD_IRQ(nr,mask) \ +void IRQ_NAME(nr); \ +void sIRQ_NAME(nr); \ +void BAD_IRQ_NAME(nr); \ +__asm__ ( \ + ".text\n\t" \ + "IRQ" #nr "_interrupt:\n\t" \ + SAVE_ALL \ + "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \ + BLOCK_IRQ(mask,nr) /* this must be done to prevent irq loops when we ei later */ \ + "moveq "#nr",$r10\n\t" \ + "move.d $sp,$r11\n\t" \ + "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \ + UNBLOCK_IRQ(mask) \ + "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \ + "jump ret_from_intr\n\t" \ + "bad_IRQ" #nr "_interrupt:\n\t" \ + "push $r0\n\t" \ + BLOCK_IRQ(mask,nr) \ + "pop $r0\n\t" \ + "reti\n\t" \ + "nop\n"); + +/* This is subtle. The timer interrupt is crucial and it should not be disabled for + * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would + * have been BLOCK'ed, and then softirq's are run before we return here to UNBLOCK. + * If the softirq's take too much time to run, the timer irq won't run and the + * watchdog will kill us. + * + * Furthermore, if a lot of other irq's occur before we return here, the multiple_irq + * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed + * it here, we would not get the multiple_irq at all. + * + * The non-blocking here is based on the knowledge that the timer interrupt is + * registred as a fast interrupt (SA_INTERRUPT) so that we _know_ there will not + * be an sti() before the timer irq handler is run to acknowledge the interrupt. + */ + +#define BUILD_TIMER_IRQ(nr,mask) \ +void IRQ_NAME(nr); \ +void sIRQ_NAME(nr); \ +void BAD_IRQ_NAME(nr); \ +__asm__ ( \ + ".text\n\t" \ + "IRQ" #nr "_interrupt:\n\t" \ + SAVE_ALL \ + "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \ + "moveq "#nr",$r10\n\t" \ + "move.d $sp,$r11\n\t" \ + "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \ + "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \ + "jump ret_from_intr\n\t" \ + "bad_IRQ" #nr "_interrupt:\n\t" \ + "push $r0\n\t" \ + BLOCK_IRQ(mask,nr) \ + "pop $r0\n\t" \ + "reti\n\t" \ + "nop\n"); + +#endif diff --git a/include/asm-cris/arch-v10/mmu.h b/include/asm-cris/arch-v10/mmu.h new file mode 100644 index 000000000000..d18aa00e50bc --- /dev/null +++ b/include/asm-cris/arch-v10/mmu.h @@ -0,0 +1,106 @@ +/* + * CRIS MMU constants and PTE layout + */ + +#ifndef _CRIS_ARCH_MMU_H +#define _CRIS_ARCH_MMU_H + +/* type used in struct mm to couple an MMU context to an active mm */ + +typedef unsigned int mm_context_t; + +/* kernel memory segments */ + +#define KSEG_F 0xf0000000UL +#define KSEG_E 0xe0000000UL +#define KSEG_D 0xd0000000UL +#define KSEG_C 0xc0000000UL +#define KSEG_B 0xb0000000UL +#define KSEG_A 0xa0000000UL +#define KSEG_9 0x90000000UL +#define KSEG_8 0x80000000UL +#define KSEG_7 0x70000000UL +#define KSEG_6 0x60000000UL +#define KSEG_5 0x50000000UL +#define KSEG_4 0x40000000UL +#define KSEG_3 0x30000000UL +#define KSEG_2 0x20000000UL +#define KSEG_1 0x10000000UL +#define KSEG_0 0x00000000UL + +/* CRIS PTE bits (see R_TLB_LO in the register description) + * + * Bit: 31-13 12-------4 3 2 1 0 + * ________________________________________________ + * | pfn | reserved | global | valid | kernel | we | + * |_____|__________|________|_______|________|_____| + * + * (pfn = physical frame number) + */ + +/* Real HW-based PTE bits. We use some synonym names so that + * things become less confusing in combination with the SW-based + * bits further below. + * + */ + +#define _PAGE_WE (1<<0) /* page is write-enabled */ +#define _PAGE_SILENT_WRITE (1<<0) /* synonym */ +#define _PAGE_KERNEL (1<<1) /* page is kernel only */ +#define _PAGE_VALID (1<<2) /* page is valid */ +#define _PAGE_SILENT_READ (1<<2) /* synonym */ +#define _PAGE_GLOBAL (1<<3) /* global page - context is ignored */ + +/* Bits the HW doesn't care about but the kernel uses them in SW */ + +#define _PAGE_PRESENT (1<<4) /* page present in memory */ +#define _PAGE_FILE (1<<5) /* set: pagecache, unset: swap (when !PRESENT) */ +#define _PAGE_ACCESSED (1<<5) /* simulated in software using valid bit */ +#define _PAGE_MODIFIED (1<<6) /* simulated in software using we bit */ +#define _PAGE_READ (1<<7) /* read-enabled */ +#define _PAGE_WRITE (1<<8) /* write-enabled */ + +/* Define some higher level generic page attributes. */ + +#define __READABLE (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED) +#define __WRITEABLE (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED) + +#define _PAGE_TABLE (_PAGE_PRESENT | __READABLE | __WRITEABLE) +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED) + +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | __READABLE | _PAGE_WRITE | \ + _PAGE_ACCESSED) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | __READABLE) // | _PAGE_COW +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | __READABLE) +#define PAGE_KERNEL __pgprot(_PAGE_GLOBAL | _PAGE_KERNEL | \ + _PAGE_PRESENT | __READABLE | __WRITEABLE) +#define _KERNPG_TABLE (_PAGE_TABLE | _PAGE_KERNEL) + +/* + * CRIS can't do page protection for execute, and considers read the same. + * Also, write permissions imply read permissions. This is the closest we can + * get.. + */ + +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +#define PTE_FILE_MAX_BITS 26 + +#endif diff --git a/include/asm-cris/arch-v10/offset.h b/include/asm-cris/arch-v10/offset.h new file mode 100644 index 000000000000..87901a752746 --- /dev/null +++ b/include/asm-cris/arch-v10/offset.h @@ -0,0 +1,33 @@ +#ifndef __ASM_OFFSETS_H__ +#define __ASM_OFFSETS_H__ +/* + * DO NOT MODIFY. + * + * This file was generated by arch/cris/Makefile + * + */ + +#define PT_orig_r10 4 /* offsetof(struct pt_regs, orig_r10) */ +#define PT_r13 8 /* offsetof(struct pt_regs, r13) */ +#define PT_r12 12 /* offsetof(struct pt_regs, r12) */ +#define PT_r11 16 /* offsetof(struct pt_regs, r11) */ +#define PT_r10 20 /* offsetof(struct pt_regs, r10) */ +#define PT_r9 24 /* offsetof(struct pt_regs, r9) */ +#define PT_mof 64 /* offsetof(struct pt_regs, mof) */ +#define PT_dccr 68 /* offsetof(struct pt_regs, dccr) */ +#define PT_srp 72 /* offsetof(struct pt_regs, srp) */ + +#define TI_task 0 /* offsetof(struct thread_info, task) */ +#define TI_flags 8 /* offsetof(struct thread_info, flags) */ +#define TI_preempt_count 16 /* offsetof(struct thread_info, preempt_count) */ + +#define THREAD_ksp 0 /* offsetof(struct thread_struct, ksp) */ +#define THREAD_usp 4 /* offsetof(struct thread_struct, usp) */ +#define THREAD_dccr 8 /* offsetof(struct thread_struct, dccr) */ + +#define TASK_pid 121 /* offsetof(struct task_struct, pid) */ + +#define LCLONE_VM 256 /* CLONE_VM */ +#define LCLONE_UNTRACED 8388608 /* CLONE_UNTRACED */ + +#endif diff --git a/include/asm-cris/arch-v10/page.h b/include/asm-cris/arch-v10/page.h new file mode 100644 index 000000000000..407e6e68f49e --- /dev/null +++ b/include/asm-cris/arch-v10/page.h @@ -0,0 +1,31 @@ +#ifndef _CRIS_ARCH_PAGE_H +#define _CRIS_ARCH_PAGE_H + +#include <linux/config.h> + +#ifdef __KERNEL__ + +/* This handles the memory map.. */ +#ifdef CONFIG_CRIS_LOW_MAP +#define PAGE_OFFSET KSEG_6 /* kseg_6 is mapped to physical ram */ +#else +#define PAGE_OFFSET KSEG_C /* kseg_c is mapped to physical ram */ +#endif + +/* macros to convert between really physical and virtual addresses + * by stripping a selected bit, we can convert between KSEG_x and 0x40000000 where + * the DRAM really resides + */ + +#ifdef CONFIG_CRIS_LOW_MAP +/* we have DRAM virtually at 0x6 */ +#define __pa(x) ((unsigned long)(x) & 0xdfffffff) +#define __va(x) ((void *)((unsigned long)(x) | 0x20000000)) +#else +/* we have DRAM virtually at 0xc */ +#define __pa(x) ((unsigned long)(x) & 0x7fffffff) +#define __va(x) ((void *)((unsigned long)(x) | 0x80000000)) +#endif + +#endif +#endif diff --git a/include/asm-cris/arch-v10/pgtable.h b/include/asm-cris/arch-v10/pgtable.h new file mode 100644 index 000000000000..65eecd1e6538 --- /dev/null +++ b/include/asm-cris/arch-v10/pgtable.h @@ -0,0 +1,19 @@ +#ifndef _CRIS_ARCH_PGTABLE_H +#define _CRIS_ARCH_PGTABLE_H + +/* + * Kernels own virtual memory area. + */ + +#ifdef CONFIG_CRIS_LOW_MAP +#define VMALLOC_START KSEG_7 +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END KSEG_8 +#else +#define VMALLOC_START KSEG_D +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END KSEG_E +#endif + +#endif + diff --git a/include/asm-cris/arch-v10/processor.h b/include/asm-cris/arch-v10/processor.h new file mode 100644 index 000000000000..9355d8675a58 --- /dev/null +++ b/include/asm-cris/arch-v10/processor.h @@ -0,0 +1,62 @@ +#ifndef __ASM_CRIS_ARCH_PROCESSOR_H +#define __ASM_CRIS_ARCH_PROCESSOR_H + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({void *pc; __asm__ ("move.d $pc,%0" : "=rm" (pc)); pc; }) + +/* CRIS has no problems with write protection */ +#define wp_works_ok 1 + +/* CRIS thread_struct. this really has nothing to do with the processor itself, since + * CRIS does not do any hardware task-switching, but it's here for legacy reasons. + * The thread_struct here is used when task-switching using _resume defined in entry.S. + * The offsets here are hardcoded into _resume - if you change this struct, you need to + * change them as well!!! +*/ + +struct thread_struct { + unsigned long ksp; /* kernel stack pointer */ + unsigned long usp; /* user stack pointer */ + unsigned long dccr; /* saved flag register */ +}; + +/* + * User space process size. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. + */ + +#ifdef CONFIG_CRIS_LOW_MAP +#define TASK_SIZE (0x50000000UL) /* 1.25 GB */ +#else +#define TASK_SIZE (0xA0000000UL) /* 2.56 GB */ +#endif + +#define INIT_THREAD { \ + 0, 0, 0x20 } /* ccr = int enable, nothing else */ + +#define KSTK_EIP(tsk) \ +({ \ + unsigned long eip = 0; \ + unsigned long regs = (unsigned long)user_regs(tsk); \ + if (regs > PAGE_SIZE && \ + virt_addr_valid(regs)) \ + eip = ((struct pt_regs *)regs)->irp; \ + eip; \ +}) + +/* give the thread a program location + * set user-mode (The 'U' flag (User mode flag) is CCR/DCCR bit 8) + * switch user-stackpointer + */ + +#define start_thread(regs, ip, usp) do { \ + set_fs(USER_DS); \ + regs->irp = ip; \ + regs->dccr |= 1 << U_DCCR_BITNR; \ + wrusp(usp); \ +} while(0) + +#endif diff --git a/include/asm-cris/arch-v10/ptrace.h b/include/asm-cris/arch-v10/ptrace.h new file mode 100644 index 000000000000..939d9846477e --- /dev/null +++ b/include/asm-cris/arch-v10/ptrace.h @@ -0,0 +1,114 @@ +#ifndef _CRIS_ARCH_PTRACE_H +#define _CRIS_ARCH_PTRACE_H + +/* Frame types */ + +#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ +#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return + path */ + +/* Register numbers in the ptrace system call interface */ + +#define PT_FRAMETYPE 0 +#define PT_ORIG_R10 1 +#define PT_R13 2 +#define PT_R12 3 +#define PT_R11 4 +#define PT_R10 5 +#define PT_R9 6 +#define PT_R8 7 +#define PT_R7 8 +#define PT_R6 9 +#define PT_R5 10 +#define PT_R4 11 +#define PT_R3 12 +#define PT_R2 13 +#define PT_R1 14 +#define PT_R0 15 +#define PT_MOF 16 +#define PT_DCCR 17 +#define PT_SRP 18 +#define PT_IRP 19 /* This is actually the debugged process' PC */ +#define PT_CSRINSTR 20 /* CPU Status record remnants - + valid if frametype == busfault */ +#define PT_CSRADDR 21 +#define PT_CSRDATA 22 +#define PT_USP 23 /* special case - USP is not in the pt_regs */ +#define PT_MAX 23 + +/* Condition code bit numbers. The same numbers apply to CCR of course, + but we use DCCR everywhere else, so let's try and be consistent. */ +#define C_DCCR_BITNR 0 +#define V_DCCR_BITNR 1 +#define Z_DCCR_BITNR 2 +#define N_DCCR_BITNR 3 +#define X_DCCR_BITNR 4 +#define I_DCCR_BITNR 5 +#define B_DCCR_BITNR 6 +#define M_DCCR_BITNR 7 +#define U_DCCR_BITNR 8 +#define P_DCCR_BITNR 9 +#define F_DCCR_BITNR 10 + +/* pt_regs not only specifices the format in the user-struct during + * ptrace but is also the frame format used in the kernel prologue/epilogues + * themselves + */ + +struct pt_regs { + unsigned long frametype; /* type of stackframe */ + unsigned long orig_r10; + /* pushed by movem r13, [sp] in SAVE_ALL, movem pushes backwards */ + unsigned long r13; + unsigned long r12; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long r7; + unsigned long r6; + unsigned long r5; + unsigned long r4; + unsigned long r3; + unsigned long r2; + unsigned long r1; + unsigned long r0; + unsigned long mof; + unsigned long dccr; + unsigned long srp; + unsigned long irp; /* This is actually the debugged process' PC */ + unsigned long csrinstr; + unsigned long csraddr; + unsigned long csrdata; +}; + +/* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) + * when doing a context-switch. it is used (apart from in resume) when a new + * thread is made and we need to make _resume (which is starting it for the + * first time) realise what is going on. + * + * Actually, the use is very close to the thread struct (TSS) in that both the + * switch_stack and the TSS are used to keep thread stuff when switching in + * _resume. + */ + +struct switch_stack { + unsigned long r9; + unsigned long r8; + unsigned long r7; + unsigned long r6; + unsigned long r5; + unsigned long r4; + unsigned long r3; + unsigned long r2; + unsigned long r1; + unsigned long r0; + unsigned long return_ip; /* ip that _resume will return to */ +}; + +/* bit 8 is user-mode flag */ +#define user_mode(regs) (((regs)->dccr & 0x100) != 0) +#define instruction_pointer(regs) ((regs)->irp) +extern void show_regs(struct pt_regs *); + +#endif diff --git a/include/asm-cris/sv_addr.agh b/include/asm-cris/arch-v10/sv_addr.agh index ddaf91fa38cf..6ac3a7bc9760 100644 --- a/include/asm-cris/sv_addr.agh +++ b/include/asm-cris/arch-v10/sv_addr.agh @@ -691,10 +691,10 @@ #define R_GEN_CONFIG__g24dir__WIDTH 1 #define R_GEN_CONFIG__g24dir__in 0 #define R_GEN_CONFIG__g24dir__out 1 -#define R_GEN_CONFIG__g16_20dir__BITNR 26 -#define R_GEN_CONFIG__g16_20dir__WIDTH 1 -#define R_GEN_CONFIG__g16_20dir__in 0 -#define R_GEN_CONFIG__g16_20dir__out 1 +#define R_GEN_CONFIG__g16_23dir__BITNR 26 +#define R_GEN_CONFIG__g16_23dir__WIDTH 1 +#define R_GEN_CONFIG__g16_23dir__in 0 +#define R_GEN_CONFIG__g16_23dir__out 1 #define R_GEN_CONFIG__g8_15dir__BITNR 25 #define R_GEN_CONFIG__g8_15dir__WIDTH 1 #define R_GEN_CONFIG__g8_15dir__in 0 @@ -1142,7 +1142,7 @@ #define R_SERIAL0_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL0_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL0_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_CTRL__rec_stick_par__stick 1 #define R_SERIAL0_CTRL__rec_par__BITNR 18 #define R_SERIAL0_CTRL__rec_par__WIDTH 1 #define R_SERIAL0_CTRL__rec_par__even 0 @@ -1172,7 +1172,7 @@ #define R_SERIAL0_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL0_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL0_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_CTRL__tr_stick_par__stick 1 #define R_SERIAL0_CTRL__tr_par__BITNR 10 #define R_SERIAL0_CTRL__tr_par__WIDTH 1 #define R_SERIAL0_CTRL__tr_par__even 0 @@ -1246,7 +1246,7 @@ #define R_SERIAL0_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL0_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL0_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL0_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL0_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL0_REC_CTRL__rec_par__even 0 @@ -1278,7 +1278,7 @@ #define R_SERIAL0_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL0_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL0_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL0_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL0_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL0_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL0_TR_CTRL__tr_par__even 0 @@ -1434,7 +1434,7 @@ #define R_SERIAL1_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL1_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL1_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_CTRL__rec_stick_par__stick 1 #define R_SERIAL1_CTRL__rec_par__BITNR 18 #define R_SERIAL1_CTRL__rec_par__WIDTH 1 #define R_SERIAL1_CTRL__rec_par__even 0 @@ -1464,7 +1464,7 @@ #define R_SERIAL1_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL1_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL1_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_CTRL__tr_stick_par__stick 1 #define R_SERIAL1_CTRL__tr_par__BITNR 10 #define R_SERIAL1_CTRL__tr_par__WIDTH 1 #define R_SERIAL1_CTRL__tr_par__even 0 @@ -1538,7 +1538,7 @@ #define R_SERIAL1_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL1_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL1_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL1_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL1_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL1_REC_CTRL__rec_par__even 0 @@ -1570,7 +1570,7 @@ #define R_SERIAL1_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL1_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL1_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL1_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL1_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL1_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL1_TR_CTRL__tr_par__even 0 @@ -1726,7 +1726,7 @@ #define R_SERIAL2_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL2_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL2_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_CTRL__rec_stick_par__stick 1 #define R_SERIAL2_CTRL__rec_par__BITNR 18 #define R_SERIAL2_CTRL__rec_par__WIDTH 1 #define R_SERIAL2_CTRL__rec_par__even 0 @@ -1756,7 +1756,7 @@ #define R_SERIAL2_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL2_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL2_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_CTRL__tr_stick_par__stick 1 #define R_SERIAL2_CTRL__tr_par__BITNR 10 #define R_SERIAL2_CTRL__tr_par__WIDTH 1 #define R_SERIAL2_CTRL__tr_par__even 0 @@ -1830,7 +1830,7 @@ #define R_SERIAL2_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL2_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL2_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL2_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL2_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL2_REC_CTRL__rec_par__even 0 @@ -1862,7 +1862,7 @@ #define R_SERIAL2_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL2_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL2_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL2_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL2_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL2_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL2_TR_CTRL__tr_par__even 0 @@ -2018,7 +2018,7 @@ #define R_SERIAL3_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL3_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL3_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_CTRL__rec_stick_par__stick 1 #define R_SERIAL3_CTRL__rec_par__BITNR 18 #define R_SERIAL3_CTRL__rec_par__WIDTH 1 #define R_SERIAL3_CTRL__rec_par__even 0 @@ -2048,7 +2048,7 @@ #define R_SERIAL3_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL3_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL3_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_CTRL__tr_stick_par__stick 1 #define R_SERIAL3_CTRL__tr_par__BITNR 10 #define R_SERIAL3_CTRL__tr_par__WIDTH 1 #define R_SERIAL3_CTRL__tr_par__even 0 @@ -2122,7 +2122,7 @@ #define R_SERIAL3_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL3_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL3_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_REC_CTRL__rec_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_REC_CTRL__rec_stick_par__stick 1 #define R_SERIAL3_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL3_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL3_REC_CTRL__rec_par__even 0 @@ -2154,7 +2154,7 @@ #define R_SERIAL3_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL3_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL3_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_TR_CTRL__tr_stick_parlocal_irq_enableck 1 +#define R_SERIAL3_TR_CTRL__tr_stick_par__stick 1 #define R_SERIAL3_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL3_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL3_TR_CTRL__tr_par__even 0 diff --git a/include/asm-cris/sv_addr_ag.h b/include/asm-cris/arch-v10/sv_addr_ag.h index c80826bf9410..e4a6b68b8982 100644 --- a/include/asm-cris/sv_addr_ag.h +++ b/include/asm-cris/arch-v10/sv_addr_ag.h @@ -25,33 +25,41 @@ /* IO_MASK returns a mask for a specified bitfield in a register. Note that this macro doesn't work when field width is 32 bits. */ -#define IO_MASK(reg,field) \ - ( ( ( 1 << reg##__##field##__WIDTH ) - 1 ) << reg##__##field##__BITNR ) +#define IO_MASK(reg, field) IO_MASK_ (reg##_, field##_) +#define IO_MASK_(reg_, field_) \ + ( ( ( 1 << reg_##_##field_##_WIDTH ) - 1 ) << reg_##_##field_##_BITNR ) /* IO_STATE returns a constant corresponding to a one of the symbolic states that the bitfield can have. (Shifted to correct position) */ -#define IO_STATE(reg,field,state) \ - ( reg##__##field##__##state << reg##__##field##__BITNR ) +#define IO_STATE(reg, field, state) IO_STATE_ (reg##_, field##_, _##state) +#define IO_STATE_(reg_, field_, _state) \ + ( reg_##_##field_##_state << reg_##_##field_##_BITNR ) /* IO_EXTRACT returns the masked and shifted value corresponding to the bitfield can have. */ -#define IO_EXTRACT(reg,field,val) ( (( ( ( 1 << reg##__##field##__WIDTH ) \ - - 1 ) << reg##__##field##__BITNR ) & (val)) >> reg##__##field##__BITNR ) +#define IO_EXTRACT(reg, field, val) IO_EXTRACT_ (reg##_, field##_, val) +#define IO_EXTRACT_(reg_, field_, val) ( (( ( ( 1 << reg_##_##field_##_WIDTH ) \ + - 1 ) << reg_##_##field_##_BITNR ) & (val)) >> reg_##_##field_##_BITNR ) /* IO_STATE_VALUE returns a constant corresponding to a one of the symbolic states that the bitfield can have. (Not shifted) */ -#define IO_STATE_VALUE(reg,field,state) ( reg##__##field##__##state ) +#define IO_STATE_VALUE(reg, field, state) \ + IO_STATE_VALUE_ (reg##_, field##_, _##state) +#define IO_STATE_VALUE_(reg_, field_, _state) ( reg_##_##field_##_state ) /* IO_FIELD shifts the val parameter to be aligned with the bitfield specified. */ -#define IO_FIELD(reg,field,val) ((val) << reg##__##field##__BITNR) +#define IO_FIELD(reg, field, val) IO_FIELD_ (reg##_, field##_, val) +#define IO_FIELD_(reg_, field_, val) ((val) << reg_##_##field_##_BITNR) /* IO_BITNR returns the starting bitnumber of a bitfield. Bit 0 is LSB and the returned bitnumber is LSB of the field. */ -#define IO_BITNR(reg,field) (reg##__##field##__BITNR) +#define IO_BITNR(reg, field) IO_BITNR_ (reg##_, field##_) +#define IO_BITNR_(reg_, field_) (reg_##_##field_##_BITNR) /* IO_WIDTH returns the width, in bits, of a bitfield. */ -#define IO_WIDTH(reg,field) (reg##__##field##__WIDTH) +#define IO_WIDTH(reg, field) IO_WIDTH_ (reg##_, field##_) +#define IO_WIDTH_(reg_, field_) (reg_##_##field_##_WIDTH) /*--- Obsolete. Kept for backw compatibility. ---*/ /* Reads (or writes) a byte/uword/udword from the specified mode @@ -66,7 +74,9 @@ !*-----------------------------------------------------------*/ #define MEM_CSE0_START (0x00000000) +#define MEM_CSE0_SIZE (0x04000000) #define MEM_CSE1_START (0x04000000) +#define MEM_CSE1_SIZE (0x04000000) #define MEM_CSR0_START (0x08000000) #define MEM_CSR1_START (0x0c000000) #define MEM_CSP0_START (0x10000000) diff --git a/include/asm-cris/svinto.h b/include/asm-cris/arch-v10/svinto.h index c0a16650a20e..0881a1af7cee 100644 --- a/include/asm-cris/svinto.h +++ b/include/asm-cris/arch-v10/svinto.h @@ -58,4 +58,7 @@ typedef struct etrax_dma_descr { */ #define WAIT_DMA( n ) WAIT_DMA_NUM( n ) +extern void prepare_rx_descriptor(struct etrax_dma_descr *desc); +extern void flush_etrax_cache(void); + #endif diff --git a/include/asm-cris/arch-v10/system.h b/include/asm-cris/arch-v10/system.h new file mode 100644 index 000000000000..781ca30229a8 --- /dev/null +++ b/include/asm-cris/arch-v10/system.h @@ -0,0 +1,62 @@ +#ifndef __ASM_CRIS_ARCH_SYSTEM_H +#define __ASM_CRIS_ARCH_SYSTEM_H + +#include <linux/config.h> + +/* read the CPU version register */ + +extern inline unsigned long rdvr(void) { + unsigned char vr; + __asm__ volatile ("move $vr,%0" : "=rm" (vr)); + return vr; +} + +/* read/write the user-mode stackpointer */ + +extern inline unsigned long rdusp(void) { + unsigned long usp; + __asm__ __volatile__("move $usp,%0" : "=rm" (usp)); + return usp; +} + +#define wrusp(usp) \ + __asm__ __volatile__("move %0,$usp" : /* no outputs */ : "rm" (usp)) + +/* read the current stackpointer */ + +extern inline unsigned long rdsp(void) { + unsigned long sp; + __asm__ __volatile__("move.d $sp,%0" : "=rm" (sp)); + return sp; +} + +extern inline unsigned long _get_base(char * addr) +{ + return 0; +} + +#define nop() __asm__ __volatile__ ("nop"); + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) +#define tas(ptr) (xchg((ptr),1)) + +struct __xchg_dummy { unsigned long a[100]; }; +#define __xg(x) ((struct __xchg_dummy *)(x)) + +/* interrupt control.. */ +#define local_save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); +#define local_irq_restore(x) __asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory"); +#define local_irq_disable() __asm__ __volatile__ ( "di" : : :"memory"); +#define local_irq_enable() __asm__ __volatile__ ( "ei" : : :"memory"); + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + !(flags & (1<<5)); \ +}) + +/* For spinlocks etc */ +#define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); + +#endif diff --git a/include/asm-cris/arch-v10/thread_info.h b/include/asm-cris/arch-v10/thread_info.h new file mode 100644 index 000000000000..357f5df0c907 --- /dev/null +++ b/include/asm-cris/arch-v10/thread_info.h @@ -0,0 +1,12 @@ +#ifndef _ASM_ARCH_THREAD_INFO_H +#define _ASM_ARCH_THREAD_INFO_H + +/* how to get the thread information struct from C */ +extern inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; + __asm__("and.d $sp,%0; ":"=r" (ti) : "0" (~8191UL)); + return ti; +} + +#endif diff --git a/include/asm-cris/arch-v10/timex.h b/include/asm-cris/arch-v10/timex.h new file mode 100644 index 000000000000..ecfc553c06a5 --- /dev/null +++ b/include/asm-cris/arch-v10/timex.h @@ -0,0 +1,30 @@ +/* + * Use prescale timer at 25000 Hz instead of the baudrate timer at + * 19200 to get rid of the 64ppm to fast timer (and we get better + * resolution within a jiffie as well. + */ +#ifndef _ASM_CRIS_ARCH_TIMEX_H +#define _ASM_CRIS_ARCH_TIMEX_H + +/* The prescaler clock runs at 25MHz, we divide it by 1000 in the prescaler */ +/* If you change anything here you must check time.c as well... */ +#define PRESCALE_FREQ 25000000 +#define PRESCALE_VALUE 1000 +#define CLOCK_TICK_RATE 25000 /* Underlying frequency of the HZ timer */ +/* The timer0 values gives 40us resolution (1/25000) but interrupts at HZ*/ +#define TIMER0_FREQ (CLOCK_TICK_RATE) +#define TIMER0_CLKSEL flexible +#define TIMER0_DIV (TIMER0_FREQ/(HZ)) + + +#define GET_JIFFIES_USEC() \ + ( (TIMER0_DIV - *R_TIMER0_DATA) * (1000000/HZ)/TIMER0_DIV ) + +unsigned long get_ns_in_jiffie(void); + +extern inline unsigned long get_us_in_jiffie_highres(void) +{ + return get_ns_in_jiffie()/1000; +} + +#endif diff --git a/include/asm-cris/arch-v10/tlb.h b/include/asm-cris/arch-v10/tlb.h new file mode 100644 index 000000000000..31525bbe75c3 --- /dev/null +++ b/include/asm-cris/arch-v10/tlb.h @@ -0,0 +1,13 @@ +#ifndef _CRIS_ARCH_TLB_H +#define _CRIS_ARCH_TLB_H + +/* The TLB can host up to 64 different mm contexts at the same time. + * The last page_id is never running - it is used as an invalid page_id + * so we can make TLB entries that will never match. + */ +#define NUM_TLB_ENTRIES 64 +#define NUM_PAGEID 64 +#define INVALID_PAGEID 63 +#define NO_CONTEXT -1 + +#endif diff --git a/include/asm-cris/arch-v10/uaccess.h b/include/asm-cris/arch-v10/uaccess.h new file mode 100644 index 000000000000..787d2e60c83c --- /dev/null +++ b/include/asm-cris/arch-v10/uaccess.h @@ -0,0 +1,660 @@ +/* + * Authors: Bjorn Wesen (bjornw@axis.com) + * Hans-Peter Nilsson (hp@axis.com) + * + */ +#ifndef _CRIS_ARCH_UACCESS_H +#define _CRIS_ARCH_UACCESS_H + +/* + * We don't tell gcc that we are accessing memory, but this is OK + * because we do not write to any memory gcc knows about, so there + * are no aliasing issues. + * + * Note that PC at a fault is the address *after* the faulting + * instruction. + */ +#define __put_user_asm(x, addr, err, op) \ + __asm__ __volatile__( \ + " "op" %1,[%2]\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + "3: move.d %3,%0\n" \ + " jump 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .dword 2b,3b\n" \ + " .previous\n" \ + : "=r" (err) \ + : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) + +#define __put_user_asm_64(x, addr, err) \ + __asm__ __volatile__( \ + " move.d %M1,[%2]\n" \ + "2: move.d %H1,[%2+4]\n" \ + "4:\n" \ + " .section .fixup,\"ax\"\n" \ + "3: move.d %3,%0\n" \ + " jump 4b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .dword 2b,3b\n" \ + " .dword 4b,3b\n" \ + " .previous\n" \ + : "=r" (err) \ + : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) + +/* See comment before __put_user_asm. */ + +#define __get_user_asm(x, addr, err, op) \ + __asm__ __volatile__( \ + " "op" [%2],%1\n" \ + "2:\n" \ + " .section .fixup,\"ax\"\n" \ + "3: move.d %3,%0\n" \ + " moveq 0,%1\n" \ + " jump 2b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .dword 2b,3b\n" \ + " .previous\n" \ + : "=r" (err), "=r" (x) \ + : "r" (addr), "g" (-EFAULT), "0" (err)) + +#define __get_user_asm_64(x, addr, err) \ + __asm__ __volatile__( \ + " move.d [%2],%M1\n" \ + "2: move.d [%2+4],%H1\n" \ + "4:\n" \ + " .section .fixup,\"ax\"\n" \ + "3: move.d %3,%0\n" \ + " moveq 0,%1\n" \ + " jump 4b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + " .dword 2b,3b\n" \ + " .dword 4b,3b\n" \ + " .previous\n" \ + : "=r" (err), "=r" (x) \ + : "r" (addr), "g" (-EFAULT), "0" (err)) + +/* + * Copy a null terminated string from userspace. + * + * Must return: + * -EFAULT for an exception + * count if we hit the buffer limit + * bytes copied if we hit a null byte + * (without the null byte) + */ +extern inline long +__do_strncpy_from_user(char *dst, const char *src, long count) +{ + long res; + + if (count == 0) + return 0; + + /* + * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop. + * So do we. + * + * This code is deduced from: + * + * char tmp2; + * long tmp1, tmp3 + * tmp1 = count; + * while ((*dst++ = (tmp2 = *src++)) != 0 + * && --tmp1) + * ; + * + * res = count - tmp1; + * + * with tweaks. + */ + + __asm__ __volatile__ ( + " move.d %3,%0\n" + " move.b [%2+],$r9\n" + "1: beq 2f\n" + " move.b $r9,[%1+]\n" + + " subq 1,%0\n" + " bne 1b\n" + " move.b [%2+],$r9\n" + + "2: sub.d %3,%0\n" + " neg.d %0,%0\n" + "3:\n" + " .section .fixup,\"ax\"\n" + "4: move.d %7,%0\n" + " jump 3b\n" + + /* There's one address for a fault at the first move, and + two possible PC values for a fault at the second move, + being a delay-slot filler. However, the branch-target + for the second move is the same as the first address. + Just so you don't get confused... */ + " .previous\n" + " .section __ex_table,\"a\"\n" + " .dword 1b,4b\n" + " .dword 2b,4b\n" + " .previous" + : "=r" (res), "=r" (dst), "=r" (src), "=r" (count) + : "3" (count), "1" (dst), "2" (src), "g" (-EFAULT) + : "r9"); + + return res; +} + +/* A few copy asms to build up the more complex ones from. + + Note again, a post-increment is performed regardless of whether a bus + fault occurred in that instruction, and PC for a faulted insn is the + address *after* the insn. */ + +#define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm__ __volatile__ ( \ + COPY \ + "1:\n" \ + " .section .fixup,\"ax\"\n" \ + FIXUP \ + " jump 1b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + TENTRY \ + " .previous\n" \ + : "=r" (to), "=r" (from), "=r" (ret) \ + : "0" (to), "1" (from), "2" (ret) \ + : "r9", "memory") + +#define __asm_copy_from_user_1(to, from, ret) \ + __asm_copy_user_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "2: move.b $r9,[%0+]\n", \ + "3: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 2b,3b\n") + +#define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_user_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + "2: move.w $r9,[%0+]\n" COPY, \ + "3: addq 2,%2\n" \ + " clear.w [%0+]\n" FIXUP, \ + " .dword 2b,3b\n" TENTRY) + +#define __asm_copy_from_user_2(to, from, ret) \ + __asm_copy_from_user_2x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_3(to, from, ret) \ + __asm_copy_from_user_2x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "4: move.b $r9,[%0+]\n", \ + "5: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 4b,5b\n") + +#define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_user_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + "2: move.d $r9,[%0+]\n" COPY, \ + "3: addq 4,%2\n" \ + " clear.d [%0+]\n" FIXUP, \ + " .dword 2b,3b\n" TENTRY) + +#define __asm_copy_from_user_4(to, from, ret) \ + __asm_copy_from_user_4x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_5(to, from, ret) \ + __asm_copy_from_user_4x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "4: move.b $r9,[%0+]\n", \ + "5: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 4b,5b\n") + +#define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_4x_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + "4: move.w $r9,[%0+]\n" COPY, \ + "5: addq 2,%2\n" \ + " clear.w [%0+]\n" FIXUP, \ + " .dword 4b,5b\n" TENTRY) + +#define __asm_copy_from_user_6(to, from, ret) \ + __asm_copy_from_user_6x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_7(to, from, ret) \ + __asm_copy_from_user_6x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "6: move.b $r9,[%0+]\n", \ + "7: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 6b,7b\n") + +#define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_4x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + "4: move.d $r9,[%0+]\n" COPY, \ + "5: addq 4,%2\n" \ + " clear.d [%0+]\n" FIXUP, \ + " .dword 4b,5b\n" TENTRY) + +#define __asm_copy_from_user_8(to, from, ret) \ + __asm_copy_from_user_8x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_9(to, from, ret) \ + __asm_copy_from_user_8x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "6: move.b $r9,[%0+]\n", \ + "7: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 6b,7b\n") + +#define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_8x_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + "6: move.w $r9,[%0+]\n" COPY, \ + "7: addq 2,%2\n" \ + " clear.w [%0+]\n" FIXUP, \ + " .dword 6b,7b\n" TENTRY) + +#define __asm_copy_from_user_10(to, from, ret) \ + __asm_copy_from_user_10x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_11(to, from, ret) \ + __asm_copy_from_user_10x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "8: move.b $r9,[%0+]\n", \ + "9: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 8b,9b\n") + +#define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_8x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + "6: move.d $r9,[%0+]\n" COPY, \ + "7: addq 4,%2\n" \ + " clear.d [%0+]\n" FIXUP, \ + " .dword 6b,7b\n" TENTRY) + +#define __asm_copy_from_user_12(to, from, ret) \ + __asm_copy_from_user_12x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_13(to, from, ret) \ + __asm_copy_from_user_12x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "8: move.b $r9,[%0+]\n", \ + "9: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 8b,9b\n") + +#define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_12x_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + "8: move.w $r9,[%0+]\n" COPY, \ + "9: addq 2,%2\n" \ + " clear.w [%0+]\n" FIXUP, \ + " .dword 8b,9b\n" TENTRY) + +#define __asm_copy_from_user_14(to, from, ret) \ + __asm_copy_from_user_14x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_15(to, from, ret) \ + __asm_copy_from_user_14x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + "10: move.b $r9,[%0+]\n", \ + "11: addq 1,%2\n" \ + " clear.b [%0+]\n", \ + " .dword 10b,11b\n") + +#define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_12x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + "8: move.d $r9,[%0+]\n" COPY, \ + "9: addq 4,%2\n" \ + " clear.d [%0+]\n" FIXUP, \ + " .dword 8b,9b\n" TENTRY) + +#define __asm_copy_from_user_16(to, from, ret) \ + __asm_copy_from_user_16x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_16x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + "10: move.d $r9,[%0+]\n" COPY, \ + "11: addq 4,%2\n" \ + " clear.d [%0+]\n" FIXUP, \ + " .dword 10b,11b\n" TENTRY) + +#define __asm_copy_from_user_20(to, from, ret) \ + __asm_copy_from_user_20x_cont(to, from, ret, "", "", "") + +#define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_from_user_20x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + "12: move.d $r9,[%0+]\n" COPY, \ + "13: addq 4,%2\n" \ + " clear.d [%0+]\n" FIXUP, \ + " .dword 12b,13b\n" TENTRY) + +#define __asm_copy_from_user_24(to, from, ret) \ + __asm_copy_from_user_24x_cont(to, from, ret, "", "", "") + +/* And now, the to-user ones. */ + +#define __asm_copy_to_user_1(to, from, ret) \ + __asm_copy_user_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n2:\n", \ + "3: addq 1,%2\n", \ + " .dword 2b,3b\n") + +#define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_user_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + " move.w $r9,[%0+]\n2:\n" COPY, \ + "3: addq 2,%2\n" FIXUP, \ + " .dword 2b,3b\n" TENTRY) + +#define __asm_copy_to_user_2(to, from, ret) \ + __asm_copy_to_user_2x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_3(to, from, ret) \ + __asm_copy_to_user_2x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n4:\n", \ + "5: addq 1,%2\n", \ + " .dword 4b,5b\n") + +#define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_user_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + " move.d $r9,[%0+]\n2:\n" COPY, \ + "3: addq 4,%2\n" FIXUP, \ + " .dword 2b,3b\n" TENTRY) + +#define __asm_copy_to_user_4(to, from, ret) \ + __asm_copy_to_user_4x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_5(to, from, ret) \ + __asm_copy_to_user_4x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n4:\n", \ + "5: addq 1,%2\n", \ + " .dword 4b,5b\n") + +#define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_4x_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + " move.w $r9,[%0+]\n4:\n" COPY, \ + "5: addq 2,%2\n" FIXUP, \ + " .dword 4b,5b\n" TENTRY) + +#define __asm_copy_to_user_6(to, from, ret) \ + __asm_copy_to_user_6x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_7(to, from, ret) \ + __asm_copy_to_user_6x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n6:\n", \ + "7: addq 1,%2\n", \ + " .dword 6b,7b\n") + +#define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_4x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + " move.d $r9,[%0+]\n4:\n" COPY, \ + "5: addq 4,%2\n" FIXUP, \ + " .dword 4b,5b\n" TENTRY) + +#define __asm_copy_to_user_8(to, from, ret) \ + __asm_copy_to_user_8x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_9(to, from, ret) \ + __asm_copy_to_user_8x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n6:\n", \ + "7: addq 1,%2\n", \ + " .dword 6b,7b\n") + +#define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_8x_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + " move.w $r9,[%0+]\n6:\n" COPY, \ + "7: addq 2,%2\n" FIXUP, \ + " .dword 6b,7b\n" TENTRY) + +#define __asm_copy_to_user_10(to, from, ret) \ + __asm_copy_to_user_10x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_11(to, from, ret) \ + __asm_copy_to_user_10x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n8:\n", \ + "9: addq 1,%2\n", \ + " .dword 8b,9b\n") + +#define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_8x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + " move.d $r9,[%0+]\n6:\n" COPY, \ + "7: addq 4,%2\n" FIXUP, \ + " .dword 6b,7b\n" TENTRY) + +#define __asm_copy_to_user_12(to, from, ret) \ + __asm_copy_to_user_12x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_13(to, from, ret) \ + __asm_copy_to_user_12x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n8:\n", \ + "9: addq 1,%2\n", \ + " .dword 8b,9b\n") + +#define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_12x_cont(to, from, ret, \ + " move.w [%1+],$r9\n" \ + " move.w $r9,[%0+]\n8:\n" COPY, \ + "9: addq 2,%2\n" FIXUP, \ + " .dword 8b,9b\n" TENTRY) + +#define __asm_copy_to_user_14(to, from, ret) \ + __asm_copy_to_user_14x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_15(to, from, ret) \ + __asm_copy_to_user_14x_cont(to, from, ret, \ + " move.b [%1+],$r9\n" \ + " move.b $r9,[%0+]\n10:\n", \ + "11: addq 1,%2\n", \ + " .dword 10b,11b\n") + +#define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_12x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + " move.d $r9,[%0+]\n8:\n" COPY, \ + "9: addq 4,%2\n" FIXUP, \ + " .dword 8b,9b\n" TENTRY) + +#define __asm_copy_to_user_16(to, from, ret) \ + __asm_copy_to_user_16x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_16x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + " move.d $r9,[%0+]\n10:\n" COPY, \ + "11: addq 4,%2\n" FIXUP, \ + " .dword 10b,11b\n" TENTRY) + +#define __asm_copy_to_user_20(to, from, ret) \ + __asm_copy_to_user_20x_cont(to, from, ret, "", "", "") + +#define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ + __asm_copy_to_user_20x_cont(to, from, ret, \ + " move.d [%1+],$r9\n" \ + " move.d $r9,[%0+]\n12:\n" COPY, \ + "13: addq 4,%2\n" FIXUP, \ + " .dword 12b,13b\n" TENTRY) + +#define __asm_copy_to_user_24(to, from, ret) \ + __asm_copy_to_user_24x_cont(to, from, ret, "", "", "") + +/* Define a few clearing asms with exception handlers. */ + +/* This frame-asm is like the __asm_copy_user_cont one, but has one less + input. */ + +#define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \ + __asm__ __volatile__ ( \ + CLEAR \ + "1:\n" \ + " .section .fixup,\"ax\"\n" \ + FIXUP \ + " jump 1b\n" \ + " .previous\n" \ + " .section __ex_table,\"a\"\n" \ + TENTRY \ + " .previous" \ + : "=r" (to), "=r" (ret) \ + : "0" (to), "1" (ret) \ + : "memory") + +#define __asm_clear_1(to, ret) \ + __asm_clear(to, ret, \ + " clear.b [%0+]\n2:\n", \ + "3: addq 1,%1\n", \ + " .dword 2b,3b\n") + +#define __asm_clear_2(to, ret) \ + __asm_clear(to, ret, \ + " clear.w [%0+]\n2:\n", \ + "3: addq 2,%1\n", \ + " .dword 2b,3b\n") + +#define __asm_clear_3(to, ret) \ + __asm_clear(to, ret, \ + " clear.w [%0+]\n" \ + "2: clear.b [%0+]\n3:\n", \ + "4: addq 2,%1\n" \ + "5: addq 1,%1\n", \ + " .dword 2b,4b\n" \ + " .dword 3b,5b\n") + +#define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ + __asm_clear(to, ret, \ + " clear.d [%0+]\n2:\n" CLEAR, \ + "3: addq 4,%1\n" FIXUP, \ + " .dword 2b,3b\n" TENTRY) + +#define __asm_clear_4(to, ret) \ + __asm_clear_4x_cont(to, ret, "", "", "") + +#define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ + __asm_clear_4x_cont(to, ret, \ + " clear.d [%0+]\n4:\n" CLEAR, \ + "5: addq 4,%1\n" FIXUP, \ + " .dword 4b,5b\n" TENTRY) + +#define __asm_clear_8(to, ret) \ + __asm_clear_8x_cont(to, ret, "", "", "") + +#define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ + __asm_clear_8x_cont(to, ret, \ + " clear.d [%0+]\n6:\n" CLEAR, \ + "7: addq 4,%1\n" FIXUP, \ + " .dword 6b,7b\n" TENTRY) + +#define __asm_clear_12(to, ret) \ + __asm_clear_12x_cont(to, ret, "", "", "") + +#define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ + __asm_clear_12x_cont(to, ret, \ + " clear.d [%0+]\n8:\n" CLEAR, \ + "9: addq 4,%1\n" FIXUP, \ + " .dword 8b,9b\n" TENTRY) + +#define __asm_clear_16(to, ret) \ + __asm_clear_16x_cont(to, ret, "", "", "") + +#define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ + __asm_clear_16x_cont(to, ret, \ + " clear.d [%0+]\n10:\n" CLEAR, \ + "11: addq 4,%1\n" FIXUP, \ + " .dword 10b,11b\n" TENTRY) + +#define __asm_clear_20(to, ret) \ + __asm_clear_20x_cont(to, ret, "", "", "") + +#define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ + __asm_clear_20x_cont(to, ret, \ + " clear.d [%0+]\n12:\n" CLEAR, \ + "13: addq 4,%1\n" FIXUP, \ + " .dword 12b,13b\n" TENTRY) + +#define __asm_clear_24(to, ret) \ + __asm_clear_24x_cont(to, ret, "", "", "") + +/* + * Return the size of a string (including the ending 0) + * + * Return length of string in userspace including terminating 0 + * or 0 for error. Return a value greater than N if too long. + */ + +extern inline long +strnlen_user(const char *s, long n) +{ + long res, tmp1; + + if (!access_ok(VERIFY_READ, s, 0)) + return 0; + + /* + * This code is deduced from: + * + * tmp1 = n; + * while (tmp1-- > 0 && *s++) + * ; + * + * res = n - tmp1; + * + * (with tweaks). + */ + + __asm__ __volatile__ ( + " move.d %1,$r9\n" + "0:\n" + " ble 1f\n" + " subq 1,$r9\n" + + " test.b [%0+]\n" + " bne 0b\n" + " test.d $r9\n" + "1:\n" + " move.d %1,%0\n" + " sub.d $r9,%0\n" + "2:\n" + " .section .fixup,\"ax\"\n" + + "3: clear.d %0\n" + " jump 2b\n" + + /* There's one address for a fault at the first move, and + two possible PC values for a fault at the second move, + being a delay-slot filler. However, the branch-target + for the second move is the same as the first address. + Just so you don't get confused... */ + " .previous\n" + " .section __ex_table,\"a\"\n" + " .dword 0b,3b\n" + " .dword 1b,3b\n" + " .previous\n" + : "=r" (res), "=r" (tmp1) + : "0" (s), "1" (n) + : "r9"); + + return res; +} + +#endif diff --git a/include/asm-cris/arch-v10/unistd.h b/include/asm-cris/arch-v10/unistd.h new file mode 100644 index 000000000000..d1a38b9e6264 --- /dev/null +++ b/include/asm-cris/arch-v10/unistd.h @@ -0,0 +1,148 @@ +#ifndef _ASM_CRIS_ARCH_UNISTD_H_ +#define _ASM_CRIS_ARCH_UNISTD_H_ + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ +/* + * Don't remove the .ifnc tests; they are an insurance against + * any hard-to-spot gcc register allocation bugs. + */ +#define _syscall0(type,name) \ +type name(void) \ +{ \ + register long __a __asm__ ("r10"); \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1,$r10$r9\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3,$r10$r9$r11\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4,$r10$r9$r11$r12\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), "r" (__c)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "move %6,$mof\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d), "g" (arg5)); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ +{ \ + register long __a __asm__ ("r10") = (long) arg1; \ + register long __b __asm__ ("r11") = (long) arg2; \ + register long __c __asm__ ("r12") = (long) arg3; \ + register long __d __asm__ ("r13") = (long) arg4; \ + register long __n_ __asm__ ("r9") = (__NR_##name); \ + __asm__ __volatile__ (".ifnc %0%1%3%4%5,$r10$r9$r11$r12$r13\n\t" \ + ".err\n\t" \ + ".endif\n\t" \ + "move %6,$mof\n\tmove %7,$srp\n\t" \ + "break 13" \ + : "=r" (__a) \ + : "r" (__n_), "0" (__a), "r" (__b), \ + "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\ + : "srp"); \ + if (__a >= 0) \ + return (type) __a; \ + errno = -__a; \ + return (type) -1; \ +} + +#endif diff --git a/include/asm-cris/arch-v10/user.h b/include/asm-cris/arch-v10/user.h new file mode 100644 index 000000000000..9303ea77c915 --- /dev/null +++ b/include/asm-cris/arch-v10/user.h @@ -0,0 +1,46 @@ +#ifndef __ASM_CRIS_ARCH_USER_H +#define __ASM_CRIS_ARCH_USER_H + +/* User mode registers, used for core dumps. In order to keep ELF_NGREG + sensible we let all registers be 32 bits. The csr registers are included + for future use. */ +struct user_regs_struct { + unsigned long r0; /* General registers. */ + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long sp; /* Stack pointer. */ + unsigned long pc; /* Program counter. */ + unsigned long p0; /* Constant zero (only 8 bits). */ + unsigned long vr; /* Version register (only 8 bits). */ + unsigned long p2; /* Reserved. */ + unsigned long p3; /* Reserved. */ + unsigned long p4; /* Constant zero (only 16 bits). */ + unsigned long ccr; /* Condition code register (only 16 bits). */ + unsigned long p6; /* Reserved. */ + unsigned long mof; /* Multiply overflow register. */ + unsigned long p8; /* Constant zero. */ + unsigned long ibr; /* Not accessible. */ + unsigned long irp; /* Not accessible. */ + unsigned long srp; /* Subroutine return pointer. */ + unsigned long bar; /* Not accessible. */ + unsigned long dccr; /* Dword condition code register. */ + unsigned long brp; /* Not accessible. */ + unsigned long usp; /* User-mode stack pointer. Same as sp when + in user mode. */ + unsigned long csrinstr; /* Internal status registers. */ + unsigned long csraddr; + unsigned long csrdata; +}; + +#endif diff --git a/include/asm-cris/atomic.h b/include/asm-cris/atomic.h index f2f51505d6dc..19ae993cb561 100644 --- a/include/asm-cris/atomic.h +++ b/include/asm-cris/atomic.h @@ -27,115 +27,115 @@ typedef struct { int counter; } atomic_t; /* These should be written in asm but we do it in C for now. */ -static __inline__ void atomic_add(int i, volatile atomic_t *v) +extern __inline__ void atomic_add(int i, volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); v->counter += i; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ void atomic_sub(int i, volatile atomic_t *v) +extern __inline__ void atomic_sub(int i, volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); v->counter -= i; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ int atomic_add_return(int i, volatile atomic_t *v) +extern __inline__ int atomic_add_return(int i, volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter += i); - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_sub_return(int i, volatile atomic_t *v) +extern __inline__ int atomic_sub_return(int i, volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter -= i); - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v) +extern __inline__ int atomic_sub_and_test(int i, volatile atomic_t *v) { int retval; unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter -= i) == 0; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ void atomic_inc(volatile atomic_t *v) +extern __inline__ void atomic_inc(volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); (v->counter)++; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ void atomic_dec(volatile atomic_t *v) +extern __inline__ void atomic_dec(volatile atomic_t *v) { unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); (v->counter)--; - restore_flags(flags); + local_irq_restore(flags); } -static __inline__ int atomic_inc_return(volatile atomic_t *v) +extern __inline__ int atomic_inc_return(volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter)++; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_dec_return(volatile atomic_t *v) +extern __inline__ int atomic_dec_return(volatile atomic_t *v) { unsigned long flags; int retval; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (v->counter)--; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_dec_and_test(volatile atomic_t *v) +extern __inline__ int atomic_dec_and_test(volatile atomic_t *v) { int retval; unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = --(v->counter) == 0; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static __inline__ int atomic_inc_and_test(volatile atomic_t *v) +extern __inline__ int atomic_inc_and_test(volatile atomic_t *v) { int retval; unsigned long flags; - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = ++(v->counter) == 0; - restore_flags(flags); + local_irq_restore(flags); return retval; } diff --git a/include/asm-cris/axisflashmap.h b/include/asm-cris/axisflashmap.h index c54f65d4a4a7..600bb8715d89 100644 --- a/include/asm-cris/axisflashmap.h +++ b/include/asm-cris/axisflashmap.h @@ -9,25 +9,6 @@ * and it has nothing to do with the partition table. */ - -/* the partitiontable consists of some "jump over" code, a head and - * then the actual entries. - * tools/mkptable is used to generate the ptable. - */ - -/* The partition table starts with code to "jump over" it. The ba - instruction and delay-slot is modified elsewhere (for example the - mkptable script); don't change this to fill the delay-slot. */ -#define PARTITIONTABLE_CODE_START { \ - 0x0f, 0x05, /* nop 0 */\ - 0x25, 0xf0, /* di 2 */\ - 0xed, 0xff /* ba 4 */ } - -/* The actual offset depend on the number of entries */ -#define PARTITIONTABLE_CODE_END { \ - 0x00, 0x00, /* ba offset 6 */\ - 0x0f, 0x05 /* nop 8 */} - #define PARTITION_TABLE_OFFSET 10 #define PARTITION_TABLE_MAGIC 0xbeef /* Not a good magic */ diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h index 563cc9f6a998..10de1ccd1e01 100644 --- a/include/asm-cris/bitops.h +++ b/include/asm-cris/bitops.h @@ -1,9 +1,6 @@ /* asm/bitops.h for Linux/CRIS * * TODO: asm versions if speed is needed - * set_bit, clear_bit and change_bit wastes cycles being only - * macros into test_and_set_bit etc. - * kernel-doc things (**) for macros are disabled * * All bit operations return 0 if the bit was cleared before the * operation and != 0 if it was not. @@ -17,11 +14,8 @@ /* Currently this is unsuitable for consumption outside the kernel. */ #ifdef __KERNEL__ +#include <asm/arch/bitops.h> #include <asm/system.h> - -/* We use generic_ffs so get it; include guards resolve the possible - mutually inclusion. */ -#include <linux/bitops.h> #include <linux/compiler.h> /* @@ -63,7 +57,7 @@ struct __dummy { unsigned long a[100]; }; /* * change_bit - Toggle a bit in memory - * @nr: Bit to clear + * @nr: Bit to change * @addr: Address to start counting from * * change_bit() is atomic and may not be reordered. @@ -75,7 +69,7 @@ struct __dummy { unsigned long a[100]; }; /* * __change_bit - Toggle a bit in memory - * @nr: the bit to set + * @nr: the bit to change * @addr: the address to start counting from * * Unlike change_bit(), this function is non-atomic and may be reordered. @@ -94,7 +88,7 @@ struct __dummy { unsigned long a[100]; }; * It also implies a memory barrier. */ -static inline int test_and_set_bit(int nr, void *addr) +extern inline int test_and_set_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; @@ -102,15 +96,15 @@ static inline int test_and_set_bit(int nr, void *addr) adr += nr >> 5; mask = 1 << (nr & 0x1f); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (mask & *adr) != 0; *adr |= mask; - restore_flags(flags); + local_irq_restore(flags); return retval; } -static inline int __test_and_set_bit(int nr, void *addr) +extern inline int __test_and_set_bit(int nr, void *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -130,14 +124,14 @@ static inline int __test_and_set_bit(int nr, void *addr) /** * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to set + * @nr: Bit to clear * @addr: Address to count from * * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int test_and_clear_bit(int nr, void *addr) +extern inline int test_and_clear_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; @@ -145,17 +139,17 @@ static inline int test_and_clear_bit(int nr, void *addr) adr += nr >> 5; mask = 1 << (nr & 0x1f); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (mask & *adr) != 0; *adr &= ~mask; - restore_flags(flags); + local_irq_restore(flags); return retval; } /** * __test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to set + * @nr: Bit to clear * @addr: Address to count from * * This operation is non-atomic and can be reordered. @@ -163,7 +157,7 @@ static inline int test_and_clear_bit(int nr, void *addr) * but actually fail. You must protect multiple accesses with a lock. */ -static inline int __test_and_clear_bit(int nr, void *addr) +extern inline int __test_and_clear_bit(int nr, void *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -176,31 +170,31 @@ static inline int __test_and_clear_bit(int nr, void *addr) } /** * test_and_change_bit - Change a bit and return its new value - * @nr: Bit to set + * @nr: Bit to change * @addr: Address to count from * * This operation is atomic and cannot be reordered. * It also implies a memory barrier. */ -static inline int test_and_change_bit(int nr, void *addr) +extern inline int test_and_change_bit(int nr, void *addr) { unsigned int mask, retval; unsigned long flags; unsigned int *adr = (unsigned int *)addr; adr += nr >> 5; mask = 1 << (nr & 0x1f); - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); retval = (mask & *adr) != 0; *adr ^= mask; - restore_flags(flags); + local_irq_restore(flags); return retval; } /* WARNING: non atomic and it can be reordered! */ -static inline int __test_and_change_bit(int nr, void *addr) +extern inline int __test_and_change_bit(int nr, void *addr) { unsigned int mask, retval; unsigned int *adr = (unsigned int *)addr; @@ -221,7 +215,7 @@ static inline int __test_and_change_bit(int nr, void *addr) * This routine doesn't need to be atomic. */ -static inline int test_bit(int nr, const void *addr) +extern inline int test_bit(int nr, const void *addr) { unsigned int mask; unsigned int *adr = (unsigned int *)addr; @@ -236,63 +230,28 @@ static inline int test_bit(int nr, const void *addr) */ /* - * Helper functions for the core of the ff[sz] functions, wrapping the - * syntactically awkward asms. The asms compute the number of leading - * zeroes of a bits-in-byte and byte-in-word and word-in-dword-swapped - * number. They differ in that the first function also inverts all bits - * in the input. + * Since we define it "external", it collides with the built-in + * definition, which doesn't have the same semantics. We don't want to + * use -fno-builtin, so just hide the name ffs. */ -static inline unsigned long cris_swapnwbrlz(unsigned long w) -{ - /* Let's just say we return the result in the same register as the - input. Saying we clobber the input but can return the result - in another register: - ! __asm__ ("swapnwbr %2\n\tlz %2,%0" - ! : "=r,r" (res), "=r,X" (dummy) : "1,0" (w)); - confuses gcc (sched.c, gcc from cris-dist-1.14). */ - - unsigned long res; - __asm__ ("swapnwbr %0 \n\t" - "lz %0,%0" - : "=r" (res) : "0" (w)); - return res; -} - -static inline unsigned long cris_swapwbrlz(unsigned long w) -{ - unsigned res; - __asm__ ("swapwbr %0 \n\t" - "lz %0,%0" - : "=r" (res) - : "0" (w)); - return res; -} +#define ffs kernel_ffs /* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. + * fls: find last bit set. */ -static inline unsigned long ffz(unsigned long w) -{ - /* The generic_ffs function is used to avoid the asm when the - argument is a constant. */ - return __builtin_constant_p (w) - ? (~w ? (unsigned long) generic_ffs ((int) ~w) - 1 : 32) - : cris_swapnwbrlz (w); -} + +#define fls(x) generic_fls(x) /* - * Somewhat like ffz but the equivalent of generic_ffs: in contrast to - * ffz we return the first one-bit *plus one*. + * hweightN - returns the hamming weight of a N-bit word + * @x: the word to weigh + * + * The Hamming Weight of a number is the total number of bits set in it. */ -static inline unsigned long ffs(unsigned long w) -{ - /* The generic_ffs function is used to avoid the asm when the - argument is a constant. */ - return __builtin_constant_p (w) - ? (unsigned long) generic_ffs ((int) w) - : w ? cris_swapwbrlz (w) + 1 : 0; -} + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) /** * find_next_zero_bit - find the first zero bit in a memory region @@ -300,7 +259,7 @@ static inline unsigned long ffs(unsigned long w) * @offset: The bitnumber to start searching at * @size: The maximum size to search */ -static inline int find_next_zero_bit (void * addr, int size, int offset) +extern inline int find_next_zero_bit (void * addr, int size, int offset) { unsigned long *p = ((unsigned long *) addr) + (offset >> 5); unsigned long result = offset & ~31UL; @@ -348,17 +307,6 @@ static inline int find_next_zero_bit (void * addr, int size, int offset) #define find_first_zero_bit(addr, size) \ find_next_zero_bit((addr), (size), 0) -/* - * hweightN - returns the hamming weight of a N-bit word - * @x: the word to weigh - * - * The Hamming Weight of a number is the total number of bits set in it. - */ - -#define hweight32(x) generic_hweight32(x) -#define hweight16(x) generic_hweight16(x) -#define hweight8(x) generic_hweight8(x) - #define ext2_set_bit test_and_set_bit #define ext2_set_bit_atomic(l,n,a) test_and_set_bit(n,a) #define ext2_clear_bit test_and_clear_bit @@ -373,44 +321,20 @@ static inline int find_next_zero_bit (void * addr, int size, int offset) #define minix_test_bit(nr,addr) test_bit(nr,addr) #define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size) -#if 0 -/* TODO: see below */ -#define sched_find_first_zero_bit(addr) find_first_zero_bit(addr, 168) - -#else -/* TODO: left out pending where to put it.. (there are .h dependencies) */ - - /* - * Every architecture must define this function. It's the fastest - * way of searching a 168-bit bitmap where the first 128 bits are - * unlikely to be set. It's guaranteed that at least one of the 168 - * bits is cleared. - */ -#if 0 -#if MAX_RT_PRIO != 128 || MAX_PRIO != 168 -# error update this function. -#endif -#else -#define MAX_RT_PRIO 128 -#define MAX_PRIO 168 -#endif - -static inline int sched_find_first_zero_bit(char *bitmap) +extern inline int sched_find_first_bit(unsigned long *b) { - unsigned int *b = (unsigned int *)bitmap; - unsigned int rt; - - rt = b[0] & b[1] & b[2] & b[3]; - if (unlikely(rt != 0xffffffff)) - return find_first_zero_bit(bitmap, MAX_RT_PRIO); - - if (b[4] != ~0) - return ffz(b[4]) + MAX_RT_PRIO; - return ffz(b[5]) + 32 + MAX_RT_PRIO; + if (unlikely(b[0])) + return __ffs(b[0]); + if (unlikely(b[1])) + return __ffs(b[1]) + 32; + if (unlikely(b[2])) + return __ffs(b[2]) + 64; + if (unlikely(b[3])) + return __ffs(b[3]) + 96; + if (b[4]) + return __ffs(b[4]) + 128; + return __ffs(b[5]) + 32 + 128; } -#undef MAX_PRIO -#undef MAX_RT_PRIO -#endif #endif /* __KERNEL__ */ diff --git a/include/asm-cris/byteorder.h b/include/asm-cris/byteorder.h index 64275f6045ef..a1a222adaa9f 100644 --- a/include/asm-cris/byteorder.h +++ b/include/asm-cris/byteorder.h @@ -1,30 +1,9 @@ -/* $Id: byteorder.h,v 1.1 2000/07/10 16:32:31 bjornw Exp $ */ - #ifndef _CRIS_BYTEORDER_H #define _CRIS_BYTEORDER_H -#include <asm/types.h> - #ifdef __GNUC__ -/* we just define these two (as we can do the swap in a single - * asm instruction in CRIS) and the arch-independent files will put - * them together into ntohl etc. - */ - -static __inline__ __const__ __u32 ___arch__swab32(__u32 x) -{ - __asm__ ("swapwb %0" : "=r" (x) : "0" (x)); - - return(x); -} - -static __inline__ __const__ __u16 ___arch__swab16(__u16 x) -{ - __asm__ ("swapb %0" : "=r" (x) : "0" (x)); - - return(x); -} +#include <asm/arch/byteorder.h> /* defines are necessary because the other files detect the presence * of a defined __arch_swab32, not an inline diff --git a/include/asm-cris/cache.h b/include/asm-cris/cache.h index 1899bd77461d..46a3b26e205a 100644 --- a/include/asm-cris/cache.h +++ b/include/asm-cris/cache.h @@ -1,12 +1,6 @@ #ifndef _ASM_CACHE_H #define _ASM_CACHE_H -/* Etrax 100LX have 32-byte cache-lines. When we add support for future chips - * here should be a check for CPU type. - */ - -#define L1_CACHE_BYTES 32 - -#define L1_CACHE_SHIFT_MAX 5 /* largest L1 which this arch supports */ +#include <asm/arch/cache.h> #endif /* _ASM_CACHE_H */ diff --git a/include/asm-cris/cacheflush.h b/include/asm-cris/cacheflush.h new file mode 100644 index 000000000000..6be38857a0ae --- /dev/null +++ b/include/asm-cris/cacheflush.h @@ -0,0 +1,23 @@ +#ifndef _CRIS_CACHEFLUSH_H +#define _CRIS_CACHEFLUSH_H + +/* Keep includes the same across arches. */ +#include <linux/mm.h> + +/* The cache doesn't need to be flushed when TLB entries change because + * the cache is mapped to physical memory, not virtual memory + */ +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_range(vma, start, end) do { } while (0) +#define flush_cache_page(vma, vmaddr) do { } while (0) +#define flush_page_to_ram(page) do { } while (0) +#define flush_dcache_page(page) do { } while (0) +#define flush_icache_range(start, end) do { } while (0) +#define flush_icache_page(vma,pg) do { } while (0) +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) + +void global_flush_tlb(void); +int change_page_attr(struct page *page, int numpages, pgprot_t prot); + +#endif /* _CRIS_CACHEFLUSH_H */ diff --git a/include/asm-cris/checksum.h b/include/asm-cris/checksum.h index 589eb323eba3..15ca8aec5c63 100644 --- a/include/asm-cris/checksum.h +++ b/include/asm-cris/checksum.h @@ -3,6 +3,8 @@ #ifndef _CRIS_CHECKSUM_H #define _CRIS_CHECKSUM_H +#include <asm/arch/checksum.h> + /* * computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) @@ -32,7 +34,7 @@ unsigned int csum_partial_copy_nocheck(const char *src, char *dst, * Fold a partial checksum into a word */ -static inline unsigned int csum_fold(unsigned int sum) +extern inline unsigned int csum_fold(unsigned int sum) { /* the while loop is unnecessary really, it's always enough with two iterations */ @@ -43,31 +45,6 @@ static inline unsigned int csum_fold(unsigned int sum) return ~sum; } -/* Checksum some values used in TCP/UDP headers. - * - * The gain by doing this in asm is that C will not generate carry-additions - * for the 32-bit components of the checksum, so otherwise we would have had - * to split all of those into 16-bit components, then add. - */ - -static inline unsigned int -csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, - unsigned short proto, unsigned int sum) -{ - int res; - __asm__ ("add.d %2, %0\n\t" - "ax\n\t" - "add.d %3, %0\n\t" - "ax\n\t" - "add.d %4, %0\n\t" - "ax\n\t" - "addq 0, %0\n" - : "=r" (res) - : "0" (sum), "r" (daddr), "r" (saddr), "r" ((ntohs(len) << 16) + (proto << 8))); - - return res; -} - extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, int len, unsigned int sum, int *errptr); @@ -78,7 +55,7 @@ extern unsigned int csum_partial_copy_from_user(const char *src, char *dst, * */ -static inline unsigned short ip_fast_csum(unsigned char * iph, +extern inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) { return csum_fold(csum_partial(iph, ihl * 4, 0)); @@ -89,7 +66,7 @@ static inline unsigned short ip_fast_csum(unsigned char * iph, * returns a 16-bit checksum, already complemented */ -static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, +extern inline unsigned short int csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, unsigned short proto, @@ -103,7 +80,7 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, * in icmp.c */ -static inline unsigned short ip_compute_csum(unsigned char * buff, int len) { +extern inline unsigned short ip_compute_csum(unsigned char * buff, int len) { return csum_fold (csum_partial(buff, len, 0)); } diff --git a/include/asm-cris/current.h b/include/asm-cris/current.h index c5cc44d537d6..dce69c99da39 100644 --- a/include/asm-cris/current.h +++ b/include/asm-cris/current.h @@ -1,14 +1,14 @@ #ifndef _CRIS_CURRENT_H #define _CRIS_CURRENT_H +#include <linux/thread_info.h> + struct task_struct; -static inline struct task_struct * get_current(void) +extern inline struct task_struct * get_current(void) { - struct task_struct *current; - __asm__("and.d $sp,%0; ":"=r" (current) : "0" (~8191UL)); - return current; - } + return current_thread_info()->task; +} #define current get_current() diff --git a/include/asm-cris/delay.h b/include/asm-cris/delay.h index 632c369c41b9..efc41aad4845 100644 --- a/include/asm-cris/delay.h +++ b/include/asm-cris/delay.h @@ -2,33 +2,12 @@ #define _CRIS_DELAY_H /* - * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB + * Copyright (C) 1998-2002 Axis Communications AB * * Delay routines, using a pre-computed "loops_per_second" value. */ -#include <linux/config.h> -#include <linux/linkage.h> - -#ifdef CONFIG_SMP -#include <asm/smp.h> -#endif - -extern void __do_delay(void); /* Special register call calling convention */ - -extern __inline__ void __delay(int loops) -{ - __asm__ __volatile__ ( - "move.d %0,$r9\n\t" - "beq 2f\n\t" - "subq 1,$r9\n\t" - "1:\n\t" - "bne 1b\n\t" - "subq 1,$r9\n" - "2:" - : : "g" (loops) : "r9"); -} - +#include <asm/arch/delay.h> /* Use only for very small delays ( < 1 msec). */ diff --git a/include/asm-cris/dma.h b/include/asm-cris/dma.h index fde1cbf1a803..c229fac35cdc 100644 --- a/include/asm-cris/dma.h +++ b/include/asm-cris/dma.h @@ -1,59 +1,13 @@ -/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $ - * linux/include/asm/dma.h: Defines for using and allocating dma channels. - */ +/* $Id: dma.h,v 1.2 2001/05/09 12:17:42 johana Exp $ */ #ifndef _ASM_DMA_H #define _ASM_DMA_H +#include <asm/arch/dma.h> + /* it's useless on the Etrax, but unfortunately needed by the new bootmem allocator (but this should do it for this) */ #define MAX_DMA_ADDRESS PAGE_OFFSET -/* TODO: check nbr of channels on Etrax-100LX */ - -#define MAX_DMA_CHANNELS 10 - -/* dma0 and dma1 used for network (ethernet) */ -#define NETWORK_TX_DMA_NBR 0 -#define NETWORK_RX_DMA_NBR 1 - -/* dma2 and dma3 shared by par0, scsi0, ser2 and ata */ -#define PAR0_TX_DMA_NBR 2 -#define PAR0_RX_DMA_NBR 3 -#define SCSI0_TX_DMA_NBR 2 -#define SCSI0_RX_DMA_NBR 3 -#define SER2_TX_DMA_NBR 2 -#define SER2_RX_DMA_NBR 3 -#define ATA_TX_DMA_NBR 2 -#define ATA_RX_DMA_NBR 3 - -/* dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ -#define PAR1_TX_DMA_NBR 4 -#define PAR1_RX_DMA_NBR 5 -#define SCSI1_TX_DMA_NBR 4 -#define SCSI1_RX_DMA_NBR 5 -#define SER3_TX_DMA_NBR 4 -#define SER3_RX_DMA_NBR 5 -#define EXTDMA0_TX_DMA_NBR 4 -#define EXTDMA0_RX_DMA_NBR 5 - -/* dma6 and dma7 shared by ser0, extdma1 and mem2mem */ -#define SER0_TX_DMA_NBR 6 -#define SER0_RX_DMA_NBR 7 -#define EXTDMA1_TX_DMA_NBR 6 -#define EXTDMA1_RX_DMA_NBR 7 -#define MEM2MEM_TX_DMA_NBR 6 -#define MEM2MEM_RX_DMA_NBR 7 - -/* dma8 and dma9 shared by ser1 and usb */ -#define SER1_TX_DMA_NBR 8 -#define SER1_RX_DMA_NBR 9 -#define USB_TX_DMA_NBR 8 -#define USB_RX_DMA_NBR 9 - -/* These are in kernel/dma.c: */ -extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */ -extern void free_dma(unsigned int dmanr); /* release it */ - #endif /* _ASM_DMA_H */ diff --git a/include/asm-cris/elf.h b/include/asm-cris/elf.h index 798aeaeaabd1..d37fd5c4a567 100644 --- a/include/asm-cris/elf.h +++ b/include/asm-cris/elf.h @@ -5,7 +5,8 @@ * ELF register definitions.. */ -#include <asm/ptrace.h> +#include <asm/arch/elf.h> +#include <asm/user.h> typedef unsigned long elf_greg_t; @@ -29,69 +30,8 @@ typedef unsigned long elf_fpregset_t; #define ELF_DATA ELFDATA2LSB; #define ELF_ARCH EM_CRIS - /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program - starts (a register; assume first param register for CRIS) - contains a pointer to a function which might be - registered using `atexit'. This provides a mean for the - dynamic linker to call DT_FINI functions for shared libraries - that have been loaded before the code runs. - - A value of 0 tells we have no such handler. */ - - /* Explicitly set registers to 0 to increase determinism. */ -#define ELF_PLAT_INIT(_r, load_addr) do { \ - (_r)->r13 = 0; (_r)->r12 = 0; (_r)->r11 = 0; (_r)->r10 = 0; \ - (_r)->r9 = 0; (_r)->r8 = 0; (_r)->r7 = 0; (_r)->r6 = 0; \ - (_r)->r5 = 0; (_r)->r4 = 0; (_r)->r3 = 0; (_r)->r2 = 0; \ - (_r)->r1 = 0; (_r)->r0 = 0; (_r)->mof = 0; (_r)->srp = 0; \ -} while (0) - #define USE_ELF_CORE_DUMP -/* The additional layer below is because the stack pointer is missing in - the pt_regs struct, but needed in a core dump. pr_reg is a elf_gregset_t, - and should be filled in according to the layout of the user_regs_struct - struct; regs is a pt_regs struct. We dump all registers, though several are - obviously unnecessary. That way there's less need for intelligence at - the receiving end (i.e. gdb). */ -#define ELF_CORE_COPY_REGS(pr_reg, regs) \ - pr_reg[0] = regs->r0; \ - pr_reg[1] = regs->r1; \ - pr_reg[2] = regs->r2; \ - pr_reg[3] = regs->r3; \ - pr_reg[4] = regs->r4; \ - pr_reg[5] = regs->r5; \ - pr_reg[6] = regs->r6; \ - pr_reg[7] = regs->r7; \ - pr_reg[8] = regs->r8; \ - pr_reg[9] = regs->r9; \ - pr_reg[10] = regs->r10; \ - pr_reg[11] = regs->r11; \ - pr_reg[12] = regs->r12; \ - pr_reg[13] = regs->r13; \ - pr_reg[14] = rdusp(); /* sp */ \ - pr_reg[15] = regs->irp; /* pc */ \ - pr_reg[16] = 0; /* p0 */ \ - pr_reg[17] = rdvr(); /* vr */ \ - pr_reg[18] = 0; /* p2 */ \ - pr_reg[19] = 0; /* p3 */ \ - pr_reg[20] = 0; /* p4 */ \ - pr_reg[21] = (regs->dccr & 0xffff); /* ccr */ \ - pr_reg[22] = 0; /* p6 */ \ - pr_reg[23] = regs->mof; /* mof */ \ - pr_reg[24] = 0; /* p8 */ \ - pr_reg[25] = 0; /* ibr */ \ - pr_reg[26] = 0; /* irp */ \ - pr_reg[27] = regs->srp; /* srp */ \ - pr_reg[28] = 0; /* bar */ \ - pr_reg[29] = regs->dccr; /* dccr */ \ - pr_reg[30] = 0; /* brp */ \ - pr_reg[31] = rdusp(); /* usp */ \ - pr_reg[32] = 0; /* csrinstr */ \ - pr_reg[33] = 0; /* csraddr */ \ - pr_reg[34] = 0; /* csrdata */ - - #define ELF_EXEC_PAGESIZE 8192 /* This is the location that an ET_DYN program is loaded if exec'ed. Typical diff --git a/include/asm-cris/etraxgpio.h b/include/asm-cris/etraxgpio.h index 0395953e883e..cf04af9635cc 100644 --- a/include/asm-cris/etraxgpio.h +++ b/include/asm-cris/etraxgpio.h @@ -1,13 +1,54 @@ +/* $Id: etraxgpio.h,v 1.8 2002/06/17 15:53:07 johana Exp $ */ +/* + * The following devices are accessable using this driver using + * GPIO_MAJOR (120) and a couple of minor numbers: + * For ETRAX 100LX (ARCH_V10): + * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction + * /dev/gpiob minor 1, 8 bit GPIO, each bit can change direction + * /dev/leds minor 2, Access to leds depending on kernelconfig + * /dev/gpiog minor 3 + g0dir, g8_15dir, g16_23dir, g24 dir configurable in R_GEN_CONFIG + g1-g7 and g25-g31 is both input and outputs but on different pins + Also note that some bits change pins depending on what interfaces + are enabled. + * + * + * For ETRAX 200 (ARCH_V32): + * /dev/gpioa minor 0, 8 bit GPIO, each bit can change direction + * /dev/gpiob minor 1, 18 bit GPIO, each bit can change direction + * /dev/gpioc minor 2, 18 bit GPIO, each bit can change direction + * /dev/gpiod minor 3, 18 bit GPIO, each bit can change direction + * /dev/gpioe minor 4, 18 bit GPIO, each bit can change direction + * /dev/leds minor 5, Access to leds depending on kernelconfig + * + */ #ifndef _ASM_ETRAXGPIO_H #define _ASM_ETRAXGPIO_H +#include <linux/config.h> /* etraxgpio _IOC_TYPE, bits 8 to 15 in ioctl cmd */ - +#ifdef CONFIG_ETRAX_ARCH_V10 +#define ETRAXGPIO_IOCTYPE 43 +#define GPIO_MINOR_A 0 +#define GPIO_MINOR_B 1 +#define GPIO_MINOR_LEDS 2 +#define GPIO_MINOR_G 3 +#define GPIO_MINOR_LAST 3 +#endif +#ifdef CONFIG_ETRAX_ARCH_V32 #define ETRAXGPIO_IOCTYPE 43 +#define GPIO_MINOR_A 0 +#define GPIO_MINOR_B 1 +#define GPIO_MINOR_C 2 +#define GPIO_MINOR_D 3 +#define GPIO_MINOR_E 4 +#define GPIO_MINOR_LEDS 5 +#define GPIO_MINOR_LAST 5 +#endif /* supported ioctl _IOC_NR's */ -#define IO_READBITS 0x1 /* read and return current port bits */ +#define IO_READBITS 0x1 /* read and return current port bits (obsolete) */ #define IO_SETBITS 0x2 /* set the bits marked by 1 in the argument */ #define IO_CLRBITS 0x3 /* clear the bits marked by 1 in the argument */ @@ -22,11 +63,11 @@ * 0=off, 1=green, 2=red, 3=yellow */ /* GPIO direction ioctl's */ -#define IO_READDIR 0x8 /* Read direction 0=input 1=output */ -#define IO_SETINPUT 0x9 /* Set direction 0=unchanged 1=input, - returns current dir */ -#define IO_SETOUTPUT 0xA /* Set direction 0=unchanged 1=output, - returns current dir */ +#define IO_READDIR 0x8 /* Read direction 0=input 1=output (obsolete) */ +#define IO_SETINPUT 0x9 /* Set direction for bits set, 0=unchanged 1=input, + returns mask with current inputs (obsolete) */ +#define IO_SETOUTPUT 0xA /* Set direction for bits set, 0=unchanged 1=output, + returns mask with current outputs (obsolete)*/ /* LED ioctl extended */ #define IO_LED_SETBIT 0xB @@ -45,5 +86,19 @@ #define IO_CFG_WRITE_MODE_VALUE(msb, data_mask, clk_mask) \ ( (((msb)&1) << 16) | (((data_mask) &0xFF) << 8) | ((clk_mask) & 0xFF) ) +/* The following 4 ioctl's take a pointer as argument and handles + * 32 bit ports (port G) properly. + * These replaces IO_READBITS,IO_SETINPUT AND IO_SETOUTPUT + */ +#define IO_READ_INBITS 0x10 /* *arg is result of reading the input pins */ +#define IO_READ_OUTBITS 0x11 /* *arg is result of reading the output shadow */ +#define IO_SETGET_INPUT 0x12 /* bits set in *arg is set to input, + * *arg updated with current input pins. + */ +#define IO_SETGET_OUTPUT 0x13 /* bits set in *arg is set to output, + * *arg updated with current output pins. + */ + + #endif diff --git a/include/asm-cris/fasttimer.h b/include/asm-cris/fasttimer.h new file mode 100644 index 000000000000..10a770647870 --- /dev/null +++ b/include/asm-cris/fasttimer.h @@ -0,0 +1,42 @@ +/* $Id: fasttimer.h,v 1.2 2002/12/11 13:03:43 starvik Exp $ + * linux/include/asm-cris/fasttimer.h + * + * Fast timers for ETRAX100LX + * This may be useful in other OS than Linux so use 2 space indentation... + * Copyright (C) 2000, 2002 Axis Communications AB + */ +#include <linux/config.h> +#include <linux/time.h> /* struct timeval */ +#include <linux/timex.h> + +#ifdef CONFIG_ETRAX_FAST_TIMER + +typedef void fast_timer_function_type(unsigned long); + +struct fast_timer{ /* Close to timer_list */ + struct fast_timer *next; + struct fast_timer *prev; + struct timeval tv_set; + struct timeval tv_expires; + unsigned long delay_us; + fast_timer_function_type *function; + unsigned long data; + const char *name; +}; + +void start_one_shot_timer(struct fast_timer *t, + fast_timer_function_type *function, + unsigned long data, + unsigned long delay_us, + const char *name); + +int del_fast_timer(struct fast_timer * t); +/* return 1 if deleted */ + + +void schedule_usleep(unsigned long us); + + +void fast_timer_init(void); + +#endif diff --git a/include/asm-cris/hardirq.h b/include/asm-cris/hardirq.h index 4a13a2445d5b..c75100f8359b 100644 --- a/include/asm-cris/hardirq.h +++ b/include/asm-cris/hardirq.h @@ -4,6 +4,7 @@ /* only non-SMP supported */ #include <linux/threads.h> +#include <linux/cache.h> /* entry.S is sensitive to the offsets of these fields */ typedef struct { @@ -17,19 +18,80 @@ typedef struct { #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ /* - * Are we in an interrupt context? Either doing bottom half - * or hardware interrupt processing? + * We put the hardirq and softirq counter into the preemption + * counter. The bitmask has the following meaning: + * + * - bits 0-7 are the preemption count (max preemption depth: 256) + * - bits 8-15 are the softirq count (max # of softirqs: 256) + * - bits 16-23 are the hardirq count (max # of hardirqs: 256) + * + * - ( bit 26 is the PREEMPT_ACTIVE flag. ) + * + * PREEMPT_MASK: 0x000000ff + * SOFTIRQ_MASK: 0x0000ff00 + * HARDIRQ_MASK: 0x00ff0000 */ -#define in_interrupt() ((local_irq_count(smp_processor_id()) + \ - local_bh_count(smp_processor_id())) != 0) -#define in_irq() (local_irq_count(smp_processor_id()) != 0) -#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) -#define hardirq_endlock(cpu) do { (void)(cpu); } while (0) +#define PREEMPT_BITS 8 +#define SOFTIRQ_BITS 8 +#define HARDIRQ_BITS 8 -#define irq_enter(cpu) (local_irq_count(cpu)++) -#define irq_exit(cpu) (local_irq_count(cpu)--) +#define PREEMPT_SHIFT 0 +#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) +#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) -#define synchronize_irq() barrier() +#define __MASK(x) ((1UL << (x))-1) + +#define PREEMPT_MASK (__MASK(PREEMPT_BITS) << PREEMPT_SHIFT) +#define HARDIRQ_MASK (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) +#define SOFTIRQ_MASK (__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) + +#define hardirq_count() (preempt_count() & HARDIRQ_MASK) +#define softirq_count() (preempt_count() & SOFTIRQ_MASK) +#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK)) + +#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) +#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) +#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) + +/* + * The hardirq mask has to be large enough to have + * space for potentially all IRQ sources in the system + * nesting on a single CPU: + */ +#if (1 << HARDIRQ_BITS) < NR_IRQS +# error HARDIRQ_BITS is too low! +#endif + +/* + * Are we doing bottom half or hardware interrupt processing? + * Are we in a softirq context? Interrupt context? + */ +#define in_irq() (hardirq_count()) +#define in_softirq() (softirq_count()) +#define in_interrupt() (irq_count()) + + +#define hardirq_trylock() (!in_interrupt()) +#define hardirq_endlock() do { } while (0) + +#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) + +#ifdef CONFIG_PREEMPT +# define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) +# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) +#else +# define in_atomic() (preempt_count() != 0) +# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET +#endif +#define irq_exit() \ +do { \ + preempt_count() -= IRQ_EXIT_OFFSET; \ + if (!in_interrupt() && softirq_pending(smp_processor_id())) \ + do_softirq(); \ + preempt_enable_no_resched(); \ +} while (0) + +#define synchronize_irq(irq) barrier() #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-cris/hdreg.h b/include/asm-cris/hdreg.h deleted file mode 100644 index 382a8e64ce8b..000000000000 --- a/include/asm-cris/hdreg.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * linux/include/asm-cris/hdreg.h - * - */ - -#ifndef __ASMCRIS_HDREG_H -#define __ASMCRIS_HDREG_H - -typedef unsigned long ide_ioreg_t; - -#endif /* __ASMCRIS_HDREG_H */ diff --git a/include/asm-cris/ide.h b/include/asm-cris/ide.h deleted file mode 100644 index 8f4bd8c131f4..000000000000 --- a/include/asm-cris/ide.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * linux/include/asm-cris/ide.h - * - * Copyright (C) 2000 Axis Communications AB - * - * Authors: Bjorn Wesen - * - */ - -/* - * This file contains the ETRAX 100LX specific IDE code. - */ - -#ifndef __ASMCRIS_IDE_H -#define __ASMCRIS_IDE_H - -#ifdef __KERNEL__ - -#include <asm/svinto.h> - -/* ETRAX 100 can support 4 IDE busses on the same pins (serialized) */ - -#define MAX_HWIFS 4 - -static __inline__ int ide_default_irq(ide_ioreg_t base) -{ - /* all IDE busses share the same IRQ, number 4. - * this has the side-effect that ide-probe.c will cluster our 4 interfaces - * together in a hwgroup, and will serialize accesses. this is good, because - * we can't access more than one interface at the same time on ETRAX100. - */ - return 4; -} - -static __inline__ ide_ioreg_t ide_default_io_base(int index) -{ - /* we have no real I/O base address per interface, since all go through the - * same register. but in a bitfield in that register, we have the i/f number. - * so we can use the io_base to remember that bitfield. - */ - static const unsigned long io_bases[MAX_HWIFS] = { - IO_FIELD(R_ATA_CTRL_DATA, sel, 0), - IO_FIELD(R_ATA_CTRL_DATA, sel, 1), - IO_FIELD(R_ATA_CTRL_DATA, sel, 2), - IO_FIELD(R_ATA_CTRL_DATA, sel, 3) - }; - return io_bases[index]; -} - -/* this is called once for each interface, to setup the port addresses. data_port is the result - * of the ide_default_io_base call above. ctrl_port will be 0, but that is don't care for us. - */ - -static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) -{ - int i; - - /* fill in ports for ATA addresses 0 to 7 */ - - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { - hw->io_ports[i] = data_port | - IO_FIELD(R_ATA_CTRL_DATA, addr, i) | - IO_STATE(R_ATA_CTRL_DATA, cs0, active); - } - - /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */ - - hw->io_ports[IDE_CONTROL_OFFSET] = data_port | - IO_FIELD(R_ATA_CTRL_DATA, addr, 6) | - IO_STATE(R_ATA_CTRL_DATA, cs1, active); - - /* whats this for ? */ - - hw->io_ports[IDE_IRQ_OFFSET] = 0; -} - -static __inline__ void ide_init_default_hwifs(void) -{ - hw_regs_t hw; - int index; - - for(index = 0; index < MAX_HWIFS; index++) { - ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL); - hw.irq = ide_default_irq(ide_default_io_base(index)); - ide_register_hw(&hw); - } -} - -/* some configuration options we don't need */ - -#undef SUPPORT_SLOW_DATA_PORTS -#define SUPPORT_SLOW_DATA_PORTS 0 - -/* the drive addressing is done through a controller register on the Etrax CPU */ -void OUT_BYTE(unsigned char data, ide_ioreg_t reg); -unsigned char IN_BYTE(ide_ioreg_t reg); - -/* this tells ide.h not to define the standard macros */ -#define HAVE_ARCH_IN_OUT 1 - -#endif /* __KERNEL__ */ - -#endif /* __ASMCRIS_IDE_H */ diff --git a/include/asm-cris/io.h b/include/asm-cris/io.h index 82a06f841c9f..8604f0e9a69d 100644 --- a/include/asm-cris/io.h +++ b/include/asm-cris/io.h @@ -2,209 +2,18 @@ #define _ASM_CRIS_IO_H #include <asm/page.h> /* for __va, __pa */ -#include <asm/svinto.h> -#include <linux/config.h> - -/* Console I/O for simulated etrax100. Use #ifdef so erroneous - use will be evident. */ -#ifdef CONFIG_SVINTO_SIM - /* Let's use the ucsim interface since it lets us do write(2, ...) */ -#define SIMCOUT(s,len) \ - asm ("moveq 4,$r9 \n\t" \ - "moveq 2,$r10 \n\t" \ - "move.d %0,$r11 \n\t" \ - "move.d %1,$r12 \n\t" \ - "push $irp \n\t" \ - "move 0f,$irp \n\t" \ - "jump -6809 \n" \ - "0: \n\t" \ - "pop $irp" \ - : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory") -#define TRACE_ON() __extension__ \ - ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \ - (255)); _Foofoo; }) - -#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0) -#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0) -#define CRIS_CYCLES() __extension__ \ - ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;}) -#else /* ! defined CONFIG_SVINTO_SIM */ -/* FIXME: Is there a reliable cycle counter available in some chip? Use - that then. */ -#define CRIS_CYCLES() 0 -#endif /* ! defined CONFIG_SVINTO_SIM */ - -/* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */ - -extern unsigned long port_g_data_shadow; -extern unsigned char port_pa_dir_shadow; -extern unsigned char port_pa_data_shadow; -extern unsigned char port_pb_i2c_shadow; -extern unsigned char port_pb_config_shadow; -extern unsigned char port_pb_dir_shadow; -extern unsigned char port_pb_data_shadow; -extern unsigned long r_timer_ctrl_shadow; - -extern unsigned long port_cse1_shadow; -extern unsigned long port_csp0_shadow; -extern unsigned long port_csp4_shadow; - -extern volatile unsigned long *port_cse1_addr; -extern volatile unsigned long *port_csp0_addr; -extern volatile unsigned long *port_csp4_addr; - -/* macro for setting regs through a shadow - - * r = register name (like R_PORT_PA_DATA) - * s = shadow name (like port_pa_data_shadow) - * b = bit number - * v = value (0 or 1) - */ - -#define REG_SHADOW_SET(r,s,b,v) *r = s = (s & ~(1 << (b))) | ((v) << (b)) - -/* The LED's on various Etrax-based products are set differently. */ - -#if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM) -#undef CONFIG_ETRAX_PA_LEDS -#undef CONFIG_ETRAX_PB_LEDS -#undef CONFIG_ETRAX_CSP0_LEDS -#define LED_NETWORK_SET_G(x) -#define LED_NETWORK_SET_R(x) -#define LED_ACTIVE_SET_G(x) -#define LED_ACTIVE_SET_R(x) -#define LED_DISK_WRITE(x) -#define LED_DISK_READ(x) -#endif - -#if !defined(CONFIG_ETRAX_CSP0_LEDS) -#define LED_BIT_SET(x) -#define LED_BIT_CLR(x) -#endif - -#define LED_OFF 0x00 -#define LED_GREEN 0x01 -#define LED_RED 0x02 -#define LED_ORANGE (LED_GREEN | LED_RED) - -#if CONFIG_ETRAX_LED1G == CONFIG_ETRAX_LED1R -#define LED_NETWORK_SET(x) \ - do { \ - LED_NETWORK_SET_G((x) & LED_GREEN); \ - } while (0) -#else -#define LED_NETWORK_SET(x) \ - do { \ - LED_NETWORK_SET_G((x) & LED_GREEN); \ - LED_NETWORK_SET_R((x) & LED_RED); \ - } while (0) -#endif -#if CONFIG_ETRAX_LED2G == CONFIG_ETRAX_LED2R -#define LED_ACTIVE_SET(x) \ - do { \ - LED_ACTIVE_SET_G((x) & LED_GREEN); \ - } while (0) -#else -#define LED_ACTIVE_SET(x) \ - do { \ - LED_ACTIVE_SET_G((x) & LED_GREEN); \ - LED_ACTIVE_SET_R((x) & LED_RED); \ - } while (0) -#endif - -#ifdef CONFIG_ETRAX_PA_LEDS -#define LED_NETWORK_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1G, !(x)) -#define LED_NETWORK_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED1R, !(x)) -#define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2G, !(x)) -#define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x)) -#define LED_DISK_WRITE(x) \ - do{\ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x));\ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x));\ - }while(0) -#define LED_DISK_READ(x) \ - REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) -#endif - -#ifdef CONFIG_ETRAX_PB_LEDS -#define LED_NETWORK_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1G, !(x)) -#define LED_NETWORK_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED1R, !(x)) -#define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2G, !(x)) -#define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x)) -#define LED_DISK_WRITE(x) \ - do{\ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x));\ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x));\ - }while(0) -#define LED_DISK_READ(x) \ - REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x)) -#endif - -#ifdef CONFIG_ETRAX_CSP0_LEDS -#define CONFIGURABLE_LEDS\ - ((1 << CONFIG_ETRAX_LED1G ) | (1 << CONFIG_ETRAX_LED1R ) |\ - (1 << CONFIG_ETRAX_LED2G ) | (1 << CONFIG_ETRAX_LED2R ) |\ - (1 << CONFIG_ETRAX_LED3G ) | (1 << CONFIG_ETRAX_LED3R ) |\ - (1 << CONFIG_ETRAX_LED4G ) | (1 << CONFIG_ETRAX_LED4R ) |\ - (1 << CONFIG_ETRAX_LED5G ) | (1 << CONFIG_ETRAX_LED5R ) |\ - (1 << CONFIG_ETRAX_LED6G ) | (1 << CONFIG_ETRAX_LED6R ) |\ - (1 << CONFIG_ETRAX_LED7G ) | (1 << CONFIG_ETRAX_LED7R ) |\ - (1 << CONFIG_ETRAX_LED8Y ) | (1 << CONFIG_ETRAX_LED9Y ) |\ - (1 << CONFIG_ETRAX_LED10Y ) |(1 << CONFIG_ETRAX_LED11Y )|\ - (1 << CONFIG_ETRAX_LED12R )) - -#define LED_NETWORK_SET_G(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1G, !(x)) -#define LED_NETWORK_SET_R(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED1R, !(x)) -#define LED_ACTIVE_SET_G(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2G, !(x)) -#define LED_ACTIVE_SET_R(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x)) -#define LED_DISK_WRITE(x) \ - do{\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x));\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x));\ - }while(0) -#define LED_DISK_READ(x) \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x)) -#define LED_BIT_SET(x)\ - do{\ - if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 1);\ - }while(0) -#define LED_BIT_CLR(x)\ - do{\ - if((( 1 << x) & CONFIGURABLE_LEDS) != 0)\ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, x, 0);\ - }while(0) -#endif - -# -#ifdef CONFIG_ETRAX_SOFT_SHUTDOWN -#define SOFT_SHUTDOWN() \ - REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_SHUTDOWN_BIT, 1) -#else -#define SOFT_SHUTDOWN() -#endif +#include <asm/arch/io.h> /* * Change virtual addresses to physical addresses and vv. */ -static inline unsigned long virt_to_phys(volatile void * address) +extern inline unsigned long virt_to_phys(volatile void * address) { return __pa(address); } -static inline void * phys_to_virt(unsigned long address) +extern inline void * phys_to_virt(unsigned long address) { return __va(address); } @@ -216,6 +25,8 @@ extern inline void * ioremap (unsigned long offset, unsigned long size) return __ioremap(offset, size, 0); } +extern void iounmap(void *addr); + /* * IO bus memory addresses are also 1:1 with the physical address */ @@ -231,10 +42,16 @@ extern inline void * ioremap (unsigned long offset, unsigned long size) #define readb(addr) (*(volatile unsigned char *) (addr)) #define readw(addr) (*(volatile unsigned short *) (addr)) #define readl(addr) (*(volatile unsigned int *) (addr)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl #define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b)) #define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b)) #define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b)) +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel #define memset_io(a,b,c) memset((void *)(a),(b),(c)) #define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) diff --git a/include/asm-cris/ioctls.h b/include/asm-cris/ioctls.h index 1628ad265a89..97787c3c575f 100644 --- a/include/asm-cris/ioctls.h +++ b/include/asm-cris/ioctls.h @@ -70,6 +70,9 @@ #define TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ #define FIOQSIZE 0x5460 +#define TIOCSERSETRS485 0x5461 /* enable rs-485 */ +#define TIOCSERWRRS485 0x5462 /* write rs-485 */ + /* Used for packet mode */ #define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 diff --git a/include/asm-cris/ipc.h b/include/asm-cris/ipc.h index 07e51a11d50d..f086af6fa03f 100644 --- a/include/asm-cris/ipc.h +++ b/include/asm-cris/ipc.h @@ -17,6 +17,7 @@ struct ipc_kludge { #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 +#define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 diff --git a/include/asm-cris/irq.h b/include/asm-cris/irq.h index 5e4fb8db6735..caa45facb1b2 100644 --- a/include/asm-cris/irq.h +++ b/include/asm-cris/irq.h @@ -1,78 +1,12 @@ -/* - * Interrupt handling assembler and defines for Linux/CRIS - * - * Copyright (c) 2000, 2001 Axis Communications AB - * - */ - #ifndef _ASM_IRQ_H #define _ASM_IRQ_H -/* - * linux/include/asm-cris/irq.h - */ - -#include <linux/linkage.h> -#include <asm/segment.h> - -#include <asm/sv_addr_ag.h> - -#define NR_IRQS 32 -#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 TIMER0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer0) /* 2 */ -#define TIMER1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, timer1) /* 3 */ -/* mio, ata, par0, scsi0 on 4 */ -/* par1, scsi1 on 5 */ -#define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */ - -#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, serial) /* 8 */ -#define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */ -/* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */ -#define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0) -#define EXTDMA1_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma1) - -/* dma0-9 is irq 16..25 */ -/* 16,17: network */ -#define DMA0_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma0) -#define DMA1_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma1) -#define NETWORK_DMA_TX_IRQ_NBR DMA0_TX_IRQ_NBR -#define NETWORK_DMA_RX_IRQ_NBR DMA1_RX_IRQ_NBR - -/* 18,19: dma2 and dma3 shared by par0, scsi0, ser2 and ata */ -#define DMA2_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma2) -#define DMA3_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma3) -#define SER2_DMA_TX_IRQ_NBR DMA2_TX_IRQ_NBR -#define SER2_DMA_RX_IRQ_NBR DMA3_RX_IRQ_NBR - -/* 20,21: dma4 and dma5 shared by par1, scsi1, ser3 and extdma0 */ -#define DMA4_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma4) -#define DMA5_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma5) -#define SER3_DMA_TX_IRQ_NBR DMA4_TX_IRQ_NBR -#define SER3_DMA_RX_IRQ_NBR DMA5_RX_IRQ_NBR - -/* 22,23: dma6 and dma7 shared by ser0, extdma1 and mem2mem */ -#define DMA6_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma6) -#define DMA7_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma7) -#define SER0_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR -#define SER0_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR -#define MEM2MEM_DMA_TX_IRQ_NBR DMA6_TX_IRQ_NBR -#define MEM2MEM_DMA_RX_IRQ_NBR DMA7_RX_IRQ_NBR - -/* 24,25: dma8 and dma9 shared by ser1 and usb */ -#define DMA8_TX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma8) -#define DMA9_RX_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, dma9) -#define SER1_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR -#define SER1_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR -#define USB_DMA_TX_IRQ_NBR DMA8_TX_IRQ_NBR -#define USB_DMA_RX_IRQ_NBR DMA9_RX_IRQ_NBR - -/* usb: controller at irq 31 + uses DMA8 and DMA9 */ -#define USB_HC_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, usb) - - - +#include <asm/arch/irq.h> +extern __inline__ int irq_canonicalize(int irq) +{ + return irq; +} extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); @@ -80,116 +14,6 @@ extern void enable_irq(unsigned int); #define disable_irq_nosync disable_irq #define enable_irq_nosync enable_irq -/* our fine, global, etrax irq vector! the pointer lives in the head.S file. */ - -typedef void (*irqvectptr)(void); - -struct etrax_interrupt_vector { - irqvectptr v[256]; -}; - -extern struct etrax_interrupt_vector *etrax_irv; -void set_int_vector(int n, irqvectptr addr, irqvectptr saddr); -void set_break_vector(int n, irqvectptr addr); - -#define __STR(x) #x -#define STR(x) __STR(x) - -/* SAVE_ALL saves registers so they match pt_regs */ - -#define SAVE_ALL \ - "move $irp,[$sp=$sp-16]\n\t" /* push instruction pointer and fake SBFS struct */ \ - "push $srp\n\t" /* push subroutine return pointer */ \ - "push $dccr\n\t" /* push condition codes */ \ - "push $mof\n\t" /* push multiply overflow reg */ \ - "di\n\t" /* need to disable irq's at this point */\ - "subq 14*4,$sp\n\t" /* make room for r0-r13 */ \ - "movem $r13,[$sp]\n\t" /* push the r0-r13 registers */ \ - "push $r10\n\t" /* push orig_r10 */ \ - "clear.d [$sp=$sp-4]\n\t" /* frametype - this is a normal stackframe */ - - /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq in irq.c */ - -#define BLOCK_IRQ(mask,nr) \ - "move.d " #mask ",$r0\n\t" \ - "move.d $r0,[0xb00000d8]\n\t" - -#define UNBLOCK_IRQ(mask) \ - "move.d " #mask ",$r0\n\t" \ - "move.d $r0,[0xb00000dc]\n\t" - -#define IRQ_NAME2(nr) nr##_interrupt(void) -#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) -#define sIRQ_NAME(nr) IRQ_NAME2(sIRQ##nr) -#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) - - /* the asm IRQ handler makes sure the causing IRQ is blocked, then it calls - * do_IRQ (with irq disabled still). after that it unblocks and jumps to - * ret_from_intr (entry.S) - * - * The reason the IRQ is blocked is to allow an sti() before the handler which - * will acknowledge the interrupt is run. - */ - -#define BUILD_IRQ(nr,mask) \ -void IRQ_NAME(nr); \ -void sIRQ_NAME(nr); \ -void BAD_IRQ_NAME(nr); \ -__asm__ ( \ - ".text\n\t" \ - "IRQ" #nr "_interrupt:\n\t" \ - SAVE_ALL \ - "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \ - BLOCK_IRQ(mask,nr) /* this must be done to prevent irq loops when we ei later */ \ - "moveq "#nr",$r10\n\t" \ - "move.d $sp,$r11\n\t" \ - "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \ - UNBLOCK_IRQ(mask) \ - "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \ - "jump ret_from_intr\n\t" \ - "bad_IRQ" #nr "_interrupt:\n\t" \ - "push $r0\n\t" \ - BLOCK_IRQ(mask,nr) \ - "pop $r0\n\t" \ - "reti\n\t" \ - "nop\n"); - -/* This is subtle. The timer interrupt is crucial and it should not be disabled for - * too long. However, if it had been a normal interrupt as per BUILD_IRQ, it would - * have been BLOCK'ed, and then softirq's are run before we return here to UNBLOCK. - * If the softirq's take too much time to run, the timer irq won't run and the - * watchdog will kill us. - * - * Furthermore, if a lot of other irq's occur before we return here, the multiple_irq - * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed - * it here, we would not get the multiple_irq at all. - * - * The non-blocking here is based on the knowledge that the timer interrupt is - * registred as a fast interrupt (SA_INTERRUPT) so that we _know_ there will not - * be an sti() before the timer irq handler is run to acknowledge the interrupt. - */ - -#define BUILD_TIMER_IRQ(nr,mask) \ -void IRQ_NAME(nr); \ -void sIRQ_NAME(nr); \ -void BAD_IRQ_NAME(nr); \ -__asm__ ( \ - ".text\n\t" \ - "IRQ" #nr "_interrupt:\n\t" \ - SAVE_ALL \ - "sIRQ" #nr "_interrupt:\n\t" /* shortcut for the multiple irq handler */ \ - "moveq "#nr",$r10\n\t" \ - "move.d $sp,$r11\n\t" \ - "jsr do_IRQ\n\t" /* irq.c, r10 and r11 are arguments */ \ - "moveq 0,$r9\n\t" /* make ret_from_intr realise we came from an irq */ \ - "jump ret_from_intr\n\t" \ - "bad_IRQ" #nr "_interrupt:\n\t" \ - "push $r0\n\t" \ - BLOCK_IRQ(mask,nr) \ - "pop $r0\n\t" \ - "reti\n\t" \ - "nop\n"); - #endif /* _ASM_IRQ_H */ diff --git a/include/asm-cris/kmap_types.h b/include/asm-cris/kmap_types.h new file mode 100644 index 000000000000..eec0974c2417 --- /dev/null +++ b/include/asm-cris/kmap_types.h @@ -0,0 +1,25 @@ +#ifndef _ASM_KMAP_TYPES_H +#define _ASM_KMAP_TYPES_H + +/* Dummy header just to define km_type. None of this + * is actually used on cris. + */ + +enum km_type { + KM_BOUNCE_READ, + KM_SKB_SUNRPC_DATA, + KM_SKB_DATA_SOFTIRQ, + KM_USER0, + KM_USER1, + KM_BIO_SRC_IRQ, + KM_BIO_DST_IRQ, + KM_PTE0, + KM_PTE1, + KM_IRQ0, + KM_IRQ1, + KM_CRYPTO_USER, + KM_CRYPTO_SOFTIRQ, + KM_TYPE_NR +}; + +#endif diff --git a/include/asm-cris/mman.h b/include/asm-cris/mman.h index 827849b9f7f1..4de58ad6efa1 100644 --- a/include/asm-cris/mman.h +++ b/include/asm-cris/mman.h @@ -6,6 +6,7 @@ #define PROT_READ 0x1 /* page can be read */ #define PROT_WRITE 0x2 /* page can be written */ #define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_SEM 0x8 /* page may be used for atomic ops */ #define PROT_NONE 0x0 /* page can not be accessed */ #define MAP_SHARED 0x01 /* Share changes */ @@ -19,6 +20,8 @@ #define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ #define MAP_LOCKED 0x2000 /* pages are locked */ #define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ #define MS_ASYNC 1 /* sync memory asynchronously */ #define MS_INVALIDATE 2 /* invalidate the caches */ diff --git a/include/asm-cris/mmu.h b/include/asm-cris/mmu.h index df2d5ee85c7b..c40a1bcad06c 100644 --- a/include/asm-cris/mmu.h +++ b/include/asm-cris/mmu.h @@ -5,58 +5,6 @@ #ifndef _CRIS_MMU_H #define _CRIS_MMU_H -/* type used in struct mm to couple an MMU context to an active mm */ - -typedef unsigned int mm_context_t; - -/* kernel memory segments */ - -#define KSEG_F 0xf0000000UL -#define KSEG_E 0xe0000000UL -#define KSEG_D 0xd0000000UL -#define KSEG_C 0xc0000000UL -#define KSEG_B 0xb0000000UL -#define KSEG_A 0xa0000000UL -#define KSEG_9 0x90000000UL -#define KSEG_8 0x80000000UL -#define KSEG_7 0x70000000UL -#define KSEG_6 0x60000000UL -#define KSEG_5 0x50000000UL -#define KSEG_4 0x40000000UL -#define KSEG_3 0x30000000UL -#define KSEG_2 0x20000000UL -#define KSEG_1 0x10000000UL -#define KSEG_0 0x00000000UL - -/* CRIS PTE bits (see R_TLB_LO in the register description) - * - * Bit: 31-13 12-------4 3 2 1 0 - * ________________________________________________ - * | pfn | reserved | global | valid | kernel | we | - * |_____|__________|________|_______|________|_____| - * - * (pfn = physical frame number) - */ - -/* Real HW-based PTE bits. We use some synonym names so that - * things become less confusing in combination with the SW-based - * bits further below. - * - */ - -#define _PAGE_WE (1<<0) /* page is write-enabled */ -#define _PAGE_SILENT_WRITE (1<<0) /* synonym */ -#define _PAGE_KERNEL (1<<1) /* page is kernel only */ -#define _PAGE_VALID (1<<2) /* page is valid */ -#define _PAGE_SILENT_READ (1<<2) /* synonym */ -#define _PAGE_GLOBAL (1<<3) /* global page - context is ignored */ - -/* Bits the HW doesn't care about but the kernel uses them in SW */ - -#define _PAGE_PRESENT (1<<4) /* page present in memory */ -#define _PAGE_ACCESSED (1<<5) /* simulated in software using valid bit */ -#define _PAGE_MODIFIED (1<<6) /* simulated in software using we bit */ -#define _PAGE_READ (1<<7) /* read-enabled */ -#define _PAGE_WRITE (1<<8) /* write-enabled */ +#include <asm/arch/mmu.h> #endif diff --git a/include/asm-cris/mmu_context.h b/include/asm-cris/mmu_context.h index 6a6ea71a85cd..dd1db4e98fcc 100644 --- a/include/asm-cris/mmu_context.h +++ b/include/asm-cris/mmu_context.h @@ -17,7 +17,7 @@ extern void switch_mm(struct mm_struct *prev, struct mm_struct *next, extern volatile pgd_t *current_pgd; /* defined in arch/cris/mm/fault.c */ -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +extern inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) { } diff --git a/include/asm-cris/module.h b/include/asm-cris/module.h index 5853a11d6163..7ee72311bd78 100644 --- a/include/asm-cris/module.h +++ b/include/asm-cris/module.h @@ -1,12 +1,9 @@ #ifndef _ASM_CRIS_MODULE_H #define _ASM_CRIS_MODULE_H -/* - * This file contains the CRIS architecture specific module code. - */ - -#define module_map(x) vmalloc(x) -#define module_unmap(x) vfree(x) -#define module_arch_init(x) (0) -#define arch_init_modules(x) do { } while (0) +/* cris is simple */ +struct mod_arch_specific { }; +#define Elf_Shdr Elf32_Shdr +#define Elf_Sym Elf32_Sym +#define Elf_Ehdr Elf32_Ehdr #endif /* _ASM_CRIS_MODULE_H */ diff --git a/include/asm-cris/page.h b/include/asm-cris/page.h index 47c83465c2af..05dc15526aa3 100644 --- a/include/asm-cris/page.h +++ b/include/asm-cris/page.h @@ -2,7 +2,7 @@ #define _CRIS_PAGE_H #include <linux/config.h> -#include <asm/mmu.h> +#include <asm/arch/page.h> /* PAGE_SHIFT determines the page size */ #define PAGE_SHIFT 13 @@ -14,12 +14,9 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) -#define clear_user_page(page, vaddr) clear_page(page) -#define copy_user_page(to, from, vaddr) copy_page(to, from) +#define clear_user_page(page, vaddr, pg) clear_page(page) +#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) -#define STRICT_MM_TYPECHECKS - -#ifdef STRICT_MM_TYPECHECKS /* * These are used to make use of C type-checking.. */ @@ -38,52 +35,11 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) -#else -/* - * .. while these make it easier on the compiler - */ -typedef unsigned long pte_t; -typedef unsigned long pmd_t; -typedef unsigned long pgd_t; -typedef unsigned long pgprot_t; - -#define pte_val(x) (x) -#define pmd_val(x) (x) -#define pgd_val(x) (x) -#define pgprot_val(x) (x) - -#define __pte(x) (x) -#define __pmd(x) (x) -#define __pgd(x) (x) -#define __pgprot(x) (x) - -#endif - -/* to align the pointer to the (next) page boundary */ -#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) - -/* This handles the memory map.. */ - -#ifdef CONFIG_CRIS_LOW_MAP -#define PAGE_OFFSET KSEG_6 /* kseg_6 is mapped to physical ram */ -#else -#define PAGE_OFFSET KSEG_C /* kseg_c is mapped to physical ram */ -#endif - -/* macros to convert between really physical and virtual addresses - * by stripping a selected bit, we can convert between KSEG_x and 0x40000000 where - * the DRAM really resides - */ - -#ifdef CONFIG_CRIS_LOW_MAP -/* we have DRAM virtually at 0x6 */ -#define __pa(x) ((unsigned long)(x) & 0xdfffffff) -#define __va(x) ((void *)((unsigned long)(x) | 0x20000000)) -#else -/* we have DRAM virtually at 0xc */ -#define __pa(x) ((unsigned long)(x) & 0x7fffffff) -#define __va(x) ((void *)((unsigned long)(x) | 0x80000000)) -#endif +/* On CRIS the PFN numbers doesn't start at 0 so we have to compensate */ +/* for that before indexing into the page table starting at mem_map */ +#define pfn_to_page(pfn) (mem_map + ((pfn) - (PAGE_OFFSET >> PAGE_SHIFT))) +#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + (PAGE_OFFSET >> PAGE_SHIFT)) +#define pfn_valid(pfn) (((pfn) - (PAGE_OFFSET >> PAGE_SHIFT)) < max_mapnr) /* to index into the page map. our pages all start at physical addr PAGE_OFFSET so * we can let the map start there. notice that we subtract PAGE_OFFSET because @@ -95,6 +51,7 @@ typedef unsigned long pgprot_t; #define virt_to_page(kaddr) (mem_map + (((unsigned long)(kaddr) - PAGE_OFFSET) >> PAGE_SHIFT)) #define VALID_PAGE(page) (((page) - mem_map) < max_mapnr) +#define virt_addr_valid(kaddr) pfn_valid((kaddr) >> PAGE_SHIFT) /* 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 @@ -102,9 +59,34 @@ typedef unsigned long pgprot_t; #define page_to_phys(page) __pa((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET) -/* from linker script */ +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +#ifndef __ASSEMBLY__ + +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ +} while (0) + +#define PAGE_BUG(page) do { \ + BUG(); \ +} while (0) + +#endif /* __ASSEMBLY__ */ + +/* Pure 2^n version of get_order */ +static inline int get_order(unsigned long size) +{ + int order; -extern unsigned long dram_start, dram_end; + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) diff --git a/include/asm-cris/param.h b/include/asm-cris/param.h index 50fe5729b29e..a9f71dbedb39 100644 --- a/include/asm-cris/param.h +++ b/include/asm-cris/param.h @@ -1,6 +1,13 @@ #ifndef _ASMCRIS_PARAM_H #define _ASMCRIS_PARAM_H +/* Currently we assume that HZ=100 is good for CRIS. */ +#ifdef __KERNEL__ +# define HZ 100 /* Internal kernel timer frequency */ +# define USER_HZ 100 /* .. some user interfaces are in "ticks" */ +# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ +#endif + #ifndef HZ #define HZ 100 #endif @@ -17,8 +24,4 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ -#ifdef __KERNEL__ -# define CLOCKS_PER_SEC 100 /* frequency at which times() counts */ -#endif - #endif diff --git a/include/asm-cris/percpu.h b/include/asm-cris/percpu.h new file mode 100644 index 000000000000..6db9b43cf80a --- /dev/null +++ b/include/asm-cris/percpu.h @@ -0,0 +1,6 @@ +#ifndef _CRIS_PERCPU_H +#define _CRIS_PERCPU_H + +#include <asm-generic/percpu.h> + +#endif /* _CRIS_PERCPU_H */ diff --git a/include/asm-cris/pgalloc.h b/include/asm-cris/pgalloc.h index 75dde6f4a42f..ca769e060298 100644 --- a/include/asm-cris/pgalloc.h +++ b/include/asm-cris/pgalloc.h @@ -3,113 +3,65 @@ #include <asm/page.h> #include <linux/threads.h> +#include <linux/mm.h> -extern struct pgtable_cache_struct { - unsigned long *pgd_cache; - unsigned long *pte_cache; - unsigned long pgtable_cache_sz; -} quicklists; - -#define pgd_quicklist (quicklists.pgd_cache) -#define pmd_quicklist ((unsigned long *)0) -#define pte_quicklist (quicklists.pte_cache) -#define pgtable_cache_size (quicklists.pgtable_cache_sz) - -#define pmd_populate(mm, pmd, pte) pmd_set(pmd, pte) +#define pmd_populate_kernel(mm, pmd, pte) pmd_set(pmd, pte) +#define pmd_populate(mm, pmd, pte) pmd_set(pmd, page_address(pte)) /* * Allocate and free page tables. */ -static inline pgd_t *get_pgd_slow(void) -{ - pgd_t *ret = (pgd_t *)__get_free_page(GFP_KERNEL); - - if (ret) { - memset(ret, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); - memcpy(ret + USER_PTRS_PER_PGD, swapper_pg_dir + USER_PTRS_PER_PGD, - (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); - } - return ret; -} - -static inline void free_pgd_slow(pgd_t *pgd) +extern inline pgd_t *pgd_alloc (struct mm_struct *mm) { - free_page((unsigned long)pgd); + return (pgd_t *)get_zeroed_page(GFP_KERNEL); } -static inline pgd_t *get_pgd_fast(void) +extern inline void pgd_free (pgd_t *pgd) { - unsigned long *ret; - - if ((ret = pgd_quicklist) != NULL) { - pgd_quicklist = (unsigned long *)(*ret); - ret[0] = 0; - pgtable_cache_size--; - } else - ret = (unsigned long *)get_pgd_slow(); - return (pgd_t *)ret; + free_page((unsigned long)pgd); } -static inline void free_pgd_fast(pgd_t *pgd) +extern inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) { - *(unsigned long *)pgd = (unsigned long) pgd_quicklist; - pgd_quicklist = (unsigned long *) pgd; - pgtable_cache_size++; + pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); + if (pte) + clear_page(pte); + return pte; } -static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) +extern inline struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) { - pte_t *pte; - - pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); - if (pte) - clear_page(pte); - return pte; + struct page *pte; + pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0); + if (pte) + clear_page(page_address(pte)); + return pte; } -static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) +extern inline void pte_free_kernel(pte_t *pte) { - unsigned long *ret; - - if((ret = (unsigned long *)pte_quicklist) != NULL) { - pte_quicklist = (unsigned long *)(*ret); - ret[0] = ret[1]; - pgtable_cache_size--; - } - return (pte_t *)ret; + free_page((unsigned long)pte); } -static __inline__ void pte_free_fast(pte_t *pte) +extern inline void pte_free(struct page *pte) { - *(unsigned long *)pte = (unsigned long) pte_quicklist; - pte_quicklist = (unsigned long *) pte; - pgtable_cache_size++; + __free_page(pte); } -static __inline__ void pte_free_slow(pte_t *pte) -{ - free_page((unsigned long)pte); -} -#define pte_free(pte) pte_free_slow(pte) -#define pgd_free(pgd) free_pgd_slow(pgd) -#define pgd_alloc(mm) get_pgd_fast() +#define __pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte)) /* * We don't have any real pmd's, and this code never triggers because * the pgd will always be present.. */ -#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) -#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) -#define pmd_free_slow(x) do { } while (0) -#define pmd_free_fast(x) do { } while (0) -#define pmd_free(x) do { } while (0) -#define pgd_populate(mm, pmd, pte) BUG() - -/* other stuff */ +#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) +#define pmd_free(x) do { } while (0) +#define __pmd_free_tlb(tlb,x) do { } while (0) +#define pgd_populate(mm, pmd, pte) BUG() -extern int do_check_pgt_cache(int, int); +#define check_pgt_cache() do { } while (0) #endif diff --git a/include/asm-cris/pgtable.h b/include/asm-cris/pgtable.h index d3ffca513750..25b2b51b55b3 100644 --- a/include/asm-cris/pgtable.h +++ b/include/asm-cris/pgtable.h @@ -1,104 +1,14 @@ -/* CRIS pgtable.h - macros and functions to manipulate page tables - * - * HISTORY: - * - * $Log: pgtable.h,v $ - * Revision 1.14 2001/12/10 03:08:50 bjornw - * Added pgtable_cache_init dummy - * - * Revision 1.13 2001/11/12 18:05:38 pkj - * Added declaration of paging_init(). - * - * Revision 1.12 2001/08/11 00:28:00 bjornw - * PAGE_CHG_MASK and PAGE_NONE had somewhat untraditional values - * - * Revision 1.11 2001/04/04 14:38:36 bjornw - * Removed bad_pagetable handling and the _kernel functions - * - * Revision 1.10 2001/03/23 07:46:42 starvik - * Corrected according to review remarks - * - * Revision 1.9 2000/11/22 14:57:53 bjornw - * * extern inline -> static inline - * * include asm-generic/pgtable.h - * - * Revision 1.8 2000/11/21 13:56:16 bjornw - * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type - * - * Revision 1.7 2000/10/06 15:05:32 bjornw - * VMALLOC area changed in memory mapping change - * - * Revision 1.6 2000/10/04 16:59:14 bjornw - * Changed comments - * - * Revision 1.5 2000/09/13 14:39:53 bjornw - * New macros - * - * Revision 1.4 2000/08/17 15:38:48 bjornw - * 2.4.0-test6 modifications: - * * flush_dcache_page added - * * MAP_NR removed - * * virt_to_page added - * - * Plus some comments and type-clarifications. - * - * Revision 1.3 2000/08/15 16:33:35 bjornw - * pmd_bad should recognize both kernel and user page-tables - * - * Revision 1.2 2000/07/10 17:06:01 bjornw - * Fixed warnings - * - * Revision 1.1.1.1 2000/07/10 16:32:31 bjornw - * CRIS architecture, working draft - * - * - * Revision 1.11 2000/05/29 14:55:56 bjornw - * Small tweaks of pte_mk routines - * - * Revision 1.10 2000/01/27 01:49:06 bjornw - * * Ooops. The physical frame number in a PTE entry needs to point to the - * DRAM directly, not to what the kernel thinks is DRAM (due to KSEG mapping). - * Hence we need to strip bit 31 so 0xcXXXXXXX -> 0x4XXXXXXX. - * - * Revision 1.9 2000/01/26 16:25:50 bjornw - * Fixed PAGE_KERNEL bits - * - * Revision 1.8 2000/01/23 22:53:22 bjornw - * Correct flush_tlb_* macros and externs - * - * Revision 1.7 2000/01/18 16:22:55 bjornw - * Use PAGE_MASK instead of PFN_MASK. - * - * Revision 1.6 2000/01/17 02:42:53 bjornw - * Added the pmd_set macro. - * - * Revision 1.5 2000/01/16 19:53:42 bjornw - * Removed VMALLOC_OFFSET. Changed definitions of swapper_pg_dir and zero_page. - * - * Revision 1.4 2000/01/14 16:38:20 bjornw - * PAGE_DIRTY -> PAGE_SILENT_WRITE, removed PAGE_COW from PAGE_COPY. - * - * Revision 1.3 1999/12/04 20:12:21 bjornw - * * PTE bits have moved to asm/mmu.h - * * Fixed definitions of the higher level page protection bits - * * Added the pte_* functions, including dirty/accessed SW simulation - * (these are exactly the same as for the MIPS port) - * - * Revision 1.2 1999/12/04 00:41:54 bjornw - * * Fixed page table offsets, sizes and shifts - * * Removed reference to i386 SMP stuff - * * Added stray comments about Linux/CRIS mm design - * * Include asm/mmu.h which will contain MMU details - * - * Revision 1.1 1999/12/03 15:04:02 bjornw - * Copied from include/asm-etrax100. For the new CRIS architecture. +/* + * CRIS pgtable.h - macros and functions to manipulate page tables. */ #ifndef _CRIS_PGTABLE_H #define _CRIS_PGTABLE_H #include <linux/config.h> +#include <linux/sched.h> #include <asm/mmu.h> +#include <asm/arch/pgtable.h> /* * The Linux memory management assumes a three-level page table setup. On @@ -114,49 +24,6 @@ extern void paging_init(void); -/* The cache doesn't need to be flushed when TLB entries change because - * the cache is mapped to physical memory, not virtual memory - */ -#define flush_cache_all() do { } while (0) -#define flush_cache_mm(mm) do { } while (0) -#define flush_cache_range(vma, start, end) do { } while (0) -#define flush_cache_page(vma, vmaddr) do { } while (0) -#define flush_dcache_page(page) do { } while (0) -#define flush_icache_range(start, end) do { } while (0) -#define flush_icache_page(vma,pg) do { } while (0) -#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) - -/* - * TLB flushing (implemented in arch/cris/mm/tlb.c): - * - * - flush_tlb() flushes the current mm struct TLBs - * - flush_tlb_all() flushes all processes TLBs - * - flush_tlb_mm(mm) flushes the specified mm context TLB's - * - flush_tlb_page(vma, vmaddr) flushes one page - * - flush_tlb_range(vma, start, end) flushes a range of pages - * - */ - -extern void flush_tlb_all(void); -extern void flush_tlb_mm(struct mm_struct *mm); -extern void flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr); -extern void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, - unsigned long end); - -static inline void flush_tlb_pgtables(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - /* CRIS does not keep any page table caches in TLB */ -} - - -static inline void flush_tlb(void) -{ - flush_tlb_mm(current->mm); -} - /* Certain architectures need to do special things when pte's * within a page table are directly modified. Thus, the following * hook is made available. @@ -204,63 +71,6 @@ static inline void flush_tlb(void) #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) #define FIRST_USER_PGD_NR 0 -/* - * Kernels own virtual memory area. - */ - -#ifdef CONFIG_CRIS_LOW_MAP -#define VMALLOC_START KSEG_7 -#define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END KSEG_8 -#else -#define VMALLOC_START KSEG_D -#define VMALLOC_VMADDR(x) ((unsigned long)(x)) -#define VMALLOC_END KSEG_E -#endif - -/* Define some higher level generic page attributes. The PTE bits are - * defined in asm-cris/mmu.h, and these are just combinations of those. - */ - -#define __READABLE (_PAGE_READ | _PAGE_SILENT_READ | _PAGE_ACCESSED) -#define __WRITEABLE (_PAGE_WRITE | _PAGE_SILENT_WRITE | _PAGE_MODIFIED) - -#define _PAGE_TABLE (_PAGE_PRESENT | __READABLE | __WRITEABLE) -#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED) - -#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | __READABLE | _PAGE_WRITE | \ - _PAGE_ACCESSED) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | __READABLE) // | _PAGE_COW -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | __READABLE) -#define PAGE_KERNEL __pgprot(_PAGE_GLOBAL | _PAGE_KERNEL | \ - _PAGE_PRESENT | __READABLE | __WRITEABLE) -#define _KERNPG_TABLE (_PAGE_TABLE | _PAGE_KERNEL) - -/* - * CRIS can't do page protection for execute, and considers read the same. - * Also, write permissions imply read permissions. This is the closest we can - * get.. - */ - -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY -#define __P110 PAGE_COPY -#define __P111 PAGE_COPY - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED - /* zero page used for uninitialized stuff */ extern unsigned long empty_zero_page; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) @@ -299,53 +109,54 @@ extern unsigned long empty_zero_page; * setup: the pgd is never bad, and a pmd always exists (as it's folded * into the pgd entry) */ -static inline int pgd_none(pgd_t pgd) { return 0; } -static inline int pgd_bad(pgd_t pgd) { return 0; } -static inline int pgd_present(pgd_t pgd) { return 1; } -static inline void pgd_clear(pgd_t * pgdp) { } +extern inline int pgd_none(pgd_t pgd) { return 0; } +extern inline int pgd_bad(pgd_t pgd) { return 0; } +extern inline int pgd_present(pgd_t pgd) { return 1; } +extern inline void pgd_clear(pgd_t * pgdp) { } /* * The following only work if pte_present() is true. * Undefined behaviour if not.. */ -static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } -static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } -static inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; } -static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } -static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +extern inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_READ; } +extern inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } +extern inline int pte_exec(pte_t pte) { return pte_val(pte) & _PAGE_READ; } +extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_MODIFIED; } +extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +extern inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } -static inline pte_t pte_wrprotect(pte_t pte) +extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_WRITE | _PAGE_SILENT_WRITE); return pte; } -static inline pte_t pte_rdprotect(pte_t pte) +extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte; } -static inline pte_t pte_exprotect(pte_t pte) +extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_READ | _PAGE_SILENT_READ); return pte; } -static inline pte_t pte_mkclean(pte_t pte) +extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~(_PAGE_MODIFIED | _PAGE_SILENT_WRITE); return pte; } -static inline pte_t pte_mkold(pte_t pte) +extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~(_PAGE_ACCESSED | _PAGE_SILENT_READ); return pte; } -static inline pte_t pte_mkwrite(pte_t pte) +extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_WRITE; if (pte_val(pte) & _PAGE_MODIFIED) @@ -353,7 +164,7 @@ static inline pte_t pte_mkwrite(pte_t pte) return pte; } -static inline pte_t pte_mkread(pte_t pte) +extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_READ; if (pte_val(pte) & _PAGE_ACCESSED) @@ -361,7 +172,7 @@ static inline pte_t pte_mkread(pte_t pte) return pte; } -static inline pte_t pte_mkexec(pte_t pte) +extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) |= _PAGE_READ; if (pte_val(pte) & _PAGE_ACCESSED) @@ -369,7 +180,7 @@ static inline pte_t pte_mkexec(pte_t pte) return pte; } -static inline pte_t pte_mkdirty(pte_t pte) +extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_MODIFIED; if (pte_val(pte) & _PAGE_WRITE) @@ -377,7 +188,7 @@ static inline pte_t pte_mkdirty(pte_t pte) return pte; } -static inline pte_t pte_mkyoung(pte_t pte) +extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; if (pte_val(pte) & _PAGE_READ) @@ -401,7 +212,7 @@ static inline pte_t pte_mkyoung(pte_t pte) * addresses (the 0xc0xxxxxx's) goes as void *'s. */ -static inline pte_t __mk_pte(void * page, pgprot_t pgprot) +extern inline pte_t __mk_pte(void * page, pgprot_t pgprot) { pte_t pte; /* the PTE needs a physical address */ @@ -419,7 +230,7 @@ static inline pte_t __mk_pte(void * page, pgprot_t pgprot) __pte; \ }) -static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; } @@ -428,7 +239,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) * pte_pagenr refers to the page-number counted starting from the virtual DRAM start */ -static inline unsigned long __pte_page(pte_t pte) +extern inline unsigned long __pte_page(pte_t pte) { /* the PTE contains a physical address */ return (unsigned long)__va(pte_val(pte) & PAGE_MASK); @@ -446,17 +257,17 @@ static inline unsigned long __pte_page(pte_t pte) * don't need the __pa and __va transformations. */ -static inline unsigned long pmd_page(pmd_t pmd) -{ return pmd_val(pmd) & PAGE_MASK; } - -static inline void pmd_set(pmd_t * pmdp, pte_t * ptep) +extern inline void pmd_set(pmd_t * pmdp, pte_t * ptep) { pmd_val(*pmdp) = _PAGE_TABLE | (unsigned long) ptep; } +#define pmd_page(pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) +#define pmd_page_kernel(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + /* to find an entry in a page-table-directory. */ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) /* to find an entry in a page-table-directory */ -static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) +extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) { return mm->pgd + pgd_index(address); } @@ -465,16 +276,24 @@ static inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) #define pgd_offset_k(address) pgd_offset(&init_mm, address) /* Find an entry in the second-level page table.. */ -static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) +extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) { return (pmd_t *) dir; } -/* Find an entry in the third-level page table.. */ -static inline pte_t * pte_offset(pmd_t * dir, unsigned long address) -{ - return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); -} +/* Find an entry in the third-level page table.. */ +#define __pte_offset(address) \ + (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define pte_offset_kernel(dir, address) \ + ((pte_t *) pmd_page_kernel(*(dir)) + __pte_offset(address)) +#define pte_offset_map(dir, address) \ + ((pte_t *)page_address(pmd_page(*(dir))) + __pte_offset(address)) +#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address) + +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) +#define pte_pfn(x) ((unsigned long)(__va((x).pte)) >> PAGE_SHIFT) +#define pfn_pte(pfn, prot) __pte((__pa((pfn) << PAGE_SHIFT)) | pgprot_val(prot)) #define pte_ERROR(e) \ printk("%s:%d: bad pte %p(%08lx).\n", __FILE__, __LINE__, &(e), pte_val(e)) @@ -483,6 +302,7 @@ static inline pte_t * pte_offset(pmd_t * dir, unsigned long address) #define pgd_ERROR(e) \ printk("%s:%d: bad pgd %p(%08lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ /* @@ -491,7 +311,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; /* defined in head.S */ * * Actually I am not sure on what this could be used for. */ -static inline void update_mmu_cache(struct vm_area_struct * vma, +extern inline void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) { } @@ -514,6 +334,9 @@ static inline void update_mmu_cache(struct vm_area_struct * vma, */ #define pgtable_cache_init() do { } while (0) +#define pte_to_pgoff(x) (pte_val(x) >> 6) +#define pgoff_to_pte(x) __pte(((x) << 6) | _PAGE_FILE) + typedef pte_t *pte_addr_t; #endif /* _CRIS_PGTABLE_H */ diff --git a/include/asm-cris/poll.h b/include/asm-cris/poll.h index 8699d59dad74..1c0efc3e4be7 100644 --- a/include/asm-cris/poll.h +++ b/include/asm-cris/poll.h @@ -14,6 +14,7 @@ #define POLLWRNORM 256 #define POLLWRBAND 512 #define POLLMSG 1024 +#define POLLREMOVE 4096 struct pollfd { int fd; diff --git a/include/asm-cris/posix_types.h b/include/asm-cris/posix_types.h index d10e9fc65c32..d1c87c652619 100644 --- a/include/asm-cris/posix_types.h +++ b/include/asm-cris/posix_types.h @@ -23,12 +23,14 @@ typedef int __kernel_pid_t; typedef unsigned short __kernel_ipc_pid_t; typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_gid_t; -typedef unsigned long __kernel_size_t; +typedef __SIZE_TYPE__ __kernel_size_t; typedef long __kernel_ssize_t; typedef int __kernel_ptrdiff_t; typedef long __kernel_time_t; typedef long __kernel_suseconds_t; typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; typedef int __kernel_daddr_t; typedef char * __kernel_caddr_t; typedef unsigned short __kernel_uid16_t; diff --git a/include/asm-cris/processor.h b/include/asm-cris/processor.h index 0a8c08fa93b5..623bdf06d911 100644 --- a/include/asm-cris/processor.h +++ b/include/asm-cris/processor.h @@ -14,32 +14,12 @@ #include <asm/system.h> #include <asm/page.h> #include <asm/ptrace.h> - -/* - * Default implementation of macro that returns current - * instruction pointer ("program counter"). - */ -#define current_text_addr() ({void *pc; __asm__ ("move.d $pc,%0" : "=rm" (pc)); pc; }) - -/* CRIS has no problems with write protection */ - -#define wp_works_ok 1 - -/* - * User space process size. This is hardcoded into a few places, - * so don't change it unless you know what you are doing. - */ - -#ifdef CONFIG_CRIS_LOW_MAP -#define TASK_SIZE (0x50000000UL) /* 1.25 GB */ -#else -#define TASK_SIZE (0xB0000000UL) /* 2.75 GB */ -#endif +#include <asm/arch/processor.h> /* This decides where the kernel will search for a free chunk of vm * space during mmap's. */ -#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) /* THREAD_SIZE is the size of the task_struct/kernel_stack combo. * normally, the stack is found by doing something like p + THREAD_SIZE @@ -49,19 +29,6 @@ #define THREAD_SIZE PAGE_SIZE #define KERNEL_STACK_SIZE PAGE_SIZE -/* CRIS thread_struct. this really has nothing to do with the processor itself, since - * CRIS does not do any hardware task-switching, but it's here for legacy reasons. - * The thread_struct here is used when task-switching using _resume defined in entry.S. - * The offsets here are hardcoded into _resume - if you change this struct, you need to - * change them as well!!! -*/ - -struct thread_struct { - unsigned long ksp; /* kernel stack pointer */ - unsigned long usp; /* user stack pointer */ - unsigned long dccr; /* saved flag register */ -}; - /* * At user->kernel entry, the pt_regs struct is stacked on the top of the kernel-stack. * This macro allows us to find those regs for a task. @@ -70,76 +37,42 @@ struct thread_struct { * registers are reached by this. */ -#define user_regs(task) (((struct pt_regs *)((unsigned long)(task) + THREAD_SIZE)) - 1) +#define user_regs(thread_info) (((struct pt_regs *)((unsigned long)(thread_info) + THREAD_SIZE)) - 1) /* * Dito but for the currently running task */ -#define current_regs() user_regs(current) +#define current_regs() user_regs(current->thread_info) -#define INIT_THREAD { \ - 0, 0, 0x20 } /* ccr = int enable, nothing else */ +extern inline void prepare_to_copy(struct task_struct *tsk) +{ +} extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags); -/* give the thread a program location - * set user-mode (The 'U' flag (User mode flag) is CCR/DCCR bit 8) - * switch user-stackpointer - */ - -#define start_thread(regs, ip, usp) do { \ - set_fs(USER_DS); \ - regs->irp = ip; \ - regs->dccr |= 1 << U_DCCR_BITNR; \ - wrusp(usp); \ -} while(0) - unsigned long get_wchan(struct task_struct *p); -#define KSTK_EIP(tsk) \ - ({ \ - unsigned long eip = 0; \ - unsigned long regs = (unsigned long)user_regs(tsk); \ - if (regs > PAGE_SIZE && \ - virt_addr_valid(regs)) \ - eip = ((struct pt_regs *)regs)->irp; \ - eip; }) - #define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) /* * Free current thread data structures etc.. */ -static inline void exit_thread(void) +extern inline void exit_thread(void) { /* Nothing needs to be done. */ } +extern unsigned long thread_saved_pc(struct task_struct *tsk); + /* Free all resources held by a thread. */ -static inline void release_thread(struct task_struct *dead_task) +extern inline void release_thread(struct task_struct *dead_task) { /* Nothing needs to be done. */ } -/* Prepare to copy thread state - unlazy all lazy status */ -#define prepare_to_copy(tsk) do { } while (0) - -/* - * Return saved PC of a blocked thread. - */ -extern inline unsigned long thread_saved_pc(struct thread_struct *t) -{ - return (unsigned long)user_regs(t)->irp; -} - -#define alloc_task_struct() ((struct task_struct *) __get_free_pages(GFP_KERNEL,1)) -#define free_task_struct(p) free_pages((unsigned long) (p), 1) -#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count) - -#define init_task (init_task_union.task) -#define init_stack (init_task_union.stack) +#define init_stack (init_thread_union.stack) #define cpu_relax() barrier() diff --git a/include/asm-cris/ptrace.h b/include/asm-cris/ptrace.h index b7391cc079dc..79045e36d0a9 100644 --- a/include/asm-cris/ptrace.h +++ b/include/asm-cris/ptrace.h @@ -1,120 +1,10 @@ #ifndef _CRIS_PTRACE_H #define _CRIS_PTRACE_H -/* Register numbers in the ptrace system call interface */ +#include <asm/arch/ptrace.h> -#define PT_FRAMETYPE 0 -#define PT_ORIG_R10 1 -#define PT_R13 2 -#define PT_R12 3 -#define PT_R11 4 -#define PT_R10 5 -#define PT_R9 6 -#define PT_R8 7 -#define PT_R7 8 -#define PT_R6 9 -#define PT_R5 10 -#define PT_R4 11 -#define PT_R3 12 -#define PT_R2 13 -#define PT_R1 14 -#define PT_R0 15 -#define PT_MOF 16 -#define PT_DCCR 17 -#define PT_SRP 18 -#define PT_IRP 19 /* This is actually the debugged process' PC */ -#define PT_CSRINSTR 20 /* CPU Status record remnants - - valid if frametype == busfault */ -#define PT_CSRADDR 21 -#define PT_CSRDATA 22 -#define PT_USP 23 /* special case - USP is not in the pt_regs */ -#define PT_MAX 23 - -/* Condition code bit numbers. The same numbers apply to CCR of course, - but we use DCCR everywhere else, so let's try and be consistent. */ -#define C_DCCR_BITNR 0 -#define V_DCCR_BITNR 1 -#define Z_DCCR_BITNR 2 -#define N_DCCR_BITNR 3 -#define X_DCCR_BITNR 4 -#define I_DCCR_BITNR 5 -#define B_DCCR_BITNR 6 -#define M_DCCR_BITNR 7 -#define U_DCCR_BITNR 8 -#define P_DCCR_BITNR 9 -#define F_DCCR_BITNR 10 - -/* Frame types */ - -#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */ -#define CRIS_FRAME_BUSFAULT 1 /* frame stacked using SBFS, need RBF return - path */ - -/* pt_regs not only specifices the format in the user-struct during - * ptrace but is also the frame format used in the kernel prologue/epilogues - * themselves - */ - -struct pt_regs { - unsigned long frametype; /* type of stackframe */ - unsigned long orig_r10; - /* pushed by movem r13, [sp] in SAVE_ALL, movem pushes backwards */ - unsigned long r13; - unsigned long r12; - unsigned long r11; - unsigned long r10; - unsigned long r9; - unsigned long r8; - unsigned long r7; - unsigned long r6; - unsigned long r5; - unsigned long r4; - unsigned long r3; - unsigned long r2; - unsigned long r1; - unsigned long r0; - unsigned long mof; - unsigned long dccr; - unsigned long srp; - unsigned long irp; /* This is actually the debugged process' PC */ - unsigned long csrinstr; - unsigned long csraddr; - unsigned long csrdata; -}; - -/* switch_stack is the extra stuff pushed onto the stack in _resume (entry.S) - * when doing a context-switch. it is used (apart from in resume) when a new - * thread is made and we need to make _resume (which is starting it for the - * first time) realise what is going on. - * - * Actually, the use is very close to the thread struct (TSS) in that both the - * switch_stack and the TSS are used to keep thread stuff when switching in - * _resume. - */ - -struct switch_stack { - unsigned long r9; - unsigned long r8; - unsigned long r7; - unsigned long r6; - unsigned long r5; - unsigned long r4; - unsigned long r3; - unsigned long r2; - unsigned long r1; - unsigned long r0; - unsigned long return_ip; /* ip that _resume will return to */ -}; - -#ifdef __KERNEL__ /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ #define PTRACE_GETREGS 12 #define PTRACE_SETREGS 13 -/* bit 8 is user-mode flag */ -#define user_mode(regs) (((regs)->dccr & 0x100) != 0) -#define instruction_pointer(regs) ((regs)->irp) -extern void show_regs(struct pt_regs *); -#endif - #endif /* _CRIS_PTRACE_H */ diff --git a/include/asm-cris/rs485.h b/include/asm-cris/rs485.h new file mode 100644 index 000000000000..c331c51b0c2b --- /dev/null +++ b/include/asm-cris/rs485.h @@ -0,0 +1,20 @@ +/* RS-485 structures */ + +/* RS-485 support */ +/* Used with ioctl() TIOCSERSETRS485 */ +struct rs485_control { + unsigned short rts_on_send; + unsigned short rts_after_sent; + unsigned long delay_rts_before_send; + unsigned short enabled; +#ifdef __KERNEL__ + int disable_serial_loopback; +#endif +}; + +/* Used with ioctl() TIOCSERWRRS485 */ +struct rs485_write { + unsigned short outc_size; + unsigned char *outc; +}; + diff --git a/include/asm-cris/rtc.h b/include/asm-cris/rtc.h index 72ff33a48a8d..382081c4ab52 100644 --- a/include/asm-cris/rtc.h +++ b/include/asm-cris/rtc.h @@ -1,42 +1,81 @@ -/* $Id: rtc.h,v 1.3 2001/03/21 09:56:31 magnusmn Exp $ */ +/* $Id: rtc.h,v 1.7 2002/11/04 07:32:09 starvik Exp $ */ + +#ifndef __RTC_H__ +#define __RTC_H__ -#ifndef RTC_H -#define RTC_H #include <linux/config.h> -/* Dallas DS1302 clock/calendar register numbers */ +#ifdef CONFIG_ETRAX_DS1302 + /* Dallas DS1302 clock/calendar register numbers. */ +# define RTC_SECONDS 0 +# define RTC_MINUTES 1 +# define RTC_HOURS 2 +# define RTC_DAY_OF_MONTH 3 +# define RTC_MONTH 4 +# define RTC_WEEKDAY 5 +# define RTC_YEAR 6 +# define RTC_CONTROL 7 + + /* Bits in CONTROL register. */ +# define RTC_CONTROL_WRITEPROTECT 0x80 +# define RTC_TRICKLECHARGER 8 + + /* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS. */ +# define RTC_TCR_PATTERN 0xA0 /* 1010xxxx */ +# define RTC_TCR_1DIOD 0x04 /* xxxx01xx */ +# define RTC_TCR_2DIOD 0x08 /* xxxx10xx */ +# define RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */ +# define RTC_TCR_2KOHM 0x01 /* xxxxxx01 2KOhm */ +# define RTC_TCR_4KOHM 0x02 /* xxxxxx10 4kOhm */ +# define RTC_TCR_8KOHM 0x03 /* xxxxxx11 8kOhm */ + +#elif defined(CONFIG_ETRAX_PCF8563) + /* I2C bus slave registers. */ +# define RTC_I2C_READ 0xa3 +# define RTC_I2C_WRITE 0xa2 -#define RTC_SECONDS 0 -#define RTC_MINUTES 1 -#define RTC_HOURS 2 -#define RTC_DAY_OF_MONTH 3 -#define RTC_MONTH 4 -#define RTC_WEEKDAY 5 -#define RTC_YEAR 6 -#define RTC_CONTROL 7 + /* Phillips PCF8563 registers. */ +# define RTC_CONTROL1 0x00 /* Control/Status register 1. */ +# define RTC_CONTROL2 0x01 /* Control/Status register 2. */ +# define RTC_CLOCKOUT_FREQ 0x0d /* CLKOUT frequency. */ +# define RTC_TIMER_CONTROL 0x0e /* Timer control. */ +# define RTC_TIMER_CNTDOWN 0x0f /* Timer countdown. */ -/* Bits in CONTROL register */ -#define RTC_CONTROL_WRITEPROTECT 0x80 -#define RTC_TRICKLECHARGER 8 -/* Bits in TRICKLECHARGER register TCS TCS TCS TCS DS DS RS RS */ -#define RTC_TCR_PATTERN 0xA0 /* 1010xxxx */ -#define RTC_TCR_1DIOD 0x04 /* xxxx01xx */ -#define RTC_TCR_2DIOD 0x08 /* xxxx10xx */ -#define RTC_TCR_DISABLED 0x00 /* xxxxxx00 Disabled */ -#define RTC_TCR_2KOHM 0x01 /* xxxxxx01 2KOhm */ -#define RTC_TCR_4KOHM 0x02 /* xxxxxx10 4kOhm */ -#define RTC_TCR_8KOHM 0x03 /* xxxxxx11 8kOhm */ + /* BCD encoded clock registers. */ +# define RTC_SECONDS 0x02 +# define RTC_MINUTES 0x03 +# define RTC_HOURS 0x04 +# define RTC_DAY_OF_MONTH 0x05 +# define RTC_WEEKDAY 0x06 /* Not coded in BCD! */ +# define RTC_MONTH 0x07 +# define RTC_YEAR 0x08 +# define RTC_MINUTE_ALARM 0x09 +# define RTC_HOUR_ALARM 0x0a +# define RTC_DAY_ALARM 0x0b +# define RTC_WEEKDAY_ALARM 0x0c + +#endif #ifdef CONFIG_ETRAX_DS1302 -#define CMOS_READ(x) ds1302_readreg(x) -#define CMOS_WRITE(val,reg) ds1302_writereg(reg,val) -#define RTC_INIT() ds1302_init() +extern unsigned char ds1302_readreg(int reg); +extern void ds1302_writereg(int reg, unsigned char val); +extern int ds1302_init(void); +# define CMOS_READ(x) ds1302_readreg(x) +# define CMOS_WRITE(val,reg) ds1302_writereg(reg,val) +# define RTC_INIT() ds1302_init() +#elif defined(CONFIG_ETRAX_PCF8563) +extern unsigned char pcf8563_readreg(int reg); +extern void pcf8563_writereg(int reg, unsigned char val); +extern int pcf8563_init(void); +# define CMOS_READ(x) pcf8563_readreg(x) +# define CMOS_WRITE(val,reg) pcf8563_writereg(reg,val) +# define RTC_INIT() pcf8563_init() #else -/* no RTC configured so we shouldn't try to access any */ -#define CMOS_READ(x) 42 -#define CMOS_WRITE(x,y) -#define RTC_INIT() (-1) + /* No RTC configured so we shouldn't try to access any. */ +# define CMOS_READ(x) 42 +# define CMOS_WRITE(x,y) +# define RTC_INIT() (-1) #endif /* @@ -44,7 +83,6 @@ * struct tm in <time.h>, but it needs to be here so that the kernel * source is self contained, allowing cross-compiles, etc. etc. */ - struct rtc_time { int tm_sec; int tm_min; @@ -57,14 +95,11 @@ struct rtc_time { int tm_isdst; }; -/* - * ioctl calls that are permitted to the /dev/rtc interface - */ - -#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ -#define RTC_SET_CHARGE _IOW('p', 0x0b, int) /* Set CHARGE mode */ - -#endif - +/* ioctl() calls that are permitted to the /dev/rtc interface. */ +#define RTC_MAGIC 'p' +#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_CHARGE _IOW(RTC_MAGIC, 0x0b, int) +#define RTC_MAX_IOCTL 0x0b +#endif /* __RTC_H__ */ diff --git a/include/asm-cris/scatterlist.h b/include/asm-cris/scatterlist.h index 11a64f5fe30b..4bdc44c4ac3d 100644 --- a/include/asm-cris/scatterlist.h +++ b/include/asm-cris/scatterlist.h @@ -11,6 +11,8 @@ struct scatterlist { }; +#define sg_dma_address(sg) ((sg)->address) +#define sg_dma_len(sg) ((sg)->length) /* i386 junk */ #define ISA_DMA_THRESHOLD (0x1fffffff) diff --git a/include/asm-cris/semaphore-helper.h b/include/asm-cris/semaphore-helper.h index 3453c88c2f2e..461c5e4fc7b8 100644 --- a/include/asm-cris/semaphore-helper.h +++ b/include/asm-cris/semaphore-helper.h @@ -9,6 +9,7 @@ #define _ASM_SEMAPHORE_HELPER_H #include <asm/atomic.h> +#include <linux/errno.h> #define read(a) ((a)->counter) #define inc(a) (((a)->counter)++) @@ -19,32 +20,34 @@ /* * These two _must_ execute atomically wrt each other. */ -static inline void wake_one_more(struct semaphore * sem) +extern inline void wake_one_more(struct semaphore * sem) { atomic_inc(&sem->waking); } -static inline int waking_non_zero(struct semaphore *sem) +extern inline int waking_non_zero(struct semaphore *sem) { unsigned long flags; int ret = 0; - save_and_cli(flags); + local_save_flags(flags); + local_irq_disable(); if (read(&sem->waking) > 0) { dec(&sem->waking); ret = 1; } - restore_flags(flags); + local_irq_restore(flags); return ret; } -static inline int waking_non_zero_interruptible(struct semaphore *sem, +extern inline int waking_non_zero_interruptible(struct semaphore *sem, struct task_struct *tsk) { int ret = 0; unsigned long flags; - save_and_cli(flags); + local_save_flags(flags); + local_irq_disable(); if (read(&sem->waking) > 0) { dec(&sem->waking); ret = 1; @@ -52,23 +55,24 @@ static inline int waking_non_zero_interruptible(struct semaphore *sem, count_inc(&sem->count); ret = -EINTR; } - restore_flags(flags); + local_irq_restore(flags); return ret; } -static inline int waking_non_zero_trylock(struct semaphore *sem) +extern inline int waking_non_zero_trylock(struct semaphore *sem) { int ret = 1; unsigned long flags; - save_and_cli(flags); + local_save_flags(flags); + local_irq_disable(); if (read(&sem->waking) <= 0) count_inc(&sem->count); else { dec(&sem->waking); ret = 0; } - restore_flags(flags); + local_irq_restore(flags); return ret; } diff --git a/include/asm-cris/semaphore.h b/include/asm-cris/semaphore.h index f55edcd2f8d2..011a3bdc9ca7 100644 --- a/include/asm-cris/semaphore.h +++ b/include/asm-cris/semaphore.h @@ -54,12 +54,12 @@ extern inline void sema_init(struct semaphore *sem, int val) *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); } -static inline void init_MUTEX (struct semaphore *sem) +extern inline void init_MUTEX (struct semaphore *sem) { sema_init(sem, 1); } -static inline void init_MUTEX_LOCKED (struct semaphore *sem) +extern inline void init_MUTEX_LOCKED (struct semaphore *sem) { sema_init(sem, 0); } @@ -81,10 +81,10 @@ extern inline void down(struct semaphore * sem) #endif /* atomically decrement the semaphores count, and if its negative, we wait */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); failed = --(sem->count) < 0; - restore_flags(flags); + local_irq_restore(flags); if(failed) { __down(sem); } @@ -106,10 +106,10 @@ extern inline int down_interruptible(struct semaphore * sem) #endif /* atomically decrement the semaphores count, and if its negative, we wait */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); failed = --(sem->count) < 0; - restore_flags(flags); + local_irq_restore(flags); if(failed) failed = __down_interruptible(sem); return(failed); @@ -124,10 +124,10 @@ extern inline int down_trylock(struct semaphore * sem) CHECK_MAGIC(sem->__magic); #endif - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); failed = --(sem->count) < 0; - restore_flags(flags); + local_irq_restore(flags); if(failed) failed = __down_trylock(sem); return(failed); @@ -149,10 +149,10 @@ extern inline void up(struct semaphore * sem) #endif /* atomically increment the semaphores count, and if it was negative, we wake people */ - save_flags(flags); - cli(); + local_save_flags(flags); + local_irq_disable(); wakeup = ++(sem->count) <= 0; - restore_flags(flags); + local_irq_restore(flags); if(wakeup) { __up(sem); } diff --git a/include/asm-cris/setup.h b/include/asm-cris/setup.h index f382d3b4d282..832c197edf48 100644 --- a/include/asm-cris/setup.h +++ b/include/asm-cris/setup.h @@ -1,405 +1,3 @@ -/* -** asm/setup.h -- Definition of the Linux/m68k boot information structure -** -** Copyright 1992 by Greg Harp -** -** This file is subject to the terms and conditions of the GNU General Public -** License. See the file COPYING in the main directory of this archive -** for more details. -** -** Created 09/29/92 by Greg Harp -** -** 5/2/94 Roman Hodek: -** Added bi_atari part of the machine dependent union bi_un; for now it -** contains just a model field to distinguish between TT and Falcon. -** 26/7/96 Roman Zippel: -** Renamed to setup.h; added some useful macros to allow gcc some -** optimizations if possible. -*/ - -#ifndef _M68K_SETUP_H -#define _M68K_SETUP_H - -#include <linux/config.h> - -#define CL_SIZE (256) - -#if 0 - -#include <asm/zorro.h> - -/* - * Amiga specific part of bootinfo structure. - */ - -#define NUM_AUTO 16 - -#ifndef __ASSEMBLY__ - -#define AMIGAHW_DECLARE(name) unsigned name : 1 -#define AMIGAHW_SET(name) (boot_info.bi_amiga.hw_present.name = 1) -#define AMIGAHW_PRESENT(name) (boot_info.bi_amiga.hw_present.name) - -struct bi_Amiga { - int model; /* Amiga Model (3000?) */ - int num_autocon; /* # of autoconfig devices found */ - struct ConfigDev autocon[NUM_AUTO]; /* up to 16 autoconfig devices */ -#ifdef HACKER_KERNEL - void (*exit_func)(void); /* addr of function to exit kernel */ - unsigned long chip_addr; /* start of chip memory (bytes) */ +#ifndef _CRIS_SETUP_H +#define _CRIS_SETUP_H #endif - unsigned long chip_size; /* size of chip memory (bytes) */ - unsigned char vblank; /* VBLANK frequency */ - unsigned char psfreq; /* power supply frequency */ - unsigned long eclock; /* EClock frequency */ - unsigned long chipset; /* native chipset present */ - struct { - /* video hardware */ - AMIGAHW_DECLARE(AMI_VIDEO); /* Amiga Video */ - AMIGAHW_DECLARE(AMI_BLITTER); /* Amiga Blitter */ - AMIGAHW_DECLARE(AMBER_FF); /* Amber Flicker Fixer */ - /* sound hardware */ - AMIGAHW_DECLARE(AMI_AUDIO); /* Amiga Audio */ - /* disk storage interfaces */ - AMIGAHW_DECLARE(AMI_FLOPPY); /* Amiga Floppy */ - AMIGAHW_DECLARE(A3000_SCSI); /* SCSI (wd33c93, A3000 alike) */ - AMIGAHW_DECLARE(A4000_SCSI); /* SCSI (ncr53c710, A4000T alike) */ - AMIGAHW_DECLARE(A1200_IDE); /* IDE (A1200 alike) */ - AMIGAHW_DECLARE(A4000_IDE); /* IDE (A4000 alike) */ - AMIGAHW_DECLARE(CD_ROM); /* CD ROM drive */ - /* other I/O hardware */ - AMIGAHW_DECLARE(AMI_KEYBOARD); /* Amiga Keyboard */ - AMIGAHW_DECLARE(AMI_MOUSE); /* Amiga Mouse */ - AMIGAHW_DECLARE(AMI_SERIAL); /* Amiga Serial */ - AMIGAHW_DECLARE(AMI_PARALLEL); /* Amiga Parallel */ - /* real time clocks */ - AMIGAHW_DECLARE(A2000_CLK); /* Hardware Clock (A2000 alike) */ - AMIGAHW_DECLARE(A3000_CLK); /* Hardware Clock (A3000 alike) */ - /* supporting hardware */ - AMIGAHW_DECLARE(CHIP_RAM); /* Chip RAM */ - AMIGAHW_DECLARE(PAULA); /* Paula (8364) */ - AMIGAHW_DECLARE(DENISE); /* Denise (8362) */ - AMIGAHW_DECLARE(DENISE_HR); /* Denise (8373) */ - AMIGAHW_DECLARE(LISA); /* Lisa (8375) */ - AMIGAHW_DECLARE(AGNUS_PAL); /* Normal/Fat PAL Agnus (8367/8371) */ - AMIGAHW_DECLARE(AGNUS_NTSC); /* Normal/Fat NTSC Agnus (8361/8370) */ - AMIGAHW_DECLARE(AGNUS_HR_PAL); /* Fat Hires PAL Agnus (8372) */ - AMIGAHW_DECLARE(AGNUS_HR_NTSC); /* Fat Hires NTSC Agnus (8372) */ - AMIGAHW_DECLARE(ALICE_PAL); /* PAL Alice (8374) */ - AMIGAHW_DECLARE(ALICE_NTSC); /* NTSC Alice (8374) */ - AMIGAHW_DECLARE(MAGIC_REKICK); /* A3000 Magic Hard Rekick */ - AMIGAHW_DECLARE(ZORRO); /* Zorro AutoConfig */ - } hw_present; -}; - -#else /* __ASSEMBLY__ */ - -BI_amiga_model = BI_un -BI_amiga_num_autcon = BI_amiga_model+4 -BI_amiga_autocon = BI_amiga_num_autcon+4 -#ifdef HACKER_KERNEL -BI_amiga_exit_func = BI_amiga_autocon+(CD_sizeof*NUM_AUTO) -BI_amiga_chip_addr = BI_amiga_exit_func+4 -BI_amiga_chip_size = BI_amiga_chip_addr+4 -#else -BI_amiga_chip_size = BI_amiga_autocon+(CD_sizeof*NUM_AUTO) -#endif -BI_amiga_vblank = BI_amiga_chip_size+4 -BI_amiga_psfreq = BI_amiga_vblank+1 -BI_amiga_eclock = BI_amiga_psfreq+1 -BI_amiga_chipset = BI_amiga_eclock+4 -BI_amiga_hw_present = BI_amiga_chipset+4 - -#endif /* __ASSEMBLY__ */ - -/* Atari specific part of bootinfo */ - -/* - * Define several Hardware-Chips for indication so that for the ATARI we do - * no longer decide whether it is a Falcon or other machine . It's just - * important what hardware the machine uses - */ - -/* ++roman 08/08/95: rewritten from ORing constants to a C bitfield */ - -#ifndef __ASSEMBLY__ - -#define ATARIHW_DECLARE(name) unsigned name : 1 -#define ATARIHW_SET(name) (boot_info.bi_atari.hw_present.name = 1) -#define ATARIHW_PRESENT(name) (boot_info.bi_atari.hw_present.name) - -struct bi_Atari { - struct { - /* video hardware */ - ATARIHW_DECLARE(STND_SHIFTER); /* ST-Shifter - no base low ! */ - ATARIHW_DECLARE(EXTD_SHIFTER); /* STe-Shifter - 24 bit address */ - ATARIHW_DECLARE(TT_SHIFTER); /* TT-Shifter */ - ATARIHW_DECLARE(VIDEL_SHIFTER); /* Falcon-Shifter */ - /* sound hardware */ - ATARIHW_DECLARE(YM_2149); /* Yamaha YM 2149 */ - ATARIHW_DECLARE(PCM_8BIT); /* PCM-Sound in STe-ATARI */ - ATARIHW_DECLARE(CODEC); /* CODEC Sound (Falcon) */ - /* disk storage interfaces */ - ATARIHW_DECLARE(TT_SCSI); /* Directly mapped NCR5380 */ - ATARIHW_DECLARE(ST_SCSI); /* NCR5380 via ST-DMA (Falcon) */ - ATARIHW_DECLARE(ACSI); /* Standard ACSI like in STs */ - ATARIHW_DECLARE(IDE); /* IDE Interface */ - ATARIHW_DECLARE(FDCSPEED); /* 8/16 MHz switch for FDC */ - /* other I/O hardware */ - ATARIHW_DECLARE(ST_MFP); /* The ST-MFP (there should - be no Atari without - it... but who knows?) */ - ATARIHW_DECLARE(TT_MFP); /* 2nd MFP */ - ATARIHW_DECLARE(SCC); /* Serial Communications Contr. */ - ATARIHW_DECLARE(ST_ESCC); /* SCC Z83230 in an ST */ - ATARIHW_DECLARE(ANALOG_JOY); /* Paddle Interface for STe - and Falcon */ - ATARIHW_DECLARE(MICROWIRE); /* Microwire Interface */ - /* DMA */ - ATARIHW_DECLARE(STND_DMA); /* 24 Bit limited ST-DMA */ - ATARIHW_DECLARE(EXTD_DMA); /* 32 Bit ST-DMA */ - ATARIHW_DECLARE(SCSI_DMA); /* DMA for the NCR5380 */ - ATARIHW_DECLARE(SCC_DMA); /* DMA for the SCC */ - /* real time clocks */ - ATARIHW_DECLARE(TT_CLK); /* TT compatible clock chip */ - ATARIHW_DECLARE(MSTE_CLK); /* Mega ST(E) clock chip */ - /* supporting hardware */ - ATARIHW_DECLARE(SCU); /* System Control Unit */ - ATARIHW_DECLARE(BLITTER); /* Blitter */ - ATARIHW_DECLARE(VME); /* VME Bus */ - } hw_present; - unsigned long mch_cookie; /* _MCH cookie from TOS */ -}; - -/* mch_cookie values (upper word) */ -#define ATARI_MCH_ST 0 -#define ATARI_MCH_STE 1 -#define ATARI_MCH_TT 2 -#define ATARI_MCH_FALCON 3 - -struct mem_info { - unsigned long addr; /* physical address of memory chunk */ - unsigned long size; /* length of memory chunk (in bytes) */ -}; - -#else /* __ASSEMBLY__ */ - -MI_addr = 0 -MI_size = MI_addr+4 -MI_sizeof = MI_size+4 - -#endif /* __ASSEMBLY__ */ - -#define NUM_MEMINFO 4 - -#define MACH_AMIGA 1 -#define MACH_ATARI 2 -#define MACH_MAC 3 - -/* - * CPU and FPU types - */ - -#define CPUB_68020 0 -#define CPUB_68030 1 -#define CPUB_68040 2 -#define CPUB_68060 3 -#define FPUB_68881 5 -#define FPUB_68882 6 -#define FPUB_68040 7 /* Internal FPU */ -#define FPUB_68060 8 /* Internal FPU */ - -#define CPU_68020 (1<<CPUB_68020) -#define CPU_68030 (1<<CPUB_68030) -#define CPU_68040 (1<<CPUB_68040) -#define CPU_68060 (1<<CPUB_68060) -#define CPU_MASK (31) -#define FPU_68881 (1<<FPUB_68881) -#define FPU_68882 (1<<FPUB_68882) -#define FPU_68040 (1<<FPUB_68040) /* Internal FPU */ -#define FPU_68060 (1<<FPUB_68060) /* Internal FPU */ -#define FPU_MASK (0xfe0) - -#define CL_SIZE (256) - -/* - * machine type definitions - */ - -#if !defined(CONFIG_AMIGA) -# define MACH_IS_AMIGA (0) -#elif defined(CONFIG_ATARI) || defined(CONFIG_MAC) -# define MACH_IS_AMIGA (boot_info.machtype == MACH_AMIGA) -#else -# define CONFIG_AMIGA_ONLY -# define MACH_IS_AMIGA (1) -# define MACH_TYPE (MACH_AMIGA) -#endif - -#if !defined(CONFIG_ATARI) -# define MACH_IS_ATARI (0) -#elif defined(CONFIG_AMIGA) || defined(CONFIG_MAC) -# define MACH_IS_ATARI (boot_info.machtype == MACH_ATARI) -#else -# define CONFIG_ATARI_ONLY -# define MACH_IS_ATARI (1) -# define MACH_TYPE (MACH_ATARI) -#endif - -#if defined(CONFIG_MAC) -# error Currently no Mac support! -#endif - -#ifndef MACH_TYPE -# define MACH_TYPE (boot_info.machtype) -#endif - -/* - * cpu type definitions - */ - -#if !defined(CONFIG_M68020) -# define CPU_IS_020 (0) -#elif defined(CONFIG_M68030) || defined(CONFIG_M68040) || defined(CONFIG_M68060) -# define CPU_IS_020 (boot_info.cputype & CPU_68020) -#else -# define CONFIG_M68020_ONLY -# define CPU_IS_020 (1) -#endif - -#if !defined(CONFIG_M68030) -# define CPU_IS_030 (0) -#elif defined(CONFIG_M68020) || defined(CONFIG_M68040) || defined(CONFIG_M68060) -# define CPU_IS_030 (boot_info.cputype & CPU_68030) -#else -# define CONFIG_M68030_ONLY -# define CPU_IS_030 (1) -#endif - -#if !defined(CONFIG_M68040) -# define CPU_IS_040 (0) -#elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68060) -# define CPU_IS_040 (boot_info.cputype & CPU_68040) -#else -# define CONFIG_M68040_ONLY -# define CPU_IS_040 (1) -#endif - -#if !defined(CONFIG_M68060) -# define CPU_IS_060 (0) -#elif defined(CONFIG_M68020) || defined(CONFIG_M68030) || defined(CONFIG_M68040) -# define CPU_IS_060 (boot_info.cputype & CPU_68060) -#else -# define CONFIG_M68060_ONLY -# define CPU_IS_060 (1) -#endif - -#if !defined(CONFIG_M68020) && !defined(CONFIG_M68030) -# define CPU_IS_020_OR_030 (0) -#else -# define CONFIG_M68020_OR_M68030 -# if defined(CONFIG_M68040) || defined(CONFIG_M68060) -# define CPU_IS_020_OR_030 (!m68k_is040or060) -# else -# define CONFIG_M68020_OR_M68030_ONLY -# define CPU_IS_020_OR_030 (1) -# endif -#endif - -#if !defined(CONFIG_M68040) && !defined(CONFIG_M68060) -# define CPU_IS_040_OR_060 (0) -#else -# define CONFIG_M68040_OR_M68060 -# if defined(CONFIG_M68020) || defined(CONFIG_M68030) -# define CPU_IS_040_OR_060 (m68k_is040or060) -# else -# define CONFIG_M68040_OR_M68060_ONLY -# define CPU_IS_040_OR_060 (1) -# endif -#endif - -#define CPU_TYPE (boot_info.cputype) - -#ifndef __ASSEMBLY__ -#ifdef __KERNEL__ - /* - * m68k_is040or060 is != 0 for a '040 or higher; - * used numbers are 4 for 68040 and 6 for 68060. - */ - -extern int m68k_is040or060; -#endif - -struct bootinfo { - unsigned long machtype; /* machine type */ - unsigned long cputype; /* system CPU & FPU */ - struct mem_info memory[NUM_MEMINFO]; /* memory description */ - int num_memory; /* # of memory blocks found */ - unsigned long ramdisk_size; /* ramdisk size in 1024 byte blocks */ - unsigned long ramdisk_addr; /* address of the ram disk in mem */ - char command_line[CL_SIZE]; /* kernel command line parameters */ - union { - struct bi_Amiga bi_ami; /* Amiga specific information */ - struct bi_Atari bi_ata; /* Atari specific information */ - } bi_un; -}; -#define bi_amiga bi_un.bi_ami -#define bi_atari bi_un.bi_ata -#define bi_mac bi_un.bi_mac - -extern struct bootinfo - boot_info; - -#else /* __ASSEMBLY__ */ - -BI_machtype = 0 -BI_cputype = BI_machtype+4 -BI_memory = BI_cputype+4 -BI_num_memory = BI_memory+(MI_sizeof*NUM_MEMINFO) -BI_ramdisk_size = BI_num_memory+4 -BI_ramdisk_addr = BI_ramdisk_size+4 -BI_command_line = BI_ramdisk_addr+4 -BI_un = BI_command_line+CL_SIZE - -#endif /* __ASSEMBLY__ */ - - -/* - * Stuff for bootinfo interface versioning - * - * At the start of kernel code, a 'struct bootversion' is located. bootstrap - * checks for a matching version of the interface before booting a kernel, to - * avoid user confusion if kernel and bootstrap don't work together :-) - * - * If incompatible changes are made to the bootinfo interface, the major - * number below should be stepped (and the minor reset to 0) for the - * appropriate machine. If a change is backward-compatible, the minor should - * be stepped. "Backwards-compatible" means that booting will work, but - * certain features may not. - */ - -#define BOOTINFOV_MAGIC 0x4249561A /* 'BIV^Z' */ -#define MK_BI_VERSION(major,minor) (((major)<<16)+(minor)) -#define BI_VERSION_MAJOR(v) (((v) >> 16) & 0xffff) -#define BI_VERSION_MINOR(v) ((v) & 0xffff) - -#ifndef __ASSEMBLY__ - -struct bootversion { - unsigned short branch; - unsigned long magic; - struct { - unsigned long machtype; - unsigned long version; - } machversions[0]; -}; - -#endif /* __ASSEMBLY__ */ - -#define AMIGA_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) -#define ATARI_BOOTI_VERSION MK_BI_VERSION( 1, 0 ) - -#endif - - -#endif /* _M68K_SETUP_H */ diff --git a/include/asm-cris/signal.h b/include/asm-cris/signal.h index bd6f9484dbfc..1335bf27d8e2 100644 --- a/include/asm-cris/signal.h +++ b/include/asm-cris/signal.h @@ -85,13 +85,13 @@ typedef unsigned long sigset_t; * Unix names RESETHAND and NODEFER respectively. */ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 +#define SA_NOCLDSTOP 0x00000001u +#define SA_NOCLDWAIT 0x00000002u +#define SA_SIGINFO 0x00000004u +#define SA_ONSTACK 0x08000000u +#define SA_RESTART 0x10000000u +#define SA_NODEFER 0x40000000u +#define SA_RESETHAND 0x80000000u #define SA_NOMASK SA_NODEFER #define SA_ONESHOT SA_RESETHAND diff --git a/include/asm-cris/smp_lock.h b/include/asm-cris/smp_lock.h deleted file mode 100644 index 085543014cd5..000000000000 --- a/include/asm-cris/smp_lock.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef __CRIS_SMPLOCK_H -#define __CRIS_SMPLOCK_H - -#include <linux/config.h> - -#ifdef CONFIG_SMP - -#error "SMP is not supported for CRIS" - -/* - * Locking the kernel - */ - -extern __inline void lock_kernel(void) -{ - unsigned long flags; - int proc = smp_processor_id(); - - save_flags(flags); - cli(); - /* set_bit works atomic in SMP machines */ - while(set_bit(0, (void *)&kernel_flag)) - { - /* - * We just start another level if we have the lock - */ - if (proc == active_kernel_processor) - break; - do - { -#ifdef __SMP_PROF__ - smp_spins[smp_processor_id()]++; -#endif - /* - * Doing test_bit here doesn't lock the bus - */ - if (test_bit(proc, (void *)&smp_invalidate_needed)) - if (clear_bit(proc, (void *)&smp_invalidate_needed)) - local_flush_tlb(); - } - while(test_bit(0, (void *)&kernel_flag)); - } - /* - * We got the lock, so tell the world we are here and increment - * the level counter - */ - active_kernel_processor = proc; - kernel_counter++; - restore_flags(flags); -} - -extern __inline void unlock_kernel(void) -{ - unsigned long flags; - save_flags(flags); - cli(); - /* - * If it's the last level we have in the kernel, then - * free the lock - */ - if (kernel_counter == 0) - panic("Kernel counter wrong.\n"); /* FIXME: Why is kernel_counter sometimes 0 here? */ - - if(! --kernel_counter) - { - active_kernel_processor = NO_PROC_ID; - clear_bit(0, (void *)&kernel_flag); - } - restore_flags(flags); -} - -#endif -#endif diff --git a/include/asm-cris/sync_serial.h b/include/asm-cris/sync_serial.h deleted file mode 100644 index 423b46175e5d..000000000000 --- a/include/asm-cris/sync_serial.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ioctl defines for synchrnous serial port driver - * - * Copyright (c) 2001 Axis Communications AB - * - * Author: Mikael Starvik - * - */ - -#ifndef SYNC_SERIAL_H -#define SYNC_SERIAL_H - -#include <linux/ioctl.h> - -#define SSP_SPEED _IOR('S', 0, unsigned int) -#define SSP_MODE _IOR('S', 1, unsigned int) -#define SSP_FRAME_SYNC _IOR('S', 2, unsigned int) -#define SSP_IPOLARITY _IOR('S', 3, unsigned int) -#define SSP_OPOLARITY _IOR('S', 4, unsigned int) -#define SSP_SPI _IOR('S', 5, unsigned int) - -/* Values for SSP_SPEED */ -#define SSP150 0 -#define SSP300 1 -#define SSP600 2 -#define SSP1200 3 -#define SSP2400 4 -#define SSP4800 5 -#define SSP9600 6 -#define SSP19200 7 -#define SSP28800 8 -#define SSP57600 9 -#define SSP115200 10 -#define SSP230400 11 -#define SSP460800 12 -#define SSP921600 13 -#define SSP3125000 14 -#define CODEC 15 - -#define FREQ_4MHz 0 -#define FREQ_2MHz 1 -#define FREQ_1MHz 2 -#define FREQ_512kHz 3 -#define FREQ_256kHz 4 -#define FREQ_128kHz 5 -#define FREQ_64kHz 6 -#define FREQ_32kHz 7 - -/* Used by application to set CODEC divider, word rate and frame rate */ -#define CODEC_VAL(freq, word, frame) (CODEC | (freq << 8) | (word << 16) | (frame << 28)) - -/* Used by driver to extract speed */ -#define GET_SPEED(x) (x & 0xff) -#define GET_FREQ(x) ((x & 0xff00) >> 8) -#define GET_WORD_RATE(x) (((x & 0x0fff0000) >> 16) - 1) -#define GET_FRAME_RATE(x) (((x & 0xf0000000) >> 28) - 1) - -/* Values for SSP_MODE */ -#define MASTER_OUTPUT 0 -#define SLAVE_OUTPUT 1 -#define MASTER_INPUT 2 -#define SLAVE_INPUT 3 -#define MASTER_BIDIR 4 -#define SLAVE_BIDIR 5 - -/* Values for SSP_FRAME_SYNC */ -#define NORMAL_SYNC 1 -#define EARLY_SYNC 2 -#define BIT_SYNC 4 -#define WORD_SYNC 8 -#define EXTENDED_SYNC 0x10 -#define SYNC_OFF 0x20 -#define SYNC_ON 0x40 -#define WORD_SIZE_8 0x80 -#define WORD_SIZE_12 0x100 -#define WORD_SIZE_16 0x200 -#define WORD_SIZE_24 0x300 -#define WORD_SIZE_32 0x800 -#define BIT_ORDER_LSB 0x1000 -#define BIT_ORDER_MSB 0x2000 -#define FLOW_CONTROL_ENABLE 0x4000 -#define FLOW_CONTROL_DISABLE 0x8000 -#define CLOCK_GATED 0x10000 -#define CLOCK_NOT_GATED 0x20000 - -/* Values for SSP_IPOLARITY and SSP_OPOLARITY */ -#define CLOCK_NORMAL 1 -#define CLOCK_INVERT 2 -#define FRAME_NORMAL 4 -#define FRAME_INVERT 8 -#define STATUS_NORMAL 0x10 -#define STATUS_INVERT 0x20 - -/* Values for SSP_SPI */ -#define SPI_MASTER 0 -#define SPI_SLAVE 1 -#endif diff --git a/include/asm-cris/system.h b/include/asm-cris/system.h index 63d2dee8172e..f9cf80262574 100644 --- a/include/asm-cris/system.h +++ b/include/asm-cris/system.h @@ -1,9 +1,7 @@ #ifndef __ASM_CRIS_SYSTEM_H #define __ASM_CRIS_SYSTEM_H -#include <linux/config.h> - -#include <asm/segment.h> +#include <asm/arch/system.h> /* the switch_to macro calls resume, an asm function in entry.S which does the actual * task switching. @@ -14,117 +12,42 @@ extern struct task_struct *resume(struct task_struct *prev, struct task_struct * #define switch_to(prev,next,last) last = resume(prev,next, \ (int)&((struct task_struct *)0)->thread) -/* read the CPU version register */ - -static inline unsigned long rdvr(void) { - unsigned char vr; - __asm__ volatile ("move $vr,%0" : "=rm" (vr)); - return vr; -} - -/* read/write the user-mode stackpointer */ - -static inline unsigned long rdusp(void) { - unsigned long usp; - __asm__ __volatile__("move $usp,%0" : "=rm" (usp)); - return usp; -} - -#define wrusp(usp) \ - __asm__ __volatile__("move %0,$usp" : /* no outputs */ : "rm" (usp)) - -/* read the current stackpointer */ - -static inline unsigned long rdsp(void) { - unsigned long sp; - __asm__ __volatile__("move.d $sp,%0" : "=rm" (sp)); - return sp; -} - -static inline unsigned long _get_base(char * addr) -{ - return 0; -} - -#define nop() __asm__ __volatile__ ("nop"); - -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) -#define tas(ptr) (xchg((ptr),1)) - -struct __xchg_dummy { unsigned long a[100]; }; -#define __xg(x) ((struct __xchg_dummy *)(x)) +#define barrier() __asm__ __volatile__("": : :"memory") +#define mb() barrier() +#define rmb() mb() +#define wmb() mb() +#define read_barrier_depends() do { } while(0) +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) -#if 0 -/* use these and an oscilloscope to see the fraction of time we're running with IRQ's disabled */ -/* it assumes the LED's are on port 0x90000000 of course. */ -#define sti() __asm__ __volatile__ ( "ei\n\tpush $r0\n\tmoveq 0,$r0\n\tmove.d $r0,[0x90000000]\n\tpop $r0" ); -#define cli() __asm__ __volatile__ ( "di\n\tpush $r0\n\tmove.d 0x40000,$r0\n\tmove.d $r0,[0x90000000]\n\tpop $r0"); -#define save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); -#define restore_flags(x) __asm__ __volatile__ ("move %0,$ccr\n\tbtstq 5,%0\n\tbpl 1f\n\tnop\n\tpush $r0\n\tmoveq 0,$r0\n\tmove.d $r0,[0x90000000]\n\tpop $r0\n1:\n" : : "r" (x) : "memory"); +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_read_barrier_depends() read_barrier_depends() #else -#define local_irq_disable() __asm__ __volatile__ ( "di"); -#define local_irq_enable() __asm__ __volatile__ ( "ei" ); -#define local_save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); -#define local_irq_restore(x) __asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory"); - -/* For spinlocks etc */ -#define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); -#define local_irq_restore(x) restore_flags(x) - -#define local_irq_disable() cli() -#define local_irq_enable() sti() - +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while(0) #endif -#define cli() local_irq_disable() -#define sti() local_irq_enable() -#define save_flags(x) local_save_flags(x) -#define restore_flags(x) local_irq_restore(x) -#define save_and_cli(x) do { local_save_flags(x); cli(); } while(0) +#define iret() -static inline unsigned long __xchg(unsigned long x, void * ptr, int size) +/* + * disable hlt during certain critical i/o operations + */ +#define HAVE_DISABLE_HLT +void disable_hlt(void); +void enable_hlt(void); + +extern inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) { /* since Etrax doesn't have any atomic xchg instructions, we need to disable irq's (if enabled) and do it with move.d's */ -#if 0 - unsigned int flags; - save_flags(flags); /* save flags, including irq enable bit */ - cli(); /* shut off irq's */ - switch (size) { - case 1: - __asm__ __volatile__ ( - "move.b %0,r0\n\t" - "move.b %1,%0\n\t" - "move.b r0,%1\n\t" - : "=r" (x) - : "m" (*__xg(ptr)), "r" (x) - : "memory","r0"); - break; - case 2: - __asm__ __volatile__ ( - "move.w %0,r0\n\t" - "move.w %1,%0\n\t" - "move.w r0,%1\n\t" - : "=r" (x) - : "m" (*__xg(ptr)), "r" (x) - : "memory","r0"); - break; - case 4: - __asm__ __volatile__ ( - "move.d %0,r0\n\t" - "move.d %1,%0\n\t" - "move.d r0,%1\n\t" - : "=r" (x) - : "m" (*__xg(ptr)), "r" (x) - : "memory","r0"); - break; - } - restore_flags(flags); /* restore irq enable bit */ - return x; -#else unsigned long flags,temp; - save_flags(flags); /* save flags, including irq enable bit */ - cli(); /* shut off irq's */ + local_save_flags(flags); /* save flags, including irq enable bit */ + local_irq_disable(); /* shut off irq's */ switch (size) { case 1: *((unsigned char *)&temp) = x; @@ -142,37 +65,8 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) *(unsigned long *)ptr = temp; break; } - restore_flags(flags); /* restore irq enable bit */ + local_irq_restore(flags); /* restore irq enable bit */ return x; -#endif } -#define mb() __asm__ __volatile__ ("" : : : "memory") -#define rmb() mb() -#define wmb() mb() -#define read_barrier_depends() do { } while(0) -#define set_mb(var, value) do { var = value; mb(); } while (0) -#define set_wmb(var, value) do { var = value; wmb(); } while (0) - -#ifdef CONFIG_SMP -#define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() -#define smp_read_barrier_depends() read_barrier_depends() -#else -#define smp_mb() barrier() -#define smp_rmb() barrier() -#define smp_wmb() barrier() -#define smp_read_barrier_depends() do { } while(0) -#endif - -#define iret() - -/* - * disable hlt during certain critical i/o operations - */ -#define HAVE_DISABLE_HLT -void disable_hlt(void); -void enable_hlt(void); - #endif diff --git a/include/asm-cris/termbits.h b/include/asm-cris/termbits.h index cea712a634f1..4f35a7d95443 100644 --- a/include/asm-cris/termbits.h +++ b/include/asm-cris/termbits.h @@ -88,6 +88,30 @@ struct termios { #define FF1 0100000 /* c_cflag bit meaning */ +/* + * 3 2 1 + * 10 987 654 321 098 765 432 109 876 543 210 + * | | ||| CBAUD + * obaud + * + * ||CSIZE + * + * |CSTOP + * |CREAD + * |CPARENB + * + * |CPARODD + * |HUPCL + * |CLOCAL + * |CBAUDEX + * 10 987 654 321 098 765 432 109 876 543 210 + * | || || CIBAUD, IBSHIFT=16 + * ibaud + * |CMSPAR + * | CRTSCTS + * x x xxx xxx x x xx Free bits + */ + #define CBAUD 0010017 #define B0 0000000 /* hang up */ #define B50 0000001 @@ -123,11 +147,18 @@ struct termios { #define B115200 0010002 #define B230400 0010003 #define B460800 0010004 -/* etrax100 supports these additional three baud rates */ -#define B921600 0010005 -#define B1843200 0010006 -#define B6250000 0010007 -#define CIBAUD 002003600000 /* input baud rate (not used) */ +/* etrax supports these additional three baud rates */ +#define B921600 0010005 +#define B1843200 0010006 +#define B6250000 0010007 +/* etrax 200 supports this as well */ +#define B12500000 0010010 +#define CIBAUD 002003600000 /* input baud rate */ +/* The values for CIBAUD bits are the same as the values for CBAUD and CBAUDEX + * shifted left IBSHIFT bits. + */ +#define IBSHIFT 16 +#define CMSPAR 010000000000 /* mark or space (stick) parity - PARODD=space*/ #define CRTSCTS 020000000000 /* flow control */ /* c_lflag bits */ diff --git a/include/asm-cris/termios.h b/include/asm-cris/termios.h index cc60e3781b00..5ce1023c5d7b 100644 --- a/include/asm-cris/termios.h +++ b/include/asm-cris/termios.h @@ -3,6 +3,7 @@ #include <asm/termbits.h> #include <asm/ioctls.h> +#include <asm/rs485.h> struct winsize { unsigned short ws_row; diff --git a/include/asm-cris/thread_info.h b/include/asm-cris/thread_info.h new file mode 100644 index 000000000000..f191637ac9ec --- /dev/null +++ b/include/asm-cris/thread_info.h @@ -0,0 +1,100 @@ +/* thread_info.h: CRIS low-level thread information + * + * Copyright (C) 2002 David Howells (dhowells@redhat.com) + * - Incorporating suggestions made by Linus Torvalds and Dave Miller + * + * CRIS port by Axis Communications + */ + +#ifndef _ASM_THREAD_INFO_H +#define _ASM_THREAD_INFO_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ +#include <asm/types.h> +#include <asm/processor.h> +#include <asm/arch/thread_info.h> +#include <asm/segment.h> +#endif + + +/* + * low level task data that entry.S needs immediate access to + * - this struct should fit entirely inside of one cache line + * - this struct shares the supervisor stack pages + * - if the contents of this structure are changed, the assembly constants must also be changed + */ +#ifndef __ASSEMBLY__ +struct thread_info { + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + unsigned long flags; /* low level flags */ + __u32 cpu; /* current CPU */ + __s32 preempt_count; /* 0 => preemptable, <0 => BUG */ + + mm_segment_t addr_limit; /* thread address space: + 0-0xBFFFFFFF for user-thead + 0-0xFFFFFFFF for kernel-thread + */ + struct restart_block restart_block; + __u8 supervisor_stack[0]; +}; + +#endif + +#define PREEMPT_ACTIVE 0x4000000 + +/* + * macros/functions for gaining access to the thread information structure + * + * preempt_count needs to be 1 initially, until the scheduler is functional. + */ +#ifndef __ASSEMBLY__ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .exec_domain = &default_exec_domain, \ + .flags = 0, \ + .cpu = 0, \ + .preempt_count = 1, \ + .addr_limit = KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) + +/* thread information allocation */ +#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) +#define free_thread_info(ti) free_pages((unsigned long) (ti), 1) +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) + +#endif /* !__ASSEMBLY__ */ + +/* + * thread information flags + * - these are process state flags that various assembly files may need to access + * - pending work-to-be-done flags are in LSW + * - other flags in MSW + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */ +#define TIF_SIGPENDING 2 /* signal pending */ +#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ +#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ + +#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) +#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) +#define _TIF_SIGPENDING (1<<TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) +#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) + +#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */ +#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */ + +#endif /* __KERNEL__ */ + +#endif /* _ASM_THREAD_INFO_H */ diff --git a/include/asm-cris/timex.h b/include/asm-cris/timex.h index 5bf3edbd6698..375c41af47de 100644 --- a/include/asm-cris/timex.h +++ b/include/asm-cris/timex.h @@ -3,23 +3,11 @@ * * CRIS architecture timex specifications */ + #ifndef _ASM_CRIS_TIMEX_H #define _ASM_CRIS_TIMEX_H -#define CLOCK_TICK_RATE 19200 /* Underlying frequency of the HZ timer */ - -/* The timer0 values gives ~52.1us resolution (1/19200) but interrupts at HZ*/ -#define TIMER0_FREQ (CLOCK_TICK_RATE) -#define TIMER0_CLKSEL c19k2Hz -#define TIMER0_DIV (TIMER0_FREQ/(HZ)) -/* This is the slow one: */ -/* -#define GET_JIFFIES_USEC() \ - ( (*R_TIMER0_DATA - TIMER0_DIV) * (1000000/HZ)/TIMER0_DIV ) -*/ -/* This is the fast version: */ -extern unsigned short cris_timer0_value_us[TIMER0_DIV+1]; /* in kernel/time.c */ -#define GET_JIFFIES_USEC() (cris_timer0_value_us[*R_TIMER0_DATA]) +#include <asm/arch/timex.h> /* * We don't have a cycle-counter.. but we do not support SMP anyway where this is @@ -28,7 +16,7 @@ extern unsigned short cris_timer0_value_us[TIMER0_DIV+1]; /* in kernel/time.c */ typedef unsigned int cycles_t; -static inline cycles_t get_cycles(void) +extern inline cycles_t get_cycles(void) { return 0; } diff --git a/include/asm-cris/tlb.h b/include/asm-cris/tlb.h index 69c0faa93194..6cc26debe40f 100644 --- a/include/asm-cris/tlb.h +++ b/include/asm-cris/tlb.h @@ -1 +1,17 @@ +#ifndef _CRIS_TLB_H +#define _CRIS_TLB_H + +#include <asm/arch/tlb.h> + +/* + * cris doesn't need any special per-pte or + * per-vma handling.. + */ +#define tlb_start_vma(tlb, vma) do { } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) + +#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) #include <asm-generic/tlb.h> + +#endif diff --git a/include/asm-cris/tlbflush.h b/include/asm-cris/tlbflush.h new file mode 100644 index 000000000000..1781fe1a32f6 --- /dev/null +++ b/include/asm-cris/tlbflush.h @@ -0,0 +1,43 @@ +#ifndef _CRIS_TLBFLUSH_H +#define _CRIS_TLBFLUSH_H + +#include <linux/config.h> +#include <linux/mm.h> +#include <asm/processor.h> +#include <asm/pgtable.h> +#include <asm/pgalloc.h> + +/* + * TLB flushing (implemented in arch/cris/mm/tlb.c): + * + * - flush_tlb() flushes the current mm struct TLBs + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(mm, start, end) flushes a range of pages + * + */ + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_page(struct vm_area_struct *vma, + unsigned long addr); +extern void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, + unsigned long end); + +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) +{ + /* CRIS does not keep any page table caches in TLB */ +} + + +extern inline void flush_tlb(void) +{ + flush_tlb_mm(current->mm); +} + +#define flush_tlb_kernel_range(start, end) flush_tlb_all() + +#endif /* _CRIS_TLBFLUSH_H */ diff --git a/include/asm-cris/uaccess.h b/include/asm-cris/uaccess.h index 41d66748c16b..7532cd76d0af 100644 --- a/include/asm-cris/uaccess.h +++ b/include/asm-cris/uaccess.h @@ -81,8 +81,8 @@ #define USER_DS MAKE_MM_SEG(TASK_SIZE) #define get_ds() (KERNEL_DS) -#define get_fs() (current->addr_limit) -#define set_fs(x) (current->addr_limit = (x)) +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit = (x)) #define segment_eq(a,b) ((a).seg == (b).seg) @@ -91,12 +91,14 @@ #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size))) #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) -extern inline int verify_area(int type, const void * addr, unsigned long size) +extern inline int verify_area(int type, const void __user * addr, unsigned long size) { return access_ok(type,addr,size) ? 0 : -EFAULT; } +#include <asm/arch/uaccess.h> + /* * The exception table consists of pairs of addresses: the first is the * address of an instruction that is allowed to fault, and the second is @@ -115,10 +117,6 @@ struct exception_table_entry unsigned long insn, fixup; }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); - - /* * These are the main single-value transfer routines. They automatically * use the right size if we just have the right pointer type. @@ -149,6 +147,30 @@ extern unsigned long search_exception_table(unsigned long); extern long __put_user_bad(void); +#define __put_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __put_user_asm(x,ptr,retval,"move.b"); break; \ + case 2: __put_user_asm(x,ptr,retval,"move.w"); break; \ + case 4: __put_user_asm(x,ptr,retval,"move.d"); break; \ + case 8: __put_user_asm_64(x,ptr,retval); break; \ + default: __put_user_bad(); \ + } \ +} while (0) + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: __get_user_asm(x,ptr,retval,"move.b"); break; \ + case 2: __get_user_asm(x,ptr,retval,"move.w"); break; \ + case 4: __get_user_asm(x,ptr,retval,"move.d"); break; \ + case 8: __get_user_asm_64(x,ptr,retval); break; \ + default: (x) = __get_user_bad(); \ + } \ +} while (0) + #define __put_user_nocheck(x,ptr,size) \ ({ \ long __pu_err; \ @@ -165,58 +187,9 @@ extern long __put_user_bad(void); __pu_err; \ }) -#define __put_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __put_user_asm(x,ptr,retval,"move.b"); break; \ - case 2: __put_user_asm(x,ptr,retval,"move.w"); break; \ - case 4: __put_user_asm(x,ptr,retval,"move.d"); break; \ - case 8: __put_user_asm_64(x,ptr,retval); break; \ - default: __put_user_bad(); \ - } \ -} while (0) - struct __large_struct { unsigned long buf[100]; }; #define __m(x) (*(struct __large_struct *)(x)) -/* - * We don't tell gcc that we are accessing memory, but this is OK - * because we do not write to any memory gcc knows about, so there - * are no aliasing issues. - * - * Note that PC at a fault is the address *after* the faulting - * instruction. - */ -#define __put_user_asm(x, addr, err, op) \ - __asm__ __volatile__( \ - " "op" %1,[%2]\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " jump 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .previous\n" \ - : "=r" (err) \ - : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) - -#define __put_user_asm_64(x, addr, err) \ - __asm__ __volatile__( \ - " move.d %M1,[%2]\n" \ - "2: move.d %H1,[%2+4]\n" \ - "4:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " jump 4b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .dword 4b,3b\n" \ - " .previous\n" \ - : "=r" (err) \ - : "r" (x), "r" (addr), "g" (-EFAULT), "0" (err)) #define __get_user_nocheck(x,ptr,size) \ @@ -239,52 +212,6 @@ struct __large_struct { unsigned long buf[100]; }; extern long __get_user_bad(void); -#define __get_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __get_user_asm(x,ptr,retval,"move.b"); break; \ - case 2: __get_user_asm(x,ptr,retval,"move.w"); break; \ - case 4: __get_user_asm(x,ptr,retval,"move.d"); break; \ - case 8: __get_user_asm_64(x,ptr,retval); break; \ - default: (x) = __get_user_bad(); \ - } \ -} while (0) - -/* See comment before __put_user_asm. */ - -#define __get_user_asm(x, addr, err, op) \ - __asm__ __volatile__( \ - " "op" [%2],%1\n" \ - "2:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " moveq 0,%1\n" \ - " jump 2b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .previous\n" \ - : "=r" (err), "=r" (x) \ - : "r" (addr), "g" (-EFAULT), "0" (err)) - -#define __get_user_asm_64(x, addr, err) \ - __asm__ __volatile__( \ - " move.d [%2],%M1\n" \ - "2: move.d [%2+4],%H1\n" \ - "4:\n" \ - " .section .fixup,\"ax\"\n" \ - "3: move.d %3,%0\n" \ - " moveq 0,%1\n" \ - " jump 4b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - " .dword 2b,3b\n" \ - " .dword 4b,3b\n" \ - " .previous\n" \ - : "=r" (err), "=r" (x) \ - : "r" (addr), "g" (-EFAULT), "0" (err)) - /* More complex functions. Most are inline, but some call functions that live in lib/usercopy.c */ @@ -292,108 +219,38 @@ extern unsigned long __copy_user(void *to, const void *from, unsigned long n); extern unsigned long __copy_user_zeroing(void *to, const void *from, unsigned long n); extern unsigned long __do_clear_user(void *to, unsigned long n); -/* - * Copy a null terminated string from userspace. - * - * Must return: - * -EFAULT for an exception - * count if we hit the buffer limit - * bytes copied if we hit a null byte - * (without the null byte) - */ - -static inline long -__do_strncpy_from_user(char *dst, const char *src, long count) -{ - long res; - - if (count == 0) - return 0; - - /* - * Currently, in 2.4.0-test9, most ports use a simple byte-copy loop. - * So do we. - * - * This code is deduced from: - * - * char tmp2; - * long tmp1, tmp3 - * tmp1 = count; - * while ((*dst++ = (tmp2 = *src++)) != 0 - * && --tmp1) - * ; - * - * res = count - tmp1; - * - * with tweaks. - */ - - __asm__ __volatile__ ( - " move.d %3,%0\n" - " move.b [%2+],$r9\n" - "1: beq 2f\n" - " move.b $r9,[%1+]\n" - - " subq 1,%0\n" - " bne 1b\n" - " move.b [%2+],$r9\n" - - "2: sub.d %3,%0\n" - " neg.d %0,%0\n" - "3:\n" - " .section .fixup,\"ax\"\n" - "4: move.d %7,%0\n" - " jump 3b\n" - - /* There's one address for a fault at the first move, and - two possible PC values for a fault at the second move, - being a delay-slot filler. However, the branch-target - for the second move is the same as the first address. - Just so you don't get confused... */ - " .previous\n" - " .section __ex_table,\"a\"\n" - " .dword 1b,4b\n" - " .dword 2b,4b\n" - " .previous" - : "=r" (res), "=r" (dst), "=r" (src), "=r" (count) - : "3" (count), "1" (dst), "2" (src), "g" (-EFAULT) - : "r9"); - - return res; -} - -static inline unsigned long -__generic_copy_to_user(void *to, const void *from, unsigned long n) +extern inline unsigned long +__generic_copy_to_user(void __user *to, const void *from, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) return __copy_user(to,from,n); return n; } -static inline unsigned long -__generic_copy_from_user(void *to, const void *from, unsigned long n) +extern inline unsigned long +__generic_copy_from_user(void *to, const void __user *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n)) return __copy_user_zeroing(to,from,n); return n; } -static inline unsigned long -__generic_clear_user(void *to, unsigned long n) +extern inline unsigned long +__generic_clear_user(void __user *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) return __do_clear_user(to,n); return n; } -static inline long -__strncpy_from_user(char *dst, const char *src, long count) +extern inline long +__strncpy_from_user(char *dst, const char __user *src, long count) { return __do_strncpy_from_user(dst, src, count); } -static inline long -strncpy_from_user(char *dst, const char *src, long count) +extern inline long +strncpy_from_user(char *dst, const char __user *src, long count) { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) @@ -401,459 +258,12 @@ strncpy_from_user(char *dst, const char *src, long count) return res; } -/* A few copy asms to build up the more complex ones from. - - Note again, a post-increment is performed regardless of whether a bus - fault occurred in that instruction, and PC for a faulted insn is the - address *after* the insn. */ - -#define __asm_copy_user_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm__ __volatile__ ( \ - COPY \ - "1:\n" \ - " .section .fixup,\"ax\"\n" \ - FIXUP \ - " jump 1b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - TENTRY \ - " .previous\n" \ - : "=r" (to), "=r" (from), "=r" (ret) \ - : "0" (to), "1" (from), "2" (ret) \ - : "r9", "memory") - -#define __asm_copy_from_user_1(to, from, ret) \ - __asm_copy_user_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "2: move.b $r9,[%0+]\n", \ - "3: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 2b,3b\n") - -#define __asm_copy_from_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "2: move.w $r9,[%0+]\n" COPY, \ - "3: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_from_user_2(to, from, ret) \ - __asm_copy_from_user_2x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_3(to, from, ret) \ - __asm_copy_from_user_2x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "4: move.b $r9,[%0+]\n", \ - "5: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_from_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "2: move.d $r9,[%0+]\n" COPY, \ - "3: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_from_user_4(to, from, ret) \ - __asm_copy_from_user_4x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_5(to, from, ret) \ - __asm_copy_from_user_4x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "4: move.b $r9,[%0+]\n", \ - "5: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_from_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_4x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "4: move.w $r9,[%0+]\n" COPY, \ - "5: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_from_user_6(to, from, ret) \ - __asm_copy_from_user_6x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_7(to, from, ret) \ - __asm_copy_from_user_6x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "6: move.b $r9,[%0+]\n", \ - "7: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_from_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_4x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "4: move.d $r9,[%0+]\n" COPY, \ - "5: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_from_user_8(to, from, ret) \ - __asm_copy_from_user_8x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_9(to, from, ret) \ - __asm_copy_from_user_8x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "6: move.b $r9,[%0+]\n", \ - "7: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_from_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_8x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "6: move.w $r9,[%0+]\n" COPY, \ - "7: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_from_user_10(to, from, ret) \ - __asm_copy_from_user_10x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_11(to, from, ret) \ - __asm_copy_from_user_10x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "8: move.b $r9,[%0+]\n", \ - "9: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_from_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_8x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "6: move.d $r9,[%0+]\n" COPY, \ - "7: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_from_user_12(to, from, ret) \ - __asm_copy_from_user_12x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_13(to, from, ret) \ - __asm_copy_from_user_12x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "8: move.b $r9,[%0+]\n", \ - "9: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_from_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_12x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - "8: move.w $r9,[%0+]\n" COPY, \ - "9: addq 2,%2\n" \ - " clear.w [%0+]\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_from_user_14(to, from, ret) \ - __asm_copy_from_user_14x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_15(to, from, ret) \ - __asm_copy_from_user_14x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - "10: move.b $r9,[%0+]\n", \ - "11: addq 1,%2\n" \ - " clear.b [%0+]\n", \ - " .dword 10b,11b\n") - -#define __asm_copy_from_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_12x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "8: move.d $r9,[%0+]\n" COPY, \ - "9: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_from_user_16(to, from, ret) \ - __asm_copy_from_user_16x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_16x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "10: move.d $r9,[%0+]\n" COPY, \ - "11: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 10b,11b\n" TENTRY) - -#define __asm_copy_from_user_20(to, from, ret) \ - __asm_copy_from_user_20x_cont(to, from, ret, "", "", "") - -#define __asm_copy_from_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_from_user_20x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - "12: move.d $r9,[%0+]\n" COPY, \ - "13: addq 4,%2\n" \ - " clear.d [%0+]\n" FIXUP, \ - " .dword 12b,13b\n" TENTRY) - -#define __asm_copy_from_user_24(to, from, ret) \ - __asm_copy_from_user_24x_cont(to, from, ret, "", "", "") - -/* And now, the to-user ones. */ - -#define __asm_copy_to_user_1(to, from, ret) \ - __asm_copy_user_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n2:\n", \ - "3: addq 1,%2\n", \ - " .dword 2b,3b\n") - -#define __asm_copy_to_user_2x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n2:\n" COPY, \ - "3: addq 2,%2\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_to_user_2(to, from, ret) \ - __asm_copy_to_user_2x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_3(to, from, ret) \ - __asm_copy_to_user_2x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n4:\n", \ - "5: addq 1,%2\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_to_user_4x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_user_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n2:\n" COPY, \ - "3: addq 4,%2\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_copy_to_user_4(to, from, ret) \ - __asm_copy_to_user_4x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_5(to, from, ret) \ - __asm_copy_to_user_4x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n4:\n", \ - "5: addq 1,%2\n", \ - " .dword 4b,5b\n") - -#define __asm_copy_to_user_6x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_4x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n4:\n" COPY, \ - "5: addq 2,%2\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_to_user_6(to, from, ret) \ - __asm_copy_to_user_6x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_7(to, from, ret) \ - __asm_copy_to_user_6x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n6:\n", \ - "7: addq 1,%2\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_to_user_8x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_4x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n4:\n" COPY, \ - "5: addq 4,%2\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_copy_to_user_8(to, from, ret) \ - __asm_copy_to_user_8x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_9(to, from, ret) \ - __asm_copy_to_user_8x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n6:\n", \ - "7: addq 1,%2\n", \ - " .dword 6b,7b\n") - -#define __asm_copy_to_user_10x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_8x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n6:\n" COPY, \ - "7: addq 2,%2\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_to_user_10(to, from, ret) \ - __asm_copy_to_user_10x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_11(to, from, ret) \ - __asm_copy_to_user_10x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n8:\n", \ - "9: addq 1,%2\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_to_user_12x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_8x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n6:\n" COPY, \ - "7: addq 4,%2\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_copy_to_user_12(to, from, ret) \ - __asm_copy_to_user_12x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_13(to, from, ret) \ - __asm_copy_to_user_12x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n8:\n", \ - "9: addq 1,%2\n", \ - " .dword 8b,9b\n") - -#define __asm_copy_to_user_14x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_12x_cont(to, from, ret, \ - " move.w [%1+],$r9\n" \ - " move.w $r9,[%0+]\n8:\n" COPY, \ - "9: addq 2,%2\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_to_user_14(to, from, ret) \ - __asm_copy_to_user_14x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_15(to, from, ret) \ - __asm_copy_to_user_14x_cont(to, from, ret, \ - " move.b [%1+],$r9\n" \ - " move.b $r9,[%0+]\n10:\n", \ - "11: addq 1,%2\n", \ - " .dword 10b,11b\n") - -#define __asm_copy_to_user_16x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_12x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n8:\n" COPY, \ - "9: addq 4,%2\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_copy_to_user_16(to, from, ret) \ - __asm_copy_to_user_16x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_20x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_16x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n10:\n" COPY, \ - "11: addq 4,%2\n" FIXUP, \ - " .dword 10b,11b\n" TENTRY) - -#define __asm_copy_to_user_20(to, from, ret) \ - __asm_copy_to_user_20x_cont(to, from, ret, "", "", "") - -#define __asm_copy_to_user_24x_cont(to, from, ret, COPY, FIXUP, TENTRY) \ - __asm_copy_to_user_20x_cont(to, from, ret, \ - " move.d [%1+],$r9\n" \ - " move.d $r9,[%0+]\n12:\n" COPY, \ - "13: addq 4,%2\n" FIXUP, \ - " .dword 12b,13b\n" TENTRY) - -#define __asm_copy_to_user_24(to, from, ret) \ - __asm_copy_to_user_24x_cont(to, from, ret, "", "", "") - -/* Define a few clearing asms with exception handlers. */ - -/* This frame-asm is like the __asm_copy_user_cont one, but has one less - input. */ - -#define __asm_clear(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm__ __volatile__ ( \ - CLEAR \ - "1:\n" \ - " .section .fixup,\"ax\"\n" \ - FIXUP \ - " jump 1b\n" \ - " .previous\n" \ - " .section __ex_table,\"a\"\n" \ - TENTRY \ - " .previous" \ - : "=r" (to), "=r" (ret) \ - : "0" (to), "1" (ret) \ - : "r9", "memory") - -#define __asm_clear_1(to, ret) \ - __asm_clear(to, ret, \ - " clear.b [%0+]\n2:\n", \ - "3: addq 1,%1\n", \ - " .dword 2b,3b\n") - -#define __asm_clear_2(to, ret) \ - __asm_clear(to, ret, \ - " clear.w [%0+]\n2:\n", \ - "3: addq 2,%1\n", \ - " .dword 2b,3b\n") - -#define __asm_clear_3(to, ret) \ - __asm_clear(to, ret, \ - " clear.w [%0+]\n" \ - "2: clear.b [%0+]\n3:\n", \ - "4: addq 2,%1\n" \ - "5: addq 1,%1\n", \ - " .dword 2b,4b\n" \ - " .dword 3b,5b\n") - -#define __asm_clear_4x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear(to, ret, \ - " clear.d [%0+]\n2:\n" CLEAR, \ - "3: addq 4,%1\n" FIXUP, \ - " .dword 2b,3b\n" TENTRY) - -#define __asm_clear_4(to, ret) \ - __asm_clear_4x_cont(to, ret, "", "", "") - -#define __asm_clear_8x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_4x_cont(to, ret, \ - " clear.d [%0+]\n4:\n" CLEAR, \ - "5: addq 4,%1\n" FIXUP, \ - " .dword 4b,5b\n" TENTRY) - -#define __asm_clear_8(to, ret) \ - __asm_clear_8x_cont(to, ret, "", "", "") - -#define __asm_clear_12x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_8x_cont(to, ret, \ - " clear.d [%0+]\n6:\n" CLEAR, \ - "7: addq 4,%1\n" FIXUP, \ - " .dword 6b,7b\n" TENTRY) - -#define __asm_clear_12(to, ret) \ - __asm_clear_12x_cont(to, ret, "", "", "") - -#define __asm_clear_16x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_12x_cont(to, ret, \ - " clear.d [%0+]\n8:\n" CLEAR, \ - "9: addq 4,%1\n" FIXUP, \ - " .dword 8b,9b\n" TENTRY) - -#define __asm_clear_16(to, ret) \ - __asm_clear_16x_cont(to, ret, "", "", "") - -#define __asm_clear_20x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_16x_cont(to, ret, \ - " clear.d [%0+]\n10:\n" CLEAR, \ - "11: addq 4,%1\n" FIXUP, \ - " .dword 10b,11b\n" TENTRY) - -#define __asm_clear_20(to, ret) \ - __asm_clear_20x_cont(to, ret, "", "", "") - -#define __asm_clear_24x_cont(to, ret, CLEAR, FIXUP, TENTRY) \ - __asm_clear_20x_cont(to, ret, \ - " clear.d [%0+]\n12:\n" CLEAR, \ - "13: addq 4,%1\n" FIXUP, \ - " .dword 12b,13b\n" TENTRY) - -#define __asm_clear_24(to, ret) \ - __asm_clear_24x_cont(to, ret, "", "", "") /* Note that if these expand awfully if made into switch constructs, so don't do that. */ -static inline unsigned long -__constant_copy_from_user(void *to, const void *from, unsigned long n) +extern inline unsigned long +__constant_copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned long ret = 0; if (n == 0) @@ -902,8 +312,8 @@ __constant_copy_from_user(void *to, const void *from, unsigned long n) /* Ditto, don't make a switch out of this. */ -static inline unsigned long -__constant_copy_to_user(void *to, const void *from, unsigned long n) +extern inline unsigned long +__constant_copy_to_user(void __user *to, const void *from, unsigned long n) { unsigned long ret = 0; if (n == 0) @@ -952,8 +362,8 @@ __constant_copy_to_user(void *to, const void *from, unsigned long n) /* No switch, please. */ -static inline unsigned long -__constant_clear_user(void *to, unsigned long n) +extern inline unsigned long +__constant_clear_user(void __user *to, unsigned long n) { unsigned long ret = 0; if (n == 0) @@ -1002,19 +412,19 @@ __constant_clear_user(void *to, unsigned long n) * used in fast paths and have only a small space overhead. */ -static inline unsigned long +extern inline unsigned long __generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) { return __copy_user_zeroing(to,from,n); } -static inline unsigned long +extern inline unsigned long __generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) { return __copy_user(to,from,n); } -static inline unsigned long +extern inline unsigned long __generic_clear_user_nocheck(void *to, unsigned long n) { return __do_clear_user(to,n); @@ -1026,68 +436,6 @@ __generic_clear_user_nocheck(void *to, unsigned long n) #define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n)) #define __clear_user(to,n) __generic_clear_user_nocheck((to),(n)) -/* - * Return the size of a string (including the ending 0) - * - * Return length of string in userspace including terminating 0 - * or 0 for error. Return a value greater than N if too long. - */ - -static inline long -strnlen_user(const char *s, long n) -{ - long res, tmp1; - - if (!access_ok(VERIFY_READ, s, 0)) - return 0; - - /* - * This code is deduced from: - * - * tmp1 = n; - * while (tmp1-- > 0 && *s++) - * ; - * - * res = n - tmp1; - * - * (with tweaks). - */ - - __asm__ __volatile__ ( - " move.d %1,$r9\n" - "0:\n" - " ble 1f\n" - " subq 1,$r9\n" - - " test.b [%0+]\n" - " bne 0b\n" - " test.d $r9\n" - "1:\n" - " move.d %1,%0\n" - " sub.d $r9,%0\n" - "2:\n" - " .section .fixup,\"ax\"\n" - - "3: clear.d %0\n" - " jump 2b\n" - - /* There's one address for a fault at the first move, and - two possible PC values for a fault at the second move, - being a delay-slot filler. However, the branch-target - for the second move is the same as the first address. - Just so you don't get confused... */ - " .previous\n" - " .section __ex_table,\"a\"\n" - " .dword 0b,3b\n" - " .dword 1b,3b\n" - " .previous\n" - : "=r" (res), "=r" (tmp1) - : "0" (s), "1" (n) - : "r9"); - - return res; -} - #define strlen_user(str) strnlen_user((str), 0x7ffffffe) #endif /* __ASSEMBLY__ */ diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h index b06623932f47..4911fee80489 100644 --- a/include/asm-cris/unistd.h +++ b/include/asm-cris/unistd.h @@ -1,11 +1,13 @@ #ifndef _ASM_CRIS_UNISTD_H_ #define _ASM_CRIS_UNISTD_H_ +#include <asm/arch/unistd.h> + /* * This file contains the system call numbers, and stub macros for libc. */ -#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_restart_syscall 0 #define __NR_exit 1 #define __NR_fork 2 #define __NR_read 3 @@ -230,125 +232,54 @@ /* 223 is unused */ #define __NR_gettid 224 #define __NR_readahead 225 -#define __NR_tkill 226 - -/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ -#define _syscall0(type,name) \ -type name(void) \ -{ \ - register long __a __asm__ ("r10"); \ - __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ - : "=r" (__a) \ - : "g" (__NR_##name) \ - : "r10", "r9"); \ - if(__a >= 0) \ - return (type) __a; \ - errno = -__a; \ - return (type) -1; \ -} - -#define _syscall1(type,name,type1,arg1) \ -type name(type1 arg1) \ -{ \ - register long __a __asm__ ("r10") = (long) arg1; \ - __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ - : "=r" (__a) \ - : "g" (__NR_##name), "0" (__a) \ - : "r10", "r9"); \ - if(__a >= 0) \ - return (type) __a; \ - errno = -__a; \ - return (type) -1; \ -} +#define __NR_setxattr 226 +#define __NR_lsetxattr 227 +#define __NR_fsetxattr 228 +#define __NR_getxattr 229 +#define __NR_lgetxattr 230 +#define __NR_fgetxattr 231 +#define __NR_listxattr 232 +#define __NR_llistxattr 233 +#define __NR_flistxattr 234 +#define __NR_removexattr 235 +#define __NR_lremovexattr 236 +#define __NR_fremovexattr 237 +#define __NR_tkill 238 +#define __NR_sendfile64 239 +#define __NR_futex 240 +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#define __NR_set_thread_area 243 +#define __NR_get_thread_area 244 +#define __NR_io_setup 245 +#define __NR_io_destroy 246 +#define __NR_io_getevents 247 +#define __NR_io_submit 248 +#define __NR_io_cancel 249 +#define __NR_fadvise64 250 +#define __NR_exit_group 252 +#define __NR_lookup_dcookie 253 +#define __NR_epoll_create 254 +#define __NR_epoll_ctl 255 +#define __NR_epoll_wait 256 +#define __NR_remap_file_pages 257 +#define __NR_set_tid_address 258 +#define __NR_timer_create 259 +#define __NR_timer_settime (__NR_timer_create+1) +#define __NR_timer_gettime (__NR_timer_create+2) +#define __NR_timer_getoverrun (__NR_timer_create+3) +#define __NR_timer_delete (__NR_timer_create+4) +#define __NR_clock_settime (__NR_timer_create+5) +#define __NR_clock_gettime (__NR_timer_create+6) +#define __NR_clock_getres (__NR_timer_create+7) +#define __NR_clock_nanosleep (__NR_timer_create+8) +#define __NR_statfs64 268 +#define __NR_fstatfs64 269 + +#define NR_syscalls 270 -#define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name(type1 arg1,type2 arg2) \ -{ \ - register long __a __asm__ ("r10") = (long) arg1; \ - register long __b __asm__ ("r11") = (long) arg2; \ - __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ - : "=r" (__a) \ - : "g" (__NR_##name), "0" (__a), "r" (__b) \ - : "r10", "r9"); \ - if(__a >= 0) \ - return (type) __a; \ - errno = -__a; \ - return (type) -1; \ -} -#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1,type2 arg2,type3 arg3) \ -{ \ - register long __a __asm__ ("r10") = (long) arg1; \ - register long __b __asm__ ("r11") = (long) arg2; \ - register long __c __asm__ ("r12") = (long) arg3; \ - __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ - : "=r" (__a) \ - : "g" (__NR_##name), "0" (__a), "r" (__b), "r" (__c) \ - : "r10", "r9"); \ - if(__a >= 0) \ - return (type) __a; \ - errno = -__a; \ - return (type) -1; \ -} -#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ -{ \ - register long __a __asm__ ("r10") = (long) arg1; \ - register long __b __asm__ ("r11") = (long) arg2; \ - register long __c __asm__ ("r12") = (long) arg3; \ - register long __d __asm__ ("r13") = (long) arg4; \ - __asm__ __volatile__ ("movu.w %1,$r9\n\tbreak 13" \ - : "=r" (__a) \ - : "g" (__NR_##name), "0" (__a), "r" (__b), \ - "r" (__c), "r" (__d) \ - : "r10", "r9"); \ - if(__a >= 0) \ - return (type) __a; \ - errno = -__a; \ - return (type) -1; \ -} - -#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ - type5,arg5) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ -{ \ - register long __a __asm__ ("r10") = (long) arg1; \ - register long __b __asm__ ("r11") = (long) arg2; \ - register long __c __asm__ ("r12") = (long) arg3; \ - register long __d __asm__ ("r13") = (long) arg4; \ - __asm__ __volatile__ ("move %6,$mof\n\t" \ - "movu.w %1,$r9\n\tbreak 13" \ - : "=r" (__a) \ - : "g" (__NR_##name), "0" (__a), "r" (__b), \ - "r" (__c), "r" (__d), "g" (arg5) \ - : "r10", "r9"); \ - if(__a >= 0) \ - return (type) __a; \ - errno = -__a; \ - return (type) -1; \ -} - -#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ - type5,arg5,type6,arg6) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ -{ \ - register long __a __asm__ ("r10") = (long) arg1; \ - register long __b __asm__ ("r11") = (long) arg2; \ - register long __c __asm__ ("r12") = (long) arg3; \ - register long __d __asm__ ("r13") = (long) arg4; \ - __asm__ __volatile__ ("move %6,$mof\n\tmove %7,$srp\n\t" \ - "movu.w %1,$r9\n\tbreak 13" \ - : "=r" (__a) \ - : "g" (__NR_##name), "0" (__a), "r" (__b), \ - "r" (__c), "r" (__d), "g" (arg5), "g" (arg6)\ - : "r10", "r9", "srp"); \ - if(__a >= 0) \ - return (type) __a; \ - errno = -__a; \ - return (type) -1; \ -} #ifdef __KERNEL_SYSCALLS__ @@ -365,21 +296,28 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \ * some others too. */ #define __NR__exit __NR_exit -static inline _syscall0(pid_t,setsid) -static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static inline _syscall1(int,dup,int,fd) -static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static inline _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static inline _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) - - /* the following are just while developing the elinux port! */ - -static inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +extern inline _syscall0(pid_t,setsid) +extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count) +extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count) +extern inline _syscall1(int,dup,int,fd) +extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +extern inline _syscall3(int,open,const char *,file,int,flag,int,mode) +extern inline _syscall1(int,close,int,fd) +/* + * Since we define it "external", it collides with the built-in + * definition, which has the "noreturn" attribute and will cause + * complaints. We don't want to use -fno-builtin, so just use a + * different name when in the kernel. + */ +#ifdef __KERNEL__ +#define _exit kernel_syscall_exit #endif +extern inline _syscall1(int,_exit,int,exitcode) +extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) +#endif + /* * "Conditional" syscalls diff --git a/include/asm-cris/user.h b/include/asm-cris/user.h index 982f4163bc94..2538e2a003df 100644 --- a/include/asm-cris/user.h +++ b/include/asm-cris/user.h @@ -4,6 +4,7 @@ #include <linux/types.h> #include <asm/ptrace.h> #include <asm/page.h> +#include <asm/arch/user.h> /* * Core file format: The core file is written in such a way that gdb @@ -27,49 +28,6 @@ * current->start_stack, so we round each of these in order to be able * to write an integer number of pages. */ - -/* User mode registers, used for core dumps. In order to keep ELF_NGREG - sensible we let all registers be 32 bits. The csr registers are included - for future use. */ -struct user_regs_struct { - unsigned long r0; /* General registers. */ - unsigned long r1; - unsigned long r2; - unsigned long r3; - unsigned long r4; - unsigned long r5; - unsigned long r6; - unsigned long r7; - unsigned long r8; - unsigned long r9; - unsigned long r10; - unsigned long r11; - unsigned long r12; - unsigned long r13; - unsigned long sp; /* Stack pointer. */ - unsigned long pc; /* Program counter. */ - unsigned long p0; /* Constant zero (only 8 bits). */ - unsigned long vr; /* Version register (only 8 bits). */ - unsigned long p2; /* Reserved. */ - unsigned long p3; /* Reserved. */ - unsigned long p4; /* Constant zero (only 16 bits). */ - unsigned long ccr; /* Condition code register (only 16 bits). */ - unsigned long p6; /* Reserved. */ - unsigned long mof; /* Multiply overflow register. */ - unsigned long p8; /* Constant zero. */ - unsigned long ibr; /* Not accessible. */ - unsigned long irp; /* Not accessible. */ - unsigned long srp; /* Subroutine return pointer. */ - unsigned long bar; /* Not accessible. */ - unsigned long dccr; /* Dword condition code register. */ - unsigned long brp; /* Not accessible. */ - unsigned long usp; /* User-mode stack pointer. Same as sp when - in user mode. */ - unsigned long csrinstr; /* Internal status registers. */ - unsigned long csraddr; - unsigned long csrdata; -}; - struct user { struct user_regs_struct regs; /* entire machine state */ |
