Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc

* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc:
  powerpc/mm: Lockless get_user_pages_fast() for 64-bit (v3)
  powerpc: Don't use the wrong thread_struct for ptrace get/set VSX regs
  powerpc: Fix ptrace buffer size for VSX
  powerpc: Correctly hookup PTRACE_GET/SETVSRREGS for 32 bit processes
  ide/powermac: Fix use of uninitialized pointer on media-bay
  powerpc: Allow non-hcall return values for lparcfg writes
  ipmi/powerpc: Use linux/of_{device,platform}.h instead of asm
  powerpc/fsl: proliferate simple-bus compatibility to soc nodes
  Documentation: remove old sbc8260 board specific information
  cpm2: Rework baud rate generators configuration to support external clocks.
  powerpc: rtc_cmos_setup: assign interrupts only if there is i8259 PIC
  cpm_uart: Add generic clock API support to set baudrates
  cpm_uart: Modem control lines support
  powerpc: implement GPIO LIB API on CPM1 Freescale SoC.
  cpm2: Implement GPIO LIB API on CPM2 Freescale SoC.
  powerpc: Fix 8xx build failure
  powerpc: clean up the Book-E HW watchpoint support
This commit is contained in:
Linus Torvalds 2008-07-30 10:43:56 -07:00
commit 660fc1f4d8
54 changed files with 907 additions and 290 deletions

View File

@ -20,8 +20,6 @@ mpc52xx-device-tree-bindings.txt
- MPC5200 Device Tree Bindings - MPC5200 Device Tree Bindings
ppc_htab.txt ppc_htab.txt
- info about the Linux/PPC /proc/ppc_htab entry - info about the Linux/PPC /proc/ppc_htab entry
SBC8260_memory_mapping.txt
- EST SBC8260 board info
smp.txt smp.txt
- use and state info about Linux/PPC on MP machines - use and state info about Linux/PPC on MP machines
sound.txt sound.txt

View File

@ -1,197 +0,0 @@
Please mail me (Jon Diekema, diekema_jon@si.com or diekema@cideas.com)
if you have questions, comments or corrections.
* EST SBC8260 Linux memory mapping rules
http://www.estc.com/
http://www.estc.com/products/boards/SBC8260-8240_ds.html
Initial conditions:
-------------------
Tasks that need to be perform by the boot ROM before control is
transferred to zImage (compressed Linux kernel):
- Define the IMMR to 0xf0000000
- Initialize the memory controller so that RAM is available at
physical address 0x00000000. On the SBC8260 is this 16M (64M)
SDRAM.
- The boot ROM should only clear the RAM that it is using.
The reason for doing this is to enhances the chances of a
successful post mortem on a Linux panic. One of the first
items to examine is the 16k (LOG_BUF_LEN) circular console
buffer called log_buf which is defined in kernel/printk.c.
- To enhance boot ROM performance, the I-cache can be enabled.
Date: Mon, 22 May 2000 14:21:10 -0700
From: Neil Russell <caret@c-side.com>
LiMon (LInux MONitor) runs with and starts Linux with MMU
off, I-cache enabled, D-cache disabled. The I-cache doesn't
need hints from the MMU to work correctly as the D-cache
does. No D-cache means no special code to handle devices in
the presence of cache (no snooping, etc). The use of the
I-cache means that the monitor can run acceptably fast
directly from ROM, rather than having to copy it to RAM.
- Build the board information structure (see
include/asm-ppc/est8260.h for its definition)
- The compressed Linux kernel (zImage) contains a bootstrap loader
that is position independent; you can load it into any RAM,
ROM or FLASH memory address >= 0x00500000 (above 5 MB), or
at its link address of 0x00400000 (4 MB).
Note: If zImage is loaded at its link address of 0x00400000 (4 MB),
then zImage will skip the step of moving itself to
its link address.
- Load R3 with the address of the board information structure
- Transfer control to zImage
- The Linux console port is SMC1, and the baud rate is controlled
from the bi_baudrate field of the board information structure.
On thing to keep in mind when picking the baud rate, is that
there is no flow control on the SMC ports. I would stick
with something safe and standard like 19200.
On the EST SBC8260, the SMC1 port is on the COM1 connector of
the board.
EST SBC8260 defaults:
---------------------
Chip
Memory Sel Bus Use
--------------------- --- --- ----------------------------------
0x00000000-0x03FFFFFF CS2 60x (16M or 64M)/64M SDRAM
0x04000000-0x04FFFFFF CS4 local 4M/16M SDRAM (soldered to the board)
0x21000000-0x21000000 CS7 60x 1B/64K Flash present detect (from the flash SIMM)
0x21000001-0x21000001 CS7 60x 1B/64K Switches (read) and LEDs (write)
0x22000000-0x2200FFFF CS5 60x 8K/64K EEPROM
0xFC000000-0xFCFFFFFF CS6 60x 2M/16M flash (8 bits wide, soldered to the board)
0xFE000000-0xFFFFFFFF CS0 60x 4M/16M flash (SIMM)
Notes:
------
- The chip selects can map 32K blocks and up (powers of 2)
- The SDRAM machine can handled up to 128Mbytes per chip select
- Linux uses the 60x bus memory (the SDRAM DIMM) for the
communications buffers.
- BATs can map 128K-256Mbytes each. There are four data BATs and
four instruction BATs. Generally the data and instruction BATs
are mapped the same.
- The IMMR must be set above the kernel virtual memory addresses,
which start at 0xC0000000. Otherwise, the kernel may crash as
soon as you start any threads or processes due to VM collisions
in the kernel or user process space.
Details from Dan Malek <dan_malek@mvista.com> on 10/29/1999:
The user application virtual space consumes the first 2 Gbytes
(0x00000000 to 0x7FFFFFFF). The kernel virtual text starts at
0xC0000000, with data following. There is a "protection hole"
between the end of kernel data and the start of the kernel
dynamically allocated space, but this space is still within
0xCxxxxxxx.
Obviously the kernel can't map any physical addresses 1:1 in
these ranges.
Details from Dan Malek <dan_malek@mvista.com> on 5/19/2000:
During the early kernel initialization, the kernel virtual
memory allocator is not operational. Prior to this KVM
initialization, we choose to map virtual to physical addresses
1:1. That is, the kernel virtual address exactly matches the
physical address on the bus. These mappings are typically done
in arch/ppc/kernel/head.S, or arch/ppc/mm/init.c. Only
absolutely necessary mappings should be done at this time, for
example board control registers or a serial uart. Normal device
driver initialization should map resources later when necessary.
Although platform dependent, and certainly the case for embedded
8xx, traditionally memory is mapped at physical address zero,
and I/O devices above physical address 0x80000000. The lowest
and highest (above 0xf0000000) I/O addresses are traditionally
used for devices or registers we need to map during kernel
initialization and prior to KVM operation. For this reason,
and since it followed prior PowerPC platform examples, I chose
to map the embedded 8xx kernel to the 0xc0000000 virtual address.
This way, we can enable the MMU to map the kernel for proper
operation, and still map a few windows before the KVM is operational.
On some systems, you could possibly run the kernel at the
0x80000000 or any other virtual address. It just depends upon
mapping that must be done prior to KVM operational. You can never
map devices or kernel spaces that overlap with the user virtual
space. This is why default IMMR mapping used by most BDM tools
won't work. They put the IMMR at something like 0x10000000 or
0x02000000 for example. You simply can't map these addresses early
in the kernel, and continue proper system operation.
The embedded 8xx/82xx kernel is mature enough that all you should
need to do is map the IMMR someplace at or above 0xf0000000 and it
should boot far enough to get serial console messages and KGDB
connected on any platform. There are lots of other subtle memory
management design features that you simply don't need to worry
about. If you are changing functions related to MMU initialization,
you are likely breaking things that are known to work and are
heading down a path of disaster and frustration. Your changes
should be to make the flexibility of the processor fit Linux,
not force arbitrary and non-workable memory mappings into Linux.
- You don't want to change KERNELLOAD or KERNELBASE, otherwise the
virtual memory and MMU code will get confused.
arch/ppc/Makefile:KERNELLOAD = 0xc0000000
include/asm-ppc/page.h:#define PAGE_OFFSET 0xc0000000
include/asm-ppc/page.h:#define KERNELBASE PAGE_OFFSET
- RAM is at physical address 0x00000000, and gets mapped to
virtual address 0xC0000000 for the kernel.
Physical addresses used by the Linux kernel:
--------------------------------------------
0x00000000-0x3FFFFFFF 1GB reserved for RAM
0xF0000000-0xF001FFFF 128K IMMR 64K used for dual port memory,
64K for 8260 registers
Logical addresses used by the Linux kernel:
-------------------------------------------
0xF0000000-0xFFFFFFFF 256M BAT0 (IMMR: dual port RAM, registers)
0xE0000000-0xEFFFFFFF 256M BAT1 (I/O space for custom boards)
0xC0000000-0xCFFFFFFF 256M BAT2 (RAM)
0xD0000000-0xDFFFFFFF 256M BAT3 (if RAM > 256MByte)
EST SBC8260 Linux mapping:
--------------------------
DBAT0, IBAT0, cache inhibited:
Chip
Memory Sel Use
--------------------- --- ---------------------------------
0xF0000000-0xF001FFFF n/a IMMR: dual port RAM, registers
DBAT1, IBAT1, cache inhibited:

