diff options
author | Jesper Nilsson <jesper@jni.nu> | 2018-03-11 11:05:23 +0100 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2018-03-16 10:56:05 +0100 |
commit | c690eddc2f3b44b24520f4a77cc3a4c9bde7d571 (patch) | |
tree | b7ba2caa6ebb2e36a529f9bf7182c9e0a73d53c4 /arch/cris/arch-v32 | |
parent | bb9d812643d8a121df7d614a2b9c60193a92deb0 (diff) | |
download | linux-stable-c690eddc2f3b44b24520f4a77cc3a4c9bde7d571.tar.gz linux-stable-c690eddc2f3b44b24520f4a77cc3a4c9bde7d571.tar.bz2 linux-stable-c690eddc2f3b44b24520f4a77cc3a4c9bde7d571.zip |
CRIS: Drop support for the CRIS port
The port was added back in 2000 so it's no longer even a good source
of inspiration for newer ports (if it ever was)
The last SoC (ARTPEC-3) with a CRIS main CPU was launched in 2008.
Coupled with time and working developer board hardware being
in low supply, it's time to drop the port from Linux.
So long and thanks for all the fish!
Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/cris/arch-v32')
60 files changed, 0 insertions, 19011 deletions
diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig deleted file mode 100644 index 958dabfca7eb..000000000000 --- a/arch/cris/arch-v32/Kconfig +++ /dev/null @@ -1,211 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -if ETRAX_ARCH_V32 - -source arch/cris/arch-v32/mach-fs/Kconfig -source arch/cris/arch-v32/mach-a3/Kconfig - -source drivers/cpufreq/Kconfig - -config ETRAX_DRAM_VIRTUAL_BASE - hex - depends on ETRAX_ARCH_V32 - default "c0000000" - -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_PORT4 - bool "Serial-4" - depends on ETRAX_SERIAL_PORTS = 5 - help - Use serial port 4 for kernel debugging. - -endchoice - -config ETRAX_MEM_GRP1_CONFIG - hex "MEM_GRP1_CONFIG" - depends on ETRAX_ARCH_V32 - default "4044a" - help - Waitstates for flash. The default value is suitable for the - standard flashes used in axis products (120 ns). - -config ETRAX_MEM_GRP2_CONFIG - hex "MEM_GRP2_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - Waitstates for SRAM. 0 is a good choice for most Axis products. - -config ETRAX_MEM_GRP3_CONFIG - hex "MEM_GRP3_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - Waitstates for CSP0-3. 0 is a good choice for most Axis products. - It may need to be changed if external devices such as extra - register-mapped LEDs are used. - -config ETRAX_MEM_GRP4_CONFIG - hex "MEM_GRP4_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - Waitstates for CSP4-6. 0 is a good choice for most Axis products. - -config ETRAX_SDRAM_GRP0_CONFIG - hex "SDRAM_GRP0_CONFIG" - depends on ETRAX_ARCH_V32 - default "336" - help - SDRAM configuration for group 0. The value depends on the - hardware configuration. The default value is suitable - for 32 MB organized as two 16 bits chips (e.g. Axis - part number 18550) connected as one 32 bit device (i.e. in - the same group). - -config ETRAX_SDRAM_GRP1_CONFIG - hex "SDRAM_GRP1_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - SDRAM configuration for group 1. The default value is 0 - because group 1 is not used in the default configuration, - described in the help for SDRAM_GRP0_CONFIG. - -config ETRAX_SDRAM_TIMING - hex "SDRAM_TIMING" - depends on ETRAX_ARCH_V32 - default "104a" - help - SDRAM timing parameters. The default value is ok for - most hardwares but large SDRAMs may require a faster - refresh (a.k.a 8K refresh). The default value implies - 100MHz clock and SDR mode. - -config ETRAX_SDRAM_COMMAND - hex "SDRAM_COMMAND" - depends on ETRAX_ARCH_V32 - default "0" - help - SDRAM command. Should be 0 unless you really know what - you are doing (may be != 0 for unusual address line - mappings such as in a MCM).. - -config ETRAX_DEF_GIO_PA_OE - hex "GIO_PA_OE" - depends on ETRAX_ARCH_V32 - default "1c" - help - Configures the direction of general port A bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PA_OUT - hex "GIO_PA_OUT" - depends on ETRAX_ARCH_V32 - default "00" - help - Configures the initial data for the general port A bits. Most - products should use 00 here. - -config ETRAX_DEF_GIO_PB_OE - hex "GIO_PB_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port B bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PB_OUT - hex "GIO_PB_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port B bits. Most - products should use 00000 here. - -config ETRAX_DEF_GIO_PC_OE - hex "GIO_PC_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port C bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PC_OUT - hex "GIO_PC_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port C bits. Most - products should use 00000 here. - -config ETRAX_DEF_GIO_PD_OE - hex "GIO_PD_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port D bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PD_OUT - hex "GIO_PD_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port D bits. Most - products should use 00000 here. - -config ETRAX_DEF_GIO_PE_OE - hex "GIO_PE_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port E bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PE_OUT - hex "GIO_PE_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port E bits. Most - products should use 00000 here. - -endif diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig deleted file mode 100644 index 4d2d744bced2..000000000000 --- a/arch/cris/arch-v32/drivers/Kconfig +++ /dev/null @@ -1,263 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -if ETRAX_ARCH_V32 - -config ETRAX_ETHERNET - bool "Ethernet support" - depends on ETRAX_ARCH_V32 && NETDEVICES - select MII - help - This option enables the ETRAX FS built-in 10/100Mbit Ethernet - controller. - -config ETRAX_NO_PHY - bool "PHY not present" - depends on ETRAX_ETHERNET - help - This option disables all MDIO communication with an ethernet - transceiver connected to the MII interface. This option shall - typically be enabled if the MII interface is connected to a - switch. This option should normally be disabled. If enabled, - speed and duplex will be locked to 100 Mbit and full duplex. - -config ETRAXFS_SERIAL - bool "Serial-port support" - depends on ETRAX_ARCH_V32 - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - help - Enables the ETRAX FS serial driver for ser0 (ttyS0) - You probably want this enabled. - -config ETRAX_RS485 - bool "RS-485 support" - depends on ETRAXFS_SERIAL - help - Enables support for RS-485 serial communication. - -config ETRAX_RS485_DISABLE_RECEIVER - bool "Disable serial receiver" - depends on ETRAX_RS485 - help - It is necessary to disable the serial receiver to avoid serial - loopback. Not all products are able to do this in software only. - -config ETRAX_SERIAL_PORT0 - bool "Serial port 0 enabled" - depends on ETRAXFS_SERIAL - help - Enables the ETRAX FS serial driver for ser0 (ttyS0) - Normally you want this on. You can control what DMA channels to use - if you do not need DMA to something else. - ser0 can use dma4 or dma6 for output and dma5 or dma7 for input. - -config ETRAX_SERIAL_PORT1 - bool "Serial port 1 enabled" - depends on ETRAXFS_SERIAL - help - Enables the ETRAX FS serial driver for ser1 (ttyS1). - -config ETRAX_SERIAL_PORT2 - bool "Serial port 2 enabled" - depends on ETRAXFS_SERIAL - help - Enables the ETRAX FS serial driver for ser2 (ttyS2). - -config ETRAX_SERIAL_PORT3 - bool "Serial port 3 enabled" - depends on ETRAXFS_SERIAL - help - Enables the ETRAX FS serial driver for ser3 (ttyS3). - -config ETRAX_SYNCHRONOUS_SERIAL - bool "Synchronous serial-port support" - depends on ETRAX_ARCH_V32 - help - Enables the ETRAX FS synchronous serial driver. - -config ETRAX_SYNCHRONOUS_SERIAL_PORT0 - bool "Synchronous serial port 0 enabled" - depends on ETRAX_SYNCHRONOUS_SERIAL - help - Enabled synchronous serial port 0. - -config ETRAX_SYNCHRONOUS_SERIAL0_DMA - bool "Enable DMA on synchronous serial port 0." - depends on ETRAX_SYNCHRONOUS_SERIAL_PORT0 - help - A synchronous serial port can run in manual or DMA mode. - Selecting this option will make it run in DMA mode. - -config ETRAX_SYNCHRONOUS_SERIAL_PORT1 - bool "Synchronous serial port 1 enabled" - depends on ETRAX_SYNCHRONOUS_SERIAL && ETRAXFS - help - Enabled synchronous serial port 1. - -config ETRAX_SYNCHRONOUS_SERIAL1_DMA - bool "Enable DMA on synchronous serial port 1." - depends on ETRAX_SYNCHRONOUS_SERIAL_PORT1 - help - A synchronous serial port can run in manual or DMA mode. - Selecting this option will make it run in DMA mode. - -config ETRAX_AXISFLASHMAP - bool "Axis flash-map support" - depends on ETRAX_ARCH_V32 - select MTD - select MTD_CFI - select MTD_CFI_AMDSTD - select MTD_JEDECPROBE - select MTD_BLOCK - select MTD_COMPLEX_MAPPINGS - select MTD_MTDRAM - help - This option enables MTD mapping of flash devices. Needed to use - flash memories. If unsure, say Y. - -config ETRAX_AXISFLASHMAP_MTD0WHOLE - bool "MTD0 is whole boot flash device" - depends on ETRAX_AXISFLASHMAP - help - When this option is not set, mtd0 refers to the first partition - on the boot flash device. When set, mtd0 refers to the whole - device, with mtd1 referring to the first partition etc. - -config ETRAX_PTABLE_SECTOR - int "Byte-offset of partition table sector" - depends on ETRAX_AXISFLASHMAP - default "65536" - help - Byte-offset of the partition table in the first flash chip. - The default value is 64kB and should not be changed unless - you know exactly what you are doing. The only valid reason - for changing this is when the flash block size is bigger - than 64kB (e.g. when using two parallel 16 bit flashes). - -config ETRAX_NANDFLASH - bool "NAND flash support" - depends on ETRAX_ARCH_V32 - select MTD_NAND - help - This option enables MTD mapping of NAND flash devices. Needed to use - NAND flash memories. If unsure, say Y. - -config ETRAX_NANDBOOT - bool "Boot from NAND flash" - depends on ETRAX_NANDFLASH - help - This options enables booting from NAND flash devices. - Say Y if your boot code, kernel and root file system is in - NAND flash. Say N if they are in NOR flash. - -config ETRAX_CARDBUS - bool "Cardbus support" - depends on ETRAX_ARCH_V32 - help - Enabled the ETRAX Cardbus driver. - -config PCI - bool - depends on ETRAX_CARDBUS - default y - select HAVE_GENERIC_DMA_COHERENT - -config ETRAX_IOP_FW_LOAD - tristate "IO-processor hotplug firmware loading support" - depends on ETRAX_ARCH_V32 - select FW_LOADER - help - Enables IO-processor hotplug firmware loading support. - -config ETRAX_STREAMCOPROC - tristate "Stream co-processor driver enabled" - depends on ETRAX_ARCH_V32 - help - This option enables a driver for the stream co-processor - for cryptographic operations. - -config ETRAX_MMC_IOP - tristate "MMC/SD host driver using IO-processor" - depends on ETRAX_ARCH_V32 && MMC - help - This option enables the SD/MMC host controller interface. - The host controller is implemented using the built in - IO-Processor. Only the SPU is used in this implementation. - -config ETRAX_SPI_MMC -# Make this one of several "choices" (possible simultaneously but -# suggested uniquely) when an IOP driver emerges for "real" MMC/SD -# protocol support. - tristate - depends on !ETRAX_MMC_IOP - default MMC - select SPI - select MMC_SPI - -# While the board info is MMC_SPI only, the drivers are written to be -# independent of MMC_SPI, so we'll keep SPI non-dependent on the -# MMC_SPI config choices (well, except for a single depends-on-line -# for the board-info file until a separate non-MMC SPI board file -# emerges). -# FIXME: When that happens, we'll need to be able to ask for and -# configure non-MMC SPI ports together with MMC_SPI ports (if multiple -# SPI ports are enabled). - -config SPI_ETRAX_SSER - tristate - depends on SPI_MASTER && ETRAX_ARCH_V32 - select SPI_BITBANG - help - This enables using an synchronous serial (sser) port as a - SPI master controller on Axis ETRAX FS and later. The - driver can be configured to use any sser port. - -config SPI_ETRAX_GPIO - tristate - depends on SPI_MASTER && ETRAX_ARCH_V32 - select SPI_BITBANG - help - This enables using GPIO pins port as a SPI master controller - on Axis ETRAX FS and later. The driver can be configured to - use any GPIO pins. - -config ETRAX_SPI_SSER0 - tristate "SPI using synchronous serial port 0 (sser0)" - depends on ETRAX_SPI_MMC - default m if MMC_SPI=m - default y if MMC_SPI=y - default y if MMC_SPI=n - select SPI_ETRAX_SSER - help - Say Y for an MMC/SD socket connected to synchronous serial port 0, - or for devices using the SPI protocol on that port. Say m if you - want to build it as a module, which will be named spi_crisv32_sser. - (You need to select MMC separately.) - -config ETRAX_SPI_SSER1 - tristate "SPI using synchronous serial port 1 (sser1)" - depends on ETRAX_SPI_MMC - default m if MMC_SPI=m && ETRAX_SPI_SSER0=n - default y if MMC_SPI=y && ETRAX_SPI_SSER0=n - default y if MMC_SPI=n && ETRAX_SPI_SSER0=n - select SPI_ETRAX_SSER - help - Say Y for an MMC/SD socket connected to synchronous serial port 1, - or for devices using the SPI protocol on that port. Say m if you - want to build it as a module, which will be named spi_crisv32_sser. - (You need to select MMC separately.) - -config ETRAX_SPI_GPIO - tristate "Bitbanged SPI using gpio pins" - depends on ETRAX_SPI_MMC - select SPI_ETRAX_GPIO - default m if MMC_SPI=m && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n - default y if MMC_SPI=y && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n - default y if MMC_SPI=n && ETRAX_SPI_SSER0=n && ETRAX_SPI_SSER1=n - help - Say Y for an MMC/SD socket connected to general I/O pins (but not - a complete synchronous serial ports), or for devices using the SPI - protocol on general I/O pins. Slow and slows down the system. - Say m to build it as a module, which will be called spi_crisv32_gpio. - (You need to select MMC separately.) - -endif diff --git a/arch/cris/arch-v32/drivers/Makefile b/arch/cris/arch-v32/drivers/Makefile deleted file mode 100644 index 57c9568707b0..000000000000 --- a/arch/cris/arch-v32/drivers/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for Etrax-specific drivers -# - -obj-$(CONFIG_ETRAX_STREAMCOPROC) += cryptocop.o -obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o -obj-$(CONFIG_ETRAXFS) += mach-fs/ -obj-$(CONFIG_CRIS_MACH_ARTPEC3) += mach-a3/ -obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o -obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o -obj-$(CONFIG_PCI) += pci/ diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c deleted file mode 100644 index 87656c41fec7..000000000000 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Physical mapping layer for MTD using the Axis partitiontable format - * - * Copyright (c) 2001-2007 Axis Communications AB - * - * This file is under the GPL. - * - * First partition is always sector 0 regardless of if we find a partitiontable - * or not. In the start of the next sector, there can be a partitiontable that - * tells us what other partitions to define. If there isn't, we use a default - * partition split defined below. - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/slab.h> - -#include <linux/mtd/concat.h> -#include <linux/mtd/map.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/mtdram.h> -#include <linux/mtd/partitions.h> - -#include <asm/axisflashmap.h> -#include <asm/mmu.h> - -#define MEM_CSE0_SIZE (0x04000000) -#define MEM_CSE1_SIZE (0x04000000) - -#define FLASH_UNCACHED_ADDR KSEG_E -#define FLASH_CACHED_ADDR KSEG_F - -#define PAGESIZE (512) - -#if CONFIG_ETRAX_FLASH_BUSWIDTH==1 -#define flash_data __u8 -#elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 -#define flash_data __u16 -#elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 -#define flash_data __u32 -#endif - -/* From head.S */ -extern unsigned long romfs_in_flash; /* 1 when romfs_start, _length in flash */ -extern unsigned long romfs_start, romfs_length; -extern unsigned long nand_boot; /* 1 when booted from nand flash */ - -struct partition_name { - char name[6]; -}; - -/* The master mtd for the entire flash. */ -struct mtd_info* axisflash_mtd = NULL; - -/* Map driver functions. */ - -static map_word flash_read(struct map_info *map, unsigned long ofs) -{ - map_word tmp; - tmp.x[0] = *(flash_data *)(map->map_priv_1 + ofs); - return tmp; -} - -static void flash_copy_from(struct map_info *map, void *to, - unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void flash_write(struct map_info *map, map_word d, unsigned long adr) -{ - *(flash_data *)(map->map_priv_1 + adr) = (flash_data)d.x[0]; -} - -/* - * The map for chip select e0. - * - * We run into tricky coherence situations if we mix cached with uncached - * accesses to we only use the uncached version here. - * - * The size field is the total size where the flash chips may be mapped on the - * chip select. MTD probes should find all devices there and it does not matter - * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD - * probes will ignore them. - * - * The start address in map_priv_1 is in virtual memory so we cannot use - * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start - * address of cse0. - */ -static struct map_info map_cse0 = { - .name = "cse0", - .size = MEM_CSE0_SIZE, - .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, - .read = flash_read, - .copy_from = flash_copy_from, - .write = flash_write, - .map_priv_1 = FLASH_UNCACHED_ADDR -}; - -/* - * The map for chip select e1. - * - * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong - * address, but there isn't. - */ -static struct map_info map_cse1 = { - .name = "cse1", - .size = MEM_CSE1_SIZE, - .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, - .read = flash_read, - .copy_from = flash_copy_from, - .write = flash_write, - .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE -}; - -#define MAX_PARTITIONS 7 -#ifdef CONFIG_ETRAX_NANDBOOT -#define NUM_DEFAULT_PARTITIONS 4 -#define DEFAULT_ROOTFS_PARTITION_NO 2 -#define DEFAULT_MEDIA_SIZE 0x2000000 /* 32 megs */ -#else -#define NUM_DEFAULT_PARTITIONS 3 -#define DEFAULT_ROOTFS_PARTITION_NO (-1) -#define DEFAULT_MEDIA_SIZE 0x800000 /* 8 megs */ -#endif - -#if (MAX_PARTITIONS < NUM_DEFAULT_PARTITIONS) -#error MAX_PARTITIONS must be >= than NUM_DEFAULT_PARTITIONS -#endif - -/* Initialize the ones normally used. */ -static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { - { - .name = "part0", - .size = CONFIG_ETRAX_PTABLE_SECTOR, - .offset = 0 - }, - { - .name = "part1", - .size = 0, - .offset = 0 - }, - { - .name = "part2", - .size = 0, - .offset = 0 - }, - { - .name = "part3", - .size = 0, - .offset = 0 - }, - { - .name = "part4", - .size = 0, - .offset = 0 - }, - { - .name = "part5", - .size = 0, - .offset = 0 - }, - { - .name = "part6", - .size = 0, - .offset = 0 - }, -}; - - -/* If no partition-table was found, we use this default-set. - * Default flash size is 8MB (NOR). CONFIG_ETRAX_PTABLE_SECTOR is most - * likely the size of one flash block and "filesystem"-partition needs - * to be >=5 blocks to be able to use JFFS. - */ -static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { - { - .name = "boot firmware", - .size = CONFIG_ETRAX_PTABLE_SECTOR, - .offset = 0 - }, - { - .name = "kernel", - .size = 10 * CONFIG_ETRAX_PTABLE_SECTOR, - .offset = CONFIG_ETRAX_PTABLE_SECTOR - }, -#define FILESYSTEM_SECTOR (11 * CONFIG_ETRAX_PTABLE_SECTOR) -#ifdef CONFIG_ETRAX_NANDBOOT - { - .name = "rootfs", - .size = 10 * CONFIG_ETRAX_PTABLE_SECTOR, - .offset = FILESYSTEM_SECTOR - }, -#undef FILESYSTEM_SECTOR -#define FILESYSTEM_SECTOR (21 * CONFIG_ETRAX_PTABLE_SECTOR) -#endif - { - .name = "rwfs", - .size = DEFAULT_MEDIA_SIZE - FILESYSTEM_SECTOR, - .offset = FILESYSTEM_SECTOR - } -}; - -#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE -/* Main flash device */ -static struct mtd_partition main_partition = { - .name = "main", - .size = 0, - .offset = 0 -}; -#endif - -/* Auxiliary partition if we find another flash */ -static struct mtd_partition aux_partition = { - .name = "aux", - .size = 0, - .offset = 0 -}; - -/* - * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash - * chips in that order (because the amd_flash-driver is faster). - */ -static struct mtd_info *probe_cs(struct map_info *map_cs) -{ - struct mtd_info *mtd_cs = NULL; - - printk(KERN_INFO - "%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n", - map_cs->name, map_cs->size, map_cs->map_priv_1); - -#ifdef CONFIG_MTD_CFI - mtd_cs = do_map_probe("cfi_probe", map_cs); -#endif -#ifdef CONFIG_MTD_JEDECPROBE - if (!mtd_cs) - mtd_cs = do_map_probe("jedec_probe", map_cs); -#endif - - return mtd_cs; -} - -/* - * Probe each chip select individually for flash chips. If there are chips on - * both cse0 and cse1, the mtd_info structs will be concatenated to one struct - * so that MTD partitions can cross chip boundaries. - * - * The only known restriction to how you can mount your chips is that each - * chip select must hold similar flash chips. But you need external hardware - * to do that anyway and you can put totally different chips on cse0 and cse1 - * so it isn't really much of a restriction. - */ -extern struct mtd_info* __init crisv32_nand_flash_probe (void); -static struct mtd_info *flash_probe(void) -{ - struct mtd_info *mtd_cse0; - struct mtd_info *mtd_cse1; - struct mtd_info *mtd_total; - struct mtd_info *mtds[2]; - int count = 0; - - if ((mtd_cse0 = probe_cs(&map_cse0)) != NULL) - mtds[count++] = mtd_cse0; - if ((mtd_cse1 = probe_cs(&map_cse1)) != NULL) - mtds[count++] = mtd_cse1; - - if (!mtd_cse0 && !mtd_cse1) { - /* No chip found. */ - return NULL; - } - - if (count > 1) { - /* Since the concatenation layer adds a small overhead we - * could try to figure out if the chips in cse0 and cse1 are - * identical and reprobe the whole cse0+cse1 window. But since - * flash chips are slow, the overhead is relatively small. - * So we use the MTD concatenation layer instead of further - * complicating the probing procedure. - */ - mtd_total = mtd_concat_create(mtds, count, "cse0+cse1"); - if (!mtd_total) { - printk(KERN_ERR "%s and %s: Concatenation failed!\n", - map_cse0.name, map_cse1.name); - - /* The best we can do now is to only use what we found - * at cse0. */ - mtd_total = mtd_cse0; - map_destroy(mtd_cse1); - } - } else - mtd_total = mtd_cse0 ? mtd_cse0 : mtd_cse1; - - return mtd_total; -} - -/* - * Probe the flash chip(s) and, if it succeeds, read the partition-table - * and register the partitions with MTD. - */ -static int __init init_axis_flash(void) -{ - struct mtd_info *main_mtd; - struct mtd_info *aux_mtd = NULL; - int err = 0; - int pidx = 0; - struct partitiontable_head *ptable_head = NULL; - struct partitiontable_entry *ptable; - int ptable_ok = 0; - static char page[PAGESIZE]; - size_t len; - int ram_rootfs_partition = -1; /* -1 => no RAM rootfs partition */ - int part; - struct mtd_partition *partition; - - /* We need a root fs. If it resides in RAM, we need to use an - * MTDRAM device, so it must be enabled in the kernel config, - * but its size must be configured as 0 so as not to conflict - * with our usage. - */ -#if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) - if (!romfs_in_flash && !nand_boot) { - printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " - "device; configure CONFIG_MTD_MTDRAM with size = 0!\n"); - panic("This kernel cannot boot from RAM!\n"); - } -#endif - - main_mtd = flash_probe(); - if (main_mtd) - printk(KERN_INFO "%s: 0x%08llx bytes of NOR flash memory.\n", - main_mtd->name, main_mtd->size); - -#ifdef CONFIG_ETRAX_NANDFLASH - aux_mtd = crisv32_nand_flash_probe(); - if (aux_mtd) - printk(KERN_INFO "%s: 0x%08x bytes of NAND flash memory.\n", - aux_mtd->name, aux_mtd->size); - -#ifdef CONFIG_ETRAX_NANDBOOT - { - struct mtd_info *tmp_mtd; - - printk(KERN_INFO "axisflashmap: Set to boot from NAND flash, " - "making NAND flash primary device.\n"); - tmp_mtd = main_mtd; - main_mtd = aux_mtd; - aux_mtd = tmp_mtd; - } -#endif /* CONFIG_ETRAX_NANDBOOT */ -#endif /* CONFIG_ETRAX_NANDFLASH */ - - if (!main_mtd && !aux_mtd) { - /* There's no reason to use this module if no flash chip can - * be identified. Make sure that's understood. - */ - printk(KERN_INFO "axisflashmap: Found no flash chip.\n"); - } - -#if 0 /* Dump flash memory so we can see what is going on */ - if (main_mtd) { - int sectoraddr; - for (sectoraddr = 0; sectoraddr < 2*65536+4096; - sectoraddr += PAGESIZE) { - main_mtd->read(main_mtd, sectoraddr, PAGESIZE, &len, - page); - printk(KERN_INFO - "Sector at %d (length %d):\n", - sectoraddr, len); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, page, PAGESIZE, false); - } - } -#endif - - if (main_mtd) { - loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR; - main_mtd->owner = THIS_MODULE; - axisflash_mtd = main_mtd; - - - /* First partition (rescue) is always set to the default. */ - pidx++; -#ifdef CONFIG_ETRAX_NANDBOOT - /* We know where the partition table should be located, - * it will be in first good block after that. - */ - int blockstat; - do { - blockstat = mtd_block_isbad(main_mtd, ptable_sector); - if (blockstat < 0) - ptable_sector = 0; /* read error */ - else if (blockstat) - ptable_sector += main_mtd->erasesize; - } while (blockstat && ptable_sector); -#endif - if (ptable_sector) { - mtd_read(main_mtd, ptable_sector, PAGESIZE, &len, - page); - ptable_head = &((struct partitiontable *) page)->head; - } - -#if 0 /* Dump partition table so we can see what is going on */ - printk(KERN_INFO - "axisflashmap: flash read %d bytes at 0x%08x, data: %8ph\n", - len, CONFIG_ETRAX_PTABLE_SECTOR, page); - printk(KERN_INFO - "axisflashmap: partition table offset %d, data: %8ph\n", - PARTITION_TABLE_OFFSET, page + PARTITION_TABLE_OFFSET); -#endif - } - - if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC) - && (ptable_head->size < - (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + - PARTITIONTABLE_END_MARKER_SIZE)) - && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + - ptable_head->size - - PARTITIONTABLE_END_MARKER_SIZE) - == PARTITIONTABLE_END_MARKER)) { - /* Looks like a start, sane length and end of a - * partition table, lets check csum etc. - */ - struct partitiontable_entry *max_addr = - (struct partitiontable_entry *) - ((unsigned long)ptable_head + sizeof(*ptable_head) + - ptable_head->size); - unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; - unsigned char *p; - unsigned long csum = 0; - - ptable = (struct partitiontable_entry *) - ((unsigned long)ptable_head + sizeof(*ptable_head)); - - /* Lets be PARANOID, and check the checksum. */ - p = (unsigned char*) ptable; - - while (p <= (unsigned char*)max_addr) { - csum += *p++; - csum += *p++; - csum += *p++; - csum += *p++; - } - ptable_ok = (csum == ptable_head->checksum); - - /* Read the entries and use/show the info. */ - printk(KERN_INFO "axisflashmap: " - "Found a%s partition table at 0x%p-0x%p.\n", - (ptable_ok ? " valid" : "n invalid"), ptable_head, - max_addr); - - /* We have found a working bootblock. Now read the - * partition table. Scan the table. It ends with 0xffffffff. - */ - while (ptable_ok - && ptable->offset != PARTITIONTABLE_END_MARKER - && ptable < max_addr - && pidx < MAX_PARTITIONS - 1) { - - axis_partitions[pidx].offset = offset + ptable->offset; -#ifdef CONFIG_ETRAX_NANDFLASH - if (main_mtd->type == MTD_NANDFLASH) { - axis_partitions[pidx].size = - (((ptable+1)->offset == - PARTITIONTABLE_END_MARKER) ? - main_mtd->size : - ((ptable+1)->offset + offset)) - - (ptable->offset + offset); - - } else -#endif /* CONFIG_ETRAX_NANDFLASH */ - axis_partitions[pidx].size = ptable->size; -#ifdef CONFIG_ETRAX_NANDBOOT - /* Save partition number of jffs2 ro partition. - * Needed if RAM booting or root file system in RAM. - */ - if (!nand_boot && - ram_rootfs_partition < 0 && /* not already set */ - ptable->type == PARTITION_TYPE_JFFS2 && - (ptable->flags & PARTITION_FLAGS_READONLY_MASK) == - PARTITION_FLAGS_READONLY) - ram_rootfs_partition = pidx; -#endif /* CONFIG_ETRAX_NANDBOOT */ - pidx++; - ptable++; - } - } - - /* Decide whether to use default partition table. */ - /* Only use default table if we actually have a device (main_mtd) */ - - partition = &axis_partitions[0]; - if (main_mtd && !ptable_ok) { - memcpy(axis_partitions, axis_default_partitions, - sizeof(axis_default_partitions)); - pidx = NUM_DEFAULT_PARTITIONS; - ram_rootfs_partition = DEFAULT_ROOTFS_PARTITION_NO; - } - - /* Add artificial partitions for rootfs if necessary */ - if (romfs_in_flash) { - /* rootfs is in directly accessible flash memory = NOR flash. - Add an overlapping device for the rootfs partition. */ - printk(KERN_INFO "axisflashmap: Adding partition for " - "overlapping root file system image\n"); - axis_partitions[pidx].size = romfs_length; - axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; - axis_partitions[pidx].name = "romfs"; - axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; - ram_rootfs_partition = -1; - pidx++; - } else if (romfs_length && !nand_boot) { - /* romfs exists in memory, but not in flash, so must be in RAM. - * Configure an MTDRAM partition. */ - if (ram_rootfs_partition < 0) { - /* None set yet, put it at the end */ - ram_rootfs_partition = pidx; - pidx++; - } - printk(KERN_INFO "axisflashmap: Adding partition for " - "root file system image in RAM\n"); - axis_partitions[ram_rootfs_partition].size = romfs_length; - axis_partitions[ram_rootfs_partition].offset = romfs_start; - axis_partitions[ram_rootfs_partition].name = "romfs"; - axis_partitions[ram_rootfs_partition].mask_flags |= - MTD_WRITEABLE; - } - -#ifdef CONFIG_ETRAX_AXISFLASHMAP_MTD0WHOLE - if (main_mtd) { - main_partition.size = main_mtd->size; - err = mtd_device_register(main_mtd, &main_partition, 1); - if (err) - panic("axisflashmap: Could not initialize " - "partition for whole main mtd device!\n"); - } -#endif - - /* Now, register all partitions with mtd. - * We do this one at a time so we can slip in an MTDRAM device - * in the proper place if required. */ - - for (part = 0; part < pidx; part++) { - if (part == ram_rootfs_partition) { - /* add MTDRAM partition here */ - struct mtd_info *mtd_ram; - - mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); - if (!mtd_ram) - panic("axisflashmap: Couldn't allocate memory " - "for mtd_info!\n"); - printk(KERN_INFO "axisflashmap: Adding RAM partition " - "for rootfs image.\n"); - err = mtdram_init_device(mtd_ram, - (void *)(u_int32_t)partition[part].offset, - partition[part].size, - partition[part].name); - if (err) - panic("axisflashmap: Could not initialize " - "MTD RAM device!\n"); - /* JFFS2 likes to have an erasesize. Keep potential - * JFFS2 rootfs happy by providing one. Since image - * was most likely created for main mtd, use that - * erasesize, if available. Otherwise, make a guess. */ - mtd_ram->erasesize = (main_mtd ? main_mtd->erasesize : - CONFIG_ETRAX_PTABLE_SECTOR); - } else { - err = mtd_device_register(main_mtd, &partition[part], - 1); - if (err) - panic("axisflashmap: Could not add mtd " - "partition %d\n", part); - } - } - - if (aux_mtd) { - aux_partition.size = aux_mtd->size; - err = mtd_device_register(aux_mtd, &aux_partition, 1); - if (err) - panic("axisflashmap: Could not initialize " - "aux mtd device!\n"); - - } - - return err; -} - -/* This adds the above to the kernels init-call chain. */ -module_init(init_axis_flash); - -EXPORT_SYMBOL(axisflash_mtd); diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c deleted file mode 100644 index a3c353472a8c..000000000000 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ /dev/null @@ -1,3522 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Stream co-processor driver for the ETRAX FS - * - * Copyright (C) 2003-2007 Axis Communications AB - */ - -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/spinlock.h> -#include <linux/stddef.h> - -#include <linux/uaccess.h> -#include <asm/io.h> -#include <linux/atomic.h> - -#include <linux/list.h> -#include <linux/interrupt.h> - -#include <asm/signal.h> -#include <asm/irq.h> - -#include <dma.h> -#include <hwregs/dma.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/intr_vect_defs.h> - -#include <hwregs/strcop.h> -#include <hwregs/strcop_defs.h> -#include <cryptocop.h> - -#ifdef CONFIG_ETRAXFS -#define IN_DMA 9 -#define OUT_DMA 8 -#define IN_DMA_INST regi_dma9 -#define OUT_DMA_INST regi_dma8 -#define DMA_IRQ DMA9_INTR_VECT -#else -#define IN_DMA 3 -#define OUT_DMA 2 -#define IN_DMA_INST regi_dma3 -#define OUT_DMA_INST regi_dma2 -#define DMA_IRQ DMA3_INTR_VECT -#endif - -#define DESCR_ALLOC_PAD (31) - -struct cryptocop_dma_desc { - char *free_buf; /* If non-null will be kfreed in free_cdesc() */ - dma_descr_data *dma_descr; - - unsigned char dma_descr_buf[sizeof(dma_descr_data) + DESCR_ALLOC_PAD]; - - unsigned int from_pool:1; /* If 1 'allocated' from the descriptor pool. */ - struct cryptocop_dma_desc *next; -}; - - -struct cryptocop_int_operation{ - void *alloc_ptr; - cryptocop_session_id sid; - - dma_descr_context ctx_out; - dma_descr_context ctx_in; - - /* DMA descriptors allocated by driver. */ - struct cryptocop_dma_desc *cdesc_out; - struct cryptocop_dma_desc *cdesc_in; - - /* Strcop config to use. */ - cryptocop_3des_mode tdes_mode; - cryptocop_csum_type csum_mode; - - /* DMA descrs provided by consumer. */ - dma_descr_data *ddesc_out; - dma_descr_data *ddesc_in; -}; - - -struct cryptocop_tfrm_ctx { - cryptocop_tfrm_id tid; - unsigned int blocklength; - - unsigned int start_ix; - - struct cryptocop_tfrm_cfg *tcfg; - struct cryptocop_transform_ctx *tctx; - - unsigned char previous_src; - unsigned char current_src; - - /* Values to use in metadata out. */ - unsigned char hash_conf; - unsigned char hash_mode; - unsigned char ciph_conf; - unsigned char cbcmode; - unsigned char decrypt; - - unsigned int requires_padding:1; - unsigned int strict_block_length:1; - unsigned int active:1; - unsigned int done:1; - size_t consumed; - size_t produced; - - /* Pad (input) descriptors to put in the DMA out list when the transform - * output is put on the DMA in list. */ - struct cryptocop_dma_desc *pad_descs; - - struct cryptocop_tfrm_ctx *prev_src; - struct cryptocop_tfrm_ctx *curr_src; - - /* Mapping to HW. */ - unsigned char unit_no; -}; - - -struct cryptocop_private{ - cryptocop_session_id sid; - struct cryptocop_private *next; -}; - -/* Session list. */ - -struct cryptocop_transform_ctx{ - struct cryptocop_transform_init init; - unsigned char dec_key[CRYPTOCOP_MAX_KEY_LENGTH]; - unsigned int dec_key_set:1; - - struct cryptocop_transform_ctx *next; -}; - - -struct cryptocop_session{ - cryptocop_session_id sid; - - struct cryptocop_transform_ctx *tfrm_ctx; - - struct cryptocop_session *next; -}; - -/* Priority levels for jobs sent to the cryptocop. Checksum operations from - kernel have highest priority since TCPIP stack processing must not - be a bottleneck. */ -typedef enum { - cryptocop_prio_kernel_csum = 0, - cryptocop_prio_kernel = 1, - cryptocop_prio_user = 2, - cryptocop_prio_no_prios = 3 -} cryptocop_queue_priority; - -struct cryptocop_prio_queue{ - struct list_head jobs; - cryptocop_queue_priority prio; -}; - -struct cryptocop_prio_job{ - struct list_head node; - cryptocop_queue_priority prio; - - struct cryptocop_operation *oper; - struct cryptocop_int_operation *iop; -}; - -struct ioctl_job_cb_ctx { - unsigned int processed:1; -}; - - -static struct cryptocop_session *cryptocop_sessions = NULL; -spinlock_t cryptocop_sessions_lock; - -/* Next Session ID to assign. */ -static cryptocop_session_id next_sid = 1; - -/* Pad for checksum. */ -static const char csum_zero_pad[1] = {0x00}; - -/* Trash buffer for mem2mem operations. */ -#define MEM2MEM_DISCARD_BUF_LENGTH (512) -static unsigned char mem2mem_discard_buf[MEM2MEM_DISCARD_BUF_LENGTH]; - -/* Descriptor pool. */ -/* FIXME Tweak this value. */ -#define CRYPTOCOP_DESCRIPTOR_POOL_SIZE (100) -static struct cryptocop_dma_desc descr_pool[CRYPTOCOP_DESCRIPTOR_POOL_SIZE]; -static struct cryptocop_dma_desc *descr_pool_free_list; -static int descr_pool_no_free; -static spinlock_t descr_pool_lock; - -/* Lock to stop cryptocop to start processing of a new operation. The holder - of this lock MUST call cryptocop_start_job() after it is unlocked. */ -spinlock_t cryptocop_process_lock; - -static struct cryptocop_prio_queue cryptocop_job_queues[cryptocop_prio_no_prios]; -static spinlock_t cryptocop_job_queue_lock; -static struct cryptocop_prio_job *cryptocop_running_job = NULL; -static spinlock_t running_job_lock; - -/* The interrupt handler appends completed jobs to this list. The scehduled - * tasklet removes them upon sending the response to the crypto consumer. */ -static struct list_head cryptocop_completed_jobs; -static spinlock_t cryptocop_completed_jobs_lock; - -DECLARE_WAIT_QUEUE_HEAD(cryptocop_ioc_process_wq); - - -/** Local functions. **/ - -static int cryptocop_open(struct inode *, struct file *); - -static int cryptocop_release(struct inode *, struct file *); - -static long cryptocop_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); - -static void cryptocop_start_job(void); - -static int cryptocop_job_queue_insert(cryptocop_queue_priority prio, struct cryptocop_operation *operation); -static int cryptocop_job_setup(struct cryptocop_prio_job **pj, struct cryptocop_operation *operation); - -static int cryptocop_job_queue_init(void); -static void cryptocop_job_queue_close(void); - -static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length); - -static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length); - -static int transform_ok(struct cryptocop_transform_init *tinit); - -static struct cryptocop_session *get_session(cryptocop_session_id sid); - -static struct cryptocop_transform_ctx *get_transform_ctx(struct cryptocop_session *sess, cryptocop_tfrm_id tid); - -static void delete_internal_operation(struct cryptocop_int_operation *iop); - -static void get_aes_decrypt_key(unsigned char *dec_key, const unsigned char *key, unsigned int keylength); - -static int init_stream_coprocessor(void); - -static void __exit exit_stream_coprocessor(void); - -/*#define LDEBUG*/ -#ifdef LDEBUG -#define DEBUG(s) s -#define DEBUG_API(s) s -static void print_cryptocop_operation(struct cryptocop_operation *cop); -static void print_dma_descriptors(struct cryptocop_int_operation *iop); -static void print_strcop_crypto_op(struct strcop_crypto_op *cop); -static void print_lock_status(void); -static void print_user_dma_lists(struct cryptocop_dma_list_operation *dma_op); -#define assert(s) do{if (!(s)) panic(#s);} while(0); -#else -#define DEBUG(s) -#define DEBUG_API(s) -#define assert(s) -#endif - - -/* Transform constants. */ -#define DES_BLOCK_LENGTH (8) -#define AES_BLOCK_LENGTH (16) -#define MD5_BLOCK_LENGTH (64) -#define SHA1_BLOCK_LENGTH (64) -#define CSUM_BLOCK_LENGTH (2) -#define MD5_STATE_LENGTH (16) -#define SHA1_STATE_LENGTH (20) - -/* The device number. */ -#define CRYPTOCOP_MAJOR (254) -#define CRYPTOCOP_MINOR (0) - - - -const struct file_operations cryptocop_fops = { - .owner = THIS_MODULE, - .open = cryptocop_open, - .release = cryptocop_release, - .unlocked_ioctl = cryptocop_ioctl, - .llseek = noop_llseek, -}; - - -static void free_cdesc(struct cryptocop_dma_desc *cdesc) -{ - DEBUG(printk("free_cdesc: cdesc 0x%p, from_pool=%d\n", cdesc, cdesc->from_pool)); - kfree(cdesc->free_buf); - - if (cdesc->from_pool) { - unsigned long int flags; - spin_lock_irqsave(&descr_pool_lock, flags); - cdesc->next = descr_pool_free_list; - descr_pool_free_list = cdesc; - ++descr_pool_no_free; - spin_unlock_irqrestore(&descr_pool_lock, flags); - } else { - kfree(cdesc); - } -} - - -static struct cryptocop_dma_desc *alloc_cdesc(int alloc_flag) -{ - int use_pool = (alloc_flag & GFP_ATOMIC) ? 1 : 0; - struct cryptocop_dma_desc *cdesc; - - if (use_pool) { - unsigned long int flags; - spin_lock_irqsave(&descr_pool_lock, flags); - if (!descr_pool_free_list) { - spin_unlock_irqrestore(&descr_pool_lock, flags); - DEBUG_API(printk("alloc_cdesc: pool is empty\n")); - return NULL; - } - cdesc = descr_pool_free_list; - descr_pool_free_list = descr_pool_free_list->next; - --descr_pool_no_free; - spin_unlock_irqrestore(&descr_pool_lock, flags); - cdesc->from_pool = 1; - } else { - cdesc = kmalloc(sizeof(struct cryptocop_dma_desc), alloc_flag); - if (!cdesc) { - DEBUG_API(printk("alloc_cdesc: kmalloc\n")); - return NULL; - } - cdesc->from_pool = 0; - } - cdesc->dma_descr = (dma_descr_data*)(((unsigned long int)cdesc + offsetof(struct cryptocop_dma_desc, dma_descr_buf) + DESCR_ALLOC_PAD) & ~0x0000001F); - - cdesc->next = NULL; - - cdesc->free_buf = NULL; - cdesc->dma_descr->out_eop = 0; - cdesc->dma_descr->in_eop = 0; - cdesc->dma_descr->intr = 0; - cdesc->dma_descr->eol = 0; - cdesc->dma_descr->wait = 0; - cdesc->dma_descr->buf = NULL; - cdesc->dma_descr->after = NULL; - - DEBUG_API(printk("alloc_cdesc: return 0x%p, cdesc->dma_descr=0x%p, from_pool=%d\n", cdesc, cdesc->dma_descr, cdesc->from_pool)); - return cdesc; -} - - -static void setup_descr_chain(struct cryptocop_dma_desc *cd) -{ - DEBUG(printk("setup_descr_chain: entering\n")); - while (cd) { - if (cd->next) { - cd->dma_descr->next = (dma_descr_data*)virt_to_phys(cd->next->dma_descr); - } else { - cd->dma_descr->next = NULL; - } - cd = cd->next; - } - DEBUG(printk("setup_descr_chain: exit\n")); -} - - -/* Create a pad descriptor for the transform. - * Return -1 for error, 0 if pad created. */ -static int create_pad_descriptor(struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **pad_desc, int alloc_flag) -{ - struct cryptocop_dma_desc *cdesc = NULL; - int error = 0; - struct strcop_meta_out mo = { - .ciphsel = src_none, - .hashsel = src_none, - .csumsel = src_none - }; - char *pad; - size_t plen; - - DEBUG(printk("create_pad_descriptor: start.\n")); - /* Setup pad descriptor. */ - - DEBUG(printk("create_pad_descriptor: setting up padding.\n")); - cdesc = alloc_cdesc(alloc_flag); - if (!cdesc){ - DEBUG_API(printk("create_pad_descriptor: alloc pad desc\n")); - goto error_cleanup; - } - switch (tc->unit_no) { - case src_md5: - error = create_md5_pad(alloc_flag, tc->consumed, &pad, &plen); - if (error){ - DEBUG_API(printk("create_pad_descriptor: create_md5_pad_failed\n")); - goto error_cleanup; - } - cdesc->free_buf = pad; - mo.hashsel = src_dma; - mo.hashconf = tc->hash_conf; - mo.hashmode = tc->hash_mode; - break; - case src_sha1: - error = create_sha1_pad(alloc_flag, tc->consumed, &pad, &plen); - if (error){ - DEBUG_API(printk("create_pad_descriptor: create_sha1_pad_failed\n")); - goto error_cleanup; - } - cdesc->free_buf = pad; - mo.hashsel = src_dma; - mo.hashconf = tc->hash_conf; - mo.hashmode = tc->hash_mode; - break; - case src_csum: - if (tc->consumed % tc->blocklength){ - pad = (char*)csum_zero_pad; - plen = 1; - } else { - pad = (char*)cdesc; /* Use any pointer. */ - plen = 0; - } - mo.csumsel = src_dma; - break; - } - cdesc->dma_descr->wait = 1; - cdesc->dma_descr->out_eop = 1; /* Since this is a pad output is pushed. EOP is ok here since the padded unit is the only one active. */ - cdesc->dma_descr->buf = (char*)virt_to_phys((char*)pad); - cdesc->dma_descr->after = cdesc->dma_descr->buf + plen; - - cdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, mo); - *pad_desc = cdesc; - - return 0; - - error_cleanup: - if (cdesc) free_cdesc(cdesc); - return -1; -} - - -static int setup_key_dl_desc(struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **kd, int alloc_flag) -{ - struct cryptocop_dma_desc *key_desc = alloc_cdesc(alloc_flag); - struct strcop_meta_out mo = {0}; - - DEBUG(printk("setup_key_dl_desc\n")); - - if (!key_desc) { - DEBUG_API(printk("setup_key_dl_desc: failed descriptor allocation.\n")); - return -ENOMEM; - } - - /* Download key. */ - if ((tc->tctx->init.alg == cryptocop_alg_aes) && (tc->tcfg->flags & CRYPTOCOP_DECRYPT)) { - /* Precook the AES decrypt key. */ - if (!tc->tctx->dec_key_set){ - get_aes_decrypt_key(tc->tctx->dec_key, tc->tctx->init.key, tc->tctx->init.keylen); - tc->tctx->dec_key_set = 1; - } - key_desc->dma_descr->buf = (char*)virt_to_phys(tc->tctx->dec_key); - key_desc->dma_descr->after = key_desc->dma_descr->buf + tc->tctx->init.keylen/8; - } else { - key_desc->dma_descr->buf = (char*)virt_to_phys(tc->tctx->init.key); - key_desc->dma_descr->after = key_desc->dma_descr->buf + tc->tctx->init.keylen/8; - } - /* Setup metadata. */ - mo.dlkey = 1; - switch (tc->tctx->init.keylen) { - case 64: - mo.decrypt = 0; - mo.hashmode = 0; - break; - case 128: - mo.decrypt = 0; - mo.hashmode = 1; - break; - case 192: - mo.decrypt = 1; - mo.hashmode = 0; - break; - case 256: - mo.decrypt = 1; - mo.hashmode = 1; - break; - default: - break; - } - mo.ciphsel = mo.hashsel = mo.csumsel = src_none; - key_desc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, mo); - - key_desc->dma_descr->out_eop = 1; - key_desc->dma_descr->wait = 1; - key_desc->dma_descr->intr = 0; - - *kd = key_desc; - return 0; -} - -static int setup_cipher_iv_desc(struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **id, int alloc_flag) -{ - struct cryptocop_dma_desc *iv_desc = alloc_cdesc(alloc_flag); - struct strcop_meta_out mo = {0}; - - DEBUG(printk("setup_cipher_iv_desc\n")); - - if (!iv_desc) { - DEBUG_API(printk("setup_cipher_iv_desc: failed CBC IV descriptor allocation.\n")); - return -ENOMEM; - } - /* Download IV. */ - iv_desc->dma_descr->buf = (char*)virt_to_phys(tc->tcfg->iv); - iv_desc->dma_descr->after = iv_desc->dma_descr->buf + tc->blocklength; - - /* Setup metadata. */ - mo.hashsel = mo.csumsel = src_none; - mo.ciphsel = src_dma; - mo.ciphconf = tc->ciph_conf; - mo.cbcmode = tc->cbcmode; - - iv_desc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, mo); - - iv_desc->dma_descr->out_eop = 0; - iv_desc->dma_descr->wait = 1; - iv_desc->dma_descr->intr = 0; - - *id = iv_desc; - return 0; -} - -/* Map the output length of the transform to operation output starting on the inject index. */ -static int create_input_descriptors(struct cryptocop_operation *operation, struct cryptocop_tfrm_ctx *tc, struct cryptocop_dma_desc **id, int alloc_flag) -{ - int err = 0; - struct cryptocop_dma_desc head = {0}; - struct cryptocop_dma_desc *outdesc = &head; - size_t iov_offset = 0; - size_t out_ix = 0; - int outiov_ix = 0; - struct strcop_meta_in mi = {0}; - - size_t out_length = tc->produced; - int rem_length; - int dlength; - - assert(out_length != 0); - if (((tc->produced + tc->tcfg->inject_ix) > operation->tfrm_op.outlen) || (tc->produced && (operation->tfrm_op.outlen == 0))) { - DEBUG_API(printk("create_input_descriptors: operation outdata too small\n")); - return -EINVAL; - } - /* Traverse the out iovec until the result inject index is reached. */ - while ((outiov_ix < operation->tfrm_op.outcount) && ((out_ix + operation->tfrm_op.outdata[outiov_ix].iov_len) <= tc->tcfg->inject_ix)){ - out_ix += operation->tfrm_op.outdata[outiov_ix].iov_len; - outiov_ix++; - } - if (outiov_ix >= operation->tfrm_op.outcount){ - DEBUG_API(printk("create_input_descriptors: operation outdata too small\n")); - return -EINVAL; - } - iov_offset = tc->tcfg->inject_ix - out_ix; - mi.dmasel = tc->unit_no; - - /* Setup the output descriptors. */ - while ((out_length > 0) && (outiov_ix < operation->tfrm_op.outcount)) { - outdesc->next = alloc_cdesc(alloc_flag); - if (!outdesc->next) { - DEBUG_API(printk("create_input_descriptors: alloc_cdesc\n")); - err = -ENOMEM; - goto error_cleanup; - } - outdesc = outdesc->next; - rem_length = operation->tfrm_op.outdata[outiov_ix].iov_len - iov_offset; - dlength = (out_length < rem_length) ? out_length : rem_length; - - DEBUG(printk("create_input_descriptors:\n" - "outiov_ix=%d, rem_length=%d, dlength=%d\n" - "iov_offset=%d, outdata[outiov_ix].iov_len=%d\n" - "outcount=%d, outiov_ix=%d\n", - outiov_ix, rem_length, dlength, iov_offset, operation->tfrm_op.outdata[outiov_ix].iov_len, operation->tfrm_op.outcount, outiov_ix)); - - outdesc->dma_descr->buf = (char*)virt_to_phys(operation->tfrm_op.outdata[outiov_ix].iov_base + iov_offset); - outdesc->dma_descr->after = outdesc->dma_descr->buf + dlength; - outdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi); - - out_length -= dlength; - iov_offset += dlength; - if (iov_offset >= operation->tfrm_op.outdata[outiov_ix].iov_len) { - iov_offset = 0; - ++outiov_ix; - } - } - if (out_length > 0){ - DEBUG_API(printk("create_input_descriptors: not enough room for output, %d remained\n", out_length)); - err = -EINVAL; - goto error_cleanup; - } - /* Set sync in last descriptor. */ - mi.sync = 1; - outdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi); - - *id = head.next; - return 0; - - error_cleanup: - while (head.next) { - outdesc = head.next->next; - free_cdesc(head.next); - head.next = outdesc; - } - return err; -} - - -static int create_output_descriptors(struct cryptocop_operation *operation, int *iniov_ix, int *iniov_offset, size_t desc_len, struct cryptocop_dma_desc **current_out_cdesc, struct strcop_meta_out *meta_out, int alloc_flag) -{ - while (desc_len != 0) { - struct cryptocop_dma_desc *cdesc; - int rem_length = operation->tfrm_op.indata[*iniov_ix].iov_len - *iniov_offset; - int dlength = (desc_len < rem_length) ? desc_len : rem_length; - - cdesc = alloc_cdesc(alloc_flag); - if (!cdesc) { - DEBUG_API(printk("create_output_descriptors: alloc_cdesc\n")); - return -ENOMEM; - } - (*current_out_cdesc)->next = cdesc; - (*current_out_cdesc) = cdesc; - - cdesc->free_buf = NULL; - - cdesc->dma_descr->buf = (char*)virt_to_phys(operation->tfrm_op.indata[*iniov_ix].iov_base + *iniov_offset); - cdesc->dma_descr->after = cdesc->dma_descr->buf + dlength; - - assert(desc_len >= dlength); - desc_len -= dlength; - *iniov_offset += dlength; - if (*iniov_offset >= operation->tfrm_op.indata[*iniov_ix].iov_len) { - *iniov_offset = 0; - ++(*iniov_ix); - if (*iniov_ix > operation->tfrm_op.incount) { - DEBUG_API(printk("create_output_descriptors: not enough indata in operation.")); - return -EINVAL; - } - } - cdesc->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, (*meta_out)); - } /* while (desc_len != 0) */ - /* Last DMA descriptor gets a 'wait' bit to signal expected change in metadata. */ - (*current_out_cdesc)->dma_descr->wait = 1; /* This will set extraneous WAIT in some situations, e.g. when padding hashes and checksums. */ - - return 0; -} - - -static int append_input_descriptors(struct cryptocop_operation *operation, struct cryptocop_dma_desc **current_in_cdesc, struct cryptocop_dma_desc **current_out_cdesc, struct cryptocop_tfrm_ctx *tc, int alloc_flag) -{ - DEBUG(printk("append_input_descriptors, tc=0x%p, unit_no=%d\n", tc, tc->unit_no)); - if (tc->tcfg) { - int failed = 0; - struct cryptocop_dma_desc *idescs = NULL; - DEBUG(printk("append_input_descriptors: pushing output, consumed %d produced %d bytes.\n", tc->consumed, tc->produced)); - if (tc->pad_descs) { - DEBUG(printk("append_input_descriptors: append pad descriptors to DMA out list.\n")); - while (tc->pad_descs) { - DEBUG(printk("append descriptor 0x%p\n", tc->pad_descs)); - (*current_out_cdesc)->next = tc->pad_descs; - tc->pad_descs = tc->pad_descs->next; - (*current_out_cdesc) = (*current_out_cdesc)->next; - } - } - - /* Setup and append output descriptors to DMA in list. */ - if (tc->unit_no == src_dma){ - /* mem2mem. Setup DMA in descriptors to discard all input prior to the requested mem2mem data. */ - struct strcop_meta_in mi = {.sync = 0, .dmasel = src_dma}; - unsigned int start_ix = tc->start_ix; - while (start_ix){ - unsigned int desclen = start_ix < MEM2MEM_DISCARD_BUF_LENGTH ? start_ix : MEM2MEM_DISCARD_BUF_LENGTH; - (*current_in_cdesc)->next = alloc_cdesc(alloc_flag); - if (!(*current_in_cdesc)->next){ - DEBUG_API(printk("append_input_descriptors: alloc_cdesc mem2mem discard failed\n")); - return -ENOMEM; - } - (*current_in_cdesc) = (*current_in_cdesc)->next; - (*current_in_cdesc)->dma_descr->buf = (char*)virt_to_phys(mem2mem_discard_buf); - (*current_in_cdesc)->dma_descr->after = (*current_in_cdesc)->dma_descr->buf + desclen; - (*current_in_cdesc)->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi); - start_ix -= desclen; - } - mi.sync = 1; - (*current_in_cdesc)->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_in, mi); - } - - failed = create_input_descriptors(operation, tc, &idescs, alloc_flag); - if (failed){ - DEBUG_API(printk("append_input_descriptors: output descriptor setup failed\n")); - return failed; - } - DEBUG(printk("append_input_descriptors: append output descriptors to DMA in list.\n")); - while (idescs) { - DEBUG(printk("append descriptor 0x%p\n", idescs)); - (*current_in_cdesc)->next = idescs; - idescs = idescs->next; - (*current_in_cdesc) = (*current_in_cdesc)->next; - } - } - return 0; -} - - - -static int cryptocop_setup_dma_list(struct cryptocop_operation *operation, struct cryptocop_int_operation **int_op, int alloc_flag) -{ - struct cryptocop_session *sess; - struct cryptocop_transform_ctx *tctx; - - struct cryptocop_tfrm_ctx digest_ctx = { - .previous_src = src_none, - .current_src = src_none, - .start_ix = 0, - .requires_padding = 1, - .strict_block_length = 0, - .hash_conf = 0, - .hash_mode = 0, - .ciph_conf = 0, - .cbcmode = 0, - .decrypt = 0, - .consumed = 0, - .produced = 0, - .pad_descs = NULL, - .active = 0, - .done = 0, - .prev_src = NULL, - .curr_src = NULL, - .tcfg = NULL}; - struct cryptocop_tfrm_ctx cipher_ctx = { - .previous_src = src_none, - .current_src = src_none, - .start_ix = 0, - .requires_padding = 0, - .strict_block_length = 1, - .hash_conf = 0, - .hash_mode = 0, - .ciph_conf = 0, - .cbcmode = 0, - .decrypt = 0, - .consumed = 0, - .produced = 0, - .pad_descs = NULL, - .active = 0, - .done = 0, - .prev_src = NULL, - .curr_src = NULL, - .tcfg = NULL}; - struct cryptocop_tfrm_ctx csum_ctx = { - .previous_src = src_none, - .current_src = src_none, - .start_ix = 0, - .blocklength = 2, - .requires_padding = 1, - .strict_block_length = 0, - .hash_conf = 0, - .hash_mode = 0, - .ciph_conf = 0, - .cbcmode = 0, - .decrypt = 0, - .consumed = 0, - .produced = 0, - .pad_descs = NULL, - .active = 0, - .done = 0, - .tcfg = NULL, - .prev_src = NULL, - .curr_src = NULL, - .unit_no = src_csum}; - struct cryptocop_tfrm_cfg *tcfg = operation->tfrm_op.tfrm_cfg; - - unsigned int indata_ix = 0; - - /* iovec accounting. */ - int iniov_ix = 0; - int iniov_offset = 0; - - /* Operation descriptor cfg traversal pointer. */ - struct cryptocop_desc *odsc; - - int failed = 0; - /* List heads for allocated descriptors. */ - struct cryptocop_dma_desc out_cdesc_head = {0}; - struct cryptocop_dma_desc in_cdesc_head = {0}; - - struct cryptocop_dma_desc *current_out_cdesc = &out_cdesc_head; - struct cryptocop_dma_desc *current_in_cdesc = &in_cdesc_head; - - struct cryptocop_tfrm_ctx *output_tc = NULL; - void *iop_alloc_ptr; - - assert(operation != NULL); - assert(int_op != NULL); - - DEBUG(printk("cryptocop_setup_dma_list: start\n")); - DEBUG(print_cryptocop_operation(operation)); - - sess = get_session(operation->sid); - if (!sess) { - DEBUG_API(printk("cryptocop_setup_dma_list: no session found for operation.\n")); - failed = -EINVAL; - goto error_cleanup; - } - iop_alloc_ptr = kmalloc(DESCR_ALLOC_PAD + sizeof(struct cryptocop_int_operation), alloc_flag); - if (!iop_alloc_ptr) { - DEBUG_API(printk("cryptocop_setup_dma_list: kmalloc cryptocop_int_operation\n")); - failed = -ENOMEM; - goto error_cleanup; - } - (*int_op) = (struct cryptocop_int_operation*)(((unsigned long int)(iop_alloc_ptr + DESCR_ALLOC_PAD + offsetof(struct cryptocop_int_operation, ctx_out)) & ~0x0000001F) - offsetof(struct cryptocop_int_operation, ctx_out)); - DEBUG(memset((*int_op), 0xff, sizeof(struct cryptocop_int_operation))); - (*int_op)->alloc_ptr = iop_alloc_ptr; - DEBUG(printk("cryptocop_setup_dma_list: *int_op=0x%p, alloc_ptr=0x%p\n", *int_op, (*int_op)->alloc_ptr)); - - (*int_op)->sid = operation->sid; - (*int_op)->cdesc_out = NULL; - (*int_op)->cdesc_in = NULL; - (*int_op)->tdes_mode = cryptocop_3des_ede; - (*int_op)->csum_mode = cryptocop_csum_le; - (*int_op)->ddesc_out = NULL; - (*int_op)->ddesc_in = NULL; - - /* Scan operation->tfrm_op.tfrm_cfg for bad configuration and set up the local contexts. */ - if (!tcfg) { - DEBUG_API(printk("cryptocop_setup_dma_list: no configured transforms in operation.\n")); - failed = -EINVAL; - goto error_cleanup; - } - while (tcfg) { - tctx = get_transform_ctx(sess, tcfg->tid); - if (!tctx) { - DEBUG_API(printk("cryptocop_setup_dma_list: no transform id %d in session.\n", tcfg->tid)); - failed = -EINVAL; - goto error_cleanup; - } - if (tcfg->inject_ix > operation->tfrm_op.outlen){ - DEBUG_API(printk("cryptocop_setup_dma_list: transform id %d inject_ix (%d) > operation->tfrm_op.outlen(%d)", tcfg->tid, tcfg->inject_ix, operation->tfrm_op.outlen)); - failed = -EINVAL; - goto error_cleanup; - } - switch (tctx->init.alg){ - case cryptocop_alg_mem2mem: - if (cipher_ctx.tcfg != NULL){ - DEBUG_API(printk("cryptocop_setup_dma_list: multiple ciphers in operation.\n")); - failed = -EINVAL; - goto error_cleanup; - } - /* mem2mem is handled as a NULL cipher. */ - cipher_ctx.cbcmode = 0; - cipher_ctx.decrypt = 0; - cipher_ctx.blocklength = 1; - cipher_ctx.ciph_conf = 0; - cipher_ctx.unit_no = src_dma; - cipher_ctx.tcfg = tcfg; - cipher_ctx.tctx = tctx; - break; - case cryptocop_alg_des: - case cryptocop_alg_3des: - case cryptocop_alg_aes: - /* cipher */ - if (cipher_ctx.tcfg != NULL){ - DEBUG_API(printk("cryptocop_setup_dma_list: multiple ciphers in operation.\n")); - failed = -EINVAL; - goto error_cleanup; - } - cipher_ctx.tcfg = tcfg; - cipher_ctx.tctx = tctx; - if (cipher_ctx.tcfg->flags & CRYPTOCOP_DECRYPT){ - cipher_ctx.decrypt = 1; - } - switch (tctx->init.cipher_mode) { - case cryptocop_cipher_mode_ecb: - cipher_ctx.cbcmode = 0; - break; - case cryptocop_cipher_mode_cbc: - cipher_ctx.cbcmode = 1; - break; - default: - DEBUG_API(printk("cryptocop_setup_dma_list: cipher_ctx, bad cipher mode==%d\n", tctx->init.cipher_mode)); - failed = -EINVAL; - goto error_cleanup; - } - DEBUG(printk("cryptocop_setup_dma_list: cipher_ctx, set CBC mode==%d\n", cipher_ctx.cbcmode)); - switch (tctx->init.alg){ - case cryptocop_alg_des: - cipher_ctx.ciph_conf = 0; - cipher_ctx.unit_no = src_des; - cipher_ctx.blocklength = DES_BLOCK_LENGTH; - break; - case cryptocop_alg_3des: - cipher_ctx.ciph_conf = 1; - cipher_ctx.unit_no = src_des; - cipher_ctx.blocklength = DES_BLOCK_LENGTH; - break; - case cryptocop_alg_aes: - cipher_ctx.ciph_conf = 2; - cipher_ctx.unit_no = src_aes; - cipher_ctx.blocklength = AES_BLOCK_LENGTH; - break; - default: - panic("cryptocop_setup_dma_list: impossible algorithm %d\n", tctx->init.alg); - } - (*int_op)->tdes_mode = tctx->init.tdes_mode; - break; - case cryptocop_alg_md5: - case cryptocop_alg_sha1: - /* digest */ - if (digest_ctx.tcfg != NULL){ - DEBUG_API(printk("cryptocop_setup_dma_list: multiple digests in operation.\n")); - failed = -EINVAL; - goto error_cleanup; - } - digest_ctx.tcfg = tcfg; - digest_ctx.tctx = tctx; - digest_ctx.hash_mode = 0; /* Don't use explicit IV in this API. */ - switch (tctx->init.alg){ - case cryptocop_alg_md5: - digest_ctx.blocklength = MD5_BLOCK_LENGTH; - digest_ctx.unit_no = src_md5; - digest_ctx.hash_conf = 1; /* 1 => MD-5 */ - break; - case cryptocop_alg_sha1: - digest_ctx.blocklength = SHA1_BLOCK_LENGTH; - digest_ctx.unit_no = src_sha1; - digest_ctx.hash_conf = 0; /* 0 => SHA-1 */ - break; - default: - panic("cryptocop_setup_dma_list: impossible digest algorithm\n"); - } - break; - case cryptocop_alg_csum: - /* digest */ - if (csum_ctx.tcfg != NULL){ - DEBUG_API(printk("cryptocop_setup_dma_list: multiple checksums in operation.\n")); - failed = -EINVAL; - goto error_cleanup; - } - (*int_op)->csum_mode = tctx->init.csum_mode; - csum_ctx.tcfg = tcfg; - csum_ctx.tctx = tctx; - break; - default: - /* no algorithm. */ - DEBUG_API(printk("cryptocop_setup_dma_list: invalid algorithm %d specified in tfrm %d.\n", tctx->init.alg, tcfg->tid)); - failed = -EINVAL; - goto error_cleanup; - } - tcfg = tcfg->next; - } - /* Download key if a cipher is used. */ - if (cipher_ctx.tcfg && (cipher_ctx.tctx->init.alg != cryptocop_alg_mem2mem)){ - struct cryptocop_dma_desc *key_desc = NULL; - - failed = setup_key_dl_desc(&cipher_ctx, &key_desc, alloc_flag); - if (failed) { - DEBUG_API(printk("cryptocop_setup_dma_list: setup key dl\n")); - goto error_cleanup; - } - current_out_cdesc->next = key_desc; - current_out_cdesc = key_desc; - indata_ix += (unsigned int)(key_desc->dma_descr->after - key_desc->dma_descr->buf); - - /* Download explicit IV if a cipher is used and CBC mode and explicit IV selected. */ - if ((cipher_ctx.tctx->init.cipher_mode == cryptocop_cipher_mode_cbc) && (cipher_ctx.tcfg->flags & CRYPTOCOP_EXPLICIT_IV)) { - struct cryptocop_dma_desc *iv_desc = NULL; - - DEBUG(printk("cryptocop_setup_dma_list: setup cipher CBC IV descriptor.\n")); - - failed = setup_cipher_iv_desc(&cipher_ctx, &iv_desc, alloc_flag); - if (failed) { - DEBUG_API(printk("cryptocop_setup_dma_list: CBC IV descriptor.\n")); - goto error_cleanup; - } - current_out_cdesc->next = iv_desc; - current_out_cdesc = iv_desc; - indata_ix += (unsigned int)(iv_desc->dma_descr->after - iv_desc->dma_descr->buf); - } - } - - /* Process descriptors. */ - odsc = operation->tfrm_op.desc; - while (odsc) { - struct cryptocop_desc_cfg *dcfg = odsc->cfg; - struct strcop_meta_out meta_out = {0}; - size_t desc_len = odsc->length; - int active_count, eop_needed_count; - - output_tc = NULL; - - DEBUG(printk("cryptocop_setup_dma_list: parsing an operation descriptor\n")); - - while (dcfg) { - struct cryptocop_tfrm_ctx *tc = NULL; - - DEBUG(printk("cryptocop_setup_dma_list: parsing an operation descriptor configuration.\n")); - /* Get the local context for the transform and mark it as the output unit if it produces output. */ - if (digest_ctx.tcfg && (digest_ctx.tcfg->tid == dcfg->tid)){ - tc = &digest_ctx; - } else if (cipher_ctx.tcfg && (cipher_ctx.tcfg->tid == dcfg->tid)){ - tc = &cipher_ctx; - } else if (csum_ctx.tcfg && (csum_ctx.tcfg->tid == dcfg->tid)){ - tc = &csum_ctx; - } - if (!tc) { - DEBUG_API(printk("cryptocop_setup_dma_list: invalid transform %d specified in descriptor.\n", dcfg->tid)); - failed = -EINVAL; - goto error_cleanup; - } - if (tc->done) { - DEBUG_API(printk("cryptocop_setup_dma_list: completed transform %d reused.\n", dcfg->tid)); - failed = -EINVAL; - goto error_cleanup; - } - if (!tc->active) { - tc->start_ix = indata_ix; - tc->active = 1; - } - - tc->previous_src = tc->current_src; - tc->prev_src = tc->curr_src; - /* Map source unit id to DMA source config. */ - switch (dcfg->src){ - case cryptocop_source_dma: - tc->current_src = src_dma; - break; - case cryptocop_source_des: - tc->current_src = src_des; - break; - case cryptocop_source_3des: - tc->current_src = src_des; - break; - case cryptocop_source_aes: - tc->current_src = src_aes; - break; - case cryptocop_source_md5: - case cryptocop_source_sha1: - case cryptocop_source_csum: - case cryptocop_source_none: - default: - /* We do not allow using accumulating style units (SHA-1, MD5, checksum) as sources to other units. - */ - DEBUG_API(printk("cryptocop_setup_dma_list: bad unit source configured %d.\n", dcfg->src)); - failed = -EINVAL; - goto error_cleanup; - } - if (tc->current_src != src_dma) { - /* Find the unit we are sourcing from. */ - if (digest_ctx.unit_no == tc->current_src){ - tc->curr_src = &digest_ctx; - } else if (cipher_ctx.unit_no == tc->current_src){ - tc->curr_src = &cipher_ctx; - } else if (csum_ctx.unit_no == tc->current_src){ - tc->curr_src = &csum_ctx; - } - if ((tc->curr_src == tc) && (tc->unit_no != src_dma)){ - DEBUG_API(printk("cryptocop_setup_dma_list: unit %d configured to source from itself.\n", tc->unit_no)); - failed = -EINVAL; - goto error_cleanup; - } - } else { - tc->curr_src = NULL; - } - - /* Detect source switch. */ - DEBUG(printk("cryptocop_setup_dma_list: tc->active=%d tc->unit_no=%d tc->current_src=%d tc->previous_src=%d, tc->curr_src=0x%p, tc->prev_srv=0x%p\n", tc->active, tc->unit_no, tc->current_src, tc->previous_src, tc->curr_src, tc->prev_src)); - if (tc->active && (tc->current_src != tc->previous_src)) { - /* Only allow source switch when both the old source unit and the new one have - * no pending data to process (i.e. the consumed length must be a multiple of the - * transform blocklength). */ - /* Note: if the src == NULL we are actually sourcing from DMA out. */ - if (((tc->prev_src != NULL) && (tc->prev_src->consumed % tc->prev_src->blocklength)) || - ((tc->curr_src != NULL) && (tc->curr_src->consumed % tc->curr_src->blocklength))) - { - DEBUG_API(printk("cryptocop_setup_dma_list: can only disconnect from or connect to a unit on a multiple of the blocklength, old: cons=%d, prod=%d, block=%d, new: cons=%d prod=%d, block=%d.\n", tc->prev_src ? tc->prev_src->consumed : INT_MIN, tc->prev_src ? tc->prev_src->produced : INT_MIN, tc->prev_src ? tc->prev_src->blocklength : INT_MIN, tc->curr_src ? tc->curr_src->consumed : INT_MIN, tc->curr_src ? tc->curr_src->produced : INT_MIN, tc->curr_src ? tc->curr_src->blocklength : INT_MIN)); - failed = -EINVAL; - goto error_cleanup; - } - } - /* Detect unit deactivation. */ - if (dcfg->last) { - /* Length check of this is handled below. */ - tc->done = 1; - } - dcfg = dcfg->next; - } /* while (dcfg) */ - DEBUG(printk("cryptocop_setup_dma_list: parsing operation descriptor configuration complete.\n")); - - if (cipher_ctx.active && (cipher_ctx.curr_src != NULL) && !cipher_ctx.curr_src->active){ - DEBUG_API(printk("cryptocop_setup_dma_list: cipher source from inactive unit %d\n", cipher_ctx.curr_src->unit_no)); - failed = -EINVAL; - goto error_cleanup; - } - if (digest_ctx.active && (digest_ctx.curr_src != NULL) && !digest_ctx.curr_src->active){ - DEBUG_API(printk("cryptocop_setup_dma_list: digest source from inactive unit %d\n", digest_ctx.curr_src->unit_no)); - failed = -EINVAL; - goto error_cleanup; - } - if (csum_ctx.active && (csum_ctx.curr_src != NULL) && !csum_ctx.curr_src->active){ - DEBUG_API(printk("cryptocop_setup_dma_list: cipher source from inactive unit %d\n", csum_ctx.curr_src->unit_no)); - failed = -EINVAL; - goto error_cleanup; - } - - /* Update consumed and produced lengths. - - The consumed length accounting here is actually cheating. If a unit source from DMA (or any - other unit that process data in blocks of one octet) it is correct, but if it source from a - block processing unit, i.e. a cipher, it will be temporarily incorrect at some times. However - since it is only allowed--by the HW--to change source to or from a block processing unit at times where that - unit has processed an exact multiple of its block length the end result will be correct. - Beware that if the source change restriction change this code will need to be (much) reworked. - */ - DEBUG(printk("cryptocop_setup_dma_list: desc->length=%d, desc_len=%d.\n", odsc->length, desc_len)); - - if (csum_ctx.active) { - csum_ctx.consumed += desc_len; - if (csum_ctx.done) { - csum_ctx.produced = 2; - } - DEBUG(printk("cryptocop_setup_dma_list: csum_ctx producing: consumed=%d, produced=%d, blocklength=%d.\n", csum_ctx.consumed, csum_ctx.produced, csum_ctx.blocklength)); - } - if (digest_ctx.active) { - digest_ctx.consumed += desc_len; - if (digest_ctx.done) { - if (digest_ctx.unit_no == src_md5) { - digest_ctx.produced = MD5_STATE_LENGTH; - } else { - digest_ctx.produced = SHA1_STATE_LENGTH; - } - } - DEBUG(printk("cryptocop_setup_dma_list: digest_ctx producing: consumed=%d, produced=%d, blocklength=%d.\n", digest_ctx.consumed, digest_ctx.produced, digest_ctx.blocklength)); - } - if (cipher_ctx.active) { - /* Ciphers are allowed only to source from DMA out. That is filtered above. */ - assert(cipher_ctx.current_src == src_dma); - cipher_ctx.consumed += desc_len; - cipher_ctx.produced = cipher_ctx.blocklength * (cipher_ctx.consumed / cipher_ctx.blocklength); - if (cipher_ctx.cbcmode && !(cipher_ctx.tcfg->flags & CRYPTOCOP_EXPLICIT_IV) && cipher_ctx.produced){ - cipher_ctx.produced -= cipher_ctx.blocklength; /* Compensate for CBC iv. */ - } - DEBUG(printk("cryptocop_setup_dma_list: cipher_ctx producing: consumed=%d, produced=%d, blocklength=%d.\n", cipher_ctx.consumed, cipher_ctx.produced, cipher_ctx.blocklength)); - } - - /* Setup the DMA out descriptors. */ - /* Configure the metadata. */ - active_count = 0; - eop_needed_count = 0; - if (cipher_ctx.active) { - ++active_count; - if (cipher_ctx.unit_no == src_dma){ - /* mem2mem */ - meta_out.ciphsel = src_none; - } else { - meta_out.ciphsel = cipher_ctx.current_src; - } - meta_out.ciphconf = cipher_ctx.ciph_conf; - meta_out.cbcmode = cipher_ctx.cbcmode; - meta_out.decrypt = cipher_ctx.decrypt; - DEBUG(printk("set ciphsel=%d ciphconf=%d cbcmode=%d decrypt=%d\n", meta_out.ciphsel, meta_out.ciphconf, meta_out.cbcmode, meta_out.decrypt)); - if (cipher_ctx.done) ++eop_needed_count; - } else { - meta_out.ciphsel = src_none; - } - - if (digest_ctx.active) { - ++active_count; - meta_out.hashsel = digest_ctx.current_src; - meta_out.hashconf = digest_ctx.hash_conf; - meta_out.hashmode = 0; /* Explicit mode is not used here. */ - DEBUG(printk("set hashsel=%d hashconf=%d hashmode=%d\n", meta_out.hashsel, meta_out.hashconf, meta_out.hashmode)); - if (digest_ctx.done) { - assert(digest_ctx.pad_descs == NULL); - failed = create_pad_descriptor(&digest_ctx, &digest_ctx.pad_descs, alloc_flag); - if (failed) { - DEBUG_API(printk("cryptocop_setup_dma_list: failed digest pad creation.\n")); - goto error_cleanup; - } - } - } else { - meta_out.hashsel = src_none; - } - - if (csum_ctx.active) { - ++active_count; - meta_out.csumsel = csum_ctx.current_src; - if (csum_ctx.done) { - assert(csum_ctx.pad_descs == NULL); - failed = create_pad_descriptor(&csum_ctx, &csum_ctx.pad_descs, alloc_flag); - if (failed) { - DEBUG_API(printk("cryptocop_setup_dma_list: failed csum pad creation.\n")); - goto error_cleanup; - } - } - } else { - meta_out.csumsel = src_none; - } - DEBUG(printk("cryptocop_setup_dma_list: %d eop needed, %d active units\n", eop_needed_count, active_count)); - /* Setup DMA out descriptors for the indata. */ - failed = create_output_descriptors(operation, &iniov_ix, &iniov_offset, desc_len, ¤t_out_cdesc, &meta_out, alloc_flag); - if (failed) { - DEBUG_API(printk("cryptocop_setup_dma_list: create_output_descriptors %d\n", failed)); - goto error_cleanup; - } - /* Setup out EOP. If there are active units that are not done here they cannot get an EOP - * so we ust setup a zero length descriptor to DMA to signal EOP only to done units. - * If there is a pad descriptor EOP for the padded unit will be EOPed by it. - */ - assert(active_count >= eop_needed_count); - assert((eop_needed_count == 0) || (eop_needed_count == 1)); - if (eop_needed_count) { - /* This means that the bulk operation (cipher/m2m) is terminated. */ - if (active_count > 1) { - /* Use zero length EOP descriptor. */ - struct cryptocop_dma_desc *ed = alloc_cdesc(alloc_flag); - struct strcop_meta_out ed_mo = {0}; - if (!ed) { - DEBUG_API(printk("cryptocop_setup_dma_list: alloc EOP descriptor for cipher\n")); - failed = -ENOMEM; - goto error_cleanup; - } - - assert(cipher_ctx.active && cipher_ctx.done); - - if (cipher_ctx.unit_no == src_dma){ - /* mem2mem */ - ed_mo.ciphsel = src_none; - } else { - ed_mo.ciphsel = cipher_ctx.current_src; - } - ed_mo.ciphconf = cipher_ctx.ciph_conf; - ed_mo.cbcmode = cipher_ctx.cbcmode; - ed_mo.decrypt = cipher_ctx.decrypt; - - ed->free_buf = NULL; - ed->dma_descr->wait = 1; - ed->dma_descr->out_eop = 1; - - ed->dma_descr->buf = (char*)virt_to_phys(&ed); /* Use any valid physical address for zero length descriptor. */ - ed->dma_descr->after = ed->dma_descr->buf; - ed->dma_descr->md = REG_TYPE_CONV(unsigned short int, struct strcop_meta_out, ed_mo); - current_out_cdesc->next = ed; - current_out_cdesc = ed; - } else { - /* Set EOP in the current out descriptor since the only active module is - * the one needing the EOP. */ - - current_out_cdesc->dma_descr->out_eop = 1; - } - } - - if (cipher_ctx.done && cipher_ctx.active) cipher_ctx.active = 0; - if (digest_ctx.done && digest_ctx.active) digest_ctx.active = 0; - if (csum_ctx.done && csum_ctx.active) csum_ctx.active = 0; - indata_ix += odsc->length; - odsc = odsc->next; - } /* while (odsc) */ /* Process descriptors. */ - DEBUG(printk("cryptocop_setup_dma_list: done parsing operation descriptors\n")); - if (cipher_ctx.tcfg && (cipher_ctx.active || !cipher_ctx.done)){ - DEBUG_API(printk("cryptocop_setup_dma_list: cipher operation not terminated.\n")); - failed = -EINVAL; - goto error_cleanup; - } - if (digest_ctx.tcfg && (digest_ctx.active || !digest_ctx.done)){ - DEBUG_API(printk("cryptocop_setup_dma_list: digest operation not terminated.\n")); - failed = -EINVAL; - goto error_cleanup; - } - if (csum_ctx.tcfg && (csum_ctx.active || !csum_ctx.done)){ - DEBUG_API(printk("cryptocop_setup_dma_list: csum operation not terminated.\n")); - failed = -EINVAL; - goto error_cleanup; - } - - failed = append_input_descriptors(operation, ¤t_in_cdesc, ¤t_out_cdesc, &cipher_ctx, alloc_flag); - if (failed){ - DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed)); - goto error_cleanup; - } - failed = append_input_descriptors(operation, ¤t_in_cdesc, ¤t_out_cdesc, &digest_ctx, alloc_flag); - if (failed){ - DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed)); - goto error_cleanup; - } - failed = append_input_descriptors(operation, ¤t_in_cdesc, ¤t_out_cdesc, &csum_ctx, alloc_flag); - if (failed){ - DEBUG_API(printk("cryptocop_setup_dma_list: append_input_descriptors cipher_ctx %d\n", failed)); - goto error_cleanup; - } - - DEBUG(printk("cryptocop_setup_dma_list: int_op=0x%p, *int_op=0x%p\n", int_op, *int_op)); - (*int_op)->cdesc_out = out_cdesc_head.next; - (*int_op)->cdesc_in = in_cdesc_head.next; - DEBUG(printk("cryptocop_setup_dma_list: out_cdesc_head=0x%p in_cdesc_head=0x%p\n", (*int_op)->cdesc_out, (*int_op)->cdesc_in)); - - setup_descr_chain(out_cdesc_head.next); - setup_descr_chain(in_cdesc_head.next); - - /* Last but not least: mark the last DMA in descriptor for a INTR and EOL and the the - * last DMA out descriptor for EOL. - */ - current_in_cdesc->dma_descr->intr = 1; - current_in_cdesc->dma_descr->eol = 1; - current_out_cdesc->dma_descr->eol = 1; - - /* Setup DMA contexts. */ - (*int_op)->ctx_out.next = NULL; - (*int_op)->ctx_out.eol = 1; - (*int_op)->ctx_out.intr = 0; - (*int_op)->ctx_out.store_mode = 0; - (*int_op)->ctx_out.en = 0; - (*int_op)->ctx_out.dis = 0; - (*int_op)->ctx_out.md0 = 0; - (*int_op)->ctx_out.md1 = 0; - (*int_op)->ctx_out.md2 = 0; - (*int_op)->ctx_out.md3 = 0; - (*int_op)->ctx_out.md4 = 0; - (*int_op)->ctx_out.saved_data = (dma_descr_data*)virt_to_phys((*int_op)->cdesc_out->dma_descr); - (*int_op)->ctx_out.saved_data_buf = (*int_op)->cdesc_out->dma_descr->buf; /* Already physical address. */ - - (*int_op)->ctx_in.next = NULL; - (*int_op)->ctx_in.eol = 1; - (*int_op)->ctx_in.intr = 0; - (*int_op)->ctx_in.store_mode = 0; - (*int_op)->ctx_in.en = 0; - (*int_op)->ctx_in.dis = 0; - (*int_op)->ctx_in.md0 = 0; - (*int_op)->ctx_in.md1 = 0; - (*int_op)->ctx_in.md2 = 0; - (*int_op)->ctx_in.md3 = 0; - (*int_op)->ctx_in.md4 = 0; - - (*int_op)->ctx_in.saved_data = (dma_descr_data*)virt_to_phys((*int_op)->cdesc_in->dma_descr); - (*int_op)->ctx_in.saved_data_buf = (*int_op)->cdesc_in->dma_descr->buf; /* Already physical address. */ - - DEBUG(printk("cryptocop_setup_dma_list: done\n")); - return 0; - -error_cleanup: - { - /* Free all allocated resources. */ - struct cryptocop_dma_desc *tmp_cdesc; - while (digest_ctx.pad_descs){ - tmp_cdesc = digest_ctx.pad_descs->next; - free_cdesc(digest_ctx.pad_descs); - digest_ctx.pad_descs = tmp_cdesc; - } - while (csum_ctx.pad_descs){ - tmp_cdesc = csum_ctx.pad_descs->next; - free_cdesc(csum_ctx.pad_descs); - csum_ctx.pad_descs = tmp_cdesc; - } - assert(cipher_ctx.pad_descs == NULL); /* The ciphers are never padded. */ - - if (*int_op != NULL) delete_internal_operation(*int_op); - } - DEBUG_API(printk("cryptocop_setup_dma_list: done with error %d\n", failed)); - return failed; -} - - -static void delete_internal_operation(struct cryptocop_int_operation *iop) -{ - void *ptr = iop->alloc_ptr; - struct cryptocop_dma_desc *cd = iop->cdesc_out; - struct cryptocop_dma_desc *next; - - DEBUG(printk("delete_internal_operation: iop=0x%p, alloc_ptr=0x%p\n", iop, ptr)); - - while (cd) { - next = cd->next; - free_cdesc(cd); - cd = next; - } - cd = iop->cdesc_in; - while (cd) { - next = cd->next; - free_cdesc(cd); - cd = next; - } - kfree(ptr); -} - -#define MD5_MIN_PAD_LENGTH (9) -#define MD5_PAD_LENGTH_FIELD_LENGTH (8) - -static int create_md5_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length) -{ - size_t padlen = MD5_BLOCK_LENGTH - (hashed_length % MD5_BLOCK_LENGTH); - unsigned char *p; - int i; - unsigned long long int bit_length = hashed_length << 3; - - if (padlen < MD5_MIN_PAD_LENGTH) padlen += MD5_BLOCK_LENGTH; - - p = kzalloc(padlen, alloc_flag); - if (!p) return -ENOMEM; - - *p = 0x80; - - DEBUG(printk("create_md5_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length)); - - i = padlen - MD5_PAD_LENGTH_FIELD_LENGTH; - while (bit_length != 0){ - p[i++] = bit_length % 0x100; - bit_length >>= 8; - } - - *pad = (char*)p; - *pad_length = padlen; - - return 0; -} - -#define SHA1_MIN_PAD_LENGTH (9) -#define SHA1_PAD_LENGTH_FIELD_LENGTH (8) - -static int create_sha1_pad(int alloc_flag, unsigned long long hashed_length, char **pad, size_t *pad_length) -{ - size_t padlen = SHA1_BLOCK_LENGTH - (hashed_length % SHA1_BLOCK_LENGTH); - unsigned char *p; - int i; - unsigned long long int bit_length = hashed_length << 3; - - if (padlen < SHA1_MIN_PAD_LENGTH) padlen += SHA1_BLOCK_LENGTH; - - p = kzalloc(padlen, alloc_flag); - if (!p) return -ENOMEM; - - *p = 0x80; - - DEBUG(printk("create_sha1_pad: hashed_length=%lld bits == %lld bytes\n", bit_length, hashed_length)); - - i = padlen - 1; - while (bit_length != 0){ - p[i--] = bit_length % 0x100; - bit_length >>= 8; - } - - *pad = (char*)p; - *pad_length = padlen; - - return 0; -} - - -static int transform_ok(struct cryptocop_transform_init *tinit) -{ - switch (tinit->alg){ - case cryptocop_alg_csum: - switch (tinit->csum_mode){ - case cryptocop_csum_le: - case cryptocop_csum_be: - break; - default: - DEBUG_API(printk("transform_ok: Bad mode set for csum transform\n")); - return -EINVAL; - } - case cryptocop_alg_mem2mem: - case cryptocop_alg_md5: - case cryptocop_alg_sha1: - if (tinit->keylen != 0) { - DEBUG_API(printk("transform_ok: non-zero keylength, %d, for a digest/csum algorithm\n", tinit->keylen)); - return -EINVAL; /* This check is a bit strict. */ - } - break; - case cryptocop_alg_des: - if (tinit->keylen != 64) { - DEBUG_API(printk("transform_ok: keylen %d invalid for DES\n", tinit->keylen)); - return -EINVAL; - } - break; - case cryptocop_alg_3des: - if (tinit->keylen != 192) { - DEBUG_API(printk("transform_ok: keylen %d invalid for 3DES\n", tinit->keylen)); - return -EINVAL; - } - break; - case cryptocop_alg_aes: - if (tinit->keylen != 128 && tinit->keylen != 192 && tinit->keylen != 256) { - DEBUG_API(printk("transform_ok: keylen %d invalid for AES\n", tinit->keylen)); - return -EINVAL; - } - break; - case cryptocop_no_alg: - default: - DEBUG_API(printk("transform_ok: no such algorithm %d\n", tinit->alg)); - return -EINVAL; - } - - switch (tinit->alg){ - case cryptocop_alg_des: - case cryptocop_alg_3des: - case cryptocop_alg_aes: - if (tinit->cipher_mode != cryptocop_cipher_mode_ecb && tinit->cipher_mode != cryptocop_cipher_mode_cbc) return -EINVAL; - default: - break; - } - return 0; -} - - -int cryptocop_new_session(cryptocop_session_id *sid, struct cryptocop_transform_init *tinit, int alloc_flag) -{ - struct cryptocop_session *sess; - struct cryptocop_transform_init *tfrm_in = tinit; - struct cryptocop_transform_init *tmp_in; - int no_tfrms = 0; - int i; - unsigned long int flags; - - init_stream_coprocessor(); /* For safety if we are called early */ - - while (tfrm_in){ - int err; - ++no_tfrms; - if ((err = transform_ok(tfrm_in))) { - DEBUG_API(printk("cryptocop_new_session, bad transform\n")); - return err; - } - tfrm_in = tfrm_in->next; - } - if (0 == no_tfrms) { - DEBUG_API(printk("cryptocop_new_session, no transforms specified\n")); - return -EINVAL; - } - - sess = kmalloc(sizeof(struct cryptocop_session), alloc_flag); - if (!sess){ - DEBUG_API(printk("cryptocop_new_session, kmalloc cryptocop_session\n")); - return -ENOMEM; - } - - sess->tfrm_ctx = kmalloc(no_tfrms * sizeof(struct cryptocop_transform_ctx), alloc_flag); - if (!sess->tfrm_ctx) { - DEBUG_API(printk("cryptocop_new_session, kmalloc cryptocop_transform_ctx\n")); - kfree(sess); - return -ENOMEM; - } - - tfrm_in = tinit; - for (i = 0; i < no_tfrms; i++){ - tmp_in = tfrm_in->next; - while (tmp_in){ - if (tmp_in->tid == tfrm_in->tid) { - DEBUG_API(printk("cryptocop_new_session, duplicate transform ids\n")); - kfree(sess->tfrm_ctx); - kfree(sess); - return -EINVAL; - } - tmp_in = tmp_in->next; - } - memcpy(&sess->tfrm_ctx[i].init, tfrm_in, sizeof(struct cryptocop_transform_init)); - sess->tfrm_ctx[i].dec_key_set = 0; - sess->tfrm_ctx[i].next = &sess->tfrm_ctx[i] + 1; - - tfrm_in = tfrm_in->next; - } - sess->tfrm_ctx[i-1].next = NULL; - - spin_lock_irqsave(&cryptocop_sessions_lock, flags); - sess->sid = next_sid; - next_sid++; - /* TODO If we are really paranoid we should do duplicate check to handle sid wraparound. - * OTOH 2^64 is a really large number of session. */ - if (next_sid == 0) next_sid = 1; - - /* Prepend to session list. */ - sess->next = cryptocop_sessions; - cryptocop_sessions = sess; - spin_unlock_irqrestore(&cryptocop_sessions_lock, flags); - *sid = sess->sid; - return 0; -} - - -int cryptocop_free_session(cryptocop_session_id sid) -{ - struct cryptocop_transform_ctx *tc; - struct cryptocop_session *sess = NULL; - struct cryptocop_session *psess = NULL; - unsigned long int flags; - int i; - LIST_HEAD(remove_list); - struct list_head *node, *tmp; - struct cryptocop_prio_job *pj; - - DEBUG(printk("cryptocop_free_session: sid=%lld\n", sid)); - - spin_lock_irqsave(&cryptocop_sessions_lock, flags); - sess = cryptocop_sessions; - while (sess && sess->sid != sid){ - psess = sess; - sess = sess->next; - } - if (sess){ - if (psess){ - psess->next = sess->next; - } else { - cryptocop_sessions = sess->next; - } - } - spin_unlock_irqrestore(&cryptocop_sessions_lock, flags); - - if (!sess) return -EINVAL; - - /* Remove queued jobs. */ - spin_lock_irqsave(&cryptocop_job_queue_lock, flags); - - for (i = 0; i < cryptocop_prio_no_prios; i++){ - if (!list_empty(&(cryptocop_job_queues[i].jobs))){ - list_for_each_safe(node, tmp, &(cryptocop_job_queues[i].jobs)) { - pj = list_entry(node, struct cryptocop_prio_job, node); - if (pj->oper->sid == sid) { - list_move_tail(node, &remove_list); - } - } - } - } - spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags); - - list_for_each_safe(node, tmp, &remove_list) { - list_del(node); - pj = list_entry(node, struct cryptocop_prio_job, node); - pj->oper->operation_status = -EAGAIN; /* EAGAIN is not ideal for job/session terminated but it's the best choice I know of. */ - DEBUG(printk("cryptocop_free_session: pj=0x%p, pj->oper=0x%p, pj->iop=0x%p\n", pj, pj->oper, pj->iop)); - pj->oper->cb(pj->oper, pj->oper->cb_data); - delete_internal_operation(pj->iop); - kfree(pj); - } - - tc = sess->tfrm_ctx; - /* Erase keying data. */ - while (tc){ - DEBUG(printk("cryptocop_free_session: memset keys, tfrm id=%d\n", tc->init.tid)); - memset(tc->init.key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH); - memset(tc->dec_key, 0xff, CRYPTOCOP_MAX_KEY_LENGTH); - tc = tc->next; - } - kfree(sess->tfrm_ctx); - kfree(sess); - - return 0; -} - -static struct cryptocop_session *get_session(cryptocop_session_id sid) -{ - struct cryptocop_session *sess; - unsigned long int flags; - - spin_lock_irqsave(&cryptocop_sessions_lock, flags); - sess = cryptocop_sessions; - while (sess && (sess->sid != sid)){ - sess = sess->next; - } - spin_unlock_irqrestore(&cryptocop_sessions_lock, flags); - - return sess; -} - -static struct cryptocop_transform_ctx *get_transform_ctx(struct cryptocop_session *sess, cryptocop_tfrm_id tid) -{ - struct cryptocop_transform_ctx *tc = sess->tfrm_ctx; - - DEBUG(printk("get_transform_ctx, sess=0x%p, tid=%d\n", sess, tid)); - assert(sess != NULL); - while (tc && tc->init.tid != tid){ - DEBUG(printk("tc=0x%p, tc->next=0x%p\n", tc, tc->next)); - tc = tc->next; - } - DEBUG(printk("get_transform_ctx, returning tc=0x%p\n", tc)); - return tc; -} - - - -/* The AES s-transform matrix (s-box). */ -static const u8 aes_sbox[256] = { - 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, - 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, - 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, - 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, - 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, - 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, - 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, - 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, - 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, - 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, - 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, - 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, - 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, - 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, - 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, - 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22 -}; - -/* AES has a 32 bit word round constants for each round in the - * key schedule. round_constant[i] is really Rcon[i+1] in FIPS187. - */ -static u32 round_constant[11] = { - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x1B000000, 0x36000000, 0x6C000000 -}; - -/* Apply the s-box to each of the four occtets in w. */ -static u32 aes_ks_subword(const u32 w) -{ - u8 bytes[4]; - - *(u32*)(&bytes[0]) = w; - bytes[0] = aes_sbox[bytes[0]]; - bytes[1] = aes_sbox[bytes[1]]; - bytes[2] = aes_sbox[bytes[2]]; - bytes[3] = aes_sbox[bytes[3]]; - return *(u32*)(&bytes[0]); -} - -/* The encrypt (forward) Rijndael key schedule algorithm pseudo code: - * (Note that AES words are 32 bit long) - * - * KeyExpansion(byte key[4*Nk], word w[Nb*(Nr+1)], Nk){ - * word temp - * i = 0 - * while (i < Nk) { - * w[i] = word(key[4*i, 4*i + 1, 4*i + 2, 4*i + 3]) - * i = i + 1 - * } - * i = Nk - * - * while (i < (Nb * (Nr + 1))) { - * temp = w[i - 1] - * if ((i mod Nk) == 0) { - * temp = SubWord(RotWord(temp)) xor Rcon[i/Nk] - * } - * else if ((Nk > 6) && ((i mod Nk) == 4)) { - * temp = SubWord(temp) - * } - * w[i] = w[i - Nk] xor temp - * } - * RotWord(t) does a 8 bit cyclic shift left on a 32 bit word. - * SubWord(t) applies the AES s-box individually to each octet - * in a 32 bit word. - * - * For AES Nk can have the values 4, 6, and 8 (corresponding to - * values for Nr of 10, 12, and 14). Nb is always 4. - * - * To construct w[i], w[i - 1] and w[i - Nk] must be - * available. Consequently we must keep a state of the last Nk words - * to be able to create the last round keys. - */ -static void get_aes_decrypt_key(unsigned char *dec_key, const unsigned char *key, unsigned int keylength) -{ - u32 temp; - u32 w_ring[8]; /* nk is max 8, use elements 0..(nk - 1) as a ringbuffer */ - u8 w_last_ix; - int i; - u8 nr, nk; - - switch (keylength){ - case 128: - nk = 4; - nr = 10; - break; - case 192: - nk = 6; - nr = 12; - break; - case 256: - nk = 8; - nr = 14; - break; - default: - panic("stream co-processor: bad aes key length in get_aes_decrypt_key\n"); - }; - - /* Need to do host byte order correction here since key is byte oriented and the - * kx algorithm is word (u32) oriented. */ - for (i = 0; i < nk; i+=1) { - w_ring[i] = be32_to_cpu(*(u32*)&key[4*i]); - } - - i = (int)nk; - w_last_ix = i - 1; - while (i < (4 * (nr + 2))) { - temp = w_ring[w_last_ix]; - if (!(i % nk)) { - /* RotWord(temp) */ - temp = (temp << 8) | (temp >> 24); - temp = aes_ks_subword(temp); - temp ^= round_constant[i/nk - 1]; - } else if ((nk > 6) && ((i % nk) == 4)) { - temp = aes_ks_subword(temp); - } - w_last_ix = (w_last_ix + 1) % nk; /* This is the same as (i-Nk) mod Nk */ - temp ^= w_ring[w_last_ix]; - w_ring[w_last_ix] = temp; - - /* We need the round keys for round Nr+1 and Nr+2 (round key - * Nr+2 is the round key beyond the last one used when - * encrypting). Rounds are numbered starting from 0, Nr=10 - * implies 11 rounds are used in encryption/decryption. - */ - if (i >= (4 * nr)) { - /* Need to do host byte order correction here, the key - * is byte oriented. */ - *(u32*)dec_key = cpu_to_be32(temp); - dec_key += 4; - } - ++i; - } -} - - -/**** Job/operation management. ****/ - -int cryptocop_job_queue_insert_csum(struct cryptocop_operation *operation) -{ - return cryptocop_job_queue_insert(cryptocop_prio_kernel_csum, operation); -} - -int cryptocop_job_queue_insert_crypto(struct cryptocop_operation *operation) -{ - return cryptocop_job_queue_insert(cryptocop_prio_kernel, operation); -} - -int cryptocop_job_queue_insert_user_job(struct cryptocop_operation *operation) -{ - return cryptocop_job_queue_insert(cryptocop_prio_user, operation); -} - -static int cryptocop_job_queue_insert(cryptocop_queue_priority prio, struct cryptocop_operation *operation) -{ - int ret; - struct cryptocop_prio_job *pj = NULL; - unsigned long int flags; - - DEBUG(printk("cryptocop_job_queue_insert(%d, 0x%p)\n", prio, operation)); - - if (!operation || !operation->cb){ - DEBUG_API(printk("cryptocop_job_queue_insert oper=0x%p, NULL operation or callback\n", operation)); - return -EINVAL; - } - - if ((ret = cryptocop_job_setup(&pj, operation)) != 0){ - DEBUG_API(printk("cryptocop_job_queue_insert: job setup failed\n")); - return ret; - } - assert(pj != NULL); - - spin_lock_irqsave(&cryptocop_job_queue_lock, flags); - list_add_tail(&pj->node, &cryptocop_job_queues[prio].jobs); - spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags); - - /* Make sure a job is running */ - cryptocop_start_job(); - return 0; -} - -static void cryptocop_do_tasklet(unsigned long unused); -DECLARE_TASKLET (cryptocop_tasklet, cryptocop_do_tasklet, 0); - -static void cryptocop_do_tasklet(unsigned long unused) -{ - struct list_head *node; - struct cryptocop_prio_job *pj = NULL; - unsigned long flags; - - DEBUG(printk("cryptocop_do_tasklet: entering\n")); - - do { - spin_lock_irqsave(&cryptocop_completed_jobs_lock, flags); - if (!list_empty(&cryptocop_completed_jobs)){ - node = cryptocop_completed_jobs.next; - list_del(node); - pj = list_entry(node, struct cryptocop_prio_job, node); - } else { - pj = NULL; - } - spin_unlock_irqrestore(&cryptocop_completed_jobs_lock, flags); - if (pj) { - assert(pj->oper != NULL); - - /* Notify consumer of operation completeness. */ - DEBUG(printk("cryptocop_do_tasklet: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data)); - - pj->oper->operation_status = 0; /* Job is completed. */ - pj->oper->cb(pj->oper, pj->oper->cb_data); - delete_internal_operation(pj->iop); - kfree(pj); - } - } while (pj != NULL); - - DEBUG(printk("cryptocop_do_tasklet: exiting\n")); -} - -static irqreturn_t -dma_done_interrupt(int irq, void *dev_id) -{ - struct cryptocop_prio_job *done_job; - reg_dma_rw_ack_intr ack_intr = { - .data = 1, - }; - - REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr); - - DEBUG(printk("cryptocop DMA done\n")); - - spin_lock(&running_job_lock); - if (cryptocop_running_job == NULL){ - printk("stream co-processor got interrupt when not busy\n"); - spin_unlock(&running_job_lock); - return IRQ_HANDLED; - } - done_job = cryptocop_running_job; - cryptocop_running_job = NULL; - spin_unlock(&running_job_lock); - - /* Start processing a job. */ - if (!spin_trylock(&cryptocop_process_lock)){ - DEBUG(printk("cryptocop irq handler, not starting a job\n")); - } else { - cryptocop_start_job(); - spin_unlock(&cryptocop_process_lock); - } - - done_job->oper->operation_status = 0; /* Job is completed. */ - if (done_job->oper->fast_callback){ - /* This operation wants callback from interrupt. */ - done_job->oper->cb(done_job->oper, done_job->oper->cb_data); - delete_internal_operation(done_job->iop); - kfree(done_job); - } else { - spin_lock(&cryptocop_completed_jobs_lock); - list_add_tail(&(done_job->node), &cryptocop_completed_jobs); - spin_unlock(&cryptocop_completed_jobs_lock); - tasklet_schedule(&cryptocop_tasklet); - } - - DEBUG(printk("cryptocop leave irq handler\n")); - return IRQ_HANDLED; -} - - -/* Setup interrupts and DMA channels. */ -static int init_cryptocop(void) -{ - unsigned long flags; - reg_dma_rw_cfg dma_cfg = {.en = 1}; - reg_dma_rw_intr_mask intr_mask_in = {.data = regk_dma_yes}; /* Only want descriptor interrupts from the DMA in channel. */ - reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 }; - reg_strcop_rw_cfg strcop_cfg = { - .ipend = regk_strcop_little, - .td1 = regk_strcop_e, - .td2 = regk_strcop_d, - .td3 = regk_strcop_e, - .ignore_sync = 0, - .en = 1 - }; - - if (request_irq(DMA_IRQ, dma_done_interrupt, 0, - "stream co-processor DMA", NULL)) - panic("request_irq stream co-processor irq dma9"); - - (void)crisv32_request_dma(OUT_DMA, "strcop", DMA_PANIC_ON_ERROR, - 0, dma_strp); - (void)crisv32_request_dma(IN_DMA, "strcop", DMA_PANIC_ON_ERROR, - 0, dma_strp); - - local_irq_save(flags); - - /* Reset and enable the cryptocop. */ - strcop_cfg.en = 0; - REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg); - strcop_cfg.en = 1; - REG_WR(strcop, regi_strcop, rw_cfg, strcop_cfg); - - /* Enable DMAs. */ - REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */ - REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */ - - /* Set up wordsize = 4 for DMAs. */ - DMA_WR_CMD(OUT_DMA_INST, regk_dma_set_w_size4); - DMA_WR_CMD(IN_DMA_INST, regk_dma_set_w_size4); - - /* Enable interrupts. */ - REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in); - - /* Clear intr ack. */ - REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr); - - local_irq_restore(flags); - - return 0; -} - -/* Free used cryptocop hw resources (interrupt and DMA channels). */ -static void release_cryptocop(void) -{ - unsigned long flags; - reg_dma_rw_cfg dma_cfg = {.en = 0}; - reg_dma_rw_intr_mask intr_mask_in = {0}; - reg_dma_rw_ack_intr ack_intr = {.data = 1,.in_eop = 1 }; - - local_irq_save(flags); - - /* Clear intr ack. */ - REG_WR(dma, IN_DMA_INST, rw_ack_intr, ack_intr); - - /* Disable DMAs. */ - REG_WR(dma, IN_DMA_INST, rw_cfg, dma_cfg); /* input DMA */ - REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_cfg); /* output DMA */ - - /* Disable interrupts. */ - REG_WR(dma, IN_DMA_INST, rw_intr_mask, intr_mask_in); - - local_irq_restore(flags); - - free_irq(DMA_IRQ, NULL); - - (void)crisv32_free_dma(OUT_DMA); - (void)crisv32_free_dma(IN_DMA); -} - - -/* Init job queue. */ -static int cryptocop_job_queue_init(void) -{ - int i; - - INIT_LIST_HEAD(&cryptocop_completed_jobs); - - for (i = 0; i < cryptocop_prio_no_prios; i++){ - cryptocop_job_queues[i].prio = (cryptocop_queue_priority)i; - INIT_LIST_HEAD(&cryptocop_job_queues[i].jobs); - } - return 0; -} - - -static void cryptocop_job_queue_close(void) -{ - struct list_head *node, *tmp; - struct cryptocop_prio_job *pj = NULL; - unsigned long int process_flags, flags; - int i; - - /* FIXME: This is as yet untested code. */ - - /* Stop strcop from getting an operation to process while we are closing the - module. */ - spin_lock_irqsave(&cryptocop_process_lock, process_flags); - - /* Empty the job queue. */ - for (i = 0; i < cryptocop_prio_no_prios; i++){ - if (!list_empty(&(cryptocop_job_queues[i].jobs))){ - list_for_each_safe(node, tmp, &(cryptocop_job_queues[i].jobs)) { - pj = list_entry(node, struct cryptocop_prio_job, node); - list_del(node); - - /* Call callback to notify consumer of job removal. */ - DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data)); - pj->oper->operation_status = -EINTR; /* Job is terminated without completion. */ - pj->oper->cb(pj->oper, pj->oper->cb_data); - - delete_internal_operation(pj->iop); - kfree(pj); - } - } - } - spin_unlock_irqrestore(&cryptocop_process_lock, process_flags); - - /* Remove the running job, if any. */ - spin_lock_irqsave(&running_job_lock, flags); - if (cryptocop_running_job){ - reg_strcop_rw_cfg rw_cfg; - reg_dma_rw_cfg dma_out_cfg, dma_in_cfg; - - /* Stop DMA. */ - dma_out_cfg = REG_RD(dma, OUT_DMA_INST, rw_cfg); - dma_out_cfg.en = regk_dma_no; - REG_WR(dma, OUT_DMA_INST, rw_cfg, dma_out_cfg); - - dma_in_cfg = REG_RD(dma, IN_DMA_INST, rw_cfg); - dma_in_cfg.en = regk_dma_no; - REG_WR(dma, IN_DMA_INST, rw_cfg, dma_in_cfg); - - /* Disable the cryptocop. */ - rw_cfg = REG_RD(strcop, regi_strcop, rw_cfg); - rw_cfg.en = 0; - REG_WR(strcop, regi_strcop, rw_cfg, rw_cfg); - - pj = cryptocop_running_job; - cryptocop_running_job = NULL; - - /* Call callback to notify consumer of job removal. */ - DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data)); - pj->oper->operation_status = -EINTR; /* Job is terminated without completion. */ - pj->oper->cb(pj->oper, pj->oper->cb_data); - - delete_internal_operation(pj->iop); - kfree(pj); - } - spin_unlock_irqrestore(&running_job_lock, flags); - - /* Remove completed jobs, if any. */ - spin_lock_irqsave(&cryptocop_completed_jobs_lock, flags); - - list_for_each_safe(node, tmp, &cryptocop_completed_jobs) { - pj = list_entry(node, struct cryptocop_prio_job, node); - list_del(node); - /* Call callback to notify consumer of job removal. */ - DEBUG(printk("cryptocop_job_queue_close: callback 0x%p, data 0x%p\n", pj->oper->cb, pj->oper->cb_data)); - pj->oper->operation_status = -EINTR; /* Job is terminated without completion. */ - pj->oper->cb(pj->oper, pj->oper->cb_data); - - delete_internal_operation(pj->iop); - kfree(pj); - } - spin_unlock_irqrestore(&cryptocop_completed_jobs_lock, flags); -} - - -static void cryptocop_start_job(void) -{ - int i; - struct cryptocop_prio_job *pj; - unsigned long int flags; - unsigned long int running_job_flags; - reg_strcop_rw_cfg rw_cfg = {.en = 1, .ignore_sync = 0}; - - DEBUG(printk("cryptocop_start_job: entering\n")); - - spin_lock_irqsave(&running_job_lock, running_job_flags); - if (cryptocop_running_job != NULL){ - /* Already running. */ - DEBUG(printk("cryptocop_start_job: already running, exit\n")); - spin_unlock_irqrestore(&running_job_lock, running_job_flags); - return; - } - spin_lock_irqsave(&cryptocop_job_queue_lock, flags); - - /* Check the queues in priority order. */ - for (i = cryptocop_prio_kernel_csum; (i < cryptocop_prio_no_prios) && list_empty(&cryptocop_job_queues[i].jobs); i++); - if (i == cryptocop_prio_no_prios) { - spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags); - spin_unlock_irqrestore(&running_job_lock, running_job_flags); - DEBUG(printk("cryptocop_start_job: no jobs to run\n")); - return; /* No jobs to run */ - } - DEBUG(printk("starting job for prio %d\n", i)); - - /* TODO: Do not starve lower priority jobs. Let in a lower - * prio job for every N-th processed higher prio job or some - * other scheduling policy. This could reasonably be - * tweakable since the optimal balance would depend on the - * type of load on the system. */ - - /* Pull the DMA lists from the job and start the DMA client. */ - pj = list_entry(cryptocop_job_queues[i].jobs.next, struct cryptocop_prio_job, node); - list_del(&pj->node); - spin_unlock_irqrestore(&cryptocop_job_queue_lock, flags); - cryptocop_running_job = pj; - - /* Set config register (3DES and CSUM modes). */ - switch (pj->iop->tdes_mode){ - case cryptocop_3des_eee: - rw_cfg.td1 = regk_strcop_e; - rw_cfg.td2 = regk_strcop_e; - rw_cfg.td3 = regk_strcop_e; - break; - case cryptocop_3des_eed: - rw_cfg.td1 = regk_strcop_e; - rw_cfg.td2 = regk_strcop_e; - rw_cfg.td3 = regk_strcop_d; - break; - case cryptocop_3des_ede: - rw_cfg.td1 = regk_strcop_e; - rw_cfg.td2 = regk_strcop_d; - rw_cfg.td3 = regk_strcop_e; - break; - case cryptocop_3des_edd: - rw_cfg.td1 = regk_strcop_e; - rw_cfg.td2 = regk_strcop_d; - rw_cfg.td3 = regk_strcop_d; - break; - case cryptocop_3des_dee: - rw_cfg.td1 = regk_strcop_d; - rw_cfg.td2 = regk_strcop_e; - rw_cfg.td3 = regk_strcop_e; - break; - case cryptocop_3des_ded: - rw_cfg.td1 = regk_strcop_d; - rw_cfg.td2 = regk_strcop_e; - rw_cfg.td3 = regk_strcop_d; - break; - case cryptocop_3des_dde: - rw_cfg.td1 = regk_strcop_d; - rw_cfg.td2 = regk_strcop_d; - rw_cfg.td3 = regk_strcop_e; - break; - case cryptocop_3des_ddd: - rw_cfg.td1 = regk_strcop_d; - rw_cfg.td2 = regk_strcop_d; - rw_cfg.td3 = regk_strcop_d; - break; - default: - DEBUG(printk("cryptocop_setup_dma_list: bad 3DES mode\n")); - } - switch (pj->iop->csum_mode){ - case cryptocop_csum_le: - rw_cfg.ipend = regk_strcop_little; - break; - case cryptocop_csum_be: - rw_cfg.ipend = regk_strcop_big; - break; - default: - DEBUG(printk("cryptocop_setup_dma_list: bad checksum mode\n")); - } - REG_WR(strcop, regi_strcop, rw_cfg, rw_cfg); - - DEBUG(printk("cryptocop_start_job: starting DMA, new cryptocop_running_job=0x%p\n" - "ctx_in: 0x%p, phys: 0x%p\n" - "ctx_out: 0x%p, phys: 0x%p\n", - pj, - &pj->iop->ctx_in, (char*)virt_to_phys(&pj->iop->ctx_in), - &pj->iop->ctx_out, (char*)virt_to_phys(&pj->iop->ctx_out))); - - /* Start input DMA. */ - flush_dma_context(&pj->iop->ctx_in); - DMA_START_CONTEXT(IN_DMA_INST, virt_to_phys(&pj->iop->ctx_in)); - - /* Start output DMA. */ - DMA_START_CONTEXT(OUT_DMA_INST, virt_to_phys(&pj->iop->ctx_out)); - - spin_unlock_irqrestore(&running_job_lock, running_job_flags); - DEBUG(printk("cryptocop_start_job: exiting\n")); -} - - -static int cryptocop_job_setup(struct cryptocop_prio_job **pj, struct cryptocop_operation *operation) -{ - int err; - int alloc_flag = operation->in_interrupt ? GFP_ATOMIC : GFP_KERNEL; - void *iop_alloc_ptr = NULL; - - *pj = kmalloc(sizeof (struct cryptocop_prio_job), alloc_flag); - if (!*pj) return -ENOMEM; - - DEBUG(printk("cryptocop_job_setup: operation=0x%p\n", operation)); - - (*pj)->oper = operation; - DEBUG(printk("cryptocop_job_setup, cb=0x%p cb_data=0x%p\n", (*pj)->oper->cb, (*pj)->oper->cb_data)); - - if (operation->use_dmalists) { - DEBUG(print_user_dma_lists(&operation->list_op)); - if (!operation->list_op.inlist || !operation->list_op.outlist || !operation->list_op.out_data_buf || !operation->list_op.in_data_buf){ - DEBUG_API(printk("cryptocop_job_setup: bad indata (use_dmalists)\n")); - kfree(*pj); - return -EINVAL; - } - iop_alloc_ptr = kmalloc(DESCR_ALLOC_PAD + sizeof(struct cryptocop_int_operation), alloc_flag); - if (!iop_alloc_ptr) { - DEBUG_API(printk("cryptocop_job_setup: kmalloc cryptocop_int_operation\n")); - kfree(*pj); - return -ENOMEM; - } - (*pj)->iop = (struct cryptocop_int_operation*)(((unsigned long int)(iop_alloc_ptr + DESCR_ALLOC_PAD + offsetof(struct cryptocop_int_operation, ctx_out)) & ~0x0000001F) - offsetof(struct cryptocop_int_operation, ctx_out)); - DEBUG(memset((*pj)->iop, 0xff, sizeof(struct cryptocop_int_operation))); - (*pj)->iop->alloc_ptr = iop_alloc_ptr; - (*pj)->iop->sid = operation->sid; - (*pj)->iop->cdesc_out = NULL; - (*pj)->iop->cdesc_in = NULL; - (*pj)->iop->tdes_mode = operation->list_op.tdes_mode; - (*pj)->iop->csum_mode = operation->list_op.csum_mode; - (*pj)->iop->ddesc_out = operation->list_op.outlist; - (*pj)->iop->ddesc_in = operation->list_op.inlist; - - /* Setup DMA contexts. */ - (*pj)->iop->ctx_out.next = NULL; - (*pj)->iop->ctx_out.eol = 1; - (*pj)->iop->ctx_out.saved_data = operation->list_op.outlist; - (*pj)->iop->ctx_out.saved_data_buf = operation->list_op.out_data_buf; - - (*pj)->iop->ctx_in.next = NULL; - (*pj)->iop->ctx_in.eol = 1; - (*pj)->iop->ctx_in.saved_data = operation->list_op.inlist; - (*pj)->iop->ctx_in.saved_data_buf = operation->list_op.in_data_buf; - } else { - if ((err = cryptocop_setup_dma_list(operation, &(*pj)->iop, alloc_flag))) { - DEBUG_API(printk("cryptocop_job_setup: cryptocop_setup_dma_list failed %d\n", err)); - kfree(*pj); - return err; - } - } - DEBUG(print_dma_descriptors((*pj)->iop)); - - DEBUG(printk("cryptocop_job_setup, DMA list setup successful\n")); - - return 0; -} - -static int cryptocop_open(struct inode *inode, struct file *filp) -{ - int p = iminor(inode); - - if (p != CRYPTOCOP_MINOR) return -EINVAL; - - filp->private_data = NULL; - return 0; -} - - -static int cryptocop_release(struct inode *inode, struct file *filp) -{ - struct cryptocop_private *dev = filp->private_data; - struct cryptocop_private *dev_next; - - while (dev){ - dev_next = dev->next; - if (dev->sid != CRYPTOCOP_SESSION_ID_NONE) { - (void)cryptocop_free_session(dev->sid); - } - kfree(dev); - dev = dev_next; - } - - return 0; -} - - -static int cryptocop_ioctl_close_session(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct cryptocop_private *dev = filp->private_data; - struct cryptocop_private *prev_dev = NULL; - struct strcop_session_op *sess_op = (struct strcop_session_op *)arg; - struct strcop_session_op sop; - int err; - - DEBUG(printk("cryptocop_ioctl_close_session\n")); - - if (!access_ok(VERIFY_READ, sess_op, sizeof(struct strcop_session_op))) - return -EFAULT; - err = copy_from_user(&sop, sess_op, sizeof(struct strcop_session_op)); - if (err) return -EFAULT; - - while (dev && (dev->sid != sop.ses_id)) { - prev_dev = dev; - dev = dev->next; - } - if (dev){ - if (prev_dev){ - prev_dev->next = dev->next; - } else { - filp->private_data = dev->next; - } - err = cryptocop_free_session(dev->sid); - if (err) return -EFAULT; - } else { - DEBUG_API(printk("cryptocop_ioctl_close_session: session %lld not found\n", sop.ses_id)); - return -EINVAL; - } - return 0; -} - - -static void ioctl_process_job_callback(struct cryptocop_operation *op, void*cb_data) -{ - struct ioctl_job_cb_ctx *jc = (struct ioctl_job_cb_ctx *)cb_data; - - DEBUG(printk("ioctl_process_job_callback: op=0x%p, cb_data=0x%p\n", op, cb_data)); - - jc->processed = 1; - wake_up(&cryptocop_ioc_process_wq); -} - - -#define CRYPTOCOP_IOCTL_CIPHER_TID (1) -#define CRYPTOCOP_IOCTL_DIGEST_TID (2) -#define CRYPTOCOP_IOCTL_CSUM_TID (3) - -static size_t first_cfg_change_ix(struct strcop_crypto_op *crp_op) -{ - size_t ch_ix = 0; - - if (crp_op->do_cipher) ch_ix = crp_op->cipher_start; - if (crp_op->do_digest && (crp_op->digest_start < ch_ix)) ch_ix = crp_op->digest_start; - if (crp_op->do_csum && (crp_op->csum_start < ch_ix)) ch_ix = crp_op->csum_start; - - DEBUG(printk("first_cfg_change_ix: ix=%d\n", ch_ix)); - return ch_ix; -} - - -static size_t next_cfg_change_ix(struct strcop_crypto_op *crp_op, size_t ix) -{ - size_t ch_ix = INT_MAX; - size_t tmp_ix = 0; - - if (crp_op->do_cipher && ((crp_op->cipher_start + crp_op->cipher_len) > ix)){ - if (crp_op->cipher_start > ix) { - ch_ix = crp_op->cipher_start; - } else { - ch_ix = crp_op->cipher_start + crp_op->cipher_len; - } - } - if (crp_op->do_digest && ((crp_op->digest_start + crp_op->digest_len) > ix)){ - if (crp_op->digest_start > ix) { - tmp_ix = crp_op->digest_start; - } else { - tmp_ix = crp_op->digest_start + crp_op->digest_len; - } - if (tmp_ix < ch_ix) ch_ix = tmp_ix; - } - if (crp_op->do_csum && ((crp_op->csum_start + crp_op->csum_len) > ix)){ - if (crp_op->csum_start > ix) { - tmp_ix = crp_op->csum_start; - } else { - tmp_ix = crp_op->csum_start + crp_op->csum_len; - } - if (tmp_ix < ch_ix) ch_ix = tmp_ix; - } - if (ch_ix == INT_MAX) ch_ix = ix; - DEBUG(printk("next_cfg_change_ix prev ix=%d, next ix=%d\n", ix, ch_ix)); - return ch_ix; -} - - -/* Map map_length bytes from the pages starting on *pageix and *pageoffset to iovecs starting on *iovix. - * Return -1 for ok, 0 for fail. */ -static int map_pages_to_iovec(struct iovec *iov, int iovlen, int *iovix, struct page **pages, int nopages, int *pageix, int *pageoffset, int map_length ) -{ - int tmplen; - - assert(iov != NULL); - assert(iovix != NULL); - assert(pages != NULL); - assert(pageix != NULL); - assert(pageoffset != NULL); - - DEBUG(printk("map_pages_to_iovec, map_length=%d, iovlen=%d, *iovix=%d, nopages=%d, *pageix=%d, *pageoffset=%d\n", map_length, iovlen, *iovix, nopages, *pageix, *pageoffset)); - - while (map_length > 0){ - DEBUG(printk("map_pages_to_iovec, map_length=%d, iovlen=%d, *iovix=%d, nopages=%d, *pageix=%d, *pageoffset=%d\n", map_length, iovlen, *iovix, nopages, *pageix, *pageoffset)); - if (*iovix >= iovlen){ - DEBUG_API(printk("map_page_to_iovec: *iovix=%d >= iovlen=%d\n", *iovix, iovlen)); - return 0; - } - if (*pageix >= nopages){ - DEBUG_API(printk("map_page_to_iovec: *pageix=%d >= nopages=%d\n", *pageix, nopages)); - return 0; - } - iov[*iovix].iov_base = (unsigned char*)page_address(pages[*pageix]) + *pageoffset; - tmplen = PAGE_SIZE - *pageoffset; - if (tmplen < map_length){ - (*pageoffset) = 0; - (*pageix)++; - } else { - tmplen = map_length; - (*pageoffset) += map_length; - } - DEBUG(printk("mapping %d bytes from page %d (or %d) to iovec %d\n", tmplen, *pageix, *pageix-1, *iovix)); - iov[*iovix].iov_len = tmplen; - map_length -= tmplen; - (*iovix)++; - } - DEBUG(printk("map_page_to_iovec, exit, *iovix=%d\n", *iovix)); - return -1; -} - - - -static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -{ - int i; - struct cryptocop_private *dev = filp->private_data; - struct strcop_crypto_op *crp_oper = (struct strcop_crypto_op *)arg; - struct strcop_crypto_op oper = {0}; - int err = 0; - struct cryptocop_operation *cop = NULL; - - struct ioctl_job_cb_ctx *jc = NULL; - - struct page **inpages = NULL; - struct page **outpages = NULL; - int noinpages = 0; - int nooutpages = 0; - - struct cryptocop_desc descs[5]; /* Max 5 descriptors are needed, there are three transforms that - * can get connected/disconnected on different places in the indata. */ - struct cryptocop_desc_cfg dcfgs[5*3]; - int desc_ix = 0; - int dcfg_ix = 0; - struct cryptocop_tfrm_cfg ciph_tcfg = {0}; - struct cryptocop_tfrm_cfg digest_tcfg = {0}; - struct cryptocop_tfrm_cfg csum_tcfg = {0}; - - unsigned char *digest_result = NULL; - int digest_length = 0; - int cblocklen = 0; - unsigned char csum_result[CSUM_BLOCK_LENGTH]; - struct cryptocop_session *sess; - - int iovlen = 0; - int iovix = 0; - int pageix = 0; - int pageoffset = 0; - - size_t prev_ix = 0; - size_t next_ix; - - int cipher_active, digest_active, csum_active; - int end_digest, end_csum; - int digest_done = 0; - int cipher_done = 0; - int csum_done = 0; - - DEBUG(printk("cryptocop_ioctl_process\n")); - - if (!access_ok(VERIFY_WRITE, crp_oper, sizeof(struct strcop_crypto_op))){ - DEBUG_API(printk("cryptocop_ioctl_process: !access_ok crp_oper!\n")); - return -EFAULT; - } - if (copy_from_user(&oper, crp_oper, sizeof(struct strcop_crypto_op))) { - DEBUG_API(printk("cryptocop_ioctl_process: copy_from_user\n")); - return -EFAULT; - } - DEBUG(print_strcop_crypto_op(&oper)); - - while (dev && dev->sid != oper.ses_id) dev = dev->next; - if (!dev){ - DEBUG_API(printk("cryptocop_ioctl_process: session %lld not found\n", oper.ses_id)); - return -EINVAL; - } - - /* Check buffers. */ - if (((oper.indata + oper.inlen) < oper.indata) || ((oper.cipher_outdata + oper.cipher_outlen) < oper.cipher_outdata)){ - DEBUG_API(printk("cryptocop_ioctl_process: user buffers wrapped around, bad user!\n")); - return -EINVAL; - } - - if (!access_ok(VERIFY_WRITE, oper.cipher_outdata, oper.cipher_outlen)){ - DEBUG_API(printk("cryptocop_ioctl_process: !access_ok out data!\n")); - return -EFAULT; - } - if (!access_ok(VERIFY_READ, oper.indata, oper.inlen)){ - DEBUG_API(printk("cryptocop_ioctl_process: !access_ok in data!\n")); - return -EFAULT; - } - - cop = kmalloc(sizeof(struct cryptocop_operation), GFP_KERNEL); - if (!cop) { - DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n")); - return -ENOMEM; - } - jc = kmalloc(sizeof(struct ioctl_job_cb_ctx), GFP_KERNEL); - if (!jc) { - DEBUG_API(printk("cryptocop_ioctl_process: kmalloc\n")); - err = -ENOMEM; - goto error_cleanup; - } - jc->processed = 0; - - cop->cb_data = jc; - cop->cb = ioctl_process_job_callback; - cop->operation_status = 0; - cop->use_dmalists = 0; - cop->in_interrupt = 0; - cop->fast_callback = 0; - cop->tfrm_op.tfrm_cfg = NULL; - cop->tfrm_op.desc = NULL; - cop->tfrm_op.indata = NULL; - cop->tfrm_op.incount = 0; - cop->tfrm_op.inlen = 0; - cop->tfrm_op.outdata = NULL; - cop->tfrm_op.outcount = 0; - cop->tfrm_op.outlen = 0; - - sess = get_session(oper.ses_id); - if (!sess){ - DEBUG_API(printk("cryptocop_ioctl_process: bad session id.\n")); - kfree(cop); - kfree(jc); - return -EINVAL; - } - - if (oper.do_cipher) { - unsigned int cipher_outlen = 0; - struct cryptocop_transform_ctx *tc = get_transform_ctx(sess, CRYPTOCOP_IOCTL_CIPHER_TID); - if (!tc) { - DEBUG_API(printk("cryptocop_ioctl_process: no cipher transform in session.\n")); - err = -EINVAL; - goto error_cleanup; - } - ciph_tcfg.tid = CRYPTOCOP_IOCTL_CIPHER_TID; - ciph_tcfg.inject_ix = 0; - ciph_tcfg.flags = 0; - if ((oper.cipher_start < 0) || (oper.cipher_len <= 0) || (oper.cipher_start > oper.inlen) || ((oper.cipher_start + oper.cipher_len) > oper.inlen)){ - DEBUG_API(printk("cryptocop_ioctl_process: bad cipher length\n")); - kfree(cop); - kfree(jc); - return -EINVAL; - } - cblocklen = tc->init.alg == cryptocop_alg_aes ? AES_BLOCK_LENGTH : DES_BLOCK_LENGTH; - if (oper.cipher_len % cblocklen) { - kfree(cop); - kfree(jc); - DEBUG_API(printk("cryptocop_ioctl_process: cipher inlength not multiple of block length.\n")); - return -EINVAL; - } - cipher_outlen = oper.cipher_len; - if (tc->init.cipher_mode == cryptocop_cipher_mode_cbc){ - if (oper.cipher_explicit) { - ciph_tcfg.flags |= CRYPTOCOP_EXPLICIT_IV; - memcpy(ciph_tcfg.iv, oper.cipher_iv, cblocklen); - } else { - cipher_outlen = oper.cipher_len - cblocklen; - } - } else { - if (oper.cipher_explicit){ - kfree(cop); - kfree(jc); - DEBUG_API(printk("cryptocop_ioctl_process: explicit_iv when not CBC mode\n")); - return -EINVAL; - } - } - if (oper.cipher_outlen != cipher_outlen) { - kfree(cop); - kfree(jc); - DEBUG_API(printk("cryptocop_ioctl_process: cipher_outlen incorrect, should be %d not %d.\n", cipher_outlen, oper.cipher_outlen)); - return -EINVAL; - } - - if (oper.decrypt){ - ciph_tcfg.flags |= CRYPTOCOP_DECRYPT; - } else { - ciph_tcfg.flags |= CRYPTOCOP_ENCRYPT; - } - ciph_tcfg.next = cop->tfrm_op.tfrm_cfg; - cop->tfrm_op.tfrm_cfg = &ciph_tcfg; - } - if (oper.do_digest){ - struct cryptocop_transform_ctx *tc = get_transform_ctx(sess, CRYPTOCOP_IOCTL_DIGEST_TID); - if (!tc) { - DEBUG_API(printk("cryptocop_ioctl_process: no digest transform in session.\n")); - err = -EINVAL; - goto error_cleanup; - } - digest_length = tc->init.alg == cryptocop_alg_md5 ? 16 : 20; - digest_result = kmalloc(digest_length, GFP_KERNEL); - if (!digest_result) { - DEBUG_API(printk("cryptocop_ioctl_process: kmalloc digest_result\n")); - err = -EINVAL; - goto error_cleanup; - } - DEBUG(memset(digest_result, 0xff, digest_length)); - - digest_tcfg.tid = CRYPTOCOP_IOCTL_DIGEST_TID; - digest_tcfg.inject_ix = 0; - ciph_tcfg.inject_ix += digest_length; - if ((oper.digest_start < 0) || (oper.digest_len <= 0) || (oper.digest_start > oper.inlen) || ((oper.digest_start + oper.digest_len) > oper.inlen)){ - DEBUG_API(printk("cryptocop_ioctl_process: bad digest length\n")); - err = -EINVAL; - goto error_cleanup; - } - - digest_tcfg.next = cop->tfrm_op.tfrm_cfg; - cop->tfrm_op.tfrm_cfg = &digest_tcfg; - } - if (oper.do_csum){ - csum_tcfg.tid = CRYPTOCOP_IOCTL_CSUM_TID; - csum_tcfg.inject_ix = digest_length; - ciph_tcfg.inject_ix += 2; - - if ((oper.csum_start < 0) || (oper.csum_len <= 0) || (oper.csum_start > oper.inlen) || ((oper.csum_start + oper.csum_len) > oper.inlen)){ - DEBUG_API(printk("cryptocop_ioctl_process: bad csum length\n")); - kfree(cop); - kfree(jc); - return -EINVAL; - } - - csum_tcfg.next = cop->tfrm_op.tfrm_cfg; - cop->tfrm_op.tfrm_cfg = &csum_tcfg; - } - - prev_ix = first_cfg_change_ix(&oper); - if (prev_ix > oper.inlen) { - DEBUG_API(printk("cryptocop_ioctl_process: length mismatch\n")); - nooutpages = noinpages = 0; - err = -EINVAL; - goto error_cleanup; - } - DEBUG(printk("cryptocop_ioctl_process: inlen=%d, cipher_outlen=%d\n", oper.inlen, oper.cipher_outlen)); - - /* Map user pages for in and out data of the operation. */ - noinpages = (((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK) + oper.inlen - 1 - prev_ix + ~PAGE_MASK) >> PAGE_SHIFT; - DEBUG(printk("cryptocop_ioctl_process: noinpages=%d\n", noinpages)); - inpages = kmalloc(noinpages * sizeof(struct page*), GFP_KERNEL); - if (!inpages){ - DEBUG_API(printk("cryptocop_ioctl_process: kmalloc inpages\n")); - nooutpages = noinpages = 0; - err = -ENOMEM; - goto error_cleanup; - } - if (oper.do_cipher){ - nooutpages = (((unsigned long int)oper.cipher_outdata & ~PAGE_MASK) + oper.cipher_outlen - 1 + ~PAGE_MASK) >> PAGE_SHIFT; - DEBUG(printk("cryptocop_ioctl_process: nooutpages=%d\n", nooutpages)); - outpages = kmalloc(nooutpages * sizeof(struct page*), GFP_KERNEL); - if (!outpages){ - DEBUG_API(printk("cryptocop_ioctl_process: kmalloc outpages\n")); - nooutpages = noinpages = 0; - err = -ENOMEM; - goto error_cleanup; - } - } - - err = get_user_pages_fast((unsigned long)(oper.indata + prev_ix), - noinpages, - false, /* read access only for in data */ - inpages); - - if (err < 0) { - nooutpages = noinpages = 0; - DEBUG_API(printk("cryptocop_ioctl_process: get_user_pages indata\n")); - goto error_cleanup; - } - noinpages = err; - if (oper.do_cipher) { - err = get_user_pages_fast((unsigned long)oper.cipher_outdata, - nooutpages, - true, /* write access for out data */ - outpages); - if (err < 0) { - nooutpages = 0; - DEBUG_API(printk("cryptocop_ioctl_process: get_user_pages outdata\n")); - goto error_cleanup; - } - nooutpages = err; - } - - /* Add 6 to nooutpages to make room for possibly inserted buffers for storing digest and - * csum output and splits when units are (dis-)connected. */ - cop->tfrm_op.indata = kmalloc((noinpages) * sizeof(struct iovec), GFP_KERNEL); - cop->tfrm_op.outdata = kmalloc((6 + nooutpages) * sizeof(struct iovec), GFP_KERNEL); - if (!cop->tfrm_op.indata || !cop->tfrm_op.outdata) { - DEBUG_API(printk("cryptocop_ioctl_process: kmalloc iovecs\n")); - err = -ENOMEM; - goto error_cleanup; - } - - cop->tfrm_op.inlen = oper.inlen - prev_ix; - cop->tfrm_op.outlen = 0; - if (oper.do_cipher) cop->tfrm_op.outlen += oper.cipher_outlen; - if (oper.do_digest) cop->tfrm_op.outlen += digest_length; - if (oper.do_csum) cop->tfrm_op.outlen += 2; - - /* Setup the in iovecs. */ - cop->tfrm_op.incount = noinpages; - if (noinpages > 1){ - size_t tmplen = cop->tfrm_op.inlen; - - cop->tfrm_op.indata[0].iov_len = PAGE_SIZE - ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK); - cop->tfrm_op.indata[0].iov_base = (unsigned char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK); - tmplen -= cop->tfrm_op.indata[0].iov_len; - for (i = 1; i<noinpages; i++){ - cop->tfrm_op.indata[i].iov_len = tmplen < PAGE_SIZE ? tmplen : PAGE_SIZE; - cop->tfrm_op.indata[i].iov_base = (unsigned char*)page_address(inpages[i]); - tmplen -= PAGE_SIZE; - } - } else { - cop->tfrm_op.indata[0].iov_len = oper.inlen - prev_ix; - cop->tfrm_op.indata[0].iov_base = (unsigned char*)page_address(inpages[0]) + ((unsigned long int)(oper.indata + prev_ix) & ~PAGE_MASK); - } - - iovlen = nooutpages + 6; - pageoffset = oper.do_cipher ? ((unsigned long int)oper.cipher_outdata & ~PAGE_MASK) : 0; - - next_ix = next_cfg_change_ix(&oper, prev_ix); - if (prev_ix == next_ix){ - DEBUG_API(printk("cryptocop_ioctl_process: length configuration broken.\n")); - err = -EINVAL; /* This should be impossible barring bugs. */ - goto error_cleanup; - } - while (prev_ix != next_ix){ - end_digest = end_csum = cipher_active = digest_active = csum_active = 0; - descs[desc_ix].cfg = NULL; - descs[desc_ix].length = next_ix - prev_ix; - - if (oper.do_cipher && (oper.cipher_start < next_ix) && (prev_ix < (oper.cipher_start + oper.cipher_len))) { - dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CIPHER_TID; - dcfgs[dcfg_ix].src = cryptocop_source_dma; - cipher_active = 1; - - if (next_ix == (oper.cipher_start + oper.cipher_len)){ - cipher_done = 1; - dcfgs[dcfg_ix].last = 1; - } else { - dcfgs[dcfg_ix].last = 0; - } - dcfgs[dcfg_ix].next = descs[desc_ix].cfg; - descs[desc_ix].cfg = &dcfgs[dcfg_ix]; - ++dcfg_ix; - } - if (oper.do_digest && (oper.digest_start < next_ix) && (prev_ix < (oper.digest_start + oper.digest_len))) { - digest_active = 1; - dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_DIGEST_TID; - dcfgs[dcfg_ix].src = cryptocop_source_dma; - if (next_ix == (oper.digest_start + oper.digest_len)){ - assert(!digest_done); - digest_done = 1; - dcfgs[dcfg_ix].last = 1; - } else { - dcfgs[dcfg_ix].last = 0; - } - dcfgs[dcfg_ix].next = descs[desc_ix].cfg; - descs[desc_ix].cfg = &dcfgs[dcfg_ix]; - ++dcfg_ix; - } - if (oper.do_csum && (oper.csum_start < next_ix) && (prev_ix < (oper.csum_start + oper.csum_len))){ - csum_active = 1; - dcfgs[dcfg_ix].tid = CRYPTOCOP_IOCTL_CSUM_TID; - dcfgs[dcfg_ix].src = cryptocop_source_dma; - if (next_ix == (oper.csum_start + oper.csum_len)){ - csum_done = 1; - dcfgs[dcfg_ix].last = 1; - } else { - dcfgs[dcfg_ix].last = 0; - } - dcfgs[dcfg_ix].next = descs[desc_ix].cfg; - descs[desc_ix].cfg = &dcfgs[dcfg_ix]; - ++dcfg_ix; - } - if (!descs[desc_ix].cfg){ - DEBUG_API(printk("cryptocop_ioctl_process: data segment %d (%d to %d) had no active transforms\n", desc_ix, prev_ix, next_ix)); - err = -EINVAL; - goto error_cleanup; - } - descs[desc_ix].next = &(descs[desc_ix]) + 1; - ++desc_ix; - prev_ix = next_ix; - next_ix = next_cfg_change_ix(&oper, prev_ix); - } - if (desc_ix > 0){ - descs[desc_ix-1].next = NULL; - } else { - descs[0].next = NULL; - } - if (oper.do_digest) { - DEBUG(printk("cryptocop_ioctl_process: mapping %d byte digest output to iovec %d\n", digest_length, iovix)); - /* Add outdata iovec, length == <length of type of digest> */ - cop->tfrm_op.outdata[iovix].iov_base = digest_result; - cop->tfrm_op.outdata[iovix].iov_len = digest_length; - ++iovix; - } - if (oper.do_csum) { - /* Add outdata iovec, length == 2, the length of csum. */ - DEBUG(printk("cryptocop_ioctl_process: mapping 2 byte csum output to iovec %d\n", iovix)); - /* Add outdata iovec, length == <length of type of digest> */ - cop->tfrm_op.outdata[iovix].iov_base = csum_result; - cop->tfrm_op.outdata[iovix].iov_len = 2; - ++iovix; - } - if (oper.do_cipher) { - if (!map_pages_to_iovec(cop->tfrm_op.outdata, iovlen, &iovix, outpages, nooutpages, &pageix, &pageoffset, oper.cipher_outlen)){ - DEBUG_API(printk("cryptocop_ioctl_process: failed to map pages to iovec.\n")); - err = -ENOSYS; /* This should be impossible barring bugs. */ - goto error_cleanup; - } - } - DEBUG(printk("cryptocop_ioctl_process: setting cop->tfrm_op.outcount %d\n", iovix)); - cop->tfrm_op.outcount = iovix; - assert(iovix <= (nooutpages + 6)); - - cop->sid = oper.ses_id; - cop->tfrm_op.desc = &descs[0]; - - DEBUG(printk("cryptocop_ioctl_process: inserting job, cb_data=0x%p\n", cop->cb_data)); - - if ((err = cryptocop_job_queue_insert_user_job(cop)) != 0) { - DEBUG_API(printk("cryptocop_ioctl_process: insert job %d\n", err)); - err = -EINVAL; - goto error_cleanup; - } - - DEBUG(printk("cryptocop_ioctl_process: begin wait for result\n")); - - wait_event(cryptocop_ioc_process_wq, (jc->processed != 0)); - DEBUG(printk("cryptocop_ioctl_process: end wait for result\n")); - if (!jc->processed){ - printk(KERN_WARNING "cryptocop_ioctl_process: job not processed at completion\n"); - err = -EIO; - goto error_cleanup; - } - - /* Job process done. Cipher output should already be correct in job so no post processing of outdata. */ - DEBUG(printk("cryptocop_ioctl_process: operation_status = %d\n", cop->operation_status)); - if (cop->operation_status == 0){ - if (oper.do_digest){ - DEBUG(printk("cryptocop_ioctl_process: copy %d bytes digest to user\n", digest_length)); - err = copy_to_user((unsigned char*)crp_oper + offsetof(struct strcop_crypto_op, digest), digest_result, digest_length); - if (0 != err){ - DEBUG_API(printk("cryptocop_ioctl_process: copy_to_user, digest length %d, err %d\n", digest_length, err)); - err = -EFAULT; - goto error_cleanup; - } - } - if (oper.do_csum){ - DEBUG(printk("cryptocop_ioctl_process: copy 2 bytes checksum to user\n")); - err = copy_to_user((unsigned char*)crp_oper + offsetof(struct strcop_crypto_op, csum), csum_result, 2); - if (0 != err){ - DEBUG_API(printk("cryptocop_ioctl_process: copy_to_user, csum, err %d\n", err)); - err = -EFAULT; - goto error_cleanup; - } - } - err = 0; - } else { - DEBUG(printk("cryptocop_ioctl_process: returning err = operation_status = %d\n", cop->operation_status)); - err = cop->operation_status; - } - - error_cleanup: - /* Release page caches. */ - for (i = 0; i < noinpages; i++){ - put_page(inpages[i]); - } - for (i = 0; i < nooutpages; i++){ - int spdl_err; - /* Mark output pages dirty. */ - spdl_err = set_page_dirty_lock(outpages[i]); - DEBUG(if (spdl_err < 0)printk("cryptocop_ioctl_process: set_page_dirty_lock returned %d\n", spdl_err)); - } - for (i = 0; i < nooutpages; i++){ - put_page(outpages[i]); - } - - kfree(digest_result); - kfree(inpages); - kfree(outpages); - if (cop){ - kfree(cop->tfrm_op.indata); - kfree(cop->tfrm_op.outdata); - kfree(cop); - } - kfree(jc); - - DEBUG(print_lock_status()); - - return err; -} - - -static int cryptocop_ioctl_create_session(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) -{ - cryptocop_session_id sid; - int err; - struct cryptocop_private *dev; - struct strcop_session_op *sess_op = (struct strcop_session_op *)arg; - struct strcop_session_op sop; - struct cryptocop_transform_init *tis = NULL; - struct cryptocop_transform_init ti_cipher = {0}; - struct cryptocop_transform_init ti_digest = {0}; - struct cryptocop_transform_init ti_csum = {0}; - - if (!access_ok(VERIFY_WRITE, sess_op, sizeof(struct strcop_session_op))) - return -EFAULT; - err = copy_from_user(&sop, sess_op, sizeof(struct strcop_session_op)); - if (err) return -EFAULT; - if (sop.cipher != cryptocop_cipher_none) { - if (!access_ok(VERIFY_READ, sop.key, sop.keylen)) return -EFAULT; - } - DEBUG(printk("cryptocop_ioctl_create_session, sess_op:\n")); - - DEBUG(printk("\tcipher:%d\n" - "\tcipher_mode:%d\n" - "\tdigest:%d\n" - "\tcsum:%d\n", - (int)sop.cipher, - (int)sop.cmode, - (int)sop.digest, - (int)sop.csum)); - - if (sop.cipher != cryptocop_cipher_none){ - /* Init the cipher. */ - switch (sop.cipher){ - case cryptocop_cipher_des: - ti_cipher.alg = cryptocop_alg_des; - break; - case cryptocop_cipher_3des: - ti_cipher.alg = cryptocop_alg_3des; - break; - case cryptocop_cipher_aes: - ti_cipher.alg = cryptocop_alg_aes; - break; - default: - DEBUG_API(printk("create session, bad cipher algorithm %d\n", sop.cipher)); - return -EINVAL; - }; - DEBUG(printk("setting cipher transform %d\n", ti_cipher.alg)); - copy_from_user(ti_cipher.key, sop.key, sop.keylen/8); - ti_cipher.keylen = sop.keylen; - switch (sop.cmode){ - case cryptocop_cipher_mode_cbc: - case cryptocop_cipher_mode_ecb: - ti_cipher.cipher_mode = sop.cmode; - break; - default: - DEBUG_API(printk("create session, bad cipher mode %d\n", sop.cmode)); - return -EINVAL; - } - DEBUG(printk("cryptocop_ioctl_create_session: setting CBC mode %d\n", ti_cipher.cipher_mode)); - switch (sop.des3_mode){ - case cryptocop_3des_eee: - case cryptocop_3des_eed: - case cryptocop_3des_ede: - case cryptocop_3des_edd: - case cryptocop_3des_dee: - case cryptocop_3des_ded: - case cryptocop_3des_dde: - case cryptocop_3des_ddd: - ti_cipher.tdes_mode = sop.des3_mode; - break; - default: - DEBUG_API(printk("create session, bad 3DES mode %d\n", sop.des3_mode)); - return -EINVAL; - } - ti_cipher.tid = CRYPTOCOP_IOCTL_CIPHER_TID; - ti_cipher.next = tis; - tis = &ti_cipher; - } /* if (sop.cipher != cryptocop_cipher_none) */ - if (sop.digest != cryptocop_digest_none){ - DEBUG(printk("setting digest transform\n")); - switch (sop.digest){ - case cryptocop_digest_md5: - ti_digest.alg = cryptocop_alg_md5; - break; - case cryptocop_digest_sha1: - ti_digest.alg = cryptocop_alg_sha1; - break; - default: - DEBUG_API(printk("create session, bad digest algorithm %d\n", sop.digest)); - return -EINVAL; - } - ti_digest.tid = CRYPTOCOP_IOCTL_DIGEST_TID; - ti_digest.next = tis; - tis = &ti_digest; - } /* if (sop.digest != cryptocop_digest_none) */ - if (sop.csum != cryptocop_csum_none){ - DEBUG(printk("setting csum transform\n")); - switch (sop.csum){ - case cryptocop_csum_le: - case cryptocop_csum_be: - ti_csum.csum_mode = sop.csum; - break; - default: - DEBUG_API(printk("create session, bad checksum algorithm %d\n", sop.csum)); - return -EINVAL; - } - ti_csum.alg = cryptocop_alg_csum; - ti_csum.tid = CRYPTOCOP_IOCTL_CSUM_TID; - ti_csum.next = tis; - tis = &ti_csum; - } /* (sop.csum != cryptocop_csum_none) */ - dev = kmalloc(sizeof(struct cryptocop_private), GFP_KERNEL); - if (!dev){ - DEBUG_API(printk("create session, alloc dev\n")); - return -ENOMEM; - } - - err = cryptocop_new_session(&sid, tis, GFP_KERNEL); - DEBUG({ if (err) printk("create session, cryptocop_new_session %d\n", err);}); - - if (err) { - kfree(dev); - return err; - } - sess_op->ses_id = sid; - dev->sid = sid; - dev->next = filp->private_data; - filp->private_data = dev; - - return 0; -} - -static long cryptocop_ioctl_unlocked(struct inode *inode, - struct file *filp, unsigned int cmd, unsigned long arg) -{ - int err = 0; - if (_IOC_TYPE(cmd) != ETRAXCRYPTOCOP_IOCTYPE) { - DEBUG_API(printk("cryptocop_ioctl: wrong type\n")); - return -ENOTTY; - } - if (_IOC_NR(cmd) > CRYPTOCOP_IO_MAXNR){ - return -ENOTTY; - } - /* Access check of the argument. Some commands, e.g. create session and process op, - needs additional checks. Those are handled in the command handling functions. */ - if (_IOC_DIR(cmd) & _IOC_READ) - err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); - else if (_IOC_DIR(cmd) & _IOC_WRITE) - err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); - if (err) return -EFAULT; - - switch (cmd) { - case CRYPTOCOP_IO_CREATE_SESSION: - return cryptocop_ioctl_create_session(inode, filp, cmd, arg); - case CRYPTOCOP_IO_CLOSE_SESSION: - return cryptocop_ioctl_close_session(inode, filp, cmd, arg); - case CRYPTOCOP_IO_PROCESS_OP: - return cryptocop_ioctl_process(inode, filp, cmd, arg); - default: - DEBUG_API(printk("cryptocop_ioctl: unknown command\n")); - return -ENOTTY; - } - return 0; -} - -static long -cryptocop_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - long ret; - - mutex_lock(&cryptocop_mutex); - ret = cryptocop_ioctl_unlocked(file_inode(filp), filp, cmd, arg); - mutex_unlock(&cryptocop_mutex); - - return ret; -} - - -#ifdef LDEBUG -static void print_dma_descriptors(struct cryptocop_int_operation *iop) -{ - struct cryptocop_dma_desc *cdesc_out = iop->cdesc_out; - struct cryptocop_dma_desc *cdesc_in = iop->cdesc_in; - int i; - - printk("print_dma_descriptors start\n"); - - printk("iop:\n"); - printk("\tsid: 0x%llx\n", iop->sid); - - printk("\tcdesc_out: 0x%p\n", iop->cdesc_out); - printk("\tcdesc_in: 0x%p\n", iop->cdesc_in); - printk("\tddesc_out: 0x%p\n", iop->ddesc_out); - printk("\tddesc_in: 0x%p\n", iop->ddesc_in); - - printk("\niop->ctx_out: 0x%p phys: 0x%p\n", &iop->ctx_out, (char*)virt_to_phys(&iop->ctx_out)); - printk("\tnext: 0x%p\n" - "\tsaved_data: 0x%p\n" - "\tsaved_data_buf: 0x%p\n", - iop->ctx_out.next, - iop->ctx_out.saved_data, - iop->ctx_out.saved_data_buf); - - printk("\niop->ctx_in: 0x%p phys: 0x%p\n", &iop->ctx_in, (char*)virt_to_phys(&iop->ctx_in)); - printk("\tnext: 0x%p\n" - "\tsaved_data: 0x%p\n" - "\tsaved_data_buf: 0x%p\n", - iop->ctx_in.next, - iop->ctx_in.saved_data, - iop->ctx_in.saved_data_buf); - - i = 0; - while (cdesc_out) { - dma_descr_data *td; - printk("cdesc_out %d, desc=0x%p\n", i, cdesc_out->dma_descr); - printk("\n\tvirt_to_phys(desc): 0x%p\n", (char*)virt_to_phys(cdesc_out->dma_descr)); - td = cdesc_out->dma_descr; - printk("\n\tbuf: 0x%p\n" - "\tafter: 0x%p\n" - "\tmd: 0x%04x\n" - "\tnext: 0x%p\n", - td->buf, - td->after, - td->md, - td->next); - printk("flags:\n" - "\twait:\t%d\n" - "\teol:\t%d\n" - "\touteop:\t%d\n" - "\tineop:\t%d\n" - "\tintr:\t%d\n", - td->wait, - td->eol, - td->out_eop, - td->in_eop, - td->intr); - cdesc_out = cdesc_out->next; - i++; - } - i = 0; - while (cdesc_in) { - dma_descr_data *td; - printk("cdesc_in %d, desc=0x%p\n", i, cdesc_in->dma_descr); - printk("\n\tvirt_to_phys(desc): 0x%p\n", (char*)virt_to_phys(cdesc_in->dma_descr)); - td = cdesc_in->dma_descr; - printk("\n\tbuf: 0x%p\n" - "\tafter: 0x%p\n" - "\tmd: 0x%04x\n" - "\tnext: 0x%p\n", - td->buf, - td->after, - td->md, - td->next); - printk("flags:\n" - "\twait:\t%d\n" - "\teol:\t%d\n" - "\touteop:\t%d\n" - "\tineop:\t%d\n" - "\tintr:\t%d\n", - td->wait, - td->eol, - td->out_eop, - td->in_eop, - td->intr); - cdesc_in = cdesc_in->next; - i++; - } - - printk("print_dma_descriptors end\n"); -} - - -static void print_strcop_crypto_op(struct strcop_crypto_op *cop) -{ - printk("print_strcop_crypto_op, 0x%p\n", cop); - - /* Indata. */ - printk("indata=0x%p\n" - "inlen=%d\n" - "do_cipher=%d\n" - "decrypt=%d\n" - "cipher_explicit=%d\n" - "cipher_start=%d\n" - "cipher_len=%d\n" - "outdata=0x%p\n" - "outlen=%d\n", - cop->indata, - cop->inlen, - cop->do_cipher, - cop->decrypt, - cop->cipher_explicit, - cop->cipher_start, - cop->cipher_len, - cop->cipher_outdata, - cop->cipher_outlen); - - printk("do_digest=%d\n" - "digest_start=%d\n" - "digest_len=%d\n", - cop->do_digest, - cop->digest_start, - cop->digest_len); - - printk("do_csum=%d\n" - "csum_start=%d\n" - "csum_len=%d\n", - cop->do_csum, - cop->csum_start, - cop->csum_len); -} - -static void print_cryptocop_operation(struct cryptocop_operation *cop) -{ - struct cryptocop_desc *d; - struct cryptocop_tfrm_cfg *tc; - struct cryptocop_desc_cfg *dc; - int i; - - printk("print_cryptocop_operation, cop=0x%p\n\n", cop); - printk("sid: %lld\n", cop->sid); - printk("operation_status=%d\n" - "use_dmalists=%d\n" - "in_interrupt=%d\n" - "fast_callback=%d\n", - cop->operation_status, - cop->use_dmalists, - cop->in_interrupt, - cop->fast_callback); - - if (cop->use_dmalists){ - print_user_dma_lists(&cop->list_op); - } else { - printk("cop->tfrm_op\n" - "tfrm_cfg=0x%p\n" - "desc=0x%p\n" - "indata=0x%p\n" - "incount=%d\n" - "inlen=%d\n" - "outdata=0x%p\n" - "outcount=%d\n" - "outlen=%d\n\n", - cop->tfrm_op.tfrm_cfg, - cop->tfrm_op.desc, - cop->tfrm_op.indata, - cop->tfrm_op.incount, - cop->tfrm_op.inlen, - cop->tfrm_op.outdata, - cop->tfrm_op.outcount, - cop->tfrm_op.outlen); - - tc = cop->tfrm_op.tfrm_cfg; - while (tc){ - printk("tfrm_cfg, 0x%p\n" - "tid=%d\n" - "flags=%d\n" - "inject_ix=%d\n" - "next=0x%p\n", - tc, - tc->tid, - tc->flags, - tc->inject_ix, - tc->next); - tc = tc->next; - } - d = cop->tfrm_op.desc; - while (d){ - printk("\n======================desc, 0x%p\n" - "length=%d\n" - "cfg=0x%p\n" - "next=0x%p\n", - d, - d->length, - d->cfg, - d->next); - dc = d->cfg; - while (dc){ - printk("=========desc_cfg, 0x%p\n" - "tid=%d\n" - "src=%d\n" - "last=%d\n" - "next=0x%p\n", - dc, - dc->tid, - dc->src, - dc->last, - dc->next); - dc = dc->next; - } - d = d->next; - } - printk("\n====iniov\n"); - for (i = 0; i < cop->tfrm_op.incount; i++){ - printk("indata[%d]\n" - "base=0x%p\n" - "len=%d\n", - i, - cop->tfrm_op.indata[i].iov_base, - cop->tfrm_op.indata[i].iov_len); - } - printk("\n====outiov\n"); - for (i = 0; i < cop->tfrm_op.outcount; i++){ - printk("outdata[%d]\n" - "base=0x%p\n" - "len=%d\n", - i, - cop->tfrm_op.outdata[i].iov_base, - cop->tfrm_op.outdata[i].iov_len); - } - } - printk("------------end print_cryptocop_operation\n"); -} - - -static void print_user_dma_lists(struct cryptocop_dma_list_operation *dma_op) -{ - dma_descr_data *dd; - int i; - - printk("print_user_dma_lists, dma_op=0x%p\n", dma_op); - - printk("out_data_buf = 0x%p, phys_to_virt(out_data_buf) = 0x%p\n", dma_op->out_data_buf, phys_to_virt((unsigned long int)dma_op->out_data_buf)); - printk("in_data_buf = 0x%p, phys_to_virt(in_data_buf) = 0x%p\n", dma_op->in_data_buf, phys_to_virt((unsigned long int)dma_op->in_data_buf)); - - printk("##############outlist\n"); - dd = phys_to_virt((unsigned long int)dma_op->outlist); - i = 0; - while (dd != NULL) { - printk("#%d phys_to_virt(desc) 0x%p\n", i, dd); - printk("\n\tbuf: 0x%p\n" - "\tafter: 0x%p\n" - "\tmd: 0x%04x\n" - "\tnext: 0x%p\n", - dd->buf, - dd->after, - dd->md, - dd->next); - printk("flags:\n" - "\twait:\t%d\n" - "\teol:\t%d\n" - "\touteop:\t%d\n" - "\tineop:\t%d\n" - "\tintr:\t%d\n", - dd->wait, - dd->eol, - dd->out_eop, - dd->in_eop, - dd->intr); - if (dd->eol) - dd = NULL; - else - dd = phys_to_virt((unsigned long int)dd->next); - ++i; - } - - printk("##############inlist\n"); - dd = phys_to_virt((unsigned long int)dma_op->inlist); - i = 0; - while (dd != NULL) { - printk("#%d phys_to_virt(desc) 0x%p\n", i, dd); - printk("\n\tbuf: 0x%p\n" - "\tafter: 0x%p\n" - "\tmd: 0x%04x\n" - "\tnext: 0x%p\n", - dd->buf, - dd->after, - dd->md, - dd->next); - printk("flags:\n" - "\twait:\t%d\n" - "\teol:\t%d\n" - "\touteop:\t%d\n" - "\tineop:\t%d\n" - "\tintr:\t%d\n", - dd->wait, - dd->eol, - dd->out_eop, - dd->in_eop, - dd->intr); - if (dd->eol) - dd = NULL; - else - dd = phys_to_virt((unsigned long int)dd->next); - ++i; - } -} - - -static void print_lock_status(void) -{ - printk("**********************print_lock_status\n"); - printk("cryptocop_completed_jobs_lock %d\n", spin_is_locked(&cryptocop_completed_jobs_lock)); - printk("cryptocop_job_queue_lock %d\n", spin_is_locked(&cryptocop_job_queue_lock)); - printk("descr_pool_lock %d\n", spin_is_locked(&descr_pool_lock)); - printk("cryptocop_sessions_lock %d\n", spin_is_locked(cryptocop_sessions_lock)); - printk("running_job_lock %d\n", spin_is_locked(running_job_lock)); - printk("cryptocop_process_lock %d\n", spin_is_locked(cryptocop_process_lock)); -} -#endif /* LDEBUG */ - - -static const char cryptocop_name[] = "ETRAX FS stream co-processor"; - -static int init_stream_coprocessor(void) -{ - int err; - int i; - static int initialized = 0; - - if (initialized) - return 0; - - initialized = 1; - - printk("ETRAX FS stream co-processor driver v0.01, (c) 2003 Axis Communications AB\n"); - - err = register_chrdev(CRYPTOCOP_MAJOR, cryptocop_name, &cryptocop_fops); - if (err < 0) { - printk(KERN_ERR "stream co-processor: could not get major number.\n"); - return err; - } - - err = init_cryptocop(); - if (err) { - (void)unregister_chrdev(CRYPTOCOP_MAJOR, cryptocop_name); - return err; - } - err = cryptocop_job_queue_init(); - if (err) { - release_cryptocop(); - (void)unregister_chrdev(CRYPTOCOP_MAJOR, cryptocop_name); - return err; - } - /* Init the descriptor pool. */ - for (i = 0; i < CRYPTOCOP_DESCRIPTOR_POOL_SIZE - 1; i++) { - descr_pool[i].from_pool = 1; - descr_pool[i].next = &descr_pool[i + 1]; - } - descr_pool[i].from_pool = 1; - descr_pool[i].next = NULL; - descr_pool_free_list = &descr_pool[0]; - descr_pool_no_free = CRYPTOCOP_DESCRIPTOR_POOL_SIZE; - - spin_lock_init(&cryptocop_completed_jobs_lock); - spin_lock_init(&cryptocop_job_queue_lock); - spin_lock_init(&descr_pool_lock); - spin_lock_init(&cryptocop_sessions_lock); - spin_lock_init(&running_job_lock); - spin_lock_init(&cryptocop_process_lock); - - cryptocop_sessions = NULL; - next_sid = 1; - - cryptocop_running_job = NULL; - - printk("stream co-processor: init done.\n"); - return 0; -} - -static void __exit exit_stream_coprocessor(void) -{ - release_cryptocop(); - cryptocop_job_queue_close(); -} - -module_init(init_stream_coprocessor); -module_exit(exit_stream_coprocessor); - diff --git a/arch/cris/arch-v32/drivers/iop_fw_load.c b/arch/cris/arch-v32/drivers/iop_fw_load.c deleted file mode 100644 index 2f8ea0f7a63c..000000000000 --- a/arch/cris/arch-v32/drivers/iop_fw_load.c +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Firmware loader for ETRAX FS IO-Processor - * - * Copyright (C) 2004 Axis Communications AB - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/device.h> -#include <linux/firmware.h> - -#include <hwregs/reg_rdwr.h> -#include <hwregs/reg_map.h> -#include <hwregs/iop/iop_reg_space.h> -#include <hwregs/iop/iop_mpu_macros.h> -#include <hwregs/iop/iop_mpu_defs.h> -#include <hwregs/iop/iop_spu_defs.h> -#include <hwregs/iop/iop_sw_cpu_defs.h> - -#define IOP_TIMEOUT 100 - -#error "This driver is broken with regard to its driver core usage." -#error "Please contact <greg@kroah.com> for details on how to fix it properly." - -static struct device iop_spu_device[2] = { - { .init_name = "iop-spu0", }, - { .init_name = "iop-spu1", }, -}; - -static struct device iop_mpu_device = { - .init_name = "iop-mpu", -}; - -static int wait_mpu_idle(void) -{ - reg_iop_mpu_r_stat mpu_stat; - unsigned int timeout = IOP_TIMEOUT; - - do { - mpu_stat = REG_RD(iop_mpu, regi_iop_mpu, r_stat); - } while (mpu_stat.instr_reg_busy == regk_iop_mpu_yes && --timeout > 0); - if (timeout == 0) { - printk(KERN_ERR "Timeout waiting for MPU to be idle\n"); - return -EBUSY; - } - return 0; -} - -int iop_fw_load_spu(const unsigned char *fw_name, unsigned int spu_inst) -{ - reg_iop_sw_cpu_rw_mc_ctrl mc_ctrl = { - .wr_spu0_mem = regk_iop_sw_cpu_no, - .wr_spu1_mem = regk_iop_sw_cpu_no, - .size = 4, - .cmd = regk_iop_sw_cpu_reg_copy, - .keep_owner = regk_iop_sw_cpu_yes - }; - reg_iop_spu_rw_ctrl spu_ctrl = { - .en = regk_iop_spu_no, - .fsm = regk_iop_spu_no, - }; - reg_iop_sw_cpu_r_mc_stat mc_stat; - const struct firmware *fw_entry; - u32 *data; - unsigned int timeout; - int retval, i; - - if (spu_inst > 1) - return -ENODEV; - - /* get firmware */ - retval = request_firmware(&fw_entry, - fw_name, - &iop_spu_device[spu_inst]); - if (retval != 0) - { - printk(KERN_ERR - "iop_load_spu: Failed to load firmware \"%s\"\n", - fw_name); - return retval; - } - data = (u32 *) fw_entry->data; - - /* acquire ownership of memory controller */ - switch (spu_inst) { - case 0: - mc_ctrl.wr_spu0_mem = regk_iop_sw_cpu_yes; - REG_WR(iop_spu, regi_iop_spu0, rw_ctrl, spu_ctrl); - break; - case 1: - mc_ctrl.wr_spu1_mem = regk_iop_sw_cpu_yes; - REG_WR(iop_spu, regi_iop_spu1, rw_ctrl, spu_ctrl); - break; - } - timeout = IOP_TIMEOUT; - do { - REG_WR(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_ctrl, mc_ctrl); - mc_stat = REG_RD(iop_sw_cpu, regi_iop_sw_cpu, r_mc_stat); - } while (mc_stat.owned_by_cpu == regk_iop_sw_cpu_no && --timeout > 0); - if (timeout == 0) { - printk(KERN_ERR "Timeout waiting to acquire MC\n"); - retval = -EBUSY; - goto out; - } - - /* write to SPU memory */ - for (i = 0; i < (fw_entry->size/4); i++) { - switch (spu_inst) { - case 0: - REG_WR_INT(iop_spu, regi_iop_spu0, rw_seq_pc, (i*4)); - break; - case 1: - REG_WR_INT(iop_spu, regi_iop_spu1, rw_seq_pc, (i*4)); - break; - } - REG_WR_INT(iop_sw_cpu, regi_iop_sw_cpu, rw_mc_data, *data); - data++; - } - - /* release ownership of memory controller */ - (void) REG_RD(iop_sw_cpu, regi_iop_sw_cpu, rs_mc_data); - - out: - release_firmware(fw_entry); - return retval; -} - -int iop_fw_load_mpu(unsigned char *fw_name) -{ - const unsigned int start_addr = 0; - reg_iop_mpu_rw_ctrl mpu_ctrl; - const struct firmware *fw_entry; - u32 *data; - int retval, i; - - /* get firmware */ - retval = request_firmware(&fw_entry, fw_name, &iop_mpu_device); - if (retval != 0) - { - printk(KERN_ERR - "iop_load_spu: Failed to load firmware \"%s\"\n", - fw_name); - return retval; - } - data = (u32 *) fw_entry->data; - - /* disable MPU */ - mpu_ctrl.en = regk_iop_mpu_no; - REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl); - /* put start address in R0 */ - REG_WR_VECT(iop_mpu, regi_iop_mpu, rw_r, 0, start_addr); - /* write to memory by executing 'SWX i, 4, R0' for each word */ - if ((retval = wait_mpu_idle()) != 0) - goto out; - REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_SWX_IIR_INSTR(0, 4, 0)); - for (i = 0; i < (fw_entry->size / 4); i++) { - REG_WR_INT(iop_mpu, regi_iop_mpu, rw_immediate, *data); - if ((retval = wait_mpu_idle()) != 0) - goto out; - data++; - } - - out: - release_firmware(fw_entry); - return retval; -} - -int iop_start_mpu(unsigned int start_addr) -{ - reg_iop_mpu_rw_ctrl mpu_ctrl = { .en = regk_iop_mpu_yes }; - int retval; - - /* disable MPU */ - if ((retval = wait_mpu_idle()) != 0) - goto out; - REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_HALT()); - if ((retval = wait_mpu_idle()) != 0) - goto out; - /* set PC and wait for it to bite */ - if ((retval = wait_mpu_idle()) != 0) - goto out; - REG_WR_INT(iop_mpu, regi_iop_mpu, rw_instr, MPU_BA_I(start_addr)); - if ((retval = wait_mpu_idle()) != 0) - goto out; - /* make sure the MPU starts executing with interrupts disabled */ - REG_WR(iop_mpu, regi_iop_mpu, rw_instr, MPU_DI()); - if ((retval = wait_mpu_idle()) != 0) - goto out; - /* enable MPU */ - REG_WR(iop_mpu, regi_iop_mpu, rw_ctrl, mpu_ctrl); - out: - return retval; -} - -static int __init iop_fw_load_init(void) -{ -#if 0 - /* - * static struct devices can not be added directly to sysfs by ignoring - * the driver model infrastructure. To fix this properly, please use - * the platform_bus to register these devices to be able to properly - * use the firmware infrastructure. - */ - device_initialize(&iop_spu_device[0]); - kobject_set_name(&iop_spu_device[0].kobj, "iop-spu0"); - kobject_add(&iop_spu_device[0].kobj); - device_initialize(&iop_spu_device[1]); - kobject_set_name(&iop_spu_device[1].kobj, "iop-spu1"); - kobject_add(&iop_spu_device[1].kobj); - device_initialize(&iop_mpu_device); - kobject_set_name(&iop_mpu_device.kobj, "iop-mpu"); - kobject_add(&iop_mpu_device.kobj); -#endif - return 0; -} - -static void __exit iop_fw_load_exit(void) -{ -} - -module_init(iop_fw_load_init); -module_exit(iop_fw_load_exit); - -MODULE_DESCRIPTION("ETRAX FS IO-Processor Firmware Loader"); -MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(iop_fw_load_spu); -EXPORT_SYMBOL(iop_fw_load_mpu); -EXPORT_SYMBOL(iop_start_mpu); diff --git a/arch/cris/arch-v32/drivers/mach-a3/Makefile b/arch/cris/arch-v32/drivers/mach-a3/Makefile deleted file mode 100644 index 59028d0b981c..000000000000 --- a/arch/cris/arch-v32/drivers/mach-a3/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for Etrax-specific drivers -# - -obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o diff --git a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c b/arch/cris/arch-v32/drivers/mach-a3/nandflash.c deleted file mode 100644 index 925a98eb6d68..000000000000 --- a/arch/cris/arch-v32/drivers/mach-a3/nandflash.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * arch/cris/arch-v32/drivers/nandflash.c - * - * Copyright (c) 2007 - * - * Derived from drivers/mtd/nand/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/rawnand.h> -#include <linux/mtd/partitions.h> -#include <arch/memmap.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/pio_defs.h> -#include <pinmux.h> -#include <asm/io.h> - -#define MANUAL_ALE_CLE_CONTROL 1 - -#define regf_ALE a0 -#define regf_CLE a1 -#define regf_NCE ce0_n - -#define CLE_BIT 10 -#define ALE_BIT 11 -#define CE_BIT 12 - -struct mtd_info_wrapper { - struct nand_chip chip; -}; - -/* Bitmask for control pins */ -#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT)) - -static struct mtd_info *crisv32_mtd; -/* - * hardware specific access to control-lines - */ -static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - unsigned long flags; - reg_pio_rw_dout dout; - struct nand_chip *this = mtd_to_nand(mtd); - - local_irq_save(flags); - - /* control bits change */ - if (ctrl & NAND_CTRL_CHANGE) { - dout = REG_RD(pio, regi_pio, rw_dout); - dout.regf_NCE = (ctrl & NAND_NCE) ? 0 : 1; - -#if !MANUAL_ALE_CLE_CONTROL - if (ctrl & NAND_ALE) { - /* A0 = ALE high */ - this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, - regi_pio, rw_io_access1); - } else if (ctrl & NAND_CLE) { - /* A1 = CLE high */ - this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, - regi_pio, rw_io_access2); - } else { - /* A1 = CLE and A0 = ALE low */ - this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio, - regi_pio, rw_io_access0); - } -#else - - dout.regf_CLE = (ctrl & NAND_CLE) ? 1 : 0; - dout.regf_ALE = (ctrl & NAND_ALE) ? 1 : 0; -#endif - REG_WR(pio, regi_pio, rw_dout, dout); - } - - /* command to chip */ - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); - - local_irq_restore(flags); -} - -/* -* read device ready pin -*/ -static int crisv32_device_ready(struct mtd_info *mtd) -{ - reg_pio_r_din din = REG_RD(pio, regi_pio, r_din); - return din.rdy; -} - -/* - * Main initialization routine - */ -struct mtd_info *__init crisv32_nand_flash_probe(void) -{ - void __iomem *read_cs; - void __iomem *write_cs; - - struct mtd_info_wrapper *wrapper; - struct nand_chip *this; - int err = 0; - - reg_pio_rw_man_ctrl man_ctrl = { - .regf_NCE = regk_pio_yes, -#if MANUAL_ALE_CLE_CONTROL - .regf_ALE = regk_pio_yes, - .regf_CLE = regk_pio_yes -#endif - }; - reg_pio_rw_oe oe = { - .regf_NCE = regk_pio_yes, -#if MANUAL_ALE_CLE_CONTROL - .regf_ALE = regk_pio_yes, - .regf_CLE = regk_pio_yes -#endif - }; - reg_pio_rw_dout dout = { .regf_NCE = 1 }; - - /* Allocate pio pins to pio */ - crisv32_pinmux_alloc_fixed(pinmux_pio); - /* Set up CE, ALE, CLE (ce0_n, a0, a1) for manual control and output */ - REG_WR(pio, regi_pio, rw_man_ctrl, man_ctrl); - REG_WR(pio, regi_pio, rw_dout, dout); - REG_WR(pio, regi_pio, rw_oe, oe); - - /* Allocate memory for MTD device structure and private data */ - wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL); - if (!wrapper) { - printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD " - "device structure.\n"); - err = -ENOMEM; - return NULL; - } - - read_cs = write_cs = (void __iomem *)REG_ADDR(pio, regi_pio, - rw_io_access0); - - /* Get pointer to private data */ - this = &wrapper->chip; - crisv32_mtd = nand_to_mtd(this); - - /* Set address of NAND IO lines */ - this->IO_ADDR_R = read_cs; - this->IO_ADDR_W = write_cs; - this->cmd_ctrl = crisv32_hwcontrol; - this->dev_ready = crisv32_device_ready; - /* 20 us command delay time */ - this->chip_delay = 20; - this->ecc.mode = NAND_ECC_SOFT; - this->ecc.algo = NAND_ECC_HAMMING; - - /* Enable the following for a flash based bad block table */ - /* this->bbt_options = NAND_BBT_USE_FLASH; */ - - /* Scan to find existence of the device */ - if (nand_scan(crisv32_mtd, 1)) { - err = -ENXIO; - goto out_mtd; - } - - return crisv32_mtd; - -out_mtd: - kfree(wrapper); - return NULL; -} - diff --git a/arch/cris/arch-v32/drivers/mach-fs/Makefile b/arch/cris/arch-v32/drivers/mach-fs/Makefile deleted file mode 100644 index 59028d0b981c..000000000000 --- a/arch/cris/arch-v32/drivers/mach-fs/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for Etrax-specific drivers -# - -obj-$(CONFIG_ETRAX_NANDFLASH) += nandflash.o diff --git a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c b/arch/cris/arch-v32/drivers/mach-fs/nandflash.c deleted file mode 100644 index 53b56a429dde..000000000000 --- a/arch/cris/arch-v32/drivers/mach-fs/nandflash.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * arch/cris/arch-v32/drivers/nandflash.c - * - * Copyright (c) 2004 - * - * Derived from drivers/mtd/nand/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/rawnand.h> -#include <linux/mtd/partitions.h> -#include <arch/memmap.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/gio_defs.h> -#include <hwregs/bif_core_defs.h> -#include <asm/io.h> - -#define CE_BIT 4 -#define CLE_BIT 5 -#define ALE_BIT 6 -#define BY_BIT 7 - -struct mtd_info_wrapper { - struct nand_chip chip; -}; - -/* Bitmask for control pins */ -#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT)) - -/* Bitmask for mtd nand control bits */ -#define CTRL_BITMASK (NAND_NCE | NAND_CLE | NAND_ALE) - - -static struct mtd_info *crisv32_mtd; -/* - * hardware specific access to control-lines - */ -static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - unsigned long flags; - reg_gio_rw_pa_dout dout; - struct nand_chip *this = mtd_to_nand(mtd); - - local_irq_save(flags); - - /* control bits change */ - if (ctrl & NAND_CTRL_CHANGE) { - dout = REG_RD(gio, regi_gio, rw_pa_dout); - dout.data &= ~PIN_BITMASK; - -#if (CE_BIT == 4 && NAND_NCE == 1 && \ - CLE_BIT == 5 && NAND_CLE == 2 && \ - ALE_BIT == 6 && NAND_ALE == 4) - /* Pins in same order as control bits, but shifted. - * Optimize for this case; works for 2.6.18 */ - dout.data |= ((ctrl & CTRL_BITMASK) ^ NAND_NCE) << CE_BIT; -#else - /* the slow way */ - if (!(ctrl & NAND_NCE)) - dout.data |= (1 << CE_BIT); - if (ctrl & NAND_CLE) - dout.data |= (1 << CLE_BIT); - if (ctrl & NAND_ALE) - dout.data |= (1 << ALE_BIT); -#endif - REG_WR(gio, regi_gio, rw_pa_dout, dout); - } - - /* command to chip */ - if (cmd != NAND_CMD_NONE) - writeb(cmd, this->IO_ADDR_W); - - local_irq_restore(flags); -} - -/* -* read device ready pin -*/ -static int crisv32_device_ready(struct mtd_info *mtd) -{ - reg_gio_r_pa_din din = REG_RD(gio, regi_gio, r_pa_din); - return ((din.data & (1 << BY_BIT)) >> BY_BIT); -} - -/* - * Main initialization routine - */ -struct mtd_info *__init crisv32_nand_flash_probe(void) -{ - void __iomem *read_cs; - void __iomem *write_cs; - - reg_bif_core_rw_grp3_cfg bif_cfg = REG_RD(bif_core, regi_bif_core, - rw_grp3_cfg); - reg_gio_rw_pa_oe pa_oe = REG_RD(gio, regi_gio, rw_pa_oe); - struct mtd_info_wrapper *wrapper; - struct nand_chip *this; - int err = 0; - - /* Allocate memory for MTD device structure and private data */ - wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL); - if (!wrapper) { - printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD " - "device structure.\n"); - err = -ENOMEM; - return NULL; - } - - read_cs = ioremap(MEM_CSP0_START | MEM_NON_CACHEABLE, 8192); - write_cs = ioremap(MEM_CSP1_START | MEM_NON_CACHEABLE, 8192); - - if (!read_cs || !write_cs) { - printk(KERN_ERR "CRISv32 NAND ioremap failed\n"); - err = -EIO; - goto out_mtd; - } - - /* Get pointer to private data */ - this = &wrapper->chip; - crisv32_mtd = nand_to_mtd(this); - - pa_oe.oe |= 1 << CE_BIT; - pa_oe.oe |= 1 << ALE_BIT; - pa_oe.oe |= 1 << CLE_BIT; - pa_oe.oe &= ~(1 << BY_BIT); - REG_WR(gio, regi_gio, rw_pa_oe, pa_oe); - - bif_cfg.gated_csp0 = regk_bif_core_rd; - bif_cfg.gated_csp1 = regk_bif_core_wr; - REG_WR(bif_core, regi_bif_core, rw_grp3_cfg, bif_cfg); - - /* Set address of NAND IO lines */ - this->IO_ADDR_R = read_cs; - this->IO_ADDR_W = write_cs; - this->cmd_ctrl = crisv32_hwcontrol; - this->dev_ready = crisv32_device_ready; - /* 20 us command delay time */ - this->chip_delay = 20; - this->ecc.mode = NAND_ECC_SOFT; - this->ecc.algo = NAND_ECC_HAMMING; - - /* Enable the following for a flash based bad block table */ - /* this->bbt_options = NAND_BBT_USE_FLASH; */ - - /* Scan to find existence of the device */ - if (nand_scan(crisv32_mtd, 1)) { - err = -ENXIO; - goto out_ior; - } - - return crisv32_mtd; - -out_ior: - iounmap((void *)read_cs); - iounmap((void *)write_cs); -out_mtd: - kfree(wrapper); - return NULL; -} - diff --git a/arch/cris/arch-v32/drivers/pci/Makefile b/arch/cris/arch-v32/drivers/pci/Makefile deleted file mode 100644 index 93c8be6170b1..000000000000 --- a/arch/cris/arch-v32/drivers/pci/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for Etrax cardbus driver -# - -obj-$(CONFIG_ETRAX_CARDBUS) += bios.o diff --git a/arch/cris/arch-v32/drivers/pci/bios.c b/arch/cris/arch-v32/drivers/pci/bios.c deleted file mode 100644 index 6b9e6cfaa29e..000000000000 --- a/arch/cris/arch-v32/drivers/pci/bios.c +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/pci.h> -#include <linux/kernel.h> -#include <hwregs/intr_vect.h> - -void pcibios_set_master(struct pci_dev *dev) -{ - u8 lat; - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat); - printk(KERN_DEBUG "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat); - pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat); -} - -resource_size_t -pcibios_align_resource(void *data, const struct resource *res, - resource_size_t size, resource_size_t align) -{ - resource_size_t start = res->start; - - if ((res->flags & IORESOURCE_IO) && (start & 0x300)) - start = (start + 0x3ff) & ~0x3ff; - - return start; -} - -int pcibios_enable_resources(struct pci_dev *dev, int mask) -{ - u16 cmd, old_cmd; - int idx; - struct resource *r; - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for(idx=0; idx<6; idx++) { - /* Only set up the requested stuff */ - if (!(mask & (1<<idx))) - continue; - - r = &dev->resource[idx]; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev)); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - if (dev->resource[PCI_ROM_RESOURCE].start) - cmd |= PCI_COMMAND_MEMORY; - if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd); - } - return 0; -} - -int pcibios_enable_irq(struct pci_dev *dev) -{ - dev->irq = EXT_INTR_VECT; - return 0; -} - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - int err; - - if ((err = pcibios_enable_resources(dev, mask)) < 0) - return err; - - if (!dev->msi_enabled) - pcibios_enable_irq(dev); - return 0; -} diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c deleted file mode 100644 index 1b0ce8a8af16..000000000000 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ /dev/null @@ -1,1715 +0,0 @@ -/* - * Simple synchronous serial port driver for ETRAX FS and ARTPEC-3. - * - * Copyright (c) 2005, 2008 Axis Communications AB - * Author: Mikael Starvik - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/major.h> -#include <linux/sched/signal.h> -#include <linux/mutex.h> -#include <linux/interrupt.h> -#include <linux/poll.h> -#include <linux/fs.h> -#include <linux/cdev.h> -#include <linux/device.h> -#include <linux/wait.h> - -#include <asm/io.h> -#include <mach/dma.h> -#include <pinmux.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/sser_defs.h> -#include <hwregs/timer_defs.h> -#include <hwregs/dma_defs.h> -#include <hwregs/dma.h> -#include <hwregs/intr_vect_defs.h> -#include <hwregs/intr_vect.h> -#include <hwregs/reg_map.h> -#include <asm/sync_serial.h> - - -/* The receiver is a bit tricky because of the continuous stream of data.*/ -/* */ -/* Three DMA descriptors are linked together. Each DMA descriptor is */ -/* responsible for port->bufchunk of a common buffer. */ -/* */ -/* +---------------------------------------------+ */ -/* | +----------+ +----------+ +----------+ | */ -/* +-> | Descr[0] |-->| Descr[1] |-->| Descr[2] |-+ */ -/* +----------+ +----------+ +----------+ */ -/* | | | */ -/* v v v */ -/* +-------------------------------------+ */ -/* | BUFFER | */ -/* +-------------------------------------+ */ -/* |<- data_avail ->| */ -/* readp writep */ -/* */ -/* If the application keeps up the pace readp will be right after writep.*/ -/* If the application can't keep the pace we have to throw away data. */ -/* The idea is that readp should be ready with the data pointed out by */ -/* Descr[i] when the DMA has filled in Descr[i+1]. */ -/* Otherwise we will discard */ -/* the rest of the data pointed out by Descr1 and set readp to the start */ -/* of Descr2 */ - -/* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ -/* words can be handled */ -#define IN_DESCR_SIZE SSP_INPUT_CHUNK_SIZE -#define NBR_IN_DESCR (8*6) -#define IN_BUFFER_SIZE (IN_DESCR_SIZE * NBR_IN_DESCR) - -#define NBR_OUT_DESCR 8 -#define OUT_BUFFER_SIZE (1024 * NBR_OUT_DESCR) - -#define DEFAULT_FRAME_RATE 0 -#define DEFAULT_WORD_RATE 7 - -/* To be removed when we move to pure udev. */ -#define SYNC_SERIAL_MAJOR 125 - -/* NOTE: Enabling some debug will likely cause overrun or underrun, - * especially if manual mode is used. - */ -#define DEBUG(x) -#define DEBUGREAD(x) -#define DEBUGWRITE(x) -#define DEBUGPOLL(x) -#define DEBUGRXINT(x) -#define DEBUGTXINT(x) -#define DEBUGTRDMA(x) -#define DEBUGOUTBUF(x) - -enum syncser_irq_setup { - no_irq_setup = 0, - dma_irq_setup = 1, - manual_irq_setup = 2, -}; - -struct sync_port { - unsigned long regi_sser; - unsigned long regi_dmain; - unsigned long regi_dmaout; - - /* Interrupt vectors. */ - unsigned long dma_in_intr_vect; /* Used for DMA in. */ - unsigned long dma_out_intr_vect; /* Used for DMA out. */ - unsigned long syncser_intr_vect; /* Used when no DMA. */ - - /* DMA number for in and out. */ - unsigned int dma_in_nbr; - unsigned int dma_out_nbr; - - /* DMA owner. */ - enum dma_owner req_dma; - - char started; /* 1 if port has been started */ - char port_nbr; /* Port 0 or 1 */ - char busy; /* 1 if port is busy */ - - char enabled; /* 1 if port is enabled */ - char use_dma; /* 1 if port uses dma */ - char tr_running; - - enum syncser_irq_setup init_irqs; - int output; - int input; - - /* Next byte to be read by application */ - unsigned char *readp; - /* Next byte to be written by etrax */ - unsigned char *writep; - - unsigned int in_buffer_size; - unsigned int in_buffer_len; - unsigned int inbufchunk; - /* Data buffers for in and output. */ - unsigned char out_buffer[OUT_BUFFER_SIZE] __aligned(32); - unsigned char in_buffer[IN_BUFFER_SIZE] __aligned(32); - unsigned char flip[IN_BUFFER_SIZE] __aligned(32); - struct timespec timestamp[NBR_IN_DESCR]; - struct dma_descr_data *next_rx_desc; - struct dma_descr_data *prev_rx_desc; - - struct timeval last_timestamp; - int read_ts_idx; - int write_ts_idx; - - /* Pointer to the first available descriptor in the ring, - * unless active_tr_descr == catch_tr_descr and a dma - * transfer is active */ - struct dma_descr_data *active_tr_descr; - - /* Pointer to the first allocated descriptor in the ring */ - struct dma_descr_data *catch_tr_descr; - - /* Pointer to the descriptor with the current end-of-list */ - struct dma_descr_data *prev_tr_descr; - int full; - - /* Pointer to the first byte being read by DMA - * or current position in out_buffer if not using DMA. */ - unsigned char *out_rd_ptr; - - /* Number of bytes currently locked for being read by DMA */ - int out_buf_count; - - dma_descr_context in_context __aligned(32); - dma_descr_context out_context __aligned(32); - dma_descr_data in_descr[NBR_IN_DESCR] __aligned(16); - dma_descr_data out_descr[NBR_OUT_DESCR] __aligned(16); - - wait_queue_head_t out_wait_q; - wait_queue_head_t in_wait_q; - - spinlock_t lock; -}; - -static DEFINE_MUTEX(sync_serial_mutex); -static int etrax_sync_serial_init(void); -static void initialize_port(int portnbr); -static inline int sync_data_avail(struct sync_port *port); - -static int sync_serial_open(struct inode *, struct file *); -static int sync_serial_release(struct inode *, struct file *); -static __poll_t sync_serial_poll(struct file *filp, poll_table *wait); - -static long sync_serial_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); -static int sync_serial_ioctl_unlocked(struct file *file, - unsigned int cmd, unsigned long arg); -static ssize_t sync_serial_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos); -static ssize_t sync_serial_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos); - -#if ((defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ - defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \ - (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \ - defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA))) -#define SYNC_SER_DMA -#else -#define SYNC_SER_MANUAL -#endif - -#ifdef SYNC_SER_DMA -static void start_dma_out(struct sync_port *port, const char *data, int count); -static void start_dma_in(struct sync_port *port); -static irqreturn_t tr_interrupt(int irq, void *dev_id); -static irqreturn_t rx_interrupt(int irq, void *dev_id); -#endif -#ifdef SYNC_SER_MANUAL -static void send_word(struct sync_port *port); -static irqreturn_t manual_interrupt(int irq, void *dev_id); -#endif - -#define artpec_pinmux_alloc_fixed crisv32_pinmux_alloc_fixed -#define artpec_request_dma crisv32_request_dma -#define artpec_free_dma crisv32_free_dma - -#ifdef CONFIG_ETRAXFS -/* ETRAX FS */ -#define DMA_OUT_NBR0 SYNC_SER0_TX_DMA_NBR -#define DMA_IN_NBR0 SYNC_SER0_RX_DMA_NBR -#define DMA_OUT_NBR1 SYNC_SER1_TX_DMA_NBR -#define DMA_IN_NBR1 SYNC_SER1_RX_DMA_NBR -#define PINMUX_SSER0 pinmux_sser0 -#define PINMUX_SSER1 pinmux_sser1 -#define SYNCSER_INST0 regi_sser0 -#define SYNCSER_INST1 regi_sser1 -#define SYNCSER_INTR_VECT0 SSER0_INTR_VECT -#define SYNCSER_INTR_VECT1 SSER1_INTR_VECT -#define OUT_DMA_INST0 regi_dma4 -#define IN_DMA_INST0 regi_dma5 -#define DMA_OUT_INTR_VECT0 DMA4_INTR_VECT -#define DMA_OUT_INTR_VECT1 DMA7_INTR_VECT -#define DMA_IN_INTR_VECT0 DMA5_INTR_VECT -#define DMA_IN_INTR_VECT1 DMA6_INTR_VECT -#define REQ_DMA_SYNCSER0 dma_sser0 -#define REQ_DMA_SYNCSER1 dma_sser1 -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) -#define PORT1_DMA 1 -#else -#define PORT1_DMA 0 -#endif -#elif defined(CONFIG_CRIS_MACH_ARTPEC3) -/* ARTPEC-3 */ -#define DMA_OUT_NBR0 SYNC_SER_TX_DMA_NBR -#define DMA_IN_NBR0 SYNC_SER_RX_DMA_NBR -#define PINMUX_SSER0 pinmux_sser -#define SYNCSER_INST0 regi_sser -#define SYNCSER_INTR_VECT0 SSER_INTR_VECT -#define OUT_DMA_INST0 regi_dma6 -#define IN_DMA_INST0 regi_dma7 -#define DMA_OUT_INTR_VECT0 DMA6_INTR_VECT -#define DMA_IN_INTR_VECT0 DMA7_INTR_VECT -#define REQ_DMA_SYNCSER0 dma_sser -#define REQ_DMA_SYNCSER1 dma_sser -#endif - -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) -#define PORT0_DMA 1 -#else -#define PORT0_DMA 0 -#endif - -/* The ports */ -static struct sync_port ports[] = { - { - .regi_sser = SYNCSER_INST0, - .regi_dmaout = OUT_DMA_INST0, - .regi_dmain = IN_DMA_INST0, - .use_dma = PORT0_DMA, - .dma_in_intr_vect = DMA_IN_INTR_VECT0, - .dma_out_intr_vect = DMA_OUT_INTR_VECT0, - .dma_in_nbr = DMA_IN_NBR0, - .dma_out_nbr = DMA_OUT_NBR0, - .req_dma = REQ_DMA_SYNCSER0, - .syncser_intr_vect = SYNCSER_INTR_VECT0, - }, -#ifdef CONFIG_ETRAXFS - { - .regi_sser = SYNCSER_INST1, - .regi_dmaout = regi_dma6, - .regi_dmain = regi_dma7, - .use_dma = PORT1_DMA, - .dma_in_intr_vect = DMA_IN_INTR_VECT1, - .dma_out_intr_vect = DMA_OUT_INTR_VECT1, - .dma_in_nbr = DMA_IN_NBR1, - .dma_out_nbr = DMA_OUT_NBR1, - .req_dma = REQ_DMA_SYNCSER1, - .syncser_intr_vect = SYNCSER_INTR_VECT1, - }, -#endif -}; - -#define NBR_PORTS ARRAY_SIZE(ports) - -static const struct file_operations syncser_fops = { - .owner = THIS_MODULE, - .write = sync_serial_write, - .read = sync_serial_read, - .poll = sync_serial_poll, - .unlocked_ioctl = sync_serial_ioctl, - .open = sync_serial_open, - .release = sync_serial_release, - .llseek = noop_llseek, -}; - -static dev_t syncser_first; -static int minor_count = NBR_PORTS; -#define SYNCSER_NAME "syncser" -static struct cdev *syncser_cdev; -static struct class *syncser_class; - -static void sync_serial_start_port(struct sync_port *port) -{ - reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); - reg_sser_rw_tr_cfg tr_cfg = - REG_RD(sser, port->regi_sser, rw_tr_cfg); - reg_sser_rw_rec_cfg rec_cfg = - REG_RD(sser, port->regi_sser, rw_rec_cfg); - cfg.en = regk_sser_yes; - tr_cfg.tr_en = regk_sser_yes; - rec_cfg.rec_en = regk_sser_yes; - REG_WR(sser, port->regi_sser, rw_cfg, cfg); - REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); - REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); - port->started = 1; -} - -static void __init initialize_port(int portnbr) -{ - struct sync_port *port = &ports[portnbr]; - reg_sser_rw_cfg cfg = { 0 }; - reg_sser_rw_frm_cfg frm_cfg = { 0 }; - reg_sser_rw_tr_cfg tr_cfg = { 0 }; - reg_sser_rw_rec_cfg rec_cfg = { 0 }; - - DEBUG(pr_info("Init sync serial port %d\n", portnbr)); - - port->port_nbr = portnbr; - port->init_irqs = no_irq_setup; - - port->out_rd_ptr = port->out_buffer; - port->out_buf_count = 0; - - port->output = 1; - port->input = 0; - - port->readp = port->flip; - port->writep = port->flip; - port->in_buffer_size = IN_BUFFER_SIZE; - port->in_buffer_len = 0; - port->inbufchunk = IN_DESCR_SIZE; - - port->read_ts_idx = 0; - port->write_ts_idx = 0; - - init_waitqueue_head(&port->out_wait_q); - init_waitqueue_head(&port->in_wait_q); - - spin_lock_init(&port->lock); - - cfg.out_clk_src = regk_sser_intern_clk; - cfg.out_clk_pol = regk_sser_pos; - cfg.clk_od_mode = regk_sser_no; - cfg.clk_dir = regk_sser_out; - cfg.gate_clk = regk_sser_no; - cfg.base_freq = regk_sser_f29_493; - cfg.clk_div = 256; - REG_WR(sser, port->regi_sser, rw_cfg, cfg); - - frm_cfg.wordrate = DEFAULT_WORD_RATE; - frm_cfg.type = regk_sser_edge; - frm_cfg.frame_pin_dir = regk_sser_out; - frm_cfg.frame_pin_use = regk_sser_frm; - frm_cfg.status_pin_dir = regk_sser_in; - frm_cfg.status_pin_use = regk_sser_hold; - frm_cfg.out_on = regk_sser_tr; - frm_cfg.tr_delay = 1; - REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg); - - tr_cfg.urun_stop = regk_sser_no; - tr_cfg.sample_size = 7; - tr_cfg.sh_dir = regk_sser_msbfirst; - tr_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; -#if 0 - tr_cfg.rate_ctrl = regk_sser_bulk; - tr_cfg.data_pin_use = regk_sser_dout; -#else - tr_cfg.rate_ctrl = regk_sser_iso; - tr_cfg.data_pin_use = regk_sser_dout; -#endif - tr_cfg.bulk_wspace = 1; - REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); - - rec_cfg.sample_size = 7; - rec_cfg.sh_dir = regk_sser_msbfirst; - rec_cfg.use_dma = port->use_dma ? regk_sser_yes : regk_sser_no; - rec_cfg.fifo_thr = regk_sser_inf; - REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); - -#ifdef SYNC_SER_DMA - { - int i; - /* Setup the descriptor ring for dma out/transmit. */ - for (i = 0; i < NBR_OUT_DESCR; i++) { - dma_descr_data *descr = &port->out_descr[i]; - descr->wait = 0; - descr->intr = 1; - descr->eol = 0; - descr->out_eop = 0; - descr->next = - (dma_descr_data *)virt_to_phys(&descr[i+1]); - } - } - - /* Create a ring from the list. */ - port->out_descr[NBR_OUT_DESCR-1].next = - (dma_descr_data *)virt_to_phys(&port->out_descr[0]); - - /* Setup context for traversing the ring. */ - port->active_tr_descr = &port->out_descr[0]; - port->prev_tr_descr = &port->out_descr[NBR_OUT_DESCR-1]; - port->catch_tr_descr = &port->out_descr[0]; -#endif -} - -static inline int sync_data_avail(struct sync_port *port) -{ - return port->in_buffer_len; -} - -static int sync_serial_open(struct inode *inode, struct file *file) -{ - int ret = 0; - int dev = iminor(inode); - struct sync_port *port; -#ifdef SYNC_SER_DMA - reg_dma_rw_cfg cfg = { .en = regk_dma_yes }; - reg_dma_rw_intr_mask intr_mask = { .data = regk_dma_yes }; -#endif - - DEBUG(pr_debug("Open sync serial port %d\n", dev)); - - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { - DEBUG(pr_info("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - /* Allow open this device twice (assuming one reader and one writer) */ - if (port->busy == 2) { - DEBUG(pr_info("syncser%d is busy\n", dev)); - return -EBUSY; - } - - mutex_lock(&sync_serial_mutex); - - /* Clear any stale date left in the flip buffer */ - port->readp = port->writep = port->flip; - port->in_buffer_len = 0; - port->read_ts_idx = 0; - port->write_ts_idx = 0; - - if (port->init_irqs != no_irq_setup) { - /* Init only on first call. */ - port->busy++; - mutex_unlock(&sync_serial_mutex); - return 0; - } - if (port->use_dma) { -#ifdef SYNC_SER_DMA - const char *tmp; - DEBUG(pr_info("Using DMA for syncser%d\n", dev)); - - tmp = dev == 0 ? "syncser0 tx" : "syncser1 tx"; - if (request_irq(port->dma_out_intr_vect, tr_interrupt, 0, - tmp, port)) { - pr_err("Can't alloc syncser%d TX IRQ", dev); - ret = -EBUSY; - goto unlock_and_exit; - } - if (artpec_request_dma(port->dma_out_nbr, tmp, - DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) { - free_irq(port->dma_out_intr_vect, port); - pr_err("Can't alloc syncser%d TX DMA", dev); - ret = -EBUSY; - goto unlock_and_exit; - } - tmp = dev == 0 ? "syncser0 rx" : "syncser1 rx"; - if (request_irq(port->dma_in_intr_vect, rx_interrupt, 0, - tmp, port)) { - artpec_free_dma(port->dma_out_nbr); - free_irq(port->dma_out_intr_vect, port); - pr_err("Can't alloc syncser%d RX IRQ", dev); - ret = -EBUSY; - goto unlock_and_exit; - } - if (artpec_request_dma(port->dma_in_nbr, tmp, - DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) { - artpec_free_dma(port->dma_out_nbr); - free_irq(port->dma_out_intr_vect, port); - free_irq(port->dma_in_intr_vect, port); - pr_err("Can't alloc syncser%d RX DMA", dev); - ret = -EBUSY; - goto unlock_and_exit; - } - /* Enable DMAs */ - REG_WR(dma, port->regi_dmain, rw_cfg, cfg); - REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); - /* Enable DMA IRQs */ - REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); - REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); - /* Set up wordsize = 1 for DMAs. */ - DMA_WR_CMD(port->regi_dmain, regk_dma_set_w_size1); - DMA_WR_CMD(port->regi_dmaout, regk_dma_set_w_size1); - - start_dma_in(port); - port->init_irqs = dma_irq_setup; -#endif - } else { /* !port->use_dma */ -#ifdef SYNC_SER_MANUAL - const char *tmp = dev == 0 ? "syncser0 manual irq" : - "syncser1 manual irq"; - if (request_irq(port->syncser_intr_vect, manual_interrupt, - 0, tmp, port)) { - pr_err("Can't alloc syncser%d manual irq", - dev); - ret = -EBUSY; - goto unlock_and_exit; - } - port->init_irqs = manual_irq_setup; -#else - panic("sync_serial: Manual mode not supported\n"); -#endif /* SYNC_SER_MANUAL */ - } - port->busy++; - ret = 0; - -unlock_and_exit: - mutex_unlock(&sync_serial_mutex); - return ret; -} - -static int sync_serial_release(struct inode *inode, struct file *file) -{ - int dev = iminor(inode); - struct sync_port *port; - - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { - DEBUG(pr_info("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - if (port->busy) - port->busy--; - if (!port->busy) - /* XXX */; - return 0; -} - -static __poll_t sync_serial_poll(struct file *file, poll_table *wait) -{ - int dev = iminor(file_inode(file)); - __poll_t mask = 0; - struct sync_port *port; - DEBUGPOLL( - static __poll_t prev_mask; - ); - - port = &ports[dev]; - - if (!port->started) - sync_serial_start_port(port); - - poll_wait(file, &port->out_wait_q, wait); - poll_wait(file, &port->in_wait_q, wait); - - /* No active transfer, descriptors are available */ - if (port->output && !port->tr_running) - mask |= EPOLLOUT | EPOLLWRNORM; - - /* Descriptor and buffer space available. */ - if (port->output && - port->active_tr_descr != port->catch_tr_descr && - port->out_buf_count < OUT_BUFFER_SIZE) - mask |= EPOLLOUT | EPOLLWRNORM; - - /* At least an inbufchunk of data */ - if (port->input && sync_data_avail(port) >= port->inbufchunk) - mask |= EPOLLIN | EPOLLRDNORM; - - DEBUGPOLL( - if (mask != prev_mask) - pr_info("sync_serial_poll: mask 0x%08X %s %s\n", - mask, - mask & EPOLLOUT ? "POLLOUT" : "", - mask & EPOLLIN ? "POLLIN" : ""); - prev_mask = mask; - ); - return mask; -} - -static ssize_t __sync_serial_read(struct file *file, - char __user *buf, - size_t count, - loff_t *ppos, - struct timespec *ts) -{ - unsigned long flags; - int dev = MINOR(file_inode(file)->i_rdev); - int avail; - struct sync_port *port; - unsigned char *start; - unsigned char *end; - - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { - DEBUG(pr_info("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - - if (!port->started) - sync_serial_start_port(port); - - /* Calculate number of available bytes */ - /* Save pointers to avoid that they are modified by interrupt */ - spin_lock_irqsave(&port->lock, flags); - start = port->readp; - end = port->writep; - spin_unlock_irqrestore(&port->lock, flags); - - while ((start == end) && !port->in_buffer_len) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - wait_event_interruptible(port->in_wait_q, - !(start == end && !port->full)); - - if (signal_pending(current)) - return -EINTR; - - spin_lock_irqsave(&port->lock, flags); - start = port->readp; - end = port->writep; - spin_unlock_irqrestore(&port->lock, flags); - } - - DEBUGREAD(pr_info("R%d c %d ri %u wi %u /%u\n", - dev, count, - start - port->flip, end - port->flip, - port->in_buffer_size)); - - /* Lazy read, never return wrapped data. */ - if (end > start) - avail = end - start; - else - avail = port->flip + port->in_buffer_size - start; - - count = count > avail ? avail : count; - if (copy_to_user(buf, start, count)) - return -EFAULT; - - /* If timestamp requested, find timestamp of first returned byte - * and copy it. - * N.B: Applications that request timstamps MUST read data in - * chunks that are multiples of IN_DESCR_SIZE. - * Otherwise the timestamps will not be aligned to the data read. - */ - if (ts != NULL) { - int idx = port->read_ts_idx; - memcpy(ts, &port->timestamp[idx], sizeof(struct timespec)); - port->read_ts_idx += count / IN_DESCR_SIZE; - if (port->read_ts_idx >= NBR_IN_DESCR) - port->read_ts_idx = 0; - } - - spin_lock_irqsave(&port->lock, flags); - port->readp += count; - /* Check for wrap */ - if (port->readp >= port->flip + port->in_buffer_size) - port->readp = port->flip; - port->in_buffer_len -= count; - port->full = 0; - spin_unlock_irqrestore(&port->lock, flags); - - DEBUGREAD(pr_info("r %d\n", count)); - - return count; -} - -static ssize_t sync_serial_input(struct file *file, unsigned long arg) -{ - struct ssp_request req; - int count; - int ret; - - /* Copy the request structure from user-mode. */ - ret = copy_from_user(&req, (struct ssp_request __user *)arg, - sizeof(struct ssp_request)); - - if (ret) { - DEBUG(pr_info("sync_serial_input copy from user failed\n")); - return -EFAULT; - } - - /* To get the timestamps aligned, make sure that 'len' - * is a multiple of IN_DESCR_SIZE. - */ - if ((req.len % IN_DESCR_SIZE) != 0) { - DEBUG(pr_info("sync_serial: req.len %x, IN_DESCR_SIZE %x\n", - req.len, IN_DESCR_SIZE)); - return -EFAULT; - } - - /* Do the actual read. */ - /* Note that req.buf is actually a pointer to user space. */ - count = __sync_serial_read(file, req.buf, req.len, - NULL, &req.ts); - - if (count < 0) { - DEBUG(pr_info("sync_serial_input read failed\n")); - return count; - } - - /* Copy the request back to user-mode. */ - ret = copy_to_user((struct ssp_request __user *)arg, &req, - sizeof(struct ssp_request)); - - if (ret) { - DEBUG(pr_info("syncser input copy2user failed\n")); - return -EFAULT; - } - - /* Return the number of bytes read. */ - return count; -} - - -static int sync_serial_ioctl_unlocked(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int return_val = 0; - int dma_w_size = regk_dma_set_w_size1; - int dev = iminor(file_inode(file)); - struct sync_port *port; - reg_sser_rw_tr_cfg tr_cfg; - reg_sser_rw_rec_cfg rec_cfg; - reg_sser_rw_frm_cfg frm_cfg; - reg_sser_rw_cfg gen_cfg; - reg_sser_rw_intr_mask intr_mask; - - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { - DEBUG(pr_info("Invalid minor %d\n", dev)); - return -1; - } - - if (cmd == SSP_INPUT) - return sync_serial_input(file, arg); - - port = &ports[dev]; - spin_lock_irq(&port->lock); - - tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); - rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); - frm_cfg = REG_RD(sser, port->regi_sser, rw_frm_cfg); - gen_cfg = REG_RD(sser, port->regi_sser, rw_cfg); - intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); - - switch (cmd) { - case SSP_SPEED: - if (GET_SPEED(arg) == CODEC) { - unsigned int freq; - - gen_cfg.base_freq = regk_sser_f32; - - /* Clock divider will internally be - * gen_cfg.clk_div + 1. - */ - - freq = GET_FREQ(arg); - switch (freq) { - case FREQ_32kHz: - case FREQ_64kHz: - case FREQ_128kHz: - case FREQ_256kHz: - gen_cfg.clk_div = 125 * - (1 << (freq - FREQ_256kHz)) - 1; - break; - case FREQ_512kHz: - gen_cfg.clk_div = 62; - break; - case FREQ_1MHz: - case FREQ_2MHz: - case FREQ_4MHz: - gen_cfg.clk_div = 8 * (1 << freq) - 1; - break; - } - } else if (GET_SPEED(arg) == CODEC_f32768) { - gen_cfg.base_freq = regk_sser_f32_768; - switch (GET_FREQ(arg)) { - case FREQ_4096kHz: - gen_cfg.clk_div = 7; - break; - default: - spin_unlock_irq(&port->lock); - return -EINVAL; - } - } else { - gen_cfg.base_freq = regk_sser_f29_493; - switch (GET_SPEED(arg)) { - case SSP150: - gen_cfg.clk_div = 29493000 / (150 * 8) - 1; - break; - case SSP300: - gen_cfg.clk_div = 29493000 / (300 * 8) - 1; - break; - case SSP600: - gen_cfg.clk_div = 29493000 / (600 * 8) - 1; - break; - case SSP1200: - gen_cfg.clk_div = 29493000 / (1200 * 8) - 1; - break; - case SSP2400: - gen_cfg.clk_div = 29493000 / (2400 * 8) - 1; - break; - case SSP4800: - gen_cfg.clk_div = 29493000 / (4800 * 8) - 1; - break; - case SSP9600: - gen_cfg.clk_div = 29493000 / (9600 * 8) - 1; - break; - case SSP19200: - gen_cfg.clk_div = 29493000 / (19200 * 8) - 1; - break; - case SSP28800: - gen_cfg.clk_div = 29493000 / (28800 * 8) - 1; - break; - case SSP57600: - gen_cfg.clk_div = 29493000 / (57600 * 8) - 1; - break; - case SSP115200: - gen_cfg.clk_div = 29493000 / (115200 * 8) - 1; - break; - case SSP230400: - gen_cfg.clk_div = 29493000 / (230400 * 8) - 1; - break; - case SSP460800: - gen_cfg.clk_div = 29493000 / (460800 * 8) - 1; - break; - case SSP921600: - gen_cfg.clk_div = 29493000 / (921600 * 8) - 1; - break; - case SSP3125000: - gen_cfg.base_freq = regk_sser_f100; - gen_cfg.clk_div = 100000000 / (3125000 * 8) - 1; - break; - - } - } - frm_cfg.wordrate = GET_WORD_RATE(arg); - - break; - case SSP_MODE: - switch (arg) { - case MASTER_OUTPUT: - port->output = 1; - port->input = 0; - frm_cfg.out_on = regk_sser_tr; - frm_cfg.frame_pin_dir = regk_sser_out; - gen_cfg.clk_dir = regk_sser_out; - break; - case SLAVE_OUTPUT: - port->output = 1; - port->input = 0; - frm_cfg.frame_pin_dir = regk_sser_in; - gen_cfg.clk_dir = regk_sser_in; - break; - case MASTER_INPUT: - port->output = 0; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_out; - frm_cfg.out_on = regk_sser_intern_tb; - gen_cfg.clk_dir = regk_sser_out; - break; - case SLAVE_INPUT: - port->output = 0; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_in; - gen_cfg.clk_dir = regk_sser_in; - break; - case MASTER_BIDIR: - port->output = 1; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_out; - frm_cfg.out_on = regk_sser_intern_tb; - gen_cfg.clk_dir = regk_sser_out; - break; - case SLAVE_BIDIR: - port->output = 1; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_in; - gen_cfg.clk_dir = regk_sser_in; - break; - default: - spin_unlock_irq(&port->lock); - return -EINVAL; - } - if (!port->use_dma || arg == MASTER_OUTPUT || - arg == SLAVE_OUTPUT) - intr_mask.rdav = regk_sser_yes; - break; - case SSP_FRAME_SYNC: - if (arg & NORMAL_SYNC) { - frm_cfg.rec_delay = 1; - frm_cfg.tr_delay = 1; - } else if (arg & EARLY_SYNC) - frm_cfg.rec_delay = frm_cfg.tr_delay = 0; - else if (arg & LATE_SYNC) { - frm_cfg.tr_delay = 2; - frm_cfg.rec_delay = 2; - } else if (arg & SECOND_WORD_SYNC) { - frm_cfg.rec_delay = 7; - frm_cfg.tr_delay = 1; - } - - tr_cfg.bulk_wspace = frm_cfg.tr_delay; - frm_cfg.early_wend = regk_sser_yes; - if (arg & BIT_SYNC) - frm_cfg.type = regk_sser_edge; - else if (arg & WORD_SYNC) - frm_cfg.type = regk_sser_level; - else if (arg & EXTENDED_SYNC) - frm_cfg.early_wend = regk_sser_no; - - if (arg & SYNC_ON) - frm_cfg.frame_pin_use = regk_sser_frm; - else if (arg & SYNC_OFF) - frm_cfg.frame_pin_use = regk_sser_gio0; - - dma_w_size = regk_dma_set_w_size2; - if (arg & WORD_SIZE_8) { - rec_cfg.sample_size = tr_cfg.sample_size = 7; - dma_w_size = regk_dma_set_w_size1; - } else if (arg & WORD_SIZE_12) - rec_cfg.sample_size = tr_cfg.sample_size = 11; - else if (arg & WORD_SIZE_16) - rec_cfg.sample_size = tr_cfg.sample_size = 15; - else if (arg & WORD_SIZE_24) - rec_cfg.sample_size = tr_cfg.sample_size = 23; - else if (arg & WORD_SIZE_32) - rec_cfg.sample_size = tr_cfg.sample_size = 31; - - if (arg & BIT_ORDER_MSB) - rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst; - else if (arg & BIT_ORDER_LSB) - rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_lsbfirst; - - if (arg & FLOW_CONTROL_ENABLE) { - frm_cfg.status_pin_use = regk_sser_frm; - rec_cfg.fifo_thr = regk_sser_thr16; - } else if (arg & FLOW_CONTROL_DISABLE) { - frm_cfg.status_pin_use = regk_sser_gio0; - rec_cfg.fifo_thr = regk_sser_inf; - } - - if (arg & CLOCK_NOT_GATED) - gen_cfg.gate_clk = regk_sser_no; - else if (arg & CLOCK_GATED) - gen_cfg.gate_clk = regk_sser_yes; - - break; - case SSP_IPOLARITY: - /* NOTE!! negedge is considered NORMAL */ - if (arg & CLOCK_NORMAL) - rec_cfg.clk_pol = regk_sser_neg; - else if (arg & CLOCK_INVERT) - rec_cfg.clk_pol = regk_sser_pos; - - if (arg & FRAME_NORMAL) - frm_cfg.level = regk_sser_pos_hi; - else if (arg & FRAME_INVERT) - frm_cfg.level = regk_sser_neg_lo; - - if (arg & STATUS_NORMAL) - gen_cfg.hold_pol = regk_sser_pos; - else if (arg & STATUS_INVERT) - gen_cfg.hold_pol = regk_sser_neg; - break; - case SSP_OPOLARITY: - if (arg & CLOCK_NORMAL) - gen_cfg.out_clk_pol = regk_sser_pos; - else if (arg & CLOCK_INVERT) - gen_cfg.out_clk_pol = regk_sser_neg; - - if (arg & FRAME_NORMAL) - frm_cfg.level = regk_sser_pos_hi; - else if (arg & FRAME_INVERT) - frm_cfg.level = regk_sser_neg_lo; - - if (arg & STATUS_NORMAL) - gen_cfg.hold_pol = regk_sser_pos; - else if (arg & STATUS_INVERT) - gen_cfg.hold_pol = regk_sser_neg; - break; - case SSP_SPI: - rec_cfg.fifo_thr = regk_sser_inf; - rec_cfg.sh_dir = tr_cfg.sh_dir = regk_sser_msbfirst; - rec_cfg.sample_size = tr_cfg.sample_size = 7; - frm_cfg.frame_pin_use = regk_sser_frm; - frm_cfg.type = regk_sser_level; - frm_cfg.tr_delay = 1; - frm_cfg.level = regk_sser_neg_lo; - if (arg & SPI_SLAVE) { - rec_cfg.clk_pol = regk_sser_neg; - gen_cfg.clk_dir = regk_sser_in; - port->input = 1; - port->output = 0; - } else { - gen_cfg.out_clk_pol = regk_sser_pos; - port->input = 0; - port->output = 1; - gen_cfg.clk_dir = regk_sser_out; - } - break; - case SSP_INBUFCHUNK: - break; - default: - return_val = -1; - } - - - if (port->started) { - rec_cfg.rec_en = port->input; - gen_cfg.en = (port->output | port->input); - } - - REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); - REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); - REG_WR(sser, port->regi_sser, rw_frm_cfg, frm_cfg); - REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); - REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); - - - if (cmd == SSP_FRAME_SYNC && (arg & (WORD_SIZE_8 | WORD_SIZE_12 | - WORD_SIZE_16 | WORD_SIZE_24 | WORD_SIZE_32))) { - int en = gen_cfg.en; - gen_cfg.en = 0; - REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); - /* ##### Should DMA be stoped before we change dma size? */ - DMA_WR_CMD(port->regi_dmain, dma_w_size); - DMA_WR_CMD(port->regi_dmaout, dma_w_size); - gen_cfg.en = en; - REG_WR(sser, port->regi_sser, rw_cfg, gen_cfg); - } - - spin_unlock_irq(&port->lock); - return return_val; -} - -static long sync_serial_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - long ret; - - mutex_lock(&sync_serial_mutex); - ret = sync_serial_ioctl_unlocked(file, cmd, arg); - mutex_unlock(&sync_serial_mutex); - - return ret; -} - -/* NOTE: sync_serial_write does not support concurrency */ -static ssize_t sync_serial_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - int dev = iminor(file_inode(file)); - DECLARE_WAITQUEUE(wait, current); - struct sync_port *port; - int trunc_count; - unsigned long flags; - int bytes_free; - int out_buf_count; - - unsigned char *rd_ptr; /* First allocated byte in the buffer */ - unsigned char *wr_ptr; /* First free byte in the buffer */ - unsigned char *buf_stop_ptr; /* Last byte + 1 */ - - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { - DEBUG(pr_info("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - - /* |<- OUT_BUFFER_SIZE ->| - * |<- out_buf_count ->| - * |<- trunc_count ->| ...->| - * ______________________________________________________ - * | free | data | free | - * |_________|___________________|________________________| - * ^ rd_ptr ^ wr_ptr - */ - DEBUGWRITE(pr_info("W d%d c %u a: %p c: %p\n", - port->port_nbr, count, port->active_tr_descr, - port->catch_tr_descr)); - - /* Read variables that may be updated by interrupts */ - spin_lock_irqsave(&port->lock, flags); - rd_ptr = port->out_rd_ptr; - out_buf_count = port->out_buf_count; - spin_unlock_irqrestore(&port->lock, flags); - - /* Check if resources are available */ - if (port->tr_running && - ((port->use_dma && port->active_tr_descr == port->catch_tr_descr) || - out_buf_count >= OUT_BUFFER_SIZE)) { - DEBUGWRITE(pr_info("sser%d full\n", dev)); - return -EAGAIN; - } - - buf_stop_ptr = port->out_buffer + OUT_BUFFER_SIZE; - - /* Determine pointer to the first free byte, before copying. */ - wr_ptr = rd_ptr + out_buf_count; - if (wr_ptr >= buf_stop_ptr) - wr_ptr -= OUT_BUFFER_SIZE; - - /* If we wrap the ring buffer, let the user space program handle it by - * truncating the data. This could be more elegant, small buffer - * fragments may occur. - */ - bytes_free = OUT_BUFFER_SIZE - out_buf_count; - if (wr_ptr + bytes_free > buf_stop_ptr) - bytes_free = buf_stop_ptr - wr_ptr; - trunc_count = (count < bytes_free) ? count : bytes_free; - - if (copy_from_user(wr_ptr, buf, trunc_count)) - return -EFAULT; - - DEBUGOUTBUF(pr_info("%-4d + %-4d = %-4d %p %p %p\n", - out_buf_count, trunc_count, - port->out_buf_count, port->out_buffer, - wr_ptr, buf_stop_ptr)); - - /* Make sure transmitter/receiver is running */ - if (!port->started) { - reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); - reg_sser_rw_rec_cfg rec_cfg = - REG_RD(sser, port->regi_sser, rw_rec_cfg); - cfg.en = regk_sser_yes; - rec_cfg.rec_en = port->input; - REG_WR(sser, port->regi_sser, rw_cfg, cfg); - REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); - port->started = 1; - } - - /* Setup wait if blocking */ - if (!(file->f_flags & O_NONBLOCK)) { - add_wait_queue(&port->out_wait_q, &wait); - set_current_state(TASK_INTERRUPTIBLE); - } - - spin_lock_irqsave(&port->lock, flags); - port->out_buf_count += trunc_count; - if (port->use_dma) { -#ifdef SYNC_SER_DMA - start_dma_out(port, wr_ptr, trunc_count); -#endif - } else if (!port->tr_running) { -#ifdef SYNC_SER_MANUAL - reg_sser_rw_intr_mask intr_mask; - intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); - /* Start sender by writing data */ - send_word(port); - /* and enable transmitter ready IRQ */ - intr_mask.trdy = 1; - REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); -#endif - } - spin_unlock_irqrestore(&port->lock, flags); - - /* Exit if non blocking */ - if (file->f_flags & O_NONBLOCK) { - DEBUGWRITE(pr_info("w d%d c %u %08x\n", - port->port_nbr, trunc_count, - REG_RD_INT(dma, port->regi_dmaout, r_intr))); - return trunc_count; - } - - schedule(); - remove_wait_queue(&port->out_wait_q, &wait); - - if (signal_pending(current)) - return -EINTR; - - DEBUGWRITE(pr_info("w d%d c %u\n", port->port_nbr, trunc_count)); - return trunc_count; -} - -static ssize_t sync_serial_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return __sync_serial_read(file, buf, count, ppos, NULL); -} - -#ifdef SYNC_SER_MANUAL -static void send_word(struct sync_port *port) -{ - reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); - reg_sser_rw_tr_data tr_data = {0}; - - switch (tr_cfg.sample_size) { - case 8: - port->out_buf_count--; - tr_data.data = *port->out_rd_ptr++; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) - port->out_rd_ptr = port->out_buffer; - break; - case 12: - { - int data = (*port->out_rd_ptr++) << 8; - data |= *port->out_rd_ptr++; - port->out_buf_count -= 2; - tr_data.data = data; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) - port->out_rd_ptr = port->out_buffer; - break; - } - case 16: - port->out_buf_count -= 2; - tr_data.data = *(unsigned short *)port->out_rd_ptr; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - port->out_rd_ptr += 2; - if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) - port->out_rd_ptr = port->out_buffer; - break; - case 24: - port->out_buf_count -= 3; - tr_data.data = *(unsigned short *)port->out_rd_ptr; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - port->out_rd_ptr += 2; - tr_data.data = *port->out_rd_ptr++; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) - port->out_rd_ptr = port->out_buffer; - break; - case 32: - port->out_buf_count -= 4; - tr_data.data = *(unsigned short *)port->out_rd_ptr; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - port->out_rd_ptr += 2; - tr_data.data = *(unsigned short *)port->out_rd_ptr; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - port->out_rd_ptr += 2; - if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) - port->out_rd_ptr = port->out_buffer; - break; - } -} -#endif - -#ifdef SYNC_SER_DMA -static void start_dma_out(struct sync_port *port, const char *data, int count) -{ - port->active_tr_descr->buf = (char *)virt_to_phys((char *)data); - port->active_tr_descr->after = port->active_tr_descr->buf + count; - port->active_tr_descr->intr = 1; - - port->active_tr_descr->eol = 1; - port->prev_tr_descr->eol = 0; - - DEBUGTRDMA(pr_info("Inserting eolr:%p eol@:%p\n", - port->prev_tr_descr, port->active_tr_descr)); - port->prev_tr_descr = port->active_tr_descr; - port->active_tr_descr = phys_to_virt((int)port->active_tr_descr->next); - - if (!port->tr_running) { - reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, - rw_tr_cfg); - - port->out_context.next = NULL; - port->out_context.saved_data = - (dma_descr_data *)virt_to_phys(port->prev_tr_descr); - port->out_context.saved_data_buf = port->prev_tr_descr->buf; - - DMA_START_CONTEXT(port->regi_dmaout, - virt_to_phys((char *)&port->out_context)); - - tr_cfg.tr_en = regk_sser_yes; - REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); - DEBUGTRDMA(pr_info("dma s\n");); - } else { - DMA_CONTINUE_DATA(port->regi_dmaout); - DEBUGTRDMA(pr_info("dma c\n");); - } - - port->tr_running = 1; -} - -static void start_dma_in(struct sync_port *port) -{ - int i; - char *buf; - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - port->writep = port->flip; - spin_unlock_irqrestore(&port->lock, flags); - - buf = (char *)virt_to_phys(port->in_buffer); - for (i = 0; i < NBR_IN_DESCR; i++) { - port->in_descr[i].buf = buf; - port->in_descr[i].after = buf + port->inbufchunk; - port->in_descr[i].intr = 1; - port->in_descr[i].next = - (dma_descr_data *)virt_to_phys(&port->in_descr[i+1]); - port->in_descr[i].buf = buf; - buf += port->inbufchunk; - } - /* Link the last descriptor to the first */ - port->in_descr[i-1].next = - (dma_descr_data *)virt_to_phys(&port->in_descr[0]); - port->in_descr[i-1].eol = regk_sser_yes; - port->next_rx_desc = &port->in_descr[0]; - port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR - 1]; - port->in_context.saved_data = - (dma_descr_data *)virt_to_phys(&port->in_descr[0]); - port->in_context.saved_data_buf = port->in_descr[0].buf; - DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context)); -} - -static irqreturn_t tr_interrupt(int irq, void *dev_id) -{ - reg_dma_r_masked_intr masked; - reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes }; - reg_dma_rw_stat stat; - int i; - int found = 0; - int stop_sser = 0; - - for (i = 0; i < NBR_PORTS; i++) { - struct sync_port *port = &ports[i]; - if (!port->enabled || !port->use_dma) - continue; - - /* IRQ active for the port? */ - masked = REG_RD(dma, port->regi_dmaout, r_masked_intr); - if (!masked.data) - continue; - - found = 1; - - /* Check if we should stop the DMA transfer */ - stat = REG_RD(dma, port->regi_dmaout, rw_stat); - if (stat.list_state == regk_dma_data_at_eol) - stop_sser = 1; - - /* Clear IRQ */ - REG_WR(dma, port->regi_dmaout, rw_ack_intr, ack_intr); - - if (!stop_sser) { - /* The DMA has completed a descriptor, EOL was not - * encountered, so step relevant descriptor and - * datapointers forward. */ - int sent; - sent = port->catch_tr_descr->after - - port->catch_tr_descr->buf; - DEBUGTXINT(pr_info("%-4d - %-4d = %-4d\t" - "in descr %p (ac: %p)\n", - port->out_buf_count, sent, - port->out_buf_count - sent, - port->catch_tr_descr, - port->active_tr_descr);); - port->out_buf_count -= sent; - port->catch_tr_descr = - phys_to_virt((int) port->catch_tr_descr->next); - port->out_rd_ptr = - phys_to_virt((int) port->catch_tr_descr->buf); - } else { - reg_sser_rw_tr_cfg tr_cfg; - int j, sent; - /* EOL handler. - * Note that if an EOL was encountered during the irq - * locked section of sync_ser_write the DMA will be - * restarted and the eol flag will be cleared. - * The remaining descriptors will be traversed by - * the descriptor interrupts as usual. - */ - j = 0; - while (!port->catch_tr_descr->eol) { - sent = port->catch_tr_descr->after - - port->catch_tr_descr->buf; - DEBUGOUTBUF(pr_info( - "traversing descr %p -%d (%d)\n", - port->catch_tr_descr, - sent, - port->out_buf_count)); - port->out_buf_count -= sent; - port->catch_tr_descr = phys_to_virt( - (int)port->catch_tr_descr->next); - j++; - if (j >= NBR_OUT_DESCR) { - /* TODO: Reset and recover */ - panic("sync_serial: missing eol"); - } - } - sent = port->catch_tr_descr->after - - port->catch_tr_descr->buf; - DEBUGOUTBUF(pr_info("eol at descr %p -%d (%d)\n", - port->catch_tr_descr, - sent, - port->out_buf_count)); - - port->out_buf_count -= sent; - - /* Update read pointer to first free byte, we - * may already be writing data there. */ - port->out_rd_ptr = - phys_to_virt((int) port->catch_tr_descr->after); - if (port->out_rd_ptr > port->out_buffer + - OUT_BUFFER_SIZE) - port->out_rd_ptr = port->out_buffer; - - tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); - DEBUGTXINT(pr_info( - "tr_int DMA stop %d, set catch @ %p\n", - port->out_buf_count, - port->active_tr_descr)); - if (port->out_buf_count != 0) - pr_err("sync_ser: buf not empty after eol\n"); - port->catch_tr_descr = port->active_tr_descr; - port->tr_running = 0; - tr_cfg.tr_en = regk_sser_no; - REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); - } - /* wake up the waiting process */ - wake_up_interruptible(&port->out_wait_q); - } - return IRQ_RETVAL(found); -} /* tr_interrupt */ - - -static inline void handle_rx_packet(struct sync_port *port) -{ - int idx; - reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes }; - unsigned long flags; - - DEBUGRXINT(pr_info("!")); - spin_lock_irqsave(&port->lock, flags); - - /* If we overrun the user experience is crap regardless if we - * drop new or old data. Its much easier to get it right when - * dropping new data so lets do that. - */ - if ((port->writep + port->inbufchunk <= - port->flip + port->in_buffer_size) && - (port->in_buffer_len + port->inbufchunk < IN_BUFFER_SIZE)) { - memcpy(port->writep, - phys_to_virt((unsigned)port->next_rx_desc->buf), - port->inbufchunk); - port->writep += port->inbufchunk; - if (port->writep >= port->flip + port->in_buffer_size) - port->writep = port->flip; - - /* Timestamp the new data chunk. */ - if (port->write_ts_idx == NBR_IN_DESCR) - port->write_ts_idx = 0; - idx = port->write_ts_idx++; - ktime_get_ts(&port->timestamp[idx]); - port->in_buffer_len += port->inbufchunk; - } - spin_unlock_irqrestore(&port->lock, flags); - - port->next_rx_desc->eol = 1; - port->prev_rx_desc->eol = 0; - /* Cache bug workaround */ - flush_dma_descr(port->prev_rx_desc, 0); - port->prev_rx_desc = port->next_rx_desc; - port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next); - /* Cache bug workaround */ - flush_dma_descr(port->prev_rx_desc, 1); - /* wake up the waiting process */ - wake_up_interruptible(&port->in_wait_q); - DMA_CONTINUE(port->regi_dmain); - REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr); - -} - -static irqreturn_t rx_interrupt(int irq, void *dev_id) -{ - reg_dma_r_masked_intr masked; - - int i; - int found = 0; - - DEBUG(pr_info("rx_interrupt\n")); - - for (i = 0; i < NBR_PORTS; i++) { - struct sync_port *port = &ports[i]; - - if (!port->enabled || !port->use_dma) - continue; - - masked = REG_RD(dma, port->regi_dmain, r_masked_intr); - - if (!masked.data) - continue; - - /* Descriptor interrupt */ - found = 1; - while (REG_RD(dma, port->regi_dmain, rw_data) != - virt_to_phys(port->next_rx_desc)) - handle_rx_packet(port); - } - return IRQ_RETVAL(found); -} /* rx_interrupt */ -#endif /* SYNC_SER_DMA */ - -#ifdef SYNC_SER_MANUAL -static irqreturn_t manual_interrupt(int irq, void *dev_id) -{ - unsigned long flags; - int i; - int found = 0; - reg_sser_r_masked_intr masked; - - for (i = 0; i < NBR_PORTS; i++) { - struct sync_port *port = &ports[i]; - - if (!port->enabled || port->use_dma) - continue; - - masked = REG_RD(sser, port->regi_sser, r_masked_intr); - /* Data received? */ - if (masked.rdav) { - reg_sser_rw_rec_cfg rec_cfg = - REG_RD(sser, port->regi_sser, rw_rec_cfg); - reg_sser_r_rec_data data = REG_RD(sser, - port->regi_sser, r_rec_data); - found = 1; - /* Read data */ - spin_lock_irqsave(&port->lock, flags); - switch (rec_cfg.sample_size) { - case 8: - *port->writep++ = data.data & 0xff; - break; - case 12: - *port->writep = (data.data & 0x0ff0) >> 4; - *(port->writep + 1) = data.data & 0x0f; - port->writep += 2; - break; - case 16: - *(unsigned short *)port->writep = data.data; - port->writep += 2; - break; - case 24: - *(unsigned int *)port->writep = data.data; - port->writep += 3; - break; - case 32: - *(unsigned int *)port->writep = data.data; - port->writep += 4; - break; - } - - /* Wrap? */ - if (port->writep >= port->flip + port->in_buffer_size) - port->writep = port->flip; - if (port->writep == port->readp) { - /* Receive buf overrun, discard oldest data */ - port->readp++; - /* Wrap? */ - if (port->readp >= port->flip + - port->in_buffer_size) - port->readp = port->flip; - } - spin_unlock_irqrestore(&port->lock, flags); - if (sync_data_avail(port) >= port->inbufchunk) - /* Wake up application */ - wake_up_interruptible(&port->in_wait_q); - } - - /* Transmitter ready? */ - if (masked.trdy) { - found = 1; - /* More data to send */ - if (port->out_buf_count > 0) - send_word(port); - else { - /* Transmission finished */ - reg_sser_rw_intr_mask intr_mask; - intr_mask = REG_RD(sser, port->regi_sser, - rw_intr_mask); - intr_mask.trdy = 0; - REG_WR(sser, port->regi_sser, - rw_intr_mask, intr_mask); - /* Wake up application */ - wake_up_interruptible(&port->out_wait_q); - } - } - } - return IRQ_RETVAL(found); -} -#endif - -static int __init etrax_sync_serial_init(void) -{ -#if 1 - /* This code will be removed when we move to udev for all devices. */ - syncser_first = MKDEV(SYNC_SERIAL_MAJOR, 0); - if (register_chrdev_region(syncser_first, minor_count, SYNCSER_NAME)) { - pr_err("Failed to register major %d\n", SYNC_SERIAL_MAJOR); - return -1; - } -#else - /* Allocate dynamic major number. */ - if (alloc_chrdev_region(&syncser_first, 0, minor_count, SYNCSER_NAME)) { - pr_err("Failed to allocate character device region\n"); - return -1; - } -#endif - syncser_cdev = cdev_alloc(); - if (!syncser_cdev) { - pr_err("Failed to allocate cdev for syncser\n"); - unregister_chrdev_region(syncser_first, minor_count); - return -1; - } - cdev_init(syncser_cdev, &syncser_fops); - - /* Create a sysfs class for syncser */ - syncser_class = class_create(THIS_MODULE, "syncser_class"); - if (IS_ERR(syncser_class)) { - pr_err("Failed to create a sysfs class for syncser\n"); - unregister_chrdev_region(syncser_first, minor_count); - cdev_del(syncser_cdev); - return -1; - } - - /* Initialize Ports */ -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) - if (artpec_pinmux_alloc_fixed(PINMUX_SSER0)) { - pr_warn("Unable to alloc pins for synchronous serial port 0\n"); - unregister_chrdev_region(syncser_first, minor_count); - return -EIO; - } - initialize_port(0); - ports[0].enabled = 1; - /* Register with sysfs so udev can pick it up. */ - device_create(syncser_class, NULL, syncser_first, NULL, - "%s%d", SYNCSER_NAME, 0); -#endif - -#if defined(CONFIG_ETRAXFS) && defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) - if (artpec_pinmux_alloc_fixed(PINMUX_SSER1)) { - pr_warn("Unable to alloc pins for synchronous serial port 1\n"); - unregister_chrdev_region(syncser_first, minor_count); - class_destroy(syncser_class); - return -EIO; - } - initialize_port(1); - ports[1].enabled = 1; - /* Register with sysfs so udev can pick it up. */ - device_create(syncser_class, NULL, syncser_first, NULL, - "%s%d", SYNCSER_NAME, 0); -#endif - - /* Add it to system */ - if (cdev_add(syncser_cdev, syncser_first, minor_count) < 0) { - pr_err("Failed to add syncser as char device\n"); - device_destroy(syncser_class, syncser_first); - class_destroy(syncser_class); - cdev_del(syncser_cdev); - unregister_chrdev_region(syncser_first, minor_count); - return -1; - } - - - pr_info("ARTPEC synchronous serial port (%s: %d, %d)\n", - SYNCSER_NAME, MAJOR(syncser_first), MINOR(syncser_first)); - - return 0; -} - -static void __exit etrax_sync_serial_exit(void) -{ - int i; - device_destroy(syncser_class, syncser_first); - class_destroy(syncser_class); - - if (syncser_cdev) { - cdev_del(syncser_cdev); - unregister_chrdev_region(syncser_first, minor_count); - } - for (i = 0; i < NBR_PORTS; i++) { - struct sync_port *port = &ports[i]; - if (port->init_irqs == dma_irq_setup) { - /* Free dma irqs and dma channels. */ -#ifdef SYNC_SER_DMA - artpec_free_dma(port->dma_in_nbr); - artpec_free_dma(port->dma_out_nbr); - free_irq(port->dma_out_intr_vect, port); - free_irq(port->dma_in_intr_vect, port); -#endif - } else if (port->init_irqs == manual_irq_setup) { - /* Free manual irq. */ - free_irq(port->syncser_intr_vect, port); - } - } - - pr_info("ARTPEC synchronous serial port unregistered\n"); -} - -module_init(etrax_sync_serial_init); -module_exit(etrax_sync_serial_exit); - -MODULE_LICENSE("GPL"); - diff --git a/arch/cris/arch-v32/kernel/Makefile b/arch/cris/arch-v32/kernel/Makefile deleted file mode 100644 index 2db7e4f7c1fa..000000000000 --- a/arch/cris/arch-v32/kernel/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the linux kernel. -# - -extra-y := head.o - - -obj-y := entry.o traps.o irq.o debugport.o \ - process.o ptrace.o setup.o signal.o traps.o time.o \ - cache.o cacheflush.o - -obj-$(CONFIG_ETRAX_KGDB) += kgdb.o kgdb_asm.o -obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o -obj-$(CONFIG_MODULES) += crisksyms.o - -clean: - diff --git a/arch/cris/arch-v32/kernel/cache.c b/arch/cris/arch-v32/kernel/cache.c deleted file mode 100644 index a080d2fa4803..000000000000 --- a/arch/cris/arch-v32/kernel/cache.c +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/module.h> -#include <asm/io.h> -#include <arch/cache.h> -#include <arch/hwregs/dma.h> - -/* This file is used to workaround a cache bug, Guinness TR 106. */ - -inline void flush_dma_descr(struct dma_descr_data *descr, int flush_buf) -{ - /* Flush descriptor to make sure we get correct in_eop and after. */ - asm volatile ("ftagd [%0]" :: "r" (descr)); - /* Flush buffer pointed out by descriptor. */ - if (flush_buf) - cris_flush_cache_range(phys_to_virt((unsigned)descr->buf), - (unsigned)(descr->after - descr->buf)); -} -EXPORT_SYMBOL(flush_dma_descr); - -void flush_dma_list(struct dma_descr_data *descr) -{ - while (1) { - flush_dma_descr(descr, 1); - if (descr->eol) - break; - descr = phys_to_virt((unsigned)descr->next); - } -} -EXPORT_SYMBOL(flush_dma_list); - -/* From cacheflush.S */ -EXPORT_SYMBOL(cris_flush_cache); -/* From cacheflush.S */ -EXPORT_SYMBOL(cris_flush_cache_range); diff --git a/arch/cris/arch-v32/kernel/cacheflush.S b/arch/cris/arch-v32/kernel/cacheflush.S deleted file mode 100644 index 2a54d793f96c..000000000000 --- a/arch/cris/arch-v32/kernel/cacheflush.S +++ /dev/null @@ -1,100 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ - .global cris_flush_cache_range - .type cris_flush_cache_range, @function -cris_flush_cache_range: - move.d 1024, $r12 - cmp.d $r11, $r12 - bhi cris_flush_1KB - nop - add.d $r10, $r11 - ftagd [$r10] -cris_flush_last: - addq 32, $r10 - cmp.d $r11, $r10 - blt cris_flush_last - ftagd [$r10] - ret - nop -cris_flush_1KB: - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ftagd [$r10] - addq 32, $r10 - ba cris_flush_cache_range - sub.d $r12, $r11 - .size cris_flush_cache_range, . - cris_flush_cache_range - - .global cris_flush_cache - .type cris_flush_cache, @function -cris_flush_cache: - moveq 0, $r10 -cris_flush_line: - move.d 16*1024, $r11 - addq 16, $r10 - cmp.d $r10, $r11 - blt cris_flush_line - fidxd [$r10] - ret - nop - .size cris_flush_cache, . - cris_flush_cache - diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c deleted file mode 100644 index 8cc8ad1cb532..000000000000 --- a/arch/cris/arch-v32/kernel/crisksyms.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/module.h> -#include <linux/irq.h> -#include <arch/dma.h> -#include <arch/intmem.h> -#include <mach/pinmux.h> - -/* Functions for allocating DMA channels */ -EXPORT_SYMBOL(crisv32_request_dma); -EXPORT_SYMBOL(crisv32_free_dma); - -/* Functions for handling internal RAM */ -EXPORT_SYMBOL(crisv32_intmem_alloc); -EXPORT_SYMBOL(crisv32_intmem_free); -EXPORT_SYMBOL(crisv32_intmem_phys_to_virt); -EXPORT_SYMBOL(crisv32_intmem_virt_to_phys); - -/* Functions for handling pinmux */ -EXPORT_SYMBOL(crisv32_pinmux_alloc); -EXPORT_SYMBOL(crisv32_pinmux_alloc_fixed); -EXPORT_SYMBOL(crisv32_pinmux_dealloc); -EXPORT_SYMBOL(crisv32_pinmux_dealloc_fixed); - -/* Functions masking/unmasking interrupts */ -EXPORT_SYMBOL(crisv32_mask_irq); -EXPORT_SYMBOL(crisv32_unmask_irq); diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c deleted file mode 100644 index 69247fd2090a..000000000000 --- a/arch/cris/arch-v32/kernel/debugport.c +++ /dev/null @@ -1,232 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2003, Axis Communications AB. - */ - -#include <linux/console.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/string.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/reg_map.h> -#include <hwregs/ser_defs.h> -#include <hwregs/dma_defs.h> -#include <mach/pinmux.h> - -struct dbg_port -{ - unsigned char nbr; - unsigned long instance; - unsigned int started; - unsigned long baudrate; - unsigned char parity; - unsigned int bits; -}; - -struct dbg_port ports[] = -{ - { - 0, - regi_ser0, - 0, - 115200, - 'N', - 8 - }, - { - 1, - regi_ser1, - 0, - 115200, - 'N', - 8 - }, - { - 2, - regi_ser2, - 0, - 115200, - 'N', - 8 - }, - { - 3, - regi_ser3, - 0, - 115200, - 'N', - 8 - }, -#if CONFIG_ETRAX_SERIAL_PORTS == 5 - { - 4, - regi_ser4, - 0, - 115200, - 'N', - 8 - }, -#endif -}; - -static struct dbg_port *port = -#if defined(CONFIG_ETRAX_DEBUG_PORT0) - &ports[0]; -#elif defined(CONFIG_ETRAX_DEBUG_PORT1) - &ports[1]; -#elif defined(CONFIG_ETRAX_DEBUG_PORT2) - &ports[2]; -#elif defined(CONFIG_ETRAX_DEBUG_PORT3) - &ports[3]; -#else - NULL; -#endif - -#ifdef CONFIG_ETRAX_KGDB -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]; -#elif defined(CONFIG_ETRAX_KGDB_PORT4) - &ports[4]; -#else - NULL; -#endif -#endif - -static void start_port(struct dbg_port *p) -{ - /* Set up serial port registers */ - reg_ser_rw_tr_ctrl tr_ctrl = {0}; - reg_ser_rw_tr_dma_en tr_dma_en = {0}; - - reg_ser_rw_rec_ctrl rec_ctrl = {0}; - reg_ser_rw_tr_baud_div tr_baud_div = {0}; - reg_ser_rw_rec_baud_div rec_baud_div = {0}; - - if (!p || p->started) - return; - - p->started = 1; - - if (p->nbr == 1) - crisv32_pinmux_alloc_fixed(pinmux_ser1); - else if (p->nbr == 2) - crisv32_pinmux_alloc_fixed(pinmux_ser2); - else if (p->nbr == 3) - crisv32_pinmux_alloc_fixed(pinmux_ser3); -#if CONFIG_ETRAX_SERIAL_PORTS == 5 - else if (p->nbr == 4) - crisv32_pinmux_alloc_fixed(pinmux_ser4); -#endif - - tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493; - tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no; - tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8; - tr_ctrl.en = rec_ctrl.en = 1; - - if (p->parity == 'O') { - tr_ctrl.par_en = regk_ser_yes; - tr_ctrl.par = regk_ser_odd; - rec_ctrl.par_en = regk_ser_yes; - rec_ctrl.par = regk_ser_odd; - } else if (p->parity == 'E') { - tr_ctrl.par_en = regk_ser_yes; - tr_ctrl.par = regk_ser_even; - rec_ctrl.par_en = regk_ser_yes; - rec_ctrl.par = regk_ser_odd; - } - - if (p->bits == 7) { - tr_ctrl.data_bits = regk_ser_bits7; - rec_ctrl.data_bits = regk_ser_bits7; - } - - REG_WR (ser, p->instance, rw_tr_baud_div, tr_baud_div); - REG_WR (ser, p->instance, rw_rec_baud_div, rec_baud_div); - REG_WR (ser, p->instance, rw_tr_dma_en, tr_dma_en); - REG_WR (ser, p->instance, rw_tr_ctrl, tr_ctrl); - REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl); -} - -#ifdef CONFIG_ETRAX_KGDB -/* Use polling to get a single character from the kernel debug port */ -int getDebugChar(void) -{ - reg_ser_rs_stat_din stat; - reg_ser_rw_ack_intr ack_intr = { 0 }; - - do { - stat = REG_RD(ser, kgdb_port->instance, rs_stat_din); - } while (!stat.dav); - - /* Ack the data_avail interrupt. */ - ack_intr.dav = 1; - REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr); - - return stat.data; -} - -/* Use polling to put a single character to the kernel debug port */ -void putDebugChar(int val) -{ - reg_ser_r_stat_din stat; - do { - stat = REG_RD(ser, kgdb_port->instance, r_stat_din); - } while (!stat.tr_rdy); - REG_WR_INT(ser, kgdb_port->instance, rw_dout, val); -} -#endif /* CONFIG_ETRAX_KGDB */ - -static void __init early_putch(int c) -{ - reg_ser_r_stat_din stat; - /* Wait until transmitter is ready and send. */ - do - stat = REG_RD(ser, port->instance, r_stat_din); - while (!stat.tr_rdy); - REG_WR_INT(ser, port->instance, rw_dout, c); -} - -static void __init -early_console_write(struct console *con, const char *s, unsigned n) -{ - extern void reset_watchdog(void); - int i; - - /* Send data. */ - for (i = 0; i < n; i++) { - /* TODO: the '\n' -> '\n\r' translation should be done at the - receiver. Remove it when the serial driver removes it. */ - if (s[i] == '\n') - early_putch('\r'); - early_putch(s[i]); - reset_watchdog(); - } -} - -static struct console early_console_dev __initdata = { - .name = "early", - .write = early_console_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1 -}; - -/* Register console for printk's, etc. */ -int __init init_etrax_debug(void) -{ - start_port(port); - - /* Register an early console if a debug port was chosen. */ - register_console(&early_console_dev); - -#ifdef CONFIG_ETRAX_KGDB - start_port(kgdb_port); -#endif /* CONFIG_ETRAX_KGDB */ - return 0; -} diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S deleted file mode 100644 index 0793a52b2c34..000000000000 --- a/arch/cris/arch-v32/kernel/entry.S +++ /dev/null @@ -1,909 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2000-2003 Axis Communications AB - * - * Authors: Bjorn Wesen (bjornw@axis.com) - * Tobias Anderberg (tobiasa@axis.com), CRISv32 port. - * - * Code for the system-call and fault low-level handling routines. - * - * NOTE: This code handles signal-recognition, which happens every time - * after a timer-interrupt and after each system call. - * - * Stack layout in 'ret_from_system_call': - * ptrace needs to have all regs on the stack. - * if the order here is changed, it needs to be - * updated in fork.c:copy_process, signal.c:do_signal, - * ptrace.c and ptrace.h - * - */ - -#include <linux/linkage.h> -#include <linux/sys.h> -#include <asm/unistd.h> -#include <asm/errno.h> -#include <asm/thread_info.h> -#include <asm/asm-offsets.h> - -#include <hwregs/asm/reg_map_asm.h> -#include <hwregs/asm/intr_vect_defs_asm.h> - - ;; Exported functions. - .globl system_call - .globl ret_from_intr - .globl ret_from_fork - .globl ret_from_kernel_thread - .globl resume - .globl multiple_interrupt - .globl nmi_interrupt - .globl spurious_interrupt - .globl do_sigtrap - .globl gdb_handle_exception - .globl sys_call_table - - ; Check if preemptive kernel scheduling should be done. -#ifdef CONFIG_PREEMPT -_resume_kernel: - di - ; Load current task struct. - movs.w -8192, $r0 ; THREAD_SIZE = 8192 - and.d $sp, $r0 - - addoq +TI_preempt_count, $r0, $acr - move.d [$acr], $r10 ; Preemption disabled? - bne _Rexit - nop - -_need_resched: - addoq +TI_flags, $r0, $acr - move.d [$acr], $r10 - btstq TIF_NEED_RESCHED, $r10 ; Check if need_resched is set. - bpl _Rexit - nop - - ; Do preemptive kernel scheduling. - jsr preempt_schedule_irq - nop - - ; Load new task struct. - movs.w -8192, $r0 ; THREAD_SIZE = 8192. - and.d $sp, $r0 - - ; One more time with new task. - ba _need_resched - nop -#else -#define _resume_kernel _Rexit -#endif - - ; Called at exit from fork. schedule_tail must be called to drop - ; spinlock if CONFIG_PREEMPT. - .type ret_from_fork,@function -ret_from_fork: - jsr schedule_tail - nop - ba ret_from_sys_call - nop - .size ret_from_fork, . - ret_from_fork - - .type ret_from_kernel_thread,@function -ret_from_kernel_thread: - jsr schedule_tail - nop - move.d $r2, $r10 - jsr $r1 - nop - moveq 0, $r9 ; no syscall restarts, TYVM... - ba ret_from_sys_call - nop - .size ret_from_kernel_thread, . - ret_from_kernel_thread - - .type ret_from_intr,@function -ret_from_intr: - moveq 0, $r9 ; not a syscall - - ;; Check for resched if preemptive kernel, or if we're going back to - ;; user-mode. This test matches the user_regs(regs) macro. Don't simply - ;; test CCS since that doesn't necessarily reflect what mode we'll - ;; return into. - addoq +PT_ccs, $sp, $acr - move.d [$acr], $r0 - btstq 16, $r0 ; User-mode flag. - bpl _resume_kernel - .size ret_from_intr, . - ret_from_intr + 2 ; +2 includes the dslot. - - ; Note that di below is in delay slot. - .type _resume_userspace,@function -_resume_userspace: - di ; So need_resched and sigpending don't change. - - movs.w -8192, $r0 ; THREAD_SIZE == 8192 - and.d $sp, $r0 - - addoq +TI_flags, $r0, $acr ; current->work - move.d [$acr], $r10 - and.d _TIF_WORK_MASK, $r10 ; Work to be done on return? - bne _work_pending - nop - ba _Rexit - nop - .size _resume_userspace, . - _resume_userspace - - ;; The system_call is called by a BREAK instruction, which looks pretty - ;; much like any other exception. - ;; - ;; System calls can't be made from interrupts but we still stack ERP - ;; to have a complete stack frame. - ;; - ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12, - ;; r13,mof,srp - ;; - ;; This function looks on the _surface_ like spaghetti programming, but it's - ;; really designed so that the fast-path does not force cache-loading of - ;; non-used instructions. Only the non-common cases cause the outlined code - ;; to run.. - - .type system_call,@function -system_call: - ;; Stack-frame similar to the irq heads, which is reversed in - ;; ret_from_sys_call. - - sub.d 92, $sp ; Skip EDA. - movem $r13, [$sp] - move.d $sp, $r8 - addq 14*4, $r8 - move.d $acr, $r0 - move $srs, $r1 - move $mof, $r2 - move $spc, $r3 - move $ccs, $r4 - move $srp, $r5 - move $erp, $r6 - move.d $r9, $r7 ; Store syscall number in EXS - subq 4, $sp - movem $r7, [$r8] - ei ; Enable interrupts while processing syscalls. - move.d $r10, [$sp] - - ; Set S-bit when kernel debugging to keep hardware breakpoints active. -#ifdef CONFIG_ETRAX_KGDB - move $ccs, $r0 - or.d (1<<9), $r0 - move $r0, $ccs -#endif - - movs.w -ENOSYS, $r0 - addoq +PT_r10, $sp, $acr - move.d $r0, [$acr] - - ;; Check if this process is syscall-traced. - movs.w -8192, $r0 ; THREAD_SIZE == 8192 - and.d $sp, $r0 - - addoq +TI_flags, $r0, $acr - move.d [$acr], $r0 - btstq TIF_SYSCALL_TRACE, $r0 - bmi _syscall_trace_entry - nop - -_syscall_traced: - ;; Check for sanity in the requested syscall number. - cmpu.w NR_syscalls, $r9 - bhs ret_from_sys_call - lslq 2, $r9 ; Multiply by 4, in the delay slot. - - ;; The location on the stack for the register structure is passed as a - ;; seventh argument. Some system calls need this. - move.d $sp, $r0 - subq 4, $sp - move.d $r0, [$sp] - - ;; The registers carrying parameters (R10-R13) are intact. The optional - ;; fifth and sixth parameters is in MOF and SRP respectively. Put them - ;; back on the stack. - subq 4, $sp - move $srp, [$sp] - subq 4, $sp - move $mof, [$sp] - - ;; Actually to the system call. - addo.d +sys_call_table, $r9, $acr - move.d [$acr], $acr - jsr $acr - nop - - addq 3*4, $sp ; Pop the mof, srp and regs parameters. - addoq +PT_r10, $sp, $acr - move.d $r10, [$acr] ; Save the return value. - - moveq 1, $r9 ; "Parameter" to ret_from_sys_call to - ; show it was a sys call. - - ;; Fall through into ret_from_sys_call to return. - -ret_from_sys_call: - ;; R9 is a parameter: - ;; >= 1 from syscall - ;; 0 from irq - - ;; Get the current task-struct pointer. - movs.w -8192, $r0 ; THREAD_SIZE == 8192 - and.d $sp, $r0 - - di ; Make sure need_resched and sigpending don't change. - - addoq +TI_flags, $r0, $acr - move.d [$acr], $r1 - and.d _TIF_ALLWORK_MASK, $r1 - bne _syscall_exit_work - nop - .size system_call, . - system_call - - .type _Rexit,@function -_Rexit: -#if defined(CONFIG_TRACE_IRQFLAGS) - addoq +PT_ccs, $sp, $acr - move.d [$acr], $r0 - btstq 15, $r0 ; I1 - bpl 1f - nop - jsr trace_hardirqs_on - nop -1: -#endif - - ;; This epilogue MUST match the prologues in multiple_interrupt, irq.h - ;; and ptregs.h. - addq 4, $sp ; Skip orig_r10. - movem [$sp+], $r13 ; Registers R0-R13. - move.d [$sp+], $acr - move [$sp], $srs - addq 4, $sp - move [$sp+], $mof - move [$sp+], $spc - move [$sp+], $ccs - move [$sp+], $srp - move [$sp+], $erp - addq 8, $sp ; Skip EXS, EDA. - jump $erp - rfe ; Restore condition code stack in delay-slot. - .size _Rexit, . - _Rexit - - ;; We get here after doing a syscall if extra work might need to be done - ;; perform syscall exit tracing if needed. - - .type _syscall_exit_work,@function -_syscall_exit_work: - ;; R0 contains current at this point and irq's are disabled. - - addoq +TI_flags, $r0, $acr - move.d [$acr], $r1 - btstq TIF_SYSCALL_TRACE, $r1 - bpl _work_pending - nop - ei - move.d $r9, $r1 ; Preserve R9. - jsr do_syscall_trace - nop - move.d $r1, $r9 - ba _resume_userspace - nop - .size _syscall_exit_work, . - _syscall_exit_work - - .type _work_pending,@function -_work_pending: - addoq +TI_flags, $r0, $acr - move.d [$acr], $r12 ; The thread_info_flags parameter. - move.d $sp, $r11 ; The regs param. - jsr do_work_pending - move.d $r9, $r10 ; The syscall/irq param. - - ba _Rexit - nop - .size _work_pending, . - _work_pending - - ;; We get here as a sidetrack when we've entered a syscall with the - ;; trace-bit set. We need to call do_syscall_trace and then continue - ;; with the call. - -_syscall_trace_entry: - ;; PT_r10 in the frame contains -ENOSYS as required, at this point. - - jsr do_syscall_trace - nop - - ;; Now re-enter the syscall code to do the syscall itself. We need to - ;; restore R9 here to contain the wanted syscall, and the other - ;; parameter-bearing registers. - addoq +PT_r9, $sp, $acr - move.d [$acr], $r9 - addoq +PT_orig_r10, $sp, $acr - move.d [$acr], $r10 ; PT_r10 is already -ENOSYS. - addoq +PT_r11, $sp, $acr - move.d [$acr], $r11 - addoq +PT_r12, $sp, $acr - move.d [$acr], $r12 - addoq +PT_r13, $sp, $acr - move.d [$acr], $r13 - addoq +PT_mof, $sp, $acr - move [$acr], $mof - addoq +PT_srp, $sp, $acr - move [$acr], $srp - - ba _syscall_traced - nop - - ;; Resume performs the actual task-switching, by switching stack - ;; pointers. Input arguments are: - ;; - ;; R10 = prev - ;; R11 = next - ;; R12 = thread offset in task struct. - ;; - ;; Returns old current in R10. - - .type resume,@function -resume: - subq 4, $sp ; Make space for srp. - - add.d $r12, $r10 ; R10 = current tasks tss. - addoq +THREAD_ccs, $r10, $acr - move $srp, [$sp] ; Keep old/new PC on the stack. - move $ccs, [$acr] ; Save IRQ enable state. - di - - addoq +THREAD_usp, $r10, $acr - subq 10*4, $sp ; Make room for R9. - move $usp, [$acr] ; Save user-mode stackpointer. - - ;; See copy_thread for the reason why register R9 is saved. - movem $r9, [$sp] ; Save non-scratch registers and R9. - - addoq +THREAD_ksp, $r10, $acr - move.d $sp, $r10 ; Return last running task in R10. - move.d $sp, [$acr] ; Save kernel SP for old task. - - and.d -8192, $r10 ; Get thread_info from stackpointer. - addoq +TI_task, $r10, $acr - add.d $r12, $r11 ; Find the new tasks tss. - move.d [$acr], $r10 ; Get task. - addoq +THREAD_ksp, $r11, $acr - move.d [$acr], $sp ; Switch to new stackframe. - addoq +THREAD_usp, $r11, $acr - movem [$sp+], $r9 ; Restore non-scratch registers and R9. - - move [$acr], $usp ; Restore user-mode stackpointer. - - addoq +THREAD_ccs, $r11, $acr - move.d [$sp+], $r11 - jump $r11 ; Restore PC. - move [$acr], $ccs ; Restore IRQ enable status. - .size resume, . - resume - -nmi_interrupt: - -;; 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! - subq 12, $sp ; Skip EXS, EDA. - move $nrp, [$sp] - subq 4, $sp - move $srp, [$sp] - subq 4, $sp - move $ccs, [$sp] - subq 4, $sp - move $spc, [$sp] - subq 4, $sp - move $mof, [$sp] - subq 4, $sp - move $srs, [$sp] - subq 4, $sp - move.d $acr, [$sp] - subq 14*4, $sp ; Make room for R0-R13. - movem $r13, [$sp] ; Push R0-R13. - subq 4, $sp - move.d $r10, [$sp] ; Push orig_r10. - move.d REG_ADDR(intr_vect, regi_irq, r_nmi), $r0 - move.d [$r0], $r0 - btstq REG_BIT(intr_vect, r_nmi, watchdog), $r0 - bpl 1f - nop - jsr handle_watchdog_bite ; In time.c. - move.d $sp, $r10 ; Pointer to registers -1: btstq REG_BIT(intr_vect, r_nmi, ext), $r0 - bpl 1f - nop - jsr handle_nmi - move.d $sp, $r10 ; Pointer to registers -1: addq 4, $sp ; Skip orig_r10 - movem [$sp+], $r13 - move.d [$sp+], $acr - move [$sp], $srs - addq 4, $sp - move [$sp+], $mof - move [$sp+], $spc - move [$sp+], $ccs - move [$sp+], $srp - move [$sp+], $nrp - addq 8, $sp ; Skip EXS, EDA. - jump $nrp - rfn - - .comm cause_of_death, 4 ;; Don't declare this anywhere. - -spurious_interrupt: - di - jump hard_reset_now - nop - - ;; This handles the case when multiple interrupts arrive at the same - ;; time. Jump to the first set interrupt bit in a priority fashion. The - ;; hardware will call the unserved interrupts after the handler - ;; finishes. - .type multiple_interrupt, @function -multiple_interrupt: - ;; This prologue MUST match the one in irq.h and the struct in ptregs.h! - subq 12, $sp ; Skip EXS, EDA. - move $erp, [$sp] - subq 4, $sp - move $srp, [$sp] - subq 4, $sp - move $ccs, [$sp] - subq 4, $sp - move $spc, [$sp] - subq 4, $sp - move $mof, [$sp] - subq 4, $sp - move $srs, [$sp] - subq 4, $sp - move.d $acr, [$sp] - subq 14*4, $sp ; Make room for R0-R13. - movem $r13, [$sp] ; Push R0-R13. - subq 4, $sp - move.d $r10, [$sp] ; Push orig_r10. - -; Set S-bit when kernel debugging to keep hardware breakpoints active. -#ifdef CONFIG_ETRAX_KGDB - move $ccs, $r0 - or.d (1<<9), $r0 - move $r0, $ccs -#endif - - jsr crisv32_do_multiple - move.d $sp, $r10 - jump ret_from_intr - nop - .size multiple_interrupt, . - multiple_interrupt - -do_sigtrap: - ;; Sigtraps the process that executed the BREAK instruction. Creates a - ;; frame that Rexit expects. - subq 4, $sp - move $eda, [$sp] - subq 4, $sp - move $exs, [$sp] - subq 4, $sp - move $erp, [$sp] - subq 4, $sp - move $srp, [$sp] - subq 4, $sp - move $ccs, [$sp] - subq 4, $sp - move $spc, [$sp] - subq 4, $sp - move $mof, [$sp] - subq 4, $sp - move $srs, [$sp] - subq 4, $sp - move.d $acr, [$sp] - di ; Need to disable irq's at this point. - subq 14*4, $sp ; Make room for r0-r13. - movem $r13, [$sp] ; Push the r0-r13 registers. - subq 4, $sp - move.d $r10, [$sp] ; Push orig_r10. - - movs.w -8192, $r9 ; THREAD_SIZE == 8192 - and.d $sp, $r9 - - ;; thread_info as first parameter - move.d $r9, $r10 - moveq 5, $r11 ; SIGTRAP as second argument. - jsr ugdb_trap_user - nop - jump ret_from_intr ; Use the return routine for interrupts. - nop - -gdb_handle_exception: - subq 4, $sp - move.d $r0, [$sp] -#ifdef CONFIG_ETRAX_KGDB - move $ccs, $r0 ; U-flag not affected by previous insns. - btstq 16, $r0 ; Test the U-flag. - bmi _ugdb_handle_exception ; Go to user mode debugging. - nop ; Empty delay-slot (cannot pop R0 here). - ba kgdb_handle_exception ; Go to kernel debugging. - move.d [$sp+], $r0 ; Restore R0 in delay slot. -#endif - -_ugdb_handle_exception: - ba do_sigtrap ; SIGTRAP the offending process. - move.d [$sp+], $r0 ; Restore R0 in delay slot. - - .data - - .section .rodata,"a" -sys_call_table: - .long sys_restart_syscall ; 0 - old "setup()" system call, used - ; for restarting. - .long sys_exit - .long sys_fork - .long sys_read - .long sys_write - .long sys_open /* 5 */ - .long sys_close - .long sys_waitpid - .long sys_creat - .long sys_link - .long sys_unlink /* 10 */ - .long sys_execve - .long sys_chdir - .long sys_time - .long sys_mknod - .long sys_chmod /* 15 */ - .long sys_lchown16 - .long sys_ni_syscall /* old break syscall holder */ - .long sys_stat - .long sys_lseek - .long sys_getpid /* 20 */ - .long sys_mount - .long sys_oldumount - .long sys_setuid16 - .long sys_getuid16 - .long sys_stime /* 25 */ - .long sys_ptrace - .long sys_alarm - .long sys_fstat - .long sys_pause - .long sys_utime /* 30 */ - .long sys_ni_syscall /* old stty syscall holder */ - .long sys_ni_syscall /* old gtty syscall holder */ - .long sys_access - .long sys_nice - .long sys_ni_syscall /* 35 old ftime syscall holder */ - .long sys_sync - .long sys_kill - .long sys_rename - .long sys_mkdir - .long sys_rmdir /* 40 */ - .long sys_dup - .long sys_pipe - .long sys_times - .long sys_ni_syscall /* old prof syscall holder */ - .long sys_brk /* 45 */ - .long sys_setgid16 - .long sys_getgid16 - .long sys_signal - .long sys_geteuid16 - .long sys_getegid16 /* 50 */ - .long sys_acct - .long sys_umount /* recycled never used phys( */ - .long sys_ni_syscall /* old lock syscall holder */ - .long sys_ioctl - .long sys_fcntl /* 55 */ - .long sys_ni_syscall /* old mpx syscall holder */ - .long sys_setpgid - .long sys_ni_syscall /* old ulimit syscall holder */ - .long sys_ni_syscall /* old sys_olduname holder */ - .long sys_umask /* 60 */ - .long sys_chroot - .long sys_ustat - .long sys_dup2 - .long sys_getppid - .long sys_getpgrp /* 65 */ - .long sys_setsid - .long sys_sigaction - .long sys_sgetmask - .long sys_ssetmask - .long sys_setreuid16 /* 70 */ - .long sys_setregid16 - .long sys_sigsuspend - .long sys_sigpending - .long sys_sethostname - .long sys_setrlimit /* 75 */ - .long sys_old_getrlimit - .long sys_getrusage - .long sys_gettimeofday - .long sys_settimeofday - .long sys_getgroups16 /* 80 */ - .long sys_setgroups16 - .long sys_select /* was old_select in Linux/E100 */ - .long sys_symlink - .long sys_lstat - .long sys_readlink /* 85 */ - .long sys_uselib - .long sys_swapon - .long sys_reboot - .long sys_old_readdir - .long sys_old_mmap /* 90 */ - .long sys_munmap - .long sys_truncate - .long sys_ftruncate - .long sys_fchmod - .long sys_fchown16 /* 95 */ - .long sys_getpriority - .long sys_setpriority - .long sys_ni_syscall /* old profil syscall holder */ - .long sys_statfs - .long sys_fstatfs /* 100 */ - .long sys_ni_syscall /* sys_ioperm in i386 */ - .long sys_socketcall - .long sys_syslog - .long sys_setitimer - .long sys_getitimer /* 105 */ - .long sys_newstat - .long sys_newlstat - .long sys_newfstat - .long sys_ni_syscall /* old sys_uname holder */ - .long sys_ni_syscall /* sys_iopl in i386 */ - .long sys_vhangup - .long sys_ni_syscall /* old "idle" system call */ - .long sys_ni_syscall /* vm86old in i386 */ - .long sys_wait4 - .long sys_swapoff /* 115 */ - .long sys_sysinfo - .long sys_ipc - .long sys_fsync - .long sys_sigreturn - .long sys_clone /* 120 */ - .long sys_setdomainname - .long sys_newuname - .long sys_ni_syscall /* sys_modify_ldt */ - .long sys_adjtimex - .long sys_mprotect /* 125 */ - .long sys_sigprocmask - .long sys_ni_syscall /* old "create_module" */ - .long sys_init_module - .long sys_delete_module - .long sys_ni_syscall /* 130: old "get_kernel_syms" */ - .long sys_quotactl - .long sys_getpgid - .long sys_fchdir - .long sys_bdflush - .long sys_sysfs /* 135 */ - .long sys_personality - .long sys_ni_syscall /* for afs_syscall */ - .long sys_setfsuid16 - .long sys_setfsgid16 - .long sys_llseek /* 140 */ - .long sys_getdents - .long sys_select - .long sys_flock - .long sys_msync - .long sys_readv /* 145 */ - .long sys_writev - .long sys_getsid - .long sys_fdatasync - .long sys_sysctl - .long sys_mlock /* 150 */ - .long sys_munlock - .long sys_mlockall - .long sys_munlockall - .long sys_sched_setparam - .long sys_sched_getparam /* 155 */ - .long sys_sched_setscheduler - .long sys_sched_getscheduler - .long sys_sched_yield - .long sys_sched_get_priority_max - .long sys_sched_get_priority_min /* 160 */ - .long sys_sched_rr_get_interval - .long sys_nanosleep - .long sys_mremap - .long sys_setresuid16 - .long sys_getresuid16 /* 165 */ - .long sys_ni_syscall /* sys_vm86 */ - .long sys_ni_syscall /* Old sys_query_module */ - .long sys_poll - .long sys_ni_syscall /* Old nfsservctl */ - .long sys_setresgid16 /* 170 */ - .long sys_getresgid16 - .long sys_prctl - .long sys_rt_sigreturn - .long sys_rt_sigaction - .long sys_rt_sigprocmask /* 175 */ - .long sys_rt_sigpending - .long sys_rt_sigtimedwait - .long sys_rt_sigqueueinfo - .long sys_rt_sigsuspend - .long sys_pread64 /* 180 */ - .long sys_pwrite64 - .long sys_chown16 - .long sys_getcwd - .long sys_capget - .long sys_capset /* 185 */ - .long sys_sigaltstack - .long sys_sendfile - .long sys_ni_syscall /* streams1 */ - .long sys_ni_syscall /* streams2 */ - .long sys_vfork /* 190 */ - .long sys_getrlimit - .long sys_mmap2 - .long sys_truncate64 - .long sys_ftruncate64 - .long sys_stat64 /* 195 */ - .long sys_lstat64 - .long sys_fstat64 - .long sys_lchown - .long sys_getuid - .long sys_getgid /* 200 */ - .long sys_geteuid - .long sys_getegid - .long sys_setreuid - .long sys_setregid - .long sys_getgroups /* 205 */ - .long sys_setgroups - .long sys_fchown - .long sys_setresuid - .long sys_getresuid - .long sys_setresgid /* 210 */ - .long sys_getresgid - .long sys_chown - .long sys_setuid - .long sys_setgid - .long sys_setfsuid /* 215 */ - .long sys_setfsgid - .long sys_pivot_root - .long sys_mincore - .long sys_madvise - .long sys_getdents64 /* 220 */ - .long sys_fcntl64 - .long sys_ni_syscall /* reserved for TUX */ - .long sys_ni_syscall - .long sys_gettid - .long sys_readahead /* 225 */ - .long sys_setxattr - .long sys_lsetxattr - .long sys_fsetxattr - .long sys_getxattr - .long sys_lgetxattr /* 230 */ - .long sys_fgetxattr - .long sys_listxattr - .long sys_llistxattr - .long sys_flistxattr - .long sys_removexattr /* 235 */ - .long sys_lremovexattr - .long sys_fremovexattr - .long sys_tkill - .long sys_sendfile64 - .long sys_futex /* 240 */ - .long sys_sched_setaffinity - .long sys_sched_getaffinity - .long sys_ni_syscall /* sys_set_thread_area */ - .long sys_ni_syscall /* sys_get_thread_area */ - .long sys_io_setup /* 245 */ - .long sys_io_destroy - .long sys_io_getevents - .long sys_io_submit - .long sys_io_cancel - .long sys_fadvise64 /* 250 */ - .long sys_ni_syscall - .long sys_exit_group - .long sys_lookup_dcookie - .long sys_epoll_create - .long sys_epoll_ctl /* 255 */ - .long sys_epoll_wait - .long sys_remap_file_pages - .long sys_set_tid_address - .long sys_timer_create - .long sys_timer_settime /* 260 */ - .long sys_timer_gettime - .long sys_timer_getoverrun - .long sys_timer_delete - .long sys_clock_settime - .long sys_clock_gettime /* 265 */ - .long sys_clock_getres - .long sys_clock_nanosleep - .long sys_statfs64 - .long sys_fstatfs64 - .long sys_tgkill /* 270 */ - .long sys_utimes - .long sys_fadvise64_64 - .long sys_ni_syscall /* sys_vserver */ - .long sys_ni_syscall /* sys_mbind */ - .long sys_ni_syscall /* 275 sys_get_mempolicy */ - .long sys_ni_syscall /* sys_set_mempolicy */ - .long sys_mq_open - .long sys_mq_unlink - .long sys_mq_timedsend - .long sys_mq_timedreceive /* 280 */ - .long sys_mq_notify - .long sys_mq_getsetattr - .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 - .long sys_ioprio_set - .long sys_ioprio_get /* 290 */ - .long sys_inotify_init - .long sys_inotify_add_watch - .long sys_inotify_rm_watch - .long sys_migrate_pages - .long sys_openat /* 295 */ - .long sys_mkdirat - .long sys_mknodat - .long sys_fchownat - .long sys_futimesat - .long sys_fstatat64 /* 300 */ - .long sys_unlinkat - .long sys_renameat - .long sys_linkat - .long sys_symlinkat - .long sys_readlinkat /* 305 */ - .long sys_fchmodat - .long sys_faccessat - .long sys_pselect6 - .long sys_ppoll - .long sys_unshare /* 310 */ - .long sys_set_robust_list - .long sys_get_robust_list - .long sys_splice - .long sys_sync_file_range - .long sys_tee /* 315 */ - .long sys_vmsplice - .long sys_move_pages - .long sys_getcpu - .long sys_epoll_pwait - .long sys_utimensat /* 320 */ - .long sys_signalfd - .long sys_timerfd_create - .long sys_eventfd - .long sys_fallocate - .long sys_timerfd_settime /* 325 */ - .long sys_timerfd_gettime - .long sys_signalfd4 - .long sys_eventfd2 - .long sys_epoll_create1 - .long sys_dup3 /* 330 */ - .long sys_pipe2 - .long sys_inotify_init1 - .long sys_preadv - .long sys_pwritev - .long sys_setns /* 335 */ - .long sys_name_to_handle_at - .long sys_open_by_handle_at - .long sys_rt_tgsigqueueinfo - .long sys_perf_event_open - .long sys_recvmmsg /* 340 */ - .long sys_accept4 - .long sys_fanotify_init - .long sys_fanotify_mark - .long sys_prlimit64 - .long sys_clock_adjtime /* 345 */ - .long sys_syncfs - .long sys_sendmmsg - .long sys_process_vm_readv - .long sys_process_vm_writev - .long sys_kcmp /* 350 */ - .long sys_finit_module - .long sys_sched_setattr - .long sys_sched_getattr - .long sys_renameat2 - .long sys_seccomp /* 355 */ - .long sys_getrandom - .long sys_memfd_create - .long sys_bpf - .long sys_execveat - - /* - * NOTE!! This doesn't have to be exact - we just have - * to make sure we have _enough_ of the "sys_ni_syscall" - * entries. Don't panic if you notice that this hasn't - * been shrunk every time we add a new system call. - */ - - .rept NR_syscalls - (.-sys_call_table) / 4 - .long sys_ni_syscall - .endr - diff --git a/arch/cris/arch-v32/kernel/fasttimer.c b/arch/cris/arch-v32/kernel/fasttimer.c deleted file mode 100644 index 7452c70f61ff..000000000000 --- a/arch/cris/arch-v32/kernel/fasttimer.c +++ /dev/null @@ -1,793 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * linux/arch/cris/kernel/fasttimer.c - * - * Fast timers for ETRAX FS - * - * Copyright (C) 2000-2006 Axis Communications AB, Lund, Sweden - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/vmalloc.h> -#include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/delay.h> - -#include <asm/irq.h> - -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/timer_defs.h> -#include <asm/fasttimer.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> - -/* - * timer0 is running at 100MHz and generating jiffies timer ticks - * at 100 or 1000 HZ. - * fasttimer gives an API that gives timers that expire "between" the jiffies - * giving microsecond resolution (10 ns). - * fasttimer uses reg_timer_rw_trig register to get interrupt when - * r_time reaches a certain value. - */ - - -#define DEBUG_LOG_INCLUDED -#define FAST_TIMER_LOG -/* #define FAST_TIMER_TEST */ - -#define FAST_TIMER_SANITY_CHECKS - -#ifdef FAST_TIMER_SANITY_CHECKS -static int sanity_failed; -#endif - -#define D1(x) -#define D2(x) -#define DP(x) - -static unsigned int fast_timer_running; -static unsigned int fast_timers_added; -static unsigned int fast_timers_started; -static unsigned int fast_timers_expired; -static unsigned int fast_timers_deleted; -static unsigned int fast_timer_is_init; -static unsigned int fast_timer_ints; - -struct fast_timer *fast_timer_list = NULL; - -#ifdef DEBUG_LOG_INCLUDED -#define DEBUG_LOG_MAX 128 -static const char * debug_log_string[DEBUG_LOG_MAX]; -static unsigned long debug_log_value[DEBUG_LOG_MAX]; -static unsigned int debug_log_cnt; -static unsigned int debug_log_cnt_wrapped; - -#define DEBUG_LOG(string, value) \ -{ \ - unsigned long log_flags; \ - 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) \ - { \ - debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ - debug_log_cnt_wrapped = 1; \ - } \ - local_irq_restore(log_flags); \ -} -#else -#define DEBUG_LOG(string, value) -#endif - - -#define NUM_TIMER_STATS 16 -#ifdef FAST_TIMER_LOG -struct fast_timer timer_added_log[NUM_TIMER_STATS]; -struct fast_timer timer_started_log[NUM_TIMER_STATS]; -struct fast_timer timer_expired_log[NUM_TIMER_STATS]; -#endif - -int timer_div_settings[NUM_TIMER_STATS]; -int timer_delay_settings[NUM_TIMER_STATS]; - -struct work_struct fast_work; - -static void -timer_trig_handler(struct work_struct *work); - - - -/* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ -inline void do_gettimeofday_fast(struct fasttime_t *tv) -{ - tv->tv_jiff = jiffies; - tv->tv_usec = GET_JIFFIES_USEC(); -} - -inline int fasttime_cmp(struct fasttime_t *t0, struct fasttime_t *t1) -{ - /* Compare jiffies. Takes care of wrapping */ - if (time_before(t0->tv_jiff, t1->tv_jiff)) - return -1; - else if (time_after(t0->tv_jiff, t1->tv_jiff)) - return 1; - - /* Compare us */ - if (t0->tv_usec < t1->tv_usec) - return -1; - else if (t0->tv_usec > t1->tv_usec) - return 1; - return 0; -} - -/* Called with ints off */ -inline void start_timer_trig(unsigned long delay_us) -{ - reg_timer_rw_ack_intr ack_intr = { 0 }; - reg_timer_rw_intr_mask intr_mask; - reg_timer_rw_trig trig; - reg_timer_rw_trig_cfg trig_cfg = { 0 }; - reg_timer_r_time r_time0; - reg_timer_r_time r_time1; - unsigned char trig_wrap; - unsigned char time_wrap; - - r_time0 = REG_RD(timer, regi_timer0, r_time); - - D1(printk("start_timer_trig : %d us freq: %i div: %i\n", - delay_us, freq_index, div)); - /* Clear trig irq */ - intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); - intr_mask.trig = 0; - REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); - - /* Set timer values and check if trigger wraps. */ - /* r_time is 100MHz (10 ns resolution) */ - trig_wrap = (trig = r_time0 + delay_us*(1000/10)) < r_time0; - - timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = trig; - timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; - - /* Ack interrupt */ - ack_intr.trig = 1; - REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); - - /* Start timer */ - REG_WR(timer, regi_timer0, rw_trig, trig); - trig_cfg.tmr = regk_timer_time; - REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); - - /* Check if we have already passed the trig time */ - r_time1 = REG_RD(timer, regi_timer0, r_time); - time_wrap = r_time1 < r_time0; - - if ((trig_wrap && !time_wrap) || (r_time1 < trig)) { - /* No, Enable trig irq */ - intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); - intr_mask.trig = 1; - REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); - fast_timers_started++; - fast_timer_running = 1; - } else { - /* We have passed the time, disable trig point, ack intr */ - trig_cfg.tmr = regk_timer_off; - REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); - REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); - /* call the int routine */ - INIT_WORK(&fast_work, timer_trig_handler); - schedule_work(&fast_work); - } - -} - -/* In version 1.4 this function takes 27 - 50 us */ -void start_one_shot_timer(struct fast_timer *t, - fast_timer_function_type *function, - unsigned long data, - unsigned long delay_us, - const char *name) -{ - unsigned long flags; - struct fast_timer *tmp; - - D1(printk("sft %s %d us\n", name, delay_us)); - - local_irq_save(flags); - - do_gettimeofday_fast(&t->tv_set); - tmp = fast_timer_list; - -#ifdef FAST_TIMER_SANITY_CHECKS - /* Check so this is not in the list already... */ - while (tmp != NULL) { - if (tmp == t) { - printk(KERN_DEBUG - "timer name: %s data: 0x%08lX already " - "in list!\n", name, data); - sanity_failed++; - goto done; - } else - tmp = tmp->next; - } - tmp = fast_timer_list; -#endif - - t->delay_us = delay_us; - t->function = function; - t->data = data; - t->name = name; - - t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; - t->tv_expires.tv_jiff = t->tv_set.tv_jiff + delay_us / 1000000 / HZ; - if (t->tv_expires.tv_usec > 1000000) { - t->tv_expires.tv_usec -= 1000000; - t->tv_expires.tv_jiff += HZ; - } -#ifdef FAST_TIMER_LOG - timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; -#endif - fast_timers_added++; - - /* Check if this should timeout before anything else */ - if (tmp == NULL || fasttime_cmp(&t->tv_expires, &tmp->tv_expires) < 0) { - /* Put first in list and modify the timer value */ - t->prev = NULL; - t->next = fast_timer_list; - if (fast_timer_list) - fast_timer_list->prev = t; - fast_timer_list = t; -#ifdef FAST_TIMER_LOG - timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; -#endif - start_timer_trig(delay_us); - } else { - /* Put in correct place in list */ - while (tmp->next && - fasttime_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) - tmp = tmp->next; - /* Insert t after tmp */ - t->prev = tmp; - t->next = tmp->next; - if (tmp->next) - { - tmp->next->prev = t; - } - tmp->next = t; - } - - D2(printk("start_one_shot_timer: %d us done\n", delay_us)); - -done: - local_irq_restore(flags); -} /* start_one_shot_timer */ - -static inline int fast_timer_pending (const struct fast_timer * t) -{ - return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list); -} - -static inline int detach_fast_timer (struct fast_timer *t) -{ - struct fast_timer *next, *prev; - if (!fast_timer_pending(t)) - return 0; - next = t->next; - prev = t->prev; - if (next) - next->prev = prev; - if (prev) - prev->next = next; - else - fast_timer_list = next; - fast_timers_deleted++; - return 1; -} - -int del_fast_timer(struct fast_timer * t) -{ - unsigned long flags; - int ret; - - local_irq_save(flags); - ret = detach_fast_timer(t); - t->next = t->prev = NULL; - local_irq_restore(flags); - return ret; -} /* del_fast_timer */ - - -/* Interrupt routines or functions called in interrupt context */ - -/* Timer interrupt handler for trig interrupts */ - -static irqreturn_t -timer_trig_interrupt(int irq, void *dev_id) -{ - reg_timer_r_masked_intr masked_intr; - /* Check if the timer interrupt is for us (a trig int) */ - masked_intr = REG_RD(timer, regi_timer0, r_masked_intr); - if (!masked_intr.trig) - return IRQ_NONE; - timer_trig_handler(NULL); - return IRQ_HANDLED; -} - -static void timer_trig_handler(struct work_struct *work) -{ - reg_timer_rw_ack_intr ack_intr = { 0 }; - reg_timer_rw_intr_mask intr_mask; - reg_timer_rw_trig_cfg trig_cfg = { 0 }; - struct fast_timer *t; - fast_timer_function_type *f; - unsigned long d; - unsigned long flags; - - /* We keep interrupts disabled not only when we modify the - * fast timer list, but any time we hold a reference to a - * timer in the list, since del_fast_timer may be called - * from (another) interrupt context. Thus, the only time - * when interrupts are enabled is when calling the timer - * callback function. - */ - local_irq_save(flags); - - /* Clear timer trig interrupt */ - intr_mask = REG_RD(timer, regi_timer0, rw_intr_mask); - intr_mask.trig = 0; - REG_WR(timer, regi_timer0, rw_intr_mask, intr_mask); - - /* First stop timer, then ack interrupt */ - /* Stop timer */ - trig_cfg.tmr = regk_timer_off; - REG_WR(timer, regi_timer0, rw_trig_cfg, trig_cfg); - - /* Ack interrupt */ - ack_intr.trig = 1; - REG_WR(timer, regi_timer0, rw_ack_intr, ack_intr); - - fast_timer_running = 0; - fast_timer_ints++; - - t = fast_timer_list; - while (t) { - struct fasttime_t tv; - - /* Has it really expired? */ - do_gettimeofday_fast(&tv); - D1(printk(KERN_DEBUG - "t: %is %06ius\n", tv.tv_jiff, tv.tv_usec)); - - if (fasttime_cmp(&t->tv_expires, &tv) <= 0) { - /* Yes it has expired */ -#ifdef FAST_TIMER_LOG - timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; -#endif - fast_timers_expired++; - - /* Remove this timer before call, since it may reuse the timer */ - if (t->prev) - t->prev->next = t->next; - else - fast_timer_list = t->next; - if (t->next) - t->next->prev = t->prev; - t->prev = NULL; - t->next = NULL; - - /* Save function callback data before enabling - * interrupts, since the timer may be removed and we - * don't know how it was allocated (e.g. ->function - * and ->data may become overwritten after deletion - * if the timer was stack-allocated). - */ - f = t->function; - d = t->data; - - if (f != NULL) { - /* Run the callback function with interrupts - * enabled. */ - local_irq_restore(flags); - f(d); - local_irq_save(flags); - } else - DEBUG_LOG("!trimertrig %i function==NULL!\n", fast_timer_ints); - } else { - /* Timer is to early, let's set it again using the normal routines */ - D1(printk(".\n")); - } - - t = fast_timer_list; - if (t != NULL) { - /* Start next timer.. */ - long us = 0; - struct fasttime_t tv; - - do_gettimeofday_fast(&tv); - - /* time_after_eq takes care of wrapping */ - if (time_after_eq(t->tv_expires.tv_jiff, tv.tv_jiff)) - us = ((t->tv_expires.tv_jiff - tv.tv_jiff) * - 1000000 / HZ + t->tv_expires.tv_usec - - tv.tv_usec); - - if (us > 0) { - if (!fast_timer_running) { -#ifdef FAST_TIMER_LOG - timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; -#endif - start_timer_trig(us); - } - break; - } else { - /* Timer already expired, let's handle it better late than never. - * The normal loop handles it - */ - D1(printk("e! %d\n", us)); - } - } - } - - local_irq_restore(flags); - - if (!t) - D1(printk("ttrig stop!\n")); -} - -static void wake_up_func(unsigned long data) -{ - wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; - wake_up(sleep_wait_p); -} - - -/* Useful API */ - -void schedule_usleep(unsigned long us) -{ - struct fast_timer t; - wait_queue_head_t sleep_wait; - init_waitqueue_head(&sleep_wait); - - D1(printk("schedule_usleep(%d)\n", us)); - start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, - "usleep"); - /* Uninterruptible sleep on the fast timer. (The condition is - * somewhat redundant since the timer is what wakes us up.) */ - wait_event(sleep_wait, !fast_timer_pending(&t)); - - D1(printk("done schedule_usleep(%d)\n", us)); -} - -#ifdef CONFIG_PROC_FS -/* This value is very much based on testing */ -#define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300) - -static int proc_fasttimer_show(struct seq_file *m, void *v) -{ - unsigned long flags; - int i = 0; - int num_to_show; - struct fasttime_t tv; - struct fast_timer *t, *nextt; - - do_gettimeofday_fast(&tv); - - seq_printf(m, "Fast timers added: %i\n", fast_timers_added); - seq_printf(m, "Fast timers started: %i\n", fast_timers_started); - seq_printf(m, "Fast timer interrupts: %i\n", fast_timer_ints); - seq_printf(m, "Fast timers expired: %i\n", fast_timers_expired); - seq_printf(m, "Fast timers deleted: %i\n", fast_timers_deleted); - seq_printf(m, "Fast timer running: %s\n", - fast_timer_running ? "yes" : "no"); - seq_printf(m, "Current time: %lu.%06lu\n", - (unsigned long)tv.tv_jiff, - (unsigned long)tv.tv_usec); -#ifdef FAST_TIMER_SANITY_CHECKS - seq_printf(m, "Sanity failed: %i\n", sanity_failed); -#endif - seq_putc(m, '\n'); - -#ifdef DEBUG_LOG_INCLUDED - { - int end_i = debug_log_cnt; - i = 0; - - if (debug_log_cnt_wrapped) - i = debug_log_cnt; - - while ((i != end_i || debug_log_cnt_wrapped)) { - seq_printf(m, debug_log_string[i], debug_log_value[i]); - if (seq_has_overflowed(m)) - return 0; - i = (i+1) % DEBUG_LOG_MAX; - } - } - seq_putc(m, '\n'); -#endif - - num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started: - NUM_TIMER_STATS); - seq_printf(m, "Timers started: %i\n", fast_timers_started); - for (i = 0; i < num_to_show; i++) { - int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS; - -#if 1 //ndef FAST_TIMER_LOG - seq_printf(m, "div: %i delay: %i\n", - timer_div_settings[cur], - timer_delay_settings[cur]); -#endif -#ifdef FAST_TIMER_LOG - t = &timer_started_log[cur]; - seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu d: %6li us data: 0x%08lX\n", - t->name, - (unsigned long)t->tv_set.tv_jiff, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_jiff, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data); - if (seq_has_overflowed(m)) - return 0; -#endif - } - seq_putc(m, '\n'); - -#ifdef FAST_TIMER_LOG - num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added: - NUM_TIMER_STATS); - seq_printf(m, "Timers added: %i\n", fast_timers_added); - for (i = 0; i < num_to_show; i++) { - t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS]; - seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu d: %6li us data: 0x%08lX\n", - t->name, - (unsigned long)t->tv_set.tv_jiff, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_jiff, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data); - if (seq_has_overflowed(m)) - return 0; - } - seq_putc(m, '\n'); - - num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired: - NUM_TIMER_STATS); - seq_printf(m, "Timers expired: %i\n", fast_timers_expired); - for (i = 0; i < num_to_show; i++){ - t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS]; - seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu d: %6li us data: 0x%08lX\n", - t->name, - (unsigned long)t->tv_set.tv_jiff, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_jiff, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data); - if (seq_has_overflowed(m)) - return 0; - } - seq_putc(m, '\n'); -#endif - - seq_puts(m, "Active timers:\n"); - local_irq_save(flags); - t = fast_timer_list; - while (t != NULL){ - nextt = t->next; - local_irq_restore(flags); - seq_printf(m, "%-14s s: %6lu.%06lu e: %6lu.%06lu d: %6li us data: 0x%08lX\n", - t->name, - (unsigned long)t->tv_set.tv_jiff, - (unsigned long)t->tv_set.tv_usec, - (unsigned long)t->tv_expires.tv_jiff, - (unsigned long)t->tv_expires.tv_usec, - t->delay_us, - t->data); - if (seq_has_overflowed(m)) - return 0; - local_irq_save(flags); - if (t->next != nextt) - printk("timer removed!\n"); - t = nextt; - } - local_irq_restore(flags); - return 0; -} - -static int proc_fasttimer_open(struct inode *inode, struct file *file) -{ - return single_open_size(file, proc_fasttimer_show, PDE_DATA(inode), BIG_BUF_SIZE); -} - -static const struct file_operations proc_fasttimer_fops = { - .open = proc_fasttimer_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#endif /* PROC_FS */ - -#ifdef FAST_TIMER_TEST -static volatile unsigned long i = 0; -static volatile int num_test_timeout = 0; -static struct fast_timer tr[10]; -static int exp_num[10]; - -static struct fasttime_t tv_exp[100]; - -static void test_timeout(unsigned long data) -{ - do_gettimeofday_fast(&tv_exp[data]); - exp_num[data] = num_test_timeout; - - num_test_timeout++; -} - -static void test_timeout1(unsigned long data) -{ - do_gettimeofday_fast(&tv_exp[data]); - exp_num[data] = num_test_timeout; - if (data < 7) - { - start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1"); - i++; - } - num_test_timeout++; -} - -DP( -static char buf0[2000]; -static char buf1[2000]; -static char buf2[2000]; -static char buf3[2000]; -static char buf4[2000]; -); - -static char buf5[6000]; -static int j_u[1000]; - -static void fast_timer_test(void) -{ - int prev_num; - int j; - - struct fasttime_t tv, tv0, tv1, tv2; - - printk("fast_timer_test() start\n"); - do_gettimeofday_fast(&tv); - - for (j = 0; j < 1000; j++) - { - j_u[j] = GET_JIFFIES_USEC(); - } - for (j = 0; j < 100; j++) - { - do_gettimeofday_fast(&tv_exp[j]); - } - printk(KERN_DEBUG "fast_timer_test() %is %06i\n", tv.tv_jiff, tv.tv_usec); - - for (j = 0; j < 1000; j++) - { - printk(KERN_DEBUG "%i %i %i %i %i\n", - j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); - j += 4; - } - for (j = 0; j < 100; j++) - { - printk(KERN_DEBUG "%i.%i %i.%i %i.%i %i.%i %i.%i\n", - tv_exp[j].tv_jiff, tv_exp[j].tv_usec, - tv_exp[j+1].tv_jiff, tv_exp[j+1].tv_usec, - tv_exp[j+2].tv_jiff, tv_exp[j+2].tv_usec, - tv_exp[j+3].tv_jiff, tv_exp[j+3].tv_usec, - tv_exp[j+4].tv_jiff, tv_exp[j+4].tv_usec); - j += 4; - } - do_gettimeofday_fast(&tv0); - start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0"); - DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0)); - i++; - start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1"); - DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0)); - i++; - start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2"); - DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0)); - i++; - start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3"); - DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0)); - i++; - start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx"); - DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0)); - i++; - do_gettimeofday_fast(&tv1); - - proc_fasttimer_read(buf5, NULL, 0, 0, 0); - - prev_num = num_test_timeout; - while (num_test_timeout < i) - { - if (num_test_timeout != prev_num) - prev_num = num_test_timeout; - } - do_gettimeofday_fast(&tv2); - printk(KERN_INFO "Timers started %is %06i\n", - tv0.tv_jiff, tv0.tv_usec); - printk(KERN_INFO "Timers started at %is %06i\n", - tv1.tv_jiff, tv1.tv_usec); - printk(KERN_INFO "Timers done %is %06i\n", - tv2.tv_jiff, tv2.tv_usec); - DP(printk("buf0:\n"); - printk(buf0); - printk("buf1:\n"); - printk(buf1); - printk("buf2:\n"); - printk(buf2); - printk("buf3:\n"); - printk(buf3); - printk("buf4:\n"); - printk(buf4); - ); - printk("buf5:\n"); - printk(buf5); - - printk("timers set:\n"); - for(j = 0; j<i; j++) - { - struct fast_timer *t = &tr[j]; - printk("%-10s set: %6is %06ius exp: %6is %06ius " - "data: 0x%08X func: 0x%08X\n", - t->name, - t->tv_set.tv_jiff, - t->tv_set.tv_usec, - t->tv_expires.tv_jiff, - t->tv_expires.tv_usec, - t->data, - t->function - ); - - printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", - t->delay_us, - tv_exp[j].tv_jiff, - tv_exp[j].tv_usec, - exp_num[j], - (tv_exp[j].tv_jiff - t->tv_expires.tv_jiff) * - 1000000 + tv_exp[j].tv_usec - - t->tv_expires.tv_usec); - } - proc_fasttimer_read(buf5, NULL, 0, 0, 0); - printk("buf5 after all done:\n"); - printk(buf5); - printk("fast_timer_test() done\n"); -} -#endif - - -int fast_timer_init(void) -{ - /* For some reason, request_irq() hangs when called froom time_init() */ - if (!fast_timer_is_init) - { - printk("fast_timer_init()\n"); - -#ifdef CONFIG_PROC_FS - proc_create("fasttimer", 0, NULL, &proc_fasttimer_fops); -#endif /* PROC_FS */ - if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt, - IRQF_SHARED, - "fast timer int", &fast_timer_list)) - printk(KERN_ERR "err: fasttimer irq\n"); - fast_timer_is_init = 1; -#ifdef FAST_TIMER_TEST - printk("do test\n"); - fast_timer_test(); -#endif - } - return 0; -} -__initcall(fast_timer_init); diff --git a/arch/cris/arch-v32/kernel/head.S b/arch/cris/arch-v32/kernel/head.S deleted file mode 100644 index 92f9fb1f6845..000000000000 --- a/arch/cris/arch-v32/kernel/head.S +++ /dev/null @@ -1,439 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * CRISv32 kernel startup code. - * - * Copyright (C) 2003, Axis Communications AB - */ - -#include <linux/init.h> - -#define ASSEMBLER_MACROS_ONLY - -/* - * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so - * -traditional must not be used when assembling this file. - */ -#include <arch/memmap.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/intr_vect.h> -#include <hwregs/asm/mmu_defs_asm.h> -#include <hwregs/asm/reg_map_asm.h> -#include <mach/startup.inc> - -#define CRAMFS_MAGIC 0x28cd3d45 -#define JHEAD_MAGIC 0x1FF528A6 -#define JHEAD_SIZE 8 -#define RAM_INIT_MAGIC 0x56902387 -#define COMMAND_LINE_MAGIC 0x87109563 -#define NAND_BOOT_MAGIC 0x9a9db001 - - ;; NOTE: R8 and R9 carry information from the decompressor (if the - ;; kernel was compressed). They must not be used in the code below - ;; until they are read! - - ;; Exported symbols. - .global etrax_irv - .global romfs_start - .global romfs_length - .global romfs_in_flash - .global nand_boot - .global swapper_pg_dir - - __HEAD -tstart: - ;; This is the entry point of the kernel. The CPU is currently in - ;; supervisor mode. - ;; - ;; 0x00000000 if flash. - ;; 0x40004000 if DRAM. - ;; - di - - START_CLOCKS - - SETUP_WAIT_STATES - - GIO_INIT - - ;; Setup and enable the MMU. Use same configuration for both the data - ;; and the instruction MMU. - ;; - ;; Note; 3 cycles is needed for a bank-select to take effect. Further; - ;; bank 1 is the instruction MMU, bank 2 is the data MMU. - -#ifdef CONFIG_CRIS_MACH_ARTPEC3 - move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ - | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ - | REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 5) \ - | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 -#else - move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ - | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ - | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 -#endif - - ;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00. - move.d REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 4) \ - | REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0), $r1 - - ;; Enable certain page protections and setup linear mapping - ;; for f,e,c,b,4,0. - - ;; ARTPEC-3: - ;; c,d used for linear kernel mapping, up to 512 MB - ;; e used for vmalloc - ;; f unused, but page mapped to get page faults - - ;; ETRAX FS: - ;; c used for linear kernel mapping, up to 256 MB - ;; d used for vmalloc - ;; e,f used for memory-mapped NOR flash - -#ifdef CONFIG_CRIS_MACH_ARTPEC3 - move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ - | REG_STATE(mmu, rw_mm_cfg, acc, on) \ - | REG_STATE(mmu, rw_mm_cfg, ex, on) \ - | REG_STATE(mmu, rw_mm_cfg, inv, on) \ - | REG_STATE(mmu, rw_mm_cfg, seg_f, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_e, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_d, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_a, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_9, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_8, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_7, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_6, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_5, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_4, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_3, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_2, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_1, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2 -#else - move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ - | REG_STATE(mmu, rw_mm_cfg, acc, on) \ - | REG_STATE(mmu, rw_mm_cfg, ex, on) \ - | REG_STATE(mmu, rw_mm_cfg, inv, on) \ - | REG_STATE(mmu, rw_mm_cfg, seg_f, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_e, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_d, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_a, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_9, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_8, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_7, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_6, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_5, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_4, linear) \ - | REG_STATE(mmu, rw_mm_cfg, seg_3, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_2, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_1, page) \ - | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2 -#endif - - ;; Update instruction MMU. - move 1, $srs - nop - nop - nop - move $r0, $s2 ; kbase_hi. - move $r1, $s1 ; kbase_lo. - move $r2, $s0 ; mm_cfg, virtual memory configuration. - - ;; Update data MMU. - move 2, $srs - nop - nop - nop - move $r0, $s2 ; kbase_hi. - move $r1, $s1 ; kbase_lo - move $r2, $s0 ; mm_cfg, virtual memory configuration. - - ;; Enable data and instruction MMU. - move 0, $srs - moveq 0xf, $r0 ; IMMU, DMMU, DCache, Icache on - nop - nop - nop - move $r0, $s0 - nop - nop - nop - - ; Check if starting from DRAM (network->RAM boot or unpacked - ; compressed kernel), or directly from flash. - lapcq ., $r0 - and.d 0x7fffffff, $r0 ; Mask off the non-cache bit. - cmp.d 0x10000, $r0 ; Arbitrary, something above this code. - blo _inflash0 - nop - - jump _inram ; Jump to cached RAM. - nop - - ;; Jumpgate. -_inflash0: - jump _inflash - nop - - ;; Put the following in a section so that storage for it can be - ;; reclaimed after init is finished. - __INIT - -_inflash: - - ;; Initialize DRAM. - cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? - beq _dram_initialized - nop - -#if defined CONFIG_ETRAXFS -#include "../mach-fs/dram_init.S" -#elif defined CONFIG_CRIS_MACH_ARTPEC3 -#include "../mach-a3/dram_init.S" -#else -#error Only ETRAXFS and ARTPEC-3 supported! -#endif - - -_dram_initialized: - ;; Copy the text and data section to DRAM. This depends on that the - ;; variables used below are correctly set up by the linker script. - ;; The calculated value stored in R4 is used below. - ;; Leave the cramfs file system (piggybacked after the kernel) in flash. - moveq 0, $r0 ; Source. - move.d text_start, $r1 ; Destination. - move.d __vmlinux_end, $r2 - move.d $r2, $r4 - sub.d $r1, $r4 -1: move.w [$r0+], $r3 - move.w $r3, [$r1+] - cmp.d $r2, $r1 - blo 1b - nop - - ;; Check for cramfs. - moveq 0, $r0 - move.d romfs_length, $r1 - move.d $r0, [$r1] - move.d [$r4], $r0 ; cramfs_super.magic - cmp.d CRAMFS_MAGIC, $r0 - bne 1f - nop - - ;; Set length and start of cramfs, set romfs_in_flash flag - addoq +4, $r4, $acr - move.d [$acr], $r0 - move.d romfs_length, $r1 - move.d $r0, [$r1] - add.d 0xf0000000, $r4 ; Add cached flash start in virtual memory. - move.d romfs_start, $r1 - move.d $r4, [$r1] -1: moveq 1, $r0 - move.d romfs_in_flash, $r1 - move.d $r0, [$r1] - - jump _start_it ; Jump to cached code. - nop - -_inram: - ;; Check if booting from NAND flash; if so, set appropriate flags - ;; and move on. - cmp.d NAND_BOOT_MAGIC, $r12 - bne move_cramfs ; not nand, jump - moveq 1, $r0 - move.d nand_boot, $r1 ; tell axisflashmap we're booting from NAND - move.d $r0, [$r1] - moveq 0, $r0 ; tell axisflashmap romfs is not in - move.d romfs_in_flash, $r1 ; (directly accessed) flash - move.d $r0, [$r1] - jump _start_it ; continue with boot - nop - -move_cramfs: - ;; kernel is in DRAM. - ;; Must figure out if there is a piggybacked rootfs image or not. - ;; Set romfs_length to 0 => no rootfs image available by default. - moveq 0, $r0 - move.d romfs_length, $r1 - move.d $r0, [$r1] - - ;; The kernel could have been unpacked to DRAM by the loader, but - ;; the cramfs image could still be in the flash immediately - ;; following the compressed kernel image. The loader passes the address - ;; of the byte succeeding the last compressed byte in the flash in - ;; register R9 when starting the kernel. - cmp.d 0x0ffffff8, $r9 - bhs _no_romfs_in_flash ; R9 points outside the flash area. - nop - ;; cramfs rootfs might to be in flash. Check for it. - move.d [$r9], $r0 ; cramfs_super.magic - cmp.d CRAMFS_MAGIC, $r0 - bne _no_romfs_in_flash - nop - - ;; found cramfs in flash. set address and size, and romfs_in_flash flag. - addoq +4, $r9, $acr - move.d [$acr], $r0 - move.d romfs_length, $r1 - move.d $r0, [$r1] - add.d 0xf0000000, $r9 ; Add cached flash start in virtual memory. - move.d romfs_start, $r1 - move.d $r9, [$r1] - moveq 1, $r0 - move.d romfs_in_flash, $r1 - move.d $r0, [$r1] - - jump _start_it ; Jump to cached code. - nop - -_no_romfs_in_flash: - ;; No romfs in flash, so look for cramfs, or jffs2 with jhead, - ;; after kernel in RAM, as is the case with network->RAM boot. - ;; For cramfs, partition starts with magic and length. - ;; For jffs2, a jhead is prepended which contains with magic and length. - ;; The jhead is not part of the jffs2 partition however. - move.d __bss_start, $r0 - move.d [$r0], $r1 - cmp.d CRAMFS_MAGIC, $r1 ; cramfs magic? - beq 2f ; yes, jump - nop - cmp.d JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic? - bne 4f ; no, skip copy - nop - addq 4, $r0 ; location of jffs2 size - move.d [$r0+], $r2 ; fetch jffs2 size -> r2 - ; r0 now points to start of jffs2 - ba 3f - nop -2: - addoq +4, $r0, $acr ; location of cramfs size - move.d [$acr], $r2 ; fetch cramfs size -> r2 - ; r0 still points to start of cramfs -3: - ;; Now, move the root fs to after kernel's BSS - - move.d _end, $r1 ; start of cramfs -> r1 - move.d romfs_start, $r3 - move.d $r1, [$r3] ; store at romfs_start (for axisflashmap) - move.d romfs_length, $r3 - move.d $r2, [$r3] ; store size at romfs_length - - add.d $r2, $r0 ; copy from end and downwards - add.d $r2, $r1 - - lsrq 1, $r2 ; Size is in bytes, we copy words. - addq 1, $r2 -1: - move.w [$r0], $r3 - move.w $r3, [$r1] - subq 2, $r0 - subq 2, $r1 - subq 1, $r2 - bne 1b - nop - -4: - ;; BSS move done. - ;; Clear romfs_in_flash flag, as we now know romfs is in DRAM - ;; Also clear nand_boot flag; if we got here, we know we've not - ;; booted from NAND flash. - moveq 0, $r0 - move.d romfs_in_flash, $r1 - move.d $r0, [$r1] - moveq 0, $r0 - move.d nand_boot, $r1 - move.d $r0, [$r1] - - jump _start_it ; Jump to cached code. - nop - -_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+], $r1 - move.b $r1, [$r10+] - subq 1, $r13 - bne 1b - nop - -no_command_line: - - ;; The kernel stack contains a task structure for each task. This - ;; the initial kernel stack is in the same page as the init_task, - ;; but starts at the top of the page, i.e. + 8192 bytes. - move.d init_thread_union + 8192, $sp - move.d ebp_start, $r0 ; Defined in linker-script. - move $r0, $ebp - move.d etrax_irv, $r1 ; Set the exception base register and pointer. - move.d $r0, [$r1] - - ;; Clear the BSS region from _bss_start to _end. - move.d __bss_start, $r0 - move.d _end, $r1 -1: clear.d [$r0+] - cmp.d $r1, $r0 - blo 1b - nop - - ; Initialize registers to increase determinism - move.d __bss_start, $r0 - movem [$r0], $r13 - -#ifdef CONFIG_ETRAX_L2CACHE - jsr l2cache_init - nop -#endif - - jump start_kernel ; Jump to start_kernel() in init/main.c. - nop - - .data -etrax_irv: - .dword 0 - -; Variables for communication with the Axis flash map driver (axisflashmap), -; and for setting up memory in arch/cris/kernel/setup.c . - -; romfs_start is set to the start of the root file system, if it exists -; in directly accessible memory (i.e. NOR Flash when booting from Flash, -; or RAM when booting directly from a network-downloaded RAM image) -romfs_start: - .dword 0 - -; romfs_length is set to the size of the root file system image, if it exists -; in directly accessible memory (see romfs_start). Otherwise it is set to 0. -romfs_length: - .dword 0 - -; romfs_in_flash is set to 1 if the root file system resides in directly -; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot -; or NAND flash boot. -romfs_in_flash: - .dword 0 - -; nand_boot is set to 1 when the kernel has been booted from NAND flash -nand_boot: - .dword 0 - -swapper_pg_dir = 0xc0002000 - - .section ".init.data", "aw" - -#if defined CONFIG_ETRAXFS -#include "../mach-fs/hw_settings.S" -#elif defined CONFIG_CRIS_MACH_ARTPEC3 -#include "../mach-a3/hw_settings.S" -#else -#error Only ETRAXFS and ARTPEC-3 supported! -#endif diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c deleted file mode 100644 index 414afd543232..000000000000 --- a/arch/cris/arch-v32/kernel/irq.c +++ /dev/null @@ -1,520 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2003, Axis Communications AB. - */ - -#include <asm/irq.h> -#include <linux/irq.h> -#include <linux/interrupt.h> -#include <linux/smp.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/profile.h> -#include <linux/of.h> -#include <linux/of_irq.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/threads.h> -#include <linux/spinlock.h> -#include <linux/kernel_stat.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/intr_vect.h> -#include <hwregs/intr_vect_defs.h> - -#define CPU_FIXED -1 - -/* IRQ masks (refer to comment for crisv32_do_multiple) */ -#if TIMER0_INTR_VECT - FIRST_IRQ < 32 -#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ)) -#undef TIMER_VECT1 -#else -#define TIMER_MASK (1 << (TIMER0_INTR_VECT - FIRST_IRQ - 32)) -#define TIMER_VECT1 -#endif -#ifdef CONFIG_ETRAX_KGDB -#if defined(CONFIG_ETRAX_KGDB_PORT0) -#define IGNOREMASK (1 << (SER0_INTR_VECT - FIRST_IRQ)) -#elif defined(CONFIG_ETRAX_KGDB_PORT1) -#define IGNOREMASK (1 << (SER1_INTR_VECT - FIRST_IRQ)) -#elif defined(CONFIG_ETRAX_KGDB_PORT2) -#define IGNOREMASK (1 << (SER2_INTR_VECT - FIRST_IRQ)) -#elif defined(CONFIG_ETRAX_KGDB_PORT3) -#define IGNOREMASK (1 << (SER3_INTR_VECT - FIRST_IRQ)) -#endif -#endif - -DEFINE_SPINLOCK(irq_lock); - -struct cris_irq_allocation -{ - int cpu; /* The CPU to which the IRQ is currently allocated. */ - cpumask_t mask; /* The CPUs to which the IRQ may be allocated. */ -}; - -struct cris_irq_allocation irq_allocations[NR_REAL_IRQS] = - { [0 ... NR_REAL_IRQS - 1] = {0, CPU_MASK_ALL} }; - -static unsigned long irq_regs[NR_CPUS] = -{ - regi_irq, -}; - -#if NR_REAL_IRQS > 32 -#define NBR_REGS 2 -#else -#define NBR_REGS 1 -#endif - -unsigned long cpu_irq_counters[NR_CPUS]; -unsigned long irq_counters[NR_REAL_IRQS]; - -/* From irq.c. */ -extern void weird_irq(void); - -/* From entry.S. */ -extern void system_call(void); -extern void nmi_interrupt(void); -extern void multiple_interrupt(void); -extern void gdb_handle_exception(void); -extern void i_mmu_refill(void); -extern void i_mmu_invalid(void); -extern void i_mmu_access(void); -extern void i_mmu_execute(void); -extern void d_mmu_refill(void); -extern void d_mmu_invalid(void); -extern void d_mmu_access(void); -extern void d_mmu_write(void); - -/* From kgdb.c. */ -extern void kgdb_init(void); -extern void breakpoint(void); - -/* From traps.c. */ -extern void breakh_BUG(void); - -/* - * Build the IRQ handler stubs using macros from irq.h. - */ -#ifdef CONFIG_CRIS_MACH_ARTPEC3 -BUILD_TIMER_IRQ(0x31, 0) -#else -BUILD_IRQ(0x31) -#endif -BUILD_IRQ(0x32) -BUILD_IRQ(0x33) -BUILD_IRQ(0x34) -BUILD_IRQ(0x35) -BUILD_IRQ(0x36) -BUILD_IRQ(0x37) -BUILD_IRQ(0x38) -BUILD_IRQ(0x39) -BUILD_IRQ(0x3a) -BUILD_IRQ(0x3b) -BUILD_IRQ(0x3c) -BUILD_IRQ(0x3d) -BUILD_IRQ(0x3e) -BUILD_IRQ(0x3f) -BUILD_IRQ(0x40) -BUILD_IRQ(0x41) -BUILD_IRQ(0x42) -BUILD_IRQ(0x43) -BUILD_IRQ(0x44) -BUILD_IRQ(0x45) -BUILD_IRQ(0x46) -BUILD_IRQ(0x47) -BUILD_IRQ(0x48) -BUILD_IRQ(0x49) -BUILD_IRQ(0x4a) -#ifdef CONFIG_ETRAXFS -BUILD_TIMER_IRQ(0x4b, 0) -#else -BUILD_IRQ(0x4b) -#endif -BUILD_IRQ(0x4c) -BUILD_IRQ(0x4d) -BUILD_IRQ(0x4e) -BUILD_IRQ(0x4f) -BUILD_IRQ(0x50) -#if MACH_IRQS > 32 -BUILD_IRQ(0x51) -BUILD_IRQ(0x52) -BUILD_IRQ(0x53) -BUILD_IRQ(0x54) -BUILD_IRQ(0x55) -BUILD_IRQ(0x56) -BUILD_IRQ(0x57) -BUILD_IRQ(0x58) -BUILD_IRQ(0x59) -BUILD_IRQ(0x5a) -BUILD_IRQ(0x5b) -BUILD_IRQ(0x5c) -BUILD_IRQ(0x5d) -BUILD_IRQ(0x5e) -BUILD_IRQ(0x5f) -BUILD_IRQ(0x60) -BUILD_IRQ(0x61) -BUILD_IRQ(0x62) -BUILD_IRQ(0x63) -BUILD_IRQ(0x64) -BUILD_IRQ(0x65) -BUILD_IRQ(0x66) -BUILD_IRQ(0x67) -BUILD_IRQ(0x68) -BUILD_IRQ(0x69) -BUILD_IRQ(0x6a) -BUILD_IRQ(0x6b) -BUILD_IRQ(0x6c) -BUILD_IRQ(0x6d) -BUILD_IRQ(0x6e) -BUILD_IRQ(0x6f) -BUILD_IRQ(0x70) -#endif - -/* Pointers to the low-level handlers. */ -static void (*interrupt[MACH_IRQS])(void) = { - IRQ0x31_interrupt, IRQ0x32_interrupt, IRQ0x33_interrupt, - IRQ0x34_interrupt, IRQ0x35_interrupt, IRQ0x36_interrupt, - IRQ0x37_interrupt, IRQ0x38_interrupt, IRQ0x39_interrupt, - IRQ0x3a_interrupt, IRQ0x3b_interrupt, IRQ0x3c_interrupt, - IRQ0x3d_interrupt, IRQ0x3e_interrupt, IRQ0x3f_interrupt, - IRQ0x40_interrupt, IRQ0x41_interrupt, IRQ0x42_interrupt, - IRQ0x43_interrupt, IRQ0x44_interrupt, IRQ0x45_interrupt, - IRQ0x46_interrupt, IRQ0x47_interrupt, IRQ0x48_interrupt, - IRQ0x49_interrupt, IRQ0x4a_interrupt, IRQ0x4b_interrupt, - IRQ0x4c_interrupt, IRQ0x4d_interrupt, IRQ0x4e_interrupt, - IRQ0x4f_interrupt, IRQ0x50_interrupt, -#if MACH_IRQS > 32 - IRQ0x51_interrupt, IRQ0x52_interrupt, IRQ0x53_interrupt, - IRQ0x54_interrupt, IRQ0x55_interrupt, IRQ0x56_interrupt, - IRQ0x57_interrupt, IRQ0x58_interrupt, IRQ0x59_interrupt, - IRQ0x5a_interrupt, IRQ0x5b_interrupt, IRQ0x5c_interrupt, - IRQ0x5d_interrupt, IRQ0x5e_interrupt, IRQ0x5f_interrupt, - IRQ0x60_interrupt, IRQ0x61_interrupt, IRQ0x62_interrupt, - IRQ0x63_interrupt, IRQ0x64_interrupt, IRQ0x65_interrupt, - IRQ0x66_interrupt, IRQ0x67_interrupt, IRQ0x68_interrupt, - IRQ0x69_interrupt, IRQ0x6a_interrupt, IRQ0x6b_interrupt, - IRQ0x6c_interrupt, IRQ0x6d_interrupt, IRQ0x6e_interrupt, - IRQ0x6f_interrupt, IRQ0x70_interrupt, -#endif -}; - -void -block_irq(int irq, int cpu) -{ - int intr_mask; - unsigned long flags; - - spin_lock_irqsave(&irq_lock, flags); - /* Remember, 1 let thru, 0 block. */ - if (irq - FIRST_IRQ < 32) { - intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], - rw_mask, 0); - intr_mask &= ~(1 << (irq - FIRST_IRQ)); - REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, - 0, intr_mask); - } else { - intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], - rw_mask, 1); - intr_mask &= ~(1 << (irq - FIRST_IRQ - 32)); - REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, - 1, intr_mask); - } - spin_unlock_irqrestore(&irq_lock, flags); -} - -void -unblock_irq(int irq, int cpu) -{ - int intr_mask; - unsigned long flags; - - spin_lock_irqsave(&irq_lock, flags); - /* Remember, 1 let thru, 0 block. */ - if (irq - FIRST_IRQ < 32) { - intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], - rw_mask, 0); - intr_mask |= (1 << (irq - FIRST_IRQ)); - REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, - 0, intr_mask); - } else { - intr_mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], - rw_mask, 1); - intr_mask |= (1 << (irq - FIRST_IRQ - 32)); - REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, - 1, intr_mask); - } - spin_unlock_irqrestore(&irq_lock, flags); -} - -/* Find out which CPU the irq should be allocated to. */ -static int irq_cpu(int irq) -{ - int cpu; - unsigned long flags; - - spin_lock_irqsave(&irq_lock, flags); - cpu = irq_allocations[irq - FIRST_IRQ].cpu; - - /* Fixed interrupts stay on the local CPU. */ - if (cpu == CPU_FIXED) - { - spin_unlock_irqrestore(&irq_lock, flags); - return smp_processor_id(); - } - - - /* Let the interrupt stay if possible */ - if (cpumask_test_cpu(cpu, &irq_allocations[irq - FIRST_IRQ].mask)) - goto out; - - /* IRQ must be moved to another CPU. */ - cpu = cpumask_first(&irq_allocations[irq - FIRST_IRQ].mask); - irq_allocations[irq - FIRST_IRQ].cpu = cpu; -out: - spin_unlock_irqrestore(&irq_lock, flags); - return cpu; -} - -void crisv32_mask_irq(int irq) -{ - int cpu; - - for (cpu = 0; cpu < NR_CPUS; cpu++) - block_irq(irq, cpu); -} - -void crisv32_unmask_irq(int irq) -{ - unblock_irq(irq, irq_cpu(irq)); -} - - -static void enable_crisv32_irq(struct irq_data *data) -{ - crisv32_unmask_irq(data->irq); -} - -static void disable_crisv32_irq(struct irq_data *data) -{ - crisv32_mask_irq(data->irq); -} - -static int set_affinity_crisv32_irq(struct irq_data *data, - const struct cpumask *dest, bool force) -{ - unsigned long flags; - - spin_lock_irqsave(&irq_lock, flags); - irq_allocations[data->irq - FIRST_IRQ].mask = *dest; - spin_unlock_irqrestore(&irq_lock, flags); - return 0; -} - -static struct irq_chip crisv32_irq_type = { - .name = "CRISv32", - .irq_shutdown = disable_crisv32_irq, - .irq_enable = enable_crisv32_irq, - .irq_disable = disable_crisv32_irq, - .irq_set_affinity = set_affinity_crisv32_irq, -}; - -void -set_exception_vector(int n, irqvectptr addr) -{ - etrax_irv->v[n] = (irqvectptr) addr; -} - -extern void do_IRQ(int irq, struct pt_regs * regs); - -void -crisv32_do_IRQ(int irq, int block, struct pt_regs* regs) -{ - /* Interrupts that may not be moved to another CPU may - * skip blocking. This is currently only valid for the - * timer IRQ and the IPI and is used for the timer - * interrupt to avoid watchdog starvation. - */ - if (!block) { - do_IRQ(irq, regs); - return; - } - - block_irq(irq, smp_processor_id()); - do_IRQ(irq, regs); - - unblock_irq(irq, irq_cpu(irq)); -} - -/* If multiple interrupts occur simultaneously we get a multiple - * interrupt from the CPU and software has to sort out which - * interrupts that happened. There are two special cases here: - * - * 1. Timer interrupts may never be blocked because of the - * watchdog (refer to comment in include/asr/arch/irq.h) - * 2. GDB serial port IRQs are unhandled here and will be handled - * as a single IRQ when it strikes again because the GDB - * stubb wants to save the registers in its own fashion. - */ -void -crisv32_do_multiple(struct pt_regs* regs) -{ - int cpu; - int mask; - int masked[NBR_REGS]; - int bit; - int i; - - cpu = smp_processor_id(); - - /* An extra irq_enter here to prevent softIRQs to run after - * each do_IRQ. This will decrease the interrupt latency. - */ - irq_enter(); - - for (i = 0; i < NBR_REGS; i++) { - /* Get which IRQs that happened. */ - masked[i] = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], - r_masked_vect, i); - - /* Calculate new IRQ mask with these IRQs disabled. */ - mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i); - mask &= ~masked[i]; - - /* Timer IRQ is never masked */ -#ifdef TIMER_VECT1 - if ((i == 1) && (masked[0] & TIMER_MASK)) - mask |= TIMER_MASK; -#else - if ((i == 0) && (masked[0] & TIMER_MASK)) - mask |= TIMER_MASK; -#endif - /* Block all the IRQs */ - REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask); - - /* Check for timer IRQ and handle it special. */ -#ifdef TIMER_VECT1 - if ((i == 1) && (masked[i] & TIMER_MASK)) { - masked[i] &= ~TIMER_MASK; - do_IRQ(TIMER0_INTR_VECT, regs); - } -#else - if ((i == 0) && (masked[i] & TIMER_MASK)) { - masked[i] &= ~TIMER_MASK; - do_IRQ(TIMER0_INTR_VECT, regs); - } -#endif - } - -#ifdef IGNORE_MASK - /* Remove IRQs that can't be handled as multiple. */ - masked[0] &= ~IGNORE_MASK; -#endif - - /* Handle the rest of the IRQs. */ - for (i = 0; i < NBR_REGS; i++) { - for (bit = 0; bit < 32; bit++) { - if (masked[i] & (1 << bit)) - do_IRQ(bit + FIRST_IRQ + i*32, regs); - } - } - - /* Unblock all the IRQs. */ - for (i = 0; i < NBR_REGS; i++) { - mask = REG_RD_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i); - mask |= masked[i]; - REG_WR_INT_VECT(intr_vect, irq_regs[cpu], rw_mask, i, mask); - } - - /* This irq_exit() will trigger the soft IRQs. */ - irq_exit(); -} - -static int crisv32_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw_irq_num) -{ - irq_set_chip_and_handler(virq, &crisv32_irq_type, handle_simple_irq); - - return 0; -} - -static struct irq_domain_ops crisv32_irq_ops = { - .map = crisv32_irq_map, - .xlate = irq_domain_xlate_onecell, -}; - -/* - * This is called by start_kernel. It fixes the IRQ masks and setup the - * interrupt vector table to point to bad_interrupt pointers. - */ -void __init -init_IRQ(void) -{ - int i; - int j; - reg_intr_vect_rw_mask vect_mask = {0}; - struct device_node *np; - struct irq_domain *domain; - - /* Clear all interrupts masks. */ - for (i = 0; i < NBR_REGS; i++) - REG_WR_VECT(intr_vect, regi_irq, rw_mask, i, vect_mask); - - for (i = 0; i < 256; i++) - etrax_irv->v[i] = weird_irq; - - np = of_find_compatible_node(NULL, NULL, "axis,crisv32-intc"); - domain = irq_domain_add_legacy(np, NBR_INTR_VECT - FIRST_IRQ, - FIRST_IRQ, FIRST_IRQ, - &crisv32_irq_ops, NULL); - BUG_ON(!domain); - irq_set_default_host(domain); - of_node_put(np); - - for (i = FIRST_IRQ, j = 0; j < NBR_INTR_VECT && j < MACH_IRQS; i++, j++) - set_exception_vector(i, interrupt[j]); - - /* Mark Timer and IPI IRQs as CPU local */ - irq_allocations[TIMER0_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; - irq_set_status_flags(TIMER0_INTR_VECT, IRQ_PER_CPU); - irq_allocations[IPI_INTR_VECT - FIRST_IRQ].cpu = CPU_FIXED; - irq_set_status_flags(IPI_INTR_VECT, IRQ_PER_CPU); - - set_exception_vector(0x00, nmi_interrupt); - set_exception_vector(0x30, multiple_interrupt); - - /* Set up handler for various MMU bus faults. */ - set_exception_vector(0x04, i_mmu_refill); - set_exception_vector(0x05, i_mmu_invalid); - set_exception_vector(0x06, i_mmu_access); - set_exception_vector(0x07, i_mmu_execute); - set_exception_vector(0x08, d_mmu_refill); - set_exception_vector(0x09, d_mmu_invalid); - set_exception_vector(0x0a, d_mmu_access); - set_exception_vector(0x0b, d_mmu_write); - -#ifdef CONFIG_BUG - /* Break 14 handler, used to implement cheap BUG(). */ - set_exception_vector(0x1e, breakh_BUG); -#endif - - /* The system-call trap is reached by "break 13". */ - set_exception_vector(0x1d, system_call); - - /* Exception handlers for debugging, both user-mode and kernel-mode. */ - - /* Break 8. */ - set_exception_vector(0x18, gdb_handle_exception); - /* Hardware single step. */ - set_exception_vector(0x3, gdb_handle_exception); - /* Hardware breakpoint. */ - set_exception_vector(0xc, gdb_handle_exception); - -#ifdef CONFIG_ETRAX_KGDB - kgdb_init(); - /* Everything is set up; now trap the kernel. */ - breakpoint(); -#endif -} - diff --git a/arch/cris/arch-v32/kernel/kgdb.c b/arch/cris/arch-v32/kernel/kgdb.c deleted file mode 100644 index 3d6f516763a5..000000000000 --- a/arch/cris/arch-v32/kernel/kgdb.c +++ /dev/null @@ -1,1593 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * arch/cris/arch-v32/kernel/kgdb.c - * - * CRIS v32 version by Orjan Friberg, Axis Communications AB. - * - * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), - * - * Originally written by Glenn Engel, Lake Stevens Instrument Division - * - * Contributed by HP Systems - * - * Modified for SPARC by Stu Grossman, Cygnus Support. - * - * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse - * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de> - * - * Copyright (C) 1995 Andreas Busse - */ - -/* FIXME: Check the documentation. */ - -/* - * kgdb usage notes: - * ----------------- - * - * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be - * built with different gcc flags: "-g" is added to get debug infos, and - * "-fomit-frame-pointer" is omitted to make debugging easier. Since the - * resulting kernel will be quite big (approx. > 7 MB), it will be stripped - * before compresion. Such a kernel will behave just as usually, except if - * given a "debug=<device>" command line option. (Only serial devices are - * allowed for <device>, i.e. no printers or the like; possible values are - * machine depedend and are the same as for the usual debug device, the one - * for logging kernel messages.) If that option is given and the device can be - * initialized, the kernel will connect to the remote gdb in trap_init(). The - * serial parameters are fixed to 8N1 and 115200 bps, for easyness of - * implementation. - * - * To start a debugging session, start that gdb with the debugging kernel - * image (the one with the symbols, vmlinux.debug) named on the command line. - * This file will be used by gdb to get symbol and debugging infos about the - * kernel. Next, select remote debug mode by - * target remote <device> - * where <device> is the name of the serial device over which the debugged - * machine is connected. Maybe you have to adjust the baud rate by - * set remotebaud <rate> - * or also other parameters with stty: - * shell stty ... </dev/... - * If the kernel to debug has already booted, it waited for gdb and now - * connects, and you'll see a breakpoint being reported. If the kernel isn't - * running yet, start it now. The order of gdb and the kernel doesn't matter. - * Another thing worth knowing about in the getting-started phase is how to - * debug the remote protocol itself. This is activated with - * set remotedebug 1 - * gdb will then print out each packet sent or received. You'll also get some - * messages about the gdb stub on the console of the debugged machine. - * - * If all that works, you can use lots of the usual debugging techniques on - * the kernel, e.g. inspecting and changing variables/memory, setting - * breakpoints, single stepping and so on. It's also possible to interrupt the - * debugged kernel by pressing C-c in gdb. Have fun! :-) - * - * The gdb stub is entered (and thus the remote gdb gets control) in the - * following situations: - * - * - If breakpoint() is called. This is just after kgdb initialization, or if - * a breakpoint() call has been put somewhere into the kernel source. - * (Breakpoints can of course also be set the usual way in gdb.) - * In eLinux, we call breakpoint() in init/main.c after IRQ initialization. - * - * - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel() - * are entered. All the CPU exceptions are mapped to (more or less..., see - * the hard_trap_info array below) appropriate signal, which are reported - * to gdb. die_if_kernel() is usually called after some kind of access - * error and thus is reported as SIGSEGV. - * - * - When panic() is called. This is reported as SIGABRT. - * - * - If C-c is received over the serial line, which is treated as - * SIGINT. - * - * Of course, all these signals are just faked for gdb, since there is no - * signal concept as such for the kernel. It also isn't possible --obviously-- - * to set signal handlers from inside gdb, or restart the kernel with a - * signal. - * - * Current limitations: - * - * - While the kernel is stopped, interrupts are disabled for safety reasons - * (i.e., variables not changing magically or the like). But this also - * means that the clock isn't running anymore, and that interrupts from the - * hardware may get lost/not be served in time. This can cause some device - * errors... - * - * - When single-stepping, only one instruction of the current thread is - * executed, but interrupts are allowed for that time and will be serviced - * if pending. Be prepared for that. - * - * - All debugging happens in kernel virtual address space. There's no way to - * access physical memory not mapped in kernel space, or to access user - * space. A way to work around this is using get_user_long & Co. in gdb - * expressions, but only for the current process. - * - * - Interrupting the kernel only works if interrupts are currently allowed, - * and the interrupt of the serial line isn't blocked by some other means - * (IPL too high, disabled, ...) - * - * - The gdb stub is currently not reentrant, i.e. errors that happen therein - * (e.g. accessing invalid memory) may not be caught correctly. This could - * be removed in future by introducing a stack of struct registers. - * - */ - -/* - * To enable debugger support, two things need to happen. One, a - * call to kgdb_init() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * Two, a breakpoint needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint(). - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * bBB..BB Set baud rate to BB..BB OK or BNN, then sets - * baud rate - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $<packet info>#<checksum>. - * - * where - * <packet info> :: <characters representing the command or response> - * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - */ - - -#include <linux/string.h> -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/linkage.h> -#include <linux/reboot.h> - -#include <asm/setup.h> -#include <asm/ptrace.h> - -#include <asm/irq.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/intr_vect_defs.h> -#include <hwregs/ser_defs.h> - -/* From entry.S. */ -extern void gdb_handle_exception(void); -/* From kgdb_asm.S. */ -extern void kgdb_handle_exception(void); - -static int kgdb_started = 0; - -/********************************* Register image ****************************/ - -typedef -struct register_image -{ - /* Offset */ - unsigned int r0; /* 0x00 */ - unsigned int r1; /* 0x04 */ - unsigned int r2; /* 0x08 */ - unsigned int r3; /* 0x0C */ - unsigned int r4; /* 0x10 */ - unsigned int r5; /* 0x14 */ - unsigned int r6; /* 0x18 */ - unsigned int r7; /* 0x1C */ - unsigned int r8; /* 0x20; Frame pointer (if any) */ - unsigned int r9; /* 0x24 */ - unsigned int r10; /* 0x28 */ - unsigned int r11; /* 0x2C */ - unsigned int r12; /* 0x30 */ - unsigned int r13; /* 0x34 */ - unsigned int sp; /* 0x38; R14, Stack pointer */ - unsigned int acr; /* 0x3C; R15, Address calculation register. */ - - unsigned char bz; /* 0x40; P0, 8-bit zero register */ - unsigned char vr; /* 0x41; P1, Version register (8-bit) */ - unsigned int pid; /* 0x42; P2, Process ID */ - unsigned char srs; /* 0x46; P3, Support register select (8-bit) */ - unsigned short wz; /* 0x47; P4, 16-bit zero register */ - unsigned int exs; /* 0x49; P5, Exception status */ - unsigned int eda; /* 0x4D; P6, Exception data address */ - unsigned int mof; /* 0x51; P7, Multiply overflow register */ - unsigned int dz; /* 0x55; P8, 32-bit zero register */ - unsigned int ebp; /* 0x59; P9, Exception base pointer */ - unsigned int erp; /* 0x5D; P10, Exception return pointer. Contains the PC we are interested in. */ - unsigned int srp; /* 0x61; P11, Subroutine return pointer */ - unsigned int nrp; /* 0x65; P12, NMI return pointer */ - unsigned int ccs; /* 0x69; P13, Condition code stack */ - unsigned int usp; /* 0x6D; P14, User mode stack pointer */ - unsigned int spc; /* 0x71; P15, Single step PC */ - unsigned int pc; /* 0x75; Pseudo register (for the most part set to ERP). */ - -} registers; - -typedef -struct bp_register_image -{ - /* Support register bank 0. */ - unsigned int s0_0; - unsigned int s1_0; - unsigned int s2_0; - unsigned int s3_0; - unsigned int s4_0; - unsigned int s5_0; - unsigned int s6_0; - unsigned int s7_0; - unsigned int s8_0; - unsigned int s9_0; - unsigned int s10_0; - unsigned int s11_0; - unsigned int s12_0; - unsigned int s13_0; - unsigned int s14_0; - unsigned int s15_0; - - /* Support register bank 1. */ - unsigned int s0_1; - unsigned int s1_1; - unsigned int s2_1; - unsigned int s3_1; - unsigned int s4_1; - unsigned int s5_1; - unsigned int s6_1; - unsigned int s7_1; - unsigned int s8_1; - unsigned int s9_1; - unsigned int s10_1; - unsigned int s11_1; - unsigned int s12_1; - unsigned int s13_1; - unsigned int s14_1; - unsigned int s15_1; - - /* Support register bank 2. */ - unsigned int s0_2; - unsigned int s1_2; - unsigned int s2_2; - unsigned int s3_2; - unsigned int s4_2; - unsigned int s5_2; - unsigned int s6_2; - unsigned int s7_2; - unsigned int s8_2; - unsigned int s9_2; - unsigned int s10_2; - unsigned int s11_2; - unsigned int s12_2; - unsigned int s13_2; - unsigned int s14_2; - unsigned int s15_2; - - /* Support register bank 3. */ - unsigned int s0_3; /* BP_CTRL */ - unsigned int s1_3; /* BP_I0_START */ - unsigned int s2_3; /* BP_I0_END */ - unsigned int s3_3; /* BP_D0_START */ - unsigned int s4_3; /* BP_D0_END */ - unsigned int s5_3; /* BP_D1_START */ - unsigned int s6_3; /* BP_D1_END */ - unsigned int s7_3; /* BP_D2_START */ - unsigned int s8_3; /* BP_D2_END */ - unsigned int s9_3; /* BP_D3_START */ - unsigned int s10_3; /* BP_D3_END */ - unsigned int s11_3; /* BP_D4_START */ - unsigned int s12_3; /* BP_D4_END */ - unsigned int s13_3; /* BP_D5_START */ - unsigned int s14_3; /* BP_D5_END */ - unsigned int s15_3; /* BP_RESERVED */ - -} support_registers; - -enum register_name -{ - R0, R1, R2, R3, - R4, R5, R6, R7, - R8, R9, R10, R11, - R12, R13, SP, ACR, - - BZ, VR, PID, SRS, - WZ, EXS, EDA, MOF, - DZ, EBP, ERP, SRP, - NRP, CCS, USP, SPC, - PC, - - S0, S1, S2, S3, - S4, S5, S6, S7, - S8, S9, S10, S11, - S12, S13, S14, S15 - -}; - -/* The register sizes of the registers in register_name. An unimplemented register - is designated by size 0 in this array. */ -static int register_size[] = -{ - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - - 1, 1, 4, 1, - 2, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - - 4, - - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4, 4, - 4, 4, 4 - -}; - -/* Contains the register image of the kernel. - (Global so that they can be reached from assembler code.) */ -registers reg; -support_registers sreg; - -/************** Prototypes for local library functions ***********************/ - -/* Copy of strcpy from libc. */ -static char *gdb_cris_strcpy(char *s1, const char *s2); - -/* Copy of strlen from libc. */ -static int gdb_cris_strlen(const char *s); - -/* Copy of memchr from libc. */ -static void *gdb_cris_memchr(const void *s, int c, int n); - -/* Copy of strtol from libc. Does only support base 16. */ -static int gdb_cris_strtol(const char *s, char **endptr, int base); - -/********************** Prototypes for local functions. **********************/ - -/* Write a value to a specified register regno in the register image - of the current thread. */ -static int write_register(int regno, char *val); - -/* Read a value from a specified register in the register image. Returns the - status of the read operation. The register value is returned in valptr. */ -static int read_register(char regno, unsigned int *valptr); - -/* Serial port, reads one character. ETRAX 100 specific. from debugport.c */ -int getDebugChar(void); - -/* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ -void putDebugChar(int val); - -/* Convert the memory, pointed to by mem into hexadecimal representation. - Put the result in buf, and return a pointer to the last character - in buf (null). */ -static char *mem2hex(char *buf, unsigned char *mem, int count); - -/* Put the content of the array, in binary representation, pointed to by buf - into memory pointed to by mem, and return a pointer to - the character after the last byte written. */ -static unsigned char *bin2mem(unsigned char *mem, unsigned char *buf, int count); - -/* Await the sequence $<data>#<checksum> and store <data> in the array buffer - returned. */ -static void getpacket(char *buffer); - -/* Send $<data>#<checksum> from the <data> in the array buffer. */ -static void putpacket(char *buffer); - -/* Build and send a response packet in order to inform the host the - stub is stopped. */ -static void stub_is_stopped(int sigval); - -/* All expected commands are sent from remote.c. Send a response according - to the description in remote.c. Not static since it needs to be reached - from assembler code. */ -void handle_exception(int sigval); - -/* Performs a complete re-start from scratch. ETRAX specific. */ -static void kill_restart(void); - -/******************** Prototypes for global functions. ***********************/ - -/* The string str is prepended with the GDB printout token and sent. */ -void putDebugString(const unsigned char *str, int len); - -/* A static breakpoint to be used at startup. */ -void breakpoint(void); - -/* Avoid warning as the internal_stack is not used in the C-code. */ -#define USEDVAR(name) { if (name) { ; } } -#define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) } - -/********************************** Packet I/O ******************************/ -/* BUFMAX defines the maximum number of characters in - inbound/outbound buffers */ -/* FIXME: How do we know it's enough? */ -#define BUFMAX 512 - -/* Run-length encoding maximum length. Send 64 at most. */ -#define RUNLENMAX 64 - -/* The inbound/outbound buffers used in packet I/O */ -static char input_buffer[BUFMAX]; -static char output_buffer[BUFMAX]; - -/* Error and warning messages. */ -enum error_type -{ - SUCCESS, E01, E02, E03, E04, E05, E06, E07, E08 -}; - -static char *error_message[] = -{ - "", - "E01 Set current or general thread - H[c,g] - internal error.", - "E02 Change register content - P - cannot change read-only register.", - "E03 Thread is not alive.", /* T, not used. */ - "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.", - "E05 Change register content - P - the register is not implemented..", - "E06 Change memory content - M - internal error.", - "E07 Change register content - P - the register is not stored on the stack", - "E08 Invalid parameter" -}; - -/********************************** Breakpoint *******************************/ -/* Use an internal stack in the breakpoint and interrupt response routines. - FIXME: How do we know the size of this stack is enough? - Global so it can be reached from assembler code. */ -#define INTERNAL_STACK_SIZE 1024 -char internal_stack[INTERNAL_STACK_SIZE]; - -/* Due to the breakpoint return pointer, a state variable is needed to keep - track of whether it is a static (compiled) or dynamic (gdb-invoked) - breakpoint to be handled. A static breakpoint uses the content of register - ERP as it is whereas a dynamic breakpoint requires subtraction with 2 - in order to execute the instruction. The first breakpoint is static; all - following are assumed to be dynamic. */ -static int dynamic_bp = 0; - -/********************************* String library ****************************/ -/* Single-step over library functions creates trap loops. */ - -/* Copy char s2[] to s1[]. */ -static char* -gdb_cris_strcpy(char *s1, const char *s2) -{ - char *s = s1; - - for (s = s1; (*s++ = *s2++) != '\0'; ) - ; - return s1; -} - -/* Find length of s[]. */ -static int -gdb_cris_strlen(const char *s) -{ - const char *sc; - - for (sc = s; *sc != '\0'; sc++) - ; - return (sc - s); -} - -/* Find first occurrence of c in s[n]. */ -static void* -gdb_cris_memchr(const void *s, int c, int n) -{ - const unsigned char uc = c; - const unsigned char *su; - - for (su = s; 0 < n; ++su, --n) - if (*su == uc) - return (void *)su; - return NULL; -} -/******************************* Standard library ****************************/ -/* Single-step over library functions creates trap loops. */ -/* Convert string to long. */ -static int -gdb_cris_strtol(const char *s, char **endptr, int base) -{ - char *s1; - char *sd; - int x = 0; - - for (s1 = (char*)s; (sd = gdb_cris_memchr(hex_asc, *s1, base)) != NULL; ++s1) - x = x * base + (sd - hex_asc); - - if (endptr) { - /* Unconverted suffix is stored in endptr unless endptr is NULL. */ - *endptr = s1; - } - - return x; -} - -/********************************* Register image ****************************/ - -/* Write a value to a specified register in the register image of the current - thread. Returns status code SUCCESS, E02, E05 or E08. */ -static int -write_register(int regno, char *val) -{ - int status = SUCCESS; - - if (regno >= R0 && regno <= ACR) { - /* Consecutive 32-bit registers. */ - if (hex2bin((unsigned char *)®.r0 + (regno - R0) * sizeof(unsigned int), - val, sizeof(unsigned int))) - status = E08; - - } else if (regno == BZ || regno == VR || regno == WZ || regno == DZ) { - /* Read-only registers. */ - status = E02; - - } else if (regno == PID) { - /* 32-bit register. (Even though we already checked SRS and WZ, we cannot - combine this with the EXS - SPC write since SRS and WZ have different size.) */ - if (hex2bin((unsigned char *)®.pid, val, sizeof(unsigned int))) - status = E08; - - } else if (regno == SRS) { - /* 8-bit register. */ - if (hex2bin((unsigned char *)®.srs, val, sizeof(unsigned char))) - status = E08; - - } else if (regno >= EXS && regno <= SPC) { - /* Consecutive 32-bit registers. */ - if (hex2bin((unsigned char *)®.exs + (regno - EXS) * sizeof(unsigned int), - val, sizeof(unsigned int))) - status = E08; - - } else if (regno == PC) { - /* Pseudo-register. Treat as read-only. */ - status = E02; - - } else if (regno >= S0 && regno <= S15) { - /* 32-bit registers. */ - if (hex2bin((unsigned char *)&sreg.s0_0 + (reg.srs * 16 * sizeof(unsigned int)) + (regno - S0) * sizeof(unsigned int), - val, sizeof(unsigned int))) - status = E08; - } else { - /* Non-existing register. */ - status = E05; - } - return status; -} - -/* Read a value from a specified register in the register image. Returns the - value in the register or -1 for non-implemented registers. */ -static int -read_register(char regno, unsigned int *valptr) -{ - int status = SUCCESS; - - /* We read the zero registers from the register struct (instead of just returning 0) - to catch errors. */ - - if (regno >= R0 && regno <= ACR) { - /* Consecutive 32-bit registers. */ - *valptr = *(unsigned int *)((char *)®.r0 + (regno - R0) * sizeof(unsigned int)); - - } else if (regno == BZ || regno == VR) { - /* Consecutive 8-bit registers. */ - *valptr = (unsigned int)(*(unsigned char *) - ((char *)®.bz + (regno - BZ) * sizeof(char))); - - } else if (regno == PID) { - /* 32-bit register. */ - *valptr = *(unsigned int *)((char *)®.pid); - - } else if (regno == SRS) { - /* 8-bit register. */ - *valptr = (unsigned int)(*(unsigned char *)((char *)®.srs)); - - } else if (regno == WZ) { - /* 16-bit register. */ - *valptr = (unsigned int)(*(unsigned short *)(char *)®.wz); - - } else if (regno >= EXS && regno <= PC) { - /* Consecutive 32-bit registers. */ - *valptr = *(unsigned int *)((char *)®.exs + (regno - EXS) * sizeof(unsigned int)); - - } else if (regno >= S0 && regno <= S15) { - /* Consecutive 32-bit registers, located elsewhere. */ - *valptr = *(unsigned int *)((char *)&sreg.s0_0 + (reg.srs * 16 * sizeof(unsigned int)) + (regno - S0) * sizeof(unsigned int)); - - } else { - /* Non-existing register. */ - status = E05; - } - return status; - -} - -/********************************** Packet I/O ******************************/ -/* Convert the memory, pointed to by mem into hexadecimal representation. - Put the result in buf, and return a pointer to the last character - in buf (null). */ - -static char * -mem2hex(char *buf, unsigned char *mem, int count) -{ - int i; - int ch; - - if (mem == NULL) { - /* Invalid address, caught by 'm' packet handler. */ - for (i = 0; i < count; i++) { - *buf++ = '0'; - *buf++ = '0'; - } - } else { - /* Valid mem address. */ - for (i = 0; i < count; i++) { - ch = *mem++; - buf = hex_byte_pack(buf, ch); - } - } - /* Terminate properly. */ - *buf = '\0'; - return buf; -} - -/* Same as mem2hex, but puts it in network byte order. */ -static char * -mem2hex_nbo(char *buf, unsigned char *mem, int count) -{ - int i; - int ch; - - mem += count - 1; - for (i = 0; i < count; i++) { - ch = *mem--; - buf = hex_byte_pack(buf, ch); - } - - /* Terminate properly. */ - *buf = '\0'; - return buf; -} - -/* Put the content of the array, in binary representation, pointed to by buf - into memory pointed to by mem, and return a pointer to the character after - the last byte written. - Gdb will escape $, #, and the escape char (0x7d). */ -static unsigned char* -bin2mem(unsigned char *mem, unsigned char *buf, int count) -{ - int i; - unsigned char *next; - for (i = 0; i < count; i++) { - /* Check for any escaped characters. Be paranoid and - only unescape chars that should be escaped. */ - if (*buf == 0x7d) { - next = buf + 1; - if (*next == 0x3 || *next == 0x4 || *next == 0x5D) { - /* #, $, ESC */ - buf++; - *buf += 0x20; - } - } - *mem++ = *buf++; - } - return mem; -} - -/* Await the sequence $<data>#<checksum> and store <data> in the array buffer - returned. */ -static void -getpacket(char *buffer) -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - char ch; - - do { - while((ch = getDebugChar ()) != '$') - /* Wait for the start character $ and ignore all other characters */; - checksum = 0; - xmitcsum = -1; - count = 0; - /* Read until a # or the end of the buffer is reached */ - while (count < BUFMAX) { - ch = getDebugChar(); - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - - if (count >= BUFMAX) - continue; - - buffer[count] = 0; - - if (ch == '#') { - xmitcsum = hex_to_bin(getDebugChar()) << 4; - xmitcsum += hex_to_bin(getDebugChar()); - if (checksum != xmitcsum) { - /* Wrong checksum */ - putDebugChar('-'); - } else { - /* Correct checksum */ - putDebugChar('+'); - /* If sequence characters are received, reply with them */ - if (buffer[2] == ':') { - putDebugChar(buffer[0]); - putDebugChar(buffer[1]); - /* Remove the sequence characters from the buffer */ - count = gdb_cris_strlen(buffer); - for (i = 3; i <= count; i++) - buffer[i - 3] = buffer[i]; - } - } - } - } while (checksum != xmitcsum); -} - -/* Send $<data>#<checksum> from the <data> in the array buffer. */ - -static void -putpacket(char *buffer) -{ - int checksum; - int runlen; - int encode; - - do { - char *src = buffer; - putDebugChar('$'); - checksum = 0; - while (*src) { - /* Do run length encoding */ - putDebugChar(*src); - checksum += *src; - runlen = 0; - while (runlen < RUNLENMAX && *src == src[runlen]) { - runlen++; - } - if (runlen > 3) { - /* Got a useful amount */ - putDebugChar ('*'); - checksum += '*'; - encode = runlen + ' ' - 4; - putDebugChar(encode); - checksum += encode; - src += runlen; - } else { - src++; - } - } - putDebugChar('#'); - putDebugChar(hex_asc_hi(checksum)); - putDebugChar(hex_asc_lo(checksum)); - } while(kgdb_started && (getDebugChar() != '+')); -} - -/* The string str is prepended with the GDB printout token and sent. Required - in traditional implementations. */ -void -putDebugString(const unsigned char *str, int len) -{ - /* Move SPC forward if we are single-stepping. */ - asm("spchere:"); - asm("move $spc, $r10"); - asm("cmp.d spchere, $r10"); - asm("bne nosstep"); - asm("nop"); - asm("move.d spccont, $r10"); - asm("move $r10, $spc"); - asm("nosstep:"); - - output_buffer[0] = 'O'; - mem2hex(&output_buffer[1], (unsigned char *)str, len); - putpacket(output_buffer); - - asm("spccont:"); -} - -/********************************** Handle exceptions ************************/ -/* Build and send a response packet in order to inform the host the - stub is stopped. TAAn...:r...;n...:r...;n...:r...; - AA = signal number - n... = register number (hex) - r... = register contents - n... = `thread' - r... = thread process ID. This is a hex integer. - n... = other string not starting with valid hex digit. - gdb should ignore this n,r pair and go on to the next. - This way we can extend the protocol. */ -static void -stub_is_stopped(int sigval) -{ - char *ptr = output_buffer; - unsigned int reg_cont; - - /* Send trap type (converted to signal) */ - - *ptr++ = 'T'; - ptr = hex_byte_pack(ptr, sigval); - - if (((reg.exs & 0xff00) >> 8) == 0xc) { - - /* Some kind of hardware watchpoint triggered. Find which one - and determine its type (read/write/access). */ - int S, bp, trig_bits = 0, rw_bits = 0; - int trig_mask = 0; - unsigned int *bp_d_regs = &sreg.s3_3; - /* In a lot of cases, the stopped data address will simply be EDA. - In some cases, we adjust it to match the watched data range. - (We don't want to change the actual EDA though). */ - unsigned int stopped_data_address; - /* The S field of EXS. */ - S = (reg.exs & 0xffff0000) >> 16; - - if (S & 1) { - /* Instruction watchpoint. */ - /* FIXME: Check against, and possibly adjust reported EDA. */ - } else { - /* Data watchpoint. Find the one that triggered. */ - for (bp = 0; bp < 6; bp++) { - - /* Dx_RD, Dx_WR in the S field of EXS for this BP. */ - int bitpos_trig = 1 + bp * 2; - /* Dx_BPRD, Dx_BPWR in BP_CTRL for this BP. */ - int bitpos_config = 2 + bp * 4; - - /* Get read/write trig bits for this BP. */ - trig_bits = (S & (3 << bitpos_trig)) >> bitpos_trig; - - /* Read/write config bits for this BP. */ - rw_bits = (sreg.s0_3 & (3 << bitpos_config)) >> bitpos_config; - if (trig_bits) { - /* Sanity check: the BP shouldn't trigger for accesses - that it isn't configured for. */ - if ((rw_bits == 0x1 && trig_bits != 0x1) || - (rw_bits == 0x2 && trig_bits != 0x2)) - panic("Invalid r/w trigging for this BP"); - - /* Mark this BP as trigged for future reference. */ - trig_mask |= (1 << bp); - - if (reg.eda >= bp_d_regs[bp * 2] && - reg.eda <= bp_d_regs[bp * 2 + 1]) { - /* EDA within range for this BP; it must be the one - we're looking for. */ - stopped_data_address = reg.eda; - break; - } - } - } - if (bp < 6) { - /* Found a trigged BP with EDA within its configured data range. */ - } else if (trig_mask) { - /* Something triggered, but EDA doesn't match any BP's range. */ - for (bp = 0; bp < 6; bp++) { - /* Dx_BPRD, Dx_BPWR in BP_CTRL for this BP. */ - int bitpos_config = 2 + bp * 4; - - /* Read/write config bits for this BP (needed later). */ - rw_bits = (sreg.s0_3 & (3 << bitpos_config)) >> bitpos_config; - - if (trig_mask & (1 << bp)) { - /* EDA within 31 bytes of the configured start address? */ - if (reg.eda + 31 >= bp_d_regs[bp * 2]) { - /* Changing the reported address to match - the start address of the first applicable BP. */ - stopped_data_address = bp_d_regs[bp * 2]; - break; - } else { - /* We continue since we might find another useful BP. */ - printk("EDA doesn't match trigged BP's range"); - } - } - } - } - - /* No match yet? */ - BUG_ON(bp >= 6); - /* Note that we report the type according to what the BP is configured - for (otherwise we'd never report an 'awatch'), not according to how - it trigged. We did check that the trigged bits match what the BP is - configured for though. */ - if (rw_bits == 0x1) { - /* read */ - strncpy(ptr, "rwatch", 6); - ptr += 6; - } else if (rw_bits == 0x2) { - /* write */ - strncpy(ptr, "watch", 5); - ptr += 5; - } else if (rw_bits == 0x3) { - /* access */ - strncpy(ptr, "awatch", 6); - ptr += 6; - } else { - panic("Invalid r/w bits for this BP."); - } - - *ptr++ = ':'; - /* Note that we don't read_register(EDA, ...) */ - ptr = mem2hex_nbo(ptr, (unsigned char *)&stopped_data_address, register_size[EDA]); - *ptr++ = ';'; - } - } - /* Only send PC, frame and stack pointer. */ - read_register(PC, ®_cont); - ptr = hex_byte_pack(ptr, PC); - *ptr++ = ':'; - ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[PC]); - *ptr++ = ';'; - - read_register(R8, ®_cont); - ptr = hex_byte_pack(ptr, R8); - *ptr++ = ':'; - ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[R8]); - *ptr++ = ';'; - - read_register(SP, ®_cont); - ptr = hex_byte_pack(ptr, SP); - *ptr++ = ':'; - ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[SP]); - *ptr++ = ';'; - - /* Send ERP as well; this will save us an entire register fetch in some cases. */ - read_register(ERP, ®_cont); - ptr = hex_byte_pack(ptr, ERP); - *ptr++ = ':'; - ptr = mem2hex(ptr, (unsigned char *)®_cont, register_size[ERP]); - *ptr++ = ';'; - - /* null-terminate and send it off */ - *ptr = 0; - putpacket(output_buffer); -} - -/* Returns the size of an instruction that has a delay slot. */ - -int insn_size(unsigned long pc) -{ - unsigned short opcode = *(unsigned short *)pc; - int size = 0; - - switch ((opcode & 0x0f00) >> 8) { - case 0x0: - case 0x9: - case 0xb: - size = 2; - break; - case 0xe: - case 0xf: - size = 6; - break; - case 0xd: - /* Could be 4 or 6; check more bits. */ - if ((opcode & 0xff) == 0xff) - size = 4; - else - size = 6; - break; - default: - panic("Couldn't find size of opcode 0x%x at 0x%lx\n", opcode, pc); - } - - return size; -} - -void register_fixup(int sigval) -{ - /* Compensate for ACR push at the beginning of exception handler. */ - reg.sp += 4; - - /* Standard case. */ - reg.pc = reg.erp; - if (reg.erp & 0x1) { - /* Delay slot bit set. Report as stopped on proper instruction. */ - if (reg.spc) { - /* Rely on SPC if set. */ - reg.pc = reg.spc; - } else { - /* Calculate the PC from the size of the instruction - that the delay slot we're in belongs to. */ - reg.pc += insn_size(reg.erp & ~1) - 1 ; - } - } - - if ((reg.exs & 0x3) == 0x0) { - /* Bits 1 - 0 indicate the type of memory operation performed - by the interrupted instruction. 0 means no memory operation, - and EDA is undefined in that case. We zero it to avoid confusion. */ - reg.eda = 0; - } - - if (sigval == SIGTRAP) { - /* Break 8, single step or hardware breakpoint exception. */ - - /* Check IDX field of EXS. */ - if (((reg.exs & 0xff00) >> 8) == 0x18) { - - /* Break 8. */ - - /* Static (compiled) breakpoints must return to the next instruction - in order to avoid infinite loops (default value of ERP). Dynamic - (gdb-invoked) must subtract the size of the break instruction from - the ERP so that the instruction that was originally in the break - instruction's place will be run when we return from the exception. */ - if (!dynamic_bp) { - /* Assuming that all breakpoints are dynamic from now on. */ - dynamic_bp = 1; - } else { - - /* Only if not in a delay slot. */ - if (!(reg.erp & 0x1)) { - reg.erp -= 2; - reg.pc -= 2; - } - } - - } else if (((reg.exs & 0xff00) >> 8) == 0x3) { - /* Single step. */ - /* Don't fiddle with S1. */ - - } else if (((reg.exs & 0xff00) >> 8) == 0xc) { - - /* Hardware watchpoint exception. */ - - /* SPC has been updated so that we will get a single step exception - when we return, but we don't want that. */ - reg.spc = 0; - - /* Don't fiddle with S1. */ - } - - } else if (sigval == SIGINT) { - /* Nothing special. */ - } -} - -static void insert_watchpoint(char type, int addr, int len) -{ - /* Breakpoint/watchpoint types (GDB terminology): - 0 = memory breakpoint for instructions - (not supported; done via memory write instead) - 1 = hardware breakpoint for instructions (supported) - 2 = write watchpoint (supported) - 3 = read watchpoint (supported) - 4 = access watchpoint (supported) */ - - if (type < '1' || type > '4') { - output_buffer[0] = 0; - return; - } - - /* Read watchpoints are set as access watchpoints, because of GDB's - inability to deal with pure read watchpoints. */ - if (type == '3') - type = '4'; - - if (type == '1') { - /* Hardware (instruction) breakpoint. */ - /* Bit 0 in BP_CTRL holds the configuration for I0. */ - if (sreg.s0_3 & 0x1) { - /* Already in use. */ - gdb_cris_strcpy(output_buffer, error_message[E04]); - return; - } - /* Configure. */ - sreg.s1_3 = addr; - sreg.s2_3 = (addr + len - 1); - sreg.s0_3 |= 1; - } else { - int bp; - unsigned int *bp_d_regs = &sreg.s3_3; - - /* The watchpoint allocation scheme is the simplest possible. - For example, if a region is watched for read and - a write watch is requested, a new watchpoint will - be used. Also, if a watch for a region that is already - covered by one or more existing watchpoints, a new - watchpoint will be used. */ - - /* First, find a free data watchpoint. */ - for (bp = 0; bp < 6; bp++) { - /* Each data watchpoint's control registers occupy 2 bits - (hence the 3), starting at bit 2 for D0 (hence the 2) - with 4 bits between for each watchpoint (yes, the 4). */ - if (!(sreg.s0_3 & (0x3 << (2 + (bp * 4))))) { - break; - } - } - - if (bp > 5) { - /* We're out of watchpoints. */ - gdb_cris_strcpy(output_buffer, error_message[E04]); - return; - } - - /* Configure the control register first. */ - if (type == '3' || type == '4') { - /* Trigger on read. */ - sreg.s0_3 |= (1 << (2 + bp * 4)); - } - if (type == '2' || type == '4') { - /* Trigger on write. */ - sreg.s0_3 |= (2 << (2 + bp * 4)); - } - - /* Ugly pointer arithmetics to configure the watched range. */ - bp_d_regs[bp * 2] = addr; - bp_d_regs[bp * 2 + 1] = (addr + len - 1); - } - - /* Set the S1 flag to enable watchpoints. */ - reg.ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT)); - gdb_cris_strcpy(output_buffer, "OK"); -} - -static void remove_watchpoint(char type, int addr, int len) -{ - /* Breakpoint/watchpoint types: - 0 = memory breakpoint for instructions - (not supported; done via memory write instead) - 1 = hardware breakpoint for instructions (supported) - 2 = write watchpoint (supported) - 3 = read watchpoint (supported) - 4 = access watchpoint (supported) */ - if (type < '1' || type > '4') { - output_buffer[0] = 0; - return; - } - - /* Read watchpoints are set as access watchpoints, because of GDB's - inability to deal with pure read watchpoints. */ - if (type == '3') - type = '4'; - - if (type == '1') { - /* Hardware breakpoint. */ - /* Bit 0 in BP_CTRL holds the configuration for I0. */ - if (!(sreg.s0_3 & 0x1)) { - /* Not in use. */ - gdb_cris_strcpy(output_buffer, error_message[E04]); - return; - } - /* Deconfigure. */ - sreg.s1_3 = 0; - sreg.s2_3 = 0; - sreg.s0_3 &= ~1; - } else { - int bp; - unsigned int *bp_d_regs = &sreg.s3_3; - /* Try to find a watchpoint that is configured for the - specified range, then check that read/write also matches. */ - - /* Ugly pointer arithmetic, since I cannot rely on a - single switch (addr) as there may be several watchpoints with - the same start address for example. */ - - for (bp = 0; bp < 6; bp++) { - if (bp_d_regs[bp * 2] == addr && - bp_d_regs[bp * 2 + 1] == (addr + len - 1)) { - /* Matching range. */ - int bitpos = 2 + bp * 4; - int rw_bits; - - /* Read/write bits for this BP. */ - rw_bits = (sreg.s0_3 & (0x3 << bitpos)) >> bitpos; - - if ((type == '3' && rw_bits == 0x1) || - (type == '2' && rw_bits == 0x2) || - (type == '4' && rw_bits == 0x3)) { - /* Read/write matched. */ - break; - } - } - } - - if (bp > 5) { - /* No watchpoint matched. */ - gdb_cris_strcpy(output_buffer, error_message[E04]); - return; - } - - /* Found a matching watchpoint. Now, deconfigure it by - both disabling read/write in bp_ctrl and zeroing its - start/end addresses. */ - sreg.s0_3 &= ~(3 << (2 + (bp * 4))); - bp_d_regs[bp * 2] = 0; - bp_d_regs[bp * 2 + 1] = 0; - } - - /* Note that we don't clear the S1 flag here. It's done when continuing. */ - gdb_cris_strcpy(output_buffer, "OK"); -} - - - -/* All expected commands are sent from remote.c. Send a response according - to the description in remote.c. */ -void -handle_exception(int sigval) -{ - /* Avoid warning of not used. */ - - USEDFUN(handle_exception); - USEDVAR(internal_stack[0]); - - register_fixup(sigval); - - /* Send response. */ - stub_is_stopped(sigval); - - for (;;) { - output_buffer[0] = '\0'; - getpacket(input_buffer); - switch (input_buffer[0]) { - case 'g': - /* Read registers: g - Success: Each byte of register data is described by two hex digits. - Registers are in the internal order for GDB, and the bytes - in a register are in the same order the machine uses. - Failure: void. */ - { - char *buf; - /* General and special registers. */ - buf = mem2hex(output_buffer, (char *)®, sizeof(registers)); - /* Support registers. */ - /* -1 because of the null termination that mem2hex adds. */ - mem2hex(buf, - (char *)&sreg + (reg.srs * 16 * sizeof(unsigned int)), - 16 * sizeof(unsigned int)); - break; - } - case 'G': - /* Write registers. GXX..XX - Each byte of register data is described by two hex digits. - Success: OK - Failure: E08. */ - /* General and special registers. */ - if (hex2bin((char *)®, &input_buffer[1], sizeof(registers))) - gdb_cris_strcpy(output_buffer, error_message[E08]); - /* Support registers. */ - else if (hex2bin((char *)&sreg + (reg.srs * 16 * sizeof(unsigned int)), - &input_buffer[1] + sizeof(registers), - 16 * sizeof(unsigned int))) - gdb_cris_strcpy(output_buffer, error_message[E08]); - else - gdb_cris_strcpy(output_buffer, "OK"); - break; - - case 'P': - /* Write register. Pn...=r... - Write register n..., hex value without 0x, with value r..., - which contains a hex value without 0x and two hex digits - for each byte in the register (target byte order). P1f=11223344 means - set register 31 to 44332211. - Success: OK - Failure: E02, E05 */ - { - char *suffix; - int regno = gdb_cris_strtol(&input_buffer[1], &suffix, 16); - int status; - - status = write_register(regno, suffix+1); - - switch (status) { - case E02: - /* Do not support read-only registers. */ - gdb_cris_strcpy(output_buffer, error_message[E02]); - break; - case E05: - /* Do not support non-existing registers. */ - gdb_cris_strcpy(output_buffer, error_message[E05]); - break; - case E08: - /* Invalid parameter. */ - gdb_cris_strcpy(output_buffer, error_message[E08]); - break; - default: - /* Valid register number. */ - gdb_cris_strcpy(output_buffer, "OK"); - break; - } - } - break; - - case 'm': - /* Read from memory. mAA..AA,LLLL - AA..AA is the address and LLLL is the length. - Success: XX..XX is the memory content. Can be fewer bytes than - requested if only part of the data may be read. m6000120a,6c means - retrieve 108 byte from base address 6000120a. - Failure: void. */ - { - char *suffix; - unsigned char *addr = (unsigned char *)gdb_cris_strtol(&input_buffer[1], - &suffix, 16); - int len = gdb_cris_strtol(suffix+1, 0, 16); - - /* Bogus read (i.e. outside the kernel's - segment)? . */ - if (!((unsigned int)addr >= 0xc0000000 && - (unsigned int)addr < 0xd0000000)) - addr = NULL; - - mem2hex(output_buffer, addr, len); - } - break; - - case 'X': - /* Write to memory. XAA..AA,LLLL:XX..XX - AA..AA is the start address, LLLL is the number of bytes, and - XX..XX is the binary data. - Success: OK - Failure: void. */ - case 'M': - /* Write to memory. MAA..AA,LLLL:XX..XX - AA..AA is the start address, LLLL is the number of bytes, and - XX..XX is the hexadecimal data. - Success: OK - Failure: E08. */ - { - char *lenptr; - char *dataptr; - unsigned char *addr = (unsigned char *)gdb_cris_strtol(&input_buffer[1], - &lenptr, 16); - int len = gdb_cris_strtol(lenptr+1, &dataptr, 16); - if (*lenptr == ',' && *dataptr == ':') { - if (input_buffer[0] == 'M') { - if (hex2bin(addr, dataptr + 1, len)) - gdb_cris_strcpy(output_buffer, error_message[E08]); - else - gdb_cris_strcpy(output_buffer, "OK"); - } else /* X */ { - bin2mem(addr, dataptr + 1, len); - gdb_cris_strcpy(output_buffer, "OK"); - } - } else { - gdb_cris_strcpy(output_buffer, error_message[E06]); - } - } - break; - - case 'c': - /* Continue execution. cAA..AA - AA..AA is the address where execution is resumed. If AA..AA is - omitted, resume at the present address. - Success: return to the executing thread. - Failure: will never know. */ - - if (input_buffer[1] != '\0') { - /* FIXME: Doesn't handle address argument. */ - gdb_cris_strcpy(output_buffer, error_message[E04]); - break; - } - - /* Before continuing, make sure everything is set up correctly. */ - - /* Set the SPC to some unlikely value. */ - reg.spc = 0; - /* Set the S1 flag to 0 unless some watchpoint is enabled (since setting - S1 to 0 would also disable watchpoints). (Note that bits 26-31 in BP_CTRL - are reserved, so don't check against those). */ - if ((sreg.s0_3 & 0x3fff) == 0) { - reg.ccs &= ~(1 << (S_CCS_BITNR + CCS_SHIFT)); - } - - return; - - case 's': - /* Step. sAA..AA - AA..AA is the address where execution is resumed. If AA..AA is - omitted, resume at the present address. Success: return to the - executing thread. Failure: will never know. */ - - if (input_buffer[1] != '\0') { - /* FIXME: Doesn't handle address argument. */ - gdb_cris_strcpy(output_buffer, error_message[E04]); - break; - } - - /* Set the SPC to PC, which is where we'll return - (deduced previously). */ - reg.spc = reg.pc; - - /* Set the S1 (first stacked, not current) flag, which will - kick into action when we rfe. */ - reg.ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT)); - return; - - case 'Z': - - /* Insert breakpoint or watchpoint, Ztype,addr,length. - Remote protocol says: A remote target shall return an empty string - for an unrecognized breakpoint or watchpoint packet type. */ - { - char *lenptr; - char *dataptr; - int addr = gdb_cris_strtol(&input_buffer[3], &lenptr, 16); - int len = gdb_cris_strtol(lenptr + 1, &dataptr, 16); - char type = input_buffer[1]; - - insert_watchpoint(type, addr, len); - break; - } - - case 'z': - /* Remove breakpoint or watchpoint, Ztype,addr,length. - Remote protocol says: A remote target shall return an empty string - for an unrecognized breakpoint or watchpoint packet type. */ - { - char *lenptr; - char *dataptr; - int addr = gdb_cris_strtol(&input_buffer[3], &lenptr, 16); - int len = gdb_cris_strtol(lenptr + 1, &dataptr, 16); - char type = input_buffer[1]; - - remove_watchpoint(type, addr, len); - break; - } - - - case '?': - /* The last signal which caused a stop. ? - Success: SAA, where AA is the signal number. - Failure: void. */ - output_buffer[0] = 'S'; - output_buffer[1] = hex_asc_hi(sigval); - output_buffer[2] = hex_asc_lo(sigval); - output_buffer[3] = 0; - break; - - case 'D': - /* Detach from host. D - Success: OK, and return to the executing thread. - Failure: will never know */ - putpacket("OK"); - return; - - case 'k': - case 'r': - /* kill request or reset request. - Success: restart of target. - Failure: will never know. */ - kill_restart(); - break; - - case 'C': - case 'S': - case '!': - case 'R': - case 'd': - /* Continue with signal sig. Csig;AA..AA - Step with signal sig. Ssig;AA..AA - Use the extended remote protocol. ! - Restart the target system. R0 - Toggle debug flag. d - Search backwards. tAA:PP,MM - Not supported: E04 */ - - /* FIXME: What's the difference between not supported - and ignored (below)? */ - gdb_cris_strcpy(output_buffer, error_message[E04]); - break; - - default: - /* The stub should ignore other request and send an empty - response ($#<checksum>). This way we can extend the protocol and GDB - can tell whether the stub it is talking to uses the old or the new. */ - output_buffer[0] = 0; - break; - } - putpacket(output_buffer); - } -} - -void -kgdb_init(void) -{ - reg_intr_vect_rw_mask intr_mask; - reg_ser_rw_intr_mask ser_intr_mask; - - /* Configure the kgdb serial port. */ -#if defined(CONFIG_ETRAX_KGDB_PORT0) - /* Note: no shortcut registered (not handled by multiple_interrupt). - See entry.S. */ - set_exception_vector(SER0_INTR_VECT, kgdb_handle_exception); - /* Enable the ser irq in the global config. */ - intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); - intr_mask.ser0 = 1; - REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); - - ser_intr_mask = REG_RD(ser, regi_ser0, rw_intr_mask); - ser_intr_mask.dav = regk_ser_yes; - REG_WR(ser, regi_ser0, rw_intr_mask, ser_intr_mask); -#elif defined(CONFIG_ETRAX_KGDB_PORT1) - /* Note: no shortcut registered (not handled by multiple_interrupt). - See entry.S. */ - set_exception_vector(SER1_INTR_VECT, kgdb_handle_exception); - /* Enable the ser irq in the global config. */ - intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); - intr_mask.ser1 = 1; - REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); - - ser_intr_mask = REG_RD(ser, regi_ser1, rw_intr_mask); - ser_intr_mask.dav = regk_ser_yes; - REG_WR(ser, regi_ser1, rw_intr_mask, ser_intr_mask); -#elif defined(CONFIG_ETRAX_KGDB_PORT2) - /* Note: no shortcut registered (not handled by multiple_interrupt). - See entry.S. */ - set_exception_vector(SER2_INTR_VECT, kgdb_handle_exception); - /* Enable the ser irq in the global config. */ - intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); - intr_mask.ser2 = 1; - REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); - - ser_intr_mask = REG_RD(ser, regi_ser2, rw_intr_mask); - ser_intr_mask.dav = regk_ser_yes; - REG_WR(ser, regi_ser2, rw_intr_mask, ser_intr_mask); -#elif defined(CONFIG_ETRAX_KGDB_PORT3) - /* Note: no shortcut registered (not handled by multiple_interrupt). - See entry.S. */ - set_exception_vector(SER3_INTR_VECT, kgdb_handle_exception); - /* Enable the ser irq in the global config. */ - intr_mask = REG_RD(intr_vect, regi_irq, rw_mask); - intr_mask.ser3 = 1; - REG_WR(intr_vect, regi_irq, rw_mask, intr_mask); - - ser_intr_mask = REG_RD(ser, regi_ser3, rw_intr_mask); - ser_intr_mask.dav = regk_ser_yes; - REG_WR(ser, regi_ser3, rw_intr_mask, ser_intr_mask); -#endif - -} -/* Performs a complete re-start from scratch. */ -static void -kill_restart(void) -{ - machine_restart(""); -} - -/* Use this static breakpoint in the start-up only. */ - -void -breakpoint(void) -{ - kgdb_started = 1; - dynamic_bp = 0; /* This is a static, not a dynamic breakpoint. */ - __asm__ volatile ("break 8"); /* Jump to kgdb_handle_breakpoint. */ -} - -/****************************** End of file **********************************/ diff --git a/arch/cris/arch-v32/kernel/kgdb_asm.S b/arch/cris/arch-v32/kernel/kgdb_asm.S deleted file mode 100644 index c26ea6b0e334..000000000000 --- a/arch/cris/arch-v32/kernel/kgdb_asm.S +++ /dev/null @@ -1,552 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Copyright (C) 2004 Axis Communications AB - * - * Code for handling break 8, hardware breakpoint, single step, and serial - * port exceptions for kernel debugging purposes. - */ - -#include <hwregs/intr_vect.h> - - ;; Exported functions. - .globl kgdb_handle_exception - -kgdb_handle_exception: - -;; Create a register image of the caller. -;; -;; First of all, save the ACR on the stack since we need it for address calculations. -;; We put it into the register struct later. - - subq 4, $sp - move.d $acr, [$sp] - -;; Now we are free to use ACR all we want. -;; If we were running this handler with interrupts on, we would have to be careful -;; to save and restore CCS manually, but since we aren't we treat it like every other -;; register. - - move.d reg, $acr - move.d $r0, [$acr] ; Save R0 (start of register struct) - addq 4, $acr - move.d $r1, [$acr] ; Save R1 - addq 4, $acr - move.d $r2, [$acr] ; Save R2 - addq 4, $acr - move.d $r3, [$acr] ; Save R3 - addq 4, $acr - move.d $r4, [$acr] ; Save R4 - addq 4, $acr - move.d $r5, [$acr] ; Save R5 - addq 4, $acr - move.d $r6, [$acr] ; Save R6 - addq 4, $acr - move.d $r7, [$acr] ; Save R7 - addq 4, $acr - move.d $r8, [$acr] ; Save R8 - addq 4, $acr - move.d $r9, [$acr] ; Save R9 - addq 4, $acr - move.d $r10, [$acr] ; Save R10 - addq 4, $acr - move.d $r11, [$acr] ; Save R11 - addq 4, $acr - move.d $r12, [$acr] ; Save R12 - addq 4, $acr - move.d $r13, [$acr] ; Save R13 - addq 4, $acr - move.d $sp, [$acr] ; Save SP (R14) - addq 4, $acr - - ;; The ACR register is already saved on the stack, so pop it from there. - move.d [$sp],$r0 - move.d $r0, [$acr] - addq 4, $acr - - move $bz, [$acr] - addq 1, $acr - move $vr, [$acr] - addq 1, $acr - move $pid, [$acr] - addq 4, $acr - move $srs, [$acr] - addq 1, $acr - move $wz, [$acr] - addq 2, $acr - move $exs, [$acr] - addq 4, $acr - move $eda, [$acr] - addq 4, $acr - move $mof, [$acr] - addq 4, $acr - move $dz, [$acr] - addq 4, $acr - move $ebp, [$acr] - addq 4, $acr - move $erp, [$acr] - addq 4, $acr - move $srp, [$acr] - addq 4, $acr - move $nrp, [$acr] - addq 4, $acr - move $ccs, [$acr] - addq 4, $acr - move $usp, [$acr] - addq 4, $acr - move $spc, [$acr] - addq 4, $acr - -;; Skip the pseudo-PC. - addq 4, $acr - -;; Save the support registers in bank 0 - 3. - clear.d $r1 ; Bank counter - move.d sreg, $acr - -;; Bank 0 - move $r1, $srs - nop - nop - nop - move $s0, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s1, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s2, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s3, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s4, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s5, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s6, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s7, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s8, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s9, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s10, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s11, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s12, $r0 - move.d $r0, [$acr] - addq 4, $acr - - ;; Nothing in S13 - S15, bank 0 - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - -;; Bank 1 and bank 2 have the same layout, hence the loop. - addq 1, $r1 -1: - move $r1, $srs - nop - nop - nop - move $s0, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s1, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s2, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s3, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s4, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s5, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s6, $r0 - move.d $r0, [$acr] - addq 4, $acr - - ;; Nothing in S7 - S15, bank 1 and 2 - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - clear.d [$acr] - addq 4, $acr - - addq 1, $r1 - cmpq 3, $r1 - bne 1b - nop - -;; Bank 3 - move $r1, $srs - nop - nop - nop - move $s0, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s1, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s2, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s3, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s4, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s5, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s6, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s7, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s8, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s9, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s10, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s11, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s12, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s13, $r0 - move.d $r0, [$acr] - addq 4, $acr - move $s14, $r0 - move.d $r0, [$acr] - addq 4, $acr -;; Nothing in S15, bank 3 - clear.d [$acr] - addq 4, $acr - -;; Check what got us here: get IDX field of EXS. - move $exs, $r10 - and.d 0xff00, $r10 - lsrq 8, $r10 -#if defined(CONFIG_ETRAX_KGDB_PORT0) - cmp.d SER0_INTR_VECT, $r10 ; IRQ for serial port 0 - beq sigint - nop -#elif defined(CONFIG_ETRAX_KGDB_PORT1) - cmp.d SER1_INTR_VECT, $r10 ; IRQ for serial port 1 - beq sigint - nop -#elif defined(CONFIG_ETRAX_KGDB_PORT2) - cmp.d SER2_INTR_VECT, $r10 ; IRQ for serial port 2 - beq sigint - nop -#elif defined(CONFIG_ETRAX_KGDB_PORT3) - cmp.d SER3_INTR_VECT, $r10 ; IRQ for serial port 3 - beq sigint - nop -#endif -;; Multiple interrupt must be due to serial break. - cmp.d 0x30, $r10 ; Multiple interrupt - beq sigint - nop -;; Neither of those? Then it's a sigtrap. - ba handle_comm - moveq 5, $r10 ; Set SIGTRAP (delay slot) - -sigint: - ;; Serial interrupt; get character - jsr getDebugChar - nop ; Delay slot - cmp.b 3, $r10 ; \003 (Ctrl-C)? - bne return ; No, get out of here - nop - moveq 2, $r10 ; Set SIGINT - -;; -;; Handle the communication -;; -handle_comm: - move.d internal_stack+1020, $sp ; Use the internal stack which grows upwards - jsr handle_exception ; Interactive routine - nop - -;; -;; Return to the caller -;; -return: - -;; First of all, write the support registers. - clear.d $r1 ; Bank counter - move.d sreg, $acr - -;; Bank 0 - move $r1, $srs - nop - nop - nop - move.d [$acr], $r0 - move $r0, $s0 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s1 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s2 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s3 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s4 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s5 - addq 4, $acr - -;; Nothing in S6 - S7, bank 0. - addq 4, $acr - addq 4, $acr - - move.d [$acr], $r0 - move $r0, $s8 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s9 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s10 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s11 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s12 - addq 4, $acr - -;; Nothing in S13 - S15, bank 0 - addq 4, $acr - addq 4, $acr - addq 4, $acr - -;; Bank 1 and bank 2 have the same layout, hence the loop. - addq 1, $r1 -2: - move $r1, $srs - nop - nop - nop - move.d [$acr], $r0 - move $r0, $s0 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s1 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s2 - addq 4, $acr - -;; S3 (MM_CAUSE) is read-only. - addq 4, $acr - - move.d [$acr], $r0 - move $r0, $s4 - addq 4, $acr - -;; FIXME: Actually write S5/S6? (Affects MM_CAUSE.) - addq 4, $acr - addq 4, $acr - -;; Nothing in S7 - S15, bank 1 and 2 - addq 4, $acr - addq 4, $acr - addq 4, $acr - addq 4, $acr - addq 4, $acr - addq 4, $acr - addq 4, $acr - addq 4, $acr - addq 4, $acr - - addq 1, $r1 - cmpq 3, $r1 - bne 2b - nop - -;; Bank 3 - move $r1, $srs - nop - nop - nop - move.d [$acr], $r0 - move $r0, $s0 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s1 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s2 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s3 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s4 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s5 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s6 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s7 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s8 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s9 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s10 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s11 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s12 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s13 - addq 4, $acr - move.d [$acr], $r0 - move $r0, $s14 - addq 4, $acr - -;; Nothing in S15, bank 3 - addq 4, $acr - -;; Now, move on to the regular register restoration process. - - move.d reg, $acr ; Reset ACR to point at the beginning of the register image - move.d [$acr], $r0 ; Restore R0 - addq 4, $acr - move.d [$acr], $r1 ; Restore R1 - addq 4, $acr - move.d [$acr], $r2 ; Restore R2 - addq 4, $acr - move.d [$acr], $r3 ; Restore R3 - addq 4, $acr - move.d [$acr], $r4 ; Restore R4 - addq 4, $acr - move.d [$acr], $r5 ; Restore R5 - addq 4, $acr - move.d [$acr], $r6 ; Restore R6 - addq 4, $acr - move.d [$acr], $r7 ; Restore R7 - addq 4, $acr - move.d [$acr], $r8 ; Restore R8 - addq 4, $acr - move.d [$acr], $r9 ; Restore R9 - addq 4, $acr - move.d [$acr], $r10 ; Restore R10 - addq 4, $acr - move.d [$acr], $r11 ; Restore R11 - addq 4, $acr - move.d [$acr], $r12 ; Restore R12 - addq 4, $acr - move.d [$acr], $r13 ; Restore R13 - -;; -;; We restore all registers, even though some of them probably haven't changed. -;; - - addq 4, $acr - move.d [$acr], $sp ; Restore SP (R14) - - ;; ACR cannot be restored just yet. - addq 8, $acr - - ;; Skip BZ, VR. - addq 2, $acr - - move [$acr], $pid ; Restore PID - addq 4, $acr - move [$acr], $srs ; Restore SRS - nop - nop - nop - addq 1, $acr - - ;; Skip WZ. - addq 2, $acr - - move [$acr], $exs ; Restore EXS. - addq 4, $acr - move [$acr], $eda ; Restore EDA. - addq 4, $acr - move [$acr], $mof ; Restore MOF. - - ;; Skip DZ. - addq 8, $acr - - move [$acr], $ebp ; Restore EBP. - addq 4, $acr - move [$acr], $erp ; Restore ERP. - addq 4, $acr - move [$acr], $srp ; Restore SRP. - addq 4, $acr - move [$acr], $nrp ; Restore NRP. - addq 4, $acr - move [$acr], $ccs ; Restore CCS like an ordinary register. - addq 4, $acr - move [$acr], $usp ; Restore USP - addq 4, $acr - move [$acr], $spc ; Restore SPC - ; No restoration of pseudo-PC of course. - - move.d reg, $acr ; Reset ACR to point at the beginning of the register image - add.d 15*4, $acr - move.d [$acr], $acr ; Finally, restore ACR. - rete ; Same as jump ERP - rfe ; Shifts CCS diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c deleted file mode 100644 index a02f276d0ed4..000000000000 --- a/arch/cris/arch-v32/kernel/process.c +++ /dev/null @@ -1,180 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2000-2003 Axis Communications AB - * - * Authors: Bjorn Wesen (bjornw@axis.com) - * Mikael Starvik (starvik@axis.com) - * Tobias Anderberg (tobiasa@axis.com), CRISv32 port. - * - * This file handles the architecture-dependent parts of process handling.. - */ - -#include <linux/sched.h> -#include <linux/sched/debug.h> -#include <linux/sched/task.h> -#include <linux/sched/task_stack.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/fs.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/reg_map.h> -#include <hwregs/timer_defs.h> -#include <hwregs/intr_vect_defs.h> -#include <linux/ptrace.h> - -extern void stop_watchdog(void); - -/* We use this if we don't have any better idle routine. */ -void default_idle(void) -{ - local_irq_enable(); - /* Halt until exception. */ - __asm__ volatile("halt"); -} - -/* - * Free current thread data structures etc.. - */ - -extern void deconfigure_bp(long pid); -void exit_thread(struct task_struct *tsk) -{ - deconfigure_bp(tsk->pid); -} - -/* - * If the watchdog is enabled, disable interrupts and enter an infinite loop. - * The watchdog will reset the CPU after 0.1s. If the watchdog isn't enabled - * then enable it and wait. - */ -extern void arch_enable_nmi(void); - -void -hard_reset_now(void) -{ - /* - * Don't declare this variable elsewhere. We don't want any other - * code to know about it than the watchdog handler in entry.S and - * this code, implementing hard reset through the watchdog. - */ -#if defined(CONFIG_ETRAX_WATCHDOG) - extern int cause_of_death; -#endif - - printk("*** HARD RESET ***\n"); - local_irq_disable(); - -#if defined(CONFIG_ETRAX_WATCHDOG) - cause_of_death = 0xbedead; -#else -{ - reg_timer_rw_wd_ctrl wd_ctrl = {0}; - - stop_watchdog(); - - wd_ctrl.key = 16; /* Arbitrary key. */ - wd_ctrl.cnt = 1; /* Minimum time. */ - wd_ctrl.cmd = regk_timer_start; - - arch_enable_nmi(); - REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); -} -#endif - - while (1) - ; /* Wait for reset. */ -} - -/* - * Setup the child's kernel stack with a pt_regs and call switch_stack() on it. - * It will be unnested during _resume and _ret_from_sys_call when the new thread - * is scheduled. - * - * Also setup the thread switching structure which is used to keep - * thread-specific data during _resumes. - */ - -extern asmlinkage void ret_from_fork(void); -extern asmlinkage void ret_from_kernel_thread(void); - -int -copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long arg, struct task_struct *p) -{ - struct pt_regs *childregs = task_pt_regs(p); - struct switch_stack *swstack = ((struct switch_stack *) childregs) - 1; - - /* - * Put the pt_regs structure at the end of the new kernel stack page and - * fix it up. Note: the task_struct doubles as the kernel stack for the - * task. - */ - if (unlikely(p->flags & PF_KTHREAD)) { - memset(swstack, 0, - sizeof(struct switch_stack) + sizeof(struct pt_regs)); - swstack->r1 = usp; - swstack->r2 = arg; - childregs->ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); - swstack->return_ip = (unsigned long) ret_from_kernel_thread; - p->thread.ksp = (unsigned long) swstack; - p->thread.usp = 0; - return 0; - } - *childregs = *current_pt_regs(); /* Struct copy of pt_regs. */ - childregs->r10 = 0; /* Child returns 0 after a fork/clone. */ - - /* Set a new TLS ? - * The TLS is in $mof because it is the 5th argument to sys_clone. - */ - if (p->mm && (clone_flags & CLONE_SETTLS)) { - task_thread_info(p)->tls = childregs->mof; - } - - /* Put the switch stack right below the pt_regs. */ - - /* Parameter to ret_from_sys_call. 0 is don't restart the syscall. */ - swstack->r9 = 0; - - /* - * We want to return into ret_from_sys_call after the _resume. - * ret_from_fork will call ret_from_sys_call. - */ - swstack->return_ip = (unsigned long) ret_from_fork; - - /* Fix the user-mode and kernel-mode stackpointer. */ - p->thread.usp = usp ?: rdusp(); - p->thread.ksp = (unsigned long) swstack; - - return 0; -} - -unsigned long -get_wchan(struct task_struct *p) -{ - /* TODO */ - return 0; -} -#undef last_sched -#undef first_sched - -void show_regs(struct pt_regs * regs) -{ - unsigned long usp = rdusp(); - - show_regs_print_info(KERN_DEFAULT); - - printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", - regs->erp, regs->srp, regs->ccs, usp, regs->mof); - - printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", - regs->r0, regs->r1, regs->r2, regs->r3); - - printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", - regs->r4, regs->r5, regs->r6, regs->r7); - - printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", - regs->r8, regs->r9, regs->r10, regs->r11); - - printk("r12: %08lx r13: %08lx oR10: %08lx\n", - regs->r12, regs->r13, regs->orig_r10); -} diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c deleted file mode 100644 index ccac1aaadc8a..000000000000 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ /dev/null @@ -1,492 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2000-2007, Axis Communications AB. - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/sched/task_stack.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/signal.h> -#include <linux/security.h> - -#include <linux/uaccess.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <arch/hwregs/supp_reg.h> - -/* - * Determines which bits in CCS the user has access to. - * 1 = access, 0 = no access. - */ -#define CCS_MASK 0x00087c00 /* SXNZVC */ - -#define SBIT_USER (1 << (S_CCS_BITNR + CCS_SHIFT)) - -static int put_debugreg(long pid, unsigned int regno, long data); -static long get_debugreg(long pid, unsigned int regno); -static unsigned long get_pseudo_pc(struct task_struct *child); -void deconfigure_bp(long pid); - -extern unsigned long cris_signal_return_page; - -/* - * Get contents of register REGNO in task TASK. - */ -long get_reg(struct task_struct *task, unsigned int regno) -{ - /* USP is a special case, it's not in the pt_regs struct but - * in the tasks thread struct - */ - unsigned long ret; - - if (regno <= PT_EDA) - ret = ((unsigned long *)task_pt_regs(task))[regno]; - else if (regno == PT_USP) - ret = task->thread.usp; - else if (regno == PT_PPC) - ret = get_pseudo_pc(task); - else if (regno <= PT_MAX) - ret = get_debugreg(task->pid, regno); - else - ret = 0; - - return ret; -} - -/* - * Write contents of register REGNO in task TASK. - */ -int put_reg(struct task_struct *task, unsigned int regno, unsigned long data) -{ - if (regno <= PT_EDA) - ((unsigned long *)task_pt_regs(task))[regno] = data; - else if (regno == PT_USP) - task->thread.usp = data; - else if (regno == PT_PPC) { - /* Write pseudo-PC to ERP only if changed. */ - if (data != get_pseudo_pc(task)) - task_pt_regs(task)->erp = data; - } else if (regno <= PT_MAX) - return put_debugreg(task->pid, regno, data); - else - return -1; - return 0; -} - -void user_enable_single_step(struct task_struct *child) -{ - unsigned long tmp; - - /* - * Set up SPC if not set already (in which case we have no other - * choice but to trust it). - */ - if (!get_reg(child, PT_SPC)) { - /* In case we're stopped in a delay slot. */ - tmp = get_reg(child, PT_ERP) & ~1; - put_reg(child, PT_SPC, tmp); - } - tmp = get_reg(child, PT_CCS) | SBIT_USER; - put_reg(child, PT_CCS, tmp); -} - -void user_disable_single_step(struct task_struct *child) -{ - put_reg(child, PT_SPC, 0); - - if (!get_debugreg(child->pid, PT_BP_CTRL)) { - unsigned long tmp; - /* If no h/w bp configured, disable S bit. */ - tmp = get_reg(child, PT_CCS) & ~SBIT_USER; - put_reg(child, PT_CCS, tmp); - } -} - -/* - * Called by kernel/ptrace.c when detaching. - * - * Make sure the single step bit is not set. - */ -void -ptrace_disable(struct task_struct *child) -{ - /* Deconfigure SPC and S-bit. */ - user_disable_single_step(child); - put_reg(child, PT_SPC, 0); - - /* Deconfigure any watchpoints associated with the child. */ - deconfigure_bp(child->pid); -} - - -long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - int ret; - unsigned int regno = addr >> 2; - unsigned long __user *datap = (unsigned long __user *)data; - - switch (request) { - /* Read word at location address. */ - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: { - unsigned long tmp; - int copied; - - ret = -EIO; - - /* The signal trampoline page is outside the normal user-addressable - * space but still accessible. This is hack to make it possible to - * access the signal handler code in GDB. - */ - if ((addr & PAGE_MASK) == cris_signal_return_page) { - /* The trampoline page is globally mapped, no page table to traverse.*/ - tmp = *(unsigned long*)addr; - } else { - copied = ptrace_access_vm(child, addr, &tmp, sizeof(tmp), FOLL_FORCE); - - if (copied != sizeof(tmp)) - break; - } - - ret = put_user(tmp,datap); - break; - } - - /* Read the word at location address in the USER area. */ - case PTRACE_PEEKUSR: { - unsigned long tmp; - - ret = -EIO; - if ((addr & 3) || regno > PT_MAX) - break; - - tmp = get_reg(child, regno); - ret = put_user(tmp, datap); - break; - } - - /* Write the word at location address. */ - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - ret = generic_ptrace_pokedata(child, addr, data); - break; - - /* Write the word at location address in the USER area. */ - case PTRACE_POKEUSR: - ret = -EIO; - if ((addr & 3) || regno > PT_MAX) - break; - - if (regno == PT_CCS) { - /* don't allow the tracing process to change stuff like - * interrupt enable, kernel/user bit, dma enables etc. - */ - data &= CCS_MASK; - data |= get_reg(child, PT_CCS) & ~CCS_MASK; - } - if (put_reg(child, regno, data)) - break; - ret = 0; - break; - - /* Get all GP registers from the child. */ - case PTRACE_GETREGS: { - int i; - unsigned long tmp; - - for (i = 0; i <= PT_MAX; i++) { - tmp = get_reg(child, i); - - if (put_user(tmp, datap)) { - ret = -EFAULT; - goto out_tsk; - } - - datap++; - } - - ret = 0; - break; - } - - /* Set all GP registers in the child. */ - case PTRACE_SETREGS: { - int i; - unsigned long tmp; - - for (i = 0; i <= PT_MAX; i++) { - if (get_user(tmp, datap)) { - ret = -EFAULT; - goto out_tsk; - } - - if (i == PT_CCS) { - tmp &= CCS_MASK; - tmp |= get_reg(child, PT_CCS) & ~CCS_MASK; - } - - put_reg(child, i, tmp); - datap++; - } - - ret = 0; - break; - } - - default: - ret = ptrace_request(child, request, addr, data); - break; - } - -out_tsk: - return ret; -} - -void do_syscall_trace(void) -{ - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - - if (!(current->ptrace & PT_PTRACED)) - return; - - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * This isn't the same as continuing with a signal, but it will do for - * normal use. - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } -} - -/* Returns the size of an instruction that has a delay slot. */ - -static int insn_size(struct task_struct *child, unsigned long pc) -{ - unsigned long opcode; - int copied; - int opsize = 0; - - /* Read the opcode at pc (do what PTRACE_PEEKTEXT would do). */ - copied = access_process_vm(child, pc, &opcode, sizeof(opcode), FOLL_FORCE); - if (copied != sizeof(opcode)) - return 0; - - switch ((opcode & 0x0f00) >> 8) { - case 0x0: - case 0x9: - case 0xb: - opsize = 2; - break; - case 0xe: - case 0xf: - opsize = 6; - break; - case 0xd: - /* Could be 4 or 6; check more bits. */ - if ((opcode & 0xff) == 0xff) - opsize = 4; - else - opsize = 6; - break; - default: - panic("ERROR: Couldn't find size of opcode 0x%lx at 0x%lx\n", - opcode, pc); - } - - return opsize; -} - -static unsigned long get_pseudo_pc(struct task_struct *child) -{ - /* Default value for PC is ERP. */ - unsigned long pc = get_reg(child, PT_ERP); - - if (pc & 0x1) { - unsigned long spc = get_reg(child, PT_SPC); - /* Delay slot bit set. Report as stopped on proper - instruction. */ - if (spc) { - /* Rely on SPC if set. FIXME: We might want to check - that EXS indicates we stopped due to a single-step - exception. */ - pc = spc; - } else { - /* Calculate the PC from the size of the instruction - that the delay slot we're in belongs to. */ - pc += insn_size(child, pc & ~1) - 1; - } - } - return pc; -} - -static long bp_owner = 0; - -/* Reachable from exit_thread in signal.c, so not static. */ -void deconfigure_bp(long pid) -{ - int bp; - - /* Only deconfigure if the pid is the owner. */ - if (bp_owner != pid) - return; - - for (bp = 0; bp < 6; bp++) { - unsigned long tmp; - /* Deconfigure start and end address (also gets rid of ownership). */ - put_debugreg(pid, PT_BP + 3 + (bp * 2), 0); - put_debugreg(pid, PT_BP + 4 + (bp * 2), 0); - - /* Deconfigure relevant bits in control register. */ - tmp = get_debugreg(pid, PT_BP_CTRL) & ~(3 << (2 + (bp * 4))); - put_debugreg(pid, PT_BP_CTRL, tmp); - } - /* No owner now. */ - bp_owner = 0; -} - -static int put_debugreg(long pid, unsigned int regno, long data) -{ - int ret = 0; - register int old_srs; - -#ifdef CONFIG_ETRAX_KGDB - /* Ignore write, but pretend it was ok if value is 0 - (we don't want POKEUSR/SETREGS failing unnessecarily). */ - return (data == 0) ? ret : -1; -#endif - - /* Simple owner management. */ - if (!bp_owner) - bp_owner = pid; - else if (bp_owner != pid) { - /* Ignore write, but pretend it was ok if value is 0 - (we don't want POKEUSR/SETREGS failing unnessecarily). */ - return (data == 0) ? ret : -1; - } - - /* Remember old SRS. */ - SPEC_REG_RD(SPEC_REG_SRS, old_srs); - /* Switch to BP bank. */ - SUPP_BANK_SEL(BANK_BP); - - switch (regno - PT_BP) { - case 0: - SUPP_REG_WR(0, data); break; - case 1: - case 2: - if (data) - ret = -1; - break; - case 3: - SUPP_REG_WR(3, data); break; - case 4: - SUPP_REG_WR(4, data); break; - case 5: - SUPP_REG_WR(5, data); break; - case 6: - SUPP_REG_WR(6, data); break; - case 7: - SUPP_REG_WR(7, data); break; - case 8: - SUPP_REG_WR(8, data); break; - case 9: - SUPP_REG_WR(9, data); break; - case 10: - SUPP_REG_WR(10, data); break; - case 11: - SUPP_REG_WR(11, data); break; - case 12: - SUPP_REG_WR(12, data); break; - case 13: - SUPP_REG_WR(13, data); break; - case 14: - SUPP_REG_WR(14, data); break; - default: - ret = -1; - break; - } - - /* Restore SRS. */ - SPEC_REG_WR(SPEC_REG_SRS, old_srs); - /* Just for show. */ - NOP(); - NOP(); - NOP(); - - return ret; -} - -static long get_debugreg(long pid, unsigned int regno) -{ - register int old_srs; - register long data; - - if (pid != bp_owner) { - return 0; - } - - /* Remember old SRS. */ - SPEC_REG_RD(SPEC_REG_SRS, old_srs); - /* Switch to BP bank. */ - SUPP_BANK_SEL(BANK_BP); - - switch (regno - PT_BP) { - case 0: - SUPP_REG_RD(0, data); break; - case 1: - case 2: - /* error return value? */ - data = 0; - break; - case 3: - SUPP_REG_RD(3, data); break; - case 4: - SUPP_REG_RD(4, data); break; - case 5: - SUPP_REG_RD(5, data); break; - case 6: - SUPP_REG_RD(6, data); break; - case 7: - SUPP_REG_RD(7, data); break; - case 8: - SUPP_REG_RD(8, data); break; - case 9: - SUPP_REG_RD(9, data); break; - case 10: - SUPP_REG_RD(10, data); break; - case 11: - SUPP_REG_RD(11, data); break; - case 12: - SUPP_REG_RD(12, data); break; - case 13: - SUPP_REG_RD(13, data); break; - case 14: - SUPP_REG_RD(14, data); break; - default: - /* error return value? */ - data = 0; - } - - /* Restore SRS. */ - SPEC_REG_WR(SPEC_REG_SRS, old_srs); - /* Just for show. */ - NOP(); - NOP(); - NOP(); - - return data; -} diff --git a/arch/cris/arch-v32/kernel/setup.c b/arch/cris/arch-v32/kernel/setup.c deleted file mode 100644 index a36372e35e96..000000000000 --- a/arch/cris/arch-v32/kernel/setup.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Display CPU info in /proc/cpuinfo. - * - * Copyright (C) 2003, Axis Communications AB. - */ - -#include <linux/seq_file.h> -#include <linux/proc_fs.h> -#include <linux/delay.h> -#include <linux/param.h> - -#include <linux/i2c.h> -#include <linux/platform_device.h> - -#ifdef CONFIG_PROC_FS - -#define HAS_FPU 0x0001 -#define HAS_MMU 0x0002 -#define HAS_ETHERNET100 0x0004 -#define HAS_TOKENRING 0x0008 -#define HAS_SCSI 0x0010 -#define HAS_ATA 0x0020 -#define HAS_USB 0x0040 -#define HAS_IRQ_BUG 0x0080 -#define HAS_MMU_BUG 0x0100 - -struct cpu_info { - char *cpu_model; - unsigned short rev; - unsigned short cache_size; - unsigned short flags; -}; - -/* Some of these model are here for historical reasons only. */ -static struct cpu_info cpinfo[] = { - {"ETRAX 1", 0, 0, 0}, - {"ETRAX 2", 1, 0, 0}, - {"ETRAX 3", 2, 0, 0}, - {"ETRAX 4", 3, 0, 0}, - {"Simulator", 7, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA}, - {"ETRAX 100", 8, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG}, - {"ETRAX 100", 9, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA}, - - {"ETRAX 100LX", 10, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB - | HAS_MMU | HAS_MMU_BUG}, - - {"ETRAX 100LX v2", 11, 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB - | HAS_MMU}, -#ifdef CONFIG_ETRAXFS - {"ETRAX FS", 32, 32, HAS_ETHERNET100 | HAS_ATA | HAS_MMU}, -#else - {"ARTPEC-3", 32, 32, HAS_ETHERNET100 | HAS_MMU}, -#endif - {"Unknown", 0, 0, 0} -}; - -int show_cpuinfo(struct seq_file *m, void *v) -{ - int i; - int cpu = (int)v - 1; - unsigned long revision; - struct cpu_info *info; - - info = &cpinfo[ARRAY_SIZE(cpinfo) - 1]; - - revision = rdvr(); - - for (i = 0; i < ARRAY_SIZE(cpinfo); i++) { - if (cpinfo[i].rev == revision) { - info = &cpinfo[i]; - break; - } - } - - seq_printf(m, - "processor\t: %d\n" - "cpu\t\t: CRIS\n" - "cpu revision\t: %lu\n" - "cpu model\t: %s\n" - "cache size\t: %d KB\n" - "fpu\t\t: %s\n" - "mmu\t\t: %s\n" - "mmu DMA bug\t: %s\n" - "ethernet\t: %s Mbps\n" - "token ring\t: %s\n" - "scsi\t\t: %s\n" - "ata\t\t: %s\n" - "usb\t\t: %s\n" - "bogomips\t: %lu.%02lu\n\n", - - cpu, - revision, - info->cpu_model, - info->cache_size, - info->flags & HAS_FPU ? "yes" : "no", - info->flags & HAS_MMU ? "yes" : "no", - info->flags & HAS_MMU_BUG ? "yes" : "no", - info->flags & HAS_ETHERNET100 ? "10/100" : "10", - info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", - info->flags & HAS_SCSI ? "yes" : "no", - info->flags & HAS_ATA ? "yes" : "no", - info->flags & HAS_USB ? "yes" : "no", - (loops_per_jiffy * HZ + 500) / 500000, - ((loops_per_jiffy * HZ + 500) / 5000) % 100); - - return 0; -} - -#endif /* CONFIG_PROC_FS */ - -void show_etrax_copyright(void) -{ -#ifdef CONFIG_ETRAXFS - printk(KERN_INFO "Linux/CRISv32 port on ETRAX FS " - "(C) 2003, 2004 Axis Communications AB\n"); -#else - printk(KERN_INFO "Linux/CRISv32 port on ARTPEC-3 " - "(C) 2003-2009 Axis Communications AB\n"); -#endif -} - -static struct i2c_board_info __initdata i2c_info[] = { - {I2C_BOARD_INFO("camblock", 0x43)}, - {I2C_BOARD_INFO("tmp100", 0x48)}, - {I2C_BOARD_INFO("tmp100", 0x4A)}, - {I2C_BOARD_INFO("tmp100", 0x4C)}, - {I2C_BOARD_INFO("tmp100", 0x4D)}, - {I2C_BOARD_INFO("tmp100", 0x4E)}, -#ifdef CONFIG_RTC_DRV_PCF8563 - {I2C_BOARD_INFO("pcf8563", 0x51)}, -#endif - {I2C_BOARD_INFO("pca9536", 0x41)}, - {I2C_BOARD_INFO("fnp300", 0x40)}, - {I2C_BOARD_INFO("fnp300", 0x42)}, - {I2C_BOARD_INFO("adc101", 0x54)}, -}; - -static struct i2c_board_info __initdata i2c_info2[] = { - {I2C_BOARD_INFO("camblock", 0x43)}, - {I2C_BOARD_INFO("tmp100", 0x48)}, - {I2C_BOARD_INFO("tmp100", 0x4A)}, - {I2C_BOARD_INFO("tmp100", 0x4C)}, - {I2C_BOARD_INFO("tmp100", 0x4D)}, - {I2C_BOARD_INFO("tmp100", 0x4E)}, - {I2C_BOARD_INFO("pca9536", 0x41)}, - {I2C_BOARD_INFO("fnp300", 0x40)}, - {I2C_BOARD_INFO("fnp300", 0x42)}, - {I2C_BOARD_INFO("adc101", 0x54)}, -}; - -static struct i2c_board_info __initdata i2c_info3[] = { - {I2C_BOARD_INFO("adc101", 0x54)}, -}; - -static int __init etrax_init(void) -{ - i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info)); - i2c_register_board_info(1, i2c_info2, ARRAY_SIZE(i2c_info2)); - i2c_register_board_info(2, i2c_info3, ARRAY_SIZE(i2c_info3)); - return 0; -} -arch_initcall(etrax_init); diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c deleted file mode 100644 index 4f2e3ba3bf40..000000000000 --- a/arch/cris/arch-v32/kernel/signal.c +++ /dev/null @@ -1,541 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2003, Axis Communications AB. - */ - -#include <linux/sched.h> -#include <linux/sched/task_stack.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/wait.h> -#include <linux/ptrace.h> -#include <linux/unistd.h> -#include <linux/stddef.h> -#include <linux/syscalls.h> -#include <linux/vmalloc.h> - -#include <asm/io.h> -#include <asm/processor.h> -#include <asm/ucontext.h> -#include <linux/uaccess.h> -#include <arch/hwregs/cpu_vect.h> - -extern unsigned long cris_signal_return_page; - -/* - * A syscall in CRIS is really a "break 13" instruction, which is 2 - * bytes. The registers is manipulated so upon return the instruction - * will be executed again. - * - * This relies on that PC points to the instruction after the break call. - */ -#define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->erp -= 2; - -/* Signal frames. */ -struct signal_frame { - struct sigcontext sc; - unsigned long extramask[_NSIG_WORDS - 1]; - unsigned char retcode[8]; /* Trampoline code. */ -}; - -struct rt_signal_frame { - struct siginfo *pinfo; - void *puc; - struct siginfo info; - struct ucontext uc; - unsigned char retcode[8]; /* Trampoline code. */ -}; - -void do_signal(int restart, struct pt_regs *regs); -void keep_debug_flags(unsigned long oldccs, unsigned long oldspc, - struct pt_regs *regs); - -static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) -{ - unsigned int err = 0; - unsigned long old_usp; - - /* Always make any pending restarted system calls return -EINTR */ - current->restart_block.fn = do_no_restart_syscall; - - /* - * Restore the registers from &sc->regs. sc is already checked - * for VERIFY_READ since the signal_frame was previously - * checked in sys_sigreturn(). - */ - if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) - goto badframe; - - /* Make that the user-mode flag is set. */ - regs->ccs |= (1 << (U_CCS_BITNR + CCS_SHIFT)); - - /* Don't perform syscall restarting */ - regs->exs = -1; - - /* Restore the old USP. */ - err |= __get_user(old_usp, &sc->usp); - wrusp(old_usp); - - return err; - -badframe: - return 1; -} - -asmlinkage int sys_sigreturn(void) -{ - struct pt_regs *regs = current_pt_regs(); - sigset_t set; - struct signal_frame __user *frame; - unsigned long oldspc = regs->spc; - unsigned long oldccs = regs->ccs; - - frame = (struct signal_frame *) rdusp(); - - /* - * Since the signal is stacked on a dword boundary, the frame - * should be dword aligned here as well. It it's not, then the - * user is trying some funny business. - */ - if (((long)frame) & 3) - goto badframe; - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - - if (__get_user(set.sig[0], &frame->sc.oldmask) || - (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], - frame->extramask, - sizeof(frame->extramask)))) - goto badframe; - - set_current_blocked(&set); - - if (restore_sigcontext(regs, &frame->sc)) - goto badframe; - - keep_debug_flags(oldccs, oldspc, regs); - - return regs->r10; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - -asmlinkage int sys_rt_sigreturn(void) -{ - struct pt_regs *regs = current_pt_regs(); - sigset_t set; - struct rt_signal_frame __user *frame; - unsigned long oldspc = regs->spc; - unsigned long oldccs = regs->ccs; - - frame = (struct rt_signal_frame *) rdusp(); - - /* - * Since the signal is stacked on a dword boundary, the frame - * should be dword aligned here as well. It it's not, then the - * user is trying some funny business. - */ - if (((long)frame) & 3) - goto badframe; - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - set_current_blocked(&set); - - if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) - goto badframe; - - if (restore_altstack(&frame->uc.uc_stack)) - goto badframe; - - keep_debug_flags(oldccs, oldspc, regs); - - return regs->r10; - -badframe: - force_sig(SIGSEGV, current); - return 0; -} - -/* Setup a signal frame. */ -static int -setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, - unsigned long mask) -{ - int err; - unsigned long usp; - - err = 0; - usp = rdusp(); - - /* - * Copy the registers. They are located first in sc, so it's - * possible to use sc directly. - */ - err |= __copy_to_user(sc, regs, sizeof(struct pt_regs)); - - err |= __put_user(mask, &sc->oldmask); - err |= __put_user(usp, &sc->usp); - - return err; -} - -/* Figure out where to put the new signal frame - usually on the stack. */ -static inline void __user * -get_sigframe(struct ksignal *ksig, size_t frame_size) -{ - unsigned long sp = sigsp(rdusp(), ksig); - - /* Make sure the frame is dword-aligned. */ - sp &= ~3; - - return (void __user *)(sp - frame_size); -} - -/* Grab and setup a signal frame. - * - * Basically a lot of state-info is stacked, and arranged for the - * user-mode program to return to the kernel using either a trampiline - * which performs the syscall sigreturn(), or a provided user-mode - * trampoline. - */ -static int -setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) -{ - int err; - unsigned long return_ip; - struct signal_frame __user *frame; - - err = 0; - frame = get_sigframe(ksig, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return -EFAULT; - - err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); - - if (err) - return -EFAULT; - - if (_NSIG_WORDS > 1) { - err |= __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); - } - - if (err) - return -EFAULT; - - /* - * Set up to return from user-space. If provided, use a stub - * already located in user-space. - */ - if (ksig->ka.sa.sa_flags & SA_RESTORER) { - return_ip = (unsigned long)ksig->ka.sa.sa_restorer; - } else { - /* Trampoline - the desired return ip is in the signal return page. */ - return_ip = cris_signal_return_page; - - /* - * This is movu.w __NR_sigreturn, r9; break 13; - * - * WE DO NOT USE IT ANY MORE! It's only left here for historical - * reasons and because gdb uses it as a signature to notice - * signal handler stack frames. - */ - err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); - err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2)); - err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); - } - - if (err) - return -EFAULT; - - /* - * Set up registers for signal handler. - * - * Where the code enters now. - * Where the code enter later. - * First argument, signo. - */ - regs->erp = (unsigned long) ksig->ka.sa.sa_handler; - regs->srp = return_ip; - regs->r10 = ksig->sig; - - /* Actually move the USP to reflect the stacked frame. */ - wrusp((unsigned long)frame); - - return 0; -} - -static int -setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) -{ - int err; - unsigned long return_ip; - struct rt_signal_frame __user *frame; - - err = 0; - frame = get_sigframe(ksig, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - return -EFAULT; - - err |= __put_user(&frame->info, &frame->pinfo); - err |= __put_user(&frame->uc, &frame->puc); - err |= copy_siginfo_to_user(&frame->info, &ksig->info); - - if (err) - return -EFAULT; - - /* Clear all the bits of the ucontext we don't use. */ - err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - err |= __save_altstack(&frame->uc.uc_stack, rdusp()); - - if (err) - return -EFAULT; - - /* - * Set up to return from user-space. If provided, use a stub - * already located in user-space. - */ - if (ksig->ka.sa.sa_flags & SA_RESTORER) { - return_ip = (unsigned long) ksig->ka.sa.sa_restorer; - } else { - /* Trampoline - the desired return ip is in the signal return page. */ - return_ip = cris_signal_return_page + 6; - - /* - * This is movu.w __NR_rt_sigreturn, r9; break 13; - * - * WE DO NOT USE IT ANY MORE! It's only left here for historical - * reasons and because gdb uses it as a signature to notice - * signal handler stack frames. - */ - err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); - - err |= __put_user(__NR_rt_sigreturn, - (short __user*)(frame->retcode+2)); - - err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); - } - - if (err) - return -EFAULT; - - /* - * Set up registers for signal handler. - * - * Where the code enters now. - * Where the code enters later. - * First argument is signo. - * Second argument is (siginfo_t *). - * Third argument is unused. - */ - regs->erp = (unsigned long) ksig->ka.sa.sa_handler; - regs->srp = return_ip; - regs->r10 = ksig->sig; - regs->r11 = (unsigned long) &frame->info; - regs->r12 = 0; - - /* Actually move the usp to reflect the stacked frame. */ - wrusp((unsigned long)frame); - - return 0; -} - -/* Invoke a signal handler to, well, handle the signal. */ -static inline void -handle_signal(int canrestart, struct ksignal *ksig, struct pt_regs *regs) -{ - sigset_t *oldset = sigmask_to_save(); - int ret; - - /* Check if this got called from a system call. */ - if (canrestart) { - /* If so, check system call restarting. */ - switch (regs->r10) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - /* - * This means that the syscall should - * only be restarted if there was no - * handler for the signal, and since - * this point isn't reached unless - * there is a handler, there's no need - * to restart. - */ - regs->r10 = -EINTR; - break; - - case -ERESTARTSYS: - /* - * This means restart the syscall if - * there is no handler, or the handler - * was registered with SA_RESTART. - */ - if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { - regs->r10 = -EINTR; - break; - } - - /* Fall through. */ - - case -ERESTARTNOINTR: - /* - * This means that the syscall should - * be called again after the signal - * handler returns. - */ - RESTART_CRIS_SYS(regs); - break; - } - } - - /* Set up the stack frame. */ - if (ksig->ka.sa.sa_flags & SA_SIGINFO) - ret = setup_rt_frame(ksig, oldset, regs); - else - ret = setup_frame(ksig, oldset, regs); - - signal_setup_done(ret, ksig, 0); -} - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - * - * Also note that the regs structure given here as an argument, is the latest - * pushed pt_regs. It may or may not be the same as the first pushed registers - * when the initial usermode->kernelmode transition took place. Therefore - * we can use user_mode(regs) to see if we came directly from kernel or user - * mode below. - */ -void -do_signal(int canrestart, struct pt_regs *regs) -{ - struct ksignal ksig; - - canrestart = canrestart && ((int)regs->exs >= 0); - - /* - * The common case should go fast, which is why this point is - * reached from kernel-mode. If that's the case, just return - * without doing anything. - */ - if (!user_mode(regs)) - return; - - if (get_signal(&ksig)) { - /* Whee! Actually deliver the signal. */ - handle_signal(canrestart, &ksig, regs); - return; - } - - /* Got here from a system call? */ - if (canrestart) { - /* Restart the system call - no handlers present. */ - if (regs->r10 == -ERESTARTNOHAND || - regs->r10 == -ERESTARTSYS || - regs->r10 == -ERESTARTNOINTR) { - RESTART_CRIS_SYS(regs); - } - - if (regs->r10 == -ERESTART_RESTARTBLOCK){ - regs->r9 = __NR_restart_syscall; - regs->erp -= 2; - } - } - - /* if there's no signal to deliver, we just put the saved sigmask - * back */ - restore_saved_sigmask(); -} - -asmlinkage void -ugdb_trap_user(struct thread_info *ti, int sig) -{ - if (((user_regs(ti)->exs & 0xff00) >> 8) != SINGLE_STEP_INTR_VECT) { - /* Zero single-step PC if the reason we stopped wasn't a single - step exception. This is to avoid relying on it when it isn't - reliable. */ - user_regs(ti)->spc = 0; - } - /* FIXME: Filter out false h/w breakpoint hits (i.e. EDA - not within any configured h/w breakpoint range). Synchronize with - what already exists for kernel debugging. */ - if (((user_regs(ti)->exs & 0xff00) >> 8) == BREAK_8_INTR_VECT) { - /* Break 8: subtract 2 from ERP unless in a delay slot. */ - if (!(user_regs(ti)->erp & 0x1)) - user_regs(ti)->erp -= 2; - } - sys_kill(ti->task->pid, sig); -} - -void -keep_debug_flags(unsigned long oldccs, unsigned long oldspc, - struct pt_regs *regs) -{ - if (oldccs & (1 << Q_CCS_BITNR)) { - /* Pending single step due to single-stepping the break 13 - in the signal trampoline: keep the Q flag. */ - regs->ccs |= (1 << Q_CCS_BITNR); - /* S flag should be set - complain if it's not. */ - if (!(oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT)))) { - printk("Q flag but no S flag?"); - } - regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT)); - /* Assume the SPC is valid and interesting. */ - regs->spc = oldspc; - - } else if (oldccs & (1 << (S_CCS_BITNR + CCS_SHIFT))) { - /* If a h/w bp was set in the signal handler we need - to keep the S flag. */ - regs->ccs |= (1 << (S_CCS_BITNR + CCS_SHIFT)); - /* Don't keep the old SPC though; if we got here due to - a single-step, the Q flag should have been set. */ - } else if (regs->spc) { - /* If we were single-stepping *before* the signal was taken, - we don't want to restore that state now, because GDB will - have forgotten all about it. */ - regs->spc = 0; - regs->ccs &= ~(1 << (S_CCS_BITNR + CCS_SHIFT)); - } -} - -/* Set up the trampolines on the signal return page. */ -int __init -cris_init_signal(void) -{ - u16* data = kmalloc(PAGE_SIZE, GFP_KERNEL); - - /* This is movu.w __NR_sigreturn, r9; break 13; */ - data[0] = 0x9c5f; - data[1] = __NR_sigreturn; - data[2] = 0xe93d; - /* This is movu.w __NR_rt_sigreturn, r9; break 13; */ - data[3] = 0x9c5f; - data[4] = __NR_rt_sigreturn; - data[5] = 0xe93d; - - /* Map to userspace with appropriate permissions (no write access...) */ - cris_signal_return_page = (unsigned long) - __ioremap_prot(virt_to_phys(data), PAGE_SIZE, PAGE_SIGNAL_TRAMPOLINE); - - return 0; -} - -__initcall(cris_init_signal); diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c deleted file mode 100644 index d07a3912687e..000000000000 --- a/arch/cris/arch-v32/kernel/time.c +++ /dev/null @@ -1,345 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * linux/arch/cris/arch-v32/kernel/time.c - * - * Copyright (C) 2003-2010 Axis Communications AB - * - */ - -#include <linux/timex.h> -#include <linux/time.h> -#include <linux/clocksource.h> -#include <linux/clockchips.h> -#include <linux/interrupt.h> -#include <linux/swap.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/cpufreq.h> -#include <linux/sched_clock.h> -#include <linux/mm.h> -#include <asm/types.h> -#include <asm/signal.h> -#include <asm/io.h> -#include <asm/delay.h> -#include <asm/irq.h> -#include <asm/irq_regs.h> - -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/timer_defs.h> -#include <hwregs/intr_vect_defs.h> -#ifdef CONFIG_CRIS_MACH_ARTPEC3 -#include <hwregs/clkgen_defs.h> -#endif - -/* Watchdog defines */ -#define ETRAX_WD_KEY_MASK 0x7F /* key is 7 bit */ -#define ETRAX_WD_HZ 763 /* watchdog counts at 763 Hz */ -/* Number of 763 counts before watchdog bites */ -#define ETRAX_WD_CNT ((2*ETRAX_WD_HZ)/HZ + 1) - -#define CRISV32_TIMER_FREQ (100000000lu) - -unsigned long timer_regs[NR_CPUS] = -{ - regi_timer0, -}; - -extern int set_rtc_mmss(unsigned long nowtime); - -#ifdef CONFIG_CPU_FREQ -static int cris_time_freq_notifier(struct notifier_block *nb, - unsigned long val, void *data); - -static struct notifier_block cris_time_freq_notifier_block = { - .notifier_call = cris_time_freq_notifier, -}; -#endif - -unsigned long get_ns_in_jiffie(void) -{ - reg_timer_r_tmr0_data data; - unsigned long ns; - - data = REG_RD(timer, regi_timer0, r_tmr0_data); - ns = (TIMER0_DIV - data) * 10; - return ns; -} - -/* From timer MDS describing the hardware watchdog: - * 4.3.1 Watchdog Operation - * The watchdog timer is an 8-bit timer with a configurable start value. - * Once started the watchdog counts downwards with a frequency of 763 Hz - * (100/131072 MHz). When the watchdog counts down to 1, it generates an - * NMI (Non Maskable Interrupt), and when it counts down to 0, it resets the - * chip. - */ -/* This gives us 1.3 ms to do something useful when the NMI comes */ - -/* Right now, starting the watchdog is the same as resetting it */ -#define start_watchdog reset_watchdog - -#if defined(CONFIG_ETRAX_WATCHDOG) -static short int watchdog_key = 42; /* arbitrary 7 bit number */ -#endif - -/* Number of pages to consider "out of memory". It is normal that the memory - * is used though, so set this really low. */ -#define WATCHDOG_MIN_FREE_PAGES 8 - -#if defined(CONFIG_ETRAX_WATCHDOG_NICE_DOGGY) -/* for reliable NICE_DOGGY behaviour */ -static int bite_in_progress; -#endif - -void reset_watchdog(void) -{ -#if defined(CONFIG_ETRAX_WATCHDOG) - reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; - -#if defined(CONFIG_ETRAX_WATCHDOG_NICE_DOGGY) - if (unlikely(bite_in_progress)) - return; -#endif - /* Only keep watchdog happy as long as we have memory left! */ - if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { - /* Reset the watchdog with the inverse of the old key */ - /* Invert key, which is 7 bits */ - watchdog_key ^= ETRAX_WD_KEY_MASK; - wd_ctrl.cnt = ETRAX_WD_CNT; - wd_ctrl.cmd = regk_timer_start; - wd_ctrl.key = watchdog_key; - REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); - } -#endif -} - -/* stop the watchdog - we still need the correct key */ - -void stop_watchdog(void) -{ -#if defined(CONFIG_ETRAX_WATCHDOG) - reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; - watchdog_key ^= ETRAX_WD_KEY_MASK; /* invert key, which is 7 bits */ - wd_ctrl.cnt = ETRAX_WD_CNT; - wd_ctrl.cmd = regk_timer_stop; - wd_ctrl.key = watchdog_key; - REG_WR(timer, regi_timer0, rw_wd_ctrl, wd_ctrl); -#endif -} - -extern void show_registers(struct pt_regs *regs); - -void handle_watchdog_bite(struct pt_regs *regs) -{ -#if defined(CONFIG_ETRAX_WATCHDOG) - extern int cause_of_death; - - nmi_enter(); - oops_in_progress = 1; -#if defined(CONFIG_ETRAX_WATCHDOG_NICE_DOGGY) - bite_in_progress = 1; -#endif - printk(KERN_WARNING "Watchdog bite\n"); - - /* Check if forced restart or unexpected watchdog */ - if (cause_of_death == 0xbedead) { -#ifdef CONFIG_CRIS_MACH_ARTPEC3 - /* There is a bug in Artpec-3 (voodoo TR 78) that requires - * us to go to lower frequency for the reset to be reliable - */ - reg_clkgen_rw_clk_ctrl ctrl = - REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); - ctrl.pll = 0; - REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, ctrl); -#endif - while(1); - } - - /* Unexpected watchdog, stop the watchdog and dump registers. */ - stop_watchdog(); - printk(KERN_WARNING "Oops: bitten by watchdog\n"); - show_registers(regs); - oops_in_progress = 0; - printk("\n"); /* Flush mtdoops. */ -#ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY - reset_watchdog(); -#endif - while(1) /* nothing */; -#endif -} - -extern void cris_profile_sample(struct pt_regs *regs); -static void __iomem *timer_base; - -static int crisv32_clkevt_switch_state(struct clock_event_device *dev) -{ - reg_timer_rw_tmr0_ctrl ctrl = { - .op = regk_timer_hold, - .freq = regk_timer_f100, - }; - - REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); - return 0; -} - -static int crisv32_clkevt_next_event(unsigned long evt, - struct clock_event_device *dev) -{ - reg_timer_rw_tmr0_ctrl ctrl = { - .op = regk_timer_ld, - .freq = regk_timer_f100, - }; - - REG_WR(timer, timer_base, rw_tmr0_div, evt); - REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); - - ctrl.op = regk_timer_run; - REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); - - return 0; -} - -static irqreturn_t crisv32_timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; - reg_timer_rw_tmr0_ctrl ctrl = { - .op = regk_timer_hold, - .freq = regk_timer_f100, - }; - reg_timer_rw_ack_intr ack = { .tmr0 = 1 }; - reg_timer_r_masked_intr intr; - - intr = REG_RD(timer, timer_base, r_masked_intr); - if (!intr.tmr0) - return IRQ_NONE; - - REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); - REG_WR(timer, timer_base, rw_ack_intr, ack); - - reset_watchdog(); -#ifdef CONFIG_SYSTEM_PROFILER - cris_profile_sample(get_irq_regs()); -#endif - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - -static struct clock_event_device crisv32_clockevent = { - .name = "crisv32-timer", - .rating = 300, - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_state_oneshot = crisv32_clkevt_switch_state, - .set_state_shutdown = crisv32_clkevt_switch_state, - .tick_resume = crisv32_clkevt_switch_state, - .set_next_event = crisv32_clkevt_next_event, -}; - -/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ -static struct irqaction irq_timer = { - .handler = crisv32_timer_interrupt, - .flags = IRQF_TIMER | IRQF_SHARED, - .name = "crisv32-timer", - .dev_id = &crisv32_clockevent, -}; - -static u64 notrace crisv32_timer_sched_clock(void) -{ - return REG_RD(timer, timer_base, r_time); -} - -static void __init crisv32_timer_init(void) -{ - reg_timer_rw_intr_mask timer_intr_mask; - reg_timer_rw_tmr0_ctrl ctrl = { - .op = regk_timer_hold, - .freq = regk_timer_f100, - }; - - REG_WR(timer, timer_base, rw_tmr0_ctrl, ctrl); - - timer_intr_mask = REG_RD(timer, timer_base, rw_intr_mask); - timer_intr_mask.tmr0 = 1; - REG_WR(timer, timer_base, rw_intr_mask, timer_intr_mask); -} - -void __init time_init(void) -{ - int irq; - int ret; - - /* Probe for the RTC and read it if it exists. - * Before the RTC can be probed the loops_per_usec variable needs - * to be initialized to make usleep work. A better value for - * loops_per_usec is calculated by the kernel later once the - * clock has started. - */ - loops_per_usec = 50; - - irq = TIMER0_INTR_VECT; - timer_base = (void __iomem *) regi_timer0; - - crisv32_timer_init(); - - sched_clock_register(crisv32_timer_sched_clock, 32, - CRISV32_TIMER_FREQ); - - clocksource_mmio_init(timer_base + REG_RD_ADDR_timer_r_time, - "crisv32-timer", CRISV32_TIMER_FREQ, - 300, 32, clocksource_mmio_readl_up); - - crisv32_clockevent.cpumask = cpu_possible_mask; - crisv32_clockevent.irq = irq; - - ret = setup_irq(irq, &irq_timer); - if (ret) - pr_warn("failed to setup irq %d\n", irq); - - clockevents_config_and_register(&crisv32_clockevent, - CRISV32_TIMER_FREQ, - 2, 0xffffffff); - - /* Enable watchdog if we should use one. */ - -#if defined(CONFIG_ETRAX_WATCHDOG) - printk(KERN_INFO "Enabling watchdog...\n"); - start_watchdog(); - - /* If we use the hardware watchdog, we want to trap it as an NMI - * and dump registers before it resets us. For this to happen, we - * must set the "m" NMI enable flag (which once set, is unset only - * when an NMI is taken). */ - { - unsigned long flags; - local_save_flags(flags); - flags |= (1<<30); /* NMI M flag is at bit 30 */ - local_irq_restore(flags); - } -#endif - -#ifdef CONFIG_CPU_FREQ - cpufreq_register_notifier(&cris_time_freq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); -#endif -} - -#ifdef CONFIG_CPU_FREQ -static int cris_time_freq_notifier(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct cpufreq_freqs *freqs = data; - if (val == CPUFREQ_POSTCHANGE) { - reg_timer_r_tmr0_data data; - reg_timer_rw_tmr0_div div = (freqs->new * 500) / HZ; - do { - data = REG_RD(timer, timer_regs[freqs->cpu], - r_tmr0_data); - } while (data > 20); - REG_WR(timer, timer_regs[freqs->cpu], rw_tmr0_div, div); - } - return 0; -} -#endif diff --git a/arch/cris/arch-v32/kernel/traps.c b/arch/cris/arch-v32/kernel/traps.c deleted file mode 100644 index ba54c7eccbaa..000000000000 --- a/arch/cris/arch-v32/kernel/traps.c +++ /dev/null @@ -1,196 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2003-2006, Axis Communications AB. - */ - -#include <linux/ptrace.h> -#include <linux/extable.h> -#include <linux/uaccess.h> -#include <linux/sched/debug.h> - -#include <hwregs/supp_reg.h> -#include <hwregs/intr_vect_defs.h> -#include <asm/irq.h> - -void show_registers(struct pt_regs *regs) -{ - /* - * It's possible to use either the USP register or current->thread.usp. - * USP might not correspond to the current process for all cases this - * function is called, and current->thread.usp isn't up to date for the - * current process. Experience shows that using USP is the way to go. - */ - unsigned long usp = rdusp(); - unsigned long d_mmu_cause; - unsigned long i_mmu_cause; - - printk("CPU: %d\n", smp_processor_id()); - - printk("ERP: %08lx SRP: %08lx CCS: %08lx USP: %08lx MOF: %08lx\n", - regs->erp, regs->srp, regs->ccs, usp, regs->mof); - - printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", - regs->r0, regs->r1, regs->r2, regs->r3); - - printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", - regs->r4, regs->r5, regs->r6, regs->r7); - - printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", - regs->r8, regs->r9, regs->r10, regs->r11); - - printk("r12: %08lx r13: %08lx oR10: %08lx acr: %08lx\n", - regs->r12, regs->r13, regs->orig_r10, regs->acr); - - printk(" sp: %08lx\n", (unsigned long)regs); - - SUPP_BANK_SEL(BANK_IM); - SUPP_REG_RD(RW_MM_CAUSE, i_mmu_cause); - - SUPP_BANK_SEL(BANK_DM); - SUPP_REG_RD(RW_MM_CAUSE, d_mmu_cause); - - printk(" Data MMU Cause: %08lx\n", d_mmu_cause); - printk("Instruction MMU Cause: %08lx\n", i_mmu_cause); - - printk("Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, (unsigned long)current); - - /* - * When in-kernel, we also print out the stack and code at the - * time of the fault.. - */ - if (!user_mode(regs)) { - int i; - - show_stack(NULL, (unsigned long *)usp); - - /* - * If the previous stack-dump wasn't a kernel one, dump the - * kernel stack now. - */ - if (usp != 0) - show_stack(NULL, NULL); - - printk("\nCode: "); - - if (regs->erp < PAGE_OFFSET) - goto bad_value; - - /* - * Quite often the value at regs->erp doesn't point to the - * interesting instruction, which often is the previous - * instruction. So dump at an offset large enough that the - * instruction decoding should be in sync at the interesting - * point, but small enough to fit on a row. The regs->erp - * location is pointed out in a ksymoops-friendly way by - * wrapping the byte for that address in parenthesises. - */ - for (i = -12; i < 12; i++) { - unsigned char c; - - if (__get_user(c, &((unsigned char *)regs->erp)[i])) { -bad_value: - printk(" Bad IP value."); - break; - } - - if (i == 0) - printk("(%02x) ", c); - else - printk("%02x ", c); - } - printk("\n"); - } -} - -void arch_enable_nmi(void) -{ - unsigned long flags; - - local_save_flags(flags); - flags |= (1 << 30); /* NMI M flag is at bit 30 */ - local_irq_restore(flags); -} - -extern void (*nmi_handler)(struct pt_regs *); -void handle_nmi(struct pt_regs *regs) -{ -#ifdef CONFIG_ETRAXFS - reg_intr_vect_r_nmi r; -#endif - - if (nmi_handler) - nmi_handler(regs); - -#ifdef CONFIG_ETRAXFS - /* Wait until nmi is no longer active. */ - do { - r = REG_RD(intr_vect, regi_irq, r_nmi); - } while (r.ext == regk_intr_vect_on); -#endif -} - - -#ifdef CONFIG_BUG -extern void die_if_kernel(const char *str, struct pt_regs *regs, long err); - -/* Copy of the regs at BUG() time. */ -struct pt_regs BUG_regs; - -void do_BUG(char *file, unsigned int line) -{ - printk("kernel BUG at %s:%d!\n", file, line); - die_if_kernel("Oops", &BUG_regs, 0); -} -EXPORT_SYMBOL(do_BUG); - -void fixup_BUG(struct pt_regs *regs) -{ - BUG_regs = *regs; - -#ifdef CONFIG_DEBUG_BUGVERBOSE - /* - * Fixup the BUG arguments through exception handlers. - */ - { - const struct exception_table_entry *fixup; - - /* - * ERP points at the "break 14" + 2, compensate for the 2 - * bytes. - */ - fixup = search_exception_tables(instruction_pointer(regs) - 2); - if (fixup) { - /* Adjust the instruction pointer in the stackframe. */ - instruction_pointer(regs) = fixup->fixup; - arch_fixup(regs); - } - } -#else - /* Dont try to lookup the filename + line, just dump regs. */ - do_BUG("unknown", 0); -#endif -} - -/* - * Break 14 handler. Save regs and jump into the fixup_BUG. - */ -__asm__ ( ".text\n\t" - ".global breakh_BUG\n\t" - "breakh_BUG:\n\t" - SAVE_ALL - KGDB_FIXUP - "move.d $sp, $r10\n\t" - "jsr fixup_BUG\n\t" - "nop\n\t" - "jump ret_from_intr\n\t" - "nop\n\t"); - - -#ifdef CONFIG_DEBUG_BUGVERBOSE -void -handle_BUG(struct pt_regs *regs) -{ -} -#endif -#endif diff --git a/arch/cris/arch-v32/lib/Makefile b/arch/cris/arch-v32/lib/Makefile deleted file mode 100644 index e91cf02f625d..000000000000 --- a/arch/cris/arch-v32/lib/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for Etrax-specific library files.. -# - -lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o \ - csumcpfruser.o delay.o strcmp.o - diff --git a/arch/cris/arch-v32/lib/checksum.S b/arch/cris/arch-v32/lib/checksum.S deleted file mode 100644 index f773d4d93609..000000000000 --- a/arch/cris/arch-v32/lib/checksum.S +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * A fast checksum routine using movem - * Copyright (c) 1998-2007 Axis Communications AB - * - * csum_partial(const unsigned char * buff, int len, unsigned int sum) - */ - - .globl csum_partial - .type csum_partial,@function -csum_partial: - - ;; r10 - src - ;; r11 - length - ;; r12 - checksum - - ;; Optimized for large packets - subq 10*4, $r11 - blt _word_loop - move.d $r11, $acr - - subq 9*4,$sp - clearf c - movem $r8,[$sp] - - ;; do a movem checksum - -_mloop: movem [$r10+],$r9 ; read 10 longwords - ;; Loop count without touching the c flag. - addoq -10*4, $acr, $acr - ;; perform dword checksumming on the 10 longwords - - addc $r0,$r12 - addc $r1,$r12 - addc $r2,$r12 - addc $r3,$r12 - addc $r4,$r12 - addc $r5,$r12 - addc $r6,$r12 - addc $r7,$r12 - addc $r8,$r12 - addc $r9,$r12 - - ;; test $acr without trashing carry. - move.d $acr, $acr - bpl _mloop - ;; r11 <= acr is not really needed in the mloop, just using the dslot - ;; to prepare for what is needed after mloop. - move.d $acr, $r11 - - ;; fold the last carry into r13 - addc 0, $r12 - movem [$sp+],$r8 ; restore regs - -_word_loop: - addq 10*4,$r11 ; compensate for last loop underflowing length - - moveq -1,$r9 ; put 0xffff in r9, faster than move.d 0xffff,r9 - lsrq 16,$r9 - - move.d $r12,$r13 - lsrq 16,$r13 ; r13 = checksum >> 16 - and.d $r9,$r12 ; checksum = checksum & 0xffff - -_no_fold: - subq 2,$r11 - blt _no_words - add.d $r13,$r12 ; checksum += r13 - - ;; checksum the rest of the words -_wloop: subq 2,$r11 - bge _wloop - addu.w [$r10+],$r12 - -_no_words: - addq 2,$r11 - ;; see if we have one odd byte more - bne _do_byte - nop - ret - move.d $r12,$r10 - -_do_byte: - ;; copy and checksum the last byte - addu.b [$r10],$r12 - ret - move.d $r12,$r10 - - .size csum_partial, .-csum_partial diff --git a/arch/cris/arch-v32/lib/checksumcopy.S b/arch/cris/arch-v32/lib/checksumcopy.S deleted file mode 100644 index a76e586d4114..000000000000 --- a/arch/cris/arch-v32/lib/checksumcopy.S +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * A fast checksum+copy routine using movem - * Copyright (c) 1998-2007 Axis Communications AB - * - * Authors: Bjorn Wesen - * - * csum_partial_copy_nocheck(const char *src, char *dst, - * int len, unsigned int sum) - */ - - .globl csum_partial_copy_nocheck - .type csum_partial_copy_nocheck,@function -csum_partial_copy_nocheck: - - ;; r10 - src - ;; r11 - dst - ;; r12 - length - ;; r13 - checksum - - ;; Optimized for large packets - subq 10*4, $r12 - blt _word_loop - move.d $r12, $acr - - subq 9*4,$sp - clearf c - movem $r8,[$sp] - - ;; do a movem copy and checksum -1: ;; A failing userspace access (the read) will have this as PC. -_mloop: movem [$r10+],$r9 ; read 10 longwords - addoq -10*4, $acr, $acr ; loop counter in latency cycle - movem $r9,[$r11+] ; write 10 longwords - - ;; perform dword checksumming on the 10 longwords - addc $r0,$r13 - addc $r1,$r13 - addc $r2,$r13 - addc $r3,$r13 - addc $r4,$r13 - addc $r5,$r13 - addc $r6,$r13 - addc $r7,$r13 - addc $r8,$r13 - addc $r9,$r13 - - ;; test $acr, without trashing carry. - move.d $acr, $acr - bpl _mloop - ;; r12 <= acr is needed after mloop and in the exception handlers. - move.d $acr, $r12 - - ;; fold the last carry into r13 - addc 0, $r13 - movem [$sp+],$r8 ; restore regs - -_word_loop: - addq 10*4,$r12 ; compensate for last loop underflowing length - - ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below - ;; r9 can be used as temporary. - move.d $r13,$r9 - lsrq 16,$r9 ; r0 = checksum >> 16 - and.d 0xffff,$r13 ; checksum = checksum & 0xffff - - subq 2, $r12 - blt _no_words - add.d $r9,$r13 ; checksum += r0 - - ;; copy and checksum the rest of the words -2: ;; A failing userspace access for the read below will have this as PC. -_wloop: move.w [$r10+],$r9 - addu.w $r9,$r13 - subq 2,$r12 - bge _wloop - move.w $r9,[$r11+] - -_no_words: - addq 2,$r12 - bne _do_byte - nop - ret - move.d $r13,$r10 - -_do_byte: - ;; copy and checksum the last byte -3: ;; A failing userspace access for the read below will have this as PC. - move.b [$r10],$r9 - addu.b $r9,$r13 - move.b $r9,[$r11] - ret - move.d $r13,$r10 - - .size csum_partial_copy_nocheck, . - csum_partial_copy_nocheck diff --git a/arch/cris/arch-v32/lib/csumcpfruser.S b/arch/cris/arch-v32/lib/csumcpfruser.S deleted file mode 100644 index 093cd757fcfa..000000000000 --- a/arch/cris/arch-v32/lib/csumcpfruser.S +++ /dev/null @@ -1,70 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into - * csum_partial_copy_from_user by adding exception records. - * - * Copyright (C) 2001, 2003 Axis Communications AB. - * - * Author: Hans-Peter Nilsson. - */ - -#include <asm/errno.h> - -/* Same function body, but a different name. If we just added exception - records to _csum_partial_copy_nocheck and made it generic, we wouldn't - know a user fault from a kernel fault and we would have overhead in - each kernel caller for the error-pointer argument. - - unsigned int csum_partial_copy_from_user - (const char *src, char *dst, int len, unsigned int sum, int *errptr); - - Note that the errptr argument is only set if we encounter an error. - It is conveniently located on the stack, so the normal function body - does not have to handle it. */ - -#define csum_partial_copy_nocheck csum_partial_copy_from_user - -/* There are local labels numbered 1, 2 and 3 present to mark the - different from-user accesses. */ -#include "checksumcopy.S" - - .section .fixup,"ax" - -;; Here from the movem loop; restore stack. -4: - movem [$sp+],$r8 -;; r12 is already decremented. Add back chunk_size-2. - addq 40-2,$r12 - -;; Here from the word loop; r12 is off by 2; add it back. -5: - addq 2,$r12 - -;; Here from a failing single byte. -6: - -;; Signal in *errptr that we had a failing access. - move.d [$sp],$acr - moveq -EFAULT,$r9 - subq 4,$sp - move.d $r9,[$acr] - -;; Clear the rest of the destination area using memset. Preserve the -;; checksum for the readable bytes. - move.d $r13,[$sp] - subq 4,$sp - move.d $r11,$r10 - move $srp,[$sp] - jsr memset - clear.d $r11 - - move [$sp+],$srp - ret - move.d [$sp+],$r10 - - .previous - .section __ex_table,"a" - .dword 1b,4b - .dword 2b,5b - .dword 3b,6b - .previous diff --git a/arch/cris/arch-v32/lib/delay.c b/arch/cris/arch-v32/lib/delay.c deleted file mode 100644 index db06a94ef646..000000000000 --- a/arch/cris/arch-v32/lib/delay.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Precise Delay Loops for ETRAX FS - * - * Copyright (C) 2006 Axis Communications AB. - * - */ - -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/timer_defs.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/module.h> - -/* - * On ETRAX FS, we can check the free-running read-only 100MHz timer - * getting 32-bit 10ns precision, theoretically good for 42.94967295 - * seconds. Unsigned arithmetic and careful expression handles - * wrapping. - */ - -void cris_delay10ns(u32 n10ns) -{ - u32 t0 = REG_RD(timer, regi_timer0, r_time); - while (REG_RD(timer, regi_timer0, r_time) - t0 < n10ns) - ; -} -EXPORT_SYMBOL(cris_delay10ns); diff --git a/arch/cris/arch-v32/lib/memset.c b/arch/cris/arch-v32/lib/memset.c deleted file mode 100644 index c94ea9b3ec29..000000000000 --- a/arch/cris/arch-v32/lib/memset.c +++ /dev/null @@ -1,259 +0,0 @@ -/* A memset for CRIS. - Copyright (C) 1999-2005 Axis Communications. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Neither the name of Axis Communications nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY AXIS COMMUNICATIONS AND ITS CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AXIS - COMMUNICATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. */ - -/* FIXME: This file should really only be used for reference, as the - result is somewhat depending on gcc generating what we expect rather - than what we describe. An assembly file should be used instead. */ - -/* Note the multiple occurrence of the expression "12*4", including the - asm. It is hard to get it into the asm in a good way. Thus better to - expose the problem everywhere: no macro. */ - -/* Assuming one cycle per dword written or read (ok, not really true; the - world is not ideal), and one cycle per instruction, then 43+3*(n/48-1) - <= 24+24*(n/48-1) so n >= 45.7; n >= 0.9; we win on the first full - 48-byte block to set. */ - -#define MEMSET_BY_BLOCK_THRESHOLD (1 * 48) - -/* No name ambiguities in this file. */ -__asm__ (".syntax no_register_prefix"); - -void *memset(void *pdst, int c, unsigned int plen) -{ - /* Now we want the parameters in special registers. Make sure the - compiler does something usable with this. */ - - register char *return_dst __asm__ ("r10") = pdst; - register int n __asm__ ("r12") = plen; - register int lc __asm__ ("r11") = c; - - /* Most apps use memset sanely. Memsetting about 3..4 bytes or less get - penalized here compared to the generic implementation. */ - - /* This is fragile performancewise at best. Check with newer GCC - releases, if they compile cascaded "x |= x << 8" to sane code. */ - __asm__("movu.b %0,r13 \n\ - lslq 8,r13 \n\ - move.b %0,r13 \n\ - move.d r13,%0 \n\ - lslq 16,r13 \n\ - or.d r13,%0" - : "=r" (lc) /* Inputs. */ - : "0" (lc) /* Outputs. */ - : "r13"); /* Trash. */ - - { - register char *dst __asm__ ("r13") = pdst; - - if (((unsigned long) pdst & 3) != 0 - /* Oops! n = 0 must be a valid call, regardless of alignment. */ - && n >= 3) - { - if ((unsigned long) dst & 1) - { - *dst = (char) lc; - n--; - dst++; - } - - if ((unsigned long) dst & 2) - { - *(short *) dst = lc; - n -= 2; - dst += 2; - } - } - - /* Decide which setting method to use. */ - if (n >= MEMSET_BY_BLOCK_THRESHOLD) - { - /* It is not optimal to tell the compiler about clobbering any - registers; that will move the saving/restoring of those registers - to the function prologue/epilogue, and make non-block sizes - suboptimal. */ - __asm__ volatile - ("\ - ;; GCC does promise correct register allocations, but let's \n\ - ;; make sure it keeps its promises. \n\ - .ifnc %0-%1-%4,$r13-$r12-$r11 \n\ - .error \"GCC reg alloc bug: %0-%1-%4 != $r13-$r12-$r11\" \n\ - .endif \n\ - \n\ - ;; Save the registers we'll clobber in the movem process \n\ - ;; on the stack. Don't mention them to gcc, it will only be \n\ - ;; upset. \n\ - subq 11*4,sp \n\ - movem r10,[sp] \n\ - \n\ - move.d r11,r0 \n\ - move.d r11,r1 \n\ - move.d r11,r2 \n\ - move.d r11,r3 \n\ - move.d r11,r4 \n\ - move.d r11,r5 \n\ - move.d r11,r6 \n\ - move.d r11,r7 \n\ - move.d r11,r8 \n\ - move.d r11,r9 \n\ - move.d r11,r10 \n\ - \n\ - ;; Now we've got this: \n\ - ;; r13 - dst \n\ - ;; r12 - n \n\ - \n\ - ;; Update n for the first loop \n\ - subq 12*4,r12 \n\ -0: \n\ -" -#ifdef __arch_common_v10_v32 - /* Cater to branch offset difference between v32 and v10. We - assume the branch below has an 8-bit offset. */ -" setf\n" -#endif -" subq 12*4,r12 \n\ - bge 0b \n\ - movem r11,[r13+] \n\ - \n\ - ;; Compensate for last loop underflowing n. \n\ - addq 12*4,r12 \n\ - \n\ - ;; Restore registers from stack. \n\ - movem [sp+],r10" - - /* Outputs. */ - : "=r" (dst), "=r" (n) - - /* Inputs. */ - : "0" (dst), "1" (n), "r" (lc)); - } - - /* An ad-hoc unroll, used for 4*12-1..16 bytes. */ - while (n >= 16) - { - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - n -= 16; - } - - switch (n) - { - case 0: - break; - - case 1: - *dst = (char) lc; - break; - - case 2: - *(short *) dst = (short) lc; - break; - - case 3: - *(short *) dst = (short) lc; dst += 2; - *dst = (char) lc; - break; - - case 4: - *(long *) dst = lc; - break; - - case 5: - *(long *) dst = lc; dst += 4; - *dst = (char) lc; - break; - - case 6: - *(long *) dst = lc; dst += 4; - *(short *) dst = (short) lc; - break; - - case 7: - *(long *) dst = lc; dst += 4; - *(short *) dst = (short) lc; dst += 2; - *dst = (char) lc; - break; - - case 8: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; - break; - - case 9: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *dst = (char) lc; - break; - - case 10: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(short *) dst = (short) lc; - break; - - case 11: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(short *) dst = (short) lc; dst += 2; - *dst = (char) lc; - break; - - case 12: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; - break; - - case 13: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *dst = (char) lc; - break; - - case 14: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(short *) dst = (short) lc; - break; - - case 15: - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(long *) dst = lc; dst += 4; - *(short *) dst = (short) lc; dst += 2; - *dst = (char) lc; - break; - } - } - - return return_dst; -} diff --git a/arch/cris/arch-v32/lib/strcmp.S b/arch/cris/arch-v32/lib/strcmp.S deleted file mode 100644 index 8f7a1ee62591..000000000000 --- a/arch/cris/arch-v32/lib/strcmp.S +++ /dev/null @@ -1,21 +0,0 @@ -; strcmp.S -- CRISv32 version. -; Copyright (C) 2008 AXIS Communications AB -; Written by Edgar E. Iglesias -; -; This source code is licensed under the GNU General Public License, -; Version 2. See the file COPYING for more details. - - .global strcmp - .type strcmp,@function -strcmp: -1: - move.b [$r10+], $r12 - seq $r13 - sub.b [$r11+], $r12 - or.b $r12, $r13 - beq 1b - nop - - ret - movs.b $r12, $r10 - .size strcmp, . - strcmp diff --git a/arch/cris/arch-v32/lib/string.c b/arch/cris/arch-v32/lib/string.c deleted file mode 100644 index c7bd6ebdc93c..000000000000 --- a/arch/cris/arch-v32/lib/string.c +++ /dev/null @@ -1,236 +0,0 @@ -/* A memcpy for CRIS. - Copyright (C) 1994-2005 Axis Communications. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Neither the name of Axis Communications nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY AXIS COMMUNICATIONS AND ITS CONTRIBUTORS - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AXIS - COMMUNICATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. */ - -/* FIXME: This file should really only be used for reference, as the - result is somewhat depending on gcc generating what we expect rather - than what we describe. An assembly file should be used instead. */ - -#include <stddef.h> - -/* Break even between movem and move16 is really at 38.7 * 2, but - modulo 44, so up to the next multiple of 44, we use ordinary code. */ -#define MEMCPY_BY_BLOCK_THRESHOLD (44 * 2) - -/* No name ambiguities in this file. */ -__asm__ (".syntax no_register_prefix"); - -void * -memcpy(void *pdst, const void *psrc, size_t pn) -{ - /* Now we want the parameters put in special registers. - Make sure the compiler is able to make something useful of this. - As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). - - If gcc was allright, it really would need no temporaries, and no - stack space to save stuff on. */ - - register void *return_dst __asm__ ("r10") = pdst; - register unsigned char *dst __asm__ ("r13") = pdst; - register unsigned const char *src __asm__ ("r11") = psrc; - register int n __asm__ ("r12") = pn; - - /* When src is aligned but not dst, this makes a few extra needless - cycles. I believe it would take as many to check that the - re-alignment was unnecessary. */ - if (((unsigned long) dst & 3) != 0 - /* Don't align if we wouldn't copy more than a few bytes; so we - don't have to check further for overflows. */ - && n >= 3) - { - if ((unsigned long) dst & 1) - { - n--; - *dst = *src; - src++; - dst++; - } - - if ((unsigned long) dst & 2) - { - n -= 2; - *(short *) dst = *(short *) src; - src += 2; - dst += 2; - } - } - - /* Decide which copying method to use. */ - if (n >= MEMCPY_BY_BLOCK_THRESHOLD) - { - /* It is not optimal to tell the compiler about clobbering any - registers; that will move the saving/restoring of those registers - to the function prologue/epilogue, and make non-movem sizes - suboptimal. */ - __asm__ volatile - ("\ - ;; GCC does promise correct register allocations, but let's \n\ - ;; make sure it keeps its promises. \n\ - .ifnc %0-%1-%2,$r13-$r11-$r12 \n\ - .error \"GCC reg alloc bug: %0-%1-%4 != $r13-$r12-$r11\" \n\ - .endif \n\ - \n\ - ;; Save the registers we'll use in the movem process \n\ - ;; on the stack. \n\ - subq 11*4,sp \n\ - movem r10,[sp] \n\ - \n\ - ;; Now we've got this: \n\ - ;; r11 - src \n\ - ;; r13 - dst \n\ - ;; r12 - n \n\ - \n\ - ;; Update n for the first loop. \n\ - subq 44,r12 \n\ -0: \n\ -" -#ifdef __arch_common_v10_v32 - /* Cater to branch offset difference between v32 and v10. We - assume the branch below has an 8-bit offset. */ -" setf\n" -#endif -" movem [r11+],r10 \n\ - subq 44,r12 \n\ - bge 0b \n\ - movem r10,[r13+] \n\ - \n\ - ;; Compensate for last loop underflowing n. \n\ - addq 44,r12 \n\ - \n\ - ;; Restore registers from stack. \n\ - movem [sp+],r10" - - /* Outputs. */ - : "=r" (dst), "=r" (src), "=r" (n) - - /* Inputs. */ - : "0" (dst), "1" (src), "2" (n)); - } - - while (n >= 16) - { - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - - n -= 16; - } - - switch (n) - { - case 0: - break; - - case 1: - *dst = *src; - break; - - case 2: - *(short *) dst = *(short *) src; - break; - - case 3: - *(short *) dst = *(short *) src; dst += 2; src += 2; - *dst = *src; - break; - - case 4: - *(long *) dst = *(long *) src; - break; - - case 5: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *dst = *src; - break; - - case 6: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(short *) dst = *(short *) src; - break; - - case 7: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(short *) dst = *(short *) src; dst += 2; src += 2; - *dst = *src; - break; - - case 8: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; - break; - - case 9: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *dst = *src; - break; - - case 10: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(short *) dst = *(short *) src; - break; - - case 11: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(short *) dst = *(short *) src; dst += 2; src += 2; - *dst = *src; - break; - - case 12: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; - break; - - case 13: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *dst = *src; - break; - - case 14: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(short *) dst = *(short *) src; - break; - - case 15: - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(long *) dst = *(long *) src; dst += 4; src += 4; - *(short *) dst = *(short *) src; dst += 2; src += 2; - *dst = *src; - break; - } - - return return_dst; -} diff --git a/arch/cris/arch-v32/lib/usercopy.c b/arch/cris/arch-v32/lib/usercopy.c deleted file mode 100644 index 04e78b6ffa22..000000000000 --- a/arch/cris/arch-v32/lib/usercopy.c +++ /dev/null @@ -1,458 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * User address space access functions. - * The non-inlined parts of asm-cris/uaccess.h are here. - * - * Copyright (C) 2000, 2003 Axis Communications AB. - * - * Written by Hans-Peter Nilsson. - * Pieces used from memcpy, originally by Kenny Ranerup long time ago. - */ - -#include <linux/uaccess.h> - -/* Asm:s have been tweaked (within the domain of correctness) to give - satisfactory results for "gcc version 3.2.1 Axis release R53/1.53-v32". - - Check regularly... - - Note that for CRISv32, the PC saved at a bus-fault is the address - *at* the faulting instruction, with a special case for instructions - in delay slots: then it's the address of the branch. Note also that - in contrast to v10, a postincrement in the instruction is *not* - performed at a bus-fault; the register is seen having the original - value in fault handlers. */ - - -/* Copy to userspace. This is based on the memcpy used for - kernel-to-kernel copying; see "string.c". */ - -unsigned long __copy_user(void __user *pdst, const void *psrc, unsigned long pn) -{ - /* We want the parameters put in special registers. - Make sure the compiler is able to make something useful of this. - As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). - - FIXME: Comment for old gcc version. Check. - If gcc was alright, it really would need no temporaries, and no - stack space to save stuff on. */ - - register char *dst __asm__ ("r13") = pdst; - register const char *src __asm__ ("r11") = psrc; - register int n __asm__ ("r12") = pn; - register int retn __asm__ ("r10") = 0; - - - /* When src is aligned but not dst, this makes a few extra needless - cycles. I believe it would take as many to check that the - re-alignment was unnecessary. */ - if (((unsigned long) dst & 3) != 0 - /* Don't align if we wouldn't copy more than a few bytes; so we - don't have to check further for overflows. */ - && n >= 3) - { - if ((unsigned long) dst & 1) - { - __asm_copy_to_user_1 (dst, src, retn); - n--; - } - - if ((unsigned long) dst & 2) - { - __asm_copy_to_user_2 (dst, src, retn); - n -= 2; - } - } - - /* Movem is dirt cheap. The overheap is low enough to always use the - minimum possible block size as the threshold. */ - if (n >= 44) - { - /* For large copies we use 'movem'. */ - - /* It is not optimal to tell the compiler about clobbering any - registers; that will move the saving/restoring of those registers - to the function prologue/epilogue, and make non-movem sizes - suboptimal. */ - __asm__ volatile ("\ - ;; Check that the register asm declaration got right. \n\ - ;; The GCC manual explicitly says TRT will happen. \n\ - .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ - .err \n\ - .endif \n\ - \n\ - ;; Save the registers we'll use in the movem process \n\ - ;; on the stack. \n\ - subq 11*4,$sp \n\ - movem $r10,[$sp] \n\ - \n\ - ;; Now we've got this: \n\ - ;; r11 - src \n\ - ;; r13 - dst \n\ - ;; r12 - n \n\ - \n\ - ;; Update n for the first loop \n\ - subq 44,$r12 \n\ -0: \n\ - movem [$r11+],$r10 \n\ - subq 44,$r12 \n\ -1: bge 0b \n\ - movem $r10,[$r13+] \n\ -3: \n\ - addq 44,$r12 ;; compensate for last loop underflowing n \n\ - \n\ - ;; Restore registers from stack \n\ - movem [$sp+],$r10 \n\ -2: \n\ - .section .fixup,\"ax\" \n\ -4: \n\ -; When failing on any of the 1..44 bytes in a chunk, we adjust back the \n\ -; source pointer and just drop through to the by-16 and by-4 loops to \n\ -; get the correct number of failing bytes. This necessarily means a \n\ -; few extra exceptions, but invalid user pointers shouldn't happen in \n\ -; time-critical code anyway. \n\ - jump 3b \n\ - subq 44,$r11 \n\ - \n\ - .previous \n\ - .section __ex_table,\"a\" \n\ - .dword 1b,4b \n\ - .previous" - - /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn) - /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn)); - - } - - while (n >= 16) - { - __asm_copy_to_user_16 (dst, src, retn); - n -= 16; - } - - /* Having a separate by-four loops cuts down on cache footprint. - FIXME: Test with and without; increasing switch to be 0..15. */ - while (n >= 4) - { - __asm_copy_to_user_4 (dst, src, retn); - n -= 4; - } - - switch (n) - { - case 0: - break; - case 1: - __asm_copy_to_user_1 (dst, src, retn); - break; - case 2: - __asm_copy_to_user_2 (dst, src, retn); - break; - case 3: - __asm_copy_to_user_3 (dst, src, retn); - break; - } - - return retn; -} -EXPORT_SYMBOL(__copy_user); - -/* Copy from user to kernel. The return-value is the number of bytes that were - inaccessible. */ -unsigned long __copy_user_in(void *pdst, const void __user *psrc, - unsigned long pn) -{ - /* We want the parameters put in special registers. - Make sure the compiler is able to make something useful of this. - As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). - - FIXME: Comment for old gcc version. Check. - If gcc was alright, it really would need no temporaries, and no - stack space to save stuff on. */ - - register char *dst __asm__ ("r13") = pdst; - register const char *src __asm__ ("r11") = psrc; - register int n __asm__ ("r12") = pn; - register int retn __asm__ ("r10") = 0; - - /* The best reason to align src is that we then know that a read-fault - was for aligned bytes; there's no 1..3 remaining good bytes to - pickle. */ - if (((unsigned long) src & 3) != 0) - { - if (((unsigned long) src & 1) && n != 0) - { - __asm_copy_from_user_1 (dst, src, retn); - n--; - if (retn != 0) - goto exception; - } - - if (((unsigned long) src & 2) && n >= 2) - { - __asm_copy_from_user_2 (dst, src, retn); - n -= 2; - if (retn != 0) - goto exception; - } - - } - - /* Movem is dirt cheap. The overheap is low enough to always use the - minimum possible block size as the threshold. */ - if (n >= 44) - { - /* It is not optimal to tell the compiler about clobbering any - registers; that will move the saving/restoring of those registers - to the function prologue/epilogue, and make non-movem sizes - suboptimal. */ - __asm__ volatile ("\ - .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ - .err \n\ - .endif \n\ - \n\ - ;; Save the registers we'll use in the movem process \n\ - ;; on the stack. \n\ - subq 11*4,$sp \n\ - movem $r10,[$sp] \n\ - \n\ - ;; Now we've got this: \n\ - ;; r11 - src \n\ - ;; r13 - dst \n\ - ;; r12 - n \n\ - \n\ - ;; Update n for the first loop \n\ - subq 44,$r12 \n\ -0: \n\ - movem [$r11+],$r10 \n\ - \n\ - subq 44,$r12 \n\ - bge 0b \n\ - movem $r10,[$r13+] \n\ - \n\ -4: \n\ - addq 44,$r12 ;; compensate for last loop underflowing n \n\ - \n\ - ;; Restore registers from stack \n\ - movem [$sp+],$r10 \n\ - .section .fixup,\"ax\" \n\ - \n\ -;; Do not jump back into the loop if we fail. For some uses, we get a \n\ -;; page fault somewhere on the line. Without checking for page limits, \n\ -;; we don't know where, but we need to copy accurately and keep an \n\ -;; accurate count; not just clear the whole line. To do that, we fall \n\ -;; down in the code below, proceeding with smaller amounts. It should \n\ -;; be kept in mind that we have to cater to code like what at one time \n\ -;; was in fs/super.c: \n\ -;; i = size - copy_from_user((void *)page, data, size); \n\ -;; which would cause repeated faults while clearing the remainder of \n\ -;; the SIZE bytes at PAGE after the first fault. \n\ -;; A caveat here is that we must not fall through from a failing page \n\ -;; to a valid page. \n\ - \n\ -3: \n\ - jump 4b ;; Fall through, pretending the fault didn't happen. \n\ - nop \n\ - \n\ - .previous \n\ - .section __ex_table,\"a\" \n\ - .dword 0b,3b \n\ - .previous" - - /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn) - /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn)); - } - - /* Either we directly start copying here, using dword copying in a loop, - or we copy as much as possible with 'movem' and then the last block - (<44 bytes) is copied here. This will work since 'movem' will have - updated src, dst and n. (Except with failing src.) - - Since we want to keep src accurate, we can't use - __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and - retn, but not src (by design; it's value is ignored elsewhere). */ - - while (n >= 4) - { - __asm_copy_from_user_4 (dst, src, retn); - n -= 4; - - if (retn) - goto exception; - } - - /* If we get here, there were no memory read faults. */ - switch (n) - { - /* These copies are at least "naturally aligned" (so we don't have - to check each byte), due to the src alignment code before the - movem loop. The *_3 case *will* get the correct count for retn. */ - case 0: - /* This case deliberately left in (if you have doubts check the - generated assembly code). */ - break; - case 1: - __asm_copy_from_user_1 (dst, src, retn); - break; - case 2: - __asm_copy_from_user_2 (dst, src, retn); - break; - case 3: - __asm_copy_from_user_3 (dst, src, retn); - break; - } - - /* If we get here, retn correctly reflects the number of failing - bytes. */ - return retn; - -exception: - return retn + n; -} -EXPORT_SYMBOL(__copy_user_in); - -/* Zero userspace. */ -unsigned long __do_clear_user(void __user *pto, unsigned long pn) -{ - /* We want the parameters put in special registers. - Make sure the compiler is able to make something useful of this. - As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). - - FIXME: Comment for old gcc version. Check. - If gcc was alright, it really would need no temporaries, and no - stack space to save stuff on. */ - - register char *dst __asm__ ("r13") = pto; - register int n __asm__ ("r12") = pn; - register int retn __asm__ ("r10") = 0; - - - if (((unsigned long) dst & 3) != 0 - /* Don't align if we wouldn't copy more than a few bytes. */ - && n >= 3) - { - if ((unsigned long) dst & 1) - { - __asm_clear_1 (dst, retn); - n--; - } - - if ((unsigned long) dst & 2) - { - __asm_clear_2 (dst, retn); - n -= 2; - } - } - - /* Decide which copying method to use. - FIXME: This number is from the "ordinary" kernel memset. */ - if (n >= 48) - { - /* For large clears we use 'movem' */ - - /* It is not optimal to tell the compiler about clobbering any - call-saved registers; that will move the saving/restoring of - those registers to the function prologue/epilogue, and make - non-movem sizes suboptimal. - - This method is not foolproof; it assumes that the "asm reg" - declarations at the beginning of the function really are used - here (beware: they may be moved to temporary registers). - This way, we do not have to save/move the registers around into - temporaries; we can safely use them straight away. - - If you want to check that the allocation was right; then - check the equalities in the first comment. It should say - something like "r13=r13, r11=r11, r12=r12". */ - __asm__ volatile ("\ - .ifnc %0%1%2,$r13$r12$r10 \n\ - .err \n\ - .endif \n\ - \n\ - ;; Save the registers we'll clobber in the movem process \n\ - ;; on the stack. Don't mention them to gcc, it will only be \n\ - ;; upset. \n\ - subq 11*4,$sp \n\ - movem $r10,[$sp] \n\ - \n\ - clear.d $r0 \n\ - clear.d $r1 \n\ - clear.d $r2 \n\ - clear.d $r3 \n\ - clear.d $r4 \n\ - clear.d $r5 \n\ - clear.d $r6 \n\ - clear.d $r7 \n\ - clear.d $r8 \n\ - clear.d $r9 \n\ - clear.d $r10 \n\ - clear.d $r11 \n\ - \n\ - ;; Now we've got this: \n\ - ;; r13 - dst \n\ - ;; r12 - n \n\ - \n\ - ;; Update n for the first loop \n\ - subq 12*4,$r12 \n\ -0: \n\ - subq 12*4,$r12 \n\ -1: \n\ - bge 0b \n\ - movem $r11,[$r13+] \n\ - \n\ - addq 12*4,$r12 ;; compensate for last loop underflowing n \n\ - \n\ - ;; Restore registers from stack \n\ - movem [$sp+],$r10 \n\ -2: \n\ - .section .fixup,\"ax\" \n\ -3: \n\ - movem [$sp],$r10 \n\ - addq 12*4,$r10 \n\ - addq 12*4,$r13 \n\ - movem $r10,[$sp] \n\ - jump 0b \n\ - clear.d $r10 \n\ - \n\ - .previous \n\ - .section __ex_table,\"a\" \n\ - .dword 1b,3b \n\ - .previous" - - /* Outputs */ : "=r" (dst), "=r" (n), "=r" (retn) - /* Inputs */ : "0" (dst), "1" (n), "2" (retn) - /* Clobber */ : "r11"); - } - - while (n >= 16) - { - __asm_clear_16 (dst, retn); - n -= 16; - } - - /* Having a separate by-four loops cuts down on cache footprint. - FIXME: Test with and without; increasing switch to be 0..15. */ - while (n >= 4) - { - __asm_clear_4 (dst, retn); - n -= 4; - } - - switch (n) - { - case 0: - break; - case 1: - __asm_clear_1 (dst, retn); - break; - case 2: - __asm_clear_2 (dst, retn); - break; - case 3: - __asm_clear_3 (dst, retn); - break; - } - - return retn; -} -EXPORT_SYMBOL(__do_clear_user); diff --git a/arch/cris/arch-v32/mach-a3/Kconfig b/arch/cris/arch-v32/mach-a3/Kconfig deleted file mode 100644 index 7b63755544dd..000000000000 --- a/arch/cris/arch-v32/mach-a3/Kconfig +++ /dev/null @@ -1,111 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -if CRIS_MACH_ARTPEC3 - -menu "Artpec-3 options" - depends on CRIS_MACH_ARTPEC3 - -config ETRAX_DRAM_VIRTUAL_BASE - hex - default "c0000000" - -config ETRAX_L2CACHE - bool - default y - -config ETRAX_SERIAL_PORTS - int - default 5 - -config ETRAX_DDR2_MRS - hex "DDR2 MRS" - default "0" - -config ETRAX_DDR2_TIMING - hex "DDR2 SDRAM timing" - default "0" - help - SDRAM timing parameters. - -config ETRAX_DDR2_CONFIG - hex "DDR2 config" - default "0" - -config ETRAX_DDR2_LATENCY - hex "DDR2 latency" - default "0" - -config ETRAX_PIO_CE0_CFG - hex "PIO CE0 configuration" - default "0" - -config ETRAX_PIO_CE1_CFG - hex "PIO CE1 configuration" - default "0" - -config ETRAX_PIO_CE2_CFG - hex "PIO CE2 configuration" - default "0" - -config ETRAX_DEF_GIO_PA_OE - hex "GIO_PA_OE" - default "00000000" - help - Configures the direction of general port A bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PA_OUT - hex "GIO_PA_OUT" - default "00000000" - help - Configures the initial data for the general port A bits. Most - products should use 00 here. - -config ETRAX_DEF_GIO_PB_OE - hex "GIO_PB_OE" - default "000000000" - help - Configures the direction of general port B bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PB_OUT - hex "GIO_PB_OUT" - default "000000000" - help - Configures the initial data for the general port B bits. Most - products should use 00000 here. - -config ETRAX_DEF_GIO_PC_OE - hex "GIO_PC_OE" - default "00000" - help - Configures the direction of general port C bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PC_OUT - hex "GIO_PC_OUT" - default "00000" - help - Configures the initial data for the general port C bits. Most - products should use 00000 here. - -endmenu - -endif diff --git a/arch/cris/arch-v32/mach-a3/Makefile b/arch/cris/arch-v32/mach-a3/Makefile deleted file mode 100644 index 0cc6eebacbed..000000000000 --- a/arch/cris/arch-v32/mach-a3/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the linux kernel. -# - -obj-y := dma.o pinmux.o arbiter.o - -clean: - diff --git a/arch/cris/arch-v32/mach-a3/arbiter.c b/arch/cris/arch-v32/mach-a3/arbiter.c deleted file mode 100644 index 076182cc65a3..000000000000 --- a/arch/cris/arch-v32/mach-a3/arbiter.c +++ /dev/null @@ -1,635 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Memory arbiter functions. Allocates bandwidth through the - * arbiter and sets up arbiter breakpoints. - * - * The algorithm first assigns slots to the clients that has specified - * bandwidth (e.g. ethernet) and then the remaining slots are divided - * on all the active clients. - * - * Copyright (c) 2004-2007 Axis Communications AB. - * - * The artpec-3 has two arbiters. The memory hierarchy looks like this: - * - * - * CPU DMAs - * | | - * | | - * -------------- ------------------ - * | foo arbiter|----| Internal memory| - * -------------- ------------------ - * | - * -------------- - * | L2 cache | - * -------------- - * | - * h264 etc | - * | | - * | | - * -------------- - * | bar arbiter| - * -------------- - * | - * --------- - * | SDRAM | - * --------- - * - */ - -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/marb_foo_defs.h> -#include <hwregs/marb_bar_defs.h> -#include <arbiter.h> -#include <hwregs/intr_vect.h> -#include <linux/interrupt.h> -#include <linux/irq.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/spinlock.h> -#include <asm/io.h> -#include <asm/irq_regs.h> - -#define D(x) - -struct crisv32_watch_entry { - unsigned long instance; - watch_callback *cb; - unsigned long start; - unsigned long end; - int used; -}; - -#define NUMBER_OF_BP 4 -#define SDRAM_BANDWIDTH 400000000 -#define INTMEM_BANDWIDTH 400000000 -#define NBR_OF_SLOTS 64 -#define NBR_OF_REGIONS 2 -#define NBR_OF_CLIENTS 15 -#define ARBITERS 2 -#define UNASSIGNED 100 - -struct arbiter { - unsigned long instance; - int nbr_regions; - int nbr_clients; - int requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; - int active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; -}; - -static struct crisv32_watch_entry watches[ARBITERS][NUMBER_OF_BP] = -{ - { - {regi_marb_foo_bp0}, - {regi_marb_foo_bp1}, - {regi_marb_foo_bp2}, - {regi_marb_foo_bp3} - }, - { - {regi_marb_bar_bp0}, - {regi_marb_bar_bp1}, - {regi_marb_bar_bp2}, - {regi_marb_bar_bp3} - } -}; - -struct arbiter arbiters[ARBITERS] = -{ - { /* L2 cache arbiter */ - .instance = regi_marb_foo, - .nbr_regions = 2, - .nbr_clients = 15 - }, - { /* DDR2 arbiter */ - .instance = regi_marb_bar, - .nbr_regions = 1, - .nbr_clients = 9 - } -}; - -static int max_bandwidth[NBR_OF_REGIONS] = {SDRAM_BANDWIDTH, INTMEM_BANDWIDTH}; - -DEFINE_SPINLOCK(arbiter_lock); - -static irqreturn_t -crisv32_foo_arbiter_irq(int irq, void *dev_id); -static irqreturn_t -crisv32_bar_arbiter_irq(int irq, void *dev_id); - -/* - * "I'm the arbiter, I know the score. - * From square one I'll be watching all 64." - * (memory arbiter slots, that is) - * - * Or in other words: - * Program the memory arbiter slots for "region" according to what's - * in requested_slots[] and active_clients[], while minimizing - * latency. A caller may pass a non-zero positive amount for - * "unused_slots", which must then be the unallocated, remaining - * number of slots, free to hand out to any client. - */ - -static void crisv32_arbiter_config(int arbiter, int region, int unused_slots) -{ - int slot; - int client; - int interval = 0; - - /* - * This vector corresponds to the hardware arbiter slots (see - * the hardware documentation for semantics). We initialize - * each slot with a suitable sentinel value outside the valid - * range {0 .. NBR_OF_CLIENTS - 1} and replace them with - * client indexes. Then it's fed to the hardware. - */ - s8 val[NBR_OF_SLOTS]; - - for (slot = 0; slot < NBR_OF_SLOTS; slot++) - val[slot] = -1; - - for (client = 0; client < arbiters[arbiter].nbr_clients; client++) { - int pos; - /* Allocate the requested non-zero number of slots, but - * also give clients with zero-requests one slot each - * while stocks last. We do the latter here, in client - * order. This makes sure zero-request clients are the - * first to get to any spare slots, else those slots - * could, when bandwidth is allocated close to the limit, - * all be allocated to low-index non-zero-request clients - * in the default-fill loop below. Another positive but - * secondary effect is a somewhat better spread of the - * zero-bandwidth clients in the vector, avoiding some of - * the latency that could otherwise be caused by the - * partitioning of non-zero-bandwidth clients at low - * indexes and zero-bandwidth clients at high - * indexes. (Note that this spreading can only affect the - * unallocated bandwidth.) All the above only matters for - * memory-intensive situations, of course. - */ - if (!arbiters[arbiter].requested_slots[region][client]) { - /* - * Skip inactive clients. Also skip zero-slot - * allocations in this pass when there are no known - * free slots. - */ - if (!arbiters[arbiter].active_clients[region][client] || - unused_slots <= 0) - continue; - - unused_slots--; - - /* Only allocate one slot for this client. */ - interval = NBR_OF_SLOTS; - } else - interval = NBR_OF_SLOTS / - arbiters[arbiter].requested_slots[region][client]; - - pos = 0; - while (pos < NBR_OF_SLOTS) { - if (val[pos] >= 0) - pos++; - else { - val[pos] = client; - pos += interval; - } - } - } - - client = 0; - for (slot = 0; slot < NBR_OF_SLOTS; slot++) { - /* - * Allocate remaining slots in round-robin - * client-number order for active clients. For this - * pass, we ignore requested bandwidth and previous - * allocations. - */ - if (val[slot] < 0) { - int first = client; - while (!arbiters[arbiter].active_clients[region][client]) { - client = (client + 1) % - arbiters[arbiter].nbr_clients; - if (client == first) - break; - } - val[slot] = client; - client = (client + 1) % arbiters[arbiter].nbr_clients; - } - if (arbiter == 0) { - if (region == EXT_REGION) - REG_WR_INT_VECT(marb_foo, regi_marb_foo, - rw_l2_slots, slot, val[slot]); - else if (region == INT_REGION) - REG_WR_INT_VECT(marb_foo, regi_marb_foo, - rw_intm_slots, slot, val[slot]); - } else { - REG_WR_INT_VECT(marb_bar, regi_marb_bar, - rw_ddr2_slots, slot, val[slot]); - } - } -} - -extern char _stext[], _etext[]; - -static void crisv32_arbiter_init(void) -{ - static int initialized; - - if (initialized) - return; - - initialized = 1; - - /* - * CPU caches are always set to active, but with zero - * bandwidth allocated. It should be ok to allocate zero - * bandwidth for the caches, because DMA for other channels - * will supposedly finish, once their programmed amount is - * done, and then the caches will get access according to the - * "fixed scheme" for unclaimed slots. Though, if for some - * use-case somewhere, there's a maximum CPU latency for - * e.g. some interrupt, we have to start allocating specific - * bandwidth for the CPU caches too. - */ - arbiters[0].active_clients[EXT_REGION][11] = 1; - arbiters[0].active_clients[EXT_REGION][12] = 1; - crisv32_arbiter_config(0, EXT_REGION, 0); - crisv32_arbiter_config(0, INT_REGION, 0); - crisv32_arbiter_config(1, EXT_REGION, 0); - - if (request_irq(MEMARB_FOO_INTR_VECT, crisv32_foo_arbiter_irq, - 0, "arbiter", NULL)) - printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); - - if (request_irq(MEMARB_BAR_INTR_VECT, crisv32_bar_arbiter_irq, - 0, "arbiter", NULL)) - printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); - -#ifndef CONFIG_ETRAX_KGDB - /* Global watch for writes to kernel text segment. */ - crisv32_arbiter_watch(virt_to_phys(_stext), _etext - _stext, - MARB_CLIENTS(arbiter_all_clients, arbiter_bar_all_clients), - arbiter_all_write, NULL); -#endif - - /* Set up max burst sizes by default */ - REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_rd_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_h264_wr_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_ccd_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_wr_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_vin_rd_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_rd_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_vout_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_sclr_fifo_burst, 3); - REG_WR_INT(marb_bar, regi_marb_bar, rw_l2cache_burst, 3); -} - -int crisv32_arbiter_allocate_bandwidth(int client, int region, - unsigned long bandwidth) -{ - int i; - int total_assigned = 0; - int total_clients = 0; - int req; - int arbiter = 0; - - crisv32_arbiter_init(); - - if (client & 0xffff0000) { - arbiter = 1; - client >>= 16; - } - - for (i = 0; i < arbiters[arbiter].nbr_clients; i++) { - total_assigned += arbiters[arbiter].requested_slots[region][i]; - total_clients += arbiters[arbiter].active_clients[region][i]; - } - - /* Avoid division by 0 for 0-bandwidth requests. */ - req = bandwidth == 0 - ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); - - /* - * We make sure that there are enough slots only for non-zero - * requests. Requesting 0 bandwidth *may* allocate slots, - * though if all bandwidth is allocated, such a client won't - * get any and will have to rely on getting memory access - * according to the fixed scheme that's the default when one - * of the slot-allocated clients doesn't claim their slot. - */ - if (total_assigned + req > NBR_OF_SLOTS) - return -ENOMEM; - - arbiters[arbiter].active_clients[region][client] = 1; - arbiters[arbiter].requested_slots[region][client] = req; - crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned); - - /* Propagate allocation from foo to bar */ - if (arbiter == 0) - crisv32_arbiter_allocate_bandwidth(8 << 16, - EXT_REGION, bandwidth); - return 0; -} - -/* - * Main entry for bandwidth deallocation. - * - * Strictly speaking, for a somewhat constant set of clients where - * each client gets a constant bandwidth and is just enabled or - * disabled (somewhat dynamically), no action is necessary here to - * avoid starvation for non-zero-allocation clients, as the allocated - * slots will just be unused. However, handing out those unused slots - * to active clients avoids needless latency if the "fixed scheme" - * would give unclaimed slots to an eager low-index client. - */ - -void crisv32_arbiter_deallocate_bandwidth(int client, int region) -{ - int i; - int total_assigned = 0; - int arbiter = 0; - - if (client & 0xffff0000) - arbiter = 1; - - arbiters[arbiter].requested_slots[region][client] = 0; - arbiters[arbiter].active_clients[region][client] = 0; - - for (i = 0; i < arbiters[arbiter].nbr_clients; i++) - total_assigned += arbiters[arbiter].requested_slots[region][i]; - - crisv32_arbiter_config(arbiter, region, NBR_OF_SLOTS - total_assigned); -} - -int crisv32_arbiter_watch(unsigned long start, unsigned long size, - unsigned long clients, unsigned long accesses, - watch_callback *cb) -{ - int i; - int arbiter; - int used[2]; - int ret = 0; - - crisv32_arbiter_init(); - - if (start > 0x80000000) { - printk(KERN_ERR "Arbiter: %lX doesn't look like a " - "physical address", start); - return -EFAULT; - } - - spin_lock(&arbiter_lock); - - if (clients & 0xffff) - used[0] = 1; - if (clients & 0xffff0000) - used[1] = 1; - - for (arbiter = 0; arbiter < ARBITERS; arbiter++) { - if (!used[arbiter]) - continue; - - for (i = 0; i < NUMBER_OF_BP; i++) { - if (!watches[arbiter][i].used) { - unsigned intr_mask; - if (arbiter) - intr_mask = REG_RD_INT(marb_bar, - regi_marb_bar, rw_intr_mask); - else - intr_mask = REG_RD_INT(marb_foo, - regi_marb_foo, rw_intr_mask); - - watches[arbiter][i].used = 1; - watches[arbiter][i].start = start; - watches[arbiter][i].end = start + size; - watches[arbiter][i].cb = cb; - - ret |= (i + 1) << (arbiter + 8); - if (arbiter) { - REG_WR_INT(marb_bar_bp, - watches[arbiter][i].instance, - rw_first_addr, - watches[arbiter][i].start); - REG_WR_INT(marb_bar_bp, - watches[arbiter][i].instance, - rw_last_addr, - watches[arbiter][i].end); - REG_WR_INT(marb_bar_bp, - watches[arbiter][i].instance, - rw_op, accesses); - REG_WR_INT(marb_bar_bp, - watches[arbiter][i].instance, - rw_clients, - clients & 0xffff); - } else { - REG_WR_INT(marb_foo_bp, - watches[arbiter][i].instance, - rw_first_addr, - watches[arbiter][i].start); - REG_WR_INT(marb_foo_bp, - watches[arbiter][i].instance, - rw_last_addr, - watches[arbiter][i].end); - REG_WR_INT(marb_foo_bp, - watches[arbiter][i].instance, - rw_op, accesses); - REG_WR_INT(marb_foo_bp, - watches[arbiter][i].instance, - rw_clients, clients >> 16); - } - - if (i == 0) - intr_mask |= 1; - else if (i == 1) - intr_mask |= 2; - else if (i == 2) - intr_mask |= 4; - else if (i == 3) - intr_mask |= 8; - - if (arbiter) - REG_WR_INT(marb_bar, regi_marb_bar, - rw_intr_mask, intr_mask); - else - REG_WR_INT(marb_foo, regi_marb_foo, - rw_intr_mask, intr_mask); - - spin_unlock(&arbiter_lock); - - break; - } - } - } - spin_unlock(&arbiter_lock); - if (ret) - return ret; - else - return -ENOMEM; -} - -int crisv32_arbiter_unwatch(int id) -{ - int arbiter; - int intr_mask; - - crisv32_arbiter_init(); - - spin_lock(&arbiter_lock); - - for (arbiter = 0; arbiter < ARBITERS; arbiter++) { - int id2; - - if (arbiter) - intr_mask = REG_RD_INT(marb_bar, regi_marb_bar, - rw_intr_mask); - else - intr_mask = REG_RD_INT(marb_foo, regi_marb_foo, - rw_intr_mask); - - id2 = (id & (0xff << (arbiter + 8))) >> (arbiter + 8); - if (id2 == 0) - continue; - id2--; - if ((id2 >= NUMBER_OF_BP) || (!watches[arbiter][id2].used)) { - spin_unlock(&arbiter_lock); - return -EINVAL; - } - - memset(&watches[arbiter][id2], 0, - sizeof(struct crisv32_watch_entry)); - - if (id2 == 0) - intr_mask &= ~1; - else if (id2 == 1) - intr_mask &= ~2; - else if (id2 == 2) - intr_mask &= ~4; - else if (id2 == 3) - intr_mask &= ~8; - - if (arbiter) - REG_WR_INT(marb_bar, regi_marb_bar, rw_intr_mask, - intr_mask); - else - REG_WR_INT(marb_foo, regi_marb_foo, rw_intr_mask, - intr_mask); - } - - spin_unlock(&arbiter_lock); - return 0; -} - -extern void show_registers(struct pt_regs *regs); - - -static irqreturn_t -crisv32_foo_arbiter_irq(int irq, void *dev_id) -{ - reg_marb_foo_r_masked_intr masked_intr = - REG_RD(marb_foo, regi_marb_foo, r_masked_intr); - reg_marb_foo_bp_r_brk_clients r_clients; - reg_marb_foo_bp_r_brk_addr r_addr; - reg_marb_foo_bp_r_brk_op r_op; - reg_marb_foo_bp_r_brk_first_client r_first; - reg_marb_foo_bp_r_brk_size r_size; - reg_marb_foo_bp_rw_ack ack = {0}; - reg_marb_foo_rw_ack_intr ack_intr = { - .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 - }; - struct crisv32_watch_entry *watch; - unsigned arbiter = (unsigned)dev_id; - - masked_intr = REG_RD(marb_foo, regi_marb_foo, r_masked_intr); - - if (masked_intr.bp0) - watch = &watches[arbiter][0]; - else if (masked_intr.bp1) - watch = &watches[arbiter][1]; - else if (masked_intr.bp2) - watch = &watches[arbiter][2]; - else if (masked_intr.bp3) - watch = &watches[arbiter][3]; - else - return IRQ_NONE; - - /* Retrieve all useful information and print it. */ - r_clients = REG_RD(marb_foo_bp, watch->instance, r_brk_clients); - r_addr = REG_RD(marb_foo_bp, watch->instance, r_brk_addr); - r_op = REG_RD(marb_foo_bp, watch->instance, r_brk_op); - r_first = REG_RD(marb_foo_bp, watch->instance, r_brk_first_client); - r_size = REG_RD(marb_foo_bp, watch->instance, r_brk_size); - - printk(KERN_DEBUG "Arbiter IRQ\n"); - printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n", - REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_clients, r_clients), - REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_addr, r_addr), - REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_op, r_op), - REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_first_client, r_first), - REG_TYPE_CONV(int, reg_marb_foo_bp_r_brk_size, r_size)); - - REG_WR(marb_foo_bp, watch->instance, rw_ack, ack); - REG_WR(marb_foo, regi_marb_foo, rw_ack_intr, ack_intr); - - printk(KERN_DEBUG "IRQ occurred at %X\n", (unsigned)get_irq_regs()); - - if (watch->cb) - watch->cb(); - - return IRQ_HANDLED; -} - -static irqreturn_t -crisv32_bar_arbiter_irq(int irq, void *dev_id) -{ - reg_marb_bar_r_masked_intr masked_intr = - REG_RD(marb_bar, regi_marb_bar, r_masked_intr); - reg_marb_bar_bp_r_brk_clients r_clients; - reg_marb_bar_bp_r_brk_addr r_addr; - reg_marb_bar_bp_r_brk_op r_op; - reg_marb_bar_bp_r_brk_first_client r_first; - reg_marb_bar_bp_r_brk_size r_size; - reg_marb_bar_bp_rw_ack ack = {0}; - reg_marb_bar_rw_ack_intr ack_intr = { - .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 - }; - struct crisv32_watch_entry *watch; - unsigned arbiter = (unsigned)dev_id; - - masked_intr = REG_RD(marb_bar, regi_marb_bar, r_masked_intr); - - if (masked_intr.bp0) - watch = &watches[arbiter][0]; - else if (masked_intr.bp1) - watch = &watches[arbiter][1]; - else if (masked_intr.bp2) - watch = &watches[arbiter][2]; - else if (masked_intr.bp3) - watch = &watches[arbiter][3]; - else - return IRQ_NONE; - - /* Retrieve all useful information and print it. */ - r_clients = REG_RD(marb_bar_bp, watch->instance, r_brk_clients); - r_addr = REG_RD(marb_bar_bp, watch->instance, r_brk_addr); - r_op = REG_RD(marb_bar_bp, watch->instance, r_brk_op); - r_first = REG_RD(marb_bar_bp, watch->instance, r_brk_first_client); - r_size = REG_RD(marb_bar_bp, watch->instance, r_brk_size); - - printk(KERN_DEBUG "Arbiter IRQ\n"); - printk(KERN_DEBUG "Clients %X addr %X op %X first %X size %X\n", - REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_clients, r_clients), - REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_addr, r_addr), - REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_op, r_op), - REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_first_client, r_first), - REG_TYPE_CONV(int, reg_marb_bar_bp_r_brk_size, r_size)); - - REG_WR(marb_bar_bp, watch->instance, rw_ack, ack); - REG_WR(marb_bar, regi_marb_bar, rw_ack_intr, ack_intr); - - printk(KERN_DEBUG "IRQ occurred at %X\n", (unsigned)get_irq_regs()->erp); - - if (watch->cb) - watch->cb(); - - return IRQ_HANDLED; -} - diff --git a/arch/cris/arch-v32/mach-a3/dma.c b/arch/cris/arch-v32/mach-a3/dma.c deleted file mode 100644 index 3f4e923b2527..000000000000 --- a/arch/cris/arch-v32/mach-a3/dma.c +++ /dev/null @@ -1,184 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Wrapper for DMA channel allocator that starts clocks etc */ - -#include <linux/kernel.h> -#include <linux/spinlock.h> -#include <mach/dma.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/marb_defs.h> -#include <hwregs/clkgen_defs.h> -#include <hwregs/strmux_defs.h> -#include <linux/errno.h> -#include <arbiter.h> - -static char used_dma_channels[MAX_DMA_CHANNELS]; -static const char *used_dma_channels_users[MAX_DMA_CHANNELS]; - -static DEFINE_SPINLOCK(dma_lock); - -int crisv32_request_dma(unsigned int dmanr, const char *device_id, - unsigned options, unsigned int bandwidth, enum dma_owner owner) -{ - unsigned long flags; - reg_clkgen_rw_clk_ctrl clk_ctrl; - reg_strmux_rw_cfg strmux_cfg; - - if (crisv32_arbiter_allocate_bandwidth(dmanr, - options & DMA_INT_MEM ? INT_REGION : EXT_REGION, - bandwidth)) - return -ENOMEM; - - spin_lock_irqsave(&dma_lock, flags); - - if (used_dma_channels[dmanr]) { - spin_unlock_irqrestore(&dma_lock, flags); - if (options & DMA_VERBOSE_ON_ERROR) - printk(KERN_ERR "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; - } - clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); - strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); - - switch (dmanr) { - case 0: - case 1: - clk_ctrl.dma0_1_eth = 1; - break; - case 2: - case 3: - clk_ctrl.dma2_3_strcop = 1; - break; - case 4: - case 5: - clk_ctrl.dma4_5_iop = 1; - break; - case 6: - case 7: - clk_ctrl.sser_ser_dma6_7 = 1; - break; - case 9: - case 11: - clk_ctrl.dma9_11 = 1; - break; -#if MAX_DMA_CHANNELS-1 != 11 -#error Check dma.c -#endif - default: - spin_unlock_irqrestore(&dma_lock, flags); - if (options & DMA_VERBOSE_ON_ERROR) - printk(KERN_ERR "Failed to request DMA %i for %s, " - "only 0-%i valid)\n", - dmanr, device_id, MAX_DMA_CHANNELS-1); - - if (options & DMA_PANIC_ON_ERROR) - panic("request_dma error!"); - return -EINVAL; - } - - switch (owner) { - case dma_eth: - if (dmanr == 0) - strmux_cfg.dma0 = regk_strmux_eth; - else if (dmanr == 1) - strmux_cfg.dma1 = regk_strmux_eth; - else - panic("Invalid DMA channel for eth\n"); - break; - case dma_ser0: - if (dmanr == 0) - strmux_cfg.dma0 = regk_strmux_ser0; - else if (dmanr == 1) - strmux_cfg.dma1 = regk_strmux_ser0; - else - panic("Invalid DMA channel for ser0\n"); - break; - case dma_ser3: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_ser3; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_ser3; - else - panic("Invalid DMA channel for ser3\n"); - break; - case dma_strp: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_strcop; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_strcop; - else - panic("Invalid DMA channel for strp\n"); - break; - case dma_ser1: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_ser1; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_ser1; - else - panic("Invalid DMA channel for ser1\n"); - break; - case dma_iop: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_iop; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_iop; - else - panic("Invalid DMA channel for iop\n"); - break; - case dma_ser2: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_ser2; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_ser2; - else - panic("Invalid DMA channel for ser2\n"); - break; - case dma_sser: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_sser; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_sser; - else - panic("Invalid DMA channel for sser\n"); - break; - case dma_ser4: - if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_ser4; - else - panic("Invalid DMA channel for ser4\n"); - break; - case dma_jpeg: - if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_jpeg; - else - panic("Invalid DMA channel for JPEG\n"); - break; - case dma_h264: - if (dmanr == 11) - strmux_cfg.dma11 = regk_strmux_h264; - else - panic("Invalid DMA channel for H264\n"); - break; - } - - used_dma_channels[dmanr] = 1; - used_dma_channels_users[dmanr] = device_id; - REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); - REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); - spin_unlock_irqrestore(&dma_lock, flags); - return 0; -} - -void crisv32_free_dma(unsigned int dmanr) -{ - spin_lock(&dma_lock); - used_dma_channels[dmanr] = 0; - spin_unlock(&dma_lock); -} diff --git a/arch/cris/arch-v32/mach-a3/dram_init.S b/arch/cris/arch-v32/mach-a3/dram_init.S deleted file mode 100644 index 733c3564ad79..000000000000 --- a/arch/cris/arch-v32/mach-a3/dram_init.S +++ /dev/null @@ -1,119 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * DDR SDRAM initialization - alter with care - * This file is intended to be included from other assembler files - * - * Note: This file may not modify r8 or r9 because they are used to - * carry information from the decompressor to the kernel - * - * Copyright (C) 2005-2007 Axis Communications AB - * - * Authors: Mikael Starvik <starvik@axis.com> - */ - -/* Just to be certain the config file is included, we include it here - * explicitly instead of depending on it being included in the file that - * uses this code. - */ - -#include <hwregs/asm/reg_map_asm.h> -#include <hwregs/asm/ddr2_defs_asm.h> - - ;; WARNING! The registers r8 and r9 are used as parameters carrying - ;; information from the decompressor (if the kernel was compressed). - ;; They should not be used in the code below. - - ;; Refer to ddr2 MDS for initialization sequence - - ; 2. Wait 200us - move.d 10000, $r2 -1: bne 1b - subq 1, $r2 - - ; Start clock - move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_cfg), $r0 - move.d REG_STATE(ddr2, rw_phy_cfg, en, yes), $r1 - move.d $r1, [$r0] - - ; 2. Wait 200us - move.d 10000, $r2 -1: bne 1b - subq 1, $r2 - - ; Reset phy and start calibration - move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_phy_ctrl), $r0 - move.d REG_STATE(ddr2, rw_phy_ctrl, rst, yes) | \ - REG_STATE(ddr2, rw_phy_ctrl, cal_rst, yes), $r1 - move.d $r1, [$r0] - move.d REG_STATE(ddr2, rw_phy_ctrl, cal_start, yes), $r1 - move.d $r1, [$r0] - - ; 2. Wait 200us - move.d 10000, $r2 -1: bne 1b - subq 1, $r2 - - ; Issue commands - move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_ctrl), $r0 - move.d sdram_commands_start, $r2 -command_loop: - movu.b [$r2+], $r1 - movu.w [$r2+], $r3 -do_cmd: - lslq 16, $r1 - or.d $r3, $r1 - move.d $r1, [$r0] - ; 2. Wait 200us - move.d 10000, $r4 -1: bne 1b - subq 1, $r4 - cmp.d sdram_commands_end, $r2 - blo command_loop - nop - - ; Set timing - move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing), $r0 - move.d CONFIG_ETRAX_DDR2_TIMING, $r1 - move.d $r1, [$r0] - - ; Set latency - move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_latency), $r0 - move.d CONFIG_ETRAX_DDR2_LATENCY, $r1 - move.d $r1, [$r0] - - ; Set configuration - move.d REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg), $r0 - move.d CONFIG_ETRAX_DDR2_CONFIG, $r1 - move.d $r1, [$r0] - - ba after_sdram_commands - nop - -sdram_commands_start: - .byte regk_ddr2_deselect - .word 0 - .byte regk_ddr2_pre - .word regk_ddr2_pre_all - .byte regk_ddr2_emrs2 - .word 0 - .byte regk_ddr2_emrs3 - .word 0 - .byte regk_ddr2_emrs - .word regk_ddr2_dll_en - .byte regk_ddr2_mrs - .word regk_ddr2_dll_rst - .byte regk_ddr2_pre - .word regk_ddr2_pre_all - .byte regk_ddr2_ref - .word 0 - .byte regk_ddr2_ref - .word 0 - .byte regk_ddr2_mrs - .word CONFIG_ETRAX_DDR2_MRS & 0xffff - .byte regk_ddr2_emrs - .word regk_ddr2_ocd_default | regk_ddr2_dll_en - .byte regk_ddr2_emrs - .word regk_ddr2_ocd_exit | regk_ddr2_dll_en | (CONFIG_ETRAX_DDR2_MRS >> 16) -sdram_commands_end: - .align 1 -after_sdram_commands: diff --git a/arch/cris/arch-v32/mach-a3/hw_settings.S b/arch/cris/arch-v32/mach-a3/hw_settings.S deleted file mode 100644 index 7c325cc59e1f..000000000000 --- a/arch/cris/arch-v32/mach-a3/hw_settings.S +++ /dev/null @@ -1,54 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * This table is used by some tools to extract hardware parameters. - * The table should be included in the kernel and the decompressor. - * Don't forget to update the tools if you change this table. - * - * Copyright (C) 2001-2007 Axis Communications AB - * - * Authors: Mikael Starvik <starvik@axis.com> - */ - -#include <hwregs/asm/reg_map_asm.h> -#include <hwregs/asm/ddr2_defs_asm.h> -#include <hwregs/asm/gio_defs_asm.h> - - .ascii "HW_PARAM_MAGIC" ; Magic number - .dword 0xc0004000 ; Kernel start address - - ; Debug port -#ifdef CONFIG_ETRAX_DEBUG_PORT0 - .dword 0 -#elif defined(CONFIG_ETRAX_DEBUG_PORT1) - .dword 1 -#elif defined(CONFIG_ETRAX_DEBUG_PORT2) - .dword 2 -#elif defined(CONFIG_ETRAX_DEBUG_PORT3) - .dword 3 -#else - .dword 4 ; No debug -#endif - - ; Register values - .dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_cfg) - .dword CONFIG_ETRAX_DDR2_CONFIG - .dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_latency) - .dword CONFIG_ETRAX_DDR2_LATENCY - .dword REG_ADDR(ddr2, regi_ddr2_ctrl, rw_timing) - .dword CONFIG_ETRAX_DDR2_TIMING - .dword CONFIG_ETRAX_DDR2_MRS - - .dword REG_ADDR(gio, regi_gio, rw_pa_dout) - .dword CONFIG_ETRAX_DEF_GIO_PA_OUT - .dword REG_ADDR(gio, regi_gio, rw_pa_oe) - .dword CONFIG_ETRAX_DEF_GIO_PA_OE - .dword REG_ADDR(gio, regi_gio, rw_pb_dout) - .dword CONFIG_ETRAX_DEF_GIO_PB_OUT - .dword REG_ADDR(gio, regi_gio, rw_pb_oe) - .dword CONFIG_ETRAX_DEF_GIO_PB_OE - .dword REG_ADDR(gio, regi_gio, rw_pc_dout) - .dword CONFIG_ETRAX_DEF_GIO_PC_OUT - .dword REG_ADDR(gio, regi_gio, rw_pc_oe) - .dword CONFIG_ETRAX_DEF_GIO_PC_OE - - .dword 0 ; No more register values diff --git a/arch/cris/arch-v32/mach-a3/pinmux.c b/arch/cris/arch-v32/mach-a3/pinmux.c deleted file mode 100644 index 4875bf7aa53f..000000000000 --- a/arch/cris/arch-v32/mach-a3/pinmux.c +++ /dev/null @@ -1,389 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Allocator for I/O pins. All pins are allocated to GPIO at bootup. - * Unassigned pins and GPIO pins can be allocated to a fixed interface - * or the I/O processor instead. - * - * Copyright (c) 2005-2007 Axis Communications AB. - */ - -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/spinlock.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <pinmux.h> -#include <hwregs/pinmux_defs.h> -#include <hwregs/clkgen_defs.h> - -#undef DEBUG - -#define PINS 80 -#define PORT_PINS 32 -#define PORTS 3 - -static char pins[PINS]; -static DEFINE_SPINLOCK(pinmux_lock); - -static void crisv32_pinmux_set(int port); - -int -crisv32_pinmux_init(void) -{ - static int initialized; - - if (!initialized) { - initialized = 1; - REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0); - crisv32_pinmux_alloc(PORT_A, 0, 31, pinmux_gpio); - crisv32_pinmux_alloc(PORT_B, 0, 31, pinmux_gpio); - crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_gpio); - } - - return 0; -} - -int -crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) -{ - int i; - unsigned long flags; - - crisv32_pinmux_init(); - - if (port >= PORTS) - return -EINVAL; - - spin_lock_irqsave(&pinmux_lock, flags); - - for (i = first_pin; i <= last_pin; i++) { - if ((pins[port * PORT_PINS + i] != pinmux_none) && - (pins[port * PORT_PINS + i] != pinmux_gpio) && - (pins[port * PORT_PINS + i] != mode)) { - spin_unlock_irqrestore(&pinmux_lock, flags); -#ifdef DEBUG - panic("Pinmux alloc failed!\n"); -#endif - return -EPERM; - } - } - - for (i = first_pin; i <= last_pin; i++) - pins[port * PORT_PINS + i] = mode; - - crisv32_pinmux_set(port); - - spin_unlock_irqrestore(&pinmux_lock, flags); - - return 0; -} - -int -crisv32_pinmux_alloc_fixed(enum fixed_function function) -{ - int ret = -EINVAL; - char saved[sizeof pins]; - unsigned long flags; - reg_pinmux_rw_hwprot hwprot; - reg_clkgen_rw_clk_ctrl clk_ctrl; - - spin_lock_irqsave(&pinmux_lock, flags); - - /* Save internal data for recovery */ - memcpy(saved, pins, sizeof pins); - - crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ - - hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); - clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); - - switch (function) { - case pinmux_eth: - clk_ctrl.eth = regk_clkgen_yes; - clk_ctrl.dma0_1_eth = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_B, 8, 23, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_B, 24, 25, pinmux_fixed); - hwprot.eth = hwprot.eth_mdio = regk_pinmux_yes; - break; - case pinmux_geth: - ret = crisv32_pinmux_alloc(PORT_B, 0, 7, pinmux_fixed); - hwprot.geth = regk_pinmux_yes; - break; - case pinmux_tg_cmos: - clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_B, 27, 29, pinmux_fixed); - hwprot.tg_clk = regk_pinmux_yes; - break; - case pinmux_tg_ccd: - clk_ctrl.ccd_tg_100 = clk_ctrl.ccd_tg_200 = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_B, 27, 31, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_C, 0, 15, pinmux_fixed); - hwprot.tg = hwprot.tg_clk = regk_pinmux_yes; - break; - case pinmux_vout: - clk_ctrl.strdma0_2_video = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_A, 8, 18, pinmux_fixed); - hwprot.vout = hwprot.vout_sync = regk_pinmux_yes; - break; - case pinmux_ser1: - clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_A, 24, 25, pinmux_fixed); - hwprot.ser1 = regk_pinmux_yes; - break; - case pinmux_ser2: - clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_A, 26, 27, pinmux_fixed); - hwprot.ser2 = regk_pinmux_yes; - break; - case pinmux_ser3: - clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_A, 28, 29, pinmux_fixed); - hwprot.ser3 = regk_pinmux_yes; - break; - case pinmux_ser4: - clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_A, 30, 31, pinmux_fixed); - hwprot.ser4 = regk_pinmux_yes; - break; - case pinmux_sser: - clk_ctrl.sser_ser_dma6_7 = regk_clkgen_yes; - ret = crisv32_pinmux_alloc(PORT_A, 19, 23, pinmux_fixed); - hwprot.sser = regk_pinmux_yes; - break; - case pinmux_pio: - hwprot.pio = regk_pinmux_yes; - ret = 0; - break; - case pinmux_pwm0: - ret = crisv32_pinmux_alloc(PORT_A, 30, 30, pinmux_fixed); - hwprot.pwm0 = regk_pinmux_yes; - break; - case pinmux_pwm1: - ret = crisv32_pinmux_alloc(PORT_A, 31, 31, pinmux_fixed); - hwprot.pwm1 = regk_pinmux_yes; - break; - case pinmux_pwm2: - ret = crisv32_pinmux_alloc(PORT_B, 26, 26, pinmux_fixed); - hwprot.pwm2 = regk_pinmux_yes; - break; - case pinmux_i2c0: - ret = crisv32_pinmux_alloc(PORT_A, 0, 1, pinmux_fixed); - hwprot.i2c0 = regk_pinmux_yes; - break; - case pinmux_i2c1: - ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); - hwprot.i2c1 = regk_pinmux_yes; - break; - case pinmux_i2c1_3wire: - ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_A, 7, 7, pinmux_fixed); - hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_yes; - break; - case pinmux_i2c1_sda1: - ret = crisv32_pinmux_alloc(PORT_A, 2, 4, pinmux_fixed); - hwprot.i2c1 = hwprot.i2c1_sda1 = regk_pinmux_yes; - break; - case pinmux_i2c1_sda2: - ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_A, 5, 5, pinmux_fixed); - hwprot.i2c1 = hwprot.i2c1_sda2 = regk_pinmux_yes; - break; - case pinmux_i2c1_sda3: - ret = crisv32_pinmux_alloc(PORT_A, 2, 3, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_A, 6, 6, pinmux_fixed); - hwprot.i2c1 = hwprot.i2c1_sda3 = regk_pinmux_yes; - break; - default: - ret = -EINVAL; - break; - } - - if (!ret) { - REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); - REG_WR(clkgen, regi_clkgen, rw_clk_ctrl, clk_ctrl); - } else - memcpy(pins, saved, sizeof pins); - - spin_unlock_irqrestore(&pinmux_lock, flags); - - return ret; -} - -void -crisv32_pinmux_set(int port) -{ - int i; - int gpio_val = 0; - int iop_val = 0; - int pin = port * PORT_PINS; - - for (i = 0; (i < PORT_PINS) && (pin < PINS); i++, pin++) { - if (pins[pin] == pinmux_gpio) - gpio_val |= (1 << i); - else if (pins[pin] == pinmux_iop) - iop_val |= (1 << i); - } - - REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_gio_pa + 4 * port, - gpio_val); - REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_iop_pa + 4 * port, - iop_val); - -#ifdef DEBUG - crisv32_pinmux_dump(); -#endif -} - -int -crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) -{ - int i; - unsigned long flags; - - crisv32_pinmux_init(); - - if (port > PORTS || port < 0) - return -EINVAL; - - spin_lock_irqsave(&pinmux_lock, flags); - - for (i = first_pin; i <= last_pin; i++) - pins[port * PORT_PINS + i] = pinmux_none; - - crisv32_pinmux_set(port); - spin_unlock_irqrestore(&pinmux_lock, flags); - - return 0; -} - -int -crisv32_pinmux_dealloc_fixed(enum fixed_function function) -{ - int ret = -EINVAL; - char saved[sizeof pins]; - unsigned long flags; - reg_pinmux_rw_hwprot hwprot; - - spin_lock_irqsave(&pinmux_lock, flags); - - /* Save internal data for recovery */ - memcpy(saved, pins, sizeof pins); - - crisv32_pinmux_init(); /* must be done before we read rw_hwprot */ - - hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); - - switch (function) { - case pinmux_eth: - ret = crisv32_pinmux_dealloc(PORT_B, 8, 23); - ret |= crisv32_pinmux_dealloc(PORT_B, 24, 25); - ret |= crisv32_pinmux_dealloc(PORT_B, 0, 7); - hwprot.eth = hwprot.eth_mdio = hwprot.geth = regk_pinmux_no; - break; - case pinmux_tg_cmos: - ret = crisv32_pinmux_dealloc(PORT_B, 27, 29); - hwprot.tg_clk = regk_pinmux_no; - break; - case pinmux_tg_ccd: - ret = crisv32_pinmux_dealloc(PORT_B, 27, 31); - ret |= crisv32_pinmux_dealloc(PORT_C, 0, 15); - hwprot.tg = hwprot.tg_clk = regk_pinmux_no; - break; - case pinmux_vout: - ret = crisv32_pinmux_dealloc(PORT_A, 8, 18); - hwprot.vout = hwprot.vout_sync = regk_pinmux_no; - break; - case pinmux_ser1: - ret = crisv32_pinmux_dealloc(PORT_A, 24, 25); - hwprot.ser1 = regk_pinmux_no; - break; - case pinmux_ser2: - ret = crisv32_pinmux_dealloc(PORT_A, 26, 27); - hwprot.ser2 = regk_pinmux_no; - break; - case pinmux_ser3: - ret = crisv32_pinmux_dealloc(PORT_A, 28, 29); - hwprot.ser3 = regk_pinmux_no; - break; - case pinmux_ser4: - ret = crisv32_pinmux_dealloc(PORT_A, 30, 31); - hwprot.ser4 = regk_pinmux_no; - break; - case pinmux_sser: - ret = crisv32_pinmux_dealloc(PORT_A, 19, 23); - hwprot.sser = regk_pinmux_no; - break; - case pinmux_pwm0: - ret = crisv32_pinmux_dealloc(PORT_A, 30, 30); - hwprot.pwm0 = regk_pinmux_no; - break; - case pinmux_pwm1: - ret = crisv32_pinmux_dealloc(PORT_A, 31, 31); - hwprot.pwm1 = regk_pinmux_no; - break; - case pinmux_pwm2: - ret = crisv32_pinmux_dealloc(PORT_B, 26, 26); - hwprot.pwm2 = regk_pinmux_no; - break; - case pinmux_i2c0: - ret = crisv32_pinmux_dealloc(PORT_A, 0, 1); - hwprot.i2c0 = regk_pinmux_no; - break; - case pinmux_i2c1: - ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); - hwprot.i2c1 = regk_pinmux_no; - break; - case pinmux_i2c1_3wire: - ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); - ret |= crisv32_pinmux_dealloc(PORT_A, 7, 7); - hwprot.i2c1 = hwprot.i2c1_sen = regk_pinmux_no; - break; - case pinmux_i2c1_sda1: - ret = crisv32_pinmux_dealloc(PORT_A, 2, 4); - hwprot.i2c1_sda1 = regk_pinmux_no; - break; - case pinmux_i2c1_sda2: - ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); - ret |= crisv32_pinmux_dealloc(PORT_A, 5, 5); - hwprot.i2c1_sda2 = regk_pinmux_no; - break; - case pinmux_i2c1_sda3: - ret = crisv32_pinmux_dealloc(PORT_A, 2, 3); - ret |= crisv32_pinmux_dealloc(PORT_A, 6, 6); - hwprot.i2c1_sda3 = regk_pinmux_no; - break; - default: - ret = -EINVAL; - break; - } - - if (!ret) - REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); - else - memcpy(pins, saved, sizeof pins); - - spin_unlock_irqrestore(&pinmux_lock, flags); - - return ret; -} - -void -crisv32_pinmux_dump(void) -{ - int i, j; - int pin = 0; - - crisv32_pinmux_init(); - - for (i = 0; i < PORTS; i++) { - pin++; - printk(KERN_DEBUG "Port %c\n", 'A'+i); - for (j = 0; (j < PORT_PINS) && (pin < PINS); j++, pin++) - printk(KERN_DEBUG - " Pin %d = %d\n", j, pins[i * PORT_PINS + j]); - } -} - -__initcall(crisv32_pinmux_init); diff --git a/arch/cris/arch-v32/mach-fs/Kconfig b/arch/cris/arch-v32/mach-fs/Kconfig deleted file mode 100644 index 743ba3bcbaec..000000000000 --- a/arch/cris/arch-v32/mach-fs/Kconfig +++ /dev/null @@ -1,198 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -if ETRAXFS - -menu "ETRAX FS options" - depends on ETRAXFS - -config ETRAX_DRAM_VIRTUAL_BASE - hex - depends on ETRAX_ARCH_V32 - default "c0000000" - -config ETRAX_SERIAL_PORTS - int - default 4 - -config ETRAX_MEM_GRP1_CONFIG - hex "MEM_GRP1_CONFIG" - depends on ETRAX_ARCH_V32 - default "4044a" - help - Waitstates for flash. The default value is suitable for the - standard flashes used in axis products (120 ns). - -config ETRAX_MEM_GRP2_CONFIG - hex "MEM_GRP2_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - Waitstates for SRAM. 0 is a good choice for most Axis products. - -config ETRAX_MEM_GRP3_CONFIG - hex "MEM_GRP3_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - Waitstates for CSP0-3. 0 is a good choice for most Axis products. - It may need to be changed if external devices such as extra - register-mapped LEDs are used. - -config ETRAX_MEM_GRP4_CONFIG - hex "MEM_GRP4_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - Waitstates for CSP4-6. 0 is a good choice for most Axis products. - -config ETRAX_SDRAM_GRP0_CONFIG - hex "SDRAM_GRP0_CONFIG" - depends on ETRAX_ARCH_V32 - default "336" - help - SDRAM configuration for group 0. The value depends on the - hardware configuration. The default value is suitable - for 32 MB organized as two 16 bits chips (e.g. Axis - part number 18550) connected as one 32 bit device (i.e. in - the same group). - -config ETRAX_SDRAM_GRP1_CONFIG - hex "SDRAM_GRP1_CONFIG" - depends on ETRAX_ARCH_V32 - default "0" - help - SDRAM configuration for group 1. The default value is 0 - because group 1 is not used in the default configuration, - described in the help for SDRAM_GRP0_CONFIG. - -config ETRAX_SDRAM_TIMING - hex "SDRAM_TIMING" - depends on ETRAX_ARCH_V32 - default "104a" - help - SDRAM timing parameters. The default value is ok for - most hardwares but large SDRAMs may require a faster - refresh (a.k.a 8K refresh). The default value implies - 100MHz clock and SDR mode. - -config ETRAX_SDRAM_COMMAND - hex "SDRAM_COMMAND" - depends on ETRAX_ARCH_V32 - default "0" - help - SDRAM command. Should be 0 unless you really know what - you are doing (may be != 0 for unusual address line - mappings such as in a MCM).. - -config ETRAX_DEF_GIO_PA_OE - hex "GIO_PA_OE" - depends on ETRAX_ARCH_V32 - default "1c" - help - Configures the direction of general port A bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PA_OUT - hex "GIO_PA_OUT" - depends on ETRAX_ARCH_V32 - default "00" - help - Configures the initial data for the general port A bits. Most - products should use 00 here. - -config ETRAX_DEF_GIO_PB_OE - hex "GIO_PB_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port B bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PB_OUT - hex "GIO_PB_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port B bits. Most - products should use 00000 here. - -config ETRAX_DEF_GIO_PC_OE - hex "GIO_PC_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port C bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PC_OUT - hex "GIO_PC_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port C bits. Most - products should use 00000 here. - -config ETRAX_DEF_GIO_PD_OE - hex "GIO_PD_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port D bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PD_OUT - hex "GIO_PD_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port D bits. Most - products should use 00000 here. - -config ETRAX_DEF_GIO_PE_OE - hex "GIO_PE_OE" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the direction of general port E bits. 1 is out, 0 is in. - This is often totally different depending on the product used. - There are some guidelines though - if you know that only LED's are - connected to port PA, then they are usually connected to bits 2-4 - and you can therefore use 1c. On other boards which don't have the - LED's at the general ports, these bits are used for all kinds of - stuff. If you don't know what to use, it is always safe to put all - as inputs, although floating inputs isn't good. - -config ETRAX_DEF_GIO_PE_OUT - hex "GIO_PE_OUT" - depends on ETRAX_ARCH_V32 - default "00000" - help - Configures the initial data for the general port E bits. Most - products should use 00000 here. - -endmenu - -endif diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile deleted file mode 100644 index 0cc6eebacbed..000000000000 --- a/arch/cris/arch-v32/mach-fs/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the linux kernel. -# - -obj-y := dma.o pinmux.o arbiter.o - -clean: - diff --git a/arch/cris/arch-v32/mach-fs/arbiter.c b/arch/cris/arch-v32/mach-fs/arbiter.c deleted file mode 100644 index c4750d97e46c..000000000000 --- a/arch/cris/arch-v32/mach-fs/arbiter.c +++ /dev/null @@ -1,405 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Memory arbiter functions. Allocates bandwidth through the - * arbiter and sets up arbiter breakpoints. - * - * The algorithm first assigns slots to the clients that has specified - * bandwidth (e.g. ethernet) and then the remaining slots are divided - * on all the active clients. - * - * Copyright (c) 2004-2007 Axis Communications AB. - */ - -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/marb_defs.h> -#include <arbiter.h> -#include <hwregs/intr_vect.h> -#include <linux/interrupt.h> -#include <linux/signal.h> -#include <linux/errno.h> -#include <linux/spinlock.h> -#include <asm/io.h> -#include <asm/irq_regs.h> - -struct crisv32_watch_entry { - unsigned long instance; - watch_callback *cb; - unsigned long start; - unsigned long end; - int used; -}; - -#define NUMBER_OF_BP 4 -#define NBR_OF_CLIENTS 14 -#define NBR_OF_SLOTS 64 -#define SDRAM_BANDWIDTH 100000000 /* Some kind of expected value */ -#define INTMEM_BANDWIDTH 400000000 -#define NBR_OF_REGIONS 2 - -static struct crisv32_watch_entry watches[NUMBER_OF_BP] = { - {regi_marb_bp0}, - {regi_marb_bp1}, - {regi_marb_bp2}, - {regi_marb_bp3} -}; - -static u8 requested_slots[NBR_OF_REGIONS][NBR_OF_CLIENTS]; -static u8 active_clients[NBR_OF_REGIONS][NBR_OF_CLIENTS]; -static int max_bandwidth[NBR_OF_REGIONS] = - { SDRAM_BANDWIDTH, INTMEM_BANDWIDTH }; - -DEFINE_SPINLOCK(arbiter_lock); - -static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id); - -/* - * "I'm the arbiter, I know the score. - * From square one I'll be watching all 64." - * (memory arbiter slots, that is) - * - * Or in other words: - * Program the memory arbiter slots for "region" according to what's - * in requested_slots[] and active_clients[], while minimizing - * latency. A caller may pass a non-zero positive amount for - * "unused_slots", which must then be the unallocated, remaining - * number of slots, free to hand out to any client. - */ - -static void crisv32_arbiter_config(int region, int unused_slots) -{ - int slot; - int client; - int interval = 0; - - /* - * This vector corresponds to the hardware arbiter slots (see - * the hardware documentation for semantics). We initialize - * each slot with a suitable sentinel value outside the valid - * range {0 .. NBR_OF_CLIENTS - 1} and replace them with - * client indexes. Then it's fed to the hardware. - */ - s8 val[NBR_OF_SLOTS]; - - for (slot = 0; slot < NBR_OF_SLOTS; slot++) - val[slot] = -1; - - for (client = 0; client < NBR_OF_CLIENTS; client++) { - int pos; - /* Allocate the requested non-zero number of slots, but - * also give clients with zero-requests one slot each - * while stocks last. We do the latter here, in client - * order. This makes sure zero-request clients are the - * first to get to any spare slots, else those slots - * could, when bandwidth is allocated close to the limit, - * all be allocated to low-index non-zero-request clients - * in the default-fill loop below. Another positive but - * secondary effect is a somewhat better spread of the - * zero-bandwidth clients in the vector, avoiding some of - * the latency that could otherwise be caused by the - * partitioning of non-zero-bandwidth clients at low - * indexes and zero-bandwidth clients at high - * indexes. (Note that this spreading can only affect the - * unallocated bandwidth.) All the above only matters for - * memory-intensive situations, of course. - */ - if (!requested_slots[region][client]) { - /* - * Skip inactive clients. Also skip zero-slot - * allocations in this pass when there are no known - * free slots. - */ - if (!active_clients[region][client] - || unused_slots <= 0) - continue; - - unused_slots--; - - /* Only allocate one slot for this client. */ - interval = NBR_OF_SLOTS; - } else - interval = - NBR_OF_SLOTS / requested_slots[region][client]; - - pos = 0; - while (pos < NBR_OF_SLOTS) { - if (val[pos] >= 0) - pos++; - else { - val[pos] = client; - pos += interval; - } - } - } - - client = 0; - for (slot = 0; slot < NBR_OF_SLOTS; slot++) { - /* - * Allocate remaining slots in round-robin - * client-number order for active clients. For this - * pass, we ignore requested bandwidth and previous - * allocations. - */ - if (val[slot] < 0) { - int first = client; - while (!active_clients[region][client]) { - client = (client + 1) % NBR_OF_CLIENTS; - if (client == first) - break; - } - val[slot] = client; - client = (client + 1) % NBR_OF_CLIENTS; - } - if (region == EXT_REGION) - REG_WR_INT_VECT(marb, regi_marb, rw_ext_slots, slot, - val[slot]); - else if (region == INT_REGION) - REG_WR_INT_VECT(marb, regi_marb, rw_int_slots, slot, - val[slot]); - } -} - -extern char _stext[], _etext[]; - -static void crisv32_arbiter_init(void) -{ - static int initialized; - - if (initialized) - return; - - initialized = 1; - - /* - * CPU caches are always set to active, but with zero - * bandwidth allocated. It should be ok to allocate zero - * bandwidth for the caches, because DMA for other channels - * will supposedly finish, once their programmed amount is - * done, and then the caches will get access according to the - * "fixed scheme" for unclaimed slots. Though, if for some - * use-case somewhere, there's a maximum CPU latency for - * e.g. some interrupt, we have to start allocating specific - * bandwidth for the CPU caches too. - */ - active_clients[EXT_REGION][10] = active_clients[EXT_REGION][11] = 1; - crisv32_arbiter_config(EXT_REGION, 0); - crisv32_arbiter_config(INT_REGION, 0); - - if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, 0, - "arbiter", NULL)) - printk(KERN_ERR "Couldn't allocate arbiter IRQ\n"); - -#ifndef CONFIG_ETRAX_KGDB - /* Global watch for writes to kernel text segment. */ - crisv32_arbiter_watch(virt_to_phys(_stext), _etext - _stext, - arbiter_all_clients, arbiter_all_write, NULL); -#endif -} - -/* Main entry for bandwidth allocation. */ - -int crisv32_arbiter_allocate_bandwidth(int client, int region, - unsigned long bandwidth) -{ - int i; - int total_assigned = 0; - int total_clients = 0; - int req; - - crisv32_arbiter_init(); - - for (i = 0; i < NBR_OF_CLIENTS; i++) { - total_assigned += requested_slots[region][i]; - total_clients += active_clients[region][i]; - } - - /* Avoid division by 0 for 0-bandwidth requests. */ - req = bandwidth == 0 - ? 0 : NBR_OF_SLOTS / (max_bandwidth[region] / bandwidth); - - /* - * We make sure that there are enough slots only for non-zero - * requests. Requesting 0 bandwidth *may* allocate slots, - * though if all bandwidth is allocated, such a client won't - * get any and will have to rely on getting memory access - * according to the fixed scheme that's the default when one - * of the slot-allocated clients doesn't claim their slot. - */ - if (total_assigned + req > NBR_OF_SLOTS) - return -ENOMEM; - - active_clients[region][client] = 1; - requested_slots[region][client] = req; - crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); - - return 0; -} - -/* - * Main entry for bandwidth deallocation. - * - * Strictly speaking, for a somewhat constant set of clients where - * each client gets a constant bandwidth and is just enabled or - * disabled (somewhat dynamically), no action is necessary here to - * avoid starvation for non-zero-allocation clients, as the allocated - * slots will just be unused. However, handing out those unused slots - * to active clients avoids needless latency if the "fixed scheme" - * would give unclaimed slots to an eager low-index client. - */ - -void crisv32_arbiter_deallocate_bandwidth(int client, int region) -{ - int i; - int total_assigned = 0; - - requested_slots[region][client] = 0; - active_clients[region][client] = 0; - - for (i = 0; i < NBR_OF_CLIENTS; i++) - total_assigned += requested_slots[region][i]; - - crisv32_arbiter_config(region, NBR_OF_SLOTS - total_assigned); -} - -int crisv32_arbiter_watch(unsigned long start, unsigned long size, - unsigned long clients, unsigned long accesses, - watch_callback *cb) -{ - int i; - - crisv32_arbiter_init(); - - if (start > 0x80000000) { - printk(KERN_ERR "Arbiter: %lX doesn't look like a " - "physical address", start); - return -EFAULT; - } - - spin_lock(&arbiter_lock); - - for (i = 0; i < NUMBER_OF_BP; i++) { - if (!watches[i].used) { - reg_marb_rw_intr_mask intr_mask = - REG_RD(marb, regi_marb, rw_intr_mask); - - watches[i].used = 1; - watches[i].start = start; - watches[i].end = start + size; - watches[i].cb = cb; - - REG_WR_INT(marb_bp, watches[i].instance, rw_first_addr, - watches[i].start); - REG_WR_INT(marb_bp, watches[i].instance, rw_last_addr, - watches[i].end); - REG_WR_INT(marb_bp, watches[i].instance, rw_op, - accesses); - REG_WR_INT(marb_bp, watches[i].instance, rw_clients, - clients); - - if (i == 0) - intr_mask.bp0 = regk_marb_yes; - else if (i == 1) - intr_mask.bp1 = regk_marb_yes; - else if (i == 2) - intr_mask.bp2 = regk_marb_yes; - else if (i == 3) - intr_mask.bp3 = regk_marb_yes; - - REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); - spin_unlock(&arbiter_lock); - - return i; - } - } - spin_unlock(&arbiter_lock); - return -ENOMEM; -} - -int crisv32_arbiter_unwatch(int id) -{ - reg_marb_rw_intr_mask intr_mask = REG_RD(marb, regi_marb, rw_intr_mask); - - crisv32_arbiter_init(); - - spin_lock(&arbiter_lock); - - if ((id < 0) || (id >= NUMBER_OF_BP) || (!watches[id].used)) { - spin_unlock(&arbiter_lock); - return -EINVAL; - } - - memset(&watches[id], 0, sizeof(struct crisv32_watch_entry)); - - if (id == 0) - intr_mask.bp0 = regk_marb_no; - else if (id == 1) - intr_mask.bp1 = regk_marb_no; - else if (id == 2) - intr_mask.bp2 = regk_marb_no; - else if (id == 3) - intr_mask.bp3 = regk_marb_no; - - REG_WR(marb, regi_marb, rw_intr_mask, intr_mask); - - spin_unlock(&arbiter_lock); - return 0; -} - -extern void show_registers(struct pt_regs *regs); - -static irqreturn_t crisv32_arbiter_irq(int irq, void *dev_id) -{ - reg_marb_r_masked_intr masked_intr = - REG_RD(marb, regi_marb, r_masked_intr); - reg_marb_bp_r_brk_clients r_clients; - reg_marb_bp_r_brk_addr r_addr; - reg_marb_bp_r_brk_op r_op; - reg_marb_bp_r_brk_first_client r_first; - reg_marb_bp_r_brk_size r_size; - reg_marb_bp_rw_ack ack = { 0 }; - reg_marb_rw_ack_intr ack_intr = { - .bp0 = 1, .bp1 = 1, .bp2 = 1, .bp3 = 1 - }; - struct crisv32_watch_entry *watch; - - if (masked_intr.bp0) { - watch = &watches[0]; - ack_intr.bp0 = regk_marb_yes; - } else if (masked_intr.bp1) { - watch = &watches[1]; - ack_intr.bp1 = regk_marb_yes; - } else if (masked_intr.bp2) { - watch = &watches[2]; - ack_intr.bp2 = regk_marb_yes; - } else if (masked_intr.bp3) { - watch = &watches[3]; - ack_intr.bp3 = regk_marb_yes; - } else { - return IRQ_NONE; - } - - /* Retrieve all useful information and print it. */ - r_clients = REG_RD(marb_bp, watch->instance, r_brk_clients); - r_addr = REG_RD(marb_bp, watch->instance, r_brk_addr); - r_op = REG_RD(marb_bp, watch->instance, r_brk_op); - r_first = REG_RD(marb_bp, watch->instance, r_brk_first_client); - r_size = REG_RD(marb_bp, watch->instance, r_brk_size); - - printk(KERN_INFO "Arbiter IRQ\n"); - printk(KERN_INFO "Clients %X addr %X op %X first %X size %X\n", - REG_TYPE_CONV(int, reg_marb_bp_r_brk_clients, r_clients), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_addr, r_addr), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_op, r_op), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_first_client, r_first), - REG_TYPE_CONV(int, reg_marb_bp_r_brk_size, r_size)); - - REG_WR(marb_bp, watch->instance, rw_ack, ack); - REG_WR(marb, regi_marb, rw_ack_intr, ack_intr); - - printk(KERN_INFO "IRQ occurred at %lX\n", get_irq_regs()->erp); - - if (watch->cb) - watch->cb(); - - return IRQ_HANDLED; -} diff --git a/arch/cris/arch-v32/mach-fs/dma.c b/arch/cris/arch-v32/mach-fs/dma.c deleted file mode 100644 index c0347a4f8c65..000000000000 --- a/arch/cris/arch-v32/mach-fs/dma.c +++ /dev/null @@ -1,229 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Wrapper for DMA channel allocator that starts clocks etc */ - -#include <linux/kernel.h> -#include <linux/spinlock.h> -#include <asm/dma.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/marb_defs.h> -#include <hwregs/config_defs.h> -#include <hwregs/strmux_defs.h> -#include <linux/errno.h> -#include <mach/arbiter.h> - -static char used_dma_channels[MAX_DMA_CHANNELS]; -static const char *used_dma_channels_users[MAX_DMA_CHANNELS]; - -static DEFINE_SPINLOCK(dma_lock); - -int crisv32_request_dma(unsigned int dmanr, const char *device_id, - unsigned options, unsigned int bandwidth, - enum dma_owner owner) -{ - unsigned long flags; - reg_config_rw_clk_ctrl clk_ctrl; - reg_strmux_rw_cfg strmux_cfg; - - if (crisv32_arbiter_allocate_bandwidth(dmanr, - options & DMA_INT_MEM ? - INT_REGION : EXT_REGION, - bandwidth)) - return -ENOMEM; - - spin_lock_irqsave(&dma_lock, flags); - - if (used_dma_channels[dmanr]) { - spin_unlock_irqrestore(&dma_lock, flags); - if (options & DMA_VERBOSE_ON_ERROR) { - printk(KERN_ERR "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; - } - clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); - strmux_cfg = REG_RD(strmux, regi_strmux, rw_cfg); - - switch (dmanr) { - case 0: - case 1: - clk_ctrl.dma01_eth0 = 1; - break; - case 2: - case 3: - clk_ctrl.dma23 = 1; - break; - case 4: - case 5: - clk_ctrl.dma45 = 1; - break; - case 6: - case 7: - clk_ctrl.dma67 = 1; - break; - case 8: - case 9: - clk_ctrl.dma89_strcop = 1; - break; -#if MAX_DMA_CHANNELS-1 != 9 -#error Check dma.c -#endif - default: - spin_unlock_irqrestore(&dma_lock, flags); - if (options & DMA_VERBOSE_ON_ERROR) { - printk(KERN_ERR "Failed to request DMA %i for %s, " - "only 0-%i valid)\n", - dmanr, device_id, MAX_DMA_CHANNELS - 1); - } - - if (options & DMA_PANIC_ON_ERROR) - panic("request_dma error!"); - return -EINVAL; - } - - switch (owner) { - case dma_eth0: - if (dmanr == 0) - strmux_cfg.dma0 = regk_strmux_eth0; - else if (dmanr == 1) - strmux_cfg.dma1 = regk_strmux_eth0; - else - panic("Invalid DMA channel for eth0\n"); - break; - case dma_eth1: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_eth1; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_eth1; - else - panic("Invalid DMA channel for eth1\n"); - break; - case dma_iop0: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_iop0; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_iop0; - else - panic("Invalid DMA channel for iop0\n"); - break; - case dma_iop1: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_iop1; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_iop1; - else - panic("Invalid DMA channel for iop1\n"); - break; - case dma_ser0: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_ser0; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_ser0; - else - panic("Invalid DMA channel for ser0\n"); - break; - case dma_ser1: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_ser1; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_ser1; - else - panic("Invalid DMA channel for ser1\n"); - break; - case dma_ser2: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_ser2; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_ser2; - else - panic("Invalid DMA channel for ser2\n"); - break; - case dma_ser3: - if (dmanr == 8) - strmux_cfg.dma8 = regk_strmux_ser3; - else if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_ser3; - else - panic("Invalid DMA channel for ser3\n"); - break; - case dma_sser0: - if (dmanr == 4) - strmux_cfg.dma4 = regk_strmux_sser0; - else if (dmanr == 5) - strmux_cfg.dma5 = regk_strmux_sser0; - else - panic("Invalid DMA channel for sser0\n"); - break; - case dma_sser1: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_sser1; - else if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_sser1; - else - panic("Invalid DMA channel for sser1\n"); - break; - case dma_ata: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_ata; - else if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_ata; - else - panic("Invalid DMA channel for ata\n"); - break; - case dma_strp: - if (dmanr == 8) - strmux_cfg.dma8 = regk_strmux_strcop; - else if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_strcop; - else - panic("Invalid DMA channel for strp\n"); - break; - case dma_ext0: - if (dmanr == 6) - strmux_cfg.dma6 = regk_strmux_ext0; - else - panic("Invalid DMA channel for ext0\n"); - break; - case dma_ext1: - if (dmanr == 7) - strmux_cfg.dma7 = regk_strmux_ext1; - else - panic("Invalid DMA channel for ext1\n"); - break; - case dma_ext2: - if (dmanr == 2) - strmux_cfg.dma2 = regk_strmux_ext2; - else if (dmanr == 8) - strmux_cfg.dma8 = regk_strmux_ext2; - else - panic("Invalid DMA channel for ext2\n"); - break; - case dma_ext3: - if (dmanr == 3) - strmux_cfg.dma3 = regk_strmux_ext3; - else if (dmanr == 9) - strmux_cfg.dma9 = regk_strmux_ext2; - else - panic("Invalid DMA channel for ext2\n"); - break; - } - - used_dma_channels[dmanr] = 1; - used_dma_channels_users[dmanr] = device_id; - REG_WR(config, regi_config, rw_clk_ctrl, clk_ctrl); - REG_WR(strmux, regi_strmux, rw_cfg, strmux_cfg); - spin_unlock_irqrestore(&dma_lock, flags); - return 0; -} - -void crisv32_free_dma(unsigned int dmanr) -{ - spin_lock(&dma_lock); - used_dma_channels[dmanr] = 0; - spin_unlock(&dma_lock); -} diff --git a/arch/cris/arch-v32/mach-fs/dram_init.S b/arch/cris/arch-v32/mach-fs/dram_init.S deleted file mode 100644 index e1a01fa4c272..000000000000 --- a/arch/cris/arch-v32/mach-fs/dram_init.S +++ /dev/null @@ -1,117 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * DRAM/SDRAM initialization - alter with care - * This file is intended to be included from other assembler files - * - * Note: This file may not modify r8 or r9 because they are used to - * carry information from the decompressor to the kernel - * - * Copyright (C) 2000-2007 Axis Communications AB - * - * Authors: Mikael Starvik <starvik@axis.com> - */ - -/* Just to be certain the config file is included, we include it here - * explicitly instead of depending on it being included in the file that - * uses this code. - */ - -#include <hwregs/asm/reg_map_asm.h> -#include <hwregs/asm/bif_core_defs_asm.h> - - ;; WARNING! The registers r8 and r9 are used as parameters carrying - ;; information from the decompressor (if the kernel was compressed). - ;; They should not be used in the code below. - - ; Refer to BIF MDS for a description of SDRAM initialization - - ; Bank configuration - move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp0), $r0 - move.d CONFIG_ETRAX_SDRAM_GRP0_CONFIG, $r1 - move.d $r1, [$r0] - move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp1), $r0 - move.d CONFIG_ETRAX_SDRAM_GRP1_CONFIG, $r1 - move.d $r1, [$r0] - - ; Calculate value of mrs_data - ; CAS latency = 2 && bus_width = 32 => 0x40 - ; CAS latency = 3 && bus_width = 32 => 0x60 - ; CAS latency = 2 && bus_width = 16 => 0x20 - ; CAS latency = 3 && bus_width = 16 => 0x30 - - ; Check if value is already supplied in kernel config - move.d CONFIG_ETRAX_SDRAM_COMMAND, $r2 - bne _set_timing - nop - - move.d 0x40, $r4 ; Assume 32 bits and CAS latency = 2 - move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 - and.d 0x07, $r1 ; Get CAS latency - cmpq 2, $r1 ; CL = 2 ? - beq _bw_check - nop - move.d 0x60, $r4 - -_bw_check: - ; Assume that group 0 width is equal to group 1. This assumption - ; is wrong for a group 1 only hardware (such as the grand old - ; StorPoint+). - move.d CONFIG_ETRAX_SDRAM_GRP0_CONFIG, $r1 - and.d 0x200, $r1 ; DRAM width is bit 9 - beq _set_timing - lslq 2, $r4 ; mrs_data starts at bit 2 - lsrq 1, $r4 ; 16 bits. Shift down value. - - ; Set timing parameters (refresh off to avoid Guinness TR 83) -_set_timing: - move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 - and.d ~(3 << reg_bif_core_rw_sdram_timing___ref___lsb), $r1 - move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing), $r0 - move.d $r1, [$r0] - - ; Issue NOP command - move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_cmd), $r5 - moveq regk_bif_core_nop, $r1 - move.d $r1, [$r5] - - ; Wait 200us - move.d 10000, $r2 -1: bne 1b - subq 1, $r2 - - ; Issue initialization command sequence - lapc _sdram_commands_start, $r2 - lapc _sdram_commands_end, $r3 -1: clear.d $r6 - move.b [$r2+], $r6 ; Load command - or.d $r4, $r6 ; Add calculated mrs - move.d $r6, [$r5] ; Write rw_sdram_cmd - ; Wait 80 ns between each command - move.d 4000, $r7 -2: bne 2b - subq 1, $r7 - cmp.d $r2, $r3 ; Last command? - bne 1b - nop - - ; Start refresh - move.d CONFIG_ETRAX_SDRAM_TIMING, $r1 - move.d REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing), $r0 - move.d $r1, [$r0] - - ; Initialization finished - ba _sdram_commands_end - nop - -_sdram_commands_start: - .byte regk_bif_core_pre ; Precharge - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_ref ; refresh - .byte regk_bif_core_mrs ; mrs -_sdram_commands_end: diff --git a/arch/cris/arch-v32/mach-fs/hw_settings.S b/arch/cris/arch-v32/mach-fs/hw_settings.S deleted file mode 100644 index 7fbadcc48c0c..000000000000 --- a/arch/cris/arch-v32/mach-fs/hw_settings.S +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * This table is used by some tools to extract hardware parameters. - * The table should be included in the kernel and the decompressor. - * Don't forget to update the tools if you change this table. - * - * Copyright (C) 2001-2007 Axis Communications AB - * - * Authors: Mikael Starvik <starvik@axis.com> - */ - -#include <hwregs/asm/reg_map_asm.h> -#include <hwregs/asm/bif_core_defs_asm.h> -#include <hwregs/asm/gio_defs_asm.h> - - .ascii "HW_PARAM_MAGIC" ; Magic number - .dword 0xc0004000 ; Kernel start address - - ; Debug port -#ifdef CONFIG_ETRAX_DEBUG_PORT0 - .dword 0 -#elif defined(CONFIG_ETRAX_DEBUG_PORT1) - .dword 1 -#elif defined(CONFIG_ETRAX_DEBUG_PORT2) - .dword 2 -#elif defined(CONFIG_ETRAX_DEBUG_PORT3) - .dword 3 -#else - .dword 4 ; No debug -#endif - - ; Register values - .dword REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg) - .dword CONFIG_ETRAX_MEM_GRP1_CONFIG - .dword REG_ADDR(bif_core, regi_bif_core, rw_grp2_cfg) - .dword CONFIG_ETRAX_MEM_GRP2_CONFIG - .dword REG_ADDR(bif_core, regi_bif_core, rw_grp3_cfg) - .dword CONFIG_ETRAX_MEM_GRP3_CONFIG - .dword REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg) - .dword CONFIG_ETRAX_MEM_GRP4_CONFIG - .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp0) - .dword CONFIG_ETRAX_SDRAM_GRP0_CONFIG - .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cfg_grp1) - .dword CONFIG_ETRAX_SDRAM_GRP1_CONFIG - .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_timing) - .dword CONFIG_ETRAX_SDRAM_TIMING - .dword REG_ADDR(bif_core, regi_bif_core, rw_sdram_cmd) - .dword CONFIG_ETRAX_SDRAM_COMMAND - - .dword REG_ADDR(gio, regi_gio, rw_pa_dout) - .dword CONFIG_ETRAX_DEF_GIO_PA_OUT - .dword REG_ADDR(gio, regi_gio, rw_pa_oe) - .dword CONFIG_ETRAX_DEF_GIO_PA_OE - .dword REG_ADDR(gio, regi_gio, rw_pb_dout) - .dword CONFIG_ETRAX_DEF_GIO_PB_OUT - .dword REG_ADDR(gio, regi_gio, rw_pb_oe) - .dword CONFIG_ETRAX_DEF_GIO_PB_OE - .dword REG_ADDR(gio, regi_gio, rw_pc_dout) - .dword CONFIG_ETRAX_DEF_GIO_PC_OUT - .dword REG_ADDR(gio, regi_gio, rw_pc_oe) - .dword CONFIG_ETRAX_DEF_GIO_PC_OE - .dword REG_ADDR(gio, regi_gio, rw_pd_dout) - .dword CONFIG_ETRAX_DEF_GIO_PD_OUT - .dword REG_ADDR(gio, regi_gio, rw_pd_oe) - .dword CONFIG_ETRAX_DEF_GIO_PD_OE - .dword REG_ADDR(gio, regi_gio, rw_pe_dout) - .dword CONFIG_ETRAX_DEF_GIO_PE_OUT - .dword REG_ADDR(gio, regi_gio, rw_pe_oe) - .dword CONFIG_ETRAX_DEF_GIO_PE_OE - - .dword 0 ; No more register values diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c deleted file mode 100644 index a0b2f101003a..000000000000 --- a/arch/cris/arch-v32/mach-fs/pinmux.c +++ /dev/null @@ -1,328 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Allocator for I/O pins. All pins are allocated to GPIO at bootup. - * Unassigned pins and GPIO pins can be allocated to a fixed interface - * or the I/O processor instead. - * - * Copyright (c) 2004-2007 Axis Communications AB. - */ - -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/spinlock.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <pinmux.h> -#include <hwregs/pinmux_defs.h> - -#undef DEBUG - -#define PORT_PINS 18 -#define PORTS 4 - -static char pins[PORTS][PORT_PINS]; -static DEFINE_SPINLOCK(pinmux_lock); - -static void crisv32_pinmux_set(int port); - -static int __crisv32_pinmux_alloc(int port, int first_pin, int last_pin, - enum pin_mode mode) -{ - int i; - - for (i = first_pin; i <= last_pin; i++) { - if ((pins[port][i] != pinmux_none) - && (pins[port][i] != pinmux_gpio) - && (pins[port][i] != mode)) { -#ifdef DEBUG - panic("Pinmux alloc failed!\n"); -#endif - return -EPERM; - } - } - - for (i = first_pin; i <= last_pin; i++) - pins[port][i] = mode; - - crisv32_pinmux_set(port); - - return 0; -} - -static int crisv32_pinmux_init(void) -{ - static int initialized; - - if (!initialized) { - reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa); - initialized = 1; - REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0); - pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 = - pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes; - REG_WR(pinmux, regi_pinmux, rw_pa, pa); - __crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio); - __crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio); - __crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio); - __crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio); - } - - return 0; -} - -int crisv32_pinmux_alloc(int port, int first_pin, int last_pin, - enum pin_mode mode) -{ - unsigned long flags; - int ret; - - crisv32_pinmux_init(); - - if (port > PORTS || port < 0) - return -EINVAL; - - spin_lock_irqsave(&pinmux_lock, flags); - - ret = __crisv32_pinmux_alloc(port, first_pin, last_pin, mode); - - spin_unlock_irqrestore(&pinmux_lock, flags); - - return ret; -} - -int crisv32_pinmux_alloc_fixed(enum fixed_function function) -{ - int ret = -EINVAL; - char saved[sizeof pins]; - unsigned long flags; - reg_pinmux_rw_hwprot hwprot; - - spin_lock_irqsave(&pinmux_lock, flags); - - /* Save internal data for recovery */ - memcpy(saved, pins, sizeof pins); - - crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ - - hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); - - switch (function) { - case pinmux_ser1: - ret = __crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed); - hwprot.ser1 = regk_pinmux_yes; - break; - case pinmux_ser2: - ret = __crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed); - hwprot.ser2 = regk_pinmux_yes; - break; - case pinmux_ser3: - ret = __crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed); - hwprot.ser3 = regk_pinmux_yes; - break; - case pinmux_sser0: - ret = __crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed); - ret |= __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); - hwprot.sser0 = regk_pinmux_yes; - break; - case pinmux_sser1: - ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); - hwprot.sser1 = regk_pinmux_yes; - break; - case pinmux_ata0: - ret = __crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed); - ret |= __crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed); - hwprot.ata0 = regk_pinmux_yes; - break; - case pinmux_ata1: - ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); - ret |= __crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed); - hwprot.ata1 = regk_pinmux_yes; - break; - case pinmux_ata2: - ret = __crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed); - ret |= __crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed); - hwprot.ata2 = regk_pinmux_yes; - break; - case pinmux_ata3: - ret = __crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed); - ret |= __crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed); - hwprot.ata2 = regk_pinmux_yes; - break; - case pinmux_ata: - ret = __crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed); - ret |= __crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed); - hwprot.ata = regk_pinmux_yes; - break; - case pinmux_eth1: - ret = __crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed); - hwprot.eth1 = regk_pinmux_yes; - hwprot.eth1_mgm = regk_pinmux_yes; - break; - case pinmux_timer: - ret = __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); - hwprot.timer = regk_pinmux_yes; - spin_unlock_irqrestore(&pinmux_lock, flags); - return ret; - } - - if (!ret) - REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); - else - memcpy(pins, saved, sizeof pins); - - spin_unlock_irqrestore(&pinmux_lock, flags); - - return ret; -} - -void crisv32_pinmux_set(int port) -{ - int i; - int gpio_val = 0; - int iop_val = 0; - - for (i = 0; i < PORT_PINS; i++) { - if (pins[port][i] == pinmux_gpio) - gpio_val |= (1 << i); - else if (pins[port][i] == pinmux_iop) - iop_val |= (1 << i); - } - - REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8 * port, - gpio_val); - REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8 * port, - iop_val); - -#ifdef DEBUG - crisv32_pinmux_dump(); -#endif -} - -static int __crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) -{ - int i; - - for (i = first_pin; i <= last_pin; i++) - pins[port][i] = pinmux_none; - - crisv32_pinmux_set(port); - return 0; -} - -int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) -{ - unsigned long flags; - - crisv32_pinmux_init(); - - if (port > PORTS || port < 0) - return -EINVAL; - - spin_lock_irqsave(&pinmux_lock, flags); - __crisv32_pinmux_dealloc(port, first_pin, last_pin); - spin_unlock_irqrestore(&pinmux_lock, flags); - - return 0; -} - -int crisv32_pinmux_dealloc_fixed(enum fixed_function function) -{ - int ret = -EINVAL; - char saved[sizeof pins]; - unsigned long flags; - reg_pinmux_rw_hwprot hwprot; - - spin_lock_irqsave(&pinmux_lock, flags); - - /* Save internal data for recovery */ - memcpy(saved, pins, sizeof pins); - - crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ - - hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); - - switch (function) { - case pinmux_ser1: - ret = __crisv32_pinmux_dealloc(PORT_C, 4, 7); - hwprot.ser1 = regk_pinmux_no; - break; - case pinmux_ser2: - ret = __crisv32_pinmux_dealloc(PORT_C, 8, 11); - hwprot.ser2 = regk_pinmux_no; - break; - case pinmux_ser3: - ret = __crisv32_pinmux_dealloc(PORT_C, 12, 15); - hwprot.ser3 = regk_pinmux_no; - break; - case pinmux_sser0: - ret = __crisv32_pinmux_dealloc(PORT_C, 0, 3); - ret |= __crisv32_pinmux_dealloc(PORT_C, 16, 16); - hwprot.sser0 = regk_pinmux_no; - break; - case pinmux_sser1: - ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4); - hwprot.sser1 = regk_pinmux_no; - break; - case pinmux_ata0: - ret = __crisv32_pinmux_dealloc(PORT_D, 5, 7); - ret |= __crisv32_pinmux_dealloc(PORT_D, 15, 17); - hwprot.ata0 = regk_pinmux_no; - break; - case pinmux_ata1: - ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4); - ret |= __crisv32_pinmux_dealloc(PORT_E, 17, 17); - hwprot.ata1 = regk_pinmux_no; - break; - case pinmux_ata2: - ret = __crisv32_pinmux_dealloc(PORT_C, 11, 15); - ret |= __crisv32_pinmux_dealloc(PORT_E, 3, 3); - hwprot.ata2 = regk_pinmux_no; - break; - case pinmux_ata3: - ret = __crisv32_pinmux_dealloc(PORT_C, 8, 10); - ret |= __crisv32_pinmux_dealloc(PORT_C, 0, 2); - hwprot.ata2 = regk_pinmux_no; - break; - case pinmux_ata: - ret = __crisv32_pinmux_dealloc(PORT_B, 0, 15); - ret |= __crisv32_pinmux_dealloc(PORT_D, 8, 15); - hwprot.ata = regk_pinmux_no; - break; - case pinmux_eth1: - ret = __crisv32_pinmux_dealloc(PORT_E, 0, 17); - hwprot.eth1 = regk_pinmux_no; - hwprot.eth1_mgm = regk_pinmux_no; - break; - case pinmux_timer: - ret = __crisv32_pinmux_dealloc(PORT_C, 16, 16); - hwprot.timer = regk_pinmux_no; - spin_unlock_irqrestore(&pinmux_lock, flags); - return ret; - } - - if (!ret) - REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); - else - memcpy(pins, saved, sizeof pins); - - spin_unlock_irqrestore(&pinmux_lock, flags); - - return ret; -} - -#ifdef DEBUG -static void crisv32_pinmux_dump(void) -{ - int i, j; - - crisv32_pinmux_init(); - - for (i = 0; i < PORTS; i++) { - printk(KERN_DEBUG "Port %c\n", 'B' + i); - for (j = 0; j < PORT_PINS; j++) - printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]); - } -} -#endif -__initcall(crisv32_pinmux_init); diff --git a/arch/cris/arch-v32/mm/Makefile b/arch/cris/arch-v32/mm/Makefile deleted file mode 100644 index 0b801f2964ac..000000000000 --- a/arch/cris/arch-v32/mm/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# Makefile for the Linux/cris parts of the memory manager. - -obj-y += mmu.o init.o tlb.o intmem.o -obj-$(CONFIG_ETRAX_L2CACHE) += l2cache.o diff --git a/arch/cris/arch-v32/mm/init.c b/arch/cris/arch-v32/mm/init.c deleted file mode 100644 index 784876afa001..000000000000 --- a/arch/cris/arch-v32/mm/init.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Set up paging and the MMU. - * - * Copyright (C) 2000-2003, Axis Communications AB. - * - * Authors: Bjorn Wesen <bjornw@axis.com> - * Tobias Anderberg <tobiasa@axis.com>, CRISv32 port. - */ -#include <linux/mmzone.h> -#include <linux/init.h> -#include <linux/bootmem.h> -#include <linux/mm.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/types.h> -#include <asm/mmu.h> -#include <asm/io.h> -#include <asm/mmu_context.h> -#include <arch/hwregs/asm/mmu_defs_asm.h> -#include <arch/hwregs/supp_reg.h> - -extern void tlb_init(void); - -/* - * The kernel is already mapped with linear mapping at kseg_c so there's no - * need to map it with a page table. However, head.S also temporarily mapped it - * at kseg_4 thus the ksegs are set up again. Also clear the TLB and do various - * other paging stuff. - */ -void __init cris_mmu_init(void) -{ - unsigned long mmu_config; - unsigned long mmu_kbase_hi; - unsigned long mmu_kbase_lo; - unsigned short mmu_page_id; - - /* - * Make sure the current pgd table points to something sane, even if it - * is most probably not used until the next switch_mm. - */ - per_cpu(current_pgd, smp_processor_id()) = init_mm.pgd; - - /* Initialise the TLB. Function found in tlb.c. */ - tlb_init(); - - /* - * Enable exceptions and initialize the kernel segments. - * See head.S for differences between ARTPEC-3 and ETRAX FS. - */ - mmu_config = ( REG_STATE(mmu, rw_mm_cfg, we, on) | - REG_STATE(mmu, rw_mm_cfg, acc, on) | - REG_STATE(mmu, rw_mm_cfg, ex, on) | - REG_STATE(mmu, rw_mm_cfg, inv, on) | -#ifdef CONFIG_CRIS_MACH_ARTPEC3 - REG_STATE(mmu, rw_mm_cfg, seg_f, page) | - REG_STATE(mmu, rw_mm_cfg, seg_e, page) | - REG_STATE(mmu, rw_mm_cfg, seg_d, linear) | -#else - REG_STATE(mmu, rw_mm_cfg, seg_f, linear) | - REG_STATE(mmu, rw_mm_cfg, seg_e, linear) | - REG_STATE(mmu, rw_mm_cfg, seg_d, page) | -#endif - REG_STATE(mmu, rw_mm_cfg, seg_c, linear) | - REG_STATE(mmu, rw_mm_cfg, seg_b, linear) | - REG_STATE(mmu, rw_mm_cfg, seg_a, page) | - REG_STATE(mmu, rw_mm_cfg, seg_9, page) | - REG_STATE(mmu, rw_mm_cfg, seg_8, page) | - REG_STATE(mmu, rw_mm_cfg, seg_7, page) | - REG_STATE(mmu, rw_mm_cfg, seg_6, page) | - REG_STATE(mmu, rw_mm_cfg, seg_5, page) | - REG_STATE(mmu, rw_mm_cfg, seg_4, page) | - REG_STATE(mmu, rw_mm_cfg, seg_3, page) | - REG_STATE(mmu, rw_mm_cfg, seg_2, page) | - REG_STATE(mmu, rw_mm_cfg, seg_1, page) | - REG_STATE(mmu, rw_mm_cfg, seg_0, page)); - - /* See head.S for differences between ARTPEC-3 and ETRAX FS. */ - mmu_kbase_hi = ( REG_FIELD(mmu, rw_mm_kbase_hi, base_f, 0x0) | -#ifdef CONFIG_CRIS_MACH_ARTPEC3 - REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x5) | -#else - REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 0x8) | - REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 0x0) | -#endif - REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) | - REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) | - REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0)); - - mmu_kbase_lo = ( REG_FIELD(mmu, rw_mm_kbase_lo, base_7, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_lo, base_6, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_lo, base_5, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_lo, base_3, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_lo, base_2, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_lo, base_1, 0x0) | - REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0x0)); - - mmu_page_id = REG_FIELD(mmu, rw_mm_tlb_hi, pid, 0); - - /* Update the instruction MMU. */ - SUPP_BANK_SEL(BANK_IM); - SUPP_REG_WR(RW_MM_CFG, mmu_config); - SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi); - SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo); - SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id); - - /* Update the data MMU. */ - SUPP_BANK_SEL(BANK_DM); - SUPP_REG_WR(RW_MM_CFG, mmu_config); - SUPP_REG_WR(RW_MM_KBASE_HI, mmu_kbase_hi); - SUPP_REG_WR(RW_MM_KBASE_LO, mmu_kbase_lo); - SUPP_REG_WR(RW_MM_TLB_HI, mmu_page_id); - - SPEC_REG_WR(SPEC_REG_PID, 0); - - /* - * The MMU has been enabled ever since head.S but just to make it - * totally obvious enable it here as well. - */ - SUPP_BANK_SEL(BANK_GC); - SUPP_REG_WR(RW_GC_CFG, 0xf); /* IMMU, DMMU, ICache, DCache on */ -} - -void __init paging_init(void) -{ - int i; - unsigned long zones_size[MAX_NR_ZONES]; - - printk("Setting up paging and the MMU.\n"); - - /* Clear out the init_mm.pgd that will contain the kernel's mappings. */ - for(i = 0; i < PTRS_PER_PGD; i++) - swapper_pg_dir[i] = __pgd(0); - - cris_mmu_init(); - - /* - * Initialize the bad page table and bad page to point to a couple of - * allocated pages. - */ - empty_zero_page = (unsigned long) alloc_bootmem_pages(PAGE_SIZE); - memset((void *) empty_zero_page, 0, PAGE_SIZE); - - /* All pages are DMA'able in Etrax, so put all in the DMA'able zone. */ - zones_size[0] = ((unsigned long) high_memory - PAGE_OFFSET) >> PAGE_SHIFT; - - for (i = 1; i < MAX_NR_ZONES; i++) - zones_size[i] = 0; - - /* - * Use free_area_init_node instead of free_area_init, because it is - * designed for systems where the DRAM starts at an address - * substantially higher than 0, like us (we start at PAGE_OFFSET). This - * saves space in the mem_map page array. - */ - free_area_init_node(0, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); - - mem_map = contig_page_data.node_mem_map; -} diff --git a/arch/cris/arch-v32/mm/intmem.c b/arch/cris/arch-v32/mm/intmem.c deleted file mode 100644 index 928b94d1d320..000000000000 --- a/arch/cris/arch-v32/mm/intmem.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Simple allocator for internal RAM in ETRAX FS - * - * Copyright (c) 2004 Axis Communications AB. - */ - -#include <linux/list.h> -#include <linux/slab.h> -#include <asm/io.h> -#include <memmap.h> - -#define STATUS_FREE 0 -#define STATUS_ALLOCATED 1 - -#ifdef CONFIG_ETRAX_L2CACHE -#define RESERVED_SIZE 66*1024 -#else -#define RESERVED_SIZE 0 -#endif - -struct intmem_allocation { - struct list_head entry; - unsigned int size; - unsigned offset; - char status; -}; - - -static struct list_head intmem_allocations; -static void* intmem_virtual; - -static void crisv32_intmem_init(void) -{ - static int initiated = 0; - if (!initiated) { - struct intmem_allocation* alloc; - alloc = kmalloc(sizeof *alloc, GFP_KERNEL); - INIT_LIST_HEAD(&intmem_allocations); - intmem_virtual = ioremap(MEM_INTMEM_START + RESERVED_SIZE, - MEM_INTMEM_SIZE - RESERVED_SIZE); - initiated = 1; - alloc->size = MEM_INTMEM_SIZE - RESERVED_SIZE; - alloc->offset = 0; - alloc->status = STATUS_FREE; - list_add_tail(&alloc->entry, &intmem_allocations); - } -} - -void* crisv32_intmem_alloc(unsigned size, unsigned align) -{ - struct intmem_allocation* allocation; - struct intmem_allocation* tmp; - void* ret = NULL; - - preempt_disable(); - crisv32_intmem_init(); - - list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) { - int alignment = allocation->offset % align; - alignment = alignment ? align - alignment : alignment; - - if (allocation->status == STATUS_FREE && - allocation->size >= size + alignment) { - if (allocation->size > size + alignment) { - struct intmem_allocation* alloc; - alloc = kmalloc(sizeof *alloc, GFP_ATOMIC); - alloc->status = STATUS_FREE; - alloc->size = allocation->size - size - - alignment; - alloc->offset = allocation->offset + size + - alignment; - list_add(&alloc->entry, &allocation->entry); - - if (alignment) { - struct intmem_allocation *tmp; - tmp = kmalloc(sizeof *tmp, GFP_ATOMIC); - tmp->offset = allocation->offset; - tmp->size = alignment; - tmp->status = STATUS_FREE; - allocation->offset += alignment; - list_add_tail(&tmp->entry, - &allocation->entry); - } - } - allocation->status = STATUS_ALLOCATED; - allocation->size = size; - ret = (void*)((int)intmem_virtual + allocation->offset); - } - } - preempt_enable(); - return ret; -} - -void crisv32_intmem_free(void* addr) -{ - struct intmem_allocation* allocation; - struct intmem_allocation* tmp; - - if (addr == NULL) - return; - - preempt_disable(); - crisv32_intmem_init(); - - list_for_each_entry_safe(allocation, tmp, &intmem_allocations, entry) { - if (allocation->offset == (int)(addr - intmem_virtual)) { - struct intmem_allocation *prev = - list_entry(allocation->entry.prev, - struct intmem_allocation, entry); - struct intmem_allocation *next = - list_entry(allocation->entry.next, - struct intmem_allocation, entry); - - allocation->status = STATUS_FREE; - /* Join with prev and/or next if also free */ - if ((&prev->entry != &intmem_allocations) && - (prev->status == STATUS_FREE)) { - prev->size += allocation->size; - list_del(&allocation->entry); - kfree(allocation); - allocation = prev; - } - if ((&next->entry != &intmem_allocations) && - (next->status == STATUS_FREE)) { - allocation->size += next->size; - list_del(&next->entry); - kfree(next); - } - preempt_enable(); - return; - } - } - preempt_enable(); -} - -void* crisv32_intmem_phys_to_virt(unsigned long addr) -{ - return (void *)(addr - (MEM_INTMEM_START + RESERVED_SIZE) + - (unsigned long)intmem_virtual); -} - -unsigned long crisv32_intmem_virt_to_phys(void* addr) -{ - return (unsigned long)((unsigned long )addr - - (unsigned long)intmem_virtual + MEM_INTMEM_START + - RESERVED_SIZE); -} - -static int __init crisv32_intmem_setup(void) -{ - crisv32_intmem_init(); - - return 0; -} -device_initcall(crisv32_intmem_setup); - diff --git a/arch/cris/arch-v32/mm/l2cache.c b/arch/cris/arch-v32/mm/l2cache.c deleted file mode 100644 index 4fef321d5606..000000000000 --- a/arch/cris/arch-v32/mm/l2cache.c +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <memmap.h> -#include <hwregs/reg_map.h> -#include <hwregs/reg_rdwr.h> -#include <hwregs/l2cache_defs.h> -#include <asm/io.h> - -#define L2CACHE_SIZE 64 - -int __init l2cache_init(void) -{ - reg_l2cache_rw_ctrl ctrl = {0}; - reg_l2cache_rw_cfg cfg = {.en = regk_l2cache_yes}; - - ctrl.csize = L2CACHE_SIZE; - ctrl.cbase = L2CACHE_SIZE / 4 + (L2CACHE_SIZE % 4 ? 1 : 0); - REG_WR(l2cache, regi_l2cache, rw_ctrl, ctrl); - - /* Flush the tag memory */ - memset((void *)(MEM_INTMEM_START | MEM_NON_CACHEABLE), 0, 2*1024); - - /* Enable the cache */ - REG_WR(l2cache, regi_l2cache, rw_cfg, cfg); - - return 0; -} - diff --git a/arch/cris/arch-v32/mm/mmu.S b/arch/cris/arch-v32/mm/mmu.S deleted file mode 100644 index f24965703f6d..000000000000 --- a/arch/cris/arch-v32/mm/mmu.S +++ /dev/null @@ -1,211 +0,0 @@ -; SPDX-License-Identifier: GPL-2.0 -; WARNING : The refill handler has been modified, see below !!! - -/* - * Copyright (C) 2003 Axis Communications AB - * - * Authors: Mikael Starvik (starvik@axis.com) - * - * Code for the fault low-level handling routines. - * - */ - -#include <asm/page.h> -#include <asm/pgtable.h> - -; Save all register. Must save in same order as struct pt_regs. -.macro SAVE_ALL - subq 12, $sp - move $erp, [$sp] - subq 4, $sp - move $srp, [$sp] - subq 4, $sp - move $ccs, [$sp] - subq 4, $sp - move $spc, [$sp] - subq 4, $sp - move $mof, [$sp] - subq 4, $sp - move $srs, [$sp] - subq 4, $sp - move.d $acr, [$sp] - subq 14*4, $sp - movem $r13, [$sp] - subq 4, $sp - move.d $r10, [$sp] -.endm - -; Bus fault handler. Extracts relevant information and calls mm subsystem -; to handle the fault. -.macro MMU_BUS_FAULT_HANDLER handler, mmu, we, ex - .globl \handler - .type \handler,"function" -\handler: - SAVE_ALL - move \mmu, $srs ; Select MMU support register bank - move.d $sp, $r11 ; regs - moveq 1, $r12 ; protection fault - moveq \we, $r13 ; write exception? - orq \ex << 1, $r13 ; execute? - move $s3, $r10 ; rw_mm_cause - and.d ~8191, $r10 ; Get faulting page start address - - jsr do_page_fault - nop - ba ret_from_intr - nop - .size \handler, . - \handler -.endm - -; Refill handler. Three cases may occur: -; 1. PMD and PTE exists in mm subsystem but not in TLB -; 2. PMD exists but not PTE -; 3. PMD doesn't exist -; The code below handles case 1 and calls the mm subsystem for case 2 and 3. -; Do not touch this code without very good reasons and extensive testing. -; Note that the code is optimized to minimize stalls (makes the code harder -; to read). -; -; WARNING !!! -; Modified by Mikael Asker 060725: added a workaround for strange TLB -; behavior. If the same PTE is present in more than one set, the TLB -; doesn't recognize it and we get stuck in a loop of refill exceptions. -; The workaround detects such loops and exits them by flushing -; the TLB contents. The problem and workaround were verified -; in VCS by Mikael Starvik. -; -; Each page is 8 KB. Each PMD holds 8192/4 PTEs (each PTE is 4 bytes) so each -; PMD holds 16 MB of virtual memory. -; Bits 0-12 : Offset within a page -; Bits 13-23 : PTE offset within a PMD -; Bits 24-31 : PMD offset within the PGD - -.macro MMU_REFILL_HANDLER handler, mmu - .data -1: .dword 0 ; refill_count - ; == 0 <=> last_refill_cause is invalid -2: .dword 0 ; last_refill_cause - .text - .globl \handler - .type \handler, "function" -\handler: - subq 4, $sp -; (The pipeline stalls for one cycle; $sp used as address in the next cycle.) - move $srs, [$sp] - subq 4, $sp - move \mmu, $srs ; Select MMU support register bank - move.d $acr, [$sp] - subq 12, $sp - move.d 1b, $acr ; Point to refill_count - movem $r2, [$sp] - - test.d [$acr] ; refill_count == 0 ? - beq 5f ; yes, last_refill_cause is invalid - move.d $acr, $r1 - - ; last_refill_cause is valid, investigate cause - addq 4, $r1 ; Point to last_refill_cause - move $s3, $r0 ; Get rw_mm_cause - move.d [$r1], $r2 ; Get last_refill_cause - cmp.d $r0, $r2 ; rw_mm_cause == last_refill_cause ? - beq 6f ; yes, increment count - moveq 1, $r2 - - ; rw_mm_cause != last_refill_cause - move.d $r2, [$acr] ; refill_count = 1 - move.d $r0, [$r1] ; last_refill_cause = rw_mm_cause - -3: ; Probably not in a loop, continue normal processing - move.d current_pgd, $acr ; PGD - ; Look up PMD in PGD - lsrq 24, $r0 ; Get PMD index into PGD (bit 24-31) - move.d [$acr], $acr ; PGD for the current process - addi $r0.d, $acr, $acr - move $s3, $r0 ; rw_mm_cause - move.d [$acr], $acr ; Get PMD - beq 8f - ; Look up PTE in PMD - lsrq PAGE_SHIFT, $r0 - and.w PAGE_MASK, $acr ; Remove PMD flags - and.d 0x7ff, $r0 ; Get PTE index into PMD (bit 13-23) - addi $r0.d, $acr, $acr - move.d [$acr], $acr ; Get PTE - beq 9f - movem [$sp], $r2 ; Restore r0-r2 in delay slot - addq 12, $sp - ; Store in TLB - move $acr, $s5 -4: ; Return - move.d [$sp+], $acr - move [$sp], $srs - addq 4, $sp - rete - rfe - -5: ; last_refill_cause is invalid - moveq 1, $r2 - addq 4, $r1 ; Point to last_refill_cause - move.d $r2, [$acr] ; refill_count = 1 - move $s3, $r0 ; Get rw_mm_cause - ba 3b ; Continue normal processing - move.d $r0,[$r1] ; last_refill_cause = rw_mm_cause - -6: ; rw_mm_cause == last_refill_cause - move.d [$acr], $r2 ; Get refill_count - cmpq 4, $r2 ; refill_count > 4 ? - bhi 7f ; yes - addq 1, $r2 ; refill_count++ - ba 3b ; Continue normal processing - move.d $r2, [$acr] - -7: ; refill_count > 4, error - move.d $acr, $r0 ; Save pointer to refill_count - clear.d [$r0] ; refill_count = 0 - - ;; rewind the short stack - movem [$sp], $r2 ; Restore r0-r2 - addq 12, $sp - move.d [$sp+], $acr - move [$sp], $srs - addq 4, $sp - ;; Keep it simple (slow), save all the regs. - SAVE_ALL - jsr __flush_tlb_all - nop - ba ret_from_intr ; Return - nop - -8: ; PMD missing, let the mm subsystem fix it up. - movem [$sp], $r2 ; Restore r0-r2 -9: ; PTE missing, let the mm subsystem fix it up. - addq 12, $sp - move.d [$sp+], $acr - move [$sp], $srs - addq 4, $sp - SAVE_ALL - move \mmu, $srs - move.d $sp, $r11 ; regs - clear.d $r12 ; Not a protection fault - move.w PAGE_MASK, $acr - move $s3, $r10 ; rw_mm_cause - btstq 9, $r10 ; Check if write access - smi $r13 - and.w PAGE_MASK, $r10 ; Get VPN (virtual address) - jsr do_page_fault - and.w $acr, $r10 - ; Return - ba ret_from_intr - nop - .size \handler, . - \handler -.endm - - ; This is the MMU bus fault handlers. - -MMU_REFILL_HANDLER i_mmu_refill, 1 -MMU_BUS_FAULT_HANDLER i_mmu_invalid, 1, 0, 0 -MMU_BUS_FAULT_HANDLER i_mmu_access, 1, 0, 0 -MMU_BUS_FAULT_HANDLER i_mmu_execute, 1, 0, 1 -MMU_REFILL_HANDLER d_mmu_refill, 2 -MMU_BUS_FAULT_HANDLER d_mmu_invalid, 2, 0, 0 -MMU_BUS_FAULT_HANDLER d_mmu_access, 2, 0, 0 -MMU_BUS_FAULT_HANDLER d_mmu_write, 2, 1, 0 diff --git a/arch/cris/arch-v32/mm/tlb.c b/arch/cris/arch-v32/mm/tlb.c deleted file mode 100644 index 9e4b5ab4971d..000000000000 --- a/arch/cris/arch-v32/mm/tlb.c +++ /dev/null @@ -1,209 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Low level TLB handling. - * - * Copyright (C) 2000-2003, Axis Communications AB. - * - * Authors: Bjorn Wesen <bjornw@axis.com> - * Tobias Anderberg <tobiasa@axis.com>, CRISv32 port. - */ -#include <linux/mm_types.h> - -#include <asm/tlb.h> -#include <asm/mmu_context.h> -#include <arch/hwregs/asm/mmu_defs_asm.h> -#include <arch/hwregs/supp_reg.h> - -#define UPDATE_TLB_SEL_IDX(val) \ -do { \ - unsigned long tlb_sel; \ - \ - tlb_sel = REG_FIELD(mmu, rw_mm_tlb_sel, idx, val); \ - SUPP_REG_WR(RW_MM_TLB_SEL, tlb_sel); \ -} while(0) - -#define UPDATE_TLB_HILO(tlb_hi, tlb_lo) \ -do { \ - SUPP_REG_WR(RW_MM_TLB_HI, tlb_hi); \ - SUPP_REG_WR(RW_MM_TLB_LO, tlb_lo); \ -} while(0) - -/* - * The TLB can host up to 256 different mm contexts at the same time. The running - * context is found in the PID register. Each TLB entry contains a page_id that - * has to match the PID register to give a hit. page_id_map keeps track of which - * mm's is assigned to which page_id's, making sure it's known when to - * invalidate TLB entries. - * - * The last page_id is never running, it is used as an invalid page_id so that - * it's possible to make TLB entries that will nerver match. - * - * Note; the flushes needs to be atomic otherwise an interrupt hander that uses - * vmalloc'ed memory might cause a TLB load in the middle of a flush. - */ - -/* Flush all TLB entries. */ -void -__flush_tlb_all(void) -{ - int i; - int mmu; - unsigned long flags; - unsigned long mmu_tlb_hi; - unsigned long mmu_tlb_sel; - - /* - * Mask with 0xf so similar TLB entries aren't written in the same 4-way - * entry group. - */ - local_irq_save(flags); - - for (mmu = 1; mmu <= 2; mmu++) { - SUPP_BANK_SEL(mmu); /* Select the MMU */ - for (i = 0; i < NUM_TLB_ENTRIES; i++) { - /* Store invalid entry */ - mmu_tlb_sel = REG_FIELD(mmu, rw_mm_tlb_sel, idx, i); - - mmu_tlb_hi = (REG_FIELD(mmu, rw_mm_tlb_hi, pid, INVALID_PAGEID) - | REG_FIELD(mmu, rw_mm_tlb_hi, vpn, i & 0xf)); - - SUPP_REG_WR(RW_MM_TLB_SEL, mmu_tlb_sel); - SUPP_REG_WR(RW_MM_TLB_HI, mmu_tlb_hi); - SUPP_REG_WR(RW_MM_TLB_LO, 0); - } - } - - local_irq_restore(flags); -} - -/* Flush an entire user address space. */ -void -__flush_tlb_mm(struct mm_struct *mm) -{ - int i; - int mmu; - unsigned long flags; - unsigned long page_id; - unsigned long tlb_hi; - unsigned long mmu_tlb_hi; - - page_id = mm->context.page_id; - - if (page_id == NO_CONTEXT) - return; - - /* Mark the TLB entries that match the page_id as invalid. */ - local_irq_save(flags); - - for (mmu = 1; mmu <= 2; mmu++) { - SUPP_BANK_SEL(mmu); - for (i = 0; i < NUM_TLB_ENTRIES; i++) { - UPDATE_TLB_SEL_IDX(i); - - /* Get the page_id */ - SUPP_REG_RD(RW_MM_TLB_HI, tlb_hi); - - /* Check if the page_id match. */ - if ((tlb_hi & 0xff) == page_id) { - mmu_tlb_hi = (REG_FIELD(mmu, rw_mm_tlb_hi, pid, - INVALID_PAGEID) - | REG_FIELD(mmu, rw_mm_tlb_hi, vpn, - i & 0xf)); - - UPDATE_TLB_HILO(mmu_tlb_hi, 0); - } - } - } - - local_irq_restore(flags); -} - -/* Invalidate a single page. */ -void -__flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) -{ - int i; - int mmu; - unsigned long page_id; - unsigned long flags; - unsigned long tlb_hi; - unsigned long mmu_tlb_hi; - - page_id = vma->vm_mm->context.page_id; - - if (page_id == NO_CONTEXT) - return; - - addr &= PAGE_MASK; - - /* - * Invalidate those TLB entries that match both the mm context and the - * requested virtual address. - */ - local_irq_save(flags); - - for (mmu = 1; mmu <= 2; mmu++) { - SUPP_BANK_SEL(mmu); - for (i = 0; i < NUM_TLB_ENTRIES; i++) { - UPDATE_TLB_SEL_IDX(i); - SUPP_REG_RD(RW_MM_TLB_HI, tlb_hi); - - /* Check if page_id and address matches */ - if (((tlb_hi & 0xff) == page_id) && - ((tlb_hi & PAGE_MASK) == addr)) { - mmu_tlb_hi = REG_FIELD(mmu, rw_mm_tlb_hi, pid, - INVALID_PAGEID) | addr; - - UPDATE_TLB_HILO(mmu_tlb_hi, 0); - } - } - } - - local_irq_restore(flags); -} - -/* - * Initialize the context related info for a new mm_struct - * instance. - */ - -int -init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - mm->context.page_id = NO_CONTEXT; - return 0; -} - -static DEFINE_SPINLOCK(mmu_context_lock); - -/* Called in schedule() just before actually doing the switch_to. */ -void -switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) -{ - if (prev != next) { - int cpu = smp_processor_id(); - - /* Make sure there is a MMU context. */ - spin_lock(&mmu_context_lock); - get_mmu_context(next); - cpumask_set_cpu(cpu, mm_cpumask(next)); - spin_unlock(&mmu_context_lock); - - /* - * Remember the pgd for the fault handlers. Keep a separate - * copy of it because current and active_mm might be invalid - * at points where * there's still a need to derefer the pgd. - */ - per_cpu(current_pgd, cpu) = next->pgd; - - /* Switch context in the MMU. */ - if (tsk && task_thread_info(tsk)) { - SPEC_REG_WR(SPEC_REG_PID, next->context.page_id | - task_thread_info(tsk)->tls); - } else { - SPEC_REG_WR(SPEC_REG_PID, next->context.page_id); - } - } -} - diff --git a/arch/cris/arch-v32/output_arch.ld b/arch/cris/arch-v32/output_arch.ld deleted file mode 100644 index d60a57db0ec2..000000000000 --- a/arch/cris/arch-v32/output_arch.ld +++ /dev/null @@ -1,2 +0,0 @@ -/* At the time of this writing, there's no equivalent ld option. */ -OUTPUT_ARCH (crisv32) |