- directory with DocBook templates etc. for kernel documentation.
HOWTO
- the process and procedures of how to do Linux kernel development.
-IO-mapping.txt
- - how to access I/O mapped memory from within device drivers.
IPMI.txt
- info on Linux Intelligent Platform Management Interface (IPMI) Driver.
IRQ-affinity.txt
- info on block devices & drivers
btmrvl.txt
- info on Marvell Bluetooth driver usage.
+bus-virt-phys-mapping.txt
+ - how to access I/O mapped memory from within device drivers.
cachetlb.txt
- describes the cache/TLB flushing interfaces Linux uses.
cdrom/
- how to use the RAM disk as an initial/temporary root filesystem.
input/
- info on Linux input device support.
+io-mapping.txt
+ - description of io_mapping functions in linux/io-mapping.h
io_ordering.txt
- info on ordering I/O writes to memory-mapped addresses.
ioctl/
+++ /dev/null
-[ NOTE: The virt_to_bus() and bus_to_virt() functions have been
- superseded by the functionality provided by the PCI DMA interface
- (see Documentation/PCI/PCI-DMA-mapping.txt). They continue
- to be documented below for historical purposes, but new code
- must not use them. --davidm 00/12/12 ]
-
-[ This is a mail message in response to a query on IO mapping, thus the
- strange format for a "document" ]
-
-The AHA-1542 is a bus-master device, and your patch makes the driver give the
-controller the physical address of the buffers, which is correct on x86
-(because all bus master devices see the physical memory mappings directly).
-
-However, on many setups, there are actually _three_ different ways of looking
-at memory addresses, and in this case we actually want the third, the
-so-called "bus address".
-
-Essentially, the three ways of addressing memory are (this is "real memory",
-that is, normal RAM--see later about other details):
-
- - CPU untranslated. This is the "physical" address. Physical address
- 0 is what the CPU sees when it drives zeroes on the memory bus.
-
- - CPU translated address. This is the "virtual" address, and is
- completely internal to the CPU itself with the CPU doing the appropriate
- translations into "CPU untranslated".
-
- - bus address. This is the address of memory as seen by OTHER devices,
- not the CPU. Now, in theory there could be many different bus
- addresses, with each device seeing memory in some device-specific way, but
- happily most hardware designers aren't actually actively trying to make
- things any more complex than necessary, so you can assume that all
- external hardware sees the memory the same way.
-
-Now, on normal PCs the bus address is exactly the same as the physical
-address, and things are very simple indeed. However, they are that simple
-because the memory and the devices share the same address space, and that is
-not generally necessarily true on other PCI/ISA setups.
-
-Now, just as an example, on the PReP (PowerPC Reference Platform), the
-CPU sees a memory map something like this (this is from memory):
-
- 0-2 GB "real memory"
- 2 GB-3 GB "system IO" (inb/out and similar accesses on x86)
- 3 GB-4 GB "IO memory" (shared memory over the IO bus)
-
-Now, that looks simple enough. However, when you look at the same thing from
-the viewpoint of the devices, you have the reverse, and the physical memory
-address 0 actually shows up as address 2 GB for any IO master.
-
-So when the CPU wants any bus master to write to physical memory 0, it
-has to give the master address 0x80000000 as the memory address.
-
-So, for example, depending on how the kernel is actually mapped on the
-PPC, you can end up with a setup like this:
-
- physical address: 0
- virtual address: 0xC0000000
- bus address: 0x80000000
-
-where all the addresses actually point to the same thing. It's just seen
-through different translations..
-
-Similarly, on the Alpha, the normal translation is
-
- physical address: 0
- virtual address: 0xfffffc0000000000
- bus address: 0x40000000
-
-(but there are also Alphas where the physical address and the bus address
-are the same).
-
-Anyway, the way to look up all these translations, you do
-
- #include <asm/io.h>
-
- phys_addr = virt_to_phys(virt_addr);
- virt_addr = phys_to_virt(phys_addr);
- bus_addr = virt_to_bus(virt_addr);
- virt_addr = bus_to_virt(bus_addr);
-
-Now, when do you need these?
-
-You want the _virtual_ address when you are actually going to access that
-pointer from the kernel. So you can have something like this:
-
- /*
- * this is the hardware "mailbox" we use to communicate with
- * the controller. The controller sees this directly.
- */
- struct mailbox {
- __u32 status;
- __u32 bufstart;
- __u32 buflen;
- ..
- } mbox;
-
- unsigned char * retbuffer;
-
- /* get the address from the controller */
- retbuffer = bus_to_virt(mbox.bufstart);
- switch (retbuffer[0]) {
- case STATUS_OK:
- ...
-
-on the other hand, you want the bus address when you have a buffer that
-you want to give to the controller:
-
- /* ask the controller to read the sense status into "sense_buffer" */
- mbox.bufstart = virt_to_bus(&sense_buffer);
- mbox.buflen = sizeof(sense_buffer);
- mbox.status = 0;
- notify_controller(&mbox);
-
-And you generally _never_ want to use the physical address, because you can't
-use that from the CPU (the CPU only uses translated virtual addresses), and
-you can't use it from the bus master.
-
-So why do we care about the physical address at all? We do need the physical
-address in some cases, it's just not very often in normal code. The physical
-address is needed if you use memory mappings, for example, because the
-"remap_pfn_range()" mm function wants the physical address of the memory to
-be remapped as measured in units of pages, a.k.a. the pfn (the memory
-management layer doesn't know about devices outside the CPU, so it
-shouldn't need to know about "bus addresses" etc).
-
-NOTE NOTE NOTE! The above is only one part of the whole equation. The above
-only talks about "real memory", that is, CPU memory (RAM).
-
-There is a completely different type of memory too, and that's the "shared
-memory" on the PCI or ISA bus. That's generally not RAM (although in the case
-of a video graphics card it can be normal DRAM that is just used for a frame
-buffer), but can be things like a packet buffer in a network card etc.
-
-This memory is called "PCI memory" or "shared memory" or "IO memory" or
-whatever, and there is only one way to access it: the readb/writeb and
-related functions. You should never take the address of such memory, because
-there is really nothing you can do with such an address: it's not
-conceptually in the same memory space as "real memory" at all, so you cannot
-just dereference a pointer. (Sadly, on x86 it _is_ in the same memory space,
-so on x86 it actually works to just deference a pointer, but it's not
-portable).
-
-For such memory, you can do things like
-
- - reading:
- /*
- * read first 32 bits from ISA memory at 0xC0000, aka
- * C000:0000 in DOS terms
- */
- unsigned int signature = isa_readl(0xC0000);
-
- - remapping and writing:
- /*
- * remap framebuffer PCI memory area at 0xFC000000,
- * size 1MB, so that we can access it: We can directly
- * access only the 640k-1MB area, so anything else
- * has to be remapped.
- */
- void __iomem *baseptr = ioremap(0xFC000000, 1024*1024);
-
- /* write a 'A' to the offset 10 of the area */
- writeb('A',baseptr+10);
-
- /* unmap when we unload the driver */
- iounmap(baseptr);
-
- - copying and clearing:
- /* get the 6-byte Ethernet address at ISA address E000:0040 */
- memcpy_fromio(kernel_buffer, 0xE0040, 6);
- /* write a packet to the driver */
- memcpy_toio(0xE1000, skb->data, skb->len);
- /* clear the frame buffer */
- memset_io(0xA0000, 0, 0x10000);
-
-OK, that just about covers the basics of accessing IO portably. Questions?
-Comments? You may think that all the above is overly complex, but one day you
-might find yourself with a 500 MHz Alpha in front of you, and then you'll be
-happy that your driver works ;)
-
-Note that kernel versions 2.0.x (and earlier) mistakenly called the
-ioremap() function "vremap()". ioremap() is the proper name, but I
-didn't think straight when I wrote it originally. People who have to
-support both can do something like:
-
- /* support old naming silliness */
- #if LINUX_VERSION_CODE < 0x020100
- #define ioremap vremap
- #define iounmap vfree
- #endif
-
-at the top of their source files, and then they can use the right names
-even on 2.0.x systems.
-
-And the above sounds worse than it really is. Most real drivers really
-don't do all that complex things (or rather: the complexity is not so
-much in the actual IO accesses as in error handling and timeouts etc).
-It's generally not hard to fix drivers, and in many cases the code
-actually looks better afterwards:
-
- unsigned long signature = *(unsigned int *) 0xC0000;
- vs
- unsigned long signature = readl(0xC0000);
-
-I think the second version actually is more readable, no?
-
- Linus
-
--- /dev/null
+[ NOTE: The virt_to_bus() and bus_to_virt() functions have been
+ superseded by the functionality provided by the PCI DMA interface
+ (see Documentation/PCI/PCI-DMA-mapping.txt). They continue
+ to be documented below for historical purposes, but new code
+ must not use them. --davidm 00/12/12 ]
+
+[ This is a mail message in response to a query on IO mapping, thus the
+ strange format for a "document" ]
+
+The AHA-1542 is a bus-master device, and your patch makes the driver give the
+controller the physical address of the buffers, which is correct on x86
+(because all bus master devices see the physical memory mappings directly).
+
+However, on many setups, there are actually _three_ different ways of looking
+at memory addresses, and in this case we actually want the third, the
+so-called "bus address".
+
+Essentially, the three ways of addressing memory are (this is "real memory",
+that is, normal RAM--see later about other details):
+
+ - CPU untranslated. This is the "physical" address. Physical address
+ 0 is what the CPU sees when it drives zeroes on the memory bus.
+
+ - CPU translated address. This is the "virtual" address, and is
+ completely internal to the CPU itself with the CPU doing the appropriate
+ translations into "CPU untranslated".
+
+ - bus address. This is the address of memory as seen by OTHER devices,
+ not the CPU. Now, in theory there could be many different bus
+ addresses, with each device seeing memory in some device-specific way, but
+ happily most hardware designers aren't actually actively trying to make
+ things any more complex than necessary, so you can assume that all
+ external hardware sees the memory the same way.
+
+Now, on normal PCs the bus address is exactly the same as the physical
+address, and things are very simple indeed. However, they are that simple
+because the memory and the devices share the same address space, and that is
+not generally necessarily true on other PCI/ISA setups.
+
+Now, just as an example, on the PReP (PowerPC Reference Platform), the
+CPU sees a memory map something like this (this is from memory):
+
+ 0-2 GB "real memory"
+ 2 GB-3 GB "system IO" (inb/out and similar accesses on x86)
+ 3 GB-4 GB "IO memory" (shared memory over the IO bus)
+
+Now, that looks simple enough. However, when you look at the same thing from
+the viewpoint of the devices, you have the reverse, and the physical memory
+address 0 actually shows up as address 2 GB for any IO master.
+
+So when the CPU wants any bus master to write to physical memory 0, it
+has to give the master address 0x80000000 as the memory address.
+
+So, for example, depending on how the kernel is actually mapped on the
+PPC, you can end up with a setup like this:
+
+ physical address: 0
+ virtual address: 0xC0000000
+ bus address: 0x80000000
+
+where all the addresses actually point to the same thing. It's just seen
+through different translations..
+
+Similarly, on the Alpha, the normal translation is
+
+ physical address: 0
+ virtual address: 0xfffffc0000000000
+ bus address: 0x40000000
+
+(but there are also Alphas where the physical address and the bus address
+are the same).
+
+Anyway, the way to look up all these translations, you do
+
+ #include <asm/io.h>
+
+ phys_addr = virt_to_phys(virt_addr);
+ virt_addr = phys_to_virt(phys_addr);
+ bus_addr = virt_to_bus(virt_addr);
+ virt_addr = bus_to_virt(bus_addr);
+
+Now, when do you need these?
+
+You want the _virtual_ address when you are actually going to access that
+pointer from the kernel. So you can have something like this:
+
+ /*
+ * this is the hardware "mailbox" we use to communicate with
+ * the controller. The controller sees this directly.
+ */
+ struct mailbox {
+ __u32 status;
+ __u32 bufstart;
+ __u32 buflen;
+ ..
+ } mbox;
+
+ unsigned char * retbuffer;
+
+ /* get the address from the controller */
+ retbuffer = bus_to_virt(mbox.bufstart);
+ switch (retbuffer[0]) {
+ case STATUS_OK:
+ ...
+
+on the other hand, you want the bus address when you have a buffer that
+you want to give to the controller:
+
+ /* ask the controller to read the sense status into "sense_buffer" */
+ mbox.bufstart = virt_to_bus(&sense_buffer);
+ mbox.buflen = sizeof(sense_buffer);
+ mbox.status = 0;
+ notify_controller(&mbox);
+
+And you generally _never_ want to use the physical address, because you can't
+use that from the CPU (the CPU only uses translated virtual addresses), and
+you can't use it from the bus master.
+
+So why do we care about the physical address at all? We do need the physical
+address in some cases, it's just not very often in normal code. The physical
+address is needed if you use memory mappings, for example, because the
+"remap_pfn_range()" mm function wants the physical address of the memory to
+be remapped as measured in units of pages, a.k.a. the pfn (the memory
+management layer doesn't know about devices outside the CPU, so it
+shouldn't need to know about "bus addresses" etc).
+
+NOTE NOTE NOTE! The above is only one part of the whole equation. The above
+only talks about "real memory", that is, CPU memory (RAM).
+
+There is a completely different type of memory too, and that's the "shared
+memory" on the PCI or ISA bus. That's generally not RAM (although in the case
+of a video graphics card it can be normal DRAM that is just used for a frame
+buffer), but can be things like a packet buffer in a network card etc.
+
+This memory is called "PCI memory" or "shared memory" or "IO memory" or
+whatever, and there is only one way to access it: the readb/writeb and
+related functions. You should never take the address of such memory, because
+there is really nothing you can do with such an address: it's not
+conceptually in the same memory space as "real memory" at all, so you cannot
+just dereference a pointer. (Sadly, on x86 it _is_ in the same memory space,
+so on x86 it actually works to just deference a pointer, but it's not
+portable).
+
+For such memory, you can do things like
+
+ - reading:
+ /*
+ * read first 32 bits from ISA memory at 0xC0000, aka
+ * C000:0000 in DOS terms
+ */
+ unsigned int signature = isa_readl(0xC0000);
+
+ - remapping and writing:
+ /*
+ * remap framebuffer PCI memory area at 0xFC000000,
+ * size 1MB, so that we can access it: We can directly
+ * access only the 640k-1MB area, so anything else
+ * has to be remapped.
+ */
+ void __iomem *baseptr = ioremap(0xFC000000, 1024*1024);
+
+ /* write a 'A' to the offset 10 of the area */
+ writeb('A',baseptr+10);
+
+ /* unmap when we unload the driver */
+ iounmap(baseptr);
+
+ - copying and clearing:
+ /* get the 6-byte Ethernet address at ISA address E000:0040 */
+ memcpy_fromio(kernel_buffer, 0xE0040, 6);
+ /* write a packet to the driver */
+ memcpy_toio(0xE1000, skb->data, skb->len);
+ /* clear the frame buffer */
+ memset_io(0xA0000, 0, 0x10000);
+
+OK, that just about covers the basics of accessing IO portably. Questions?
+Comments? You may think that all the above is overly complex, but one day you
+might find yourself with a 500 MHz Alpha in front of you, and then you'll be
+happy that your driver works ;)
+
+Note that kernel versions 2.0.x (and earlier) mistakenly called the
+ioremap() function "vremap()". ioremap() is the proper name, but I
+didn't think straight when I wrote it originally. People who have to
+support both can do something like:
+
+ /* support old naming silliness */
+ #if LINUX_VERSION_CODE < 0x020100
+ #define ioremap vremap
+ #define iounmap vfree
+ #endif
+
+at the top of their source files, and then they can use the right names
+even on 2.0.x systems.
+
+And the above sounds worse than it really is. Most real drivers really
+don't do all that complex things (or rather: the complexity is not so
+much in the actual IO accesses as in error handling and timeouts etc).
+It's generally not hard to fix drivers, and in many cases the code
+actually looks better afterwards:
+
+ unsigned long signature = *(unsigned int *) 0xC0000;
+ vs
+ unsigned long signature = readl(0xC0000);
+
+I think the second version actually is more readable, no?
+
+ Linus
+
----------------------------
+What: The acpi_sleep=s4_nonvs command line option
+When: 2.6.37
+Files: arch/x86/kernel/acpi/sleep.c
+Why: superseded by acpi_sleep=nonvs
+Who: Rafael J. Wysocki <rjw@sisk.pl>
+
+----------------------------
control method, with respect to putting devices into
low power states, to be enforced (the ACPI 2.0 ordering
of _PTS is used by default).
- s4_nonvs prevents the kernel from saving/restoring the
- ACPI NVS memory during hibernation.
+ nonvs prevents the kernel from saving/restoring the
+ ACPI NVS memory during suspend/hibernation and resume.
sci_force_enable causes the kernel to set SCI_EN directly
on resume from S1/S3 (which is against the ACPI spec,
but some broken systems don't work without it).
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6.git
S: Maintained
F: arch/sparc/
+F: drivers/sbus
SPARC SERIAL DRIVERS
M: "David S. Miller" <davem@davemloft.net>
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 35
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc6
NAME = Sheep on Meth
# *DOCUMENTATION*
help
Support for the Marvell Loki (88RC8480) SoC.
+config ARCH_LPC32XX
+ bool "NXP LPC32XX"
+ select CPU_ARM926T
+ select ARCH_REQUIRE_GPIOLIB
+ select HAVE_IDE
+ select ARM_AMBA
+ select USB_ARCH_HAS_OHCI
+ select COMMON_CLKDEV
+ select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
+ help
+ Support for the NXP LPC32XX family of processors
+
config ARCH_MV78XX0
bool "Marvell MV78xx0"
select CPU_FEROCEON
source "arch/arm/mach-loki/Kconfig"
+source "arch/arm/mach-lpc32xx/Kconfig"
+
source "arch/arm/mach-msm/Kconfig"
source "arch/arm/mach-mv78xx0/Kconfig"
machine-$(CONFIG_ARCH_L7200) := l7200
machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x
machine-$(CONFIG_ARCH_LOKI) := loki
+machine-$(CONFIG_ARCH_LPC32XX) := lpc32xx
machine-$(CONFIG_ARCH_MMP) := mmp
machine-$(CONFIG_ARCH_MSM) := msm
machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0
*
*/
+#include <mach/hardware.h>
#include <asm/hardware/clps7111.h>
.macro addruart, rx, tmp
unsigned long __pfn_to_bus(unsigned long pfn)
{
- return __pfn_to_phys(pfn) + (fb_bus_sdram_offset() - PHYS_OFFSET));
+ return __pfn_to_phys(pfn) + (fb_bus_sdram_offset() - PHYS_OFFSET);
}
EXPORT_SYMBOL(__pfn_to_bus);
*
*/
- .equ io_virt, IO_BASE
- .equ io_phys, IO_START
+#include <mach/hardware.h>
+
+ .equ io_virt, IO_VIRT
+ .equ io_phys, IO_PHYS
.macro addruart, rx, tmp
mrc p15, 0, \rx, c1, c0
#ifndef __ARCH_KIRKWOOD_TSX1X_COMMON_H
#define __ARCH_KIRKWOOD_TSX1X_COMMON_H
-extern void qnap_tsx1x_register_flash(void);
+extern void __init qnap_tsx1x_register_flash(void);
extern void qnap_tsx1x_power_off(void);
#endif
--- /dev/null
+if ARCH_LPC32XX
+
+menu "Individual UART enable selections"
+
+config ARCH_LPC32XX_UART3_SELECT
+ bool "Add support for standard UART3"
+ help
+ Adds support for standard UART 3 when the 8250 serial support
+ is enabled.
+
+config ARCH_LPC32XX_UART4_SELECT
+ bool "Add support for standard UART4"
+ help
+ Adds support for standard UART 4 when the 8250 serial support
+ is enabled.
+
+config ARCH_LPC32XX_UART5_SELECT
+ bool "Add support for standard UART5"
+ default y
+ help
+ Adds support for standard UART 5 when the 8250 serial support
+ is enabled.
+
+config ARCH_LPC32XX_UART6_SELECT
+ bool "Add support for standard UART6"
+ help
+ Adds support for standard UART 6 when the 8250 serial support
+ is enabled.
+
+endmenu
+
+endif
+
--- /dev/null
+#
+# Makefile for the linux kernel.
+#
+
+obj-y := timer.o irq.o common.o serial.o clock.o
+obj-y += gpiolib.o pm.o suspend.o
+obj-y += phy3250.o
+
--- /dev/null
+ zreladdr-y := 0x80008000
+params_phys-y := 0x80000100
+initrd_phys-y := 0x82000000
+
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/clock.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+/*
+ * LPC32xx clock management driver overview
+ *
+ * The LPC32XX contains a number of high level system clocks that can be
+ * generated from different sources. These system clocks are used to
+ * generate the CPU and bus rates and the individual peripheral clocks in
+ * the system. When Linux is started by the boot loader, the system
+ * clocks are already running. Stopping a system clock during normal
+ * Linux operation should never be attempted, as peripherals that require
+ * those clocks will quit working (ie, DRAM).
+ *
+ * The LPC32xx high level clock tree looks as follows. Clocks marked with
+ * an asterisk are always on and cannot be disabled. Clocks marked with
+ * an ampersand can only be disabled in CPU suspend mode. Clocks marked
+ * with a caret are always on if it is the selected clock for the SYSCLK
+ * source. The clock that isn't used for SYSCLK can be enabled and
+ * disabled normally.
+ * 32KHz oscillator*
+ * / | \
+ * RTC* PLL397^ TOUCH
+ * /
+ * Main oscillator^ /
+ * | \ /
+ * | SYSCLK&
+ * | \
+ * | \
+ * USB_PLL HCLK_PLL&
+ * | | |
+ * USB host/device PCLK& |
+ * | |
+ * Peripherals
+ *
+ * The CPU and chip bus rates are derived from the HCLK PLL, which can
+ * generate various clock rates up to 266MHz and beyond. The internal bus
+ * rates (PCLK and HCLK) are generated from dividers based on the HCLK
+ * PLL rate. HCLK can be a ratio of 1:1, 1:2, or 1:4 or HCLK PLL rate,
+ * while PCLK can be 1:1 to 1:32 of HCLK PLL rate. Most peripherals high
+ * level clocks are based on either HCLK or PCLK, but have their own
+ * dividers as part of the IP itself. Because of this, the system clock
+ * rates should not be changed.
+ *
+ * The HCLK PLL is clocked from SYSCLK, which can be derived from the
+ * main oscillator or PLL397. PLL397 generates a rate that is 397 times
+ * the 32KHz oscillator rate. The main oscillator runs at the selected
+ * oscillator/crystal rate on the mosc_in pin of the LPC32xx. This rate
+ * is normally 13MHz, but depends on the selection of external crystals
+ * or oscillators. If USB operation is required, the main oscillator must
+ * be used in the system.
+ *
+ * Switching SYSCLK between sources during normal Linux operation is not
+ * supported. SYSCLK is preset in the bootloader. Because of the
+ * complexities of clock management during clock frequency changes,
+ * there are some limitations to the clock driver explained below:
+ * - The PLL397 and main oscillator can be enabled and disabled by the
+ * clk_enable() and clk_disable() functions unless SYSCLK is based
+ * on that clock. This allows the other oscillator that isn't driving
+ * the HCLK PLL to be used as another system clock that can be routed
+ * to an external pin.
+ * - The muxed SYSCLK input and HCLK_PLL rate cannot be changed with
+ * this driver.
+ * - HCLK and PCLK rates cannot be changed as part of this driver.
+ * - Most peripherals have their own dividers are part of the peripheral
+ * block. Changing SYSCLK, HCLK PLL, HCLK, or PCLK sources or rates
+ * will also impact the individual peripheral rates.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+
+#include <mach/hardware.h>
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
+#include <mach/platform.h>
+#include "clock.h"
+#include "common.h"
+
+static struct clk clk_armpll;
+static struct clk clk_usbpll;
+static DEFINE_MUTEX(clkm_lock);
+
+/*
+ * Post divider values for PLLs based on selected register value
+ */
+static const u32 pll_postdivs[4] = {1, 2, 4, 8};
+
+static unsigned long local_return_parent_rate(struct clk *clk)
+{
+ /*
+ * If a clock has a rate of 0, then it inherits it's parent
+ * clock rate
+ */
+ while (clk->rate == 0)
+ clk = clk->parent;
+
+ return clk->rate;
+}
+
+/* 32KHz clock has a fixed rate and is not stoppable */
+static struct clk osc_32KHz = {
+ .rate = LPC32XX_CLOCK_OSC_FREQ,
+ .get_rate = local_return_parent_rate,
+};
+
+static int local_pll397_enable(struct clk *clk, int enable)
+{
+ u32 reg;
+ unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+ reg = __raw_readl(LPC32XX_CLKPWR_PLL397_CTRL);
+
+ if (enable == 0) {
+ reg |= LPC32XX_CLKPWR_SYSCTRL_PLL397_DIS;
+ __raw_writel(reg, LPC32XX_CLKPWR_PLL397_CTRL);
+ } else {
+ /* Enable PLL397 */
+ reg &= ~LPC32XX_CLKPWR_SYSCTRL_PLL397_DIS;
+ __raw_writel(reg, LPC32XX_CLKPWR_PLL397_CTRL);
+
+ /* Wait for PLL397 lock */
+ while (((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
+ LPC32XX_CLKPWR_SYSCTRL_PLL397_STS) == 0) &&
+ (timeout > jiffies))
+ cpu_relax();
+
+ if ((__raw_readl(LPC32XX_CLKPWR_PLL397_CTRL) &
+ LPC32XX_CLKPWR_SYSCTRL_PLL397_STS) == 0)
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int local_oscmain_enable(struct clk *clk, int enable)
+{
+ u32 reg;
+ unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+ reg = __raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL);
+
+ if (enable == 0) {
+ reg |= LPC32XX_CLKPWR_MOSC_DISABLE;
+ __raw_writel(reg, LPC32XX_CLKPWR_MAIN_OSC_CTRL);
+ } else {
+ /* Enable main oscillator */
+ reg &= ~LPC32XX_CLKPWR_MOSC_DISABLE;
+ __raw_writel(reg, LPC32XX_CLKPWR_MAIN_OSC_CTRL);
+
+ /* Wait for main oscillator to start */
+ while (((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
+ LPC32XX_CLKPWR_MOSC_DISABLE) != 0) &&
+ (timeout > jiffies))
+ cpu_relax();
+
+ if ((__raw_readl(LPC32XX_CLKPWR_MAIN_OSC_CTRL) &
+ LPC32XX_CLKPWR_MOSC_DISABLE) != 0)
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static struct clk osc_pll397 = {
+ .parent = &osc_32KHz,
+ .enable = local_pll397_enable,
+ .rate = LPC32XX_CLOCK_OSC_FREQ * 397,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk osc_main = {
+ .enable = local_oscmain_enable,
+ .rate = LPC32XX_MAIN_OSC_FREQ,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_sys;
+
+/*
+ * Convert a PLL register value to a PLL output frequency
+ */
+u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval)
+{
+ struct clk_pll_setup pllcfg;
+
+ pllcfg.cco_bypass_b15 = 0;
+ pllcfg.direct_output_b14 = 0;
+ pllcfg.fdbk_div_ctrl_b13 = 0;
+ if ((regval & LPC32XX_CLKPWR_HCLKPLL_CCO_BYPASS) != 0)
+ pllcfg.cco_bypass_b15 = 1;
+ if ((regval & LPC32XX_CLKPWR_HCLKPLL_POSTDIV_BYPASS) != 0)
+ pllcfg.direct_output_b14 = 1;
+ if ((regval & LPC32XX_CLKPWR_HCLKPLL_FDBK_SEL_FCLK) != 0)
+ pllcfg.fdbk_div_ctrl_b13 = 1;
+ pllcfg.pll_m = 1 + ((regval >> 1) & 0xFF);
+ pllcfg.pll_n = 1 + ((regval >> 9) & 0x3);
+ pllcfg.pll_p = pll_postdivs[((regval >> 11) & 0x3)];
+
+ return clk_check_pll_setup(inputclk, &pllcfg);
+}
+
+/*
+ * Setup the HCLK PLL with a PLL structure
+ */
+static u32 local_clk_pll_setup(struct clk_pll_setup *PllSetup)
+{
+ u32 tv, tmp = 0;
+
+ if (PllSetup->analog_on != 0)
+ tmp |= LPC32XX_CLKPWR_HCLKPLL_POWER_UP;
+ if (PllSetup->cco_bypass_b15 != 0)
+ tmp |= LPC32XX_CLKPWR_HCLKPLL_CCO_BYPASS;
+ if (PllSetup->direct_output_b14 != 0)
+ tmp |= LPC32XX_CLKPWR_HCLKPLL_POSTDIV_BYPASS;
+ if (PllSetup->fdbk_div_ctrl_b13 != 0)
+ tmp |= LPC32XX_CLKPWR_HCLKPLL_FDBK_SEL_FCLK;
+
+ tv = ffs(PllSetup->pll_p) - 1;
+ if ((!is_power_of_2(PllSetup->pll_p)) || (tv > 3))
+ return 0;
+
+ tmp |= LPC32XX_CLKPWR_HCLKPLL_POSTDIV_2POW(tv);
+ tmp |= LPC32XX_CLKPWR_HCLKPLL_PREDIV_PLUS1(PllSetup->pll_n - 1);
+ tmp |= LPC32XX_CLKPWR_HCLKPLL_PLLM(PllSetup->pll_m - 1);
+
+ return tmp;
+}
+
+/*
+ * Update the ARM core PLL frequency rate variable from the actual PLL setting
+ */
+static void local_update_armpll_rate(void)
+{
+ u32 clkin, pllreg;
+
+ clkin = clk_armpll.parent->rate;
+ pllreg = __raw_readl(LPC32XX_CLKPWR_HCLKPLL_CTRL) & 0x1FFFF;
+
+ clk_armpll.rate = clk_get_pllrate_from_reg(clkin, pllreg);
+}
+
+/*
+ * Find a PLL configuration for the selected input frequency
+ */
+static u32 local_clk_find_pll_cfg(u32 pllin_freq, u32 target_freq,
+ struct clk_pll_setup *pllsetup)
+{
+ u32 ifreq, freqtol, m, n, p, fclkout;
+
+ /* Determine frequency tolerance limits */
+ freqtol = target_freq / 250;
+ ifreq = pllin_freq;
+
+ /* Is direct bypass mode possible? */
+ if (abs(pllin_freq - target_freq) <= freqtol) {
+ pllsetup->analog_on = 0;
+ pllsetup->cco_bypass_b15 = 1;
+ pllsetup->direct_output_b14 = 1;
+ pllsetup->fdbk_div_ctrl_b13 = 1;
+ pllsetup->pll_p = pll_postdivs[0];
+ pllsetup->pll_n = 1;
+ pllsetup->pll_m = 1;
+ return clk_check_pll_setup(ifreq, pllsetup);
+ } else if (target_freq <= ifreq) {
+ pllsetup->analog_on = 0;
+ pllsetup->cco_bypass_b15 = 1;
+ pllsetup->direct_output_b14 = 0;
+ pllsetup->fdbk_div_ctrl_b13 = 1;
+ pllsetup->pll_n = 1;
+ pllsetup->pll_m = 1;
+ for (p = 0; p <= 3; p++) {
+ pllsetup->pll_p = pll_postdivs[p];
+ fclkout = clk_check_pll_setup(ifreq, pllsetup);
+ if (abs(target_freq - fclkout) <= freqtol)
+ return fclkout;
+ }
+ }
+
+ /* Is direct mode possible? */
+ pllsetup->analog_on = 1;
+ pllsetup->cco_bypass_b15 = 0;
+ pllsetup->direct_output_b14 = 1;
+ pllsetup->fdbk_div_ctrl_b13 = 0;
+ pllsetup->pll_p = pll_postdivs[0];
+ for (m = 1; m <= 256; m++) {
+ for (n = 1; n <= 4; n++) {
+ /* Compute output frequency for this value */
+ pllsetup->pll_n = n;
+ pllsetup->pll_m = m;
+ fclkout = clk_check_pll_setup(ifreq,
+ pllsetup);
+ if (abs(target_freq - fclkout) <=
+ freqtol)
+ return fclkout;
+ }
+ }
+
+ /* Is integer mode possible? */
+ pllsetup->analog_on = 1;
+ pllsetup->cco_bypass_b15 = 0;
+ pllsetup->direct_output_b14 = 0;
+ pllsetup->fdbk_div_ctrl_b13 = 1;
+ for (m = 1; m <= 256; m++) {
+ for (n = 1; n <= 4; n++) {
+ for (p = 0; p < 4; p++) {
+ /* Compute output frequency */
+ pllsetup->pll_p = pll_postdivs[p];
+ pllsetup->pll_n = n;
+ pllsetup->pll_m = m;
+ fclkout = clk_check_pll_setup(
+ ifreq, pllsetup);
+ if (abs(target_freq - fclkout) <= freqtol)
+ return fclkout;
+ }
+ }
+ }
+
+ /* Try non-integer mode */
+ pllsetup->analog_on = 1;
+ pllsetup->cco_bypass_b15 = 0;
+ pllsetup->direct_output_b14 = 0;
+ pllsetup->fdbk_div_ctrl_b13 = 0;
+ for (m = 1; m <= 256; m++) {
+ for (n = 1; n <= 4; n++) {
+ for (p = 0; p < 4; p++) {
+ /* Compute output frequency */
+ pllsetup->pll_p = pll_postdivs[p];
+ pllsetup->pll_n = n;
+ pllsetup->pll_m = m;
+ fclkout = clk_check_pll_setup(
+ ifreq, pllsetup);
+ if (abs(target_freq - fclkout) <= freqtol)
+ return fclkout;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct clk clk_armpll = {
+ .parent = &clk_sys,
+ .get_rate = local_return_parent_rate,
+};
+
+/*
+ * Setup the USB PLL with a PLL structure
+ */
+static u32 local_clk_usbpll_setup(struct clk_pll_setup *pHCLKPllSetup)
+{
+ u32 reg, tmp = local_clk_pll_setup(pHCLKPllSetup);
+
+ reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL) & ~0x1FFFF;
+ reg |= tmp;
+ __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+ return clk_check_pll_setup(clk_usbpll.parent->rate,
+ pHCLKPllSetup);
+}
+
+static int local_usbpll_enable(struct clk *clk, int enable)
+{
+ u32 reg;
+ int ret = -ENODEV;
+ unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+ reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+
+ if (enable == 0) {
+ reg &= ~(LPC32XX_CLKPWR_USBCTRL_CLK_EN1 |
+ LPC32XX_CLKPWR_USBCTRL_CLK_EN2);
+ __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+ } else if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP) {
+ reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
+ __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+ /* Wait for PLL lock */
+ while ((timeout > jiffies) & (ret == -ENODEV)) {
+ reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+ if (reg & LPC32XX_CLKPWR_USBCTRL_PLL_STS)
+ ret = 0;
+ }
+
+ if (ret == 0) {
+ reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
+ __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+ }
+ }
+
+ return ret;
+}
+
+static unsigned long local_usbpll_round_rate(struct clk *clk,
+ unsigned long rate)
+{
+ u32 clkin, usbdiv;
+ struct clk_pll_setup pllsetup;
+
+ /*
+ * Unlike other clocks, this clock has a KHz input rate, so bump
+ * it up to work with the PLL function
+ */
+ rate = rate * 1000;
+
+ clkin = clk->parent->rate;
+ usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
+ LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
+ clkin = clkin / usbdiv;
+
+ /* Try to find a good rate setup */
+ if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
+ return 0;
+
+ return clk_check_pll_setup(clkin, &pllsetup);
+}
+
+static int local_usbpll_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 clkin, reg, usbdiv;
+ struct clk_pll_setup pllsetup;
+
+ /*
+ * Unlike other clocks, this clock has a KHz input rate, so bump
+ * it up to work with the PLL function
+ */
+ rate = rate * 1000;
+
+ clkin = clk->get_rate(clk);
+ usbdiv = (__raw_readl(LPC32XX_CLKPWR_USBCLK_PDIV) &
+ LPC32XX_CLKPWR_USBPDIV_PLL_MASK) + 1;
+ clkin = clkin / usbdiv;
+
+ /* Try to find a good rate setup */
+ if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
+ return -EINVAL;
+
+ local_usbpll_enable(clk, 0);
+
+ reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+ reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN1;
+ __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+ pllsetup.analog_on = 1;
+ local_clk_usbpll_setup(&pllsetup);
+
+ clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+
+ reg = __raw_readl(LPC32XX_CLKPWR_USB_CTRL);
+ reg |= LPC32XX_CLKPWR_USBCTRL_CLK_EN2;
+ __raw_writel(reg, LPC32XX_CLKPWR_USB_CTRL);
+
+ return 0;
+}
+
+static struct clk clk_usbpll = {
+ .parent = &osc_main,
+ .set_rate = local_usbpll_set_rate,
+ .enable = local_usbpll_enable,
+ .rate = 48000, /* In KHz */
+ .get_rate = local_return_parent_rate,
+ .round_rate = local_usbpll_round_rate,
+};
+
+static u32 clk_get_hclk_div(void)
+{
+ static const u32 hclkdivs[4] = {1, 2, 4, 4};
+ return hclkdivs[LPC32XX_CLKPWR_HCLKDIV_DIV_2POW(
+ __raw_readl(LPC32XX_CLKPWR_HCLK_DIV))];
+}
+
+static struct clk clk_hclk = {
+ .parent = &clk_armpll,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_pclk = {
+ .parent = &clk_armpll,
+ .get_rate = local_return_parent_rate,
+};
+
+static int local_onoff_enable(struct clk *clk, int enable)
+{
+ u32 tmp;
+
+ tmp = __raw_readl(clk->enable_reg);
+
+ if (enable == 0)
+ tmp &= ~clk->enable_mask;
+ else
+ tmp |= clk->enable_mask;
+
+ __raw_writel(tmp, clk->enable_reg);
+
+ return 0;
+}
+
+/* Peripheral clock sources */
+static struct clk clk_timer0 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+ .enable_mask = LPC32XX_CLKPWR_TMRPWMCLK_TIMER0_EN,
+ .get_rate = local_return_parent_rate,
+};
+static struct clk clk_timer1 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+ .enable_mask = LPC32XX_CLKPWR_TMRPWMCLK_TIMER1_EN,
+ .get_rate = local_return_parent_rate,
+};
+static struct clk clk_timer2 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+ .enable_mask = LPC32XX_CLKPWR_TMRPWMCLK_TIMER2_EN,
+ .get_rate = local_return_parent_rate,
+};
+static struct clk clk_timer3 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1,
+ .enable_mask = LPC32XX_CLKPWR_TMRPWMCLK_TIMER3_EN,
+ .get_rate = local_return_parent_rate,
+};
+static struct clk clk_wdt = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_TIMER_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_PWMCLK_WDOG_EN,
+ .get_rate = local_return_parent_rate,
+};
+static struct clk clk_vfp9 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_DEBUG_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_VFP_CLOCK_ENABLE_BIT,
+ .get_rate = local_return_parent_rate,
+};
+static struct clk clk_dma = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_DMA_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_DMACLKCTRL_CLK_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_uart3 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_UART_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_UARTCLKCTRL_UART3_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_uart4 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_UART_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_UARTCLKCTRL_UART4_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_uart5 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_UART_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_UARTCLKCTRL_UART5_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_uart6 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_UART_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_UARTCLKCTRL_UART6_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_i2c0 = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_I2C_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_I2CCLK_I2C1CLK_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_i2c1 = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_I2C_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_I2CCLK_I2C2CLK_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_i2c2 = {
+ .parent = &clk_pclk,
+ .enable = local_onoff_enable,
+ .enable_reg = io_p2v(LPC32XX_USB_BASE + 0xFF4),
+ .enable_mask = 0x4,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_ssp0 = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_SSP_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_ssp1 = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_SSP_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_SSPCTRL_SSPCLK1_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_kscan = {
+ .parent = &osc_32KHz,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_KEY_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_KEYCLKCTRL_CLK_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_nand = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_NAND_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_NANDCLK_SLCCLK_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_i2s0 = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_I2S_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_I2SCTRL_I2SCLK0_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_i2s1 = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_I2S_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_I2SCTRL_I2SCLK1_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_net = {
+ .parent = &clk_hclk,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_MACCLK_CTRL,
+ .enable_mask = (LPC32XX_CLKPWR_MACCTRL_DMACLK_EN |
+ LPC32XX_CLKPWR_MACCTRL_MMIOCLK_EN |
+ LPC32XX_CLKPWR_MACCTRL_HRCCLK_EN),
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_rtc = {
+ .parent = &osc_32KHz,
+ .rate = 1, /* 1 Hz */
+ .get_rate = local_return_parent_rate,
+};
+
+static struct clk clk_usbd = {
+ .parent = &clk_usbpll,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_USB_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_USBCTRL_HCLK_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static int tsc_onoff_enable(struct clk *clk, int enable)
+{
+ u32 tmp;
+
+ /* Make sure 32KHz clock is the selected clock */
+ tmp = __raw_readl(LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+ tmp &= ~LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL;
+ __raw_writel(tmp, LPC32XX_CLKPWR_ADC_CLK_CTRL_1);
+
+ if (enable == 0)
+ __raw_writel(0, clk->enable_reg);
+ else
+ __raw_writel(clk->enable_mask, clk->enable_reg);
+
+ return 0;
+}
+
+static struct clk clk_tsc = {
+ .parent = &osc_32KHz,
+ .enable = tsc_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_ADC_CLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN,
+ .get_rate = local_return_parent_rate,
+};
+
+static int mmc_onoff_enable(struct clk *clk, int enable)
+{
+ u32 tmp;
+
+ tmp = __raw_readl(LPC32XX_CLKPWR_MS_CTRL) &
+ ~LPC32XX_CLKPWR_MSCARD_SDCARD_EN;
+
+ /* If rate is 0, disable clock */
+ if (enable != 0)
+ tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_EN;
+
+ __raw_writel(tmp, LPC32XX_CLKPWR_MS_CTRL);
+
+ return 0;
+}
+
+static unsigned long mmc_get_rate(struct clk *clk)
+{
+ u32 div, rate, oldclk;
+
+ /* The MMC clock must be on when accessing an MMC register */
+ oldclk = __raw_readl(LPC32XX_CLKPWR_MS_CTRL);
+ __raw_writel(oldclk | LPC32XX_CLKPWR_MSCARD_SDCARD_EN,
+ LPC32XX_CLKPWR_MS_CTRL);
+ div = __raw_readl(LPC32XX_CLKPWR_MS_CTRL);
+ __raw_writel(oldclk, LPC32XX_CLKPWR_MS_CTRL);
+
+ /* Get the parent clock rate */
+ rate = clk->parent->get_rate(clk->parent);
+
+ /* Get the MMC controller clock divider value */
+ div = div & LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(0xf);
+
+ if (!div)
+ div = 1;
+
+ return rate / div;
+}
+
+static unsigned long mmc_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long div, prate;
+
+ /* Get the parent clock rate */
+ prate = clk->parent->get_rate(clk->parent);
+
+ if (rate >= prate)
+ return prate;
+
+ div = prate / rate;
+ if (div > 0xf)
+ div = 0xf;
+
+ return prate / div;
+}
+
+static int mmc_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 oldclk, tmp;
+ unsigned long prate, div, crate = mmc_round_rate(clk, rate);
+
+ prate = clk->parent->get_rate(clk->parent);
+
+ div = prate / crate;
+
+ /* The MMC clock must be on when accessing an MMC register */
+ oldclk = __raw_readl(LPC32XX_CLKPWR_MS_CTRL);
+ __raw_writel(oldclk | LPC32XX_CLKPWR_MSCARD_SDCARD_EN,
+ LPC32XX_CLKPWR_MS_CTRL);
+ tmp = __raw_readl(LPC32XX_CLKPWR_MS_CTRL) &
+ ~LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(0xf);
+ tmp |= LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(div);
+ __raw_writel(tmp, LPC32XX_CLKPWR_MS_CTRL);
+
+ __raw_writel(oldclk, LPC32XX_CLKPWR_MS_CTRL);
+
+ return 0;
+}
+
+static struct clk clk_mmc = {
+ .parent = &clk_armpll,
+ .set_rate = mmc_set_rate,
+ .get_rate = mmc_get_rate,
+ .round_rate = mmc_round_rate,
+ .enable = mmc_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_MS_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_MSCARD_SDCARD_EN,
+};
+
+static unsigned long clcd_get_rate(struct clk *clk)
+{
+ u32 tmp, div, rate, oldclk;
+
+ /* The LCD clock must be on when accessing an LCD register */
+ oldclk = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
+ __raw_writel(oldclk | LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
+ LPC32XX_CLKPWR_LCDCLK_CTRL);
+ tmp = __raw_readl(io_p2v(LPC32XX_LCD_BASE + CLCD_TIM2));
+ __raw_writel(oldclk, LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+ rate = clk->parent->get_rate(clk->parent);
+
+ /* Only supports internal clocking */
+ if (tmp & TIM2_BCD)
+ return rate;
+
+ div = (tmp & 0x1F) | ((tmp & 0xF8) >> 22);
+ tmp = rate / (2 + div);
+
+ return tmp;
+}
+
+static int clcd_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 tmp, prate, div, oldclk;
+
+ /* The LCD clock must be on when accessing an LCD register */
+ oldclk = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
+ __raw_writel(oldclk | LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
+ LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+ tmp = __raw_readl(io_p2v(LPC32XX_LCD_BASE + CLCD_TIM2)) | TIM2_BCD;
+ prate = clk->parent->get_rate(clk->parent);
+
+ if (rate < prate) {
+ /* Find closest divider */
+ div = prate / rate;
+ if (div >= 2) {
+ div -= 2;
+ tmp &= ~TIM2_BCD;
+ }
+
+ tmp &= ~(0xF800001F);
+ tmp |= (div & 0x1F);
+ tmp |= (((div >> 5) & 0x1F) << 27);
+ }
+
+ __raw_writel(tmp, io_p2v(LPC32XX_LCD_BASE + CLCD_TIM2));
+ __raw_writel(oldclk, LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+ return 0;
+}
+
+static unsigned long clcd_round_rate(struct clk *clk, unsigned long rate)
+{
+ u32 prate, div;
+
+ prate = clk->parent->get_rate(clk->parent);
+
+ if (rate >= prate)
+ rate = prate;
+ else {
+ div = prate / rate;
+ if (div > 0x3ff)
+ div = 0x3ff;
+
+ rate = prate / div;
+ }
+
+ return rate;
+}
+
+static struct clk clk_lcd = {
+ .parent = &clk_hclk,
+ .set_rate = clcd_set_rate,
+ .get_rate = clcd_get_rate,
+ .round_rate = clcd_round_rate,
+ .enable = local_onoff_enable,
+ .enable_reg = LPC32XX_CLKPWR_LCDCLK_CTRL,
+ .enable_mask = LPC32XX_CLKPWR_LCDCTRL_CLK_EN,
+};
+
+static inline void clk_lock(void)
+{
+ mutex_lock(&clkm_lock);
+}
+
+static inline void clk_unlock(void)
+{
+ mutex_unlock(&clkm_lock);
+}
+
+static void local_clk_disable(struct clk *clk)
+{
+ WARN_ON(clk->usecount == 0);
+
+ /* Don't attempt to disable clock if it has no users */
+ if (clk->usecount > 0) {
+ clk->usecount--;
+
+ /* Only disable clock when it has no more users */
+ if ((clk->usecount == 0) && (clk->enable))
+ clk->enable(clk, 0);
+
+ /* Check parent clocks, they may need to be disabled too */
+ if (clk->parent)
+ local_clk_disable(clk->parent);
+ }
+}
+
+static int local_clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ /* Enable parent clocks first and update use counts */
+ if (clk->parent)
+ ret = local_clk_enable(clk->parent);
+
+ if (!ret) {
+ /* Only enable clock if it's currently disabled */
+ if ((clk->usecount == 0) && (clk->enable))
+ ret = clk->enable(clk, 1);
+
+ if (!ret)
+ clk->usecount++;
+ else if (clk->parent)
+ local_clk_disable(clk->parent);
+ }
+
+ return ret;
+}
+
+/*
+ * clk_enable - inform the system when the clock source should be running.
+ */
+int clk_enable(struct clk *clk)
+{
+ int ret;
+
+ clk_lock();
+ ret = local_clk_enable(clk);
+ clk_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+/*
+ * clk_disable - inform the system when the clock source is no longer required
+ */
+void clk_disable(struct clk *clk)
+{
+ clk_lock();
+ local_clk_disable(clk);
+ clk_unlock();
+}
+EXPORT_SYMBOL(clk_disable);
+
+/*
+ * clk_get_rate - obtain the current clock rate (in Hz) for a clock source
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+ unsigned long rate;
+
+ clk_lock();
+ rate = clk->get_rate(clk);
+ clk_unlock();
+
+ return rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/*
+ * clk_set_rate - set the clock rate for a clock source
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = -EINVAL;
+
+ /*
+ * Most system clocks can only be enabled or disabled, with
+ * the actual rate set as part of the peripheral dividers
+ * instead of high level clock control
+ */
+ if (clk->set_rate) {
+ clk_lock();
+ ret = clk->set_rate(clk, rate);
+ clk_unlock();
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/*
+ * clk_round_rate - adjust a rate to the exact rate a clock can provide
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ clk_lock();
+
+ if (clk->round_rate)
+ rate = clk->round_rate(clk, rate);
+ else
+ rate = clk->get_rate(clk);
+
+ clk_unlock();
+
+ return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+/*
+ * clk_set_parent - set the parent clock source for this clock
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ /* Clock re-parenting is not supported */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+/*
+ * clk_get_parent - get the parent clock source for this clock
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+ return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+#define _REGISTER_CLOCK(d, n, c) \
+ { \
+ .dev_id = (d), \
+ .con_id = (n), \
+ .clk = &(c), \
+ },
+
+static struct clk_lookup lookups[] = {
+ _REGISTER_CLOCK(NULL, "osc_32KHz", osc_32KHz)
+ _REGISTER_CLOCK(NULL, "osc_pll397", osc_pll397)
+ _REGISTER_CLOCK(NULL, "osc_main", osc_main)
+ _REGISTER_CLOCK(NULL, "sys_ck", clk_sys)
+ _REGISTER_CLOCK(NULL, "arm_pll_ck", clk_armpll)
+ _REGISTER_CLOCK(NULL, "ck_pll5", clk_usbpll)
+ _REGISTER_CLOCK(NULL, "hclk_ck", clk_hclk)
+ _REGISTER_CLOCK(NULL, "pclk_ck", clk_pclk)
+ _REGISTER_CLOCK(NULL, "timer0_ck", clk_timer0)
+ _REGISTER_CLOCK(NULL, "timer1_ck", clk_timer1)
+ _REGISTER_CLOCK(NULL, "timer2_ck", clk_timer2)
+ _REGISTER_CLOCK(NULL, "timer3_ck", clk_timer3)
+ _REGISTER_CLOCK(NULL, "vfp9_ck", clk_vfp9)
+ _REGISTER_CLOCK(NULL, "clk_dmac", clk_dma)
+ _REGISTER_CLOCK("pnx4008-watchdog", NULL, clk_wdt)
+ _REGISTER_CLOCK(NULL, "uart3_ck", clk_uart3)
+ _REGISTER_CLOCK(NULL, "uart4_ck", clk_uart4)
+ _REGISTER_CLOCK(NULL, "uart5_ck", clk_uart5)
+ _REGISTER_CLOCK(NULL, "uart6_ck", clk_uart6)
+ _REGISTER_CLOCK("pnx-i2c.0", NULL, clk_i2c0)
+ _REGISTER_CLOCK("pnx-i2c.1", NULL, clk_i2c1)
+ _REGISTER_CLOCK("pnx-i2c.2", NULL, clk_i2c2)
+ _REGISTER_CLOCK("dev:ssp0", NULL, clk_ssp0)
+ _REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
+ _REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
+ _REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
+ _REGISTER_CLOCK("tbd", "i2s0_ck", clk_i2s0)
+ _REGISTER_CLOCK("tbd", "i2s1_ck", clk_i2s1)
+ _REGISTER_CLOCK("lpc32xx-ts", NULL, clk_tsc)
+ _REGISTER_CLOCK("dev:mmc0", "MCLK", clk_mmc)
+ _REGISTER_CLOCK("lpc-net.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)
+};
+
+static int __init clk_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lookups); i++)
+ clkdev_add(&lookups[i]);
+
+ /*
+ * Setup muxed SYSCLK for HCLK PLL base -this selects the
+ * parent clock used for the ARM PLL and is used to derive
+ * the many system clock rates in the device.
+ */
+ if (clk_is_sysclk_mainosc() != 0)
+ clk_sys.parent = &osc_main;
+ else
+ clk_sys.parent = &osc_pll397;
+
+ clk_sys.rate = clk_sys.parent->rate;
+
+ /* Compute the current ARM PLL and USB PLL frequencies */
+ local_update_armpll_rate();
+
+ /* Compute HCLK and PCLK bus rates */
+ clk_hclk.rate = clk_hclk.parent->rate / clk_get_hclk_div();
+ clk_pclk.rate = clk_pclk.parent->rate / clk_get_pclk_div();
+
+ /*
+ * Enable system clocks - this step is somewhat formal, as the
+ * clocks are already running, but it does get the clock data
+ * inline with the actual system state. Never disable these
+ * clocks as they will only stop if the system is going to sleep.
+ * In that case, the chip/system power management functions will
+ * handle clock gating.
+ */
+ if (clk_enable(&clk_hclk) || clk_enable(&clk_pclk))
+ printk(KERN_ERR "Error enabling system HCLK and PCLK\n");
+
+ /*
+ * Timers 0 and 1 were enabled and are being used by the high
+ * resolution tick function prior to this driver being initialized.
+ * Tag them now as used.
+ */
+ if (clk_enable(&clk_timer0) || clk_enable(&clk_timer1))
+ printk(KERN_ERR "Error enabling timer tick clocks\n");
+
+ return 0;
+}
+core_initcall(clk_init);
+
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/clock.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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 __LPC32XX_CLOCK_H
+#define __LPC32XX_CLOCK_H
+
+struct clk {
+ struct list_head node;
+ struct clk *parent;
+ u32 rate;
+ u32 usecount;
+
+ int (*set_rate) (struct clk *, unsigned long);
+ unsigned long (*round_rate) (struct clk *, unsigned long);
+ unsigned long (*get_rate) (struct clk *clk);
+ int (*enable) (struct clk *, int);
+
+ /* Register address and bit mask for simple clocks */
+ void __iomem *enable_reg;
+ u32 enable_mask;
+};
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/common.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/i2c-pnx.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/i2c.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+/*
+ * Watchdog timer
+ */
+static struct resource watchdog_resources[] = {
+ [0] = {
+ .start = LPC32XX_WDTIM_BASE,
+ .end = LPC32XX_WDTIM_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+struct platform_device lpc32xx_watchdog_device = {
+ .name = "pnx4008-watchdog",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(watchdog_resources),
+ .resource = watchdog_resources,
+};
+
+/*
+ * I2C busses
+ */
+static struct i2c_pnx_data i2c0_data = {
+ .name = I2C_CHIP_NAME "1",
+ .base = LPC32XX_I2C1_BASE,
+ .irq = IRQ_LPC32XX_I2C_1,
+};
+
+static struct i2c_pnx_data i2c1_data = {
+ .name = I2C_CHIP_NAME "2",
+ .base = LPC32XX_I2C2_BASE,
+ .irq = IRQ_LPC32XX_I2C_2,
+};
+
+static struct i2c_pnx_data i2c2_data = {
+ .name = "USB-I2C",
+ .base = LPC32XX_OTG_I2C_BASE,
+ .irq = IRQ_LPC32XX_USB_I2C,
+};
+
+struct platform_device lpc32xx_i2c0_device = {
+ .name = "pnx-i2c",
+ .id = 0,
+ .dev = {
+ .platform_data = &i2c0_data,
+ },
+};
+
+struct platform_device lpc32xx_i2c1_device = {
+ .name = "pnx-i2c",
+ .id = 1,
+ .dev = {
+ .platform_data = &i2c1_data,
+ },
+};
+
+struct platform_device lpc32xx_i2c2_device = {
+ .name = "pnx-i2c",
+ .id = 2,
+ .dev = {
+ .platform_data = &i2c2_data,
+ },
+};
+
+/*
+ * Returns the unique ID for the device
+ */
+void lpc32xx_get_uid(u32 devid[4])
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ devid[i] = __raw_readl(LPC32XX_CLKPWR_DEVID(i << 2));
+}
+
+/*
+ * Returns SYSCLK source
+ * 0 = PLL397, 1 = main oscillator
+ */
+int clk_is_sysclk_mainosc(void)
+{
+ if ((__raw_readl(LPC32XX_CLKPWR_SYSCLK_CTRL) &
+ LPC32XX_CLKPWR_SYSCTRL_SYSCLKMUX) == 0)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * System reset via the watchdog timer
+ */
+void lpc32xx_watchdog_reset(void)
+{
+ /* Make sure WDT clocks are enabled */
+ __raw_writel(LPC32XX_CLKPWR_PWMCLK_WDOG_EN,
+ LPC32XX_CLKPWR_TIMER_CLK_CTRL);
+
+ /* Instant assert of RESETOUT_N with pulse length 1mS */
+ __raw_writel(13000, io_p2v(LPC32XX_WDTIM_BASE + 0x18));
+ __raw_writel(0x70, io_p2v(LPC32XX_WDTIM_BASE + 0xC));
+}
+
+/*
+ * Detects and returns IRAM size for the device variation
+ */
+#define LPC32XX_IRAM_BANK_SIZE SZ_128K
+static u32 iram_size;
+u32 lpc32xx_return_iram_size(void)
+{
+ if (iram_size == 0) {
+ u32 savedval1, savedval2;
+ void __iomem *iramptr1, *iramptr2;
+
+ iramptr1 = io_p2v(LPC32XX_IRAM_BASE);
+ iramptr2 = io_p2v(LPC32XX_IRAM_BASE + LPC32XX_IRAM_BANK_SIZE);
+ savedval1 = __raw_readl(iramptr1);
+ savedval2 = __raw_readl(iramptr2);
+
+ if (savedval1 == savedval2) {
+ __raw_writel(savedval2 + 1, iramptr2);
+ if (__raw_readl(iramptr1) == savedval2 + 1)
+ iram_size = LPC32XX_IRAM_BANK_SIZE;
+ else
+ iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
+ __raw_writel(savedval2, iramptr2);
+ } else
+ iram_size = LPC32XX_IRAM_BANK_SIZE * 2;
+ }
+
+ return iram_size;
+}
+
+/*
+ * Computes PLL rate from PLL register and input clock
+ */
+u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup)
+{
+ u32 ilfreq, p, m, n, fcco, fref, cfreq;
+ int mode;
+
+ /*
+ * PLL requirements
+ * ifreq must be >= 1MHz and <= 20MHz
+ * FCCO must be >= 156MHz and <= 320MHz
+ * FREF must be >= 1MHz and <= 27MHz
+ * Assume the passed input data is not valid
+ */
+
+ ilfreq = ifreq;
+ m = pllsetup->pll_m;
+ n = pllsetup->pll_n;
+ p = pllsetup->pll_p;
+
+ mode = (pllsetup->cco_bypass_b15 << 2) |
+ (pllsetup->direct_output_b14 << 1) |
+ pllsetup->fdbk_div_ctrl_b13;
+
+ switch (mode) {
+ case 0x0: /* Non-integer mode */
+ cfreq = (m * ilfreq) / (2 * p * n);
+ fcco = (m * ilfreq) / n;
+ fref = ilfreq / n;
+ break;
+
+ case 0x1: /* integer mode */
+ cfreq = (m * ilfreq) / n;
+ fcco = (m * ilfreq) / (n * 2 * p);
+ fref = ilfreq / n;
+ break;
+
+ case 0x2:
+ case 0x3: /* Direct mode */
+ cfreq = (m * ilfreq) / n;
+ fcco = cfreq;
+ fref = ilfreq / n;
+ break;
+
+ case 0x4:
+ case 0x5: /* Bypass mode */
+ cfreq = ilfreq / (2 * p);
+ fcco = 156000000;
+ fref = 1000000;
+ break;
+
+ case 0x6:
+ case 0x7: /* Direct bypass mode */
+ default:
+ cfreq = ilfreq;
+ fcco = 156000000;
+ fref = 1000000;
+ break;
+ }
+
+ if (fcco < 156000000 || fcco > 320000000)
+ cfreq = 0;
+
+ if (fref < 1000000 || fref > 27000000)
+ cfreq = 0;
+
+ return (u32) cfreq;
+}
+
+u32 clk_get_pclk_div(void)
+{
+ return 1 + ((__raw_readl(LPC32XX_CLKPWR_HCLK_DIV) >> 2) & 0x1F);
+}
+
+static struct map_desc lpc32xx_io_desc[] __initdata = {
+ {
+ .virtual = IO_ADDRESS(LPC32XX_AHB0_START),
+ .pfn = __phys_to_pfn(LPC32XX_AHB0_START),
+ .length = LPC32XX_AHB0_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = IO_ADDRESS(LPC32XX_AHB1_START),
+ .pfn = __phys_to_pfn(LPC32XX_AHB1_START),
+ .length = LPC32XX_AHB1_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = IO_ADDRESS(LPC32XX_FABAPB_START),
+ .pfn = __phys_to_pfn(LPC32XX_FABAPB_START),
+ .length = LPC32XX_FABAPB_SIZE,
+ .type = MT_DEVICE
+ },
+ {
+ .virtual = IO_ADDRESS(LPC32XX_IRAM_BASE),
+ .pfn = __phys_to_pfn(LPC32XX_IRAM_BASE),
+ .length = (LPC32XX_IRAM_BANK_SIZE * 2),
+ .type = MT_DEVICE
+ },
+};
+
+void __init lpc32xx_map_io(void)
+{
+ iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
+}
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/common.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2009-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 __LPC32XX_COMMON_H
+#define __LPC32XX_COMMON_H
+
+#include <linux/platform_device.h>
+
+/*
+ * Arch specific platform device structures
+ */
+extern struct platform_device lpc32xx_watchdog_device;
+extern struct platform_device lpc32xx_i2c0_device;
+extern struct platform_device lpc32xx_i2c1_device;
+extern struct platform_device lpc32xx_i2c2_device;
+
+/*
+ * Other arch specific structures and functions
+ */
+extern struct sys_timer lpc32xx_timer;
+extern void __init lpc32xx_init_irq(void);
+extern void __init lpc32xx_map_io(void);
+extern void __init lpc32xx_serial_init(void);
+extern void __init lpc32xx_gpio_init(void);
+
+/*
+ * Structure used for setting up and querying the PLLS
+ */
+struct clk_pll_setup {
+ int analog_on;
+ int cco_bypass_b15;
+ int direct_output_b14;
+ int fdbk_div_ctrl_b13;
+ int pll_p;
+ int pll_n;
+ u32 pll_m;
+};
+
+extern int clk_is_sysclk_mainosc(void);
+extern u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup);
+extern u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval);
+extern u32 clk_get_pclk_div(void);
+
+/*
+ * Returns the LPC32xx unique 128-bit chip ID
+ */
+extern void lpc32xx_get_uid(u32 devid[4]);
+
+extern void lpc32xx_watchdog_reset(void);
+extern u32 lpc32xx_return_iram_size(void);
+
+/*
+ * Pointers used for sizing and copying suspend function data
+ */
+extern int lpc32xx_sys_suspend(void);
+extern int lpc32xx_sys_suspend_sz;
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/gpiolib.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+#define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000)
+#define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004)
+#define LPC32XX_GPIO_P3_OUTP_CLR _GPREG(0x008)
+#define LPC32XX_GPIO_P3_OUTP_STATE _GPREG(0x00C)
+#define LPC32XX_GPIO_P2_DIR_SET _GPREG(0x010)
+#define LPC32XX_GPIO_P2_DIR_CLR _GPREG(0x014)
+#define LPC32XX_GPIO_P2_DIR_STATE _GPREG(0x018)
+#define LPC32XX_GPIO_P2_INP_STATE _GPREG(0x01C)
+#define LPC32XX_GPIO_P2_OUTP_SET _GPREG(0x020)
+#define LPC32XX_GPIO_P2_OUTP_CLR _GPREG(0x024)
+#define LPC32XX_GPIO_P2_MUX_SET _GPREG(0x028)
+#define LPC32XX_GPIO_P2_MUX_CLR _GPREG(0x02C)
+#define LPC32XX_GPIO_P2_MUX_STATE _GPREG(0x030)
+#define LPC32XX_GPIO_P0_INP_STATE _GPREG(0x040)
+#define LPC32XX_GPIO_P0_OUTP_SET _GPREG(0x044)
+#define LPC32XX_GPIO_P0_OUTP_CLR _GPREG(0x048)
+#define LPC32XX_GPIO_P0_OUTP_STATE _GPREG(0x04C)
+#define LPC32XX_GPIO_P0_DIR_SET _GPREG(0x050)
+#define LPC32XX_GPIO_P0_DIR_CLR _GPREG(0x054)
+#define LPC32XX_GPIO_P0_DIR_STATE _GPREG(0x058)
+#define LPC32XX_GPIO_P1_INP_STATE _GPREG(0x060)
+#define LPC32XX_GPIO_P1_OUTP_SET _GPREG(0x064)
+#define LPC32XX_GPIO_P1_OUTP_CLR _GPREG(0x068)
+#define LPC32XX_GPIO_P1_OUTP_STATE _GPREG(0x06C)
+#define LPC32XX_GPIO_P1_DIR_SET _GPREG(0x070)
+#define LPC32XX_GPIO_P1_DIR_CLR _GPREG(0x074)
+#define LPC32XX_GPIO_P1_DIR_STATE _GPREG(0x078)
+
+#define GPIO012_PIN_TO_BIT(x) (1 << (x))
+#define GPIO3_PIN_TO_BIT(x) (1 << ((x) + 25))
+#define GPO3_PIN_TO_BIT(x) (1 << (x))
+#define GPIO012_PIN_IN_SEL(x, y) (((x) >> (y)) & 1)
+#define GPIO3_PIN_IN_SHIFT(x) ((x) == 5 ? 24 : 10 + (x))
+#define GPIO3_PIN_IN_SEL(x, y) ((x) >> GPIO3_PIN_IN_SHIFT(y))
+#define GPIO3_PIN5_IN_SEL(x) (((x) >> 24) & 1)
+#define GPI3_PIN_IN_SEL(x, y) (((x) >> (y)) & 1)
+
+struct gpio_regs {
+ void __iomem *inp_state;
+ void __iomem *outp_set;
+ void __iomem *outp_clr;
+ void __iomem *dir_set;
+ void __iomem *dir_clr;
+};
+
+/*
+ * GPIO names
+ */
+static const char *gpio_p0_names[LPC32XX_GPIO_P0_MAX] = {
+ "p0.0", "p0.1", "p0.2", "p0.3",
+ "p0.4", "p0.5", "p0.6", "p0.7"
+};
+
+static const char *gpio_p1_names[LPC32XX_GPIO_P1_MAX] = {
+ "p1.0", "p1.1", "p1.2", "p1.3",
+ "p1.4", "p1.5", "p1.6", "p1.7",
+ "p1.8", "p1.9", "p1.10", "p1.11",
+ "p1.12", "p1.13", "p1.14", "p1.15",
+ "p1.16", "p1.17", "p1.18", "p1.19",
+ "p1.20", "p1.21", "p1.22", "p1.23",
+};
+
+static const char *gpio_p2_names[LPC32XX_GPIO_P2_MAX] = {
+ "p2.0", "p2.1", "p2.2", "p2.3",
+ "p2.4", "p2.5", "p2.6", "p2.7",
+ "p2.8", "p2.9", "p2.10", "p2.11",
+ "p2.12"
+};
+
+static const char *gpio_p3_names[LPC32XX_GPIO_P3_MAX] = {
+ "gpi000", "gpio01", "gpio02", "gpio03",
+ "gpio04", "gpio05"
+};
+
+static const char *gpi_p3_names[LPC32XX_GPI_P3_MAX] = {
+ "gpi00", "gpi01", "gpi02", "gpi03",
+ "gpi04", "gpi05", "gpi06", "gpi07",
+ "gpi08", "gpi09", NULL, NULL,
+ NULL, NULL, NULL, "gpi15",
+ "gpi16", "gpi17", "gpi18", "gpi19",
+ "gpi20", "gpi21", "gpi22", "gpi23",
+ "gpi24", "gpi25", "gpi26", "gpi27"
+};
+
+static const char *gpo_p3_names[LPC32XX_GPO_P3_MAX] = {
+ "gpo00", "gpo01", "gpo02", "gpo03",
+ "gpo04", "gpo05", "gpo06", "gpo07",
+ "gpo08", "gpo09", "gpo10", "gpo11",
+ "gpo12", "gpo13", "gpo14", "gpo15",
+ "gpo16", "gpo17", "gpo18", "gpo19",
+ "gpo20", "gpo21", "gpo22", "gpo23"
+};
+
+static struct gpio_regs gpio_grp_regs_p0 = {
+ .inp_state = LPC32XX_GPIO_P0_INP_STATE,
+ .outp_set = LPC32XX_GPIO_P0_OUTP_SET,
+ .outp_clr = LPC32XX_GPIO_P0_OUTP_CLR,
+ .dir_set = LPC32XX_GPIO_P0_DIR_SET,
+ .dir_clr = LPC32XX_GPIO_P0_DIR_CLR,
+};
+
+static struct gpio_regs gpio_grp_regs_p1 = {
+ .inp_state = LPC32XX_GPIO_P1_INP_STATE,
+ .outp_set = LPC32XX_GPIO_P1_OUTP_SET,
+ .outp_clr = LPC32XX_GPIO_P1_OUTP_CLR,
+ .dir_set = LPC32XX_GPIO_P1_DIR_SET,
+ .dir_clr = LPC32XX_GPIO_P1_DIR_CLR,
+};
+
+static struct gpio_regs gpio_grp_regs_p2 = {
+ .inp_state = LPC32XX_GPIO_P2_INP_STATE,
+ .outp_set = LPC32XX_GPIO_P2_OUTP_SET,
+ .outp_clr = LPC32XX_GPIO_P2_OUTP_CLR,
+ .dir_set = LPC32XX_GPIO_P2_DIR_SET,
+ .dir_clr = LPC32XX_GPIO_P2_DIR_CLR,
+};
+
+static struct gpio_regs gpio_grp_regs_p3 = {
+ .inp_state = LPC32XX_GPIO_P3_INP_STATE,
+ .outp_set = LPC32XX_GPIO_P3_OUTP_SET,
+ .outp_clr = LPC32XX_GPIO_P3_OUTP_CLR,
+ .dir_set = LPC32XX_GPIO_P2_DIR_SET,
+ .dir_clr = LPC32XX_GPIO_P2_DIR_CLR,
+};
+
+struct lpc32xx_gpio_chip {
+ struct gpio_chip chip;
+ struct gpio_regs *gpio_grp;
+};
+
+static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio(
+ struct gpio_chip *gpc)
+{
+ return container_of(gpc, struct lpc32xx_gpio_chip, chip);
+}
+
+static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
+ unsigned pin, int input)
+{
+ if (input)
+ __raw_writel(GPIO012_PIN_TO_BIT(pin),
+ group->gpio_grp->dir_clr);
+ else
+ __raw_writel(GPIO012_PIN_TO_BIT(pin),
+ group->gpio_grp->dir_set);
+}
+
+static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group,
+ unsigned pin, int input)
+{
+ u32 u = GPIO3_PIN_TO_BIT(pin);
+
+ if (input)
+ __raw_writel(u, group->gpio_grp->dir_clr);
+ else
+ __raw_writel(u, group->gpio_grp->dir_set);
+}
+
+static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group,
+ unsigned pin, int high)
+{
+ if (high)
+ __raw_writel(GPIO012_PIN_TO_BIT(pin),
+ group->gpio_grp->outp_set);
+ else
+ __raw_writel(GPIO012_PIN_TO_BIT(pin),
+ group->gpio_grp->outp_clr);
+}
+
+static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group,
+ unsigned pin, int high)
+{
+ u32 u = GPIO3_PIN_TO_BIT(pin);
+
+ if (high)
+ __raw_writel(u, group->gpio_grp->outp_set);
+ else
+ __raw_writel(u, group->gpio_grp->outp_clr);
+}
+
+static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group,
+ unsigned pin, int high)
+{
+ if (high)
+ __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_set);
+ else
+ __raw_writel(GPO3_PIN_TO_BIT(pin), group->gpio_grp->outp_clr);
+}
+
+static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group,
+ unsigned pin)
+{
+ return GPIO012_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state),
+ pin);
+}
+
+static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
+ unsigned pin)
+{
+ int state = __raw_readl(group->gpio_grp->inp_state);
+
+ /*
+ * P3 GPIO pin input mapping is not contiguous, GPIOP3-0..4 is mapped
+ * to bits 10..14, while GPIOP3-5 is mapped to bit 24.
+ */
+ return GPIO3_PIN_IN_SEL(state, pin);
+}
+
+static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
+ unsigned pin)
+{
+ return GPI3_PIN_IN_SEL(__raw_readl(group->gpio_grp->inp_state), pin);
+}
+
+/*
+ * GENERIC_GPIO primitives.
+ */
+static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
+ unsigned pin)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ __set_gpio_dir_p012(group, pin, 1);
+
+ return 0;
+}
+
+static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip,
+ unsigned pin)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ __set_gpio_dir_p3(group, pin, 1);
+
+ return 0;
+}
+
+static int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip,
+ unsigned pin)
+{
+ return 0;
+}
+
+static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ return __get_gpio_state_p012(group, pin);
+}
+
+static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ return __get_gpio_state_p3(group, pin);
+}
+
+static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ return __get_gpi_state_p3(group, pin);
+}
+
+static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
+ int value)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ __set_gpio_dir_p012(group, pin, 0);
+
+ return 0;
+}
+
+static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
+ int value)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ __set_gpio_dir_p3(group, pin, 0);
+
+ return 0;
+}
+
+static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
+ int value)
+{
+ return 0;
+}
+
+static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
+ int value)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ __set_gpio_level_p012(group, pin, value);
+}
+
+static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
+ int value)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ __set_gpio_level_p3(group, pin, value);
+}
+
+static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
+ int value)
+{
+ struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+ __set_gpo_level_p3(group, pin, value);
+}
+
+static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
+{
+ if (pin < chip->ngpio)
+ return 0;
+
+ return -EINVAL;
+}
+
+static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
+ {
+ .chip = {
+ .label = "gpio_p0",
+ .direction_input = lpc32xx_gpio_dir_input_p012,
+ .get = lpc32xx_gpio_get_value_p012,
+ .direction_output = lpc32xx_gpio_dir_output_p012,
+ .set = lpc32xx_gpio_set_value_p012,
+ .request = lpc32xx_gpio_request,
+ .base = LPC32XX_GPIO_P0_GRP,
+ .ngpio = LPC32XX_GPIO_P0_MAX,
+ .names = gpio_p0_names,
+ .can_sleep = 0,
+ },
+ .gpio_grp = &gpio_grp_regs_p0,
+ },
+ {
+ .chip = {
+ .label = "gpio_p1",
+ .direction_input = lpc32xx_gpio_dir_input_p012,
+ .get = lpc32xx_gpio_get_value_p012,
+ .direction_output = lpc32xx_gpio_dir_output_p012,
+ .set = lpc32xx_gpio_set_value_p012,
+ .request = lpc32xx_gpio_request,
+ .base = LPC32XX_GPIO_P1_GRP,
+ .ngpio = LPC32XX_GPIO_P1_MAX,
+ .names = gpio_p1_names,
+ .can_sleep = 0,
+ },
+ .gpio_grp = &gpio_grp_regs_p1,
+ },
+ {
+ .chip = {
+ .label = "gpio_p2",
+ .direction_input = lpc32xx_gpio_dir_input_p012,
+ .get = lpc32xx_gpio_get_value_p012,
+ .direction_output = lpc32xx_gpio_dir_output_p012,
+ .set = lpc32xx_gpio_set_value_p012,
+ .request = lpc32xx_gpio_request,
+ .base = LPC32XX_GPIO_P2_GRP,
+ .ngpio = LPC32XX_GPIO_P2_MAX,
+ .names = gpio_p2_names,
+ .can_sleep = 0,
+ },
+ .gpio_grp = &gpio_grp_regs_p2,
+ },
+ {
+ .chip = {
+ .label = "gpio_p3",
+ .direction_input = lpc32xx_gpio_dir_input_p3,
+ .get = lpc32xx_gpio_get_value_p3,
+ .direction_output = lpc32xx_gpio_dir_output_p3,
+ .set = lpc32xx_gpio_set_value_p3,
+ .request = lpc32xx_gpio_request,
+ .base = LPC32XX_GPIO_P3_GRP,
+ .ngpio = LPC32XX_GPIO_P3_MAX,
+ .names = gpio_p3_names,
+ .can_sleep = 0,
+ },
+ .gpio_grp = &gpio_grp_regs_p3,
+ },
+ {
+ .chip = {
+ .label = "gpi_p3",
+ .direction_input = lpc32xx_gpio_dir_in_always,
+ .get = lpc32xx_gpi_get_value,
+ .request = lpc32xx_gpio_request,
+ .base = LPC32XX_GPI_P3_GRP,
+ .ngpio = LPC32XX_GPI_P3_MAX,
+ .names = gpi_p3_names,
+ .can_sleep = 0,
+ },
+ .gpio_grp = &gpio_grp_regs_p3,
+ },
+ {
+ .chip = {
+ .label = "gpo_p3",
+ .direction_output = lpc32xx_gpio_dir_out_always,
+ .set = lpc32xx_gpo_set_value,
+ .request = lpc32xx_gpio_request,
+ .base = LPC32XX_GPO_P3_GRP,
+ .ngpio = LPC32XX_GPO_P3_MAX,
+ .names = gpo_p3_names,
+ .can_sleep = 0,
+ },
+ .gpio_grp = &gpio_grp_regs_p3,
+ },
+};
+
+void __init lpc32xx_gpio_init(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++)
+ gpiochip_add(&lpc32xx_gpiochip[i].chip);
+}
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/clkdev.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_ARCH_CLKDEV_H
+#define __ASM_ARCH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/debug-macro.S
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+/*
+ * Debug output is hardcoded to standard UART 5
+*/
+
+ .macro addruart,rx, tmp
+ mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ MMU enabled?
+ ldreq \rx, =0x40090000
+ ldrne \rx, =0xF4090000
+ .endm
+
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/entry-macro.S
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#define LPC32XX_INTC_MASKED_STATUS_OFS 0x8
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_preamble, base, tmp
+ ldr \base, =IO_ADDRESS(LPC32XX_MIC_BASE)
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
+
+/*
+ * Return IRQ number in irqnr. Also return processor Z flag status in CPSR
+ * as set if an interrupt is pending.
+ */
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \irqstat, [\base, #LPC32XX_INTC_MASKED_STATUS_OFS]
+ clz \irqnr, \irqstat
+ rsb \irqnr, \irqnr, #31
+ teq \irqstat, #0
+ .endm
+
+ .macro irq_prio_table
+ .endm
+
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/gpio.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+/*
+ * Note!
+ * Muxed GP pins need to be setup to the GP state in the board level
+ * code prior to using this driver.
+ * GPI pins : 28xP3 group
+ * GPO pins : 24xP3 group
+ * GPIO pins: 8xP0 group, 24xP1 group, 13xP2 group, 6xP3 group
+ */
+
+#define LPC32XX_GPIO_P0_MAX 8
+#define LPC32XX_GPIO_P1_MAX 24
+#define LPC32XX_GPIO_P2_MAX 13
+#define LPC32XX_GPIO_P3_MAX 6
+#define LPC32XX_GPI_P3_MAX 28
+#define LPC32XX_GPO_P3_MAX 24
+
+#define LPC32XX_GPIO_P0_GRP 0
+#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX)
+#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX)
+#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX)
+#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX)
+#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX)
+
+/*
+ * A specific GPIO can be selected with this macro
+ * ie, GPIO_05 can be selected with LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
+ * See the LPC32x0 User's guide for GPIO group numbers
+ */
+#define LPC32XX_GPIO(x, y) ((x) + (y))
+
+static inline int gpio_get_value(unsigned gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+ return __gpio_to_irq(gpio);
+}
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/hardware.h
+ *
+ * Copyright (c) 2005 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * 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_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+/*
+ * Start of virtual addresses for IO devices
+ */
+#define IO_BASE 0xF0000000
+
+/*
+ * This macro relies on fact that for all HW i/o addresses bits 20-23 are 0
+ */
+#define IO_ADDRESS(x) (((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\
+ IO_BASE)
+
+#define io_p2v(x) ((void __iomem *) (unsigned long) IO_ADDRESS(x))
+#define io_v2p(x) ((((x) & 0x0ff00000) << 4) | ((x) & 0x000fffff))
+
+#endif
--- /dev/null
+/*
+ * PNX4008-specific tweaks for I2C IP3204 block
+ *
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2005 (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_I2C_H
+#define __ASM_ARCH_I2C_H
+
+enum {
+ mstatus_tdi = 0x00000001,
+ mstatus_afi = 0x00000002,
+ mstatus_nai = 0x00000004,
+ mstatus_drmi = 0x00000008,
+ mstatus_active = 0x00000020,
+ mstatus_scl = 0x00000040,
+ mstatus_sda = 0x00000080,
+ mstatus_rff = 0x00000100,
+ mstatus_rfe = 0x00000200,
+ mstatus_tff = 0x00000400,
+ mstatus_tfe = 0x00000800,
+};
+
+enum {
+ mcntrl_tdie = 0x00000001,
+ mcntrl_afie = 0x00000002,
+ mcntrl_naie = 0x00000004,
+ mcntrl_drmie = 0x00000008,
+ mcntrl_daie = 0x00000020,
+ mcntrl_rffie = 0x00000040,
+ mcntrl_tffie = 0x00000080,
+ mcntrl_reset = 0x00000100,
+ mcntrl_cdbmode = 0x00000400,
+};
+
+enum {
+ rw_bit = 1 << 0,
+ start_bit = 1 << 8,
+ stop_bit = 1 << 9,
+};
+
+#define I2C_REG_RX(a) ((a)->ioaddr) /* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a) ((a)->ioaddr) /* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a) ((a)->ioaddr + 0x04) /* Status reg (RO) */
+#define I2C_REG_CTL(a) ((a)->ioaddr + 0x08) /* Ctl reg */
+#define I2C_REG_CKL(a) ((a)->ioaddr + 0x0c) /* Clock divider low */
+#define I2C_REG_CKH(a) ((a)->ioaddr + 0x10) /* Clock divider high */
+#define I2C_REG_ADR(a) ((a)->ioaddr + 0x14) /* I2C address */
+#define I2C_REG_RFL(a) ((a)->ioaddr + 0x18) /* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a) ((a)->ioaddr + 0x1c) /* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a) ((a)->ioaddr + 0x20) /* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a) ((a)->ioaddr + 0x24) /* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a) ((a)->ioaddr + 0x28) /* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a) ((a)->ioaddr + 0x2c) /* Tx slave FIFO level (RO) */
+
+#define I2C_CHIP_NAME "PNX4008-I2C"
+
+#endif /* __ASM_ARCH_I2C_H */
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/io.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/irqs.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_IRQS_H
+#define __ASM_ARM_ARCH_IRQS_H
+
+#define LPC32XX_SIC1_IRQ(n) (32 + (n))
+#define LPC32XX_SIC2_IRQ(n) (64 + (n))
+
+/*
+ * MIC interrupts
+ */
+#define IRQ_LPC32XX_SUB1IRQ 0
+#define IRQ_LPC32XX_SUB2IRQ 1
+#define IRQ_LPC32XX_PWM3 3
+#define IRQ_LPC32XX_PWM4 4
+#define IRQ_LPC32XX_HSTIMER 5
+#define IRQ_LPC32XX_WATCH 6
+#define IRQ_LPC32XX_UART_IIR3 7
+#define IRQ_LPC32XX_UART_IIR4 8
+#define IRQ_LPC32XX_UART_IIR5 9
+#define IRQ_LPC32XX_UART_IIR6 10
+#define IRQ_LPC32XX_FLASH 11
+#define IRQ_LPC32XX_SD1 13
+#define IRQ_LPC32XX_LCD 14
+#define IRQ_LPC32XX_SD0 15
+#define IRQ_LPC32XX_TIMER0 16
+#define IRQ_LPC32XX_TIMER1 17
+#define IRQ_LPC32XX_TIMER2 18
+#define IRQ_LPC32XX_TIMER3 19
+#define IRQ_LPC32XX_SSP0 20
+#define IRQ_LPC32XX_SSP1 21
+#define IRQ_LPC32XX_I2S0 22
+#define IRQ_LPC32XX_I2S1 23
+#define IRQ_LPC32XX_UART_IIR7 24
+#define IRQ_LPC32XX_UART_IIR2 25
+#define IRQ_LPC32XX_UART_IIR1 26
+#define IRQ_LPC32XX_MSTIMER 27
+#define IRQ_LPC32XX_DMA 28
+#define IRQ_LPC32XX_ETHERNET 29
+#define IRQ_LPC32XX_SUB1FIQ 30
+#define IRQ_LPC32XX_SUB2FIQ 31
+
+/*
+ * SIC1 interrupts start at offset 32
+ */
+#define IRQ_LPC32XX_JTAG_COMM_TX LPC32XX_SIC1_IRQ(1)
+#define IRQ_LPC32XX_JTAG_COMM_RX LPC32XX_SIC1_IRQ(2)
+#define IRQ_LPC32XX_GPI_11 LPC32XX_SIC1_IRQ(4)
+#define IRQ_LPC32XX_TS_P LPC32XX_SIC1_IRQ(6)
+#define IRQ_LPC32XX_TS_IRQ LPC32XX_SIC1_IRQ(7)
+#define IRQ_LPC32XX_TS_AUX LPC32XX_SIC1_IRQ(8)
+#define IRQ_LPC32XX_SPI2 LPC32XX_SIC1_IRQ(12)
+#define IRQ_LPC32XX_PLLUSB LPC32XX_SIC1_IRQ(13)
+#define IRQ_LPC32XX_PLLHCLK LPC32XX_SIC1_IRQ(14)
+#define IRQ_LPC32XX_PLL397 LPC32XX_SIC1_IRQ(17)
+#define IRQ_LPC32XX_I2C_2 LPC32XX_SIC1_IRQ(18)
+#define IRQ_LPC32XX_I2C_1 LPC32XX_SIC1_IRQ(19)
+#define IRQ_LPC32XX_RTC LPC32XX_SIC1_IRQ(20)
+#define IRQ_LPC32XX_KEY LPC32XX_SIC1_IRQ(22)
+#define IRQ_LPC32XX_SPI1 LPC32XX_SIC1_IRQ(23)
+#define IRQ_LPC32XX_SW LPC32XX_SIC1_IRQ(24)
+#define IRQ_LPC32XX_USB_OTG_TIMER LPC32XX_SIC1_IRQ(25)
+#define IRQ_LPC32XX_USB_OTG_ATX LPC32XX_SIC1_IRQ(26)
+#define IRQ_LPC32XX_USB_HOST LPC32XX_SIC1_IRQ(27)
+#define IRQ_LPC32XX_USB_DEV_DMA LPC32XX_SIC1_IRQ(28)
+#define IRQ_LPC32XX_USB_DEV_LP LPC32XX_SIC1_IRQ(29)
+#define IRQ_LPC32XX_USB_DEV_HP LPC32XX_SIC1_IRQ(30)
+#define IRQ_LPC32XX_USB_I2C LPC32XX_SIC1_IRQ(31)
+
+/*
+ * SIC2 interrupts start at offset 64
+ */
+#define IRQ_LPC32XX_GPIO_00 LPC32XX_SIC2_IRQ(0)
+#define IRQ_LPC32XX_GPIO_01 LPC32XX_SIC2_IRQ(1)
+#define IRQ_LPC32XX_GPIO_02 LPC32XX_SIC2_IRQ(2)
+#define IRQ_LPC32XX_GPIO_03 LPC32XX_SIC2_IRQ(3)
+#define IRQ_LPC32XX_GPIO_04 LPC32XX_SIC2_IRQ(4)
+#define IRQ_LPC32XX_GPIO_05 LPC32XX_SIC2_IRQ(5)
+#define IRQ_LPC32XX_SPI2_DATAIN LPC32XX_SIC2_IRQ(6)
+#define IRQ_LPC32XX_U2_HCTS LPC32XX_SIC2_IRQ(7)
+#define IRQ_LPC32XX_P0_P1_IRQ LPC32XX_SIC2_IRQ(8)
+#define IRQ_LPC32XX_GPI_08 LPC32XX_SIC2_IRQ(9)
+#define IRQ_LPC32XX_GPI_09 LPC32XX_SIC2_IRQ(10)
+#define IRQ_LPC32XX_GPI_19 LPC32XX_SIC2_IRQ(11)
+#define IRQ_LPC32XX_U7_HCTS LPC32XX_SIC2_IRQ(12)
+#define IRQ_LPC32XX_GPI_07 LPC32XX_SIC2_IRQ(15)
+#define IRQ_LPC32XX_SDIO LPC32XX_SIC2_IRQ(18)
+#define IRQ_LPC32XX_U5_RX LPC32XX_SIC2_IRQ(19)
+#define IRQ_LPC32XX_SPI1_DATAIN LPC32XX_SIC2_IRQ(20)
+#define IRQ_LPC32XX_GPI_00 LPC32XX_SIC2_IRQ(22)
+#define IRQ_LPC32XX_GPI_01 LPC32XX_SIC2_IRQ(23)
+#define IRQ_LPC32XX_GPI_02 LPC32XX_SIC2_IRQ(24)
+#define IRQ_LPC32XX_GPI_03 LPC32XX_SIC2_IRQ(25)
+#define IRQ_LPC32XX_GPI_04 LPC32XX_SIC2_IRQ(26)
+#define IRQ_LPC32XX_GPI_05 LPC32XX_SIC2_IRQ(27)
+#define IRQ_LPC32XX_GPI_06 LPC32XX_SIC2_IRQ(28)
+#define IRQ_LPC32XX_SYSCLK LPC32XX_SIC2_IRQ(31)
+
+#define NR_IRQS 96
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/memory.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset of bank 0
+ */
+#define PHYS_OFFSET UL(0x80000000)
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/platform.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_ARCH_PLATFORM_H
+#define __ASM_ARCH_PLATFORM_H
+
+#define _SBF(f, v) ((v) << (f))
+#define _BIT(n) _SBF(n, 1)
+
+/*
+ * AHB 0 physical base addresses
+ */
+#define LPC32XX_SLC_BASE 0x20020000
+#define LPC32XX_SSP0_BASE 0x20084000
+#define LPC32XX_SPI1_BASE 0x20088000
+#define LPC32XX_SSP1_BASE 0x2008C000
+#define LPC32XX_SPI2_BASE 0x20090000
+#define LPC32XX_I2S0_BASE 0x20094000
+#define LPC32XX_SD_BASE 0x20098000
+#define LPC32XX_I2S1_BASE 0x2009C000
+#define LPC32XX_MLC_BASE 0x200A8000
+#define LPC32XX_AHB0_START LPC32XX_SLC_BASE
+#define LPC32XX_AHB0_SIZE 0x00089000
+
+/*
+ * AHB 1 physical base addresses
+ */
+#define LPC32XX_DMA_BASE 0x31000000
+#define LPC32XX_USB_BASE 0x31020000
+#define LPC32XX_USBH_BASE 0x31020000
+#define LPC32XX_USB_OTG_BASE 0x31020000
+#define LPC32XX_OTG_I2C_BASE 0x31020300
+#define LPC32XX_LCD_BASE 0x31040000
+#define LPC32XX_ETHERNET_BASE 0x31060000
+#define LPC32XX_EMC_BASE 0x31080000
+#define LPC32XX_ETB_CFG_BASE 0x310C0000
+#define LPC32XX_ETB_DATA_BASE 0x310E0000
+#define LPC32XX_AHB1_START LPC32XX_DMA_BASE
+#define LPC32XX_AHB1_SIZE 0x000E1000
+
+/*
+ * FAB physical base addresses
+ */
+#define LPC32XX_CLK_PM_BASE 0x40004000
+#define LPC32XX_MIC_BASE 0x40008000
+#define LPC32XX_SIC1_BASE 0x4000C000
+#define LPC32XX_SIC2_BASE 0x40010000
+#define LPC32XX_HS_UART1_BASE 0x40014000
+#define LPC32XX_HS_UART2_BASE 0x40018000
+#define LPC32XX_HS_UART7_BASE 0x4001C000
+#define LPC32XX_RTC_BASE 0x40024000
+#define LPC32XX_RTC_RAM_BASE 0x40024080
+#define LPC32XX_GPIO_BASE 0x40028000
+#define LPC32XX_PWM3_BASE 0x4002C000
+#define LPC32XX_PWM4_BASE 0x40030000
+#define LPC32XX_MSTIM_BASE 0x40034000
+#define LPC32XX_HSTIM_BASE 0x40038000
+#define LPC32XX_WDTIM_BASE 0x4003C000
+#define LPC32XX_DEBUG_CTRL_BASE 0x40040000
+#define LPC32XX_TIMER0_BASE 0x40044000
+#define LPC32XX_ADC_BASE 0x40048000
+#define LPC32XX_TIMER1_BASE 0x4004C000
+#define LPC32XX_KSCAN_BASE 0x40050000
+#define LPC32XX_UART_CTRL_BASE 0x40054000
+#define LPC32XX_TIMER2_BASE 0x40058000
+#define LPC32XX_PWM1_BASE 0x4005C000
+#define LPC32XX_PWM2_BASE 0x4005C004
+#define LPC32XX_TIMER3_BASE 0x40060000
+
+/*
+ * APB physical base addresses
+ */
+#define LPC32XX_UART3_BASE 0x40080000
+#define LPC32XX_UART4_BASE 0x40088000
+#define LPC32XX_UART5_BASE 0x40090000
+#define LPC32XX_UART6_BASE 0x40098000
+#define LPC32XX_I2C1_BASE 0x400A0000
+#define LPC32XX_I2C2_BASE 0x400A8000
+
+/*
+ * FAB and APB base and sizing
+ */
+#define LPC32XX_FABAPB_START LPC32XX_CLK_PM_BASE
+#define LPC32XX_FABAPB_SIZE 0x000A5000
+
+/*
+ * Internal memory bases and sizes
+ */
+#define LPC32XX_IRAM_BASE 0x08000000
+#define LPC32XX_IROM_BASE 0x0C000000
+
+/*
+ * External Static Memory Bank Address Space Bases
+ */
+#define LPC32XX_EMC_CS0_BASE 0xE0000000
+#define LPC32XX_EMC_CS1_BASE 0xE1000000
+#define LPC32XX_EMC_CS2_BASE 0xE2000000
+#define LPC32XX_EMC_CS3_BASE 0xE3000000
+
+/*
+ * External SDRAM Memory Bank Address Space Bases
+ */
+#define LPC32XX_EMC_DYCS0_BASE 0x80000000
+#define LPC32XX_EMC_DYCS1_BASE 0xA0000000
+
+/*
+ * Clock and crystal information
+ */
+#define LPC32XX_MAIN_OSC_FREQ 13000000
+#define LPC32XX_CLOCK_OSC_FREQ 32768
+
+/*
+ * Clock and Power control register offsets
+ */
+#define _PMREG(x) io_p2v(LPC32XX_CLK_PM_BASE +\
+ (x))
+#define LPC32XX_CLKPWR_DEBUG_CTRL _PMREG(0x000)
+#define LPC32XX_CLKPWR_BOOTMAP _PMREG(0x014)
+#define LPC32XX_CLKPWR_P01_ER _PMREG(0x018)
+#define LPC32XX_CLKPWR_USBCLK_PDIV _PMREG(0x01C)
+#define LPC32XX_CLKPWR_INT_ER _PMREG(0x020)
+#define LPC32XX_CLKPWR_INT_RS _PMREG(0x024)
+#define LPC32XX_CLKPWR_INT_SR _PMREG(0x028)
+#define LPC32XX_CLKPWR_INT_AP _PMREG(0x02C)
+#define LPC32XX_CLKPWR_PIN_ER _PMREG(0x030)
+#define LPC32XX_CLKPWR_PIN_RS _PMREG(0x034)
+#define LPC32XX_CLKPWR_PIN_SR _PMREG(0x038)
+#define LPC32XX_CLKPWR_PIN_AP _PMREG(0x03C)
+#define LPC32XX_CLKPWR_HCLK_DIV _PMREG(0x040)
+#define LPC32XX_CLKPWR_PWR_CTRL _PMREG(0x044)
+#define LPC32XX_CLKPWR_PLL397_CTRL _PMREG(0x048)
+#define LPC32XX_CLKPWR_MAIN_OSC_CTRL _PMREG(0x04C)
+#define LPC32XX_CLKPWR_SYSCLK_CTRL _PMREG(0x050)
+#define LPC32XX_CLKPWR_LCDCLK_CTRL _PMREG(0x054)
+#define LPC32XX_CLKPWR_HCLKPLL_CTRL _PMREG(0x058)
+#define LPC32XX_CLKPWR_ADC_CLK_CTRL_1 _PMREG(0x060)
+#define LPC32XX_CLKPWR_USB_CTRL _PMREG(0x064)
+#define LPC32XX_CLKPWR_SDRAMCLK_CTRL _PMREG(0x068)
+#define LPC32XX_CLKPWR_DDR_LAP_NOM _PMREG(0x06C)
+#define LPC32XX_CLKPWR_DDR_LAP_COUNT _PMREG(0x070)
+#define LPC32XX_CLKPWR_DDR_LAP_DELAY _PMREG(0x074)
+#define LPC32XX_CLKPWR_SSP_CLK_CTRL _PMREG(0x078)
+#define LPC32XX_CLKPWR_I2S_CLK_CTRL _PMREG(0x07C)
+#define LPC32XX_CLKPWR_MS_CTRL _PMREG(0x080)
+#define LPC32XX_CLKPWR_MACCLK_CTRL _PMREG(0x090)
+#define LPC32XX_CLKPWR_TEST_CLK_SEL _PMREG(0x0A4)
+#define LPC32XX_CLKPWR_SFW_INT _PMREG(0x0A8)
+#define LPC32XX_CLKPWR_I2C_CLK_CTRL _PMREG(0x0AC)
+#define LPC32XX_CLKPWR_KEY_CLK_CTRL _PMREG(0x0B0)
+#define LPC32XX_CLKPWR_ADC_CLK_CTRL _PMREG(0x0B4)
+#define LPC32XX_CLKPWR_PWM_CLK_CTRL _PMREG(0x0B8)
+#define LPC32XX_CLKPWR_TIMER_CLK_CTRL _PMREG(0x0BC)
+#define LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1 _PMREG(0x0C0)
+#define LPC32XX_CLKPWR_SPI_CLK_CTRL _PMREG(0x0C4)
+#define LPC32XX_CLKPWR_NAND_CLK_CTRL _PMREG(0x0C8)
+#define LPC32XX_CLKPWR_UART3_CLK_CTRL _PMREG(0x0D0)
+#define LPC32XX_CLKPWR_UART4_CLK_CTRL _PMREG(0x0D4)
+#define LPC32XX_CLKPWR_UART5_CLK_CTRL _PMREG(0x0D8)
+#define LPC32XX_CLKPWR_UART6_CLK_CTRL _PMREG(0x0DC)
+#define LPC32XX_CLKPWR_IRDA_CLK_CTRL _PMREG(0x0E0)
+#define LPC32XX_CLKPWR_UART_CLK_CTRL _PMREG(0x0E4)
+#define LPC32XX_CLKPWR_DMA_CLK_CTRL _PMREG(0x0E8)
+#define LPC32XX_CLKPWR_AUTOCLOCK _PMREG(0x0EC)
+#define LPC32XX_CLKPWR_DEVID(x) _PMREG(0x130 + (x))
+
+/*
+ * clkpwr_debug_ctrl register definitions
+*/
+#define LPC32XX_CLKPWR_VFP_CLOCK_ENABLE_BIT _BIT(4)
+
+/*
+ * clkpwr_bootmap register definitions
+ */
+#define LPC32XX_CLKPWR_BOOTMAP_SEL_BIT _BIT(1)
+
+/*
+ * clkpwr_start_gpio register bit definitions
+ */
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO23_BIT _BIT(31)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO22_BIT _BIT(30)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO21_BIT _BIT(29)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO20_BIT _BIT(28)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO19_BIT _BIT(27)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO18_BIT _BIT(26)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO17_BIT _BIT(25)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO16_BIT _BIT(24)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO15_BIT _BIT(23)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO14_BIT _BIT(22)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO13_BIT _BIT(21)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO12_BIT _BIT(20)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO11_BIT _BIT(19)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO10_BIT _BIT(18)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO9_BIT _BIT(17)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO8_BIT _BIT(16)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO7_BIT _BIT(15)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO6_BIT _BIT(14)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO5_BIT _BIT(13)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO4_BIT _BIT(12)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO3_BIT _BIT(11)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO2_BIT _BIT(10)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO1_BIT _BIT(9)
+#define LPC32XX_CLKPWR_GPIOSRC_P1IO0_BIT _BIT(8)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO7_BIT _BIT(7)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO6_BIT _BIT(6)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO5_BIT _BIT(5)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO4_BIT _BIT(4)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO3_BIT _BIT(3)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO2_BIT _BIT(2)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO1_BIT _BIT(1)
+#define LPC32XX_CLKPWR_GPIOSRC_P0IO0_BIT _BIT(0)
+
+/*
+ * clkpwr_usbclk_pdiv register definitions
+ */
+#define LPC32XX_CLKPWR_USBPDIV_PLL_MASK 0xF
+
+/*
+ * clkpwr_start_int, clkpwr_start_raw_sts_int, clkpwr_start_sts_int,
+ * clkpwr_start_pol_int, register bit definitions
+ */
+#define LPC32XX_CLKPWR_INTSRC_ADC_BIT _BIT(31)
+#define LPC32XX_CLKPWR_INTSRC_TS_P_BIT _BIT(30)
+#define LPC32XX_CLKPWR_INTSRC_TS_AUX_BIT _BIT(29)
+#define LPC32XX_CLKPWR_INTSRC_USBAHNEEDCLK_BIT _BIT(26)
+#define LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT _BIT(25)
+#define LPC32XX_CLKPWR_INTSRC_RTC_BIT _BIT(24)
+#define LPC32XX_CLKPWR_INTSRC_USBNEEDCLK_BIT _BIT(23)
+#define LPC32XX_CLKPWR_INTSRC_USB_BIT _BIT(22)
+#define LPC32XX_CLKPWR_INTSRC_I2C_BIT _BIT(21)
+#define LPC32XX_CLKPWR_INTSRC_USBOTGTIMER_BIT _BIT(20)
+#define LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT _BIT(19)
+#define LPC32XX_CLKPWR_INTSRC_KEY_BIT _BIT(16)
+#define LPC32XX_CLKPWR_INTSRC_MAC_BIT _BIT(7)
+#define LPC32XX_CLKPWR_INTSRC_P0P1_BIT _BIT(6)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_05_BIT _BIT(5)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_04_BIT _BIT(4)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_03_BIT _BIT(3)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_02_BIT _BIT(2)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_01_BIT _BIT(1)
+#define LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT _BIT(0)
+
+/*
+ * clkpwr_start_pin, clkpwr_start_raw_sts_pin, clkpwr_start_sts_pin,
+ * clkpwr_start_pol_pin register bit definitions
+ */
+#define LPC32XX_CLKPWR_EXTSRC_U7_RX_BIT _BIT(31)
+#define LPC32XX_CLKPWR_EXTSRC_U7_HCTS_BIT _BIT(30)
+#define LPC32XX_CLKPWR_EXTSRC_U6_IRRX_BIT _BIT(28)
+#define LPC32XX_CLKPWR_EXTSRC_U5_RX_BIT _BIT(26)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_28_BIT _BIT(25)
+#define LPC32XX_CLKPWR_EXTSRC_U3_RX_BIT _BIT(24)
+#define LPC32XX_CLKPWR_EXTSRC_U2_HCTS_BIT _BIT(23)
+#define LPC32XX_CLKPWR_EXTSRC_U2_RX_BIT _BIT(22)
+#define LPC32XX_CLKPWR_EXTSRC_U1_RX_BIT _BIT(21)
+#define LPC32XX_CLKPWR_EXTSRC_MSDIO_INT_BIT _BIT(18)
+#define LPC32XX_CLKPWR_EXTSRC_MSDIO_SRT_BIT _BIT(17)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT _BIT(16)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_05_BIT _BIT(15)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_04_BIT _BIT(14)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_03_BIT _BIT(13)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_02_BIT _BIT(12)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_01_BIT _BIT(11)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_00_BIT _BIT(10)
+#define LPC32XX_CLKPWR_EXTSRC_SYSCLKEN_BIT _BIT(9)
+#define LPC32XX_CLKPWR_EXTSRC_SPI1_DATIN_BIT _BIT(8)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_07_BIT _BIT(7)
+#define LPC32XX_CLKPWR_EXTSRC_SPI2_DATIN_BIT _BIT(6)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_19_BIT _BIT(5)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_09_BIT _BIT(4)
+#define LPC32XX_CLKPWR_EXTSRC_GPI_08_BIT _BIT(3)
+
+/*
+ * clkpwr_hclk_div register definitions
+ */
+#define LPC32XX_CLKPWR_HCLKDIV_DDRCLK_STOP (0x0 << 7)
+#define LPC32XX_CLKPWR_HCLKDIV_DDRCLK_NORM (0x1 << 7)
+#define LPC32XX_CLKPWR_HCLKDIV_DDRCLK_HALF (0x2 << 7)
+#define LPC32XX_CLKPWR_HCLKDIV_PCLK_DIV(n) (((n) & 0x1F) << 2)
+#define LPC32XX_CLKPWR_HCLKDIV_DIV_2POW(n) ((n) & 0x3)
+
+/*
+ * clkpwr_pwr_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_CTRL_FORCE_PCLK _BIT(10)
+#define LPC32XX_CLKPWR_SDRAM_SELF_RFSH _BIT(9)
+#define LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH _BIT(8)
+#define LPC32XX_CLKPWR_AUTO_SDRAM_SELF_RFSH _BIT(7)
+#define LPC32XX_CLKPWR_HIGHCORE_STATE_BIT _BIT(5)
+#define LPC32XX_CLKPWR_SYSCLKEN_STATE_BIT _BIT(4)
+#define LPC32XX_CLKPWR_SYSCLKEN_GPIO_EN _BIT(3)
+#define LPC32XX_CLKPWR_SELECT_RUN_MODE _BIT(2)
+#define LPC32XX_CLKPWR_HIGHCORE_GPIO_EN _BIT(1)
+#define LPC32XX_CLKPWR_STOP_MODE_CTRL _BIT(0)
+
+/*
+ * clkpwr_pll397_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_PLL397_MSLOCK_STS _BIT(10)
+#define LPC32XX_CLKPWR_PLL397_BYPASS _BIT(9)
+#define LPC32XX_CLKPWR_PLL397_BIAS_NORM 0x000
+#define LPC32XX_CLKPWR_PLL397_BIAS_N12_5 0x040
+#define LPC32XX_CLKPWR_PLL397_BIAS_N25 0x080
+#define LPC32XX_CLKPWR_PLL397_BIAS_N37_5 0x0C0
+#define LPC32XX_CLKPWR_PLL397_BIAS_P12_5 0x100
+#define LPC32XX_CLKPWR_PLL397_BIAS_P25 0x140
+#define LPC32XX_CLKPWR_PLL397_BIAS_P37_5 0x180
+#define LPC32XX_CLKPWR_PLL397_BIAS_P50 0x1C0
+#define LPC32XX_CLKPWR_PLL397_BIAS_MASK 0x1C0
+#define LPC32XX_CLKPWR_SYSCTRL_PLL397_DIS _BIT(1)
+#define LPC32XX_CLKPWR_SYSCTRL_PLL397_STS _BIT(0)
+
+/*
+ * clkpwr_main_osc_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_MOSC_ADD_CAP(n) (((n) & 0x7F) << 2)
+#define LPC32XX_CLKPWR_MOSC_CAP_MASK (0x7F << 2)
+#define LPC32XX_CLKPWR_TEST_MODE _BIT(1)
+#define LPC32XX_CLKPWR_MOSC_DISABLE _BIT(0)
+
+/*
+ * clkpwr_sysclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SYSCTRL_BP_TRIG(n) (((n) & 0x3FF) << 2)
+#define LPC32XX_CLKPWR_SYSCTRL_BP_MASK (0x3FF << 2)
+#define LPC32XX_CLKPWR_SYSCTRL_USEPLL397 _BIT(1)
+#define LPC32XX_CLKPWR_SYSCTRL_SYSCLKMUX _BIT(0)
+
+/*
+ * clkpwr_lcdclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT12 0x000
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16 0x040
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT15 0x080
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT24 0x0C0
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_STN4M 0x100
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_STN8C 0x140
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_DSTN4M 0x180
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_DSTN8C 0x1C0
+#define LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK 0x01C0
+#define LPC32XX_CLKPWR_LCDCTRL_CLK_EN 0x020
+#define LPC32XX_CLKPWR_LCDCTRL_SET_PSCALE(n) ((n - 1) & 0x1F)
+#define LPC32XX_CLKPWR_LCDCTRL_PSCALE_MSK 0x001F
+
+/*
+ * clkpwr_hclkpll_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_HCLKPLL_POWER_UP _BIT(16)
+#define LPC32XX_CLKPWR_HCLKPLL_CCO_BYPASS _BIT(15)
+#define LPC32XX_CLKPWR_HCLKPLL_POSTDIV_BYPASS _BIT(14)
+#define LPC32XX_CLKPWR_HCLKPLL_FDBK_SEL_FCLK _BIT(13)
+#define LPC32XX_CLKPWR_HCLKPLL_POSTDIV_2POW(n) (((n) & 0x3) << 11)
+#define LPC32XX_CLKPWR_HCLKPLL_PREDIV_PLUS1(n) (((n) & 0x3) << 9)
+#define LPC32XX_CLKPWR_HCLKPLL_PLLM(n) (((n) & 0xFF) << 1)
+#define LPC32XX_CLKPWR_HCLKPLL_PLL_STS _BIT(0)
+
+/*
+ * clkpwr_adc_clk_ctrl_1 register definitions
+ */
+#define LPC32XX_CLKPWR_ADCCTRL1_RTDIV(n) (((n) & 0xFF) << 0)
+#define LPC32XX_CLKPWR_ADCCTRL1_PCLK_SEL _BIT(8)
+
+/*
+ * clkpwr_usb_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_USBCTRL_HCLK_EN _BIT(24)
+#define LPC32XX_CLKPWR_USBCTRL_USBI2C_EN _BIT(23)
+#define LPC32XX_CLKPWR_USBCTRL_USBDVND_EN _BIT(22)
+#define LPC32XX_CLKPWR_USBCTRL_USBHSTND_EN _BIT(21)
+#define LPC32XX_CLKPWR_USBCTRL_PU_ADD (0x0 << 19)
+#define LPC32XX_CLKPWR_USBCTRL_BUS_KEEPER (0x1 << 19)
+#define LPC32XX_CLKPWR_USBCTRL_PD_ADD (0x3 << 19)
+#define LPC32XX_CLKPWR_USBCTRL_CLK_EN2 _BIT(18)
+#define LPC32XX_CLKPWR_USBCTRL_CLK_EN1 _BIT(17)
+#define LPC32XX_CLKPWR_USBCTRL_PLL_PWRUP _BIT(16)
+#define LPC32XX_CLKPWR_USBCTRL_CCO_BYPASS _BIT(15)
+#define LPC32XX_CLKPWR_USBCTRL_POSTDIV_BYPASS _BIT(14)
+#define LPC32XX_CLKPWR_USBCTRL_FDBK_SEL_FCLK _BIT(13)
+#define LPC32XX_CLKPWR_USBCTRL_POSTDIV_2POW(n) (((n) & 0x3) << 11)
+#define LPC32XX_CLKPWR_USBCTRL_PREDIV_PLUS1(n) (((n) & 0x3) << 9)
+#define LPC32XX_CLKPWR_USBCTRL_FDBK_PLUS1(n) (((n) & 0xFF) << 1)
+#define LPC32XX_CLKPWR_USBCTRL_PLL_STS _BIT(0)
+
+/*
+ * clkpwr_sdramclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SDRCLK_FASTSLEW_CLK _BIT(22)
+#define LPC32XX_CLKPWR_SDRCLK_FASTSLEW _BIT(21)
+#define LPC32XX_CLKPWR_SDRCLK_FASTSLEW_DAT _BIT(20)
+#define LPC32XX_CLKPWR_SDRCLK_SW_DDR_RESET _BIT(19)
+#define LPC32XX_CLKPWR_SDRCLK_HCLK_DLY(n) (((n) & 0x1F) << 14)
+#define LPC32XX_CLKPWR_SDRCLK_DLY_ADDR_STS _BIT(13)
+#define LPC32XX_CLKPWR_SDRCLK_SENS_FACT(n) (((n) & 0x7) << 10)
+#define LPC32XX_CLKPWR_SDRCLK_USE_CAL _BIT(9)
+#define LPC32XX_CLKPWR_SDRCLK_DO_CAL _BIT(8)
+#define LPC32XX_CLKPWR_SDRCLK_CAL_ON_RTC _BIT(7)
+#define LPC32XX_CLKPWR_SDRCLK_DQS_DLY(n) (((n) & 0x1F) << 2)
+#define LPC32XX_CLKPWR_SDRCLK_USE_DDR _BIT(1)
+#define LPC32XX_CLKPWR_SDRCLK_CLK_DIS _BIT(0)
+
+/*
+ * clkpwr_ssp_blk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP1RX _BIT(5)
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP1TX _BIT(4)
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP0RX _BIT(3)
+#define LPC32XX_CLKPWR_SSPCTRL_DMA_SSP0TX _BIT(2)
+#define LPC32XX_CLKPWR_SSPCTRL_SSPCLK1_EN _BIT(1)
+#define LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN _BIT(0)
+
+/*
+ * clkpwr_i2s_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_I2SCTRL_I2S1_RX_FOR_TX _BIT(6)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S1_TX_FOR_RX _BIT(5)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA _BIT(4)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S0_RX_FOR_TX _BIT(3)
+#define LPC32XX_CLKPWR_I2SCTRL_I2S0_TX_FOR_RX _BIT(2)
+#define LPC32XX_CLKPWR_I2SCTRL_I2SCLK1_EN _BIT(1)
+#define LPC32XX_CLKPWR_I2SCTRL_I2SCLK0_EN _BIT(0)
+
+/*
+ * clkpwr_ms_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_MSCARD_MSDIO_PIN_DIS _BIT(10)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO_PU_EN _BIT(9)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO23_DIS _BIT(8)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO1_DIS _BIT(7)
+#define LPC32XX_CLKPWR_MSCARD_MSDIO0_DIS _BIT(6)
+#define LPC32XX_CLKPWR_MSCARD_SDCARD_EN _BIT(5)
+#define LPC32XX_CLKPWR_MSCARD_SDCARD_DIV(n) ((n) & 0xF)
+
+/*
+ * clkpwr_macclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_MACCTRL_NO_ENET_PIS 0x00
+#define LPC32XX_CLKPWR_MACCTRL_USE_MII_PINS 0x08
+#define LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS 0x18
+#define LPC32XX_CLKPWR_MACCTRL_PINS_MSK 0x18
+#define LPC32XX_CLKPWR_MACCTRL_DMACLK_EN _BIT(2)
+#define LPC32XX_CLKPWR_MACCTRL_MMIOCLK_EN _BIT(1)
+#define LPC32XX_CLKPWR_MACCTRL_HRCCLK_EN _BIT(0)
+
+/*
+ * clkpwr_test_clk_sel register definitions
+ */
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_PERCLK (0x0 << 5)
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_RTC (0x1 << 5)
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_MOSC (0x2 << 5)
+#define LPC32XX_CLKPWR_TESTCLK1_SEL_MASK (0x3 << 5)
+#define LPC32XX_CLKPWR_TESTCLK_TESTCLK1_EN _BIT(4)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_HCLK (0x0 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_PERCLK (0x1 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_USBCLK (0x2 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC (0x5 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_PLL397 (0x7 << 1)
+#define LPC32XX_CLKPWR_TESTCLK2_SEL_MASK (0x7 << 1)
+#define LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN _BIT(0)
+
+/*
+ * clkpwr_sw_int register definitions
+ */
+#define LPC32XX_CLKPWR_SW_INT(n) (_BIT(0) | (((n) & 0x7F) << 1))
+#define LPC32XX_CLKPWR_SW_GET_ARG(n) (((n) & 0xFE) >> 1)
+
+/*
+ * clkpwr_i2c_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE _BIT(4)
+#define LPC32XX_CLKPWR_I2CCLK_I2C2HI_DRIVE _BIT(3)
+#define LPC32XX_CLKPWR_I2CCLK_I2C1HI_DRIVE _BIT(2)
+#define LPC32XX_CLKPWR_I2CCLK_I2C2CLK_EN _BIT(1)
+#define LPC32XX_CLKPWR_I2CCLK_I2C1CLK_EN _BIT(0)
+
+/*
+ * clkpwr_key_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_KEYCLKCTRL_CLK_EN 0x1
+
+/*
+ * clkpwr_adc_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_ADC32CLKCTRL_CLK_EN 0x1
+
+/*
+ * clkpwr_pwm_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_PWMCLK_PWM2_DIV(n) (((n) & 0xF) << 8)
+#define LPC32XX_CLKPWR_PWMCLK_PWM1_DIV(n) (((n) & 0xF) << 4)
+#define LPC32XX_CLKPWR_PWMCLK_PWM2SEL_PCLK 0x8
+#define LPC32XX_CLKPWR_PWMCLK_PWM2CLK_EN 0x4
+#define LPC32XX_CLKPWR_PWMCLK_PWM1SEL_PCLK 0x2
+#define LPC32XX_CLKPWR_PWMCLK_PWM1CLK_EN 0x1
+
+/*
+ * clkpwr_timer_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_PWMCLK_HSTIMER_EN 0x2
+#define LPC32XX_CLKPWR_PWMCLK_WDOG_EN 0x1
+
+/*
+ * clkpwr_timers_pwms_clk_ctrl_1 register definitions
+ */
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER3_EN 0x20
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER2_EN 0x10
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER1_EN 0x08
+#define LPC32XX_CLKPWR_TMRPWMCLK_TIMER0_EN 0x04
+#define LPC32XX_CLKPWR_TMRPWMCLK_PWM4_EN 0x02
+#define LPC32XX_CLKPWR_TMRPWMCLK_PWM3_EN 0x01
+
+/*
+ * clkpwr_spi_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI2DATIO 0x80
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI2CLK 0x40
+#define LPC32XX_CLKPWR_SPICLK_USE_SPI2 0x20
+#define LPC32XX_CLKPWR_SPICLK_SPI2CLK_EN 0x10
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI1DATIO 0x08
+#define LPC32XX_CLKPWR_SPICLK_SET_SPI1CLK 0x04
+#define LPC32XX_CLKPWR_SPICLK_USE_SPI1 0x02
+#define LPC32XX_CLKPWR_SPICLK_SPI1CLK_EN 0x01
+
+/*
+ * clkpwr_nand_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_NANDCLK_INTSEL_MLC 0x20
+#define LPC32XX_CLKPWR_NANDCLK_DMA_RNB 0x10
+#define LPC32XX_CLKPWR_NANDCLK_DMA_INT 0x08
+#define LPC32XX_CLKPWR_NANDCLK_SEL_SLC 0x04
+#define LPC32XX_CLKPWR_NANDCLK_MLCCLK_EN 0x02
+#define LPC32XX_CLKPWR_NANDCLK_SLCCLK_EN 0x01
+
+/*
+ * clkpwr_uart3_clk_ctrl, clkpwr_uart4_clk_ctrl, clkpwr_uart5_clk_ctrl
+ * and clkpwr_uart6_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_UART_Y_DIV(y) ((y) & 0xFF)
+#define LPC32XX_CLKPWR_UART_X_DIV(x) (((x) & 0xFF) << 8)
+#define LPC32XX_CLKPWR_UART_USE_HCLK _BIT(16)
+
+/*
+ * clkpwr_irda_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_IRDA_Y_DIV(y) ((y) & 0xFF)
+#define LPC32XX_CLKPWR_IRDA_X_DIV(x) (((x) & 0xFF) << 8)
+
+/*
+ * clkpwr_uart_clk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART6_EN _BIT(3)
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART5_EN _BIT(2)
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART4_EN _BIT(1)
+#define LPC32XX_CLKPWR_UARTCLKCTRL_UART3_EN _BIT(0)
+
+/*
+ * clkpwr_dmaclk_ctrl register definitions
+ */
+#define LPC32XX_CLKPWR_DMACLKCTRL_CLK_EN 0x1
+
+/*
+ * clkpwr_autoclock register definitions
+ */
+#define LPC32XX_CLKPWR_AUTOCLK_USB_EN 0x40
+#define LPC32XX_CLKPWR_AUTOCLK_IRAM_EN 0x02
+#define LPC32XX_CLKPWR_AUTOCLK_IROM_EN 0x01
+
+/*
+ * Interrupt controller register offsets
+ */
+#define LPC32XX_INTC_MASK(x) io_p2v((x) + 0x00)
+#define LPC32XX_INTC_RAW_STAT(x) io_p2v((x) + 0x04)
+#define LPC32XX_INTC_STAT(x) io_p2v((x) + 0x08)
+#define LPC32XX_INTC_POLAR(x) io_p2v((x) + 0x0C)
+#define LPC32XX_INTC_ACT_TYPE(x) io_p2v((x) + 0x10)
+#define LPC32XX_INTC_TYPE(x) io_p2v((x) + 0x14)
+
+/*
+ * Timer/counter register offsets
+ */
+#define LCP32XX_TIMER_IR(x) io_p2v((x) + 0x00)
+#define LCP32XX_TIMER_TCR(x) io_p2v((x) + 0x04)
+#define LCP32XX_TIMER_TC(x) io_p2v((x) + 0x08)
+#define LCP32XX_TIMER_PR(x) io_p2v((x) + 0x0C)
+#define LCP32XX_TIMER_PC(x) io_p2v((x) + 0x10)
+#define LCP32XX_TIMER_MCR(x) io_p2v((x) + 0x14)
+#define LCP32XX_TIMER_MR0(x) io_p2v((x) + 0x18)
+#define LCP32XX_TIMER_MR1(x) io_p2v((x) + 0x1C)
+#define LCP32XX_TIMER_MR2(x) io_p2v((x) + 0x20)
+#define LCP32XX_TIMER_MR3(x) io_p2v((x) + 0x24)
+#define LCP32XX_TIMER_CCR(x) io_p2v((x) + 0x28)
+#define LCP32XX_TIMER_CR0(x) io_p2v((x) + 0x2C)
+#define LCP32XX_TIMER_CR1(x) io_p2v((x) + 0x30)
+#define LCP32XX_TIMER_CR2(x) io_p2v((x) + 0x34)
+#define LCP32XX_TIMER_CR3(x) io_p2v((x) + 0x38)
+#define LCP32XX_TIMER_EMR(x) io_p2v((x) + 0x3C)
+#define LCP32XX_TIMER_CTCR(x) io_p2v((x) + 0x70)
+
+/*
+ * ir register definitions
+ */
+#define LCP32XX_TIMER_CNTR_MTCH_BIT(n) (1 << ((n) & 0x3))
+#define LCP32XX_TIMER_CNTR_CAPT_BIT(n) (1 << (4 + ((n) & 0x3)))
+
+/*
+ * tcr register definitions
+ */
+#define LCP32XX_TIMER_CNTR_TCR_EN 0x1
+#define LCP32XX_TIMER_CNTR_TCR_RESET 0x2
+
+/*
+ * mcr register definitions
+ */
+#define LCP32XX_TIMER_CNTR_MCR_MTCH(n) (0x1 << ((n) * 3))
+#define LCP32XX_TIMER_CNTR_MCR_RESET(n) (0x1 << (((n) * 3) + 1))
+#define LCP32XX_TIMER_CNTR_MCR_STOP(n) (0x1 << (((n) * 3) + 2))
+
+/*
+ * Standard UART register offsets
+ */
+#define LPC32XX_UART_DLL_FIFO(x) io_p2v((x) + 0x00)
+#define LPC32XX_UART_DLM_IER(x) io_p2v((x) + 0x04)
+#define LPC32XX_UART_IIR_FCR(x) io_p2v((x) + 0x08)
+#define LPC32XX_UART_LCR(x) io_p2v((x) + 0x0C)
+#define LPC32XX_UART_MODEM_CTRL(x) io_p2v((x) + 0x10)
+#define LPC32XX_UART_LSR(x) io_p2v((x) + 0x14)
+#define LPC32XX_UART_MODEM_STATUS(x) io_p2v((x) + 0x18)
+#define LPC32XX_UART_RXLEV(x) io_p2v((x) + 0x1C)
+
+/*
+ * UART control structure offsets
+ */
+#define _UCREG(x) io_p2v(\
+ LPC32XX_UART_CTRL_BASE + (x))
+#define LPC32XX_UARTCTL_CTRL _UCREG(0x00)
+#define LPC32XX_UARTCTL_CLKMODE _UCREG(0x04)
+#define LPC32XX_UARTCTL_CLOOP _UCREG(0x08)
+
+/*
+ * ctrl register definitions
+ */
+#define LPC32XX_UART_U3_MD_CTRL_EN _BIT(11)
+#define LPC32XX_UART_IRRX6_INV_EN _BIT(10)
+#define LPC32XX_UART_HDPX_EN _BIT(9)
+#define LPC32XX_UART_UART6_IRDAMOD_BYPASS _BIT(5)
+#define LPC32XX_RT_IRTX6_INV_EN _BIT(4)
+#define LPC32XX_RT_IRTX6_INV_MIR_EN _BIT(3)
+#define LPC32XX_RT_RX_IRPULSE_3_16_115K _BIT(2)
+#define LPC32XX_RT_TX_IRPULSE_3_16_115K _BIT(1)
+#define LPC32XX_UART_U5_ROUTE_TO_USB _BIT(0)
+
+/*
+ * clkmode register definitions
+ */
+#define LPC32XX_UART_ENABLED_CLOCKS(n) (((n) >> 16) & 0x7F)
+#define LPC32XX_UART_ENABLED_CLOCK(n, u) (((n) >> (16 + (u))) & 0x1)
+#define LPC32XX_UART_ENABLED_CLKS_ANY _BIT(14)
+#define LPC32XX_UART_CLKMODE_OFF 0x0
+#define LPC32XX_UART_CLKMODE_ON 0x1
+#define LPC32XX_UART_CLKMODE_AUTO 0x2
+#define LPC32XX_UART_CLKMODE_MASK(u) (0x3 << ((((u) - 3) * 2) + 4))
+#define LPC32XX_UART_CLKMODE_LOAD(m, u) ((m) << ((((u) - 3) * 2) + 4))
+
+/*
+ * GPIO Module Register offsets
+ */
+#define _GPREG(x) io_p2v(LPC32XX_GPIO_BASE + (x))
+#define LPC32XX_GPIO_P_MUX_SET _GPREG(0x100)
+#define LPC32XX_GPIO_P_MUX_CLR _GPREG(0x104)
+#define LPC32XX_GPIO_P_MUX_STATE _GPREG(0x108)
+#define LPC32XX_GPIO_P3_MUX_SET _GPREG(0x110)
+#define LPC32XX_GPIO_P3_MUX_CLR _GPREG(0x114)
+#define LPC32XX_GPIO_P3_MUX_STATE _GPREG(0x118)
+#define LPC32XX_GPIO_P0_MUX_SET _GPREG(0x120)
+#define LPC32XX_GPIO_P0_MUX_CLR _GPREG(0x124)
+#define LPC32XX_GPIO_P0_MUX_STATE _GPREG(0x128)
+#define LPC32XX_GPIO_P1_MUX_SET _GPREG(0x130)
+#define LPC32XX_GPIO_P1_MUX_CLR _GPREG(0x134)
+#define LPC32XX_GPIO_P1_MUX_STATE _GPREG(0x138)
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/system.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+static void arch_idle(void)
+{
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+ extern void lpc32xx_watchdog_reset(void);
+
+ switch (mode) {
+ case 's':
+ case 'h':
+ printk(KERN_CRIT "RESET: Rebooting system\n");
+
+ /* Disable interrupts */
+ local_irq_disable();
+
+ lpc32xx_watchdog_reset();
+ break;
+
+ default:
+ /* Do nothing */
+ break;
+ }
+
+ /* Wait for watchdog to reset system */
+ while (1)
+ ;
+}
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/timex.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/*
+ * Rate in Hz of the main system oscillator. This value should match
+ * the value 'MAIN_OSC_FREQ' in platform.h
+ */
+#define CLOCK_TICK_RATE 13000000
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/uncompress.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_UNCOMPRESS_H
+#define __ASM_ARM_ARCH_UNCOMPRESS_H
+
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+/*
+ * Uncompress output is hardcoded to standard UART 5
+ */
+
+#define UART_FIFO_CTL_TX_RESET (1 << 2)
+#define UART_STATUS_TX_MT (1 << 6)
+
+#define _UARTREG(x) (void __iomem *)(LPC32XX_UART5_BASE + (x))
+
+#define LPC32XX_UART_DLLFIFO_O 0x00
+#define LPC32XX_UART_IIRFCR_O 0x08
+#define LPC32XX_UART_LSR_O 0x14
+
+static inline void putc(int ch)
+{
+ /* Wait for transmit FIFO to empty */
+ while ((__raw_readl(_UARTREG(LPC32XX_UART_LSR_O)) &
+ UART_STATUS_TX_MT) == 0)
+ ;
+
+ __raw_writel((u32) ch, _UARTREG(LPC32XX_UART_DLLFIFO_O));
+}
+
+static inline void flush(void)
+{
+ __raw_writel(__raw_readl(_UARTREG(LPC32XX_UART_IIRFCR_O)) |
+ UART_FIFO_CTL_TX_RESET, _UARTREG(LPC32XX_UART_IIRFCR_O));
+}
+
+/* NULL functions; we don't presently need them */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/include/mach/vmalloc.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END 0xF0000000
+
+#endif
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/irq.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+/*
+ * Default value representing the Activation polarity of all internal
+ * interrupt sources
+ */
+#define MIC_APR_DEFAULT 0x3FF0EFE0
+#define SIC1_APR_DEFAULT 0xFBD27186
+#define SIC2_APR_DEFAULT 0x801810C0
+
+/*
+ * Default value representing the Activation Type of all internal
+ * interrupt sources. All are level sensitive.
+ */
+#define MIC_ATR_DEFAULT 0x00000000
+#define SIC1_ATR_DEFAULT 0x00026000
+#define SIC2_ATR_DEFAULT 0x00000000
+
+struct lpc32xx_event_group_regs {
+ void __iomem *enab_reg;
+ void __iomem *edge_reg;
+ void __iomem *maskstat_reg;
+ void __iomem *rawstat_reg;
+};
+
+static const struct lpc32xx_event_group_regs lpc32xx_event_int_regs = {
+ .enab_reg = LPC32XX_CLKPWR_INT_ER,
+ .edge_reg = LPC32XX_CLKPWR_INT_AP,
+ .maskstat_reg = LPC32XX_CLKPWR_INT_SR,
+ .rawstat_reg = LPC32XX_CLKPWR_INT_RS,
+};
+
+static const struct lpc32xx_event_group_regs lpc32xx_event_pin_regs = {
+ .enab_reg = LPC32XX_CLKPWR_PIN_ER,
+ .edge_reg = LPC32XX_CLKPWR_PIN_AP,
+ .maskstat_reg = LPC32XX_CLKPWR_PIN_SR,
+ .rawstat_reg = LPC32XX_CLKPWR_PIN_RS,
+};
+
+struct lpc32xx_event_info {
+ const struct lpc32xx_event_group_regs *event_group;
+ u32 mask;
+};
+
+/*
+ * Maps an IRQ number to and event mask and register
+ */
+static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = {
+ [IRQ_LPC32XX_GPI_08] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_08_BIT,
+ },
+ [IRQ_LPC32XX_GPI_09] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_09_BIT,
+ },
+ [IRQ_LPC32XX_GPI_19] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_19_BIT,
+ },
+ [IRQ_LPC32XX_GPI_07] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_07_BIT,
+ },
+ [IRQ_LPC32XX_GPI_00] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_00_BIT,
+ },
+ [IRQ_LPC32XX_GPI_01] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_01_BIT,
+ },
+ [IRQ_LPC32XX_GPI_02] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_02_BIT,
+ },
+ [IRQ_LPC32XX_GPI_03] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_03_BIT,
+ },
+ [IRQ_LPC32XX_GPI_04] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_04_BIT,
+ },
+ [IRQ_LPC32XX_GPI_05] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_05_BIT,
+ },
+ [IRQ_LPC32XX_GPI_06] = {
+ .event_group = &lpc32xx_event_pin_regs,
+ .mask = LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT,
+ },
+ [IRQ_LPC32XX_GPIO_00] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT,
+ },
+ [IRQ_LPC32XX_GPIO_01] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_GPIO_01_BIT,
+ },
+ [IRQ_LPC32XX_GPIO_02] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_GPIO_02_BIT,
+ },
+ [IRQ_LPC32XX_GPIO_03] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_GPIO_03_BIT,
+ },
+ [IRQ_LPC32XX_GPIO_04] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_GPIO_04_BIT,
+ },
+ [IRQ_LPC32XX_GPIO_05] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_GPIO_05_BIT,
+ },
+ [IRQ_LPC32XX_KEY] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_KEY_BIT,
+ },
+ [IRQ_LPC32XX_USB_OTG_ATX] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT,
+ },
+ [IRQ_LPC32XX_USB_HOST] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_USB_BIT,
+ },
+ [IRQ_LPC32XX_RTC] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_RTC_BIT,
+ },
+ [IRQ_LPC32XX_MSTIMER] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT,
+ },
+ [IRQ_LPC32XX_TS_AUX] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_TS_AUX_BIT,
+ },
+ [IRQ_LPC32XX_TS_P] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_TS_P_BIT,
+ },
+ [IRQ_LPC32XX_TS_IRQ] = {
+ .event_group = &lpc32xx_event_int_regs,
+ .mask = LPC32XX_CLKPWR_INTSRC_ADC_BIT,
+ },
+};
+
+static void get_controller(unsigned int irq, unsigned int *base,
+ unsigned int *irqbit)
+{
+ if (irq < 32) {
+ *base = LPC32XX_MIC_BASE;
+ *irqbit = 1 << irq;
+ } else if (irq < 64) {
+ *base = LPC32XX_SIC1_BASE;
+ *irqbit = 1 << (irq - 32);
+ } else {
+ *base = LPC32XX_SIC2_BASE;
+ *irqbit = 1 << (irq - 64);
+ }
+}
+
+static void lpc32xx_mask_irq(unsigned int irq)
+{
+ unsigned int reg, ctrl, mask;
+
+ get_controller(irq, &ctrl, &mask);
+
+ reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask;
+ __raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
+}
+
+static void lpc32xx_unmask_irq(unsigned int irq)
+{
+ unsigned int reg, ctrl, mask;
+
+ get_controller(irq, &ctrl, &mask);
+
+ reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask;
+ __raw_writel(reg, LPC32XX_INTC_MASK(ctrl));
+}
+
+static void lpc32xx_ack_irq(unsigned int irq)
+{
+ unsigned int ctrl, mask;
+
+ get_controller(irq, &ctrl, &mask);
+
+ __raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl));
+
+ /* Also need to clear pending wake event */
+ if (lpc32xx_events[irq].mask != 0)
+ __raw_writel(lpc32xx_events[irq].mask,
+ lpc32xx_events[irq].event_group->rawstat_reg);
+}
+
+static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level,
+ int use_edge)
+{
+ unsigned int reg, ctrl, mask;
+
+ get_controller(irq, &ctrl, &mask);
+
+ /* Activation level, high or low */
+ reg = __raw_readl(LPC32XX_INTC_POLAR(ctrl));
+ if (use_high_level)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ __raw_writel(reg, LPC32XX_INTC_POLAR(ctrl));
+
+ /* Activation type, edge or level */
+ reg = __raw_readl(LPC32XX_INTC_ACT_TYPE(ctrl));
+ if (use_edge)
+ reg |= mask;
+ else
+ reg &= ~mask;
+ __raw_writel(reg, LPC32XX_INTC_ACT_TYPE(ctrl));
+
+ /* Use same polarity for the wake events */
+ if (lpc32xx_events[irq].mask != 0) {
+ reg = __raw_readl(lpc32xx_events[irq].event_group->edge_reg);
+
+ if (use_high_level)
+ reg |= lpc32xx_events[irq].mask;
+ else
+ reg &= ~lpc32xx_events[irq].mask;
+
+ __raw_writel(reg, lpc32xx_events[irq].event_group->edge_reg);
+ }
+}
+
+static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
+{
+ switch (type) {
+ case IRQ_TYPE_EDGE_RISING:
+ /* Rising edge sensitive */
+ __lpc32xx_set_irq_type(irq, 1, 1);
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ /* Falling edge sensitive */
+ __lpc32xx_set_irq_type(irq, 0, 1);
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ /* Low level sensitive */
+ __lpc32xx_set_irq_type(irq, 0, 0);
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ /* High level sensitive */
+ __lpc32xx_set_irq_type(irq, 1, 0);
+ break;
+
+ /* Other modes are not supported */
+ default:
+ return -EINVAL;
+ }
+
+ /* Ok to use the level handler for all types */
+ set_irq_handler(irq, handle_level_irq);
+
+ return 0;
+}
+
+static int lpc32xx_irq_wake(unsigned int irqno, unsigned int state)
+{
+ unsigned long eventreg;
+
+ if (lpc32xx_events[irqno].mask != 0) {
+ eventreg = __raw_readl(lpc32xx_events[irqno].
+ event_group->enab_reg);
+
+ if (state)
+ eventreg |= lpc32xx_events[irqno].mask;
+ else
+ eventreg &= ~lpc32xx_events[irqno].mask;
+
+ __raw_writel(eventreg,
+ lpc32xx_events[irqno].event_group->enab_reg);
+
+ return 0;
+ }
+
+ /* Clear event */
+ __raw_writel(lpc32xx_events[irqno].mask,
+ lpc32xx_events[irqno].event_group->rawstat_reg);
+
+ return -ENODEV;
+}
+
+static void __init lpc32xx_set_default_mappings(unsigned int apr,
+ unsigned int atr, unsigned int offset)
+{
+ unsigned int i;
+
+ /* Set activation levels for each interrupt */
+ i = 0;
+ while (i < 32) {
+ __lpc32xx_set_irq_type(offset + i, ((apr >> i) & 0x1),
+ ((atr >> i) & 0x1));
+ i++;
+ }
+}
+
+static struct irq_chip lpc32xx_irq_chip = {
+ .ack = lpc32xx_ack_irq,
+ .mask = lpc32xx_mask_irq,
+ .unmask = lpc32xx_unmask_irq,
+ .set_type = lpc32xx_set_irq_type,
+ .set_wake = lpc32xx_irq_wake
+};
+
+static void lpc32xx_sic1_handler(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned long ints = __raw_readl(LPC32XX_INTC_STAT(LPC32XX_SIC1_BASE));
+
+ while (ints != 0) {
+ int irqno = fls(ints) - 1;
+
+ ints &= ~(1 << irqno);
+
+ generic_handle_irq(LPC32XX_SIC1_IRQ(irqno));
+ }
+}
+
+static void lpc32xx_sic2_handler(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned long ints = __raw_readl(LPC32XX_INTC_STAT(LPC32XX_SIC2_BASE));
+
+ while (ints != 0) {
+ int irqno = fls(ints) - 1;
+
+ ints &= ~(1 << irqno);
+
+ generic_handle_irq(LPC32XX_SIC2_IRQ(irqno));
+ }
+}
+
+void __init lpc32xx_init_irq(void)
+{
+ unsigned int i;
+
+ /* Setup MIC */
+ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE));
+ __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_MIC_BASE));
+ __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_MIC_BASE));
+
+ /* Setup SIC1 */
+ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE));
+ __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE));
+ __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE));
+
+ /* Setup SIC2 */
+ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE));
+ __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE));
+ __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE));
+
+ /* Configure supported IRQ's */
+ for (i = 0; i < NR_IRQS; i++) {
+ set_irq_chip(i, &lpc32xx_irq_chip);
+ set_irq_handler(i, handle_level_irq);
+ set_irq_flags(i, IRQF_VALID);
+ }
+
+ /* Set default mappings */
+ lpc32xx_set_default_mappings(MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0);
+ lpc32xx_set_default_mappings(SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, 32);
+ lpc32xx_set_default_mappings(SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, 64);
+
+ /* mask all interrupts except SUBIRQ */
+ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE));
+ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE));
+ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE));
+
+ /* MIC SUBIRQx interrupts will route handling to the chain handlers */
+ set_irq_chained_handler(IRQ_LPC32XX_SUB1IRQ, lpc32xx_sic1_handler);
+ set_irq_chained_handler(IRQ_LPC32XX_SUB2IRQ, lpc32xx_sic2_handler);
+
+ /* Initially disable all wake events */
+ __raw_writel(0, LPC32XX_CLKPWR_P01_ER);
+ __raw_writel(0, LPC32XX_CLKPWR_INT_ER);
+ __raw_writel(0, LPC32XX_CLKPWR_PIN_ER);
+
+ /*
+ * Default wake activation polarities, all pin sources are low edge
+ * triggered
+ */
+ __raw_writel(LPC32XX_CLKPWR_INTSRC_TS_P_BIT |
+ LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT |
+ LPC32XX_CLKPWR_INTSRC_RTC_BIT,
+ LPC32XX_CLKPWR_INT_AP);
+ __raw_writel(0, LPC32XX_CLKPWR_PIN_AP);
+
+ /* Clear latched wake event states */
+ __raw_writel(__raw_readl(LPC32XX_CLKPWR_PIN_RS),
+ LPC32XX_CLKPWR_PIN_RS);
+ __raw_writel(__raw_readl(LPC32XX_CLKPWR_INT_RS),
+ LPC32XX_CLKPWR_INT_RS);
+}
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/phy3250.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/amba/pl022.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+/*
+ * Mapped GPIOLIB GPIOs
+ */
+#define SPI0_CS_GPIO LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5)
+#define LCD_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 0)
+#define BKL_POWER_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 4)
+#define LED_GPIO LPC32XX_GPIO(LPC32XX_GPO_P3_GRP, 1)
+
+/*
+ * AMBA LCD controller
+ */
+static struct clcd_panel conn_lcd_panel = {
+ .mode = {
+ .name = "QVGA portrait",
+ .refresh = 60,
+ .xres = 240,
+ .yres = 320,
+ .pixclock = 191828,
+ .left_margin = 22,
+ .right_margin = 11,
+ .upper_margin = 2,
+ .lower_margin = 1,
+ .hsync_len = 5,
+ .vsync_len = 2,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+ },
+ .width = -1,
+ .height = -1,
+ .tim2 = (TIM2_IVS | TIM2_IHS),
+ .cntl = (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) |
+ CNTL_LCDBPP16_565),
+ .bpp = 16,
+};
+#define PANEL_SIZE (3 * SZ_64K)
+
+static int lpc32xx_clcd_setup(struct clcd_fb *fb)
+{
+ dma_addr_t dma;
+
+ fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+ PANEL_SIZE, &dma, GFP_KERNEL);
+ if (!fb->fb.screen_base) {
+ printk(KERN_ERR "CLCD: unable to map framebuffer\n");
+ return -ENOMEM;
+ }
+
+ fb->fb.fix.smem_start = dma;
+ fb->fb.fix.smem_len = PANEL_SIZE;
+ fb->panel = &conn_lcd_panel;
+
+ if (gpio_request(LCD_POWER_GPIO, "LCD power"))
+ printk(KERN_ERR "Error requesting gpio %u",
+ LCD_POWER_GPIO);
+ else if (gpio_direction_output(LCD_POWER_GPIO, 1))
+ printk(KERN_ERR "Error setting gpio %u to output",
+ LCD_POWER_GPIO);
+
+ if (gpio_request(BKL_POWER_GPIO, "LCD backlight power"))
+ printk(KERN_ERR "Error requesting gpio %u",
+ BKL_POWER_GPIO);
+ else if (gpio_direction_output(BKL_POWER_GPIO, 1))
+ printk(KERN_ERR "Error setting gpio %u to output",
+ BKL_POWER_GPIO);
+
+ return 0;
+}
+
+static int lpc32xx_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+ return dma_mmap_writecombine(&fb->dev->dev, vma,
+ fb->fb.screen_base, fb->fb.fix.smem_start,
+ fb->fb.fix.smem_len);
+}
+
+static void lpc32xx_clcd_remove(struct clcd_fb *fb)
+{
+ dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+ fb->fb.screen_base, fb->fb.fix.smem_start);
+}
+
+/*
+ * On some early LCD modules (1307.0), the backlight logic is inverted.
+ * For those board variants, swap the disable and enable states for
+ * BKL_POWER_GPIO.
+*/
+static void clcd_disable(struct clcd_fb *fb)
+{
+ gpio_set_value(BKL_POWER_GPIO, 0);
+ gpio_set_value(LCD_POWER_GPIO, 0);
+}
+
+static void clcd_enable(struct clcd_fb *fb)
+{
+ gpio_set_value(BKL_POWER_GPIO, 1);
+ gpio_set_value(LCD_POWER_GPIO, 1);
+}
+
+static struct clcd_board lpc32xx_clcd_data = {
+ .name = "Phytec LCD",
+ .check = clcdfb_check,
+ .decode = clcdfb_decode,
+ .disable = clcd_disable,
+ .enable = clcd_enable,
+ .setup = lpc32xx_clcd_setup,
+ .mmap = lpc32xx_clcd_mmap,
+ .remove = lpc32xx_clcd_remove,
+};
+
+static struct amba_device lpc32xx_clcd_device = {
+ .dev = {
+ .coherent_dma_mask = ~0,
+ .init_name = "dev:clcd",
+ .platform_data = &lpc32xx_clcd_data,
+ },
+ .res = {
+ .start = LPC32XX_LCD_BASE,
+ .end = (LPC32XX_LCD_BASE + SZ_4K - 1),
+ .flags = IORESOURCE_MEM,
+ },
+ .dma_mask = ~0,
+ .irq = {IRQ_LPC32XX_LCD, NO_IRQ},
+};
+
+/*
+ * AMBA SSP (SPI)
+ */
+static void phy3250_spi_cs_set(u32 control)
+{
+ gpio_set_value(SPI0_CS_GPIO, (int) control);
+}
+
+static struct pl022_config_chip spi0_chip_info = {
+ .lbm = LOOPBACK_DISABLED,
+ .com_mode = INTERRUPT_TRANSFER,
+ .iface = SSP_INTERFACE_MOTOROLA_SPI,
+ .hierarchy = SSP_MASTER,
+ .slave_tx_disable = 0,
+ .endian_tx = SSP_TX_LSB,
+ .endian_rx = SSP_RX_LSB,
+ .data_size = SSP_DATA_BITS_8,
+ .rx_lev_trig = SSP_RX_4_OR_MORE_ELEM,
+ .tx_lev_trig = SSP_TX_4_OR_MORE_EMPTY_LOC,
+ .clk_phase = SSP_CLK_FIRST_EDGE,
+ .clk_pol = SSP_CLK_POL_IDLE_LOW,
+ .ctrl_len = SSP_BITS_8,
+ .wait_state = SSP_MWIRE_WAIT_ZERO,
+ .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
+ .cs_control = phy3250_spi_cs_set,
+};
+
+static struct pl022_ssp_controller lpc32xx_ssp0_data = {
+ .bus_id = 0,
+ .num_chipselect = 1,
+ .enable_dma = 0,
+};
+
+static struct amba_device lpc32xx_ssp0_device = {
+ .dev = {
+ .coherent_dma_mask = ~0,
+ .init_name = "dev:ssp0",
+ .platform_data = &lpc32xx_ssp0_data,
+ },
+ .res = {
+ .start = LPC32XX_SSP0_BASE,
+ .end = (LPC32XX_SSP0_BASE + SZ_4K - 1),
+ .flags = IORESOURCE_MEM,
+ },
+ .dma_mask = ~0,
+ .irq = {IRQ_LPC32XX_SSP0, NO_IRQ},
+};
+
+/* AT25 driver registration */
+static int __init phy3250_spi_board_register(void)
+{
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+ static struct spi_board_info info[] = {
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 5000000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .controller_data = &spi0_chip_info,
+ },
+ };
+
+#else
+ static struct spi_eeprom eeprom = {
+ .name = "at25256a",
+ .byte_len = 0x8000,
+ .page_size = 64,
+ .flags = EE_ADDR2,
+ };
+
+ static struct spi_board_info info[] = {
+ {
+ .modalias = "at25",
+ .max_speed_hz = 5000000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .platform_data = &eeprom,
+ .controller_data = &spi0_chip_info,
+ },
+ };
+#endif
+ return spi_register_board_info(info, ARRAY_SIZE(info));
+}
+arch_initcall(phy3250_spi_board_register);
+
+static struct i2c_board_info __initdata phy3250_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("pcf8563", 0x51),
+ },
+};
+
+static struct gpio_led phy_leds[] = {
+ {
+ .name = "led0",
+ .gpio = LED_GPIO,
+ .active_low = 1,
+ .default_trigger = "heartbeat",
+ },
+};
+
+static struct gpio_led_platform_data led_data = {
+ .leds = phy_leds,
+ .num_leds = ARRAY_SIZE(phy_leds),
+};
+
+static struct platform_device lpc32xx_gpio_led_device = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev.platform_data = &led_data,
+};
+
+static struct platform_device *phy3250_devs[] __initdata = {
+ &lpc32xx_i2c0_device,
+ &lpc32xx_i2c1_device,
+ &lpc32xx_i2c2_device,
+ &lpc32xx_watchdog_device,
+ &lpc32xx_gpio_led_device,
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+ &lpc32xx_clcd_device,
+ &lpc32xx_ssp0_device,
+};
+
+/*
+ * Board specific functions
+ */
+static void __init phy3250_board_init(void)
+{
+ u32 tmp;
+ int i;
+
+ lpc32xx_gpio_init();
+
+ /* Register GPIOs used on this board */
+ if (gpio_request(SPI0_CS_GPIO, "spi0 cs"))
+ printk(KERN_ERR "Error requesting gpio %u",
+ SPI0_CS_GPIO);
+ else if (gpio_direction_output(SPI0_CS_GPIO, 1))
+ printk(KERN_ERR "Error setting gpio %u to output",
+ SPI0_CS_GPIO);
+
+ /* Setup network interface for RMII mode */
+ tmp = __raw_readl(LPC32XX_CLKPWR_MACCLK_CTRL);
+ tmp &= ~LPC32XX_CLKPWR_MACCTRL_PINS_MSK;
+ tmp |= LPC32XX_CLKPWR_MACCTRL_USE_RMII_PINS;
+ __raw_writel(tmp, LPC32XX_CLKPWR_MACCLK_CTRL);
+
+ /* Setup SLC NAND controller muxing */
+ __raw_writel(LPC32XX_CLKPWR_NANDCLK_SEL_SLC,
+ LPC32XX_CLKPWR_NAND_CLK_CTRL);
+
+ /* Setup LCD muxing to RGB565 */
+ tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL) &
+ ~(LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_MSK |
+ LPC32XX_CLKPWR_LCDCTRL_PSCALE_MSK);
+ tmp |= LPC32XX_CLKPWR_LCDCTRL_LCDTYPE_TFT16;
+ __raw_writel(tmp, LPC32XX_CLKPWR_LCDCLK_CTRL);
+
+ /* Set up I2C pull levels */
+ tmp = __raw_readl(LPC32XX_CLKPWR_I2C_CLK_CTRL);
+ tmp |= LPC32XX_CLKPWR_I2CCLK_USBI2CHI_DRIVE |
+ LPC32XX_CLKPWR_I2CCLK_I2C2HI_DRIVE;
+ __raw_writel(tmp, LPC32XX_CLKPWR_I2C_CLK_CTRL);
+
+ /* Disable IrDA pulsing support on UART6 */
+ tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
+ tmp |= LPC32XX_UART_UART6_IRDAMOD_BYPASS;
+ __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
+
+ /* Enable DMA for I2S1 channel */
+ tmp = __raw_readl(LPC32XX_CLKPWR_I2S_CLK_CTRL);
+ tmp = LPC32XX_CLKPWR_I2SCTRL_I2S1_USE_DMA;
+ __raw_writel(tmp, LPC32XX_CLKPWR_I2S_CLK_CTRL);
+
+ lpc32xx_serial_init();
+
+ /*
+ * AMBA peripheral clocks need to be enabled prior to AMBA device
+ * detection or a data fault will occur, so enable the clocks
+ * here. However, we don't want to enable them if the peripheral
+ * isn't included in the image
+ */
+#ifdef CONFIG_FB_ARMCLCD
+ tmp = __raw_readl(LPC32XX_CLKPWR_LCDCLK_CTRL);
+ __raw_writel((tmp | LPC32XX_CLKPWR_LCDCTRL_CLK_EN),
+ LPC32XX_CLKPWR_LCDCLK_CTRL);
+#endif
+#ifdef CONFIG_SPI_PL022
+ tmp = __raw_readl(LPC32XX_CLKPWR_SSP_CLK_CTRL);
+ __raw_writel((tmp | LPC32XX_CLKPWR_SSPCTRL_SSPCLK0_EN),
+ LPC32XX_CLKPWR_SSP_CLK_CTRL);
+#endif
+
+ platform_add_devices(phy3250_devs, ARRAY_SIZE(phy3250_devs));
+ for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+ struct amba_device *d = amba_devs[i];
+ amba_device_register(d, &iomem_resource);
+ }
+
+ /* Test clock needed for UDA1380 initial init */
+ __raw_writel(LPC32XX_CLKPWR_TESTCLK2_SEL_MOSC |
+ LPC32XX_CLKPWR_TESTCLK_TESTCLK2_EN,
+ LPC32XX_CLKPWR_TEST_CLK_SEL);
+
+ i2c_register_board_info(0, phy3250_i2c_board_info,
+ ARRAY_SIZE(phy3250_i2c_board_info));
+}
+
+static int __init lpc32xx_display_uid(void)
+{
+ u32 uid[4];
+
+ lpc32xx_get_uid(uid);
+
+ printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
+ uid[3], uid[2], uid[1], uid[0]);
+
+ return 1;
+}
+arch_initcall(lpc32xx_display_uid);
+
+MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
+ /* Maintainer: Kevin Wells, NXP Semiconductors */
+ .phys_io = LPC32XX_UART5_BASE,
+ .io_pg_offst = ((IO_ADDRESS(LPC32XX_UART5_BASE))>>18) & 0xfffc,
+ .boot_params = 0x80000100,
+ .map_io = lpc32xx_map_io,
+ .init_irq = lpc32xx_init_irq,
+ .timer = &lpc32xx_timer,
+ .init_machine = phy3250_board_init,
+MACHINE_END
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/pm.c
+ *
+ * Original authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
+ * Modified by Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 2005 (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.
+ */
+
+/*
+ * LPC32XX CPU and system power management
+ *
+ * The LCP32XX has three CPU modes for controlling system power: run,
+ * direct-run, and halt modes. When switching between halt and run modes,
+ * the CPU transistions through direct-run mode. For Linux, direct-run
+ * mode is not used in normal operation. Halt mode is used when the
+ * system is fully suspended.
+ *
+ * Run mode:
+ * The ARM CPU clock (HCLK_PLL), HCLK bus clock, and PCLK bus clocks are
+ * derived from the HCLK PLL. The HCLK and PCLK bus rates are divided from
+ * the HCLK_PLL rate. Linux runs in this mode.
+ *
+ * Direct-run mode:
+ * The ARM CPU clock, HCLK bus clock, and PCLK bus clocks are driven from
+ * SYSCLK. SYSCLK is usually around 13MHz, but may vary based on SYSCLK
+ * source or the frequency of the main oscillator. In this mode, the
+ * HCLK_PLL can be safely enabled, changed, or disabled.
+ *
+ * Halt mode:
+ * SYSCLK is gated off and the CPU and system clocks are halted.
+ * Peripherals based on the 32KHz oscillator clock (ie, RTC, touch,
+ * key scanner, etc.) still operate if enabled. In this state, an enabled
+ * system event (ie, GPIO state change, RTC match, key press, etc.) will
+ * wake the system up back into direct-run mode.
+ *
+ * DRAM refresh
+ * DRAM clocking and refresh are slightly different for systems with DDR
+ * DRAM or regular SDRAM devices. If SDRAM is used in the system, the
+ * SDRAM will still be accessible in direct-run mode. In DDR based systems,
+ * a transistion to direct-run mode will stop all DDR accesses (no clocks).
+ * Because of this, the code to switch power modes and the code to enter
+ * and exit DRAM self-refresh modes must not be executed in DRAM. A small
+ * section of IRAM is used instead for this.
+ *
+ * Suspend is handled with the following logic:
+ * Backup a small area of IRAM used for the suspend code
+ * Copy suspend code to IRAM
+ * Transfer control to code in IRAM
+ * Places DRAMs in self-refresh mode
+ * Enter direct-run mode
+ * Save state of HCLK_PLL PLL
+ * Disable HCLK_PLL PLL
+ * Enter halt mode - CPU and buses will stop
+ * System enters direct-run mode when an enabled event occurs
+ * HCLK PLL state is restored
+ * Run mode is entered
+ * DRAMS are placed back into normal mode
+ * Code execution returns from IRAM
+ * IRAM code are used for suspend is restored
+ * Suspend mode is exited
+ */
+
+#include <linux/suspend.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include <asm/cacheflush.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+#include "clock.h"
+
+#define TEMP_IRAM_AREA IO_ADDRESS(LPC32XX_IRAM_BASE)
+
+/*
+ * Both STANDBY and MEM suspend states are handled the same with no
+ * loss of CPU or memory state
+ */
+static int lpc32xx_pm_enter(suspend_state_t state)
+{
+ int (*lpc32xx_suspend_ptr) (void);
+ void *iram_swap_area;
+
+ /* Allocate some space for temporary IRAM storage */
+ iram_swap_area = kmalloc(lpc32xx_sys_suspend_sz, GFP_KERNEL);
+ if (!iram_swap_area) {
+ printk(KERN_ERR
+ "PM Suspend: cannot allocate memory to save portion "
+ "of SRAM\n");
+ return -ENOMEM;
+ }
+
+ /* Backup a small area of IRAM used for the suspend code */
+ memcpy(iram_swap_area, (void *) TEMP_IRAM_AREA,
+ lpc32xx_sys_suspend_sz);
+
+ /*
+ * Copy code to suspend system into IRAM. The suspend code
+ * needs to run from IRAM as DRAM may no longer be available
+ * when the PLL is stopped.
+ */
+ memcpy((void *) TEMP_IRAM_AREA, &lpc32xx_sys_suspend,
+ lpc32xx_sys_suspend_sz);
+ flush_icache_range((unsigned long)TEMP_IRAM_AREA,
+ (unsigned long)(TEMP_IRAM_AREA) + lpc32xx_sys_suspend_sz);
+
+ /* Transfer to suspend code in IRAM */
+ lpc32xx_suspend_ptr = (void *) TEMP_IRAM_AREA;
+ flush_cache_all();
+ (void) lpc32xx_suspend_ptr();
+
+ /* Restore original IRAM contents */
+ memcpy((void *) TEMP_IRAM_AREA, iram_swap_area,
+ lpc32xx_sys_suspend_sz);
+
+ kfree(iram_swap_area);
+
+ return 0;
+}
+
+static struct platform_suspend_ops lpc32xx_pm_ops = {
+ .valid = suspend_valid_only_mem,
+ .enter = lpc32xx_pm_enter,
+};
+
+#define EMC_DYN_MEM_CTRL_OFS 0x20
+#define EMC_SRMMC (1 << 3)
+#define EMC_CTRL_REG io_p2v(LPC32XX_EMC_BASE + EMC_DYN_MEM_CTRL_OFS)
+static int __init lpc32xx_pm_init(void)
+{
+ /*
+ * Setup SDRAM self-refresh clock to automatically disable o
+ * start of self-refresh. This only needs to be done once.
+ */
+ __raw_writel(__raw_readl(EMC_CTRL_REG) | EMC_SRMMC, EMC_CTRL_REG);
+
+ suspend_set_ops(&lpc32xx_pm_ops);
+
+ return 0;
+}
+arch_initcall(lpc32xx_pm_init);
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/serial.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+#define LPC32XX_SUART_FIFO_SIZE 64
+
+/* Standard 8250/16550 compatible serial ports */
+static struct plat_serial8250_port serial_std_platform_data[] = {
+#ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT
+ {
+ .membase = io_p2v(LPC32XX_UART5_BASE),
+ .mapbase = LPC32XX_UART5_BASE,
+ .irq = IRQ_LPC32XX_UART_IIR5,
+ .uartclk = LPC32XX_MAIN_OSC_FREQ,
+ .regshift = 2,
+ .iotype = UPIO_MEM32,
+ .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+ UPF_SKIP_TEST,
+ },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
+ {
+ .membase = io_p2v(LPC32XX_UART3_BASE),
+ .mapbase = LPC32XX_UART3_BASE,
+ .irq = IRQ_LPC32XX_UART_IIR3,
+ .uartclk = LPC32XX_MAIN_OSC_FREQ,
+ .regshift = 2,
+ .iotype = UPIO_MEM32,
+ .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+ UPF_SKIP_TEST,
+ },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
+ {
+ .membase = io_p2v(LPC32XX_UART4_BASE),
+ .mapbase = LPC32XX_UART4_BASE,
+ .irq = IRQ_LPC32XX_UART_IIR4,
+ .uartclk = LPC32XX_MAIN_OSC_FREQ,
+ .regshift = 2,
+ .iotype = UPIO_MEM32,
+ .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+ UPF_SKIP_TEST,
+ },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
+ {
+ .membase = io_p2v(LPC32XX_UART6_BASE),
+ .mapbase = LPC32XX_UART6_BASE,
+ .irq = IRQ_LPC32XX_UART_IIR6,
+ .uartclk = LPC32XX_MAIN_OSC_FREQ,
+ .regshift = 2,
+ .iotype = UPIO_MEM32,
+ .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+ UPF_SKIP_TEST,
+ },
+#endif
+ { },
+};
+
+struct uartinit {
+ char *uart_ck_name;
+ u32 ck_mode_mask;
+ void __iomem *pdiv_clk_reg;
+};
+
+static struct uartinit uartinit_data[] __initdata = {
+#ifdef CONFIG_ARCH_LPC32XX_UART5_SELECT
+ {
+ .uart_ck_name = "uart5_ck",
+ .ck_mode_mask =
+ LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5),
+ .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL,
+ },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT
+ {
+ .uart_ck_name = "uart3_ck",
+ .ck_mode_mask =
+ LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3),
+ .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL,
+ },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT
+ {
+ .uart_ck_name = "uart4_ck",
+ .ck_mode_mask =
+ LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4),
+ .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL,
+ },
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT
+ {
+ .uart_ck_name = "uart6_ck",
+ .ck_mode_mask =
+ LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6),
+ .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL,
+ },
+#endif
+};
+
+static struct platform_device serial_std_platform_device = {
+ .name = "serial8250",
+ .id = 0,
+ .dev = {
+ .platform_data = serial_std_platform_data,
+ },
+};
+
+static struct platform_device *lpc32xx_serial_devs[] __initdata = {
+ &serial_std_platform_device,
+};
+
+void __init lpc32xx_serial_init(void)
+{
+ u32 tmp, clkmodes = 0;
+ struct clk *clk;
+ unsigned int puart;
+ int i, j;
+
+ /* UART clocks are off, let clock driver manage them */
+ __raw_writel(0, LPC32XX_CLKPWR_UART_CLK_CTRL);
+
+ for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
+ clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
+ if (!IS_ERR(clk)) {
+ clk_enable(clk);
+ serial_std_platform_data[i].uartclk =
+ clk_get_rate(clk);
+ }
+
+ /* Fall back on main osc rate if clock rate return fails */
+ if (serial_std_platform_data[i].uartclk == 0)
+ serial_std_platform_data[i].uartclk =
+ LPC32XX_MAIN_OSC_FREQ;
+
+ /* Setup UART clock modes for all UARTs, disable autoclock */
+ clkmodes |= uartinit_data[i].ck_mode_mask;
+
+ /* pre-UART clock divider set to 1 */
+ __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg);
+ }
+
+ /* This needs to be done after all UART clocks are setup */
+ __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE);
+ for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) {
+ /* Force a flush of the RX FIFOs to work around a HW bug */
+ puart = serial_std_platform_data[i].mapbase;
+ __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart));
+ __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart));
+ j = LPC32XX_SUART_FIFO_SIZE;
+ while (j--)
+ tmp = __raw_readl(LPC32XX_UART_DLL_FIFO(puart));
+ __raw_writel(0, LPC32XX_UART_IIR_FCR(puart));
+ }
+
+ /* Disable UART5->USB transparent mode or USB won't work */
+ tmp = __raw_readl(LPC32XX_UARTCTL_CTRL);
+ tmp &= ~LPC32XX_UART_U5_ROUTE_TO_USB;
+ __raw_writel(tmp, LPC32XX_UARTCTL_CTRL);
+
+ platform_add_devices(lpc32xx_serial_devs,
+ ARRAY_SIZE(lpc32xx_serial_devs));
+}
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/suspend.S
+ *
+ * Original authors: Dmitry Chigirev, Vitaly Wool <source@mvista.com>
+ * Modified by Kevin Wells <kevin.wells@nxp.com>
+ *
+ * 2005 (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.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/* Using named register defines makes the code easier to follow */
+#define WORK1_REG r0
+#define WORK2_REG r1
+#define SAVED_HCLK_DIV_REG r2
+#define SAVED_HCLK_PLL_REG r3
+#define SAVED_DRAM_CLKCTRL_REG r4
+#define SAVED_PWR_CTRL_REG r5
+#define CLKPWRBASE_REG r6
+#define EMCBASE_REG r7
+
+#define LPC32XX_EMC_STATUS_OFFS 0x04
+#define LPC32XX_EMC_STATUS_BUSY 0x1
+#define LPC32XX_EMC_STATUS_SELF_RFSH 0x4
+
+#define LPC32XX_CLKPWR_PWR_CTRL_OFFS 0x44
+#define LPC32XX_CLKPWR_HCLK_DIV_OFFS 0x40
+#define LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS 0x58
+
+#define CLKPWR_PCLK_DIV_MASK 0xFFFFFE7F
+
+ .text
+
+ENTRY(lpc32xx_sys_suspend)
+ @ Save a copy of the used registers in IRAM, r0 is corrupted
+ adr r0, tmp_stack_end
+ stmfd r0!, {r3 - r7, sp, lr}
+
+ @ Load a few common register addresses
+ adr WORK1_REG, reg_bases
+ ldr CLKPWRBASE_REG, [WORK1_REG, #0]
+ ldr EMCBASE_REG, [WORK1_REG, #4]
+
+ ldr SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
+ #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+ orr WORK1_REG, SAVED_PWR_CTRL_REG, #LPC32XX_CLKPWR_SDRAM_SELF_RFSH
+
+ @ Wait for SDRAM busy status to go busy and then idle
+ @ This guarantees a small windows where DRAM isn't busy
+1:
+ ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+ and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+ cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+ bne 1b @ Branch while idle
+2:
+ ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+ and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+ cmp WORK2_REG, #LPC32XX_EMC_STATUS_BUSY
+ beq 2b @ Branch until idle
+
+ @ Setup self-refresh with support for manual exit of
+ @ self-refresh mode
+ str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+ orr WORK2_REG, WORK1_REG, #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
+ str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+ str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+ @ Wait for self-refresh acknowledge, clocks to the DRAM device
+ @ will automatically stop on start of self-refresh
+3:
+ ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+ and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
+ cmp WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
+ bne 3b @ Branch until self-refresh mode starts
+
+ @ Enter direct-run mode from run mode
+ bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_SELECT_RUN_MODE
+ str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+ @ Safe disable of DRAM clock in EMC block, prevents DDR sync
+ @ issues on restart
+ ldr SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
+ #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
+ and WORK2_REG, SAVED_HCLK_DIV_REG, #CLKPWR_PCLK_DIV_MASK
+ str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
+
+ @ Save HCLK PLL state and disable HCLK PLL
+ ldr SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
+ #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+ bic WORK2_REG, SAVED_HCLK_PLL_REG, #LPC32XX_CLKPWR_HCLKPLL_POWER_UP
+ str WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+
+ @ Enter stop mode until an enabled event occurs
+ orr WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
+ str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+ .rept 9
+ nop
+ .endr
+
+ @ Clear stop status
+ bic WORK1_REG, WORK1_REG, #LPC32XX_CLKPWR_STOP_MODE_CTRL
+
+ @ Restore original HCLK PLL value and wait for PLL lock
+ str SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG,\
+ #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+4:
+ ldr WORK2_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_HCLKPLL_CTRL_OFFS]
+ and WORK2_REG, WORK2_REG, #LPC32XX_CLKPWR_HCLKPLL_PLL_STS
+ bne 4b
+
+ @ Re-enter run mode with self-refresh flag cleared, but no DRAM
+ @ update yet. DRAM is still in self-refresh
+ str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
+ #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+ @ Restore original DRAM clock mode to restore DRAM clocks
+ str SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG,\
+ #LPC32XX_CLKPWR_HCLK_DIV_OFFS]
+
+ @ Clear self-refresh mode
+ orr WORK1_REG, SAVED_PWR_CTRL_REG,\
+ #LPC32XX_CLKPWR_UPD_SDRAM_SELF_RFSH
+ str WORK1_REG, [CLKPWRBASE_REG, #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+ str SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG,\
+ #LPC32XX_CLKPWR_PWR_CTRL_OFFS]
+
+ @ Wait for EMC to clear self-refresh mode
+5:
+ ldr WORK2_REG, [EMCBASE_REG, #LPC32XX_EMC_STATUS_OFFS]
+ and WORK2_REG, WORK2_REG, #LPC32XX_EMC_STATUS_SELF_RFSH
+ bne 5b @ Branch until self-refresh has exited
+
+ @ restore regs and return
+ adr r0, tmp_stack
+ ldmfd r0!, {r3 - r7, sp, pc}
+
+reg_bases:
+ .long IO_ADDRESS(LPC32XX_CLK_PM_BASE)
+ .long IO_ADDRESS(LPC32XX_EMC_BASE)
+
+tmp_stack:
+ .long 0, 0, 0, 0, 0, 0, 0
+tmp_stack_end:
+
+ENTRY(lpc32xx_sys_suspend_sz)
+ .word . - lpc32xx_sys_suspend
--- /dev/null
+/*
+ * arch/arm/mach-lpc32xx/timer.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2009 - 2010 NXP Semiconductors
+ * Copyright (C) 2009 Fontys University of Applied Sciences, Eindhoven
+ * Ed Schouten <e.schouten@fontys.nl>
+ * Laurens Timmermans <l.timmermans@fontys.nl>
+ *
+ * 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/clockchips.h>
+
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+static cycle_t lpc32xx_clksrc_read(struct clocksource *cs)
+{
+ return (cycle_t)__raw_readl(LCP32XX_TIMER_TC(LPC32XX_TIMER1_BASE));
+}
+
+static struct clocksource lpc32xx_clksrc = {
+ .name = "lpc32xx_clksrc",
+ .shift = 24,
+ .rating = 300,
+ .read = lpc32xx_clksrc_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int lpc32xx_clkevt_next_event(unsigned long delta,
+ struct clock_event_device *dev)
+{
+ __raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
+ LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+ __raw_writel(delta, LCP32XX_TIMER_PR(LPC32XX_TIMER0_BASE));
+ __raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
+ LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+
+ return 0;
+}
+
+static void lpc32xx_clkevt_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ WARN_ON(1);
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /*
+ * Disable the timer. When using oneshot, we must also
+ * disable the timer to wait for the first call to
+ * set_next_event().
+ */
+ __raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static struct clock_event_device lpc32xx_clkevt = {
+ .name = "lpc32xx_clkevt",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .shift = 32,
+ .rating = 300,
+ .set_next_event = lpc32xx_clkevt_next_event,
+ .set_mode = lpc32xx_clkevt_mode,
+};
+
+static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = &lpc32xx_clkevt;
+
+ /* Clear match */
+ __raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
+ LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction lpc32xx_timer_irq = {
+ .name = "LPC32XX Timer Tick",
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = lpc32xx_timer_interrupt,
+};
+
+/*
+ * The clock management driver isn't initialized at this point, so the
+ * clocks need to be enabled here manually and then tagged as used in
+ * the clock driver initialization
+ */
+static void __init lpc32xx_timer_init(void)
+{
+ u32 clkrate, pllreg;
+
+ /* Enable timer clock */
+ __raw_writel(LPC32XX_CLKPWR_TMRPWMCLK_TIMER0_EN |
+ LPC32XX_CLKPWR_TMRPWMCLK_TIMER1_EN,
+ LPC32XX_CLKPWR_TIMERS_PWMS_CLK_CTRL_1);
+
+ /*
+ * The clock driver isn't initialized at this point. So determine if
+ * the SYSCLK is driven from the PLL397 or main oscillator and then use
+ * it to compute the PLL frequency and the PCLK divider to get the base
+ * timer rates. This rate is needed to compute the tick rate.
+ */
+ if (clk_is_sysclk_mainosc() != 0)
+ clkrate = LPC32XX_MAIN_OSC_FREQ;
+ else
+ clkrate = 397 * LPC32XX_CLOCK_OSC_FREQ;
+
+ /* Get ARM HCLKPLL register and convert it into a frequency */
+ pllreg = __raw_readl(LPC32XX_CLKPWR_HCLKPLL_CTRL) & 0x1FFFF;
+ clkrate = clk_get_pllrate_from_reg(clkrate, pllreg);
+
+ /* Get PCLK divider and divide ARM PLL clock by it to get timer rate */
+ clkrate = clkrate / clk_get_pclk_div();
+
+ /* Initial timer setup */
+ __raw_writel(0, LCP32XX_TIMER_TCR(LPC32XX_TIMER0_BASE));
+ __raw_writel(LCP32XX_TIMER_CNTR_MTCH_BIT(0),
+ LCP32XX_TIMER_IR(LPC32XX_TIMER0_BASE));
+ __raw_writel(1, LCP32XX_TIMER_MR0(LPC32XX_TIMER0_BASE));
+ __raw_writel(LCP32XX_TIMER_CNTR_MCR_MTCH(0) |
+ LCP32XX_TIMER_CNTR_MCR_STOP(0) |
+ LCP32XX_TIMER_CNTR_MCR_RESET(0),
+ LCP32XX_TIMER_MCR(LPC32XX_TIMER0_BASE));
+
+ /* Setup tick interrupt */
+ setup_irq(IRQ_LPC32XX_TIMER0, &lpc32xx_timer_irq);
+
+ /* Setup the clockevent structure. */
+ lpc32xx_clkevt.mult = div_sc(clkrate, NSEC_PER_SEC,
+ lpc32xx_clkevt.shift);
+ lpc32xx_clkevt.max_delta_ns = clockevent_delta2ns(-1,
+ &lpc32xx_clkevt);
+ lpc32xx_clkevt.min_delta_ns = clockevent_delta2ns(1,
+ &lpc32xx_clkevt) + 1;
+ lpc32xx_clkevt.cpumask = cpumask_of(0);
+ clockevents_register_device(&lpc32xx_clkevt);
+
+ /* Use timer1 as clock source. */
+ __raw_writel(LCP32XX_TIMER_CNTR_TCR_RESET,
+ LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+ __raw_writel(0, LCP32XX_TIMER_PR(LPC32XX_TIMER1_BASE));
+ __raw_writel(0, LCP32XX_TIMER_MCR(LPC32XX_TIMER1_BASE));
+ __raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
+ LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
+ lpc32xx_clksrc.mult = clocksource_hz2mult(clkrate,
+ lpc32xx_clksrc.shift);
+ clocksource_register(&lpc32xx_clksrc);
+}
+
+struct sys_timer lpc32xx_timer = {
+ .init = &lpc32xx_timer_init,
+};
+
* the Free Software Foundation.
*/
#include <mach/hardware.h>
+#include <asm/memory.h>
#include <mach/regs-board-a9m9750dev.h>
/* nothing */
}
+static int timeout;
+
static void putc_ns9360(char c, void __iomem *base)
{
- static int t = 0x10000;
do {
- if (t)
- --t;
+ if (timeout)
+ --timeout;
if (__raw_readl(base + 8) & (1 << 3)) {
__raw_writeb(c, base + 16);
- t = 0x10000;
+ timeout = 0x10000;
break;
}
- } while (t);
+ } while (timeout);
}
static void putc_a9m9750dev(char c, void __iomem *base)
{
- static int t = 0x10000;
do {
- if (t)
- --t;
+ if (timeout)
+ --timeout;
if (__raw_readb(base + 5) & (1 << 5)) {
__raw_writeb(c, base);
- t = 0x10000;
+ timeout = 0x10000;
break;
}
- } while (t);
+ } while (timeout);
}
static void putc_ns921x(char c, void __iomem *base)
{
- static int t = 0x10000;
do {
- if (t)
- --t;
+ if (timeout)
+ --timeout;
if (!(__raw_readl(base) & (1 << 11))) {
__raw_writeb(c, base + 0x0028);
- t = 0x10000;
+ timeout = 0x10000;
break;
}
- } while (t);
+ } while (timeout);
}
#define MSCS __REG(0xA0900184)
static void autodetect(void (**putc)(char, void __iomem *), void __iomem **base)
{
+ timeout = 0x10000;
if (((__raw_readl(MSCS) >> 16) & 0xfe) == 0x00) {
/* ns9360 or ns9750 */
if (NS9360_UART_ENABLED(NS9360_UARTA)) {
#endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
static int board_keymap[] = {
+ /*
+ * Note that KEY(x, 8, KEY_XXX) entries represent "entrire row
+ * connected to the ground" matrix state.
+ */
KEY(0, 0, KEY_Q),
KEY(0, 1, KEY_O),
KEY(0, 2, KEY_P),
KEY(0, 4, KEY_BACKSPACE),
KEY(0, 6, KEY_A),
KEY(0, 7, KEY_S),
+
KEY(1, 0, KEY_W),
KEY(1, 1, KEY_D),
KEY(1, 2, KEY_F),
KEY(1, 5, KEY_J),
KEY(1, 6, KEY_K),
KEY(1, 7, KEY_L),
+
KEY(2, 0, KEY_E),
KEY(2, 1, KEY_DOT),
KEY(2, 2, KEY_UP),
KEY(2, 5, KEY_Z),
KEY(2, 6, KEY_X),
KEY(2, 7, KEY_C),
+ KEY(2, 8, KEY_F9),
+
KEY(3, 0, KEY_R),
KEY(3, 1, KEY_V),
KEY(3, 2, KEY_B),
KEY(3, 5, KEY_SPACE),
KEY(3, 6, KEY_SPACE),
KEY(3, 7, KEY_LEFT),
+
KEY(4, 0, KEY_T),
KEY(4, 1, KEY_DOWN),
KEY(4, 2, KEY_RIGHT),
KEY(4, 4, KEY_LEFTCTRL),
KEY(4, 5, KEY_RIGHTALT),
KEY(4, 6, KEY_LEFTSHIFT),
+ KEY(4, 8, KEY_F10),
+
KEY(5, 0, KEY_Y),
+ KEY(5, 8, KEY_F11),
+
KEY(6, 0, KEY_U),
+
KEY(7, 0, KEY_I),
KEY(7, 1, KEY_F7),
KEY(7, 2, KEY_F8),
- KEY(0xff, 2, KEY_F9),
- KEY(0xff, 4, KEY_F10),
- KEY(0xff, 5, KEY_F11),
};
static struct matrix_keymap_data board_map_data = {
#include <mach/colibri.h>
#include <mach/ohci.h>
#include <mach/pxafb.h>
+#include <mach/audio.h>
#include "generic.h"
#include "devices.h"
static inline void colibri_pxa300_init_lcd(void) {}
#endif /* CONFIG_FB_PXA || CONFIG_FB_PXA_MODULE */
-#if defined(SND_AC97_CODEC) || defined(SND_AC97_CODEC_MODULE)
+#if defined(CONFIG_SND_AC97_CODEC) || defined(CONFIG_SND_AC97_CODEC_MODULE)
static mfp_cfg_t colibri_pxa310_ac97_pin_config[] __initdata = {
GPIO24_AC97_SYSCLK,
GPIO23_AC97_nACRESET,
static struct pxamci_platform_data corgi_mci_platform_data = {
.detect_delay_ms = 250,
.ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .gpio_card_detect = -1,
+ .gpio_card_detect = CORGI_GPIO_nSD_DETECT,
.gpio_card_ro = CORGI_GPIO_nSD_WP,
.gpio_power = CORGI_GPIO_SD_PWR,
};
static u32 mdrefr_dri(unsigned int freq)
{
- u32 dri = 0;
+ u32 interval = freq * SDRAM_TREF / sdram_rows;
- if (cpu_is_pxa25x())
- dri = ((freq * SDRAM_TREF) / (sdram_rows * 32));
- if (cpu_is_pxa27x())
- dri = ((freq * SDRAM_TREF) / (sdram_rows - 31)) / 32;
- return dri;
+ return (interval - (cpu_is_pxa27x() ? 31 : 0)) / 32;
}
/* find a valid frequency point */
EXPORT_SYMBOL(pxa27x_clear_otgph);
static unsigned long ac97_reset_config[] = {
- GPIO95_AC97_nRESET,
- GPIO95_GPIO,
- GPIO113_AC97_nRESET,
GPIO113_GPIO,
+ GPIO113_AC97_nRESET,
+ GPIO95_GPIO,
+ GPIO95_AC97_nRESET,
};
void pxa27x_assert_ac97reset(int reset_gpio, int on)
strb \rd, [\rx]
.endm
+ .macro waituart,rd,rx
+ .endm
+
.macro busyuart,rd,rx
mov \rd, #0
1001: add \rd, \rd, #1
DEF_CLKLOOK(&clk_kpi, "nuc900-kpi", NULL),
DEF_CLKLOOK(&clk_wdt, "nuc900-wdt", NULL),
DEF_CLKLOOK(&clk_gdma, "nuc900-gdma", NULL),
- DEF_CLKLOOK(&clk_adc, "nuc900-adc", NULL),
+ DEF_CLKLOOK(&clk_adc, "nuc900-ts", NULL),
DEF_CLKLOOK(&clk_usi, "nuc900-spi", NULL),
DEF_CLKLOOK(&clk_ext, NULL, "ext"),
DEF_CLKLOOK(&clk_timer0, NULL, "timer0"),
.macro addruart, rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
- moveq \rx, =SPEAR_DBG_UART_BASE @ Physical base
- movne \rx, =VA_SPEAR_DBG_UART_BASE @ Virtual base
+ moveq \rx, #SPEAR_DBG_UART_BASE @ Physical base
+ movne \rx, #VA_SPEAR_DBG_UART_BASE @ Virtual base
.endm
.macro senduart, rd, rx
#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
+#define TIOCGRS485 0x542E
+#define TIOCSRS485 0x542F
+
#define FIONCLEX 0x5450
#define FIOCLEX 0x5451
#define FIOASYNC 0x5452
#define __ASM_ARCH_BOARD_H
#include <linux/types.h>
+#include <linux/serial.h>
#define GPIO_PIN_NONE (-1)
short use_dma_tx; /* use transmit DMA? */
short use_dma_rx; /* use receive DMA? */
void __iomem *regs; /* virtual base address, if any */
+ struct serial_rs485 rs485; /* rs485 settings */
};
void at32_map_usart(unsigned int hw_id, unsigned int line, int flags);
struct platform_device *at32_add_device_usart(unsigned int id);
static int __init au1xxx_platform_init(void)
{
unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
- int i;
+ int err, i;
/* Fill up uartclk. */
for (i = 0; au1x00_uart_data[i].flags; i++)
au1x00_uart_data[i].uartclk = uartclk;
+ err = platform_add_devices(au1xxx_platform_devices,
+ ARRAY_SIZE(au1xxx_platform_devices));
#ifndef CONFIG_SOC_AU1100
/* Register second MAC if enabled in pinfunc */
- if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2))
+ if (!err && !(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2))
platform_device_register(&au1xxx_eth1_device);
#endif
- return platform_add_devices(au1xxx_platform_devices,
- ARRAY_SIZE(au1xxx_platform_devices));
+ return err;
}
arch_initcall(au1xxx_platform_init);
void __init board_setup(void)
{
- alchemy_gpio2_enable();
-
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
/* Enable USB power switch */
alchemy_gpio_direction_output(204, 0);
if (assert && devsel != 0)
/* Suppress signal to Cardbus */
- gpio_set_value(1, 0); /* set EXT_IO3 OFF */
+ alchemy_gpio_set_value(1, 0); /* set EXT_IO3 OFF */
else
- gpio_set_value(1, 1); /* set EXT_IO3 ON */
+ alchemy_gpio_set_value(1, 1); /* set EXT_IO3 ON */
- au_sync_udelay(1);
+ udelay(1);
return 1;
}
if (unit > 1)
return -ENODEV;
+ if (unit == 1 && BCMCPU_IS_6338())
+ return -ENODEV;
+
if (!shared_device_registered) {
shared_res[0].start = bcm63xx_regset_address(RSET_ENETDMA);
shared_res[0].end = shared_res[0].start;
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %0, %1 # atomic64_add \n"
- " addu %0, %2 \n"
+ " daddu %0, %2 \n"
" scd %0, %1 \n"
" beqzl %0, 1b \n"
" .set mips0 \n"
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %0, %1 # atomic64_add \n"
- " addu %0, %2 \n"
+ " daddu %0, %2 \n"
" scd %0, %1 \n"
" beqz %0, 2f \n"
" .subsection 2 \n"
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %0, %1 # atomic64_sub \n"
- " subu %0, %2 \n"
+ " dsubu %0, %2 \n"
" scd %0, %1 \n"
" beqzl %0, 1b \n"
" .set mips0 \n"
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %0, %1 # atomic64_sub \n"
- " subu %0, %2 \n"
+ " dsubu %0, %2 \n"
" scd %0, %1 \n"
" beqz %0, 2f \n"
" .subsection 2 \n"
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %1, %2 # atomic64_add_return \n"
- " addu %0, %1, %3 \n"
+ " daddu %0, %1, %3 \n"
" scd %0, %2 \n"
" beqzl %0, 1b \n"
- " addu %0, %1, %3 \n"
+ " daddu %0, %1, %3 \n"
" .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter)
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %1, %2 # atomic64_add_return \n"
- " addu %0, %1, %3 \n"
+ " daddu %0, %1, %3 \n"
" scd %0, %2 \n"
" beqz %0, 2f \n"
- " addu %0, %1, %3 \n"
+ " daddu %0, %1, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %1, %2 # atomic64_sub_return \n"
- " subu %0, %1, %3 \n"
+ " dsubu %0, %1, %3 \n"
" scd %0, %2 \n"
" beqzl %0, 1b \n"
- " subu %0, %1, %3 \n"
+ " dsubu %0, %1, %3 \n"
" .set mips0 \n"
: "=&r" (result), "=&r" (temp), "=m" (v->counter)
: "Ir" (i), "m" (v->counter)
__asm__ __volatile__(
" .set mips3 \n"
"1: lld %1, %2 # atomic64_sub_return \n"
- " subu %0, %1, %3 \n"
+ " dsubu %0, %1, %3 \n"
" scd %0, %2 \n"
" beqz %0, 2f \n"
- " subu %0, %1, %3 \n"
+ " dsubu %0, %1, %3 \n"
" .subsection 2 \n"
"2: b 1b \n"
" .previous \n"
#define __NR_perf_event_open (__NR_Linux + 296)
#define __NR_accept4 (__NR_Linux + 297)
#define __NR_recvmmsg (__NR_Linux + 298)
+#define __NR_getdents64 (__NR_Linux + 299)
/*
* Offset of the last N32 flavoured syscall
*/
-#define __NR_Linux_syscalls 298
+#define __NR_Linux_syscalls 299
#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
#define __NR_N32_Linux 6000
-#define __NR_N32_Linux_syscalls 298
+#define __NR_N32_Linux_syscalls 299
#ifdef __KERNEL__
PTR sys_perf_event_open
PTR sys_accept4
PTR compat_sys_recvmmsg
+ PTR sys_getdents
.size sysn32_call_table,.-sysn32_call_table
vunmap(vdso);
- pr_notice("init_vdso successfull\n");
-
return 0;
}
-device_initcall(init_vdso);
+subsys_initcall(init_vdso);
static unsigned long vdso_addr(unsigned long start)
{
iomem_resource.end &= 0xfffffffffULL; /* 64 GB */
ioport_resource.end = controller->io_resource->end;
+ controller->io_map_base = mips_io_port_base;
+
register_pci_controller(controller);
}
static struct pci_controller pnx8550_controller = {
.pci_ops = &pnx8550_pci_ops,
+ .io_map_base = PNX8550_PORT_BASE,
.io_resource = &pci_io_resource,
.mem_resource = &pci_mem_resource,
};
PNX8550_GLB2_ENAB_INTA_O = 0;
/* IO/MEM resources. */
- set_io_port_base(KSEG1);
+ set_io_port_base(PNX8550_PORT_BASE);
ioport_resource.start = 0;
ioport_resource.end = ~0;
iomem_resource.start = 0;
.pci_ops = &msp_pci_ops,
.mem_resource = &pci_mem_resource,
.mem_offset = 0,
+ .io_map_base = MSP_PCI_IOSPACE_BASE,
.io_resource = &pci_io_resource,
.io_offset = 0
};
panic(ioremap_failed);
set_io_port_base(io_v_base);
+ py_controller.io_map_base = io_v_base;
TITAN_WRITE(RM9000x2_OCD_LKM7, TITAN_READ(RM9000x2_OCD_LKM7) | 1);
ioport_resource.end = TITAN_IO_SIZE - 1;
* it*/
platform_features = FFS_CAPABLE | DISPLAY_CAPABLE;
+ /* Cronus and Cronus Lite have the same register map */
+ set_register_map(CRONUS_IO_BASE, &cronus_register_map);
+
/* ASIC version will determine if this is a real CronusLite or
* Castrati(Cronus) */
chipversion = asic_read(chipver3) << 24;
else
asic = ASIC_CRONUSLITE;
- /* Cronus and Cronus Lite have the same register map */
- set_register_map(CRONUS_IO_BASE, &cronus_register_map);
gp_resources = non_dvr_cronuslite_resources;
pr_info("Platform: 4600 - %s, NON_DVR_CAPABLE, "
"chipversion=0x%08X\n",
* On FSL-BookE we setup a 1:1 mapping which covers the first 2GiB of memory
* and therefore we can only deal with memory within this range
*/
-#define KEXEC_SOURCE_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
-#define KEXEC_DESTINATION_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
-#define KEXEC_CONTROL_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
+#define KEXEC_SOURCE_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL - 1)
+#define KEXEC_DESTINATION_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL - 1)
+#define KEXEC_CONTROL_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL - 1)
#else
int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
pte_t *ptep, unsigned long trap, int local, int ssize,
unsigned int shift, unsigned int mmu_psize);
-
+extern void hash_failure_debug(unsigned long ea, unsigned long access,
+ unsigned long vsid, unsigned long trap,
+ int ssize, int psize, unsigned long pte);
extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
unsigned long pstart, unsigned long prot,
int psize, int ssize);
* Finally record data if requested.
*/
if (record) {
- struct perf_sample_data data = {
- .period = event->hw.last_period,
- };
+ struct perf_sample_data data;
+
+ perf_sample_data_init(&data, 0);
if (perf_event_overflow(event, nmi, &data, regs)) {
/*
u64 base, size, memblock_size;
unsigned int is_kexec_kdump = 0, rngs;
- ls = of_get_flat_dt_prop(node, "ibm,memblock-size", &l);
+ ls = of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
if (ls == NULL || l < dt_root_size_cells * sizeof(__be32))
return 0;
memblock_size = dt_mem_next_cell(dt_root_size_cells, &ls);
std r8,STK_PARM(r8)(r1)
std r9,STK_PARM(r9)(r1)
- /* Add _PAGE_PRESENT to access */
- ori r4,r4,_PAGE_PRESENT
-
/* Save non-volatile registers.
* r31 will hold "old PTE"
* r30 is "new PTE"
std r8,STK_PARM(r8)(r1)
std r9,STK_PARM(r9)(r1)
- /* Add _PAGE_PRESENT to access */
- ori r4,r4,_PAGE_PRESENT
-
/* Save non-volatile registers.
* r31 will hold "old PTE"
* r30 is "new PTE"
std r8,STK_PARM(r8)(r1)
std r9,STK_PARM(r9)(r1)
- /* Add _PAGE_PRESENT to access */
- ori r4,r4,_PAGE_PRESENT
-
/* Save non-volatile registers.
* r31 will hold "old PTE"
* r30 is "new PTE"
}
#endif
+void hash_failure_debug(unsigned long ea, unsigned long access,
+ unsigned long vsid, unsigned long trap,
+ int ssize, int psize, unsigned long pte)
+{
+ if (!printk_ratelimit())
+ return;
+ pr_info("mm: Hashing failure ! EA=0x%lx access=0x%lx current=%s\n",
+ ea, access, current->comm);
+ pr_info(" trap=0x%lx vsid=0x%lx ssize=%d psize=%d pte=0x%lx\n",
+ trap, vsid, ssize, psize, pte);
+}
+
/* Result code is:
* 0 - handled
* 1 - normal page fault
return 1;
}
+ /* Add _PAGE_PRESENT to the required access perm */
+ access |= _PAGE_PRESENT;
+
+ /* Pre-check access permissions (will be re-checked atomically
+ * in __hash_page_XX but this pre-check is a fast path
+ */
+ if (access & ~pte_val(*ptep)) {
+ DBG_LOW(" no access !\n");
+ return 1;
+ }
+
#ifdef CONFIG_HUGETLB_PAGE
if (hugeshift)
return __hash_page_huge(ea, access, vsid, ptep, trap, local,
DBG_LOW(" i-pte: %016lx %016lx\n", pte_val(*ptep),
pte_val(*(ptep + PTRS_PER_PTE)));
#endif
- /* Pre-check access permissions (will be re-checked atomically
- * in __hash_page_XX but this pre-check is a fast path
- */
- if (access & ~pte_val(*ptep)) {
- DBG_LOW(" no access !\n");
- return 1;
- }
-
/* Do actual hashing */
#ifdef CONFIG_PPC_64K_PAGES
/* If _PAGE_4K_PFN is set, make sure this is a 4k segment */
local, ssize, spp);
}
+ /* Dump some info in case of hash insertion failure, they should
+ * never happen so it is really useful to know if/when they do
+ */
+ if (rc == -1)
+ hash_failure_debug(ea, access, vsid, trap, ssize, psize,
+ pte_val(*ptep));
#ifndef CONFIG_PPC_64K_PAGES
DBG_LOW(" o-pte: %016lx\n", pte_val(*ptep));
#else
void *pgdir;
pte_t *ptep;
unsigned long flags;
- int local = 0;
- int ssize;
+ int rc, ssize, local = 0;
BUG_ON(REGION_ID(ea) != USER_REGION_ID);
/* Hash it in */
#ifdef CONFIG_PPC_HAS_HASH_64K
if (mm->context.user_psize == MMU_PAGE_64K)
- __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize);
+ rc = __hash_page_64K(ea, access, vsid, ptep, trap, local, ssize);
else
#endif /* CONFIG_PPC_HAS_HASH_64K */
- __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
- subpage_protection(pgdir, ea));
+ rc = __hash_page_4K(ea, access, vsid, ptep, trap, local, ssize,
+ subpage_protection(pgdir, ea));
+
+ /* Dump some info in case of hash insertion failure, they should
+ * never happen so it is really useful to know if/when they do
+ */
+ if (rc == -1)
+ hash_failure_debug(ea, access, vsid, trap, ssize,
+ mm->context.user_psize, pte_val(*ptep));
local_irq_restore(flags);
}
unsigned long old_pte, new_pte;
unsigned long va, rflags, pa, sz;
long slot;
- int err = 1;
BUG_ON(shift != mmu_psize_defs[mmu_psize].shift);
/* Search the Linux page table for a match with va */
va = hpt_va(ea, vsid, ssize);
- /*
- * Check the user's access rights to the page. If access should be
- * prevented then send the problem up to do_page_fault.
- */
- if (unlikely(access & ~pte_val(*ptep)))
- goto out;
- /*
- * At this point, we have a pte (old_pte) which can be used to build
+ /* At this point, we have a pte (old_pte) which can be used to build
* or update an HPTE. There are 2 cases:
*
* 1. There is a valid (present) pte with no associated HPTE (this is
do {
old_pte = pte_val(*ptep);
- if (old_pte & _PAGE_BUSY)
- goto out;
+ /* If PTE busy, retry the access */
+ if (unlikely(old_pte & _PAGE_BUSY))
+ return 0;
+ /* If PTE permissions don't match, take page fault */
+ if (unlikely(access & ~old_pte))
+ return 1;
+ /* Try to lock the PTE, add ACCESSED and DIRTY if it was
+ * a write access */
new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED;
+ if (access & _PAGE_RW)
+ new_pte |= _PAGE_DIRTY;
} while(old_pte != __cmpxchg_u64((unsigned long *)ptep,
old_pte, new_pte));
}
}
- if (unlikely(slot == -2))
- panic("hash_huge_page: pte_insert failed\n");
+ /*
+ * Hypervisor failure. Restore old pte and return -1
+ * similar to __hash_page_*
+ */
+ if (unlikely(slot == -2)) {
+ *ptep = __pte(old_pte);
+ hash_failure_debug(ea, access, vsid, trap, ssize,
+ mmu_psize, old_pte);
+ return -1;
+ }
new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX);
}
* No need to use ldarx/stdcx here
*/
*ptep = __pte(new_pte & ~_PAGE_BUSY);
-
- err = 0;
-
- out:
- return err;
+ return 0;
}
}
/*
- * Retreive and validate the ibm,memblock-size property for drconf memory
+ * Retreive and validate the ibm,lmb-size property for drconf memory
* from the device tree.
*/
-static u64 of_get_memblock_size(struct device_node *memory)
+static u64 of_get_lmb_size(struct device_node *memory)
{
const u32 *prop;
u32 len;
- prop = of_get_property(memory, "ibm,memblock-size", &len);
+ prop = of_get_property(memory, "ibm,lmb-size", &len);
if (!prop || len < sizeof(unsigned int))
return 0;
static inline int __init read_usm_ranges(const u32 **usm)
{
/*
- * For each memblock in ibm,dynamic-memory a corresponding
+ * For each lmb in ibm,dynamic-memory a corresponding
* entry in linux,drconf-usable-memory property contains
* a counter followed by that many (base, size) duple.
* read the counter from linux,drconf-usable-memory
{
const u32 *dm, *usm;
unsigned int n, rc, ranges, is_kexec_kdump = 0;
- unsigned long memblock_size, base, size, sz;
+ unsigned long lmb_size, base, size, sz;
int nid;
struct assoc_arrays aa;
if (!n)
return;
- memblock_size = of_get_memblock_size(memory);
- if (!memblock_size)
+ lmb_size = of_get_lmb_size(memory);
+ if (!lmb_size)
return;
rc = of_get_assoc_arrays(memory, &aa);
continue;
base = drmem.base_addr;
- size = memblock_size;
+ size = lmb_size;
ranges = 1;
if (is_kexec_kdump) {
{
const u32 *dm;
unsigned int drconf_cell_cnt, rc;
- unsigned long memblock_size;
+ unsigned long lmb_size;
struct assoc_arrays aa;
int nid = -1;
if (!drconf_cell_cnt)
return -1;
- memblock_size = of_get_memblock_size(memory);
- if (!memblock_size)
+ lmb_size = of_get_lmb_size(memory);
+ if (!lmb_size)
return -1;
rc = of_get_assoc_arrays(memory, &aa);
continue;
if ((scn_addr < drmem.base_addr)
- || (scn_addr >= (drmem.base_addr + memblock_size)))
+ || (scn_addr >= (drmem.base_addr + lmb_size)))
continue;
nid = of_drconf_to_nid_single(&drmem, &aa);
const char *type;
const unsigned int *regs;
unsigned long base;
- unsigned int memblock_size;
+ unsigned int lmb_size;
int ret = -EINVAL;
/*
return ret;
base = *(unsigned long *)regs;
- memblock_size = regs[3];
+ lmb_size = regs[3];
- ret = pseries_remove_memblock(base, memblock_size);
+ ret = pseries_remove_memblock(base, lmb_size);
return ret;
}
const char *type;
const unsigned int *regs;
unsigned long base;
- unsigned int memblock_size;
+ unsigned int lmb_size;
int ret = -EINVAL;
/*
return ret;
base = *(unsigned long *)regs;
- memblock_size = regs[3];
+ lmb_size = regs[3];
/*
* Update memory region to represent the memory add
*/
- ret = memblock_add(base, memblock_size);
+ ret = memblock_add(base, lmb_size);
return (ret < 0) ? -EINVAL : 0;
}
static int pseries_drconf_memory(unsigned long *base, unsigned int action)
{
struct device_node *np;
- const unsigned long *memblock_size;
+ const unsigned long *lmb_size;
int rc;
np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
if (!np)
return -EINVAL;
- memblock_size = of_get_property(np, "ibm,memblock-size", NULL);
- if (!memblock_size) {
+ lmb_size = of_get_property(np, "ibm,lmb-size", NULL);
+ if (!lmb_size) {
of_node_put(np);
return -EINVAL;
}
if (action == PSERIES_DRCONF_MEM_ADD) {
- rc = memblock_add(*base, *memblock_size);
+ rc = memblock_add(*base, *lmb_size);
rc = (rc < 0) ? -EINVAL : 0;
} else if (action == PSERIES_DRCONF_MEM_REMOVE) {
- rc = pseries_remove_memblock(*base, *memblock_size);
+ rc = pseries_remove_memblock(*base, *lmb_size);
} else {
rc = -EINVAL;
}
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.34-rc3
-# Sat Apr 3 15:49:56 2010
+# Linux kernel version: 2.6.34
+# Wed May 26 21:14:01 2010
#
CONFIG_64BIT=y
CONFIG_SPARC=y
# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PCI_QUIRKS=y
-CONFIG_SLUB_DEBUG=y
# CONFIG_COMPAT_BRK is not set
-# CONFIG_SLAB is not set
-CONFIG_SLUB=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
# CONFIG_SLOB is not set
CONFIG_PROFILING=y
CONFIG_TRACEPOINTS=y
CONFIG_SPARSEMEM_VMEMMAP=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
CONFIG_MIGRATION=y
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_ZONE_DMA_FLAG=0
# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
# CONFIG_BRIDGE is not set
# CONFIG_NET_DSA is not set
CONFIG_VLAN_8021Q=m
# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
+CONFIG_RPS=y
#
# Network testing
#
# CFG80211 needs to be enabled for MAC80211
#
+
+#
+# Some wireless drivers require a rate control algorithm
+#
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
#
# Device Drivers
# CONFIG_NATIONAL_PHY is not set
# CONFIG_STE10XP is not set
# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
CONFIG_MII=m
# CONFIG_CHELSIO_T1 is not set
CONFIG_CHELSIO_T3_DEPENDS=y
# CONFIG_CHELSIO_T3 is not set
+CONFIG_CHELSIO_T4_DEPENDS=y
+# CONFIG_CHELSIO_T4 is not set
# CONFIG_ENIC is not set
# CONFIG_IXGBE is not set
# CONFIG_IXGBEVF is not set
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
# CONFIG_WAN is not set
# CONFIG_FDDI is not set
# CONFIG_HIPPI is not set
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_MPPE=m
CONFIG_PPPOE=m
-# CONFIG_PPPOL2TP is not set
# CONFIG_SLIP is not set
CONFIG_SLHC=m
# CONFIG_NET_FC is not set
CONFIG_KEYBOARD_ATKBD=y
# CONFIG_QT2160 is not set
CONFIG_KEYBOARD_LKKBD=m
+# CONFIG_KEYBOARD_TCA6416 is not set
# CONFIG_KEYBOARD_MAX7359 is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_OPENCORES is not set
# CONFIG_INPUT_TABLET is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_AD714X is not set
CONFIG_INPUT_SPARCSPKR=y
# CONFIG_INPUT_ATI_REMOTE is not set
# CONFIG_INPUT_ATI_REMOTE2 is not set
# CONFIG_INPUT_YEALINK is not set
# CONFIG_INPUT_CM109 is not set
# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_PCF8574 is not set
#
# Hardware I/O ports
# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_DEVKMEM is not set
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
# CONFIG_NOZOMI is not set
#
# CONFIG_SERIAL_JSM is not set
# CONFIG_SERIAL_TIMBERDALE is not set
# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
+# CONFIG_HID_CANDO is not set
CONFIG_HID_CHERRY=y
CONFIG_HID_CHICONY=y
+# CONFIG_HID_PRODIKEYS is not set
CONFIG_HID_CYPRESS=y
CONFIG_HID_DRAGONRISE=y
# CONFIG_DRAGONRISE_FF is not set
+# CONFIG_HID_EGALAX is not set
CONFIG_HID_EZKEY=y
CONFIG_HID_KYE=y
CONFIG_HID_GYRATION=y
CONFIG_HID_PANTHERLORD=y
# CONFIG_PANTHERLORD_FF is not set
CONFIG_HID_PETALYNX=y
+# CONFIG_HID_PICOLCD is not set
# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT_KONE is not set
CONFIG_HID_SAMSUNG=y
CONFIG_HID_SONY=y
# CONFIG_HID_STANTUM is not set
# CONFIG_THRUSTMASTER_FF is not set
CONFIG_HID_ZEROPLUS=y
# CONFIG_ZEROPLUS_FF is not set
+# CONFIG_HID_ZYDACRON is not set
CONFIG_USB_SUPPORT=y
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_USB_DEVICEFS is not set
# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_OTG is not set
# CONFIG_USB_MON is not set
# CONFIG_USB_WUSB is not set
# CONFIG_USB_WUSB_CBAF is not set
# CONFIG_DMADEVICES is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
-
-#
-# TI VLYNQ
-#
# CONFIG_STAGING is not set
#
CONFIG_SCHEDSTATS=y
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_OBJECTS is not set
-# CONFIG_SLUB_DEBUG_ON is not set
-# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
# CONFIG_DEBUG_RT_MUTEXES is not set
# CONFIG_RT_MUTEX_TESTER is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_NOP_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
# CONFIG_RING_BUFFER_BENCHMARK is not set
# CONFIG_DYNAMIC_DEBUG is not set
# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_DEBUG_DCFLUSH is not set
-# CONFIG_STACK_DEBUG is not set
# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
#
#
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_NIAGARA2 is not set
# CONFIG_CRYPTO_DEV_HIFN_795X is not set
CONFIG_BINARY_PRINTF=y
#define L1_CACHE_SHIFT 5
#define L1_CACHE_BYTES 32
-#define L1_CACHE_ALIGN(x) ((((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)))
#ifdef CONFIG_SPARC32
#define SMP_CACHE_BYTES_SHIFT 5
#define pmd_page(pmd) BTFIXUP_CALL(pmd_page)(pmd)
#define pgd_page_vaddr(pgd) BTFIXUP_CALL(pgd_page_vaddr)(pgd)
-BTFIXUPDEF_SETHI(none_mask)
BTFIXUPDEF_CALL_CONST(int, pte_present, pte_t)
BTFIXUPDEF_CALL(void, pte_clear, pte_t *)
static inline int pte_none(pte_t pte)
{
- return !(pte_val(pte) & ~BTFIXUP_SETHI(none_mask));
+ return !pte_val(pte);
}
#define pte_present(pte) BTFIXUP_CALL(pte_present)(pte)
static inline int pmd_none(pmd_t pmd)
{
- return !(pmd_val(pmd) & ~BTFIXUP_SETHI(none_mask));
+ return !pmd_val(pmd);
}
#define pmd_bad(pmd) BTFIXUP_CALL(pmd_bad)(pmd)
cpuc->current_idx[i] = idx;
enc = perf_event_get_enc(cpuc->events[i]);
+ pcr &= ~mask_for_index(idx);
pcr |= event_encoding(enc, idx);
}
out:
goto out_unlock;
}
- if (action && tmp)
+ if (tmp)
tmp->next = action->next;
else
*actionp = action->next;
tl0_irq6: BTRAP(0x46)
#endif
tl0_irq7: TRAP_IRQ(deferred_pcr_work_irq, 7)
-#ifdef CONFIG_KGDB
+#if defined(CONFIG_KGDB) && defined(CONFIG_SMP)
tl0_irq8: TRAP_IRQ(smp_kgdb_capture_client, 8)
#else
tl0_irq8: BTRAP(0x48)
BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pgd_page_vaddr, srmmu_pgd_page, BTFIXUPCALL_NORM);
- BTFIXUPSET_SETHI(none_mask, 0xF0000000);
-
BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0);
BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0);
- /* The 2.4.18 code does not set this on sun4c, how does it work? XXX */
- /* BTFIXUPSET_SETHI(none_mask, 0x00000000); */ /* Defaults to zero? */
-
BTFIXUPSET_CALL(pte_pfn, sun4c_pte_pfn, BTFIXUPCALL_NORM);
#if 0 /* PAGE_SHIFT <= 12 */ /* Eek. Investigate. XXX */
BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1));
percpu_entry->states[cx->index].eax = cx->address;
percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
}
+
+ /*
+ * For _CST FFH on Intel, if GAS.access_size bit 1 is cleared,
+ * then we should skip checking BM_STS for this C-state.
+ * ref: "Intel Processor Vendor-Specific ACPI Interface Specification"
+ */
+ if ((c->x86_vendor == X86_VENDOR_INTEL) && !(reg->access_size & 0x2))
+ cx->bm_sts_skip = 1;
+
return retval;
}
EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
#ifdef CONFIG_HIBERNATION
if (strncmp(str, "s4_nohwsig", 10) == 0)
acpi_no_s4_hw_signature();
- if (strncmp(str, "s4_nonvs", 8) == 0)
- acpi_s4_no_nvs();
+ if (strncmp(str, "s4_nonvs", 8) == 0) {
+ pr_warning("ACPI: acpi_sleep=s4_nonvs is deprecated, "
+ "please use acpi_sleep=nonvs instead");
+ acpi_nvs_nosave();
+ }
#endif
+ if (strncmp(str, "nonvs", 5) == 0)
+ acpi_nvs_nosave();
if (strncmp(str, "old_ordering", 12) == 0)
acpi_old_suspend_ordering();
str = strchr(str, ',');
unsigned int value;
/* APIC hasn't been mapped yet */
- if (!apic_phys)
+ if (!x2apic_mode && !apic_phys)
return;
clear_local_APIC();
return -ENODEV;
out_obj = output.pointer;
- if (out_obj->type != ACPI_TYPE_BUFFER) {
- ret = -ENODEV;
- goto out_free;
- }
+ if (out_obj->type != ACPI_TYPE_BUFFER)
+ return -ENODEV;
errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
- if (errors) {
- ret = -ENODEV;
- goto out_free;
- }
+ if (errors)
+ return -ENODEV;
supported = *((u32 *)(out_obj->buffer.pointer + 4));
- if (!(supported & 0x1)) {
- ret = -ENODEV;
- goto out_free;
- }
+ if (!(supported & 0x1))
+ return -ENODEV;
out_free:
kfree(output.pointer);
struct pcc_memory_resource *mem_resource;
struct pcc_register_resource *reg_resource;
union acpi_object *out_obj, *member;
- acpi_handle handle, osc_handle;
+ acpi_handle handle, osc_handle, pcch_handle;
int ret = 0;
status = acpi_get_handle(NULL, "\\_SB", &handle);
if (ACPI_FAILURE(status))
return -ENODEV;
+ status = acpi_get_handle(handle, "PCCH", &pcch_handle);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
status = acpi_get_handle(handle, "_OSC", &osc_handle);
if (ACPI_SUCCESS(status)) {
ret = pcc_cpufreq_do_osc(&osc_handle);
if (!pcch_virt_addr) {
result = -1;
- goto pcch_null;
+ goto out;
}
result = pcc_get_offset(cpu);
if (result) {
dprintk("init: PCCP evaluation failed\n");
- goto free;
+ goto out;
}
policy->max = policy->cpuinfo.max_freq =
ioread32(&pcch_hdr->minimum_frequency) * 1000;
policy->cur = pcc_get_freq(cpu);
+ if (!policy->cur) {
+ dprintk("init: Unable to get current CPU frequency\n");
+ result = -EINVAL;
+ goto out;
+ }
+
dprintk("init: policy->max is %d, policy->min is %d\n",
policy->max, policy->min);
-
- return 0;
-free:
- pcc_clear_mapping();
- free_percpu(pcc_cpu_info);
-pcch_null:
+out:
return result;
}
}
if (max_latency == 0) {
/*
- * Fam 11h always returns 0 as transition latency.
- * This is intended and means "very fast". While cpufreq core
- * and governors currently can handle that gracefully, better
- * set it to 1 to avoid problems in the future.
- * For all others it's a BIOS bug.
+ * Fam 11h and later may return 0 as transition latency. This
+ * is intended and means "very fast". While cpufreq core and
+ * governors currently can handle that gracefully, better set it
+ * to 1 to avoid problems in the future.
*/
- if (boot_cpu_data.x86 != 0x11)
+ if (boot_cpu_data.x86 < 0x11)
printk(KERN_ERR FW_WARN PFX "Invalid zero transition "
"latency\n");
max_latency = 1;
#include <asm/apic.h>
#include <asm/iommu.h>
#include <asm/gart.h>
+#include <asm/hpet.h>
static void __init fix_hypertransport_config(int num, int slot, int func)
{
}
#endif
+/*
+ * Force the read back of the CMP register in hpet_next_event()
+ * to work around the problem that the CMP register write seems to be
+ * delayed. See hpet_next_event() for details.
+ *
+ * We do this on all SMBUS incarnations for now until we have more
+ * information about the affected chipsets.
+ */
+static void __init ati_hpet_bugs(int num, int slot, int func)
+{
+#ifdef CONFIG_HPET_TIMER
+ hpet_readback_cmp = 1;
+#endif
+}
+
#define QFLAG_APPLY_ONCE 0x1
#define QFLAG_APPLIED 0x2
#define QFLAG_DONE (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs },
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_bugs_contd },
+ { PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_SMBUS, PCI_ANY_ID, 0, ati_hpet_bugs },
{}
};
* masked off.
*/
sysret_audit:
- movq %rax,%rsi /* second arg, syscall return value */
- cmpq $0,%rax /* is it < 0? */
+ movq RAX-ARGOFFSET(%rsp),%rsi /* second arg, syscall return value */
+ cmpq $0,%rsi /* is it < 0? */
setl %al /* 1 if so, 0 if not */
movzbl %al,%edi /* zero-extend that into %edi */
inc %edi /* first arg, 0->1(AUDITSC_SUCCESS), 1->2(AUDITSC_FAILURE) */
void hpet_disable(void)
{
- if (is_hpet_capable()) {
+ if (is_hpet_capable() && hpet_virt_address) {
unsigned int cfg = hpet_readl(HPET_CFG);
if (hpet_legacy_int_enabled) {
.cls = &i8259_sysdev_class,
};
-static int __init i8259A_init_sysfs(void)
-{
- int error = sysdev_class_register(&i8259_sysdev_class);
- if (!error)
- error = sysdev_register(&device_i8259A);
- return error;
-}
-
-device_initcall(i8259A_init_sysfs);
-
static void mask_8259A(void)
{
unsigned long flags;
};
struct legacy_pic *legacy_pic = &default_legacy_pic;
+
+static int __init i8259A_init_sysfs(void)
+{
+ int error;
+
+ if (legacy_pic != &default_legacy_pic)
+ return 0;
+
+ error = sysdev_class_register(&i8259_sysdev_class);
+ if (!error)
+ error = sysdev_register(&device_i8259A);
+ return error;
+}
+
+device_initcall(i8259A_init_sysfs);
/* Skip cs, ip, orig_ax and gs. */ \
" subl $16, %esp\n" \
" pushl %fs\n" \
- " pushl %ds\n" \
" pushl %es\n" \
+ " pushl %ds\n" \
" pushl %eax\n" \
" pushl %ebp\n" \
" pushl %edi\n" \
* See erratum #27 (Misinterpreted MSI Requests May Result in
* Corrupted LPC DMA Data) in AMD Publication #46837,
* "SB700 Family Product Errata", Rev. 1.0, March 2010.
- *
- * Also force the read back of the CMP register in hpet_next_event()
- * to work around the problem that the CMP register write seems to be
- * delayed. See hpet_next_event() for details.
*/
static void force_disable_hpet_msi(struct pci_dev *unused)
{
hpet_msi_disable = 1;
- hpet_readback_cmp = 1;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS,
#ifdef CONFIG_NUMA
per_cpu(x86_cpu_to_node_map, cpu) =
early_per_cpu_map(x86_cpu_to_node_map, cpu);
+ /*
+ * Ensure that the boot cpu numa_node is correct when the boot
+ * cpu is on a node that doesn't have memory installed.
+ * Also cpu_up() will call cpu_to_node() for APs when
+ * MEMORY_HOTPLUG is defined, before per_cpu(numa_node) is set
+ * up later with c_init aka intel_init/amd_init.
+ * So set them all (boot cpu and all APs).
+ */
+ set_cpu_numa_node(cpu, early_cpu_to_node(cpu));
#endif
#endif
/*
early_per_cpu_ptr(x86_cpu_to_node_map) = NULL;
#endif
-#if defined(CONFIG_X86_64) && defined(CONFIG_NUMA)
- /*
- * make sure boot cpu numa_node is right, when boot cpu is on the
- * node that doesn't have mem installed
- */
- set_cpu_numa_node(boot_cpu_id, early_cpu_to_node(boot_cpu_id));
-#endif
-
/* Setup node to cpumask map */
setup_node_to_cpumask_map();
return kvm_mmu_zap_page(kvm, page) + 1;
}
-static int mmu_shrink(int nr_to_scan, gfp_t gfp_mask)
+static int mmu_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
{
struct kvm *kvm;
struct kvm *kvm_freed = NULL;
/* advance table_gfn when emulating 1gb pages with 4k */
if (delta == 0)
table_gfn += PT_INDEX(addr, level);
+ access &= gw->pte_access;
} else {
direct = 0;
table_gfn = gw->table_gfn[level - 2];
r = -ENOMEM;
size = sizeof(struct kvm_msr_entry) * msrs.nmsrs;
- entries = vmalloc(size);
+ entries = kmalloc(size, GFP_KERNEL);
if (!entries)
goto out;
r = n;
out_free:
- vfree(entries);
+ kfree(entries);
out:
return r;
}
idx, r, disabled, pass);
if (pci_claim_resource(dev, idx) < 0) {
/* We'll assign a new address later */
+ dev->fw_addr[idx] = r->start;
r->end -= r->start;
r->start = 0;
}
devfn, pos, 4, &pcie_cap))
return 0;
- if (pcie_cap == 0xffffffff)
- return 0;
+ if (PCI_EXT_CAP_ID(pcie_cap) == 0x0000 ||
+ PCI_EXT_CAP_ID(pcie_cap) == 0xffff)
+ break;
if (PCI_EXT_CAP_ID(pcie_cap) == PCI_EXT_CAP_ID_VNDR) {
raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number,
return pos;
}
- pos = pcie_cap >> 20;
+ pos = PCI_EXT_CAP_NEXT(pcie_cap);
}
return 0;
acpi_status acpi_enable(void)
{
acpi_status status;
+ int retry;
ACPI_FUNCTION_TRACE(acpi_enable);
/* Sanity check that transition succeeded */
- if (acpi_hw_get_mode() != ACPI_SYS_MODE_ACPI) {
- ACPI_ERROR((AE_INFO,
- "Hardware did not enter ACPI mode"));
- return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
+ for (retry = 0; retry < 30000; ++retry) {
+ if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
+ if (retry != 0)
+ ACPI_WARNING((AE_INFO,
+ "Platform took > %d00 usec to enter ACPI mode", retry));
+ return_ACPI_STATUS(AE_OK);
+ }
+ acpi_os_stall(100); /* 100 usec */
}
- ACPI_DEBUG_PRINT((ACPI_DB_INIT,
- "Transition to ACPI mode successful\n"));
-
- return_ACPI_STATUS(AE_OK);
+ ACPI_ERROR((AE_INFO, "Hardware did not enter ACPI mode"));
+ return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
}
ACPI_EXPORT_SYMBOL(acpi_enable)
static void acpi_battery_notify(struct acpi_device *device, u32 event)
{
struct acpi_battery *battery = acpi_driver_data(device);
+#ifdef CONFIG_ACPI_SYSFS_POWER
+ struct device *old;
+#endif
if (!battery)
return;
+#ifdef CONFIG_ACPI_SYSFS_POWER
+ old = battery->bat.dev;
+#endif
acpi_battery_update(battery);
acpi_bus_generate_proc_event(device, event,
acpi_battery_present(battery));
acpi_battery_present(battery));
#ifdef CONFIG_ACPI_SYSFS_POWER
/* acpi_battery_update could remove power_supply object */
- if (battery->bat.dev)
+ if (old && battery->bat.dev)
power_supply_changed(&battery->bat);
#endif
}
.ident = "Sony VGN-SR290J",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
- DMI_MATCH(DMI_PRODUCT_NAME, "Sony VGN-SR290J"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SR290J"),
},
},
{
type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
cpuid = acpi_get_cpuid(handle, type, acpi_id);
- if (cpuid == -1)
+ if ((cpuid == -1) && (num_possible_cpus() > 1))
return false;
return true;
module_param(max_cstate, uint, 0000);
static unsigned int nocst __read_mostly;
module_param(nocst, uint, 0000);
+static int bm_check_disable __read_mostly;
+module_param(bm_check_disable, uint, 0000);
static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644);
+#ifdef CONFIG_ACPI_PROCFS
static u64 us_to_pm_timer_ticks(s64 t)
{
return div64_u64(t * PM_TIMER_FREQUENCY, 1000000);
}
+#endif
+
/*
* IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
* For now disable this. Probably a bug somewhere else.
{
u32 bm_status = 0;
+ if (bm_check_disable)
+ return 0;
+
acpi_read_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
if (bm_status)
acpi_write_bit_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
if (acpi_idle_suspend)
return(acpi_idle_enter_c1(dev, state));
- if (acpi_idle_bm_check()) {
+ if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
if (dev->safe_state) {
dev->last_state = dev->safe_state;
return dev->safe_state->enter(dev, dev->safe_state);
#ifdef CONFIG_ACPI_SLEEP
static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+/*
+ * The ACPI specification wants us to save NVS memory regions during hibernation
+ * and to restore them during the subsequent resume. Windows does that also for
+ * suspend to RAM. However, it is known that this mechanism does not work on
+ * all machines, so we allow the user to disable it with the help of the
+ * 'acpi_sleep=nonvs' kernel command line option.
+ */
+static bool nvs_nosave;
+
+void __init acpi_nvs_nosave(void)
+{
+ nvs_nosave = true;
+}
+
/*
* ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the
* user to request that behavior by using the 'acpi_old_suspend_ordering'
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
- error = suspend_nvs_alloc();
-
+ error = nvs_nosave ? 0 : suspend_nvs_alloc();
if (error)
return error;
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATION
-/*
- * The ACPI specification wants us to save NVS memory regions during hibernation
- * and to restore them during the subsequent resume. However, it is not certain
- * if this mechanism is going to work on all machines, so we allow the user to
- * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line
- * option.
- */
-static bool s4_no_nvs;
-
-void __init acpi_s4_no_nvs(void)
-{
- s4_no_nvs = true;
-}
-
static unsigned long s4_hardware_signature;
static struct acpi_table_facs *facs;
static bool nosigcheck;
{
int error;
- error = s4_no_nvs ? 0 : suspend_nvs_alloc();
+ error = nvs_nosave ? 0 : suspend_nvs_alloc();
if (!error) {
acpi_target_sleep_state = ACPI_STATE_S4;
acpi_sleep_tts_switch(acpi_target_sleep_state);
error = acpi_sleep_prepare(ACPI_STATE_S4);
if (!error) {
- if (!s4_no_nvs)
+ if (!nvs_nosave)
error = suspend_nvs_alloc();
if (!error)
acpi_target_sleep_state = ACPI_STATE_S4;
*/
if (parent == NULL)
parent_kobj = virtual_device_parent(dev);
- else if (parent->class)
+ else if (parent->class && !dev->class->ns_type)
return &parent->kobj;
else
parent_kobj = &parent->kobj;
/* G33's GTT size defined in gmch_ctrl */
pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
- switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
- case G33_PGETBL_SIZE_1M:
+ switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+ case I830_GMCH_GMS_STOLEN_512:
+ size = 512;
+ break;
+ case I830_GMCH_GMS_STOLEN_1024:
size = 1024;
break;
- case G33_PGETBL_SIZE_2M:
- size = 2048;
+ case I830_GMCH_GMS_STOLEN_8192:
+ size = 8*1024;
break;
default:
dev_info(&agp_bridge->dev->dev,
"unknown page table size 0x%x, assuming 512KB\n",
- (gmch_ctrl & G33_PGETBL_SIZE_MASK));
+ (gmch_ctrl & I830_GMCH_GMS_MASK));
size = 512;
}
} else {
sysrq_key_table[i] = op_p;
}
-static void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
+void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
{
struct sysrq_key_op *op_p;
int orig_log_level;
static int tpm_tis_pnp_resume(struct pnp_dev *dev)
{
- return tpm_pm_resume(&dev->dev);
+ struct tpm_chip *chip = pnp_get_drvdata(dev);
+ int ret;
+
+ ret = tpm_pm_resume(&dev->dev);
+ if (!ret)
+ tpm_continue_selftest(chip);
+
+ return ret;
}
static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
module_init(cs5535_mfgpt_init);
-MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>");
+MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("CS5535/CS5536 MFGPT clock event driver");
MODULE_LICENSE("GPL");
err_unlock_policy:
unlock_policy_rwsem_write(cpu);
+ free_cpumask_var(policy->related_cpus);
err_free_cpumask:
free_cpumask_var(policy->cpus);
err_free_policy:
dprintk("governor switch\n");
/* end old governor */
- if (data->governor) {
- /*
- * Need to release the rwsem around governor
- * stop due to lock dependency between
- * cancel_delayed_work_sync and the read lock
- * taken in the delayed work handler.
- */
- unlock_policy_rwsem_write(data->cpu);
+ if (data->governor)
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
- lock_policy_rwsem_write(data->cpu);
- }
/* start new governor */
data->governor = policy->governor;
/* Copy part of this segment */
ignore = skip - offset;
len = miter.length - ignore;
+ if (boffset + len > buflen)
+ len = buflen - boffset;
memcpy(buf + boffset, miter.addr + ignore, len);
} else {
- /* Copy all of this segment */
+ /* Copy all of this segment (up to buflen) */
len = miter.length;
+ if (boffset + len > buflen)
+ len = buflen - boffset;
memcpy(buf + boffset, miter.addr, len);
}
boffset += len;
config EDAC_MPC85XX
tristate "Freescale MPC83xx / MPC85xx"
- depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || MPC85xx)
+ depends on EDAC_MM_EDAC && FSL_SOC && (PPC_83xx || PPC_85xx)
help
Support for error detection and correction on the Freescale
MPC8349, MPC8560, MPC8540, MPC8548
if (devno == 0)
return -ENODEV;
- i7core_printk(KERN_ERR,
+ i7core_printk(KERN_INFO,
"Device not found: dev %02x.%d PCI ID %04x:%04x\n",
dev_descr->dev, dev_descr->func,
PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
},
{},
};
+MODULE_DEVICE_TABLE(of, mpc85xx_pci_err_of_match);
static struct of_platform_driver mpc85xx_pci_err_driver = {
.probe = mpc85xx_pci_err_probe,
{ .compatible = "fsl,p2020-l2-cache-controller", },
{},
};
+MODULE_DEVICE_TABLE(of, mpc85xx_l2_err_of_match);
static struct of_platform_driver mpc85xx_l2_err_driver = {
.probe = mpc85xx_l2_err_probe,
{ .compatible = "fsl,mpc8555-memory-controller", },
{ .compatible = "fsl,mpc8560-memory-controller", },
{ .compatible = "fsl,mpc8568-memory-controller", },
+ { .compatible = "fsl,mpc8569-memory-controller", },
{ .compatible = "fsl,mpc8572-memory-controller", },
{ .compatible = "fsl,mpc8349-memory-controller", },
{ .compatible = "fsl,p2020-memory-controller", },
{},
};
+MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match);
static struct of_platform_driver mpc85xx_mc_err_driver = {
.probe = mpc85xx_mc_err_probe,
module_init(cs5535_gpio_init);
module_exit(cs5535_gpio_exit);
-MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>");
+MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("AMD CS5535/CS5536 GPIO driver");
MODULE_LICENSE("GPL");
void gpio_unexport(unsigned gpio)
{
struct gpio_desc *desc;
- int status = -EINVAL;
+ int status = 0;
- if (!gpio_is_valid(gpio))
+ if (!gpio_is_valid(gpio)) {
+ status = -EINVAL;
goto done;
+ }
mutex_lock(&sysfs_lock);
clear_bit(FLAG_EXPORT, &desc->flags);
put_device(dev);
device_unregister(dev);
- status = 0;
} else
status = -ENODEV;
}
case FBC_NOT_TILED:
seq_printf(m, "scanout buffer not tiled");
break;
+ case FBC_MULTIPLE_PIPES:
+ seq_printf(m, "multiple pipes are enabled");
+ break;
default:
seq_printf(m, "unknown reason");
}
struct drm_i915_private *dev_priv = dev->dev_private;
drm_mm_put_block(dev_priv->compressed_fb);
- if (!IS_GM45(dev))
+ if (dev_priv->compressed_llb)
drm_mm_put_block(dev_priv->compressed_llb);
}
FBC_MODE_TOO_LARGE, /* mode too large for compression */
FBC_BAD_PLANE, /* fbc not supported on plane */
FBC_NOT_TILED, /* buffer not tiled */
+ FBC_MULTIPLE_PIPES, /* more than one pipe active */
};
enum intel_pch {
PCH_CPT, /* Cougarpoint PCH */
};
+#define QUIRK_PIPEA_FORCE (1<<0)
+
struct intel_fbdev;
typedef struct drm_i915_private {
/* PCH chipset type */
enum intel_pch pch_type;
+ unsigned long quirks;
+
/* Register state */
bool modeset_on_lid;
u8 saveLBB;
page = read_cache_page_gfp(mapping, i,
GFP_HIGHUSER |
__GFP_COLD |
+ __GFP_RECLAIMABLE |
gfpmask);
if (IS_ERR(page))
goto err_pages;
return ret;
}
+
int
i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv,
unsigned long long total_size = 0;
int num_fences = 0;
for (i = 0; i < args->buffer_count; i++) {
- obj_priv = object_list[i]->driver_private;
+ obj_priv = to_intel_bo(object_list[i]);
total_size += object_list[i]->size;
num_fences +=
list_add(&dev_priv->mm.shrink_list, &shrink_list);
spin_unlock(&shrink_list_lock);
+ /* On GEN3 we really need to make sure the ARB C3 LP bit is set */
+ if (IS_GEN3(dev)) {
+ u32 tmp = I915_READ(MI_ARB_STATE);
+ if (!(tmp & MI_ARB_C3_LP_WRITE_ENABLE)) {
+ /* arb state is a masked write, so set bit + bit in mask */
+ tmp = MI_ARB_C3_LP_WRITE_ENABLE | (MI_ARB_C3_LP_WRITE_ENABLE << MI_ARB_MASK_SHIFT);
+ I915_WRITE(MI_ARB_STATE, tmp);
+ }
+ }
+
/* Old X drivers will take 0-2 for front, back, depth buffers */
if (!drm_core_check_feature(dev, DRIVER_MODESET))
dev_priv->fence_reg_start = 3;
}
static int
-i915_gem_shrink(int nr_to_scan, gfp_t gfp_mask)
+i915_gem_shrink(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
{
drm_i915_private_t *dev_priv, *next_dev;
struct drm_i915_gem_object *obj_priv, *next_obj;
#define LM_BURST_LENGTH 0x00000700
#define LM_FIFO_WATERMARK 0x0000001F
#define MI_ARB_STATE 0x020e4 /* 915+ only */
+#define MI_ARB_MASK_SHIFT 16 /* shift for enable bits */
+
+/* Make render/texture TLB fetches lower priorty than associated data
+ * fetches. This is not turned on by default
+ */
+#define MI_ARB_RENDER_TLB_LOW_PRIORITY (1 << 15)
+
+/* Isoch request wait on GTT enable (Display A/B/C streams).
+ * Make isoch requests stall on the TLB update. May cause
+ * display underruns (test mode only)
+ */
+#define MI_ARB_ISOCH_WAIT_GTT (1 << 14)
+
+/* Block grant count for isoch requests when block count is
+ * set to a finite value.
+ */
+#define MI_ARB_BLOCK_GRANT_MASK (3 << 12)
+#define MI_ARB_BLOCK_GRANT_8 (0 << 12) /* for 3 display planes */
+#define MI_ARB_BLOCK_GRANT_4 (1 << 12) /* for 2 display planes */
+#define MI_ARB_BLOCK_GRANT_2 (2 << 12) /* for 1 display plane */
+#define MI_ARB_BLOCK_GRANT_0 (3 << 12) /* don't use */
+
+/* Enable render writes to complete in C2/C3/C4 power states.
+ * If this isn't enabled, render writes are prevented in low
+ * power states. That seems bad to me.
+ */
+#define MI_ARB_C3_LP_WRITE_ENABLE (1 << 11)
+
+/* This acknowledges an async flip immediately instead
+ * of waiting for 2TLB fetches.
+ */
+#define MI_ARB_ASYNC_FLIP_ACK_IMMEDIATE (1 << 10)
+
+/* Enables non-sequential data reads through arbiter
+ */
+#define MI_ARB_DUAL_DATA_PHASE_DISABLE (1 << 9)
+
+/* Disable FSB snooping of cacheable write cycles from binner/render
+ * command stream
+ */
+#define MI_ARB_CACHE_SNOOP_DISABLE (1 << 8)
+
+/* Arbiter time slice for non-isoch streams */
+#define MI_ARB_TIME_SLICE_MASK (7 << 5)
+#define MI_ARB_TIME_SLICE_1 (0 << 5)
+#define MI_ARB_TIME_SLICE_2 (1 << 5)
+#define MI_ARB_TIME_SLICE_4 (2 << 5)
+#define MI_ARB_TIME_SLICE_6 (3 << 5)
+#define MI_ARB_TIME_SLICE_8 (4 << 5)
+#define MI_ARB_TIME_SLICE_10 (5 << 5)
+#define MI_ARB_TIME_SLICE_14 (6 << 5)
+#define MI_ARB_TIME_SLICE_16 (7 << 5)
+
+/* Low priority grace period page size */
+#define MI_ARB_LOW_PRIORITY_GRACE_4KB (0 << 4) /* default */
+#define MI_ARB_LOW_PRIORITY_GRACE_8KB (1 << 4)
+
+/* Disable display A/B trickle feed */
+#define MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE (1 << 2)
+
+/* Set display plane priority */
+#define MI_ARB_DISPLAY_PRIORITY_A_B (0 << 0) /* display A > display B */
+#define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */
+
#define CACHE_MODE_0 0x02120 /* 915+ only */
#define CM0_MASK_SHIFT 16
#define CM0_IZ_OPT_DISABLE (1<<6)
#define PCH_PP_STATUS 0xc7200
#define PCH_PP_CONTROL 0xc7204
+#define PANEL_UNLOCK_REGS (0xabcd << 16)
#define EDP_FORCE_VDD (1 << 3)
#define EDP_BLC_ENABLE (1 << 2)
#define PANEL_POWER_RESET (1 << 1)
intel_clock_t clock;
int max_n;
bool found;
- /* approximately equals target * 0.00488 */
- int err_most = (target >> 8) + (target >> 10);
+ /* approximately equals target * 0.00585 */
+ int err_most = (target >> 8) + (target >> 9);
found = false;
if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
struct drm_framebuffer *fb = crtc->fb;
struct intel_framebuffer *intel_fb;
struct drm_i915_gem_object *obj_priv;
+ struct drm_crtc *tmp_crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int plane = intel_crtc->plane;
+ int crtcs_enabled = 0;
+
+ DRM_DEBUG_KMS("\n");
if (!i915_powersave)
return;
* If FBC is already on, we just have to verify that we can
* keep it that way...
* Need to disable if:
+ * - more than one pipe is active
* - changing FBC params (stride, fence, mode)
* - new fb is too large to fit in compressed buffer
* - going to an unsupported config (interlace, pixel multiply, etc.)
*/
+ list_for_each_entry(tmp_crtc, &dev->mode_config.crtc_list, head) {
+ if (tmp_crtc->enabled)
+ crtcs_enabled++;
+ }
+ DRM_DEBUG_KMS("%d pipes active\n", crtcs_enabled);
+ if (crtcs_enabled > 1) {
+ DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+ dev_priv->no_fbc_reason = FBC_MULTIPLE_PIPES;
+ goto out_disable;
+ }
if (intel_fb->obj->size > dev_priv->cfb_size) {
DRM_DEBUG_KMS("framebuffer too large, disabling "
"compression\n");
}
}
-static int
+int
intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_gem_object *obj)
{
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
intel_wait_for_vblank(dev);
}
+ /* Don't disable pipe A or pipe A PLLs if needed */
+ if (pipeconf_reg == PIPEACONF &&
+ (dev_priv->quirks & QUIRK_PIPEA_FORCE))
+ goto skip_pipe_off;
+
/* Next, disable display pipes */
temp = I915_READ(pipeconf_reg);
if ((temp & PIPEACONF_ENABLE) != 0) {
I915_WRITE(dpll_reg, temp & ~DPLL_VCO_ENABLE);
I915_READ(dpll_reg);
}
-
+ skip_pipe_off:
/* Wait for the clocks to turn off. */
udelay(150);
break;
if (mode->clock * 3 > 27000 * 4)
return MODE_CLOCK_HIGH;
}
-
- drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
}
if (dev_priv->lvds_dither) {
if (HAS_PCH_SPLIT(dev)) {
pipeconf |= PIPE_ENABLE_DITHER;
+ pipeconf &= ~PIPE_DITHER_TYPE_MASK;
pipeconf |= PIPE_DITHER_TYPE_ST01;
} else
lvds |= LVDS_ENABLE_DITHER;
DRM_DEBUG_DRIVER("upclocking LVDS\n");
/* Unlock panel regs */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16));
+ I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
+ PANEL_UNLOCK_REGS);
dpll &= ~DISPLAY_RATE_SELECT_FPA1;
I915_WRITE(dpll_reg, dpll);
DRM_DEBUG_DRIVER("downclocking LVDS\n");
/* Unlock panel regs */
- I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) | (0xabcd << 16));
+ I915_WRITE(PP_CONTROL, I915_READ(PP_CONTROL) |
+ PANEL_UNLOCK_REGS);
dpll |= DISPLAY_RATE_SELECT_FPA1;
I915_WRITE(dpll_reg, dpll);
struct drm_gem_object *obj;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_unpin_work *work;
- unsigned long flags;
+ unsigned long flags, offset;
int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
int ret, pipesrc;
u32 flip_mask;
while (I915_READ(ISR) & flip_mask)
;
+ /* Offset into the new buffer for cases of shared fbs between CRTCs */
+ offset = obj_priv->gtt_offset;
+ offset += (crtc->y * fb->pitch) + (crtc->x * (fb->bits_per_pixel) / 8);
+
BEGIN_LP_RING(4);
if (IS_I965G(dev)) {
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
- OUT_RING(obj_priv->gtt_offset | obj_priv->tiling_mode);
+ OUT_RING(offset | obj_priv->tiling_mode);
pipesrc = I915_READ(pipesrc_reg);
OUT_RING(pipesrc & 0x0fff0fff);
} else {
OUT_RING(MI_DISPLAY_FLIP_I915 |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch);
- OUT_RING(obj_priv->gtt_offset);
+ OUT_RING(offset);
OUT_RING(MI_NOOP);
}
ADVANCE_LP_RING();
}
}
+/*
+ * Some BIOSes insist on assuming the GPU's pipe A is enabled at suspend,
+ * resume, or other times. This quirk makes sure that's the case for
+ * affected systems.
+ */
+static void quirk_pipea_force (struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ dev_priv->quirks |= QUIRK_PIPEA_FORCE;
+ DRM_DEBUG_DRIVER("applying pipe a force quirk\n");
+}
+
+struct intel_quirk {
+ int device;
+ int subsystem_vendor;
+ int subsystem_device;
+ void (*hook)(struct drm_device *dev);
+};
+
+struct intel_quirk intel_quirks[] = {
+ /* HP Compaq 2730p needs pipe A force quirk (LP: #291555) */
+ { 0x2a42, 0x103c, 0x30eb, quirk_pipea_force },
+ /* HP Mini needs pipe A force quirk (LP: #322104) */
+ { 0x27ae,0x103c, 0x361a, quirk_pipea_force },
+
+ /* Thinkpad R31 needs pipe A force quirk */
+ { 0x3577, 0x1014, 0x0505, quirk_pipea_force },
+ /* Toshiba Protege R-205, S-209 needs pipe A force quirk */
+ { 0x2592, 0x1179, 0x0001, quirk_pipea_force },
+
+ /* ThinkPad X30 needs pipe A force quirk (LP: #304614) */
+ { 0x3577, 0x1014, 0x0513, quirk_pipea_force },
+ /* ThinkPad X40 needs pipe A force quirk */
+
+ /* ThinkPad T60 needs pipe A force quirk (bug #16494) */
+ { 0x2782, 0x17aa, 0x201a, quirk_pipea_force },
+
+ /* 855 & before need to leave pipe A & dpll A up */
+ { 0x3582, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
+ { 0x2562, PCI_ANY_ID, PCI_ANY_ID, quirk_pipea_force },
+};
+
+static void intel_init_quirks(struct drm_device *dev)
+{
+ struct pci_dev *d = dev->pdev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(intel_quirks); i++) {
+ struct intel_quirk *q = &intel_quirks[i];
+
+ if (d->device == q->device &&
+ (d->subsystem_vendor == q->subsystem_vendor ||
+ q->subsystem_vendor == PCI_ANY_ID) &&
+ (d->subsystem_device == q->subsystem_device ||
+ q->subsystem_device == PCI_ANY_ID))
+ q->hook(dev);
+ }
+}
+
void intel_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
dev->mode_config.funcs = (void *)&intel_mode_funcs;
+ intel_init_quirks(dev);
+
intel_init_display(dev);
if (IS_I965G(dev)) {
}
}
+static void ironlake_edp_panel_on (struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long timeout = jiffies + msecs_to_jiffies(5000);
+ u32 pp, pp_status;
+
+ pp_status = I915_READ(PCH_PP_STATUS);
+ if (pp_status & PP_ON)
+ return;
+
+ pp = I915_READ(PCH_PP_CONTROL);
+ pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
+ I915_WRITE(PCH_PP_CONTROL, pp);
+ do {
+ pp_status = I915_READ(PCH_PP_STATUS);
+ } while (((pp_status & PP_ON) == 0) && !time_after(jiffies, timeout));
+
+ if (time_after(jiffies, timeout))
+ DRM_DEBUG_KMS("panel on wait timed out: 0x%08x\n", pp_status);
+
+ pp &= ~(PANEL_UNLOCK_REGS | EDP_FORCE_VDD);
+ I915_WRITE(PCH_PP_CONTROL, pp);
+}
+
+static void ironlake_edp_panel_off (struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long timeout = jiffies + msecs_to_jiffies(5000);
+ u32 pp, pp_status;
+
+ pp = I915_READ(PCH_PP_CONTROL);
+ pp &= ~POWER_TARGET_ON;
+ I915_WRITE(PCH_PP_CONTROL, pp);
+ do {
+ pp_status = I915_READ(PCH_PP_STATUS);
+ } while ((pp_status & PP_ON) && !time_after(jiffies, timeout));
+
+ if (time_after(jiffies, timeout))
+ DRM_DEBUG_KMS("panel off wait timed out\n");
+
+ /* Make sure VDD is enabled so DP AUX will work */
+ pp |= EDP_FORCE_VDD;
+ I915_WRITE(PCH_PP_CONTROL, pp);
+}
+
static void ironlake_edp_backlight_on (struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
if (mode != DRM_MODE_DPMS_ON) {
if (dp_reg & DP_PORT_EN) {
intel_dp_link_down(intel_encoder, dp_priv->DP);
- if (IS_eDP(intel_encoder))
+ if (IS_eDP(intel_encoder)) {
ironlake_edp_backlight_off(dev);
+ ironlake_edp_panel_off(dev);
+ }
}
} else {
if (!(dp_reg & DP_PORT_EN)) {
intel_dp_link_train(intel_encoder, dp_priv->DP, dp_priv->link_configuration);
- if (IS_eDP(intel_encoder))
+ if (IS_eDP(intel_encoder)) {
+ ironlake_edp_panel_on(dev);
ironlake_edp_backlight_on(dev);
+ }
}
}
dp_priv->dpms_mode = mode;
extern void ironlake_enable_drps(struct drm_device *dev);
extern void ironlake_disable_drps(struct drm_device *dev);
+extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
+ struct drm_gem_object *obj);
+
extern int intel_framebuffer_init(struct drm_device *dev,
struct intel_framebuffer *ifb,
struct drm_mode_fb_cmd *mode_cmd,
mutex_lock(&dev->struct_mutex);
- ret = i915_gem_object_pin(fbo, 64*1024);
+ ret = intel_pin_and_fence_fb_obj(dev, fbo);
if (ret) {
DRM_ERROR("failed to pin fb: %d\n", ret);
goto out_unref;
drm_framebuffer_cleanup(&ifb->base);
if (ifb->obj)
- drm_gem_object_unreference_unlocked(ifb->obj);
+ drm_gem_object_unreference(ifb->obj);
return 0;
}
return 0;
}
+static int intel_no_modeset_on_lid_dmi_callback(const struct dmi_system_id *id)
+{
+ DRM_DEBUG_KMS("Skipping forced modeset for %s\n", id->ident);
+ return 1;
+}
+
+/* The GPU hangs up on these systems if modeset is performed on LID open */
+static const struct dmi_system_id intel_no_modeset_on_lid[] = {
+ {
+ .callback = intel_no_modeset_on_lid_dmi_callback,
+ .ident = "Toshiba Tecra A11",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TECRA A11"),
+ },
+ },
+
+ { } /* terminating entry */
+};
+
/*
* Lid events. Note the use of 'modeset_on_lid':
* - we set it on lid close, and reset it on open
*/
if (connector)
connector->status = connector->funcs->detect(connector);
+ /* Don't force modeset on machines where it causes a GPU lockup */
+ if (dmi_check_system(intel_no_modeset_on_lid))
+ return NOTIFY_OK;
if (!acpi_lid_open()) {
dev_priv->modeset_on_lid = 1;
return NOTIFY_OK;
const bool rw;
};
-static struct methods nv04_methods[] = {
- { "PROM", load_vbios_prom, false },
- { "PRAMIN", load_vbios_pramin, true },
- { "PCIROM", load_vbios_pci, true },
-};
-
-static struct methods nv50_methods[] = {
- { "ACPI", load_vbios_acpi, true },
+static struct methods shadow_methods[] = {
{ "PRAMIN", load_vbios_pramin, true },
{ "PROM", load_vbios_prom, false },
{ "PCIROM", load_vbios_pci, true },
+ { "ACPI", load_vbios_acpi, true },
};
-#define METHODCNT 3
-
static bool NVShadowVBIOS(struct drm_device *dev, uint8_t *data)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct methods *methods;
- int i;
+ const int nr_methods = ARRAY_SIZE(shadow_methods);
+ struct methods *methods = shadow_methods;
int testscore = 3;
- int scores[METHODCNT];
+ int scores[nr_methods], i;
if (nouveau_vbios) {
- methods = nv04_methods;
- for (i = 0; i < METHODCNT; i++)
+ for (i = 0; i < nr_methods; i++)
if (!strcasecmp(nouveau_vbios, methods[i].desc))
break;
- if (i < METHODCNT) {
+ if (i < nr_methods) {
NV_INFO(dev, "Attempting to use BIOS image from %s\n",
methods[i].desc);
NV_ERROR(dev, "VBIOS source \'%s\' invalid\n", nouveau_vbios);
}
- if (dev_priv->card_type < NV_50)
- methods = nv04_methods;
- else
- methods = nv50_methods;
-
- for (i = 0; i < METHODCNT; i++) {
+ for (i = 0; i < nr_methods; i++) {
NV_TRACE(dev, "Attempting to load BIOS image from %s\n",
methods[i].desc);
data[0] = data[1] = 0; /* avoid reuse of previous image */
}
while (--testscore > 0) {
- for (i = 0; i < METHODCNT; i++) {
+ for (i = 0; i < nr_methods; i++) {
if (scores[i] == testscore) {
NV_TRACE(dev, "Using BIOS image from %s\n",
methods[i].desc);
dev_priv->nfbdev = nfbdev;
nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
- ret = drm_fb_helper_init(dev, &nfbdev->helper, 2, 4);
+ ret = drm_fb_helper_init(dev, &nfbdev->helper,
+ nv_two_heads(dev) ? 2 : 1, 4);
if (ret) {
kfree(nfbdev);
return ret;
header = radeon_get_ib_value(p, h_idx);
crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
reg = CP_PACKET0_GET_REG(header);
- mutex_lock(&p->rdev->ddev->mode_config.mutex);
obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
DRM_ERROR("cannot find crtc %d\n", crtc_id);
}
}
out:
- mutex_unlock(&p->rdev->ddev->mode_config.mutex);
return r;
}
header = radeon_get_ib_value(p, h_idx);
crtc_id = radeon_get_ib_value(p, h_idx + 5);
reg = CP_PACKET0_GET_REG(header);
- mutex_lock(&p->rdev->ddev->mode_config.mutex);
obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
DRM_ERROR("cannot find crtc %d\n", crtc_id);
ib[h_idx + 3] |= RADEON_ENG_DISPLAY_SELECT_CRTC1;
}
out:
- mutex_unlock(&p->rdev->ddev->mode_config.mutex);
return r;
}
if (rdev->flags & RADEON_IS_IGP)
base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
radeon_vram_location(rdev, &rdev->mc, base);
+ rdev->mc.gtt_base_align = 0;
if (!(rdev->flags & RADEON_IS_AGP))
radeon_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
if (rdev->flags & RADEON_IS_IGP)
base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
radeon_vram_location(rdev, &rdev->mc, base);
+ rdev->mc.gtt_base_align = 0;
if (!(rdev->flags & RADEON_IS_AGP))
radeon_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
int r;
track = kzalloc(sizeof(*track), GFP_KERNEL);
+ if (track == NULL)
+ return -ENOMEM;
r100_cs_track_clear(p->rdev, track);
p->track = track;
do {
r520_vram_get_type(rdev);
r100_vram_init_sizes(rdev);
radeon_vram_location(rdev, &rdev->mc, 0);
+ rdev->mc.gtt_base_align = 0;
if (!(rdev->flags & RADEON_IS_AGP))
radeon_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
if (rdev->flags & RADEON_IS_IGP)
base = (RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
radeon_vram_location(rdev, &rdev->mc, base);
+ rdev->mc.gtt_base_align = 0;
radeon_gtt_location(rdev, mc);
}
}
r600_prepare_blit_copy(struct drm_device *dev, struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
+ int ret;
DRM_DEBUG("\n");
- r600_nomm_get_vb(dev);
+ ret = r600_nomm_get_vb(dev);
+ if (ret)
+ return ret;
dev_priv->blit_vb->file_priv = file_priv;
header = radeon_get_ib_value(p, h_idx);
crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
reg = CP_PACKET0_GET_REG(header);
- mutex_lock(&p->rdev->ddev->mode_config.mutex);
+
obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
DRM_ERROR("cannot find crtc %d\n", crtc_id);
ib[h_idx + 4] = AVIVO_D2MODE_VLINE_STATUS >> 2;
}
out:
- mutex_unlock(&p->rdev->ddev->mode_config.mutex);
return r;
}
int vram_mtrr;
bool vram_is_ddr;
bool igp_sideport_enabled;
+ u64 gtt_base_align;
};
bool radeon_combios_sideport_present(struct radeon_device *rdev);
}
}
+ /* ASUS HD 3600 board lists the DVI port as HDMI */
+ if ((dev->pdev->device == 0x9598) &&
+ (dev->pdev->subsystem_vendor == 0x1043) &&
+ (dev->pdev->subsystem_device == 0x01e4)) {
+ if (*connector_type == DRM_MODE_CONNECTOR_HDMIA) {
+ *connector_type = DRM_MODE_CONNECTOR_DVII;
+ }
+ }
+
/* ASUS HD 3450 board lists the DVI port as HDMI */
if ((dev->pdev->device == 0x95C5) &&
(dev->pdev->subsystem_vendor == 0x1043) &&
data_offset);
switch (crev) {
case 1:
- if (igp_info->info.ucMemoryType & 0xf0)
- return true;
+ /* AMD IGPS */
+ if ((rdev->family == CHIP_RS690) ||
+ (rdev->family == CHIP_RS740)) {
+ if (igp_info->info.ulBootUpMemoryClock)
+ return true;
+ } else {
+ if (igp_info->info.ucMemoryType & 0xf0)
+ return true;
+ }
break;
case 2:
if (igp_info->info_2.ucMemoryType & 0x0f)
rdev->pdev->subsystem_device == 0x308b)
return;
+ /* quirk for rs4xx HP dv5000 laptop to make it resume
+ * - it hangs on resume inside the dynclk 1 table.
+ */
+ if (rdev->family == CHIP_RS480 &&
+ rdev->pdev->subsystem_vendor == 0x103c &&
+ rdev->pdev->subsystem_device == 0x30a4)
+ return;
+
/* DYN CLK 1 */
table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
if (table)
} else
ret = connector_status_connected;
- /* multiple connectors on the same encoder with the same ddc line
- * This tends to be HDMI and DVI on the same encoder with the
- * same ddc line. If the edid says HDMI, consider the HDMI port
- * connected and the DVI port disconnected. If the edid doesn't
- * say HDMI, vice versa.
+ /* This gets complicated. We have boards with VGA + HDMI with a
+ * shared DDC line and we have boards with DVI-D + HDMI with a shared
+ * DDC line. The latter is more complex because with DVI<->HDMI adapters
+ * you don't really know what's connected to which port as both are digital.
*/
if (radeon_connector->shared_ddc && (ret == connector_status_connected)) {
struct drm_device *dev = connector->dev;
+ struct radeon_device *rdev = dev->dev_private;
struct drm_connector *list_connector;
struct radeon_connector *list_radeon_connector;
list_for_each_entry(list_connector, &dev->mode_config.connector_list, head) {
if (list_radeon_connector->shared_ddc &&
(list_radeon_connector->ddc_bus->rec.i2c_id ==
radeon_connector->ddc_bus->rec.i2c_id)) {
- if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
- if (connector->connector_type == DRM_MODE_CONNECTOR_DVID) {
- kfree(radeon_connector->edid);
- radeon_connector->edid = NULL;
- ret = connector_status_disconnected;
- }
- } else {
- if ((connector->connector_type == DRM_MODE_CONNECTOR_HDMIA) ||
- (connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)) {
+ /* cases where both connectors are digital */
+ if (list_connector->connector_type != DRM_MODE_CONNECTOR_VGA) {
+ /* hpd is our only option in this case */
+ if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
kfree(radeon_connector->edid);
radeon_connector->edid = NULL;
ret = connector_status_disconnected;
{
u64 size_af, size_bf;
- size_af = 0xFFFFFFFF - mc->vram_end;
- size_bf = mc->vram_start;
+ size_af = ((0xFFFFFFFF - mc->vram_end) + mc->gtt_base_align) & ~mc->gtt_base_align;
+ size_bf = mc->vram_start & ~mc->gtt_base_align;
if (size_bf > size_af) {
if (mc->gtt_size > size_bf) {
dev_warn(rdev->dev, "limiting GTT\n");
mc->gtt_size = size_bf;
}
- mc->gtt_start = mc->vram_start - mc->gtt_size;
+ mc->gtt_start = (mc->vram_start & ~mc->gtt_base_align) - mc->gtt_size;
} else {
if (mc->gtt_size > size_af) {
dev_warn(rdev->dev, "limiting GTT\n");
mc->gtt_size = size_af;
}
- mc->gtt_start = mc->vram_end + 1;
+ mc->gtt_start = (mc->vram_end + 1 + mc->gtt_base_align) & ~mc->gtt_base_align;
}
mc->gtt_end = mc->gtt_start + mc->gtt_size - 1;
dev_info(rdev->dev, "GTT: %lluM 0x%08llX - 0x%08llX\n",
for (i = 0, found = 0; i < rdev->num_crtc; i++) {
crtc = (struct drm_crtc *)minfo->crtcs[i];
if (crtc && crtc->base.id == value) {
- value = i;
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ value = radeon_crtc->crtc_id;
found = 1;
break;
}
udelay(panel_pwr_delay * 1000);
WREG32(RADEON_LVDS_GEN_CNTL, lvds_gen_cntl);
WREG32_PLL(RADEON_PIXCLKS_CNTL, pixclks_cntl);
+ udelay(panel_pwr_delay * 1000);
break;
}
}
flicker_removal = (tmp + 500) / 1000;
- if (flicker_removal < 2)
- flicker_removal = 2;
+ if (flicker_removal < 3)
+ flicker_removal = 3;
for (i = 0; i < ARRAY_SIZE(SLOPE_limit); ++i) {
if (flicker_removal == SLOPE_limit[i])
break;
}
if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480) {
/* FIXME: RS400 & RS480 seems to have issue with GART size
- * if 4G of system memory (needs more testing) */
+ * if 4G of system memory (needs more testing)
+ */
+ /* XXX is this still an issue with proper alignment? */
rdev->mc.gtt_size = 32 * 1024 * 1024;
DRM_ERROR("Forcing to 32M GART size (because of ASIC bug ?)\n");
}
r100_vram_init_sizes(rdev);
base = (RREG32(RADEON_NB_TOM) & 0xffff) << 16;
radeon_vram_location(rdev, &rdev->mc, base);
+ rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1;
radeon_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
}
base = G_000004_MC_FB_START(base) << 16;
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
radeon_vram_location(rdev, &rdev->mc, base);
+ rdev->mc.gtt_base_align = 0;
radeon_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
}
rs690_pm_info(rdev);
rdev->mc.igp_sideport_enabled = radeon_atombios_sideport_present(rdev);
radeon_vram_location(rdev, &rdev->mc, base);
+ rdev->mc.gtt_base_align = rdev->mc.gtt_size - 1;
radeon_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
}
rv515_vram_get_type(rdev);
r100_vram_init_sizes(rdev);
radeon_vram_location(rdev, &rdev->mc, 0);
+ rdev->mc.gtt_base_align = 0;
if (!(rdev->flags & RADEON_IS_AGP))
radeon_gtt_location(rdev, &rdev->mc);
radeon_update_bandwidth_info(rdev);
#include <linux/slab.h>
#include <asm/atomic.h>
-#include <asm/agp.h>
#include "ttm/ttm_bo_driver.h"
#include "ttm/ttm_page_alloc.h"
+#ifdef TTM_HAS_AGP
+#include <asm/agp.h>
+#endif
#define NUM_PAGES_TO_ALLOC (PAGE_SIZE/sizeof(struct page *))
#define SMALL_ALLOCATION 16
/**
* Callback for mm to request pool to reduce number of page held.
*/
-static int ttm_pool_mm_shrink(int shrink_pages, gfp_t gfp_mask)
+static int ttm_pool_mm_shrink(struct shrinker *shrink, int shrink_pages, gfp_t gfp_mask)
{
static atomic_t start_pool = ATOMIC_INIT(0);
unsigned i;
ret = copy_from_user(rects, user_rects, rects_size);
if (unlikely(ret != 0)) {
DRM_ERROR("Failed to get rects.\n");
+ ret = -EFAULT;
goto out_free;
}
struct gc {
struct pardevice *pd;
struct gc_pad pads[GC_MAX_DEVICES];
- struct input_dev *dev[GC_MAX_DEVICES];
struct timer_list timer;
int pad_count[GC_MAX];
int used;
for (i = 0; i < GC_MAX_DEVICES; i++) {
pad = &gc->pads[i];
- dev = gc->dev[i];
+ dev = pad->dev;
s = gc_status_bit[i];
switch (pad->type) {
read = parport_read_status(port) ^ 0x80;
for (j = 0; j < GC_MAX_DEVICES; j++) {
- struct gc_pad *pad = &gc->pads[i];
+ struct gc_pad *pad = &gc->pads[j];
if (pad->type == GC_PSX || pad->type == GC_DDR)
data[j] |= (read & gc_status_bit[j]) ? (1 << i) : 0;
right-hand column will be interpreted as the key shown in the
left-hand column.
-config QT2160
+config KEYBOARD_QT2160
tristate "Atmel AT42QT2160 Touch Sensor Chip"
depends on I2C && EXPERIMENTAL
help
*/
#define TWL4030_MAX_ROWS 8 /* TWL4030 hard limit */
#define TWL4030_MAX_COLS 8
-#define TWL4030_ROW_SHIFT 3
-#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS * TWL4030_MAX_COLS)
+/*
+ * Note that we add space for an extra column so that we can handle
+ * row lines connected to the gnd (see twl4030_col_xlate()).
+ */
+#define TWL4030_ROW_SHIFT 4
+#define TWL4030_KEYMAP_SIZE (TWL4030_MAX_ROWS << TWL4030_ROW_SHIFT)
struct twl4030_keypad {
unsigned short keymap[TWL4030_KEYMAP_SIZE];
return ret;
}
-static int twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state)
+static bool twl4030_is_in_ghost_state(struct twl4030_keypad *kp, u16 *key_state)
{
int i;
u16 check = 0;
u16 col = key_state[i];
if ((col & check) && hweight16(col) > 1)
- return 1;
+ return true;
check |= col;
}
- return 0;
+ return false;
}
static void twl4030_kp_scan(struct twl4030_keypad *kp, bool release_all)
if (!changed)
continue;
- for (col = 0; col < kp->n_cols; col++) {
+ /* Extra column handles "all gnd" rows */
+ for (col = 0; col < kp->n_cols + 1; col++) {
int code;
if (!(changed & (1 << col)))
.probe = w90p910_keypad_probe,
.remove = __devexit_p(w90p910_keypad_remove),
.driver = {
- .name = "nuc900-keypad",
+ .name = "nuc900-kpi",
.owner = THIS_MODULE,
},
};
priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2];
priv->ext_cap = priv->ext_cap_0c = 0;
- if (!SYN_CAP_VALID(priv->capabilities))
+ /*
+ * Older firmwares had submodel ID fixed to 0x47
+ */
+ if (SYN_ID_FULL(priv->identity) < 0x705 &&
+ SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) {
return -1;
+ }
/*
* Unless capExtended is set the rest of the flags should be ignored
#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3))
#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1))
#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0))
-#define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47)
+#define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8)
#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20)
#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12)
#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16)
#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f)
#define SYN_ID_MAJOR(i) ((i) & 0x0f)
#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff)
+#define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i))
#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47)
/* synaptics special commands */
DMI_MATCH(DMI_BOARD_VERSION, "1.02"),
},
},
+ {
+ /* Gigabyte Spring Peak - defines wrong chassis type */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "GIGABYTE"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Spring Peak"),
+ },
+ },
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
module_init(cs5535_mfgpt_init);
-MODULE_AUTHOR("Andres Salomon <dilinger@collabora.co.uk>");
+MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>");
MODULE_DESCRIPTION("CS5535/CS5536 MFGPT timer driver");
MODULE_LICENSE("GPL");
static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct sdhci_s3c *sc = sdhci_priv(host);
+ int ptr;
+
+ sdhci_remove_host(host, 1);
+
+ for (ptr = 0; ptr < 3; ptr++) {
+ clk_disable(sc->clk_bus[ptr]);
+ clk_put(sc->clk_bus[ptr]);
+ }
+ clk_disable(sc->clk_io);
+ clk_put(sc->clk_io);
+
+ iounmap(host->ioaddr);
+ release_resource(sc->ioarea);
+ kfree(sc->ioarea);
+
+ sdhci_free_host(host);
+ platform_set_drvdata(pdev, NULL);
+
return 0;
}
/* used to synchronize stats collecting */
int stats_state;
+
+ /* used for synchronization of concurrent threads statistics handling */
+ spinlock_t stats_lock;
+
/* used by dmae command loader */
struct dmae_command stats_dmae;
int executer_idx;
#include "bnx2x_init_ops.h"
#include "bnx2x_dump.h"
-#define DRV_MODULE_VERSION "1.52.53-1"
-#define DRV_MODULE_RELDATE "2010/18/04"
+#define DRV_MODULE_VERSION "1.52.53-2"
+#define DRV_MODULE_RELDATE "2010/21/07"
#define BNX2X_BC_VER 0x040200
#include <linux/firmware.h>
struct eth_query_ramrod_data ramrod_data = {0};
int i, rc;
+ spin_lock_bh(&bp->stats_lock);
+
ramrod_data.drv_counter = bp->stats_counter++;
ramrod_data.collect_port = bp->port.pmf ? 1 : 0;
for_each_queue(bp, i)
bp->spq_left++;
bp->stats_pending = 1;
}
+
+ spin_unlock_bh(&bp->stats_lock);
}
}
struct host_func_stats *fstats = bnx2x_sp(bp, func_stats);
struct bnx2x_eth_stats *estats = &bp->eth_stats;
int i;
+ u16 cur_stats_counter;
+
+ /* Make sure we use the value of the counter
+ * used for sending the last stats ramrod.
+ */
+ spin_lock_bh(&bp->stats_lock);
+ cur_stats_counter = bp->stats_counter - 1;
+ spin_unlock_bh(&bp->stats_lock);
memcpy(&(fstats->total_bytes_received_hi),
&(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi),
u32 diff;
/* are storm stats valid? */
- if ((u16)(le16_to_cpu(xclient->stats_counter) + 1) !=
- bp->stats_counter) {
+ if (le16_to_cpu(xclient->stats_counter) != cur_stats_counter) {
DP(BNX2X_MSG_STATS, "[%d] stats not updated by xstorm"
" xstorm counter (0x%x) != stats_counter (0x%x)\n",
- i, xclient->stats_counter, bp->stats_counter);
+ i, xclient->stats_counter, cur_stats_counter + 1);
return -1;
}
- if ((u16)(le16_to_cpu(tclient->stats_counter) + 1) !=
- bp->stats_counter) {
+ if (le16_to_cpu(tclient->stats_counter) != cur_stats_counter) {
DP(BNX2X_MSG_STATS, "[%d] stats not updated by tstorm"
" tstorm counter (0x%x) != stats_counter (0x%x)\n",
- i, tclient->stats_counter, bp->stats_counter);
+ i, tclient->stats_counter, cur_stats_counter + 1);
return -2;
}
- if ((u16)(le16_to_cpu(uclient->stats_counter) + 1) !=
- bp->stats_counter) {
+ if (le16_to_cpu(uclient->stats_counter) != cur_stats_counter) {
DP(BNX2X_MSG_STATS, "[%d] stats not updated by ustorm"
" ustorm counter (0x%x) != stats_counter (0x%x)\n",
- i, uclient->stats_counter, bp->stats_counter);
+ i, uclient->stats_counter, cur_stats_counter + 1);
return -4;
}
static void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event)
{
- enum bnx2x_stats_state state = bp->stats_state;
+ enum bnx2x_stats_state state;
if (unlikely(bp->panic))
return;
- bnx2x_stats_stm[state][event].action(bp);
+ /* Protect a state change flow */
+ spin_lock_bh(&bp->stats_lock);
+ state = bp->stats_state;
bp->stats_state = bnx2x_stats_stm[state][event].next_state;
+ spin_unlock_bh(&bp->stats_lock);
- /* Make sure the state has been "changed" */
- smp_wmb();
+ bnx2x_stats_stm[state][event].action(bp);
if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp))
DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n",
mutex_init(&bp->port.phy_mutex);
mutex_init(&bp->fw_mb_mutex);
+ spin_lock_init(&bp->stats_lock);
#ifdef BCM_CNIC
mutex_init(&bp->cnic_mutex);
#endif
/*initialize packet type*/
pk_type->type = cpu_to_be16(ETH_P_ARP);
- pk_type->dev = NULL;
+ pk_type->dev = bond->dev;
pk_type->func = rlb_arp_recv;
/* register to receive ARPs */
.ndo_set_mac_address = eth_mac_addr,
};
-static int __init dec_lance_probe(struct device *bdev, const int type)
+static int __devinit dec_lance_probe(struct device *bdev, const int type)
{
static unsigned version_printed;
static const char fmt[] = "declance%d";
}
#ifdef CONFIG_TC
-static int __init dec_lance_tc_probe(struct device *dev);
+static int __devinit dec_lance_tc_probe(struct device *dev);
static int __exit dec_lance_tc_remove(struct device *dev);
static const struct tc_device_id dec_lance_tc_table[] = {
},
};
-static int __init dec_lance_tc_probe(struct device *dev)
+static int __devinit dec_lance_tc_probe(struct device *dev)
{
int status = dec_lance_probe(dev, PMAD_LANCE);
if (!status)
if (!adapter->pool_config)
netif_stop_queue(netdev);
- free_irq(netdev->irq, netdev);
+ h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
do {
lpar_rc = h_free_logical_lan(adapter->vdev->unit_address);
lpar_rc);
}
+ free_irq(netdev->irq, netdev);
+
adapter->rx_no_buffer = *(u64*)(((char*)adapter->buffer_list_addr) + 4096 - 8);
ibmveth_cleanup(adapter);
u16 eeprom_apme_mask = IGB_EEPROM_APME;
u32 part_num;
+ /* Catch broken hardware that put the wrong VF device ID in
+ * the PCIe SR-IOV capability.
+ */
+ if (pdev->is_virtfn) {
+ WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n",
+ pci_name(pdev), pdev->vendor, pdev->device);
+ return -EINVAL;
+ }
+
err = pci_enable_device_mem(pdev);
if (err)
return err;
#endif
u32 part_num, eec;
+ /* Catch broken hardware that put the wrong VF device ID in
+ * the PCIe SR-IOV capability.
+ */
+ if (pdev->is_virtfn) {
+ WARN(1, KERN_ERR "%s (%hx:%hx) should not be a VF!\n",
+ pci_name(pdev), pdev->vendor, pdev->device);
+ return -EINVAL;
+ }
+
err = pci_enable_device_mem(pdev);
if (err)
return err;
.ndo_validate_addr = eth_validate_addr,
};
-static void macvlan_setup(struct net_device *dev)
+void macvlan_common_setup(struct net_device *dev)
{
ether_setup(dev);
dev->destructor = free_netdev;
dev->header_ops = &macvlan_hard_header_ops,
dev->ethtool_ops = &macvlan_ethtool_ops;
+}
+EXPORT_SYMBOL_GPL(macvlan_common_setup);
+
+static void macvlan_setup(struct net_device *dev)
+{
+ macvlan_common_setup(dev);
dev->tx_queue_len = 0;
}
/* common fields */
ops->priv_size = sizeof(struct macvlan_dev);
ops->get_tx_queues = macvlan_get_tx_queues;
- ops->setup = macvlan_setup;
ops->validate = macvlan_validate;
ops->maxtype = IFLA_MACVLAN_MAX;
ops->policy = macvlan_policy;
static struct rtnl_link_ops macvlan_link_ops = {
.kind = "macvlan",
+ .setup = macvlan_setup,
.newlink = macvlan_newlink,
.dellink = macvlan_dellink,
};
{
struct macvtap_queue *q = macvtap_get_queue(dev, skb);
if (!q)
- return -ENOLINK;
+ goto drop;
+
+ if (skb_queue_len(&q->sk.sk_receive_queue) >= dev->tx_queue_len)
+ goto drop;
skb_queue_tail(&q->sk.sk_receive_queue, skb);
wake_up_interruptible_poll(sk_sleep(&q->sk), POLLIN | POLLRDNORM | POLLRDBAND);
- return 0;
+ return NET_RX_SUCCESS;
+
+drop:
+ kfree_skb(skb);
+ return NET_RX_DROP;
}
/*
macvlan_dellink(dev, head);
}
+static void macvtap_setup(struct net_device *dev)
+{
+ macvlan_common_setup(dev);
+ dev->tx_queue_len = TUN_READQ_SIZE;
+}
+
static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
.kind = "macvtap",
+ .setup = macvtap_setup,
.newlink = macvtap_newlink,
.dellink = macvtap_dellink,
};
int interrupts, nr_serviced = 0, i;
struct ei_device *ei_local;
int handled = 0;
+ unsigned long flags;
e8390_base = dev->base_addr;
ei_local = netdev_priv(dev);
* Protect the irq test too.
*/
- spin_lock(&ei_local->page_lock);
+ spin_lock_irqsave(&ei_local->page_lock, flags);
if (ei_local->irqlock)
{
dev->name, inb_p(e8390_base + EN0_ISR),
inb_p(e8390_base + EN0_IMR));
#endif
- spin_unlock(&ei_local->page_lock);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
return IRQ_NONE;
}
ei_local->irqlock = 0;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- spin_unlock(&ei_local->page_lock);
+ spin_unlock_irqrestore(&ei_local->page_lock, flags);
return IRQ_RETVAL(handled);
}
{ 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
/* 8168C family. */
- { 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 },
+ { 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
{ 0x7cf00000, 0x3c900000, RTL_GIGA_MAC_VER_23 },
{ 0x7cf00000, 0x3c800000, RTL_GIGA_MAC_VER_18 },
{ 0x7c800000, 0x3c800000, RTL_GIGA_MAC_VER_24 },
/* DEBUG message print. */
#define DBG_PRINT(dbg_level, fmt, args...) do { \
- if (dbg_level >= debug_level) \
+ if (dbg_level <= debug_level) \
pr_info(fmt, ##args); \
} while (0)
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
else if (sinfo->gso_type & SKB_GSO_UDP)
gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
- else
- BUG();
+ else {
+ printk(KERN_ERR "tun: unexpected GSO type: "
+ "0x%x, gso_size %d, hdr_len %d\n",
+ sinfo->gso_type, gso.gso_size,
+ gso.hdr_len);
+ print_hex_dump(KERN_ERR, "tun: ",
+ DUMP_PREFIX_NONE,
+ 16, 1, skb->head,
+ min((int)gso.hdr_len, 64), true);
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
if (sinfo->gso_type & SKB_GSO_TCP_ECN)
gso.gso_type |= VIRTIO_NET_HDR_GSO_ECN;
} else
/* Device IDs */
USB_DEVICE_ID_I6050 = 0x0186,
USB_DEVICE_ID_I6050_2 = 0x0188,
+ USB_DEVICE_ID_I6250 = 0x0187,
};
switch (id->idProduct) {
case USB_DEVICE_ID_I6050:
case USB_DEVICE_ID_I6050_2:
+ case USB_DEVICE_ID_I6250:
i2400mu->i6050 = 1;
break;
default:
struct usb_device_id i2400mu_id_table[] = {
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6050) },
{ USB_DEVICE(0x8086, USB_DEVICE_ID_I6050_2) },
+ { USB_DEVICE(0x8086, USB_DEVICE_ID_I6250) },
{ USB_DEVICE(0x8086, 0x0181) },
{ USB_DEVICE(0x8086, 0x1403) },
{ USB_DEVICE(0x8086, 0x1405) },
/* RX */
if (ath9k_hif_usb_alloc_rx_urbs(hif_dev) < 0)
- goto err;
+ goto err_rx;
/* Register Read */
if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
- goto err;
+ goto err_reg;
return 0;
+err_reg:
+ ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
+err_rx:
+ ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
err:
return -ENOMEM;
}
int dma_type;
if (edma)
- dma_type = DMA_FROM_DEVICE;
- else
dma_type = DMA_BIDIRECTIONAL;
+ else
+ dma_type = DMA_FROM_DEVICE;
qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
spin_lock_bh(&sc->rx.rxbuflock);
dev->irq = pdev->irq;
hw_priv->mem_start = mem;
+ dev->base_addr = (unsigned long) mem;
prism2_pci_cor_sreset(local);
spin_lock_irqsave(&priv->sta_lock, flags);
memset(priv->stations, 0, sizeof(priv->stations));
priv->num_stations = 0;
+
+ /*
+ * Remove all key information that is not stored as part of station
+ * information since mac80211 may not have had a
+ * chance to remove all the keys. When device is reconfigured by
+ * mac80211 after an error all keys will be reconfigured.
+ */
+ priv->ucode_key_table = 0;
+ priv->key_mapping_key = 0;
+ memset(priv->wep_keys, 0, sizeof(priv->wep_keys));
+
spin_unlock_irqrestore(&priv->sta_lock, flags);
}
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_WDS);
+ /*
+ * Initialize configuration work.
+ */
+ INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
+
/*
* Let the driver probe the device to detect the capabilities.
*/
goto exit;
}
- /*
- * Initialize configuration work.
- */
- INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
-
/*
* Allocate queue array.
*/
pcibios_align_resource, dev);
}
+ if (ret < 0 && dev->fw_addr[resno]) {
+ struct resource *root, *conflict;
+ resource_size_t start, end;
+
+ /*
+ * If we failed to assign anything, let's try the address
+ * where firmware left it. That at least has a chance of
+ * working, which is better than just leaving it disabled.
+ */
+
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ else
+ root = &iomem_resource;
+
+ start = res->start;
+ end = res->end;
+ res->start = dev->fw_addr[resno];
+ res->end = res->start + size - 1;
+ dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
+ resno, res);
+ conflict = request_resource_conflict(root, res);
+ if (conflict) {
+ dev_info(&dev->dev,
+ "BAR %d: %pR conflicts with %s %pR\n", resno,
+ res, conflict->name, conflict);
+ res->start = start;
+ res->end = end;
+ } else
+ ret = 0;
+ }
+
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
{
pcmcia_release_configuration(p_dev);
pcmcia_release_io(p_dev, &p_dev->io);
- if (p_dev->_irq)
+ if (p_dev->_irq) {
free_irq(p_dev->irq, p_dev->priv);
+ p_dev->_irq = 0;
+ }
if (p_dev->win)
pcmcia_release_window(p_dev, p_dev->win);
}
unsigned long val,
struct cpufreq_freqs *freqs)
{
-#warning "it's not clear if this is right since the core CPU (N) clock has no effect on the memory (L) clock"
switch (val) {
case CPUFREQ_PRECHANGE:
if (freqs->new > freqs->old) {
"pre-updating\n",
freqs->new / 1000, (freqs->new / 100) % 10,
freqs->old / 1000, (freqs->old / 100) % 10);
- pxa2xx_pcmcia_set_mcxx(skt, freqs->new);
+ pxa2xx_pcmcia_set_timing(skt);
}
break;
"post-updating\n",
freqs->new / 1000, (freqs->new / 100) % 10,
freqs->old / 1000, (freqs->old / 100) % 10);
- pxa2xx_pcmcia_set_mcxx(skt, freqs->new);
+ pxa2xx_pcmcia_set_timing(skt);
}
break;
}
mutex_unlock(&ipclock);
return -ENODEV;
}
- ipc_command(cmd << 12 | sub);
+ ipc_command(sub << 12 | cmd);
err = busy_loop();
mutex_unlock(&ipclock);
return err;
* @cmd: command
* @sub: sub type
* @in: input data
- * @inlen: input length
+ * @inlen: input length in dwords
* @out: output data
- * @outlein: output length
+ * @outlein: output length in dwords
*
* Issue a command to the SCU which involves data transfers. Do the
* data copies under the lock but leave it for the caller to interpret
for (i = 0; i < inlen; i++)
ipc_data_writel(*in++, 4 * i);
- ipc_command((cmd << 12) | sub | (inlen << 18));
+ ipc_command((sub << 12) | cmd | (inlen << 18));
err = busy_loop();
for (i = 0; i < outlen; i++)
u32 cmd = 0;
mutex_lock(&ipclock);
+ if (ipcdev.pdev == NULL) {
+ mutex_unlock(&ipclock);
+ return -ENODEV;
+ }
cmd = (addr >> 24) & 0xFF;
if (cmd == IPC_I2C_READ) {
writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR);
struct ds278x_info;
struct ds278x_battery_ops {
- int (*get_current)(struct ds278x_info *info, int *current_uA);
- int (*get_voltage)(struct ds278x_info *info, int *voltage_uA);
- int (*get_capacity)(struct ds278x_info *info, int *capacity_uA);
-
+ int (*get_battery_current)(struct ds278x_info *info, int *current_uA);
+ int (*get_battery_voltage)(struct ds278x_info *info, int *voltage_uA);
+ int (*get_battery_capacity)(struct ds278x_info *info, int *capacity_uA);
};
#define to_ds278x_info(x) container_of(x, struct ds278x_info, battery)
if (err)
return err;
*capacity = raw;
- return raw;
+ return 0;
}
static int ds2786_get_current(struct ds278x_info *info, int *current_uA)
int current_uA;
int capacity;
- err = info->ops->get_current(info, ¤t_uA);
+ err = info->ops->get_battery_current(info, ¤t_uA);
if (err)
return err;
- err = info->ops->get_capacity(info, &capacity);
+ err = info->ops->get_battery_capacity(info, &capacity);
if (err)
return err;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- ret = info->ops->get_capacity(info, &val->intval);
+ ret = info->ops->get_battery_capacity(info, &val->intval);
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
- ret = info->ops->get_voltage(info, &val->intval);
+ ret = info->ops->get_battery_voltage(info, &val->intval);
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
- ret = info->ops->get_current(info, &val->intval);
+ ret = info->ops->get_battery_current(info, &val->intval);
break;
case POWER_SUPPLY_PROP_TEMP:
static struct ds278x_battery_ops ds278x_ops[] = {
[DS2782] = {
- .get_current = ds2782_get_current,
- .get_voltage = ds2782_get_voltage,
- .get_capacity = ds2782_get_capacity,
+ .get_battery_current = ds2782_get_current,
+ .get_battery_voltage = ds2782_get_voltage,
+ .get_battery_capacity = ds2782_get_capacity,
},
[DS2786] = {
- .get_current = ds2786_get_current,
- .get_voltage = ds2786_get_voltage,
- .get_capacity = ds2786_get_capacity,
+ .get_battery_current = ds2786_get_current,
+ .get_battery_voltage = ds2786_get_voltage,
+ .get_battery_capacity = ds2786_get_capacity,
}
};
return -EIO;
}
- err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
+ err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL,
(data | RX8581_CTRL_STOP));
if (err < 0) {
dev_err(&client->dev, "Unable to write control register\n");
return -EIO;
}
+ /* get VLF and clear it */
+ data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG);
+ if (data < 0) {
+ dev_err(&client->dev, "Unable to read flag register\n");
+ return -EIO;
+ }
+
+ err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
+ (data & ~(RX8581_FLAG_VLF)));
+ if (err != 0) {
+ dev_err(&client->dev, "Unable to write flag register\n");
+ return -EIO;
+ }
+
/* Restart the clock */
data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL);
if (data < 0) {
return -EIO;
}
- err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
- (data | ~(RX8581_CTRL_STOP)));
+ err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL,
+ (data & ~(RX8581_CTRL_STOP)));
if (err != 0) {
dev_err(&client->dev, "Unable to write control register\n");
return -EIO;
if (device->discipline && device->discipline->get_uid &&
!device->discipline->get_uid(device, &uid)) {
if (uid.type == UA_BASE_PAV_ALIAS ||
- uid.type == UA_HYPER_PAV_ALIAS)
+ uid.type == UA_HYPER_PAV_ALIAS) {
+ dasd_put_device(device);
return sprintf(buf, "1\n");
+ }
}
dasd_put_device(device);
ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp);
if (ret)
goto out_free;
- memcpy(desc, &chsc_resp->data, chsc_resp->length);
+ memcpy(desc, &chsc_resp->data, sizeof(*desc));
out_free:
kfree(chsc_resp);
return ret;
static int openprom_bsd_ioctl(struct file * file,
unsigned int cmd, unsigned long arg)
{
- DATA *data = (DATA *) file->private_data;
+ DATA *data = file->private_data;
void __user *argp = (void __user *)arg;
int err;
static long openprom_ioctl(struct file * file,
unsigned int cmd, unsigned long arg)
{
- DATA *data = (DATA *) file->private_data;
+ DATA *data = file->private_data;
switch (cmd) {
case OPROMGETOPT:
#include <linux/uaccess.h>
#include <asm/io.h>
+#include <asm/ioctls.h>
#include <asm/mach/serial_at91.h>
#include <mach/board.h>
con->index = line;
drv->cons = con;
- add_preferred_console(con->name, line, NULL);
+
+ if (!console_set_on_cmdline)
+ add_preferred_console(con->name, line, NULL);
return 1;
}
static int __devexit su_remove(struct of_device *op)
{
struct uart_sunsu_port *up = dev_get_drvdata(&op->dev);
+ bool kbdms = false;
if (up->su_type == SU_PORT_MS ||
- up->su_type == SU_PORT_KBD) {
+ up->su_type == SU_PORT_KBD)
+ kbdms = true;
+
+ if (kbdms) {
#ifdef CONFIG_SERIO
serio_unregister_port(&up->serio);
#endif
- kfree(up);
- } else if (up->port.type != PORT_UNKNOWN) {
+ } else if (up->port.type != PORT_UNKNOWN)
uart_remove_one_port(&sunsu_reg, &up->port);
- }
if (up->port.membase)
of_iounmap(&op->resource[0], up->port.membase, up->reg_size);
+ if (kbdms)
+ kfree(up);
+
dev_set_drvdata(&op->dev, NULL);
return 0;
{ NOKIA_PCSUITE_ACM_INFO(0x00e9), }, /* Nokia 5320 XpressMusic */
{ NOKIA_PCSUITE_ACM_INFO(0x0108), }, /* Nokia 5320 XpressMusic 2G */
{ NOKIA_PCSUITE_ACM_INFO(0x01f5), }, /* Nokia N97, RM-505 */
+ { NOKIA_PCSUITE_ACM_INFO(0x02e3), }, /* Nokia 5230, RM-588 */
/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
(portstatus & USB_PORT_STAT_ENABLE)) {
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_WIRELESS;
+ else if (portstatus & USB_PORT_STAT_SUPER_SPEED)
+ udev->speed = USB_SPEED_SUPER;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* Artisman Watchdog Dongle */
+ { USB_DEVICE(0x04b4, 0x0526), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
/* Roland SC-8820 */
{ USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
/* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */
{ USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF },
+ /* Broadcom BCM92035DGROM BT dongle */
+ { USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME },
+
/* Action Semiconductor flash disk */
{ USB_DEVICE(0x10d6, 0x2200), .driver_info =
USB_QUIRK_STRING_FETCH_255 },
* handling setup requests immidiatelly user space may be so
* slow that another setup will be sent to the gadget but this
* time not to us but another function and then there could be
- * a race. Is taht the case? Or maybe we can use cdev->req
+ * a race. Is that the case? Or maybe we can use cdev->req
* after all, maybe we just need some spinlock for that? */
struct usb_request *ep0req; /* P: mutex */
struct completion ep0req_completion; /* P: mutex */
udc_disable(udc);
}
-#ifdef CONFIG_CPU_PXA27x
+#ifdef CONFIG_PXA27x
extern void pxa27x_clear_otgph(void);
#else
#define pxa27x_clear_otgph() do {} while (0)
else
dev->ep0state = EP0_OUT_DATA_PHASE;
+ if (!dev->driver)
+ return;
+
+ /* deliver the request to the gadget driver */
ret = dev->driver->setup(&dev->gadget, crq);
if (ret < 0) {
if (dev->req_config) {
__raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR);
}
-#ifdef CONFIG_CPU_PXA27x
+#ifdef CONFIG_PXA27x
extern void pxa27x_clear_otgph(void);
#else
#define pxa27x_clear_otgph() do {} while (0)
return 0;
}
+void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
+ struct usb_device *udev)
+{
+ struct xhci_virt_device *virt_dev;
+ struct xhci_ep_ctx *ep0_ctx;
+ struct xhci_ring *ep_ring;
+
+ virt_dev = xhci->devs[udev->slot_id];
+ ep0_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, 0);
+ ep_ring = virt_dev->eps[0].ring;
+ /*
+ * FIXME we don't keep track of the dequeue pointer very well after a
+ * Set TR dequeue pointer, so we're setting the dequeue pointer of the
+ * host to our enqueue pointer. This should only be called after a
+ * configured device has reset, so all control transfers should have
+ * been completed or cancelled before the reset.
+ */
+ ep0_ctx->deq = xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue);
+ ep0_ctx->deq |= ep_ring->cycle_state;
+}
+
/* Setup an xHCI virtual device for a Set Address command */
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev)
{
return EP_INTERVAL(interval);
}
-/* The "Mult" field in the endpoint context is only set for SuperSpeed devices.
+/* The "Mult" field in the endpoint context is only set for SuperSpeed isoc eps.
* High speed endpoint descriptors can define "the number of additional
* transaction opportunities per microframe", but that goes in the Max Burst
* endpoint context field.
static inline u32 xhci_get_endpoint_mult(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
- if (udev->speed != USB_SPEED_SUPER)
+ if (udev->speed != USB_SPEED_SUPER ||
+ !usb_endpoint_xfer_isoc(&ep->desc))
return 0;
return ep->ss_ep_comp.bmAttributes;
}
u32 field3, u32 field4, bool command_must_succeed)
{
int reserved_trbs = xhci->cmd_ring_reserved_trbs;
+ int ret;
+
if (!command_must_succeed)
reserved_trbs++;
- if (!room_on_ring(xhci, xhci->cmd_ring, reserved_trbs)) {
- if (!in_interrupt())
- xhci_err(xhci, "ERR: No room for command on command ring\n");
+ ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
+ reserved_trbs, GFP_ATOMIC);
+ if (ret < 0) {
+ xhci_err(xhci, "ERR: No room for command on command ring\n");
if (command_must_succeed)
xhci_err(xhci, "ERR: Reserved TRB counting for "
"unfailable commands failed.\n");
- return -ENOMEM;
+ return ret;
}
queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3,
field4 | xhci->cmd_ring->cycle_state);
/* If this is a Set Address to an unconfigured device, setup ep 0 */
if (!udev->config)
xhci_setup_addressable_virt_dev(xhci, udev);
+ else
+ xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev);
/* Otherwise, assume the core has the device configured how it wants */
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id);
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags);
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
+void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,
+ struct usb_device *udev);
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
}
if (!sisusb->devinit) {
- if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
+ if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH ||
+ sisusb->sisusb_dev->speed == USB_SPEED_SUPER) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
sisusb->present = 1;
- if (dev->speed == USB_SPEED_HIGH) {
+ if (dev->speed == USB_SPEED_HIGH || dev->speed == USB_SPEED_SUPER) {
int initscreen = 1;
#ifdef INCL_SISUSB_CON
if (sisusb_first_vc > 0 &&
#define TUSB_REV_MAJOR(reg_val) ((reg_val >> 4) & 0xf)
#define TUSB_REV_MINOR(reg_val) (reg_val & 0xf)
-#ifdef CONFIG_PM
-/* REVISIT: These should be only needed if somebody implements off idle */
-void musb_platform_save_context(struct musb *musb,
- struct musb_context_registers *musb_context)
-{
-}
-
-void musb_platform_restore_context(struct musb *musb,
- struct musb_context_registers *musb_context)
-{
-}
-#endif
-
/*
* Checks the revision. We need to use the DMA register as 3.0 does not
* have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV.
{ USB_DEVICE(FTDI_VID, FTDI_NDI_AURORA_SCU_PID),
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
+ { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_SERIAL_VX7_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PHI_FISCO_PID) },
{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
{ USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
{ USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
{ USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
+ { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_ST_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SLITE_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH2_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, XVERVE_SIGNALYZER_SH4_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
#define TELLDUS_VID 0x1781 /* Vendor ID */
#define TELLDUS_TELLSTICK_PID 0x0C30 /* RF control dongle 433 MHz using FT232RL */
+/*
+ * RT Systems programming cables for various ham radios
+ */
+#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
+#define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */
+
/*
* Bayer Ascensia Contour blood glucose meter USB-converter cable.
* http://winglucofacts.com/cables/
#define MJSG_SR_RADIO_PID 0x9379
#define MJSG_XM_RADIO_PID 0x937A
#define MJSG_HD_RADIO_PID 0x937C
+
+/*
+ * Xverve Signalyzer tools (http://www.signalyzer.com/)
+ */
+#define XVERVE_SIGNALYZER_ST_PID 0xBCA0
+#define XVERVE_SIGNALYZER_SLITE_PID 0xBCA1
+#define XVERVE_SIGNALYZER_SH2_PID 0xBCA2
+#define XVERVE_SIGNALYZER_SH4_PID 0xBCA4
+
#define AMOI_PRODUCT_H01 0x0800
#define AMOI_PRODUCT_H01A 0x7002
#define AMOI_PRODUCT_H02 0x0802
+#define AMOI_PRODUCT_SKYPEPHONE_S2 0x0407
#define DELL_VENDOR_ID 0x413C
#define QISDA_PRODUCT_H21_4512 0x4512
#define QISDA_PRODUCT_H21_4523 0x4523
#define QISDA_PRODUCT_H20_4515 0x4515
+#define QISDA_PRODUCT_H20_4518 0x4518
#define QISDA_PRODUCT_H20_4519 0x4519
/* TLAYTECH PRODUCTS */
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H02) },
+ { USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_SKYPEPHONE_S2) },
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5700_MINICARD) }, /* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */
{ USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5500_MINICARD) }, /* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4512) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
+ { USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4518) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
{USB_DEVICE(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */
{USB_DEVICE(0x413c, 0x8185)}, /* Dell Gobi 2000 QDL device (N0218, VU936) */
{USB_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */
+ {USB_DEVICE(0x05c6, 0x9208)}, /* Generic Gobi 2000 QDL device */
+ {USB_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */
{USB_DEVICE(0x05c6, 0x9224)}, /* Sony Gobi 2000 QDL device (N0279, VU730) */
{USB_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
{USB_DEVICE(0x05c6, 0x9244)}, /* Samsung Gobi 2000 QDL device (VL176) */
{ USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
{ USB_DEVICE(0x1199, 0x0120) }, /* Sierra Wireless USB Dongle 595U */
+ { USB_DEVICE(0x1199, 0x0301) }, /* Sierra Wireless USB Dongle 250U */
/* Sierra Wireless C597 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x0023, 0xFF, 0xFF, 0xFF) },
/* Sierra Wireless T598 */
/* fill the common fields in the URB */
us->current_urb->context = &urb_done;
- us->current_urb->actual_length = 0;
- us->current_urb->error_count = 0;
- us->current_urb->status = 0;
+ us->current_urb->transfer_flags = 0;
/* we assume that if transfer_buffer isn't us->iobuf then it
* hasn't been mapped for DMA. Yes, this is clunky, but it's
break;
}
if (err != len)
- pr_err("Truncated TX packet: "
- " len %d != %zd\n", err, len);
+ pr_debug("Truncated TX packet: "
+ " len %d != %zd\n", err, len);
vhost_add_used_and_signal(&net->dev, vq, head, 0);
total_len += len;
if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
}
/* TODO: Should check and handle checksum. */
if (err > len) {
- pr_err("Discarded truncated rx packet: "
- " len %d > %zd\n", err, len);
+ pr_debug("Discarded truncated rx packet: "
+ " len %d > %zd\n", err, len);
vhost_discard_vq_desc(vq);
continue;
}
rcu_assign_pointer(vq->private_data, sock);
vhost_net_enable_vq(n, vq);
done:
+ mutex_unlock(&vq->mutex);
+
if (oldsock) {
vhost_net_flush_vq(n, index);
fput(oldsock->file);
}
+ mutex_unlock(&n->dev.mutex);
+ return 0;
+
err_vq:
mutex_unlock(&vq->mutex);
err:
}
#if 0
- /* Power down TV DAC, taht saves a significant amount of power,
+ /* Power down TV DAC, that saves a significant amount of power,
* we'll have something better once we actually have some TVOut
* support
*/
{ { 8, 4, 0 }, { 4, 4, 0 }, { 0, 4, 0 }, { 0, 0, 0 } },
};
-static struct fb_fix_screeninfo au1100fb_fix __initdata = {
+static struct fb_fix_screeninfo au1100fb_fix __devinitdata = {
.id = "AU1100 FB",
.xpanstep = 1,
.ypanstep = 1,
.accel = FB_ACCEL_NONE,
};
-static struct fb_var_screeninfo au1100fb_var __initdata = {
+static struct fb_var_screeninfo au1100fb_var __devinitdata = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
/* AU1100 LCD controller device driver */
-static int __init au1100fb_drv_probe(struct platform_device *dev)
+static int __devinit au1100fb_drv_probe(struct platform_device *dev)
{
struct au1100fb_device *fbdev = NULL;
struct resource *regs_res;
static uint32_t gbe_cmap[256];
static int gbe_turned_on; /* 0 turned off, 1 turned on */
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
/* default CRT mode */
-static struct fb_var_screeninfo default_var_CRT __initdata = {
+static struct fb_var_screeninfo default_var_CRT __devinitdata = {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
.xres = 640,
.yres = 480,
};
/* default LCD mode */
-static struct fb_var_screeninfo default_var_LCD __initdata = {
+static struct fb_var_screeninfo default_var_LCD __devinitdata = {
/* 1600x1024, 8 bpp */
.xres = 1600,
.yres = 1024,
/* default modedb mode */
/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
-static struct fb_videomode default_mode_CRT __initdata = {
+static struct fb_videomode default_mode_CRT __devinitdata = {
.refresh = 60,
.xres = 640,
.yres = 480,
.vmode = FB_VMODE_NONINTERLACED,
};
/* 1600x1024 SGI flatpanel 1600sw */
-static struct fb_videomode default_mode_LCD __initdata = {
+static struct fb_videomode default_mode_LCD __devinitdata = {
/* 1600x1024, 8 bpp */
.xres = 1600,
.yres = 1024,
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_videomode *default_mode __initdata = &default_mode_CRT;
-static struct fb_var_screeninfo *default_var __initdata = &default_var_CRT;
+static struct fb_videomode *default_mode __devinitdata = &default_mode_CRT;
+static struct fb_var_screeninfo *default_var __devinitdata = &default_var_CRT;
static int flat_panel_enabled = 0;
* Initialization
*/
-static int __init gbefb_setup(char *options)
+static int __devinit gbefb_setup(char *options)
{
char *this_opt;
};
-static struct fb_var_screeninfo pmagbafb_defined __initdata = {
+static struct fb_var_screeninfo pmagbafb_defined __devinitdata = {
.xres = 1024,
.yres = 864,
.xres_virtual = 1024,
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo pmagbafb_fix __initdata = {
+static struct fb_fix_screeninfo pmagbafb_fix __devinitdata = {
.id = "PMAG-BA",
.smem_len = (1024 * 1024),
.type = FB_TYPE_PACKED_PIXELS,
}
-static int __init pmagbafb_probe(struct device *dev)
+static int __devinit pmagbafb_probe(struct device *dev)
{
struct tc_dev *tdev = to_tc_dev(dev);
resource_size_t start, len;
};
-static struct fb_var_screeninfo pmagbbfb_defined __initdata = {
+static struct fb_var_screeninfo pmagbbfb_defined __devinitdata = {
.bits_per_pixel = 8,
.red.length = 8,
.green.length = 8,
.vmode = FB_VMODE_NONINTERLACED,
};
-static struct fb_fix_screeninfo pmagbbfb_fix __initdata = {
+static struct fb_fix_screeninfo pmagbbfb_fix __devinitdata = {
.id = "PMAGB-BA",
.smem_len = (2048 * 1024),
.type = FB_TYPE_PACKED_PIXELS,
/*
* Set up screen parameters.
*/
-static void __init pmagbbfb_screen_setup(struct fb_info *info)
+static void __devinit pmagbbfb_screen_setup(struct fb_info *info)
{
struct pmagbbfb_par *par = info->par;
/*
* Determine oscillator configuration.
*/
-static void __init pmagbbfb_osc_setup(struct fb_info *info)
+static void __devinit pmagbbfb_osc_setup(struct fb_info *info)
{
- static unsigned int pmagbbfb_freqs[] __initdata = {
+ static unsigned int pmagbbfb_freqs[] __devinitdata = {
130808, 119843, 104000, 92980, 74370, 72800,
69197, 66000, 65000, 50350, 36000, 32000, 25175
};
};
-static int __init pmagbbfb_probe(struct device *dev)
+static int __devinit pmagbbfb_probe(struct device *dev)
{
struct tc_dev *tdev = to_tc_dev(dev);
resource_size_t start, len;
gfp_t gfp)
{
struct vring_virtqueue *vq = to_vvq(_vq);
- unsigned int i, avail, head, uninitialized_var(prev);
+ unsigned int i, avail, uninitialized_var(prev);
+ int head;
START_USE(vq);
* buffers, then go indirect. FIXME: tune this threshold */
if (vq->indirect && (out + in) > 1 && vq->num_free) {
head = vring_add_indirect(vq, sg, out, in, gfp);
- if (head != vq->vring.num)
+ if (likely(head >= 0))
goto add_head;
}
while (rdir->head < rdir->tail) {
p9stat_init(&st);
err = p9stat_read(rdir->buf + rdir->head,
- buflen - rdir->head, &st,
+ rdir->tail - rdir->head, &st,
fid->clnt->proto_version);
if (err) {
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
return ret;
}
+/*
+ * min slot controls the lowest index we're willing to push to the
+ * right. We'll push up to and including min_slot, but no lower
+ */
static noinline int __push_leaf_right(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
int data_size, int empty,
struct extent_buffer *right,
- int free_space, u32 left_nritems)
+ int free_space, u32 left_nritems,
+ u32 min_slot)
{
struct extent_buffer *left = path->nodes[0];
struct extent_buffer *upper = path->nodes[1];
if (empty)
nr = 0;
else
- nr = 1;
+ nr = max_t(u32, 1, min_slot);
if (path->slots[0] >= left_nritems)
push_space += data_size;
*
* returns 1 if the push failed because the other node didn't have enough
* room, 0 if everything worked out and < 0 if there were major errors.
+ *
+ * this will push starting from min_slot to the end of the leaf. It won't
+ * push any slot lower than min_slot
*/
static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_path *path, int data_size,
- int empty)
+ *root, struct btrfs_path *path,
+ int min_data_size, int data_size,
+ int empty, u32 min_slot)
{
struct extent_buffer *left = path->nodes[0];
struct extent_buffer *right;
if (left_nritems == 0)
goto out_unlock;
- return __push_leaf_right(trans, root, path, data_size, empty,
- right, free_space, left_nritems);
+ return __push_leaf_right(trans, root, path, min_data_size, empty,
+ right, free_space, left_nritems, min_slot);
out_unlock:
btrfs_tree_unlock(right);
free_extent_buffer(right);
/*
* push some data in the path leaf to the left, trying to free up at
* least data_size bytes. returns zero if the push worked, nonzero otherwise
+ *
+ * max_slot can put a limit on how far into the leaf we'll push items. The
+ * item at 'max_slot' won't be touched. Use (u32)-1 to make us do all the
+ * items
*/
static noinline int __push_leaf_left(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path, int data_size,
int empty, struct extent_buffer *left,
- int free_space, int right_nritems)
+ int free_space, u32 right_nritems,
+ u32 max_slot)
{
struct btrfs_disk_key disk_key;
struct extent_buffer *right = path->nodes[0];
slot = path->slots[1];
if (empty)
- nr = right_nritems;
+ nr = min(right_nritems, max_slot);
else
- nr = right_nritems - 1;
+ nr = min(right_nritems - 1, max_slot);
for (i = 0; i < nr; i++) {
item = btrfs_item_nr(right, i);
/*
* push some data in the path leaf to the left, trying to free up at
* least data_size bytes. returns zero if the push worked, nonzero otherwise
+ *
+ * max_slot can put a limit on how far into the leaf we'll push items. The
+ * item at 'max_slot' won't be touched. Use (u32)-1 to make us push all the
+ * items
*/
static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root
- *root, struct btrfs_path *path, int data_size,
- int empty)
+ *root, struct btrfs_path *path, int min_data_size,
+ int data_size, int empty, u32 max_slot)
{
struct extent_buffer *right = path->nodes[0];
struct extent_buffer *left;
goto out;
}
- return __push_leaf_left(trans, root, path, data_size,
- empty, left, free_space, right_nritems);
+ return __push_leaf_left(trans, root, path, min_data_size,
+ empty, left, free_space, right_nritems,
+ max_slot);
out:
btrfs_tree_unlock(left);
free_extent_buffer(left);
return ret;
}
+/*
+ * double splits happen when we need to insert a big item in the middle
+ * of a leaf. A double split can leave us with 3 mostly empty leaves:
+ * leaf: [ slots 0 - N] [ our target ] [ N + 1 - total in leaf ]
+ * A B C
+ *
+ * We avoid this by trying to push the items on either side of our target
+ * into the adjacent leaves. If all goes well we can avoid the double split
+ * completely.
+ */
+static noinline int push_for_double_split(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root,
+ struct btrfs_path *path,
+ int data_size)
+{
+ int ret;
+ int progress = 0;
+ int slot;
+ u32 nritems;
+
+ slot = path->slots[0];
+
+ /*
+ * try to push all the items after our slot into the
+ * right leaf
+ */
+ ret = push_leaf_right(trans, root, path, 1, data_size, 0, slot);
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0)
+ progress++;
+
+ nritems = btrfs_header_nritems(path->nodes[0]);
+ /*
+ * our goal is to get our slot at the start or end of a leaf. If
+ * we've done so we're done
+ */
+ if (path->slots[0] == 0 || path->slots[0] == nritems)
+ return 0;
+
+ if (btrfs_leaf_free_space(root, path->nodes[0]) >= data_size)
+ return 0;
+
+ /* try to push all the items before our slot into the next leaf */
+ slot = path->slots[0];
+ ret = push_leaf_left(trans, root, path, 1, data_size, 0, slot);
+ if (ret < 0)
+ return ret;
+
+ if (ret == 0)
+ progress++;
+
+ if (progress)
+ return 0;
+ return 1;
+}
+
/*
* split the path's leaf in two, making sure there is at least data_size
* available for the resulting leaf level of the path.
int wret;
int split;
int num_doubles = 0;
+ int tried_avoid_double = 0;
l = path->nodes[0];
slot = path->slots[0];
return -EOVERFLOW;
/* first try to make some room by pushing left and right */
- if (data_size && ins_key->type != BTRFS_DIR_ITEM_KEY) {
- wret = push_leaf_right(trans, root, path, data_size, 0);
+ if (data_size) {
+ wret = push_leaf_right(trans, root, path, data_size,
+ data_size, 0, 0);
if (wret < 0)
return wret;
if (wret) {
- wret = push_leaf_left(trans, root, path, data_size, 0);
+ wret = push_leaf_left(trans, root, path, data_size,
+ data_size, 0, (u32)-1);
if (wret < 0)
return wret;
}
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
data_size > BTRFS_LEAF_DATA_SIZE(root)) {
+ if (data_size && !tried_avoid_double)
+ goto push_for_double;
split = 2;
}
}
if (mid != nritems &&
leaf_space_used(l, mid, nritems - mid) +
data_size > BTRFS_LEAF_DATA_SIZE(root)) {
+ if (data_size && !tried_avoid_double)
+ goto push_for_double;
split = 2 ;
}
}
}
return ret;
+
+push_for_double:
+ push_for_double_split(trans, root, path, data_size);
+ tried_avoid_double = 1;
+ if (btrfs_leaf_free_space(root, path->nodes[0]) >= data_size)
+ return 0;
+ goto again;
}
static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans,
extent_buffer_get(leaf);
btrfs_set_path_blocking(path);
- wret = push_leaf_left(trans, root, path, 1, 1);
+ wret = push_leaf_left(trans, root, path, 1, 1,
+ 1, (u32)-1);
if (wret < 0 && wret != -ENOSPC)
ret = wret;
if (path->nodes[0] == leaf &&
btrfs_header_nritems(leaf)) {
- wret = push_leaf_right(trans, root, path, 1, 1);
+ wret = push_leaf_right(trans, root, path, 1,
+ 1, 1, 0);
if (wret < 0 && wret != -ENOSPC)
ret = wret;
}
*/
/* the destination must be opened for writing */
- if (!(file->f_mode & FMODE_WRITE))
+ if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
return -EINVAL;
ret = mnt_want_write(file->f_path.mnt);
/* determine range to clone */
ret = -EINVAL;
- if (off >= src->i_size || off + len > src->i_size)
+ if (off + len > src->i_size || off + len < off)
goto out_unlock;
if (len == 0)
olen = len = src->i_size - off;
u64 disko = 0, diskl = 0;
u64 datao = 0, datal = 0;
u8 comp;
+ u64 endoff;
size = btrfs_item_size_nr(leaf, slot);
read_extent_buffer(leaf, buf,
btrfs_release_path(root, path);
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- if (new_key.offset + datal > inode->i_size)
- btrfs_i_size_write(inode,
- new_key.offset + datal);
+
+ /*
+ * we round up to the block size at eof when
+ * determining which extents to clone above,
+ * but shouldn't round up the file size
+ */
+ endoff = new_key.offset + datal;
+ if (endoff > off+olen)
+ endoff = off+olen;
+ if (endoff > inode->i_size)
+ btrfs_i_size_write(inode, endoff);
+
BTRFS_I(inode)->flags = BTRFS_I(src)->flags;
ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
remove_ticket_handler(ac, th);
}
+ if (xi->auth_authorizer.buf)
+ ceph_buffer_put(xi->auth_authorizer.buf);
+
kfree(ac->private);
ac->private = NULL;
}
ceph_encode_filepath(&p, end, ino1, path1);
ceph_encode_filepath(&p, end, ino2, path2);
+ /* make note of release offset, in case we need to replay */
+ req->r_request_release_offset = p - msg->front.iov_base;
+
/* cap releases */
releases = 0;
if (req->r_inode_drop)
dout("prepare_send_request %p tid %lld %s (attempt %d)\n", req,
req->r_tid, ceph_mds_op_name(req->r_op), req->r_attempts);
+ if (req->r_got_unsafe) {
+ /*
+ * Replay. Do not regenerate message (and rebuild
+ * paths, etc.); just use the original message.
+ * Rebuilding paths will break for renames because
+ * d_move mangles the src name.
+ */
+ msg = req->r_request;
+ rhead = msg->front.iov_base;
+
+ flags = le32_to_cpu(rhead->flags);
+ flags |= CEPH_MDS_FLAG_REPLAY;
+ rhead->flags = cpu_to_le32(flags);
+
+ if (req->r_target_inode)
+ rhead->ino = cpu_to_le64(ceph_ino(req->r_target_inode));
+
+ rhead->num_retry = req->r_attempts - 1;
+
+ /* remove cap/dentry releases from message */
+ rhead->num_releases = 0;
+ msg->hdr.front_len = cpu_to_le32(req->r_request_release_offset);
+ msg->front.iov_len = req->r_request_release_offset;
+ return 0;
+ }
+
if (req->r_request) {
ceph_msg_put(req->r_request);
req->r_request = NULL;
rhead->flags = cpu_to_le32(flags);
rhead->num_fwd = req->r_num_fwd;
rhead->num_retry = req->r_attempts - 1;
+ rhead->ino = 0;
dout(" r_locked_dir = %p\n", req->r_locked_dir);
-
- if (req->r_target_inode && req->r_got_unsafe)
- rhead->ino = cpu_to_le64(ceph_ino(req->r_target_inode));
- else
- rhead->ino = 0;
return 0;
}
int r_old_inode_drop, r_old_inode_unless;
struct ceph_msg *r_request; /* original request */
+ int r_request_release_offset;
struct ceph_msg *r_reply;
struct ceph_mds_reply_info_parsed r_reply_info;
int r_err;
* nicely render a sockaddr as a string.
*/
#define MAX_ADDR_STR 20
-static char addr_str[MAX_ADDR_STR][40];
+#define MAX_ADDR_STR_LEN 60
+static char addr_str[MAX_ADDR_STR][MAX_ADDR_STR_LEN];
static DEFINE_SPINLOCK(addr_str_lock);
static int last_addr_str;
int i;
char *s;
struct sockaddr_in *in4 = (void *)ss;
- unsigned char *quad = (void *)&in4->sin_addr.s_addr;
struct sockaddr_in6 *in6 = (void *)ss;
spin_lock(&addr_str_lock);
switch (ss->ss_family) {
case AF_INET:
- sprintf(s, "%u.%u.%u.%u:%u",
- (unsigned int)quad[0],
- (unsigned int)quad[1],
- (unsigned int)quad[2],
- (unsigned int)quad[3],
- (unsigned int)ntohs(in4->sin_port));
+ snprintf(s, MAX_ADDR_STR_LEN, "%pI4:%u", &in4->sin_addr,
+ (unsigned int)ntohs(in4->sin_port));
break;
case AF_INET6:
- sprintf(s, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%u",
- in6->sin6_addr.s6_addr16[0],
- in6->sin6_addr.s6_addr16[1],
- in6->sin6_addr.s6_addr16[2],
- in6->sin6_addr.s6_addr16[3],
- in6->sin6_addr.s6_addr16[4],
- in6->sin6_addr.s6_addr16[5],
- in6->sin6_addr.s6_addr16[6],
- in6->sin6_addr.s6_addr16[7],
- (unsigned int)ntohs(in6->sin6_port));
+ snprintf(s, MAX_ADDR_STR_LEN, "[%pI6c]:%u", &in6->sin6_addr,
+ (unsigned int)ntohs(in6->sin6_port));
break;
default:
*/
static struct socket *ceph_tcp_connect(struct ceph_connection *con)
{
- struct sockaddr *paddr = (struct sockaddr *)&con->peer_addr.in_addr;
+ struct sockaddr_storage *paddr = &con->peer_addr.in_addr;
struct socket *sock;
int ret;
BUG_ON(con->sock);
- ret = sock_create_kern(AF_INET, SOCK_STREAM, IPPROTO_TCP, &sock);
+ ret = sock_create_kern(con->peer_addr.in_addr.ss_family, SOCK_STREAM,
+ IPPROTO_TCP, &sock);
if (ret)
return ERR_PTR(ret);
con->sock = sock;
dout("connect %s\n", pr_addr(&con->peer_addr.in_addr));
- ret = sock->ops->connect(sock, paddr, sizeof(*paddr), O_NONBLOCK);
+ ret = sock->ops->connect(sock, (struct sockaddr *)paddr, sizeof(*paddr),
+ O_NONBLOCK);
if (ret == -EINPROGRESS) {
dout("connect %s EINPROGRESS sk_state = %u\n",
pr_addr(&con->peer_addr.in_addr),
struct sockaddr_in *in4 = (void *)ss;
struct sockaddr_in6 *in6 = (void *)ss;
int port;
+ char delim = ',';
+
+ if (*p == '[') {
+ delim = ']';
+ p++;
+ }
memset(ss, 0, sizeof(*ss));
if (in4_pton(p, end - p, (u8 *)&in4->sin_addr.s_addr,
- ',', &ipend)) {
+ delim, &ipend))
ss->ss_family = AF_INET;
- } else if (in6_pton(p, end - p, (u8 *)&in6->sin6_addr.s6_addr,
- ',', &ipend)) {
+ else if (in6_pton(p, end - p, (u8 *)&in6->sin6_addr.s6_addr,
+ delim, &ipend))
ss->ss_family = AF_INET6;
- } else {
+ else
goto bad;
- }
p = ipend;
+ if (delim == ']') {
+ if (*p != ']') {
+ dout("missing matching ']'\n");
+ goto bad;
+ }
+ p++;
+ }
+
/* port? */
if (p < end && *p == ':') {
port = 0;
return 0;
bad:
- pr_err("parse_ips bad ip '%s'\n", c);
+ pr_err("parse_ips bad ip '%.*s'\n", (int)(end - c), c);
return -EINVAL;
}
{
mutex_lock(&con->mutex);
if (!list_empty(&msg->list_head)) {
- dout("con_revoke %p msg %p\n", con, msg);
+ dout("con_revoke %p msg %p - was on queue\n", con, msg);
list_del_init(&msg->list_head);
ceph_msg_put(msg);
msg->hdr.seq = 0;
- if (con->out_msg == msg) {
- ceph_msg_put(con->out_msg);
- con->out_msg = NULL;
- }
+ }
+ if (con->out_msg == msg) {
+ dout("con_revoke %p msg %p - was sending\n", con, msg);
+ con->out_msg = NULL;
if (con->out_kvec_is_msg) {
con->out_skip = con->out_kvec_bytes;
con->out_kvec_is_msg = false;
}
- } else {
- dout("con_revoke %p msg %p - not queued (sent?)\n", con, msg);
+ ceph_msg_put(msg);
+ msg->hdr.seq = 0;
}
mutex_unlock(&con->mutex);
}
if (ev > CEPH_PG_POOL_VERSION) {
pr_warning("got unknown v %d > %d of ceph_pg_pool\n",
ev, CEPH_PG_POOL_VERSION);
+ kfree(pi);
goto bad;
}
__decode_pool(p, pi);
goto out_unregister_filesystem;
#endif
#ifdef CONFIG_CIFS_DFS_UPCALL
- rc = register_key_type(&key_type_dns_resolver);
+ rc = cifs_init_dns_resolver();
if (rc)
goto out_unregister_key_type;
#endif
out_unregister_resolver_key:
#ifdef CONFIG_CIFS_DFS_UPCALL
- unregister_key_type(&key_type_dns_resolver);
+ cifs_exit_dns_resolver();
out_unregister_key_type:
#endif
#ifdef CONFIG_CIFS_UPCALL
cifs_proc_clean();
#ifdef CONFIG_CIFS_DFS_UPCALL
cifs_dfs_release_automount_timer();
- unregister_key_type(&key_type_dns_resolver);
+ cifs_exit_dns_resolver();
#endif
#ifdef CONFIG_CIFS_UPCALL
unregister_key_type(&cifs_spnego_key_type);
*/
#include <linux/slab.h>
+#include <linux/keyctl.h>
+#include <linux/key-type.h>
#include <keys/user-type.h>
#include "dns_resolve.h"
#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
+static const struct cred *dns_resolver_cache;
+
/* Checks if supplied name is IP address
* returns:
* 1 - name is IP
int
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
{
+ const struct cred *saved_cred;
int rc = -EAGAIN;
struct key *rkey = ERR_PTR(-EAGAIN);
char *name;
goto skip_upcall;
}
+ saved_cred = override_creds(dns_resolver_cache);
rkey = request_key(&key_type_dns_resolver, name, "");
+ revert_creds(saved_cred);
if (!IS_ERR(rkey)) {
+ if (!(rkey->perm & KEY_USR_VIEW)) {
+ down_read(&rkey->sem);
+ rkey->perm |= KEY_USR_VIEW;
+ up_read(&rkey->sem);
+ }
len = rkey->type_data.x[0];
data = rkey->payload.data;
} else {
return rc;
}
+int __init cifs_init_dns_resolver(void)
+{
+ struct cred *cred;
+ struct key *keyring;
+ int ret;
+
+ printk(KERN_NOTICE "Registering the %s key type\n",
+ key_type_dns_resolver.name);
+
+ /* create an override credential set with a special thread keyring in
+ * which DNS requests are cached
+ *
+ * this is used to prevent malicious redirections from being installed
+ * with add_key().
+ */
+ cred = prepare_kernel_cred(NULL);
+ if (!cred)
+ return -ENOMEM;
+
+ keyring = key_alloc(&key_type_keyring, ".dns_resolver", 0, 0, cred,
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ,
+ KEY_ALLOC_NOT_IN_QUOTA);
+ if (IS_ERR(keyring)) {
+ ret = PTR_ERR(keyring);
+ goto failed_put_cred;
+ }
+
+ ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
+ if (ret < 0)
+ goto failed_put_key;
+
+ ret = register_key_type(&key_type_dns_resolver);
+ if (ret < 0)
+ goto failed_put_key;
+
+ /* instruct request_key() to use this special keyring as a cache for
+ * the results it looks up */
+ cred->thread_keyring = keyring;
+ cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
+ dns_resolver_cache = cred;
+ return 0;
+
+failed_put_key:
+ key_put(keyring);
+failed_put_cred:
+ put_cred(cred);
+ return ret;
+}
+void __exit cifs_exit_dns_resolver(void)
+{
+ key_revoke(dns_resolver_cache->thread_keyring);
+ unregister_key_type(&key_type_dns_resolver);
+ put_cred(dns_resolver_cache);
+ printk(KERN_NOTICE "Unregistered %s key type\n",
+ key_type_dns_resolver.name);
+}
#define _DNS_RESOLVE_H
#ifdef __KERNEL__
-#include <linux/key-type.h>
-extern struct key_type key_type_dns_resolver;
+extern int __init cifs_init_dns_resolver(void);
+extern void __exit cifs_exit_dns_resolver(void);
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
#endif /* KERNEL */
*
* In this case we return -1 to tell the caller that we baled.
*/
-static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
+static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
{
if (nr) {
if (!(gfp_mask & __GFP_FS))
}
-static int gfs2_shrink_glock_memory(int nr, gfp_t gfp_mask)
+static int gfs2_shrink_glock_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
{
struct gfs2_glock *gl;
int may_demote;
static atomic_t qd_lru_count = ATOMIC_INIT(0);
static DEFINE_SPINLOCK(qd_lru_lock);
-int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask)
+int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
{
struct gfs2_quota_data *qd;
struct gfs2_sbd *sdp;
return ret;
}
-extern int gfs2_shrink_qd_memory(int nr, gfp_t gfp_mask);
+extern int gfs2_shrink_qd_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask);
extern const struct quotactl_ops gfs2_quotactl_ops;
#endif /* __QUOTA_DOT_H__ */
* This function is passed the number of inodes to scan, and it returns the
* total number of remaining possibly-reclaimable inodes.
*/
-static int shrink_icache_memory(int nr, gfp_t gfp_mask)
+static int shrink_icache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
{
if (nr) {
/*
struct page *new_page;
unsigned int new_offset;
struct buffer_head *bh_in = jh2bh(jh_in);
- struct jbd2_buffer_trigger_type *triggers;
journal_t *journal = transaction->t_journal;
/*
done_copy_out = 1;
new_page = virt_to_page(jh_in->b_frozen_data);
new_offset = offset_in_page(jh_in->b_frozen_data);
- triggers = jh_in->b_frozen_triggers;
} else {
new_page = jh2bh(jh_in)->b_page;
new_offset = offset_in_page(jh2bh(jh_in)->b_data);
- triggers = jh_in->b_triggers;
}
mapped_data = kmap_atomic(new_page, KM_USER0);
/*
- * Fire any commit trigger. Do this before checking for escaping,
- * as the trigger may modify the magic offset. If a copy-out
- * happens afterwards, it will have the correct data in the buffer.
+ * Fire data frozen trigger if data already wasn't frozen. Do this
+ * before checking for escaping, as the trigger may modify the magic
+ * offset. If a copy-out happens afterwards, it will have the correct
+ * data in the buffer.
*/
- jbd2_buffer_commit_trigger(jh_in, mapped_data + new_offset,
- triggers);
+ if (!done_copy_out)
+ jbd2_buffer_frozen_trigger(jh_in, mapped_data + new_offset,
+ jh_in->b_triggers);
/*
* Check for escaping
page = jh2bh(jh)->b_page;
offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK;
source = kmap_atomic(page, KM_USER0);
+ /* Fire data frozen trigger just before we copy the data */
+ jbd2_buffer_frozen_trigger(jh, source + offset,
+ jh->b_triggers);
memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
kunmap_atomic(source, KM_USER0);
jh->b_triggers = type;
}
-void jbd2_buffer_commit_trigger(struct journal_head *jh, void *mapped_data,
+void jbd2_buffer_frozen_trigger(struct journal_head *jh, void *mapped_data,
struct jbd2_buffer_trigger_type *triggers)
{
struct buffer_head *bh = jh2bh(jh);
- if (!triggers || !triggers->t_commit)
+ if (!triggers || !triggers->t_frozen)
return;
- triggers->t_commit(triggers, bh, mapped_data, bh->b_size);
+ triggers->t_frozen(triggers, bh, mapped_data, bh->b_size);
}
void jbd2_buffer_abort_trigger(struct journal_head *jh,
static int check_xattr_ref_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic)
{
- /* success of check_xattr_ref_inode() means taht inode (ic) dose not have
+ /* success of check_xattr_ref_inode() means that inode (ic) dose not have
* duplicate name/value pairs. If duplicate name/value pair would be found,
* one will be removed.
*/
* What the mbcache registers as to get shrunk dynamically.
*/
-static int mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask);
+static int mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask);
static struct shrinker mb_cache_shrinker = {
.shrink = mb_cache_shrink_fn,
* This function is called by the kernel memory management when memory
* gets low.
*
+ * @shrink: (ignored)
* @nr_to_scan: Number of objects to scan
* @gfp_mask: (ignored)
*
* Returns the number of objects which are present in the cache.
*/
static int
-mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask)
+mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
{
LIST_HEAD(free_list);
struct list_head *l, *ltmp;
}
}
-int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
+int nfs_access_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
{
LIST_HEAD(head);
struct nfs_inode *nfsi;
void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
/* dir.c */
-extern int nfs_access_cache_shrinker(int nr_to_scan, gfp_t gfp_mask);
+extern int nfs_access_cache_shrinker(struct shrinker *shrink,
+ int nr_to_scan, gfp_t gfp_mask);
/* inode.c */
extern struct workqueue_struct *nfsiod_workqueue;
dump_stack();
goto bail;
}
-
- past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
- mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino,
- (unsigned long long)past_eof);
-
- if (create && (iblock >= past_eof))
- set_buffer_new(bh_result);
}
+ past_eof = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
+ mlog(0, "Inode %lu, past_eof = %llu\n", inode->i_ino,
+ (unsigned long long)past_eof);
+ if (create && (iblock >= past_eof))
+ set_buffer_new(bh_result);
+
bail:
if (err < 0)
err = -EIO;
return ret;
}
-handle_t *ocfs2_start_walk_page_trans(struct inode *inode,
- struct page *page,
- unsigned from,
- unsigned to)
-{
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
- handle_t *handle;
- int ret = 0;
-
- handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
- if (IS_ERR(handle)) {
- ret = -ENOMEM;
- mlog_errno(ret);
- goto out;
- }
-
- if (ocfs2_should_order_data(inode)) {
- ret = ocfs2_jbd2_file_inode(handle, inode);
- if (ret < 0)
- mlog_errno(ret);
- }
-out:
- if (ret) {
- if (!IS_ERR(handle))
- ocfs2_commit_trans(osb, handle);
- handle = ERR_PTR(ret);
- }
- return handle;
-}
-
static sector_t ocfs2_bmap(struct address_space *mapping, sector_t block)
{
sector_t status;
*/
static int ocfs2_grab_pages_for_write(struct address_space *mapping,
struct ocfs2_write_ctxt *wc,
- u32 cpos, loff_t user_pos, int new,
+ u32 cpos, loff_t user_pos,
+ unsigned user_len, int new,
struct page *mmap_page)
{
int ret = 0, i;
- unsigned long start, target_index, index;
+ unsigned long start, target_index, end_index, index;
struct inode *inode = mapping->host;
+ loff_t last_byte;
target_index = user_pos >> PAGE_CACHE_SHIFT;
/*
* Figure out how many pages we'll be manipulating here. For
* non allocating write, we just change the one
- * page. Otherwise, we'll need a whole clusters worth.
+ * page. Otherwise, we'll need a whole clusters worth. If we're
+ * writing past i_size, we only need enough pages to cover the
+ * last page of the write.
*/
if (new) {
wc->w_num_pages = ocfs2_pages_per_cluster(inode->i_sb);
start = ocfs2_align_clusters_to_page_index(inode->i_sb, cpos);
+ /*
+ * We need the index *past* the last page we could possibly
+ * touch. This is the page past the end of the write or
+ * i_size, whichever is greater.
+ */
+ last_byte = max(user_pos + user_len, i_size_read(inode));
+ BUG_ON(last_byte < 1);
+ end_index = ((last_byte - 1) >> PAGE_CACHE_SHIFT) + 1;
+ if ((start + wc->w_num_pages) > end_index)
+ wc->w_num_pages = end_index - start;
} else {
wc->w_num_pages = 1;
start = target_index;
* write path can treat it as an non-allocating write, which has no
* special case code for sparse/nonsparse files.
*/
-static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos,
- unsigned len,
+static int ocfs2_expand_nonsparse_inode(struct inode *inode,
+ struct buffer_head *di_bh,
+ loff_t pos, unsigned len,
struct ocfs2_write_ctxt *wc)
{
int ret;
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
loff_t newsize = pos + len;
- if (ocfs2_sparse_alloc(osb))
- return 0;
+ BUG_ON(ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)));
if (newsize <= i_size_read(inode))
return 0;
- ret = ocfs2_extend_no_holes(inode, newsize, pos);
+ ret = ocfs2_extend_no_holes(inode, di_bh, newsize, pos);
if (ret)
mlog_errno(ret);
return ret;
}
+static int ocfs2_zero_tail(struct inode *inode, struct buffer_head *di_bh,
+ loff_t pos)
+{
+ int ret = 0;
+
+ BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)));
+ if (pos > i_size_read(inode))
+ ret = ocfs2_zero_extend(inode, di_bh, pos);
+
+ return ret;
+}
+
int ocfs2_write_begin_nolock(struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
}
}
- ret = ocfs2_expand_nonsparse_inode(inode, pos, len, wc);
+ if (ocfs2_sparse_alloc(osb))
+ ret = ocfs2_zero_tail(inode, di_bh, pos);
+ else
+ ret = ocfs2_expand_nonsparse_inode(inode, di_bh, pos, len,
+ wc);
if (ret) {
mlog_errno(ret);
goto out;
* that we can zero and flush if we error after adding the
* extent.
*/
- ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos,
+ ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos, len,
cluster_of_pages, mmap_page);
if (ret) {
mlog_errno(ret);
struct dlm_ctxt *dlm = NULL;
struct dlm_ctxt *new_ctxt = NULL;
- if (strlen(domain) > O2NM_MAX_NAME_LEN) {
+ if (strlen(domain) >= O2NM_MAX_NAME_LEN) {
ret = -ENAMETOOLONG;
mlog(ML_ERROR, "domain name length too long\n");
goto leave;
}
if (dlm_protocol_compare(&dlm->fs_locking_proto, fs_proto)) {
+ spin_unlock(&dlm_domain_lock);
mlog(ML_ERROR,
"Requested locking protocol version is not "
"compatible with already registered domain "
mlog(0, "trying again...\n");
goto again;
}
- /* now that we are sure the MIGRATING state is there, drop
- * the unneded state which blocked threads trying to DIRTY */
- spin_lock(&res->spinlock);
- BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY));
- BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
- res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
- spin_unlock(&res->spinlock);
+ ret = 0;
/* did the target go down or die? */
spin_lock(&dlm->spinlock);
if (!test_bit(target, dlm->domain_map)) {
}
spin_unlock(&dlm->spinlock);
+ /*
+ * if target is down, we need to clear DLM_LOCK_RES_BLOCK_DIRTY for
+ * another try; otherwise, we are sure the MIGRATING state is there,
+ * drop the unneded state which blocked threads trying to DIRTY
+ */
+ spin_lock(&res->spinlock);
+ BUG_ON(!(res->state & DLM_LOCK_RES_BLOCK_DIRTY));
+ res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
+ if (!ret)
+ BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
+ spin_unlock(&res->spinlock);
+
/*
* at this point:
*
- * o the DLM_LOCK_RES_MIGRATING flag is set
+ * o the DLM_LOCK_RES_MIGRATING flag is set if target not down
* o there are no pending asts on this lockres
* o all processes trying to reserve an ast on this
* lockres must wait for the MIGRATING flag to clear
if (dlm->reco.dead_node == O2NM_INVALID_NODE_NUM) {
int bit;
- bit = find_next_bit (dlm->recovery_map, O2NM_MAX_NODES+1, 0);
+ bit = find_next_bit (dlm->recovery_map, O2NM_MAX_NODES, 0);
if (bit >= O2NM_MAX_NODES || bit < 0)
dlm_set_reco_dead_node(dlm, O2NM_INVALID_NODE_NUM);
else
return status;
}
+/*
+ * While a write will already be ordering the data, a truncate will not.
+ * Thus, we need to explicitly order the zeroed pages.
+ */
+static handle_t *ocfs2_zero_start_ordered_transaction(struct inode *inode)
+{
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ handle_t *handle = NULL;
+ int ret = 0;
+
+ if (!ocfs2_should_order_data(inode))
+ goto out;
+
+ handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_jbd2_file_inode(handle, inode);
+ if (ret < 0)
+ mlog_errno(ret);
+
+out:
+ if (ret) {
+ if (!IS_ERR(handle))
+ ocfs2_commit_trans(osb, handle);
+ handle = ERR_PTR(ret);
+ }
+ return handle;
+}
+
/* Some parts of this taken from generic_cont_expand, which turned out
* to be too fragile to do exactly what we need without us having to
* worry about recursive locking in ->write_begin() and ->write_end(). */
-static int ocfs2_write_zero_page(struct inode *inode,
- u64 size)
+static int ocfs2_write_zero_page(struct inode *inode, u64 abs_from,
+ u64 abs_to)
{
struct address_space *mapping = inode->i_mapping;
struct page *page;
- unsigned long index;
- unsigned int offset;
+ unsigned long index = abs_from >> PAGE_CACHE_SHIFT;
handle_t *handle = NULL;
- int ret;
+ int ret = 0;
+ unsigned zero_from, zero_to, block_start, block_end;
- offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */
- /* ugh. in prepare/commit_write, if from==to==start of block, we
- ** skip the prepare. make sure we never send an offset for the start
- ** of a block
- */
- if ((offset & (inode->i_sb->s_blocksize - 1)) == 0) {
- offset++;
- }
- index = size >> PAGE_CACHE_SHIFT;
+ BUG_ON(abs_from >= abs_to);
+ BUG_ON(abs_to > (((u64)index + 1) << PAGE_CACHE_SHIFT));
+ BUG_ON(abs_from & (inode->i_blkbits - 1));
page = grab_cache_page(mapping, index);
if (!page) {
goto out;
}
- ret = ocfs2_prepare_write_nolock(inode, page, offset, offset);
- if (ret < 0) {
- mlog_errno(ret);
- goto out_unlock;
- }
+ /* Get the offsets within the page that we want to zero */
+ zero_from = abs_from & (PAGE_CACHE_SIZE - 1);
+ zero_to = abs_to & (PAGE_CACHE_SIZE - 1);
+ if (!zero_to)
+ zero_to = PAGE_CACHE_SIZE;
- if (ocfs2_should_order_data(inode)) {
- handle = ocfs2_start_walk_page_trans(inode, page, offset,
- offset);
- if (IS_ERR(handle)) {
- ret = PTR_ERR(handle);
- handle = NULL;
+ mlog(0,
+ "abs_from = %llu, abs_to = %llu, index = %lu, zero_from = %u, zero_to = %u\n",
+ (unsigned long long)abs_from, (unsigned long long)abs_to,
+ index, zero_from, zero_to);
+
+ /* We know that zero_from is block aligned */
+ for (block_start = zero_from; block_start < zero_to;
+ block_start = block_end) {
+ block_end = block_start + (1 << inode->i_blkbits);
+
+ /*
+ * block_start is block-aligned. Bump it by one to
+ * force ocfs2_{prepare,commit}_write() to zero the
+ * whole block.
+ */
+ ret = ocfs2_prepare_write_nolock(inode, page,
+ block_start + 1,
+ block_start + 1);
+ if (ret < 0) {
+ mlog_errno(ret);
goto out_unlock;
}
- }
- /* must not update i_size! */
- ret = block_commit_write(page, offset, offset);
- if (ret < 0)
- mlog_errno(ret);
- else
- ret = 0;
+ if (!handle) {
+ handle = ocfs2_zero_start_ordered_transaction(inode);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ handle = NULL;
+ break;
+ }
+ }
+
+ /* must not update i_size! */
+ ret = block_commit_write(page, block_start + 1,
+ block_start + 1);
+ if (ret < 0)
+ mlog_errno(ret);
+ else
+ ret = 0;
+ }
if (handle)
ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+
out_unlock:
unlock_page(page);
page_cache_release(page);
return ret;
}
-static int ocfs2_zero_extend(struct inode *inode,
- u64 zero_to_size)
+/*
+ * Find the next range to zero. We do this in terms of bytes because
+ * that's what ocfs2_zero_extend() wants, and it is dealing with the
+ * pagecache. We may return multiple extents.
+ *
+ * zero_start and zero_end are ocfs2_zero_extend()s current idea of what
+ * needs to be zeroed. range_start and range_end return the next zeroing
+ * range. A subsequent call should pass the previous range_end as its
+ * zero_start. If range_end is 0, there's nothing to do.
+ *
+ * Unwritten extents are skipped over. Refcounted extents are CoWd.
+ */
+static int ocfs2_zero_extend_get_range(struct inode *inode,
+ struct buffer_head *di_bh,
+ u64 zero_start, u64 zero_end,
+ u64 *range_start, u64 *range_end)
{
- int ret = 0;
- u64 start_off;
- struct super_block *sb = inode->i_sb;
+ int rc = 0, needs_cow = 0;
+ u32 p_cpos, zero_clusters = 0;
+ u32 zero_cpos =
+ zero_start >> OCFS2_SB(inode->i_sb)->s_clustersize_bits;
+ u32 last_cpos = ocfs2_clusters_for_bytes(inode->i_sb, zero_end);
+ unsigned int num_clusters = 0;
+ unsigned int ext_flags = 0;
- start_off = ocfs2_align_bytes_to_blocks(sb, i_size_read(inode));
- while (start_off < zero_to_size) {
- ret = ocfs2_write_zero_page(inode, start_off);
- if (ret < 0) {
- mlog_errno(ret);
+ while (zero_cpos < last_cpos) {
+ rc = ocfs2_get_clusters(inode, zero_cpos, &p_cpos,
+ &num_clusters, &ext_flags);
+ if (rc) {
+ mlog_errno(rc);
+ goto out;
+ }
+
+ if (p_cpos && !(ext_flags & OCFS2_EXT_UNWRITTEN)) {
+ zero_clusters = num_clusters;
+ if (ext_flags & OCFS2_EXT_REFCOUNTED)
+ needs_cow = 1;
+ break;
+ }
+
+ zero_cpos += num_clusters;
+ }
+ if (!zero_clusters) {
+ *range_end = 0;
+ goto out;
+ }
+
+ while ((zero_cpos + zero_clusters) < last_cpos) {
+ rc = ocfs2_get_clusters(inode, zero_cpos + zero_clusters,
+ &p_cpos, &num_clusters,
+ &ext_flags);
+ if (rc) {
+ mlog_errno(rc);
goto out;
}
- start_off += sb->s_blocksize;
+ if (!p_cpos || (ext_flags & OCFS2_EXT_UNWRITTEN))
+ break;
+ if (ext_flags & OCFS2_EXT_REFCOUNTED)
+ needs_cow = 1;
+ zero_clusters += num_clusters;
+ }
+ if ((zero_cpos + zero_clusters) > last_cpos)
+ zero_clusters = last_cpos - zero_cpos;
+
+ if (needs_cow) {
+ rc = ocfs2_refcount_cow(inode, di_bh, zero_cpos, zero_clusters,
+ UINT_MAX);
+ if (rc) {
+ mlog_errno(rc);
+ goto out;
+ }
+ }
+
+ *range_start = ocfs2_clusters_to_bytes(inode->i_sb, zero_cpos);
+ *range_end = ocfs2_clusters_to_bytes(inode->i_sb,
+ zero_cpos + zero_clusters);
+
+out:
+ return rc;
+}
+
+/*
+ * Zero one range returned from ocfs2_zero_extend_get_range(). The caller
+ * has made sure that the entire range needs zeroing.
+ */
+static int ocfs2_zero_extend_range(struct inode *inode, u64 range_start,
+ u64 range_end)
+{
+ int rc = 0;
+ u64 next_pos;
+ u64 zero_pos = range_start;
+
+ mlog(0, "range_start = %llu, range_end = %llu\n",
+ (unsigned long long)range_start,
+ (unsigned long long)range_end);
+ BUG_ON(range_start >= range_end);
+
+ while (zero_pos < range_end) {
+ next_pos = (zero_pos & PAGE_CACHE_MASK) + PAGE_CACHE_SIZE;
+ if (next_pos > range_end)
+ next_pos = range_end;
+ rc = ocfs2_write_zero_page(inode, zero_pos, next_pos);
+ if (rc < 0) {
+ mlog_errno(rc);
+ break;
+ }
+ zero_pos = next_pos;
/*
* Very large extends have the potential to lock up
cond_resched();
}
-out:
+ return rc;
+}
+
+int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh,
+ loff_t zero_to_size)
+{
+ int ret = 0;
+ u64 zero_start, range_start = 0, range_end = 0;
+ struct super_block *sb = inode->i_sb;
+
+ zero_start = ocfs2_align_bytes_to_blocks(sb, i_size_read(inode));
+ mlog(0, "zero_start %llu for i_size %llu\n",
+ (unsigned long long)zero_start,
+ (unsigned long long)i_size_read(inode));
+ while (zero_start < zero_to_size) {
+ ret = ocfs2_zero_extend_get_range(inode, di_bh, zero_start,
+ zero_to_size,
+ &range_start,
+ &range_end);
+ if (ret) {
+ mlog_errno(ret);
+ break;
+ }
+ if (!range_end)
+ break;
+ /* Trim the ends */
+ if (range_start < zero_start)
+ range_start = zero_start;
+ if (range_end > zero_to_size)
+ range_end = zero_to_size;
+
+ ret = ocfs2_zero_extend_range(inode, range_start,
+ range_end);
+ if (ret) {
+ mlog_errno(ret);
+ break;
+ }
+ zero_start = range_end;
+ }
+
return ret;
}
-int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size, u64 zero_to)
+int ocfs2_extend_no_holes(struct inode *inode, struct buffer_head *di_bh,
+ u64 new_i_size, u64 zero_to)
{
int ret;
u32 clusters_to_add;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ /*
+ * Only quota files call this without a bh, and they can't be
+ * refcounted.
+ */
+ BUG_ON(!di_bh && (oi->ip_dyn_features & OCFS2_HAS_REFCOUNT_FL));
+ BUG_ON(!di_bh && !(oi->ip_flags & OCFS2_INODE_SYSTEM_FILE));
+
clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size);
if (clusters_to_add < oi->ip_clusters)
clusters_to_add = 0;
* still need to zero the area between the old i_size and the
* new i_size.
*/
- ret = ocfs2_zero_extend(inode, zero_to);
+ ret = ocfs2_zero_extend(inode, di_bh, zero_to);
if (ret < 0)
mlog_errno(ret);
goto out;
if (i_size_read(inode) == new_i_size)
- goto out;
+ goto out;
BUG_ON(new_i_size < i_size_read(inode));
- /*
- * Fall through for converting inline data, even if the fs
- * supports sparse files.
- *
- * The check for inline data here is legal - nobody can add
- * the feature since we have i_mutex. We must check it again
- * after acquiring ip_alloc_sem though, as paths like mmap
- * might have raced us to converting the inode to extents.
- */
- if (!(oi->ip_dyn_features & OCFS2_INLINE_DATA_FL)
- && ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
- goto out_update_size;
-
/*
* The alloc sem blocks people in read/write from reading our
* allocation until we're done changing it. We depend on
* i_mutex to block other extend/truncate calls while we're
- * here.
+ * here. We even have to hold it for sparse files because there
+ * might be some tail zeroing.
*/
down_write(&oi->ip_alloc_sem);
ret = ocfs2_convert_inline_data_to_extents(inode, di_bh);
if (ret) {
up_write(&oi->ip_alloc_sem);
-
mlog_errno(ret);
goto out;
}
}
- if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
- ret = ocfs2_extend_no_holes(inode, new_i_size, new_i_size);
+ if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
+ ret = ocfs2_zero_extend(inode, di_bh, new_i_size);
+ else
+ ret = ocfs2_extend_no_holes(inode, di_bh, new_i_size,
+ new_i_size);
up_write(&oi->ip_alloc_sem);
int ocfs2_simple_size_update(struct inode *inode,
struct buffer_head *di_bh,
u64 new_i_size);
-int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
- u64 zero_to);
+int ocfs2_extend_no_holes(struct inode *inode, struct buffer_head *di_bh,
+ u64 new_i_size, u64 zero_to);
+int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh,
+ loff_t zero_to);
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
return container_of(triggers, struct ocfs2_triggers, ot_triggers);
}
-static void ocfs2_commit_trigger(struct jbd2_buffer_trigger_type *triggers,
+static void ocfs2_frozen_trigger(struct jbd2_buffer_trigger_type *triggers,
struct buffer_head *bh,
void *data, size_t size)
{
* Quota blocks have their own trigger because the struct ocfs2_block_check
* offset depends on the blocksize.
*/
-static void ocfs2_dq_commit_trigger(struct jbd2_buffer_trigger_type *triggers,
+static void ocfs2_dq_frozen_trigger(struct jbd2_buffer_trigger_type *triggers,
struct buffer_head *bh,
void *data, size_t size)
{
* Directory blocks also have their own trigger because the
* struct ocfs2_block_check offset depends on the blocksize.
*/
-static void ocfs2_db_commit_trigger(struct jbd2_buffer_trigger_type *triggers,
+static void ocfs2_db_frozen_trigger(struct jbd2_buffer_trigger_type *triggers,
struct buffer_head *bh,
void *data, size_t size)
{
static struct ocfs2_triggers di_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_commit_trigger,
+ .t_frozen = ocfs2_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
.ot_offset = offsetof(struct ocfs2_dinode, i_check),
static struct ocfs2_triggers eb_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_commit_trigger,
+ .t_frozen = ocfs2_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
.ot_offset = offsetof(struct ocfs2_extent_block, h_check),
static struct ocfs2_triggers rb_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_commit_trigger,
+ .t_frozen = ocfs2_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
.ot_offset = offsetof(struct ocfs2_refcount_block, rf_check),
static struct ocfs2_triggers gd_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_commit_trigger,
+ .t_frozen = ocfs2_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
.ot_offset = offsetof(struct ocfs2_group_desc, bg_check),
static struct ocfs2_triggers db_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_db_commit_trigger,
+ .t_frozen = ocfs2_db_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
};
static struct ocfs2_triggers xb_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_commit_trigger,
+ .t_frozen = ocfs2_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
.ot_offset = offsetof(struct ocfs2_xattr_block, xb_check),
static struct ocfs2_triggers dq_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_dq_commit_trigger,
+ .t_frozen = ocfs2_dq_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
};
static struct ocfs2_triggers dr_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_commit_trigger,
+ .t_frozen = ocfs2_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
.ot_offset = offsetof(struct ocfs2_dx_root_block, dr_check),
static struct ocfs2_triggers dl_triggers = {
.ot_triggers = {
- .t_commit = ocfs2_commit_trigger,
+ .t_frozen = ocfs2_frozen_trigger,
.t_abort = ocfs2_abort_trigger,
},
.ot_offset = offsetof(struct ocfs2_dx_leaf, dl_check),
mutex_lock(&os->os_lock);
ocfs2_queue_orphan_scan(osb);
if (atomic_read(&os->os_state) == ORPHAN_SCAN_ACTIVE)
- schedule_delayed_work(&os->os_orphan_scan_work,
+ queue_delayed_work(ocfs2_wq, &os->os_orphan_scan_work,
ocfs2_orphan_scan_timeout());
mutex_unlock(&os->os_lock);
}
atomic_set(&os->os_state, ORPHAN_SCAN_INACTIVE);
else {
atomic_set(&os->os_state, ORPHAN_SCAN_ACTIVE);
- schedule_delayed_work(&os->os_orphan_scan_work,
- ocfs2_orphan_scan_timeout());
+ queue_delayed_work(ocfs2_wq, &os->os_orphan_scan_work,
+ ocfs2_orphan_scan_timeout());
}
}
{
unsigned int la_mb;
unsigned int gd_mb;
+ unsigned int la_max_mb;
unsigned int megs_per_slot;
struct super_block *sb = osb->sb;
if (megs_per_slot < la_mb)
la_mb = megs_per_slot;
+ /* We can't store more bits than we can in a block. */
+ la_max_mb = ocfs2_clusters_to_megabytes(osb->sb,
+ ocfs2_local_alloc_size(sb) * 8);
+ if (la_mb > la_max_mb)
+ la_mb = la_max_mb;
+
return la_mb;
}
* locking allocators ranks above a transaction start
*/
WARN_ON(journal_current_handle());
- status = ocfs2_extend_no_holes(gqinode,
+ status = ocfs2_extend_no_holes(gqinode, NULL,
gqinode->i_size + (need_alloc << sb->s_blocksize_bits),
gqinode->i_size);
if (status < 0)
u64 p_blkno;
/* We are protected by dqio_sem so no locking needed */
- status = ocfs2_extend_no_holes(lqinode,
+ status = ocfs2_extend_no_holes(lqinode, NULL,
lqinode->i_size + 2 * sb->s_blocksize,
lqinode->i_size);
if (status < 0) {
return ocfs2_local_quota_add_chunk(sb, type, offset);
/* We are protected by dqio_sem so no locking needed */
- status = ocfs2_extend_no_holes(lqinode,
+ status = ocfs2_extend_no_holes(lqinode, NULL,
lqinode->i_size + sb->s_blocksize,
lqinode->i_size);
if (status < 0) {
offset = ((loff_t)cpos) << OCFS2_SB(sb)->s_clustersize_bits;
end = offset + (new_len << OCFS2_SB(sb)->s_clustersize_bits);
+ /*
+ * We only duplicate pages until we reach the page contains i_size - 1.
+ * So trim 'end' to i_size.
+ */
+ if (end > i_size_read(context->inode))
+ end = i_size_read(context->inode);
while (offset < end) {
page_index = offset >> PAGE_CACHE_SHIFT;
struct inode *inode = old_dentry->d_inode;
struct buffer_head *new_bh = NULL;
+ if (OCFS2_I(inode)->ip_flags & OCFS2_INODE_SYSTEM_FILE) {
+ ret = -EINVAL;
+ mlog_errno(ret);
+ goto out;
+ }
+
ret = filemap_fdatawrite(inode->i_mapping);
if (ret) {
mlog_errno(ret);
le16_to_cpu(bg->bg_free_bits_count));
le32_add_cpu(&cl->cl_recs[alloc_rec].c_total,
le16_to_cpu(bg->bg_bits));
- cl->cl_recs[alloc_rec].c_blkno = cpu_to_le64(bg->bg_blkno);
+ cl->cl_recs[alloc_rec].c_blkno = bg->bg_blkno;
if (le16_to_cpu(cl->cl_next_free_rec) < le16_to_cpu(cl->cl_count))
le16_add_cpu(&cl->cl_next_free_rec, 1);
struct ocfs2_xattr_value_buf *vb,
struct ocfs2_xattr_set_ctxt *ctxt)
{
- int status = 0;
+ int status = 0, credits;
handle_t *handle = ctxt->handle;
enum ocfs2_alloc_restarted why;
u32 prev_clusters, logical_start = le32_to_cpu(vb->vb_xv->xr_clusters);
ocfs2_init_xattr_value_extent_tree(&et, INODE_CACHE(inode), vb);
- status = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto leave;
- }
+ while (clusters_to_add) {
+ status = vb->vb_access(handle, INODE_CACHE(inode), vb->vb_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (status < 0) {
+ mlog_errno(status);
+ break;
+ }
- prev_clusters = le32_to_cpu(vb->vb_xv->xr_clusters);
- status = ocfs2_add_clusters_in_btree(handle,
- &et,
- &logical_start,
- clusters_to_add,
- 0,
- ctxt->data_ac,
- ctxt->meta_ac,
- &why);
- if (status < 0) {
- mlog_errno(status);
- goto leave;
- }
+ prev_clusters = le32_to_cpu(vb->vb_xv->xr_clusters);
+ status = ocfs2_add_clusters_in_btree(handle,
+ &et,
+ &logical_start,
+ clusters_to_add,
+ 0,
+ ctxt->data_ac,
+ ctxt->meta_ac,
+ &why);
+ if ((status < 0) && (status != -EAGAIN)) {
+ if (status != -ENOSPC)
+ mlog_errno(status);
+ break;
+ }
- ocfs2_journal_dirty(handle, vb->vb_bh);
+ ocfs2_journal_dirty(handle, vb->vb_bh);
- clusters_to_add -= le32_to_cpu(vb->vb_xv->xr_clusters) - prev_clusters;
+ clusters_to_add -= le32_to_cpu(vb->vb_xv->xr_clusters) -
+ prev_clusters;
- /*
- * We should have already allocated enough space before the transaction,
- * so no need to restart.
- */
- BUG_ON(why != RESTART_NONE || clusters_to_add);
-
-leave:
+ if (why != RESTART_NONE && clusters_to_add) {
+ /*
+ * We can only fail in case the alloc file doesn't give
+ * up enough clusters.
+ */
+ BUG_ON(why == RESTART_META);
+
+ mlog(0, "restarting xattr value extension for %u"
+ " clusters,.\n", clusters_to_add);
+ credits = ocfs2_calc_extend_credits(inode->i_sb,
+ &vb->vb_xv->xr_list,
+ clusters_to_add);
+ status = ocfs2_extend_trans(handle, credits);
+ if (status < 0) {
+ status = -ENOMEM;
+ mlog_errno(status);
+ break;
+ }
+ }
+ }
return status;
}
return ret;
}
-static int ocfs2_reflink_xattr_buckets(handle_t *handle,
+static int ocfs2_reflink_xattr_bucket(handle_t *handle,
u64 blkno, u64 new_blkno, u32 clusters,
+ u32 *cpos, int num_buckets,
struct ocfs2_alloc_context *meta_ac,
struct ocfs2_alloc_context *data_ac,
struct ocfs2_reflink_xattr_tree_args *args)
{
int i, j, ret = 0;
struct super_block *sb = args->reflink->old_inode->i_sb;
- u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(sb));
- u32 num_buckets = clusters * bpc;
int bpb = args->old_bucket->bu_blocks;
struct ocfs2_xattr_value_buf vb = {
.vb_access = ocfs2_journal_access,
break;
}
- /*
- * The real bucket num in this series of blocks is stored
- * in the 1st bucket.
- */
- if (i == 0)
- num_buckets = le16_to_cpu(
- bucket_xh(args->old_bucket)->xh_num_buckets);
-
ret = ocfs2_xattr_bucket_journal_access(handle,
args->new_bucket,
OCFS2_JOURNAL_ACCESS_CREATE);
bucket_block(args->old_bucket, j),
sb->s_blocksize);
+ /*
+ * Record the start cpos so that we can use it to initialize
+ * our xattr tree we also set the xh_num_bucket for the new
+ * bucket.
+ */
+ if (i == 0) {
+ *cpos = le32_to_cpu(bucket_xh(args->new_bucket)->
+ xh_entries[0].xe_name_hash);
+ bucket_xh(args->new_bucket)->xh_num_buckets =
+ cpu_to_le16(num_buckets);
+ }
+
ocfs2_xattr_bucket_journal_dirty(handle, args->new_bucket);
ret = ocfs2_reflink_xattr_header(handle, args->reflink,
}
ocfs2_xattr_bucket_journal_dirty(handle, args->new_bucket);
+
ocfs2_xattr_bucket_relse(args->old_bucket);
ocfs2_xattr_bucket_relse(args->new_bucket);
}
ocfs2_xattr_bucket_relse(args->new_bucket);
return ret;
}
+
+static int ocfs2_reflink_xattr_buckets(handle_t *handle,
+ struct inode *inode,
+ struct ocfs2_reflink_xattr_tree_args *args,
+ struct ocfs2_extent_tree *et,
+ struct ocfs2_alloc_context *meta_ac,
+ struct ocfs2_alloc_context *data_ac,
+ u64 blkno, u32 cpos, u32 len)
+{
+ int ret, first_inserted = 0;
+ u32 p_cluster, num_clusters, reflink_cpos = 0;
+ u64 new_blkno;
+ unsigned int num_buckets, reflink_buckets;
+ unsigned int bpc =
+ ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb));
+
+ ret = ocfs2_read_xattr_bucket(args->old_bucket, blkno);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ num_buckets = le16_to_cpu(bucket_xh(args->old_bucket)->xh_num_buckets);
+ ocfs2_xattr_bucket_relse(args->old_bucket);
+
+ while (len && num_buckets) {
+ ret = ocfs2_claim_clusters(handle, data_ac,
+ 1, &p_cluster, &num_clusters);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ new_blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+ reflink_buckets = min(num_buckets, bpc * num_clusters);
+
+ ret = ocfs2_reflink_xattr_bucket(handle, blkno,
+ new_blkno, num_clusters,
+ &reflink_cpos, reflink_buckets,
+ meta_ac, data_ac, args);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * For the 1st allocated cluster, we make it use the same cpos
+ * so that the xattr tree looks the same as the original one
+ * in the most case.
+ */
+ if (!first_inserted) {
+ reflink_cpos = cpos;
+ first_inserted = 1;
+ }
+ ret = ocfs2_insert_extent(handle, et, reflink_cpos, new_blkno,
+ num_clusters, 0, meta_ac);
+ if (ret)
+ mlog_errno(ret);
+
+ mlog(0, "insert new xattr extent rec start %llu len %u to %u\n",
+ (unsigned long long)new_blkno, num_clusters, reflink_cpos);
+
+ len -= num_clusters;
+ blkno += ocfs2_clusters_to_blocks(inode->i_sb, num_clusters);
+ num_buckets -= reflink_buckets;
+ }
+out:
+ return ret;
+}
+
/*
* Create the same xattr extent record in the new inode's xattr tree.
*/
void *para)
{
int ret, credits = 0;
- u32 p_cluster, num_clusters;
- u64 new_blkno;
handle_t *handle;
struct ocfs2_reflink_xattr_tree_args *args =
(struct ocfs2_reflink_xattr_tree_args *)para;
struct ocfs2_alloc_context *data_ac = NULL;
struct ocfs2_extent_tree et;
+ mlog(0, "reflink xattr buckets %llu len %u\n",
+ (unsigned long long)blkno, len);
+
ocfs2_init_xattr_tree_extent_tree(&et,
INODE_CACHE(args->reflink->new_inode),
args->new_blk_bh);
goto out;
}
- ret = ocfs2_claim_clusters(handle, data_ac,
- len, &p_cluster, &num_clusters);
- if (ret) {
- mlog_errno(ret);
- goto out_commit;
- }
-
- new_blkno = ocfs2_clusters_to_blocks(osb->sb, p_cluster);
-
- mlog(0, "reflink xattr buckets %llu to %llu, len %u\n",
- (unsigned long long)blkno, (unsigned long long)new_blkno, len);
- ret = ocfs2_reflink_xattr_buckets(handle, blkno, new_blkno, len,
- meta_ac, data_ac, args);
- if (ret) {
- mlog_errno(ret);
- goto out_commit;
- }
-
- mlog(0, "insert new xattr extent rec start %llu len %u to %u\n",
- (unsigned long long)new_blkno, len, cpos);
- ret = ocfs2_insert_extent(handle, &et, cpos, new_blkno,
- len, 0, meta_ac);
+ ret = ocfs2_reflink_xattr_buckets(handle, inode, args, &et,
+ meta_ac, data_ac,
+ blkno, cpos, len);
if (ret)
mlog_errno(ret);
-out_commit:
ocfs2_commit_trans(osb, handle);
out:
} *label;
unsigned char *data;
Sector sect;
+ sector_t labelsect;
res = 0;
blocksize = bdev_logical_block_size(bdev);
ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo) != 0)
goto out_freeall;
+ /*
+ * Special case for FBA disks: label sector does not depend on
+ * blocksize.
+ */
+ if ((info->cu_type == 0x6310 && info->dev_type == 0x9336) ||
+ (info->cu_type == 0x3880 && info->dev_type == 0x3370))
+ labelsect = info->label_block;
+ else
+ labelsect = info->label_block * (blocksize >> 9);
+
/*
* Get volume label, extract name and type.
*/
- data = read_part_sector(state, info->label_block*(blocksize/512),
- §);
+ data = read_part_sector(state, labelsect, §);
if (data == NULL)
goto out_readerr;
* This is called from kswapd when we think we need some
* more memory
*/
-static int shrink_dqcache_memory(int nr, gfp_t gfp_mask)
+static int shrink_dqcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask)
{
if (nr) {
spin_lock(&dq_list_lock);
struct sysfs_dirent *target_sd = NULL;
struct sysfs_dirent *sd = NULL;
struct sysfs_addrm_cxt acxt;
+ enum kobj_ns_type ns_type;
int error;
BUG_ON(!name);
if (!sd)
goto out_put;
- if (sysfs_ns_type(parent_sd))
+ ns_type = sysfs_ns_type(parent_sd);
+ if (ns_type)
sd->s_ns = target->ktype->namespace(target);
sd->s_symlink.target_sd = target_sd;
target_sd = NULL; /* reference is now owned by the symlink */
sysfs_addrm_start(&acxt, parent_sd);
- if (warn)
- error = sysfs_add_one(&acxt, sd);
- else
- error = __sysfs_add_one(&acxt, sd);
+ /* Symlinks must be between directories with the same ns_type */
+ if (!ns_type ||
+ (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) {
+ if (warn)
+ error = sysfs_add_one(&acxt, sd);
+ else
+ error = __sysfs_add_one(&acxt, sd);
+ } else {
+ error = -EINVAL;
+ WARN(1, KERN_WARNING
+ "sysfs: symlink across ns_types %s/%s -> %s/%s\n",
+ parent_sd->s_name,
+ sd->s_name,
+ sd->s_symlink.target_sd->s_parent->s_name,
+ sd->s_symlink.target_sd->s_name);
+ }
sysfs_addrm_finish(&acxt);
if (error)
{
const void *ns = NULL;
spin_lock(&sysfs_assoc_lock);
- if (targ->sd)
+ if (targ->sd && sysfs_ns_type(kobj->sd))
ns = targ->sd->s_ns;
spin_unlock(&sysfs_assoc_lock);
sysfs_hash_and_remove(kobj->sd, ns, name);
return 0;
}
-int ubifs_shrinker(int nr, gfp_t gfp_mask)
+int ubifs_shrinker(struct shrinker *shrink, int nr, gfp_t gfp_mask)
{
int freed, contention = 0;
long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
int ubifs_tnc_end_commit(struct ubifs_info *c);
/* shrinker.c */
-int ubifs_shrinker(int nr_to_scan, gfp_t gfp_mask);
+int ubifs_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask);
/* commit.c */
int ubifs_bg_thread(void *info);
static kmem_zone_t *xfs_buf_zone;
STATIC int xfsbufd(void *);
-STATIC int xfsbufd_wakeup(int, gfp_t);
+STATIC int xfsbufd_wakeup(struct shrinker *, int, gfp_t);
STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int);
static struct shrinker xfs_buf_shake = {
.shrink = xfsbufd_wakeup,
__func__, gfp_mask);
XFS_STATS_INC(xb_page_retries);
- xfsbufd_wakeup(0, gfp_mask);
+ xfsbufd_wakeup(NULL, 0, gfp_mask);
congestion_wait(BLK_RW_ASYNC, HZ/50);
goto retry;
}
STATIC int
xfsbufd_wakeup(
+ struct shrinker *shrink,
int priority,
gfp_t mask)
{
goto out_cleanup_procfs;
vfs_initquota();
- xfs_inode_shrinker_init();
error = register_filesystem(&xfs_fs_type);
if (error)
{
vfs_exitquota();
unregister_filesystem(&xfs_fs_type);
- xfs_inode_shrinker_destroy();
xfs_sysctl_unregister();
xfs_cleanup_procfs();
xfs_buf_terminate();
return last_error;
}
+/*
+ * Select the next per-ag structure to iterate during the walk. The reclaim
+ * walk is optimised only to walk AGs with reclaimable inodes in them.
+ */
+static struct xfs_perag *
+xfs_inode_ag_iter_next_pag(
+ struct xfs_mount *mp,
+ xfs_agnumber_t *first,
+ int tag)
+{
+ struct xfs_perag *pag = NULL;
+
+ if (tag == XFS_ICI_RECLAIM_TAG) {
+ int found;
+ int ref;
+
+ spin_lock(&mp->m_perag_lock);
+ found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
+ (void **)&pag, *first, 1, tag);
+ if (found <= 0) {
+ spin_unlock(&mp->m_perag_lock);
+ return NULL;
+ }
+ *first = pag->pag_agno + 1;
+ /* open coded pag reference increment */
+ ref = atomic_inc_return(&pag->pag_ref);
+ spin_unlock(&mp->m_perag_lock);
+ trace_xfs_perag_get_reclaim(mp, pag->pag_agno, ref, _RET_IP_);
+ } else {
+ pag = xfs_perag_get(mp, *first);
+ (*first)++;
+ }
+ return pag;
+}
+
int
xfs_inode_ag_iterator(
struct xfs_mount *mp,
int exclusive,
int *nr_to_scan)
{
+ struct xfs_perag *pag;
int error = 0;
int last_error = 0;
xfs_agnumber_t ag;
int nr;
nr = nr_to_scan ? *nr_to_scan : INT_MAX;
- for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
- struct xfs_perag *pag;
-
- pag = xfs_perag_get(mp, ag);
+ ag = 0;
+ while ((pag = xfs_inode_ag_iter_next_pag(mp, &ag, tag))) {
error = xfs_inode_ag_walk(mp, pag, execute, flags, tag,
exclusive, &nr);
xfs_perag_put(pag);
radix_tree_tag_set(&pag->pag_ici_root,
XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
XFS_ICI_RECLAIM_TAG);
+
+ if (!pag->pag_ici_reclaimable) {
+ /* propagate the reclaim tag up into the perag radix tree */
+ spin_lock(&ip->i_mount->m_perag_lock);
+ radix_tree_tag_set(&ip->i_mount->m_perag_tree,
+ XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
+ XFS_ICI_RECLAIM_TAG);
+ spin_unlock(&ip->i_mount->m_perag_lock);
+ trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno,
+ -1, _RET_IP_);
+ }
pag->pag_ici_reclaimable++;
}
radix_tree_tag_clear(&pag->pag_ici_root,
XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
pag->pag_ici_reclaimable--;
+ if (!pag->pag_ici_reclaimable) {
+ /* clear the reclaim tag from the perag radix tree */
+ spin_lock(&ip->i_mount->m_perag_lock);
+ radix_tree_tag_clear(&ip->i_mount->m_perag_tree,
+ XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
+ XFS_ICI_RECLAIM_TAG);
+ spin_unlock(&ip->i_mount->m_perag_lock);
+ trace_xfs_perag_clear_reclaim(ip->i_mount, pag->pag_agno,
+ -1, _RET_IP_);
+ }
}
/*
/*
* Shrinker infrastructure.
- *
- * This is all far more complex than it needs to be. It adds a global list of
- * mounts because the shrinkers can only call a global context. We need to make
- * the shrinkers pass a context to avoid the need for global state.
*/
-static LIST_HEAD(xfs_mount_list);
-static struct rw_semaphore xfs_mount_list_lock;
-
static int
xfs_reclaim_inode_shrink(
+ struct shrinker *shrink,
int nr_to_scan,
gfp_t gfp_mask)
{
struct xfs_mount *mp;
struct xfs_perag *pag;
xfs_agnumber_t ag;
- int reclaimable = 0;
+ int reclaimable;
+ mp = container_of(shrink, struct xfs_mount, m_inode_shrink);
if (nr_to_scan) {
if (!(gfp_mask & __GFP_FS))
return -1;
- down_read(&xfs_mount_list_lock);
- list_for_each_entry(mp, &xfs_mount_list, m_mplist) {
- xfs_inode_ag_iterator(mp, xfs_reclaim_inode, 0,
+ xfs_inode_ag_iterator(mp, xfs_reclaim_inode, 0,
XFS_ICI_RECLAIM_TAG, 1, &nr_to_scan);
- if (nr_to_scan <= 0)
- break;
- }
- up_read(&xfs_mount_list_lock);
- }
+ /* if we don't exhaust the scan, don't bother coming back */
+ if (nr_to_scan > 0)
+ return -1;
+ }
- down_read(&xfs_mount_list_lock);
- list_for_each_entry(mp, &xfs_mount_list, m_mplist) {
- for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
- pag = xfs_perag_get(mp, ag);
- reclaimable += pag->pag_ici_reclaimable;
- xfs_perag_put(pag);
- }
+ reclaimable = 0;
+ ag = 0;
+ while ((pag = xfs_inode_ag_iter_next_pag(mp, &ag,
+ XFS_ICI_RECLAIM_TAG))) {
+ reclaimable += pag->pag_ici_reclaimable;
+ xfs_perag_put(pag);
}
- up_read(&xfs_mount_list_lock);
return reclaimable;
}
-static struct shrinker xfs_inode_shrinker = {
- .shrink = xfs_reclaim_inode_shrink,
- .seeks = DEFAULT_SEEKS,
-};
-
-void __init
-xfs_inode_shrinker_init(void)
-{
- init_rwsem(&xfs_mount_list_lock);
- register_shrinker(&xfs_inode_shrinker);
-}
-
-void
-xfs_inode_shrinker_destroy(void)
-{
- ASSERT(list_empty(&xfs_mount_list));
- unregister_shrinker(&xfs_inode_shrinker);
-}
-
void
xfs_inode_shrinker_register(
struct xfs_mount *mp)
{
- down_write(&xfs_mount_list_lock);
- list_add_tail(&mp->m_mplist, &xfs_mount_list);
- up_write(&xfs_mount_list_lock);
+ mp->m_inode_shrink.shrink = xfs_reclaim_inode_shrink;
+ mp->m_inode_shrink.seeks = DEFAULT_SEEKS;
+ register_shrinker(&mp->m_inode_shrink);
}
void
xfs_inode_shrinker_unregister(
struct xfs_mount *mp)
{
- down_write(&xfs_mount_list_lock);
- list_del(&mp->m_mplist);
- up_write(&xfs_mount_list_lock);
+ unregister_shrinker(&mp->m_inode_shrink);
}
int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags),
int flags, int tag, int write_lock, int *nr_to_scan);
-void xfs_inode_shrinker_init(void);
-void xfs_inode_shrinker_destroy(void);
void xfs_inode_shrinker_register(struct xfs_mount *mp);
void xfs_inode_shrinker_unregister(struct xfs_mount *mp);
unsigned long caller_ip), \
TP_ARGS(mp, agno, refcount, caller_ip))
DEFINE_PERAG_REF_EVENT(xfs_perag_get);
+DEFINE_PERAG_REF_EVENT(xfs_perag_get_reclaim);
DEFINE_PERAG_REF_EVENT(xfs_perag_put);
+DEFINE_PERAG_REF_EVENT(xfs_perag_set_reclaim);
+DEFINE_PERAG_REF_EVENT(xfs_perag_clear_reclaim);
TRACE_EVENT(xfs_attr_list_node_descend,
TP_PROTO(struct xfs_attr_list_context *ctx,
STATIC int xfs_qm_init_quotainos(xfs_mount_t *);
STATIC int xfs_qm_init_quotainfo(xfs_mount_t *);
-STATIC int xfs_qm_shake(int, gfp_t);
+STATIC int xfs_qm_shake(struct shrinker *, int, gfp_t);
static struct shrinker xfs_qm_shaker = {
.shrink = xfs_qm_shake,
*/
/* ARGSUSED */
STATIC int
-xfs_qm_shake(int nr_to_scan, gfp_t gfp_mask)
+xfs_qm_shake(
+ struct shrinker *shrink,
+ int nr_to_scan,
+ gfp_t gfp_mask)
{
int ndqused, nfree, n;
wait_queue_head_t m_wait_single_sync_task;
__int64_t m_update_flags; /* sb flags we need to update
on the next remount,rw */
- struct list_head m_mplist; /* inode shrinker mount list */
+ struct shrinker m_inode_shrink; /* inode reclaim shrinker */
} xfs_mount_t;
/*
u8 space_id;
u8 bit_width;
u8 bit_offset;
- u8 reserved;
+ u8 access_size;
u64 address;
} __attribute__ ((packed));
u32 power;
u32 usage;
u64 time;
+ u8 bm_sts_skip;
char desc[ACPI_CX_DESC_LEN];
};
/* Align . to a 8 byte boundary equals to maximum function alignment. */
#define ALIGN_FUNCTION() . = ALIGN(8)
+/*
+ * Align to a 32 byte boundary equal to the
+ * alignment gcc 4.5 uses for a struct
+ */
+#define STRUCT_ALIGN() . = ALIGN(32)
+
/* The actual configuration determine if the init/exit sections
* are handled as text/data or they can be discarded (which
* often happens at runtime)
LIKELY_PROFILE() \
BRANCH_PROFILE() \
TRACE_PRINTKS() \
+ \
+ STRUCT_ALIGN(); \
FTRACE_EVENTS() \
+ \
+ STRUCT_ALIGN(); \
TRACE_SYSCALLS()
/*
*/
#define INIT_TASK_DATA_SECTION(align) \
. = ALIGN(align); \
- .data..init_task : { \
+ .data..init_task : AT(ADDR(.data..init_task) - LOAD_OFFSET) { \
INIT_TASK_DATA(align) \
}
#ifdef CONFIG_PM_SLEEP
void __init acpi_no_s4_hw_signature(void);
void __init acpi_old_suspend_ordering(void);
-void __init acpi_s4_no_nvs(void);
+void __init acpi_nvs_nosave(void);
#endif /* CONFIG_PM_SLEEP */
struct acpi_osc_context {
static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
struct apertures_struct *a = kzalloc(sizeof(struct apertures_struct)
+ max_num * sizeof(struct aperture), GFP_KERNEL);
+ if (!a)
+ return NULL;
a->count = max_num;
return a;
}
(rcu_dereference_check((fdtfd), \
rcu_read_lock_held() || \
lockdep_is_held(&(files)->file_lock) || \
- atomic_read(&(files)->count) == 1))
+ atomic_read(&(files)->count) == 1 || \
+ rcu_my_thread_group_empty()))
#define files_fdtable(files) \
(rcu_dereference_check_fdtable((files), (files)->fdt))
}
}
+extern void macvlan_common_setup(struct net_device *dev);
+
extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[],
int (*receive)(struct sk_buff *skb),
struct jbd2_buffer_trigger_type {
/*
- * Fired just before a buffer is written to the journal.
- * mapped_data is a mapped buffer that is the frozen data for
- * commit.
+ * Fired a the moment data to write to the journal are known to be
+ * stable - so either at the moment b_frozen_data is created or just
+ * before a buffer is written to the journal. mapped_data is a mapped
+ * buffer that is the frozen data for commit.
*/
- void (*t_commit)(struct jbd2_buffer_trigger_type *type,
+ void (*t_frozen)(struct jbd2_buffer_trigger_type *type,
struct buffer_head *bh, void *mapped_data,
size_t size);
struct buffer_head *bh);
};
-extern void jbd2_buffer_commit_trigger(struct journal_head *jh,
+extern void jbd2_buffer_frozen_trigger(struct journal_head *jh,
void *mapped_data,
struct jbd2_buffer_trigger_type *triggers);
extern void jbd2_buffer_abort_trigger(struct journal_head *jh,
* querying the cache size, so a fastpath for that case is appropriate.
*/
struct shrinker {
- int (*shrink)(int nr_to_scan, gfp_t gfp_mask);
+ int (*shrink)(struct shrinker *, int nr_to_scan, gfp_t gfp_mask);
int seeks; /* seeks to recreate an obj */
/* These are for internal use */
*/
unsigned int irq;
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
+ resource_size_t fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */
/* These fields are used by common fixups */
unsigned int transparent:1; /* Transparent PCI bridge */
*/
void handle_sysrq(int key, struct tty_struct *tty);
+void __handle_sysrq(int key, struct tty_struct *tty, int check_mask);
int register_sysrq_key(int key, struct sysrq_key_op *op);
int unregister_sysrq_key(int key, struct sysrq_key_op *op);
struct sysrq_key_op *__sysrq_get_key_op(int key);
*/
#ifndef LINUX_VGA_H
+#define LINUX_VGA_H
#include <asm/vga.h>
X##_e -= (_FP_W_TYPE_SIZE - rsize); \
X##_e = rsize - X##_e - 1; \
\
- if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \
+ if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs <= X##_e) \
__FP_FRAC_SRS_1(ur_, (X##_e - _FP_WFRACBITS_##fs + 1), rsize);\
_FP_FRAC_DISASSEMBLE_##wc(X, ur_, rsize); \
if ((_FP_WFRACBITS_##fs - X##_e - 1) > 0) \
static inline int sk_tx_queue_get(const struct sock *sk)
{
- return sk->sk_tx_queue_mapping;
-}
-
-static inline bool sk_tx_queue_recorded(const struct sock *sk)
-{
- return (sk && sk->sk_tx_queue_mapping >= 0);
+ return sk ? sk->sk_tx_queue_mapping : -1;
}
static inline void sk_set_socket(struct sock *sk, struct socket *sock)
int tcfm_ifindex;
int tcfm_ok_push;
struct net_device *tcfm_dev;
+ struct list_head tcfm_list;
};
#define to_mirred(pc) \
container_of(pc, struct tcf_mirred, common)
return un;
}
+
+/**
+ * get_queue_result - Retrieve the result code from sem_queue
+ * @q: Pointer to queue structure
+ *
+ * Retrieve the return code from the pending queue. If IN_WAKEUP is found in
+ * q->status, then we must loop until the value is replaced with the final
+ * value: This may happen if a task is woken up by an unrelated event (e.g.
+ * signal) and in parallel the task is woken up by another task because it got
+ * the requested semaphores.
+ *
+ * The function can be called with or without holding the semaphore spinlock.
+ */
+static int get_queue_result(struct sem_queue *q)
+{
+ int error;
+
+ error = q->status;
+ while (unlikely(error == IN_WAKEUP)) {
+ cpu_relax();
+ error = q->status;
+ }
+
+ return error;
+}
+
+
SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
unsigned, nsops, const struct timespec __user *, timeout)
{
else
schedule();
- error = queue.status;
- while(unlikely(error == IN_WAKEUP)) {
- cpu_relax();
- error = queue.status;
- }
+ error = get_queue_result(&queue);
if (error != -EINTR) {
/* fast path: update_queue already obtained all requested
- * resources */
+ * resources.
+ * Perform a smp_mb(): User space could assume that semop()
+ * is a memory barrier: Without the mb(), the cpu could
+ * speculatively read in user space stale data that was
+ * overwritten by the previous owner of the semaphore.
+ */
+ smp_mb();
+
goto out_free;
}
goto out_free;
}
+ error = get_queue_result(&queue);
+
/*
* If queue.status != -EINTR we are woken up by another process
*/
- error = queue.status;
+
if (error != -EINTR) {
goto out_unlock_free;
}
if (dbg_kdb_mode) {
kgdb_connected = 1;
error = kdb_stub(ks);
+ kgdb_connected = 0;
} else {
error = gdb_serial_stub(ks);
}
if (error == DBG_PASS_EVENT) {
dbg_kdb_mode = !dbg_kdb_mode;
- kgdb_connected = 0;
} else if (error == DBG_SWITCH_CPU_EVENT) {
dbg_cpu_switch(cpu, dbg_switch_cpu);
goto cpu_loop;
switch (remcom_in_buffer[1]) {
case 's':
case 'f':
- if (memcmp(remcom_in_buffer + 2, "ThreadInfo", 10)) {
- error_packet(remcom_out_buffer, -EINVAL);
+ if (memcmp(remcom_in_buffer + 2, "ThreadInfo", 10))
break;
- }
i = 0;
remcom_out_buffer[0] = 'm';
pack_threadid(remcom_out_buffer + 2, thref);
break;
case 'T':
- if (memcmp(remcom_in_buffer + 1, "ThreadExtraInfo,", 16)) {
- error_packet(remcom_out_buffer, -EINVAL);
+ if (memcmp(remcom_in_buffer + 1, "ThreadExtraInfo,", 16))
break;
- }
+
ks->threadid = 0;
ptr = remcom_in_buffer + 17;
kgdb_hex2long(&ptr, &ks->threadid);
{
if (argc != 1)
return KDB_ARGCOUNT;
- sysrq_toggle_support(1);
kdb_trap_printk++;
- handle_sysrq(*argv[1], NULL);
+ __handle_sysrq(*argv[1], NULL, 0);
kdb_trap_printk--;
return 0;
kdb_printf(" (Loading)");
else
kdb_printf(" (Live)");
+ kdb_printf(" 0x%p", mod->module_core);
#ifdef CONFIG_MODULE_UNLOAD
{
while (va) {
char buf[80];
+ if (KDB_FLAG(CMD_INTERRUPT))
+ return 0;
+
sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va);
diag = kdb_parse(buf);
if (diag)
#include <linux/bootmem.h>
#include <linux/mm.h>
#include <linux/early_res.h>
+#include <linux/slab.h>
+#include <linux/kmemleak.h>
/*
* Early reserved memory areas.
struct early_res *r;
int i;
+ kmemleak_free_part(__va(start), end - start);
+
i = find_overlapped_early(start, end);
r = &early_res[i];
if (i >= max_early_res || r->end != end || r->start != start)
struct early_res *r;
int i;
+ kmemleak_free_part(__va(start), end - start);
+
if (start == end)
return;
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
- ddebug_remove_module(mod->name);
free_module(mod);
return 0;
remove_sect_attrs(mod);
mod_kobject_remove(mod);
+ /* Remove dynamic debug info */
+ ddebug_remove_module(mod->name);
+
/* Arch-specific cleanup. */
module_arch_cleanup(mod);
void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size,
unsigned long align, unsigned long goal)
{
+ void *ptr;
+
if (WARN_ON_ONCE(slab_is_available()))
return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
#ifdef CONFIG_NO_BOOTMEM
- return __alloc_memory_core_early(pgdat->node_id, size, align,
+ ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+ goal, -1ULL);
+ if (ptr)
+ return ptr;
+
+ ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
goal, -1ULL);
#else
- return ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0);
+ ptr = ___alloc_bootmem_node(pgdat->bdata, size, align, goal, 0);
#endif
+
+ return ptr;
}
void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size,
void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size,
unsigned long align, unsigned long goal)
{
+ void *ptr;
+
if (WARN_ON_ONCE(slab_is_available()))
return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id);
#ifdef CONFIG_NO_BOOTMEM
- return __alloc_memory_core_early(pgdat->node_id, size, align,
+ ptr = __alloc_memory_core_early(pgdat->node_id, size, align,
+ goal, ARCH_LOW_ADDRESS_LIMIT);
+ if (ptr)
+ return ptr;
+ ptr = __alloc_memory_core_early(MAX_NUMNODES, size, align,
goal, ARCH_LOW_ADDRESS_LIMIT);
#else
- return ___alloc_bootmem_node(pgdat->bdata, size, align,
+ ptr = ___alloc_bootmem_node(pgdat->bdata, size, align,
goal, ARCH_LOW_ADDRESS_LIMIT);
#endif
+ return ptr;
}
int i;
void *ptr;
+ if (limit > get_max_mapped())
+ limit = get_max_mapped();
+
/* need to go over early_node_map to find out good range for node */
for_each_active_range_index_in_nid(i, nid) {
u64 addr;
ptr = phys_to_virt(addr);
memset(ptr, 0, size);
reserve_early_without_check(addr, addr + size, "BOOTMEM");
+ /*
+ * The min_count is set to 0 so that bootmem allocated blocks
+ * are never reported as leaks.
+ */
+ kmemleak_alloc(ptr, size, 0, 0);
return ptr;
}
#include <linux/vmalloc.h>
#include <linux/cgroup.h>
#include <linux/swapops.h>
+#include <linux/kmemleak.h>
static void __meminit
__init_page_cgroup(struct page_cgroup *pc, unsigned long pfn)
if (!base)
base = vmalloc(table_size);
}
+ /*
+ * The value stored in section->page_cgroup is (base - pfn)
+ * and it does not point to the memory block allocated above,
+ * causing kmemleak false positives.
+ */
+ kmemleak_not_leak(base);
} else {
/*
* We don't have to allocate page_cgroup again, but
list_for_each_entry(shrinker, &shrinker_list, list) {
unsigned long long delta;
unsigned long total_scan;
- unsigned long max_pass = (*shrinker->shrink)(0, gfp_mask);
+ unsigned long max_pass;
+ max_pass = (*shrinker->shrink)(shrinker, 0, gfp_mask);
delta = (4 * scanned) / shrinker->seeks;
delta *= max_pass;
do_div(delta, lru_pages + 1);
int shrink_ret;
int nr_before;
- nr_before = (*shrinker->shrink)(0, gfp_mask);
- shrink_ret = (*shrinker->shrink)(this_scan, gfp_mask);
+ nr_before = (*shrinker->shrink)(shrinker, 0, gfp_mask);
+ shrink_ret = (*shrinker->shrink)(shrinker, this_scan,
+ gfp_mask);
if (shrink_ret == -1)
break;
if (shrink_ret < nr_before)
static void handle_write_error(struct address_space *mapping,
struct page *page, int error)
{
- lock_page(page);
+ lock_page_nosync(page);
if (page_mapping(page) == mapping)
mapping_set_error(mapping, error);
unlock_page(page);
acl->sec_level = sec_level;
acl->auth_type = auth_type;
hci_acl_connect(acl);
+ } else {
+ if (acl->sec_level < sec_level)
+ acl->sec_level = sec_level;
+ if (acl->auth_type < auth_type)
+ acl->auth_type = auth_type;
}
if (type == ACL_LINK)
if (conn) {
if (!ev->status)
conn->link_mode |= HCI_LM_AUTH;
+ else
+ conn->sec_level = BT_SECURITY_LOW;
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
l2cap_send_sframe(pi, control);
}
+static inline int __l2cap_no_conn_pending(struct sock *sk)
+{
+ return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND);
+}
+
static void l2cap_do_start(struct sock *sk)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
return;
- if (l2cap_check_security(sk)) {
+ if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) {
struct l2cap_conn_req req;
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
}
if (sk->sk_state == BT_CONNECT) {
- if (l2cap_check_security(sk)) {
+ if (l2cap_check_security(sk) &&
+ __l2cap_no_conn_pending(sk)) {
struct l2cap_conn_req req;
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
l2cap_pi(sk)->ident = 0;
l2cap_pi(sk)->dcid = dcid;
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
-
l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
req.psm = l2cap_pi(sk)->psm;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
+ l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
return count != 0 && ret;
}
-static void br_poll_controller(struct net_device *br_dev)
-{
- struct netpoll *np = br_dev->npinfo->netpoll;
-
- if (np->real_dev != br_dev)
- netpoll_poll_dev(np->real_dev);
-}
-
void br_netpoll_cleanup(struct net_device *dev)
{
struct net_bridge *br = netdev_priv(dev);
.ndo_do_ioctl = br_dev_ioctl,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_netpoll_cleanup = br_netpoll_cleanup,
- .ndo_poll_controller = br_poll_controller,
#endif
};
kfree_skb(skb);
else {
skb_push(skb, ETH_HLEN);
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
- if (unlikely(skb->dev->priv_flags & IFF_IN_NETPOLL)) {
- netpoll_send_skb(skb->dev->npinfo->netpoll, skb);
- skb->dev->priv_flags &= ~IFF_IN_NETPOLL;
- } else
-#endif
- dev_queue_xmit(skb);
+ dev_queue_xmit(skb);
}
}
static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
{
-#ifdef CONFIG_NET_POLL_CONTROLLER
- struct net_bridge *br = to->br;
- if (unlikely(br->dev->priv_flags & IFF_IN_NETPOLL)) {
- struct netpoll *np;
- to->dev->npinfo = skb->dev->npinfo;
- np = skb->dev->npinfo->netpoll;
- np->real_dev = np->dev = to->dev;
- to->dev->priv_flags |= IFF_IN_NETPOLL;
- }
-#endif
skb->dev = to->dev;
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
br_forward_finish);
-#ifdef CONFIG_NET_POLL_CONTROLLER
- if (skb->dev->npinfo)
- skb->dev->npinfo->netpoll->dev = br->dev;
-#endif
}
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
{
skb_orphan(skb);
+ nf_reset(skb);
if (!(dev->flags & IFF_UP) ||
(skb->len > (dev->mtu + dev->hard_header_len))) {
*/
static inline void skb_orphan_try(struct sk_buff *skb)
{
- if (!skb_tx(skb)->flags)
+ struct sock *sk = skb->sk;
+
+ if (sk && !skb_tx(skb)->flags) {
+ /* skb_tx_hash() wont be able to get sk.
+ * We copy sk_hash into skb->rxhash
+ */
+ if (!skb->rxhash)
+ skb->rxhash = sk->sk_hash;
skb_orphan(skb);
+ }
}
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
if (skb->sk && skb->sk->sk_hash)
hash = skb->sk->sk_hash;
else
- hash = (__force u16) skb->protocol;
-
+ hash = (__force u16) skb->protocol ^ skb->rxhash;
hash = jhash_1word(hash, hashrnd);
return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
static struct netdev_queue *dev_pick_tx(struct net_device *dev,
struct sk_buff *skb)
{
- u16 queue_index;
+ int queue_index;
struct sock *sk = skb->sk;
- if (sk_tx_queue_recorded(sk)) {
- queue_index = sk_tx_queue_get(sk);
- } else {
+ queue_index = sk_tx_queue_get(sk);
+ if (queue_index < 0) {
const struct net_device_ops *ops = dev->netdev_ops;
if (ops->ndo_select_queue) {
{
struct hh_cache *hh;
void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *)
- = neigh->dev->header_ops->cache_update;
+ = NULL;
+
+ if (neigh->dev->header_ops)
+ update = neigh->dev->header_ops->cache_update;
if (update) {
for (hh = neigh->hh; hh; hh = hh->hh_next) {
skb->network_header += off;
if (skb_mac_header_was_set(skb))
skb->mac_header += off;
- skb->csum_start += nhead;
+ /* Only adjust this if it actually is csum_start rather than csum */
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
+ skb->csum_start += nhead;
skb->cloned = 0;
skb->hdr_len = 0;
skb->nohdr = 0;
copy_skb_header(n, skb);
off = newheadroom - oldheadroom;
- n->csum_start += off;
+ if (n->ip_summed == CHECKSUM_PARTIAL)
+ n->csum_start += off;
#ifdef NET_SKBUFF_DATA_USES_OFFSET
n->transport_header += off;
n->network_header += off;
menuconfig NET_DSA
bool "Distributed Switch Architecture support"
default n
- depends on EXPERIMENTAL && !S390
+ depends on EXPERIMENTAL && NET_ETHERNET && !S390
select PHYLIB
---help---
This allows you to use hardware switch chips that use
int err;
err = ipmr_fib_lookup(net, &fl, &mrt);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb(skb);
return err;
+ }
read_lock(&mrt_lock);
dev->stats.tx_bytes += skb->len;
goto dont_forward;
err = ipmr_fib_lookup(net, &skb_rtable(skb)->fl, &mrt);
- if (err < 0)
+ if (err < 0) {
+ kfree_skb(skb);
return err;
+ }
if (!local) {
if (IPCB(skb)->opt.router_alert) {
ssize_t spliced;
int ret;
+ sock_rps_record_flow(sk);
/*
* We can't seek on a socket input
*/
int mib_idx;
int fwd_rexmitting = 0;
+ if (!tp->packets_out)
+ return;
+
if (!tp->lost_out)
tp->retransmit_high = tp->snd_una;
idev = ipv6_find_idev(dev);
if (!idev)
- return NULL;
+ return ERR_PTR(-ENOBUFS);
+
+ if (idev->cnf.disable_ipv6)
+ return ERR_PTR(-EACCES);
/* Add default multicast route */
addrconf_add_mroute(dev);
if (!dev)
return -ENODEV;
- if ((idev = addrconf_add_dev(dev)) == NULL)
- return -ENOBUFS;
+ idev = addrconf_add_dev(dev);
+ if (IS_ERR(idev))
+ return PTR_ERR(idev);
scope = ipv6_addr_scope(pfx);
}
idev = addrconf_add_dev(dev);
- if (idev == NULL)
+ if (IS_ERR(idev))
return;
memset(&addr, 0, sizeof(struct in6_addr));
ASSERT_RTNL();
idev = addrconf_add_dev(dev);
- if (!idev) {
+ if (IS_ERR(idev)) {
printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");
return;
}
static int mip6_rthdr_input(struct xfrm_state *x, struct sk_buff *skb)
{
+ struct ipv6hdr *iph = ipv6_hdr(skb);
struct rt2_hdr *rt2 = (struct rt2_hdr *)skb->data;
int err = rt2->rt_hdr.nexthdr;
spin_lock(&x->lock);
- if (!ipv6_addr_equal(&rt2->addr, (struct in6_addr *)x->coaddr) &&
+ if (!ipv6_addr_equal(&iph->daddr, (struct in6_addr *)x->coaddr) &&
!ipv6_addr_any((struct in6_addr *)x->coaddr))
err = -ENOENT;
spin_unlock(&x->lock);
skb->dev = sta->sdata->dev;
skb->protocol = eth_type_trans(skb, sta->sdata->dev);
memset(skb->cb, 0, sizeof(skb->cb));
- netif_rx(skb);
+ netif_rx_ni(skb);
}
static void sta_apply_parameters(struct ieee80211_local *local,
newsk = NULL;
goto out;
}
+ kfree_skb(oskb);
sock_hold(sk);
pep_sk(newsk)->listener = sk;
static struct tcf_common *tcf_mirred_ht[MIRRED_TAB_MASK + 1];
static u32 mirred_idx_gen;
static DEFINE_RWLOCK(mirred_lock);
+static LIST_HEAD(mirred_list);
static struct tcf_hashinfo mirred_hash_info = {
.htab = tcf_mirred_ht,
m->tcf_bindcnt--;
m->tcf_refcnt--;
if(!m->tcf_bindcnt && m->tcf_refcnt <= 0) {
- dev_put(m->tcfm_dev);
+ list_del(&m->tcfm_list);
+ if (m->tcfm_dev)
+ dev_put(m->tcfm_dev);
tcf_hash_destroy(&m->common, &mirred_hash_info);
return 1;
}
m->tcfm_ok_push = ok_push;
}
spin_unlock_bh(&m->tcf_lock);
- if (ret == ACT_P_CREATED)
+ if (ret == ACT_P_CREATED) {
+ list_add(&m->tcfm_list, &mirred_list);
tcf_hash_insert(pc, &mirred_hash_info);
+ }
return ret;
}
m->tcf_tm.lastuse = jiffies;
dev = m->tcfm_dev;
+ if (!dev) {
+ printk_once(KERN_NOTICE "tc mirred: target device is gone\n");
+ goto out;
+ }
+
if (!(dev->flags & IFF_UP)) {
if (net_ratelimit())
- pr_notice("tc mirred to Houston: device %s is gone!\n",
+ pr_notice("tc mirred to Houston: device %s is down\n",
dev->name);
goto out;
}
return -1;
}
+static int mirred_device_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+ struct tcf_mirred *m;
+
+ if (event == NETDEV_UNREGISTER)
+ list_for_each_entry(m, &mirred_list, tcfm_list) {
+ if (m->tcfm_dev == dev) {
+ dev_put(dev);
+ m->tcfm_dev = NULL;
+ }
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block mirred_device_notifier = {
+ .notifier_call = mirred_device_event,
+};
+
+
static struct tc_action_ops act_mirred_ops = {
.kind = "mirred",
.hinfo = &mirred_hash_info,
static int __init mirred_init_module(void)
{
+ int err = register_netdevice_notifier(&mirred_device_notifier);
+ if (err)
+ return err;
+
pr_info("Mirror/redirect action on\n");
return tcf_register_action(&act_mirred_ops);
}
static void __exit mirred_cleanup_module(void)
{
+ unregister_netdevice_notifier(&mirred_device_notifier);
tcf_unregister_action(&act_mirred_ops);
}
{
struct icmphdr *icmph;
- if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph)))
+ if (!pskb_may_pull(skb, ihl + sizeof(*icmph)))
goto drop;
icmph = (void *)(skb_network_header(skb) + ihl);
(icmph->type != ICMP_PARAMETERPROB))
break;
+ if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph)))
+ goto drop;
+
iph = (void *)(icmph + 1);
if (egress)
addr = iph->daddr;
* Run memory cache shrinker.
*/
static int
-rpcauth_cache_shrinker(int nr_to_scan, gfp_t gfp_mask)
+rpcauth_cache_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
{
LIST_HEAD(free);
int res;
/* Try to instantiate a bundle */
err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family);
- if (err < 0) {
- if (err != -EAGAIN)
+ if (err <= 0) {
+ if (err != 0 && err != -EAGAIN)
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR);
return ERR_PTR(err);
}
goto make_dummy_bundle;
dst_hold(&xdst->u.dst);
return oldflo;
+ } else if (new_xdst == NULL) {
+ num_xfrms = 0;
+ if (oldflo == NULL)
+ goto make_dummy_bundle;
+ xdst->num_xfrms = 0;
+ dst_hold(&xdst->u.dst);
+ return oldflo;
}
/* Kill the previous bundle */
xfrm_pols_put(pols, num_pols);
err = PTR_ERR(xdst);
goto dropdst;
+ } else if (xdst == NULL) {
+ num_xfrms = 0;
+ drop_pols = num_pols;
+ goto no_transform;
}
spin_lock_bh(&xfrm_policy_sk_bundle_lock);
int len = get_line_length(line);
strncpy(tmp, line, min(len, x));
tmp[len] = '\0';
- mvwprintw(win, i, 0, tmp);
+ mvwprintw(win, i, 0, "%s", tmp);
}
}
fi
$(MAKE) clean
$(PREV) ln -sf $(srctree) $(KERNELPATH)
- $(CONFIG_SHELL) $(srctree)/scripts/setlocalversion --scm-only > $(objtree)/.scmversion
+ $(CONFIG_SHELL) $(srctree)/scripts/setlocalversion --save-scmversion
$(PREV) tar -cz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/.
$(PREV) rm $(KERNELPATH)
rm -f $(objtree)/.scmversion
#
usage() {
- echo "Usage: $0 [--scm-only] [srctree]" >&2
+ echo "Usage: $0 [--save-scmversion] [srctree]" >&2
exit 1
}
scm_only=false
srctree=.
-if test "$1" = "--scm-only"; then
+if test "$1" = "--save-scmversion"; then
scm_only=true
shift
fi
scm_version()
{
- local short=false
+ local short
+ short=false
cd "$srctree"
if test -e .scmversion; then
- cat "$_"
+ cat .scmversion
return
fi
if test "$1" = "--short"; then
}
if $scm_only; then
- scm_version
+ if test ! -e .scmversion; then
+ res=$(scm_version)
+ echo "$res" >.scmversion
+ fi
exit
fi
if test -e include/config/auto.conf; then
- source "$_"
+ . include/config/auto.conf
else
echo "Error: kernelrelease not valid - run 'make prepare' to update it"
exit 1
};
EXPORT_SYMBOL(au1xpsc_i2s_dai);
-static int __init au1xpsc_i2s_drvprobe(struct platform_device *pdev)
+static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
{
struct resource *r;
unsigned long sel;
config SND_SOC_WM_HUBS
tristate
- default y if SND_SOC_WM8993=y
- default m if SND_SOC_WM8993=m
+ default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
+ default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m
config SND_SOC_AC97_CODEC
tristate
goto err_codec;
}
+ return 0;
+
err_codec:
snd_soc_unregister_codec(codec);
err:
static const struct snd_soc_dapm_widget wm8776_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AUX"),
-SND_SOC_DAPM_INPUT("AUX"),
SND_SOC_DAPM_INPUT("AIN1"),
SND_SOC_DAPM_INPUT("AIN2"),
ret = snd_soc_register_dai(&wm8988_dai);
if (ret != 0) {
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
- snd_soc_unregister_codec(codec);
goto err_codec;
}
/* clock inversion (CKG2) */
data = 0;
- switch (SH_FSI_INVERSION_MASK & flags) {
- case SH_FSI_LRM_INV:
- data = 1 << 12;
- break;
- case SH_FSI_BRM_INV:
- data = 1 << 8;
- break;
- case SH_FSI_LRS_INV:
- data = 1 << 4;
- break;
- case SH_FSI_BRS_INV:
- data = 1 << 0;
- break;
- }
+ if (SH_FSI_LRM_INV & flags)
+ data |= 1 << 12;
+ if (SH_FSI_BRM_INV & flags)
+ data |= 1 << 8;
+ if (SH_FSI_LRS_INV & flags)
+ data |= 1 << 4;
+ if (SH_FSI_BRS_INV & flags)
+ data |= 1 << 0;
+
fsi_reg_write(fsi, CKG2, data);
/* do fmt, di fmt */
break;
case SH_FSI_FMT_TDM:
msg = "TDM";
- data = CR_FMT(CR_TDM) | (fsi->chan - 1);
fsi->chan = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
+ data = CR_FMT(CR_TDM) | (fsi->chan - 1);
break;
case SH_FSI_FMT_TDM_DELAY:
msg = "TDM Delay";
- data = CR_FMT(CR_TDM_D) | (fsi->chan - 1);
fsi->chan = is_play ?
SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags);
+ data = CR_FMT(CR_TDM_D) | (fsi->chan - 1);
break;
default:
dev_err(dai->dev, "unknown format.\n");
ifdef NO_DEMANGLE
BASIC_CFLAGS += -DNO_DEMANGLE
-else ifdef HAVE_CPLUS_DEMANGLE
- EXTLIBS += -liberty
- BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
else
- has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
-
- ifeq ($(has_bfd),y)
- EXTLIBS += -lbfd
+ ifdef HAVE_CPLUS_DEMANGLE
+ EXTLIBS += -liberty
+ BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
else
- has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
- ifeq ($(has_bfd_iberty),y)
- EXTLIBS += -lbfd -liberty
+ has_bfd := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd "$(QUIET_STDERR)" && echo y")
+
+ ifeq ($(has_bfd),y)
+ EXTLIBS += -lbfd
else
- has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
- ifeq ($(has_bfd_iberty_z),y)
- EXTLIBS += -lbfd -liberty -lz
+ has_bfd_iberty := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty "$(QUIET_STDERR)" && echo y")
+ ifeq ($(has_bfd_iberty),y)
+ EXTLIBS += -lbfd -liberty
else
- has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
- ifeq ($(has_cplus_demangle),y)
- EXTLIBS += -liberty
- BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
+ has_bfd_iberty_z := $(shell sh -c "(echo '\#include <bfd.h>'; echo 'int main(void) { bfd_demangle(0, 0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd -liberty -lz "$(QUIET_STDERR)" && echo y")
+ ifeq ($(has_bfd_iberty_z),y)
+ EXTLIBS += -lbfd -liberty -lz
else
- msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
- BASIC_CFLAGS += -DNO_DEMANGLE
+ has_cplus_demangle := $(shell sh -c "(echo 'extern char *cplus_demangle(const char *, int);'; echo 'int main(void) { cplus_demangle(0, 0); return 0; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) -liberty "$(QUIET_STDERR)" && echo y")
+ ifeq ($(has_cplus_demangle),y)
+ EXTLIBS += -liberty
+ BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
+ else
+ msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
+ BASIC_CFLAGS += -DNO_DEMANGLE
+ endif
endif
endif
endif
--- /dev/null
+ifndef NO_DWARF
+PERF_HAVE_DWARF_REGS := 1
+LIB_OBJS += $(OUTPUT)arch/$(ARCH)/util/dwarf-regs.o
+endif
--- /dev/null
+/*
+ * Mapping of DWARF debug register numbers into register names.
+ *
+ * Copyright (C) 2010 David S. Miller <davem@davemloft.net>
+ *
+ * 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.
+ */
+
+#include <libio.h>
+#include <dwarf-regs.h>
+
+#define SPARC_MAX_REGS 96
+
+const char *sparc_regs_table[SPARC_MAX_REGS] = {
+ "%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7",
+ "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7",
+ "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7",
+ "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7",
+ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7",
+ "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15",
+ "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23",
+ "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31",
+ "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39",
+ "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47",
+ "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55",
+ "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63",
+};
+
+/**
+ * get_arch_regstr() - lookup register name from it's DWARF register number
+ * @n: the DWARF register number
+ *
+ * get_arch_regstr() returns the name of the register in struct
+ * regdwarfnum_table from it's DWARF register number. If the register is not
+ * found in the table, this returns NULL;
+ */
+const char *get_arch_regstr(unsigned int n)
+{
+ return (n <= SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL;
+}
u64 session_total)
{
char bf[512];
- hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
- show_displacement, displacement,
- true, session_total);
+ int ret;
+
+ ret = hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
+ show_displacement, displacement,
+ true, session_total);
+ if (!ret)
+ return 0;
+
return fprintf(fp, "%s\n", bf);
}
print_entries:
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ int cnt;
if (show_displacement) {
if (h->pair != NULL)
displacement = 0;
++position;
}
- ret += hist_entry__fprintf(h, pair, show_displacement,
- displacement, fp, self->stats.total_period);
+ cnt = hist_entry__fprintf(h, pair, show_displacement,
+ displacement, fp, self->stats.total_period);
+ /* Ignore those that didn't match the parent filter */
+ if (!cnt)
+ continue;
+
+ ret += cnt;
if (symbol_conf.use_callchain)
ret += hist_entry__fprintf_callchain(h, fp, self->stats.total_period);
* Parse hexa addresses followed by ':'
*/
line_ip = strtoull(tmp, &tmp2, 16);
- if (*tmp2 != ':' || tmp == tmp2)
+ if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
line_ip = -1;
}
if (line_ip != -1) {
- u64 start = map__rip_2objdump(self->ms.map, sym->start);
+ u64 start = map__rip_2objdump(self->ms.map, sym->start),
+ end = map__rip_2objdump(self->ms.map, sym->end);
+
offset = line_ip - start;
+ if (offset < 0 || (u64)line_ip > end)
+ offset = -1;
}
objdump_line = objdump_line__new(offset, line);
{
struct dirent *dent;
DIR *dir = opendir(dir_name);
+ int ret = 0;
if (!dir) {
pr_debug("%s: cannot open %s dir\n", __func__, dir_name);
snprintf(path, sizeof(path), "%s/%s",
dir_name, dent->d_name);
- if (map_groups__set_modules_path_dir(self, path) < 0)
- goto failure;
+ ret = map_groups__set_modules_path_dir(self, path);
+ if (ret < 0)
+ goto out;
} else {
char *dot = strrchr(dent->d_name, '.'),
dso_name[PATH_MAX];
dir_name, dent->d_name);
long_name = strdup(path);
- if (long_name == NULL)
- goto failure;
+ if (long_name == NULL) {
+ ret = -1;
+ goto out;
+ }
dso__set_long_name(map->dso, long_name);
dso__kernel_module_get_build_id(map->dso, "");
}
}
- return 0;
-failure:
+out:
closedir(dir);
- return -1;
+ return ret;
}
static char *get_kernel_version(const char *root_dir)