View File

@ -7,6 +7,15 @@ Currently defined compatibles:
- fsl,cpm2-scc-uart - fsl,cpm2-scc-uart
- fsl,qe-uart - fsl,qe-uart
Modem control lines connected to GPIO controllers are listed in the gpios
property as described in booting-without-of.txt, section IX.1 in the following
order:
CTS, RTS, DCD, DSR, DTR, and RI.
The gpios property is optional and can be left out when control lines are
not used.
Example: Example:
serial@11a00 { serial@11a00 {
@ -18,4 +27,6 @@ Example:
interrupt-parent = <&PIC>; interrupt-parent = <&PIC>;
fsl,cpm-brg = <1>; fsl,cpm-brg = <1>;
fsl,cpm-command = <00800000>; fsl,cpm-command = <00800000>;
gpios = <&gpio_c 15 0
&gpio_d 29 0>;
}; };

View File

@ -42,6 +42,9 @@ config GENERIC_HARDIRQS
bool bool
default y default y
config HAVE_GET_USER_PAGES_FAST
def_bool PPC64
config HAVE_SETUP_PER_CPU_AREA config HAVE_SETUP_PER_CPU_AREA
def_bool PPC64 def_bool PPC64

View File

@ -68,6 +68,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <132000000>; bus-frequency = <132000000>;

View File

@ -51,6 +51,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -52,6 +52,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader

View File

@ -50,6 +50,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; // from bootloader bus-frequency = <0>; // from bootloader

View File

@ -57,6 +57,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -61,6 +61,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <264000000>; bus-frequency = <264000000>;

View File

@ -149,18 +149,14 @@
}; };
crypto@30000 { crypto@30000 {
compatible = "fsl,sec2-crypto"; compatible = "fsl,sec2.0";
reg = <0x30000 0x10000>; reg = <0x30000 0x10000>;
interrupts = <11 8>; interrupts = <11 0x8>;
interrupt-parent = <&ipic>; interrupt-parent = <&ipic>;
num-channels = <4>; fsl,num-channels = <4>;
channel-fifo-len = <24>; fsl,channel-fifo-len = <24>;
exec-units-mask = <0x7e>; fsl,exec-units-mask = <0x7e>;
/* fsl,descriptor-types-mask = <0x01010ebf>;
* desc mask is for rev1.x, we need runtime fixup
* for >=2.x
*/
descriptor-types-mask = <0x1010ebf>;
}; };
ipic: interrupt-controller@700 { ipic: interrupt-controller@700 {

View File

@ -117,6 +117,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -117,6 +117,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -117,6 +117,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x00100000>; ranges = <0x0 0xe0000000 0x00100000>;
reg = <0xe0000000 0x00000200>; reg = <0xe0000000 0x00000200>;
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -49,6 +49,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xffe00000 0x100000>; ranges = <0x0 0xffe00000 0x100000>;
reg = <0xffe00000 0x1000>; reg = <0xffe00000 0x1000>;
bus-frequency = <0>; // Filled out by uboot. bus-frequency = <0>; // Filled out by uboot.

View File

@ -53,6 +53,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>; ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x100000>; // CCSRBAR 1M reg = <0xe0000000 0x100000>; // CCSRBAR 1M
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -53,6 +53,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>; ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR 1M reg = <0xe0000000 0x1000>; // CCSRBAR 1M
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -54,6 +54,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>; ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR 1M reg = <0xe0000000 0x1000>; // CCSRBAR 1M

View File

@ -58,6 +58,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>; ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR reg = <0xe0000000 0x1000>; // CCSRBAR
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -53,6 +53,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>; ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; // CCSRBAR 1M reg = <0xe0000000 0x1000>; // CCSRBAR 1M
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -53,6 +53,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>; ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x200>; reg = <0xe0000000 0x200>;
bus-frequency = <330000000>; bus-frequency = <330000000>;

View File

@ -60,6 +60,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xe0000000 0x100000>; ranges = <0x0 0xe0000000 0x100000>;
reg = <0xe0000000 0x1000>; reg = <0xe0000000 0x1000>;
bus-frequency = <0>; bus-frequency = <0>;

View File

@ -68,6 +68,7 @@
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
device_type = "soc"; device_type = "soc";
compatible = "simple-bus";
ranges = <0x0 0xffe00000 0x100000>; ranges = <0x0 0xffe00000 0x100000>;
reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed
bus-frequency = <0>; // Filled out by uboot. bus-frequency = <0>; // Filled out by uboot.

View File

@ -636,10 +636,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf,
retval = -EIO; retval = -EIO;
} else if (retval == H_PARAMETER) { } else if (retval == H_PARAMETER) {
retval = -EINVAL; retval = -EINVAL;
} else {
printk(KERN_WARNING "%s: received unknown hv return code %ld",
__func__, retval);
retval = -EIO;
} }
return retval; return retval;

