diff --git a/[refs] b/[refs] index 02b09f206087..c14c8db6e6c4 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: e152c38abaa92352679c9b53c4cce533c03997c6 +refs/heads/master: 714daf73d0889c62e90abf4510e4fab65b4668e8 diff --git a/trunk/Documentation/ABI/testing/debugfs-olpc b/trunk/Documentation/ABI/testing/debugfs-olpc deleted file mode 100644 index bd76cc6d55f9..000000000000 --- a/trunk/Documentation/ABI/testing/debugfs-olpc +++ /dev/null @@ -1,16 +0,0 @@ -What: /sys/kernel/debug/olpc-ec/cmd -Date: Dec 2011 -KernelVersion: 3.4 -Contact: devel@lists.laptop.org -Description: - -A generic interface for executing OLPC Embedded Controller commands and -reading their responses. - -To execute a command, write data with the format: CC:N A A A A -CC is the (hex) command, N is the count of expected reply bytes, and A A A A -are optional (hex) arguments. - -To read the response (if any), read from the generic node after executing -a command. Hex reply bytes will be returned, *whether or not* they came from -the immediately previous command. diff --git a/trunk/Documentation/devicetree/bindings/mtd/arm-versatile.txt b/trunk/Documentation/devicetree/bindings/mtd/arm-versatile.txt index beace4b89daa..476845db94d0 100644 --- a/trunk/Documentation/devicetree/bindings/mtd/arm-versatile.txt +++ b/trunk/Documentation/devicetree/bindings/mtd/arm-versatile.txt @@ -4,5 +4,5 @@ Required properties: - compatible : must be "arm,versatile-flash"; - bank-width : width in bytes of flash interface. -The device tree may optionally contain sub-nodes describing partitions of the -address space. See partition.txt for more detail. +Optional properties: +- Subnode partition map from mtd flash binding diff --git a/trunk/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt b/trunk/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt index 1889a4db5b7c..ef66ddd01da0 100644 --- a/trunk/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt +++ b/trunk/Documentation/devicetree/bindings/mtd/atmel-dataflash.txt @@ -3,9 +3,6 @@ Required properties: - compatible : "atmel,", "atmel,", "atmel,dataflash". -The device tree may optionally contain sub-nodes describing partitions of the -address space. See partition.txt for more detail. - Example: flash@1 { diff --git a/trunk/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt b/trunk/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt index fce4894f5a98..00f1f546b32e 100644 --- a/trunk/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt +++ b/trunk/Documentation/devicetree/bindings/mtd/fsl-upm-nand.txt @@ -19,10 +19,6 @@ Optional properties: read registers (tR). Required if property "gpios" is not used (R/B# pins not connected). -Each flash chip described may optionally contain additional sub-nodes -describing partitions of the address space. See partition.txt for more -detail. - Examples: upm@1,0 { diff --git a/trunk/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt b/trunk/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt index 36ef07d3c90f..719f4dc58df7 100644 --- a/trunk/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt +++ b/trunk/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt @@ -25,9 +25,6 @@ Optional properties: GPIO state and before and after command byte writes, this register will be read to ensure that the GPIO accesses have completed. -The device tree may optionally contain sub-nodes describing partitions of the -address space. See partition.txt for more detail. - Examples: gpio-nand@1,0 { diff --git a/trunk/Documentation/devicetree/bindings/mtd/mtd-physmap.txt b/trunk/Documentation/devicetree/bindings/mtd/mtd-physmap.txt index a63c2bd7de2b..80152cb567d9 100644 --- a/trunk/Documentation/devicetree/bindings/mtd/mtd-physmap.txt +++ b/trunk/Documentation/devicetree/bindings/mtd/mtd-physmap.txt @@ -23,8 +23,27 @@ are defined: - vendor-id : Contains the flash chip's vendor id (1 byte). - device-id : Contains the flash chip's device id (1 byte). -The device tree may optionally contain sub-nodes describing partitions of the -address space. See partition.txt for more detail. +In addition to the information on the mtd bank itself, the +device tree may optionally contain additional information +describing partitions of the address space. This can be +used on platforms which have strong conventions about which +portions of a flash are used for what purposes, but which don't +use an on-flash partition table such as RedBoot. + +Each partition is represented as a sub-node of the mtd device. +Each node's name represents the name of the corresponding +partition of the mtd device. + +Flash partitions + - reg : The partition's offset and size within the mtd bank. + - label : (optional) The label / name for this partition. + If omitted, the label is taken from the node name (excluding + the unit address). + - read-only : (optional) This parameter, if present, is a hint to + Linux that this partition should only be mounted + read-only. This is usually used for flash partitions + containing early-boot firmware images or data which should not + be clobbered. Example: diff --git a/trunk/Documentation/devicetree/bindings/mtd/partition.txt b/trunk/Documentation/devicetree/bindings/mtd/partition.txt deleted file mode 100644 index f114ce1657c2..000000000000 --- a/trunk/Documentation/devicetree/bindings/mtd/partition.txt +++ /dev/null @@ -1,38 +0,0 @@ -Representing flash partitions in devicetree - -Partitions can be represented by sub-nodes of an mtd device. This can be used -on platforms which have strong conventions about which portions of a flash are -used for what purposes, but which don't use an on-flash partition table such -as RedBoot. - -#address-cells & #size-cells must both be present in the mtd device and be -equal to 1. - -Required properties: -- reg : The partition's offset and size within the mtd bank. - -Optional properties: -- label : The label / name for this partition. If omitted, the label is taken - from the node name (excluding the unit address). -- read-only : This parameter, if present, is a hint to Linux that this - partition should only be mounted read-only. This is usually used for flash - partitions containing early-boot firmware images or data which should not be - clobbered. - -Examples: - - -flash@0 { - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "u-boot"; - reg = <0x0000000 0x100000>; - read-only; - }; - - uimage@100000 { - reg = <0x0100000 0x200000>; - }; -]; diff --git a/trunk/Documentation/devicetree/usage-model.txt b/trunk/Documentation/devicetree/usage-model.txt deleted file mode 100644 index c5a80099b71c..000000000000 --- a/trunk/Documentation/devicetree/usage-model.txt +++ /dev/null @@ -1,412 +0,0 @@ -Linux and the Device Tree -------------------------- -The Linux usage model for device tree data - -Author: Grant Likely - -This article describes how Linux uses the device tree. An overview of -the device tree data format can be found on the device tree usage page -at devicetree.org[1]. - -[1] http://devicetree.org/Device_Tree_Usage - -The "Open Firmware Device Tree", or simply Device Tree (DT), is a data -structure and language for describing hardware. More specifically, it -is a description of hardware that is readable by an operating system -so that the operating system doesn't need to hard code details of the -machine. - -Structurally, the DT is a tree, or acyclic graph with named nodes, and -nodes may have an arbitrary number of named properties encapsulating -arbitrary data. A mechanism also exists to create arbitrary -links from one node to another outside of the natural tree structure. - -Conceptually, a common set of usage conventions, called 'bindings', -is defined for how data should appear in the tree to describe typical -hardware characteristics including data busses, interrupt lines, GPIO -connections, and peripheral devices. - -As much as possible, hardware is described using existing bindings to -maximize use of existing support code, but since property and node -names are simply text strings, it is easy to extend existing bindings -or create new ones by defining new nodes and properties. Be wary, -however, of creating a new binding without first doing some homework -about what already exists. There are currently two different, -incompatible, bindings for i2c busses that came about because the new -binding was created without first investigating how i2c devices were -already being enumerated in existing systems. - -1. History ----------- -The DT was originally created by Open Firmware as part of the -communication method for passing data from Open Firmware to a client -program (like to an operating system). An operating system used the -Device Tree to discover the topology of the hardware at runtime, and -thereby support a majority of available hardware without hard coded -information (assuming drivers were available for all devices). - -Since Open Firmware is commonly used on PowerPC and SPARC platforms, -the Linux support for those architectures has for a long time used the -Device Tree. - -In 2005, when PowerPC Linux began a major cleanup and to merge 32-bit -and 64-bit support, the decision was made to require DT support on all -powerpc platforms, regardless of whether or not they used Open -Firmware. To do this, a DT representation called the Flattened Device -Tree (FDT) was created which could be passed to the kernel as a binary -blob without requiring a real Open Firmware implementation. U-Boot, -kexec, and other bootloaders were modified to support both passing a -Device Tree Binary (dtb) and to modify a dtb at boot time. DT was -also added to the PowerPC boot wrapper (arch/powerpc/boot/*) so that -a dtb could be wrapped up with the kernel image to support booting -existing non-DT aware firmware. - -Some time later, FDT infrastructure was generalized to be usable by -all architectures. At the time of this writing, 6 mainlined -architectures (arm, microblaze, mips, powerpc, sparc, and x86) and 1 -out of mainline (nios) have some level of DT support. - -2. Data Model -------------- -If you haven't already read the Device Tree Usage[1] page, -then go read it now. It's okay, I'll wait.... - -2.1 High Level View -------------------- -The most important thing to understand is that the DT is simply a data -structure that describes the hardware. There is nothing magical about -it, and it doesn't magically make all hardware configuration problems -go away. What it does do is provide a language for decoupling the -hardware configuration from the board and device driver support in the -Linux kernel (or any other operating system for that matter). Using -it allows board and device support to become data driven; to make -setup decisions based on data passed into the kernel instead of on -per-machine hard coded selections. - -Ideally, data driven platform setup should result in less code -duplication and make it easier to support a wide range of hardware -with a single kernel image. - -Linux uses DT data for three major purposes: -1) platform identification, -2) runtime configuration, and -3) device population. - -2.2 Platform Identification ---------------------------- -First and foremost, the kernel will use data in the DT to identify the -specific machine. In a perfect world, the specific platform shouldn't -matter to the kernel because all platform details would be described -perfectly by the device tree in a consistent and reliable manner. -Hardware is not perfect though, and so the kernel must identify the -machine during early boot so that it has the opportunity to run -machine-specific fixups. - -In the majority of cases, the machine identity is irrelevant, and the -kernel will instead select setup code based on the machine's core -CPU or SoC. On ARM for example, setup_arch() in -arch/arm/kernel/setup.c will call setup_machine_fdt() in -arch/arm/kernel/devicetree.c which searches through the machine_desc -table and selects the machine_desc which best matches the device tree -data. It determines the best match by looking at the 'compatible' -property in the root device tree node, and comparing it with the -dt_compat list in struct machine_desc. - -The 'compatible' property contains a sorted list of strings starting -with the exact name of the machine, followed by an optional list of -boards it is compatible with sorted from most compatible to least. For -example, the root compatible properties for the TI BeagleBoard and its -successor, the BeagleBoard xM board might look like: - - compatible = "ti,omap3-beagleboard", "ti,omap3450", "ti,omap3"; - compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3"; - -Where "ti,omap3-beagleboard-xm" specifies the exact model, it also -claims that it compatible with the OMAP 3450 SoC, and the omap3 family -of SoCs in general. You'll notice that the list is sorted from most -specific (exact board) to least specific (SoC family). - -Astute readers might point out that the Beagle xM could also claim -compatibility with the original Beagle board. However, one should be -cautioned about doing so at the board level since there is typically a -high level of change from one board to another, even within the same -product line, and it is hard to nail down exactly what is meant when one -board claims to be compatible with another. For the top level, it is -better to err on the side of caution and not claim one board is -compatible with another. The notable exception would be when one -board is a carrier for another, such as a CPU module attached to a -carrier board. - -One more note on compatible values. Any string used in a compatible -property must be documented as to what it indicates. Add -documentation for compatible strings in Documentation/devicetree/bindings. - -Again on ARM, for each machine_desc, the kernel looks to see if -any of the dt_compat list entries appear in the compatible property. -If one does, then that machine_desc is a candidate for driving the -machine. After searching the entire table of machine_descs, -setup_machine_fdt() returns the 'most compatible' machine_desc based -on which entry in the compatible property each machine_desc matches -against. If no matching machine_desc is found, then it returns NULL. - -The reasoning behind this scheme is the observation that in the majority -of cases, a single machine_desc can support a large number of boards -if they all use the same SoC, or same family of SoCs. However, -invariably there will be some exceptions where a specific board will -require special setup code that is not useful in the generic case. -Special cases could be handled by explicitly checking for the -troublesome board(s) in generic setup code, but doing so very quickly -becomes ugly and/or unmaintainable if it is more than just a couple of -cases. - -Instead, the compatible list allows a generic machine_desc to provide -support for a wide common set of boards by specifying "less -compatible" value in the dt_compat list. In the example above, -generic board support can claim compatibility with "ti,omap3" or -"ti,omap3450". If a bug was discovered on the original beagleboard -that required special workaround code during early boot, then a new -machine_desc could be added which implements the workarounds and only -matches on "ti,omap3-beagleboard". - -PowerPC uses a slightly different scheme where it calls the .probe() -hook from each machine_desc, and the first one returning TRUE is used. -However, this approach does not take into account the priority of the -compatible list, and probably should be avoided for new architecture -support. - -2.3 Runtime configuration -------------------------- -In most cases, a DT will be the sole method of communicating data from -firmware to the kernel, so also gets used to pass in runtime and -configuration data like the kernel parameters string and the location -of an initrd image. - -Most of this data is contained in the /chosen node, and when booting -Linux it will look something like this: - - chosen { - bootargs = "console=ttyS0,115200 loglevel=8"; - initrd-start = <0xc8000000>; - initrd-end = <0xc8200000>; - }; - -The bootargs property contains the kernel arguments, and the initrd-* -properties define the address and size of an initrd blob. The -chosen node may also optionally contain an arbitrary number of -additional properties for platform-specific configuration data. - -During early boot, the architecture setup code calls of_scan_flat_dt() -several times with different helper callbacks to parse device tree -data before paging is setup. The of_scan_flat_dt() code scans through -the device tree and uses the helpers to extract information required -during early boot. Typically the early_init_dt_scan_chosen() helper -is used to parse the chosen node including kernel parameters, -early_init_dt_scan_root() to initialize the DT address space model, -and early_init_dt_scan_memory() to determine the size and -location of usable RAM. - -On ARM, the function setup_machine_fdt() is responsible for early -scanning of the device tree after selecting the correct machine_desc -that supports the board. - -2.4 Device population ---------------------- -After the board has been identified, and after the early configuration data -has been parsed, then kernel initialization can proceed in the normal -way. At some point in this process, unflatten_device_tree() is called -to convert the data into a more efficient runtime representation. -This is also when machine-specific setup hooks will get called, like -the machine_desc .init_early(), .init_irq() and .init_machine() hooks -on ARM. The remainder of this section uses examples from the ARM -implementation, but all architectures will do pretty much the same -thing when using a DT. - -As can be guessed by the names, .init_early() is used for any machine- -specific setup that needs to be executed early in the boot process, -and .init_irq() is used to set up interrupt handling. Using a DT -doesn't materially change the behaviour of either of these functions. -If a DT is provided, then both .init_early() and .init_irq() are able -to call any of the DT query functions (of_* in include/linux/of*.h) to -get additional data about the platform. - -The most interesting hook in the DT context is .init_machine() which -is primarily responsible for populating the Linux device model with -data about the platform. Historically this has been implemented on -embedded platforms by defining a set of static clock structures, -platform_devices, and other data in the board support .c file, and -registering it en-masse in .init_machine(). When DT is used, then -instead of hard coding static devices for each platform, the list of -devices can be obtained by parsing the DT, and allocating device -structures dynamically. - -The simplest case is when .init_machine() is only responsible for -registering a block of platform_devices. A platform_device is a concept -used by Linux for memory or I/O mapped devices which cannot be detected -by hardware, and for 'composite' or 'virtual' devices (more on those -later). While there is no 'platform device' terminology for the DT, -platform devices roughly correspond to device nodes at the root of the -tree and children of simple memory mapped bus nodes. - -About now is a good time to lay out an example. Here is part of the -device tree for the NVIDIA Tegra board. - -/{ - compatible = "nvidia,harmony", "nvidia,tegra20"; - #address-cells = <1>; - #size-cells = <1>; - interrupt-parent = <&intc>; - - chosen { }; - aliases { }; - - memory { - device_type = "memory"; - reg = <0x00000000 0x40000000>; - }; - - soc { - compatible = "nvidia,tegra20-soc", "simple-bus"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - - intc: interrupt-controller@50041000 { - compatible = "nvidia,tegra20-gic"; - interrupt-controller; - #interrupt-cells = <1>; - reg = <0x50041000 0x1000>, < 0x50040100 0x0100 >; - }; - - serial@70006300 { - compatible = "nvidia,tegra20-uart"; - reg = <0x70006300 0x100>; - interrupts = <122>; - }; - - i2s1: i2s@70002800 { - compatible = "nvidia,tegra20-i2s"; - reg = <0x70002800 0x100>; - interrupts = <77>; - codec = <&wm8903>; - }; - - i2c@7000c000 { - compatible = "nvidia,tegra20-i2c"; - #address-cells = <1>; - #size-cells = <0>; - reg = <0x7000c000 0x100>; - interrupts = <70>; - - wm8903: codec@1a { - compatible = "wlf,wm8903"; - reg = <0x1a>; - interrupts = <347>; - }; - }; - }; - - sound { - compatible = "nvidia,harmony-sound"; - i2s-controller = <&i2s1>; - i2s-codec = <&wm8903>; - }; -}; - -At .machine_init() time, Tegra board support code will need to look at -this DT and decide which nodes to create platform_devices for. -However, looking at the tree, it is not immediately obvious what kind -of device each node represents, or even if a node represents a device -at all. The /chosen, /aliases, and /memory nodes are informational -nodes that don't describe devices (although arguably memory could be -considered a device). The children of the /soc node are memory mapped -devices, but the codec@1a is an i2c device, and the sound node -represents not a device, but rather how other devices are connected -together to create the audio subsystem. I know what each device is -because I'm familiar with the board design, but how does the kernel -know what to do with each node? - -The trick is that the kernel starts at the root of the tree and looks -for nodes that have a 'compatible' property. First, it is generally -assumed that any node with a 'compatible' property represents a device -of some kind, and second, it can be assumed that any node at the root -of the tree is either directly attached to the processor bus, or is a -miscellaneous system device that cannot be described any other way. -For each of these nodes, Linux allocates and registers a -platform_device, which in turn may get bound to a platform_driver. - -Why is using a platform_device for these nodes a safe assumption? -Well, for the way that Linux models devices, just about all bus_types -assume that its devices are children of a bus controller. For -example, each i2c_client is a child of an i2c_master. Each spi_device -is a child of an SPI bus. Similarly for USB, PCI, MDIO, etc. The -same hierarchy is also found in the DT, where I2C device nodes only -ever appear as children of an I2C bus node. Ditto for SPI, MDIO, USB, -etc. The only devices which do not require a specific type of parent -device are platform_devices (and amba_devices, but more on that -later), which will happily live at the base of the Linux /sys/devices -tree. Therefore, if a DT node is at the root of the tree, then it -really probably is best registered as a platform_device. - -Linux board support code calls of_platform_populate(NULL, NULL, NULL) -to kick off discovery of devices at the root of the tree. The -parameters are all NULL because when starting from the root of the -tree, there is no need to provide a starting node (the first NULL), a -parent struct device (the last NULL), and we're not using a match -table (yet). For a board that only needs to register devices, -.init_machine() can be completely empty except for the -of_platform_populate() call. - -In the Tegra example, this accounts for the /soc and /sound nodes, but -what about the children of the SoC node? Shouldn't they be registered -as platform devices too? For Linux DT support, the generic behaviour -is for child devices to be registered by the parent's device driver at -driver .probe() time. So, an i2c bus device driver will register a -i2c_client for each child node, an SPI bus driver will register -its spi_device children, and similarly for other bus_types. -According to that model, a driver could be written that binds to the -SoC node and simply registers platform_devices for each of its -children. The board support code would allocate and register an SoC -device, a (theoretical) SoC device driver could bind to the SoC device, -and register platform_devices for /soc/interrupt-controller, /soc/serial, -/soc/i2s, and /soc/i2c in its .probe() hook. Easy, right? - -Actually, it turns out that registering children of some -platform_devices as more platform_devices is a common pattern, and the -device tree support code reflects that and makes the above example -simpler. The second argument to of_platform_populate() is an -of_device_id table, and any node that matches an entry in that table -will also get its child nodes registered. In the tegra case, the code -can look something like this: - -static void __init harmony_init_machine(void) -{ - /* ... */ - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); -} - -"simple-bus" is defined in the ePAPR 1.0 specification as a property -meaning a simple memory mapped bus, so the of_platform_populate() code -could be written to just assume simple-bus compatible nodes will -always be traversed. However, we pass it in as an argument so that -board support code can always override the default behaviour. - -[Need to add discussion of adding i2c/spi/etc child devices] - -Appendix A: AMBA devices ------------------------- - -ARM Primecells are a certain kind of device attached to the ARM AMBA -bus which include some support for hardware detection and power -management. In Linux, struct amba_device and the amba_bus_type is -used to represent Primecell devices. However, the fiddly bit is that -not all devices on an AMBA bus are Primecells, and for Linux it is -typical for both amba_device and platform_device instances to be -siblings of the same bus segment. - -When using the DT, this creates problems for of_platform_populate() -because it must decide whether to register each node as either a -platform_device or an amba_device. This unfortunately complicates the -device creation model a little bit, but the solution turns out not to -be too invasive. If a node is compatible with "arm,amba-primecell", then -of_platform_populate() will register it as an amba_device instead of a -platform_device. diff --git a/trunk/Documentation/filesystems/files.txt b/trunk/Documentation/filesystems/files.txt index 46dfc6b038c3..ac2facc50d2a 100644 --- a/trunk/Documentation/filesystems/files.txt +++ b/trunk/Documentation/filesystems/files.txt @@ -113,8 +113,8 @@ the fdtable structure - if (fd >= 0) { /* locate_fd() may have expanded fdtable, load the ptr */ fdt = files_fdtable(files); - __set_open_fd(fd, fdt); - __clear_close_on_exec(fd, fdt); + FD_SET(fd, fdt->open_fds); + FD_CLR(fd, fdt->close_on_exec); spin_unlock(&files->file_lock); ..... diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index c1601e5a8b71..e2f8c297a8a4 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -1699,12 +1699,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. The default is to send the implementation identification information. - nfsd.nfs4_disable_idmapping= - [NFSv4] When set to the default of '1', the NFSv4 - server will return only numeric uids and gids to - clients using auth_sys, and will accept numeric uids - and gids from such clients. This is intended to ease - migration from NFSv2/v3. objlayoutdriver.osd_login_prog= [NFS] [OBJLAYOUT] sets the pathname to the program which diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 64168f6dd89e..f9faadef7ab7 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -5185,7 +5185,7 @@ F: kernel/delayacct.c PERFORMANCE EVENTS SUBSYSTEM M: Peter Zijlstra M: Paul Mackerras -M: Ingo Molnar +M: Ingo Molnar M: Arnaldo Carvalho de Melo T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core S: Supported @@ -5833,7 +5833,7 @@ S: Maintained F: drivers/watchdog/sc1200wdt.c SCHEDULER -M: Ingo Molnar +M: Ingo Molnar M: Peter Zijlstra T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core S: Maintained diff --git a/trunk/arch/Kconfig b/trunk/arch/Kconfig index 684eb5af439d..a6f14f622d13 100644 --- a/trunk/arch/Kconfig +++ b/trunk/arch/Kconfig @@ -213,7 +213,4 @@ config HAVE_CMPXCHG_LOCAL config HAVE_CMPXCHG_DOUBLE bool -config ARCH_WANT_OLD_COMPAT_IPC - bool - source "kernel/gcov/Kconfig" diff --git a/trunk/arch/alpha/include/asm/posix_types.h b/trunk/arch/alpha/include/asm/posix_types.h index 24779fc95994..db167413300b 100644 --- a/trunk/arch/alpha/include/asm/posix_types.h +++ b/trunk/arch/alpha/include/asm/posix_types.h @@ -8,13 +8,116 @@ */ typedef unsigned int __kernel_ino_t; -#define __kernel_ino_t __kernel_ino_t - +typedef unsigned int __kernel_mode_t; typedef unsigned int __kernel_nlink_t; -#define __kernel_nlink_t __kernel_nlink_t - +typedef long __kernel_off_t; +typedef long long __kernel_loff_t; +typedef int __kernel_pid_t; +typedef int __kernel_ipc_pid_t; +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +typedef unsigned long __kernel_size_t; +typedef long __kernel_ssize_t; +typedef long __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef int __kernel_clockid_t; +typedef int __kernel_timer_t; + +typedef struct { + int val[2]; +} __kernel_fsid_t; + +typedef __kernel_uid_t __kernel_old_uid_t; +typedef __kernel_gid_t __kernel_old_gid_t; +typedef __kernel_uid_t __kernel_uid32_t; +typedef __kernel_gid_t __kernel_gid32_t; + +typedef unsigned int __kernel_old_dev_t; + +#ifdef __KERNEL__ + +#ifndef __GNUC__ + +#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d)) +#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d)) +#define __FD_ISSET(d, set) (((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0) +#define __FD_ZERO(set) \ + ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set))) + +#else /* __GNUC__ */ + +/* With GNU C, use inline functions instead so args are evaluated only once: */ + +#undef __FD_SET +static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] |= (1UL<<_rem); +} + +#undef __FD_CLR +static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); +} + +#undef __FD_ISSET +static __inline__ int __FD_ISSET(unsigned long fd, const __kernel_fd_set *p) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; +} + +/* + * This will unroll the loop for the normal constant case (8 ints, + * for a 256-bit fd_set) + */ +#undef __FD_ZERO +static __inline__ void __FD_ZERO(__kernel_fd_set *p) +{ + unsigned long *tmp = p->fds_bits; + int i; + + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { + case 16: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; + tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0; + tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0; + return; + + case 8: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; + return; + + case 4: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + return; + } + } + i = __FDSET_LONGS; + while (i) { + i--; + *tmp = 0; + tmp++; + } +} + +#endif /* __GNUC__ */ -#include +#endif /* __KERNEL__ */ #endif /* _ALPHA_POSIX_TYPES_H */ diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index 93180845ae16..5098564d5879 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -9,7 +9,6 @@ config ARM select SYS_SUPPORTS_APM_EMULATION select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) select HAVE_OPROFILE if (HAVE_PERF_EVENTS) - select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL select HAVE_ARCH_KGDB select HAVE_KPROBES if !XIP_KERNEL select HAVE_KRETPROBES if (HAVE_KPROBES) @@ -22,7 +21,6 @@ config ARM select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZO select HAVE_KERNEL_LZMA - select HAVE_KERNEL_XZ select HAVE_IRQ_WORK select HAVE_PERF_EVENTS select PERF_USE_VMALLOC @@ -30,10 +28,10 @@ config ARM select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7)) select HAVE_C_RECORDMCOUNT select HAVE_GENERIC_HARDIRQS + select HAVE_SPARSE_IRQ select GENERIC_IRQ_SHOW select CPU_PM if (SUSPEND || CPU_IDLE) select GENERIC_PCI_IOMAP - select HAVE_BPF_JIT if NET help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and @@ -54,6 +52,9 @@ config MIGHT_HAVE_PCI config SYS_SUPPORTS_APM_EMULATION bool +config HAVE_SCHED_CLOCK + bool + config GENERIC_GPIO bool @@ -179,9 +180,6 @@ config ZONE_DMA config NEED_DMA_MAP_STATE def_bool y -config ARCH_HAS_DMA_SET_COHERENT_MASK - bool - config GENERIC_ISA_DMA bool @@ -219,13 +217,6 @@ config ARM_PATCH_PHYS_VIRT this feature (eg, building a kernel for a single machine) and you need to shrink the kernel to the minimal size. -config NEED_MACH_IO_H - bool - help - Select this when mach/io.h is required to provide special - definitions for this platform. The need for mach/io.h should - be avoided when possible. - config NEED_MACH_MEMORY_H bool help @@ -277,9 +268,7 @@ config ARCH_INTEGRATOR select GENERIC_CLOCKEVENTS select PLAT_VERSATILE select PLAT_VERSATILE_FPGA_IRQ - select NEED_MACH_IO_H select NEED_MACH_MEMORY_H - select SPARSE_IRQ help Support for ARM's Integrator platform. @@ -326,7 +315,6 @@ config ARCH_VEXPRESS select HAVE_CLK select HAVE_PATA_PLATFORM select ICST - select NO_IOPORT select PLAT_VERSATILE select PLAT_VERSATILE_CLCD help @@ -366,7 +354,6 @@ config ARCH_HIGHBANK select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU select HAVE_SMP - select SPARSE_IRQ select USE_OF help Support for the Calxeda Highbank SoC based boards. @@ -417,7 +404,6 @@ config ARCH_EBSA110 select ISA select NO_IOPORT select ARCH_USES_GETTIMEOFFSET - select NEED_MACH_IO_H select NEED_MACH_MEMORY_H help This is an evaluation board for the StrongARM processor available @@ -444,7 +430,6 @@ config ARCH_FOOTBRIDGE select FOOTBRIDGE select GENERIC_CLOCKEVENTS select HAVE_IDE - select NEED_MACH_IO_H select NEED_MACH_MEMORY_H help Support for systems based on the DC21285 companion chip @@ -457,6 +442,7 @@ config ARCH_MXC select CLKDEV_LOOKUP select CLKSRC_MMIO select GENERIC_IRQ_CHIP + select HAVE_SCHED_CLOCK select MULTI_IRQ_HANDLER help Support for Freescale MXC/iMX-based family of processors @@ -496,7 +482,6 @@ config ARCH_IOP13XX select PCI select ARCH_SUPPORTS_MSI select VMSPLIT_1G - select NEED_MACH_IO_H select NEED_MACH_MEMORY_H select NEED_RET_TO_USER help @@ -506,7 +491,6 @@ config ARCH_IOP32X bool "IOP32x-based" depends on MMU select CPU_XSCALE - select NEED_MACH_IO_H select NEED_RET_TO_USER select PLAT_IOP select PCI @@ -519,7 +503,6 @@ config ARCH_IOP33X bool "IOP33x-based" depends on MMU select CPU_XSCALE - select NEED_MACH_IO_H select NEED_RET_TO_USER select PLAT_IOP select PCI @@ -533,7 +516,6 @@ config ARCH_IXP23XX select CPU_XSC3 select PCI select ARCH_USES_GETTIMEOFFSET - select NEED_MACH_IO_H select NEED_MACH_MEMORY_H help Support for Intel's IXP23xx (XScale) family of processors. @@ -544,7 +526,6 @@ config ARCH_IXP2000 select CPU_XSCALE select PCI select ARCH_USES_GETTIMEOFFSET - select NEED_MACH_IO_H select NEED_MACH_MEMORY_H help Support for Intel's IXP2400/2800 (XScale) family of processors. @@ -552,13 +533,12 @@ config ARCH_IXP2000 config ARCH_IXP4XX bool "IXP4xx-based" depends on MMU - select ARCH_HAS_DMA_SET_COHERENT_MASK select CLKSRC_MMIO select CPU_XSCALE select GENERIC_GPIO select GENERIC_CLOCKEVENTS + select HAVE_SCHED_CLOCK select MIGHT_HAVE_PCI - select NEED_MACH_IO_H select DMABOUNCE if PCI help Support for Intel's IXP4XX (XScale) family of processors. @@ -569,7 +549,6 @@ config ARCH_DOVE select PCI select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS - select NEED_MACH_IO_H select PLAT_ORION help Support for the Marvell Dove SoC 88AP510 @@ -580,7 +559,6 @@ config ARCH_KIRKWOOD select PCI select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS - select NEED_MACH_IO_H select PLAT_ORION help Support for the following Marvell Kirkwood series SoCs: @@ -605,7 +583,6 @@ config ARCH_MV78XX0 select PCI select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS - select NEED_MACH_IO_H select PLAT_ORION help Support for the following Marvell MV78xx0 series SoCs: @@ -631,6 +608,7 @@ config ARCH_MMP select CLKDEV_LOOKUP select GENERIC_CLOCKEVENTS select GPIO_PXA + select HAVE_SCHED_CLOCK select TICK_ONESHOT select PLAT_PXA select SPARSE_IRQ @@ -671,9 +649,9 @@ config ARCH_TEGRA select GENERIC_CLOCKEVENTS select GENERIC_GPIO select HAVE_CLK + select HAVE_SCHED_CLOCK select HAVE_SMP select MIGHT_HAVE_CACHE_L2X0 - select NEED_MACH_IO_H if PCI select ARCH_HAS_CPUFREQ help This enables support for NVIDIA Tegra based systems (Tegra APX, @@ -688,6 +666,7 @@ config ARCH_PICOXCELL select DW_APB_TIMER select GENERIC_CLOCKEVENTS select GENERIC_GPIO + select HAVE_SCHED_CLOCK select HAVE_TCM select NO_IOPORT select SPARSE_IRQ @@ -715,6 +694,7 @@ config ARCH_PXA select ARCH_REQUIRE_GPIOLIB select GENERIC_CLOCKEVENTS select GPIO_PXA + select HAVE_SCHED_CLOCK select TICK_ONESHOT select PLAT_PXA select SPARSE_IRQ @@ -765,7 +745,6 @@ config ARCH_RPC select ARCH_SPARSEMEM_ENABLE select ARCH_USES_GETTIMEOFFSET select HAVE_IDE - select NEED_MACH_IO_H select NEED_MACH_MEMORY_H help On the Acorn Risc-PC, Linux can support the internal IDE disk and @@ -782,6 +761,7 @@ config ARCH_SA1100 select CPU_FREQ select GENERIC_CLOCKEVENTS select CLKDEV_LOOKUP + select HAVE_SCHED_CLOCK select TICK_ONESHOT select ARCH_REQUIRE_GPIOLIB select HAVE_IDE @@ -800,7 +780,6 @@ config ARCH_S3C24XX select HAVE_S3C2410_I2C if I2C select HAVE_S3C_RTC if RTC_CLASS select HAVE_S3C2410_WATCHDOG if WATCHDOG - select NEED_MACH_IO_H help Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443 and S3C2450 SoCs based systems, such as the Simtec Electronics BAST @@ -839,6 +818,7 @@ config ARCH_S5P64X0 select CLKSRC_MMIO select HAVE_S3C2410_WATCHDOG if WATCHDOG select GENERIC_CLOCKEVENTS + select HAVE_SCHED_CLOCK select HAVE_S3C2410_I2C if I2C select HAVE_S3C_RTC if RTC_CLASS help @@ -869,6 +849,7 @@ config ARCH_S5PV210 select CLKSRC_MMIO select ARCH_HAS_CPUFREQ select GENERIC_CLOCKEVENTS + select HAVE_SCHED_CLOCK select HAVE_S3C2410_I2C if I2C select HAVE_S3C_RTC if RTC_CLASS select HAVE_S3C2410_WATCHDOG if WATCHDOG @@ -902,7 +883,6 @@ config ARCH_SHARK select PCI select ARCH_USES_GETTIMEOFFSET select NEED_MACH_MEMORY_H - select NEED_MACH_IO_H help Support for the StrongARM based Digital DNARD machine, also known as "Shark" (). @@ -912,6 +892,7 @@ config ARCH_U300 depends on MMU select CLKSRC_MMIO select CPU_ARM926T + select HAVE_SCHED_CLOCK select HAVE_TCM select ARM_AMBA select ARM_PATCH_PHYS_VIRT @@ -970,6 +951,7 @@ config ARCH_OMAP select ARCH_HAS_CPUFREQ select CLKSRC_MMIO select GENERIC_CLOCKEVENTS + select HAVE_SCHED_CLOCK select ARCH_HAS_HOLES_MEMORYMODEL help Support for TI's OMAP platform (OMAP1/2/3/4). @@ -1133,11 +1115,13 @@ config ARCH_ACORN config PLAT_IOP bool select GENERIC_CLOCKEVENTS + select HAVE_SCHED_CLOCK config PLAT_ORION bool select CLKSRC_MMIO select GENERIC_IRQ_CHIP + select HAVE_SCHED_CLOCK config PLAT_PXA bool diff --git a/trunk/arch/arm/Kconfig.debug b/trunk/arch/arm/Kconfig.debug index 85348a09d655..66ca8014ff3e 100644 --- a/trunk/arch/arm/Kconfig.debug +++ b/trunk/arch/arm/Kconfig.debug @@ -292,22 +292,6 @@ choice Note that the system will appear to hang during boot if there is nothing connected to read from the DCC. - config DEBUG_SEMIHOSTING - bool "Kernel low-level debug output via semihosting I" - help - Semihosting enables code running on an ARM target to use - the I/O facilities on a host debugger/emulator through a - simple SVC calls. The host debugger or emulator must have - semihosting enabled for the special svc call to be trapped - otherwise the kernel will crash. - - This is known to work with OpenOCD, as wellas - ARM's Fast Models, or any other controlling environment - that implements semihosting. - - For more details about semihosting, please see - chapter 8 of DUI0203I_rvct_developer_guide.pdf from ARM Ltd. - endchoice config EARLY_PRINTK diff --git a/trunk/arch/arm/Makefile b/trunk/arch/arm/Makefile index 047a20780fc1..dcb088e868fe 100644 --- a/trunk/arch/arm/Makefile +++ b/trunk/arch/arm/Makefile @@ -253,7 +253,6 @@ core-$(CONFIG_VFP) += arch/arm/vfp/ # If we have a machine-specific directory, then include it in the build. core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/ -core-y += arch/arm/net/ core-y += $(machdirs) $(platdirs) drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/ diff --git a/trunk/arch/arm/boot/compressed/.gitignore b/trunk/arch/arm/boot/compressed/.gitignore index d0d441c429ae..e0936a148516 100644 --- a/trunk/arch/arm/boot/compressed/.gitignore +++ b/trunk/arch/arm/boot/compressed/.gitignore @@ -1,10 +1,8 @@ -ashldi3.S font.c lib1funcs.S piggy.gzip piggy.lzo piggy.lzma -piggy.xzkern vmlinux vmlinux.lds diff --git a/trunk/arch/arm/boot/compressed/Makefile b/trunk/arch/arm/boot/compressed/Makefile index bb267562e7ed..cf0a64ce4b83 100644 --- a/trunk/arch/arm/boot/compressed/Makefile +++ b/trunk/arch/arm/boot/compressed/Makefile @@ -92,7 +92,6 @@ SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ suffix_$(CONFIG_KERNEL_GZIP) = gzip suffix_$(CONFIG_KERNEL_LZO) = lzo suffix_$(CONFIG_KERNEL_LZMA) = lzma -suffix_$(CONFIG_KERNEL_XZ) = xzkern # Borrowed libfdt files for the ATAG compatibility mode @@ -113,12 +112,10 @@ endif targets := vmlinux vmlinux.lds \ piggy.$(suffix_y) piggy.$(suffix_y).o \ - lib1funcs.o lib1funcs.S ashldi3.o ashldi3.S \ - font.o font.c head.o misc.o $(OBJS) + lib1funcs.o lib1funcs.S font.o font.c head.o misc.o $(OBJS) # Make sure files are removed during clean -extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern \ - lib1funcs.S ashldi3.S $(libfdt) $(libfdt_hdrs) +extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs) ifeq ($(CONFIG_FUNCTION_TRACER),y) ORIG_CFLAGS := $(KBUILD_CFLAGS) @@ -154,12 +151,6 @@ lib1funcs = $(obj)/lib1funcs.o $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S $(call cmd,shipped) -# For __aeabi_llsl -ashldi3 = $(obj)/ashldi3.o - -$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S - $(call cmd,shipped) - # We need to prevent any GOTOFF relocs being used with references # to symbols in the .bss section since we cannot relocate them # independently from the rest at run time. This can be achieved by @@ -181,7 +172,7 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \ fi $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ - $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE + $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE @$(check_for_multiple_zreladdr) $(call if_changed,ld) @$(check_for_bad_syms) diff --git a/trunk/arch/arm/boot/compressed/decompress.c b/trunk/arch/arm/boot/compressed/decompress.c index f41b38cafce8..07be5a2f8302 100644 --- a/trunk/arch/arm/boot/compressed/decompress.c +++ b/trunk/arch/arm/boot/compressed/decompress.c @@ -44,12 +44,6 @@ extern void error(char *); #include "../../../../lib/decompress_unlzma.c" #endif -#ifdef CONFIG_KERNEL_XZ -#define memmove memmove -#define memcpy memcpy -#include "../../../../lib/decompress_unxz.c" -#endif - int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) { return decompress(input, len, NULL, NULL, output, NULL, error); diff --git a/trunk/arch/arm/boot/compressed/piggy.xzkern.S b/trunk/arch/arm/boot/compressed/piggy.xzkern.S deleted file mode 100644 index 5703f300d027..000000000000 --- a/trunk/arch/arm/boot/compressed/piggy.xzkern.S +++ /dev/null @@ -1,6 +0,0 @@ - .section .piggydata,#alloc - .globl input_data -input_data: - .incbin "arch/arm/boot/compressed/piggy.xzkern" - .globl input_data_end -input_data_end: diff --git a/trunk/arch/arm/common/Kconfig b/trunk/arch/arm/common/Kconfig index 283fa1d804f4..3bb1d7589bd9 100644 --- a/trunk/arch/arm/common/Kconfig +++ b/trunk/arch/arm/common/Kconfig @@ -24,6 +24,9 @@ config ARM_VIC_NR config ICST bool +config PL330 + bool + config SA1111 bool select DMABOUNCE if !ARCH_PXA diff --git a/trunk/arch/arm/common/Makefile b/trunk/arch/arm/common/Makefile index 215816f1775f..69feafe7286c 100644 --- a/trunk/arch/arm/common/Makefile +++ b/trunk/arch/arm/common/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_ARM_GIC) += gic.o obj-$(CONFIG_ARM_VIC) += vic.o obj-$(CONFIG_ICST) += icst.o +obj-$(CONFIG_PL330) += pl330.o obj-$(CONFIG_SA1111) += sa1111.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o obj-$(CONFIG_DMABOUNCE) += dmabounce.o diff --git a/trunk/arch/arm/common/gic.c b/trunk/arch/arm/common/gic.c index aa5269984187..f0783be17352 100644 --- a/trunk/arch/arm/common/gic.c +++ b/trunk/arch/arm/common/gic.c @@ -686,12 +686,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, * For primary GICs, skip over SGIs. * For secondary GICs, skip over PPIs, too. */ - if (gic_nr == 0 && (irq_start & 31) > 0) { - hwirq_base = 16; - if (irq_start != -1) - irq_start = (irq_start & ~31) + 16; - } else { - hwirq_base = 32; + hwirq_base = 32; + if (gic_nr == 0) { + if ((irq_start & 31) > 0) { + hwirq_base = 16; + if (irq_start != -1) + irq_start = (irq_start & ~31) + 16; + } } /* diff --git a/trunk/arch/arm/common/pl330.c b/trunk/arch/arm/common/pl330.c new file mode 100644 index 000000000000..ff3ad2244824 --- /dev/null +++ b/trunk/arch/arm/common/pl330.c @@ -0,0 +1,1960 @@ +/* linux/arch/arm/common/pl330.c + * + * Copyright (C) 2010 Samsung Electronics Co Ltd. + * Jaswinder Singh + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* Register and Bit field Definitions */ +#define DS 0x0 +#define DS_ST_STOP 0x0 +#define DS_ST_EXEC 0x1 +#define DS_ST_CMISS 0x2 +#define DS_ST_UPDTPC 0x3 +#define DS_ST_WFE 0x4 +#define DS_ST_ATBRR 0x5 +#define DS_ST_QBUSY 0x6 +#define DS_ST_WFP 0x7 +#define DS_ST_KILL 0x8 +#define DS_ST_CMPLT 0x9 +#define DS_ST_FLTCMP 0xe +#define DS_ST_FAULT 0xf + +#define DPC 0x4 +#define INTEN 0x20 +#define ES 0x24 +#define INTSTATUS 0x28 +#define INTCLR 0x2c +#define FSM 0x30 +#define FSC 0x34 +#define FTM 0x38 + +#define _FTC 0x40 +#define FTC(n) (_FTC + (n)*0x4) + +#define _CS 0x100 +#define CS(n) (_CS + (n)*0x8) +#define CS_CNS (1 << 21) + +#define _CPC 0x104 +#define CPC(n) (_CPC + (n)*0x8) + +#define _SA 0x400 +#define SA(n) (_SA + (n)*0x20) + +#define _DA 0x404 +#define DA(n) (_DA + (n)*0x20) + +#define _CC 0x408 +#define CC(n) (_CC + (n)*0x20) + +#define CC_SRCINC (1 << 0) +#define CC_DSTINC (1 << 14) +#define CC_SRCPRI (1 << 8) +#define CC_DSTPRI (1 << 22) +#define CC_SRCNS (1 << 9) +#define CC_DSTNS (1 << 23) +#define CC_SRCIA (1 << 10) +#define CC_DSTIA (1 << 24) +#define CC_SRCBRSTLEN_SHFT 4 +#define CC_DSTBRSTLEN_SHFT 18 +#define CC_SRCBRSTSIZE_SHFT 1 +#define CC_DSTBRSTSIZE_SHFT 15 +#define CC_SRCCCTRL_SHFT 11 +#define CC_SRCCCTRL_MASK 0x7 +#define CC_DSTCCTRL_SHFT 25 +#define CC_DRCCCTRL_MASK 0x7 +#define CC_SWAP_SHFT 28 + +#define _LC0 0x40c +#define LC0(n) (_LC0 + (n)*0x20) + +#define _LC1 0x410 +#define LC1(n) (_LC1 + (n)*0x20) + +#define DBGSTATUS 0xd00 +#define DBG_BUSY (1 << 0) + +#define DBGCMD 0xd04 +#define DBGINST0 0xd08 +#define DBGINST1 0xd0c + +#define CR0 0xe00 +#define CR1 0xe04 +#define CR2 0xe08 +#define CR3 0xe0c +#define CR4 0xe10 +#define CRD 0xe14 + +#define PERIPH_ID 0xfe0 +#define PCELL_ID 0xff0 + +#define CR0_PERIPH_REQ_SET (1 << 0) +#define CR0_BOOT_EN_SET (1 << 1) +#define CR0_BOOT_MAN_NS (1 << 2) +#define CR0_NUM_CHANS_SHIFT 4 +#define CR0_NUM_CHANS_MASK 0x7 +#define CR0_NUM_PERIPH_SHIFT 12 +#define CR0_NUM_PERIPH_MASK 0x1f +#define CR0_NUM_EVENTS_SHIFT 17 +#define CR0_NUM_EVENTS_MASK 0x1f + +#define CR1_ICACHE_LEN_SHIFT 0 +#define CR1_ICACHE_LEN_MASK 0x7 +#define CR1_NUM_ICACHELINES_SHIFT 4 +#define CR1_NUM_ICACHELINES_MASK 0xf + +#define CRD_DATA_WIDTH_SHIFT 0 +#define CRD_DATA_WIDTH_MASK 0x7 +#define CRD_WR_CAP_SHIFT 4 +#define CRD_WR_CAP_MASK 0x7 +#define CRD_WR_Q_DEP_SHIFT 8 +#define CRD_WR_Q_DEP_MASK 0xf +#define CRD_RD_CAP_SHIFT 12 +#define CRD_RD_CAP_MASK 0x7 +#define CRD_RD_Q_DEP_SHIFT 16 +#define CRD_RD_Q_DEP_MASK 0xf +#define CRD_DATA_BUFF_SHIFT 20 +#define CRD_DATA_BUFF_MASK 0x3ff + +#define PART 0x330 +#define DESIGNER 0x41 +#define REVISION 0x0 +#define INTEG_CFG 0x0 +#define PERIPH_ID_VAL ((PART << 0) | (DESIGNER << 12)) + +#define PCELL_ID_VAL 0xb105f00d + +#define PL330_STATE_STOPPED (1 << 0) +#define PL330_STATE_EXECUTING (1 << 1) +#define PL330_STATE_WFE (1 << 2) +#define PL330_STATE_FAULTING (1 << 3) +#define PL330_STATE_COMPLETING (1 << 4) +#define PL330_STATE_WFP (1 << 5) +#define PL330_STATE_KILLING (1 << 6) +#define PL330_STATE_FAULT_COMPLETING (1 << 7) +#define PL330_STATE_CACHEMISS (1 << 8) +#define PL330_STATE_UPDTPC (1 << 9) +#define PL330_STATE_ATBARRIER (1 << 10) +#define PL330_STATE_QUEUEBUSY (1 << 11) +#define PL330_STATE_INVALID (1 << 15) + +#define PL330_STABLE_STATES (PL330_STATE_STOPPED | PL330_STATE_EXECUTING \ + | PL330_STATE_WFE | PL330_STATE_FAULTING) + +#define CMD_DMAADDH 0x54 +#define CMD_DMAEND 0x00 +#define CMD_DMAFLUSHP 0x35 +#define CMD_DMAGO 0xa0 +#define CMD_DMALD 0x04 +#define CMD_DMALDP 0x25 +#define CMD_DMALP 0x20 +#define CMD_DMALPEND 0x28 +#define CMD_DMAKILL 0x01 +#define CMD_DMAMOV 0xbc +#define CMD_DMANOP 0x18 +#define CMD_DMARMB 0x12 +#define CMD_DMASEV 0x34 +#define CMD_DMAST 0x08 +#define CMD_DMASTP 0x29 +#define CMD_DMASTZ 0x0c +#define CMD_DMAWFE 0x36 +#define CMD_DMAWFP 0x30 +#define CMD_DMAWMB 0x13 + +#define SZ_DMAADDH 3 +#define SZ_DMAEND 1 +#define SZ_DMAFLUSHP 2 +#define SZ_DMALD 1 +#define SZ_DMALDP 2 +#define SZ_DMALP 2 +#define SZ_DMALPEND 2 +#define SZ_DMAKILL 1 +#define SZ_DMAMOV 6 +#define SZ_DMANOP 1 +#define SZ_DMARMB 1 +#define SZ_DMASEV 2 +#define SZ_DMAST 1 +#define SZ_DMASTP 2 +#define SZ_DMASTZ 1 +#define SZ_DMAWFE 2 +#define SZ_DMAWFP 2 +#define SZ_DMAWMB 1 +#define SZ_DMAGO 6 + +#define BRST_LEN(ccr) ((((ccr) >> CC_SRCBRSTLEN_SHFT) & 0xf) + 1) +#define BRST_SIZE(ccr) (1 << (((ccr) >> CC_SRCBRSTSIZE_SHFT) & 0x7)) + +#define BYTE_TO_BURST(b, ccr) ((b) / BRST_SIZE(ccr) / BRST_LEN(ccr)) +#define BURST_TO_BYTE(c, ccr) ((c) * BRST_SIZE(ccr) * BRST_LEN(ccr)) + +/* + * With 256 bytes, we can do more than 2.5MB and 5MB xfers per req + * at 1byte/burst for P<->M and M<->M respectively. + * For typical scenario, at 1word/burst, 10MB and 20MB xfers per req + * should be enough for P<->M and M<->M respectively. + */ +#define MCODE_BUFF_PER_REQ 256 + +/* If the _pl330_req is available to the client */ +#define IS_FREE(req) (*((u8 *)((req)->mc_cpu)) == CMD_DMAEND) + +/* Use this _only_ to wait on transient states */ +#define UNTIL(t, s) while (!(_state(t) & (s))) cpu_relax(); + +#ifdef PL330_DEBUG_MCGEN +static unsigned cmd_line; +#define PL330_DBGCMD_DUMP(off, x...) do { \ + printk("%x:", cmd_line); \ + printk(x); \ + cmd_line += off; \ + } while (0) +#define PL330_DBGMC_START(addr) (cmd_line = addr) +#else +#define PL330_DBGCMD_DUMP(off, x...) do {} while (0) +#define PL330_DBGMC_START(addr) do {} while (0) +#endif + +struct _xfer_spec { + u32 ccr; + struct pl330_req *r; + struct pl330_xfer *x; +}; + +enum dmamov_dst { + SAR = 0, + CCR, + DAR, +}; + +enum pl330_dst { + SRC = 0, + DST, +}; + +enum pl330_cond { + SINGLE, + BURST, + ALWAYS, +}; + +struct _pl330_req { + u32 mc_bus; + void *mc_cpu; + /* Number of bytes taken to setup MC for the req */ + u32 mc_len; + struct pl330_req *r; + /* Hook to attach to DMAC's list of reqs with due callback */ + struct list_head rqd; +}; + +/* ToBeDone for tasklet */ +struct _pl330_tbd { + bool reset_dmac; + bool reset_mngr; + u8 reset_chan; +}; + +/* A DMAC Thread */ +struct pl330_thread { + u8 id; + int ev; + /* If the channel is not yet acquired by any client */ + bool free; + /* Parent DMAC */ + struct pl330_dmac *dmac; + /* Only two at a time */ + struct _pl330_req req[2]; + /* Index of the last enqueued request */ + unsigned lstenq; + /* Index of the last submitted request or -1 if the DMA is stopped */ + int req_running; +}; + +enum pl330_dmac_state { + UNINIT, + INIT, + DYING, +}; + +/* A DMAC */ +struct pl330_dmac { + spinlock_t lock; + /* Holds list of reqs with due callbacks */ + struct list_head req_done; + /* Pointer to platform specific stuff */ + struct pl330_info *pinfo; + /* Maximum possible events/irqs */ + int events[32]; + /* BUS address of MicroCode buffer */ + u32 mcode_bus; + /* CPU address of MicroCode buffer */ + void *mcode_cpu; + /* List of all Channel threads */ + struct pl330_thread *channels; + /* Pointer to the MANAGER thread */ + struct pl330_thread *manager; + /* To handle bad news in interrupt */ + struct tasklet_struct tasks; + struct _pl330_tbd dmac_tbd; + /* State of DMAC operation */ + enum pl330_dmac_state state; +}; + +static inline void _callback(struct pl330_req *r, enum pl330_op_err err) +{ + if (r && r->xfer_cb) + r->xfer_cb(r->token, err); +} + +static inline bool _queue_empty(struct pl330_thread *thrd) +{ + return (IS_FREE(&thrd->req[0]) && IS_FREE(&thrd->req[1])) + ? true : false; +} + +static inline bool _queue_full(struct pl330_thread *thrd) +{ + return (IS_FREE(&thrd->req[0]) || IS_FREE(&thrd->req[1])) + ? false : true; +} + +static inline bool is_manager(struct pl330_thread *thrd) +{ + struct pl330_dmac *pl330 = thrd->dmac; + + /* MANAGER is indexed at the end */ + if (thrd->id == pl330->pinfo->pcfg.num_chan) + return true; + else + return false; +} + +/* If manager of the thread is in Non-Secure mode */ +static inline bool _manager_ns(struct pl330_thread *thrd) +{ + struct pl330_dmac *pl330 = thrd->dmac; + + return (pl330->pinfo->pcfg.mode & DMAC_MODE_NS) ? true : false; +} + +static inline u32 get_id(struct pl330_info *pi, u32 off) +{ + void __iomem *regs = pi->base; + u32 id = 0; + + id |= (readb(regs + off + 0x0) << 0); + id |= (readb(regs + off + 0x4) << 8); + id |= (readb(regs + off + 0x8) << 16); + id |= (readb(regs + off + 0xc) << 24); + + return id; +} + +static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[], + enum pl330_dst da, u16 val) +{ + if (dry_run) + return SZ_DMAADDH; + + buf[0] = CMD_DMAADDH; + buf[0] |= (da << 1); + *((u16 *)&buf[1]) = val; + + PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n", + da == 1 ? "DA" : "SA", val); + + return SZ_DMAADDH; +} + +static inline u32 _emit_END(unsigned dry_run, u8 buf[]) +{ + if (dry_run) + return SZ_DMAEND; + + buf[0] = CMD_DMAEND; + + PL330_DBGCMD_DUMP(SZ_DMAEND, "\tDMAEND\n"); + + return SZ_DMAEND; +} + +static inline u32 _emit_FLUSHP(unsigned dry_run, u8 buf[], u8 peri) +{ + if (dry_run) + return SZ_DMAFLUSHP; + + buf[0] = CMD_DMAFLUSHP; + + peri &= 0x1f; + peri <<= 3; + buf[1] = peri; + + PL330_DBGCMD_DUMP(SZ_DMAFLUSHP, "\tDMAFLUSHP %u\n", peri >> 3); + + return SZ_DMAFLUSHP; +} + +static inline u32 _emit_LD(unsigned dry_run, u8 buf[], enum pl330_cond cond) +{ + if (dry_run) + return SZ_DMALD; + + buf[0] = CMD_DMALD; + + if (cond == SINGLE) + buf[0] |= (0 << 1) | (1 << 0); + else if (cond == BURST) + buf[0] |= (1 << 1) | (1 << 0); + + PL330_DBGCMD_DUMP(SZ_DMALD, "\tDMALD%c\n", + cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A')); + + return SZ_DMALD; +} + +static inline u32 _emit_LDP(unsigned dry_run, u8 buf[], + enum pl330_cond cond, u8 peri) +{ + if (dry_run) + return SZ_DMALDP; + + buf[0] = CMD_DMALDP; + + if (cond == BURST) + buf[0] |= (1 << 1); + + peri &= 0x1f; + peri <<= 3; + buf[1] = peri; + + PL330_DBGCMD_DUMP(SZ_DMALDP, "\tDMALDP%c %u\n", + cond == SINGLE ? 'S' : 'B', peri >> 3); + + return SZ_DMALDP; +} + +static inline u32 _emit_LP(unsigned dry_run, u8 buf[], + unsigned loop, u8 cnt) +{ + if (dry_run) + return SZ_DMALP; + + buf[0] = CMD_DMALP; + + if (loop) + buf[0] |= (1 << 1); + + cnt--; /* DMAC increments by 1 internally */ + buf[1] = cnt; + + PL330_DBGCMD_DUMP(SZ_DMALP, "\tDMALP_%c %u\n", loop ? '1' : '0', cnt); + + return SZ_DMALP; +} + +struct _arg_LPEND { + enum pl330_cond cond; + bool forever; + unsigned loop; + u8 bjump; +}; + +static inline u32 _emit_LPEND(unsigned dry_run, u8 buf[], + const struct _arg_LPEND *arg) +{ + enum pl330_cond cond = arg->cond; + bool forever = arg->forever; + unsigned loop = arg->loop; + u8 bjump = arg->bjump; + + if (dry_run) + return SZ_DMALPEND; + + buf[0] = CMD_DMALPEND; + + if (loop) + buf[0] |= (1 << 2); + + if (!forever) + buf[0] |= (1 << 4); + + if (cond == SINGLE) + buf[0] |= (0 << 1) | (1 << 0); + else if (cond == BURST) + buf[0] |= (1 << 1) | (1 << 0); + + buf[1] = bjump; + + PL330_DBGCMD_DUMP(SZ_DMALPEND, "\tDMALP%s%c_%c bjmpto_%x\n", + forever ? "FE" : "END", + cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A'), + loop ? '1' : '0', + bjump); + + return SZ_DMALPEND; +} + +static inline u32 _emit_KILL(unsigned dry_run, u8 buf[]) +{ + if (dry_run) + return SZ_DMAKILL; + + buf[0] = CMD_DMAKILL; + + return SZ_DMAKILL; +} + +static inline u32 _emit_MOV(unsigned dry_run, u8 buf[], + enum dmamov_dst dst, u32 val) +{ + if (dry_run) + return SZ_DMAMOV; + + buf[0] = CMD_DMAMOV; + buf[1] = dst; + *((u32 *)&buf[2]) = val; + + PL330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n", + dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"), val); + + return SZ_DMAMOV; +} + +static inline u32 _emit_NOP(unsigned dry_run, u8 buf[]) +{ + if (dry_run) + return SZ_DMANOP; + + buf[0] = CMD_DMANOP; + + PL330_DBGCMD_DUMP(SZ_DMANOP, "\tDMANOP\n"); + + return SZ_DMANOP; +} + +static inline u32 _emit_RMB(unsigned dry_run, u8 buf[]) +{ + if (dry_run) + return SZ_DMARMB; + + buf[0] = CMD_DMARMB; + + PL330_DBGCMD_DUMP(SZ_DMARMB, "\tDMARMB\n"); + + return SZ_DMARMB; +} + +static inline u32 _emit_SEV(unsigned dry_run, u8 buf[], u8 ev) +{ + if (dry_run) + return SZ_DMASEV; + + buf[0] = CMD_DMASEV; + + ev &= 0x1f; + ev <<= 3; + buf[1] = ev; + + PL330_DBGCMD_DUMP(SZ_DMASEV, "\tDMASEV %u\n", ev >> 3); + + return SZ_DMASEV; +} + +static inline u32 _emit_ST(unsigned dry_run, u8 buf[], enum pl330_cond cond) +{ + if (dry_run) + return SZ_DMAST; + + buf[0] = CMD_DMAST; + + if (cond == SINGLE) + buf[0] |= (0 << 1) | (1 << 0); + else if (cond == BURST) + buf[0] |= (1 << 1) | (1 << 0); + + PL330_DBGCMD_DUMP(SZ_DMAST, "\tDMAST%c\n", + cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'A')); + + return SZ_DMAST; +} + +static inline u32 _emit_STP(unsigned dry_run, u8 buf[], + enum pl330_cond cond, u8 peri) +{ + if (dry_run) + return SZ_DMASTP; + + buf[0] = CMD_DMASTP; + + if (cond == BURST) + buf[0] |= (1 << 1); + + peri &= 0x1f; + peri <<= 3; + buf[1] = peri; + + PL330_DBGCMD_DUMP(SZ_DMASTP, "\tDMASTP%c %u\n", + cond == SINGLE ? 'S' : 'B', peri >> 3); + + return SZ_DMASTP; +} + +static inline u32 _emit_STZ(unsigned dry_run, u8 buf[]) +{ + if (dry_run) + return SZ_DMASTZ; + + buf[0] = CMD_DMASTZ; + + PL330_DBGCMD_DUMP(SZ_DMASTZ, "\tDMASTZ\n"); + + return SZ_DMASTZ; +} + +static inline u32 _emit_WFE(unsigned dry_run, u8 buf[], u8 ev, + unsigned invalidate) +{ + if (dry_run) + return SZ_DMAWFE; + + buf[0] = CMD_DMAWFE; + + ev &= 0x1f; + ev <<= 3; + buf[1] = ev; + + if (invalidate) + buf[1] |= (1 << 1); + + PL330_DBGCMD_DUMP(SZ_DMAWFE, "\tDMAWFE %u%s\n", + ev >> 3, invalidate ? ", I" : ""); + + return SZ_DMAWFE; +} + +static inline u32 _emit_WFP(unsigned dry_run, u8 buf[], + enum pl330_cond cond, u8 peri) +{ + if (dry_run) + return SZ_DMAWFP; + + buf[0] = CMD_DMAWFP; + + if (cond == SINGLE) + buf[0] |= (0 << 1) | (0 << 0); + else if (cond == BURST) + buf[0] |= (1 << 1) | (0 << 0); + else + buf[0] |= (0 << 1) | (1 << 0); + + peri &= 0x1f; + peri <<= 3; + buf[1] = peri; + + PL330_DBGCMD_DUMP(SZ_DMAWFP, "\tDMAWFP%c %u\n", + cond == SINGLE ? 'S' : (cond == BURST ? 'B' : 'P'), peri >> 3); + + return SZ_DMAWFP; +} + +static inline u32 _emit_WMB(unsigned dry_run, u8 buf[]) +{ + if (dry_run) + return SZ_DMAWMB; + + buf[0] = CMD_DMAWMB; + + PL330_DBGCMD_DUMP(SZ_DMAWMB, "\tDMAWMB\n"); + + return SZ_DMAWMB; +} + +struct _arg_GO { + u8 chan; + u32 addr; + unsigned ns; +}; + +static inline u32 _emit_GO(unsigned dry_run, u8 buf[], + const struct _arg_GO *arg) +{ + u8 chan = arg->chan; + u32 addr = arg->addr; + unsigned ns = arg->ns; + + if (dry_run) + return SZ_DMAGO; + + buf[0] = CMD_DMAGO; + buf[0] |= (ns << 1); + + buf[1] = chan & 0x7; + + *((u32 *)&buf[2]) = addr; + + return SZ_DMAGO; +} + +#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) + +/* Returns Time-Out */ +static bool _until_dmac_idle(struct pl330_thread *thrd) +{ + void __iomem *regs = thrd->dmac->pinfo->base; + unsigned long loops = msecs_to_loops(5); + + do { + /* Until Manager is Idle */ + if (!(readl(regs + DBGSTATUS) & DBG_BUSY)) + break; + + cpu_relax(); + } while (--loops); + + if (!loops) + return true; + + return false; +} + +static inline void _execute_DBGINSN(struct pl330_thread *thrd, + u8 insn[], bool as_manager) +{ + void __iomem *regs = thrd->dmac->pinfo->base; + u32 val; + + val = (insn[0] << 16) | (insn[1] << 24); + if (!as_manager) { + val |= (1 << 0); + val |= (thrd->id << 8); /* Channel Number */ + } + writel(val, regs + DBGINST0); + + val = *((u32 *)&insn[2]); + writel(val, regs + DBGINST1); + + /* If timed out due to halted state-machine */ + if (_until_dmac_idle(thrd)) { + dev_err(thrd->dmac->pinfo->dev, "DMAC halted!\n"); + return; + } + + /* Get going */ + writel(0, regs + DBGCMD); +} + +/* + * Mark a _pl330_req as free. + * We do it by writing DMAEND as the first instruction + * because no valid request is going to have DMAEND as + * its first instruction to execute. + */ +static void mark_free(struct pl330_thread *thrd, int idx) +{ + struct _pl330_req *req = &thrd->req[idx]; + + _emit_END(0, req->mc_cpu); + req->mc_len = 0; + + thrd->req_running = -1; +} + +static inline u32 _state(struct pl330_thread *thrd) +{ + void __iomem *regs = thrd->dmac->pinfo->base; + u32 val; + + if (is_manager(thrd)) + val = readl(regs + DS) & 0xf; + else + val = readl(regs + CS(thrd->id)) & 0xf; + + switch (val) { + case DS_ST_STOP: + return PL330_STATE_STOPPED; + case DS_ST_EXEC: + return PL330_STATE_EXECUTING; + case DS_ST_CMISS: + return PL330_STATE_CACHEMISS; + case DS_ST_UPDTPC: + return PL330_STATE_UPDTPC; + case DS_ST_WFE: + return PL330_STATE_WFE; + case DS_ST_FAULT: + return PL330_STATE_FAULTING; + case DS_ST_ATBRR: + if (is_manager(thrd)) + return PL330_STATE_INVALID; + else + return PL330_STATE_ATBARRIER; + case DS_ST_QBUSY: + if (is_manager(thrd)) + return PL330_STATE_INVALID; + else + return PL330_STATE_QUEUEBUSY; + case DS_ST_WFP: + if (is_manager(thrd)) + return PL330_STATE_INVALID; + else + return PL330_STATE_WFP; + case DS_ST_KILL: + if (is_manager(thrd)) + return PL330_STATE_INVALID; + else + return PL330_STATE_KILLING; + case DS_ST_CMPLT: + if (is_manager(thrd)) + return PL330_STATE_INVALID; + else + return PL330_STATE_COMPLETING; + case DS_ST_FLTCMP: + if (is_manager(thrd)) + return PL330_STATE_INVALID; + else + return PL330_STATE_FAULT_COMPLETING; + default: + return PL330_STATE_INVALID; + } +} + +static void _stop(struct pl330_thread *thrd) +{ + void __iomem *regs = thrd->dmac->pinfo->base; + u8 insn[6] = {0, 0, 0, 0, 0, 0}; + + if (_state(thrd) == PL330_STATE_FAULT_COMPLETING) + UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING); + + /* Return if nothing needs to be done */ + if (_state(thrd) == PL330_STATE_COMPLETING + || _state(thrd) == PL330_STATE_KILLING + || _state(thrd) == PL330_STATE_STOPPED) + return; + + _emit_KILL(0, insn); + + /* Stop generating interrupts for SEV */ + writel(readl(regs + INTEN) & ~(1 << thrd->ev), regs + INTEN); + + _execute_DBGINSN(thrd, insn, is_manager(thrd)); +} + +/* Start doing req 'idx' of thread 'thrd' */ +static bool _trigger(struct pl330_thread *thrd) +{ + void __iomem *regs = thrd->dmac->pinfo->base; + struct _pl330_req *req; + struct pl330_req *r; + struct _arg_GO go; + unsigned ns; + u8 insn[6] = {0, 0, 0, 0, 0, 0}; + int idx; + + /* Return if already ACTIVE */ + if (_state(thrd) != PL330_STATE_STOPPED) + return true; + + idx = 1 - thrd->lstenq; + if (!IS_FREE(&thrd->req[idx])) + req = &thrd->req[idx]; + else { + idx = thrd->lstenq; + if (!IS_FREE(&thrd->req[idx])) + req = &thrd->req[idx]; + else + req = NULL; + } + + /* Return if no request */ + if (!req || !req->r) + return true; + + r = req->r; + + if (r->cfg) + ns = r->cfg->nonsecure ? 1 : 0; + else if (readl(regs + CS(thrd->id)) & CS_CNS) + ns = 1; + else + ns = 0; + + /* See 'Abort Sources' point-4 at Page 2-25 */ + if (_manager_ns(thrd) && !ns) + dev_info(thrd->dmac->pinfo->dev, "%s:%d Recipe for ABORT!\n", + __func__, __LINE__); + + go.chan = thrd->id; + go.addr = req->mc_bus; + go.ns = ns; + _emit_GO(0, insn, &go); + + /* Set to generate interrupts for SEV */ + writel(readl(regs + INTEN) | (1 << thrd->ev), regs + INTEN); + + /* Only manager can execute GO */ + _execute_DBGINSN(thrd, insn, true); + + thrd->req_running = idx; + + return true; +} + +static bool _start(struct pl330_thread *thrd) +{ + switch (_state(thrd)) { + case PL330_STATE_FAULT_COMPLETING: + UNTIL(thrd, PL330_STATE_FAULTING | PL330_STATE_KILLING); + + if (_state(thrd) == PL330_STATE_KILLING) + UNTIL(thrd, PL330_STATE_STOPPED) + + case PL330_STATE_FAULTING: + _stop(thrd); + + case PL330_STATE_KILLING: + case PL330_STATE_COMPLETING: + UNTIL(thrd, PL330_STATE_STOPPED) + + case PL330_STATE_STOPPED: + return _trigger(thrd); + + case PL330_STATE_WFP: + case PL330_STATE_QUEUEBUSY: + case PL330_STATE_ATBARRIER: + case PL330_STATE_UPDTPC: + case PL330_STATE_CACHEMISS: + case PL330_STATE_EXECUTING: + return true; + + case PL330_STATE_WFE: /* For RESUME, nothing yet */ + default: + return false; + } +} + +static inline int _ldst_memtomem(unsigned dry_run, u8 buf[], + const struct _xfer_spec *pxs, int cyc) +{ + int off = 0; + + while (cyc--) { + off += _emit_LD(dry_run, &buf[off], ALWAYS); + off += _emit_RMB(dry_run, &buf[off]); + off += _emit_ST(dry_run, &buf[off], ALWAYS); + off += _emit_WMB(dry_run, &buf[off]); + } + + return off; +} + +static inline int _ldst_devtomem(unsigned dry_run, u8 buf[], + const struct _xfer_spec *pxs, int cyc) +{ + int off = 0; + + while (cyc--) { + off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri); + off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->r->peri); + off += _emit_ST(dry_run, &buf[off], ALWAYS); + off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri); + } + + return off; +} + +static inline int _ldst_memtodev(unsigned dry_run, u8 buf[], + const struct _xfer_spec *pxs, int cyc) +{ + int off = 0; + + while (cyc--) { + off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->r->peri); + off += _emit_LD(dry_run, &buf[off], ALWAYS); + off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->r->peri); + off += _emit_FLUSHP(dry_run, &buf[off], pxs->r->peri); + } + + return off; +} + +static int _bursts(unsigned dry_run, u8 buf[], + const struct _xfer_spec *pxs, int cyc) +{ + int off = 0; + + switch (pxs->r->rqtype) { + case MEMTODEV: + off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc); + break; + case DEVTOMEM: + off += _ldst_devtomem(dry_run, &buf[off], pxs, cyc); + break; + case MEMTOMEM: + off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc); + break; + default: + off += 0x40000000; /* Scare off the Client */ + break; + } + + return off; +} + +/* Returns bytes consumed and updates bursts */ +static inline int _loop(unsigned dry_run, u8 buf[], + unsigned long *bursts, const struct _xfer_spec *pxs) +{ + int cyc, cycmax, szlp, szlpend, szbrst, off; + unsigned lcnt0, lcnt1, ljmp0, ljmp1; + struct _arg_LPEND lpend; + + /* Max iterations possible in DMALP is 256 */ + if (*bursts >= 256*256) { + lcnt1 = 256; + lcnt0 = 256; + cyc = *bursts / lcnt1 / lcnt0; + } else if (*bursts > 256) { + lcnt1 = 256; + lcnt0 = *bursts / lcnt1; + cyc = 1; + } else { + lcnt1 = *bursts; + lcnt0 = 0; + cyc = 1; + } + + szlp = _emit_LP(1, buf, 0, 0); + szbrst = _bursts(1, buf, pxs, 1); + + lpend.cond = ALWAYS; + lpend.forever = false; + lpend.loop = 0; + lpend.bjump = 0; + szlpend = _emit_LPEND(1, buf, &lpend); + + if (lcnt0) { + szlp *= 2; + szlpend *= 2; + } + + /* + * Max bursts that we can unroll due to limit on the + * size of backward jump that can be encoded in DMALPEND + * which is 8-bits and hence 255 + */ + cycmax = (255 - (szlp + szlpend)) / szbrst; + + cyc = (cycmax < cyc) ? cycmax : cyc; + + off = 0; + + if (lcnt0) { + off += _emit_LP(dry_run, &buf[off], 0, lcnt0); + ljmp0 = off; + } + + off += _emit_LP(dry_run, &buf[off], 1, lcnt1); + ljmp1 = off; + + off += _bursts(dry_run, &buf[off], pxs, cyc); + + lpend.cond = ALWAYS; + lpend.forever = false; + lpend.loop = 1; + lpend.bjump = off - ljmp1; + off += _emit_LPEND(dry_run, &buf[off], &lpend); + + if (lcnt0) { + lpend.cond = ALWAYS; + lpend.forever = false; + lpend.loop = 0; + lpend.bjump = off - ljmp0; + off += _emit_LPEND(dry_run, &buf[off], &lpend); + } + + *bursts = lcnt1 * cyc; + if (lcnt0) + *bursts *= lcnt0; + + return off; +} + +static inline int _setup_loops(unsigned dry_run, u8 buf[], + const struct _xfer_spec *pxs) +{ + struct pl330_xfer *x = pxs->x; + u32 ccr = pxs->ccr; + unsigned long c, bursts = BYTE_TO_BURST(x->bytes, ccr); + int off = 0; + + while (bursts) { + c = bursts; + off += _loop(dry_run, &buf[off], &c, pxs); + bursts -= c; + } + + return off; +} + +static inline int _setup_xfer(unsigned dry_run, u8 buf[], + const struct _xfer_spec *pxs) +{ + struct pl330_xfer *x = pxs->x; + int off = 0; + + /* DMAMOV SAR, x->src_addr */ + off += _emit_MOV(dry_run, &buf[off], SAR, x->src_addr); + /* DMAMOV DAR, x->dst_addr */ + off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr); + + /* Setup Loop(s) */ + off += _setup_loops(dry_run, &buf[off], pxs); + + return off; +} + +/* + * A req is a sequence of one or more xfer units. + * Returns the number of bytes taken to setup the MC for the req. + */ +static int _setup_req(unsigned dry_run, struct pl330_thread *thrd, + unsigned index, struct _xfer_spec *pxs) +{ + struct _pl330_req *req = &thrd->req[index]; + struct pl330_xfer *x; + u8 *buf = req->mc_cpu; + int off = 0; + + PL330_DBGMC_START(req->mc_bus); + + /* DMAMOV CCR, ccr */ + off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); + + x = pxs->r->x; + do { + /* Error if xfer length is not aligned at burst size */ + if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr))) + return -EINVAL; + + pxs->x = x; + off += _setup_xfer(dry_run, &buf[off], pxs); + + x = x->next; + } while (x); + + /* DMASEV peripheral/event */ + off += _emit_SEV(dry_run, &buf[off], thrd->ev); + /* DMAEND */ + off += _emit_END(dry_run, &buf[off]); + + return off; +} + +static inline u32 _prepare_ccr(const struct pl330_reqcfg *rqc) +{ + u32 ccr = 0; + + if (rqc->src_inc) + ccr |= CC_SRCINC; + + if (rqc->dst_inc) + ccr |= CC_DSTINC; + + /* We set same protection levels for Src and DST for now */ + if (rqc->privileged) + ccr |= CC_SRCPRI | CC_DSTPRI; + if (rqc->nonsecure) + ccr |= CC_SRCNS | CC_DSTNS; + if (rqc->insnaccess) + ccr |= CC_SRCIA | CC_DSTIA; + + ccr |= (((rqc->brst_len - 1) & 0xf) << CC_SRCBRSTLEN_SHFT); + ccr |= (((rqc->brst_len - 1) & 0xf) << CC_DSTBRSTLEN_SHFT); + + ccr |= (rqc->brst_size << CC_SRCBRSTSIZE_SHFT); + ccr |= (rqc->brst_size << CC_DSTBRSTSIZE_SHFT); + + ccr |= (rqc->scctl << CC_SRCCCTRL_SHFT); + ccr |= (rqc->dcctl << CC_DSTCCTRL_SHFT); + + ccr |= (rqc->swap << CC_SWAP_SHFT); + + return ccr; +} + +static inline bool _is_valid(u32 ccr) +{ + enum pl330_dstcachectrl dcctl; + enum pl330_srccachectrl scctl; + + dcctl = (ccr >> CC_DSTCCTRL_SHFT) & CC_DRCCCTRL_MASK; + scctl = (ccr >> CC_SRCCCTRL_SHFT) & CC_SRCCCTRL_MASK; + + if (dcctl == DINVALID1 || dcctl == DINVALID2 + || scctl == SINVALID1 || scctl == SINVALID2) + return false; + else + return true; +} + +/* + * Submit a list of xfers after which the client wants notification. + * Client is not notified after each xfer unit, just once after all + * xfer units are done or some error occurs. + */ +int pl330_submit_req(void *ch_id, struct pl330_req *r) +{ + struct pl330_thread *thrd = ch_id; + struct pl330_dmac *pl330; + struct pl330_info *pi; + struct _xfer_spec xs; + unsigned long flags; + void __iomem *regs; + unsigned idx; + u32 ccr; + int ret = 0; + + /* No Req or Unacquired Channel or DMAC */ + if (!r || !thrd || thrd->free) + return -EINVAL; + + pl330 = thrd->dmac; + pi = pl330->pinfo; + regs = pi->base; + + if (pl330->state == DYING + || pl330->dmac_tbd.reset_chan & (1 << thrd->id)) { + dev_info(thrd->dmac->pinfo->dev, "%s:%d\n", + __func__, __LINE__); + return -EAGAIN; + } + + /* If request for non-existing peripheral */ + if (r->rqtype != MEMTOMEM && r->peri >= pi->pcfg.num_peri) { + dev_info(thrd->dmac->pinfo->dev, + "%s:%d Invalid peripheral(%u)!\n", + __func__, __LINE__, r->peri); + return -EINVAL; + } + + spin_lock_irqsave(&pl330->lock, flags); + + if (_queue_full(thrd)) { + ret = -EAGAIN; + goto xfer_exit; + } + + /* Prefer Secure Channel */ + if (!_manager_ns(thrd)) + r->cfg->nonsecure = 0; + else + r->cfg->nonsecure = 1; + + /* Use last settings, if not provided */ + if (r->cfg) + ccr = _prepare_ccr(r->cfg); + else + ccr = readl(regs + CC(thrd->id)); + + /* If this req doesn't have valid xfer settings */ + if (!_is_valid(ccr)) { + ret = -EINVAL; + dev_info(thrd->dmac->pinfo->dev, "%s:%d Invalid CCR(%x)!\n", + __func__, __LINE__, ccr); + goto xfer_exit; + } + + idx = IS_FREE(&thrd->req[0]) ? 0 : 1; + + xs.ccr = ccr; + xs.r = r; + + /* First dry run to check if req is acceptable */ + ret = _setup_req(1, thrd, idx, &xs); + if (ret < 0) + goto xfer_exit; + + if (ret > pi->mcbufsz / 2) { + dev_info(thrd->dmac->pinfo->dev, + "%s:%d Trying increasing mcbufsz\n", + __func__, __LINE__); + ret = -ENOMEM; + goto xfer_exit; + } + + /* Hook the request */ + thrd->lstenq = idx; + thrd->req[idx].mc_len = _setup_req(0, thrd, idx, &xs); + thrd->req[idx].r = r; + + ret = 0; + +xfer_exit: + spin_unlock_irqrestore(&pl330->lock, flags); + + return ret; +} +EXPORT_SYMBOL(pl330_submit_req); + +static void pl330_dotask(unsigned long data) +{ + struct pl330_dmac *pl330 = (struct pl330_dmac *) data; + struct pl330_info *pi = pl330->pinfo; + unsigned long flags; + int i; + + spin_lock_irqsave(&pl330->lock, flags); + + /* The DMAC itself gone nuts */ + if (pl330->dmac_tbd.reset_dmac) { + pl330->state = DYING; + /* Reset the manager too */ + pl330->dmac_tbd.reset_mngr = true; + /* Clear the reset flag */ + pl330->dmac_tbd.reset_dmac = false; + } + + if (pl330->dmac_tbd.reset_mngr) { + _stop(pl330->manager); + /* Reset all channels */ + pl330->dmac_tbd.reset_chan = (1 << pi->pcfg.num_chan) - 1; + /* Clear the reset flag */ + pl330->dmac_tbd.reset_mngr = false; + } + + for (i = 0; i < pi->pcfg.num_chan; i++) { + + if (pl330->dmac_tbd.reset_chan & (1 << i)) { + struct pl330_thread *thrd = &pl330->channels[i]; + void __iomem *regs = pi->base; + enum pl330_op_err err; + + _stop(thrd); + + if (readl(regs + FSC) & (1 << thrd->id)) + err = PL330_ERR_FAIL; + else + err = PL330_ERR_ABORT; + + spin_unlock_irqrestore(&pl330->lock, flags); + + _callback(thrd->req[1 - thrd->lstenq].r, err); + _callback(thrd->req[thrd->lstenq].r, err); + + spin_lock_irqsave(&pl330->lock, flags); + + thrd->req[0].r = NULL; + thrd->req[1].r = NULL; + mark_free(thrd, 0); + mark_free(thrd, 1); + + /* Clear the reset flag */ + pl330->dmac_tbd.reset_chan &= ~(1 << i); + } + } + + spin_unlock_irqrestore(&pl330->lock, flags); + + return; +} + +/* Returns 1 if state was updated, 0 otherwise */ +int pl330_update(const struct pl330_info *pi) +{ + struct _pl330_req *rqdone; + struct pl330_dmac *pl330; + unsigned long flags; + void __iomem *regs; + u32 val; + int id, ev, ret = 0; + + if (!pi || !pi->pl330_data) + return 0; + + regs = pi->base; + pl330 = pi->pl330_data; + + spin_lock_irqsave(&pl330->lock, flags); + + val = readl(regs + FSM) & 0x1; + if (val) + pl330->dmac_tbd.reset_mngr = true; + else + pl330->dmac_tbd.reset_mngr = false; + + val = readl(regs + FSC) & ((1 << pi->pcfg.num_chan) - 1); + pl330->dmac_tbd.reset_chan |= val; + if (val) { + int i = 0; + while (i < pi->pcfg.num_chan) { + if (val & (1 << i)) { + dev_info(pi->dev, + "Reset Channel-%d\t CS-%x FTC-%x\n", + i, readl(regs + CS(i)), + readl(regs + FTC(i))); + _stop(&pl330->channels[i]); + } + i++; + } + } + + /* Check which event happened i.e, thread notified */ + val = readl(regs + ES); + if (pi->pcfg.num_events < 32 + && val & ~((1 << pi->pcfg.num_events) - 1)) { + pl330->dmac_tbd.reset_dmac = true; + dev_err(pi->dev, "%s:%d Unexpected!\n", __func__, __LINE__); + ret = 1; + goto updt_exit; + } + + for (ev = 0; ev < pi->pcfg.num_events; ev++) { + if (val & (1 << ev)) { /* Event occurred */ + struct pl330_thread *thrd; + u32 inten = readl(regs + INTEN); + int active; + + /* Clear the event */ + if (inten & (1 << ev)) + writel(1 << ev, regs + INTCLR); + + ret = 1; + + id = pl330->events[ev]; + + thrd = &pl330->channels[id]; + + active = thrd->req_running; + if (active == -1) /* Aborted */ + continue; + + rqdone = &thrd->req[active]; + mark_free(thrd, active); + + /* Get going again ASAP */ + _start(thrd); + + /* For now, just make a list of callbacks to be done */ + list_add_tail(&rqdone->rqd, &pl330->req_done); + } + } + + /* Now that we are in no hurry, do the callbacks */ + while (!list_empty(&pl330->req_done)) { + struct pl330_req *r; + + rqdone = container_of(pl330->req_done.next, + struct _pl330_req, rqd); + + list_del_init(&rqdone->rqd); + + /* Detach the req */ + r = rqdone->r; + rqdone->r = NULL; + + spin_unlock_irqrestore(&pl330->lock, flags); + _callback(r, PL330_ERR_NONE); + spin_lock_irqsave(&pl330->lock, flags); + } + +updt_exit: + spin_unlock_irqrestore(&pl330->lock, flags); + + if (pl330->dmac_tbd.reset_dmac + || pl330->dmac_tbd.reset_mngr + || pl330->dmac_tbd.reset_chan) { + ret = 1; + tasklet_schedule(&pl330->tasks); + } + + return ret; +} +EXPORT_SYMBOL(pl330_update); + +int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op) +{ + struct pl330_thread *thrd = ch_id; + struct pl330_dmac *pl330; + unsigned long flags; + int ret = 0, active; + + if (!thrd || thrd->free || thrd->dmac->state == DYING) + return -EINVAL; + + pl330 = thrd->dmac; + active = thrd->req_running; + + spin_lock_irqsave(&pl330->lock, flags); + + switch (op) { + case PL330_OP_FLUSH: + /* Make sure the channel is stopped */ + _stop(thrd); + + thrd->req[0].r = NULL; + thrd->req[1].r = NULL; + mark_free(thrd, 0); + mark_free(thrd, 1); + break; + + case PL330_OP_ABORT: + /* Make sure the channel is stopped */ + _stop(thrd); + + /* ABORT is only for the active req */ + if (active == -1) + break; + + thrd->req[active].r = NULL; + mark_free(thrd, active); + + /* Start the next */ + case PL330_OP_START: + if ((active == -1) && !_start(thrd)) + ret = -EIO; + break; + + default: + ret = -EINVAL; + } + + spin_unlock_irqrestore(&pl330->lock, flags); + return ret; +} +EXPORT_SYMBOL(pl330_chan_ctrl); + +int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus) +{ + struct pl330_thread *thrd = ch_id; + struct pl330_dmac *pl330; + struct pl330_info *pi; + void __iomem *regs; + int active; + u32 val; + + if (!pstatus || !thrd || thrd->free) + return -EINVAL; + + pl330 = thrd->dmac; + pi = pl330->pinfo; + regs = pi->base; + + /* The client should remove the DMAC and add again */ + if (pl330->state == DYING) + pstatus->dmac_halted = true; + else + pstatus->dmac_halted = false; + + val = readl(regs + FSC); + if (val & (1 << thrd->id)) + pstatus->faulting = true; + else + pstatus->faulting = false; + + active = thrd->req_running; + + if (active == -1) { + /* Indicate that the thread is not running */ + pstatus->top_req = NULL; + pstatus->wait_req = NULL; + } else { + pstatus->top_req = thrd->req[active].r; + pstatus->wait_req = !IS_FREE(&thrd->req[1 - active]) + ? thrd->req[1 - active].r : NULL; + } + + pstatus->src_addr = readl(regs + SA(thrd->id)); + pstatus->dst_addr = readl(regs + DA(thrd->id)); + + return 0; +} +EXPORT_SYMBOL(pl330_chan_status); + +/* Reserve an event */ +static inline int _alloc_event(struct pl330_thread *thrd) +{ + struct pl330_dmac *pl330 = thrd->dmac; + struct pl330_info *pi = pl330->pinfo; + int ev; + + for (ev = 0; ev < pi->pcfg.num_events; ev++) + if (pl330->events[ev] == -1) { + pl330->events[ev] = thrd->id; + return ev; + } + + return -1; +} + +static bool _chan_ns(const struct pl330_info *pi, int i) +{ + return pi->pcfg.irq_ns & (1 << i); +} + +/* Upon success, returns IdentityToken for the + * allocated channel, NULL otherwise. + */ +void *pl330_request_channel(const struct pl330_info *pi) +{ + struct pl330_thread *thrd = NULL; + struct pl330_dmac *pl330; + unsigned long flags; + int chans, i; + + if (!pi || !pi->pl330_data) + return NULL; + + pl330 = pi->pl330_data; + + if (pl330->state == DYING) + return NULL; + + chans = pi->pcfg.num_chan; + + spin_lock_irqsave(&pl330->lock, flags); + + for (i = 0; i < chans; i++) { + thrd = &pl330->channels[i]; + if ((thrd->free) && (!_manager_ns(thrd) || + _chan_ns(pi, i))) { + thrd->ev = _alloc_event(thrd); + if (thrd->ev >= 0) { + thrd->free = false; + thrd->lstenq = 1; + thrd->req[0].r = NULL; + mark_free(thrd, 0); + thrd->req[1].r = NULL; + mark_free(thrd, 1); + break; + } + } + thrd = NULL; + } + + spin_unlock_irqrestore(&pl330->lock, flags); + + return thrd; +} +EXPORT_SYMBOL(pl330_request_channel); + +/* Release an event */ +static inline void _free_event(struct pl330_thread *thrd, int ev) +{ + struct pl330_dmac *pl330 = thrd->dmac; + struct pl330_info *pi = pl330->pinfo; + + /* If the event is valid and was held by the thread */ + if (ev >= 0 && ev < pi->pcfg.num_events + && pl330->events[ev] == thrd->id) + pl330->events[ev] = -1; +} + +void pl330_release_channel(void *ch_id) +{ + struct pl330_thread *thrd = ch_id; + struct pl330_dmac *pl330; + unsigned long flags; + + if (!thrd || thrd->free) + return; + + _stop(thrd); + + _callback(thrd->req[1 - thrd->lstenq].r, PL330_ERR_ABORT); + _callback(thrd->req[thrd->lstenq].r, PL330_ERR_ABORT); + + pl330 = thrd->dmac; + + spin_lock_irqsave(&pl330->lock, flags); + _free_event(thrd, thrd->ev); + thrd->free = true; + spin_unlock_irqrestore(&pl330->lock, flags); +} +EXPORT_SYMBOL(pl330_release_channel); + +/* Initialize the structure for PL330 configuration, that can be used + * by the client driver the make best use of the DMAC + */ +static void read_dmac_config(struct pl330_info *pi) +{ + void __iomem *regs = pi->base; + u32 val; + + val = readl(regs + CRD) >> CRD_DATA_WIDTH_SHIFT; + val &= CRD_DATA_WIDTH_MASK; + pi->pcfg.data_bus_width = 8 * (1 << val); + + val = readl(regs + CRD) >> CRD_DATA_BUFF_SHIFT; + val &= CRD_DATA_BUFF_MASK; + pi->pcfg.data_buf_dep = val + 1; + + val = readl(regs + CR0) >> CR0_NUM_CHANS_SHIFT; + val &= CR0_NUM_CHANS_MASK; + val += 1; + pi->pcfg.num_chan = val; + + val = readl(regs + CR0); + if (val & CR0_PERIPH_REQ_SET) { + val = (val >> CR0_NUM_PERIPH_SHIFT) & CR0_NUM_PERIPH_MASK; + val += 1; + pi->pcfg.num_peri = val; + pi->pcfg.peri_ns = readl(regs + CR4); + } else { + pi->pcfg.num_peri = 0; + } + + val = readl(regs + CR0); + if (val & CR0_BOOT_MAN_NS) + pi->pcfg.mode |= DMAC_MODE_NS; + else + pi->pcfg.mode &= ~DMAC_MODE_NS; + + val = readl(regs + CR0) >> CR0_NUM_EVENTS_SHIFT; + val &= CR0_NUM_EVENTS_MASK; + val += 1; + pi->pcfg.num_events = val; + + pi->pcfg.irq_ns = readl(regs + CR3); + + pi->pcfg.periph_id = get_id(pi, PERIPH_ID); + pi->pcfg.pcell_id = get_id(pi, PCELL_ID); +} + +static inline void _reset_thread(struct pl330_thread *thrd) +{ + struct pl330_dmac *pl330 = thrd->dmac; + struct pl330_info *pi = pl330->pinfo; + + thrd->req[0].mc_cpu = pl330->mcode_cpu + + (thrd->id * pi->mcbufsz); + thrd->req[0].mc_bus = pl330->mcode_bus + + (thrd->id * pi->mcbufsz); + thrd->req[0].r = NULL; + mark_free(thrd, 0); + + thrd->req[1].mc_cpu = thrd->req[0].mc_cpu + + pi->mcbufsz / 2; + thrd->req[1].mc_bus = thrd->req[0].mc_bus + + pi->mcbufsz / 2; + thrd->req[1].r = NULL; + mark_free(thrd, 1); +} + +static int dmac_alloc_threads(struct pl330_dmac *pl330) +{ + struct pl330_info *pi = pl330->pinfo; + int chans = pi->pcfg.num_chan; + struct pl330_thread *thrd; + int i; + + /* Allocate 1 Manager and 'chans' Channel threads */ + pl330->channels = kzalloc((1 + chans) * sizeof(*thrd), + GFP_KERNEL); + if (!pl330->channels) + return -ENOMEM; + + /* Init Channel threads */ + for (i = 0; i < chans; i++) { + thrd = &pl330->channels[i]; + thrd->id = i; + thrd->dmac = pl330; + _reset_thread(thrd); + thrd->free = true; + } + + /* MANAGER is indexed at the end */ + thrd = &pl330->channels[chans]; + thrd->id = chans; + thrd->dmac = pl330; + thrd->free = false; + pl330->manager = thrd; + + return 0; +} + +static int dmac_alloc_resources(struct pl330_dmac *pl330) +{ + struct pl330_info *pi = pl330->pinfo; + int chans = pi->pcfg.num_chan; + int ret; + + /* + * Alloc MicroCode buffer for 'chans' Channel threads. + * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN) + */ + pl330->mcode_cpu = dma_alloc_coherent(pi->dev, + chans * pi->mcbufsz, + &pl330->mcode_bus, GFP_KERNEL); + if (!pl330->mcode_cpu) { + dev_err(pi->dev, "%s:%d Can't allocate memory!\n", + __func__, __LINE__); + return -ENOMEM; + } + + ret = dmac_alloc_threads(pl330); + if (ret) { + dev_err(pi->dev, "%s:%d Can't to create channels for DMAC!\n", + __func__, __LINE__); + dma_free_coherent(pi->dev, + chans * pi->mcbufsz, + pl330->mcode_cpu, pl330->mcode_bus); + return ret; + } + + return 0; +} + +int pl330_add(struct pl330_info *pi) +{ + struct pl330_dmac *pl330; + void __iomem *regs; + int i, ret; + + if (!pi || !pi->dev) + return -EINVAL; + + /* If already added */ + if (pi->pl330_data) + return -EINVAL; + + /* + * If the SoC can perform reset on the DMAC, then do it + * before reading its configuration. + */ + if (pi->dmac_reset) + pi->dmac_reset(pi); + + regs = pi->base; + + /* Check if we can handle this DMAC */ + if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL + || get_id(pi, PCELL_ID) != PCELL_ID_VAL) { + dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n", + get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID)); + return -EINVAL; + } + + /* Read the configuration of the DMAC */ + read_dmac_config(pi); + + if (pi->pcfg.num_events == 0) { + dev_err(pi->dev, "%s:%d Can't work without events!\n", + __func__, __LINE__); + return -EINVAL; + } + + pl330 = kzalloc(sizeof(*pl330), GFP_KERNEL); + if (!pl330) { + dev_err(pi->dev, "%s:%d Can't allocate memory!\n", + __func__, __LINE__); + return -ENOMEM; + } + + /* Assign the info structure and private data */ + pl330->pinfo = pi; + pi->pl330_data = pl330; + + spin_lock_init(&pl330->lock); + + INIT_LIST_HEAD(&pl330->req_done); + + /* Use default MC buffer size if not provided */ + if (!pi->mcbufsz) + pi->mcbufsz = MCODE_BUFF_PER_REQ * 2; + + /* Mark all events as free */ + for (i = 0; i < pi->pcfg.num_events; i++) + pl330->events[i] = -1; + + /* Allocate resources needed by the DMAC */ + ret = dmac_alloc_resources(pl330); + if (ret) { + dev_err(pi->dev, "Unable to create channels for DMAC\n"); + kfree(pl330); + return ret; + } + + tasklet_init(&pl330->tasks, pl330_dotask, (unsigned long) pl330); + + pl330->state = INIT; + + return 0; +} +EXPORT_SYMBOL(pl330_add); + +static int dmac_free_threads(struct pl330_dmac *pl330) +{ + struct pl330_info *pi = pl330->pinfo; + int chans = pi->pcfg.num_chan; + struct pl330_thread *thrd; + int i; + + /* Release Channel threads */ + for (i = 0; i < chans; i++) { + thrd = &pl330->channels[i]; + pl330_release_channel((void *)thrd); + } + + /* Free memory */ + kfree(pl330->channels); + + return 0; +} + +static void dmac_free_resources(struct pl330_dmac *pl330) +{ + struct pl330_info *pi = pl330->pinfo; + int chans = pi->pcfg.num_chan; + + dmac_free_threads(pl330); + + dma_free_coherent(pi->dev, chans * pi->mcbufsz, + pl330->mcode_cpu, pl330->mcode_bus); +} + +void pl330_del(struct pl330_info *pi) +{ + struct pl330_dmac *pl330; + + if (!pi || !pi->pl330_data) + return; + + pl330 = pi->pl330_data; + + pl330->state = UNINIT; + + tasklet_kill(&pl330->tasks); + + /* Free DMAC resources */ + dmac_free_resources(pl330); + + kfree(pl330); + pi->pl330_data = NULL; +} +EXPORT_SYMBOL(pl330_del); diff --git a/trunk/arch/arm/configs/integrator_defconfig b/trunk/arch/arm/configs/integrator_defconfig index a8314c3ee84d..1103f62a1964 100644 --- a/trunk/arch/arm/configs/integrator_defconfig +++ b/trunk/arch/arm/configs/integrator_defconfig @@ -57,24 +57,18 @@ CONFIG_NETDEVICES=y CONFIG_NET_ETHERNET=y CONFIG_NET_PCI=y CONFIG_E100=y -CONFIG_SMC91X=y # CONFIG_KEYBOARD_ATKBD is not set # CONFIG_SERIO_SERPORT is not set CONFIG_SERIAL_AMBA_PL010=y CONFIG_SERIAL_AMBA_PL010_CONSOLE=y CONFIG_FB=y CONFIG_FB_MODE_HELPERS=y -CONFIG_FB_ARMCLCD=y CONFIG_FB_MATROX=y CONFIG_FB_MATROX_MILLENIUM=y CONFIG_FB_MATROX_MYSTIQUE=y -# CONFIG_VGA_CONSOLE is not set -CONFIG_MMC=y -CONFIG_MMC_ARMMMCI=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_PL030=y CONFIG_EXT2_FS=y -CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y @@ -84,7 +78,5 @@ CONFIG_ROOT_NFS=y CONFIG_NFSD=y CONFIG_NFSD_V3=y CONFIG_PARTITION_ADVANCED=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_ISO8859_1=y CONFIG_MAGIC_SYSRQ=y CONFIG_DEBUG_KERNEL=y diff --git a/trunk/arch/arm/include/asm/assembler.h b/trunk/arch/arm/include/asm/assembler.h index 03fb93621d0d..23371b17b23e 100644 --- a/trunk/arch/arm/include/asm/assembler.h +++ b/trunk/arch/arm/include/asm/assembler.h @@ -23,8 +23,6 @@ #include #include -#define IOMEM(x) (x) - /* * Endian independent macros for shifting bytes within registers. */ diff --git a/trunk/arch/arm/include/asm/elf.h b/trunk/arch/arm/include/asm/elf.h index 38050b1c4800..0e9ce8d9686e 100644 --- a/trunk/arch/arm/include/asm/elf.h +++ b/trunk/arch/arm/include/asm/elf.h @@ -130,4 +130,8 @@ struct mm_struct; extern unsigned long arch_randomize_brk(struct mm_struct *mm); #define arch_randomize_brk arch_randomize_brk +extern int vectors_user_mapping(void); +#define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping() +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES + #endif diff --git a/trunk/arch/arm/include/asm/hardware/cache-l2x0.h b/trunk/arch/arm/include/asm/hardware/cache-l2x0.h index c4c87bc12231..7df239bcdf27 100644 --- a/trunk/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/trunk/arch/arm/include/asm/hardware/cache-l2x0.h @@ -103,11 +103,11 @@ #define L2X0_ADDR_FILTER_EN 1 #ifndef __ASSEMBLY__ -extern void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask); +extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask); #if defined(CONFIG_CACHE_L2X0) && defined(CONFIG_OF) -extern int l2x0_of_init(u32 aux_val, u32 aux_mask); +extern int l2x0_of_init(__u32 aux_val, __u32 aux_mask); #else -static inline int l2x0_of_init(u32 aux_val, u32 aux_mask) +static inline int l2x0_of_init(__u32 aux_val, __u32 aux_mask) { return -ENODEV; } diff --git a/trunk/arch/arm/include/asm/hardware/iop_adma.h b/trunk/arch/arm/include/asm/hardware/iop_adma.h index 122f86d8c991..59b8c3892f76 100644 --- a/trunk/arch/arm/include/asm/hardware/iop_adma.h +++ b/trunk/arch/arm/include/asm/hardware/iop_adma.h @@ -49,6 +49,7 @@ struct iop_adma_device { /** * struct iop_adma_chan - internal representation of an ADMA device * @pending: allows batching of hardware operations + * @completed_cookie: identifier for the most recently completed operation * @lock: serializes enqueue/dequeue operations to the slot pool * @mmr_base: memory mapped register base * @chain: device chain view of the descriptors @@ -61,6 +62,7 @@ struct iop_adma_device { */ struct iop_adma_chan { int pending; + dma_cookie_t completed_cookie; spinlock_t lock; /* protects the descriptor slot pool */ void __iomem *mmr_base; struct list_head chain; diff --git a/trunk/arch/arm/include/asm/hardware/it8152.h b/trunk/arch/arm/include/asm/hardware/it8152.h index 73f84fa4f366..43cab498bc27 100644 --- a/trunk/arch/arm/include/asm/hardware/it8152.h +++ b/trunk/arch/arm/include/asm/hardware/it8152.h @@ -9,9 +9,6 @@ #ifndef __ASM_HARDWARE_IT8152_H #define __ASM_HARDWARE_IT8152_H - -#include - extern void __iomem *it8152_base_address; #define IT8152_IO_BASE (it8152_base_address + 0x03e00000) diff --git a/trunk/arch/arm/include/asm/hardware/pl330.h b/trunk/arch/arm/include/asm/hardware/pl330.h new file mode 100644 index 000000000000..c1821385abfa --- /dev/null +++ b/trunk/arch/arm/include/asm/hardware/pl330.h @@ -0,0 +1,217 @@ +/* linux/include/asm/hardware/pl330.h + * + * Copyright (C) 2010 Samsung Electronics Co. Ltd. + * Jaswinder Singh + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __PL330_CORE_H +#define __PL330_CORE_H + +#define PL330_MAX_CHAN 8 +#define PL330_MAX_IRQS 32 +#define PL330_MAX_PERI 32 + +enum pl330_srccachectrl { + SCCTRL0 = 0, /* Noncacheable and nonbufferable */ + SCCTRL1, /* Bufferable only */ + SCCTRL2, /* Cacheable, but do not allocate */ + SCCTRL3, /* Cacheable and bufferable, but do not allocate */ + SINVALID1, + SINVALID2, + SCCTRL6, /* Cacheable write-through, allocate on reads only */ + SCCTRL7, /* Cacheable write-back, allocate on reads only */ +}; + +enum pl330_dstcachectrl { + DCCTRL0 = 0, /* Noncacheable and nonbufferable */ + DCCTRL1, /* Bufferable only */ + DCCTRL2, /* Cacheable, but do not allocate */ + DCCTRL3, /* Cacheable and bufferable, but do not allocate */ + DINVALID1, /* AWCACHE = 0x1000 */ + DINVALID2, + DCCTRL6, /* Cacheable write-through, allocate on writes only */ + DCCTRL7, /* Cacheable write-back, allocate on writes only */ +}; + +/* Populated by the PL330 core driver for DMA API driver's info */ +struct pl330_config { + u32 periph_id; + u32 pcell_id; +#define DMAC_MODE_NS (1 << 0) + unsigned int mode; + unsigned int data_bus_width:10; /* In number of bits */ + unsigned int data_buf_dep:10; + unsigned int num_chan:4; + unsigned int num_peri:6; + u32 peri_ns; + unsigned int num_events:6; + u32 irq_ns; +}; + +/* Handle to the DMAC provided to the PL330 core */ +struct pl330_info { + /* Owning device */ + struct device *dev; + /* Size of MicroCode buffers for each channel. */ + unsigned mcbufsz; + /* ioremap'ed address of PL330 registers. */ + void __iomem *base; + /* Client can freely use it. */ + void *client_data; + /* PL330 core data, Client must not touch it. */ + void *pl330_data; + /* Populated by the PL330 core driver during pl330_add */ + struct pl330_config pcfg; + /* + * If the DMAC has some reset mechanism, then the + * client may want to provide pointer to the method. + */ + void (*dmac_reset)(struct pl330_info *pi); +}; + +enum pl330_byteswap { + SWAP_NO = 0, + SWAP_2, + SWAP_4, + SWAP_8, + SWAP_16, +}; + +/** + * Request Configuration. + * The PL330 core does not modify this and uses the last + * working configuration if the request doesn't provide any. + * + * The Client may want to provide this info only for the + * first request and a request with new settings. + */ +struct pl330_reqcfg { + /* Address Incrementing */ + unsigned dst_inc:1; + unsigned src_inc:1; + + /* + * For now, the SRC & DST protection levels + * and burst size/length are assumed same. + */ + bool nonsecure; + bool privileged; + bool insnaccess; + unsigned brst_len:5; + unsigned brst_size:3; /* in power of 2 */ + + enum pl330_dstcachectrl dcctl; + enum pl330_srccachectrl scctl; + enum pl330_byteswap swap; +}; + +/* + * One cycle of DMAC operation. + * There may be more than one xfer in a request. + */ +struct pl330_xfer { + u32 src_addr; + u32 dst_addr; + /* Size to xfer */ + u32 bytes; + /* + * Pointer to next xfer in the list. + * The last xfer in the req must point to NULL. + */ + struct pl330_xfer *next; +}; + +/* The xfer callbacks are made with one of these arguments. */ +enum pl330_op_err { + /* The all xfers in the request were success. */ + PL330_ERR_NONE, + /* If req aborted due to global error. */ + PL330_ERR_ABORT, + /* If req failed due to problem with Channel. */ + PL330_ERR_FAIL, +}; + +enum pl330_reqtype { + MEMTOMEM, + MEMTODEV, + DEVTOMEM, + DEVTODEV, +}; + +/* A request defining Scatter-Gather List ending with NULL xfer. */ +struct pl330_req { + enum pl330_reqtype rqtype; + /* Index of peripheral for the xfer. */ + unsigned peri:5; + /* Unique token for this xfer, set by the client. */ + void *token; + /* Callback to be called after xfer. */ + void (*xfer_cb)(void *token, enum pl330_op_err err); + /* If NULL, req will be done at last set parameters. */ + struct pl330_reqcfg *cfg; + /* Pointer to first xfer in the request. */ + struct pl330_xfer *x; +}; + +/* + * To know the status of the channel and DMAC, the client + * provides a pointer to this structure. The PL330 core + * fills it with current information. + */ +struct pl330_chanstatus { + /* + * If the DMAC engine halted due to some error, + * the client should remove-add DMAC. + */ + bool dmac_halted; + /* + * If channel is halted due to some error, + * the client should ABORT/FLUSH and START the channel. + */ + bool faulting; + /* Location of last load */ + u32 src_addr; + /* Location of last store */ + u32 dst_addr; + /* + * Pointer to the currently active req, NULL if channel is + * inactive, even though the requests may be present. + */ + struct pl330_req *top_req; + /* Pointer to req waiting second in the queue if any. */ + struct pl330_req *wait_req; +}; + +enum pl330_chan_op { + /* Start the channel */ + PL330_OP_START, + /* Abort the active xfer */ + PL330_OP_ABORT, + /* Stop xfer and flush queue */ + PL330_OP_FLUSH, +}; + +extern int pl330_add(struct pl330_info *); +extern void pl330_del(struct pl330_info *pi); +extern int pl330_update(const struct pl330_info *pi); +extern void pl330_release_channel(void *ch_id); +extern void *pl330_request_channel(const struct pl330_info *pi); +extern int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus); +extern int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op); +extern int pl330_submit_req(void *ch_id, struct pl330_req *r); + +#endif /* __PL330_CORE_H */ diff --git a/trunk/arch/arm/include/asm/io.h b/trunk/arch/arm/include/asm/io.h index df0ac0bb39aa..bae7eb6011d2 100644 --- a/trunk/arch/arm/include/asm/io.h +++ b/trunk/arch/arm/include/asm/io.h @@ -82,11 +82,6 @@ extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, uns extern void __iomem *__arm_ioremap(unsigned long, size_t, unsigned int); extern void __iomem *__arm_ioremap_exec(unsigned long, size_t, bool cached); extern void __iounmap(volatile void __iomem *addr); -extern void __arm_iounmap(volatile void __iomem *addr); - -extern void __iomem * (*arch_ioremap_caller)(unsigned long, size_t, - unsigned int, void *); -extern void (*arch_iounmap)(volatile void __iomem *); /* * Bad read/write accesses... @@ -101,8 +96,6 @@ static inline void __iomem *__typesafe_io(unsigned long addr) return (void __iomem *)addr; } -#define IOMEM(x) ((void __force __iomem *)(x)) - /* IO barriers */ #ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE #include @@ -116,11 +109,7 @@ static inline void __iomem *__typesafe_io(unsigned long addr) /* * Now, pick up the machine-defined IO definitions */ -#ifdef CONFIG_NEED_MACH_IO_H #include -#else -#define __io(a) ({ (void)(a); __typesafe_io(0); }) -#endif /* * This is the limit of PC card/PCI/ISA IO space, which is by default @@ -222,18 +211,18 @@ extern void _memset_io(volatile void __iomem *, int, size_t); * Again, this are defined to perform little endian accesses. See the * IO port primitives for more information. */ -#ifndef readl -#define readb_relaxed(c) ({ u8 __r = __raw_readb(c); __r; }) +#ifdef __mem_pci +#define readb_relaxed(c) ({ u8 __r = __raw_readb(__mem_pci(c)); __r; }) #define readw_relaxed(c) ({ u16 __r = le16_to_cpu((__force __le16) \ - __raw_readw(c)); __r; }) + __raw_readw(__mem_pci(c))); __r; }) #define readl_relaxed(c) ({ u32 __r = le32_to_cpu((__force __le32) \ - __raw_readl(c)); __r; }) + __raw_readl(__mem_pci(c))); __r; }) -#define writeb_relaxed(v,c) ((void)__raw_writeb(v,c)) +#define writeb_relaxed(v,c) ((void)__raw_writeb(v,__mem_pci(c))) #define writew_relaxed(v,c) ((void)__raw_writew((__force u16) \ - cpu_to_le16(v),c)) + cpu_to_le16(v),__mem_pci(c))) #define writel_relaxed(v,c) ((void)__raw_writel((__force u32) \ - cpu_to_le32(v),c)) + cpu_to_le32(v),__mem_pci(c))) #define readb(c) ({ u8 __v = readb_relaxed(c); __iormb(); __v; }) #define readw(c) ({ u16 __v = readw_relaxed(c); __iormb(); __v; }) @@ -243,19 +232,30 @@ extern void _memset_io(volatile void __iomem *, int, size_t); #define writew(v,c) ({ __iowmb(); writew_relaxed(v,c); }) #define writel(v,c) ({ __iowmb(); writel_relaxed(v,c); }) -#define readsb(p,d,l) __raw_readsb(p,d,l) -#define readsw(p,d,l) __raw_readsw(p,d,l) -#define readsl(p,d,l) __raw_readsl(p,d,l) +#define readsb(p,d,l) __raw_readsb(__mem_pci(p),d,l) +#define readsw(p,d,l) __raw_readsw(__mem_pci(p),d,l) +#define readsl(p,d,l) __raw_readsl(__mem_pci(p),d,l) + +#define writesb(p,d,l) __raw_writesb(__mem_pci(p),d,l) +#define writesw(p,d,l) __raw_writesw(__mem_pci(p),d,l) +#define writesl(p,d,l) __raw_writesl(__mem_pci(p),d,l) -#define writesb(p,d,l) __raw_writesb(p,d,l) -#define writesw(p,d,l) __raw_writesw(p,d,l) -#define writesl(p,d,l) __raw_writesl(p,d,l) +#define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l)) +#define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l)) +#define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l)) -#define memset_io(c,v,l) _memset_io(c,(v),(l)) -#define memcpy_fromio(a,c,l) _memcpy_fromio((a),c,(l)) -#define memcpy_toio(c,a,l) _memcpy_toio(c,(a),(l)) +#elif !defined(readb) -#endif /* readl */ +#define readb(c) (__readwrite_bug("readb"),0) +#define readw(c) (__readwrite_bug("readw"),0) +#define readl(c) (__readwrite_bug("readl"),0) +#define writeb(v,c) __readwrite_bug("writeb") +#define writew(v,c) __readwrite_bug("writew") +#define writel(v,c) __readwrite_bug("writel") + +#define check_signature(io,sig,len) (0) + +#endif /* __mem_pci */ /* * ioremap and friends. @@ -264,11 +264,16 @@ extern void _memset_io(volatile void __iomem *, int, size_t); * Documentation/io-mapping.txt. * */ -#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE) -#define ioremap_nocache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE) -#define ioremap_cached(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_CACHED) -#define ioremap_wc(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_WC) -#define iounmap __arm_iounmap +#ifndef __arch_ioremap +#define __arch_ioremap __arm_ioremap +#define __arch_iounmap __iounmap +#endif + +#define ioremap(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE) +#define ioremap_nocache(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE) +#define ioremap_cached(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_CACHED) +#define ioremap_wc(cookie,size) __arch_ioremap((cookie), (size), MT_DEVICE_WC) +#define iounmap __arch_iounmap /* * io{read,write}{8,16,32} macros diff --git a/trunk/arch/arm/include/asm/irq.h b/trunk/arch/arm/include/asm/irq.h index 35c21c375d81..5a526afb5f18 100644 --- a/trunk/arch/arm/include/asm/irq.h +++ b/trunk/arch/arm/include/asm/irq.h @@ -1,18 +1,14 @@ #ifndef __ASM_ARM_IRQ_H #define __ASM_ARM_IRQ_H -#define NR_IRQS_LEGACY 16 - -#ifndef CONFIG_SPARSE_IRQ #include -#else -#define NR_IRQS NR_IRQS_LEGACY -#endif #ifndef irq_canonicalize #define irq_canonicalize(i) (i) #endif +#define NR_IRQS_LEGACY 16 + /* * Use this value to indicate lack of interrupt * capability diff --git a/trunk/arch/arm/include/asm/jump_label.h b/trunk/arch/arm/include/asm/jump_label.h deleted file mode 100644 index 5c5ca2ea62b0..000000000000 --- a/trunk/arch/arm/include/asm/jump_label.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _ASM_ARM_JUMP_LABEL_H -#define _ASM_ARM_JUMP_LABEL_H - -#ifdef __KERNEL__ - -#include -#include - -#define JUMP_LABEL_NOP_SIZE 4 - -#ifdef CONFIG_THUMB2_KERNEL -#define JUMP_LABEL_NOP "nop.w" -#else -#define JUMP_LABEL_NOP "nop" -#endif - -static __always_inline bool arch_static_branch(struct jump_label_key *key) -{ - asm goto("1:\n\t" - JUMP_LABEL_NOP "\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".word 1b, %l[l_yes], %c0\n\t" - ".popsection\n\t" - : : "i" (key) : : l_yes); - - return false; -l_yes: - return true; -} - -#endif /* __KERNEL__ */ - -typedef u32 jump_label_t; - -struct jump_entry { - jump_label_t code; - jump_label_t target; - jump_label_t key; -}; - -#endif diff --git a/trunk/arch/arm/include/asm/mc146818rtc.h b/trunk/arch/arm/include/asm/mc146818rtc.h index e8567bb99dfc..6b884d2b0b69 100644 --- a/trunk/arch/arm/include/asm/mc146818rtc.h +++ b/trunk/arch/arm/include/asm/mc146818rtc.h @@ -5,9 +5,7 @@ #define _ASM_MC146818RTC_H #include -#include - -#define RTC_IRQ BUILD_BUG_ON(1) +#include #ifndef RTC_PORT #define RTC_PORT(x) (0x70 + (x)) diff --git a/trunk/arch/arm/include/asm/memory.h b/trunk/arch/arm/include/asm/memory.h index fcb575747e5e..a8997d71084e 100644 --- a/trunk/arch/arm/include/asm/memory.h +++ b/trunk/arch/arm/include/asm/memory.h @@ -116,8 +116,6 @@ #define MODULES_END (END_MEM) #define MODULES_VADDR (PHYS_OFFSET) -#define XIP_VIRT_ADDR(physaddr) (physaddr) - #endif /* !CONFIG_MMU */ /* diff --git a/trunk/arch/arm/include/asm/mmu_context.h b/trunk/arch/arm/include/asm/mmu_context.h index a0b3cac0547c..71605d9f8e42 100644 --- a/trunk/arch/arm/include/asm/mmu_context.h +++ b/trunk/arch/arm/include/asm/mmu_context.h @@ -18,7 +18,6 @@ #include #include #include -#include void __check_kvm_seq(struct mm_struct *mm); @@ -134,4 +133,32 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next, #define deactivate_mm(tsk,mm) do { } while (0) #define activate_mm(prev,next) switch_mm(prev, next, NULL) +/* + * We are inserting a "fake" vma for the user-accessible vector page so + * gdb and friends can get to it through ptrace and /proc//mem. + * But we also want to remove it before the generic code gets to see it + * during process exit or the unmapping of it would cause total havoc. + * (the macro is used as remove_vma() is static to mm/mmap.c) + */ +#define arch_exit_mmap(mm) \ +do { \ + struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \ + if (high_vma) { \ + BUG_ON(high_vma->vm_next); /* it should be last */ \ + if (high_vma->vm_prev) \ + high_vma->vm_prev->vm_next = NULL; \ + else \ + mm->mmap = NULL; \ + rb_erase(&high_vma->vm_rb, &mm->mm_rb); \ + mm->mmap_cache = NULL; \ + mm->map_count--; \ + remove_vma(high_vma); \ + } \ +} while (0) + +static inline void arch_dup_mmap(struct mm_struct *oldmm, + struct mm_struct *mm) +{ +} + #endif diff --git a/trunk/arch/arm/include/asm/opcodes.h b/trunk/arch/arm/include/asm/opcodes.h index 19c48deda70f..c0efdd60966f 100644 --- a/trunk/arch/arm/include/asm/opcodes.h +++ b/trunk/arch/arm/include/asm/opcodes.h @@ -17,63 +17,4 @@ extern asmlinkage unsigned int arm_check_condition(u32 opcode, u32 psr); #define ARM_OPCODE_CONDTEST_PASS 1 #define ARM_OPCODE_CONDTEST_UNCOND 2 - -/* - * Opcode byteswap helpers - * - * These macros help with converting instructions between a canonical integer - * format and in-memory representation, in an endianness-agnostic manner. - * - * __mem_to_opcode_*() convert from in-memory representation to canonical form. - * __opcode_to_mem_*() convert from canonical form to in-memory representation. - * - * - * Canonical instruction representation: - * - * ARM: 0xKKLLMMNN - * Thumb 16-bit: 0x0000KKLL, where KK < 0xE8 - * Thumb 32-bit: 0xKKLLMMNN, where KK >= 0xE8 - * - * There is no way to distinguish an ARM instruction in canonical representation - * from a Thumb instruction (just as these cannot be distinguished in memory). - * Where this distinction is important, it needs to be tracked separately. - * - * Note that values in the range 0x0000E800..0xE7FFFFFF intentionally do not - * represent any valid Thumb-2 instruction. For this range, - * __opcode_is_thumb32() and __opcode_is_thumb16() will both be false. - */ - -#ifndef __ASSEMBLY__ - -#include -#include - -#ifdef CONFIG_CPU_ENDIAN_BE8 -#define __opcode_to_mem_arm(x) swab32(x) -#define __opcode_to_mem_thumb16(x) swab16(x) -#define __opcode_to_mem_thumb32(x) swahb32(x) -#else -#define __opcode_to_mem_arm(x) ((u32)(x)) -#define __opcode_to_mem_thumb16(x) ((u16)(x)) -#define __opcode_to_mem_thumb32(x) swahw32(x) -#endif - -#define __mem_to_opcode_arm(x) __opcode_to_mem_arm(x) -#define __mem_to_opcode_thumb16(x) __opcode_to_mem_thumb16(x) -#define __mem_to_opcode_thumb32(x) __opcode_to_mem_thumb32(x) - -/* Operations specific to Thumb opcodes */ - -/* Instruction size checks: */ -#define __opcode_is_thumb32(x) ((u32)(x) >= 0xE8000000UL) -#define __opcode_is_thumb16(x) ((u32)(x) < 0xE800UL) - -/* Operations to construct or split 32-bit Thumb instructions: */ -#define __opcode_thumb32_first(x) ((u16)((x) >> 16)) -#define __opcode_thumb32_second(x) ((u16)(x)) -#define __opcode_thumb32_compose(first, second) \ - (((u32)(u16)(first) << 16) | (u32)(u16)(second)) - -#endif /* __ASSEMBLY__ */ - #endif /* __ASM_ARM_OPCODES_H */ diff --git a/trunk/arch/arm/include/asm/page.h b/trunk/arch/arm/include/asm/page.h index 5838361c48b3..97b440c25c58 100644 --- a/trunk/arch/arm/include/asm/page.h +++ b/trunk/arch/arm/include/asm/page.h @@ -151,8 +151,6 @@ extern void __cpu_copy_user_highpage(struct page *to, struct page *from, #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) extern void copy_page(void *to, const void *from); -#define __HAVE_ARCH_GATE_AREA 1 - #ifdef CONFIG_ARM_LPAE #include #else diff --git a/trunk/arch/arm/include/asm/perf_event.h b/trunk/arch/arm/include/asm/perf_event.h index 00cbe10a50e3..7523340afb8a 100644 --- a/trunk/arch/arm/include/asm/perf_event.h +++ b/trunk/arch/arm/include/asm/perf_event.h @@ -22,7 +22,6 @@ enum arm_perf_pmu_ids { ARM_PERF_PMU_ID_CA9, ARM_PERF_PMU_ID_CA5, ARM_PERF_PMU_ID_CA15, - ARM_PERF_PMU_ID_CA7, ARM_NUM_PMU_IDS, }; diff --git a/trunk/arch/arm/include/asm/posix_types.h b/trunk/arch/arm/include/asm/posix_types.h index efdf99045d87..2446d23bfdbf 100644 --- a/trunk/arch/arm/include/asm/posix_types.h +++ b/trunk/arch/arm/include/asm/posix_types.h @@ -19,22 +19,59 @@ * assume GCC is being used. */ +typedef unsigned long __kernel_ino_t; typedef unsigned short __kernel_mode_t; -#define __kernel_mode_t __kernel_mode_t - typedef unsigned short __kernel_nlink_t; -#define __kernel_nlink_t __kernel_nlink_t - +typedef long __kernel_off_t; +typedef int __kernel_pid_t; typedef unsigned short __kernel_ipc_pid_t; -#define __kernel_ipc_pid_t __kernel_ipc_pid_t - typedef unsigned short __kernel_uid_t; typedef unsigned short __kernel_gid_t; -#define __kernel_uid_t __kernel_uid_t +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; typedef unsigned short __kernel_old_dev_t; -#define __kernel_old_dev_t __kernel_old_dev_t -#include +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { + int val[2]; +} __kernel_fsid_t; + +#if defined(__KERNEL__) + +#undef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31))) + +#undef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31))) + +#undef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset (fdsetp, 0, sizeof (*(fd_set *)(fdsetp)))) + +#endif #endif diff --git a/trunk/arch/arm/include/asm/processor.h b/trunk/arch/arm/include/asm/processor.h index 5ac8d3d3e025..f4d7f56ee51f 100644 --- a/trunk/arch/arm/include/asm/processor.h +++ b/trunk/arch/arm/include/asm/processor.h @@ -55,6 +55,7 @@ struct thread_struct { #define start_thread(regs,pc,sp) \ ({ \ unsigned long *stack = (unsigned long *)sp; \ + set_fs(USER_DS); \ memset(regs->uregs, 0, sizeof(regs->uregs)); \ if (current->personality & ADDR_LIMIT_32BIT) \ regs->ARM_cpsr = USR_MODE; \ diff --git a/trunk/arch/arm/include/asm/prom.h b/trunk/arch/arm/include/asm/prom.h index aeae9c609df4..ee0363307918 100644 --- a/trunk/arch/arm/include/asm/prom.h +++ b/trunk/arch/arm/include/asm/prom.h @@ -13,6 +13,8 @@ #ifdef CONFIG_OF +#include + extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys); extern void arm_dt_memblock_reserve(void); diff --git a/trunk/arch/arm/include/asm/tlbflush.h b/trunk/arch/arm/include/asm/tlbflush.h index 85fe61e73202..02b2f8203982 100644 --- a/trunk/arch/arm/include/asm/tlbflush.h +++ b/trunk/arch/arm/include/asm/tlbflush.h @@ -318,21 +318,6 @@ extern struct cpu_tlb_fns cpu_tlb; #define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f))) -#define __tlb_op(f, insnarg, arg) \ - do { \ - if (always_tlb_flags & (f)) \ - asm("mcr " insnarg \ - : : "r" (arg) : "cc"); \ - else if (possible_tlb_flags & (f)) \ - asm("tst %1, %2\n\t" \ - "mcrne " insnarg \ - : : "r" (arg), "r" (__tlb_flag), "Ir" (f) \ - : "cc"); \ - } while (0) - -#define tlb_op(f, regs, arg) __tlb_op(f, "p15, 0, %0, " regs, arg) -#define tlb_l2_op(f, regs, arg) __tlb_op(f, "p15, 1, %0, " regs, arg) - static inline void local_flush_tlb_all(void) { const int zero = 0; @@ -341,11 +326,16 @@ static inline void local_flush_tlb_all(void) if (tlb_flag(TLB_WB)) dsb(); - tlb_op(TLB_V3_FULL, "c6, c0, 0", zero); - tlb_op(TLB_V4_U_FULL | TLB_V6_U_FULL, "c8, c7, 0", zero); - tlb_op(TLB_V4_D_FULL | TLB_V6_D_FULL, "c8, c6, 0", zero); - tlb_op(TLB_V4_I_FULL | TLB_V6_I_FULL, "c8, c5, 0", zero); - tlb_op(TLB_V7_UIS_FULL, "c8, c3, 0", zero); + if (tlb_flag(TLB_V3_FULL)) + asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V4_U_FULL | TLB_V6_U_FULL)) + asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V4_D_FULL | TLB_V6_D_FULL)) + asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL)) + asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V7_UIS_FULL)) + asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc"); if (tlb_flag(TLB_BARRIER)) { dsb(); @@ -362,23 +352,29 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm) if (tlb_flag(TLB_WB)) dsb(); - if (possible_tlb_flags & (TLB_V3_FULL|TLB_V4_U_FULL|TLB_V4_D_FULL|TLB_V4_I_FULL)) { - if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) { - tlb_op(TLB_V3_FULL, "c6, c0, 0", zero); - tlb_op(TLB_V4_U_FULL, "c8, c7, 0", zero); - tlb_op(TLB_V4_D_FULL, "c8, c6, 0", zero); - tlb_op(TLB_V4_I_FULL, "c8, c5, 0", zero); - } - put_cpu(); + if (cpumask_test_cpu(get_cpu(), mm_cpumask(mm))) { + if (tlb_flag(TLB_V3_FULL)) + asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V4_U_FULL)) + asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V4_D_FULL)) + asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc"); + if (tlb_flag(TLB_V4_I_FULL)) + asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); } - - tlb_op(TLB_V6_U_ASID, "c8, c7, 2", asid); - tlb_op(TLB_V6_D_ASID, "c8, c6, 2", asid); - tlb_op(TLB_V6_I_ASID, "c8, c5, 2", asid); + put_cpu(); + + if (tlb_flag(TLB_V6_U_ASID)) + asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc"); + if (tlb_flag(TLB_V6_D_ASID)) + asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc"); + if (tlb_flag(TLB_V6_I_ASID)) + asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc"); + if (tlb_flag(TLB_V7_UIS_ASID)) #ifdef CONFIG_ARM_ERRATA_720789 - tlb_op(TLB_V7_UIS_ASID, "c8, c3, 0", zero); + asm("mcr p15, 0, %0, c8, c3, 0" : : "r" (zero) : "cc"); #else - tlb_op(TLB_V7_UIS_ASID, "c8, c3, 2", asid); + asm("mcr p15, 0, %0, c8, c3, 2" : : "r" (asid) : "cc"); #endif if (tlb_flag(TLB_BARRIER)) @@ -396,23 +392,30 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr) if (tlb_flag(TLB_WB)) dsb(); - if (possible_tlb_flags & (TLB_V3_PAGE|TLB_V4_U_PAGE|TLB_V4_D_PAGE|TLB_V4_I_PAGE|TLB_V4_I_FULL) && - cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { - tlb_op(TLB_V3_PAGE, "c6, c0, 0", uaddr); - tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", uaddr); - tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", uaddr); - tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", uaddr); + if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) { + if (tlb_flag(TLB_V3_PAGE)) + asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc"); + if (tlb_flag(TLB_V4_U_PAGE)) + asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc"); + if (tlb_flag(TLB_V4_D_PAGE)) + asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc"); + if (tlb_flag(TLB_V4_I_PAGE)) + asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc"); if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL)) asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); } - tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", uaddr); - tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", uaddr); - tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", uaddr); + if (tlb_flag(TLB_V6_U_PAGE)) + asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc"); + if (tlb_flag(TLB_V6_D_PAGE)) + asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc"); + if (tlb_flag(TLB_V6_I_PAGE)) + asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc"); + if (tlb_flag(TLB_V7_UIS_PAGE)) #ifdef CONFIG_ARM_ERRATA_720789 - tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 3", uaddr & PAGE_MASK); + asm("mcr p15, 0, %0, c8, c3, 3" : : "r" (uaddr & PAGE_MASK) : "cc"); #else - tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", uaddr); + asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (uaddr) : "cc"); #endif if (tlb_flag(TLB_BARRIER)) @@ -429,17 +432,25 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr) if (tlb_flag(TLB_WB)) dsb(); - tlb_op(TLB_V3_PAGE, "c6, c0, 0", kaddr); - tlb_op(TLB_V4_U_PAGE, "c8, c7, 1", kaddr); - tlb_op(TLB_V4_D_PAGE, "c8, c6, 1", kaddr); - tlb_op(TLB_V4_I_PAGE, "c8, c5, 1", kaddr); + if (tlb_flag(TLB_V3_PAGE)) + asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc"); + if (tlb_flag(TLB_V4_U_PAGE)) + asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc"); + if (tlb_flag(TLB_V4_D_PAGE)) + asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc"); + if (tlb_flag(TLB_V4_I_PAGE)) + asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc"); if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL)) asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc"); - tlb_op(TLB_V6_U_PAGE, "c8, c7, 1", kaddr); - tlb_op(TLB_V6_D_PAGE, "c8, c6, 1", kaddr); - tlb_op(TLB_V6_I_PAGE, "c8, c5, 1", kaddr); - tlb_op(TLB_V7_UIS_PAGE, "c8, c3, 1", kaddr); + if (tlb_flag(TLB_V6_U_PAGE)) + asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc"); + if (tlb_flag(TLB_V6_D_PAGE)) + asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc"); + if (tlb_flag(TLB_V6_I_PAGE)) + asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc"); + if (tlb_flag(TLB_V7_UIS_PAGE)) + asm("mcr p15, 0, %0, c8, c3, 1" : : "r" (kaddr) : "cc"); if (tlb_flag(TLB_BARRIER)) { dsb(); @@ -464,8 +475,13 @@ static inline void flush_pmd_entry(void *pmd) { const unsigned int __tlb_flag = __cpu_tlb_flags; - tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd); - tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd); + if (tlb_flag(TLB_DCLEAN)) + asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd" + : : "r" (pmd) : "cc"); + + if (tlb_flag(TLB_L2CLEAN_FR)) + asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd" + : : "r" (pmd) : "cc"); if (tlb_flag(TLB_WB)) dsb(); @@ -475,11 +491,15 @@ static inline void clean_pmd_entry(void *pmd) { const unsigned int __tlb_flag = __cpu_tlb_flags; - tlb_op(TLB_DCLEAN, "c7, c10, 1 @ flush_pmd", pmd); - tlb_l2_op(TLB_L2CLEAN_FR, "c15, c9, 1 @ L2 flush_pmd", pmd); + if (tlb_flag(TLB_DCLEAN)) + asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd" + : : "r" (pmd) : "cc"); + + if (tlb_flag(TLB_L2CLEAN_FR)) + asm("mcr p15, 1, %0, c15, c9, 1 @ L2 flush_pmd" + : : "r" (pmd) : "cc"); } -#undef tlb_op #undef tlb_flag #undef always_tlb_flags #undef possible_tlb_flags diff --git a/trunk/arch/arm/include/asm/traps.h b/trunk/arch/arm/include/asm/traps.h index f555bb3664dc..5b29a6673625 100644 --- a/trunk/arch/arm/include/asm/traps.h +++ b/trunk/arch/arm/include/asm/traps.h @@ -46,7 +46,7 @@ static inline int in_exception_text(unsigned long ptr) return in ? : __in_irqentry_text(ptr); } -extern void __init early_trap_init(void *); +extern void __init early_trap_init(void); extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame); extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs); diff --git a/trunk/arch/arm/kernel/Makefile b/trunk/arch/arm/kernel/Makefile index 8269d8928742..3a274878412e 100644 --- a/trunk/arch/arm/kernel/Makefile +++ b/trunk/arch/arm/kernel/Makefile @@ -7,8 +7,6 @@ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_ftrace.o = -pg -CFLAGS_REMOVE_insn.o = -pg -CFLAGS_REMOVE_patch.o = -pg endif CFLAGS_REMOVE_return_address.o = -pg @@ -16,8 +14,8 @@ CFLAGS_REMOVE_return_address.o = -pg # Object file lists. obj-y := elf.o entry-armv.o entry-common.o irq.o opcodes.o \ - process.o ptrace.o return_address.o sched_clock.o \ - setup.o signal.o stacktrace.o sys_arm.o time.o traps.o + process.o ptrace.o return_address.o setup.o signal.o \ + sys_arm.o stacktrace.o time.o traps.o obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o @@ -31,14 +29,14 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o +obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o obj-$(CONFIG_SMP) += smp.o smp_tlb.o obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o -obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o insn.o -obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o insn.o -obj-$(CONFIG_JUMP_LABEL) += jump_label.o insn.o patch.o +obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o +obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o patch.o +obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o ifdef CONFIG_THUMB2_KERNEL obj-$(CONFIG_KPROBES) += kprobes-thumb.o else diff --git a/trunk/arch/arm/kernel/debug.S b/trunk/arch/arm/kernel/debug.S index c45522c36787..204e2160cfcc 100644 --- a/trunk/arch/arm/kernel/debug.S +++ b/trunk/arch/arm/kernel/debug.S @@ -10,7 +10,6 @@ * 32-bit debugging code */ #include -#include .text @@ -101,7 +100,7 @@ #endif /* CONFIG_CPU_V6 */ -#elif !defined(CONFIG_DEBUG_SEMIHOSTING) +#else #include #endif /* CONFIG_DEBUG_ICEDCC */ @@ -156,8 +155,6 @@ hexbuf: .space 16 .ltorg -#ifndef CONFIG_DEBUG_SEMIHOSTING - ENTRY(printascii) addruart_current r3, r1, r2 b 2f @@ -180,24 +177,3 @@ ENTRY(printch) mov r0, #0 b 1b ENDPROC(printch) - -#else - -ENTRY(printascii) - mov r1, r0 - mov r0, #0x04 @ SYS_WRITE0 - ARM( svc #0x123456 ) - THUMB( svc #0xab ) - mov pc, lr -ENDPROC(printascii) - -ENTRY(printch) - adr r1, hexbuf - strb r0, [r1] - mov r0, #0x03 @ SYS_WRITEC - ARM( svc #0x123456 ) - THUMB( svc #0xab ) - mov pc, lr -ENDPROC(printch) - -#endif diff --git a/trunk/arch/arm/kernel/entry-armv.S b/trunk/arch/arm/kernel/entry-armv.S index 7fd3ad048da9..8ec5eed55e37 100644 --- a/trunk/arch/arm/kernel/entry-armv.S +++ b/trunk/arch/arm/kernel/entry-armv.S @@ -15,7 +15,6 @@ * that causes it to save wrong values... Be aware! */ -#include #include #include #include diff --git a/trunk/arch/arm/kernel/ftrace.c b/trunk/arch/arm/kernel/ftrace.c index df0bf0c8cb79..c0062ad1e847 100644 --- a/trunk/arch/arm/kernel/ftrace.c +++ b/trunk/arch/arm/kernel/ftrace.c @@ -16,13 +16,10 @@ #include #include -#include #include -#include "insn.h" - #ifdef CONFIG_THUMB2_KERNEL -#define NOP 0xf85deb04 /* pop.w {lr} */ +#define NOP 0xeb04f85d /* pop.w {lr} */ #else #define NOP 0xe8bd4000 /* pop {lr} */ #endif @@ -63,31 +60,76 @@ static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr) } #endif +#ifdef CONFIG_THUMB2_KERNEL +static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, + bool link) +{ + unsigned long s, j1, j2, i1, i2, imm10, imm11; + unsigned long first, second; + long offset; + + offset = (long)addr - (long)(pc + 4); + if (offset < -16777216 || offset > 16777214) { + WARN_ON_ONCE(1); + return 0; + } + + s = (offset >> 24) & 0x1; + i1 = (offset >> 23) & 0x1; + i2 = (offset >> 22) & 0x1; + imm10 = (offset >> 12) & 0x3ff; + imm11 = (offset >> 1) & 0x7ff; + + j1 = (!i1) ^ s; + j2 = (!i2) ^ s; + + first = 0xf000 | (s << 10) | imm10; + second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; + if (link) + second |= 1 << 14; + + return (second << 16) | first; +} +#else +static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, + bool link) +{ + unsigned long opcode = 0xea000000; + long offset; + + if (link) + opcode |= 1 << 24; + + offset = (long)addr - (long)(pc + 8); + if (unlikely(offset < -33554432 || offset > 33554428)) { + /* Can't generate branches that far (from ARM ARM). Ftrace + * doesn't generate branches outside of kernel text. + */ + WARN_ON_ONCE(1); + return 0; + } + + offset = (offset >> 2) & 0x00ffffff; + + return opcode | offset; +} +#endif + static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) { - return arm_gen_branch_link(pc, addr); + return ftrace_gen_branch(pc, addr, true); } static int ftrace_modify_code(unsigned long pc, unsigned long old, - unsigned long new, bool validate) + unsigned long new) { unsigned long replaced; - if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { - old = __opcode_to_mem_thumb32(old); - new = __opcode_to_mem_thumb32(new); - } else { - old = __opcode_to_mem_arm(old); - new = __opcode_to_mem_arm(new); - } + if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE)) + return -EFAULT; - if (validate) { - if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE)) - return -EFAULT; - - if (replaced != old) - return -EINVAL; - } + if (replaced != old) + return -EINVAL; if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE)) return -EPERM; @@ -99,21 +141,23 @@ static int ftrace_modify_code(unsigned long pc, unsigned long old, int ftrace_update_ftrace_func(ftrace_func_t func) { - unsigned long pc; + unsigned long pc, old; unsigned long new; int ret; pc = (unsigned long)&ftrace_call; + memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE); new = ftrace_call_replace(pc, (unsigned long)func); - ret = ftrace_modify_code(pc, 0, new, false); + ret = ftrace_modify_code(pc, old, new); #ifdef CONFIG_OLD_MCOUNT if (!ret) { pc = (unsigned long)&ftrace_call_old; + memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE); new = ftrace_call_replace(pc, (unsigned long)func); - ret = ftrace_modify_code(pc, 0, new, false); + ret = ftrace_modify_code(pc, old, new); } #endif @@ -128,7 +172,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) old = ftrace_nop_replace(rec); new = ftrace_call_replace(ip, adjust_address(rec, addr)); - return ftrace_modify_code(rec->ip, old, new, true); + return ftrace_modify_code(rec->ip, old, new); } int ftrace_make_nop(struct module *mod, @@ -141,7 +185,7 @@ int ftrace_make_nop(struct module *mod, old = ftrace_call_replace(ip, adjust_address(rec, addr)); new = ftrace_nop_replace(rec); - ret = ftrace_modify_code(ip, old, new, true); + ret = ftrace_modify_code(ip, old, new); #ifdef CONFIG_OLD_MCOUNT if (ret == -EINVAL && addr == MCOUNT_ADDR) { @@ -149,7 +193,7 @@ int ftrace_make_nop(struct module *mod, old = ftrace_call_replace(ip, adjust_address(rec, addr)); new = ftrace_nop_replace(rec); - ret = ftrace_modify_code(ip, old, new, true); + ret = ftrace_modify_code(ip, old, new); } #endif @@ -205,12 +249,12 @@ static int __ftrace_modify_caller(unsigned long *callsite, { unsigned long caller_fn = (unsigned long) func; unsigned long pc = (unsigned long) callsite; - unsigned long branch = arm_gen_branch(pc, caller_fn); + unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); unsigned long nop = 0xe1a00000; /* mov r0, r0 */ unsigned long old = enable ? nop : branch; unsigned long new = enable ? branch : nop; - return ftrace_modify_code(pc, old, new, true); + return ftrace_modify_code(pc, old, new); } static int ftrace_modify_graph_caller(bool enable) diff --git a/trunk/arch/arm/kernel/head.S b/trunk/arch/arm/kernel/head.S index 3bf0c7f8b043..a2e9694a68ee 100644 --- a/trunk/arch/arm/kernel/head.S +++ b/trunk/arch/arm/kernel/head.S @@ -265,7 +265,7 @@ __create_page_tables: str r6, [r3] #ifdef CONFIG_DEBUG_LL -#if !defined(CONFIG_DEBUG_ICEDCC) && !defined(CONFIG_DEBUG_SEMIHOSTING) +#ifndef CONFIG_DEBUG_ICEDCC /* * Map in IO space for serial debugging. * This allows debug messages to be output @@ -297,10 +297,10 @@ __create_page_tables: cmp r0, r6 blo 1b -#else /* CONFIG_DEBUG_ICEDCC || CONFIG_DEBUG_SEMIHOSTING */ - /* we don't need any serial debugging mappings */ +#else /* CONFIG_DEBUG_ICEDCC */ + /* we don't need any serial debugging mappings for ICEDCC */ ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags -#endif +#endif /* !CONFIG_DEBUG_ICEDCC */ #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS) /* diff --git a/trunk/arch/arm/kernel/insn.c b/trunk/arch/arm/kernel/insn.c deleted file mode 100644 index ab312e516546..000000000000 --- a/trunk/arch/arm/kernel/insn.c +++ /dev/null @@ -1,61 +0,0 @@ -#include -#include - -static unsigned long -__arm_gen_branch_thumb2(unsigned long pc, unsigned long addr, bool link) -{ - unsigned long s, j1, j2, i1, i2, imm10, imm11; - unsigned long first, second; - long offset; - - offset = (long)addr - (long)(pc + 4); - if (offset < -16777216 || offset > 16777214) { - WARN_ON_ONCE(1); - return 0; - } - - s = (offset >> 24) & 0x1; - i1 = (offset >> 23) & 0x1; - i2 = (offset >> 22) & 0x1; - imm10 = (offset >> 12) & 0x3ff; - imm11 = (offset >> 1) & 0x7ff; - - j1 = (!i1) ^ s; - j2 = (!i2) ^ s; - - first = 0xf000 | (s << 10) | imm10; - second = 0x9000 | (j1 << 13) | (j2 << 11) | imm11; - if (link) - second |= 1 << 14; - - return __opcode_thumb32_compose(first, second); -} - -static unsigned long -__arm_gen_branch_arm(unsigned long pc, unsigned long addr, bool link) -{ - unsigned long opcode = 0xea000000; - long offset; - - if (link) - opcode |= 1 << 24; - - offset = (long)addr - (long)(pc + 8); - if (unlikely(offset < -33554432 || offset > 33554428)) { - WARN_ON_ONCE(1); - return 0; - } - - offset = (offset >> 2) & 0x00ffffff; - - return opcode | offset; -} - -unsigned long -__arm_gen_branch(unsigned long pc, unsigned long addr, bool link) -{ - if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) - return __arm_gen_branch_thumb2(pc, addr, link); - else - return __arm_gen_branch_arm(pc, addr, link); -} diff --git a/trunk/arch/arm/kernel/insn.h b/trunk/arch/arm/kernel/insn.h deleted file mode 100644 index e96065da4dae..000000000000 --- a/trunk/arch/arm/kernel/insn.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __ASM_ARM_INSN_H -#define __ASM_ARM_INSN_H - -static inline unsigned long -arm_gen_nop(void) -{ -#ifdef CONFIG_THUMB2_KERNEL - return 0xf3af8000; /* nop.w */ -#else - return 0xe1a00000; /* mov r0, r0 */ -#endif -} - -unsigned long -__arm_gen_branch(unsigned long pc, unsigned long addr, bool link); - -static inline unsigned long -arm_gen_branch(unsigned long pc, unsigned long addr) -{ - return __arm_gen_branch(pc, addr, false); -} - -static inline unsigned long -arm_gen_branch_link(unsigned long pc, unsigned long addr) -{ - return __arm_gen_branch(pc, addr, true); -} - -#endif diff --git a/trunk/arch/arm/kernel/irq.c b/trunk/arch/arm/kernel/irq.c index 71ccdbfed662..6a6a097edd61 100644 --- a/trunk/arch/arm/kernel/irq.c +++ b/trunk/arch/arm/kernel/irq.c @@ -180,7 +180,10 @@ void migrate_irqs(void) local_irq_save(flags); for_each_irq_desc(i, desc) { - bool affinity_broken; + bool affinity_broken = false; + + if (!desc) + continue; raw_spin_lock(&desc->lock); affinity_broken = migrate_one_irq(desc); diff --git a/trunk/arch/arm/kernel/jump_label.c b/trunk/arch/arm/kernel/jump_label.c deleted file mode 100644 index 4ce4f789446d..000000000000 --- a/trunk/arch/arm/kernel/jump_label.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -#include "insn.h" -#include "patch.h" - -#ifdef HAVE_JUMP_LABEL - -static void __arch_jump_label_transform(struct jump_entry *entry, - enum jump_label_type type, - bool is_static) -{ - void *addr = (void *)entry->code; - unsigned int insn; - - if (type == JUMP_LABEL_ENABLE) - insn = arm_gen_branch(entry->code, entry->target); - else - insn = arm_gen_nop(); - - if (is_static) - __patch_text(addr, insn); - else - patch_text(addr, insn); -} - -void arch_jump_label_transform(struct jump_entry *entry, - enum jump_label_type type) -{ - __arch_jump_label_transform(entry, type, false); -} - -void arch_jump_label_transform_static(struct jump_entry *entry, - enum jump_label_type type) -{ - __arch_jump_label_transform(entry, type, true); -} - -#endif diff --git a/trunk/arch/arm/kernel/kprobes.c b/trunk/arch/arm/kernel/kprobes.c index ab1869dac97a..129c1163248b 100644 --- a/trunk/arch/arm/kernel/kprobes.c +++ b/trunk/arch/arm/kernel/kprobes.c @@ -29,7 +29,6 @@ #include #include "kprobes.h" -#include "patch.h" #define MIN_STACK_SIZE(addr) \ min((unsigned long)MAX_STACK_SIZE, \ @@ -104,34 +103,58 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) return 0; } -void __kprobes arch_arm_kprobe(struct kprobe *p) -{ - unsigned int brkp; - void *addr; +#ifdef CONFIG_THUMB2_KERNEL - if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) { - /* Remove any Thumb flag */ - addr = (void *)((uintptr_t)p->addr & ~1); +/* + * For a 32-bit Thumb breakpoint spanning two memory words we need to take + * special precautions to insert the breakpoint atomically, especially on SMP + * systems. This is achieved by calling this arming function using stop_machine. + */ +static int __kprobes set_t32_breakpoint(void *addr) +{ + ((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16; + ((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff; + flush_insns(addr, 2*sizeof(u16)); + return 0; +} - if (is_wide_instruction(p->opcode)) - brkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION; - else - brkp = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION; +void __kprobes arch_arm_kprobe(struct kprobe *p) +{ + uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */ + + if (!is_wide_instruction(p->opcode)) { + *(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION; + flush_insns(addr, sizeof(u16)); + } else if (addr & 2) { + /* A 32-bit instruction spanning two words needs special care */ + stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map); } else { - kprobe_opcode_t insn = p->opcode; - - addr = p->addr; - brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION; - - if (insn >= 0xe0000000) - brkp |= 0xe0000000; /* Unconditional instruction */ - else - brkp |= insn & 0xf0000000; /* Copy condition from insn */ + /* Word aligned 32-bit instruction can be written atomically */ + u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION; +#ifndef __ARMEB__ /* Swap halfwords for little-endian */ + bkp = (bkp >> 16) | (bkp << 16); +#endif + *(u32 *)addr = bkp; + flush_insns(addr, sizeof(u32)); } +} - patch_text(addr, brkp); +#else /* !CONFIG_THUMB2_KERNEL */ + +void __kprobes arch_arm_kprobe(struct kprobe *p) +{ + kprobe_opcode_t insn = p->opcode; + kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION; + if (insn >= 0xe0000000) + brkp |= 0xe0000000; /* Unconditional instruction */ + else + brkp |= insn & 0xf0000000; /* Copy condition from insn */ + *p->addr = brkp; + flush_insns(p->addr, sizeof(p->addr[0])); } +#endif /* !CONFIG_THUMB2_KERNEL */ + /* * The actual disarming is done here on each CPU and synchronized using * stop_machine. This synchronization is necessary on SMP to avoid removing @@ -143,10 +166,25 @@ void __kprobes arch_arm_kprobe(struct kprobe *p) int __kprobes __arch_disarm_kprobe(void *p) { struct kprobe *kp = p; - void *addr = (void *)((uintptr_t)kp->addr & ~1); +#ifdef CONFIG_THUMB2_KERNEL + u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1); + kprobe_opcode_t insn = kp->opcode; + unsigned int len; - __patch_text(addr, kp->opcode); + if (is_wide_instruction(insn)) { + ((u16 *)addr)[0] = insn>>16; + ((u16 *)addr)[1] = insn; + len = 2*sizeof(u16); + } else { + ((u16 *)addr)[0] = insn; + len = sizeof(u16); + } + flush_insns(addr, len); +#else /* !CONFIG_THUMB2_KERNEL */ + *kp->addr = kp->opcode; + flush_insns(kp->addr, sizeof(kp->addr[0])); +#endif return 0; } diff --git a/trunk/arch/arm/kernel/machine_kexec.c b/trunk/arch/arm/kernel/machine_kexec.c index dfcdb9f7c126..56995983eed8 100644 --- a/trunk/arch/arm/kernel/machine_kexec.c +++ b/trunk/arch/arm/kernel/machine_kexec.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -54,29 +53,6 @@ void machine_crash_nonpanic_core(void *unused) cpu_relax(); } -static void machine_kexec_mask_interrupts(void) -{ - unsigned int i; - struct irq_desc *desc; - - for_each_irq_desc(i, desc) { - struct irq_chip *chip; - - chip = irq_desc_get_chip(desc); - if (!chip) - continue; - - if (chip->irq_eoi && irqd_irq_inprogress(&desc->irq_data)) - chip->irq_eoi(&desc->irq_data); - - if (chip->irq_mask) - chip->irq_mask(&desc->irq_data); - - if (chip->irq_disable && !irqd_irq_disabled(&desc->irq_data)) - chip->irq_disable(&desc->irq_data); - } -} - void machine_crash_shutdown(struct pt_regs *regs) { unsigned long msecs; @@ -94,7 +70,6 @@ void machine_crash_shutdown(struct pt_regs *regs) printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n"); crash_save_cpu(regs, smp_processor_id()); - machine_kexec_mask_interrupts(); printk(KERN_INFO "Loading crashdump kernel...\n"); } diff --git a/trunk/arch/arm/kernel/patch.c b/trunk/arch/arm/kernel/patch.c deleted file mode 100644 index 07314af47733..000000000000 --- a/trunk/arch/arm/kernel/patch.c +++ /dev/null @@ -1,75 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -#include "patch.h" - -struct patch { - void *addr; - unsigned int insn; -}; - -void __kprobes __patch_text(void *addr, unsigned int insn) -{ - bool thumb2 = IS_ENABLED(CONFIG_THUMB2_KERNEL); - int size; - - if (thumb2 && __opcode_is_thumb16(insn)) { - *(u16 *)addr = __opcode_to_mem_thumb16(insn); - size = sizeof(u16); - } else if (thumb2 && ((uintptr_t)addr & 2)) { - u16 first = __opcode_thumb32_first(insn); - u16 second = __opcode_thumb32_second(insn); - u16 *addrh = addr; - - addrh[0] = __opcode_to_mem_thumb16(first); - addrh[1] = __opcode_to_mem_thumb16(second); - - size = sizeof(u32); - } else { - if (thumb2) - insn = __opcode_to_mem_thumb32(insn); - else - insn = __opcode_to_mem_arm(insn); - - *(u32 *)addr = insn; - size = sizeof(u32); - } - - flush_icache_range((uintptr_t)(addr), - (uintptr_t)(addr) + size); -} - -static int __kprobes patch_text_stop_machine(void *data) -{ - struct patch *patch = data; - - __patch_text(patch->addr, patch->insn); - - return 0; -} - -void __kprobes patch_text(void *addr, unsigned int insn) -{ - struct patch patch = { - .addr = addr, - .insn = insn, - }; - - if (cache_ops_need_broadcast()) { - stop_machine(patch_text_stop_machine, &patch, cpu_online_mask); - } else { - bool straddles_word = IS_ENABLED(CONFIG_THUMB2_KERNEL) - && __opcode_is_thumb32(insn) - && ((uintptr_t)addr & 2); - - if (straddles_word) - stop_machine(patch_text_stop_machine, &patch, NULL); - else - __patch_text(addr, insn); - } -} diff --git a/trunk/arch/arm/kernel/patch.h b/trunk/arch/arm/kernel/patch.h deleted file mode 100644 index b4731f2dac38..000000000000 --- a/trunk/arch/arm/kernel/patch.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _ARM_KERNEL_PATCH_H -#define _ARM_KERNEL_PATCH_H - -void patch_text(void *addr, unsigned int insn); -void __patch_text(void *addr, unsigned int insn); - -#endif diff --git a/trunk/arch/arm/kernel/perf_event.c b/trunk/arch/arm/kernel/perf_event.c index 186c8cb982c5..8a89d3b7626b 100644 --- a/trunk/arch/arm/kernel/perf_event.c +++ b/trunk/arch/arm/kernel/perf_event.c @@ -738,9 +738,6 @@ init_hw_perf_events(void) case 0xC0F0: /* Cortex-A15 */ cpu_pmu = armv7_a15_pmu_init(); break; - case 0xC070: /* Cortex-A7 */ - cpu_pmu = armv7_a7_pmu_init(); - break; } /* Intel CPUs [xscale]. */ } else if (0x69 == implementor) { diff --git a/trunk/arch/arm/kernel/perf_event_v7.c b/trunk/arch/arm/kernel/perf_event_v7.c index 00755d82e2f2..4d7095af2ab3 100644 --- a/trunk/arch/arm/kernel/perf_event_v7.c +++ b/trunk/arch/arm/kernel/perf_event_v7.c @@ -609,130 +609,6 @@ static const unsigned armv7_a15_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] }, }; -/* - * Cortex-A7 HW events mapping - */ -static const unsigned armv7_a7_perf_map[PERF_COUNT_HW_MAX] = { - [PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES, - [PERF_COUNT_HW_INSTRUCTIONS] = ARMV7_PERFCTR_INSTR_EXECUTED, - [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, - [PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_L1_DCACHE_REFILL, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE, - [PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - [PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_BUS_CYCLES, - [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED, -}; - -static const unsigned armv7_a7_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX] = { - [C(L1D)] = { - /* - * The performance counters don't differentiate between read - * and write accesses/misses so this isn't strictly correct, - * but it's the best we can do. Writes and reads get - * combined. - */ - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_DCACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_DCACHE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(L1I)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L1_ICACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_L1_ICACHE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_CACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_L2_CACHE_ACCESS, - [C(RESULT_MISS)] = ARMV7_PERFCTR_L2_CACHE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_DTLB_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_ITLB_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(BPU)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV7_PERFCTR_PC_BRANCH_PRED, - [C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, -}; - /* * Perf Events' indices */ @@ -1228,12 +1104,6 @@ static int armv7_a15_map_event(struct perf_event *event) &armv7_a15_perf_cache_map, 0xFF); } -static int armv7_a7_map_event(struct perf_event *event) -{ - return map_cpu_event(event, &armv7_a7_perf_map, - &armv7_a7_perf_cache_map, 0xFF); -} - static struct arm_pmu armv7pmu = { .handle_irq = armv7pmu_handle_irq, .enable = armv7pmu_enable_event, @@ -1294,16 +1164,6 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) armv7pmu.set_event_filter = armv7pmu_set_event_filter; return &armv7pmu; } - -static struct arm_pmu *__init armv7_a7_pmu_init(void) -{ - armv7pmu.id = ARM_PERF_PMU_ID_CA7; - armv7pmu.name = "ARMv7 Cortex-A7"; - armv7pmu.map_event = armv7_a7_map_event; - armv7pmu.num_events = armv7_read_num_pmnc_events(); - armv7pmu.set_event_filter = armv7pmu_set_event_filter; - return &armv7pmu; -} #else static struct arm_pmu *__init armv7_a8_pmu_init(void) { @@ -1324,9 +1184,4 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void) { return NULL; } - -static struct arm_pmu *__init armv7_a7_pmu_init(void) -{ - return NULL; -} #endif /* CONFIG_CPU_V7 */ diff --git a/trunk/arch/arm/kernel/process.c b/trunk/arch/arm/kernel/process.c index 2b7b017a20cd..7b9cddef6e53 100644 --- a/trunk/arch/arm/kernel/process.c +++ b/trunk/arch/arm/kernel/process.c @@ -528,39 +528,21 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) #ifdef CONFIG_MMU /* * The vectors page is always readable from user space for the - * atomic helpers and the signal restart code. Insert it into the - * gate_vma so that it is visible through ptrace and /proc//mem. + * atomic helpers and the signal restart code. Let's declare a mapping + * for it so it is visible through ptrace and /proc//mem. */ -static struct vm_area_struct gate_vma; -static int __init gate_vma_init(void) +int vectors_user_mapping(void) { - gate_vma.vm_start = 0xffff0000; - gate_vma.vm_end = 0xffff0000 + PAGE_SIZE; - gate_vma.vm_page_prot = PAGE_READONLY_EXEC; - gate_vma.vm_flags = VM_READ | VM_EXEC | - VM_MAYREAD | VM_MAYEXEC; - return 0; -} -arch_initcall(gate_vma_init); - -struct vm_area_struct *get_gate_vma(struct mm_struct *mm) -{ - return &gate_vma; -} - -int in_gate_area(struct mm_struct *mm, unsigned long addr) -{ - return (addr >= gate_vma.vm_start) && (addr < gate_vma.vm_end); -} - -int in_gate_area_no_mm(unsigned long addr) -{ - return in_gate_area(NULL, addr); + struct mm_struct *mm = current->mm; + return install_special_mapping(mm, 0xffff0000, PAGE_SIZE, + VM_READ | VM_EXEC | + VM_MAYREAD | VM_MAYEXEC | VM_RESERVED, + NULL); } const char *arch_vma_name(struct vm_area_struct *vma) { - return (vma == &gate_vma) ? "[vectors]" : NULL; + return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL; } #endif diff --git a/trunk/arch/arm/kernel/sched_clock.c b/trunk/arch/arm/kernel/sched_clock.c index 27d186abbc06..5416c7c12528 100644 --- a/trunk/arch/arm/kernel/sched_clock.c +++ b/trunk/arch/arm/kernel/sched_clock.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include @@ -165,20 +164,3 @@ void __init sched_clock_postinit(void) sched_clock_poll(sched_clock_timer.data); } - -static int sched_clock_suspend(void) -{ - sched_clock_poll(sched_clock_timer.data); - return 0; -} - -static struct syscore_ops sched_clock_ops = { - .suspend = sched_clock_suspend, -}; - -static int __init sched_clock_syscore_init(void) -{ - register_syscore_ops(&sched_clock_ops); - return 0; -} -device_initcall(sched_clock_syscore_init); diff --git a/trunk/arch/arm/kernel/setup.c b/trunk/arch/arm/kernel/setup.c index b91411371ae1..9e0fdb3a1988 100644 --- a/trunk/arch/arm/kernel/setup.c +++ b/trunk/arch/arm/kernel/setup.c @@ -976,6 +976,7 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif #endif + early_trap_init(); if (mdesc->init_early) mdesc->init_early(); diff --git a/trunk/arch/arm/kernel/signal.c b/trunk/arch/arm/kernel/signal.c index 7cb532fc8aa4..9e617bd4a146 100644 --- a/trunk/arch/arm/kernel/signal.c +++ b/trunk/arch/arm/kernel/signal.c @@ -66,13 +66,12 @@ const unsigned long syscall_restart_code[2] = { */ asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask) { - sigset_t blocked; - - current->saved_sigmask = current->blocked; - mask &= _BLOCKABLE; - siginitset(&blocked, mask); - set_current_blocked(&blocked); + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); @@ -281,7 +280,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf) err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set)); if (err == 0) { sigdelsetmask(&set, ~_BLOCKABLE); - set_current_blocked(&set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } __get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err); @@ -634,7 +636,13 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, /* * Block the signal if we were successful. */ - block_sigmask(ka, sig); + spin_lock_irq(&tsk->sighand->siglock); + sigorsets(&tsk->blocked, &tsk->blocked, + &ka->sa.sa_mask); + if (!(ka->sa.sa_flags & SA_NODEFER)) + sigaddset(&tsk->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(&tsk->sighand->siglock); return 0; } diff --git a/trunk/arch/arm/kernel/smp.c b/trunk/arch/arm/kernel/smp.c index 2cee7d1eb958..8f8cce2c46c4 100644 --- a/trunk/arch/arm/kernel/smp.c +++ b/trunk/arch/arm/kernel/smp.c @@ -58,8 +58,6 @@ enum ipi_msg_type { IPI_CPU_STOP, }; -static DECLARE_COMPLETION(cpu_running); - int __cpuinit __cpu_up(unsigned int cpu) { struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu); @@ -100,12 +98,20 @@ int __cpuinit __cpu_up(unsigned int cpu) */ ret = boot_secondary(cpu, idle); if (ret == 0) { + unsigned long timeout; + /* * CPU was successfully started, wait for it * to come online or time out. */ - wait_for_completion_timeout(&cpu_running, - msecs_to_jiffies(1000)); + timeout = jiffies + HZ; + while (time_before(jiffies, timeout)) { + if (cpu_online(cpu)) + break; + + udelay(10); + barrier(); + } if (!cpu_online(cpu)) { pr_crit("CPU%u: failed to come online\n", cpu); @@ -282,10 +288,9 @@ asmlinkage void __cpuinit secondary_start_kernel(void) /* * OK, now it's safe to let the boot CPU continue. Wait for * the CPU migration code to notice that the CPU is online - * before we continue - which happens after __cpu_up returns. + * before we continue. */ set_cpu_online(cpu, true); - complete(&cpu_running); /* * Setup the percpu timer for this CPU. diff --git a/trunk/arch/arm/kernel/time.c b/trunk/arch/arm/kernel/time.c index fe31b22f18fd..8c57dd3680e9 100644 --- a/trunk/arch/arm/kernel/time.c +++ b/trunk/arch/arm/kernel/time.c @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -147,6 +149,8 @@ void __init time_init(void) { system_timer = machine_desc->timer; system_timer->init(); +#ifdef CONFIG_HAVE_SCHED_CLOCK sched_clock_postinit(); +#endif } diff --git a/trunk/arch/arm/kernel/traps.c b/trunk/arch/arm/kernel/traps.c index 778454750a6c..cd77743472a2 100644 --- a/trunk/arch/arm/kernel/traps.c +++ b/trunk/arch/arm/kernel/traps.c @@ -227,11 +227,6 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) #else #define S_SMP "" #endif -#ifdef CONFIG_THUMB2_KERNEL -#define S_ISA " THUMB2" -#else -#define S_ISA " ARM" -#endif static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) { @@ -239,8 +234,8 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt static int die_counter; int ret; - printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP - S_ISA "\n", str, err, ++die_counter); + printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", + str, err, ++die_counter); /* trap and error numbers are mostly meaningless on ARM */ ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV); @@ -789,16 +784,18 @@ static void __init kuser_get_tls_init(unsigned long vectors) memcpy((void *)vectors + 0xfe0, (void *)vectors + 0xfe8, 4); } -void __init early_trap_init(void *vectors_base) +void __init early_trap_init(void) { - unsigned long vectors = (unsigned long)vectors_base; +#if defined(CONFIG_CPU_USE_DOMAINS) + unsigned long vectors = CONFIG_VECTORS_BASE; +#else + unsigned long vectors = (unsigned long)vectors_page; +#endif extern char __stubs_start[], __stubs_end[]; extern char __vectors_start[], __vectors_end[]; extern char __kuser_helper_start[], __kuser_helper_end[]; int kuser_sz = __kuser_helper_end - __kuser_helper_start; - vectors_page = vectors_base; - /* * Copy the vectors, stubs and kuser helpers (in entry-armv.S) * into the vector page, mapped at 0xffff0000, and ensure these diff --git a/trunk/arch/arm/mach-at91/at91sam9g45_devices.c b/trunk/arch/arm/mach-at91/at91sam9g45_devices.c index 698479f1e197..4320b2096789 100644 --- a/trunk/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/trunk/arch/arm/mach-at91/at91sam9g45_devices.c @@ -437,6 +437,7 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) /* DMA slave channel configuration */ atslave->dma_dev = &at_hdmac_device.dev; + atslave->reg_width = AT_DMA_SLAVE_WIDTH_32BIT; atslave->cfg = ATC_FIFOCFG_HALFFIFO | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW; atslave->ctrla = ATC_SCSIZE_16 | ATC_DCSIZE_16; diff --git a/trunk/arch/arm/mach-at91/include/mach/at_hdmac.h b/trunk/arch/arm/mach-at91/include/mach/at_hdmac.h index fff48d1a0f4e..187cb58345c0 100644 --- a/trunk/arch/arm/mach-at91/include/mach/at_hdmac.h +++ b/trunk/arch/arm/mach-at91/include/mach/at_hdmac.h @@ -23,6 +23,18 @@ struct at_dma_platform_data { dma_cap_mask_t cap_mask; }; +/** + * enum at_dma_slave_width - DMA slave register access width. + * @AT_DMA_SLAVE_WIDTH_8BIT: Do 8-bit slave register accesses + * @AT_DMA_SLAVE_WIDTH_16BIT: Do 16-bit slave register accesses + * @AT_DMA_SLAVE_WIDTH_32BIT: Do 32-bit slave register accesses + */ +enum at_dma_slave_width { + AT_DMA_SLAVE_WIDTH_8BIT = 0, + AT_DMA_SLAVE_WIDTH_16BIT, + AT_DMA_SLAVE_WIDTH_32BIT, +}; + /** * struct at_dma_slave - Controller-specific information about a slave * @dma_dev: required DMA master device @@ -36,6 +48,9 @@ struct at_dma_platform_data { */ struct at_dma_slave { struct device *dma_dev; + dma_addr_t tx_reg; + dma_addr_t rx_reg; + enum at_dma_slave_width reg_width; u32 cfg; u32 ctrla; }; diff --git a/trunk/arch/arm/mach-at91/include/mach/io.h b/trunk/arch/arm/mach-at91/include/mach/io.h new file mode 100644 index 000000000000..4003001eca3d --- /dev/null +++ b/trunk/arch/arm/mach-at91/include/mach/io.h @@ -0,0 +1,31 @@ +/* + * arch/arm/mach-at91/include/mach/io.h + * + * Copyright (C) 2003 SAN People + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_ARCH_IO_H +#define __ASM_ARCH_IO_H + +#include + +#define IO_SPACE_LIMIT 0xFFFFFFFF + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/trunk/arch/arm/mach-at91/include/mach/uncompress.h b/trunk/arch/arm/mach-at91/include/mach/uncompress.h index 4218647c1fcd..0234fd9d20d6 100644 --- a/trunk/arch/arm/mach-at91/include/mach/uncompress.h +++ b/trunk/arch/arm/mach-at91/include/mach/uncompress.h @@ -23,7 +23,6 @@ #include #include -#include #if defined(CONFIG_AT91_EARLY_DBGU0) #define UART_OFFSET AT91_BASE_DBGU0 diff --git a/trunk/arch/arm/mach-bcmring/include/mach/io.h b/trunk/arch/arm/mach-bcmring/include/mach/io.h new file mode 100644 index 000000000000..dae5e9b166ea --- /dev/null +++ b/trunk/arch/arm/mach-bcmring/include/mach/io.h @@ -0,0 +1,33 @@ +/* + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#include + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/trunk/arch/arm/mach-clps711x/include/mach/io.h b/trunk/arch/arm/mach-clps711x/include/mach/io.h new file mode 100644 index 000000000000..2e0b3ced8f07 --- /dev/null +++ b/trunk/arch/arm/mach-clps711x/include/mach/io.h @@ -0,0 +1,36 @@ +/* + * arch/arm/mach-clps711x/include/mach/io.h + * + * Copyright (C) 1999 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +/* + * We don't support ins[lb]/outs[lb]. Make them fault. + */ +#define __raw_readsb(p,d,l) do { *(int *)0 = 0; } while (0) +#define __raw_readsl(p,d,l) do { *(int *)0 = 0; } while (0) +#define __raw_writesb(p,d,l) do { *(int *)0 = 0; } while (0) +#define __raw_writesl(p,d,l) do { *(int *)0 = 0; } while (0) + +#endif diff --git a/trunk/arch/arm/mach-clps711x/include/mach/uncompress.h b/trunk/arch/arm/mach-clps711x/include/mach/uncompress.h index 35ed731b9f16..7164310dea7c 100644 --- a/trunk/arch/arm/mach-clps711x/include/mach/uncompress.h +++ b/trunk/arch/arm/mach-clps711x/include/mach/uncompress.h @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include #include #include diff --git a/trunk/arch/arm/mach-cns3xxx/core.c b/trunk/arch/arm/mach-cns3xxx/core.c index 031805b1428d..941a308e1253 100644 --- a/trunk/arch/arm/mach-cns3xxx/core.c +++ b/trunk/arch/arm/mach-cns3xxx/core.c @@ -72,13 +72,13 @@ void __init cns3xxx_map_io(void) /* used by entry-macro.S */ void __init cns3xxx_init_irq(void) { - gic_init(0, 29, IOMEM(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT), - IOMEM(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT)); + gic_init(0, 29, __io(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT), + __io(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT)); } void cns3xxx_power_off(void) { - u32 __iomem *pm_base = IOMEM(CNS3XXX_PM_BASE_VIRT); + u32 __iomem *pm_base = __io(CNS3XXX_PM_BASE_VIRT); u32 clkctrl; printk(KERN_INFO "powering system down...\n"); @@ -237,7 +237,7 @@ static void __init __cns3xxx_timer_init(unsigned int timer_irq) static void __init cns3xxx_timer_init(void) { - cns3xxx_tmr1 = IOMEM(CNS3XXX_TIMER1_2_3_BASE_VIRT); + cns3xxx_tmr1 = __io(CNS3XXX_TIMER1_2_3_BASE_VIRT); __cns3xxx_timer_init(IRQ_CNS3XXX_TIMER0); } diff --git a/trunk/arch/arm/mach-cns3xxx/devices.c b/trunk/arch/arm/mach-cns3xxx/devices.c index 1e40c99b015f..79d1fb02c23f 100644 --- a/trunk/arch/arm/mach-cns3xxx/devices.c +++ b/trunk/arch/arm/mach-cns3xxx/devices.c @@ -98,7 +98,7 @@ static struct platform_device cns3xxx_sdhci_pdev = { void __init cns3xxx_sdhci_init(void) { - u32 __iomem *gpioa = IOMEM(CNS3XXX_MISC_BASE_VIRT + 0x0014); + u32 __iomem *gpioa = __io(CNS3XXX_MISC_BASE_VIRT + 0x0014); u32 gpioa_pins = __raw_readl(gpioa); /* MMC/SD pins share with GPIOA */ diff --git a/trunk/arch/arm/mach-cns3xxx/include/mach/io.h b/trunk/arch/arm/mach-cns3xxx/include/mach/io.h new file mode 100644 index 000000000000..33b6fc1ece7c --- /dev/null +++ b/trunk/arch/arm/mach-cns3xxx/include/mach/io.h @@ -0,0 +1,17 @@ +/* + * Copyright 2008 Cavium Networks + * Copyright 2003 ARM Limited + * + * This file 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. + */ +#ifndef __MACH_IO_H +#define __MACH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S b/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S index 768b3c060214..c1661d2feca9 100644 --- a/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S +++ b/trunk/arch/arm/mach-davinci/include/mach/entry-macro.S @@ -8,6 +8,7 @@ * is licensed "as is" without any warranty of any kind, whether express * or implied. */ +#include #include .macro get_irqnr_preamble, base, tmp diff --git a/trunk/arch/arm/mach-davinci/include/mach/hardware.h b/trunk/arch/arm/mach-davinci/include/mach/hardware.h index 2184691ebc2f..0209b1fc22a1 100644 --- a/trunk/arch/arm/mach-davinci/include/mach/hardware.h +++ b/trunk/arch/arm/mach-davinci/include/mach/hardware.h @@ -30,4 +30,10 @@ #define __IO_ADDRESS(x) ((x) + IO_OFFSET) #define IO_ADDRESS(pa) IOMEM(__IO_ADDRESS(pa)) +#ifdef __ASSEMBLER__ +#define IOMEM(x) x +#else +#define IOMEM(x) ((void __force __iomem *)(x)) +#endif + #endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/trunk/arch/arm/mach-davinci/include/mach/io.h b/trunk/arch/arm/mach-davinci/include/mach/io.h new file mode 100644 index 000000000000..b2267d1e1a71 --- /dev/null +++ b/trunk/arch/arm/mach-davinci/include/mach/io.h @@ -0,0 +1,24 @@ +/* + * DaVinci IO address definitions + * + * Copied from include/asm/arm/arch-omap/io.h + * + * 2007 (c) MontaVista Software, Inc. This file is licensed under + * the terms of the GNU General Public License version 2. This program + * is licensed "as is" without any warranty of any kind, whether express + * or implied. + */ +#ifndef __ASM_ARCH_IO_H +#define __ASM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We don't actually have real ISA nor PCI buses, but there is so many + * drivers out there that might just work if we fake them... + */ +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) + +#endif /* __ASM_ARCH_IO_H */ diff --git a/trunk/arch/arm/mach-davinci/include/mach/uncompress.h b/trunk/arch/arm/mach-davinci/include/mach/uncompress.h index da2fb2c2155a..9dc7cf9664fe 100644 --- a/trunk/arch/arm/mach-davinci/include/mach/uncompress.h +++ b/trunk/arch/arm/mach-davinci/include/mach/uncompress.h @@ -25,8 +25,6 @@ #include -#define IOMEM(x) ((void __force __iomem *)(x)) - u32 *uart; /* PORT_16C550A, in polled non-fifo mode */ diff --git a/trunk/arch/arm/mach-davinci/time.c b/trunk/arch/arm/mach-davinci/time.c index 75da315b6587..e1969ce904dc 100644 --- a/trunk/arch/arm/mach-davinci/time.c +++ b/trunk/arch/arm/mach-davinci/time.c @@ -19,14 +19,11 @@ #include #include -#include +#include #include #include - #include -#include #include - #include "clock.h" static struct clock_event_device clockevent_davinci; @@ -275,9 +272,19 @@ static cycle_t read_cycles(struct clocksource *cs) return (cycles_t)timer32_read(t); } +/* + * Kernel assumes that sched_clock can be called early but may not have + * things ready yet. + */ +static cycle_t read_dummy(struct clocksource *cs) +{ + return 0; +} + + static struct clocksource clocksource_davinci = { .rating = 300, - .read = read_cycles, + .read = read_dummy, .mask = CLOCKSOURCE_MASK(32), .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -285,9 +292,12 @@ static struct clocksource clocksource_davinci = { /* * Overwrite weak default sched_clock with something more precise */ -static u32 notrace davinci_read_sched_clock(void) +unsigned long long notrace sched_clock(void) { - return timer32_read(&timers[TID_CLOCKSOURCE]); + const cycle_t cyc = clocksource_davinci.read(&clocksource_davinci); + + return clocksource_cyc2ns(cyc, clocksource_davinci.mult, + clocksource_davinci.shift); } /* @@ -387,14 +397,12 @@ static void __init davinci_timer_init(void) davinci_clock_tick_rate = clk_get_rate(timer_clk); /* setup clocksource */ + clocksource_davinci.read = read_cycles; clocksource_davinci.name = id_to_name[clocksource_id]; if (clocksource_register_hz(&clocksource_davinci, davinci_clock_tick_rate)) printk(err, clocksource_davinci.name); - setup_sched_clock(davinci_read_sched_clock, 32, - davinci_clock_tick_rate); - /* setup clockevent */ clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id]; clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC, diff --git a/trunk/arch/arm/mach-dove/addr-map.c b/trunk/arch/arm/mach-dove/addr-map.c index 2a06c0163418..98b8c83b09ab 100644 --- a/trunk/arch/arm/mach-dove/addr-map.c +++ b/trunk/arch/arm/mach-dove/addr-map.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "common.h" diff --git a/trunk/arch/arm/mach-dove/include/mach/io.h b/trunk/arch/arm/mach-dove/include/mach/io.h index 29c8b85355a5..eb4936ff90ad 100644 --- a/trunk/arch/arm/mach-dove/include/mach/io.h +++ b/trunk/arch/arm/mach-dove/include/mach/io.h @@ -15,5 +15,6 @@ #define __io(a) ((void __iomem *)(((a) - DOVE_PCIE0_IO_BUS_BASE) + \ DOVE_PCIE0_IO_VIRT_BASE)) +#define __mem_pci(a) (a) #endif diff --git a/trunk/arch/arm/mach-ebsa110/core.c b/trunk/arch/arm/mach-ebsa110/core.c index 6f8068692edf..8c9f56a3e8ec 100644 --- a/trunk/arch/arm/mach-ebsa110/core.c +++ b/trunk/arch/arm/mach-ebsa110/core.c @@ -116,20 +116,6 @@ static void __init ebsa110_map_io(void) iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc)); } -static void __iomem *ebsa110_ioremap_caller(unsigned long cookie, size_t size, - unsigned int flags, void *caller) -{ - return (void __iomem *)cookie; -} - -static void ebsa110_iounmap(volatile void __iomem *io_addr) -{} - -static void __init ebsa110_init_early(void) -{ - arch_ioremap_caller = ebsa110_ioremap_caller; - arch_iounmap = ebsa110_iounmap; -} #define PIT_CTRL (PIT_BASE + 0x0d) #define PIT_T2 (PIT_BASE + 0x09) @@ -326,7 +312,6 @@ MACHINE_START(EBSA110, "EBSA110") .reserve_lp2 = 1, .restart_mode = 's', .map_io = ebsa110_map_io, - .init_early = ebsa110_init_early, .init_irq = ebsa110_init_irq, .timer = &ebsa110_timer, .restart = ebsa110_restart, diff --git a/trunk/arch/arm/mach-ebsa110/include/mach/io.h b/trunk/arch/arm/mach-ebsa110/include/mach/io.h index 11bb0799424b..44679db672fb 100644 --- a/trunk/arch/arm/mach-ebsa110/include/mach/io.h +++ b/trunk/arch/arm/mach-ebsa110/include/mach/io.h @@ -62,6 +62,15 @@ void __writel(u32 val, void __iomem *addr); #define writew(v,b) __writew(v,b) #define writel(v,b) __writel(v,b) +static inline void __iomem *__arch_ioremap(unsigned long cookie, size_t size, + unsigned int flags) +{ + return (void __iomem *)cookie; +} + +#define __arch_ioremap __arch_ioremap +#define __arch_iounmap(cookie) do { } while (0) + extern void insb(unsigned int port, void *buf, int sz); extern void insw(unsigned int port, void *buf, int sz); extern void insl(unsigned int port, void *buf, int sz); diff --git a/trunk/arch/arm/mach-ep93xx/include/mach/io.h b/trunk/arch/arm/mach-ep93xx/include/mach/io.h new file mode 100644 index 000000000000..594b77f21054 --- /dev/null +++ b/trunk/arch/arm/mach-ep93xx/include/mach/io.h @@ -0,0 +1,22 @@ +/* + * arch/arm/mach-ep93xx/include/mach/io.h + */ + +#ifndef __ASM_MACH_IO_H +#define __ASM_MACH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(p) __typesafe_io(p) +#define __mem_pci(p) (p) + +/* + * A typesafe __io() variation for variable initialisers + */ +#ifdef __ASSEMBLER__ +#define IOMEM(p) p +#else +#define IOMEM(p) ((void __iomem __force *)(p)) +#endif + +#endif /* __ASM_MACH_IO_H */ diff --git a/trunk/arch/arm/mach-exynos/include/mach/io.h b/trunk/arch/arm/mach-exynos/include/mach/io.h new file mode 100644 index 000000000000..d5478d247535 --- /dev/null +++ b/trunk/arch/arm/mach-exynos/include/mach/io.h @@ -0,0 +1,26 @@ +/* linux/arch/arm/mach-exynos4/include/mach/io.h + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Copyright 2008-2010 Ben Dooks + * + * Based on arch/arm/mach-s5p6442/include/mach/io.h + * + * Default IO routines for EXYNOS4 + * + * 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. +*/ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H __FILE__ + +/* No current ISA/PCI bus support. */ +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#define IO_SPACE_LIMIT (0xFFFFFFFF) + +#endif /* __ASM_ARM_ARCH_IO_H */ diff --git a/trunk/arch/arm/mach-footbridge/include/mach/io.h b/trunk/arch/arm/mach-footbridge/include/mach/io.h index aba531eebbc6..15a70396c27d 100644 --- a/trunk/arch/arm/mach-footbridge/include/mach/io.h +++ b/trunk/arch/arm/mach-footbridge/include/mach/io.h @@ -27,5 +27,18 @@ * Translation of various region addresses to virtual addresses */ #define __io(a) ((void __iomem *)(PCIO_BASE + (a))) +#if 1 +#define __mem_pci(a) (a) +#else + +static inline void __iomem *___mem_pci(void __iomem *p) +{ + unsigned long a = (unsigned long)p; + BUG_ON(a <= 0xc0000000 || a >= 0xe0000000); + return p; +} + +#define __mem_pci(a) ___mem_pci(a) +#endif #endif diff --git a/trunk/arch/arm/mach-gemini/include/mach/io.h b/trunk/arch/arm/mach-gemini/include/mach/io.h new file mode 100644 index 000000000000..c548056b98b2 --- /dev/null +++ b/trunk/arch/arm/mach-gemini/include/mach/io.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2001-2006 Storlink, Corp. + * Copyright (C) 2008-2009 Paulius Zaleckas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __MACH_IO_H +#define __MACH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif /* __MACH_IO_H */ diff --git a/trunk/arch/arm/mach-h720x/include/mach/io.h b/trunk/arch/arm/mach-h720x/include/mach/io.h new file mode 100644 index 000000000000..2c8659c21a93 --- /dev/null +++ b/trunk/arch/arm/mach-h720x/include/mach/io.h @@ -0,0 +1,22 @@ +/* + * arch/arm/mach-h720x/include/mach/io.h + * + * Copyright (C) 2000 Steve Hill (sjhill@cotw.com) + * + * Changelog: + * + * 09-19-2001 JJKIM + * Created from arch/arm/mach-l7200/include/mach/io.h + * + * 03-27-2003 Robert Schwebel : + * re-unified header files for h720x + */ +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/trunk/arch/arm/mach-highbank/highbank.c b/trunk/arch/arm/mach-highbank/highbank.c index 410a112bb52e..808b055289b2 100644 --- a/trunk/arch/arm/mach-highbank/highbank.c +++ b/trunk/arch/arm/mach-highbank/highbank.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "core.h" #include "sysregs.h" diff --git a/trunk/arch/arm/mach-highbank/include/mach/io.h b/trunk/arch/arm/mach-highbank/include/mach/io.h new file mode 100644 index 000000000000..70cfa3ba7697 --- /dev/null +++ b/trunk/arch/arm/mach-highbank/include/mach/io.h @@ -0,0 +1,7 @@ +#ifndef __MACH_IO_H +#define __MACH_IO_H + +#define __io(a) ({ (void)(a); __typesafe_io(0); }) +#define __mem_pci(a) (a) + +#endif diff --git a/trunk/arch/arm/mach-highbank/include/mach/irqs.h b/trunk/arch/arm/mach-highbank/include/mach/irqs.h new file mode 100644 index 000000000000..9746aab14e9a --- /dev/null +++ b/trunk/arch/arm/mach-highbank/include/mach/irqs.h @@ -0,0 +1,6 @@ +#ifndef __MACH_IRQS_H +#define __MACH_IRQS_H + +#define NR_IRQS 192 + +#endif diff --git a/trunk/arch/arm/mach-imx/Kconfig b/trunk/arch/arm/mach-imx/Kconfig index 7561eca131b0..52359f80c42d 100644 --- a/trunk/arch/arm/mach-imx/Kconfig +++ b/trunk/arch/arm/mach-imx/Kconfig @@ -1,3 +1,6 @@ +config IMX_HAVE_DMA_V1 + bool + config HAVE_IMX_GPC bool @@ -35,6 +38,7 @@ config SOC_IMX1 bool select ARCH_MX1 select CPU_ARM920T + select IMX_HAVE_DMA_V1 select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -42,6 +46,7 @@ config SOC_IMX21 bool select MACH_MX21 select CPU_ARM926T + select IMX_HAVE_DMA_V1 select IMX_HAVE_IOMUX_V1 select MXC_AVIC @@ -56,6 +61,7 @@ config SOC_IMX27 bool select MACH_MX27 select CPU_ARM926T + select IMX_HAVE_DMA_V1 select IMX_HAVE_IOMUX_V1 select MXC_AVIC diff --git a/trunk/arch/arm/mach-imx/Makefile b/trunk/arch/arm/mach-imx/Makefile index ab939c5046c3..35fc450fa263 100644 --- a/trunk/arch/arm/mach-imx/Makefile +++ b/trunk/arch/arm/mach-imx/Makefile @@ -1,3 +1,5 @@ +obj-$(CONFIG_IMX_HAVE_DMA_V1) += dma-v1.o + obj-$(CONFIG_SOC_IMX1) += clock-imx1.o mm-imx1.o obj-$(CONFIG_SOC_IMX21) += clock-imx21.o mm-imx21.o diff --git a/trunk/arch/arm/mach-imx/dma-v1.c b/trunk/arch/arm/mach-imx/dma-v1.c new file mode 100644 index 000000000000..3189a6004cf9 --- /dev/null +++ b/trunk/arch/arm/mach-imx/dma-v1.c @@ -0,0 +1,845 @@ +/* + * linux/arch/arm/plat-mxc/dma-v1.c + * + * i.MX DMA registration and IRQ dispatching + * + * Copyright 2006 Pavel Pisa + * Copyright 2008 Juergen Beisert, + * Copyright 2008 Sascha Hauer, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DMA_DCR 0x00 /* Control Register */ +#define DMA_DISR 0x04 /* Interrupt status Register */ +#define DMA_DIMR 0x08 /* Interrupt mask Register */ +#define DMA_DBTOSR 0x0c /* Burst timeout status Register */ +#define DMA_DRTOSR 0x10 /* Request timeout Register */ +#define DMA_DSESR 0x14 /* Transfer Error Status Register */ +#define DMA_DBOSR 0x18 /* Buffer overflow status Register */ +#define DMA_DBTOCR 0x1c /* Burst timeout control Register */ +#define DMA_WSRA 0x40 /* W-Size Register A */ +#define DMA_XSRA 0x44 /* X-Size Register A */ +#define DMA_YSRA 0x48 /* Y-Size Register A */ +#define DMA_WSRB 0x4c /* W-Size Register B */ +#define DMA_XSRB 0x50 /* X-Size Register B */ +#define DMA_YSRB 0x54 /* Y-Size Register B */ +#define DMA_SAR(x) (0x80 + ((x) << 6)) /* Source Address Registers */ +#define DMA_DAR(x) (0x84 + ((x) << 6)) /* Destination Address Registers */ +#define DMA_CNTR(x) (0x88 + ((x) << 6)) /* Count Registers */ +#define DMA_CCR(x) (0x8c + ((x) << 6)) /* Control Registers */ +#define DMA_RSSR(x) (0x90 + ((x) << 6)) /* Request source select Registers */ +#define DMA_BLR(x) (0x94 + ((x) << 6)) /* Burst length Registers */ +#define DMA_RTOR(x) (0x98 + ((x) << 6)) /* Request timeout Registers */ +#define DMA_BUCR(x) (0x98 + ((x) << 6)) /* Bus Utilization Registers */ +#define DMA_CCNR(x) (0x9C + ((x) << 6)) /* Channel counter Registers */ + +#define DCR_DRST (1<<1) +#define DCR_DEN (1<<0) +#define DBTOCR_EN (1<<15) +#define DBTOCR_CNT(x) ((x) & 0x7fff) +#define CNTR_CNT(x) ((x) & 0xffffff) +#define CCR_ACRPT (1<<14) +#define CCR_DMOD_LINEAR (0x0 << 12) +#define CCR_DMOD_2D (0x1 << 12) +#define CCR_DMOD_FIFO (0x2 << 12) +#define CCR_DMOD_EOBFIFO (0x3 << 12) +#define CCR_SMOD_LINEAR (0x0 << 10) +#define CCR_SMOD_2D (0x1 << 10) +#define CCR_SMOD_FIFO (0x2 << 10) +#define CCR_SMOD_EOBFIFO (0x3 << 10) +#define CCR_MDIR_DEC (1<<9) +#define CCR_MSEL_B (1<<8) +#define CCR_DSIZ_32 (0x0 << 6) +#define CCR_DSIZ_8 (0x1 << 6) +#define CCR_DSIZ_16 (0x2 << 6) +#define CCR_SSIZ_32 (0x0 << 4) +#define CCR_SSIZ_8 (0x1 << 4) +#define CCR_SSIZ_16 (0x2 << 4) +#define CCR_REN (1<<3) +#define CCR_RPT (1<<2) +#define CCR_FRC (1<<1) +#define CCR_CEN (1<<0) +#define RTOR_EN (1<<15) +#define RTOR_CLK (1<<14) +#define RTOR_PSC (1<<13) + +/* + * struct imx_dma_channel - i.MX specific DMA extension + * @name: name specified by DMA client + * @irq_handler: client callback for end of transfer + * @err_handler: client callback for error condition + * @data: clients context data for callbacks + * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE + * @sg: pointer to the actual read/written chunk for scatter-gather emulation + * @resbytes: total residual number of bytes to transfer + * (it can be lower or same as sum of SG mapped chunk sizes) + * @sgcount: number of chunks to be read/written + * + * Structure is used for IMX DMA processing. It would be probably good + * @struct dma_struct in the future for external interfacing and use + * @struct imx_dma_channel only as extension to it. + */ + +struct imx_dma_channel { + const char *name; + void (*irq_handler) (int, void *); + void (*err_handler) (int, void *, int errcode); + void (*prog_handler) (int, void *, struct scatterlist *); + void *data; + unsigned int dma_mode; + struct scatterlist *sg; + unsigned int resbytes; + int dma_num; + + int in_use; + + u32 ccr_from_device; + u32 ccr_to_device; + + struct timer_list watchdog; + + int hw_chaining; +}; + +static void __iomem *imx_dmav1_baseaddr; + +static void imx_dmav1_writel(unsigned val, unsigned offset) +{ + __raw_writel(val, imx_dmav1_baseaddr + offset); +} + +static unsigned imx_dmav1_readl(unsigned offset) +{ + return __raw_readl(imx_dmav1_baseaddr + offset); +} + +static struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; + +static struct clk *dma_clk; + +static int imx_dma_hw_chain(struct imx_dma_channel *imxdma) +{ + if (cpu_is_mx27()) + return imxdma->hw_chaining; + else + return 0; +} + +/* + * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation + */ +static inline int imx_dma_sg_next(int channel, struct scatterlist *sg) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long now; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return 0; + } + + now = min(imxdma->resbytes, sg->length); + if (imxdma->resbytes != IMX_DMA_LENGTH_LOOP) + imxdma->resbytes -= now; + + if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ) + imx_dmav1_writel(sg->dma_address, DMA_DAR(channel)); + else + imx_dmav1_writel(sg->dma_address, DMA_SAR(channel)); + + imx_dmav1_writel(now, DMA_CNTR(channel)); + + pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, " + "size 0x%08x\n", channel, + imx_dmav1_readl(DMA_DAR(channel)), + imx_dmav1_readl(DMA_SAR(channel)), + imx_dmav1_readl(DMA_CNTR(channel))); + + return now; +} + +/** + * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from + * device transfer + * + * @channel: i.MX DMA channel number + * @dma_address: the DMA/physical memory address of the linear data block + * to transfer + * @dma_length: length of the data block in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_single(int channel, dma_addr_t dma_address, + unsigned int dma_length, unsigned int dev_addr, + unsigned int dmamode) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + + imxdma->sg = NULL; + imxdma->dma_mode = dmamode; + + if (!dma_address) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n", + channel); + return -EINVAL; + } + + if (!dma_length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n", + channel); + return -EINVAL; + } + + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d " + "dev_addr=0x%08x for read\n", + channel, __func__, (unsigned int)dma_address, + dma_length, dev_addr); + + imx_dmav1_writel(dev_addr, DMA_SAR(channel)); + imx_dmav1_writel(dma_address, DMA_DAR(channel)); + imx_dmav1_writel(imxdma->ccr_from_device, DMA_CCR(channel)); + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d " + "dev_addr=0x%08x for write\n", + channel, __func__, (unsigned int)dma_address, + dma_length, dev_addr); + + imx_dmav1_writel(dma_address, DMA_SAR(channel)); + imx_dmav1_writel(dev_addr, DMA_DAR(channel)); + imx_dmav1_writel(imxdma->ccr_to_device, + DMA_CCR(channel)); + } else { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n", + channel); + return -EINVAL; + } + + imx_dmav1_writel(dma_length, DMA_CNTR(channel)); + + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_single); + +/** + * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer + * @channel: i.MX DMA channel number + * @sg: pointer to the scatter-gather list/vector + * @sgcount: scatter-gather list hungs count + * @dma_length: total length of the transfer request in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * The function sets up DMA channel state and registers to be ready for + * transfer specified by provided parameters. The scatter-gather emulation + * is set up according to the parameters. + * + * The full preparation of the transfer requires setup of more register + * by the caller before imx_dma_enable() can be called. + * + * %BLR(channel) holds transfer burst length in bytes, 0 means 64 bytes + * + * %RSSR(channel) has to be set to the DMA request line source %DMA_REQ_xxx + * + * %CCR(channel) has to specify transfer parameters, the next settings is + * typical for linear or simple scatter-gather transfers if %DMA_MODE_READ is + * specified + * + * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x + * + * The typical setup for %DMA_MODE_WRITE is specified by next options + * combination + * + * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x + * + * Be careful here and do not mistakenly mix source and target device + * port sizes constants, they are really different: + * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32, + * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32 + * + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_sg(int channel, + struct scatterlist *sg, unsigned int sgcount, + unsigned int dma_length, unsigned int dev_addr, + unsigned int dmamode) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + + if (imxdma->in_use) + return -EBUSY; + + imxdma->sg = sg; + imxdma->dma_mode = dmamode; + imxdma->resbytes = dma_length; + + if (!sg || !sgcount) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg empty sg list\n", + channel); + return -EINVAL; + } + + if (!sg->length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n", + channel); + return -EINVAL; + } + + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d " + "dev_addr=0x%08x for read\n", + channel, __func__, sg, sgcount, dma_length, dev_addr); + + imx_dmav1_writel(dev_addr, DMA_SAR(channel)); + imx_dmav1_writel(imxdma->ccr_from_device, DMA_CCR(channel)); + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d " + "dev_addr=0x%08x for write\n", + channel, __func__, sg, sgcount, dma_length, dev_addr); + + imx_dmav1_writel(dev_addr, DMA_DAR(channel)); + imx_dmav1_writel(imxdma->ccr_to_device, DMA_CCR(channel)); + } else { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n", + channel); + return -EINVAL; + } + + imx_dma_sg_next(channel, sg); + + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_sg); + +int +imx_dma_config_channel(int channel, unsigned int config_port, + unsigned int config_mem, unsigned int dmareq, int hw_chaining) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + u32 dreq = 0; + + imxdma->hw_chaining = 0; + + if (hw_chaining) { + imxdma->hw_chaining = 1; + if (!imx_dma_hw_chain(imxdma)) + return -EINVAL; + } + + if (dmareq) + dreq = CCR_REN; + + imxdma->ccr_from_device = config_port | (config_mem << 2) | dreq; + imxdma->ccr_to_device = config_mem | (config_port << 2) | dreq; + + imx_dmav1_writel(dmareq, DMA_RSSR(channel)); + + return 0; +} +EXPORT_SYMBOL(imx_dma_config_channel); + +void imx_dma_config_burstlen(int channel, unsigned int burstlen) +{ + imx_dmav1_writel(burstlen, DMA_BLR(channel)); +} +EXPORT_SYMBOL(imx_dma_config_burstlen); + +/** + * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification + * handlers + * @channel: i.MX DMA channel number + * @irq_handler: the pointer to the function called if the transfer + * ends successfully + * @err_handler: the pointer to the function called if the premature + * end caused by error occurs + * @data: user specified value to be passed to the handlers + */ +int +imx_dma_setup_handlers(int channel, + void (*irq_handler) (int, void *), + void (*err_handler) (int, void *, int), + void *data) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return -ENODEV; + } + + local_irq_save(flags); + imx_dmav1_writel(1 << channel, DMA_DISR); + imxdma->irq_handler = irq_handler; + imxdma->err_handler = err_handler; + imxdma->data = data; + local_irq_restore(flags); + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_handlers); + +/** + * imx_dma_setup_progression_handler - setup i.MX DMA channel progression + * handlers + * @channel: i.MX DMA channel number + * @prog_handler: the pointer to the function called if the transfer progresses + */ +int +imx_dma_setup_progression_handler(int channel, + void (*prog_handler) (int, void*, struct scatterlist*)) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return -ENODEV; + } + + local_irq_save(flags); + imxdma->prog_handler = prog_handler; + local_irq_restore(flags); + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_progression_handler); + +/** + * imx_dma_enable - function to start i.MX DMA channel operation + * @channel: i.MX DMA channel number + * + * The channel has to be allocated by driver through imx_dma_request() + * or imx_dma_request_by_prio() function. + * The transfer parameters has to be set to the channel registers through + * call of the imx_dma_setup_single() or imx_dma_setup_sg() function + * and registers %BLR(channel), %RSSR(channel) and %CCR(channel) has to + * be set prior this function call by the channel user. + */ +void imx_dma_enable(int channel) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + pr_debug("imxdma%d: imx_dma_enable\n", channel); + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return; + } + + if (imxdma->in_use) + return; + + local_irq_save(flags); + + imx_dmav1_writel(1 << channel, DMA_DISR); + imx_dmav1_writel(imx_dmav1_readl(DMA_DIMR) & ~(1 << channel), DMA_DIMR); + imx_dmav1_writel(imx_dmav1_readl(DMA_CCR(channel)) | CCR_CEN | + CCR_ACRPT, DMA_CCR(channel)); + + if ((cpu_is_mx21() || cpu_is_mx27()) && + imxdma->sg && imx_dma_hw_chain(imxdma)) { + imxdma->sg = sg_next(imxdma->sg); + if (imxdma->sg) { + u32 tmp; + imx_dma_sg_next(channel, imxdma->sg); + tmp = imx_dmav1_readl(DMA_CCR(channel)); + imx_dmav1_writel(tmp | CCR_RPT | CCR_ACRPT, + DMA_CCR(channel)); + } + } + imxdma->in_use = 1; + + local_irq_restore(flags); +} +EXPORT_SYMBOL(imx_dma_enable); + +/** + * imx_dma_disable - stop, finish i.MX DMA channel operatin + * @channel: i.MX DMA channel number + */ +void imx_dma_disable(int channel) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + pr_debug("imxdma%d: imx_dma_disable\n", channel); + + if (imx_dma_hw_chain(imxdma)) + del_timer(&imxdma->watchdog); + + local_irq_save(flags); + imx_dmav1_writel(imx_dmav1_readl(DMA_DIMR) | (1 << channel), DMA_DIMR); + imx_dmav1_writel(imx_dmav1_readl(DMA_CCR(channel)) & ~CCR_CEN, + DMA_CCR(channel)); + imx_dmav1_writel(1 << channel, DMA_DISR); + imxdma->in_use = 0; + local_irq_restore(flags); +} +EXPORT_SYMBOL(imx_dma_disable); + +static void imx_dma_watchdog(unsigned long chno) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[chno]; + + imx_dmav1_writel(0, DMA_CCR(chno)); + imxdma->in_use = 0; + imxdma->sg = NULL; + + if (imxdma->err_handler) + imxdma->err_handler(chno, imxdma->data, IMX_DMA_ERR_TIMEOUT); +} + +static irqreturn_t dma_err_handler(int irq, void *dev_id) +{ + int i, disr; + struct imx_dma_channel *imxdma; + unsigned int err_mask; + int errcode; + + disr = imx_dmav1_readl(DMA_DISR); + + err_mask = imx_dmav1_readl(DMA_DBTOSR) | + imx_dmav1_readl(DMA_DRTOSR) | + imx_dmav1_readl(DMA_DSESR) | + imx_dmav1_readl(DMA_DBOSR); + + if (!err_mask) + return IRQ_HANDLED; + + imx_dmav1_writel(disr & err_mask, DMA_DISR); + + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + if (!(err_mask & (1 << i))) + continue; + imxdma = &imx_dma_channels[i]; + errcode = 0; + + if (imx_dmav1_readl(DMA_DBTOSR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DBTOSR); + errcode |= IMX_DMA_ERR_BURST; + } + if (imx_dmav1_readl(DMA_DRTOSR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DRTOSR); + errcode |= IMX_DMA_ERR_REQUEST; + } + if (imx_dmav1_readl(DMA_DSESR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DSESR); + errcode |= IMX_DMA_ERR_TRANSFER; + } + if (imx_dmav1_readl(DMA_DBOSR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DBOSR); + errcode |= IMX_DMA_ERR_BUFFER; + } + if (imxdma->name && imxdma->err_handler) { + imxdma->err_handler(i, imxdma->data, errcode); + continue; + } + + imx_dma_channels[i].sg = NULL; + + printk(KERN_WARNING + "DMA timeout on channel %d (%s) -%s%s%s%s\n", + i, imxdma->name, + errcode & IMX_DMA_ERR_BURST ? " burst" : "", + errcode & IMX_DMA_ERR_REQUEST ? " request" : "", + errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "", + errcode & IMX_DMA_ERR_BUFFER ? " buffer" : ""); + } + return IRQ_HANDLED; +} + +static void dma_irq_handle_channel(int chno) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[chno]; + + if (!imxdma->name) { + /* + * IRQ for an unregistered DMA channel: + * let's clear the interrupts and disable it. + */ + printk(KERN_WARNING + "spurious IRQ for DMA channel %d\n", chno); + return; + } + + if (imxdma->sg) { + u32 tmp; + struct scatterlist *current_sg = imxdma->sg; + imxdma->sg = sg_next(imxdma->sg); + + if (imxdma->sg) { + imx_dma_sg_next(chno, imxdma->sg); + + tmp = imx_dmav1_readl(DMA_CCR(chno)); + + if (imx_dma_hw_chain(imxdma)) { + /* FIXME: The timeout should probably be + * configurable + */ + mod_timer(&imxdma->watchdog, + jiffies + msecs_to_jiffies(500)); + + tmp |= CCR_CEN | CCR_RPT | CCR_ACRPT; + imx_dmav1_writel(tmp, DMA_CCR(chno)); + } else { + imx_dmav1_writel(tmp & ~CCR_CEN, DMA_CCR(chno)); + tmp |= CCR_CEN; + } + + imx_dmav1_writel(tmp, DMA_CCR(chno)); + + if (imxdma->prog_handler) + imxdma->prog_handler(chno, imxdma->data, + current_sg); + + return; + } + + if (imx_dma_hw_chain(imxdma)) { + del_timer(&imxdma->watchdog); + return; + } + } + + imx_dmav1_writel(0, DMA_CCR(chno)); + imxdma->in_use = 0; + if (imxdma->irq_handler) + imxdma->irq_handler(chno, imxdma->data); +} + +static irqreturn_t dma_irq_handler(int irq, void *dev_id) +{ + int i, disr; + + if (cpu_is_mx21() || cpu_is_mx27()) + dma_err_handler(irq, dev_id); + + disr = imx_dmav1_readl(DMA_DISR); + + pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n", + disr); + + imx_dmav1_writel(disr, DMA_DISR); + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + if (disr & (1 << i)) + dma_irq_handle_channel(i); + } + + return IRQ_HANDLED; +} + +/** + * imx_dma_request - request/allocate specified channel number + * @channel: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + */ +int imx_dma_request(int channel, const char *name) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + int ret = 0; + + /* basic sanity checks */ + if (!name) + return -EINVAL; + + if (channel >= IMX_DMA_CHANNELS) { + printk(KERN_CRIT "%s: called for non-existed channel %d\n", + __func__, channel); + return -EINVAL; + } + + local_irq_save(flags); + if (imxdma->name) { + local_irq_restore(flags); + return -EBUSY; + } + memset(imxdma, 0, sizeof(*imxdma)); + imxdma->name = name; + local_irq_restore(flags); /* request_irq() can block */ + + if (cpu_is_mx21() || cpu_is_mx27()) { + ret = request_irq(MX2x_INT_DMACH0 + channel, + dma_irq_handler, 0, "DMA", NULL); + if (ret) { + imxdma->name = NULL; + pr_crit("Can't register IRQ %d for DMA channel %d\n", + MX2x_INT_DMACH0 + channel, channel); + return ret; + } + init_timer(&imxdma->watchdog); + imxdma->watchdog.function = &imx_dma_watchdog; + imxdma->watchdog.data = channel; + } + + return ret; +} +EXPORT_SYMBOL(imx_dma_request); + +/** + * imx_dma_free - release previously acquired channel + * @channel: i.MX DMA channel number + */ +void imx_dma_free(int channel) +{ + unsigned long flags; + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + + if (!imxdma->name) { + printk(KERN_CRIT + "%s: trying to free free channel %d\n", + __func__, channel); + return; + } + + local_irq_save(flags); + /* Disable interrupts */ + imx_dma_disable(channel); + imxdma->name = NULL; + + if (cpu_is_mx21() || cpu_is_mx27()) + free_irq(MX2x_INT_DMACH0 + channel, NULL); + + local_irq_restore(flags); +} +EXPORT_SYMBOL(imx_dma_free); + +/** + * imx_dma_request_by_prio - find and request some of free channels best + * suiting requested priority + * @channel: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + * + * This function tries to find a free channel in the specified priority group + * if the priority cannot be achieved it tries to look for free channel + * in the higher and then even lower priority groups. + * + * Return value: If there is no free channel to allocate, -%ENODEV is returned. + * On successful allocation channel is returned. + */ +int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio) +{ + int i; + int best; + + switch (prio) { + case (DMA_PRIO_HIGH): + best = 8; + break; + case (DMA_PRIO_MEDIUM): + best = 4; + break; + case (DMA_PRIO_LOW): + default: + best = 0; + break; + } + + for (i = best; i < IMX_DMA_CHANNELS; i++) + if (!imx_dma_request(i, name)) + return i; + + for (i = best - 1; i >= 0; i--) + if (!imx_dma_request(i, name)) + return i; + + printk(KERN_ERR "%s: no free DMA channel found\n", __func__); + + return -ENODEV; +} +EXPORT_SYMBOL(imx_dma_request_by_prio); + +static int __init imx_dma_init(void) +{ + int ret = 0; + int i; + + if (cpu_is_mx1()) + imx_dmav1_baseaddr = MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR); + else if (cpu_is_mx21()) + imx_dmav1_baseaddr = MX21_IO_ADDRESS(MX21_DMA_BASE_ADDR); + else if (cpu_is_mx27()) + imx_dmav1_baseaddr = MX27_IO_ADDRESS(MX27_DMA_BASE_ADDR); + else + return 0; + + dma_clk = clk_get(NULL, "dma"); + if (IS_ERR(dma_clk)) + return PTR_ERR(dma_clk); + clk_enable(dma_clk); + + /* reset DMA module */ + imx_dmav1_writel(DCR_DRST, DMA_DCR); + + if (cpu_is_mx1()) { + ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", NULL); + if (ret) { + pr_crit("Wow! Can't register IRQ for DMA\n"); + return ret; + } + + ret = request_irq(MX1_DMA_ERR, dma_err_handler, 0, "DMA", NULL); + if (ret) { + pr_crit("Wow! Can't register ERRIRQ for DMA\n"); + free_irq(MX1_DMA_INT, NULL); + return ret; + } + } + + /* enable DMA module */ + imx_dmav1_writel(DCR_DEN, DMA_DCR); + + /* clear all interrupts */ + imx_dmav1_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_DISR); + + /* disable interrupts */ + imx_dmav1_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_DIMR); + + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + imx_dma_channels[i].sg = NULL; + imx_dma_channels[i].dma_num = i; + } + + return ret; +} + +arch_initcall(imx_dma_init); diff --git a/trunk/arch/arm/mach-imx/include/mach/dma-v1.h b/trunk/arch/arm/mach-imx/include/mach/dma-v1.h new file mode 100644 index 000000000000..ac6fd713828a --- /dev/null +++ b/trunk/arch/arm/mach-imx/include/mach/dma-v1.h @@ -0,0 +1,103 @@ +/* + * linux/arch/arm/mach-imx/include/mach/dma-v1.h + * + * i.MX DMA registration and IRQ dispatching + * + * Copyright 2006 Pavel Pisa + * Copyright 2008 Juergen Beisert, + * Copyright 2008 Sascha Hauer, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __MACH_DMA_V1_H__ +#define __MACH_DMA_V1_H__ + +#define imx_has_dma_v1() (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27()) + +#include + +#define IMX_DMA_CHANNELS 16 + +#define DMA_MODE_READ 0 +#define DMA_MODE_WRITE 1 +#define DMA_MODE_MASK 1 + +#define MX1_DMA_REG(offset) MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR + (offset)) + +/* DMA Interrupt Mask Register */ +#define MX1_DMA_DIMR MX1_DMA_REG(0x08) + +/* Channel Control Register */ +#define MX1_DMA_CCR(x) MX1_DMA_REG(0x8c + ((x) << 6)) + +#define IMX_DMA_MEMSIZE_32 (0 << 4) +#define IMX_DMA_MEMSIZE_8 (1 << 4) +#define IMX_DMA_MEMSIZE_16 (2 << 4) +#define IMX_DMA_TYPE_LINEAR (0 << 10) +#define IMX_DMA_TYPE_2D (1 << 10) +#define IMX_DMA_TYPE_FIFO (2 << 10) + +#define IMX_DMA_ERR_BURST (1 << 0) +#define IMX_DMA_ERR_REQUEST (1 << 1) +#define IMX_DMA_ERR_TRANSFER (1 << 2) +#define IMX_DMA_ERR_BUFFER (1 << 3) +#define IMX_DMA_ERR_TIMEOUT (1 << 4) + +int +imx_dma_config_channel(int channel, unsigned int config_port, + unsigned int config_mem, unsigned int dmareq, int hw_chaining); + +void +imx_dma_config_burstlen(int channel, unsigned int burstlen); + +int +imx_dma_setup_single(int channel, dma_addr_t dma_address, + unsigned int dma_length, unsigned int dev_addr, + unsigned int dmamode); + + +/* + * Use this flag as the dma_length argument to imx_dma_setup_sg() + * to create an endless running dma loop. The end of the scatterlist + * must be linked to the beginning for this to work. + */ +#define IMX_DMA_LENGTH_LOOP ((unsigned int)-1) + +int +imx_dma_setup_sg(int channel, struct scatterlist *sg, + unsigned int sgcount, unsigned int dma_length, + unsigned int dev_addr, unsigned int dmamode); + +int +imx_dma_setup_handlers(int channel, + void (*irq_handler) (int, void *), + void (*err_handler) (int, void *, int), void *data); + +int +imx_dma_setup_progression_handler(int channel, + void (*prog_handler) (int, void*, struct scatterlist*)); + +void imx_dma_enable(int channel); + +void imx_dma_disable(int channel); + +int imx_dma_request(int channel, const char *name); + +void imx_dma_free(int channel); + +int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio); + +#endif /* __MACH_DMA_V1_H__ */ diff --git a/trunk/arch/arm/mach-imx/mm-imx3.c b/trunk/arch/arm/mach-imx/mm-imx3.c index d534d7f988e0..f8ca96c354f2 100644 --- a/trunk/arch/arm/mach-imx/mm-imx3.c +++ b/trunk/arch/arm/mach-imx/mm-imx3.c @@ -61,8 +61,8 @@ static void imx3_idle(void) : "=r" (reg)); } -static void __iomem *imx3_ioremap_caller(unsigned long phys_addr, size_t size, - unsigned int mtype, void *caller) +static void __iomem *imx3_ioremap(unsigned long phys_addr, size_t size, + unsigned int mtype) { if (mtype == MT_DEVICE) { /* @@ -75,7 +75,7 @@ static void __iomem *imx3_ioremap_caller(unsigned long phys_addr, size_t size, mtype = MT_DEVICE_NONSHARED; } - return __arm_ioremap_caller(phys_addr, size, mtype, caller); + return __arm_ioremap(phys_addr, size, mtype); } void __init imx3_init_l2x0(void) @@ -134,7 +134,7 @@ void __init imx31_init_early(void) { mxc_set_cpu_type(MXC_CPU_MX31); mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); - arch_ioremap_caller = imx3_ioremap_caller; + imx_ioremap = imx3_ioremap; arm_pm_idle = imx3_idle; } @@ -208,7 +208,7 @@ void __init imx35_init_early(void) mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR)); mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); arm_pm_idle = imx3_idle; - arch_ioremap_caller = imx3_ioremap_caller; + imx_ioremap = imx3_ioremap; } void __init mx35_init_irq(void) diff --git a/trunk/arch/arm/mach-integrator/core.c b/trunk/arch/arm/mach-integrator/core.c index eaf6c6366ffa..1a65d77bd55d 100644 --- a/trunk/arch/arm/mach-integrator/core.c +++ b/trunk/arch/arm/mach-integrator/core.c @@ -25,9 +25,8 @@ #include #include +#include #include -#include - #include #include #include diff --git a/trunk/arch/arm/mach-integrator/include/mach/io.h b/trunk/arch/arm/mach-integrator/include/mach/io.h index 8de70de3dd0a..37beed3fa3ed 100644 --- a/trunk/arch/arm/mach-integrator/include/mach/io.h +++ b/trunk/arch/arm/mach-integrator/include/mach/io.h @@ -29,5 +29,6 @@ #define PCI_IO_VADDR 0xee000000 #define __io(a) ((void __iomem *)(PCI_IO_VADDR + (a))) +#define __mem_pci(a) (a) #endif diff --git a/trunk/arch/arm/mach-integrator/include/mach/irqs.h b/trunk/arch/arm/mach-integrator/include/mach/irqs.h index a19a1a2fcf6b..1fbe6d190222 100644 --- a/trunk/arch/arm/mach-integrator/include/mach/irqs.h +++ b/trunk/arch/arm/mach-integrator/include/mach/irqs.h @@ -78,6 +78,5 @@ #define IRQ_SIC_CP_LMINT7 46 #define IRQ_SIC_END 46 -#define NR_IRQS_INTEGRATOR_AP 34 -#define NR_IRQS_INTEGRATOR_CP 47 +#define NR_IRQS 47 diff --git a/trunk/arch/arm/mach-integrator/integrator_ap.c b/trunk/arch/arm/mach-integrator/integrator_ap.c index 871f148ffd72..21a1d6cbef40 100644 --- a/trunk/arch/arm/mach-integrator/integrator_ap.c +++ b/trunk/arch/arm/mach-integrator/integrator_ap.c @@ -38,13 +38,12 @@ #include #include #include +#include #include #include /* HZ */ #include -#include #include -#include #include #include @@ -326,11 +325,6 @@ static void __init ap_init(void) static unsigned long timer_reload; -static u32 notrace integrator_read_sched_clock(void) -{ - return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE); -} - static void integrator_clocksource_init(unsigned long inrate) { void __iomem *base = (void __iomem *)TIMER2_VA_BASE; @@ -347,7 +341,6 @@ static void integrator_clocksource_init(unsigned long inrate) clocksource_mmio_init(base + TIMER_VALUE, "timer2", rate, 200, 16, clocksource_mmio_readl_down); - setup_sched_clock(integrator_read_sched_clock, 16, rate); } static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE; @@ -475,7 +468,6 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator") .atag_offset = 0x100, .reserve = integrator_reserve, .map_io = ap_map_io, - .nr_irqs = NR_IRQS_INTEGRATOR_AP, .init_early = integrator_init_early, .init_irq = ap_init_irq, .timer = &ap_timer, diff --git a/trunk/arch/arm/mach-integrator/integrator_cp.c b/trunk/arch/arm/mach-integrator/integrator_cp.c index 48a115a91d9d..be9ead4a3bcc 100644 --- a/trunk/arch/arm/mach-integrator/integrator_cp.c +++ b/trunk/arch/arm/mach-integrator/integrator_cp.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include -#include #include #include @@ -464,7 +464,6 @@ MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP") .atag_offset = 0x100, .reserve = integrator_reserve, .map_io = intcp_map_io, - .nr_irqs = NR_IRQS_INTEGRATOR_CP, .init_early = intcp_init_early, .init_irq = intcp_init_irq, .timer = &cp_timer, diff --git a/trunk/arch/arm/mach-integrator/pci.c b/trunk/arch/arm/mach-integrator/pci.c index f1ca9c122861..36068f438f2b 100644 --- a/trunk/arch/arm/mach-integrator/pci.c +++ b/trunk/arch/arm/mach-integrator/pci.c @@ -26,11 +26,10 @@ #include #include +#include #include #include -#include - /* * A small note about bridges and interrupts. The DECchip 21050 (and * later) adheres to the PCI-PCI bridge specification. This says that diff --git a/trunk/arch/arm/mach-integrator/pci_v3.c b/trunk/arch/arm/mach-integrator/pci_v3.c index 67e6f9a9d1a0..4be172c3cbe0 100644 --- a/trunk/arch/arm/mach-integrator/pci_v3.c +++ b/trunk/arch/arm/mach-integrator/pci_v3.c @@ -30,8 +30,7 @@ #include #include -#include - +#include #include #include #include diff --git a/trunk/arch/arm/mach-iop13xx/include/mach/io.h b/trunk/arch/arm/mach-iop13xx/include/mach/io.h index f13188518025..dffb234bb967 100644 --- a/trunk/arch/arm/mach-iop13xx/include/mach/io.h +++ b/trunk/arch/arm/mach-iop13xx/include/mach/io.h @@ -22,7 +22,20 @@ #define IO_SPACE_LIMIT 0xffffffff #define __io(a) __iop13xx_io(a) +#define __mem_pci(a) (a) +#define __mem_isa(a) (a) extern void __iomem * __iop13xx_io(unsigned long io_addr); +extern void __iomem *__iop13xx_ioremap(unsigned long cookie, size_t size, + unsigned int mtype); +extern void __iop13xx_iounmap(void __iomem *addr); + +extern u32 iop13xx_atue_mem_base; +extern u32 iop13xx_atux_mem_base; +extern size_t iop13xx_atue_mem_size; +extern size_t iop13xx_atux_mem_size; + +#define __arch_ioremap __iop13xx_ioremap +#define __arch_iounmap __iop13xx_iounmap #endif diff --git a/trunk/arch/arm/mach-iop13xx/include/mach/iop13xx.h b/trunk/arch/arm/mach-iop13xx/include/mach/iop13xx.h index e190dcd7d72d..07e9ff7adafb 100644 --- a/trunk/arch/arm/mach-iop13xx/include/mach/iop13xx.h +++ b/trunk/arch/arm/mach-iop13xx/include/mach/iop13xx.h @@ -5,7 +5,6 @@ /* The ATU offsets can change based on the strapping */ extern u32 iop13xx_atux_pmmr_offset; extern u32 iop13xx_atue_pmmr_offset; -void iop13xx_init_early(void); void iop13xx_init_irq(void); void iop13xx_map_io(void); void iop13xx_platform_init(void); diff --git a/trunk/arch/arm/mach-iop13xx/io.c b/trunk/arch/arm/mach-iop13xx/io.c index 3c364198db9c..48642e66c566 100644 --- a/trunk/arch/arm/mach-iop13xx/io.c +++ b/trunk/arch/arm/mach-iop13xx/io.c @@ -21,8 +21,6 @@ #include #include -#include "pci.h" - void * __iomem __iop13xx_io(unsigned long io_addr) { void __iomem * io_virt; @@ -42,8 +40,8 @@ void * __iomem __iop13xx_io(unsigned long io_addr) } EXPORT_SYMBOL(__iop13xx_io); -static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie, - size_t size, unsigned int mtype, void *caller) +void * __iomem __iop13xx_ioremap(unsigned long cookie, size_t size, + unsigned int mtype) { void __iomem * retval; @@ -78,14 +76,17 @@ static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie, break; default: retval = __arm_ioremap_caller(cookie, size, mtype, - caller); + __builtin_return_address(0)); } return retval; } +EXPORT_SYMBOL(__iop13xx_ioremap); -static void __iop13xx_iounmap(volatile void __iomem *addr) +void __iop13xx_iounmap(void __iomem *addr) { + extern void __iounmap(volatile void __iomem *addr); + if (iop13xx_atue_mem_base) if (addr >= (void __iomem *) iop13xx_atue_mem_base && addr < (void __iomem *) (iop13xx_atue_mem_base + @@ -109,9 +110,4 @@ static void __iop13xx_iounmap(volatile void __iomem *addr) skip: return; } - -void __init iop13xx_init_early(void) -{ - arch_ioremap_caller = __iop13xx_ioremap_caller; - arch_iounmap = __iop13xx_iounmap; -} +EXPORT_SYMBOL(__iop13xx_iounmap); diff --git a/trunk/arch/arm/mach-iop13xx/iq81340mc.c b/trunk/arch/arm/mach-iop13xx/iq81340mc.c index 5c96b73e6964..abaee8833588 100644 --- a/trunk/arch/arm/mach-iop13xx/iq81340mc.c +++ b/trunk/arch/arm/mach-iop13xx/iq81340mc.c @@ -92,7 +92,6 @@ static struct sys_timer iq81340mc_timer = { MACHINE_START(IQ81340MC, "Intel IQ81340MC") /* Maintainer: Dan Williams */ .atag_offset = 0x100, - .init_early = iop13xx_init_early, .map_io = iop13xx_map_io, .init_irq = iop13xx_init_irq, .timer = &iq81340mc_timer, diff --git a/trunk/arch/arm/mach-iop13xx/iq81340sc.c b/trunk/arch/arm/mach-iop13xx/iq81340sc.c index aa4dd750135a..690916a09dc6 100644 --- a/trunk/arch/arm/mach-iop13xx/iq81340sc.c +++ b/trunk/arch/arm/mach-iop13xx/iq81340sc.c @@ -94,7 +94,6 @@ static struct sys_timer iq81340sc_timer = { MACHINE_START(IQ81340SC, "Intel IQ81340SC") /* Maintainer: Dan Williams */ .atag_offset = 0x100, - .init_early = iop13xx_init_early, .map_io = iop13xx_map_io, .init_irq = iop13xx_init_irq, .timer = &iq81340sc_timer, diff --git a/trunk/arch/arm/mach-iop13xx/pci.h b/trunk/arch/arm/mach-iop13xx/pci.h deleted file mode 100644 index c70cf5b41e31..000000000000 --- a/trunk/arch/arm/mach-iop13xx/pci.h +++ /dev/null @@ -1,6 +0,0 @@ -#include - -extern u32 iop13xx_atue_mem_base; -extern u32 iop13xx_atux_mem_base; -extern size_t iop13xx_atue_mem_size; -extern size_t iop13xx_atux_mem_size; diff --git a/trunk/arch/arm/mach-iop32x/include/mach/io.h b/trunk/arch/arm/mach-iop32x/include/mach/io.h index e2ada265bb8d..2d88264b9863 100644 --- a/trunk/arch/arm/mach-iop32x/include/mach/io.h +++ b/trunk/arch/arm/mach-iop32x/include/mach/io.h @@ -15,5 +15,6 @@ #define IO_SPACE_LIMIT 0xffffffff #define __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p)) +#define __mem_pci(a) (a) #endif diff --git a/trunk/arch/arm/mach-iop33x/include/mach/io.h b/trunk/arch/arm/mach-iop33x/include/mach/io.h index f7c1b6595660..a8a66fc8fbdb 100644 --- a/trunk/arch/arm/mach-iop33x/include/mach/io.h +++ b/trunk/arch/arm/mach-iop33x/include/mach/io.h @@ -15,5 +15,6 @@ #define IO_SPACE_LIMIT 0xffffffff #define __io(p) ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p)) +#define __mem_pci(a) (a) #endif diff --git a/trunk/arch/arm/mach-ixp2000/include/mach/io.h b/trunk/arch/arm/mach-ixp2000/include/mach/io.h index f6552d6f35ab..859e584914d9 100644 --- a/trunk/arch/arm/mach-ixp2000/include/mach/io.h +++ b/trunk/arch/arm/mach-ixp2000/include/mach/io.h @@ -18,6 +18,7 @@ #include #define IO_SPACE_LIMIT 0xffffffff +#define __mem_pci(a) (a) /* * The A? revisions of the IXP2000s assert byte lanes for PCI I/O diff --git a/trunk/arch/arm/mach-ixp23xx/include/mach/io.h b/trunk/arch/arm/mach-ixp23xx/include/mach/io.h index a7aceb55c130..4ce4353b9f72 100644 --- a/trunk/arch/arm/mach-ixp23xx/include/mach/io.h +++ b/trunk/arch/arm/mach-ixp23xx/include/mach/io.h @@ -18,5 +18,6 @@ #define IO_SPACE_LIMIT 0xffffffff #define __io(p) ((void __iomem*)((p) + IXP23XX_PCI_IO_VIRT)) +#define __mem_pci(a) (a) #endif diff --git a/trunk/arch/arm/mach-ixp4xx/avila-setup.c b/trunk/arch/arm/mach-ixp4xx/avila-setup.c index 90e42e9982cb..a7277ad470a5 100644 --- a/trunk/arch/arm/mach-ixp4xx/avila-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/avila-setup.c @@ -165,7 +165,6 @@ static void __init avila_init(void) MACHINE_START(AVILA, "Gateworks Avila Network Platform") /* Maintainer: Deepak Saxena */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, @@ -185,7 +184,6 @@ MACHINE_END MACHINE_START(LOFT, "Giant Shoulder Inc Loft board") /* Maintainer: Tom Billman */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/common.c b/trunk/arch/arm/mach-ixp4xx/common.c index c60e7b86192c..a6329a0a8ec4 100644 --- a/trunk/arch/arm/mach-ixp4xx/common.c +++ b/trunk/arch/arm/mach-ixp4xx/common.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include @@ -518,35 +517,3 @@ void ixp4xx_restart(char mode, const char *cmd) *IXP4XX_OSWE = IXP4XX_WDT_RESET_ENABLE | IXP4XX_WDT_COUNT_ENABLE; } } - -#ifdef CONFIG_IXP4XX_INDIRECT_PCI -/* - * In the case of using indirect PCI, we simply return the actual PCI - * address and our read/write implementation use that to drive the - * access registers. If something outside of PCI is ioremap'd, we - * fallback to the default. - */ - -static void __iomem *ixp4xx_ioremap_caller(unsigned long addr, size_t size, - unsigned int mtype, void *caller) -{ - if (!is_pci_memory(addr)) - return __arm_ioremap_caller(addr, size, mtype, caller); - - return (void __iomem *)addr; -} - -static void ixp4xx_iounmap(void __iomem *addr) -{ - if (!is_pci_memory((__force u32)addr)) - __iounmap(addr); -} - -void __init ixp4xx_init_early(void) -{ - arch_ioremap_caller = ixp4xx_ioremap_caller; - arch_iounmap = ixp4xx_iounmap; -} -#else -void __init ixp4xx_init_early(void) {} -#endif diff --git a/trunk/arch/arm/mach-ixp4xx/coyote-setup.c b/trunk/arch/arm/mach-ixp4xx/coyote-setup.c index 1b83110028d6..a74f86ce8bcc 100644 --- a/trunk/arch/arm/mach-ixp4xx/coyote-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/coyote-setup.c @@ -110,7 +110,6 @@ static void __init coyote_init(void) MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote") /* Maintainer: MontaVista Software, Inc. */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, @@ -130,7 +129,6 @@ MACHINE_END MACHINE_START(IXDPG425, "Intel IXDPG425") /* Maintainer: MontaVista Software, Inc. */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c b/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c index 97a0af8f1955..67be177b336a 100644 --- a/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/dsmg600-setup.c @@ -280,7 +280,6 @@ MACHINE_START(DSMG600, "D-Link DSM-G600 RevA") /* Maintainer: www.nslu2-linux.org */ .atag_offset = 0x100, .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &dsmg600_timer, .init_machine = dsmg600_init, diff --git a/trunk/arch/arm/mach-ixp4xx/fsg-setup.c b/trunk/arch/arm/mach-ixp4xx/fsg-setup.c index 9175a25a7511..6d5818285af8 100644 --- a/trunk/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/fsg-setup.c @@ -270,7 +270,6 @@ static void __init fsg_init(void) MACHINE_START(FSG, "Freecom FSG-3") /* Maintainer: www.nslu2-linux.org */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c b/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c index 033c71758953..7ecf9b28f1c0 100644 --- a/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/gateway7001-setup.c @@ -97,7 +97,6 @@ static void __init gateway7001_init(void) MACHINE_START(GATEWAY7001, "Gateway 7001 AP") /* Maintainer: Imre Kaloz */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c b/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c index 46bb924962ee..78ae12c46261 100644 --- a/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c +++ b/trunk/arch/arm/mach-ixp4xx/goramo_mlr.c @@ -496,7 +496,6 @@ subsys_initcall(gmlr_pci_init); MACHINE_START(GORAMO_MLR, "MultiLink") /* Maintainer: Krzysztof Halasa */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c index 18ebc6be7969..a23f89391458 100644 --- a/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/gtwx5715-setup.c @@ -165,7 +165,6 @@ static void __init gtwx5715_init(void) MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)") /* Maintainer: George Joseph */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/include/mach/hardware.h b/trunk/arch/arm/mach-ixp4xx/include/mach/hardware.h index 034bb2a1b805..c30e7e923a73 100644 --- a/trunk/arch/arm/mach-ixp4xx/include/mach/hardware.h +++ b/trunk/arch/arm/mach-ixp4xx/include/mach/hardware.h @@ -23,6 +23,8 @@ #define PCIBIOS_MAX_MEM 0x4BFFFFFF #endif +#define ARCH_HAS_DMA_SET_COHERENT_MASK + /* Register locations and bits */ #include "ixp4xx-regs.h" diff --git a/trunk/arch/arm/mach-ixp4xx/include/mach/io.h b/trunk/arch/arm/mach-ixp4xx/include/mach/io.h index 5cf30d1b78d2..ffb9d6afb89f 100644 --- a/trunk/arch/arm/mach-ixp4xx/include/mach/io.h +++ b/trunk/arch/arm/mach-ixp4xx/include/mach/io.h @@ -39,7 +39,11 @@ extern int ixp4xx_pci_write(u32 addr, u32 cmd, u32 data); * but in some cases the performance hit is acceptable. In addition, you * cannot mmap() PCI devices in this case. */ -#ifdef CONFIG_IXP4XX_INDIRECT_PCI +#ifndef CONFIG_IXP4XX_INDIRECT_PCI + +#define __mem_pci(a) (a) + +#else /* * In the case of using indirect PCI, we simply return the actual PCI @@ -53,6 +57,24 @@ static inline int is_pci_memory(u32 addr) return (addr >= PCIBIOS_MIN_MEM) && (addr <= 0x4FFFFFFF); } +static inline void __iomem * __indirect_ioremap(unsigned long addr, size_t size, + unsigned int mtype) +{ + if (!is_pci_memory(addr)) + return __arm_ioremap(addr, size, mtype); + + return (void __iomem *)addr; +} + +static inline void __indirect_iounmap(void __iomem *addr) +{ + if (!is_pci_memory((__force u32)addr)) + __iounmap(addr); +} + +#define __arch_ioremap __indirect_ioremap +#define __arch_iounmap __indirect_iounmap + #define writeb(v, p) __indirect_writeb(v, p) #define writew(v, p) __indirect_writew(v, p) #define writel(v, p) __indirect_writel(v, p) diff --git a/trunk/arch/arm/mach-ixp4xx/include/mach/platform.h b/trunk/arch/arm/mach-ixp4xx/include/mach/platform.h index b66bedc64de1..df9250bbf13d 100644 --- a/trunk/arch/arm/mach-ixp4xx/include/mach/platform.h +++ b/trunk/arch/arm/mach-ixp4xx/include/mach/platform.h @@ -121,7 +121,6 @@ extern unsigned long ixp4xx_timer_freq; * Functions used by platform-level setup code */ extern void ixp4xx_map_io(void); -extern void ixp4xx_init_early(void); extern void ixp4xx_init_irq(void); extern void ixp4xx_sys_init(void); extern void ixp4xx_timer_init(void); diff --git a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c index 3d742aee1773..8a38b39999f8 100644 --- a/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -254,7 +254,6 @@ static void __init ixdp425_init(void) MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") /* Maintainer: MontaVista Software, Inc. */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, @@ -270,7 +269,6 @@ MACHINE_END MACHINE_START(IXDP465, "Intel IXDP465 Development Platform") /* Maintainer: MontaVista Software, Inc. */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, @@ -285,7 +283,6 @@ MACHINE_END MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") /* Maintainer: MontaVista Software, Inc. */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, @@ -300,7 +297,6 @@ MACHINE_END MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform") /* Maintainer: MontaVista Software, Inc. */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c b/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c index 33cb0955b6bf..1010eb7b0083 100644 --- a/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -315,7 +315,6 @@ MACHINE_START(NAS100D, "Iomega NAS 100d") /* Maintainer: www.nslu2-linux.org */ .atag_offset = 0x100, .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .init_machine = nas100d_init, diff --git a/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c b/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c index e2903faaebb3..aa355c360d57 100644 --- a/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -301,7 +301,6 @@ MACHINE_START(NSLU2, "Linksys NSLU2") /* Maintainer: www.nslu2-linux.org */ .atag_offset = 0x100, .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &nslu2_timer, .init_machine = nslu2_init, diff --git a/trunk/arch/arm/mach-ixp4xx/omixp-setup.c b/trunk/arch/arm/mach-ixp4xx/omixp-setup.c index 158ddb79821d..0940869fcfdd 100644 --- a/trunk/arch/arm/mach-ixp4xx/omixp-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/omixp-setup.c @@ -243,7 +243,6 @@ static void __init omixp_init(void) MACHINE_START(DEVIXP, "Omicron DEVIXP") .atag_offset = 0x100, .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .init_machine = omixp_init, @@ -255,7 +254,6 @@ MACHINE_END MACHINE_START(MICCPT, "Omicron MICCPT") .atag_offset = 0x100, .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .init_machine = omixp_init, @@ -270,7 +268,6 @@ MACHINE_END MACHINE_START(MIC256, "Omicron MIC256") .atag_offset = 0x100, .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .init_machine = omixp_init, diff --git a/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c b/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c index 2798f435aaf4..9dec20683291 100644 --- a/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/vulcan-setup.c @@ -237,7 +237,6 @@ static void __init vulcan_init(void) MACHINE_START(ARCOM_VULCAN, "Arcom/Eurotech Vulcan") /* Maintainer: Marc Zyngier */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c b/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c index a785175b115b..5ac0f0a0fd8c 100644 --- a/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c +++ b/trunk/arch/arm/mach-ixp4xx/wg302v2-setup.c @@ -98,7 +98,6 @@ static void __init wg302v2_init(void) MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2") /* Maintainer: Imre Kaloz */ .map_io = ixp4xx_map_io, - .init_early = ixp4xx_init_early, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .atag_offset = 0x100, diff --git a/trunk/arch/arm/mach-kirkwood/include/mach/io.h b/trunk/arch/arm/mach-kirkwood/include/mach/io.h index 5d0ab61700d2..49dd0cb5e166 100644 --- a/trunk/arch/arm/mach-kirkwood/include/mach/io.h +++ b/trunk/arch/arm/mach-kirkwood/include/mach/io.h @@ -20,5 +20,7 @@ static inline void __iomem *__io(unsigned long addr) } #define __io(a) __io(a) +#define __mem_pci(a) (a) + #endif diff --git a/trunk/arch/arm/mach-ks8695/include/mach/io.h b/trunk/arch/arm/mach-ks8695/include/mach/io.h new file mode 100644 index 000000000000..a7a63ac3ba4e --- /dev/null +++ b/trunk/arch/arm/mach-ks8695/include/mach/io.h @@ -0,0 +1,19 @@ +/* + * arch/arm/mach-ks8695/include/mach/io.h + * + * Copyright (C) 2006 Andrew Victor + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __ASM_ARCH_IO_H +#define __ASM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/trunk/arch/arm/mach-lpc32xx/clock.c b/trunk/arch/arm/mach-lpc32xx/clock.c index b7ef51119d37..2fc24ca12054 100644 --- a/trunk/arch/arm/mach-lpc32xx/clock.c +++ b/trunk/arch/arm/mach-lpc32xx/clock.c @@ -1134,7 +1134,7 @@ static struct clk_lookup lookups[] = { _REGISTER_CLOCK(NULL, "i2s1_ck", clk_i2s1) _REGISTER_CLOCK("ts-lpc32xx", NULL, clk_tsc) _REGISTER_CLOCK("dev:mmc0", NULL, clk_mmc) - _REGISTER_CLOCK("lpc-net.0", NULL, clk_net) + _REGISTER_CLOCK("lpc-eth.0", NULL, clk_net) _REGISTER_CLOCK("dev:clcd", NULL, clk_lcd) _REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd) _REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc) diff --git a/trunk/arch/arm/mach-lpc32xx/include/mach/io.h b/trunk/arch/arm/mach-lpc32xx/include/mach/io.h new file mode 100644 index 000000000000..9b59ab5cef89 --- /dev/null +++ b/trunk/arch/arm/mach-lpc32xx/include/mach/io.h @@ -0,0 +1,27 @@ +/* + * arch/arm/mach-lpc32xx/include/mach/io.h + * + * Author: Kevin Wells + * + * Copyright (C) 2010 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#define IO_SPACE_LIMIT 0xffffffff + +#define __io(a) __typesafe_io(a) +#define __mem_pci(a) (a) + +#endif diff --git a/trunk/arch/arm/mach-mmp/aspenite.c b/trunk/arch/arm/mach-mmp/aspenite.c index bf5d8e195c3e..3588a5584153 100644 --- a/trunk/arch/arm/mach-mmp/aspenite.c +++ b/trunk/arch/arm/mach-mmp/aspenite.c @@ -23,7 +23,6 @@ #include #include #include -#include #include