diff options
Diffstat (limited to 'arch/cris/arch-v10')
29 files changed, 2018 insertions, 704 deletions
diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig index 2ca64cc..44eb1b9 100644 --- a/arch/cris/arch-v10/Kconfig +++ b/arch/cris/arch-v10/Kconfig @@ -260,6 +260,37 @@ config ETRAX_DEBUG_PORT_NULL endchoice choice + prompt "Kernel GDB port" + depends on ETRAX_KGDB + default ETRAX_KGDB_PORT0 + help + Choose a serial port for kernel debugging. NOTE: This port should + not be enabled under Drivers for built-in interfaces (as it has its + own initialization code) and should not be the same as the debug port. + +config ETRAX_KGDB_PORT0 + bool "Serial-0" + help + Use serial port 0 for kernel debugging. + +config ETRAX_KGDB_PORT1 + bool "Serial-1" + help + Use serial port 1 for kernel debugging. + +config ETRAX_KGDB_PORT2 + bool "Serial-2" + help + Use serial port 2 for kernel debugging. + +config ETRAX_KGDB_PORT3 + bool "Serial-3" + help + Use serial port 3 for kernel debugging. + +endchoice + +choice prompt "Product rescue-port" depends on ETRAX_ARCH_V10 default ETRAX_RESCUE_SER0 diff --git a/arch/cris/arch-v10/boot/Makefile b/arch/cris/arch-v10/boot/Makefile index fe66503..e5b1058 100644 --- a/arch/cris/arch-v10/boot/Makefile +++ b/arch/cris/arch-v10/boot/Makefile @@ -1,12 +1,13 @@ # # arch/cris/boot/Makefile # +target = $(target_boot_dir) +src = $(src_boot_dir) zImage: compressed/vmlinuz -compressed/vmlinuz: $(TOPDIR)/vmlinux - @$(MAKE) -C compressed vmlinuz +compressed/vmlinuz: + @$(MAKE) -f $(src)/compressed/Makefile $(target_compressed_dir)/vmlinuz clean: - rm -f zImage tools/build compressed/vmlinux.out - @$(MAKE) -C compressed clean + @$(MAKE) -f $(src)/compressed/Makefile clean diff --git a/arch/cris/arch-v10/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile index 5f71c2c..6584a44 100644 --- a/arch/cris/arch-v10/boot/compressed/Makefile +++ b/arch/cris/arch-v10/boot/compressed/Makefile @@ -1,40 +1,45 @@ # -# linux/arch/etrax100/boot/compressed/Makefile -# -# create a compressed vmlinux image from the original vmlinux files and romfs +# create a compressed vmlinuz image from the binary vmlinux.bin file # +target = $(target_compressed_dir) +src = $(src_compressed_dir) -CC = gcc-cris -melf -I $(TOPDIR)/include +CC = gcc-cris -melf $(LINUXINCLUDE) CFLAGS = -O2 LD = ld-cris OBJCOPY = objcopy-cris OBJCOPYFLAGS = -O binary --remove-section=.bss -OBJECTS = head.o misc.o +OBJECTS = $(target)/head.o $(target)/misc.o # files to compress -SYSTEM = $(TOPDIR)/vmlinux.bin +SYSTEM = $(objtree)/vmlinux.bin -all: vmlinuz +all: $(target_compressed_dir)/vmlinuz -decompress.bin: $(OBJECTS) - $(LD) -T decompress.ld -o decompress.o $(OBJECTS) - $(OBJCOPY) $(OBJCOPYFLAGS) decompress.o decompress.bin -# save it for mkprod in the topdir. - cp decompress.bin $(TOPDIR) +$(target)/decompress.bin: $(OBJECTS) + $(LD) -T $(src)/decompress.ld -o $(target)/decompress.o $(OBJECTS) + $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/decompress.o $(target)/decompress.bin +# Create vmlinuz image in top-level build directory +$(target_compressed_dir)/vmlinuz: $(target) piggy.img $(target)/decompress.bin + @echo " COMPR vmlinux.bin --> vmlinuz" + @cat $(target)/decompress.bin piggy.img > $(target_compressed_dir)/vmlinuz + @rm -f piggy.img -vmlinuz: piggy.img decompress.bin - cat decompress.bin piggy.img > vmlinuz - rm -f piggy.img +$(target)/head.o: $(src)/head.S + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $@ -head.o: head.S - $(CC) -D__ASSEMBLY__ -traditional -c head.S -o head.o +$(target)/misc.o: $(src)/misc.c + $(CC) -D__KERNEL__ -c $< -o $@ # gzip the kernel image piggy.img: $(SYSTEM) - cat $(SYSTEM) | gzip -f -9 > piggy.img + @cat $(SYSTEM) | gzip -f -9 > piggy.img + +$(target): + mkdir -p $(target) clean: - rm -f piggy.img vmlinuz vmlinuz.o + rm -f piggy.img $(objtree)/vmlinuz diff --git a/arch/cris/arch-v10/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S index 4cbdd4b..e73f44c 100644 --- a/arch/cris/arch-v10/boot/compressed/head.S +++ b/arch/cris/arch-v10/boot/compressed/head.S @@ -13,7 +13,8 @@ #include <asm/arch/sv_addr_ag.h> #define RAM_INIT_MAGIC 0x56902387 - +#define COMMAND_LINE_MAGIC 0x87109563 + ;; Exported symbols .globl _input_data @@ -88,6 +89,12 @@ basse: move.d pc, r5 cmp.d r2, r1 bcs 1b nop + + ;; Save command line magic and address. + move.d _cmd_line_magic, $r12 + move.d $r10, [$r12] + move.d _cmd_line_addr, $r12 + move.d $r11, [$r12] ;; Do the decompression and save compressed size in _inptr @@ -98,7 +105,13 @@ basse: move.d pc, r5 move.d [_input_data], r9 ; flash address of compressed kernel add.d [_inptr], r9 ; size of compressed kernel - + + ;; Restore command line magic and address. + move.d _cmd_line_magic, $r10 + move.d [$r10], $r10 + move.d _cmd_line_addr, $r11 + move.d [$r11], $r11 + ;; Enter the decompressed kernel move.d RAM_INIT_MAGIC, r8 ; Tell kernel that DRAM is initialized jump 0x40004000 ; kernel is linked to this address @@ -107,5 +120,8 @@ basse: move.d pc, r5 _input_data: .dword 0 ; used by the decompressor - +_cmd_line_magic: + .dword 0 +_cmd_line_addr: + .dword 0 #include "../../lib/hw_settings.S" diff --git a/arch/cris/arch-v10/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile index e9f2ba2..8be9b31 100644 --- a/arch/cris/arch-v10/boot/rescue/Makefile +++ b/arch/cris/arch-v10/boot/rescue/Makefile @@ -1,52 +1,53 @@ # # Makefile for rescue code # -ifndef TOPDIR -TOPDIR = ../../../.. -endif -CC = gcc-cris -mlinux -I $(TOPDIR)/include +target = $(target_rescue_dir) +src = $(src_rescue_dir) + +CC = gcc-cris -mlinux $(LINUXINCLUDE) CFLAGS = -O2 LD = gcc-cris -mlinux -nostdlib OBJCOPY = objcopy-cris OBJCOPYFLAGS = -O binary --remove-section=.bss -all: rescue.bin testrescue.bin kimagerescue.bin - -rescue: rescue.bin - # do nothing +all: $(target)/rescue.bin $(target)/testrescue.bin $(target)/kimagerescue.bin -rescue.bin: head.o - $(LD) -T rescue.ld -o rescue.o head.o - $(OBJCOPY) $(OBJCOPYFLAGS) rescue.o rescue.bin - cp rescue.bin $(TOPDIR) +$(target)/rescue.bin: $(target) $(target)/head.o + $(LD) -T $(src)/rescue.ld -o $(target)/rescue.o $(target)/head.o + $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/rescue.o $(target)/rescue.bin +# Place a copy in top-level build directory + cp -p $(target)/rescue.bin $(objtree) -testrescue.bin: testrescue.o - $(OBJCOPY) $(OBJCOPYFLAGS) testrescue.o tr.bin +$(target)/testrescue.bin: $(target) $(target)/testrescue.o + $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/testrescue.o tr.bin # Pad it to 784 bytes dd if=/dev/zero of=tmp2423 bs=1 count=784 cat tr.bin tmp2423 >testrescue_tmp.bin - dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784 + dd if=testrescue_tmp.bin of=$(target)/testrescue.bin bs=1 count=784 rm tr.bin tmp2423 testrescue_tmp.bin -kimagerescue.bin: kimagerescue.o - $(OBJCOPY) $(OBJCOPYFLAGS) kimagerescue.o ktr.bin +$(target)/kimagerescue.bin: $(target) $(target)/kimagerescue.o + $(OBJCOPY) $(OBJCOPYFLAGS) $(target)/kimagerescue.o ktr.bin # Pad it to 784 bytes, that's what the rescue loader expects dd if=/dev/zero of=tmp2423 bs=1 count=784 cat ktr.bin tmp2423 >kimagerescue_tmp.bin - dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784 + dd if=kimagerescue_tmp.bin of=$(target)/kimagerescue.bin bs=1 count=784 rm ktr.bin tmp2423 kimagerescue_tmp.bin -head.o: head.S +$(target): + mkdir -p $(target) + +$(target)/head.o: $(src)/head.S $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o -testrescue.o: testrescue.S +$(target)/testrescue.o: $(src)/testrescue.S $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o -kimagerescue.o: kimagerescue.S +$(target)/kimagerescue.o: $(src)/kimagerescue.S $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o clean: - rm -f *.o *.bin + rm -f $(target)/*.o $(target)/*.bin fastdep: diff --git a/arch/cris/arch-v10/boot/rescue/head.S b/arch/cris/arch-v10/boot/rescue/head.S index 8689ea9..addb219 100644 --- a/arch/cris/arch-v10/boot/rescue/head.S +++ b/arch/cris/arch-v10/boot/rescue/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.6 2003/04/09 08:12:43 pkj Exp $ +/* $Id: head.S,v 1.7 2005/03/07 12:11:06 starvik Exp $ * * Rescue code, made to reside at the beginning of the * flash-memory. when it starts, it checks a partition @@ -121,12 +121,13 @@ ;; 0x80000000 if loaded in flash (as it should be) ;; since etrax actually starts at address 2 when booting from flash, we ;; put a nop (2 bytes) here first so we dont accidentally skip the di - + nop di jump in_cache ; enter cached area instead -in_cache: +in_cache: + ;; first put a jump test to give a possibility of upgrading the rescue code ;; without erasing/reflashing the sector. we put a longword of -1 here and if @@ -325,9 +326,29 @@ flash_ok: ;; result will be in r0 checksum: moveq 0, $r0 -1: addu.b [$r1+], $r0 - subq 1, $r2 - bne 1b + moveq CONFIG_ETRAX_FLASH1_SIZE, $r6 + + ;; If the first physical flash memory is exceeded wrap to the second one. + btstq 26, $r1 ; Are we addressing first flash? + bpl 1f + nop + clear.d $r6 + +1: test.d $r6 ; 0 = no wrapping + beq 2f + nop + lslq 20, $r6 ; Convert MB to bytes + sub.d $r1, $r6 + +2: addu.b [$r1+], $r0 + subq 1, $r6 ; Flash memory left + beq 3f + subq 1, $r2 ; Length left + bne 2b nop ret nop + +3: move.d MEM_CSE1_START, $r1 ; wrap to second flash + ba 2b + nop diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig index 748374f..8b50e84 100644 --- a/arch/cris/arch-v10/drivers/Kconfig +++ b/arch/cris/arch-v10/drivers/Kconfig @@ -1,17 +1,11 @@ config ETRAX_ETHERNET bool "Ethernet support" depends on ETRAX_ARCH_V10 + select NET_ETHERNET help This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet controller. -# this is just so that the user does not have to go into the -# normal ethernet driver section just to enable ethernetworking -config NET_ETHERNET - bool - depends on ETRAX_ETHERNET - default y - choice prompt "Network LED behavior" depends on ETRAX_ETHERNET @@ -20,26 +14,26 @@ 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 @@ -91,11 +85,11 @@ choice depends on ETRAX_SERIAL_PORT0 default ETRAX_SERIAL_PORT0_DMA6_OUT -config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT - bool "No DMA out" +config ETRAX_SERIAL_PORT0_NO_DMA_OUT + bool "No DMA out" -config CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT - bool "DMA 6" +config ETRAX_SERIAL_PORT0_DMA6_OUT + bool "DMA 6" endchoice @@ -104,11 +98,11 @@ choice depends on ETRAX_SERIAL_PORT0 default ETRAX_SERIAL_PORT0_DMA7_IN -config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN - bool "No DMA in" +config ETRAX_SERIAL_PORT0_NO_DMA_IN + bool "No DMA in" -config CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN - bool "DMA 7" +config ETRAX_SERIAL_PORT0_DMA7_IN + bool "DMA 7" endchoice @@ -205,11 +199,11 @@ choice depends on ETRAX_SERIAL_PORT1 default ETRAX_SERIAL_PORT1_DMA8_OUT -config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT - bool "No DMA out" +config ETRAX_SERIAL_PORT1_NO_DMA_OUT + bool "No DMA out" -config CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT - bool "DMA 8" +config ETRAX_SERIAL_PORT1_DMA8_OUT + bool "DMA 8" endchoice @@ -218,11 +212,11 @@ choice depends on ETRAX_SERIAL_PORT1 default ETRAX_SERIAL_PORT1_DMA9_IN -config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN - bool "No DMA in" +config ETRAX_SERIAL_PORT1_NO_DMA_IN + bool "No DMA in" -config CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN - bool "DMA 9" +config ETRAX_SERIAL_PORT1_DMA9_IN + bool "DMA 9" endchoice @@ -308,7 +302,7 @@ config ETRAX_SER1_CD_ON_PB_BIT Specify the pin of the PB port to carry the CD signal for serial port 1. -comment "Make sure you dont have the same PB bits more than once!" +comment "Make sure you do not have the same PB bits more than once!" depends on ETRAX_SERIAL && ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && ETRAX_SER1_DTR_RI_DSR_CD_ON_PB config ETRAX_SERIAL_PORT2 @@ -322,11 +316,11 @@ choice depends on ETRAX_SERIAL_PORT2 default ETRAX_SERIAL_PORT2_DMA2_OUT -config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT - bool "No DMA out" +config ETRAX_SERIAL_PORT2_NO_DMA_OUT + bool "No DMA out" -config CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT - bool "DMA 2" +config ETRAX_SERIAL_PORT2_DMA2_OUT + bool "DMA 2" endchoice @@ -335,11 +329,11 @@ choice depends on ETRAX_SERIAL_PORT2 default ETRAX_SERIAL_PORT2_DMA3_IN -config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN - bool "No DMA in" +config ETRAX_SERIAL_PORT2_NO_DMA_IN + bool "No DMA in" -config CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN - bool "DMA 3" +config ETRAX_SERIAL_PORT2_DMA3_IN + bool "DMA 3" endchoice @@ -436,11 +430,11 @@ choice depends on ETRAX_SERIAL_PORT3 default ETRAX_SERIAL_PORT3_DMA4_OUT -config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_OUT - bool "No DMA out" +config ETRAX_SERIAL_PORT3_NO_DMA_OUT + bool "No DMA out" -config CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT - bool "DMA 4" +config ETRAX_SERIAL_PORT3_DMA4_OUT + bool "DMA 4" endchoice @@ -449,11 +443,11 @@ choice depends on ETRAX_SERIAL_PORT3 default ETRAX_SERIAL_PORT3_DMA5_IN -config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_IN - bool "No DMA in" +config ETRAX_SERIAL_PORT3_NO_DMA_IN + bool "No DMA in" -config CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN - bool "DMA 5" +config ETRAX_SERIAL_PORT3_DMA5_IN + bool "DMA 5" endchoice @@ -554,7 +548,6 @@ config ETRAX_IDE select BLK_DEV_IDEDISK select BLK_DEV_IDECD select BLK_DEV_IDEDMA - select DMA_NONPCI help Enable this to get support for ATA/IDE. You can't use paralell ports or SCSI ports @@ -579,7 +572,7 @@ config ETRAX_IDE_PB7_RESET IDE reset on pin 7 on port B config ETRAX_IDE_G27_RESET - bool "Port_G_Bit_27" + bool "Port_G_Bit_27" help IDE reset on pin 27 on port G @@ -588,30 +581,36 @@ endchoice config ETRAX_USB_HOST bool "USB host" + select USB help This option enables the host functionality of the ETRAX 100LX built-in USB controller. In host mode the controller is designed for CTRL and BULK traffic only, INTR traffic may work as well however (depending on the requirements of timeliness). -config USB - tristate - depends on ETRAX_USB_HOST - default y - config ETRAX_USB_HOST_PORT1 - bool " USB port 1 enabled" - depends on ETRAX_USB_HOST - default n + bool "USB port 1 enabled" + depends on ETRAX_USB_HOST + default n config ETRAX_USB_HOST_PORT2 - bool " USB port 2 enabled" - depends on ETRAX_USB_HOST - default n + bool "USB port 2 enabled" + depends on ETRAX_USB_HOST + default n config ETRAX_AXISFLASHMAP bool "Axis flash-map support" depends on ETRAX_ARCH_V10 + select MTD + select MTD_CFI + select MTD_CFI_AMDSTD + select MTD_OBSOLETE_CHIPS + select MTD_AMDSTD + select MTD_CHAR + select MTD_BLOCK + select MTD_PARTITIONS + select MTD_CONCAT + select MTD_COMPLEX_MAPPINGS help This option enables MTD mapping of flash devices. Needed to use flash memories. If unsure, say Y. @@ -627,119 +626,6 @@ config ETRAX_PTABLE_SECTOR for changing this is when the flash block size is bigger than 64kB (e.g. when using two parallel 16 bit flashes). -# here we define the CONFIG_'s necessary to enable MTD support -# for the flash -config MTD - tristate - depends on ETRAX_AXISFLASHMAP - default y - help - Memory Technology Devices are flash, RAM and similar chips, often - used for solid state file systems on embedded devices. This option - will provide the generic support for MTD drivers to register - themselves with the kernel and for potential users of MTD devices - to enumerate the devices which are present and obtain a handle on - them. It will also allow you to select individual drivers for - particular hardware and users of MTD devices. If unsure, say N. - -config MTD_CFI - tristate - depends on ETRAX_AXISFLASHMAP - default y - help - The Common Flash Interface specification was developed by Intel, - AMD and other flash manufactures that provides a universal method - for probing the capabilities of flash devices. If you wish to - support any device that is CFI-compliant, you need to enable this - option. Visit <http://www.amd.com/products/nvd/overview/cfi.html> - for more information on CFI. - -config MTD_CFI_AMDSTD - tristate - depends on ETRAX_AXISFLASHMAP - default y - help - The Common Flash Interface defines a number of different command - sets which a CFI-compliant chip may claim to implement. This code - 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 - default y - help - This option enables support for flash chips using AMD-compatible - commands, including some which are not CFI-compatible and hence - cannot be used with the CONFIG_MTD_CFI_AMDSTD option. - - It also works on AMD compatible chips that do conform to CFI. - -config MTD_CHAR - tristate - depends on ETRAX_AXISFLASHMAP - default y - help - This provides a character device for each MTD device present in - the system, allowing the user to read and write directly to the - memory chips, and also use ioctl() to obtain information about - the device, or to erase parts of it. - -config MTD_BLOCK - tristate - depends on ETRAX_AXISFLASHMAP - default y - ---help--- - Although most flash chips have an erase size too large to be useful - as block devices, it is possible to use MTD devices which are based - on RAM chips in this manner. This block device is a user of MTD - devices performing that function. - - At the moment, it is also required for the Journalling Flash File - System(s) to obtain a handle on the MTD device when it's mounted - (although JFFS and JFFS2 don't actually use any of the functionality - of the mtdblock device). - - Later, it may be extended to perform read/erase/modify/write cycles - on flash chips to emulate a smaller block size. Needless to say, - this is very unsafe, but could be useful for file systems which are - almost never written to. - - You do not need this option for use with the DiskOnChip devices. For - those, enable NFTL support (CONFIG_NFTL) instead. - -config MTD_PARTITIONS - tristate - depends on ETRAX_AXISFLASHMAP - default y - help - If you have a device which needs to divide its flash chip(s) up - into multiple 'partitions', each of which appears to the user as - a separate MTD device, you require this option to be enabled. If - unsure, say 'Y'. - - Note, however, that you don't need this option for the DiskOnChip - 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 @@ -752,7 +638,7 @@ config ETRAX_I2C val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg); # this is true for most products since PB-I2C seems to be somewhat -# flawed.. +# flawed.. config ETRAX_I2C_USES_PB_NOT_PB_I2C bool "I2C uses PB not PB-I2C" depends on ETRAX_I2C @@ -886,7 +772,7 @@ config ETRAX_RTC bool "Real Time Clock support" depends on ETRAX_ARCH_V10 help - Enables drivers for the Real-Time Clock battery-backed chips on + 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 @@ -903,13 +789,13 @@ config ETRAX_DS1302 bool "DS1302" help Enables the driver for the DS1302 Real-Time Clock battery-backed - chip on some products. + 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. + chip on some products. endchoice @@ -954,10 +840,8 @@ config ETRAX_DS1302_TRICKLE_CHARGE 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 + 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/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c index fb7d485..11ab383 100644 --- a/arch/cris/arch-v10/drivers/axisflashmap.c +++ b/arch/cris/arch-v10/drivers/axisflashmap.c @@ -11,6 +11,9 @@ * partition split defined below. * * $Log: axisflashmap.c,v $ + * Revision 1.11 2004/11/15 10:27:14 starvik + * Corrected typo (Thanks to Milton Miller <miltonm@bga.com>). + * * Revision 1.10 2004/08/16 12:37:22 starvik * Merge of Linux 2.6.8 * @@ -161,7 +164,7 @@ #elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 #define flash_data __u16 #elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 -#define flash_data __u16 +#define flash_data __u32 #endif /* From head.S */ diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c index fba530f..10795f6 100644 --- a/arch/cris/arch-v10/drivers/ds1302.c +++ b/arch/cris/arch-v10/drivers/ds1302.c @@ -7,6 +7,15 @@ *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init *! *! $Log: ds1302.c,v $ +*! Revision 1.18 2005/01/24 09:11:26 mikaelam +*! Minor changes to get DS1302 RTC chip driver to work +*! +*! Revision 1.17 2005/01/05 06:11:22 starvik +*! No need to do local_irq_disable after local_irq_save. +*! +*! Revision 1.16 2004/12/13 12:21:52 starvik +*! Added I/O and DMA allocators from Linux 2.4 +*! *! Revision 1.14 2004/08/24 06:48:43 starvik *! Whitespace cleanup *! @@ -124,9 +133,9 @@ *! *! --------------------------------------------------------------------------- *! -*! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN +*! (C) Copyright 1999, 2000, 2001, 2002, 2003, 2004 Axis Communications AB, LUND, SWEDEN *! -*! $Id: ds1302.c,v 1.14 2004/08/24 06:48:43 starvik Exp $ +*! $Id: ds1302.c,v 1.18 2005/01/24 09:11:26 mikaelam Exp $ *! *!***************************************************************************/ @@ -145,6 +154,7 @@ #include <asm/arch/svinto.h> #include <asm/io.h> #include <asm/rtc.h> +#include <asm/arch/io_interface_mux.h> #define RTC_MAJOR_NR 121 /* local major, change later */ @@ -320,7 +330,6 @@ get_rtc_time(struct rtc_time *rtc_tm) unsigned long flags; local_irq_save(flags); - local_irq_disable(); rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); @@ -358,7 +367,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - unsigned long flags; + unsigned long flags; switch(cmd) { case RTC_RD_TIME: /* read the time/date from RTC */ @@ -382,7 +391,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, return -EPERM; if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) - return -EFAULT; + return -EFAULT; yrs = rtc_tm.tm_year + 1900; mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ @@ -419,7 +428,6 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, BIN_TO_BCD(yrs); local_irq_save(flags); - local_irq_disable(); CMOS_WRITE(yrs, RTC_YEAR); CMOS_WRITE(mon, RTC_MONTH); CMOS_WRITE(day, RTC_DAY_OF_MONTH); @@ -438,7 +446,7 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ { - int tcs_val; + int tcs_val; if (!capable(CAP_SYS_TIME)) return -EPERM; @@ -492,8 +500,8 @@ print_rtc_status(void) /* The various file operations we support. */ static struct file_operations rtc_fops = { - .owner = THIS_MODULE, - .ioctl = rtc_ioctl, + .owner = THIS_MODULE, + .ioctl = rtc_ioctl, }; /* Probe for the chip by writing something to its RAM and try reading it back. */ @@ -532,7 +540,7 @@ ds1302_probe(void) "PB", #endif CONFIG_ETRAX_DS1302_RSTBIT); - print_rtc_status(); + print_rtc_status(); retval = 1; } else { stop(); @@ -548,7 +556,9 @@ ds1302_probe(void) int __init ds1302_init(void) { +#ifdef CONFIG_ETRAX_I2C i2c_init(); +#endif if (!ds1302_probe()) { #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT @@ -558,25 +568,42 @@ ds1302_init(void) * * Make sure that R_GEN_CONFIG is setup correct. */ - genconfig_shadow = ((genconfig_shadow & - ~IO_MASK(R_GEN_CONFIG, ata)) | - (IO_STATE(R_GEN_CONFIG, ata, select))); - *R_GEN_CONFIG = genconfig_shadow; + /* Allocating the ATA interface will grab almost all + * pins in I/O groups a, b, c and d. A consequence of + * allocating the ATA interface is that the fixed + * interfaces shared RAM, parallel port 0, parallel + * port 1, parallel port W, SCSI-8 port 0, SCSI-8 port + * 1, SCSI-W, serial port 2, serial port 3, + * synchronous serial port 3 and USB port 2 and almost + * all GPIO pins on port g cannot be used. + */ + if (cris_request_io_interface(if_ata, "ds1302/ATA")) { + printk(KERN_WARNING "ds1302: Failed to get IO interface\n"); + return -1; + } + #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; + if (cris_io_interface_allocate_pins(if_gpio_grp_a, + 'g', + CONFIG_ETRAX_DS1302_RSTBIT, + CONFIG_ETRAX_DS1302_RSTBIT)) { + printk(KERN_WARNING "ds1302: Failed to get IO interface\n"); + return -1; + } + + /* 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()) { printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); - return -1; + return -1; } #else printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); - return -1; + return -1; #endif } /* Initialise trickle charger */ diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c index 316ca15..512f16d 100644 --- a/arch/cris/arch-v10/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -20,6 +20,12 @@ *! in the spin-lock. *! *! $Log: eeprom.c,v $ +*! Revision 1.12 2005/06/19 17:06:46 starvik +*! Merge of Linux 2.6.12. +*! +*! Revision 1.11 2005/01/26 07:14:46 starvik +*! Applied diff from kernel janitors (Nish Aravamudan). +*! *! Revision 1.10 2003/09/11 07:29:48 starvik *! Merge of Linux 2.6.0-test5 *! @@ -94,6 +100,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/wait.h> #include <asm/uaccess.h> #include "i2c.h" @@ -526,15 +533,10 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t return -EFAULT; } - while(eeprom.busy) - { - interruptible_sleep_on(&eeprom.wait_q); + wait_event_interruptible(eeprom.wait_q, !eeprom.busy); + if (signal_pending(current)) + return -EINTR; - /* bail out if we get interrupted */ - if (signal_pending(current)) - return -EINTR; - - } eeprom.busy++; page = (unsigned char) (p >> 8); @@ -604,13 +606,10 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, return -EFAULT; } - while(eeprom.busy) - { - interruptible_sleep_on(&eeprom.wait_q); - /* bail out if we get interrupted */ - if (signal_pending(current)) - return -EINTR; - } + wait_event_interruptible(eeprom.wait_q, !eeprom.busy); + /* bail out if we get interrupted */ + if (signal_pending(current)) + return -EINTR; eeprom.busy++; for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) { diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c index c095de8..09963fe 100644 --- a/arch/cris/arch-v10/drivers/gpio.c +++ b/arch/cris/arch-v10/drivers/gpio.c @@ -1,4 +1,4 @@ -/* $Id: gpio.c,v 1.12 2004/08/24 07:19:59 starvik Exp $ +/* $Id: gpio.c,v 1.17 2005/06/19 17:06:46 starvik Exp $ * * Etrax general port I/O device * @@ -9,6 +9,18 @@ * Johan Adolfsson (read/set directions, write, port G) * * $Log: gpio.c,v $ + * Revision 1.17 2005/06/19 17:06:46 starvik + * Merge of Linux 2.6.12. + * + * Revision 1.16 2005/03/07 13:02:29 starvik + * Protect driver global states with spinlock + * + * Revision 1.15 2005/01/05 06:08:55 starvik + * No need to do local_irq_disable after local_irq_save. + * + * Revision 1.14 2004/12/13 12:21:52 starvik + * Added I/O and DMA allocators from Linux 2.4 + * * Revision 1.12 2004/08/24 07:19:59 starvik * Whitespace cleanup * @@ -142,6 +154,7 @@ #include <asm/io.h> #include <asm/system.h> #include <asm/irq.h> +#include <asm/arch/io_interface_mux.h> #define GPIO_MAJOR 120 /* experimental MAJOR number */ @@ -194,6 +207,8 @@ static struct gpio_private *alarmlist = 0; static int gpio_some_alarms = 0; /* Set if someone uses alarm */ static unsigned long gpio_pa_irq_enabled_mask = 0; +static DEFINE_SPINLOCK(gpio_lock); /* Protect directions etc */ + /* Port A and B use 8 bit access, but Port G is 32 bit */ #define NUM_PORTS (GPIO_MINOR_B+1) @@ -241,6 +256,9 @@ static volatile unsigned char *dir_shadow[NUM_PORTS] = { &port_pb_dir_shadow }; +/* All bits in port g that can change dir. */ +static const unsigned long int changeable_dir_g_mask = 0x01FFFF01; + /* 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. */ @@ -260,6 +278,7 @@ gpio_poll(struct file *file, unsigned int mask = 0; struct gpio_private *priv = (struct gpio_private *)file->private_data; unsigned long data; + spin_lock(&gpio_lock); poll_wait(file, &priv->alarm_wq, wait); if (priv->minor == GPIO_MINOR_A) { unsigned long flags; @@ -270,10 +289,10 @@ gpio_poll(struct file *file, */ tmp = ~data & priv->highalarm & 0xFF; tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); - save_flags(flags); cli(); + local_irq_save(flags); gpio_pa_irq_enabled_mask |= tmp; *R_IRQ_MASK1_SET = tmp; - restore_flags(flags); + local_irq_restore(flags); } else if (priv->minor == GPIO_MINOR_B) data = *R_PORT_PB_DATA; @@ -286,8 +305,11 @@ gpio_poll(struct file *file, (~data & priv->lowalarm)) { mask = POLLIN|POLLRDNORM; } + + spin_unlock(&gpio_lock); DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); + return mask; } @@ -296,6 +318,7 @@ int etrax_gpio_wake_up_check(void) struct gpio_private *priv = alarmlist; unsigned long data = 0; int ret = 0; + spin_lock(&gpio_lock); while (priv) { if (USE_PORTS(priv)) { data = *priv->port; @@ -310,6 +333,7 @@ int etrax_gpio_wake_up_check(void) } priv = priv->next; } + spin_unlock(&gpio_lock); return ret; } @@ -327,6 +351,7 @@ static irqreturn_t gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long tmp; + spin_lock(&gpio_lock); /* Find what PA interrupts are active */ tmp = (*R_IRQ_READ1); @@ -337,6 +362,8 @@ gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) *R_IRQ_MASK1_CLR = tmp; gpio_pa_irq_enabled_mask &= ~tmp; + spin_unlock(&gpio_lock); + if (gpio_some_alarms) { return IRQ_RETVAL(etrax_gpio_wake_up_check()); } @@ -350,6 +377,9 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, struct gpio_private *priv = (struct gpio_private *)file->private_data; unsigned char data, clk_mask, data_mask, write_msb; unsigned long flags; + + spin_lock(&gpio_lock); + ssize_t retval = count; if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { return -EFAULT; @@ -372,7 +402,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, data = *buf++; if (priv->write_msb) { for (i = 7; i >= 0;i--) { - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); *priv->port = *priv->shadow &= ~clk_mask; if (data & 1<<i) *priv->port = *priv->shadow |= data_mask; @@ -384,7 +414,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, } } else { for (i = 0; i <= 7;i++) { - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); *priv->port = *priv->shadow &= ~clk_mask; if (data & 1<<i) *priv->port = *priv->shadow |= data_mask; @@ -396,6 +426,7 @@ static ssize_t gpio_write(struct file * file, const char * buf, size_t count, } } } + spin_unlock(&gpio_lock); return retval; } @@ -452,9 +483,14 @@ gpio_open(struct inode *inode, struct file *filp) 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; - + struct gpio_private *p; + struct gpio_private *todel; + + spin_lock(&gpio_lock); + + p = alarmlist; + todel = (struct gpio_private *)filp->private_data; + /* unlink from alarmlist and free the private structure */ if (p == todel) { @@ -476,7 +512,7 @@ gpio_release(struct inode *inode, struct file *filp) p = p->next; } gpio_some_alarms = 0; - + spin_unlock(&gpio_lock); return 0; } @@ -491,14 +527,14 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) */ unsigned long flags; if (USE_PORTS(priv)) { - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); *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 */ - save_flags(flags); cli(); + local_irq_save(flags); if (((arg & dir_g_in_bits) != arg) && (arg & changeable_dir_g)) { arg &= changeable_dir_g; @@ -533,7 +569,7 @@ unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) /* Must be a >120 ns delay before writing this again */ } - restore_flags(flags); + local_irq_restore(flags); return dir_g_in_bits; } return 0; @@ -543,14 +579,14 @@ 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(); + local_irq_save(flags); *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 */ - save_flags(flags); cli(); + local_irq_save(flags); if (((arg & dir_g_out_bits) != arg) && (arg & changeable_dir_g)) { /* Set bits in genconfig to set to output */ @@ -583,7 +619,7 @@ unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) *R_GEN_CONFIG = genconfig_shadow; /* Must be a >120 ns delay before writing this again */ } - restore_flags(flags); + local_irq_restore(flags); return dir_g_out_bits & 0x7FFFFFFF; } return 0; @@ -598,22 +634,26 @@ gpio_ioctl(struct inode *inode, struct file *file, { unsigned long flags; unsigned long val; + int ret = 0; + struct gpio_private *priv = (struct gpio_private *)file->private_data; if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { return -EINVAL; } + spin_lock(&gpio_lock); + 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; + ret = *priv->port; } else if (priv->minor == GPIO_MINOR_G) { - return (*R_PORT_G_DATA) & 0x7FFFFFFF; + ret = (*R_PORT_G_DATA) & 0x7FFFFFFF; } break; case IO_SETBITS: - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); // set changeable bits with a 1 in arg if (USE_PORTS(priv)) { *priv->port = *priv->shadow |= @@ -624,7 +664,7 @@ gpio_ioctl(struct inode *inode, struct file *file, local_irq_restore(flags); break; case IO_CLRBITS: - local_irq_save(flags); local_irq_disable(); + local_irq_save(flags); // clear changeable bits with a 1 in arg if (USE_PORTS(priv)) { *priv->port = *priv->shadow &= @@ -666,33 +706,34 @@ gpio_ioctl(struct inode *inode, struct file *file, case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ /* Read direction 0=input 1=output */ if (USE_PORTS(priv)) { - return *priv->dir_shadow; + ret = *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; + ret = (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; } + break; 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; + ret = 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; - + ret = setget_output(priv, arg) & 0x7FFFFFFF; + break; 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)); + ret = (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); #else - return 0; + ret = 0; #endif break; case IO_CFG_WRITE_MODE: @@ -709,7 +750,7 @@ gpio_ioctl(struct inode *inode, struct file *file, { priv->clk_mask = 0; priv->data_mask = 0; - return -EPERM; + ret = -EPERM; } break; case IO_READ_INBITS: @@ -720,8 +761,7 @@ gpio_ioctl(struct inode *inode, struct file *file, val = *R_PORT_G_DATA; } if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; - return 0; + ret = -EFAULT; break; case IO_READ_OUTBITS: /* *arg is result of reading the output shadow */ @@ -731,36 +771,43 @@ gpio_ioctl(struct inode *inode, struct file *file, val = port_g_data_shadow; } if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; + ret = -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; + { + ret = -EFAULT; + break; + } val = setget_input(priv, val); if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; + ret = -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; + { + ret = -EFAULT; + break; + } val = setget_output(priv, val); if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) - return -EFAULT; + ret = -EFAULT; break; default: if (priv->minor == GPIO_MINOR_LEDS) - return gpio_leds_ioctl(cmd, arg); + ret = gpio_leds_ioctl(cmd, arg); else - return -EINVAL; + ret = -EINVAL; } /* switch */ - - return 0; + + spin_unlock(&gpio_lock); + return ret; } static int @@ -802,60 +849,20 @@ struct file_operations gpio_fops = { }; -static void __init gpio_init_port_g(void) +void ioif_watcher(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available) { -#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; - } + unsigned long int flags; + D(printk("gpio.c: ioif_watcher called\n")); + D(printk("gpio.c: G in: 0x%08x G out: 0x%08x PA: 0x%02x PB: 0x%02x\n", + gpio_in_available, gpio_out_available, pa_available, pb_available)); - 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); - } + spin_lock_irqsave(&gpio_lock, flags); - 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? */ + dir_g_in_bits = gpio_in_available; + dir_g_out_bits = gpio_out_available; /* Initialise the dir_g_shadow etc. depending on genconfig */ /* 0=input 1=output */ @@ -868,10 +875,7 @@ static void __init gpio_init_port_g(void) 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 = changeable_dir_g_mask; changeable_dir_g &= dir_g_out_bits; changeable_dir_g &= dir_g_in_bits; /* Correct the bits that can change direction */ @@ -880,6 +884,7 @@ static void __init gpio_init_port_g(void) dir_g_in_bits &= ~changeable_dir_g; dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); + spin_unlock_irqrestore(&gpio_lock, flags); printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); @@ -896,6 +901,7 @@ gpio_init(void) #if defined (CONFIG_ETRAX_CSP0_LEDS) int i; #endif + printk("gpio init\n"); /* do the formalities */ @@ -919,8 +925,13 @@ gpio_init(void) #endif #endif - gpio_init_port_g(); - printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); + /* The I/O interface allocation watcher will be called when + * registering it. */ + if (cris_io_interface_register_watcher(ioif_watcher)){ + printk(KERN_WARNING "gpio_init: Failed to install IO if allocator watcher\n"); + } + + printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002, 2003, 2004 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 diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c index 8bbe233..b38267d 100644 --- a/arch/cris/arch-v10/drivers/i2c.c +++ b/arch/cris/arch-v10/drivers/i2c.c @@ -12,6 +12,15 @@ *! don't use PB_I2C if DS1302 uses same bits, *! use PB. *! $Log: i2c.c,v $ +*! Revision 1.13 2005/03/07 13:13:07 starvik +*! Added spinlocks to protect states etc +*! +*! Revision 1.12 2005/01/05 06:11:22 starvik +*! No need to do local_irq_disable after local_irq_save. +*! +*! Revision 1.11 2004/12/13 12:21:52 starvik +*! Added I/O and DMA allocators from Linux 2.4 +*! *! Revision 1.9 2004/08/24 06:49:14 starvik *! Whitespace cleanup *! @@ -75,7 +84,7 @@ *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN *! *!***************************************************************************/ -/* $Id: i2c.c,v 1.9 2004/08/24 06:49:14 starvik Exp $ */ +/* $Id: i2c.c,v 1.13 2005/03/07 13:13:07 starvik Exp $ */ /****************** INCLUDE FILES SECTION ***********************************/ @@ -95,6 +104,7 @@ #include <asm/arch/svinto.h> #include <asm/io.h> #include <asm/delay.h> +#include <asm/arch/io_interface_mux.h> #include "i2c.h" @@ -184,6 +194,7 @@ static const char i2c_name[] = "i2c"; #define i2c_delay(usecs) udelay(usecs) +static DEFINE_SPINLOCK(i2c_lock); /* Protect directions etc */ /****************** FUNCTION DEFINITION SECTION *************************/ @@ -488,13 +499,14 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, int error, cntr = 3; unsigned long flags; + spin_lock(&i2c_lock); + do { error = 0; /* * we don't like to be interrupted */ local_irq_save(flags); - local_irq_disable(); i2c_start(); /* @@ -538,6 +550,8 @@ i2c_writereg(unsigned char theSlave, unsigned char theReg, i2c_delay(CLOCK_LOW_TIME); + spin_unlock(&i2c_lock); + return -error; } @@ -555,13 +569,14 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) int error, cntr = 3; unsigned long flags; + spin_lock(&i2c_lock); + do { error = 0; /* * we don't like to be interrupted */ local_irq_save(flags); - local_irq_disable(); /* * generate start condition */ @@ -620,6 +635,8 @@ i2c_readreg(unsigned char theSlave, unsigned char theReg) } while(error && cntr--); + spin_unlock(&i2c_lock); + return b; } @@ -686,15 +703,26 @@ static struct file_operations i2c_fops = { int __init i2c_init(void) { + static int res = 0; + static int first = 1; + + if (!first) { + return res; + } + /* Setup and enable the Port B I2C interface */ #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C + if ((res = cris_request_io_interface(if_i2c, "I2C"))) { + printk(KERN_CRIT "i2c_init: Failed to get IO interface\n"); + return res; + } + *R_PORT_PB_I2C = port_pb_i2c_shadow |= IO_STATE(R_PORT_PB_I2C, i2c_en, on) | IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); -#endif port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); @@ -702,8 +730,26 @@ i2c_init(void) *R_PORT_PB_DIR = (port_pb_dir_shadow |= IO_STATE(R_PORT_PB_DIR, dir0, input) | IO_STATE(R_PORT_PB_DIR, dir1, output)); +#else + if ((res = cris_io_interface_allocate_pins(if_i2c, + 'b', + CONFIG_ETRAX_I2C_DATA_PORT, + CONFIG_ETRAX_I2C_DATA_PORT))) { + printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C data port\n"); + return res; + } else if ((res = cris_io_interface_allocate_pins(if_i2c, + 'b', + CONFIG_ETRAX_I2C_CLK_PORT, + CONFIG_ETRAX_I2C_CLK_PORT))) { + cris_io_interface_free_pins(if_i2c, + 'b', + CONFIG_ETRAX_I2C_DATA_PORT, + CONFIG_ETRAX_I2C_DATA_PORT); + printk(KERN_WARNING "i2c_init: Failed to get IO pin for I2C clk port\n"); + } +#endif - return 0; + return res; } static int __init @@ -711,14 +757,16 @@ i2c_register(void) { int res; - i2c_init(); + res = i2c_init(); + if (res < 0) + return res; res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); if(res < 0) { printk(KERN_ERR "i2c: couldn't get a major number.\n"); return res; } - printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); + printk(KERN_INFO "I2C driver v2.2, (c) 1999-2004 Axis Communications AB\n"); return 0; } diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c index b3dfdf7..201f4c9 100644 --- a/arch/cris/arch-v10/drivers/pcf8563.c +++ b/arch/cris/arch-v10/drivers/pcf8563.c @@ -15,7 +15,7 @@ * * Author: Tobias Anderberg <tobiasa@axis.com>. * - * $Id: pcf8563.c,v 1.8 2004/08/24 06:42:51 starvik Exp $ + * $Id: pcf8563.c,v 1.11 2005/03/07 13:13:07 starvik Exp $ */ #include <linux/config.h> @@ -40,7 +40,7 @@ #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.8 $" +#define DRIVER_VERSION "$Revision: 1.11 $" /* I2C bus slave registers. */ #define RTC_I2C_READ 0xa3 @@ -49,6 +49,8 @@ /* 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 DEFINE_SPINLOCK(rtc_lock); /* Protect state etc */ static const unsigned char days_in_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -125,9 +127,12 @@ get_rtc_time(struct rtc_time *tm) int __init pcf8563_init(void) { - unsigned char ret; + int ret; - i2c_init(); + if ((ret = i2c_init())) { + printk(KERN_CRIT "pcf8563_init: failed to init i2c\n"); + return ret; + } /* * First of all we need to reset the chip. This is done by @@ -200,12 +205,15 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned { struct rtc_time tm; + spin_lock(&rtc_lock); get_rtc_time(&tm); if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { + spin_unlock(&rtc_lock); return -EFAULT; } + spin_unlock(&rtc_lock); return 0; } break; @@ -250,6 +258,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned BIN_TO_BCD(tm.tm_min); BIN_TO_BCD(tm.tm_sec); tm.tm_mon |= century; + + spin_lock(&rtc_lock); rtc_write(RTC_YEAR, tm.tm_year); rtc_write(RTC_MONTH, tm.tm_mon); @@ -258,6 +268,8 @@ pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned rtc_write(RTC_MINUTES, tm.tm_min); rtc_write(RTC_SECONDS, tm.tm_sec); + spin_unlock(&rtc_lock); + return 0; #endif /* !CONFIG_ETRAX_RTC_READONLY */ } diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile index 5276160..dcfec41 100644 --- a/arch/cris/arch-v10/kernel/Makefile +++ b/arch/cris/arch-v10/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $ +# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $ # # Makefile for the linux kernel. # @@ -7,7 +7,8 @@ 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 + process.o setup.o signal.o traps.o time.o ptrace.o \ + dma.o io_interface_mux.o obj-$(CONFIG_ETRAX_KGDB) += kgdb.o obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c index 6cf069e..f3a85b7 100644 --- a/arch/cris/arch-v10/kernel/debugport.c +++ b/arch/cris/arch-v10/kernel/debugport.c @@ -12,6 +12,31 @@ * init_etrax_debug() * * $Log: debugport.c,v $ + * Revision 1.27 2005/06/10 10:34:14 starvik + * Real console support + * + * Revision 1.26 2005/06/07 07:06:07 starvik + * Added LF->CR translation to make ETRAX customers happy. + * + * Revision 1.25 2005/03/08 08:56:47 mikaelam + * Do only set index as port->index if port is defined, otherwise use the index from the command line + * + * Revision 1.24 2005/01/19 10:26:33 mikaelam + * Return the cris serial driver in console device driver callback function + * + * Revision 1.23 2005/01/14 10:12:17 starvik + * KGDB on separate port. + * Console fixes from 2.4. + * + * Revision 1.22 2005/01/11 16:06:13 starvik + * typo + * + * Revision 1.21 2005/01/11 13:49:14 starvik + * Added raw_printk to be used where we don't trust the console. + * + * Revision 1.20 2004/12/27 11:18:32 starvik + * Merge of Linux 2.6.10 (not functional yet). + * * Revision 1.19 2004/10/21 07:26:16 starvik * Made it possible to specify console settings on kernel command line. * @@ -114,7 +139,11 @@ struct dbg_port ports[]= R_SERIAL0_BAUD, R_SERIAL0_TR_CTRL, R_SERIAL0_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser0_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser0_data, set), + 0, + 115200, + 'N', + 8 }, { 1, @@ -124,7 +153,11 @@ struct dbg_port ports[]= R_SERIAL1_BAUD, R_SERIAL1_TR_CTRL, R_SERIAL1_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser1_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser1_data, set), + 0, + 115200, + 'N', + 8 }, { 2, @@ -134,7 +167,11 @@ struct dbg_port ports[]= R_SERIAL2_BAUD, R_SERIAL2_TR_CTRL, R_SERIAL2_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser2_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser2_data, set), + 0, + 115200, + 'N', + 8 }, { 3, @@ -144,11 +181,15 @@ struct dbg_port ports[]= R_SERIAL3_BAUD, R_SERIAL3_TR_CTRL, R_SERIAL3_REC_CTRL, - IO_STATE(R_IRQ_MASK1_SET, ser3_data, set) + IO_STATE(R_IRQ_MASK1_SET, ser3_data, set), + 0, + 115200, + 'N', + 8 } }; -static struct tty_driver *serial_driver; +extern struct tty_driver *serial_driver; struct dbg_port* port = #if defined(CONFIG_ETRAX_DEBUG_PORT0) @@ -162,37 +203,44 @@ struct dbg_port* port = #else NULL; #endif -/* Used by serial.c to register a debug_write_function so that the normal - * serial driver is used for kernel debug output - */ -typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len); -debugport_write_function debug_write_function = NULL; +static struct dbg_port* kgdb_port = +#if defined(CONFIG_ETRAX_KGDB_PORT0) + &ports[0]; +#elif defined(CONFIG_ETRAX_KGDB_PORT1) + &ports[1]; +#elif defined(CONFIG_ETRAX_KGDB_PORT2) + &ports[2]; +#elif defined(CONFIG_ETRAX_KGDB_PORT3) + &ports[3]; +#else + NULL; +#endif static void -start_port(void) +start_port(struct dbg_port* p) { unsigned long rec_ctrl = 0; unsigned long tr_ctrl = 0; - if (!port) + if (!p) return; - if (port->started) + if (p->started) return; - port->started = 1; + p->started = 1; - if (port->index == 0) + if (p->index == 0) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); } - else if (port->index == 1) + else if (p->index == 1) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); } - else if (port->index == 2) + else if (p->index == 2) { genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); @@ -211,69 +259,69 @@ start_port(void) *R_GEN_CONFIG = genconfig_shadow; - *port->xoff = + *p->xoff = IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) | IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) | IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0); - switch (port->baudrate) + switch (p->baudrate) { case 0: case 115200: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); break; case 1200: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz); break; case 2400: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz); break; case 4800: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz); break; case 9600: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz); break; case 19200: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz); break; case 38400: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz); break; case 57600: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz); break; default: - *port->baud = + *p->baud = IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); break; } - if (port->parity == 'E') { + if (p->parity == 'E') { rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); tr_ctrl = IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); - } else if (port->parity == 'O') { + } else if (p->parity == 'O') { rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); @@ -288,8 +336,7 @@ start_port(void) IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable); } - - if (port->bits == 7) + if (p->bits == 7) { rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); @@ -300,7 +347,7 @@ start_port(void) tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit); } - *port->rec_ctrl = + *p->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) | IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) | IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) | @@ -308,7 +355,7 @@ start_port(void) IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) | rec_ctrl; - *port->tr_ctrl = + *p->tr_ctrl = IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) | IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) | IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) | @@ -323,8 +370,18 @@ console_write_direct(struct console *co, const char *buf, unsigned int len) int i; unsigned long flags; local_irq_save(flags); + + if (!port) + return; + /* Send data */ for (i = 0; i < len; i++) { + /* LF -> CRLF */ + if (buf[i] == '\n') { + while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) + ; + *port->write = '\r'; + } /* Wait until transmitter is ready and send.*/ while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) ; @@ -333,6 +390,25 @@ console_write_direct(struct console *co, const char *buf, unsigned int len) local_irq_restore(flags); } +int raw_printk(const char *fmt, ...) +{ + static char buf[1024]; + int printed_len; + static int first = 1; + if (first) { + /* Force reinitialization of the port to get manual mode. */ + port->started = 0; + start_port(port); + first = 0; + } + va_list args; + va_start(args, fmt); + printed_len = vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + console_write_direct(NULL, buf, strlen(buf)); + return printed_len; +} + static void console_write(struct console *co, const char *buf, unsigned int len) { @@ -345,18 +421,7 @@ console_write(struct console *co, const char *buf, unsigned int len) return; #endif - start_port(); - -#ifdef CONFIG_ETRAX_KGDB - /* kgdb needs to output debug info using the gdb protocol */ - putDebugString(buf, len); - return; -#endif - - if (debug_write_function) - debug_write_function(co->index, buf, len); - else - console_write_direct(co, buf, len); + console_write_direct(co, buf, len); } /* legacy function */ @@ -374,8 +439,11 @@ getDebugChar(void) { unsigned long readval; + if (!kgdb_port) + return 0; + do { - readval = *port->read; + readval = *kgdb_port->read; } while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail))); return (readval & IO_MASK(R_SERIAL0_READ, data_in)); @@ -386,9 +454,12 @@ getDebugChar(void) void putDebugChar(int val) { - while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) + if (!kgdb_port) + return; + + while (!(*kgdb_port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) ; - *port->write = val; + *kgdb_port->write = val; } /* Enable irq for receiving chars on the debug port, used by kgdb */ @@ -396,19 +467,16 @@ putDebugChar(int val) void enableDebugIRQ(void) { - *R_IRQ_MASK1_SET = port->irq; + if (!kgdb_port) + return; + + *R_IRQ_MASK1_SET = kgdb_port->irq; /* use R_VECT_MASK directly, since we really bypass Linux normal * IRQ handling in kgdb anyway, we don't need to use enable_irq */ *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); - *port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); -} - -static struct tty_driver* -etrax_console_device(struct console* co, int *index) -{ - return serial_driver; + *kgdb_port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); } static int __init @@ -428,11 +496,69 @@ console_setup(struct console *co, char *options) if (*s) port->parity = *s++; if (*s) port->bits = *s++ - '0'; port->started = 0; - start_port(); + start_port(0); } return 0; } +/* This is a dummy serial device that throws away anything written to it. + * This is used when no debug output is wanted. + */ +static struct tty_driver dummy_driver; + +static int dummy_open(struct tty_struct *tty, struct file * filp) +{ + return 0; +} + +static void dummy_close(struct tty_struct *tty, struct file * filp) +{ +} + +static int dummy_write(struct tty_struct * tty, + const unsigned char *buf, int count) +{ + return count; +} + +static int +dummy_write_room(struct tty_struct *tty) +{ + return 8192; +} + +void __init +init_dummy_console(void) +{ + memset(&dummy_driver, 0, sizeof(struct tty_driver)); + dummy_driver.driver_name = "serial"; + dummy_driver.name = "ttyS"; + dummy_driver.major = TTY_MAJOR; + dummy_driver.minor_start = 68; + dummy_driver.num = 1; /* etrax100 has 4 serial ports */ + dummy_driver.type = TTY_DRIVER_TYPE_SERIAL; + dummy_driver.subtype = SERIAL_TYPE_NORMAL; + dummy_driver.init_termios = tty_std_termios; + dummy_driver.init_termios.c_cflag = + B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */ + dummy_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + + dummy_driver.open = dummy_open; + dummy_driver.close = dummy_close; + dummy_driver.write = dummy_write; + dummy_driver.write_room = dummy_write_room; + if (tty_register_driver(&dummy_driver)) + panic("Couldn't register dummy serial driver\n"); +} + +static struct tty_driver* +etrax_console_device(struct console* co, int *index) +{ + if (port) + *index = port->index; + return port ? serial_driver : &dummy_driver; +} + static struct console sercons = { name : "ttyS", write: console_write, @@ -504,28 +630,21 @@ init_etrax_debug(void) static int first = 1; if (!first) { - if (!port) { - register_console(&sercons0); - register_console(&sercons1); - register_console(&sercons2); - register_console(&sercons3); - unregister_console(&sercons); - } + unregister_console(&sercons); + register_console(&sercons0); + register_console(&sercons1); + register_console(&sercons2); + register_console(&sercons3); + init_dummy_console(); return 0; } - first = 0; - if (port) - register_console(&sercons); - return 0; -} -int __init -init_console(void) -{ - serial_driver = alloc_tty_driver(1); - if (!serial_driver) - return -ENOMEM; + first = 0; + register_console(&sercons); + start_port(port); +#ifdef CONFIG_ETRAX_KGDB + start_port(kgdb_port); +#endif return 0; } - __initcall(init_etrax_debug); diff --git a/arch/cris/arch-v10/kernel/dma.c b/arch/cris/arch-v10/kernel/dma.c new file mode 100644 index 0000000..e9a0311 --- /dev/null +++ b/arch/cris/arch-v10/kernel/dma.c @@ -0,0 +1,287 @@ +/* Wrapper for DMA channel allocator that updates DMA client muxing. + * Copyright 2004, Axis Communications AB + * $Id: dma.c,v 1.1 2004/12/13 12:21:51 starvik Exp $ + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> + +#include <asm/dma.h> +#include <asm/arch/svinto.h> + +/* Macro to access ETRAX 100 registers */ +#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_STATE_(reg##_, field##_, _##val) + + +static char used_dma_channels[MAX_DMA_CHANNELS]; +static const char * used_dma_channels_users[MAX_DMA_CHANNELS]; + +int cris_request_dma(unsigned int dmanr, const char * device_id, + unsigned options, enum dma_owner owner) +{ + unsigned long flags; + unsigned long int gens; + int fail = -EINVAL; + + if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) { + printk(KERN_CRIT "cris_request_dma: invalid DMA channel %u\n", dmanr); + return -EINVAL; + } + + local_irq_save(flags); + if (used_dma_channels[dmanr]) { + local_irq_restore(flags); + if (options & DMA_VERBOSE_ON_ERROR) { + printk(KERN_CRIT "Failed to request DMA %i for %s, already allocated by %s\n", dmanr, device_id, used_dma_channels_users[dmanr]); + } + if (options & DMA_PANIC_ON_ERROR) { + panic("request_dma error!"); + } + return -EBUSY; + } + + gens = genconfig_shadow; + + switch(owner) + { + case dma_eth: + if ((dmanr != NETWORK_TX_DMA_NBR) && + (dmanr != NETWORK_RX_DMA_NBR)) { + printk(KERN_CRIT "Invalid DMA channel for eth\n"); + goto bail; + } + break; + case dma_ser0: + if (dmanr == SER0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma6, serial0); + } else if (dmanr == SER0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma7, serial0); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser0\n"); + goto bail; + } + break; + case dma_ser1: + if (dmanr == SER1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma8, serial1); + } else if (dmanr == SER1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma9, serial1); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser1\n"); + goto bail; + } + break; + case dma_ser2: + if (dmanr == SER2_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, serial2); + } else if (dmanr == SER2_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, serial2); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser2\n"); + goto bail; + } + break; + case dma_ser3: + if (dmanr == SER3_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, serial3); + } else if (dmanr == SER3_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, serial3); + } else { + printk(KERN_CRIT "Invalid DMA channel for ser3\n"); + goto bail; + } + break; + case dma_ata: + if (dmanr == ATA_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, ata); + } else if (dmanr == ATA_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, ata); + } else { + printk(KERN_CRIT "Invalid DMA channel for ata\n"); + goto bail; + } + break; + case dma_ext0: + if (dmanr == EXTDMA0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, extdma0); + } else if (dmanr == EXTDMA0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, extdma0); + } else { + printk(KERN_CRIT "Invalid DMA channel for ext0\n"); + goto bail; + } + break; + case dma_ext1: + if (dmanr == EXTDMA1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma6, extdma1); + } else if (dmanr == EXTDMA1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma7, extdma1); + } else { + printk(KERN_CRIT "Invalid DMA channel for ext1\n"); + goto bail; + } + break; + case dma_int6: + if (dmanr == MEM2MEM_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma7, intdma6); + } else { + printk(KERN_CRIT "Invalid DMA channel for int6\n"); + goto bail; + } + break; + case dma_int7: + if (dmanr == MEM2MEM_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma6, intdma7); + } else { + printk(KERN_CRIT "Invalid DMA channel for int7\n"); + goto bail; + } + break; + case dma_usb: + if (dmanr == USB_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma8, usb); + } else if (dmanr == USB_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma9, usb); + } else { + printk(KERN_CRIT "Invalid DMA channel for usb\n"); + goto bail; + } + break; + case dma_scsi0: + if (dmanr == SCSI0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, scsi0); + } else if (dmanr == SCSI0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, scsi0); + } else { + printk(KERN_CRIT "Invalid DMA channel for scsi0\n"); + goto bail; + } + break; + case dma_scsi1: + if (dmanr == SCSI1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, scsi1); + } else if (dmanr == SCSI1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, scsi1); + } else { + printk(KERN_CRIT "Invalid DMA channel for scsi1\n"); + goto bail; + } + break; + case dma_par0: + if (dmanr == PAR0_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma2, par0); + } else if (dmanr == PAR0_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma3, par0); + } else { + printk(KERN_CRIT "Invalid DMA channel for par0\n"); + goto bail; + } + break; + case dma_par1: + if (dmanr == PAR1_TX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma4, par1); + } else if (dmanr == PAR1_RX_DMA_NBR) { + SETS(gens, R_GEN_CONFIG, dma5, par1); + } else { + printk(KERN_CRIT "Invalid DMA channel for par1\n"); + goto bail; + } + break; + default: + printk(KERN_CRIT "Invalid DMA owner.\n"); + goto bail; + } + + used_dma_channels[dmanr] = 1; + used_dma_channels_users[dmanr] = device_id; + + { + volatile int i; + genconfig_shadow = gens; + *R_GEN_CONFIG = genconfig_shadow; + /* Wait 12 cycles before doing any DMA command */ + for(i = 6; i > 0; i--) + nop(); + } + fail = 0; + bail: + local_irq_restore(flags); + return fail; +} + +void cris_free_dma(unsigned int dmanr, const char * device_id) +{ + unsigned long flags; + if ((dmanr < 0) || (dmanr >= MAX_DMA_CHANNELS)) { + printk(KERN_CRIT "cris_free_dma: invalid DMA channel %u\n", dmanr); + return; + } + + local_irq_save(flags); + if (!used_dma_channels[dmanr]) { + printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated\n", dmanr); + } else if (device_id != used_dma_channels_users[dmanr]) { + printk(KERN_CRIT "cris_free_dma: DMA channel %u not allocated by device\n", dmanr); + } else { + switch(dmanr) + { + case 0: + *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH0_CMD, cmd, *R_DMA_CH0_CMD) == + IO_STATE_VALUE(R_DMA_CH0_CMD, cmd, reset)); + break; + case 1: + *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH1_CMD, cmd, *R_DMA_CH1_CMD) == + IO_STATE_VALUE(R_DMA_CH1_CMD, cmd, reset)); + break; + case 2: + *R_DMA_CH2_CMD = IO_STATE(R_DMA_CH2_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH2_CMD, cmd, *R_DMA_CH2_CMD) == + IO_STATE_VALUE(R_DMA_CH2_CMD, cmd, reset)); + break; + case 3: + *R_DMA_CH3_CMD = IO_STATE(R_DMA_CH3_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH3_CMD, cmd, *R_DMA_CH3_CMD) == + IO_STATE_VALUE(R_DMA_CH3_CMD, cmd, reset)); + break; + case 4: + *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH4_CMD, cmd, *R_DMA_CH4_CMD) == + IO_STATE_VALUE(R_DMA_CH4_CMD, cmd, reset)); + break; + case 5: + *R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH5_CMD, cmd, *R_DMA_CH5_CMD) == + IO_STATE_VALUE(R_DMA_CH5_CMD, cmd, reset)); + break; + case 6: + *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH6_CMD, cmd, *R_DMA_CH6_CMD) == + IO_STATE_VALUE(R_DMA_CH6_CMD, cmd, reset)); + break; + case 7: + *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH7_CMD, cmd, *R_DMA_CH7_CMD) == + IO_STATE_VALUE(R_DMA_CH7_CMD, cmd, reset)); + break; + case 8: + *R_DMA_CH8_CMD = IO_STATE(R_DMA_CH8_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH8_CMD, cmd, *R_DMA_CH8_CMD) == + IO_STATE_VALUE(R_DMA_CH8_CMD, cmd, reset)); + break; + case 9: + *R_DMA_CH9_CMD = IO_STATE(R_DMA_CH9_CMD, cmd, reset); + while (IO_EXTRACT(R_DMA_CH9_CMD, cmd, *R_DMA_CH9_CMD) == + IO_STATE_VALUE(R_DMA_CH9_CMD, cmd, reset)); + break; + } + used_dma_channels[dmanr] = 0; + } + local_irq_restore(flags); +} + +EXPORT_SYMBOL(cris_request_dma); +EXPORT_SYMBOL(cris_free_dma); diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 1bc44f4..c0163bf 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $ +/* $Id: entry.S,v 1.28 2005/06/20 05:06:30 starvik Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,22 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.28 2005/06/20 05:06:30 starvik + * Remove unnecessary diff to kernel.org tree + * + * Revision 1.27 2005/03/04 08:16:16 starvik + * Merge of Linux 2.6.11. + * + * Revision 1.26 2005/01/11 13:49:47 starvik + * Added NMI handler. + * + * Revision 1.25 2004/12/27 11:18:32 starvik + * Merge of Linux 2.6.10 (not functional yet). + * + * Revision 1.24 2004/12/22 10:41:23 starvik + * Updates to make v10 compile with the latest SMP aware generic code (even + * though v10 will never have SMP). + * * Revision 1.23 2004/10/19 13:07:37 starvik * Merge of Linux 2.6.9 * @@ -279,6 +295,7 @@ #ifdef CONFIG_PREEMPT ; Check if preemptive kernel scheduling should be done _resume_kernel: + di ; Load current task struct movs.w -8192, $r0 ; THREAD_SIZE = 8192 and.d $sp, $r0 @@ -291,12 +308,7 @@ _need_resched: 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 + jsr preempt_schedule_irq ; Load new task struct movs.w -8192, $r0 ; THREAD_SIZE = 8192 and.d $sp, $r0 @@ -590,15 +602,15 @@ mmu_bus_fault: move.d $r0, [$sp+16] 1: btstq 12, $r1 ; Refill? bpl 2f - lsrq PMD_SHIFT, $r1 ; Get PMD index into PGD (bit 24-31) - move.d [current_pgd], $r0 ; PGD for the current process + lsrq 24, $r1 ; Get PGD index (bit 24-31) + move.d [per_cpu__current_pgd], $r0 ; PGD for the current process move.d [$r0+$r1.d], $r0 ; Get PMD beq 2f nop and.w PAGE_MASK, $r0 ; Remove PMD flags move.d [R_MMU_CAUSE], $r1 lsrq PAGE_SHIFT, $r1 - and.d 0x7ff, $r1 ; Get PTE index into PMD (bit 13-24) + and.d 0x7ff, $r1 ; Get PTE index into PGD (bit 13-23) move.d [$r0+$r1.d], $r1 ; Get PTE beq 2f nop @@ -656,11 +668,6 @@ hwbreakpoint: nop IRQ1_interrupt: - -#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) -;; If we receive a watchdog interrupt while it is not expected, then set -;; up a canonical frame and dump register contents before dying. - ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame push $srp @@ -672,9 +679,16 @@ IRQ1_interrupt: push $r10 ; push orig_r10 clear.d [$sp=$sp-4] ; frametype == 0, normal frame -;; We don't check that we actually were bit by the watchdog as opposed to -;; an external NMI, since there is currently no handler for external NMI. - + move.d [R_IRQ_MASK0_RD], $r1 ; External NMI or watchdog? + and.d 0x80000000, $r1 + beq wdog + move.d $sp, $r10 + jsr handle_nmi + setf m ; Enable NMI again + retb ; Return from NMI + nop +wdog: +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) ;; Check if we're waiting for reset to happen, as signalled by ;; hard_reset_now setting cause_of_death to a magic value. If so, just ;; get stuck until reset happens. @@ -1118,6 +1132,10 @@ sys_call_table: .long sys_mq_getsetattr .long sys_ni_syscall /* reserved for kexec */ .long sys_waitid + .long sys_ni_syscall /* 285 */ /* available */ + .long sys_add_key + .long sys_request_key + .long sys_keyctl /* * NOTE!! This doesn't have to be exact - we just have diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c index 4717f7a..094ff45 100644 --- a/arch/cris/arch-v10/kernel/fasttimer.c +++ b/arch/cris/arch-v10/kernel/fasttimer.c @@ -1,10 +1,20 @@ -/* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $ +/* $Id: fasttimer.c,v 1.9 2005/03/04 08:16:16 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.9 2005/03/04 08:16:16 starvik + * Merge of Linux 2.6.11. + * + * Revision 1.8 2005/01/05 06:09:29 starvik + * cli()/sti() will be obsolete in 2.6.11. + * + * Revision 1.7 2005/01/03 13:35:46 starvik + * Removed obsolete stuff. + * Mark fast timer IRQ as not shared. + * * Revision 1.6 2004/05/14 10:18:39 starvik * Export fast_timer_list * @@ -148,8 +158,7 @@ static int debug_log_cnt_wrapped = 0; #define DEBUG_LOG(string, value) \ { \ unsigned long log_flags; \ - save_flags(log_flags); \ - cli(); \ + local_irq_save(log_flags); \ debug_log_string[debug_log_cnt] = (string); \ debug_log_value[debug_log_cnt] = (unsigned long)(value); \ if (++debug_log_cnt >= DEBUG_LOG_MAX) \ @@ -157,7 +166,7 @@ static int debug_log_cnt_wrapped = 0; debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ debug_log_cnt_wrapped = 1; \ } \ - restore_flags(log_flags); \ + local_irq_restore(log_flags); \ } #else #define DEBUG_LOG(string, value) @@ -320,8 +329,7 @@ void start_one_shot_timer(struct fast_timer *t, D1(printk("sft %s %d us\n", name, delay_us)); - save_flags(flags); - cli(); + local_irq_save(flags); do_gettimeofday_fast(&t->tv_set); tmp = fast_timer_list; @@ -395,7 +403,7 @@ void start_one_shot_timer(struct fast_timer *t, D2(printk("start_one_shot_timer: %d us done\n", delay_us)); - restore_flags(flags); + local_irq_restore(flags); } /* start_one_shot_timer */ static inline int fast_timer_pending (const struct fast_timer * t) @@ -425,11 +433,10 @@ int del_fast_timer(struct fast_timer * t) unsigned long flags; int ret; - save_flags(flags); - cli(); + local_irq_save(flags); ret = detach_fast_timer(t); t->next = t->prev = NULL; - restore_flags(flags); + local_irq_restore(flags); return ret; } /* del_fast_timer */ @@ -444,8 +451,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) struct fast_timer *t; unsigned long flags; - save_flags(flags); - cli(); + local_irq_save(flags); /* Clear timer1 irq */ *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); @@ -462,7 +468,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timer_running = 0; fast_timer_ints++; - restore_flags(flags); + local_irq_restore(flags); t = fast_timer_list; while (t) @@ -482,8 +488,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) fast_timers_expired++; /* Remove this timer before call, since it may reuse the timer */ - save_flags(flags); - cli(); + local_irq_save(flags); if (t->prev) { t->prev->next = t->next; @@ -498,7 +503,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) } t->prev = NULL; t->next = NULL; - restore_flags(flags); + local_irq_restore(flags); if (t->function != NULL) { @@ -515,8 +520,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk(".\n")); } - save_flags(flags); - cli(); + local_irq_save(flags); if ((t = fast_timer_list) != NULL) { /* Start next timer.. */ @@ -535,7 +539,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) #endif start_timer1(us); } - restore_flags(flags); + local_irq_restore(flags); break; } else @@ -546,7 +550,7 @@ timer1_handler(int irq, void *dev_id, struct pt_regs *regs) D1(printk("e! %d\n", us)); } } - restore_flags(flags); + local_irq_restore(flags); } if (!t) @@ -748,13 +752,12 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len #endif used += sprintf(bigbuf + used, "Active timers:\n"); - save_flags(flags); - cli(); + local_irq_save(flags); t = fast_timer_list; while (t != NULL && (used+100 < BIG_BUF_SIZE)) { nextt = t->next; - restore_flags(flags); + local_irq_restore(flags); used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " "d: %6li us data: 0x%08lX" /* " func: 0x%08lX" */ @@ -768,14 +771,14 @@ static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len t->data /* , t->function */ ); - cli(); + local_irq_disable(); if (t->next != nextt) { printk(KERN_WARNING "timer removed!\n"); } t = nextt; } - restore_flags(flags); + local_irq_restore(flags); } if (used - offset < len) @@ -963,7 +966,7 @@ void fast_timer_init(void) if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) fasttimer_proc_entry->read_proc = proc_fasttimer_read; #endif /* PROC_FS */ - if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, + if(request_irq(TIMER1_IRQ_NBR, timer1_handler, 0, "fast timer int", NULL)) { printk("err: timer1 irq\n"); diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S index 2c1dd11..f00c145 100644 --- a/arch/cris/arch-v10/kernel/head.S +++ b/arch/cris/arch-v10/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $ +/* $Id: head.S,v 1.10 2005/06/20 05:12:54 starvik Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,16 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.10 2005/06/20 05:12:54 starvik + * Remove unnecessary diff to kernel.org tree + * + * Revision 1.9 2004/12/13 12:21:51 starvik + * Added I/O and DMA allocators from Linux 2.4 + * + * Revision 1.8 2004/11/22 11:41:14 starvik + * Kernel command line may be supplied to kernel. Not used by Axis but may + * be used by customers. + * * Revision 1.7 2004/05/14 07:58:01 starvik * Merge of changes from 2.4 * @@ -181,6 +191,7 @@ #define CRAMFS_MAGIC 0x28cd3d45 #define RAM_INIT_MAGIC 0x56902387 +#define COMMAND_LINE_MAGIC 0x87109563 #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) @@ -490,6 +501,23 @@ _no_romfs_in_flash: _start_it: + ;; Check if kernel command line is supplied + cmp.d COMMAND_LINE_MAGIC, $r10 + bne no_command_line + nop + + move.d 256, $r13 + move.d cris_command_line, $r10 + or.d 0x80000000, $r11 ; Make it virtual +1: + move.b [$r11+], $r12 + move.b $r12, [$r10+] + subq 1, $r13 + bne 1b + nop + +no_command_line: + ;; 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) @@ -567,76 +595,32 @@ _start_it: ;; Etrax product HW genconfig setup moveq 0,$r0 -#if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \ - && !defined(CONFIG_DMA_MEMCPY) - ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ - | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0 -#endif -#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) - ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \ - | IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0 -#endif -#ifdef CONFIG_DMA_MEMCPY - ; 6/7 memory-memory DMA - or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \ - | IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0 -#endif -#ifdef CONFIG_ETRAX_SERIAL_PORT2 - ; Enable serial port 2 - or.w IO_STATE (R_GEN_CONFIG, ser2, select),$r0 -#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2) - ; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \ - | IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0 -#endif -#endif -#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) - ; Enable serial port 3 - or.w IO_STATE (R_GEN_CONFIG, ser3, select),$r0 -#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3) - ; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA - or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \ - | IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0 -#endif -#endif -#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) - ; parport 0 enabled using DMA 2/3 - or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0 -#endif -#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) - ; parport 1 enabled using DMA 4/5 - or.w IO_STATE (R_GEN_CONFIG, par1, select),$r0 -#endif -#ifdef CONFIG_ETRAX_IDE - ; DMA channels 2 and 3 to ATA, ATA enabled - or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \ - | IO_STATE (R_GEN_CONFIG, dma2, ata) \ - | IO_STATE (R_GEN_CONFIG, ata, select),$r0 -#endif - -#ifdef CONFIG_ETRAX_USB_HOST_PORT1 - ; Set the USB port 1 enable bit - or.d IO_STATE (R_GEN_CONFIG, usb1, select),$r0 -#endif -#ifdef CONFIG_ETRAX_USB_HOST_PORT2 - ; Set the USB port 2 enable bit - or.d IO_STATE (R_GEN_CONFIG, usb2, select),$r0 -#endif -#ifdef CONFIG_ETRAX_USB_HOST - ; Connect DMA channels 8 and 9 to USB - and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \ - | IO_MASK (R_GEN_CONFIG, dma8))) \ - | IO_STATE (R_GEN_CONFIG, dma9, usb) \ - | IO_STATE (R_GEN_CONFIG, dma8, usb),$r0 -#endif - -#ifdef CONFIG_JULIETTE - ; DMA channels 4 and 5 to EXTDMA0, for Juliette - or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \ - | IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0 -#endif + + ;; Init interfaces (disable them). + or.d IO_STATE (R_GEN_CONFIG, scsi0, disable) \ + | IO_STATE (R_GEN_CONFIG, ata, disable) \ + | IO_STATE (R_GEN_CONFIG, par0, disable) \ + | IO_STATE (R_GEN_CONFIG, ser2, disable) \ + | IO_STATE (R_GEN_CONFIG, mio, disable) \ + | IO_STATE (R_GEN_CONFIG, scsi1, disable) \ + | IO_STATE (R_GEN_CONFIG, scsi0w, disable) \ + | IO_STATE (R_GEN_CONFIG, par1, disable) \ + | IO_STATE (R_GEN_CONFIG, ser3, disable) \ + | IO_STATE (R_GEN_CONFIG, mio_w, disable) \ + | IO_STATE (R_GEN_CONFIG, usb1, disable) \ + | IO_STATE (R_GEN_CONFIG, usb2, disable) \ + | IO_STATE (R_GEN_CONFIG, par_w, disable),$r0 + + ;; Init DMA channel muxing (set to unused clients). + or.d IO_STATE (R_GEN_CONFIG, dma2, ata) \ + | IO_STATE (R_GEN_CONFIG, dma3, ata) \ + | IO_STATE (R_GEN_CONFIG, dma4, scsi1) \ + | IO_STATE (R_GEN_CONFIG, dma5, scsi1) \ + | IO_STATE (R_GEN_CONFIG, dma6, unused) \ + | IO_STATE (R_GEN_CONFIG, dma7, unused) \ + | IO_STATE (R_GEN_CONFIG, dma8, usb) \ + | IO_STATE (R_GEN_CONFIG, dma9, usb),$r0 + #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT) or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0 diff --git a/arch/cris/arch-v10/kernel/io_interface_mux.c b/arch/cris/arch-v10/kernel/io_interface_mux.c new file mode 100644 index 0000000..29d48ad --- /dev/null +++ b/arch/cris/arch-v10/kernel/io_interface_mux.c @@ -0,0 +1,879 @@ +/* IO interface mux allocator for ETRAX100LX. + * Copyright 2004, Axis Communications AB + * $Id: io_interface_mux.c,v 1.2 2004/12/21 12:08:38 starvik Exp $ + */ + + +/* C.f. ETRAX100LX Designer's Reference 20.9 */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/init.h> + +#include <asm/arch/svinto.h> +#include <asm/io.h> +#include <asm/arch/io_interface_mux.h> + + +#define DBG(s) + +/* Macro to access ETRAX 100 registers */ +#define SETS(var, reg, field, val) var = (var & ~IO_MASK_(reg##_, field##_)) | \ + IO_STATE_(reg##_, field##_, _##val) + +enum io_if_group { + group_a = (1<<0), + group_b = (1<<1), + group_c = (1<<2), + group_d = (1<<3), + group_e = (1<<4), + group_f = (1<<5) +}; + +struct watcher +{ + void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available); + struct watcher *next; +}; + + +struct if_group +{ + enum io_if_group group; + unsigned char used; + enum cris_io_interface owner; +}; + + +struct interface +{ + enum cris_io_interface ioif; + unsigned char groups; + unsigned char used; + char *owner; + unsigned int gpio_g_in; + unsigned int gpio_g_out; + unsigned char gpio_b; +}; + +static struct if_group if_groups[6] = { + { + .group = group_a, + .used = 0, + }, + { + .group = group_b, + .used = 0, + }, + { + .group = group_c, + .used = 0, + }, + { + .group = group_d, + .used = 0, + }, + { + .group = group_e, + .used = 0, + }, + { + .group = group_f, + .used = 0, + } +}; + +/* The order in the array must match the order of enum + * cris_io_interface in io_interface_mux.h */ +static struct interface interfaces[] = { + /* Begin Non-multiplexed interfaces */ + { + .ioif = if_eth, + .groups = 0, + .gpio_g_in = 0, + .gpio_g_out = 0, + .gpio_b = 0 + }, + { + .ioif = if_serial_0, + .groups = 0, + .gpio_g_in = 0, + .gpio_g_out = 0, + .gpio_b = 0 + }, + /* End Non-multiplexed interfaces */ + { + .ioif = if_serial_1, + .groups = group_e, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x00 + }, + { + .ioif = if_serial_2, + .groups = group_b, + .gpio_g_in = 0x000000c0, + .gpio_g_out = 0x000000c0, + .gpio_b = 0x00 + }, + { + .ioif = if_serial_3, + .groups = group_c, + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x00 + }, + { + .ioif = if_sync_serial_1, + .groups = group_e | group_f, /* if_sync_serial_1 and if_sync_serial_3 + can be used simultaneously */ + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x10 + }, + { + .ioif = if_sync_serial_3, + .groups = group_c | group_f, + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x80 + }, + { + .ioif = if_shared_ram, + .groups = group_a, + .gpio_g_in = 0x0000ff3e, + .gpio_g_out = 0x0000ff38, + .gpio_b = 0x00 + }, + { + .ioif = if_shared_ram_w, + .groups = group_a | group_d, + .gpio_g_in = 0x00ffff3e, + .gpio_g_out = 0x00ffff38, + .gpio_b = 0x00 + }, + { + .ioif = if_par_0, + .groups = group_a, + .gpio_g_in = 0x0000ff3e, + .gpio_g_out = 0x0000ff3e, + .gpio_b = 0x00 + }, + { + .ioif = if_par_1, + .groups = group_d, + .gpio_g_in = 0x3eff0000, + .gpio_g_out = 0x3eff0000, + .gpio_b = 0x00 + }, + { + .ioif = if_par_w, + .groups = group_a | group_d, + .gpio_g_in = 0x00ffff3e, + .gpio_g_out = 0x00ffff3e, + .gpio_b = 0x00 + }, + { + .ioif = if_scsi8_0, + .groups = group_a | group_b | group_f, /* if_scsi8_0 and if_scsi8_1 + can be used simultaneously */ + .gpio_g_in = 0x0000ffff, + .gpio_g_out = 0x0000ffff, + .gpio_b = 0x10 + }, + { + .ioif = if_scsi8_1, + .groups = group_c | group_d | group_f, /* if_scsi8_0 and if_scsi8_1 + can be used simultaneously */ + .gpio_g_in = 0xffff0000, + .gpio_g_out = 0xffff0000, + .gpio_b = 0x80 + }, + { + .ioif = if_scsi_w, + .groups = group_a | group_b | group_d | group_f, + .gpio_g_in = 0x01ffffff, + .gpio_g_out = 0x07ffffff, + .gpio_b = 0x80 + }, + { + .ioif = if_ata, + .groups = group_a | group_b | group_c | group_d, + .gpio_g_in = 0xf9ffffff, + .gpio_g_out = 0xffffffff, + .gpio_b = 0x80 + }, + { + .ioif = if_csp, + .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0xfc + }, + { + .ioif = if_i2c, + .groups = group_f, /* if_csp and if_i2c can be used simultaneously */ + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x03 + }, + { + .ioif = if_usb_1, + .groups = group_e | group_f, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x2c + }, + { + .ioif = if_usb_2, + .groups = group_d, + .gpio_g_in = 0x0e000000, + .gpio_g_out = 0x3c000000, + .gpio_b = 0x00 + }, + /* GPIO pins */ + { + .ioif = if_gpio_grp_a, + .groups = group_a, + .gpio_g_in = 0x0000ff3f, + .gpio_g_out = 0x0000ff3f, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_b, + .groups = group_b, + .gpio_g_in = 0x000000c0, + .gpio_g_out = 0x000000c0, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_c, + .groups = group_c, + .gpio_g_in = 0xc0000000, + .gpio_g_out = 0xc0000000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_d, + .groups = group_d, + .gpio_g_in = 0x3fff0000, + .gpio_g_out = 0x3fff0000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_e, + .groups = group_e, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0x00 + }, + { + .ioif = if_gpio_grp_f, + .groups = group_f, + .gpio_g_in = 0x00000000, + .gpio_g_out = 0x00000000, + .gpio_b = 0xff + } + /* Array end */ +}; + +static struct watcher *watchers = NULL; + +static unsigned int gpio_in_pins = 0xffffffff; +static unsigned int gpio_out_pins = 0xffffffff; +static unsigned char gpio_pb_pins = 0xff; +static unsigned char gpio_pa_pins = 0xff; + +static enum cris_io_interface gpio_pa_owners[8]; +static enum cris_io_interface gpio_pb_owners[8]; +static enum cris_io_interface gpio_pg_owners[32]; + +static int cris_io_interface_init(void); + +static unsigned char clear_group_from_set(const unsigned char groups, struct if_group *group) +{ + return (groups & ~group->group); +} + + +static struct if_group *get_group(const unsigned char groups) +{ + int i; + for (i = 0; i < sizeof(if_groups)/sizeof(struct if_group); i++) { + if (groups & if_groups[i].group) { + return &if_groups[i]; + } + } + return NULL; +} + + +static void notify_watchers(void) +{ + struct watcher *w = watchers; + + DBG(printk("io_interface_mux: notifying watchers\n")); + + while (NULL != w) { + w->notify((const unsigned int)gpio_in_pins, + (const unsigned int)gpio_out_pins, + (const unsigned char)gpio_pa_pins, + (const unsigned char)gpio_pb_pins); + w = w->next; + } +} + + +int cris_request_io_interface(enum cris_io_interface ioif, const char *device_id) +{ + int set_gen_config = 0; + int set_gen_config_ii = 0; + unsigned long int gens; + unsigned long int gens_ii; + struct if_group *grp; + unsigned char group_set; + unsigned long flags; + + (void)cris_io_interface_init(); + + DBG(printk("cris_request_io_interface(%d, \"%s\")\n", ioif, device_id)); + + if ((ioif >= if_max_interfaces) || (ioif < 0)) { + printk(KERN_CRIT "cris_request_io_interface: Bad interface %u submitted for %s\n", + ioif, + device_id); + return -EINVAL; + } + + local_irq_save(flags); + + if (interfaces[ioif].used) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface: Cannot allocate interface for %s, in use by %s\n", + device_id, + interfaces[ioif].owner); + return -EBUSY; + } + + /* Check that all required groups are free before allocating, */ + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + if (grp->used) { + if (grp->group == group_f) { + if ((if_sync_serial_1 == ioif) || + (if_sync_serial_3 == ioif)) { + if ((grp->owner != if_sync_serial_1) && + (grp->owner != if_sync_serial_3)) { + local_irq_restore(flags); + return -EBUSY; + } + } else if ((if_scsi8_0 == ioif) || + (if_scsi8_1 == ioif)) { + if ((grp->owner != if_scsi8_0) && + (grp->owner != if_scsi8_1)) { + local_irq_restore(flags); + return -EBUSY; + } + } + } else { + local_irq_restore(flags); + return -EBUSY; + } + } + group_set = clear_group_from_set(group_set, grp); + } + + /* Are the required GPIO pins available too? */ + if (((interfaces[ioif].gpio_g_in & gpio_in_pins) != interfaces[ioif].gpio_g_in) || + ((interfaces[ioif].gpio_g_out & gpio_out_pins) != interfaces[ioif].gpio_g_out) || + ((interfaces[ioif].gpio_b & gpio_pb_pins) != interfaces[ioif].gpio_b)) { + printk(KERN_CRIT "cris_request_io_interface: Could not get required pins for interface %u\n", + ioif); + return -EBUSY; + } + + /* All needed I/O pins and pin groups are free, allocate. */ + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + grp->used = 1; + grp->owner = ioif; + group_set = clear_group_from_set(group_set, grp); + } + + gens = genconfig_shadow; + gens_ii = gen_config_ii_shadow; + + set_gen_config = 1; + switch (ioif) + { + /* Begin Non-multiplexed interfaces */ + case if_eth: + /* fall through */ + case if_serial_0: + set_gen_config = 0; + break; + /* End Non-multiplexed interfaces */ + case if_serial_1: + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode1, async); + break; + case if_serial_2: + SETS(gens, R_GEN_CONFIG, ser2, select); + break; + case if_serial_3: + SETS(gens, R_GEN_CONFIG, ser3, select); + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode3, async); + break; + case if_sync_serial_1: + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode1, sync); + break; + case if_sync_serial_3: + SETS(gens, R_GEN_CONFIG, ser3, select); + set_gen_config_ii = 1; + SETS(gens_ii, R_GEN_CONFIG_II, sermode3, sync); + break; + case if_shared_ram: + SETS(gens, R_GEN_CONFIG, mio, select); + break; + case if_shared_ram_w: + SETS(gens, R_GEN_CONFIG, mio_w, select); + break; + case if_par_0: + SETS(gens, R_GEN_CONFIG, par0, select); + break; + case if_par_1: + SETS(gens, R_GEN_CONFIG, par1, select); + break; + case if_par_w: + SETS(gens, R_GEN_CONFIG, par0, select); + SETS(gens, R_GEN_CONFIG, par_w, select); + break; + case if_scsi8_0: + SETS(gens, R_GEN_CONFIG, scsi0, select); + break; + case if_scsi8_1: + SETS(gens, R_GEN_CONFIG, scsi1, select); + break; + case if_scsi_w: + SETS(gens, R_GEN_CONFIG, scsi0, select); + SETS(gens, R_GEN_CONFIG, scsi0w, select); + break; + case if_ata: + SETS(gens, R_GEN_CONFIG, ata, select); + break; + case if_csp: + /* fall through */ + case if_i2c: + set_gen_config = 0; + break; + case if_usb_1: + SETS(gens, R_GEN_CONFIG, usb1, select); + break; + case if_usb_2: + SETS(gens, R_GEN_CONFIG, usb2, select); + break; + case if_gpio_grp_a: + /* GPIO groups are only accounted, don't do configuration changes. */ + /* fall through */ + case if_gpio_grp_b: + /* fall through */ + case if_gpio_grp_c: + /* fall through */ + case if_gpio_grp_d: + /* fall through */ + case if_gpio_grp_e: + /* fall through */ + case if_gpio_grp_f: + set_gen_config = 0; + break; + default: + panic("cris_request_io_interface: Bad interface %u submitted for %s\n", + ioif, + device_id); + } + + interfaces[ioif].used = 1; + interfaces[ioif].owner = (char*)device_id; + + if (set_gen_config) { + volatile int i; + genconfig_shadow = gens; + *R_GEN_CONFIG = genconfig_shadow; + /* Wait 12 cycles before doing any DMA command */ + for(i = 6; i > 0; i--) + nop(); + } + if (set_gen_config_ii) { + gen_config_ii_shadow = gens_ii; + *R_GEN_CONFIG_II = gen_config_ii_shadow; + } + + DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + DBG(printk("grabbing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + interfaces[ioif].gpio_g_in, + interfaces[ioif].gpio_g_out, + interfaces[ioif].gpio_b)); + + gpio_in_pins &= ~interfaces[ioif].gpio_g_in; + gpio_out_pins &= ~interfaces[ioif].gpio_g_out; + gpio_pb_pins &= ~interfaces[ioif].gpio_b; + + DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + + local_irq_restore(flags); + + notify_watchers(); + + return 0; +} + + +void cris_free_io_interface(enum cris_io_interface ioif) +{ + struct if_group *grp; + unsigned char group_set; + unsigned long flags; + + (void)cris_io_interface_init(); + + if ((ioif >= if_max_interfaces) || (ioif < 0)) { + printk(KERN_CRIT "cris_free_io_interface: Bad interface %u\n", + ioif); + return; + } + local_irq_save(flags); + if (!interfaces[ioif].used) { + printk(KERN_CRIT "cris_free_io_interface: Freeing free interface %u\n", + ioif); + local_irq_restore(flags); + return; + } + group_set = interfaces[ioif].groups; + while (NULL != (grp = get_group(group_set))) { + if (grp->group == group_f) { + switch (ioif) + { + case if_sync_serial_1: + if ((grp->owner == if_sync_serial_1) && + interfaces[if_sync_serial_3].used) { + grp->owner = if_sync_serial_3; + } else + grp->used = 0; + break; + case if_sync_serial_3: + if ((grp->owner == if_sync_serial_3) && + interfaces[if_sync_serial_1].used) { + grp->owner = if_sync_serial_1; + } else + grp->used = 0; + break; + case if_scsi8_0: + if ((grp->owner == if_scsi8_0) && + interfaces[if_scsi8_1].used) { + grp->owner = if_scsi8_1; + } else + grp->used = 0; + break; + case if_scsi8_1: + if ((grp->owner == if_scsi8_1) && + interfaces[if_scsi8_0].used) { + grp->owner = if_scsi8_0; + } else + grp->used = 0; + break; + default: + grp->used = 0; + } + } else { + grp->used = 0; + } + group_set = clear_group_from_set(group_set, grp); + } + interfaces[ioif].used = 0; + interfaces[ioif].owner = NULL; + + DBG(printk("GPIO pins: available before: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + DBG(printk("freeing pins: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + interfaces[ioif].gpio_g_in, + interfaces[ioif].gpio_g_out, + interfaces[ioif].gpio_b)); + + gpio_in_pins |= interfaces[ioif].gpio_g_in; + gpio_out_pins |= interfaces[ioif].gpio_g_out; + gpio_pb_pins |= interfaces[ioif].gpio_b; + + DBG(printk("GPIO pins: available after: g_in=0x%08x g_out=0x%08x pb=0x%02x\n", + gpio_in_pins, gpio_out_pins, gpio_pb_pins)); + + local_irq_restore(flags); + + notify_watchers(); +} + +/* Create a bitmask from bit 0 (inclusive) to bit stop_bit + (non-inclusive). stop_bit == 0 returns 0x0 */ +static inline unsigned int create_mask(const unsigned stop_bit) +{ + /* Avoid overflow */ + if (stop_bit >= 32) { + return 0xffffffff; + } + return (1<<stop_bit)-1; +} + + +/* port can be 'a', 'b' or 'g' */ +int cris_io_interface_allocate_pins(const enum cris_io_interface ioif, + const char port, + const unsigned start_bit, + const unsigned stop_bit) +{ + unsigned int i; + unsigned int mask = 0; + unsigned int tmp_mask; + unsigned long int flags; + enum cris_io_interface *owners; + + (void)cris_io_interface_init(); + + DBG(printk("cris_io_interface_allocate_pins: if=%d port=%c start=%u stop=%u\n", + ioif, port, start_bit, stop_bit)); + + if (!((start_bit <= stop_bit) && + ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) || + ((port == 'g') && (stop_bit < 32))))) { + return -EINVAL; + } + + mask = create_mask(stop_bit + 1); + tmp_mask = create_mask(start_bit); + mask &= ~tmp_mask; + + DBG(printk("cris_io_interface_allocate_pins: port=%c start=%u stop=%u mask=0x%08x\n", + port, start_bit, stop_bit, mask)); + + local_irq_save(flags); + + switch (port) { + case 'a': + if ((gpio_pa_pins & mask) != mask) { + local_irq_restore(flags); + return -EBUSY; + } + owners = gpio_pa_owners; + gpio_pa_pins &= ~mask; + break; + case 'b': + if ((gpio_pb_pins & mask) != mask) { + local_irq_restore(flags); + return -EBUSY; + } + owners = gpio_pb_owners; + gpio_pb_pins &= ~mask; + break; + case 'g': + if (((gpio_in_pins & mask) != mask) || + ((gpio_out_pins & mask) != mask)) { + local_irq_restore(flags); + return -EBUSY; + } + owners = gpio_pg_owners; + gpio_in_pins &= ~mask; + gpio_out_pins &= ~mask; + break; + default: + local_irq_restore(flags); + return -EINVAL; + } + + for (i = start_bit; i <= stop_bit; i++) { + owners[i] = ioif; + } + local_irq_restore(flags); + + notify_watchers(); + return 0; +} + + +/* port can be 'a', 'b' or 'g' */ +int cris_io_interface_free_pins(const enum cris_io_interface ioif, + const char port, + const unsigned start_bit, + const unsigned stop_bit) +{ + unsigned int i; + unsigned int mask = 0; + unsigned int tmp_mask; + unsigned long int flags; + enum cris_io_interface *owners; + + (void)cris_io_interface_init(); + + if (!((start_bit <= stop_bit) && + ((((port == 'a') || (port == 'b')) && (stop_bit < 8)) || + ((port == 'g') && (stop_bit < 32))))) { + return -EINVAL; + } + + mask = create_mask(stop_bit + 1); + tmp_mask = create_mask(start_bit); + mask &= ~tmp_mask; + + DBG(printk("cris_io_interface_free_pins: port=%c start=%u stop=%u mask=0x%08x\n", + port, start_bit, stop_bit, mask)); + + local_irq_save(flags); + + switch (port) { + case 'a': + if ((~gpio_pa_pins & mask) != mask) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); + } + owners = gpio_pa_owners; + break; + case 'b': + if ((~gpio_pb_pins & mask) != mask) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); + } + owners = gpio_pb_owners; + break; + case 'g': + if (((~gpio_in_pins & mask) != mask) || + ((~gpio_out_pins & mask) != mask)) { + local_irq_restore(flags); + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing free pins"); + } + owners = gpio_pg_owners; + break; + default: + owners = NULL; /* Cannot happen. Shut up, gcc! */ + } + + for (i = start_bit; i <= stop_bit; i++) { + if (owners[i] != ioif) { + printk(KERN_CRIT "cris_io_interface_free_pins: Freeing unowned pins"); + } + } + + /* All was ok, change data. */ + switch (port) { + case 'a': + gpio_pa_pins |= mask; + break; + case 'b': + gpio_pb_pins |= mask; + break; + case 'g': + gpio_in_pins |= mask; + gpio_out_pins |= mask; + break; + } + + for (i = start_bit; i <= stop_bit; i++) { + owners[i] = if_unclaimed; + } + local_irq_restore(flags); + notify_watchers(); + + return 0; +} + + +int cris_io_interface_register_watcher(void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available)) +{ + struct watcher *w; + + (void)cris_io_interface_init(); + + if (NULL == notify) { + return -EINVAL; + } + w = kmalloc(sizeof(*w), GFP_KERNEL); + if (!w) { + return -ENOMEM; + } + w->notify = notify; + w->next = watchers; + watchers = w; + + w->notify((const unsigned int)gpio_in_pins, + (const unsigned int)gpio_out_pins, + (const unsigned char)gpio_pa_pins, + (const unsigned char)gpio_pb_pins); + + return 0; +} + +void cris_io_interface_delete_watcher(void (*notify)(const unsigned int gpio_in_available, + const unsigned int gpio_out_available, + const unsigned char pa_available, + const unsigned char pb_available)) +{ + struct watcher *w = watchers, *prev = NULL; + + (void)cris_io_interface_init(); + + while ((NULL != w) && (w->notify != notify)){ + prev = w; + w = w->next; + } + if (NULL != w) { + if (NULL != prev) { + prev->next = w->next; + } else { + watchers = w->next; + } + kfree(w); + return; + } + printk(KERN_WARNING "cris_io_interface_delete_watcher: Deleting unknown watcher 0x%p\n", notify); +} + + +static int cris_io_interface_init(void) +{ + static int first = 1; + int i; + + if (!first) { + return 0; + } + first = 0; + + for (i = 0; i<8; i++) { + gpio_pa_owners[i] = if_unclaimed; + gpio_pb_owners[i] = if_unclaimed; + gpio_pg_owners[i] = if_unclaimed; + } + for (; i<32; i++) { + gpio_pg_owners[i] = if_unclaimed; + } + return 0; +} + + +module_init(cris_io_interface_init); + + +EXPORT_SYMBOL(cris_request_io_interface); +EXPORT_SYMBOL(cris_free_io_interface); +EXPORT_SYMBOL(cris_io_interface_allocate_pins); +EXPORT_SYMBOL(cris_io_interface_free_pins); +EXPORT_SYMBOL(cris_io_interface_register_watcher); +EXPORT_SYMBOL(cris_io_interface_delete_watcher); diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c index b2f16d6..4b368a1 100644 --- a/arch/cris/arch-v10/kernel/irq.c +++ b/arch/cris/arch-v10/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $ +/* $Id: irq.c,v 1.4 2005/01/04 12:22:28 starvik Exp $ * * linux/arch/cris/kernel/irq.c * @@ -12,11 +12,13 @@ */ #include <asm/irq.h> +#include <linux/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 */ +#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr)); +#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr)); /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is * global just so that the kernel gdb can use it. @@ -102,41 +104,52 @@ static void (*interrupt[NR_IRQS])(void) = { IRQ31_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 -}; +static void enable_crisv10_irq(unsigned int irq); + +static unsigned int startup_crisv10_irq(unsigned int irq) +{ + enable_crisv10_irq(irq); + return 0; +} + +#define shutdown_crisv10_irq disable_crisv10_irq -void arch_setup_irq(int irq) +static void enable_crisv10_irq(unsigned int irq) { - set_int_vector(irq, interrupt[irq]); + unmask_irq(irq); } -void arch_free_irq(int irq) +static void disable_crisv10_irq(unsigned int irq) { - set_int_vector(irq, bad_interrupt[irq]); + mask_irq(irq); } +static void ack_crisv10_irq(unsigned int irq) +{ +} + +static void end_crisv10_irq(unsigned int irq) +{ +} + +static struct hw_interrupt_type crisv10_irq_type = { + .typename = "CRISv10", + .startup = startup_crisv10_irq, + .shutdown = shutdown_crisv10_irq, + .enable = enable_crisv10_irq, + .disable = disable_crisv10_irq, + .ack = ack_crisv10_irq, + .end = end_crisv10_irq, + .set_affinity = NULL +}; + 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. + setting the irq vector table. */ void __init @@ -154,14 +167,15 @@ init_IRQ(void) *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; + /* Initialize IRQ handler descriptiors. */ + for(i = 2; i < NR_IRQS; i++) { + irq_desc[i].handler = &crisv10_irq_type; + set_int_vector(i, interrupt[i]); + } + /* 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 @@ -170,10 +184,6 @@ init_IRQ(void) 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]); - /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ set_int_vector(15, multiple_interrupt); diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c index 7d368c8..b72e6a9 100644 --- a/arch/cris/arch-v10/kernel/kgdb.c +++ b/arch/cris/arch-v10/kernel/kgdb.c @@ -18,6 +18,10 @@ *! Jul 21 1999 Bjorn Wesen eLinux port *! *! $Log: kgdb.c,v $ +*! Revision 1.6 2005/01/14 10:12:17 starvik +*! KGDB on separate port. +*! Console fixes from 2.4. +*! *! Revision 1.5 2004/10/07 13:59:08 starvik *! Corrected call to set_int_vector *! @@ -71,7 +75,7 @@ *! *!--------------------------------------------------------------------------- *! -*! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $ +*! $Id: kgdb.c,v 1.6 2005/01/14 10:12:17 starvik Exp $ *! *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN *! @@ -225,6 +229,7 @@ #include <linux/kernel.h> #include <linux/delay.h> #include <linux/linkage.h> +#include <linux/reboot.h> #include <asm/setup.h> #include <asm/ptrace.h> @@ -1344,12 +1349,11 @@ handle_exception (int sigval) } } -/* The jump is to the address 0x00000002. Performs a complete re-start - from scratch. */ +/* Performs a complete re-start from scratch. */ static void kill_restart () { - __asm__ volatile ("jump 2"); + machine_restart(""); } /********************************** Breakpoint *******************************/ @@ -1506,6 +1510,11 @@ kgdb_handle_serial: bne goback nop + move.d [reg+0x5E], $r10 ; Get DCCR + btstq 8, $r10 ; Test the U-flag. + bmi goback + nop + ;; ;; Handle the communication ;; diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c index 87ff377..69e28b4 100644 --- a/arch/cris/arch-v10/kernel/process.c +++ b/arch/cris/arch-v10/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $ +/* $Id: process.c,v 1.12 2004/12/27 11:18:32 starvik Exp $ * * linux/arch/cris/kernel/process.c * @@ -101,6 +101,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) regs.r11 = (unsigned long)fn; regs.r12 = (unsigned long)arg; regs.irp = (unsigned long)kernel_thread_helper; + regs.dccr = 1 << I_DCCR_BITNR; /* Ok, create the new process.. */ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c index 581ecab..130dd21 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -11,6 +11,7 @@ #include <linux/ptrace.h> #include <linux/user.h> #include <linux/signal.h> +#include <linux/security.h> #include <asm/uaccess.h> #include <asm/page.h> @@ -86,9 +87,13 @@ sys_ptrace(long request, long pid, long addr, long data) ret = -EPERM; if (request == PTRACE_TRACEME) { + /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - + ret = security_ptrace(current->parent, current); + if (ret) + goto out; + /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; ret = 0; goto out; @@ -207,7 +212,7 @@ sys_ptrace(long request, long pid, long addr, long data) case PTRACE_KILL: ret = 0; - if (child->state == TASK_ZOMBIE) + if (child->exit_state == EXIT_ZOMBIE) break; child->exit_code = SIGKILL; diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c index 561a890..38fd44d 100644 --- a/arch/cris/arch-v10/kernel/shadows.c +++ b/arch/cris/arch-v10/kernel/shadows.c @@ -1,4 +1,4 @@ -/* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ +/* $Id: shadows.c,v 1.2 2004/12/13 12:21:51 starvik Exp $ * * Various shadow registers. Defines for these are in include/asm-etrax100/io.h */ @@ -6,6 +6,7 @@ /* Shadows for internal Etrax-registers */ unsigned long genconfig_shadow; +unsigned long gen_config_ii_shadow; unsigned long port_g_data_shadow; unsigned char port_pa_dir_shadow; unsigned char port_pa_data_shadow; diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c index da491f4..34a27ea 100644 --- a/arch/cris/arch-v10/kernel/traps.c +++ b/arch/cris/arch-v10/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ +/* $Id: traps.c,v 1.4 2005/04/24 18:47:55 starvik Exp $ * * linux/arch/cris/arch-v10/traps.c * @@ -16,6 +16,8 @@ #include <asm/uaccess.h> #include <asm/arch/sv_addr_ag.h> +extern int raw_printk(const char *fmt, ...); + void show_registers(struct pt_regs * regs) { @@ -26,18 +28,18 @@ show_registers(struct pt_regs * regs) register. */ unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", + raw_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", + raw_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", + raw_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", + raw_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", + raw_printk("r12: %08lx r13: %08lx oR10: %08lx sp: %08lx\n", + regs->r12, regs->r13, regs->orig_r10, regs); + raw_printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); + raw_printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); /* @@ -53,7 +55,7 @@ show_registers(struct pt_regs * regs) if (usp != 0) show_stack (NULL, NULL); - printk("\nCode: "); + raw_printk("\nCode: "); if(regs->irp < PAGE_OFFSET) goto bad; @@ -70,16 +72,16 @@ show_registers(struct pt_regs * regs) unsigned char c; if(__get_user(c, &((unsigned char*)regs->irp)[i])) { bad: - printk(" Bad IP value."); + raw_printk(" Bad IP value."); break; } if (i == 0) - printk("(%02x) ", c); + raw_printk("(%02x) ", c); else - printk("%02x ", c); + raw_printk("%02x ", c); } - printk("\n"); + raw_printk("\n"); } } @@ -121,7 +123,7 @@ die_if_kernel(const char * str, struct pt_regs * regs, long err) stop_watchdog(); #endif - printk("%s: %04lx\n", str, err & 0xffff); + raw_printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); @@ -130,3 +132,8 @@ die_if_kernel(const char * str, struct pt_regs * regs, long err) #endif do_exit(SIGSEGV); } + +void arch_enable_nmi(void) +{ + asm volatile("setf m"); +} diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c index 6805cdb..fe26150 100644 --- a/arch/cris/arch-v10/mm/fault.c +++ b/arch/cris/arch-v10/mm/fault.c @@ -14,6 +14,7 @@ #include <asm/uaccess.h> #include <asm/pgtable.h> #include <asm/arch/svinto.h> +#include <asm/mmu_context.h> /* debug of low-level TLB reload */ #undef DEBUG @@ -24,8 +25,6 @@ #define D(x) #endif -extern volatile pgd_t *current_pgd; - extern const struct exception_table_entry *search_exception_tables(unsigned long addr); @@ -46,7 +45,7 @@ handle_mmu_bus_fault(struct pt_regs *regs) int page_id; int acc, inv; #endif - pgd_t* pgd = (pgd_t*)current_pgd; + pgd_t* pgd = (pgd_t*)per_cpu(current_pgd, smp_processor_id()); pmd_t *pmd; pte_t pte; int miss, we, writeac; @@ -94,24 +93,3 @@ handle_mmu_bus_fault(struct pt_regs *regs) *R_TLB_LO = pte_val(pte); local_irq_restore(flags); } - -/* 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 index a9f975a..ff3481e 100644 --- a/arch/cris/arch-v10/mm/init.c +++ b/arch/cris/arch-v10/mm/init.c @@ -42,7 +42,7 @@ paging_init(void) * switch_mm) */ - current_pgd = init_mm.pgd; + per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd; /* initialise the TLB (tlb.c) */ diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c index 9d06125..70a5523 100644 --- a/arch/cris/arch-v10/mm/tlb.c +++ b/arch/cris/arch-v10/mm/tlb.c @@ -139,53 +139,6 @@ flush_tlb_page(struct vm_area_struct *vma, 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.page_id; - 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 @@ -237,7 +190,7 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, * the pgd. */ - current_pgd = next->pgd; + per_cpu(current_pgd, smp_processor_id()) = next->pgd; /* switch context in the MMU */ |