View File

@ -375,7 +375,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset,
flush_vsx_to_thread(target); flush_vsx_to_thread(target);
for (i = 0; i < 32 ; i++) for (i = 0; i < 32 ; i++)
buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; buf[i] = target->thread.fpr[i][TS_VSRLOWOFFSET];
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double)); buf, 0, 32 * sizeof(double));
@ -394,7 +394,7 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset,
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double)); buf, 0, 32 * sizeof(double));
for (i = 0; i < 32 ; i++) for (i = 0; i < 32 ; i++)
current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; target->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i];
return ret; return ret;
@ -975,15 +975,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_GETVSRREGS: case PTRACE_GETVSRREGS:
return copy_regset_to_user(child, &user_ppc_native_view, return copy_regset_to_user(child, &user_ppc_native_view,
REGSET_VSX, REGSET_VSX,
0, (32 * sizeof(vector128) + 0, 32 * sizeof(double),
sizeof(u32)),
(void __user *) data); (void __user *) data);
case PTRACE_SETVSRREGS: case PTRACE_SETVSRREGS:
return copy_regset_from_user(child, &user_ppc_native_view, return copy_regset_from_user(child, &user_ppc_native_view,
REGSET_VSX, REGSET_VSX,
0, (32 * sizeof(vector128) + 0, 32 * sizeof(double),
sizeof(u32)),
(const void __user *) data); (const void __user *) data);
#endif #endif
#ifdef CONFIG_SPE #ifdef CONFIG_SPE

View File

@ -294,6 +294,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
case PTRACE_SETFPREGS: case PTRACE_SETFPREGS:
case PTRACE_GETVRREGS: case PTRACE_GETVRREGS:
case PTRACE_SETVRREGS: case PTRACE_SETVRREGS:
case PTRACE_GETVSRREGS:
case PTRACE_SETVSRREGS:
case PTRACE_GETREGS64: case PTRACE_GETREGS64:
case PTRACE_SETREGS64: case PTRACE_SETREGS64:
case PPC_PTRACE_GETFPREGS: case PPC_PTRACE_GETFPREGS:

View File

@ -12,7 +12,8 @@ obj-y := fault.o mem.o \
mmu_context_$(CONFIG_WORD_SIZE).o mmu_context_$(CONFIG_WORD_SIZE).o
hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o
obj-$(CONFIG_PPC64) += hash_utils_64.o \ obj-$(CONFIG_PPC64) += hash_utils_64.o \
slb_low.o slb.o stab.o mmap.o $(hash-y) slb_low.o slb.o stab.o \
gup.o mmap.o $(hash-y)
obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o
obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \
tlb_$(CONFIG_WORD_SIZE).o tlb_$(CONFIG_WORD_SIZE).o

280
arch/powerpc/mm/gup.c Normal file
View File

@ -0,0 +1,280 @@
/*
* Lockless get_user_pages_fast for powerpc
*
* Copyright (C) 2008 Nick Piggin
* Copyright (C) 2008 Novell Inc.
*/
#undef DEBUG
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/hugetlb.h>
#include <linux/vmstat.h>
#include <linux/pagemap.h>
#include <linux/rwsem.h>
#include <asm/pgtable.h>
/*
* The performance critical leaf functions are made noinline otherwise gcc
* inlines everything into a single function which results in too much
* register pressure.
*/
static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
unsigned long end, int write, struct page **pages, int *nr)
{
unsigned long mask, result;
pte_t *ptep;
result = _PAGE_PRESENT|_PAGE_USER;
if (write)
result |= _PAGE_RW;
mask = result | _PAGE_SPECIAL;
ptep = pte_offset_kernel(&pmd, addr);
do {
pte_t pte = *ptep;
struct page *page;
if ((pte_val(pte) & mask) != result)
return 0;
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
page = pte_page(pte);
if (!page_cache_get_speculative(page))
return 0;
if (unlikely(pte != *ptep)) {
put_page(page);
return 0;
}
pages[*nr] = page;
(*nr)++;
} while (ptep++, addr += PAGE_SIZE, addr != end);
return 1;
}
#ifdef CONFIG_HUGETLB_PAGE
static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate,
unsigned long *addr, unsigned long end,
int write, struct page **pages, int *nr)
{
unsigned long mask;
unsigned long pte_end;
struct page *head, *page;
pte_t pte;
int refs;
pte_end = (*addr + huge_page_size(hstate)) & huge_page_mask(hstate);
if (pte_end < end)
end = pte_end;
pte = *ptep;
mask = _PAGE_PRESENT|_PAGE_USER;
if (write)
mask |= _PAGE_RW;
if ((pte_val(pte) & mask) != mask)
return 0;
/* hugepages are never "special" */
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
refs = 0;
head = pte_page(pte);
page = head + ((*addr & ~huge_page_mask(hstate)) >> PAGE_SHIFT);
do {
VM_BUG_ON(compound_head(page) != head);
pages[*nr] = page;
(*nr)++;
page++;
refs++;
} while (*addr += PAGE_SIZE, *addr != end);
if (!page_cache_add_speculative(head, refs)) {
*nr -= refs;
return 0;
}
if (unlikely(pte != *ptep)) {
/* Could be optimized better */
while (*nr) {
put_page(page);
(*nr)--;
}
}
return 1;
}
#endif /* CONFIG_HUGETLB_PAGE */
static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
int write, struct page **pages, int *nr)
{
unsigned long next;
pmd_t *pmdp;
pmdp = pmd_offset(&pud, addr);
do {
pmd_t pmd = *pmdp;
next = pmd_addr_end(addr, end);
if (pmd_none(pmd))
return 0;
if (!gup_pte_range(pmd, addr, next, write, pages, nr))
return 0;
} while (pmdp++, addr = next, addr != end);
return 1;
}
static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
int write, struct page **pages, int *nr)
{
unsigned long next;
pud_t *pudp;
pudp = pud_offset(&pgd, addr);
do {
pud_t pud = *pudp;
next = pud_addr_end(addr, end);
if (pud_none(pud))
return 0;
if (!gup_pmd_range(pud, addr, next, write, pages, nr))
return 0;
} while (pudp++, addr = next, addr != end);
return 1;
}
int get_user_pages_fast(unsigned long start, int nr_pages, int write,
struct page **pages)
{
struct mm_struct *mm = current->mm;
unsigned long addr, len, end;
unsigned long next;
pgd_t *pgdp;
int psize, nr = 0;
unsigned int shift;
pr_debug("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read");
start &= PAGE_MASK;
addr = start;
len = (unsigned long) nr_pages << PAGE_SHIFT;
end = start + len;
if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ,
start, len)))
goto slow_irqon;
pr_debug(" aligned: %lx .. %lx\n", start, end);
#ifdef CONFIG_HUGETLB_PAGE
/* We bail out on slice boundary crossing when hugetlb is
* enabled in order to not have to deal with two different
* page table formats
*/
if (addr < SLICE_LOW_TOP) {
if (end > SLICE_LOW_TOP)
goto slow_irqon;
if (unlikely(GET_LOW_SLICE_INDEX(addr) !=
GET_LOW_SLICE_INDEX(end - 1)))
goto slow_irqon;
} else {
if (unlikely(GET_HIGH_SLICE_INDEX(addr) !=
GET_HIGH_SLICE_INDEX(end - 1)))
goto slow_irqon;
}
#endif /* CONFIG_HUGETLB_PAGE */
/*
* XXX: batch / limit 'nr', to avoid large irq off latency
* needs some instrumenting to determine the common sizes used by
* important workloads (eg. DB2), and whether limiting the batch size
* will decrease performance.
*
* It seems like we're in the clear for the moment. Direct-IO is
* the main guy that batches up lots of get_user_pages, and even
* they are limited to 64-at-a-time which is not so many.
*/
/*
* This doesn't prevent pagetable teardown, but does prevent
* the pagetables from being freed on powerpc.
*
* So long as we atomically load page table pointers versus teardown,
* we can follow the address down to the the page and take a ref on it.
*/
local_irq_disable();
psize = get_slice_psize(mm, addr);
shift = mmu_psize_defs[psize].shift;
#ifdef CONFIG_HUGETLB_PAGE
if (unlikely(mmu_huge_psizes[psize])) {
pte_t *ptep;
unsigned long a = addr;
unsigned long sz = ((1UL) << shift);
struct hstate *hstate = size_to_hstate(sz);
BUG_ON(!hstate);
/*
* XXX: could be optimized to avoid hstate
* lookup entirely (just use shift)
*/
do {
VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, a)].shift);
ptep = huge_pte_offset(mm, a);
pr_debug(" %016lx: huge ptep %p\n", a, ptep);
if (!ptep || !gup_huge_pte(ptep, hstate, &a, end, write, pages,
&nr))
goto slow;
} while (a != end);
} else
#endif /* CONFIG_HUGETLB_PAGE */
{
pgdp = pgd_offset(mm, addr);
do {
pgd_t pgd = *pgdp;
VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift);
pr_debug(" %016lx: normal pgd %p\n", addr, (void *)pgd);
next = pgd_addr_end(addr, end);
if (pgd_none(pgd))
goto slow;
if (!gup_pud_range(pgd, addr, next, write, pages, &nr))
goto slow;
} while (pgdp++, addr = next, addr != end);
}
local_irq_enable();
VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT);
return nr;
{
int ret;
slow:
local_irq_enable();
slow_irqon:
pr_debug(" slow path ! nr = %d\n", nr);
/* Try to get the remaining pages with get_user_pages */
start += nr << PAGE_SHIFT;
pages += nr;
down_read(&mm->mmap_sem);
ret = get_user_pages(current, mm, start,
(end - start) >> PAGE_SHIFT, write, 0, pages, NULL);
up_read(&mm->mmap_sem);
/* Have to be a bit careful with return values */
if (nr > 0) {
if (ret < 0)
ret = nr;
else
ret += nr;
}
return ret;
}
}

View File

@ -105,6 +105,7 @@ static void __init mpc832x_sys_setup_arch(void)
static struct of_device_id mpc832x_ids[] = { static struct of_device_id mpc832x_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{ .type = "qe", }, { .type = "qe", },
{ .compatible = "fsl,qe", }, { .compatible = "fsl,qe", },
{}, {},

View File

@ -115,6 +115,7 @@ static void __init mpc832x_rdb_setup_arch(void)
static struct of_device_id mpc832x_ids[] = { static struct of_device_id mpc832x_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{ .type = "qe", }, { .type = "qe", },
{ .compatible = "fsl,qe", }, { .compatible = "fsl,qe", },
{}, {},

View File

@ -41,6 +41,7 @@
static struct of_device_id __initdata mpc834x_itx_ids[] = { static struct of_device_id __initdata mpc834x_itx_ids[] = {
{ .compatible = "fsl,pq2pro-localbus", }, { .compatible = "fsl,pq2pro-localbus", },
{ .compatible = "simple-bus", },
{}, {},
}; };

View File

@ -111,6 +111,7 @@ static void __init mpc834x_mds_init_IRQ(void)
static struct of_device_id mpc834x_ids[] = { static struct of_device_id mpc834x_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{}, {},
}; };

View File

@ -136,6 +136,7 @@ static void __init mpc836x_mds_setup_arch(void)
static struct of_device_id mpc836x_ids[] = { static struct of_device_id mpc836x_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{ .type = "qe", }, { .type = "qe", },
{ .compatible = "fsl,qe", }, { .compatible = "fsl,qe", },
{}, {},

View File

@ -83,6 +83,7 @@ static void __init sbc834x_init_IRQ(void)
static struct __initdata of_device_id sbc834x_ids[] = { static struct __initdata of_device_id sbc834x_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{}, {},
}; };

View File

@ -222,6 +222,7 @@ static void ksi8560_show_cpuinfo(struct seq_file *m)
static struct of_device_id __initdata of_bus_ids[] = { static struct of_device_id __initdata of_bus_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .type = "simple-bus", },
{ .name = "cpm", }, { .name = "cpm", },
{ .name = "localbus", }, { .name = "localbus", },
{}, {},

View File

@ -91,6 +91,7 @@ static void __init mpc8536_ds_setup_arch(void)
static struct of_device_id __initdata mpc8536_ds_ids[] = { static struct of_device_id __initdata mpc8536_ds_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{}, {},
}; };

View File

@ -230,6 +230,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .name = "cpm", }, { .name = "cpm", },
{ .name = "localbus", }, { .name = "localbus", },
{ .compatible = "simple-bus", },
{}, {},
}; };

View File

@ -186,6 +186,7 @@ static int __init mpc8544_ds_probe(void)
static struct of_device_id __initdata mpc85xxds_ids[] = { static struct of_device_id __initdata mpc85xxds_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{}, {},
}; };

View File

@ -260,6 +260,7 @@ machine_arch_initcall(mpc85xx_mds, board_fixups);
static struct of_device_id mpc85xx_ids[] = { static struct of_device_id mpc85xx_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .compatible = "soc", }, { .compatible = "soc", },
{ .compatible = "simple-bus", },
{ .type = "qe", }, { .type = "qe", },
{ .compatible = "fsl,qe", }, { .compatible = "fsl,qe", },
{}, {},

View File

@ -217,6 +217,7 @@ static struct of_device_id __initdata of_bus_ids[] = {
{ .type = "soc", }, { .type = "soc", },
{ .name = "cpm", }, { .name = "cpm", },
{ .name = "localbus", }, { .name = "localbus", },
{ .compatible = "simple-bus", },
{}, {},
}; };

View File

@ -105,6 +105,16 @@ config 8xx_COPYBACK
If in doubt, say Y here. If in doubt, say Y here.
config 8xx_GPIO
bool "GPIO API Support"
select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB
help
Saying Y here will cause the ports on an MPC8xx processor to be used
with the GPIO API. If you say N here, the kernel needs less memory.
If in doubt, say Y here.
config 8xx_CPU6 config 8xx_CPU6
bool "CPU6 Silicon Errata (860 Pre Rev. C)" bool "CPU6 Silicon Errata (860 Pre Rev. C)"
help help

View File

@ -254,6 +254,8 @@ config CPM2
select CPM select CPM
select PPC_LIB_RHEAP select PPC_LIB_RHEAP
select PPC_PCI_CHOICE select PPC_PCI_CHOICE
select ARCH_REQUIRE_GPIOLIB
select GENERIC_GPIO
help help
The CPM2 (Communications Processor Module) is a coprocessor on The CPM2 (Communications Processor Module) is a coprocessor on
embedded CPUs made by Freescale. Selecting this option means that embedded CPUs made by Freescale. Selecting this option means that
@ -281,6 +283,7 @@ config FSL_ULI1575
config CPM config CPM
bool bool
select PPC_CLOCK
config OF_RTC config OF_RTC
bool bool

View File

@ -30,6 +30,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/8xx_immap.h> #include <asm/8xx_immap.h>
@ -42,6 +43,10 @@
#include <asm/fs_pd.h> #include <asm/fs_pd.h>
#ifdef CONFIG_8xx_GPIO
#include <linux/of_gpio.h>
#endif
#define CPM_MAP_SIZE (0x4000) #define CPM_MAP_SIZE (0x4000)
cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */
@ -290,20 +295,24 @@ struct cpm_ioport16 {
__be16 res[3]; __be16 res[3];
}; };
struct cpm_ioport32 { struct cpm_ioport32b {
__be32 dir, par, sor; __be32 dir, par, odr, dat;
};
struct cpm_ioport32e {
__be32 dir, par, sor, odr, dat;
}; };
static void cpm1_set_pin32(int port, int pin, int flags) static void cpm1_set_pin32(int port, int pin, int flags)
{ {
struct cpm_ioport32 __iomem *iop; struct cpm_ioport32e __iomem *iop;
pin = 1 << (31 - pin); pin = 1 << (31 - pin);
if (port == CPM_PORTB) if (port == CPM_PORTB)
iop = (struct cpm_ioport32 __iomem *) iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pbdir; &mpc8xx_immr->im_cpm.cp_pbdir;
else else
iop = (struct cpm_ioport32 __iomem *) iop = (struct cpm_ioport32e __iomem *)
&mpc8xx_immr->im_cpm.cp_pedir; &mpc8xx_immr->im_cpm.cp_pedir;
if (flags & CPM_PIN_OUTPUT) if (flags & CPM_PIN_OUTPUT)
@ -498,3 +507,251 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode)
return 0; return 0;
} }
/*
* GPIO LIB API implementation
*/
#ifdef CONFIG_8xx_GPIO
struct cpm1_gpio16_chip {
struct of_mm_gpio_chip mm_gc;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
u16 cpdata;
};
static inline struct cpm1_gpio16_chip *
to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc)
{
return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc);
}
static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc)
{
struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
cpm1_gc->cpdata = in_be16(&iop->dat);
}
static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
u16 pin_mask;
pin_mask = 1 << (15 - gpio);
return !!(in_be16(&iop->dat) & pin_mask);
}
static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
unsigned long flags;
u16 pin_mask = 1 << (15 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
if (value)
cpm1_gc->cpdata |= pin_mask;
else
cpm1_gc->cpdata &= ~pin_mask;
out_be16(&iop->dat, cpm1_gc->cpdata);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
}
static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
u16 pin_mask;
pin_mask = 1 << (15 - gpio);
setbits16(&iop->dir, pin_mask);
cpm1_gpio16_set(gc, gpio, val);
return 0;
}
static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
u16 pin_mask;
pin_mask = 1 << (15 - gpio);
clrbits16(&iop->dir, pin_mask);
return 0;
}
int cpm1_gpiochip_add16(struct device_node *np)
{
struct cpm1_gpio16_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
if (!cpm1_gc)
return -ENOMEM;
spin_lock_init(&cpm1_gc->lock);
mm_gc = &cpm1_gc->mm_gc;
of_gc = &mm_gc->of_gc;
gc = &of_gc->gc;
mm_gc->save_regs = cpm1_gpio16_save_regs;
of_gc->gpio_cells = 2;
gc->ngpio = 16;
gc->direction_input = cpm1_gpio16_dir_in;
gc->direction_output = cpm1_gpio16_dir_out;
gc->get = cpm1_gpio16_get;
gc->set = cpm1_gpio16_set;
return of_mm_gpiochip_add(np, mm_gc);
}
struct cpm1_gpio32_chip {
struct of_mm_gpio_chip mm_gc;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
u32 cpdata;
};
static inline struct cpm1_gpio32_chip *
to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
{
return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc);
}
static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
{
struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
cpm1_gc->cpdata = in_be32(&iop->dat);
}
static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
return !!(in_be32(&iop->dat) & pin_mask);
}
static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm1_gc->lock, flags);
if (value)
cpm1_gc->cpdata |= pin_mask;
else
cpm1_gc->cpdata &= ~pin_mask;
out_be32(&iop->dat, cpm1_gc->cpdata);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
}
static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
setbits32(&iop->dir, pin_mask);
cpm1_gpio32_set(gc, gpio, val);
return 0;
}
static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
clrbits32(&iop->dir, pin_mask);
return 0;
}
int cpm1_gpiochip_add32(struct device_node *np)
{
struct cpm1_gpio32_chip *cpm1_gc;
struct of_mm_gpio_chip *mm_gc;
struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL);
if (!cpm1_gc)
return -ENOMEM;
spin_lock_init(&cpm1_gc->lock);
mm_gc = &cpm1_gc->mm_gc;
of_gc = &mm_gc->of_gc;
gc = &of_gc->gc;
mm_gc->save_regs = cpm1_gpio32_save_regs;
of_gc->gpio_cells = 2;
gc->ngpio = 32;
gc->direction_input = cpm1_gpio32_dir_in;
gc->direction_output = cpm1_gpio32_dir_out;
gc->get = cpm1_gpio32_get;
gc->set = cpm1_gpio32_set;
return of_mm_gpiochip_add(np, mm_gc);
}
static int cpm_init_par_io(void)
{
struct device_node *np;
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a")
cpm1_gpiochip_add16(np);
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b")
cpm1_gpiochip_add32(np);
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c")
cpm1_gpiochip_add16(np);
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d")
cpm1_gpiochip_add16(np);
/* Port E uses CPM2 layout */
for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e")
cpm2_gpiochip_add32(np);
return 0;
}
arch_initcall(cpm_init_par_io);
#endif /* CONFIG_8xx_GPIO */

View File

@ -115,16 +115,10 @@ EXPORT_SYMBOL(cpm_command);
* Baud rate clocks are zero-based in the driver code (as that maps * Baud rate clocks are zero-based in the driver code (as that maps
* to port numbers). Documentation uses 1-based numbering. * to port numbers). Documentation uses 1-based numbering.
*/ */
#define BRG_INT_CLK (get_brgfreq()) void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src)
#define BRG_UART_CLK (BRG_INT_CLK/16)
/* This function is used by UARTS, or anything else that uses a 16x
* oversampled clock.
*/
void
cpm_setbrg(uint brg, uint rate)
{ {
u32 __iomem *bp; u32 __iomem *bp;
u32 val;
/* This is good enough to get SMCs running..... /* This is good enough to get SMCs running.....
*/ */
@ -135,34 +129,14 @@ cpm_setbrg(uint brg, uint rate)
brg -= 4; brg -= 4;
} }
bp += brg; bp += brg;
out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); val = (((clk / rate) - 1) << 1) | CPM_BRG_EN | src;
cpm2_unmap(bp);
}
/* This function is used to set high speed synchronous baud rate
* clocks.
*/
void
cpm2_fastbrg(uint brg, uint rate, int div16)
{
u32 __iomem *bp;
u32 val;
if (brg < 4) {
bp = cpm2_map_size(im_brgc1, 16);
} else {
bp = cpm2_map_size(im_brgc5, 16);
brg -= 4;
}
bp += brg;
val = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
if (div16) if (div16)
val |= CPM_BRG_DIV16; val |= CPM_BRG_DIV16;
out_be32(bp, val); out_be32(bp, val);
cpm2_unmap(bp); cpm2_unmap(bp);
} }
EXPORT_SYMBOL(__cpm2_setbrg);
int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
{ {
@ -377,3 +351,14 @@ void cpm2_set_pin(int port, int pin, int flags)
else else
clrbits32(&iop[port].odr, pin); clrbits32(&iop[port].odr, pin);
} }
static int cpm_init_par_io(void)
{
struct device_node *np;
for_each_compatible_node(np, NULL, "fsl,cpm2-pario-bank")
cpm2_gpiochip_add32(np);
return 0;
}
arch_initcall(cpm_init_par_io);

View File

@ -19,6 +19,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/spinlock.h>
#include <linux/of.h>
#include <asm/udbg.h> #include <asm/udbg.h>
#include <asm/io.h> #include <asm/io.h>
@ -28,6 +30,10 @@
#include <mm/mmu_decl.h> #include <mm/mmu_decl.h>
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
#include <linux/of_gpio.h>
#endif
#ifdef CONFIG_PPC_EARLY_DEBUG_CPM #ifdef CONFIG_PPC_EARLY_DEBUG_CPM
static u32 __iomem *cpm_udbg_txdesc = static u32 __iomem *cpm_udbg_txdesc =
(u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR;
@ -207,3 +213,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr)
return muram_pbase + ((u8 __iomem *)addr - muram_vbase); return muram_pbase + ((u8 __iomem *)addr - muram_vbase);
} }
EXPORT_SYMBOL(cpm_muram_dma); EXPORT_SYMBOL(cpm_muram_dma);
#if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO)
struct cpm2_ioports {
u32 dir, par, sor, odr, dat;
u32 res[3];
};
struct cpm2_gpio32_chip {
struct of_mm_gpio_chip mm_gc;
spinlock_t lock;
/* shadowed data register to clear/set bits safely */
u32 cpdata;
};
static inline struct cpm2_gpio32_chip *
to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc)
{
return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc);
}
static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc)
{
struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
cpm2_gc->cpdata = in_be32(&iop->dat);
}
static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
return !!(in_be32(&iop->dat) & pin_mask);
}
static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
unsigned long flags;
u32 pin_mask = 1 << (31 - gpio);
spin_lock_irqsave(&cpm2_gc->lock, flags);
if (value)
cpm2_gc->cpdata |= pin_mask;
else
cpm2_gc->cpdata &= ~pin_mask;
out_be32(&iop->dat, cpm2_gc->cpdata);
spin_unlock_irqrestore(&cpm2_gc->lock, flags);
}
static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
setbits32(&iop->dir, pin_mask);
cpm2_gpio32_set(gc, gpio, val);
return 0;
}
static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm2_ioports __iomem *iop = mm_gc->regs;
u32 pin_mask;
pin_mask = 1 << (31 - gpio);
clrbits32(&iop->dir, pin_mask);
return 0;
}
int cpm2_gpiochip_add32(struct device_node *np)
{
struct cpm2_gpio32_chip *cpm2_gc;
struct of_mm_gpio_chip *mm_gc;
struct of_gpio_chip *of_gc;
struct gpio_chip *gc;
cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL);
if (!cpm2_gc)
return -ENOMEM;
spin_lock_init(&cpm2_gc->lock);
mm_gc = &cpm2_gc->mm_gc;
of_gc = &mm_gc->of_gc;
gc = &of_gc->gc;
mm_gc->save_regs = cpm2_gpio32_save_regs;
of_gc->gpio_cells = 2;
gc->ngpio = 32;
gc->direction_input = cpm2_gpio32_dir_in;
gc->direction_output = cpm2_gpio32_dir_out;
gc->get = cpm2_gpio32_get;
gc->set = cpm2_gpio32_set;
return of_mm_gpiochip_add(np, mm_gc);
}
#endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */

View File

@ -21,6 +21,7 @@ static int __init add_rtc(void)
struct device_node *np; struct device_node *np;
struct platform_device *pd; struct platform_device *pd;
struct resource res[2]; struct resource res[2];
unsigned int num_res = 1;
int ret; int ret;
memset(&res, 0, sizeof(res)); memset(&res, 0, sizeof(res));
@ -41,14 +42,24 @@ static int __init add_rtc(void)
if (res[0].start != RTC_PORT(0)) if (res[0].start != RTC_PORT(0))
return -EINVAL; return -EINVAL;
/* Use a fixed interrupt value of 8 since on PPC if we are using this np = of_find_compatible_node(NULL, NULL, "chrp,iic");
* its off an i8259 which we ensure has interrupt numbers 0..15. */ if (!np)
res[1].start = 8; np = of_find_compatible_node(NULL, NULL, "pnpPNP,000");
res[1].end = 8; if (np) {
res[1].flags = IORESOURCE_IRQ; of_node_put(np);
/*
* Use a fixed interrupt value of 8 since on PPC if we are
* using this its off an i8259 which we ensure has interrupt
* numbers 0..15.
*/
res[1].start = 8;
res[1].end = 8;
res[1].flags = IORESOURCE_IRQ;
num_res++;
}
pd = platform_device_register_simple("rtc_cmos", -1, pd = platform_device_register_simple("rtc_cmos", -1,
&res[0], 2); &res[0], num_res);
if (IS_ERR(pd)) if (IS_ERR(pd))
return PTR_ERR(pd); return PTR_ERR(pd);

View File

@ -66,8 +66,8 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#ifdef CONFIG_PPC_OF #ifdef CONFIG_PPC_OF
#include <asm/of_device.h> #include <linux/of_device.h>
#include <asm/of_platform.h> #include <linux/of_platform.h>
#endif #endif
#define PFX "ipmi_si: " #define PFX "ipmi_si: "

View File

@ -1086,6 +1086,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
/* Make sure we have sane timings */ /* Make sure we have sane timings */
sanitize_timings(pmif); sanitize_timings(pmif);
host = ide_host_alloc(&d, hws);
if (host == NULL)
return -ENOMEM;
hwif = host->ports[0];
#ifndef CONFIG_PPC64 #ifndef CONFIG_PPC64
/* XXX FIXME: Media bay stuff need re-organizing */ /* XXX FIXME: Media bay stuff need re-organizing */
if (np->parent && np->parent->name if (np->parent && np->parent->name
@ -1119,11 +1124,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw)
pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id,
pmif->mediabay ? " (mediabay)" : "", hw->irq); pmif->mediabay ? " (mediabay)" : "", hw->irq);
rc = ide_host_add(&d, hws, &host); rc = ide_host_register(host, &d, hws);
if (rc) if (rc) {
ide_host_free(host);
return rc; return rc;
}
hwif = host->ports[0];
return 0; return 0;
} }

View File

@ -50,6 +50,15 @@
#define SCC_WAIT_CLOSING 100 #define SCC_WAIT_CLOSING 100
#define GPIO_CTS 0
#define GPIO_RTS 1
#define GPIO_DCD 2
#define GPIO_DSR 3
#define GPIO_DTR 4
#define GPIO_RI 5
#define NUM_GPIOS (GPIO_RI+1)
struct uart_cpm_port { struct uart_cpm_port {
struct uart_port port; struct uart_port port;
u16 rx_nrfifos; u16 rx_nrfifos;
@ -68,6 +77,7 @@ struct uart_cpm_port {
unsigned char *rx_buf; unsigned char *rx_buf;
u32 flags; u32 flags;
void (*set_lineif)(struct uart_cpm_port *); void (*set_lineif)(struct uart_cpm_port *);
struct clk *clk;
u8 brg; u8 brg;
uint dp_addr; uint dp_addr;
void *mem_addr; void *mem_addr;
@ -82,6 +92,7 @@ struct uart_cpm_port {
int wait_closing; int wait_closing;
/* value to combine with opcode to form cpm command */ /* value to combine with opcode to form cpm command */
u32 command; u32 command;
int gpios[NUM_GPIOS];
}; };
extern int cpm_uart_nr; extern int cpm_uart_nr;

View File

@ -43,6 +43,9 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/fs_uart_pd.h> #include <linux/fs_uart_pd.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
@ -96,13 +99,41 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port)
static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{ {
/* Whee. Do nothing. */ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
if (pinfo->gpios[GPIO_RTS] >= 0)
gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
if (pinfo->gpios[GPIO_DTR] >= 0)
gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
} }
static unsigned int cpm_uart_get_mctrl(struct uart_port *port) static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
{ {
/* Whee. Do nothing. */ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
if (pinfo->gpios[GPIO_CTS] >= 0) {
if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
mctrl &= ~TIOCM_CTS;
}
if (pinfo->gpios[GPIO_DSR] >= 0) {
if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
mctrl &= ~TIOCM_DSR;
}
if (pinfo->gpios[GPIO_DCD] >= 0) {
if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
mctrl &= ~TIOCM_CAR;
}
if (pinfo->gpios[GPIO_RI] >= 0) {
if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
mctrl |= TIOCM_RNG;
}
return mctrl;
} }
/* /*
@ -566,7 +597,10 @@ static void cpm_uart_set_termios(struct uart_port *port,
out_be16(&sccp->scc_psmr, (sbits << 12) | scval); out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
} }
cpm_set_brg(pinfo->brg - 1, baud); if (pinfo->clk)
clk_set_rate(pinfo->clk, baud);
else
cpm_set_brg(pinfo->brg - 1, baud);
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
} }
@ -991,14 +1025,23 @@ static int cpm_uart_init_port(struct device_node *np,
void __iomem *mem, *pram; void __iomem *mem, *pram;
int len; int len;
int ret; int ret;
int i;
data = of_get_property(np, "fsl,cpm-brg", &len); data = of_get_property(np, "clock", NULL);
if (!data || len != 4) { if (data) {
printk(KERN_ERR "CPM UART %s has no/invalid " struct clk *clk = clk_get(NULL, (const char*)data);
"fsl,cpm-brg property.\n", np->name); if (!IS_ERR(clk))
return -EINVAL; pinfo->clk = clk;
}
if (!pinfo->clk) {
data = of_get_property(np, "fsl,cpm-brg", &len);
if (!data || len != 4) {
printk(KERN_ERR "CPM UART %s has no/invalid "
"fsl,cpm-brg property.\n", np->name);
return -EINVAL;
}
pinfo->brg = *data;
} }
pinfo->brg = *data;
data = of_get_property(np, "fsl,cpm-command", &len); data = of_get_property(np, "fsl,cpm-command", &len);
if (!data || len != 4) { if (!data || len != 4) {
@ -1050,6 +1093,9 @@ static int cpm_uart_init_port(struct device_node *np,
goto out_pram; goto out_pram;
} }
for (i = 0; i < NUM_GPIOS; i++)
pinfo->gpios[i] = of_get_gpio(np, i);
return cpm_uart_request_port(&pinfo->port); return cpm_uart_request_port(&pinfo->port);
out_pram: out_pram:

View File

@ -3,6 +3,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/of.h>
/* Opcodes common to CPM1 and CPM2 /* Opcodes common to CPM1 and CPM2
*/ */
@ -100,4 +101,6 @@ unsigned long cpm_muram_offset(void __iomem *addr);
dma_addr_t cpm_muram_dma(void __iomem *addr); dma_addr_t cpm_muram_dma(void __iomem *addr);
int cpm_command(u32 command, u8 opcode); int cpm_command(u32 command, u8 opcode);
int cpm2_gpiochip_add32(struct device_node *np);
#endif #endif

View File

@ -12,6 +12,7 @@
#include <asm/immap_cpm2.h> #include <asm/immap_cpm2.h>
#include <asm/cpm.h> #include <asm/cpm.h>
#include <sysdev/fsl_soc.h>
#ifdef CONFIG_PPC_85xx #ifdef CONFIG_PPC_85xx
#define CPM_MAP_ADDR (get_immrbase() + 0x80000) #define CPM_MAP_ADDR (get_immrbase() + 0x80000)
@ -93,10 +94,40 @@ extern cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor */
#define cpm_dpfree cpm_muram_free #define cpm_dpfree cpm_muram_free
#define cpm_dpram_addr cpm_muram_addr #define cpm_dpram_addr cpm_muram_addr
extern void cpm_setbrg(uint brg, uint rate);
extern void cpm2_fastbrg(uint brg, uint rate, int div16);
extern void cpm2_reset(void); extern void cpm2_reset(void);
/* Baud rate generators.
*/
#define CPM_BRG_RST ((uint)0x00020000)
#define CPM_BRG_EN ((uint)0x00010000)
#define CPM_BRG_EXTC_INT ((uint)0x00000000)
#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000)
#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000)
#define CPM_BRG_ATB ((uint)0x00002000)
#define CPM_BRG_CD_MASK ((uint)0x00001ffe)
#define CPM_BRG_DIV16 ((uint)0x00000001)
#define CPM2_BRG_INT_CLK (get_brgfreq())
#define CPM2_BRG_UART_CLK (CPM2_BRG_INT_CLK/16)
extern void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src);
/* This function is used by UARTS, or anything else that uses a 16x
* oversampled clock.
*/
static inline void cpm_setbrg(uint brg, uint rate)
{
__cpm2_setbrg(brg, rate, CPM2_BRG_UART_CLK, 0, CPM_BRG_EXTC_INT);
}
/* This function is used to set high speed synchronous baud rate
* clocks.
*/
static inline void cpm2_fastbrg(uint brg, uint rate, int div16)
{
__cpm2_setbrg(brg, rate, CPM2_BRG_INT_CLK, div16, CPM_BRG_EXTC_INT);
}
/* Function code bits, usually generic to devices. /* Function code bits, usually generic to devices.
*/ */
#define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ #define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */
@ -195,17 +226,6 @@ typedef struct smc_uart {
#define SMCM_TX ((unsigned char)0x02) #define SMCM_TX ((unsigned char)0x02)
#define SMCM_RX ((unsigned char)0x01) #define SMCM_RX ((unsigned char)0x01)
/* Baud rate generators.
*/
#define CPM_BRG_RST ((uint)0x00020000)
#define CPM_BRG_EN ((uint)0x00010000)
#define CPM_BRG_EXTC_INT ((uint)0x00000000)
#define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000)
#define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000)
#define CPM_BRG_ATB ((uint)0x00002000)
#define CPM_BRG_CD_MASK ((uint)0x00001ffe)
#define CPM_BRG_DIV16 ((uint)0x00000001)
/* SCCs. /* SCCs.
*/ */
#define SCC_GSMRH_IRP ((uint)0x00040000) #define SCC_GSMRH_IRP ((uint)0x00040000)

View File

@ -461,6 +461,8 @@ void pgtable_cache_init(void);
return pt; return pt;
} }
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address);
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */

View File

@ -143,6 +143,29 @@ static inline int page_cache_get_speculative(struct page *page)
return 1; return 1;
} }
/*
* Same as above, but add instead of inc (could just be merged)
*/
static inline int page_cache_add_speculative(struct page *page, int count)
{
VM_BUG_ON(in_interrupt());
#if !defined(CONFIG_SMP) && defined(CONFIG_CLASSIC_RCU)
# ifdef CONFIG_PREEMPT
VM_BUG_ON(!in_atomic());
# endif
VM_BUG_ON(page_count(page) == 0);
atomic_add(count, &page->_count);
#else
if (unlikely(!atomic_add_unless(&page->_count, count, 0)))
return 0;
#endif
VM_BUG_ON(PageCompound(page) && page != compound_head(page));
return 1;
}
static inline int page_freeze_refs(struct page *page, int count) static inline int page_freeze_refs(struct page *page, int count)
{ {
return likely(atomic_cmpxchg(&page->_count, count, 0) == count); return likely(atomic_cmpxchg(&page->_count, count, 0) == count);