Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6:
[IA64] Quicklist support for IA64
[IA64] fix Kprobes reentrancy
[IA64] SN: validate smp_affinity mask on intr redirect
[IA64] drivers/char/snsc_event.c:206: warning: unused variable `p'
[IA64] mca.c:121: warning: 'cpe_poll_timer' defined but not used
[IA64] Fix - Section mismatch: reference to .init.data:mvec_name
[IA64] more warning cleanups
[IA64] Wire up epoll_pwait and utimensat
[IA64] Fix warnings resulting from type-checking in dev_dbg()
[IA64] typo s/kenrel/kernel/
diff --git a/CREDITS b/CREDITS
index 6829e91..273d72b 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2299,8 +2299,8 @@
W: http://oops.ghostprotocols.net:81/blog/
P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD 841A B6AB 4681 9224 DF01
D: IPX, LLC, DCCP, cyc2x, wl3501_cs, net/ hacks
-S: R. Brasílio Itiberê, 4270/1010 - Água Verde
-S: 80240-060 - Curitiba - Paraná
+S: R. Brasílio Itiberê, 4270/1010 - Água Verde
+S: 80240-060 - Curitiba - Paraná
S: Brazil
N: Karsten Merker
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index 6491b2c..3af3e65 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -73,9 +73,9 @@
If the new code is substantial, addition of subsystem-specific fault
injection might be appropriate.
-22: Newly-added code has been compiled with `gcc -W'. This will generate
- lots of noise, but is good for finding bugs like "warning: comparison
- between signed and unsigned".
+22: Newly-added code has been compiled with `gcc -W' (use "make
+ EXTRA_CFLAGS=-W"). This will generate lots of noise, but is good for
+ finding bugs like "warning: comparison between signed and unsigned".
23: Tested after it has been merged into the -mm patchset to make sure
that it still works with all of the other queued patches and various
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 676b798..c6322c7 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -278,14 +278,6 @@
---------------------------
-What: i8xx_tco watchdog driver
-When: in 2.6.22
-Why: the i8xx_tco watchdog driver has been replaced by the iTCO_wdt
- watchdog driver.
-Who: Wim Van Sebroeck <wim@iguana.be>
-
----------------------------
-
What: Multipath cached routing support in ipv4
When: in 2.6.23
Why: Code was merged, then submitter immediately disappeared leaving
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index f8528db..e8be0ab 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -66,7 +66,9 @@
used for several very different kinds of GPIO controller.
That said, if the convention is supported on their platform, drivers should
-use it when possible:
+use it when possible. Platforms should declare GENERIC_GPIO support in
+Kconfig (boolean true), which multi-platform drivers can depend on when
+using the include file:
#include <asm/gpio.h>
diff --git a/Documentation/kref.txt b/Documentation/kref.txt
index 42fe284..f38b59d 100644
--- a/Documentation/kref.txt
+++ b/Documentation/kref.txt
@@ -67,7 +67,7 @@
.
. do stuff with data here
.
- kref_put(data, data_release);
+ kref_put(&data->refcount, data_release);
}
int my_data_handler(void)
diff --git a/Documentation/mips/pci/pci.README b/Documentation/mips/pci/pci.README
deleted file mode 100644
index 8697ee4..0000000
--- a/Documentation/mips/pci/pci.README
+++ /dev/null
@@ -1,54 +0,0 @@
-
-Pete Popov, ppopov@pacbell.net
-07/11/2001
-
-This README briefly explains how to use the pci and pci_auto
-code in arch/mips/kernel. The code was ported from PowerPC and
-modified slightly. It has been tested pretty well on PPC on some
-rather complex systems with multiple bridges and devices behind
-each bridge. However, at the time this README was written, the
-mips port was tested only on boards with a single pci bus and
-no P2P bridges. It's very possible that on boards with P2P
-bridges some modifications have to be made. The code will
-evolve, no doubt, but currently every single mips board
-is doing its own pcibios thing and it has become a big
-mess. This generic pci code is meant to clean up the mips
-pci mess and make it easier to add pci support to new boards.
-
-inside the define for your board in arch/mips/config.in.
-For example, the Galileo EV96100 board looks like this:
-
-if [ "$CONFIG_MIPS_EV96100" = "y" ]; then
- define_bool CONFIG_PCI y
- define_bool CONFIG_MIPS_GT96100 y
- define_bool CONFIG_NEW_PCI y
- define_bool CONFIG_SWAP_IO_SPACE y
-fi
-
-
-Next, if you want to use the arch/mips/kernel/pci code, which has the
-pcibios_init() function, add
-
-define_bool CONFIG_NEW_PCI y
-
-inside the define for your board. Again, the EV96100 example above
-show NEW_PCI turned on.
-
-
-Now you need to add your files to hook in your pci configuration
-cycles. Usually you'll need only a couple of files named something
-like pci_fixups.c and pci_ops.c. You can copy the templates
-provided and fill in the code.
-
-The file pci_ops.c should contain the pci configuration cycles routines.
-It also has the mips_pci_channels[] array which contains the descriptors
-of each pci controller.
-
-The file pci_fixups.c contains a few routines to do interrupt fixups,
-resources fixups, and, if needed, pci bios fixups.
-
-Usually you'll put your pci_fixups.c file in your board specific directory,
-since the functions in that file are board specific. The functions in
-pci_ops.c, on the other hand, are usually pci controller specific so that
-file could be shared among a few different boards using the same
-pci controller.
diff --git a/MAINTAINERS b/MAINTAINERS
index cfd26dd..bd558ac 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1718,12 +1718,6 @@
M: hpa@zytor.com
S: Maintained
-i810 TCO TIMER WATCHDOG
-P: Nils Faerber
-M: nils@kernelconcepts.de
-W: http://www.kernelconcepts.de/
-S: Maintained
-
IA64 (Itanium) PLATFORM
P: Tony Luck
M: tony.luck@intel.com
diff --git a/arch/frv/kernel/gdb-stub.c b/arch/frv/kernel/gdb-stub.c
index 9550f37..1e7a101 100644
--- a/arch/frv/kernel/gdb-stub.c
+++ b/arch/frv/kernel/gdb-stub.c
@@ -1195,7 +1195,7 @@
/*
*
*/
-static void __attribute__((unused)) gdbstub_show_regs(void)
+static void __maybe_unused gdbstub_show_regs(void)
{
unsigned long *reg;
int loop;
@@ -1223,7 +1223,7 @@
/*
* dump debugging regs
*/
-static void __attribute__((unused)) gdbstub_dump_debugregs(void)
+static void __maybe_unused gdbstub_dump_debugregs(void)
{
gdbstub_printk("DCR %08lx ", __debug_status.dcr);
gdbstub_printk("BRR %08lx\n", __debug_status.brr);
@@ -2079,25 +2079,25 @@
* GDB wants to call malloc() and free() to allocate memory for calling kernel
* functions directly from its command line
*/
-static void *malloc(size_t size) __attribute__((unused));
+static void *malloc(size_t size) __maybe_unused;
static void *malloc(size_t size)
{
return kmalloc(size, GFP_ATOMIC);
}
-static void free(void *p) __attribute__((unused));
+static void free(void *p) __maybe_unused;
static void free(void *p)
{
kfree(p);
}
-static uint32_t ___get_HSR0(void) __attribute__((unused));
+static uint32_t ___get_HSR0(void) __maybe_unused;
static uint32_t ___get_HSR0(void)
{
return __get_HSR(0);
}
-static uint32_t ___set_HSR0(uint32_t x) __attribute__((unused));
+static uint32_t ___set_HSR0(uint32_t x) __maybe_unused;
static uint32_t ___set_HSR0(uint32_t x)
{
__set_HSR(0, x);
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index dab98fd..54e21c3 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -31,7 +31,7 @@
.long SYMBOL_NAME(sys_mknod)
.long SYMBOL_NAME(sys_chmod) /* 15 */
.long SYMBOL_NAME(sys_chown16)
- .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old break syscall holder */
.long SYMBOL_NAME(sys_stat)
.long SYMBOL_NAME(sys_lseek)
.long SYMBOL_NAME(sys_getpid) /* 20 */
@@ -45,11 +45,11 @@
.long SYMBOL_NAME(sys_fstat)
.long SYMBOL_NAME(sys_pause)
.long SYMBOL_NAME(sys_utime) /* 30 */
- .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
- .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old stty syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old gtty syscall holder */
.long SYMBOL_NAME(sys_access)
.long SYMBOL_NAME(sys_nice)
- .long SYMBOL_NAME(sys_ni_syscall) /* 35 */ /* old ftime syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* 35 old ftime syscall holder */
.long SYMBOL_NAME(sys_sync)
.long SYMBOL_NAME(sys_kill)
.long SYMBOL_NAME(sys_rename)
@@ -58,7 +58,7 @@
.long SYMBOL_NAME(sys_dup)
.long SYMBOL_NAME(sys_pipe)
.long SYMBOL_NAME(sys_times)
- .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old prof syscall holder */
.long SYMBOL_NAME(sys_brk) /* 45 */
.long SYMBOL_NAME(sys_setgid16)
.long SYMBOL_NAME(sys_getgid16)
@@ -66,13 +66,13 @@
.long SYMBOL_NAME(sys_geteuid16)
.long SYMBOL_NAME(sys_getegid16) /* 50 */
.long SYMBOL_NAME(sys_acct)
- .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */
- .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
+ .long SYMBOL_NAME(sys_umount) /* recycled never used phys() */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old lock syscall holder */
.long SYMBOL_NAME(sys_ioctl)
.long SYMBOL_NAME(sys_fcntl) /* 55 */
- .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old mpx syscall holder */
.long SYMBOL_NAME(sys_setpgid)
- .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old ulimit syscall holder */
.long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_umask) /* 60 */
.long SYMBOL_NAME(sys_chroot)
@@ -112,7 +112,7 @@
.long SYMBOL_NAME(sys_fchown16) /* 95 */
.long SYMBOL_NAME(sys_getpriority)
.long SYMBOL_NAME(sys_setpriority)
- .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
+ .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */
.long SYMBOL_NAME(sys_statfs)
.long SYMBOL_NAME(sys_fstatfs) /* 100 */
.long SYMBOL_NAME(sys_ni_syscall) /* ioperm for i386 */
@@ -202,8 +202,8 @@
.long SYMBOL_NAME(sys_capset) /* 185 */
.long SYMBOL_NAME(sys_sigaltstack)
.long SYMBOL_NAME(sys_sendfile)
- .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
- .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
.long SYMBOL_NAME(sys_getrlimit)
.long SYMBOL_NAME(sys_mmap2)
@@ -236,10 +236,10 @@
.long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_getdents64) /* 220 */
.long SYMBOL_NAME(sys_fcntl64)
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved for TUX */
- .long SYMBOL_NAME(sys_ni_syscall)
+ .long SYMBOL_NAME(sys_ni_syscall) /* reserved TUX */
+ .long SYMBOL_NAME(sys_ni_syscall) /* reserved Security */
.long SYMBOL_NAME(sys_gettid)
- .long SYMBOL_NAME(sys_ni_syscall) /* 225 */ /* sys_readahead */
+ .long SYMBOL_NAME(sys_readahead) /* 225 */
.long SYMBOL_NAME(sys_setxattr)
.long SYMBOL_NAME(sys_lsetxattr)
.long SYMBOL_NAME(sys_fsetxattr)
@@ -257,8 +257,8 @@
.long SYMBOL_NAME(sys_futex) /* 240 */
.long SYMBOL_NAME(sys_sched_setaffinity)
.long SYMBOL_NAME(sys_sched_getaffinity)
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_set_thread_area */
- .long SYMBOL_NAME(sys_ni_syscall) /* sys_get_thread_area */
+ .long SYMBOL_NAME(sys_ni_syscall)
+ .long SYMBOL_NAME(sys_ni_syscall)
.long SYMBOL_NAME(sys_io_setup) /* 245 */
.long SYMBOL_NAME(sys_io_destroy)
.long SYMBOL_NAME(sys_io_getevents)
@@ -288,8 +288,8 @@
.long SYMBOL_NAME(sys_utimes)
.long SYMBOL_NAME(sys_fadvise64_64)
.long SYMBOL_NAME(sys_ni_syscall) /* sys_vserver */
- .long SYMBOL_NAME(sys_mbind)
- .long SYMBOL_NAME(sys_get_mempolicy)
+ .long SYMBOL_NAME(sys_ni_syscall)
+ .long SYMBOL_NAME(sys_get_mempolicy) /* 275 */
.long SYMBOL_NAME(sys_set_mempolicy)
.long SYMBOL_NAME(sys_mq_open)
.long SYMBOL_NAME(sys_mq_unlink)
@@ -297,16 +297,42 @@
.long SYMBOL_NAME(sys_mq_timedreceive) /* 280 */
.long SYMBOL_NAME(sys_mq_notify)
.long SYMBOL_NAME(sys_mq_getsetattr)
- .long SYMBOL_NAME(sys_ni_syscall) /* reserved for kexec */
.long SYMBOL_NAME(sys_waitid)
- .long SYMBOL_NAME(sys_ni_syscall) /* 285 */ /* available */
- .long SYMBOL_NAME(sys_add_key)
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_kexec_load */
+ .long SYMBOL_NAME(sys_add_key) /* 285 */
.long SYMBOL_NAME(sys_request_key)
.long SYMBOL_NAME(sys_keyctl)
-
- .rept NR_syscalls-(.-SYMBOL_NAME(sys_call_table))/4
- .long SYMBOL_NAME(sys_ni_syscall)
- .endr
+ .long SYMBOL_NAME(sys_ioprio_set)
+ .long SYMBOL_NAME(sys_ioprio_get) /* 290 */
+ .long SYMBOL_NAME(sys_inotify_init)
+ .long SYMBOL_NAME(sys_inotify_add_watch)
+ .long SYMBOL_NAME(sys_inotify_rm_watch)
+ .long SYMBOL_NAME(sys_migrate_pages)
+ .long SYMBOL_NAME(sys_openat) /* 295 */
+ .long SYMBOL_NAME(sys_mkdirat)
+ .long SYMBOL_NAME(sys_mknodat)
+ .long SYMBOL_NAME(sys_fchownat)
+ .long SYMBOL_NAME(sys_futimesat)
+ .long SYMBOL_NAME(sys_fstatat64) /* 300 */
+ .long SYMBOL_NAME(sys_unlinkat)
+ .long SYMBOL_NAME(sys_renameat)
+ .long SYMBOL_NAME(sys_linkat)
+ .long SYMBOL_NAME(sys_symlinkat)
+ .long SYMBOL_NAME(sys_readlinkat) /* 305 */
+ .long SYMBOL_NAME(sys_fchmodat)
+ .long SYMBOL_NAME(sys_faccessat)
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_pselect6 */
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_ppoll */
+ .long SYMBOL_NAME(sys_unshare) /* 310 */
+ .long SYMBOL_NAME(sys_set_robust_list)
+ .long SYMBOL_NAME(sys_get_robust_list)
+ .long SYMBOL_NAME(sys_splice)
+ .long SYMBOL_NAME(sys_sync_file_range)
+ .long SYMBOL_NAME(sys_tee) /* 315 */
+ .long SYMBOL_NAME(sys_vmsplice)
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_move_pages */
+ .long SYMBOL_NAME(sys_getcpu)
+ .long SYMBOL_NAME(sys_ni_syscall) /* sys_epoll_pwait */
.macro call_sp addr
mov.l #SYMBOL_NAME(\addr),er6
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index 9b10af6..f74dfc4 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -71,12 +71,6 @@
.section .text.head,"ax",@progbits
ENTRY(startup_32)
-#ifdef CONFIG_PARAVIRT
- movl %cs, %eax
- testl $0x3, %eax
- jnz startup_paravirt
-#endif
-
/*
* Set segments to known values.
*/
@@ -501,38 +495,6 @@
iret
.section .text
-#ifdef CONFIG_PARAVIRT
-startup_paravirt:
- cld
- movl $(init_thread_union+THREAD_SIZE),%esp
-
- /* We take pains to preserve all the regs. */
- pushl %edx
- pushl %ecx
- pushl %eax
-
- pushl $__start_paravirtprobe
-1:
- movl 0(%esp), %eax
- cmpl $__stop_paravirtprobe, %eax
- je unhandled_paravirt
- pushl (%eax)
- movl 8(%esp), %eax
- call *(%esp)
- popl %eax
-
- movl 4(%esp), %eax
- movl 8(%esp), %ecx
- movl 12(%esp), %edx
-
- addl $4, (%esp)
- jmp 1b
-
-unhandled_paravirt:
- /* Nothing wanted us: we're screwed. */
- ud2
-#endif
-
/*
* Real beginning of normal "text" segment
*/
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c
index 5c10f37..faab09a 100644
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/efi.h>
#include <linux/bcd.h>
-#include <linux/start_kernel.h>
#include <linux/highmem.h>
#include <asm/bug.h>
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 0772678..bf6adce 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -320,3 +320,6 @@
.long sys_getcpu
.long sys_epoll_pwait
.long sys_utimensat /* 320 */
+ .long sys_signalfd
+ .long sys_timerfd
+ .long sys_eventfd
diff --git a/arch/i386/kernel/verify_cpu.S b/arch/i386/kernel/verify_cpu.S
index e51a869..b2a9d80 100644
--- a/arch/i386/kernel/verify_cpu.S
+++ b/arch/i386/kernel/verify_cpu.S
@@ -10,7 +10,9 @@
#if CONFIG_X86_MINIMUM_CPU_MODEL >= 4
pushfl
- orl $(1<<18),(%esp) # try setting AC
+ pop %eax
+ orl $(1<<18),%eax # try setting AC
+ push %eax
popfl
pushfl
popl %eax
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 23e8614..80bec66 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -78,12 +78,6 @@
CONSTRUCTORS
} :data
- .paravirtprobe : AT(ADDR(.paravirtprobe) - LOAD_OFFSET) {
- __start_paravirtprobe = .;
- *(.paravirtprobe)
- __stop_paravirtprobe = .;
- }
-
. = ALIGN(4096);
.data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
__nosave_begin = .;
diff --git a/arch/ia64/ia32/audit.c b/arch/ia64/ia32/audit.c
index 92d7d0c..8850fe4 100644
--- a/arch/ia64/ia32/audit.c
+++ b/arch/ia64/ia32/audit.c
@@ -20,6 +20,11 @@
~0U
};
+unsigned ia32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
int ia32_classify_syscall(unsigned syscall)
{
switch(syscall) {
diff --git a/arch/ia64/kernel/audit.c b/arch/ia64/kernel/audit.c
index 0468255..f3802ae 100644
--- a/arch/ia64/kernel/audit.c
+++ b/arch/ia64/kernel/audit.c
@@ -23,6 +23,20 @@
~0U
};
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_IA32_SUPPORT
+ if (arch == AUDIT_ARCH_I386)
+ return 1;
+#endif
+ return 0;
+}
+
int audit_classify_syscall(int abi, unsigned syscall)
{
#ifdef CONFIG_IA32_SUPPORT
@@ -49,15 +63,18 @@
extern __u32 ia32_write_class[];
extern __u32 ia32_read_class[];
extern __u32 ia32_chattr_class[];
+ extern __u32 ia32_signal_class[];
audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class);
audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, ia32_signal_class);
#endif
audit_register_class(AUDIT_CLASS_WRITE, write_class);
audit_register_class(AUDIT_CLASS_READ, read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
return 0;
}
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 9740d6b..c3bb8a75 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -241,6 +241,10 @@
bool
default y
+config SCHED_NO_NO_OMIT_FRAME_POINTER
+ bool
+ default y
+
config PREEMPT
bool "Preemptible Kernel"
help
diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S
index 8bb74b1..49a6d16 100644
--- a/arch/m32r/mm/mmu.S
+++ b/arch/m32r/mm/mmu.S
@@ -163,7 +163,8 @@
; pte_data = (unsigned long)pte_val(*pte);
ld r2, @r3 ; r2: pte data
- or3 r2, r2, #2 ; _PAGE_PRESENT(=2)
+ and3 r3, r2, #2 ; _PAGE_PRESENT(=2) check
+ beqz r3, 3f
.fillinsn
5:
@@ -264,11 +265,8 @@
;
and3 r1, r1, #0xeff
ldi r4, #611 ; _KERNPG_TABLE(=611)
- beq r1, r4, 4f ; !pmd_bad(*pmd) ?
- .fillinsn
-3:
- ldi r1, #0 ; r1: pte_data = 0
- bra 5f
+ bne r1, r4, 3f ; !pmd_bad(*pmd) ?
+
.fillinsn
4:
; pte = pte_offset(pmd, address);
@@ -282,8 +280,10 @@
add r4, r3 ; r4: pte
; pte_data = (unsigned long)pte_val(*pte);
ld r1, @r4 ; r1: pte_data
- .fillinsn
+ and3 r3, r1, #2 ; _PAGE_PRESENT(=2) check
+ beqz r3, 3f
+ .fillinsn
;; set tlb
; r0: address, r1: pte_data, r2: entry
; r3,r4: (free)
@@ -295,8 +295,7 @@
and3 r4, r4, #(MMU_CONTEXT_ASID_MASK)
or r3, r4
st r3, @r2
- or3 r4, r1, #2 ; _PAGE_PRESENT(=2)
- st r4, @(4,r2) ; set_tlb_data(entry, pte_data);
+ st r1, @(4,r2) ; set_tlb_data(entry, pte_data);
ld r4, @sp+
ld r3, @sp+
@@ -306,6 +305,11 @@
ld sp, @sp+
rte
+ .fillinsn
+3:
+ ldi r1, #2 ; r1: pte_data = 0 | _PAGE_PRESENT(=2)
+ bra 5b
+
#else
#error unknown isa configuration
#endif
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 16ecea3..0f09412 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -15,121 +15,8 @@
prompt "System type"
default SGI_IP22
-config MIPS_MTX1
- bool "4G Systems MTX-1 board"
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select RESOURCES_64BIT if PCI
- select SOC_AU1500
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_BOSPORUS
- bool "AMD Alchemy Bosporus board"
- select SOC_AU1500
- select DMA_NONCOHERENT
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_PB1000
- bool "AMD Alchemy PB1000 board"
- select SOC_AU1000
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select RESOURCES_64BIT if PCI
- select SWAP_IO_SPACE
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_PB1100
- bool "AMD Alchemy PB1100 board"
- select SOC_AU1100
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select RESOURCES_64BIT if PCI
- select SWAP_IO_SPACE
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_PB1500
- bool "AMD Alchemy PB1500 board"
- select SOC_AU1500
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select RESOURCES_64BIT if PCI
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_PB1550
- bool "AMD Alchemy PB1550 board"
- select SOC_AU1550
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select MIPS_DISABLE_OBSOLETE_IDE
- select RESOURCES_64BIT if PCI
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_PB1200
- bool "AMD Alchemy PB1200 board"
- select SOC_AU1200
- select DMA_NONCOHERENT
- select MIPS_DISABLE_OBSOLETE_IDE
- select RESOURCES_64BIT if PCI
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_DB1000
- bool "AMD Alchemy DB1000 board"
- select SOC_AU1000
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select RESOURCES_64BIT if PCI
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_DB1100
- bool "AMD Alchemy DB1100 board"
- select SOC_AU1100
- select DMA_NONCOHERENT
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_DB1500
- bool "AMD Alchemy DB1500 board"
- select SOC_AU1500
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select MIPS_DISABLE_OBSOLETE_IDE
- select RESOURCES_64BIT if PCI
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_BIG_ENDIAN
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_DB1550
- bool "AMD Alchemy DB1550 board"
- select SOC_AU1550
- select HW_HAS_PCI
- select DMA_NONCOHERENT
- select MIPS_DISABLE_OBSOLETE_IDE
- select RESOURCES_64BIT if PCI
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_DB1200
- bool "AMD Alchemy DB1200 board"
- select SOC_AU1200
- select DMA_COHERENT
- select MIPS_DISABLE_OBSOLETE_IDE
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
-config MIPS_MIRAGE
- bool "AMD Alchemy Mirage board"
- select DMA_NONCOHERENT
- select SOC_AU1500
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_LITTLE_ENDIAN
+config MACH_ALCHEMY
+ bool "Alchemy processor based machines"
config BASLER_EXCITE
bool "Basler eXcite smart camera"
@@ -369,28 +256,6 @@
This option enables support for MIPS Technologies MIPSsim software
emulator.
-config MOMENCO_JAGUAR_ATX
- bool "Momentum Jaguar board"
- select BOOT_ELF32
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select IRQ_CPU
- select IRQ_CPU_RM7K
- select IRQ_MV64340
- select LIMITED_DMA
- select PCI_MARVELL
- select RM7000_CPU_SCACHE
- select SWAP_IO_SPACE
- select SYS_HAS_CPU_RM9000
- select SYS_HAS_EARLY_PRINTK
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL
- select SYS_SUPPORTS_BIG_ENDIAN
- select SYS_SUPPORTS_KGDB
- help
- The Jaguar ATX is a MIPS-based Single Board Computer (SBC) made by
- Momentum Computer <http://www.momenco.com/>.
-
config MOMENCO_OCELOT
bool "Momentum Ocelot board"
select DMA_NONCOHERENT
@@ -446,29 +311,6 @@
The Ocelot is a MIPS-based Single Board Computer (SBC) made by
Momentum Computer <http://www.momenco.com/>.
-config MOMENCO_OCELOT_G
- bool "Momentum Ocelot-G board"
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select IRQ_CPU
- select IRQ_CPU_RM7K
- select PCI_MARVELL
- select RM7000_CPU_SCACHE
- select SWAP_IO_SPACE
- select SYS_HAS_CPU_RM7000
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL if BROKEN
- select SYS_SUPPORTS_BIG_ENDIAN
- help
- The Ocelot is a MIPS-based Single Board Computer (SBC) made by
- Momentum Computer <http://www.momenco.com/>.
-
-config MIPS_XXS1500
- bool "MyCable XXS1500 board"
- select DMA_NONCOHERENT
- select SOC_AU1500
- select SYS_SUPPORTS_LITTLE_ENDIAN
-
config PNX8550_JBS
bool "Philips PNX8550 based JBS board"
select PNX8550
@@ -775,7 +617,6 @@
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_BIG_ENDIAN
- select TOSHIBA_BOARDS
select GENERIC_HARDIRQS_NO__DO_IRQ
config TOSHIBA_RBTX4927
@@ -791,7 +632,6 @@
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_KGDB
- select TOSHIBA_BOARDS
select GENERIC_HARDIRQS_NO__DO_IRQ
help
This Toshiba board is based on the TX4927 processor. Say Y here to
@@ -811,7 +651,6 @@
select SYS_SUPPORTS_LITTLE_ENDIAN
select SYS_SUPPORTS_BIG_ENDIAN
select SYS_SUPPORTS_KGDB
- select TOSHIBA_BOARDS
select GENERIC_HARDIRQS_NO__DO_IRQ
help
This Toshiba board is based on the TX4938 processor. Say Y here to
@@ -819,11 +658,11 @@
endchoice
+source "arch/mips/au1000/Kconfig"
source "arch/mips/ddb5xxx/Kconfig"
source "arch/mips/gt64120/ev64120/Kconfig"
source "arch/mips/jazz/Kconfig"
source "arch/mips/lasat/Kconfig"
-source "arch/mips/momentum/Kconfig"
source "arch/mips/pmc-sierra/Kconfig"
source "arch/mips/sgi-ip27/Kconfig"
source "arch/mips/sibyte/Kconfig"
@@ -923,11 +762,6 @@
config I8259
bool
-config LIMITED_DMA
- bool
- select HIGHMEM
- select SYS_SUPPORTS_HIGHMEM
-
config MIPS_BONITO64
bool
@@ -1013,33 +847,6 @@
config PCI_MARVELL
bool
-config SOC_AU1000
- bool
- select SOC_AU1X00
-
-config SOC_AU1100
- bool
- select SOC_AU1X00
-
-config SOC_AU1500
- bool
- select SOC_AU1X00
-
-config SOC_AU1550
- bool
- select SOC_AU1X00
-
-config SOC_AU1200
- bool
- select SOC_AU1X00
-
-config SOC_AU1X00
- bool
- select SYS_HAS_CPU_MIPS32_R1
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_APM_EMULATION
- select SYS_SUPPORTS_KGDB
-
config SERIAL_RM9000
bool
@@ -1081,9 +888,9 @@
choice
prompt "Galileo Chip Clock"
#default SYSCLK_83 if MIPS_EV64120
- depends on MIPS_EV64120 || MOMENCO_OCELOT || MOMENCO_OCELOT_G
+ depends on MIPS_EV64120 || MOMENCO_OCELOT
default SYSCLK_83 if MIPS_EV64120
- default SYSCLK_100 if MOMENCO_OCELOT || MOMENCO_OCELOT_G
+ default SYSCLK_100 if MOMENCO_OCELOT
config SYSCLK_75
bool "75" if MIPS_EV64120
@@ -1092,7 +899,7 @@
bool "83.3" if MIPS_EV64120
config SYSCLK_100
- bool "100" if MIPS_EV64120 || MOMENCO_OCELOT || MOMENCO_OCELOT_G
+ bool "100" if MIPS_EV64120 || MOMENCO_OCELOT
endchoice
@@ -1131,9 +938,6 @@
config BOOT_ELF64
bool
-config TOSHIBA_BOARDS
- bool
-
menu "CPU selection"
choice
@@ -1557,6 +1361,7 @@
bool "Use 1 TC on each available VPE for SMP"
depends on SYS_SUPPORTS_MULTITHREADING
select CPU_MIPSR2_IRQ_VI
+ select CPU_MIPSR2_IRQ_EI
select CPU_MIPSR2_SRS
select MIPS_MT
select NR_CPUS_DEFAULT_2
@@ -1572,6 +1377,7 @@
#depends on CPU_MIPS64_R2 # once there is hardware ...
depends on SYS_SUPPORTS_MULTITHREADING
select CPU_MIPSR2_IRQ_VI
+ select CPU_MIPSR2_IRQ_EI
select CPU_MIPSR2_SRS
select MIPS_MT
select NR_CPUS_DEFAULT_8
@@ -1584,6 +1390,8 @@
config MIPS_VPE_LOADER
bool "VPE loader support."
depends on SYS_SUPPORTS_MULTITHREADING
+ select CPU_MIPSR2_IRQ_VI
+ select CPU_MIPSR2_IRQ_EI
select MIPS_MT
help
Includes a loader for loading an elf relocatable object
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 4892db8..f450066 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -343,15 +343,6 @@
load-$(CONFIG_MOMENCO_OCELOT) += 0xffffffff80100000
#
-# Momentum Ocelot-G board
-#
-# The Ocelot-G setup.o must be linked early - it does the ioremap() for the
-# mips_io_port_base.
-#
-core-$(CONFIG_MOMENCO_OCELOT_G) += arch/mips/momentum/ocelot_g/
-load-$(CONFIG_MOMENCO_OCELOT_G) += 0xffffffff80100000
-
-#
# Momentum Ocelot-C and -CS boards
#
# The Ocelot-C[S] setup.o must be linked early - it does the ioremap() for the
@@ -388,17 +379,6 @@
load-$(CONFIG_BASLER_EXCITE) += 0x80100000
#
-# Momentum Jaguar ATX
-#
-core-$(CONFIG_MOMENCO_JAGUAR_ATX) += arch/mips/momentum/jaguar_atx/
-cflags-$(CONFIG_MOMENCO_JAGUAR_ATX) += -Iinclude/asm-mips/mach-ja
-#ifdef CONFIG_JAGUAR_DMALOW
-#load-$(CONFIG_MOMENCO_JAGUAR_ATX) += 0xffffffff88000000
-#else
-load-$(CONFIG_MOMENCO_JAGUAR_ATX) += 0xffffffff80100000
-#endif
-
-#
# NEC DDB
#
core-$(CONFIG_DDB5XXX_COMMON) += arch/mips/ddb5xxx/common/
@@ -729,3 +709,25 @@
CLEAN_FILES += vmlinux.32 \
vmlinux.64 \
vmlinux.ecoff
+
+quiet_cmd_syscalls_n32 = CALL-N32 $<
+ cmd_syscalls_n32 = $(CONFIG_SHELL) $< $(CC) $(c_flags) -mabi=n32
+
+quiet_cmd_syscalls_o32 = CALL-O32 $<
+ cmd_syscalls_o32 = $(CONFIG_SHELL) $< $(CC) $(c_flags) -mabi=32
+
+PHONY += missing-syscalls-n32 missing-syscalls-o32
+
+missing-syscalls-n32: scripts/checksyscalls.sh FORCE
+ $(call cmd,syscalls_n32)
+
+missing-syscalls-o32: scripts/checksyscalls.sh FORCE
+ $(call cmd,syscalls_o32)
+
+archprepare:
+ifdef CONFIG_MIPS32_N32
+ $(Q)$(MAKE) $(build)=arch/mips missing-syscalls-n32
+endif
+ifdef CONFIG_MIPS32_O32
+ $(Q)$(MAKE) $(build)=arch/mips missing-syscalls-o32
+endif
diff --git a/arch/mips/au1000/Kconfig b/arch/mips/au1000/Kconfig
new file mode 100644
index 0000000..abea880
--- /dev/null
+++ b/arch/mips/au1000/Kconfig
@@ -0,0 +1,142 @@
+choice
+ prompt "Machine type"
+ depends on MACH_ALCHEMY
+ default MIPS_DB1000
+
+config MIPS_MTX1
+ bool "4G Systems MTX-1 board"
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select RESOURCES_64BIT if PCI
+ select SOC_AU1500
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_BOSPORUS
+ bool "Alchemy Bosporus board"
+ select SOC_AU1500
+ select DMA_NONCOHERENT
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_DB1000
+ bool "Alchemy DB1000 board"
+ select SOC_AU1000
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select RESOURCES_64BIT if PCI
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_DB1100
+ bool "Alchemy DB1100 board"
+ select SOC_AU1100
+ select DMA_NONCOHERENT
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_DB1200
+ bool "Alchemy DB1200 board"
+ select SOC_AU1200
+ select DMA_COHERENT
+ select MIPS_DISABLE_OBSOLETE_IDE
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_DB1500
+ bool "Alchemy DB1500 board"
+ select SOC_AU1500
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select MIPS_DISABLE_OBSOLETE_IDE
+ select RESOURCES_64BIT if PCI
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_DB1550
+ bool "Alchemy DB1550 board"
+ select SOC_AU1550
+ select HW_HAS_PCI
+ select DMA_NONCOHERENT
+ select MIPS_DISABLE_OBSOLETE_IDE
+ select RESOURCES_64BIT if PCI
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_MIRAGE
+ bool "Alchemy Mirage board"
+ select DMA_NONCOHERENT
+ select SOC_AU1500
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_PB1000
+ bool "Alchemy PB1000 board"
+ select SOC_AU1000
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select RESOURCES_64BIT if PCI
+ select SWAP_IO_SPACE
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_PB1100
+ bool "Alchemy PB1100 board"
+ select SOC_AU1100
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select RESOURCES_64BIT if PCI
+ select SWAP_IO_SPACE
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_PB1200
+ bool "Alchemy PB1200 board"
+ select SOC_AU1200
+ select DMA_NONCOHERENT
+ select MIPS_DISABLE_OBSOLETE_IDE
+ select RESOURCES_64BIT if PCI
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_PB1500
+ bool "Alchemy PB1500 board"
+ select SOC_AU1500
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select RESOURCES_64BIT if PCI
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_PB1550
+ bool "Alchemy PB1550 board"
+ select SOC_AU1550
+ select DMA_NONCOHERENT
+ select HW_HAS_PCI
+ select MIPS_DISABLE_OBSOLETE_IDE
+ select RESOURCES_64BIT if PCI
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+config MIPS_XXS1500
+ bool "MyCable XXS1500 board"
+ select DMA_NONCOHERENT
+ select SOC_AU1500
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+
+endchoice
+
+config SOC_AU1000
+ bool
+ select SOC_AU1X00
+
+config SOC_AU1100
+ bool
+ select SOC_AU1X00
+
+config SOC_AU1500
+ bool
+ select SOC_AU1X00
+
+config SOC_AU1550
+ bool
+ select SOC_AU1X00
+
+config SOC_AU1200
+ bool
+ select SOC_AU1X00
+
+config SOC_AU1X00
+ bool
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_APM_EMULATION
+ select SYS_SUPPORTS_KGDB
diff --git a/arch/mips/basler/excite/excite_device.c b/arch/mips/basler/excite/excite_device.c
index cc1ce77..e00bc2d 100644
--- a/arch/mips/basler/excite/excite_device.c
+++ b/arch/mips/basler/excite/excite_device.c
@@ -68,7 +68,7 @@
static struct resource
- excite_ctr_resource __attribute__((unused)) = {
+ excite_ctr_resource __maybe_unused = {
.name = "GPI counters",
.start = 0,
.end = 5,
@@ -77,7 +77,7 @@
.sibling = NULL,
.child = NULL
},
- excite_gpislice_resource __attribute__((unused)) = {
+ excite_gpislice_resource __maybe_unused = {
.name = "GPI slices",
.start = 0,
.end = 1,
@@ -86,7 +86,7 @@
.sibling = NULL,
.child = NULL
},
- excite_mdio_channel_resource __attribute__((unused)) = {
+ excite_mdio_channel_resource __maybe_unused = {
.name = "MDIO channels",
.start = 0,
.end = 1,
@@ -95,7 +95,7 @@
.sibling = NULL,
.child = NULL
},
- excite_fifomem_resource __attribute__((unused)) = {
+ excite_fifomem_resource __maybe_unused = {
.name = "FIFO memory",
.start = 0,
.end = 767,
@@ -104,7 +104,7 @@
.sibling = NULL,
.child = NULL
},
- excite_scram_resource __attribute__((unused)) = {
+ excite_scram_resource __maybe_unused = {
.name = "Scratch RAM",
.start = EXCITE_PHYS_SCRAM,
.end = EXCITE_PHYS_SCRAM + EXCITE_SIZE_SCRAM - 1,
@@ -113,7 +113,7 @@
.sibling = NULL,
.child = NULL
},
- excite_fpga_resource __attribute__((unused)) = {
+ excite_fpga_resource __maybe_unused = {
.name = "System FPGA",
.start = EXCITE_PHYS_FPGA,
.end = EXCITE_PHYS_FPGA + EXCITE_SIZE_FPGA - 1,
@@ -122,7 +122,7 @@
.sibling = NULL,
.child = NULL
},
- excite_nand_resource __attribute__((unused)) = {
+ excite_nand_resource __maybe_unused = {
.name = "NAND flash control",
.start = EXCITE_PHYS_NAND,
.end = EXCITE_PHYS_NAND + EXCITE_SIZE_NAND - 1,
@@ -131,7 +131,7 @@
.sibling = NULL,
.child = NULL
},
- excite_titan_resource __attribute__((unused)) = {
+ excite_titan_resource __maybe_unused = {
.name = "TITAN registers",
.start = EXCITE_PHYS_TITAN,
.end = EXCITE_PHYS_TITAN + EXCITE_SIZE_TITAN - 1,
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index 9565b21..c292f80 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -2,7 +2,7 @@
# Makefile for the Cobalt micro systems family specific parts of the kernel
#
-obj-y := irq.o reset.o setup.o buttons.o
+obj-y := buttons.o irq.o reset.o rtc.o serial.o setup.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_EARLY_PRINTK) += console.o
diff --git a/arch/mips/cobalt/rtc.c b/arch/mips/cobalt/rtc.c
new file mode 100644
index 0000000..284daef
--- /dev/null
+++ b/arch/mips/cobalt/rtc.c
@@ -0,0 +1,63 @@
+/*
+ * Registration of Cobalt RTC platform device.
+ *
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+
+static struct resource cobalt_rtc_resource[] __initdata = {
+ {
+ .start = 0x70,
+ .end = 0x77,
+ .flags = IORESOURCE_IO,
+ },
+ {
+ .start = 8,
+ .end = 8,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static __init int cobalt_rtc_add(void)
+{
+ struct platform_device *pdev;
+ int retval;
+
+ pdev = platform_device_alloc("rtc_cmos", -1);
+ if (!pdev)
+ return -ENOMEM;
+
+ retval = platform_device_add_resources(pdev, cobalt_rtc_resource,
+ ARRAY_SIZE(cobalt_rtc_resource));
+ if (retval)
+ goto err_free_device;
+
+ retval = platform_device_add(pdev);
+ if (retval)
+ goto err_free_device;
+
+ return 0;
+
+err_free_device:
+ platform_device_put(pdev);
+
+ return retval;
+}
+device_initcall(cobalt_rtc_add);
diff --git a/arch/mips/cobalt/serial.c b/arch/mips/cobalt/serial.c
new file mode 100644
index 0000000..c271165
--- /dev/null
+++ b/arch/mips/cobalt/serial.c
@@ -0,0 +1,85 @@
+/*
+ * Registration of Cobalt UART platform device.
+ *
+ * Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+
+#include <cobalt.h>
+
+static struct resource cobalt_uart_resource[] __initdata = {
+ {
+ .start = 0x1c800000,
+ .end = 0x1c800007,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = COBALT_SERIAL_IRQ,
+ .end = COBALT_SERIAL_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct plat_serial8250_port cobalt_serial8250_port[] = {
+ {
+ .irq = COBALT_SERIAL_IRQ,
+ .uartclk = 18432000,
+ .iotype = UPIO_MEM,
+ .flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ .mapbase = 0x1c800000,
+ },
+ {},
+};
+
+static __init int cobalt_uart_add(void)
+{
+ struct platform_device *pdev;
+ int retval;
+
+ /*
+ * Cobalt Qube1 and RAQ1 have no UART.
+ */
+ if (cobalt_board_id <= COBALT_BRD_ID_RAQ1)
+ return 0;
+
+ pdev = platform_device_alloc("serial8250", -1);
+ if (!pdev)
+ return -ENOMEM;
+
+ pdev->id = PLAT8250_DEV_PLATFORM;
+ pdev->dev.platform_data = cobalt_serial8250_port;
+
+ retval = platform_device_add_resources(pdev, cobalt_uart_resource, ARRAY_SIZE(cobalt_uart_resource));
+ if (retval)
+ goto err_free_device;
+
+ retval = platform_device_add(pdev);
+ if (retval)
+ goto err_free_device;
+
+ return 0;
+
+err_free_device:
+ platform_device_put(pdev);
+
+ return retval;
+}
+device_initcall(cobalt_uart_add);
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index d0dd817..7abe45e 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -10,11 +10,8 @@
*
*/
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/init.h>
#include <linux/pm.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
#include <asm/bootinfo.h>
#include <asm/time.h>
@@ -27,9 +24,6 @@
extern void cobalt_machine_restart(char *command);
extern void cobalt_machine_halt(void);
extern void cobalt_machine_power_off(void);
-extern void cobalt_early_console(void);
-
-int cobalt_board_id;
const char *get_system_type(void)
{
@@ -95,8 +89,6 @@
void __init plat_mem_setup(void)
{
- static struct uart_port uart;
- unsigned int devfn = PCI_DEVFN(COBALT_PCICONF_VIA, 0);
int i;
_machine_restart = cobalt_machine_restart;
@@ -111,29 +103,6 @@
/* These resources have been reserved by VIA SuperI/O chip. */
for (i = 0; i < ARRAY_SIZE(cobalt_reserved_resources); i++)
request_resource(&ioport_resource, cobalt_reserved_resources + i);
-
- /* Read the cobalt id register out of the PCI config space */
- PCI_CFG_SET(devfn, (VIA_COBALT_BRD_ID_REG & ~0x3));
- cobalt_board_id = GT_READ(GT_PCI0_CFGDATA_OFS);
- cobalt_board_id >>= ((VIA_COBALT_BRD_ID_REG & 3) * 8);
- cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(cobalt_board_id);
-
- printk("Cobalt board ID: %d\n", cobalt_board_id);
-
- if (cobalt_board_id > COBALT_BRD_ID_RAQ1) {
-#ifdef CONFIG_SERIAL_8250
- uart.line = 0;
- uart.type = PORT_UNKNOWN;
- uart.uartclk = 18432000;
- uart.irq = COBALT_SERIAL_IRQ;
- uart.flags = UPF_IOREMAP | UPF_BOOT_AUTOCONF |
- UPF_SKIP_TEST;
- uart.iotype = UPIO_MEM;
- uart.mapbase = 0x1c800000;
-
- early_serial_setup(&uart);
-#endif
- }
}
/*
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
index ba593b5..631b213 100644
--- a/arch/mips/configs/cobalt_defconfig
+++ b/arch/mips/configs/cobalt_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Tue Feb 20 21:47:24 2007
+# Linux kernel version: 2.6.21-rc7
+# Wed Apr 18 14:25:45 2007
#
CONFIG_MIPS=y
@@ -62,7 +62,6 @@
# CONFIG_TOSHIBA_JMR3927 is not set
# CONFIG_TOSHIBA_RBTX4927 is not set
# CONFIG_TOSHIBA_RBTX4938 is not set
-CONFIG_EARLY_PRINTK=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -74,12 +73,14 @@
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_SYS_HAS_EARLY_PRINTK=y
CONFIG_I8259=y
# CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_IRQ_CPU=y
-CONFIG_MIPS_GT64111=y
+CONFIG_PCI_GT64XXX_PCI0=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
@@ -179,6 +180,7 @@
# CONFIG_IKCONFIG is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_RELAY=y
+# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -477,7 +479,6 @@
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
CONFIG_CDROM_PKTCDVD=y
CONFIG_CDROM_PKTCDVD_BUFFERS=8
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
@@ -518,7 +519,7 @@
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-# CONFIG_IDEDMA_PCI_AUTO is not set
+# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
# CONFIG_BLK_DEV_AMD74XX is not set
@@ -546,7 +547,6 @@
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
# CONFIG_BLK_DEV_HD is not set
#
@@ -779,7 +779,8 @@
#
# CONFIG_WATCHDOG is not set
# CONFIG_HW_RANDOM is not set
-CONFIG_RTC=y
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
CONFIG_COBALT_LCD=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -815,6 +816,11 @@
# CONFIG_HWMON_VID is not set
#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -827,7 +833,7 @@
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
# CONFIG_FB is not set
#
@@ -835,7 +841,6 @@
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -894,7 +899,29 @@
#
# Real Time Clock
#
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+
+#
+# RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_TEST is not set
+# CONFIG_RTC_DRV_V3020 is not set
#
# DMA Engine support
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
index 0db6a8b..10f6af4 100644
--- a/arch/mips/configs/db1000_defconfig
+++ b/arch/mips/configs/db1000_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
index 162add9..4b08629 100644
--- a/arch/mips/configs/db1100_defconfig
+++ b/arch/mips/configs/db1100_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
index 82801ec..820659e 100644
--- a/arch/mips/configs/db1200_defconfig
+++ b/arch/mips/configs/db1200_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
index 545f230..4050b9b 100644
--- a/arch/mips/configs/db1500_defconfig
+++ b/arch/mips/configs/db1500_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
index 5bd3b43..7b35190 100644
--- a/arch/mips/configs/db1550_defconfig
+++ b/arch/mips/configs/db1550_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig
deleted file mode 100644
index 083104d..0000000
--- a/arch/mips/configs/jaguar-atx_defconfig
+++ /dev/null
@@ -1,897 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Tue Feb 20 21:47:33 2007
-#
-CONFIG_MIPS=y
-
-#
-# Machine selection
-#
-CONFIG_ZONE_DMA=y
-# CONFIG_MIPS_MTX1 is not set
-# CONFIG_MIPS_BOSPORUS is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1100 is not set
-# CONFIG_MIPS_PB1500 is not set
-# CONFIG_MIPS_PB1550 is not set
-# CONFIG_MIPS_PB1200 is not set
-# CONFIG_MIPS_DB1000 is not set
-# CONFIG_MIPS_DB1100 is not set
-# CONFIG_MIPS_DB1500 is not set
-# CONFIG_MIPS_DB1550 is not set
-# CONFIG_MIPS_DB1200 is not set
-# CONFIG_MIPS_MIRAGE is not set
-# CONFIG_BASLER_EXCITE is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_MACH_DECSTATION is not set
-# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_LASAT is not set
-# CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_SEAD is not set
-# CONFIG_WR_PPMC is not set
-# CONFIG_MIPS_SIM is not set
-CONFIG_MOMENCO_JAGUAR_ATX=y
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_3 is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MIPS_XXS1500 is not set
-# CONFIG_PNX8550_JBS is not set
-# CONFIG_PNX8550_STB810 is not set
-# CONFIG_DDB5477 is not set
-# CONFIG_MACH_VR41XX is not set
-# CONFIG_PMC_YOSEMITE is not set
-# CONFIG_QEMU is not set
-# CONFIG_MARKEINS is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_BIGSUR is not set
-# CONFIG_SIBYTE_SWARM is not set
-# CONFIG_SIBYTE_SENTOSA is not set
-# CONFIG_SIBYTE_RHONE is not set
-# CONFIG_SIBYTE_CARMEL is not set
-# CONFIG_SIBYTE_PTSWARM is not set
-# CONFIG_SIBYTE_LITTLESUR is not set
-# CONFIG_SIBYTE_CRHINE is not set
-# CONFIG_SIBYTE_CRHONE is not set
-# CONFIG_SNI_RM is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
-# CONFIG_TOSHIBA_RBTX4938 is not set
-CONFIG_JAGUAR_DMALOW=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_TIME=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-CONFIG_LIMITED_DMA=y
-CONFIG_CPU_BIG_ENDIAN=y
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
-CONFIG_IRQ_CPU=y
-CONFIG_IRQ_CPU_RM7K=y
-CONFIG_IRQ_MV64340=y
-CONFIG_PCI_MARVELL=y
-CONFIG_SWAP_IO_SPACE=y
-CONFIG_BOOT_ELF32=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-
-#
-# CPU selection
-#
-# CONFIG_CPU_MIPS32_R1 is not set
-# CONFIG_CPU_MIPS32_R2 is not set
-# CONFIG_CPU_MIPS64_R1 is not set
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_VR41XX is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R6000 is not set
-# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
-# CONFIG_CPU_RM7000 is not set
-CONFIG_CPU_RM9000=y
-# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_RM9000=y
-CONFIG_WEAK_ORDERING=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
-
-#
-# Kernel type
-#
-CONFIG_32BIT=y
-# CONFIG_64BIT is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_BOARD_SCACHE=y
-CONFIG_RM7000_CPU_SCACHE=y
-CONFIG_CPU_HAS_PREFETCH=y
-CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMP is not set
-# CONFIG_MIPS_MT_SMTC is not set
-# CONFIG_MIPS_VPE_LOADER is not set
-# CONFIG_64BIT_PHYS_ADDR is not set
-CONFIG_CPU_HAS_LLSC=y
-CONFIG_CPU_HAS_SYNC=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_HIGHMEM=y
-CONFIG_CPU_SUPPORTS_HIGHMEM=y
-CONFIG_SYS_SUPPORTS_HIGHMEM=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-# CONFIG_HZ_48 is not set
-# CONFIG_HZ_100 is not set
-# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_256 is not set
-CONFIG_HZ_1000=y
-# CONFIG_HZ_1024 is not set
-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=1000
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
-CONFIG_LOCKDEP_SUPPORT=y
-CONFIG_STACKTRACE_SUPPORT=y
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-# CONFIG_EXPERIMENTAL is not set
-CONFIG_BROKEN_ON_SMP=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_RELAY=y
-CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SHMEM=y
-CONFIG_SLAB=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
-
-#
-# Block layer
-#
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
-# CONFIG_DEFAULT_CFQ is not set
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
-
-#
-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
-#
-CONFIG_HW_HAS_PCI=y
-CONFIG_PCI=y
-CONFIG_MMU=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
-
-#
-# Power management options
-#
-CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_NETDEBUG is not set
-# CONFIG_PACKET is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-CONFIG_INET_TUNNEL=m
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-CONFIG_IPV6=m
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_INET6_XFRM_TUNNEL=m
-CONFIG_INET6_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-CONFIG_INET6_XFRM_MODE_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_BEET=m
-CONFIG_IPV6_SIT=m
-CONFIG_IPV6_TUNNEL=m
-CONFIG_NETWORK_SECMARK=y
-# CONFIG_NETFILTER is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
-# CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-CONFIG_CONNECTOR=m
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-# CONFIG_PNPACPI is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-CONFIG_ATA_OVER_ETH=m
-
-#
-# Misc devices
-#
-CONFIG_SGI_IOC4=m
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_RAID_ATTRS=m
-# CONFIG_SCSI is not set
-# CONFIG_SCSI_NETLINK is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
-# CONFIG_ATA is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Network device support
-#
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
-CONFIG_PHYLIB=m
-
-#
-# MII PHY device drivers
-#
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_FIXED_PHY is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_CASSINI is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_DM9000 is not set
-
-#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-# CONFIG_PCNET32 is not set
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-CONFIG_EEPRO100=y
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_R8169 is not set
-# CONFIG_SIS190 is not set
-# CONFIG_SKGE is not set
-# CONFIG_SKY2 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
-# CONFIG_BNX2 is not set
-CONFIG_MV643XX_ETH=y
-CONFIG_QLA3XXX=m
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_CHELSIO_T1 is not set
-CONFIG_CHELSIO_T3=m
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-# CONFIG_MYRI10GE is not set
-CONFIG_NETXEN_NIC=m
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-# CONFIG_INPUT is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-# CONFIG_VT is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-CONFIG_USB_ARCH_HAS_EHCI=y
-# CONFIG_USB is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# LED devices
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
-
-#
-# Real Time Clock
-#
-
-#
-# DMA Engine support
-#
-# CONFIG_DMA_ENGINE is not set
-
-#
-# DMA Clients
-#
-
-#
-# DMA Devices
-#
-
-#
-# Auxiliary Display support
-#
-
-#
-# Virtualization
-#
-
-#
-# File systems
-#
-# CONFIG_EXT2_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-CONFIG_FS_POSIX_ACL=y
-# CONFIG_XFS_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=m
-CONFIG_GENERIC_ACL=y
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Kernel hacking
-#
-CONFIG_TRACE_IRQFLAGS_SUPPORT=y
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE=""
-CONFIG_SYS_SUPPORTS_KGDB=y
-
-#
-# Security options
-#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_CRC32C=m
-CONFIG_CRYPTO_CAMELLIA=m
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=m
-# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=m
-CONFIG_CRC32=m
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=m
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index 068e48e..1b364cf 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -80,7 +80,6 @@
CONFIG_MIPS_TX3927=y
CONFIG_SWAP_IO_SPACE=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
-CONFIG_TOSHIBA_BOARDS=y
#
# CPU selection
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
index 69678d9..37d696c 100644
--- a/arch/mips/configs/pb1100_defconfig
+++ b/arch/mips/configs/pb1100_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
index 0706727..b11f0e8 100644
--- a/arch/mips/configs/pb1500_defconfig
+++ b/arch/mips/configs/pb1500_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
index 354e49b..2927f38 100644
--- a/arch/mips/configs/pb1550_defconfig
+++ b/arch/mips/configs/pb1550_defconfig
@@ -9,6 +9,7 @@
# Machine selection
#
CONFIG_ZONE_DMA=y
+CONFIG_MACH_ALCHEMY=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/rbhma4200_defconfig
similarity index 73%
rename from arch/mips/configs/ocelot_g_defconfig
rename to arch/mips/configs/rbhma4200_defconfig
index 7078e6b..35d6426 100644
--- a/arch/mips/configs/ocelot_g_defconfig
+++ b/arch/mips/configs/rbhma4200_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Tue Feb 20 21:47:36 2007
+# Linux kernel version: 2.6.21
+# Wed May 9 23:44:19 2007
#
CONFIG_MIPS=y
#
# Machine selection
#
-CONFIG_ZONE_DMA=y
# CONFIG_MIPS_MTX1 is not set
# CONFIG_MIPS_BOSPORUS is not set
# CONFIG_MIPS_PB1000 is not set
@@ -33,11 +32,9 @@
# CONFIG_MIPS_SEAD is not set
# CONFIG_WR_PPMC is not set
# CONFIG_MIPS_SIM is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
# CONFIG_MOMENCO_OCELOT is not set
# CONFIG_MOMENCO_OCELOT_3 is not set
# CONFIG_MOMENCO_OCELOT_C is not set
-CONFIG_MOMENCO_OCELOT_G=y
# CONFIG_MIPS_XXS1500 is not set
# CONFIG_PNX8550_JBS is not set
# CONFIG_PNX8550_STB810 is not set
@@ -60,8 +57,9 @@
# CONFIG_SIBYTE_CRHONE is not set
# CONFIG_SNI_RM is not set
# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
+CONFIG_TOSHIBA_RBTX4927=y
# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_TOSHIBA_FPCIB0 is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -70,19 +68,15 @@
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_GENERIC_TIME=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-# CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ is not set
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_I8259=y
CONFIG_CPU_BIG_ENDIAN=y
# CONFIG_CPU_LITTLE_ENDIAN is not set
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
-CONFIG_IRQ_CPU=y
-CONFIG_IRQ_CPU_RM7K=y
-CONFIG_PCI_MARVELL=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SWAP_IO_SPACE=y
-# CONFIG_SYSCLK_75 is not set
-# CONFIG_SYSCLK_83 is not set
-CONFIG_SYSCLK_100=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
@@ -97,18 +91,19 @@
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
+CONFIG_CPU_TX49XX=y
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
# CONFIG_CPU_R6000 is not set
# CONFIG_CPU_NEVADA is not set
# CONFIG_CPU_R8000 is not set
# CONFIG_CPU_R10000 is not set
-CONFIG_CPU_RM7000=y
+# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_RM7000=y
+CONFIG_SYS_HAS_CPU_TX49XX=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
@@ -121,19 +116,15 @@
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_BOARD_SCACHE=y
-CONFIG_RM7000_CPU_SCACHE=y
CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
# CONFIG_MIPS_MT_SMP is not set
# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_VPE_LOADER is not set
-# CONFIG_64BIT_PHYS_ADDR is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
@@ -143,17 +134,17 @@
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
-CONFIG_RESOURCES_64BIT=y
-CONFIG_ZONE_DMA_FLAG=1
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
# CONFIG_HZ_48 is not set
# CONFIG_HZ_100 is not set
# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_256 is not set
-CONFIG_HZ_1000=y
+# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=1000
+CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
@@ -183,34 +174,42 @@
# CONFIG_TASKSTATS is not set
# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-# CONFIG_IKCONFIG is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
CONFIG_SYSFS_DEPRECATED=y
-CONFIG_RELAY=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_HOTPLUG=y
+# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_RT_MUTEXES=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
#
# Loadable module support
#
-# CONFIG_MODULES is not set
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
#
# Block layer
@@ -218,7 +217,7 @@
CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
-CONFIG_LSF=y
+# CONFIG_LSF is not set
#
# IO Schedulers
@@ -238,17 +237,12 @@
#
CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
CONFIG_MMU=y
#
# PCCARD (PCMCIA/CardBus) support
#
-# CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
-# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -260,10 +254,7 @@
#
# Power management options
#
-CONFIG_PM=y
-# CONFIG_PM_LEGACY is not set
-# CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
+# CONFIG_PM is not set
#
# Networking
@@ -273,25 +264,21 @@
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=y
-# CONFIG_XFRM_SUB_POLICY is not set
-CONFIG_XFRM_MIGRATE=y
-CONFIG_NET_KEY=y
-CONFIG_NET_KEY_MIGRATE=y
+# CONFIG_NET_KEY is not set
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_DHCP is not set
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
@@ -299,19 +286,19 @@
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
CONFIG_TCP_CONG_CUBIC=y
CONFIG_DEFAULT_TCP_CONG="cubic"
-CONFIG_TCP_MD5SIG=y
+# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
-CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -352,13 +339,16 @@
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-CONFIG_IEEE80211=y
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=y
-CONFIG_IEEE80211_CRYPT_CCMP=y
-CONFIG_IEEE80211_SOFTMAC=y
-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
-CONFIG_WIRELESS_EXT=y
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
#
# Device Drivers
@@ -369,18 +359,12 @@
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
#
-CONFIG_CONNECTOR=y
-CONFIG_PROC_EVENTS=y
-
-#
-# Memory Technology Devices (MTD)
-#
+# CONFIG_CONNECTOR is not set
# CONFIG_MTD is not set
#
@@ -401,21 +385,24 @@
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_CDROM_PKTCDVD=y
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-CONFIG_ATA_OVER_ETH=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
#
# Misc devices
#
-CONFIG_SGI_IOC4=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
# CONFIG_TIFM_CORE is not set
+# CONFIG_BLINK is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -425,7 +412,7 @@
#
# SCSI device support
#
-CONFIG_RAID_ATTRS=y
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_NETLINK is not set
@@ -471,27 +458,13 @@
#
# PHY device support
#
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-CONFIG_MARVELL_PHY=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_QSEMI_PHY=y
-CONFIG_LXT_PHY=y
-CONFIG_CICADA_PHY=y
-CONFIG_VITESSE_PHY=y
-CONFIG_SMSC_PHY=y
-# CONFIG_BROADCOM_PHY is not set
-# CONFIG_FIXED_PHY is not set
+# CONFIG_PHYLIB is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_GALILEO_64240_ETH=y
+# CONFIG_MII is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
@@ -503,6 +476,7 @@
#
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
+CONFIG_NE2000=y
# CONFIG_NET_PCI is not set
#
@@ -521,18 +495,18 @@
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
-CONFIG_QLA3XXX=y
+# CONFIG_QLA3XXX is not set
# CONFIG_ATL1 is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_CHELSIO_T1 is not set
-CONFIG_CHELSIO_T3=y
+# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
-CONFIG_NETXEN_NIC=y
+# CONFIG_NETXEN_NIC is not set
#
# Token Ring devices
@@ -540,9 +514,10 @@
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
# Wan interfaces
@@ -570,29 +545,7 @@
#
# Input device support
#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
+# CONFIG_INPUT is not set
#
# Hardware I/O ports
@@ -601,34 +554,31 @@
# CONFIG_SERIO_I8042 is not set
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-CONFIG_SERIO_RAW=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_TXX9=y
+CONFIG_HAS_TXX9_SERIAL=y
+CONFIG_SERIAL_TXX9_NR_UARTS=6
+CONFIG_SERIAL_TXX9_CONSOLE=y
+CONFIG_SERIAL_TXX9_STDSERIAL=y
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
@@ -656,10 +606,7 @@
# TPM devices
#
# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
# CONFIG_I2C is not set
#
@@ -672,12 +619,12 @@
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
+# CONFIG_HWMON is not set
#
-# Hardware Monitoring support
+# Multifunction device drivers
#
-# CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
+# CONFIG_MFD_SM501 is not set
#
# Multimedia devices
@@ -692,15 +639,14 @@
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
-# Console display driver support
+# Display device support
#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_FB is not set
#
# Sound
@@ -708,11 +654,6 @@
# CONFIG_SOUND is not set
#
-# HID Devices
-#
-# CONFIG_HID is not set
-
-#
# USB support
#
CONFIG_USB_ARCH_HAS_HCD=y
@@ -728,10 +669,6 @@
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
# CONFIG_MMC is not set
#
@@ -759,7 +696,40 @@
#
# Real Time Clock
#
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1553 is not set
+CONFIG_RTC_DRV_DS1742=y
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
#
# DMA Engine support
@@ -785,9 +755,7 @@
#
# File systems
#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_EXT4DEV_FS is not set
# CONFIG_REISERFS_FS is not set
@@ -801,10 +769,10 @@
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
+# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=y
+# CONFIG_FUSE_FS is not set
CONFIG_GENERIC_ACL=y
#
@@ -824,21 +792,20 @@
# Pseudo filesystems
#
CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
+# CONFIG_PROC_KCORE is not set
CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
-CONFIG_CONFIGFS_FS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
-# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
@@ -855,17 +822,17 @@
# Network File Systems
#
CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
+# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
+CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -889,10 +856,7 @@
#
# Distributed Lock Manager
#
-CONFIG_DLM=y
-CONFIG_DLM_TCP=y
-# CONFIG_DLM_SCTP is not set
-# CONFIG_DLM_DEBUG is not set
+# CONFIG_DLM is not set
#
# Profiling support
@@ -910,72 +874,29 @@
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE=""
+CONFIG_SYS_SUPPORTS_KGDB=y
#
# Security options
#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=y
-CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_HASH=y
-CONFIG_CRYPTO_MANAGER=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_XCBC=y
-CONFIG_CRYPTO_NULL=y
-CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_SHA512=y
-CONFIG_CRYPTO_WP512=y
-CONFIG_CRYPTO_TGR192=y
-CONFIG_CRYPTO_GF128MUL=y
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_LRW=y
-CONFIG_CRYPTO_DES=y
-CONFIG_CRYPTO_FCRYPT=y
-CONFIG_CRYPTO_BLOWFISH=y
-CONFIG_CRYPTO_TWOFISH=y
-CONFIG_CRYPTO_TWOFISH_COMMON=y
-CONFIG_CRYPTO_SERPENT=y
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_CAST5=y
-CONFIG_CRYPTO_CAST6=y
-CONFIG_CRYPTO_TEA=y
-CONFIG_CRYPTO_ARC4=y
-CONFIG_CRYPTO_KHAZAD=y
-CONFIG_CRYPTO_ANUBIS=y
-CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_MICHAEL_MIC=y
-CONFIG_CRYPTO_CRC32C=y
-CONFIG_CRYPTO_CAMELLIA=y
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO is not set
#
# Library routines
#
CONFIG_BITREVERSE=y
# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=y
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
-CONFIG_LIBCRC32C=y
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
-CONFIG_PLIST=y
+# CONFIG_LIBCRC32C is not set
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
index 7d0f217..41011f7 100644
--- a/arch/mips/configs/rbhma4500_defconfig
+++ b/arch/mips/configs/rbhma4500_defconfig
@@ -89,7 +89,6 @@
CONFIG_SWAP_IO_SPACE=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
CONFIG_HAVE_STD_PC_SERIAL_PORT=y
-CONFIG_TOSHIBA_BOARDS=y
#
# CPU selection
diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0219_defconfig
similarity index 98%
rename from arch/mips/configs/tb0229_defconfig
rename to arch/mips/configs/tb0219_defconfig
index 1756d2b..8b1675c 100644
--- a/arch/mips/configs/tb0229_defconfig
+++ b/arch/mips/configs/tb0219_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20
-# Tue Feb 20 21:47:41 2007
+# Linux kernel version: 2.6.21-rc6
+# Sun Apr 15 01:06:01 2007
#
CONFIG_MIPS=y
@@ -66,10 +66,11 @@
# CONFIG_IBM_WORKPAD is not set
# CONFIG_NEC_CMBVR4133 is not set
CONFIG_TANBAC_TB022X=y
-# CONFIG_TANBAC_TB0226 is not set
-# CONFIG_TANBAC_TB0287 is not set
# CONFIG_VICTOR_MPC30X is not set
# CONFIG_ZAO_CAPCELLA is not set
+CONFIG_TANBAC_TB0219=y
+# CONFIG_TANBAC_TB0226 is not set
+# CONFIG_TANBAC_TB0287 is not set
CONFIG_PCI_VR41XX=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
@@ -184,6 +185,7 @@
# CONFIG_IKCONFIG is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
@@ -375,7 +377,7 @@
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=m
# CONFIG_SYS_HYPERVISOR is not set
#
@@ -415,7 +417,6 @@
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -646,7 +647,7 @@
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
-CONFIG_TANBAC_TB0219=y
+CONFIG_GPIO_TB0219=y
# CONFIG_DRM is not set
CONFIG_GPIO_VR41XX=y
# CONFIG_RAW_DRIVER is not set
@@ -679,6 +680,11 @@
# CONFIG_HWMON_VID is not set
#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -692,7 +698,7 @@
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
# CONFIG_FB is not set
#
@@ -700,7 +706,6 @@
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -831,6 +836,7 @@
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
#
diff --git a/arch/mips/kernel/early_printk.c b/arch/mips/kernel/early_printk.c
index 4fa54b2..9dccfa4 100644
--- a/arch/mips/kernel/early_printk.c
+++ b/arch/mips/kernel/early_printk.c
@@ -12,7 +12,8 @@
extern void prom_putchar(char);
-static void early_console_write(struct console *con, const char *s, unsigned n)
+static void __init
+early_console_write(struct console *con, const char *s, unsigned n)
{
while (n-- && *s) {
if (*s == '\n')
@@ -22,14 +23,20 @@
}
}
-static struct console early_console = {
+static struct console early_console __initdata = {
.name = "early",
.write = early_console_write,
.flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1
};
+static int early_console_initialized __initdata;
+
void __init setup_early_printk(void)
{
+ if (early_console_initialized)
+ return;
+ early_console_initialized = 1;
+
register_console(&early_console);
}
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index 2967537..410868b 100644
--- a/arch/mips/kernel/irq-msc01.c
+++ b/arch/mips/kernel/irq-msc01.c
@@ -132,11 +132,11 @@
};
-void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq)
+void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq)
{
extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset);
- _icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000);
+ _icctrl_msc = (unsigned long) ioremap (icubase, 0x40000);
/* Reset interrupt controller - initialises all registers to 0 */
MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT);
@@ -148,14 +148,14 @@
switch (imp->im_type) {
case MSC01_IRQ_EDGE:
- set_irq_chip(base+n, &msc_edgeirq_type);
+ set_irq_chip(irqbase+n, &msc_edgeirq_type);
if (cpu_has_veic)
MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT);
else
MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl);
break;
case MSC01_IRQ_LEVEL:
- set_irq_chip(base+n, &msc_levelirq_type);
+ set_irq_chip(irqbase+n, &msc_levelirq_type);
if (cpu_has_veic)
MSCIC_WRITE(MSC01_IC_SUP+n*8, 0);
else
@@ -163,7 +163,7 @@
}
}
- irq_base = base;
+ irq_base = irqbase;
MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 2fe4c86..aeded6c 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -28,7 +28,7 @@
static unsigned long irq_map[NR_IRQS / BITS_PER_LONG];
-int __devinit allocate_irqno(void)
+int allocate_irqno(void)
{
int irq;
@@ -59,7 +59,7 @@
BUG_ON(test_and_set_bit(i, irq_map));
}
-void __devinit free_irqno(unsigned int irq)
+void free_irqno(unsigned int irq)
{
smp_mb__before_clear_bit();
clear_bit(irq, irq_map);
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index e5e56bd..751b4a1 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -306,7 +306,7 @@
struct clocksource clocksource_mips = {
.name = "MIPS",
- .mask = 0xffffffff,
+ .mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index ff45a4b..200de02 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -927,9 +927,9 @@
(regs->cp0_cause & 0x7f) >> 2);
}
-asmlinkage void do_default_vi(struct pt_regs *regs)
+static asmlinkage void do_default_vi(void)
{
- show_regs(regs);
+ show_regs(get_irq_regs());
panic("Caught unexpected vectored interrupt.");
}
@@ -1128,7 +1128,7 @@
clear_bit(set, &sr->sr_allocated);
}
-static void *set_vi_srs_handler(int n, void *addr, int srs)
+static void *set_vi_srs_handler(int n, vi_handler_t addr, int srs)
{
unsigned long handler;
unsigned long old_handler = vi_handlers[n];
@@ -1217,7 +1217,7 @@
return (void *)old_handler;
}
-void *set_vi_handler(int n, void *addr)
+void *set_vi_handler(int n, vi_handler_t addr)
{
return set_vi_srs_handler(n, addr, 0);
}
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index d7d3b14..5dad13e 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -9,4 +9,4 @@
obj-$(CONFIG_PCI) += iomap-pci.o
# libgcc-style stuff needed in the kernel
-lib-y += ashldi3.o ashrdi3.o lshrdi3.o
+lib-y += ashldi3.o ashrdi3.o lshrdi3.o ucmpdi2.o
diff --git a/arch/mips/lib/ucmpdi2.c b/arch/mips/lib/ucmpdi2.c
new file mode 100644
index 0000000..e9ff258
--- /dev/null
+++ b/arch/mips/lib/ucmpdi2.c
@@ -0,0 +1,19 @@
+#include <linux/module.h>
+
+#include "libgcc.h"
+
+word_type __ucmpdi2 (unsigned long a, unsigned long b)
+{
+ const DWunion au = {.ll = a};
+ const DWunion bu = {.ll = b};
+
+ if ((unsigned int) au.s.high < (unsigned int) bu.s.high)
+ return 0;
+ else if ((unsigned int) au.s.high > (unsigned int) bu.s.high)
+ return 2;
+ if ((unsigned int) au.s.low < (unsigned int) bu.s.low)
+ return 0;
+ else if ((unsigned int) au.s.low > (unsigned int) bu.s.low)
+ return 2;
+ return 1;
+}
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 83d7602..1cd830e 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -311,16 +311,21 @@
if (!cpu_has_veic)
mips_cpu_irq_init();
- switch(mips_revision_corid) {
- case MIPS_REVISION_CORID_CORE_MSC:
- case MIPS_REVISION_CORID_CORE_FPGA2:
- case MIPS_REVISION_CORID_CORE_FPGA3:
- case MIPS_REVISION_CORID_CORE_24K:
- case MIPS_REVISION_CORID_CORE_EMUL_MSC:
+ switch(mips_revision_sconid) {
+ case MIPS_REVISION_SCON_SOCIT:
+ case MIPS_REVISION_SCON_ROCIT:
if (cpu_has_veic)
- init_msc_irqs (MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs);
+ init_msc_irqs (MIPS_MSC01_IC_REG_BASE, MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs);
else
- init_msc_irqs (MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs);
+ init_msc_irqs (MIPS_MSC01_IC_REG_BASE, MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs);
+ break;
+
+ case MIPS_REVISION_SCON_SOCITSC:
+ case MIPS_REVISION_SCON_SOCITSCP:
+ if (cpu_has_veic)
+ init_msc_irqs (MIPS_SOCITSC_IC_REG_BASE, MSC01E_INT_BASE, msc_eicirqmap, msc_nr_eicirqs);
+ else
+ init_msc_irqs (MIPS_SOCITSC_IC_REG_BASE, MSC01C_INT_BASE, msc_irqmap, msc_nr_irqs);
}
if (cpu_has_veic) {
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index 675502a..10dd2af 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -80,7 +80,6 @@
pagefault_enable();
}
-#ifndef CONFIG_LIMITED_DMA
/*
* This is the same as kmap_atomic() but can map memory that doesn't
* have a struct page associated with it.
@@ -99,7 +98,6 @@
return (void*) vaddr;
}
-#endif /* CONFIG_LIMITED_DMA */
struct page *__kmap_atomic_to_page(void *ptr)
{
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 2d1c2c0..4c80528 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -424,9 +424,6 @@
continue;
}
ClearPageReserved(page);
-#ifdef CONFIG_LIMITED_DMA
- set_page_address(page, lowmem_page_address(page));
-#endif
init_page_count(page);
__free_page(page);
totalhigh_pages++;
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 492c518..e714929 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -35,24 +35,24 @@
#include <asm/smp.h>
#include <asm/war.h>
-static __init int __attribute__((unused)) r45k_bvahwbug(void)
+static __init int __maybe_unused r45k_bvahwbug(void)
{
/* XXX: We should probe for the presence of this bug, but we don't. */
return 0;
}
-static __init int __attribute__((unused)) r4k_250MHZhwbug(void)
+static __init int __maybe_unused r4k_250MHZhwbug(void)
{
/* XXX: We should probe for the presence of this bug, but we don't. */
return 0;
}
-static __init int __attribute__((unused)) bcm1250_m3_war(void)
+static __init int __maybe_unused bcm1250_m3_war(void)
{
return BCM1250_M3_WAR;
}
-static __init int __attribute__((unused)) r10000_llsc_war(void)
+static __init int __maybe_unused r10000_llsc_war(void)
{
return R10000_LLSC_WAR;
}
@@ -511,18 +511,18 @@
#define i_ehb(buf) i_sll(buf, 0, 0, 3)
#ifdef CONFIG_64BIT
-static __init int __attribute__((unused)) in_compat_space_p(long addr)
+static __init int __maybe_unused in_compat_space_p(long addr)
{
/* Is this address in 32bit compat space? */
return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
}
-static __init int __attribute__((unused)) rel_highest(long val)
+static __init int __maybe_unused rel_highest(long val)
{
return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
}
-static __init int __attribute__((unused)) rel_higher(long val)
+static __init int __maybe_unused rel_higher(long val)
{
return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
}
@@ -556,8 +556,8 @@
i_lui(buf, rs, rel_hi(addr));
}
-static __init void __attribute__((unused)) i_LA(u32 **buf, unsigned int rs,
- long addr)
+static __init void __maybe_unused i_LA(u32 **buf, unsigned int rs,
+ long addr)
{
i_LA_mostly(buf, rs, addr);
if (rel_lo(addr))
@@ -636,8 +636,8 @@
move_labels(lab, first, end, off);
}
-static __init int __attribute__((unused)) insn_has_bdelay(struct reloc *rel,
- u32 *addr)
+static __init int __maybe_unused insn_has_bdelay(struct reloc *rel,
+ u32 *addr)
{
for (; rel->lab != label_invalid; rel++) {
if (rel->addr == addr
@@ -650,15 +650,15 @@
}
/* convenience functions for labeled branches */
-static void __init __attribute__((unused))
+static void __init __maybe_unused
il_bltz(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
{
r_mips_pc16(r, *p, l);
i_bltz(p, reg, 0);
}
-static void __init __attribute__((unused)) il_b(u32 **p, struct reloc **r,
- enum label_id l)
+static void __init __maybe_unused il_b(u32 **p, struct reloc **r,
+ enum label_id l)
{
r_mips_pc16(r, *p, l);
i_b(p, 0);
@@ -671,7 +671,7 @@
i_beqz(p, reg, 0);
}
-static void __init __attribute__((unused))
+static void __init __maybe_unused
il_beqzl(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
{
r_mips_pc16(r, *p, l);
@@ -692,7 +692,7 @@
i_bgezl(p, reg, 0);
}
-static void __init __attribute__((unused))
+static void __init __maybe_unused
il_bgez(u32 **p, struct reloc **r, unsigned int reg, enum label_id l)
{
r_mips_pc16(r, *p, l);
@@ -810,7 +810,7 @@
*
* As if we MIPS hackers wouldn't know how to nop pipelines happy ...
*/
-static __init void __attribute__((unused)) build_tlb_probe_entry(u32 **p)
+static __init void __maybe_unused build_tlb_probe_entry(u32 **p)
{
switch (current_cpu_data.cputype) {
/* Found by experiment: R4600 v2.0 needs this, too. */
@@ -1098,7 +1098,7 @@
* TMP and PTR are scratch.
* TMP will be clobbered, PTR will hold the pgd entry.
*/
-static __init void __attribute__((unused))
+static __init void __maybe_unused
build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
{
long pgdc = (long)pgd_current;
diff --git a/arch/mips/momentum/Kconfig b/arch/mips/momentum/Kconfig
deleted file mode 100644
index 70a61cf..0000000
--- a/arch/mips/momentum/Kconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-config JAGUAR_DMALOW
- bool "Low DMA Mode"
- depends on MOMENCO_JAGUAR_ATX
- help
- Select to Y if jump JP5 is set on your board, N otherwise. Normally
- the jumper is set, so if you feel unsafe, just say Y.
diff --git a/arch/mips/momentum/jaguar_atx/Makefile b/arch/mips/momentum/jaguar_atx/Makefile
deleted file mode 100644
index 2e8cebd..0000000
--- a/arch/mips/momentum/jaguar_atx/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for Momentum Computer's Jaguar-ATX board.
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-obj-y += irq.o platform.o prom.o reset.o setup.o
-
-obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
-obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
diff --git a/arch/mips/momentum/jaguar_atx/dbg_io.c b/arch/mips/momentum/jaguar_atx/dbg_io.c
deleted file mode 100644
index b85a652..0000000
--- a/arch/mips/momentum/jaguar_atx/dbg_io.c
+++ /dev/null
@@ -1,125 +0,0 @@
-
-#if defined(CONFIG_REMOTE_DEBUG)
-
-#include <asm/serial.h> /* For the serial port location and base baud */
-
-/* --- CONFIG --- */
-
-typedef unsigned char uint8;
-typedef unsigned int uint32;
-
-/* --- END OF CONFIG --- */
-
-#define UART16550_BAUD_2400 2400
-#define UART16550_BAUD_4800 4800
-#define UART16550_BAUD_9600 9600
-#define UART16550_BAUD_19200 19200
-#define UART16550_BAUD_38400 38400
-#define UART16550_BAUD_57600 57600
-#define UART16550_BAUD_115200 115200
-
-#define UART16550_PARITY_NONE 0
-#define UART16550_PARITY_ODD 0x08
-#define UART16550_PARITY_EVEN 0x18
-#define UART16550_PARITY_MARK 0x28
-#define UART16550_PARITY_SPACE 0x38
-
-#define UART16550_DATA_5BIT 0x0
-#define UART16550_DATA_6BIT 0x1
-#define UART16550_DATA_7BIT 0x2
-#define UART16550_DATA_8BIT 0x3
-
-#define UART16550_STOP_1BIT 0x0
-#define UART16550_STOP_2BIT 0x4
-
-/* ----------------------------------------------------- */
-
-/* === CONFIG === */
-
-/* [jsun] we use the second serial port for kdb */
-#define BASE OCELOT_SERIAL1_BASE
-#define MAX_BAUD OCELOT_BASE_BAUD
-
-/* === END OF CONFIG === */
-
-#define REG_OFFSET 4
-
-/* register offset */
-#define OFS_RCV_BUFFER 0
-#define OFS_TRANS_HOLD 0
-#define OFS_SEND_BUFFER 0
-#define OFS_INTR_ENABLE (1*REG_OFFSET)
-#define OFS_INTR_ID (2*REG_OFFSET)
-#define OFS_DATA_FORMAT (3*REG_OFFSET)
-#define OFS_LINE_CONTROL (3*REG_OFFSET)
-#define OFS_MODEM_CONTROL (4*REG_OFFSET)
-#define OFS_RS232_OUTPUT (4*REG_OFFSET)
-#define OFS_LINE_STATUS (5*REG_OFFSET)
-#define OFS_MODEM_STATUS (6*REG_OFFSET)
-#define OFS_RS232_INPUT (6*REG_OFFSET)
-#define OFS_SCRATCH_PAD (7*REG_OFFSET)
-
-#define OFS_DIVISOR_LSB (0*REG_OFFSET)
-#define OFS_DIVISOR_MSB (1*REG_OFFSET)
-
-
-/* memory-mapped read/write of the port */
-#define UART16550_READ(y) (*((volatile uint8*)(BASE + y)))
-#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z)
-
-void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
-{
- /* disable interrupts */
- UART16550_WRITE(OFS_INTR_ENABLE, 0);
-
- /* set up baud rate */
- {
- uint32 divisor;
-
- /* set DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
-
- /* set divisor */
- divisor = MAX_BAUD / baud;
- UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
- UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
-
- /* clear DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
- }
-
- /* set data format */
- UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
-}
-
-static int remoteDebugInitialized = 0;
-
-uint8 getDebugChar(void)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(UART16550_BAUD_38400,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
- return UART16550_READ(OFS_RCV_BUFFER);
-}
-
-
-int putDebugChar(uint8 byte)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(UART16550_BAUD_38400,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
- UART16550_WRITE(OFS_SEND_BUFFER, byte);
- return 1;
-}
-
-#endif
diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c
deleted file mode 100644
index f2b4325..0000000
--- a/arch/mips/momentum/jaguar_atx/irq.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2002 Momentum Computer, Inc.
- * Author: Matthew Dharm, mdharm@momenco.com
- *
- * Based on work by:
- * Copyright (C) 2000 RidgeRun, Inc.
- * Author: RidgeRun, Inc.
- * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * Copyright (C) 2000, 01, 06 Ralf Baechle (ralf@linux-mips.org)
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/signal.h>
-#include <linux/types.h>
-#include <asm/irq_cpu.h>
-#include <asm/mipsregs.h>
-#include <asm/time.h>
-
-asmlinkage void plat_irq_dispatch(void)
-{
- unsigned int pending = read_c0_cause() & read_c0_status();
-
- if (pending & STATUSF_IP0)
- do_IRQ(0);
- else if (pending & STATUSF_IP1)
- do_IRQ(1);
- else if (pending & STATUSF_IP2)
- do_IRQ(2);
- else if (pending & STATUSF_IP3)
- do_IRQ(3);
- else if (pending & STATUSF_IP4)
- do_IRQ(4);
- else if (pending & STATUSF_IP5)
- do_IRQ(5);
- else if (pending & STATUSF_IP6)
- do_IRQ(6);
- else if (pending & STATUSF_IP7)
- ll_timer_interrupt(7);
- else {
- /*
- * Now look at the extended interrupts
- */
- pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
- if (pending & STATUSF_IP8)
- ll_mv64340_irq();
- }
-}
-
-static struct irqaction cascade_mv64340 = {
- no_action, IRQF_DISABLED, CPU_MASK_NONE, "MV64340-Cascade", NULL, NULL
-};
-
-void __init arch_init_irq(void)
-{
- /*
- * Clear all of the interrupts while we change the able around a bit.
- * int-handler is not on bootstrap
- */
- clear_c0_status(ST0_IM);
-
- mips_cpu_irq_init();
- rm7k_cpu_irq_init();
-
- /* set up the cascading interrupts */
- setup_irq(8, &cascade_mv64340);
-
- mv64340_irq_init(16);
-
- set_c0_status(ST0_IM);
-}
diff --git a/arch/mips/momentum/jaguar_atx/ja-console.c b/arch/mips/momentum/jaguar_atx/ja-console.c
deleted file mode 100644
index 2c30b4f..0000000
--- a/arch/mips/momentum/jaguar_atx/ja-console.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001, 2002, 2004 Ralf Baechle
- */
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/kdev_t.h>
-#include <linux/major.h>
-#include <linux/termios.h>
-#include <linux/sched.h>
-#include <linux/tty.h>
-
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-#include <asm/serial.h>
-
-/* SUPERIO uart register map */
-struct ja_uartregs {
- union {
- volatile u8 pad0[3];
- volatile u8 rbr; /* read only, DLAB == 0 */
- volatile u8 pad1[3];
- volatile u8 thr; /* write only, DLAB == 0 */
- volatile u8 pad2[3];
- volatile u8 dll; /* DLAB == 1 */
- } u1;
- union {
- volatile u8 pad0[3];
- volatile u8 ier; /* DLAB == 0 */
- volatile u8 pad1[3];
- volatile u8 dlm; /* DLAB == 1 */
- } u2;
- union {
- volatile u8 pad0[3];
- volatile u8 iir; /* read only */
- volatile u8 pad1[3];
- volatile u8 fcr; /* write only */
- } u3;
- volatile u8 pad0[3];
- volatile u8 iu_lcr;
- volatile u8 pad1[3];
- volatile u8 iu_mcr;
- volatile u8 pad2[3];
- volatile u8 iu_lsr;
- volatile u8 pad3[3];
- volatile u8 iu_msr;
- volatile u8 pad4[3];
- volatile u8 iu_scr;
-} ja_uregs_t;
-
-#define iu_rbr u1.rbr
-#define iu_thr u1.thr
-#define iu_dll u1.dll
-#define iu_ier u2.ier
-#define iu_dlm u2.dlm
-#define iu_iir u3.iir
-#define iu_fcr u3.fcr
-
-extern unsigned long uart_base;
-
-static inline struct ja_uartregs *console_uart(void)
-{
- return (struct ja_uartregs *) (uart_base + 0x23UL);
-}
-
-void prom_putchar(char c)
-{
- struct ja_uartregs *uart = console_uart();
-
- while ((uart->iu_lsr & 0x20) == 0);
- uart->iu_thr = c;
-}
-
-static void inline ja_console_probe(void)
-{
- struct uart_port up;
-
- /*
- * Register to interrupt zero because we share the interrupt with
- * the serial driver which we don't properly support yet.
- */
- memset(&up, 0, sizeof(up));
- up.membase = (unsigned char *) uart_base + 0x23UL;
- up.irq = JAGUAR_ATX_SERIAL1_IRQ;
- up.uartclk = JAGUAR_ATX_UART_CLK;
- up.regshift = 2;
- up.iotype = UPIO_MEM;
- up.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST;
- up.line = 0;
-
- if (early_serial_setup(&up))
- printk(KERN_ERR "Early serial init of port 0 failed\n");
-}
-
-__init void ja_setup_console(void)
-{
- ja_console_probe();
-}
diff --git a/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h b/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
deleted file mode 100644
index 022f697..0000000
--- a/arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Jaguar-ATX Board Register Definitions
- *
- * (C) 2002 Momentum Computer Inc.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef __JAGUAR_ATX_FPGA_H__
-#define __JAGUAR_ATX_FPGA_H__
-
-#define JAGUAR_ATX_REG_BOARDREV 0x0
-#define JAGUAR_ATX_REG_FPGA_REV 0x1
-#define JAGUAR_ATX_REG_FPGA_TYPE 0x2
-#define JAGUAR_ATX_REG_RESET_STATUS 0x3
-#define JAGUAR_ATX_REG_BOARD_STATUS 0x4
-#define JAGUAR_ATX_REG_RESERVED1 0x5
-#define JAGUAR_ATX_REG_SET 0x6
-#define JAGUAR_ATX_REG_CLR 0x7
-#define JAGUAR_ATX_REG_EEPROM_MODE 0x9
-#define JAGUAR_ATX_REG_RESERVED2 0xa
-#define JAGUAR_ATX_REG_RESERVED3 0xb
-#define JAGUAR_ATX_REG_RESERVED4 0xc
-#define JAGUAR_ATX_REG_PHY_INTSTAT 0xd
-#define JAGUAR_ATX_REG_RESERVED5 0xe
-#define JAGUAR_ATX_REG_RESERVED6 0xf
-
-#define JAGUAR_ATX_CS0_ADDR 0xfc000000L
-
-extern unsigned long ja_fpga_base;
-
-#define __FPGA_REG_TO_ADDR(reg) \
- ((void *) ja_fpga_base + JAGUAR_ATX_REG_##reg)
-#define JAGUAR_FPGA_WRITE(x, reg) writeb(x, __FPGA_REG_TO_ADDR(reg))
-#define JAGUAR_FPGA_READ(reg) readb(__FPGA_REG_TO_ADDR(reg))
-
-#endif
diff --git a/arch/mips/momentum/jaguar_atx/platform.c b/arch/mips/momentum/jaguar_atx/platform.c
deleted file mode 100644
index 5618448..0000000
--- a/arch/mips/momentum/jaguar_atx/platform.c
+++ /dev/null
@@ -1,208 +0,0 @@
-#include <linux/delay.h>
-#include <linux/if_ether.h>
-#include <linux/ioport.h>
-#include <linux/mv643xx.h>
-#include <linux/platform_device.h>
-
-#include "jaguar_atx_fpga.h"
-
-#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
-
-static struct resource mv643xx_eth_shared_resources[] = {
- [0] = {
- .name = "ethernet shared base",
- .start = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
- .end = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
- MV643XX_ETH_SHARED_REGS_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device mv643xx_eth_shared_device = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(mv643xx_eth_shared_resources),
- .resource = mv643xx_eth_shared_resources,
-};
-
-#define MV_SRAM_BASE 0xfe000000UL
-#define MV_SRAM_SIZE (256 * 1024)
-
-#define MV_SRAM_RXRING_SIZE (MV_SRAM_SIZE / 4)
-#define MV_SRAM_TXRING_SIZE (MV_SRAM_SIZE / 4)
-
-#define MV_SRAM_BASE_ETH0 MV_SRAM_BASE
-#define MV_SRAM_BASE_ETH1 (MV_SRAM_BASE + (MV_SRAM_SIZE / 2))
-
-#define MV64x60_IRQ_ETH_0 48
-#define MV64x60_IRQ_ETH_1 49
-#define MV64x60_IRQ_ETH_2 50
-
-static struct resource mv64x60_eth0_resources[] = {
- [0] = {
- .name = "eth0 irq",
- .start = MV64x60_IRQ_ETH_0,
- .end = MV64x60_IRQ_ETH_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv643xx_eth_platform_data eth0_pd = {
- .port_number = 0,
-
- .tx_sram_addr = MV_SRAM_BASE_ETH0,
- .tx_sram_size = MV_SRAM_TXRING_SIZE,
- .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
-
- .rx_sram_addr = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE,
- .rx_sram_size = MV_SRAM_RXRING_SIZE,
- .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
-};
-
-static struct platform_device eth0_device = {
- .name = MV643XX_ETH_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(mv64x60_eth0_resources),
- .resource = mv64x60_eth0_resources,
- .dev = {
- .platform_data = ð0_pd,
- },
-};
-
-static struct resource mv64x60_eth1_resources[] = {
- [0] = {
- .name = "eth1 irq",
- .start = MV64x60_IRQ_ETH_1,
- .end = MV64x60_IRQ_ETH_1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv643xx_eth_platform_data eth1_pd = {
- .port_number = 1,
-
- .tx_sram_addr = MV_SRAM_BASE_ETH1,
- .tx_sram_size = MV_SRAM_TXRING_SIZE,
- .tx_queue_size = MV_SRAM_TXRING_SIZE / 16,
-
- .rx_sram_addr = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE,
- .rx_sram_size = MV_SRAM_RXRING_SIZE,
- .rx_queue_size = MV_SRAM_RXRING_SIZE / 16,
-};
-
-static struct platform_device eth1_device = {
- .name = MV643XX_ETH_NAME,
- .id = 1,
- .num_resources = ARRAY_SIZE(mv64x60_eth1_resources),
- .resource = mv64x60_eth1_resources,
- .dev = {
- .platform_data = ð1_pd,
- },
-};
-
-static struct resource mv64x60_eth2_resources[] = {
- [0] = {
- .name = "eth2 irq",
- .start = MV64x60_IRQ_ETH_2,
- .end = MV64x60_IRQ_ETH_2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv643xx_eth_platform_data eth2_pd = {
- .port_number = 2,
-};
-
-static struct platform_device eth2_device = {
- .name = MV643XX_ETH_NAME,
- .id = 2,
- .num_resources = ARRAY_SIZE(mv64x60_eth2_resources),
- .resource = mv64x60_eth2_resources,
- .dev = {
- .platform_data = ð2_pd,
- },
-};
-
-static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
- &mv643xx_eth_shared_device,
- ð0_device,
- ð1_device,
- ð2_device,
-};
-
-static u8 __init exchange_bit(u8 val, u8 cs)
-{
- /* place the data */
- JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
- udelay(1);
-
- /* turn the clock on */
- JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
- udelay(1);
-
- /* turn the clock off and read-strobe */
- JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-
- /* return the data */
- return (JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1;
-}
-
-static void __init get_mac(char dest[6])
-{
- u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- int i,j;
-
- for (i = 0; i < 12; i++)
- exchange_bit(read_opcode[i], 1);
-
- for (j = 0; j < 6; j++) {
- dest[j] = 0;
- for (i = 0; i < 8; i++) {
- dest[j] <<= 1;
- dest[j] |= exchange_bit(0, 1);
- }
- }
-
- /* turn off CS */
- exchange_bit(0,0);
-}
-
-/*
- * Copy and increment ethernet MAC address by a small value.
- *
- * This is useful for systems where the only one MAC address is stored in
- * non-volatile memory for multiple ports.
- */
-static inline void eth_mac_add(unsigned char *dst, unsigned char *src,
- unsigned int add)
-{
- int i;
-
- BUG_ON(add >= 256);
-
- for (i = ETH_ALEN; i >= 0; i--) {
- dst[i] = src[i] + add;
- add = dst[i] < src[i]; /* compute carry */
- }
-
- WARN_ON(add);
-}
-
-static int __init mv643xx_eth_add_pds(void)
-{
- unsigned char mac[ETH_ALEN];
- int ret;
-
- get_mac(mac);
- eth_mac_add(eth0_pd.mac_addr, mac, 0);
- eth_mac_add(eth1_pd.mac_addr, mac, 1);
- eth_mac_add(eth2_pd.mac_addr, mac, 2);
- ret = platform_add_devices(mv643xx_eth_pd_devs,
- ARRAY_SIZE(mv643xx_eth_pd_devs));
-
- return ret;
-}
-
-device_initcall(mv643xx_eth_add_pds);
-
-#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */
diff --git a/arch/mips/momentum/jaguar_atx/prom.c b/arch/mips/momentum/jaguar_atx/prom.c
deleted file mode 100644
index 5dd154e..0000000
--- a/arch/mips/momentum/jaguar_atx/prom.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright 2002 Momentum Computer Inc.
- * Author: Matthew Dharm <mdharm@momenco.com>
- *
- * Louis Hamilton, Red Hat, Inc.
- * hamilton@redhat.com [MIPS64 modifications]
- *
- * Based on Ocelot Linux port, which is
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.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.
- *
- * Added changes for SMP - Manish Lachwani (lachwani@pmc-sierra.com)
- */
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/mv643xx.h>
-
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-#include <asm/pmon.h>
-
-#include "jaguar_atx_fpga.h"
-
-extern void ja_setup_console(void);
-
-struct callvectors *debug_vectors;
-
-extern unsigned long cpu_clock;
-
-const char *get_system_type(void)
-{
- return "Momentum Jaguar-ATX";
-}
-
-#ifdef CONFIG_64BIT
-
-unsigned long signext(unsigned long addr)
-{
- addr &= 0xffffffff;
- return (unsigned long)((int)addr);
-}
-
-void *get_arg(unsigned long args, int arc)
-{
- unsigned long ul;
- unsigned char *puc, uc;
-
- args += (arc * 4);
- ul = (unsigned long)signext(args);
- puc = (unsigned char *)ul;
- if (puc == 0)
- return (void *)0;
-
-#ifdef CONFIG_CPU_LITTLE_ENDIAN
- uc = *puc++;
- l = (unsigned long)uc;
- uc = *puc++;
- ul |= (((unsigned long)uc) << 8);
- uc = *puc++;
- ul |= (((unsigned long)uc) << 16);
- uc = *puc++;
- ul |= (((unsigned long)uc) << 24);
-#else
- uc = *puc++;
- ul = ((unsigned long)uc) << 24;
- uc = *puc++;
- ul |= (((unsigned long)uc) << 16);
- uc = *puc++;
- ul |= (((unsigned long)uc) << 8);
- uc = *puc++;
- ul |= ((unsigned long)uc);
-#endif
- ul = signext(ul);
-
- return (void *)ul;
-}
-
-char *arg64(unsigned long addrin, int arg_index)
-{
- unsigned long args;
- char *p;
-
- args = signext(addrin);
- p = (char *)get_arg(args, arg_index);
-
- return p;
-}
-#endif /* CONFIG_64BIT */
-
-/* PMON passes arguments in C main() style */
-void __init prom_init(void)
-{
- int argc = fw_arg0;
- char **arg = (char **) fw_arg1;
- char **env = (char **) fw_arg2;
- struct callvectors *cv = (struct callvectors *) fw_arg3;
- int i;
-
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-// ja_setup_console(); /* The very first thing. */
-#endif
-
-#ifdef CONFIG_64BIT
- char *ptr;
-
- printk("Mips64 Jaguar-ATX\n");
- /* save the PROM vectors for debugging use */
- debug_vectors = (struct callvectors *)signext((unsigned long)cv);
-
- /* arg[0] is "g", the rest is boot parameters */
- arcs_cmdline[0] = '\0';
-
- for (i = 1; i < argc; i++) {
- ptr = (char *)arg64((unsigned long)arg, i);
- if ((strlen(arcs_cmdline) + strlen(ptr) + 1) >=
- sizeof(arcs_cmdline))
- break;
- strcat(arcs_cmdline, ptr);
- strcat(arcs_cmdline, " ");
- }
-
- i = 0;
- while (1) {
- ptr = (char *)arg64((unsigned long)env, i);
- if (! ptr)
- break;
-
- if (strncmp("gtbase", ptr, strlen("gtbase")) == 0) {
- marvell_base = simple_strtol(ptr + strlen("gtbase="),
- NULL, 16);
-
- if ((marvell_base & 0xffffffff00000000) == 0)
- marvell_base |= 0xffffffff00000000;
-
- printk("marvell_base set to 0x%016lx\n", marvell_base);
- }
- if (strncmp("cpuclock", ptr, strlen("cpuclock")) == 0) {
- cpu_clock = simple_strtol(ptr + strlen("cpuclock="),
- NULL, 10);
- printk("cpu_clock set to %d\n", cpu_clock);
- }
- i++;
- }
- printk("arcs_cmdline: %s\n", arcs_cmdline);
-
-#else /* CONFIG_64BIT */
- /* save the PROM vectors for debugging use */
- debug_vectors = cv;
-
- /* arg[0] is "g", the rest is boot parameters */
- arcs_cmdline[0] = '\0';
- for (i = 1; i < argc; i++) {
- if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
- >= sizeof(arcs_cmdline))
- break;
- strcat(arcs_cmdline, arg[i]);
- strcat(arcs_cmdline, " ");
- }
-
- while (*env) {
- if (strncmp("gtbase", *env, strlen("gtbase")) == 0) {
- marvell_base = simple_strtol(*env + strlen("gtbase="),
- NULL, 16);
- }
- if (strncmp("cpuclock", *env, strlen("cpuclock")) == 0) {
- cpu_clock = simple_strtol(*env + strlen("cpuclock="),
- NULL, 10);
- }
- env++;
- }
-#endif /* CONFIG_64BIT */
- mips_machgroup = MACH_GROUP_MOMENCO;
- mips_machtype = MACH_MOMENCO_JAGUAR_ATX;
-}
-
-void __init prom_free_prom_memory(void)
-{
-}
-
-void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
-{
-}
-
-int prom_boot_secondary(int cpu, unsigned long sp, unsigned long gp)
-{
- /* Clear the semaphore */
- *(volatile uint32_t *)(0xbb000a68) = 0x80000000;
-
- return 1;
-}
-
-void prom_init_secondary(void)
-{
- clear_c0_config(CONF_CM_CMASK);
- set_c0_config(0x2);
-
- clear_c0_status(ST0_IM);
- set_c0_status(0x1ffff);
-}
-
-void prom_smp_finish(void)
-{
-}
diff --git a/arch/mips/momentum/jaguar_atx/reset.c b/arch/mips/momentum/jaguar_atx/reset.c
deleted file mode 100644
index c73b089..0000000
--- a/arch/mips/momentum/jaguar_atx/reset.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 1997, 2001 Ralf Baechle
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- *
- * Copyright (C) 2002 Momentum Computer Inc.
- * Author: Matthew Dharm <mdharm@momenco.com>
- *
- * Louis Hamilton, Red Hat, Inc.
- * hamilton@redhat.com [MIPS64 modifications]
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-
-void momenco_jaguar_restart(char *command)
-{
- /* base address of timekeeper portion of part */
-#ifdef CONFIG_64BIT
- void *nvram = (void*) 0xfffffffffc807000;
-#else
- void *nvram = (void*) 0xfc807000;
-#endif
- /* Ask the NVRAM/RTC/watchdog chip to assert reset in 1/16 second */
- writeb(0x84, nvram + 0xff7);
-
- /* wait for the watchdog to go off */
- mdelay(100+(1000/16));
-
- /* if the watchdog fails for some reason, let people know */
- printk(KERN_NOTICE "Watchdog reset failed\n");
-}
-
-void momenco_jaguar_halt(void)
-{
- printk(KERN_NOTICE "\n** You can safely turn off the power\n");
- while (1)
- __asm__(".set\tmips3\n\t"
- "wait\n\t"
- ".set\tmips0");
-}
-
-void momenco_jaguar_power_off(void)
-{
- momenco_jaguar_halt();
-}
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
deleted file mode 100644
index 5a51014..0000000
--- a/arch/mips/momentum/jaguar_atx/setup.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Momentum Computer Jaguar-ATX board dependent boot routines
- *
- * Copyright (C) 1996, 1997, 2001, 04, 06 Ralf Baechle (ralf@linux-mips.org)
- * Copyright (C) 2000 RidgeRun, Inc.
- * Copyright (C) 2001 Red Hat, Inc.
- * Copyright (C) 2002 Momentum Computer
- *
- * Author: Matthew Dharm, Momentum Computer
- * mdharm@momenco.com
- *
- * Louis Hamilton, Red Hat, Inc.
- * hamilton@redhat.com [MIPS64 modifications]
- *
- * Author: RidgeRun, Inc.
- * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/bcd.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/swap.h>
-#include <linux/ioport.h>
-#include <linux/pm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/vmalloc.h>
-#include <linux/mv643xx.h>
-
-#include <asm/time.h>
-#include <asm/bootinfo.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/tlbflush.h>
-
-#include "jaguar_atx_fpga.h"
-
-extern unsigned long mv64340_sram_base;
-unsigned long cpu_clock;
-
-/* These functions are used for rebooting or halting the machine*/
-extern void momenco_jaguar_restart(char *command);
-extern void momenco_jaguar_halt(void);
-extern void momenco_jaguar_power_off(void);
-
-void momenco_time_init(void);
-
-static char reset_reason;
-
-static inline unsigned long ENTRYLO(unsigned long paddr)
-{
- return ((paddr & PAGE_MASK) |
- (_PAGE_PRESENT | __READABLE | __WRITEABLE | _PAGE_GLOBAL |
- _CACHE_UNCACHED)) >> 6;
-}
-
-void __init bus_error_init(void) { /* nothing */ }
-
-/*
- * Load a few TLB entries for the MV64340 and perhiperals. The MV64340 is going
- * to be hit on every IRQ anyway - there's absolutely no point in letting it be
- * a random TLB entry, as it'll just cause needless churning of the TLB. And we
- * use the other half for the serial port, which is just a PITA otherwise :)
- *
- * Device Physical Virtual
- * MV64340 Internal Regs 0xf4000000 0xf4000000
- * Ocelot-C[S] PLD (CS0) 0xfc000000 0xfc000000
- * NVRAM (CS1) 0xfc800000 0xfc800000
- * UARTs (CS2) 0xfd000000 0xfd000000
- * Internal SRAM 0xfe000000 0xfe000000
- * M-Systems DOC (CS3) 0xff000000 0xff000000
- */
-
-static __init void wire_stupidity_into_tlb(void)
-{
-#ifdef CONFIG_32BIT
- write_c0_wired(0);
- local_flush_tlb_all();
-
- /* marvell and extra space */
- add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000),
- 0xf4000000UL, PM_64K);
- /* fpga, rtc, and uart */
- add_wired_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfd000000),
- 0xfc000000UL, PM_16M);
-// /* m-sys and internal SRAM */
-// add_wired_entry(ENTRYLO(0xfe000000), ENTRYLO(0xff000000),
-// 0xfe000000UL, PM_16M);
-
- marvell_base = 0xf4000000;
- //mv64340_sram_base = 0xfe000000; /* Currently unused */
-#endif
-}
-
-unsigned long marvell_base = 0xf4000000L;
-unsigned long ja_fpga_base = JAGUAR_ATX_CS0_ADDR;
-unsigned long uart_base = 0xfd000000L;
-static unsigned char *rtc_base = (unsigned char*) 0xfc800000L;
-
-EXPORT_SYMBOL(marvell_base);
-
-static __init int per_cpu_mappings(void)
-{
- marvell_base = (unsigned long) ioremap(0xf4000000, 0x10000);
- ja_fpga_base = (unsigned long) ioremap(JAGUAR_ATX_CS0_ADDR, 0x1000);
- uart_base = (unsigned long) ioremap(0xfd000000UL, 0x1000);
- rtc_base = ioremap(0xfc000000UL, 0x8000);
- // ioremap(0xfe000000, 32 << 20);
- write_c0_wired(0);
- local_flush_tlb_all();
- ja_setup_console();
-
- return 0;
-}
-arch_initcall(per_cpu_mappings);
-
-unsigned long m48t37y_get_time(void)
-{
- unsigned int year, month, day, hour, min, sec;
- unsigned long flags;
-
- spin_lock_irqsave(&rtc_lock, flags);
- /* stop the update */
- rtc_base[0x7ff8] = 0x40;
-
- year = BCD2BIN(rtc_base[0x7fff]);
- year += BCD2BIN(rtc_base[0x7ff1]) * 100;
-
- month = BCD2BIN(rtc_base[0x7ffe]);
-
- day = BCD2BIN(rtc_base[0x7ffd]);
-
- hour = BCD2BIN(rtc_base[0x7ffb]);
- min = BCD2BIN(rtc_base[0x7ffa]);
- sec = BCD2BIN(rtc_base[0x7ff9]);
-
- /* start the update */
- rtc_base[0x7ff8] = 0x00;
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return mktime(year, month, day, hour, min, sec);
-}
-
-int m48t37y_set_time(unsigned long sec)
-{
- struct rtc_time tm;
- unsigned long flags;
-
- /* convert to a more useful format -- note months count from 0 */
- to_tm(sec, &tm);
- tm.tm_mon += 1;
-
- spin_lock_irqsave(&rtc_lock, flags);
- /* enable writing */
- rtc_base[0x7ff8] = 0x80;
-
- /* year */
- rtc_base[0x7fff] = BIN2BCD(tm.tm_year % 100);
- rtc_base[0x7ff1] = BIN2BCD(tm.tm_year / 100);
-
- /* month */
- rtc_base[0x7ffe] = BIN2BCD(tm.tm_mon);
-
- /* day */
- rtc_base[0x7ffd] = BIN2BCD(tm.tm_mday);
-
- /* hour/min/sec */
- rtc_base[0x7ffb] = BIN2BCD(tm.tm_hour);
- rtc_base[0x7ffa] = BIN2BCD(tm.tm_min);
- rtc_base[0x7ff9] = BIN2BCD(tm.tm_sec);
-
- /* day of week -- not really used, but let's keep it up-to-date */
- rtc_base[0x7ffc] = BIN2BCD(tm.tm_wday + 1);
-
- /* disable writing */
- rtc_base[0x7ff8] = 0x00;
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return 0;
-}
-
-void __init plat_timer_setup(struct irqaction *irq)
-{
- setup_irq(8, irq);
-}
-
-/*
- * Ugly but the least of all evils. TLB initialization did flush the TLB so
- * We need to setup mappings again before we can touch the RTC.
- */
-void momenco_time_init(void)
-{
- wire_stupidity_into_tlb();
-
- mips_hpt_frequency = cpu_clock / 2;
-
- rtc_mips_get_time = m48t37y_get_time;
- rtc_mips_set_time = m48t37y_set_time;
-}
-
-static struct resource mv_pci_io_mem0_resource = {
- .name = "MV64340 PCI0 IO MEM",
- .flags = IORESOURCE_IO
-};
-
-static struct resource mv_pci_mem0_resource = {
- .name = "MV64340 PCI0 MEM",
- .flags = IORESOURCE_MEM
-};
-
-static struct mv_pci_controller mv_bus0_controller = {
- .pcic = {
- .pci_ops = &mv_pci_ops,
- .mem_resource = &mv_pci_mem0_resource,
- .io_resource = &mv_pci_io_mem0_resource,
- },
- .config_addr = MV64340_PCI_0_CONFIG_ADDR,
- .config_vreg = MV64340_PCI_0_CONFIG_DATA_VIRTUAL_REG,
-};
-
-static uint32_t mv_io_base, mv_io_size;
-
-static void ja_pci0_init(void)
-{
- uint32_t mem0_base, mem0_size;
- uint32_t io_base, io_size;
-
- io_base = MV_READ(MV64340_PCI_0_IO_BASE_ADDR) << 16;
- io_size = (MV_READ(MV64340_PCI_0_IO_SIZE) + 1) << 16;
- mem0_base = MV_READ(MV64340_PCI_0_MEMORY0_BASE_ADDR) << 16;
- mem0_size = (MV_READ(MV64340_PCI_0_MEMORY0_SIZE) + 1) << 16;
-
- mv_pci_io_mem0_resource.start = 0;
- mv_pci_io_mem0_resource.end = io_size - 1;
- mv_pci_mem0_resource.start = mem0_base;
- mv_pci_mem0_resource.end = mem0_base + mem0_size - 1;
- mv_bus0_controller.pcic.mem_offset = mem0_base;
- mv_bus0_controller.pcic.io_offset = 0;
-
- ioport_resource.end = io_size - 1;
-
- register_pci_controller(&mv_bus0_controller.pcic);
-
- mv_io_base = io_base;
- mv_io_size = io_size;
-}
-
-static struct resource mv_pci_io_mem1_resource = {
- .name = "MV64340 PCI1 IO MEM",
- .flags = IORESOURCE_IO
-};
-
-static struct resource mv_pci_mem1_resource = {
- .name = "MV64340 PCI1 MEM",
- .flags = IORESOURCE_MEM
-};
-
-static struct mv_pci_controller mv_bus1_controller = {
- .pcic = {
- .pci_ops = &mv_pci_ops,
- .mem_resource = &mv_pci_mem1_resource,
- .io_resource = &mv_pci_io_mem1_resource,
- },
- .config_addr = MV64340_PCI_1_CONFIG_ADDR,
- .config_vreg = MV64340_PCI_1_CONFIG_DATA_VIRTUAL_REG,
-};
-
-static __init void ja_pci1_init(void)
-{
- uint32_t mem0_base, mem0_size;
- uint32_t io_base, io_size;
-
- io_base = MV_READ(MV64340_PCI_1_IO_BASE_ADDR) << 16;
- io_size = (MV_READ(MV64340_PCI_1_IO_SIZE) + 1) << 16;
- mem0_base = MV_READ(MV64340_PCI_1_MEMORY0_BASE_ADDR) << 16;
- mem0_size = (MV_READ(MV64340_PCI_1_MEMORY0_SIZE) + 1) << 16;
-
- /*
- * Here we assume the I/O window of second bus to be contiguous with
- * the first. A gap is no problem but would waste address space for
- * remapping the port space.
- */
- mv_pci_io_mem1_resource.start = mv_io_size;
- mv_pci_io_mem1_resource.end = mv_io_size + io_size - 1;
- mv_pci_mem1_resource.start = mem0_base;
- mv_pci_mem1_resource.end = mem0_base + mem0_size - 1;
- mv_bus1_controller.pcic.mem_offset = mem0_base;
- mv_bus1_controller.pcic.io_offset = 0;
-
- ioport_resource.end = io_base + io_size -mv_io_base - 1;
-
- register_pci_controller(&mv_bus1_controller.pcic);
-
- mv_io_size = io_base + io_size - mv_io_base;
-}
-
-static __init int __init ja_pci_init(void)
-{
- unsigned long io_v_base;
- uint32_t enable;
-
- enable = ~MV_READ(MV64340_BASE_ADDR_ENABLE);
-
- /*
- * We require at least one enabled I/O or PCI memory window or we
- * will ignore this PCI bus. We ignore PCI windows 1, 2 and 3.
- */
- if (enable & (0x01 << 9) || enable & (0x01 << 10))
- ja_pci0_init();
-
- if (enable & (0x01 << 14) || enable & (0x01 << 15))
- ja_pci1_init();
-
- if (mv_io_size) {
- io_v_base = (unsigned long) ioremap(mv_io_base, mv_io_size);
- if (!io_v_base)
- panic("Could not ioremap I/O port range");
-
- set_io_port_base(io_v_base);
- }
-
- return 0;
-}
-
-arch_initcall(ja_pci_init);
-
-void __init plat_mem_setup(void)
-{
- unsigned int tmpword;
-
- board_time_init = momenco_time_init;
-
- _machine_restart = momenco_jaguar_restart;
- _machine_halt = momenco_jaguar_halt;
- pm_power_off = momenco_jaguar_power_off;
-
- /*
- * initrd_start = (unsigned long)jaguar_initrd_start;
- * initrd_end = (unsigned long)jaguar_initrd_start + (ulong)jaguar_initrd_size;
- * initrd_below_start_ok = 1;
- */
-
- wire_stupidity_into_tlb();
-
- /*
- * shut down ethernet ports, just to be sure our memory doesn't get
- * corrupted by random ethernet traffic.
- */
- MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0), 0xff << 8);
- MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1), 0xff << 8);
- MV_WRITE(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(2), 0xff << 8);
- MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0), 0xff << 8);
- MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1), 0xff << 8);
- MV_WRITE(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(2), 0xff << 8);
- while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(0)) & 0xff);
- while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(1)) & 0xff);
- while (MV_READ(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(2)) & 0xff);
- while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(0)) & 0xff);
- while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(1)) & 0xff);
- while (MV_READ(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(2)) & 0xff);
- MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0),
- MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(0)) & ~1);
- MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1),
- MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(1)) & ~1);
- MV_WRITE(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(2),
- MV_READ(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(2)) & ~1);
-
- /* Turn off the Bit-Error LED */
- JAGUAR_FPGA_WRITE(0x80, CLR);
-
- tmpword = JAGUAR_FPGA_READ(BOARDREV);
- if (tmpword < 26)
- printk("Momentum Jaguar-ATX: Board Assembly Rev. %c\n",
- 'A'+tmpword);
- else
- printk("Momentum Jaguar-ATX: Board Assembly Revision #0x%x\n",
- tmpword);
-
- tmpword = JAGUAR_FPGA_READ(FPGA_REV);
- printk("FPGA Rev: %d.%d\n", tmpword>>4, tmpword&15);
- tmpword = JAGUAR_FPGA_READ(RESET_STATUS);
- printk("Reset reason: 0x%x\n", tmpword);
- switch (tmpword) {
- case 0x1:
- printk(" - Power-up reset\n");
- break;
- case 0x2:
- printk(" - Push-button reset\n");
- break;
- case 0x8:
- printk(" - Watchdog reset\n");
- break;
- case 0x10:
- printk(" - JTAG reset\n");
- break;
- default:
- printk(" - Unknown reset cause\n");
- }
- reset_reason = tmpword;
- JAGUAR_FPGA_WRITE(0xff, RESET_STATUS);
-
- tmpword = JAGUAR_FPGA_READ(BOARD_STATUS);
- printk("Board Status register: 0x%02x\n", tmpword);
- printk(" - User jumper: %s\n", (tmpword & 0x80)?"installed":"absent");
- printk(" - Boot flash write jumper: %s\n", (tmpword&0x40)?"installed":"absent");
-
- /* 256MiB of RM9000x2 DDR */
-// add_memory_region(0x0, 0x100<<20, BOOT_MEM_RAM);
-
- /* 128MiB of MV-64340 DDR */
-// add_memory_region(0x100<<20, 0x80<<20, BOOT_MEM_RAM);
-
- /* XXX Memory configuration should be picked up from PMON2k */
-#ifdef CONFIG_JAGUAR_DMALOW
- printk("Jaguar ATX DMA-low mode set\n");
- add_memory_region(0x00000000, 0x08000000, BOOT_MEM_RAM);
- add_memory_region(0x08000000, 0x10000000, BOOT_MEM_RAM);
-#else
- /* 128MiB of MV-64340 DDR RAM */
- printk("Jaguar ATX DMA-low mode is not set\n");
- add_memory_region(0x100<<20, 0x80<<20, BOOT_MEM_RAM);
-#endif
-
-#ifdef GEMDEBUG_TRACEBUFFER
- {
- unsigned int tbControl;
- tbControl =
- 0 << 26 | /* post trigger delay 0 */
- 0x2 << 16 | /* sequential trace mode */
- // 0x0 << 16 | /* non-sequential trace mode */
- // 0xf << 4 | /* watchpoints disabled */
- 2 << 2 | /* armed */
- 2 ; /* interrupt disabled */
- printk ("setting tbControl = %08lx\n", tbControl);
- write_32bit_cp0_set1_register($22, tbControl);
- __asm__ __volatile__(".set noreorder\n\t" \
- "nop; nop; nop; nop; nop; nop;\n\t" \
- "nop; nop; nop; nop; nop; nop;\n\t" \
- ".set reorder\n\t");
-
- }
-#endif
-}
diff --git a/arch/mips/momentum/ocelot_g/Makefile b/arch/mips/momentum/ocelot_g/Makefile
deleted file mode 100644
index c0a0030..0000000
--- a/arch/mips/momentum/ocelot_g/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for Momentum Computer's Ocelot-G board.
-#
-
-obj-y += irq.o gt-irq.o prom.o reset.o setup.o
-obj-$(CONFIG_KGDB) += dbg_io.o
diff --git a/arch/mips/momentum/ocelot_g/dbg_io.c b/arch/mips/momentum/ocelot_g/dbg_io.c
deleted file mode 100644
index 32d6fb4..0000000
--- a/arch/mips/momentum/ocelot_g/dbg_io.c
+++ /dev/null
@@ -1,121 +0,0 @@
-
-#include <asm/serial.h> /* For the serial port location and base baud */
-
-/* --- CONFIG --- */
-
-typedef unsigned char uint8;
-typedef unsigned int uint32;
-
-/* --- END OF CONFIG --- */
-
-#define UART16550_BAUD_2400 2400
-#define UART16550_BAUD_4800 4800
-#define UART16550_BAUD_9600 9600
-#define UART16550_BAUD_19200 19200
-#define UART16550_BAUD_38400 38400
-#define UART16550_BAUD_57600 57600
-#define UART16550_BAUD_115200 115200
-
-#define UART16550_PARITY_NONE 0
-#define UART16550_PARITY_ODD 0x08
-#define UART16550_PARITY_EVEN 0x18
-#define UART16550_PARITY_MARK 0x28
-#define UART16550_PARITY_SPACE 0x38
-
-#define UART16550_DATA_5BIT 0x0
-#define UART16550_DATA_6BIT 0x1
-#define UART16550_DATA_7BIT 0x2
-#define UART16550_DATA_8BIT 0x3
-
-#define UART16550_STOP_1BIT 0x0
-#define UART16550_STOP_2BIT 0x4
-
-/* ----------------------------------------------------- */
-
-/* === CONFIG === */
-
-/* [jsun] we use the second serial port for kdb */
-#define BASE OCELOT_SERIAL1_BASE
-#define MAX_BAUD OCELOT_BASE_BAUD
-
-/* === END OF CONFIG === */
-
-#define REG_OFFSET 4
-
-/* register offset */
-#define OFS_RCV_BUFFER 0
-#define OFS_TRANS_HOLD 0
-#define OFS_SEND_BUFFER 0
-#define OFS_INTR_ENABLE (1*REG_OFFSET)
-#define OFS_INTR_ID (2*REG_OFFSET)
-#define OFS_DATA_FORMAT (3*REG_OFFSET)
-#define OFS_LINE_CONTROL (3*REG_OFFSET)
-#define OFS_MODEM_CONTROL (4*REG_OFFSET)
-#define OFS_RS232_OUTPUT (4*REG_OFFSET)
-#define OFS_LINE_STATUS (5*REG_OFFSET)
-#define OFS_MODEM_STATUS (6*REG_OFFSET)
-#define OFS_RS232_INPUT (6*REG_OFFSET)
-#define OFS_SCRATCH_PAD (7*REG_OFFSET)
-
-#define OFS_DIVISOR_LSB (0*REG_OFFSET)
-#define OFS_DIVISOR_MSB (1*REG_OFFSET)
-
-
-/* memory-mapped read/write of the port */
-#define UART16550_READ(y) (*((volatile uint8*)(BASE + y)))
-#define UART16550_WRITE(y, z) ((*((volatile uint8*)(BASE + y))) = z)
-
-void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
-{
- /* disable interrupts */
- UART16550_WRITE(OFS_INTR_ENABLE, 0);
-
- /* set up baud rate */
- {
- uint32 divisor;
-
- /* set DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
-
- /* set divisor */
- divisor = MAX_BAUD / baud;
- UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
- UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
-
- /* clear DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
- }
-
- /* set data format */
- UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
-}
-
-static int remoteDebugInitialized = 0;
-
-uint8 getDebugChar(void)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(UART16550_BAUD_38400,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
- return UART16550_READ(OFS_RCV_BUFFER);
-}
-
-
-int putDebugChar(uint8 byte)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(UART16550_BAUD_38400,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
- UART16550_WRITE(OFS_SEND_BUFFER, byte);
- return 1;
-}
diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c
deleted file mode 100644
index e5576bd..0000000
--- a/arch/mips/momentum/ocelot_g/gt-irq.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- *
- * Copyright 2002 Momentum Computer
- * Author: mdharm@momenco.com
- *
- * arch/mips/momentum/ocelot_g/gt_irq.c
- * Interrupt routines for gt64240. Currently it only handles timer irq.
- *
- * 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 <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <asm/gt64240.h>
-#include <asm/io.h>
-
-unsigned long bus_clock;
-
-/*
- * These are interrupt handlers for the GT on-chip interrupts. They
- * all come in to the MIPS on a single interrupt line, and have to
- * be handled and ack'ed differently than other MIPS interrupts.
- */
-
-#if 0
-
-struct tq_struct irq_handlers[MAX_CAUSE_REGS][MAX_CAUSE_REG_WIDTH];
-void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr);
-
-/*
- * Hooks IRQ handler to the system. When the system is interrupted
- * the interrupt service routine is called.
- *
- * Inputs :
- * int_cause - The interrupt cause number. In EVB64120 two parameters
- * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
- * bit_num - Indicates which bit number in the cause register
- * isr_ptr - Pointer to the interrupt service routine
- */
-void hook_irq_handler(int int_cause, int bit_num, void *isr_ptr)
-{
- irq_handlers[int_cause][bit_num].routine = isr_ptr;
-}
-
-
-/*
- * Enables the IRQ on Galileo Chip
- *
- * Inputs :
- * int_cause - The interrupt cause number. In EVB64120 two parameters
- * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
- * bit_num - Indicates which bit number in the cause register
- *
- * Outputs :
- * 1 if successful, 0 if failure
- */
-int enable_galileo_irq(int int_cause, int bit_num)
-{
- if (int_cause == INT_CAUSE_MAIN)
- SET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER, (1 << bit_num));
- else if (int_cause == INT_CAUSE_HIGH)
- SET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
- (1 << bit_num));
- else
- return 0;
-
- return 1;
-}
-
-/*
- * Disables the IRQ on Galileo Chip
- *
- * Inputs :
- * int_cause - The interrupt cause number. In EVB64120 two parameters
- * are declared, INT_CAUSE_MAIN and INT_CAUSE_HIGH.
- * bit_num - Indicates which bit number in the cause register
- *
- * Outputs :
- * 1 if successful, 0 if failure
- */
-int disable_galileo_irq(int int_cause, int bit_num)
-{
- if (int_cause == INT_CAUSE_MAIN)
- RESET_REG_BITS(CPU_INTERRUPT_MASK_REGISTER,
- (1 << bit_num));
- else if (int_cause == INT_CAUSE_HIGH)
- RESET_REG_BITS(CPU_HIGH_INTERRUPT_MASK_REGISTER,
- (1 << bit_num));
- else
- return 0;
- return 1;
-}
-#endif /* 0 */
-
-/*
- * Interrupt handler for interrupts coming from the Galileo chip via P0_INT#.
- *
- * We route the timer interrupt to P0_INT# (IRQ 6), and that's all this
- * routine can handle, for now.
- *
- * In the future, we'll route more interrupts to this pin, and that's why
- * we keep this particular structure in the function.
- */
-
-static irqreturn_t gt64240_p0int_irq(int irq, void *dev)
-{
- uint32_t irq_src, irq_src_mask;
- int handled;
-
- /* get the low interrupt cause register */
- irq_src = MV_READ(LOW_INTERRUPT_CAUSE_REGISTER);
-
- /* get the mask register for this pin */
- irq_src_mask = MV_READ(PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW);
-
- /* mask off only the interrupts we're interested in */
- irq_src = irq_src & irq_src_mask;
-
- handled = IRQ_NONE;
-
- /* Check for timer interrupt */
- if (irq_src & 0x00000100) {
- handled = IRQ_HANDLED;
- irq_src &= ~0x00000100;
-
- /* Clear any pending cause bits */
- MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);
-
- /* handle the timer call */
- do_timer(1);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(get_irq_regs()));
-#endif
- }
-
- if (irq_src) {
- printk(KERN_INFO
- "UNKNOWN P0_INT# interrupt received, irq_src=0x%x\n",
- irq_src);
- }
-
- return handled;
-}
-
-/*
- * Initializes timer using galileo's built in timer.
- */
-
-/*
- * This will ignore the standard MIPS timer interrupt handler
- * that is passed in as *irq (=irq0 in ../kernel/time.c).
- * We will do our own timer interrupt handling.
- */
-void gt64240_time_init(void)
-{
- static struct irqaction timer;
-
- /* Stop the timer -- we'll use timer #0 */
- MV_WRITE(TIMER_COUNTER_0_3_CONTROL, 0x0);
-
- /* Load timer value for 100 Hz */
- MV_WRITE(TIMER_COUNTER0, bus_clock / 100);
-
- /*
- * Create the IRQ structure entry for the timer. Since we're too early
- * in the boot process to use the "request_irq()" call, we'll hard-code
- * the values to the correct interrupt line.
- */
- timer.handler = >64240_p0int_irq;
- timer.flags = IRQF_SHARED | IRQF_DISABLED;
- timer.name = "timer";
- timer.dev_id = NULL;
- timer.next = NULL;
- timer.mask = CPU_MASK_NONE;
- irq_desc[6].action = &timer;
-
- enable_irq(6);
-
- /* Clear any pending cause bits */
- MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);
-
- /* Enable the interrupt for timer 0 */
- MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_MASK, 0x1);
-
- /* Enable the timer interrupt for GT-64240 pin P0_INT# */
- MV_WRITE (PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW, 0x100);
-
- /* Configure and start the timer */
- MV_WRITE(TIMER_COUNTER_0_3_CONTROL, 0x3);
-}
-
-void gt64240_irq_init(void)
-{
-#if 0
- int i, j;
-
- /* Reset irq handlers pointers to NULL */
- for (i = 0; i < MAX_CAUSE_REGS; i++) {
- for (j = 0; j < MAX_CAUSE_REG_WIDTH; j++) {
- irq_handlers[i][j].next = NULL;
- irq_handlers[i][j].sync = 0;
- irq_handlers[i][j].routine = NULL;
- irq_handlers[i][j].data = NULL;
- }
- }
-#endif /* 0 */
-}
diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c
deleted file mode 100644
index 273541f..0000000
--- a/arch/mips/momentum/ocelot_g/irq.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2000 RidgeRun, Inc.
- * Author: RidgeRun, Inc.
- * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- * Copyright (C) 2000, 01, 05 Ralf Baechle (ralf@linux-mips.org)
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/irq_cpu.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-
-asmlinkage void plat_irq_dispatch(void)
-{
- unsigned int pending = read_c0_cause() & read_c0_status();
-
- if (pending & STATUSF_IP2)
- do_IRQ(2);
- else if (pending & STATUSF_IP3)
- do_IRQ(3);
- else if (pending & STATUSF_IP4)
- do_IRQ(4);
- else if (pending & STATUSF_IP5)
- do_IRQ(5);
- else if (pending & STATUSF_IP6)
- do_IRQ(6);
- else if (pending & STATUSF_IP7)
- do_IRQ(7);
- else {
- /*
- * Now look at the extended interrupts
- */
- pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
-
- if (pending & STATUSF_IP8)
- do_IRQ(8);
- else if (pending & STATUSF_IP9)
- do_IRQ(9);
- else if (pending & STATUSF_IP10)
- do_IRQ(10);
- else if (pending & STATUSF_IP11)
- do_IRQ(11);
- else
- spurious_interrupt();
- }
-}
-
-extern void gt64240_irq_init(void);
-
-void __init arch_init_irq(void)
-{
- /*
- * Clear all of the interrupts while we change the able around a bit.
- * int-handler is not on bootstrap
- */
- clear_c0_status(ST0_IM);
- local_irq_disable();
-
- mips_cpu_irq_init();
- rm7k_cpu_irq_init();
-
- gt64240_irq_init();
-}
diff --git a/arch/mips/momentum/ocelot_g/ocelot_pld.h b/arch/mips/momentum/ocelot_g/ocelot_pld.h
deleted file mode 100644
index 95e0534..0000000
--- a/arch/mips/momentum/ocelot_g/ocelot_pld.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Ocelot Board Register Definitions
- *
- * (C) 2001 Red Hat, Inc.
- *
- * GPL'd
- */
-#ifndef __MOMENCO_OCELOT_PLD_H__
-#define __MOMENCO_OCELOT_PLD_H__
-
-#define OCELOT_CS0_ADDR (0xfc000000)
-
-#define OCELOT_REG_BOARDREV (0)
-#define OCELOT_REG_PLD1_ID (1)
-#define OCELOT_REG_PLD2_ID (2)
-#define OCELOT_REG_RESET_STATUS (3)
-#define OCELOT_REG_BOARD_STATUS (4)
-#define OCELOT_REG_CPCI_ID (5)
-#define OCELOT_REG_I2C_CTRL (8)
-#define OCELOT_REG_EEPROM_MODE (9)
-#define OCELOT_REG_INTMASK (10)
-#define OCELOT_REG_INTSTATUS (11)
-#define OCELOT_REG_INTSET (12)
-#define OCELOT_REG_INTCLR (13)
-
-#define __PLD_REG_TO_ADDR(reg) ((void *) OCELOT_CS0_ADDR + OCELOT_REG_##reg)
-#define OCELOT_PLD_WRITE(x, reg) writeb(x, __PLD_REG_TO_ADDR(reg))
-#define OCELOT_PLD_READ(reg) readb(__PLD_REG_TO_ADDR(reg))
-
-#endif /* __MOMENCO_OCELOT_PLD_H__ */
diff --git a/arch/mips/momentum/ocelot_g/prom.c b/arch/mips/momentum/ocelot_g/prom.c
deleted file mode 100644
index 836d08307..0000000
--- a/arch/mips/momentum/ocelot_g/prom.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2002 Momentum Computer Inc.
- * Author: Matthew Dharm <mdharm@momenco.com>
- *
- * Based on Ocelot Linux port, which is
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.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 <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-#include <asm/pmon.h>
-#include <asm/gt64240.h>
-
-#include "ocelot_pld.h"
-
-struct callvectors* debug_vectors;
-
-extern unsigned long marvell_base;
-extern unsigned long bus_clock;
-
-#ifdef CONFIG_GALILEO_GT64240_ETH
-extern unsigned char prom_mac_addr_base[6];
-#endif
-
-const char *get_system_type(void)
-{
- return "Momentum Ocelot";
-}
-
-void __init prom_init(void)
-{
- int argc = fw_arg0;
- char **arg = (char **) fw_arg1;
- char **env = (char **) fw_arg2;
- struct callvectors *cv = (struct callvectors *) fw_arg3;
- int i;
-
- /* save the PROM vectors for debugging use */
- debug_vectors = cv;
-
- /* arg[0] is "g", the rest is boot parameters */
- arcs_cmdline[0] = '\0';
- for (i = 1; i < argc; i++) {
- if (strlen(arcs_cmdline) + strlen(arg[i] + 1)
- >= sizeof(arcs_cmdline))
- break;
- strcat(arcs_cmdline, arg[i]);
- strcat(arcs_cmdline, " ");
- }
-
- mips_machgroup = MACH_GROUP_MOMENCO;
- mips_machtype = MACH_MOMENCO_OCELOT_G;
-
-#ifdef CONFIG_GALILEO_GT64240_ETH
- /* get the base MAC address for on-board ethernet ports */
- memcpy(prom_mac_addr_base, (void*)0xfc807cf2, 6);
-#endif
-
- while (*env) {
- if (strncmp("gtbase", *env, strlen("gtbase")) == 0) {
- marvell_base = simple_strtol(*env + strlen("gtbase="),
- NULL, 16);
- }
- if (strncmp("busclock", *env, strlen("busclock")) == 0) {
- bus_clock = simple_strtol(*env + strlen("busclock="),
- NULL, 10);
- }
- env++;
- }
-}
-
-void __init prom_free_prom_memory(void)
-{
-}
diff --git a/arch/mips/momentum/ocelot_g/reset.c b/arch/mips/momentum/ocelot_g/reset.c
deleted file mode 100644
index 3fd499a..0000000
--- a/arch/mips/momentum/ocelot_g/reset.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 1997, 2001 Ralf Baechle
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.net
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-
-void momenco_ocelot_restart(char *command)
-{
- void *nvram = ioremap_nocache(0x2c807000, 0x1000);
-
- if (!nvram) {
- printk(KERN_NOTICE "ioremap of reset register failed\n");
- return;
- }
- writeb(0x84, nvram + 0xff7); /* Ask the NVRAM/RTC/watchdog chip to
- assert reset in 1/16 second */
- mdelay(10+(1000/16));
- iounmap(nvram);
- printk(KERN_NOTICE "Watchdog reset failed\n");
-}
-
-void momenco_ocelot_halt(void)
-{
- printk(KERN_NOTICE "\n** You can safely turn off the power\n");
- while (1)
- __asm__(".set\tmips3\n\t"
- "wait\n\t"
- ".set\tmips0");
-}
-
-void momenco_ocelot_power_off(void)
-{
- momenco_ocelot_halt();
-}
diff --git a/arch/mips/momentum/ocelot_g/setup.c b/arch/mips/momentum/ocelot_g/setup.c
deleted file mode 100644
index 9db638a..0000000
--- a/arch/mips/momentum/ocelot_g/setup.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Momentum Computer Ocelot-G (CP7000G) - board dependent boot routines
- *
- * Copyright (C) 1996, 1997, 2001 Ralf Baechle
- * Copyright (C) 2000 RidgeRun, Inc.
- * Copyright (C) 2001 Red Hat, Inc.
- * Copyright (C) 2002 Momentum Computer
- *
- * Author: Matthew Dharm, Momentum Computer
- * mdharm@momenco.com
- *
- * Author: RidgeRun, Inc.
- * glonnon@ridgerun.com, skranz@ridgerun.com, stevej@ridgerun.com
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: jsun@mvista.com or jsun@junsun.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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/pm.h>
-#include <linux/timex.h>
-#include <linux/vmalloc.h>
-
-#include <asm/time.h>
-#include <asm/bootinfo.h>
-#include <asm/page.h>
-#include <asm/io.h>
-#include <asm/gt64240.h>
-#include <asm/irq.h>
-#include <asm/pci.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <linux/bootmem.h>
-
-#include "ocelot_pld.h"
-
-#ifdef CONFIG_GALILEO_GT64240_ETH
-extern unsigned char prom_mac_addr_base[6];
-#endif
-
-unsigned long marvell_base;
-
-/* These functions are used for rebooting or halting the machine*/
-extern void momenco_ocelot_restart(char *command);
-extern void momenco_ocelot_halt(void);
-extern void momenco_ocelot_power_off(void);
-
-extern void gt64240_time_init(void);
-extern void momenco_ocelot_irq_setup(void);
-
-static char reset_reason;
-
-static unsigned long ENTRYLO(unsigned long paddr)
-{
- return ((paddr & PAGE_MASK) |
- (_PAGE_PRESENT | __READABLE | __WRITEABLE | _PAGE_GLOBAL |
- _CACHE_UNCACHED)) >> 6;
-}
-
-/* setup code for a handoff from a version 2 PMON 2000 PROM */
-void PMON_v2_setup(void)
-{
- /* A wired TLB entry for the GT64240 and the serial port. The
- GT64240 is going to be hit on every IRQ anyway - there's
- absolutely no point in letting it be a random TLB entry, as
- it'll just cause needless churning of the TLB. And we use
- the other half for the serial port, which is just a PITA
- otherwise :)
-
- Device Physical Virtual
- GT64240 Internal Regs 0xf4000000 0xe0000000
- UARTs (CS2) 0xfd000000 0xe0001000
- */
- add_wired_entry(ENTRYLO(0xf4000000), ENTRYLO(0xf4010000),
- 0xf4000000, PM_64K);
- add_wired_entry(ENTRYLO(0xfd000000), ENTRYLO(0xfd001000),
- 0xfd000000, PM_4K);
-
- /* Also a temporary entry to let us talk to the Ocelot PLD and NVRAM
- in the CS[012] region. We can't use ioremap() yet. The NVRAM
- is a ST M48T37Y, which includes NVRAM, RTC, and Watchdog functions.
-
- Ocelot PLD (CS0) 0xfc000000 0xe0020000
- NVRAM (CS1) 0xfc800000 0xe0030000
- */
- add_temporary_entry(ENTRYLO(0xfc000000), ENTRYLO(0xfc010000),
- 0xfc000000, PM_64K);
- add_temporary_entry(ENTRYLO(0xfc800000), ENTRYLO(0xfc810000),
- 0xfc800000, PM_64K);
-
- marvell_base = 0xf4000000;
-}
-
-extern int rm7k_tcache_enabled;
-
-/*
- * This runs in KSEG1. See the verbiage in rm7k.c::probe_scache()
- */
-#define Page_Invalidate_T 0x16
-static void __init setup_l3cache(unsigned long size)
-{
- int register i;
-
- printk("Enabling L3 cache...");
-
- /* Enable the L3 cache in the GT64120A's CPU Configuration register */
- MV_WRITE(0, MV_READ(0) | (1<<14));
-
- /* Enable the L3 cache in the CPU */
- set_c0_config(1<<12 /* CONF_TE */);
-
- /* Clear the cache */
- write_c0_taglo(0);
- write_c0_taghi(0);
-
- for (i=0; i < size; i+= 4096) {
- __asm__ __volatile__ (
- ".set noreorder\n\t"
- ".set mips3\n\t"
- "cache %1, (%0)\n\t"
- ".set mips0\n\t"
- ".set reorder"
- :
- : "r" (KSEG0ADDR(i)),
- "i" (Page_Invalidate_T));
- }
-
- /* Let the RM7000 MM code know that the tertiary cache is enabled */
- rm7k_tcache_enabled = 1;
-
- printk("Done\n");
-}
-
-void __init plat_timer_setup(struct irqaction *irq)
-{
-}
-
-void __init plat_mem_setup(void)
-{
- void (*l3func)(unsigned long) = (void *) KSEG1ADDR(setup_l3cache);
- unsigned int tmpword;
-
- board_time_init = gt64240_time_init;
-
- _machine_restart = momenco_ocelot_restart;
- _machine_halt = momenco_ocelot_halt;
- pm_power_off = momenco_ocelot_power_off;
-
- /*
- * initrd_start = (unsigned long)ocelot_initrd_start;
- * initrd_end = (unsigned long)ocelot_initrd_start + (ulong)ocelot_initrd_size;
- * initrd_below_start_ok = 1;
- */
-
- /* do handoff reconfiguration */
- PMON_v2_setup();
-
-#ifdef CONFIG_GALILEO_GT64240_ETH
- /* get the mac addr */
- memcpy(prom_mac_addr_base, (void*)0xfc807cf2, 6);
-#endif
-
- /* Turn off the Bit-Error LED */
- OCELOT_PLD_WRITE(0x80, INTCLR);
-
- tmpword = OCELOT_PLD_READ(BOARDREV);
- if (tmpword < 26)
- printk("Momenco Ocelot-G: Board Assembly Rev. %c\n", 'A'+tmpword);
- else
- printk("Momenco Ocelot-G: Board Assembly Revision #0x%x\n", tmpword);
-
- tmpword = OCELOT_PLD_READ(PLD1_ID);
- printk("PLD 1 ID: %d.%d\n", tmpword>>4, tmpword&15);
- tmpword = OCELOT_PLD_READ(PLD2_ID);
- printk("PLD 2 ID: %d.%d\n", tmpword>>4, tmpword&15);
- tmpword = OCELOT_PLD_READ(RESET_STATUS);
- printk("Reset reason: 0x%x\n", tmpword);
- reset_reason = tmpword;
- OCELOT_PLD_WRITE(0xff, RESET_STATUS);
-
- tmpword = OCELOT_PLD_READ(BOARD_STATUS);
- printk("Board Status register: 0x%02x\n", tmpword);
- printk(" - User jumper: %s\n", (tmpword & 0x80)?"installed":"absent");
- printk(" - Boot flash write jumper: %s\n", (tmpword&0x40)?"installed":"absent");
- printk(" - Tulip PHY %s connected\n", (tmpword&0x10)?"is":"not");
- printk(" - L3 Cache size: %d MiB\n", (1<<((tmpword&12) >> 2))&~1);
- printk(" - SDRAM size: %d MiB\n", 1<<(6+(tmpword&3)));
-
- if (tmpword&12)
- l3func((1<<(((tmpword&12) >> 2)+20)));
-
- switch(tmpword &3) {
- case 3:
- /* 512MiB -- two banks of 256MiB */
- add_memory_region( 0x0<<20, 0x100<<20, BOOT_MEM_RAM);
-/*
- add_memory_region(0x100<<20, 0x100<<20, BOOT_MEM_RAM);
-*/
- break;
- case 2:
- /* 256MiB -- two banks of 128MiB */
- add_memory_region( 0x0<<20, 0x80<<20, BOOT_MEM_RAM);
- add_memory_region(0x80<<20, 0x80<<20, BOOT_MEM_RAM);
- break;
- case 1:
- /* 128MiB -- 64MiB per bank */
- add_memory_region( 0x0<<20, 0x40<<20, BOOT_MEM_RAM);
- add_memory_region(0x40<<20, 0x40<<20, BOOT_MEM_RAM);
- break;
- case 0:
- /* 64MiB */
- add_memory_region( 0x0<<20, 0x40<<20, BOOT_MEM_RAM);
- break;
- }
-
- /* FIXME: Fix up the DiskOnChip mapping */
- MV_WRITE(0x468, 0xfef73);
-}
-
-/* This needs to be one of the first initcalls, because no I/O port access
- can work before this */
-
-static int io_base_ioremap(void)
-{
- /* we're mapping PCI accesses from 0xc0000000 to 0xf0000000 */
- unsigned long io_remap_range;
-
- io_remap_range = (unsigned long) ioremap(0xc0000000, 0x30000000);
- if (!io_remap_range)
- panic("Could not ioremap I/O port range");
-
- set_io_port_base(io_remap_range - 0xc0000000);
-
- return 0;
-}
-
-module_init(io_base_ioremap);
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index df487c0..aba3dbf 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -30,11 +30,9 @@
obj-$(CONFIG_SOC_AU1550) += fixup-au1000.o ops-au1000.o
obj-$(CONFIG_SOC_PNX8550) += fixup-pnx8550.o ops-pnx8550.o
obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o
-obj-$(CONFIG_MOMENCO_JAGUAR_ATX)+= fixup-jaguar.o
obj-$(CONFIG_MOMENCO_OCELOT) += fixup-ocelot.o pci-ocelot.o
obj-$(CONFIG_MOMENCO_OCELOT_3) += fixup-ocelot3.o
obj-$(CONFIG_MOMENCO_OCELOT_C) += fixup-ocelot-c.o pci-ocelot-c.o
-obj-$(CONFIG_MOMENCO_OCELOT_G) += fixup-ocelot-g.o pci-ocelot-g.o
obj-$(CONFIG_PMC_YOSEMITE) += fixup-yosemite.o ops-titan.o ops-titan-ht.o \
pci-yosemite.o
obj-$(CONFIG_SGI_IP27) += ops-bridge.o pci-ip27.o
diff --git a/arch/mips/pci/fixup-cobalt.c b/arch/mips/pci/fixup-cobalt.c
index 7d5f6bb..d57ffd7 100644
--- a/arch/mips/pci/fixup-cobalt.c
+++ b/arch/mips/pci/fixup-cobalt.c
@@ -17,9 +17,7 @@
#include <asm/io.h>
#include <asm/gt64120.h>
-#include <asm/mach-cobalt/cobalt.h>
-
-extern int cobalt_board_id;
+#include <cobalt.h>
static void qube_raq_galileo_early_fixup(struct pci_dev *dev)
{
@@ -115,6 +113,27 @@
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_DEVICE_ID_MARVELL_GT64111,
qube_raq_galileo_fixup);
+int cobalt_board_id;
+
+static void qube_raq_via_board_id_fixup(struct pci_dev *dev)
+{
+ u8 id;
+ int retval;
+
+ retval = pci_read_config_byte(dev, VIA_COBALT_BRD_ID_REG, &id);
+ if (retval) {
+ panic("Cannot read board ID");
+ return;
+ }
+
+ cobalt_board_id = VIA_COBALT_BRD_REG_to_ID(id);
+
+ printk(KERN_INFO "Cobalt board ID: %d\n", cobalt_board_id);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0,
+ qube_raq_via_board_id_fixup);
+
static char irq_tab_qube1[] __initdata = {
[COBALT_PCICONF_CPU] = 0,
[COBALT_PCICONF_ETH0] = COBALT_QUBE1_ETH0_IRQ,
diff --git a/arch/mips/pci/fixup-jaguar.c b/arch/mips/pci/fixup-jaguar.c
deleted file mode 100644
index 6c5e1d4..0000000
--- a/arch/mips/pci/fixup-jaguar.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Marvell MV64340 interrupt fixup code.
- *
- * Marvell wants an NDA for their docs so this was written without
- * documentation. You've been warned.
- *
- * Copyright (C) 2004 Ralf Baechle (ralf@linux-mips.org)
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/mipsregs.h>
-
-/*
- * WARNING: Example of how _NOT_ to do it.
- */
-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- int bus = dev->bus->number;
-
- if (bus == 0 && slot == 1)
- return 3; /* PCI-X A */
- if (bus == 0 && slot == 2)
- return 4; /* PCI-X B */
- if (bus == 1 && slot == 1)
- return 5; /* PCI A */
- if (bus == 1 && slot == 2)
- return 6; /* PCI B */
-
-return 0;
- panic("Whooops in pcibios_map_irq");
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- return 0;
-}
diff --git a/arch/mips/pci/fixup-ocelot-g.c b/arch/mips/pci/fixup-ocelot-g.c
deleted file mode 100644
index d7a652e..0000000
--- a/arch/mips/pci/fixup-ocelot-g.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 2004 Ralf Baechle (ralf@linux-mips.org)
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- int bus = dev->bus->number;
-
- if (bus == 0 && slot == 1) /* Intel 82543 Gigabit MAC */
- return 2; /* irq_nr is 2 for INT0 */
-
- if (bus == 0 && slot == 2) /* Intel 82543 Gigabit MAC */
- return 3; /* irq_nr is 3 for INT1 */
-
- if (bus == 1 && slot == 3) /* Intel 21555 bridge */
- return 5; /* irq_nr is 8 for INT6 */
-
- if (bus == 1 && slot == 4) /* PMC Slot */
- return 9; /* irq_nr is 9 for INT7 */
-
- return -1;
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- return 0;
-}
diff --git a/arch/mips/pci/pci-ocelot-g.c b/arch/mips/pci/pci-ocelot-g.c
deleted file mode 100644
index 1e34301..0000000
--- a/arch/mips/pci/pci-ocelot-g.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.org)
- *
- * This doesn't really fly - but I don't have a GT64240 system for testing.
- */
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <asm/gt64240.h>
-
-/*
- * We assume these address ranges have been programmed into the GT-64240 by
- * the firmware. PMON in case of the Ocelot G does that. Note the size of
- * the I/O range is completly stupid; I/O mappings are limited to at most
- * 256 bytes by the PCI spec and deprecated; and just to make things worse
- * apparently many devices don't decode more than 64k of I/O space.
- */
-
-#define gt_io_size 0x20000000UL
-#define gt_io_base 0xe0000000UL
-
-static struct resource gt_pci_mem0_resource = {
- .name = "MV64240 PCI0 MEM",
- .start = 0xc0000000UL,
- .end = 0xcfffffffUL,
- .flags = IORESOURCE_MEM
-};
-
-static struct resource gt_pci_io_mem0_resource = {
- .name = "MV64240 PCI0 IO MEM",
- .start = 0xe0000000UL,
- .end = 0xefffffffUL,
- .flags = IORESOURCE_IO
-};
-
-static struct mv_pci_controller gt_bus0_controller = {
- .pcic = {
- .pci_ops = &mv_pci_ops,
- .mem_resource = >_pci_mem0_resource,
- .mem_offset = 0xc0000000UL,
- .io_resource = >_pci_io_mem0_resource,
- .io_offset = 0x00000000UL
- },
- .config_addr = PCI_0CONFIGURATION_ADDRESS,
- .config_vreg = PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER,
-};
-
-static struct resource gt_pci_mem1_resource = {
- .name = "MV64240 PCI1 MEM",
- .start = 0xd0000000UL,
- .end = 0xdfffffffUL,
- .flags = IORESOURCE_MEM
-};
-
-static struct resource gt_pci_io_mem1_resource = {
- .name = "MV64240 PCI1 IO MEM",
- .start = 0xf0000000UL,
- .end = 0xffffffffUL,
- .flags = IORESOURCE_IO
-};
-
-static struct mv_pci_controller gt_bus1_controller = {
- .pcic = {
- .pci_ops = &mv_pci_ops,
- .mem_resource = >_pci_mem1_resource,
- .mem_offset = 0xd0000000UL,
- .io_resource = >_pci_io_mem1_resource,
- .io_offset = 0x10000000UL
- },
- .config_addr = PCI_1CONFIGURATION_ADDRESS,
- .config_vreg = PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER,
-};
-
-static __init int __init ocelot_g_pci_init(void)
-{
- unsigned long io_v_base;
-
- if (gt_io_size) {
- io_v_base = (unsigned long) ioremap(gt_io_base, gt_io_size);
- if (!io_v_base)
- panic("Could not ioremap I/O port range");
-
- set_io_port_base(io_v_base);
- }
-
- register_pci_controller(>_bus0_controller.pcic);
- register_pci_controller(>_bus1_controller.pcic);
-
- return 0;
-}
-
-arch_initcall(ocelot_g_pci_init);
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index b6d6492..1fb3e35 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -4,6 +4,6 @@
#
obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-berr.o \
- ip22-time.o ip22-nvram.o ip22-reset.o ip22-setup.o
+ ip22-time.o ip22-nvram.o ip22-platform.o ip22-reset.o ip22-setup.o
obj-$(CONFIG_EISA) += ip22-eisa.o
diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c
new file mode 100644
index 0000000..78b608d2
--- /dev/null
+++ b/arch/mips/sgi-ip22/ip22-platform.c
@@ -0,0 +1,177 @@
+#include <linux/init.h>
+#include <linux/if_ether.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/paccess.h>
+#include <asm/sgi/ip22.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/mc.h>
+#include <asm/sgi/seeq.h>
+#include <asm/sgi/wd.h>
+
+static struct resource sgiwd93_0_resources[] = {
+ {
+ .name = "eth0 irq",
+ .start = SGI_WD93_0_IRQ,
+ .end = SGI_WD93_0_IRQ,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct sgiwd93_platform_data sgiwd93_0_pd = {
+ .unit = 0,
+ .irq = SGI_WD93_0_IRQ,
+};
+
+static struct platform_device sgiwd93_0_device = {
+ .name = "sgiwd93",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sgiwd93_0_resources),
+ .resource = sgiwd93_0_resources,
+ .dev = {
+ .platform_data = &sgiwd93_0_pd,
+ },
+};
+
+static struct resource sgiwd93_1_resources[] = {
+ {
+ .name = "eth0 irq",
+ .start = SGI_WD93_1_IRQ,
+ .end = SGI_WD93_1_IRQ,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct sgiwd93_platform_data sgiwd93_1_pd = {
+ .unit = 1,
+ .irq = SGI_WD93_1_IRQ,
+};
+
+static struct platform_device sgiwd93_1_device = {
+ .name = "sgiwd93",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(sgiwd93_1_resources),
+ .resource = sgiwd93_1_resources,
+ .dev = {
+ .platform_data = &sgiwd93_1_pd,
+ },
+};
+
+/*
+ * Create a platform device for the GPI port that receives the
+ * image data from the embedded camera.
+ */
+static int __init sgiwd93_devinit(void)
+{
+ int res;
+
+ sgiwd93_0_pd.hregs = &hpc3c0->scsi_chan0;
+ sgiwd93_0_pd.wdregs = (unsigned char *) hpc3c0->scsi0_ext;
+
+ res = platform_device_register(&sgiwd93_0_device);
+ if (res)
+ return res;
+
+ if (!ip22_is_fullhouse())
+ return 0;
+
+ sgiwd93_1_pd.hregs = &hpc3c0->scsi_chan1;
+ sgiwd93_1_pd.wdregs = (unsigned char *) hpc3c0->scsi1_ext;
+
+ return platform_device_register(&sgiwd93_1_device);
+}
+
+device_initcall(sgiwd93_devinit);
+
+static struct resource sgiseeq_0_resources[] = {
+ {
+ .name = "eth0 irq",
+ .start = SGI_ENET_IRQ,
+ .end = SGI_ENET_IRQ,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct sgiseeq_platform_data eth0_pd;
+
+static struct platform_device eth0_device = {
+ .name = "sgiseeq",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sgiseeq_0_resources),
+ .resource = sgiseeq_0_resources,
+ .dev = {
+ .platform_data = ð0_pd,
+ },
+};
+
+static struct resource sgiseeq_1_resources[] = {
+ {
+ .name = "eth1 irq",
+ .start = SGI_GIO_0_IRQ,
+ .end = SGI_GIO_0_IRQ,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+static struct sgiseeq_platform_data eth1_pd;
+
+static struct platform_device eth1_device = {
+ .name = "sgiseeq",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(sgiseeq_1_resources),
+ .resource = sgiseeq_1_resources,
+ .dev = {
+ .platform_data = ð1_pd,
+ },
+};
+
+/*
+ * Create a platform device for the GPI port that receives the
+ * image data from the embedded camera.
+ */
+static int __init sgiseeq_devinit(void)
+{
+ unsigned int tmp;
+ int res, i;
+
+ eth0_pd.hpc = hpc3c0;
+ eth0_pd.irq = SGI_ENET_IRQ;
+#define EADDR_NVOFS 250
+ for (i = 0; i < 3; i++) {
+ unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i);
+
+ eth0_pd.mac[2 * i] = tmp >> 8;
+ eth0_pd.mac[2 * i + 1] = tmp & 0xff;
+ }
+
+ res = platform_device_register(ð0_device);
+ if (res)
+ return res;
+
+ /* Second HPC is missing? */
+ if (ip22_is_fullhouse() ||
+ !get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]))
+ return 0;
+
+ sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | SGIMC_GIOPAR_EXP164 |
+ SGIMC_GIOPAR_HPC264;
+ hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
+ /* interrupt/config register on Challenge S Mezz board */
+ hpc3c1->pbus_extregs[0][0] = 0x30;
+
+ eth1_pd.hpc = hpc3c1;
+ eth1_pd.irq = SGI_GIO_0_IRQ;
+#define EADDR_NVOFS 250
+ for (i = 0; i < 3; i++) {
+ unsigned short tmp = ip22_eeprom_read(&hpc3c1->eeprom,
+ EADDR_NVOFS / 2 + i);
+
+ eth1_pd.mac[2 * i] = tmp >> 8;
+ eth1_pd.mac[2 * i + 1] = tmp & 0xff;
+ }
+
+ return platform_device_register(ð1_device);
+}
+
+device_initcall(sgiseeq_devinit);
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index 93b7606..112dd51 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -146,7 +146,7 @@
interrupt-parent = < &ipic >;
interrupts = <42 8>;
bus-range = <0 0>;
- ranges = <02000000 0 a0000000 90000000 0 10000000
+ ranges = <02000000 0 90000000 90000000 0 10000000
42000000 0 80000000 80000000 0 10000000
01000000 0 00000000 d0000000 0 00100000>;
clock-frequency = <0>;
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index 07bcc51..df773fa 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -223,7 +223,7 @@
interrupt-parent = < &ipic >;
interrupts = <42 8>;
bus-range = <0 0>;
- ranges = <02000000 0 a0000000 a0000000 0 10000000
+ ranges = <02000000 0 90000000 90000000 0 10000000
42000000 0 80000000 80000000 0 10000000
01000000 0 00000000 e2000000 0 00100000>;
clock-frequency = <3f940aa>;
@@ -284,7 +284,7 @@
interrupts = <42 8>;
bus-range = <0 0>;
ranges = <02000000 0 b0000000 b0000000 0 10000000
- 42000000 0 90000000 90000000 0 10000000
+ 42000000 0 a0000000 a0000000 0 10000000
01000000 0 00000000 e2100000 0 00100000>;
clock-frequency = <3f940aa>;
#interrupt-cells = <1>;
diff --git a/arch/powerpc/configs/celleb_defconfig b/arch/powerpc/configs/celleb_defconfig
index a1fe971..91b657b 100644
--- a/arch/powerpc/configs/celleb_defconfig
+++ b/arch/powerpc/configs/celleb_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.20-rc4
-# Thu Jan 11 20:55:33 2007
+# Linux kernel version: 2.6.21
+# Tue May 8 12:32:16 2007
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -60,6 +60,7 @@
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_IPC_NS is not set
+CONFIG_SYSVIPC_SYSCTL=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
@@ -70,6 +71,7 @@
# CONFIG_CPUSETS is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SYSCTL=y
@@ -132,15 +134,26 @@
# CONFIG_PPC_PSERIES is not set
# CONFIG_PPC_ISERIES is not set
# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_MPC5200 is not set
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
# CONFIG_PPC_PASEMI is not set
+CONFIG_PPC_CELLEB=y
+# CONFIG_PPC_PS3 is not set
CONFIG_PPC_CELL=y
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_IBM_CELL_BLADE is not set
-# CONFIG_PPC_PS3 is not set
-CONFIG_PPC_CELLEB=y
+
+#
+# Cell Broadband Engine options
+#
+CONFIG_SPU_FS=y
+CONFIG_SPU_BASE=y
+# CONFIG_PQ2ADS is not set
CONFIG_PPC_UDBG_BEAT=y
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
# CONFIG_U3_DART is not set
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
@@ -149,15 +162,7 @@
# CONFIG_PPC_INDIRECT_IO is not set
# CONFIG_GENERIC_IOMAP is not set
# CONFIG_CPU_FREQ is not set
-# CONFIG_WANT_EARLY_SERIAL is not set
-# CONFIG_MPIC is not set
-
-#
-# Cell Broadband Engine options
-#
-CONFIG_SPU_FS=y
-CONFIG_SPU_BASE=y
-# CONFIG_CBE_RAS is not set
+# CONFIG_CPM2 is not set
#
# Kernel options
@@ -183,7 +188,6 @@
CONFIG_NODES_SHIFT=4
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
-CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
@@ -199,6 +203,7 @@
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
CONFIG_ARCH_MEMORY_PROBE=y
CONFIG_NODES_SPAN_OTHER_NODES=y
# CONFIG_PPC_64K_PAGES is not set
@@ -207,14 +212,14 @@
# CONFIG_CMDLINE_BOOL is not set
# CONFIG_PM is not set
CONFIG_SECCOMP=y
+# CONFIG_WANT_DEVICE_TREE is not set
CONFIG_ISA_DMA_API=y
#
# Bus options
#
+CONFIG_ZONE_DMA=y
CONFIG_GENERIC_ISA_DMA=y
-# CONFIG_MPIC_WEIRD is not set
-# CONFIG_PPC_I8259 is not set
# CONFIG_PPC_INDIRECT_PCI is not set
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
@@ -240,13 +245,13 @@
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -262,7 +267,7 @@
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_XFRM_MODE_BEET=y
@@ -280,6 +285,7 @@
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
@@ -302,17 +308,21 @@
#
# CONFIG_NETFILTER_NETLINK is not set
# CONFIG_NF_CONNTRACK_ENABLED is not set
+# CONFIG_NF_CONNTRACK is not set
# CONFIG_NETFILTER_XTABLES is not set
#
# IP: Netfilter Configuration
#
CONFIG_IP_NF_QUEUE=m
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
#
# IPv6: Netfilter Configuration (EXPERIMENTAL)
#
# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
#
# DCCP Configuration (EXPERIMENTAL)
@@ -352,6 +362,13 @@
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
# CONFIG_IEEE80211 is not set
#
@@ -365,16 +382,13 @@
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
#
# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
# CONFIG_MTD is not set
#
@@ -385,6 +399,7 @@
#
# Plug and Play support
#
+# CONFIG_PNPACPI is not set
#
# Block devices
@@ -404,7 +419,6 @@
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=131072
CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -443,7 +457,6 @@
# CONFIG_BLK_DEV_OPTI621 is not set
CONFIG_BLK_DEV_IDEDMA_PCI=y
# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_IDEDMA_ONLYDISK is not set
# CONFIG_BLK_DEV_AEC62XX is not set
# CONFIG_BLK_DEV_ALI15X3 is not set
@@ -458,6 +471,7 @@
# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
# CONFIG_BLK_DEV_IT821X is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
@@ -468,11 +482,11 @@
# CONFIG_BLK_DEV_SLC90E66 is not set
# CONFIG_BLK_DEV_TRM290 is not set
# CONFIG_BLK_DEV_VIA82CXXX is not set
-CONFIG_BLK_DEV_IDE_CELLEB=y
+# CONFIG_BLK_DEV_TC86C001 is not set
+CONFIG_BLK_DEV_CELLEB=y
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
-CONFIG_IDEDMA_AUTO=y
# CONFIG_BLK_DEV_HD is not set
#
@@ -546,6 +560,7 @@
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_ESP_CORE is not set
# CONFIG_SCSI_SRP is not set
#
@@ -591,12 +606,7 @@
# I2O device support
#
# CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-# CONFIG_MAC_EMUMOUSEBTN is not set
-# CONFIG_WINDFARM is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
#
# Network device support
@@ -652,15 +662,18 @@
# CONFIG_BNX2 is not set
CONFIG_SPIDER_NET=y
# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
#
# Ethernet (10000 Mbit)
#
# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
+# CONFIG_PASEMI_MAC is not set
#
# Token Ring devices
@@ -668,9 +681,10 @@
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
+# Wireless LAN
#
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
#
# Wan interfaces
@@ -770,6 +784,7 @@
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_SERIAL_TXX9=y
CONFIG_HAS_TXX9_SERIAL=y
+CONFIG_SERIAL_TXX9_NR_UARTS=3
CONFIG_SERIAL_TXX9_CONSOLE=y
# CONFIG_SERIAL_TXX9_STDSERIAL is not set
# CONFIG_SERIAL_JSM is not set
@@ -891,6 +906,11 @@
# CONFIG_HWMON_VID is not set
#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+
+#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
@@ -904,7 +924,7 @@
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
# CONFIG_FB is not set
# CONFIG_FB_IBM_GXT4500 is not set
@@ -913,7 +933,6 @@
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -924,6 +943,15 @@
# HID Devices
#
CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+CONFIG_USB_HIDDEV=y
#
# USB support
@@ -938,9 +966,8 @@
# Miscellaneous USB options
#
CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DEVICE_CLASS is not set
# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_MULTITHREAD_PROBE is not set
# CONFIG_USB_OTG is not set
#
@@ -953,6 +980,7 @@
CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
@@ -989,10 +1017,6 @@
#
# USB Input Devices
#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-CONFIG_USB_HIDDEV=y
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
# CONFIG_USB_ACECAD is not set
@@ -1005,6 +1029,7 @@
# CONFIG_USB_ATI_REMOTE2 is not set
# CONFIG_USB_KEYSPAN_REMOTE is not set
# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_GTCO is not set
#
# USB Imaging devices
@@ -1042,6 +1067,7 @@
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
@@ -1052,6 +1078,7 @@
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1109,6 +1136,10 @@
#
#
+# Auxiliary Display support
+#
+
+#
# Virtualization
#
@@ -1293,6 +1324,8 @@
# Distributed Lock Manager
#
# CONFIG_DLM is not set
+# CONFIG_UCC_SLOW is not set
+# CONFIG_UCC_FAST is not set
#
# Library routines
@@ -1305,7 +1338,8 @@
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
CONFIG_PLIST=y
-CONFIG_IOMAP_COPY=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
#
# Instrumentation Support
@@ -1323,15 +1357,16 @@
CONFIG_DEBUG_FS=y
# CONFIG_HEADERS_CHECK is not set
CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
CONFIG_LOG_BUF_SHIFT=15
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_SLAB 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_MUTEXES=y
-# CONFIG_DEBUG_RWSEMS is not set
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
@@ -1341,8 +1376,10 @@
# CONFIG_DEBUG_LIST is not set
# CONFIG_FORCED_INLINING is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
# CONFIG_DEBUG_STACKOVERFLOW is not set
# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
CONFIG_DEBUGGER=y
CONFIG_XMON=y
CONFIG_XMON_DEFAULT=y
@@ -1356,6 +1393,7 @@
# CONFIG_PPC_EARLY_DEBUG_RTAS_CONSOLE is not set
# CONFIG_PPC_EARLY_DEBUG_MAPLE is not set
# CONFIG_PPC_EARLY_DEBUG_ISERIES is not set
+# CONFIG_PPC_EARLY_DEBUG_PAS_REALMODE is not set
CONFIG_PPC_EARLY_DEBUG_BEAT=y
#
@@ -1385,8 +1423,10 @@
# CONFIG_CRYPTO_GF128MUL is not set
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
CONFIG_CRYPTO_TWOFISH_COMMON=m
@@ -1401,6 +1441,7 @@
CONFIG_CRYPTO_DEFLATE=m
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_CAMELLIA is not set
CONFIG_CRYPTO_TEST=m
#
diff --git a/arch/powerpc/kernel/audit.c b/arch/powerpc/kernel/audit.c
index 7fe5e63..a4dab7c 100644
--- a/arch/powerpc/kernel/audit.c
+++ b/arch/powerpc/kernel/audit.c
@@ -23,6 +23,20 @@
~0U
};
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_PPC64
+ if (arch == AUDIT_ARCH_PPC)
+ return 1;
+#endif
+ return 0;
+}
+
int audit_classify_syscall(int abi, unsigned syscall)
{
#ifdef CONFIG_PPC64
@@ -51,15 +65,18 @@
extern __u32 ppc32_write_class[];
extern __u32 ppc32_read_class[];
extern __u32 ppc32_chattr_class[];
+ extern __u32 ppc32_signal_class[];
audit_register_class(AUDIT_CLASS_WRITE_32, ppc32_write_class);
audit_register_class(AUDIT_CLASS_READ_32, ppc32_read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ppc32_dir_class);
audit_register_class(AUDIT_CLASS_CHATTR_32, ppc32_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, ppc32_signal_class);
#endif
audit_register_class(AUDIT_CLASS_WRITE, write_class);
audit_register_class(AUDIT_CLASS_READ, read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
return 0;
}
diff --git a/arch/powerpc/kernel/compat_audit.c b/arch/powerpc/kernel/compat_audit.c
index 640d4bb..108ff14 100644
--- a/arch/powerpc/kernel/compat_audit.c
+++ b/arch/powerpc/kernel/compat_audit.c
@@ -21,6 +21,11 @@
~0U
};
+unsigned ppc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
int ppc32_classify_syscall(unsigned syscall)
{
switch(syscall) {
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 9ed4931..068377a 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -173,7 +173,7 @@
lv1_get_version_info(&tmp);
}
- hard_irq_enable();
+ __hard_irq_enable();
}
#endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 6d05a1f..b0409e1 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -1098,35 +1098,24 @@
unsigned long *start_virt, unsigned long *size)
{
struct pci_controller *hose = pci_bus_to_host(bus);
- struct pci_bus_region region;
struct resource *res;
- if (bus->self) {
+ if (bus->self)
res = bus->resource[0];
- pcibios_resource_to_bus(bus->self, ®ion, res);
- *start_phys = hose->io_base_phys + region.start;
- *start_virt = (unsigned long) hose->io_base_virt +
- region.start;
- if (region.end > region.start)
- *size = region.end - region.start + 1;
- else {
- printk("%s(): unexpected region 0x%lx->0x%lx\n",
- __FUNCTION__, region.start, region.end);
- return 1;
- }
-
- } else {
+ else
/* Root Bus */
res = &hose->io_resource;
- *start_phys = hose->io_base_phys + res->start;
- *start_virt = (unsigned long) hose->io_base_virt + res->start;
- if (res->end > res->start)
- *size = res->end - res->start + 1;
- else {
- printk("%s(): unexpected region 0x%lx->0x%lx\n",
- __FUNCTION__, res->start, res->end);
- return 1;
- }
+
+ *start_virt = pci_io_base + res->start;
+ *start_phys = *start_virt + hose->io_base_phys
+ - (unsigned long) hose->io_base_virt;
+
+ if (res->end > res->start)
+ *size = res->end - res->start + 1;
+ else {
+ printk("%s(): unexpected region 0x%lx->0x%lx\n",
+ __FUNCTION__, res->start, res->end);
+ return 1;
}
return 0;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index caef555..c065b55 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -716,11 +716,40 @@
return 0;
}
+#ifdef CONFIG_BLK_DEV_INITRD
+static void __init early_init_dt_check_for_initrd(unsigned long node)
+{
+ unsigned long l;
+ u32 *prop;
+
+ DBG("Looking for initrd properties... ");
+
+ prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
+ if (prop) {
+ initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
+
+ prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
+ if (prop) {
+ initrd_end = (unsigned long)
+ __va(of_read_ulong(prop, l/4));
+ initrd_below_start_ok = 1;
+ } else {
+ initrd_start = 0;
+ }
+ }
+
+ DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end);
+}
+#else
+static inline void early_init_dt_check_for_initrd(unsigned long node)
+{
+}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
static int __init early_init_dt_scan_chosen(unsigned long node,
const char *uname, int depth, void *data)
{
unsigned long *lprop;
- u32 *prop;
unsigned long l;
char *p;
@@ -762,21 +791,7 @@
crashk_res.end = crashk_res.start + *lprop - 1;
#endif
-#ifdef CONFIG_BLK_DEV_INITRD
- DBG("Looking for initrd properties... ");
- prop = of_get_flat_dt_prop(node, "linux,initrd-start", &l);
- if (prop) {
- initrd_start = (unsigned long)__va(of_read_ulong(prop, l/4));
- prop = of_get_flat_dt_prop(node, "linux,initrd-end", &l);
- if (prop) {
- initrd_end = (unsigned long)__va(of_read_ulong(prop, l/4));
- initrd_below_start_ok = 1;
- } else {
- initrd_start = 0;
- }
- }
- DBG("initrd_start=0x%lx initrd_end=0x%lx\n", initrd_start, initrd_end);
-#endif /* CONFIG_BLK_DEV_INITRD */
+ early_init_dt_check_for_initrd(node);
/* Retreive command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
diff --git a/arch/powerpc/kernel/swsusp.c b/arch/powerpc/kernel/swsusp.c
index 064a7ba..77b7b34 100644
--- a/arch/powerpc/kernel/swsusp.c
+++ b/arch/powerpc/kernel/swsusp.c
@@ -36,8 +36,4 @@
#ifdef CONFIG_PPC32
set_context(current->active_mm->context.id, current->active_mm->pgd);
#endif
-
-#ifdef CONFIG_PPC64
- hard_irq_enable();
-#endif
}
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 450258d..0a486d4 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -23,7 +23,5 @@
endif
# Temporary hack until we have migrated to asm-powerpc
-ifeq ($(CONFIG_PPC_MERGE),y)
obj-$(CONFIG_8xx) += rheap.o
obj-$(CONFIG_CPM2) += rheap.o
-endif
diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
index 6c5c5dd..b2f6dcc 100644
--- a/arch/powerpc/lib/rheap.c
+++ b/arch/powerpc/lib/rheap.c
@@ -133,7 +133,7 @@
info->empty_slots--;
/* Initialize */
- blk->start = NULL;
+ blk->start = 0;
blk->size = 0;
blk->owner = NULL;
@@ -158,7 +158,7 @@
/* We assume that they are aligned properly */
size = blkn->size;
- s = (unsigned long)blkn->start;
+ s = blkn->start;
e = s + size;
/* Find the blocks immediately before and after the given one
@@ -170,7 +170,7 @@
list_for_each(l, &info->free_list) {
blk = list_entry(l, rh_block_t, list);
- bs = (unsigned long)blk->start;
+ bs = blk->start;
be = bs + blk->size;
if (next == NULL && s >= bs)
@@ -188,10 +188,10 @@
}
/* Now check if they are really adjacent */
- if (before != NULL && s != (unsigned long)before->start + before->size)
+ if (before && s != (before->start + before->size))
before = NULL;
- if (after != NULL && e != (unsigned long)after->start)
+ if (after && e != after->start)
after = NULL;
/* No coalescing; list insert and return */
@@ -216,7 +216,7 @@
/* Grow the after block backwards */
if (before == NULL && after != NULL) {
- after->start = (int8_t *)after->start - size;
+ after->start -= size;
after->size += size;
return;
}
@@ -321,14 +321,14 @@
}
/* Attach a free memory region, coalesces regions if adjuscent */
-int rh_attach_region(rh_info_t * info, void *start, int size)
+int rh_attach_region(rh_info_t * info, unsigned long start, int size)
{
rh_block_t *blk;
unsigned long s, e, m;
int r;
/* The region must be aligned */
- s = (unsigned long)start;
+ s = start;
e = s + size;
m = info->alignment - 1;
@@ -338,9 +338,12 @@
/* Round end down */
e = e & ~m;
+ if (IS_ERR_VALUE(e) || (e < s))
+ return -ERANGE;
+
/* Take final values */
- start = (void *)s;
- size = (int)(e - s);
+ start = s;
+ size = e - s;
/* Grow the blocks, if needed */
r = assure_empty(info, 1);
@@ -358,7 +361,7 @@
}
/* Detatch given address range, splits free block if needed. */
-void *rh_detach_region(rh_info_t * info, void *start, int size)
+unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size)
{
struct list_head *l;
rh_block_t *blk, *newblk;
@@ -366,10 +369,10 @@
/* Validate size */
if (size <= 0)
- return ERR_PTR(-EINVAL);
+ return (unsigned long) -EINVAL;
/* The region must be aligned */
- s = (unsigned long)start;
+ s = start;
e = s + size;
m = info->alignment - 1;
@@ -380,34 +383,34 @@
e = e & ~m;
if (assure_empty(info, 1) < 0)
- return ERR_PTR(-ENOMEM);
+ return (unsigned long) -ENOMEM;
blk = NULL;
list_for_each(l, &info->free_list) {
blk = list_entry(l, rh_block_t, list);
/* The range must lie entirely inside one free block */
- bs = (unsigned long)blk->start;
- be = (unsigned long)blk->start + blk->size;
+ bs = blk->start;
+ be = blk->start + blk->size;
if (s >= bs && e <= be)
break;
blk = NULL;
}
if (blk == NULL)
- return ERR_PTR(-ENOMEM);
+ return (unsigned long) -ENOMEM;
/* Perfect fit */
if (bs == s && be == e) {
/* Delete from free list, release slot */
list_del(&blk->list);
release_slot(info, blk);
- return (void *)s;
+ return s;
}
/* blk still in free list, with updated start and/or size */
if (bs == s || be == e) {
if (bs == s)
- blk->start = (int8_t *)blk->start + size;
+ blk->start += size;
blk->size -= size;
} else {
@@ -416,25 +419,29 @@
/* the back free fragment */
newblk = get_slot(info);
- newblk->start = (void *)e;
+ newblk->start = e;
newblk->size = be - e;
list_add(&newblk->list, &blk->list);
}
- return (void *)s;
+ return s;
}
-void *rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
+/* Allocate a block of memory at the specified alignment. The value returned
+ * is an offset into the buffer initialized by rh_init(), or a negative number
+ * if there is an error.
+ */
+unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment, const char *owner)
{
struct list_head *l;
rh_block_t *blk;
rh_block_t *newblk;
- void *start;
+ unsigned long start;
- /* Validate size, (must be power of two) */
+ /* Validate size, and alignment must be power of two */
if (size <= 0 || (alignment & (alignment - 1)) != 0)
- return ERR_PTR(-EINVAL);
+ return (unsigned long) -EINVAL;
/* given alignment larger that default rheap alignment */
if (alignment > info->alignment)
@@ -444,7 +451,7 @@
size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
if (assure_empty(info, 1) < 0)
- return ERR_PTR(-ENOMEM);
+ return (unsigned long) -ENOMEM;
blk = NULL;
list_for_each(l, &info->free_list) {
@@ -455,7 +462,7 @@
}
if (blk == NULL)
- return ERR_PTR(-ENOMEM);
+ return (unsigned long) -ENOMEM;
/* Just fits */
if (blk->size == size) {
@@ -475,7 +482,7 @@
newblk->owner = owner;
/* blk still in free list, with updated start, size */
- blk->start = (int8_t *)blk->start + size;
+ blk->start += size;
blk->size -= size;
start = newblk->start;
@@ -486,19 +493,25 @@
/* this is no problem with the deallocator since */
/* we scan for pointers that lie in the blocks */
if (alignment > info->alignment)
- start = (void *)(((unsigned long)start + alignment - 1) &
- ~(alignment - 1));
+ start = (start + alignment - 1) & ~(alignment - 1);
return start;
}
-void *rh_alloc(rh_info_t * info, int size, const char *owner)
+/* Allocate a block of memory at the default alignment. The value returned is
+ * an offset into the buffer initialized by rh_init(), or a negative number if
+ * there is an error.
+ */
+unsigned long rh_alloc(rh_info_t * info, int size, const char *owner)
{
return rh_alloc_align(info, size, info->alignment, owner);
}
-/* allocate at precisely the given address */
-void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
+/* Allocate a block of memory at the given offset, rounded up to the default
+ * alignment. The value returned is an offset into the buffer initialized by
+ * rh_init(), or a negative number if there is an error.
+ */
+unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size, const char *owner)
{
struct list_head *l;
rh_block_t *blk, *newblk1, *newblk2;
@@ -506,10 +519,10 @@
/* Validate size */
if (size <= 0)
- return ERR_PTR(-EINVAL);
+ return (unsigned long) -EINVAL;
/* The region must be aligned */
- s = (unsigned long)start;
+ s = start;
e = s + size;
m = info->alignment - 1;
@@ -520,20 +533,20 @@
e = e & ~m;
if (assure_empty(info, 2) < 0)
- return ERR_PTR(-ENOMEM);
+ return (unsigned long) -ENOMEM;
blk = NULL;
list_for_each(l, &info->free_list) {
blk = list_entry(l, rh_block_t, list);
/* The range must lie entirely inside one free block */
- bs = (unsigned long)blk->start;
- be = (unsigned long)blk->start + blk->size;
+ bs = blk->start;
+ be = blk->start + blk->size;
if (s >= bs && e <= be)
break;
}
if (blk == NULL)
- return ERR_PTR(-ENOMEM);
+ return (unsigned long) -ENOMEM;
/* Perfect fit */
if (bs == s && be == e) {
@@ -551,7 +564,7 @@
/* blk still in free list, with updated start and/or size */
if (bs == s || be == e) {
if (bs == s)
- blk->start = (int8_t *)blk->start + size;
+ blk->start += size;
blk->size -= size;
} else {
@@ -560,14 +573,14 @@
/* The back free fragment */
newblk2 = get_slot(info);
- newblk2->start = (void *)e;
+ newblk2->start = e;
newblk2->size = be - e;
list_add(&newblk2->list, &blk->list);
}
newblk1 = get_slot(info);
- newblk1->start = (void *)s;
+ newblk1->start = s;
newblk1->size = e - s;
newblk1->owner = owner;
@@ -577,7 +590,11 @@
return start;
}
-int rh_free(rh_info_t * info, void *start)
+/* Deallocate the memory previously allocated by one of the rh_alloc functions.
+ * The return value is the size of the deallocated block, or a negative number
+ * if there is an error.
+ */
+int rh_free(rh_info_t * info, unsigned long start)
{
rh_block_t *blk, *blk2;
struct list_head *l;
@@ -642,7 +659,7 @@
return nr;
}
-int rh_set_owner(rh_info_t * info, void *start, const char *owner)
+int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner)
{
rh_block_t *blk, *blk2;
struct list_head *l;
@@ -684,8 +701,8 @@
nr = maxnr;
for (i = 0; i < nr; i++)
printk(KERN_INFO
- " 0x%p-0x%p (%u)\n",
- st[i].start, (int8_t *) st[i].start + st[i].size,
+ " 0x%lx-0x%lx (%u)\n",
+ st[i].start, st[i].start + st[i].size,
st[i].size);
printk(KERN_INFO "\n");
@@ -695,8 +712,8 @@
nr = maxnr;
for (i = 0; i < nr; i++)
printk(KERN_INFO
- " 0x%p-0x%p (%u) %s\n",
- st[i].start, (int8_t *) st[i].start + st[i].size,
+ " 0x%lx-0x%lx (%u) %s\n",
+ st[i].start, st[i].start + st[i].size,
st[i].size, st[i].owner != NULL ? st[i].owner : "");
printk(KERN_INFO "\n");
}
@@ -704,6 +721,6 @@
void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
{
printk(KERN_INFO
- "blk @0x%p: 0x%p-0x%p (%u)\n",
- blk, blk->start, (int8_t *) blk->start + blk->size, blk->size);
+ "blk @0x%p: 0x%lx-0x%lx (%u)\n",
+ blk, blk->start, blk->start + blk->size, blk->size);
}
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 7b7fe2d..7d722ee 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -376,31 +376,28 @@
}
}
- /*
- * FIXME, the code below works for 16M, 64K, and 4K pages as these
- * fall under the p<=23 rules for calculating the virtual address.
- * In the case of 16M pages, an extra bit is stolen from the AVPN
- * field to achieve the requisite 24 bits.
- *
- * Does not work for 16G pages or 1 TB segments.
- */
+ /* This works for all page sizes, and for 256M and 1T segments */
shift = mmu_psize_defs[size].shift;
- if (mmu_psize_defs[size].avpnm)
- avpnm_bits = __ilog2_u64(mmu_psize_defs[size].avpnm) + 1;
- else
- avpnm_bits = 0;
- if (shift - avpnm_bits <= 23) {
- avpn = HPTE_V_AVPN_VAL(hpte_v) << 23;
+ avpn = (HPTE_V_AVPN_VAL(hpte_v) & ~mmu_psize_defs[size].avpnm) << 23;
- if (shift < 23) {
- unsigned long vpi, pteg;
+ if (shift < 23) {
+ unsigned long vpi, vsid, pteg;
- pteg = slot / HPTES_PER_GROUP;
- if (hpte_v & HPTE_V_SECONDARY)
- pteg = ~pteg;
+ pteg = slot / HPTES_PER_GROUP;
+ if (hpte_v & HPTE_V_SECONDARY)
+ pteg = ~pteg;
+ switch (hpte_v >> HPTE_V_SSIZE_SHIFT) {
+ case MMU_SEGSIZE_256M:
vpi = ((avpn >> 28) ^ pteg) & htab_hash_mask;
- avpn |= (vpi << mmu_psize_defs[size].shift);
+ break;
+ case MMU_SEGSIZE_1T:
+ vsid = avpn >> 40;
+ vpi = (vsid ^ (vsid << 25) ^ pteg) & htab_hash_mask;
+ break;
+ default:
+ avpn = vpi = psize = 0;
}
+ avpn |= (vpi << mmu_psize_defs[size].shift);
}
*va = avpn;
diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
index 32e9e94..96970ac 100644
--- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c
@@ -40,7 +40,9 @@
*/
static void __init mpc8313_rdb_setup_arch(void)
{
+#ifdef CONFIG_PCI
struct device_node *np;
+#endif
if (ppc_md.progress)
ppc_md.progress("mpc8313_rdb_setup_arch()", 0);
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index b0b22bb..3db68b7 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -44,7 +44,9 @@
*/
static void __init mpc832x_rdb_setup_arch(void)
{
+#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE)
struct device_node *np;
+#endif
if (ppc_md.progress)
ppc_md.progress("mpc832x_rdb_setup_arch()", 0);
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 3c009f6..40a0194 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -50,7 +50,9 @@
*/
static void __init mpc834x_itx_setup_arch(void)
{
+#ifdef CONFIG_PCI
struct device_node *np;
+#endif
if (ppc_md.progress)
ppc_md.progress("mpc834x_itx_setup_arch()", 0);
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c
index 8aa9a93..10394b2 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c
@@ -120,7 +120,9 @@
*/
static void __init mpc834x_mds_setup_arch(void)
{
+#ifdef CONFIG_PCI
struct device_node *np;
+#endif
if (ppc_md.progress)
ppc_md.progress("mpc834x_mds_setup_arch()", 0);
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index 90877565..1051702 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -168,7 +168,7 @@
{
unsigned short temp;
struct pci_controller *hose = pci_bus_to_host(dev->bus);
- unsigned char irq2pin[16];
+ unsigned char irq2pin[16], c;
unsigned long pirq_map_word = 0;
u32 irq;
int i;
@@ -288,6 +288,11 @@
outb(0x1e, 0x4d1);
#undef ULI1575_SET_DEV_IRQ
+
+ /* Disable the HD interface and enable the AC97 interface. */
+ pci_read_config_byte(dev, 0xb8, &c);
+ c &= 0x7f;
+ pci_write_config_byte(dev, 0xb8, c);
}
static void __devinit quirk_uli5288(struct pci_dev *dev)
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index 8c20f0f..812bf56 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -43,12 +43,10 @@
unsigned long ctrl, thread_switch_control;
/*
- * We need to hard disable interrupts, but we also need to mark them
- * hard disabled in the PACA so that the local_irq_enable() done by
- * our caller upon return propertly hard enables.
+ * We need to hard disable interrupts, the local_irq_enable() done by
+ * our caller upon return will hard re-enable.
*/
hard_irq_disable();
- get_paca()->hard_enabled = 0;
ctrl = mfspr(SPRN_CTRLF);
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
index d1adf34..e9ac19c 100644
--- a/arch/powerpc/platforms/celleb/pci.c
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -457,6 +457,7 @@
pr_debug("PCI: celleb_setup_phb() %s\n", name);
phb_set_bus_ranges(dev, phb);
+ phb->buid = 1;
if (strcmp(name, "epci") == 0) {
phb->ops = &celleb_epci_ops;
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c
index fb23d53..c4b0110 100644
--- a/arch/powerpc/platforms/celleb/scc_epci.c
+++ b/arch/powerpc/platforms/celleb/scc_epci.c
@@ -133,13 +133,13 @@
}
static volatile void __iomem *celleb_epci_make_config_addr(
+ struct pci_bus *bus,
struct pci_controller *hose,
unsigned int devfn, int where)
{
volatile void __iomem *addr;
- struct pci_bus *bus = hose->bus;
- if (bus->self)
+ if (bus != hose->bus)
addr = celleb_epci_get_epci_cfg(hose) +
(((bus->number & 0xff) << 16)
| ((devfn & 0xff) << 8)
@@ -193,7 +193,7 @@
} else {
clear_and_disable_master_abort_interrupt(hose);
- addr = celleb_epci_make_config_addr(hose, devfn, where);
+ addr = celleb_epci_make_config_addr(bus, hose, devfn, where);
switch (size) {
case 1:
@@ -257,7 +257,7 @@
} else {
clear_and_disable_master_abort_interrupt(hose);
- addr = celleb_epci_make_config_addr(hose, devfn, where);
+ addr = celleb_epci_make_config_addr(bus, hose, devfn, where);
switch (size) {
case 1:
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
index 596ab2a..5e9f7f1 100644
--- a/arch/powerpc/platforms/celleb/setup.c
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -80,7 +80,7 @@
return 0;
}
-__setup("celleb_machine_type_hack", celleb_machine_type_hack);
+__setup("celleb_machine_type_hack=", celleb_machine_type_hack);
static void celleb_progress(char *s, unsigned short hex)
{
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 093438b..5f3e6d8 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -76,7 +76,7 @@
*/
#define EEH_MAX_FAILS 2100000
-/* Time to wait for a PCI slot to retport status, in milliseconds */
+/* Time to wait for a PCI slot to report status, in milliseconds */
#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
/* RTAS tokens */
@@ -95,11 +95,18 @@
/* Lock to avoid races due to multiple reports of an error */
static DEFINE_SPINLOCK(confirm_error_lock);
-/* Buffer for reporting slot-error-detail rtas calls */
+/* Buffer for reporting slot-error-detail rtas calls. Its here
+ * in BSS, and not dynamically alloced, so that it ends up in
+ * RMO where RTAS can access it.
+ */
static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX];
static DEFINE_SPINLOCK(slot_errbuf_lock);
static int eeh_error_buf_size;
+/* Buffer for reporting pci register dumps. Its here in BSS, and
+ * not dynamically alloced, so that it ends up in RMO where RTAS
+ * can access it.
+ */
#define EEH_PCI_REGS_LOG_LEN 4096
static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN];
@@ -218,7 +225,7 @@
void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
{
size_t loglen = 0;
- memset(pci_regs_buf, 0, EEH_PCI_REGS_LOG_LEN);
+ pci_regs_buf[0] = 0;
rtas_pci_enable(pdn, EEH_THAW_MMIO);
loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index f07d849..161a584 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -378,8 +378,9 @@
/* Since rtas may enable MMIO when posting the error log,
* don't post the error log until after all dev drivers
- * have been informed. */
- eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
+ * have been informed.
+ */
+ eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE);
/* If all device drivers were EEH-unaware, then shut
* down all of the device drivers, and hope they
@@ -470,7 +471,7 @@
location, drv_str, pci_str);
perm_error:
- eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */);
+ eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE);
/* Notify all devices that they're about to go down. */
pci_walk_bus(frozen_bus, eeh_report_failure, NULL);
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index eec684a..be17d23 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -520,7 +520,6 @@
dev->dev.archdata.dma_data = PCI_DN(pdn)->iommu_table;
return;
}
- DBG(" found DMA window, table: %p\n", pci->iommu_table);
pci = PCI_DN(pdn);
if (!pci->iommu_table) {
@@ -534,6 +533,8 @@
pci->iommu_table = iommu_init_table(tbl, pci->phb->node);
DBG(" created table: %p\n", pci->iommu_table);
+ } else {
+ DBG(" found DMA window, table: %p\n", pci->iommu_table);
}
dev->dev.archdata.dma_data = pci->iommu_table;
diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c
index af26856..412a5e7 100644
--- a/arch/powerpc/platforms/pseries/kexec.c
+++ b/arch/powerpc/platforms/pseries/kexec.c
@@ -12,6 +12,7 @@
#include <asm/firmware.h>
#include <asm/kexec.h>
#include <asm/mpic.h>
+#include <asm/smp.h>
#include "pseries.h"
#include "xics.h"
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/commproc.c
index 9b4fafd..4f67b89 100644
--- a/arch/powerpc/sysdev/commproc.c
+++ b/arch/powerpc/sysdev/commproc.c
@@ -330,7 +330,7 @@
* with the processor and the microcode patches applied / activated.
* But the following should be at least safe.
*/
- rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
+ rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
}
/*
@@ -338,9 +338,9 @@
* This function returns an offset into the DPRAM area.
* Use cpm_dpram_addr() to get the virtual address of the area.
*/
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -352,30 +352,30 @@
}
EXPORT_SYMBOL(cpm_dpalloc);
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
- ret = rh_free(&cpm_dpmem_info, (void *)offset);
+ ret = rh_free(&cpm_dpmem_info, offset);
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
return ret;
}
EXPORT_SYMBOL(cpm_dpfree);
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
cpm_dpmem_info.alignment = align;
- start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+ start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
- return (uint)start;
+ return start;
}
EXPORT_SYMBOL(cpm_dpalloc_fixed);
@@ -385,7 +385,7 @@
}
EXPORT_SYMBOL(cpm_dpdump);
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
{
return (void *)(dpram_vbase + offset);
}
diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c
index ec26599..9244129 100644
--- a/arch/powerpc/sysdev/cpm2_common.c
+++ b/arch/powerpc/sysdev/cpm2_common.c
@@ -248,15 +248,14 @@
* varies with the processor and the microcode patches activated.
* But the following should be at least safe.
*/
- rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
- CPM_DATAONLY_SIZE);
+ rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
}
/* This function returns an index into the DPRAM area.
*/
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -268,13 +267,13 @@
}
EXPORT_SYMBOL(cpm_dpalloc);
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
- ret = rh_free(&cpm_dpmem_info, (void *)offset);
+ ret = rh_free(&cpm_dpmem_info, offset);
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
return ret;
@@ -282,17 +281,17 @@
EXPORT_SYMBOL(cpm_dpfree);
/* not sure if this is ever needed */
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
cpm_dpmem_info.alignment = align;
- start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+ start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
- return (uint)start;
+ return start;
}
EXPORT_SYMBOL(cpm_dpalloc_fixed);
@@ -302,7 +301,7 @@
}
EXPORT_SYMBOL(cpm_dpdump);
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
{
return (void *)(im_dprambase + offset);
}
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
index 7f4c075..90f8740 100644
--- a/arch/powerpc/sysdev/qe_lib/qe.c
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -244,7 +244,7 @@
static int qe_sdma_init(void)
{
struct sdma *sdma = &qe_immr->sdma;
- u32 sdma_buf_offset;
+ unsigned long sdma_buf_offset;
if (!sdma)
return -ENODEV;
@@ -252,10 +252,10 @@
/* allocate 2 internal temporary buffers (512 bytes size each) for
* the SDMA */
sdma_buf_offset = qe_muram_alloc(512 * 2, 4096);
- if (IS_MURAM_ERR(sdma_buf_offset))
+ if (IS_ERR_VALUE(sdma_buf_offset))
return -ENOMEM;
- out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
+ out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK);
out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK |
(0x1 << QE_SDMR_CEN_SHIFT)));
@@ -291,33 +291,32 @@
if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
address = *of_get_address(np, 0, &size, &flags);
of_node_put(np);
- rh_attach_region(&qe_muram_info,
- (void *)address, (int)size);
+ rh_attach_region(&qe_muram_info, address, (int) size);
}
}
/* This function returns an index into the MURAM area.
*/
-u32 qe_muram_alloc(u32 size, u32 align)
+unsigned long qe_muram_alloc(int size, int align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&qe_muram_lock, flags);
start = rh_alloc_align(&qe_muram_info, size, align, "QE");
spin_unlock_irqrestore(&qe_muram_lock, flags);
- return (u32) start;
+ return start;
}
EXPORT_SYMBOL(qe_muram_alloc);
-int qe_muram_free(u32 offset)
+int qe_muram_free(unsigned long offset)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&qe_muram_lock, flags);
- ret = rh_free(&qe_muram_info, (void *)offset);
+ ret = rh_free(&qe_muram_info, offset);
spin_unlock_irqrestore(&qe_muram_lock, flags);
return ret;
@@ -325,16 +324,16 @@
EXPORT_SYMBOL(qe_muram_free);
/* not sure if this is ever needed */
-u32 qe_muram_alloc_fixed(u32 offset, u32 size)
+unsigned long qe_muram_alloc_fixed(unsigned long offset, int size)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&qe_muram_lock, flags);
- start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc");
+ start = rh_alloc_fixed(&qe_muram_info, offset, size, "commproc");
spin_unlock_irqrestore(&qe_muram_lock, flags);
- return (u32) start;
+ return start;
}
EXPORT_SYMBOL(qe_muram_alloc_fixed);
@@ -344,7 +343,7 @@
}
EXPORT_SYMBOL(qe_muram_dump);
-void *qe_muram_addr(u32 offset)
+void *qe_muram_addr(unsigned long offset)
{
return (void *)&qe_immr->muram[offset];
}
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
index 66137bf..9143236 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_fast.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/interrupt.h>
+#include <linux/err.h>
#include <asm/io.h>
#include <asm/immap_qe.h>
@@ -268,7 +269,7 @@
/* Allocate memory for Tx Virtual Fifo */
uccf->ucc_fast_tx_virtual_fifo_base_offset =
qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
- if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
+ if (IS_ERR_VALUE(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
printk(KERN_ERR "%s: cannot allocate MURAM for TX FIFO", __FUNCTION__);
uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
ucc_fast_free(uccf);
@@ -280,7 +281,7 @@
qe_muram_alloc(uf_info->urfs +
UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
- if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
+ if (IS_ERR_VALUE(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
printk(KERN_ERR "%s: cannot allocate MURAM for RX FIFO", __FUNCTION__);
uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
ucc_fast_free(uccf);
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
index b930d68..1f65c26 100644
--- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c
+++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/stddef.h>
#include <linux/interrupt.h>
+#include <linux/err.h>
#include <asm/io.h>
#include <asm/immap_qe.h>
@@ -175,7 +176,7 @@
/* Get PRAM base */
uccs->us_pram_offset =
qe_muram_alloc(UCC_SLOW_PRAM_SIZE, ALIGNMENT_OF_UCC_SLOW_PRAM);
- if (IS_MURAM_ERR(uccs->us_pram_offset)) {
+ if (IS_ERR_VALUE(uccs->us_pram_offset)) {
printk(KERN_ERR "%s: cannot allocate MURAM for PRAM", __FUNCTION__);
ucc_slow_free(uccs);
return -ENOMEM;
@@ -210,7 +211,7 @@
uccs->rx_base_offset =
qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd),
QE_ALIGNMENT_OF_BD);
- if (IS_MURAM_ERR(uccs->rx_base_offset)) {
+ if (IS_ERR_VALUE(uccs->rx_base_offset)) {
printk(KERN_ERR "%s: cannot allocate RX BDs", __FUNCTION__);
uccs->rx_base_offset = 0;
ucc_slow_free(uccs);
@@ -220,7 +221,7 @@
uccs->tx_base_offset =
qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd),
QE_ALIGNMENT_OF_BD);
- if (IS_MURAM_ERR(uccs->tx_base_offset)) {
+ if (IS_ERR_VALUE(uccs->tx_base_offset)) {
printk(KERN_ERR "%s: cannot allocate TX BDs", __FUNCTION__);
uccs->tx_base_offset = 0;
ucc_slow_free(uccs);
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
index 7a8722b..e2c6210 100644
--- a/arch/ppc/8xx_io/commproc.c
+++ b/arch/ppc/8xx_io/commproc.c
@@ -402,7 +402,7 @@
* with the processor and the microcode patches applied / activated.
* But the following should be at least safe.
*/
- rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
+ rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
}
/*
@@ -410,9 +410,9 @@
* This function returns an offset into the DPRAM area.
* Use cpm_dpram_addr() to get the virtual address of the area.
*/
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -420,34 +420,34 @@
start = rh_alloc(&cpm_dpmem_info, size, "commproc");
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
- return (uint)start;
+ return start;
}
EXPORT_SYMBOL(cpm_dpalloc);
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
- ret = rh_free(&cpm_dpmem_info, (void *)offset);
+ ret = rh_free(&cpm_dpmem_info, offset);
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
return ret;
}
EXPORT_SYMBOL(cpm_dpfree);
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
cpm_dpmem_info.alignment = align;
- start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+ start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
- return (uint)start;
+ return start;
}
EXPORT_SYMBOL(cpm_dpalloc_fixed);
@@ -457,7 +457,7 @@
}
EXPORT_SYMBOL(cpm_dpdump);
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
{
return ((immap_t *)IMAP_ADDR)->im_cpm.cp_dpmem + offset;
}
diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
index 422bef9..095e661 100644
--- a/arch/ppc/lib/Makefile
+++ b/arch/ppc/lib/Makefile
@@ -3,6 +3,3 @@
#
obj-y := checksum.o string.o div64.o
-
-obj-$(CONFIG_8xx) += rheap.o
-obj-$(CONFIG_CPM2) += rheap.o
diff --git a/arch/ppc/lib/rheap.c b/arch/ppc/lib/rheap.c
deleted file mode 100644
index d407007..0000000
--- a/arch/ppc/lib/rheap.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- * A Remote Heap. Remote means that we don't touch the memory that the
- * heap points to. Normal heap implementations use the memory they manage
- * to place their list. We cannot do that because the memory we manage may
- * have special properties, for example it is uncachable or of different
- * endianess.
- *
- * Author: Pantelis Antoniou <panto@intracom.gr>
- *
- * 2004 (c) INTRACOM S.A. Greece. 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/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include <asm/rheap.h>
-
-/*
- * Fixup a list_head, needed when copying lists. If the pointers fall
- * between s and e, apply the delta. This assumes that
- * sizeof(struct list_head *) == sizeof(unsigned long *).
- */
-static inline void fixup(unsigned long s, unsigned long e, int d,
- struct list_head *l)
-{
- unsigned long *pp;
-
- pp = (unsigned long *)&l->next;
- if (*pp >= s && *pp < e)
- *pp += d;
-
- pp = (unsigned long *)&l->prev;
- if (*pp >= s && *pp < e)
- *pp += d;
-}
-
-/* Grow the allocated blocks */
-static int grow(rh_info_t * info, int max_blocks)
-{
- rh_block_t *block, *blk;
- int i, new_blocks;
- int delta;
- unsigned long blks, blke;
-
- if (max_blocks <= info->max_blocks)
- return -EINVAL;
-
- new_blocks = max_blocks - info->max_blocks;
-
- block = kmalloc(sizeof(rh_block_t) * max_blocks, GFP_KERNEL);
- if (block == NULL)
- return -ENOMEM;
-
- if (info->max_blocks > 0) {
-
- /* copy old block area */
- memcpy(block, info->block,
- sizeof(rh_block_t) * info->max_blocks);
-
- delta = (char *)block - (char *)info->block;
-
- /* and fixup list pointers */
- blks = (unsigned long)info->block;
- blke = (unsigned long)(info->block + info->max_blocks);
-
- for (i = 0, blk = block; i < info->max_blocks; i++, blk++)
- fixup(blks, blke, delta, &blk->list);
-
- fixup(blks, blke, delta, &info->empty_list);
- fixup(blks, blke, delta, &info->free_list);
- fixup(blks, blke, delta, &info->taken_list);
-
- /* free the old allocated memory */
- if ((info->flags & RHIF_STATIC_BLOCK) == 0)
- kfree(info->block);
- }
-
- info->block = block;
- info->empty_slots += new_blocks;
- info->max_blocks = max_blocks;
- info->flags &= ~RHIF_STATIC_BLOCK;
-
- /* add all new blocks to the free list */
- for (i = 0, blk = block + info->max_blocks; i < new_blocks; i++, blk++)
- list_add(&blk->list, &info->empty_list);
-
- return 0;
-}
-
-/*
- * Assure at least the required amount of empty slots. If this function
- * causes a grow in the block area then all pointers kept to the block
- * area are invalid!
- */
-static int assure_empty(rh_info_t * info, int slots)
-{
- int max_blocks;
-
- /* This function is not meant to be used to grow uncontrollably */
- if (slots >= 4)
- return -EINVAL;
-
- /* Enough space */
- if (info->empty_slots >= slots)
- return 0;
-
- /* Next 16 sized block */
- max_blocks = ((info->max_blocks + slots) + 15) & ~15;
-
- return grow(info, max_blocks);
-}
-
-static rh_block_t *get_slot(rh_info_t * info)
-{
- rh_block_t *blk;
-
- /* If no more free slots, and failure to extend. */
- /* XXX: You should have called assure_empty before */
- if (info->empty_slots == 0) {
- printk(KERN_ERR "rh: out of slots; crash is imminent.\n");
- return NULL;
- }
-
- /* Get empty slot to use */
- blk = list_entry(info->empty_list.next, rh_block_t, list);
- list_del_init(&blk->list);
- info->empty_slots--;
-
- /* Initialize */
- blk->start = NULL;
- blk->size = 0;
- blk->owner = NULL;
-
- return blk;
-}
-
-static inline void release_slot(rh_info_t * info, rh_block_t * blk)
-{
- list_add(&blk->list, &info->empty_list);
- info->empty_slots++;
-}
-
-static void attach_free_block(rh_info_t * info, rh_block_t * blkn)
-{
- rh_block_t *blk;
- rh_block_t *before;
- rh_block_t *after;
- rh_block_t *next;
- int size;
- unsigned long s, e, bs, be;
- struct list_head *l;
-
- /* We assume that they are aligned properly */
- size = blkn->size;
- s = (unsigned long)blkn->start;
- e = s + size;
-
- /* Find the blocks immediately before and after the given one
- * (if any) */
- before = NULL;
- after = NULL;
- next = NULL;
-
- list_for_each(l, &info->free_list) {
- blk = list_entry(l, rh_block_t, list);
-
- bs = (unsigned long)blk->start;
- be = bs + blk->size;
-
- if (next == NULL && s >= bs)
- next = blk;
-
- if (be == s)
- before = blk;
-
- if (e == bs)
- after = blk;
-
- /* If both are not null, break now */
- if (before != NULL && after != NULL)
- break;
- }
-
- /* Now check if they are really adjacent */
- if (before != NULL && s != (unsigned long)before->start + before->size)
- before = NULL;
-
- if (after != NULL && e != (unsigned long)after->start)
- after = NULL;
-
- /* No coalescing; list insert and return */
- if (before == NULL && after == NULL) {
-
- if (next != NULL)
- list_add(&blkn->list, &next->list);
- else
- list_add(&blkn->list, &info->free_list);
-
- return;
- }
-
- /* We don't need it anymore */
- release_slot(info, blkn);
-
- /* Grow the before block */
- if (before != NULL && after == NULL) {
- before->size += size;
- return;
- }
-
- /* Grow the after block backwards */
- if (before == NULL && after != NULL) {
- after->start = (int8_t *)after->start - size;
- after->size += size;
- return;
- }
-
- /* Grow the before block, and release the after block */
- before->size += size + after->size;
- list_del(&after->list);
- release_slot(info, after);
-}
-
-static void attach_taken_block(rh_info_t * info, rh_block_t * blkn)
-{
- rh_block_t *blk;
- struct list_head *l;
-
- /* Find the block immediately before the given one (if any) */
- list_for_each(l, &info->taken_list) {
- blk = list_entry(l, rh_block_t, list);
- if (blk->start > blkn->start) {
- list_add_tail(&blkn->list, &blk->list);
- return;
- }
- }
-
- list_add_tail(&blkn->list, &info->taken_list);
-}
-
-/*
- * Create a remote heap dynamically. Note that no memory for the blocks
- * are allocated. It will upon the first allocation
- */
-rh_info_t *rh_create(unsigned int alignment)
-{
- rh_info_t *info;
-
- /* Alignment must be a power of two */
- if ((alignment & (alignment - 1)) != 0)
- return ERR_PTR(-EINVAL);
-
- info = kmalloc(sizeof(*info), GFP_KERNEL);
- if (info == NULL)
- return ERR_PTR(-ENOMEM);
-
- info->alignment = alignment;
-
- /* Initially everything as empty */
- info->block = NULL;
- info->max_blocks = 0;
- info->empty_slots = 0;
- info->flags = 0;
-
- INIT_LIST_HEAD(&info->empty_list);
- INIT_LIST_HEAD(&info->free_list);
- INIT_LIST_HEAD(&info->taken_list);
-
- return info;
-}
-
-/*
- * Destroy a dynamically created remote heap. Deallocate only if the areas
- * are not static
- */
-void rh_destroy(rh_info_t * info)
-{
- if ((info->flags & RHIF_STATIC_BLOCK) == 0 && info->block != NULL)
- kfree(info->block);
-
- if ((info->flags & RHIF_STATIC_INFO) == 0)
- kfree(info);
-}
-
-/*
- * Initialize in place a remote heap info block. This is needed to support
- * operation very early in the startup of the kernel, when it is not yet safe
- * to call kmalloc.
- */
-void rh_init(rh_info_t * info, unsigned int alignment, int max_blocks,
- rh_block_t * block)
-{
- int i;
- rh_block_t *blk;
-
- /* Alignment must be a power of two */
- if ((alignment & (alignment - 1)) != 0)
- return;
-
- info->alignment = alignment;
-
- /* Initially everything as empty */
- info->block = block;
- info->max_blocks = max_blocks;
- info->empty_slots = max_blocks;
- info->flags = RHIF_STATIC_INFO | RHIF_STATIC_BLOCK;
-
- INIT_LIST_HEAD(&info->empty_list);
- INIT_LIST_HEAD(&info->free_list);
- INIT_LIST_HEAD(&info->taken_list);
-
- /* Add all new blocks to the free list */
- for (i = 0, blk = block; i < max_blocks; i++, blk++)
- list_add(&blk->list, &info->empty_list);
-}
-
-/* Attach a free memory region, coalesces regions if adjuscent */
-int rh_attach_region(rh_info_t * info, void *start, int size)
-{
- rh_block_t *blk;
- unsigned long s, e, m;
- int r;
-
- /* The region must be aligned */
- s = (unsigned long)start;
- e = s + size;
- m = info->alignment - 1;
-
- /* Round start up */
- s = (s + m) & ~m;
-
- /* Round end down */
- e = e & ~m;
-
- /* Take final values */
- start = (void *)s;
- size = (int)(e - s);
-
- /* Grow the blocks, if needed */
- r = assure_empty(info, 1);
- if (r < 0)
- return r;
-
- blk = get_slot(info);
- blk->start = start;
- blk->size = size;
- blk->owner = NULL;
-
- attach_free_block(info, blk);
-
- return 0;
-}
-
-/* Detatch given address range, splits free block if needed. */
-void *rh_detach_region(rh_info_t * info, void *start, int size)
-{
- struct list_head *l;
- rh_block_t *blk, *newblk;
- unsigned long s, e, m, bs, be;
-
- /* Validate size */
- if (size <= 0)
- return ERR_PTR(-EINVAL);
-
- /* The region must be aligned */
- s = (unsigned long)start;
- e = s + size;
- m = info->alignment - 1;
-
- /* Round start up */
- s = (s + m) & ~m;
-
- /* Round end down */
- e = e & ~m;
-
- if (assure_empty(info, 1) < 0)
- return ERR_PTR(-ENOMEM);
-
- blk = NULL;
- list_for_each(l, &info->free_list) {
- blk = list_entry(l, rh_block_t, list);
- /* The range must lie entirely inside one free block */
- bs = (unsigned long)blk->start;
- be = (unsigned long)blk->start + blk->size;
- if (s >= bs && e <= be)
- break;
- blk = NULL;
- }
-
- if (blk == NULL)
- return ERR_PTR(-ENOMEM);
-
- /* Perfect fit */
- if (bs == s && be == e) {
- /* Delete from free list, release slot */
- list_del(&blk->list);
- release_slot(info, blk);
- return (void *)s;
- }
-
- /* blk still in free list, with updated start and/or size */
- if (bs == s || be == e) {
- if (bs == s)
- blk->start = (int8_t *)blk->start + size;
- blk->size -= size;
-
- } else {
- /* The front free fragment */
- blk->size = s - bs;
-
- /* the back free fragment */
- newblk = get_slot(info);
- newblk->start = (void *)e;
- newblk->size = be - e;
-
- list_add(&newblk->list, &blk->list);
- }
-
- return (void *)s;
-}
-
-void *rh_alloc(rh_info_t * info, int size, const char *owner)
-{
- struct list_head *l;
- rh_block_t *blk;
- rh_block_t *newblk;
- void *start;
-
- /* Validate size */
- if (size <= 0)
- return ERR_PTR(-EINVAL);
-
- /* Align to configured alignment */
- size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
-
- if (assure_empty(info, 1) < 0)
- return ERR_PTR(-ENOMEM);
-
- blk = NULL;
- list_for_each(l, &info->free_list) {
- blk = list_entry(l, rh_block_t, list);
- if (size <= blk->size)
- break;
- blk = NULL;
- }
-
- if (blk == NULL)
- return ERR_PTR(-ENOMEM);
-
- /* Just fits */
- if (blk->size == size) {
- /* Move from free list to taken list */
- list_del(&blk->list);
- blk->owner = owner;
- start = blk->start;
-
- attach_taken_block(info, blk);
-
- return start;
- }
-
- newblk = get_slot(info);
- newblk->start = blk->start;
- newblk->size = size;
- newblk->owner = owner;
-
- /* blk still in free list, with updated start, size */
- blk->start = (int8_t *)blk->start + size;
- blk->size -= size;
-
- start = newblk->start;
-
- attach_taken_block(info, newblk);
-
- return start;
-}
-
-/* allocate at precisely the given address */
-void *rh_alloc_fixed(rh_info_t * info, void *start, int size, const char *owner)
-{
- struct list_head *l;
- rh_block_t *blk, *newblk1, *newblk2;
- unsigned long s, e, m, bs, be;
-
- /* Validate size */
- if (size <= 0)
- return ERR_PTR(-EINVAL);
-
- /* The region must be aligned */
- s = (unsigned long)start;
- e = s + size;
- m = info->alignment - 1;
-
- /* Round start up */
- s = (s + m) & ~m;
-
- /* Round end down */
- e = e & ~m;
-
- if (assure_empty(info, 2) < 0)
- return ERR_PTR(-ENOMEM);
-
- blk = NULL;
- list_for_each(l, &info->free_list) {
- blk = list_entry(l, rh_block_t, list);
- /* The range must lie entirely inside one free block */
- bs = (unsigned long)blk->start;
- be = (unsigned long)blk->start + blk->size;
- if (s >= bs && e <= be)
- break;
- }
-
- if (blk == NULL)
- return ERR_PTR(-ENOMEM);
-
- /* Perfect fit */
- if (bs == s && be == e) {
- /* Move from free list to taken list */
- list_del(&blk->list);
- blk->owner = owner;
-
- start = blk->start;
- attach_taken_block(info, blk);
-
- return start;
-
- }
-
- /* blk still in free list, with updated start and/or size */
- if (bs == s || be == e) {
- if (bs == s)
- blk->start = (int8_t *)blk->start + size;
- blk->size -= size;
-
- } else {
- /* The front free fragment */
- blk->size = s - bs;
-
- /* The back free fragment */
- newblk2 = get_slot(info);
- newblk2->start = (void *)e;
- newblk2->size = be - e;
-
- list_add(&newblk2->list, &blk->list);
- }
-
- newblk1 = get_slot(info);
- newblk1->start = (void *)s;
- newblk1->size = e - s;
- newblk1->owner = owner;
-
- start = newblk1->start;
- attach_taken_block(info, newblk1);
-
- return start;
-}
-
-int rh_free(rh_info_t * info, void *start)
-{
- rh_block_t *blk, *blk2;
- struct list_head *l;
- int size;
-
- /* Linear search for block */
- blk = NULL;
- list_for_each(l, &info->taken_list) {
- blk2 = list_entry(l, rh_block_t, list);
- if (start < blk2->start)
- break;
- blk = blk2;
- }
-
- if (blk == NULL || start > (blk->start + blk->size))
- return -EINVAL;
-
- /* Remove from taken list */
- list_del(&blk->list);
-
- /* Get size of freed block */
- size = blk->size;
- attach_free_block(info, blk);
-
- return size;
-}
-
-int rh_get_stats(rh_info_t * info, int what, int max_stats, rh_stats_t * stats)
-{
- rh_block_t *blk;
- struct list_head *l;
- struct list_head *h;
- int nr;
-
- switch (what) {
-
- case RHGS_FREE:
- h = &info->free_list;
- break;
-
- case RHGS_TAKEN:
- h = &info->taken_list;
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Linear search for block */
- nr = 0;
- list_for_each(l, h) {
- blk = list_entry(l, rh_block_t, list);
- if (stats != NULL && nr < max_stats) {
- stats->start = blk->start;
- stats->size = blk->size;
- stats->owner = blk->owner;
- stats++;
- }
- nr++;
- }
-
- return nr;
-}
-
-int rh_set_owner(rh_info_t * info, void *start, const char *owner)
-{
- rh_block_t *blk, *blk2;
- struct list_head *l;
- int size;
-
- /* Linear search for block */
- blk = NULL;
- list_for_each(l, &info->taken_list) {
- blk2 = list_entry(l, rh_block_t, list);
- if (start < blk2->start)
- break;
- blk = blk2;
- }
-
- if (blk == NULL || start > (blk->start + blk->size))
- return -EINVAL;
-
- blk->owner = owner;
- size = blk->size;
-
- return size;
-}
-
-void rh_dump(rh_info_t * info)
-{
- static rh_stats_t st[32]; /* XXX maximum 32 blocks */
- int maxnr;
- int i, nr;
-
- maxnr = ARRAY_SIZE(st);
-
- printk(KERN_INFO
- "info @0x%p (%d slots empty / %d max)\n",
- info, info->empty_slots, info->max_blocks);
-
- printk(KERN_INFO " Free:\n");
- nr = rh_get_stats(info, RHGS_FREE, maxnr, st);
- if (nr > maxnr)
- nr = maxnr;
- for (i = 0; i < nr; i++)
- printk(KERN_INFO
- " 0x%p-0x%p (%u)\n",
- st[i].start, (int8_t *) st[i].start + st[i].size,
- st[i].size);
- printk(KERN_INFO "\n");
-
- printk(KERN_INFO " Taken:\n");
- nr = rh_get_stats(info, RHGS_TAKEN, maxnr, st);
- if (nr > maxnr)
- nr = maxnr;
- for (i = 0; i < nr; i++)
- printk(KERN_INFO
- " 0x%p-0x%p (%u) %s\n",
- st[i].start, (int8_t *) st[i].start + st[i].size,
- st[i].size, st[i].owner != NULL ? st[i].owner : "");
- printk(KERN_INFO "\n");
-}
-
-void rh_dump_blk(rh_info_t * info, rh_block_t * blk)
-{
- printk(KERN_INFO
- "blk @0x%p: 0x%p-0x%p (%u)\n",
- blk, blk->start, (int8_t *) blk->start + blk->size, blk->size);
-}
diff --git a/arch/ppc/syslib/cpm2_common.c b/arch/ppc/syslib/cpm2_common.c
index cbac44b..6cd859d 100644
--- a/arch/ppc/syslib/cpm2_common.c
+++ b/arch/ppc/syslib/cpm2_common.c
@@ -136,15 +136,14 @@
* varies with the processor and the microcode patches activated.
* But the following should be at least safe.
*/
- rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
- CPM_DATAONLY_SIZE);
+ rh_attach_region(&cpm_dpmem_info, CPM_DATAONLY_BASE, CPM_DATAONLY_SIZE);
}
/* This function returns an index into the DPRAM area.
*/
-uint cpm_dpalloc(uint size, uint align)
+unsigned long cpm_dpalloc(uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
@@ -152,17 +151,17 @@
start = rh_alloc(&cpm_dpmem_info, size, "commproc");
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
- return (uint)start;
+ return start;
}
EXPORT_SYMBOL(cpm_dpalloc);
-int cpm_dpfree(uint offset)
+int cpm_dpfree(unsigned long offset)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
- ret = rh_free(&cpm_dpmem_info, (void *)offset);
+ ret = rh_free(&cpm_dpmem_info, offset);
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
return ret;
@@ -170,17 +169,17 @@
EXPORT_SYMBOL(cpm_dpfree);
/* not sure if this is ever needed */
-uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align)
{
- void *start;
+ unsigned long start;
unsigned long flags;
spin_lock_irqsave(&cpm_dpmem_lock, flags);
cpm_dpmem_info.alignment = align;
- start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
+ start = rh_alloc_fixed(&cpm_dpmem_info, offset, size, "commproc");
spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
- return (uint)start;
+ return start;
}
EXPORT_SYMBOL(cpm_dpalloc_fixed);
@@ -190,7 +189,7 @@
}
EXPORT_SYMBOL(cpm_dpdump);
-void *cpm_dpram_addr(uint offset)
+void *cpm_dpram_addr(unsigned long offset)
{
return (void *)&cpm2_immr->im_dprambase[offset];
}
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 1a84719..098c62c 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -4,27 +4,23 @@
#
config MMU
- bool
- default y
+ def_bool y
config ZONE_DMA
def_bool y
depends on 64BIT
config LOCKDEP_SUPPORT
- bool
- default y
+ def_bool y
config STACKTRACE_SUPPORT
- bool
- default y
+ def_bool y
config RWSEM_GENERIC_SPINLOCK
bool
config RWSEM_XCHGADD_ALGORITHM
- bool
- default y
+ def_bool y
config ARCH_HAS_ILOG2_U32
bool
@@ -35,8 +31,7 @@
default n
config GENERIC_HWEIGHT
- bool
- default y
+ def_bool y
config GENERIC_TIME
def_bool y
@@ -55,8 +50,7 @@
mainmenu "Linux Kernel Configuration"
config S390
- bool
- default y
+ def_bool y
source "init/Kconfig"
@@ -280,6 +274,10 @@
config ARCH_POPULATES_NODE_MAP
def_bool y
+comment "Kernel preemption"
+
+source "kernel/Kconfig.preempt"
+
source "mm/Kconfig"
config HOLES_IN_ZONE
@@ -320,17 +318,6 @@
comment "Misc"
-config PREEMPT
- bool "Preemptible Kernel"
- help
- This option reduces the latency of the kernel when reacting to
- real-time or interactive events by allowing a low priority process to
- be preempted even if it is in kernel mode executing a system call.
- This allows applications to run more reliably even when the system is
- under load.
-
- Say N if you are unsure.
-
config IPL
bool "Builtin IPL record support"
help
@@ -488,6 +475,8 @@
This can also be compiled as a module, which will be called
appldata_net_sum.o.
+source kernel/Kconfig.hz
+
config NO_IDLE_HZ
bool "No HZ timer ticks in idle"
help
@@ -535,18 +524,12 @@
source "net/Kconfig"
config PCMCIA
- bool
- default n
+ def_bool n
-source "drivers/base/Kconfig"
+config CCW
+ def_bool y
-source "drivers/connector/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
-source "drivers/s390/Kconfig"
-
-source "drivers/net/Kconfig"
+source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 0e4da8a..485b60c 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21-rc1
-# Wed Feb 21 10:44:30 2007
+# Linux kernel version: 2.6.21
+# Thu May 10 15:18:19 2007
#
CONFIG_MMU=y
CONFIG_ZONE_DMA=y
@@ -14,6 +14,7 @@
CONFIG_GENERIC_TIME=y
CONFIG_GENERIC_BUG=y
CONFIG_NO_IOMEM=y
+CONFIG_NO_DMA=y
CONFIG_S390=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -41,9 +42,11 @@
# CONFIG_AUDITSYSCALL is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=17
# CONFIG_CPUSETS is not set
CONFIG_SYSFS_DEPRECATED=y
# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SYSCTL=y
@@ -60,12 +63,14 @@
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
-CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
#
# Loadable module support
@@ -128,6 +133,14 @@
CONFIG_STACK_GUARD=256
# CONFIG_WARN_STACK is not set
CONFIG_ARCH_POPULATES_NODE_MAP=y
+
+#
+# Kernel preemption
+#
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -150,7 +163,6 @@
#
# Misc
#
-CONFIG_PREEMPT=y
CONFIG_IPL=y
# CONFIG_IPL_TAPE is not set
CONFIG_IPL_VM=y
@@ -163,6 +175,11 @@
CONFIG_VIRT_TIMER=y
CONFIG_VIRT_CPU_ACCOUNTING=y
# CONFIG_APPLDATA_BASE is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
CONFIG_NO_IDLE_HZ=y
CONFIG_NO_IDLE_HZ_INIT=y
CONFIG_S390_HYPFS_FS=y
@@ -177,7 +194,6 @@
#
# Networking options
#
-# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
@@ -216,6 +232,7 @@
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
@@ -240,7 +257,12 @@
#
# SCTP Configuration (EXPERIMENTAL)
#
-# CONFIG_IP_SCTP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
#
# TIPC Configuration (EXPERIMENTAL)
@@ -263,9 +285,6 @@
#
CONFIG_NET_SCHED=y
CONFIG_NET_SCH_FIFO=y
-CONFIG_NET_SCH_CLK_JIFFIES=y
-# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
-# CONFIG_NET_SCH_CLK_CPU is not set
#
# Queueing/Scheduling
@@ -308,11 +327,14 @@
#
# CONFIG_NET_PKTGEN is not set
# CONFIG_NET_TCPPROBE is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_RFKILL is not set
# CONFIG_PCMCIA is not set
+CONFIG_CCW=y
+
+#
+# Device Drivers
+#
#
# Generic Driver Options
@@ -330,6 +352,37 @@
# CONFIG_CONNECTOR is not set
#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# S/390 block device drivers
+#
+CONFIG_BLK_DEV_XPRAM=m
+# CONFIG_DCSSBLK is not set
+CONFIG_DASD=y
+CONFIG_DASD_PROFILE=y
+CONFIG_DASD_ECKD=y
+CONFIG_DASD_FBA=y
+CONFIG_DASD_DIAG=y
+CONFIG_DASD_EER=y
+
+#
+# Misc devices
+#
+# CONFIG_BLINK is not set
+
+#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
@@ -356,6 +409,7 @@
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=m
#
# SCSI Transports
@@ -372,34 +426,6 @@
# CONFIG_ISCSI_TCP is not set
# CONFIG_SCSI_DEBUG is not set
CONFIG_ZFCP=y
-CONFIG_CCW=y
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-CONFIG_BLK_DEV_INITRD=y
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# S/390 block device drivers
-#
-CONFIG_BLK_DEV_XPRAM=m
-# CONFIG_DCSSBLK is not set
-CONFIG_DASD=y
-CONFIG_DASD_PROFILE=y
-CONFIG_DASD_ECKD=y
-CONFIG_DASD_FBA=y
-CONFIG_DASD_DIAG=y
-CONFIG_DASD_EER=y
-# CONFIG_ATA_OVER_ETH is not set
#
# Multi-device support (RAID and LVM)
@@ -421,56 +447,7 @@
CONFIG_DM_ZERO=y
CONFIG_DM_MULTIPATH=y
# CONFIG_DM_MULTIPATH_EMC is not set
-
-#
-# Character device drivers
-#
-CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=2048
-# CONFIG_HANGCHECK_TIMER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-
-#
-# S/390 character device drivers
-#
-CONFIG_TN3270=y
-CONFIG_TN3270_TTY=y
-CONFIG_TN3270_FS=m
-CONFIG_TN3270_CONSOLE=y
-CONFIG_TN3215=y
-CONFIG_TN3215_CONSOLE=y
-CONFIG_CCW_CONSOLE=y
-CONFIG_SCLP_TTY=y
-CONFIG_SCLP_CONSOLE=y
-CONFIG_SCLP_VT220_TTY=y
-CONFIG_SCLP_VT220_CONSOLE=y
-CONFIG_SCLP_CPI=m
-CONFIG_S390_TAPE=m
-
-#
-# S/390 tape interface support
-#
-CONFIG_S390_TAPE_BLOCK=y
-
-#
-# S/390 tape hardware support
-#
-CONFIG_S390_TAPE_34XX=m
-# CONFIG_S390_TAPE_3590 is not set
-# CONFIG_VMLOGRDR is not set
-# CONFIG_VMCP is not set
-# CONFIG_MONREADER is not set
-CONFIG_MONWRITER=m
-
-#
-# Cryptographic devices
-#
-CONFIG_ZCRYPT=m
-# CONFIG_ZCRYPT_MONOLITHIC is not set
+# CONFIG_DM_DELAY is not set
#
# Network device support
@@ -482,10 +459,6 @@
CONFIG_TUN=m
#
-# PHY device support
-#
-
-#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -498,6 +471,7 @@
#
# Ethernet (10000 Mbit)
#
+CONFIG_MLX4_DEBUG=y
#
# Token Ring devices
@@ -505,11 +479,6 @@
# CONFIG_TR is not set
#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
# Wan interfaces
#
# CONFIG_WAN is not set
@@ -537,6 +506,56 @@
# CONFIG_NET_POLL_CONTROLLER is not set
#
+# Character devices
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=m
+# CONFIG_R3964 is not set
+CONFIG_RAW_DRIVER=m
+CONFIG_MAX_RAW_DEVS=256
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# S/390 character device drivers
+#
+CONFIG_TN3270=y
+CONFIG_TN3270_TTY=y
+CONFIG_TN3270_FS=m
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
+CONFIG_CCW_CONSOLE=y
+CONFIG_SCLP=y
+CONFIG_SCLP_TTY=y
+CONFIG_SCLP_CONSOLE=y
+CONFIG_SCLP_VT220_TTY=y
+CONFIG_SCLP_VT220_CONSOLE=y
+CONFIG_SCLP_CPI=m
+CONFIG_S390_TAPE=m
+
+#
+# S/390 tape interface support
+#
+CONFIG_S390_TAPE_BLOCK=y
+
+#
+# S/390 tape hardware support
+#
+CONFIG_S390_TAPE_34XX=m
+# CONFIG_S390_TAPE_3590 is not set
+# CONFIG_VMLOGRDR is not set
+# CONFIG_VMCP is not set
+# CONFIG_MONREADER is not set
+CONFIG_MONWRITER=m
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -628,6 +647,7 @@
CONFIG_EXPORTFS=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
@@ -658,6 +678,7 @@
# CONFIG_SUN_PARTITION is not set
# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
#
# Native Language Support
@@ -668,8 +689,6 @@
# Distributed Lock Manager
#
CONFIG_DLM=m
-CONFIG_DLM_TCP=y
-# CONFIG_DLM_SCTP is not set
# CONFIG_DLM_DEBUG is not set
#
@@ -693,7 +712,6 @@
CONFIG_DEBUG_FS=y
CONFIG_HEADERS_CHECK=y
CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=17
# CONFIG_SCHEDSTATS is not set
# CONFIG_TIMER_STATS is not set
# CONFIG_DEBUG_SLAB is not set
@@ -729,12 +747,13 @@
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=m
CONFIG_CRYPTO_MANAGER=y
-# CONFIG_CRYPTO_HMAC is not set
+CONFIG_CRYPTO_HMAC=m
# CONFIG_CRYPTO_XCBC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
+CONFIG_CRYPTO_MD5=m
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
@@ -745,6 +764,7 @@
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
# CONFIG_CRYPTO_DES is not set
CONFIG_CRYPTO_FCRYPT=m
# CONFIG_CRYPTO_BLOWFISH is not set
@@ -771,6 +791,8 @@
# CONFIG_CRYPTO_DES_S390 is not set
# CONFIG_CRYPTO_AES_S390 is not set
CONFIG_S390_PRNG=m
+CONFIG_ZCRYPT=m
+# CONFIG_ZCRYPT_MONOLITHIC is not set
#
# Library routines
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index ba5d316..8e1ea1c 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -477,7 +477,7 @@
goto fail_diag;
}
}
- kset_set_kset_s(&s390_subsys, hypervisor_subsys);
+ kobj_set_kset_s(&s390_subsys, hypervisor_subsys);
rc = subsystem_register(&s390_subsys);
if (rc)
goto fail_sysfs;
diff --git a/arch/s390/kernel/audit.c b/arch/s390/kernel/audit.c
index 0741d91..d1c76fe 100644
--- a/arch/s390/kernel/audit.c
+++ b/arch/s390/kernel/audit.c
@@ -23,6 +23,20 @@
~0U
};
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_COMPAT
+ if (arch == AUDIT_ARCH_S390)
+ return 1;
+#endif
+ return 0;
+}
+
int audit_classify_syscall(int abi, unsigned syscall)
{
#ifdef CONFIG_COMPAT
@@ -51,15 +65,18 @@
extern __u32 s390_write_class[];
extern __u32 s390_read_class[];
extern __u32 s390_chattr_class[];
+ extern __u32 s390_signal_class[];
audit_register_class(AUDIT_CLASS_WRITE_32, s390_write_class);
audit_register_class(AUDIT_CLASS_READ_32, s390_read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE_32, s390_dir_class);
audit_register_class(AUDIT_CLASS_CHATTR_32, s390_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, s390_signal_class);
#endif
audit_register_class(AUDIT_CLASS_WRITE, write_class);
audit_register_class(AUDIT_CLASS_READ, read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
return 0;
}
diff --git a/arch/s390/kernel/compat_audit.c b/arch/s390/kernel/compat_audit.c
index 16d9436..0569f51 100644
--- a/arch/s390/kernel/compat_audit.c
+++ b/arch/s390/kernel/compat_audit.c
@@ -21,6 +21,11 @@
~0U
};
+unsigned s390_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
int s390_classify_syscall(unsigned syscall)
{
switch(syscall) {
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 0ea048d..367caf9 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -816,23 +816,23 @@
{
int rc;
- rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+ rc = sysfs_create_group(&ipl_subsys.kobj,
&ipl_fcp_attr_group);
if (rc)
goto out;
- rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+ rc = sysfs_create_bin_file(&ipl_subsys.kobj,
&ipl_parameter_attr);
if (rc)
goto out_ipl_parm;
- rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj,
+ rc = sysfs_create_bin_file(&ipl_subsys.kobj,
&ipl_scp_data_attr);
if (!rc)
goto out;
- sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr);
+ sysfs_remove_bin_file(&ipl_subsys.kobj, &ipl_parameter_attr);
out_ipl_parm:
- sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group);
+ sysfs_remove_group(&ipl_subsys.kobj, &ipl_fcp_attr_group);
out:
return rc;
}
@@ -846,7 +846,7 @@
return rc;
switch (ipl_info.type) {
case IPL_TYPE_CCW:
- rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+ rc = sysfs_create_group(&ipl_subsys.kobj,
&ipl_ccw_attr_group);
break;
case IPL_TYPE_FCP:
@@ -854,11 +854,11 @@
rc = ipl_register_fcp_files();
break;
case IPL_TYPE_NSS:
- rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+ rc = sysfs_create_group(&ipl_subsys.kobj,
&ipl_nss_attr_group);
break;
default:
- rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+ rc = sysfs_create_group(&ipl_subsys.kobj,
&ipl_unknown_attr_group);
break;
}
@@ -885,7 +885,7 @@
if (!MACHINE_IS_VM)
return 0;
- rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
+ rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_nss_attr_group);
if (rc)
return rc;
strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
@@ -900,7 +900,7 @@
reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
if (!reipl_block_ccw)
return -ENOMEM;
- rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group);
+ rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_ccw_attr_group);
if (rc) {
free_page((unsigned long)reipl_block_ccw);
return rc;
@@ -938,7 +938,7 @@
reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
if (!reipl_block_fcp)
return -ENOMEM;
- rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group);
+ rc = sysfs_create_group(&reipl_subsys.kobj, &reipl_fcp_attr_group);
if (rc) {
free_page((unsigned long)reipl_block_fcp);
return rc;
@@ -990,7 +990,7 @@
dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL);
if (!dump_block_ccw)
return -ENOMEM;
- rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group);
+ rc = sysfs_create_group(&dump_subsys.kobj, &dump_ccw_attr_group);
if (rc) {
free_page((unsigned long)dump_block_ccw);
return rc;
@@ -1014,7 +1014,7 @@
dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL);
if (!dump_block_fcp)
return -ENOMEM;
- rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group);
+ rc = sysfs_create_group(&dump_subsys.kobj, &dump_fcp_attr_group);
if (rc) {
free_page((unsigned long)dump_block_fcp);
return rc;
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 8b924b3..d855cdb 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -253,7 +253,10 @@
unsigned long address, unsigned long error_code)
{
u16 instruction;
- int rc, compat;
+ int rc;
+#ifdef CONFIG_COMPAT
+ int compat;
+#endif
pagefault_disable();
rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
diff --git a/arch/sparc64/kernel/audit.c b/arch/sparc64/kernel/audit.c
index aef19cc..24d7f4b 100644
--- a/arch/sparc64/kernel/audit.c
+++ b/arch/sparc64/kernel/audit.c
@@ -23,6 +23,20 @@
~0U
};
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_SPARC32_COMPAT
+ if (arch == AUDIT_ARCH_SPARC)
+ return 1;
+#endif
+ return 0;
+}
+
int audit_classify_syscall(int abi, unsigned syscall)
{
#ifdef CONFIG_SPARC32_COMPAT
@@ -51,15 +65,18 @@
extern __u32 sparc32_write_class[];
extern __u32 sparc32_read_class[];
extern __u32 sparc32_chattr_class[];
+ extern __u32 sparc32_signal_class[];
audit_register_class(AUDIT_CLASS_WRITE_32, sparc32_write_class);
audit_register_class(AUDIT_CLASS_READ_32, sparc32_read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE_32, sparc32_dir_class);
audit_register_class(AUDIT_CLASS_CHATTR_32, sparc32_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, sparc32_signal_class);
#endif
audit_register_class(AUDIT_CLASS_WRITE, write_class);
audit_register_class(AUDIT_CLASS_READ, read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
return 0;
}
diff --git a/arch/sparc64/kernel/compat_audit.c b/arch/sparc64/kernel/compat_audit.c
index cca96c9..c197948 100644
--- a/arch/sparc64/kernel/compat_audit.c
+++ b/arch/sparc64/kernel/compat_audit.c
@@ -20,6 +20,11 @@
~0U
};
+unsigned sparc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
int sparc32_classify_syscall(unsigned syscall)
{
switch(syscall) {
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index d85e1ed..cf9a751 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -377,7 +377,7 @@
const char *type;
u32 class;
- dev = kzalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ dev = alloc_pci_dev();
if (!dev)
return NULL;
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 76faaa8..f974fef 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -14,6 +14,200 @@
#include <asm/oplib.h>
#include "pci_impl.h"
+#include "pci_sun4v.h"
+
+static int config_out_of_range(struct pci_pbm_info *pbm,
+ unsigned long bus,
+ unsigned long devfn,
+ unsigned long reg)
+{
+ if (bus < pbm->pci_first_busno ||
+ bus > pbm->pci_last_busno)
+ return 1;
+ return 0;
+}
+
+static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm,
+ unsigned long bus,
+ unsigned long devfn,
+ unsigned long reg)
+{
+ unsigned long rbits = pbm->config_space_reg_bits;
+
+ if (config_out_of_range(pbm, bus, devfn, reg))
+ return NULL;
+
+ reg = (reg & ((1 << rbits) - 1));
+ devfn <<= rbits;
+ bus <<= rbits + 8;
+
+ return (void *) (pbm->config_space | bus | devfn | reg);
+}
+
+static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ struct pci_pbm_info *pbm = bus_dev->sysdata;
+ unsigned char bus = bus_dev->number;
+ u32 *addr;
+ u16 tmp16;
+ u8 tmp8;
+
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+ size, value);
+
+ switch (size) {
+ case 1:
+ *value = 0xff;
+ break;
+ case 2:
+ *value = 0xffff;
+ break;
+ case 4:
+ *value = 0xffffffff;
+ break;
+ }
+
+ addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ switch (size) {
+ case 1:
+ pci_config_read8((u8 *)addr, &tmp8);
+ *value = (u32) tmp8;
+ break;
+
+ case 2:
+ if (where & 0x01) {
+ printk("pci_read_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_read16((u16 *)addr, &tmp16);
+ *value = (u32) tmp16;
+ break;
+
+ case 4:
+ if (where & 0x03) {
+ printk("pci_read_config_dword: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_read32(addr, value);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct pci_pbm_info *pbm = bus_dev->sysdata;
+ unsigned char bus = bus_dev->number;
+ u32 *addr;
+
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+ size, value);
+ addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ switch (size) {
+ case 1:
+ pci_config_write8((u8 *)addr, value);
+ break;
+
+ case 2:
+ if (where & 0x01) {
+ printk("pci_write_config_word: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_write16((u16 *)addr, value);
+ break;
+
+ case 4:
+ if (where & 0x03) {
+ printk("pci_write_config_dword: misaligned reg [%x]\n",
+ where);
+ return PCIBIOS_SUCCESSFUL;
+ }
+ pci_config_write32(addr, value);
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sun4u_pci_ops = {
+ .read = sun4u_read_pci_cfg,
+ .write = sun4u_write_pci_cfg,
+};
+
+static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ struct pci_pbm_info *pbm = bus_dev->sysdata;
+ u32 devhandle = pbm->devhandle;
+ unsigned int bus = bus_dev->number;
+ unsigned int device = PCI_SLOT(devfn);
+ unsigned int func = PCI_FUNC(devfn);
+ unsigned long ret;
+
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
+ size, value);
+ if (config_out_of_range(pbm, bus, devfn, where)) {
+ ret = ~0UL;
+ } else {
+ ret = pci_sun4v_config_get(devhandle,
+ HV_PCI_DEVICE_BUILD(bus, device, func),
+ where, size);
+ }
+ switch (size) {
+ case 1:
+ *value = ret & 0xff;
+ break;
+ case 2:
+ *value = ret & 0xffff;
+ break;
+ case 4:
+ *value = ret & 0xffffffff;
+ break;
+ };
+
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ struct pci_pbm_info *pbm = bus_dev->sysdata;
+ u32 devhandle = pbm->devhandle;
+ unsigned int bus = bus_dev->number;
+ unsigned int device = PCI_SLOT(devfn);
+ unsigned int func = PCI_FUNC(devfn);
+ unsigned long ret;
+
+ if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
+ size, value);
+ if (config_out_of_range(pbm, bus, devfn, where)) {
+ /* Do nothing. */
+ } else {
+ ret = pci_sun4v_config_put(devhandle,
+ HV_PCI_DEVICE_BUILD(bus, device, func),
+ where, size, value);
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sun4v_pci_ops = {
+ .read = sun4v_read_pci_cfg,
+ .write = sun4v_write_pci_cfg,
+};
void pci_get_pbm_props(struct pci_pbm_info *pbm)
{
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index 2e0eb4e..9198c1a 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -27,138 +27,6 @@
"i" (ASI_PHYS_BYPASS_EC_E) \
: "memory")
-/* Fire config space address format is nearly identical to
- * that of SCHIZO and PSYCHO, except that in order to accomodate
- * PCI-E extended config space the encoding can handle 12 bits
- * of register address:
- *
- * 32 28 27 20 19 15 14 12 11 2 1 0
- * -------------------------------------------------
- * |0 0 0 0 0| bus | device | function | reg | 0 0 |
- * -------------------------------------------------
- */
-#define FIRE_CONFIG_BASE(PBM) ((PBM)->config_space)
-#define FIRE_CONFIG_ENCODE(BUS, DEVFN, REG) \
- (((unsigned long)(BUS) << 20) | \
- ((unsigned long)(DEVFN) << 12) | \
- ((unsigned long)(REG)))
-
-static void *fire_pci_config_mkaddr(struct pci_pbm_info *pbm,
- unsigned char bus,
- unsigned int devfn,
- int where)
-{
- if (!pbm)
- return NULL;
- return (void *)
- (FIRE_CONFIG_BASE(pbm) |
- FIRE_CONFIG_ENCODE(bus, devfn, where));
-}
-
-/* FIRE PCI configuration space accessors. */
-
-static int fire_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 *value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
- u16 tmp16;
- u8 tmp8;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
- size, value);
- switch (size) {
- case 1:
- *value = 0xff;
- break;
- case 2:
- *value = 0xffff;
- break;
- case 4:
- *value = 0xffffffff;
- break;
- }
-
- addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- pci_config_read8((u8 *)addr, &tmp8);
- *value = tmp8;
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_read_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read16((u16 *)addr, &tmp16);
- *value = tmp16;
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_read_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_config_read32(addr, value);
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int fire_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
- size, value);
- addr = fire_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- pci_config_write8((u8 *)addr, value);
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_write_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_write16((u16 *)addr, value);
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_write_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_config_write32(addr, value);
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_fire_ops = {
- .read = fire_read_pci_cfg,
- .write = fire_write_pci_cfg,
-};
-
static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
{
pbm->pci_bus = pci_scan_one_pbm(pbm);
@@ -314,7 +182,8 @@
pci_pbm_root = pbm;
pbm->scan_bus = pci_fire_scan_bus;
- pbm->pci_ops = &pci_fire_ops;
+ pbm->pci_ops = &sun4u_pci_ops;
+ pbm->config_space_reg_bits = 12;
pbm->index = pci_num_pbms++;
diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h
index 8e38023..f660c2b 100644
--- a/arch/sparc64/kernel/pci_impl.h
+++ b/arch/sparc64/kernel/pci_impl.h
@@ -77,6 +77,9 @@
/* Base of PCI Config space, can be per-PBM or shared. */
unsigned long config_space;
+ /* This will be 12 on PCI-E controllers, 8 elsewhere. */
+ unsigned long config_space_reg_bits;
+
/* State of 66MHz capabilities on this PBM. */
int is_66mhz_capable;
int all_devs_66mhz;
@@ -156,4 +159,7 @@
extern void pci_config_write16(u16 *addr, u16 val);
extern void pci_config_write32(u32 *addr, u32 val);
+extern struct pci_ops sun4u_pci_ops;
+extern struct pci_ops sun4v_pci_ops;
+
#endif /* !(PCI_IMPL_H) */
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 2edcb1d..598393a2 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -94,122 +94,6 @@
PSYCHO_CONFIG_ENCODE(bus, devfn, where));
}
-static int psycho_out_of_range(struct pci_pbm_info *pbm,
- unsigned char bus,
- unsigned char devfn)
-{
- return ((bus == pbm->pci_first_busno) &&
- PCI_SLOT(devfn) > 8);
-}
-
-/* PSYCHO PCI configuration space accessors. */
-
-static int psycho_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 *value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
- u16 tmp16;
- u8 tmp8;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
- size, value);
-
- switch (size) {
- case 1:
- *value = 0xff;
- break;
- case 2:
- *value = 0xffff;
- break;
- case 4:
- *value = 0xffffffff;
- break;
- }
-
- addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (psycho_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
- switch (size) {
- case 1:
- pci_config_read8((u8 *)addr, &tmp8);
- *value = (u32) tmp8;
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_read_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read16((u16 *)addr, &tmp16);
- *value = (u32) tmp16;
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_read_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read32(addr, value);
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int psycho_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
- size, value);
- addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (psycho_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- pci_config_write8((u8 *)addr, value);
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_write_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_write16((u16 *)addr, value);
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_write_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_write32(addr, value);
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops psycho_ops = {
- .read = psycho_read_pci_cfg,
- .write = psycho_write_pci_cfg,
-};
-
/* PSYCHO error handling support. */
enum psycho_error_type {
UE_ERR, CE_ERR, PCI_ERR
@@ -1089,7 +973,8 @@
pci_pbm_root = pbm;
pbm->scan_bus = psycho_scan_bus;
- pbm->pci_ops = &psycho_ops;
+ pbm->pci_ops = &sun4u_pci_ops;
+ pbm->config_space_reg_bits = 8;
pbm->index = pci_num_pbms++;
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 4cefe6e..e237779 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -205,294 +205,9 @@
#define SABRE_MEMSPACE 0x100000000UL
#define SABRE_MEMSPACE_SIZE 0x07fffffffUL
-/* UltraSparc-IIi Programmer's Manual, page 325, PCI
- * configuration space address format:
- *
- * 32 24 23 16 15 11 10 8 7 2 1 0
- * ---------------------------------------------------------
- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 |
- * ---------------------------------------------------------
- */
-#define SABRE_CONFIG_BASE(PBM) \
- ((PBM)->config_space | (1UL << 24))
-#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \
- (((unsigned long)(BUS) << 16) | \
- ((unsigned long)(DEVFN) << 8) | \
- ((unsigned long)(REG)))
-
static int hummingbird_p;
static struct pci_bus *sabre_root_bus;
-static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm,
- unsigned char bus,
- unsigned int devfn,
- int where)
-{
- if (!pbm)
- return NULL;
- return (void *)
- (SABRE_CONFIG_BASE(pbm) |
- SABRE_CONFIG_ENCODE(bus, devfn, where));
-}
-
-static int sabre_out_of_range(unsigned char devfn)
-{
- if (hummingbird_p)
- return 0;
-
- return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) ||
- ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) ||
- (PCI_SLOT(devfn) > 1));
-}
-
-static int __sabre_out_of_range(struct pci_pbm_info *pbm,
- unsigned char bus,
- unsigned char devfn)
-{
- if (hummingbird_p)
- return 0;
-
- return ((pbm->parent == 0) ||
- ((pbm == &pbm->parent->pbm_A) &&
- (bus == pbm->pci_first_busno) &&
- PCI_SLOT(devfn) > 8));
-}
-
-static int __sabre_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 *value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
- u16 tmp16;
- u8 tmp8;
-
- switch (size) {
- case 1:
- *value = 0xff;
- break;
- case 2:
- *value = 0xffff;
- break;
- case 4:
- *value = 0xffffffff;
- break;
- }
-
- addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (__sabre_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- pci_config_read8((u8 *) addr, &tmp8);
- *value = tmp8;
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_read_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read16((u16 *) addr, &tmp16);
- *value = tmp16;
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_read_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read32(addr, value);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int sabre_read_pci_cfg(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *value)
-{
- struct pci_pbm_info *pbm = bus->sysdata;
-
- if (bus == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus, devfn, where,
- size, value);
-
- if (!bus->number && sabre_out_of_range(devfn)) {
- switch (size) {
- case 1:
- *value = 0xff;
- break;
- case 2:
- *value = 0xffff;
- break;
- case 4:
- *value = 0xffffffff;
- break;
- }
- return PCIBIOS_SUCCESSFUL;
- }
-
- if (bus->number || PCI_SLOT(devfn))
- return __sabre_read_pci_cfg(bus, devfn, where, size, value);
-
- /* When accessing PCI config space of the PCI controller itself (bus
- * 0, device slot 0, function 0) there are restrictions. Each
- * register must be accessed as it's natural size. Thus, for example
- * the Vendor ID must be accessed as a 16-bit quantity.
- */
-
- switch (size) {
- case 1:
- if (where < 8) {
- u32 tmp32;
- u16 tmp16;
-
- __sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
- tmp16 = (u16) tmp32;
- if (where & 1)
- *value = tmp16 >> 8;
- else
- *value = tmp16 & 0xff;
- } else
- return __sabre_read_pci_cfg(bus, devfn, where, 1, value);
- break;
-
- case 2:
- if (where < 8)
- return __sabre_read_pci_cfg(bus, devfn, where, 2, value);
- else {
- u32 tmp32;
- u8 tmp8;
-
- __sabre_read_pci_cfg(bus, devfn, where, 1, &tmp32);
- tmp8 = (u8) tmp32;
- *value = tmp8;
- __sabre_read_pci_cfg(bus, devfn, where + 1, 1, &tmp32);
- tmp8 = (u8) tmp32;
- *value |= tmp8 << 8;
- }
- break;
-
- case 4: {
- u32 tmp32;
- u16 tmp16;
-
- sabre_read_pci_cfg(bus, devfn, where, 2, &tmp32);
- tmp16 = (u16) tmp32;
- *value = tmp16;
- sabre_read_pci_cfg(bus, devfn, where + 2, 2, &tmp32);
- tmp16 = (u16) tmp32;
- *value |= tmp16 << 16;
- break;
- }
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int __sabre_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
-
- addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (__sabre_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- pci_config_write8((u8 *) addr, value);
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_write_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_write16((u16 *) addr, value);
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_write_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_write32(addr, value);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 value)
-{
- struct pci_pbm_info *pbm = bus->sysdata;
-
- if (bus == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus, devfn, where,
- size, value);
-
- if (bus->number)
- return __sabre_write_pci_cfg(bus, devfn, where, size, value);
-
- if (sabre_out_of_range(devfn))
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- if (where < 8) {
- u32 tmp32;
- u16 tmp16;
-
- __sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);
- tmp16 = (u16) tmp32;
- if (where & 1) {
- value &= 0x00ff;
- value |= tmp16 << 8;
- } else {
- value &= 0xff00;
- value |= tmp16;
- }
- tmp32 = (u32) tmp16;
- return __sabre_write_pci_cfg(bus, devfn, where & ~1, 2, tmp32);
- } else
- return __sabre_write_pci_cfg(bus, devfn, where, 1, value);
- break;
- case 2:
- if (where < 8)
- return __sabre_write_pci_cfg(bus, devfn, where, 2, value);
- else {
- __sabre_write_pci_cfg(bus, devfn, where, 1, value & 0xff);
- __sabre_write_pci_cfg(bus, devfn, where + 1, 1, value >> 8);
- }
- break;
- case 4:
- sabre_write_pci_cfg(bus, devfn, where, 2, value & 0xffff);
- sabre_write_pci_cfg(bus, devfn, where + 2, 2, value >> 16);
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops sabre_ops = {
- .read = sabre_read_pci_cfg,
- .write = sabre_write_pci_cfg,
-};
-
/* SABRE error handling support. */
static void sabre_check_iommu_error(struct pci_pbm_info *pbm,
unsigned long afsr,
@@ -1010,7 +725,8 @@
printk("%s: SABRE PCI Bus Module\n", pbm->name);
pbm->scan_bus = sabre_scan_bus;
- pbm->pci_ops = &sabre_ops;
+ pbm->pci_ops = &sun4u_pci_ops;
+ pbm->config_space_reg_bits = 8;
pbm->index = pci_num_pbms++;
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index e375d72..ae76898 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -104,125 +104,6 @@
SCHIZO_CONFIG_ENCODE(bus, devfn, where));
}
-/* Just make sure the bus number is in range. */
-static int schizo_out_of_range(struct pci_pbm_info *pbm,
- unsigned char bus,
- unsigned char devfn)
-{
- if (bus < pbm->pci_first_busno ||
- bus > pbm->pci_last_busno)
- return 1;
- return 0;
-}
-
-/* SCHIZO PCI configuration space accessors. */
-
-static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 *value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
- u16 tmp16;
- u8 tmp8;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
- size, value);
- switch (size) {
- case 1:
- *value = 0xff;
- break;
- case 2:
- *value = 0xffff;
- break;
- case 4:
- *value = 0xffffffff;
- break;
- }
-
- addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (schizo_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
- switch (size) {
- case 1:
- pci_config_read8((u8 *)addr, &tmp8);
- *value = tmp8;
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_read_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read16((u16 *)addr, &tmp16);
- *value = tmp16;
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_read_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_read32(addr, value);
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- unsigned char bus = bus_dev->number;
- u32 *addr;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
- size, value);
- addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);
- if (!addr)
- return PCIBIOS_SUCCESSFUL;
-
- if (schizo_out_of_range(pbm, bus, devfn))
- return PCIBIOS_SUCCESSFUL;
-
- switch (size) {
- case 1:
- pci_config_write8((u8 *)addr, value);
- break;
-
- case 2:
- if (where & 0x01) {
- printk("pci_write_config_word: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
- pci_config_write16((u16 *)addr, value);
- break;
-
- case 4:
- if (where & 0x03) {
- printk("pci_write_config_dword: misaligned reg [%x]\n",
- where);
- return PCIBIOS_SUCCESSFUL;
- }
-
- pci_config_write32(addr, value);
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops schizo_ops = {
- .read = schizo_read_pci_cfg,
- .write = schizo_write_pci_cfg,
-};
-
/* SCHIZO error handling support. */
enum schizo_error_type {
UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR
@@ -1494,7 +1375,8 @@
pci_pbm_root = pbm;
pbm->scan_bus = schizo_scan_bus;
- pbm->pci_ops = &schizo_ops;
+ pbm->pci_ops = &sun4u_pci_ops;
+ pbm->config_space_reg_bits = 8;
pbm->index = pci_num_pbms++;
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 0c76a88..34df404 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -593,89 +593,6 @@
.dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu,
};
-static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func)
-{
- if (bus < pbm->pci_first_busno ||
- bus > pbm->pci_last_busno)
- return 1;
- return 0;
-}
-
-static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 *value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- u32 devhandle = pbm->devhandle;
- unsigned int bus = bus_dev->number;
- unsigned int device = PCI_SLOT(devfn);
- unsigned int func = PCI_FUNC(devfn);
- unsigned long ret;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
- size, value);
- if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
- ret = ~0UL;
- } else {
- ret = pci_sun4v_config_get(devhandle,
- HV_PCI_DEVICE_BUILD(bus, device, func),
- where, size);
-#if 0
- printk("rcfg: [%x:%x:%x:%d]=[%lx]\n",
- devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
- where, size, ret);
-#endif
- }
- switch (size) {
- case 1:
- *value = ret & 0xff;
- break;
- case 2:
- *value = ret & 0xffff;
- break;
- case 4:
- *value = ret & 0xffffffff;
- break;
- };
-
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
- int where, int size, u32 value)
-{
- struct pci_pbm_info *pbm = bus_dev->sysdata;
- u32 devhandle = pbm->devhandle;
- unsigned int bus = bus_dev->number;
- unsigned int device = PCI_SLOT(devfn);
- unsigned int func = PCI_FUNC(devfn);
- unsigned long ret;
-
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
- size, value);
- if (pci_sun4v_out_of_range(pbm, bus, device, func)) {
- /* Do nothing. */
- } else {
- ret = pci_sun4v_config_put(devhandle,
- HV_PCI_DEVICE_BUILD(bus, device, func),
- where, size, value);
-#if 0
- printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n",
- devhandle, HV_PCI_DEVICE_BUILD(bus, device, func),
- where, size, value, ret);
-#endif
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_sun4v_ops = {
- .read = pci_sun4v_read_pci_cfg,
- .write = pci_sun4v_write_pci_cfg,
-};
-
-
static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
{
struct property *prop;
@@ -1238,7 +1155,8 @@
pci_pbm_root = pbm;
pbm->scan_bus = pci_sun4v_scan_bus;
- pbm->pci_ops = &pci_sun4v_ops;
+ pbm->pci_ops = &sun4v_pci_ops;
+ pbm->config_space_reg_bits = 12;
pbm->index = pci_num_pbms++;
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index c54d4d8..b7976b1 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -1636,10 +1636,21 @@
static struct device_node * __init build_tree(struct device_node *parent, phandle node, struct device_node ***nextp)
{
+ struct device_node *ret = NULL, *prev_sibling = NULL;
struct device_node *dp;
- dp = create_node(node, parent);
- if (dp) {
+ while (1) {
+ dp = create_node(node, parent);
+ if (!dp)
+ break;
+
+ if (prev_sibling)
+ prev_sibling->sibling = dp;
+
+ if (!ret)
+ ret = dp;
+ prev_sibling = dp;
+
*(*nextp) = dp;
*nextp = &dp->allnext;
@@ -1648,10 +1659,10 @@
dp->child = build_tree(dp, prom_getchild(node), nextp);
- dp->sibling = build_tree(parent, prom_getsibling(node), nextp);
+ node = prom_getsibling(node);
}
- return dp;
+ return ret;
}
void __init prom_build_devicetree(void)
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index b9c0f30..c504312 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -277,7 +277,8 @@
config KERNEL_STACK_ORDER
int "Kernel stack size order"
- default 2
+ default 1 if 64BIT
+ default 0 if !64BIT
help
This option determines the size of UML kernel stacks. They will
be 1 << order pages. The default is OK unless you're running Valgrind
diff --git a/arch/um/defconfig b/arch/um/defconfig
index f938fa8..a54d0ef 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -86,7 +86,7 @@
# CONFIG_MAGIC_SYSRQ is not set
CONFIG_NEST_LEVEL=0
# CONFIG_HIGHMEM is not set
-CONFIG_KERNEL_STACK_ORDER=2
+CONFIG_KERNEL_STACK_ORDER=0
CONFIG_UML_REAL_TIME_CLOCK=y
#
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 5593a80..541f4a8 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -28,3 +28,5 @@
/* For crypto assembler code. */
DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+
+DEFINE(UM_THREAD_SIZE, THREAD_SIZE);
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 50a4969..8d7f7c1 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -117,4 +117,7 @@
extern void copy_sc(union uml_pt_regs *regs, void *from);
+unsigned long to_irq_stack(int sig, unsigned long *mask_out);
+unsigned long from_irq_stack(int nested);
+
#endif
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 688d181..4d9fb263 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -272,7 +272,6 @@
/* util.c */
extern void stack_protections(unsigned long address);
-extern void task_protections(unsigned long address);
extern int raw(int fd);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(char *buf, int len);
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index e36f92b..87a4e44 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -97,6 +97,8 @@
.data : {
. = ALIGN(KERNEL_STACK_SIZE); /* init_task */
*(.data.init_task)
+ . = ALIGN(KERNEL_STACK_SIZE);
+ *(.data.init_irqstack)
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index cda91aa..d4f1d1a 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -1,5 +1,5 @@
-/*
- * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+/*
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,intel.linux}.com)
* Licensed under the GPL
*/
@@ -33,28 +33,20 @@
/*
* Initial thread structure.
*
- * We need to make sure that this is 16384-byte aligned due to the
+ * We need to make sure that this is aligned due to the
* way process stacks are handled. This is done by having a special
* "init_task" linker map entry..
*/
-union thread_union init_thread_union
-__attribute__((__section__(".data.init_task"))) =
-{ INIT_THREAD_INFO(init_task) };
+union thread_union init_thread_union
+ __attribute__((__section__(".data.init_task"))) =
+ { INIT_THREAD_INFO(init_task) };
+
+union thread_union cpu0_irqstack
+ __attribute__((__section__(".data.init_irqstack"))) =
+ { INIT_THREAD_INFO(init_task) };
void unprotect_stack(unsigned long stack)
{
- os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE,
- 1, 1, 0);
+ os_protect_memory((void *) stack, THREAD_SIZE, 1, 1, 0);
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 8f2ed36..dba04d8 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
* Derived (i.e. mostly copied) from arch/i386/kernel/irq.c:
@@ -32,6 +32,7 @@
#include "sigio.h"
#include "um_malloc.h"
#include "misc_constants.h"
+#include "as-layout.h"
/*
* Generic, controller-independent functions:
@@ -53,7 +54,7 @@
if (i < NR_IRQS) {
spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
- if (!action)
+ if (!action)
goto skip;
seq_printf(p, "%3d: ",i);
#ifndef CONFIG_SMP
@@ -468,3 +469,113 @@
out:
return err;
}
+
+/*
+ * IRQ stack entry and exit:
+ *
+ * Unlike i386, UML doesn't receive IRQs on the normal kernel stack
+ * and switch over to the IRQ stack after some preparation. We use
+ * sigaltstack to receive signals on a separate stack from the start.
+ * These two functions make sure the rest of the kernel won't be too
+ * upset by being on a different stack. The IRQ stack has a
+ * thread_info structure at the bottom so that current et al continue
+ * to work.
+ *
+ * to_irq_stack copies the current task's thread_info to the IRQ stack
+ * thread_info and sets the tasks's stack to point to the IRQ stack.
+ *
+ * from_irq_stack copies the thread_info struct back (flags may have
+ * been modified) and resets the task's stack pointer.
+ *
+ * Tricky bits -
+ *
+ * What happens when two signals race each other? UML doesn't block
+ * signals with sigprocmask, SA_DEFER, or sa_mask, so a second signal
+ * could arrive while a previous one is still setting up the
+ * thread_info.
+ *
+ * There are three cases -
+ * The first interrupt on the stack - sets up the thread_info and
+ * handles the interrupt
+ * A nested interrupt interrupting the copying of the thread_info -
+ * can't handle the interrupt, as the stack is in an unknown state
+ * A nested interrupt not interrupting the copying of the
+ * thread_info - doesn't do any setup, just handles the interrupt
+ *
+ * The first job is to figure out whether we interrupted stack setup.
+ * This is done by xchging the signal mask with thread_info->pending.
+ * If the value that comes back is zero, then there is no setup in
+ * progress, and the interrupt can be handled. If the value is
+ * non-zero, then there is stack setup in progress. In order to have
+ * the interrupt handled, we leave our signal in the mask, and it will
+ * be handled by the upper handler after it has set up the stack.
+ *
+ * Next is to figure out whether we are the outer handler or a nested
+ * one. As part of setting up the stack, thread_info->real_thread is
+ * set to non-NULL (and is reset to NULL on exit). This is the
+ * nesting indicator. If it is non-NULL, then the stack is already
+ * set up and the handler can run.
+ */
+
+static unsigned long pending_mask;
+
+unsigned long to_irq_stack(int sig, unsigned long *mask_out)
+{
+ struct thread_info *ti;
+ unsigned long mask, old;
+ int nested;
+
+ mask = xchg(&pending_mask, 1 << sig);
+ if(mask != 0){
+ /* If any interrupts come in at this point, we want to
+ * make sure that their bits aren't lost by our
+ * putting our bit in. So, this loop accumulates bits
+ * until xchg returns the same value that we put in.
+ * When that happens, there were no new interrupts,
+ * and pending_mask contains a bit for each interrupt
+ * that came in.
+ */
+ old = 1 << sig;
+ do {
+ old |= mask;
+ mask = xchg(&pending_mask, old);
+ } while(mask != old);
+ return 1;
+ }
+
+ ti = current_thread_info();
+ nested = (ti->real_thread != NULL);
+ if(!nested){
+ struct task_struct *task;
+ struct thread_info *tti;
+
+ task = cpu_tasks[ti->cpu].task;
+ tti = task_thread_info(task);
+ *ti = *tti;
+ ti->real_thread = tti;
+ task->stack = ti;
+ }
+
+ mask = xchg(&pending_mask, 0);
+ *mask_out |= mask | nested;
+ return 0;
+}
+
+unsigned long from_irq_stack(int nested)
+{
+ struct thread_info *ti, *to;
+ unsigned long mask;
+
+ ti = current_thread_info();
+
+ pending_mask = 1;
+
+ to = ti->real_thread;
+ current->stack = to;
+ ti->real_thread = NULL;
+ *to = *ti;
+
+ mask = xchg(&pending_mask, 0);
+ return mask & ~1;
+}
+
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index a96ae1a..2a69a7c 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -163,8 +163,12 @@
extern int userspace_pid[];
+extern char cpu0_irqstack[];
+
int start_uml_skas(void)
{
+ stack_protections((unsigned long) &cpu0_irqstack);
+ set_sigstack(cpu0_irqstack, THREAD_SIZE);
if(proc_mm)
userspace_pid[0] = start_userspace(0);
diff --git a/arch/um/kernel/tt/exec_kern.c b/arch/um/kernel/tt/exec_kern.c
index 98e2174..40126cb 100644
--- a/arch/um/kernel/tt/exec_kern.c
+++ b/arch/um/kernel/tt/exec_kern.c
@@ -57,7 +57,7 @@
enable_timer();
free_page(stack);
protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
- task_protections((unsigned long) current_thread);
+ stack_protections((unsigned long) current_thread);
force_flush_all();
unblock_signals();
}
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index c631303..74347ad 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -209,7 +209,7 @@
if(current->mm != current->parent->mm)
protect_memory(uml_reserved, high_physmem - uml_reserved, 1,
1, 0, 1);
- task_protections((unsigned long) current_thread);
+ stack_protections((unsigned long) current_thread);
free_page(current->thread.temp_stack);
local_irq_disable();
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 1cf954a..ecc458f 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -459,7 +459,7 @@
uml_postsetup();
- task_protections((unsigned long) &init_thread_info);
+ stack_protections((unsigned long) &init_thread_info);
os_flush_stdout();
return CHOOSE_MODE(start_uml_tt(), start_uml_skas());
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index f630127..bc59f97 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -59,6 +59,8 @@
{
. = ALIGN(KERNEL_STACK_SIZE); /* init_task */
*(.data.init_task)
+ . = ALIGN(KERNEL_STACK_SIZE);
+ *(.data.init_irqstack)
*(.data)
*(.gnu.linkonce.d*)
CONSTRUCTORS
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 48d4934..18e5c8b 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -61,15 +61,19 @@
static void real_alarm_handler(int sig, struct sigcontext *sc)
{
+ union uml_pt_regs regs;
+
if(sig == SIGALRM)
switch_timers(0);
- CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
- sig, sc);
+ if(sc != NULL)
+ copy_sc(®s, sc);
+ regs.skas.is_user = 0;
+ unblock_signals();
+ timer_handler(sig, ®s);
if(sig == SIGALRM)
switch_timers(1);
-
}
void alarm_handler(int sig, struct sigcontext *sc)
@@ -113,6 +117,46 @@
void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
+void handle_signal(int sig, struct sigcontext *sc)
+{
+ unsigned long pending = 0;
+
+ do {
+ int nested, bail;
+
+ /*
+ * pending comes back with one bit set for each
+ * interrupt that arrived while setting up the stack,
+ * plus a bit for this interrupt, plus the zero bit is
+ * set if this is a nested interrupt.
+ * If bail is true, then we interrupted another
+ * handler setting up the stack. In this case, we
+ * have to return, and the upper handler will deal
+ * with this interrupt.
+ */
+ bail = to_irq_stack(sig, &pending);
+ if(bail)
+ return;
+
+ nested = pending & 1;
+ pending &= ~1;
+
+ while((sig = ffs(pending)) != 0){
+ sig--;
+ pending &= ~(1 << sig);
+ (*handlers[sig])(sig, sc);
+ }
+
+ /* Again, pending comes back with a mask of signals
+ * that arrived while tearing down the stack. If this
+ * is non-zero, we just go back, set up the stack
+ * again, and handle the new interrupts.
+ */
+ if(!nested)
+ pending = from_irq_stack(nested);
+ } while(pending);
+}
+
extern void hard_handler(int sig);
void set_handler(int sig, void (*handler)(int), int flags, ...)
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 6a0e466..f9d2f85 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -288,7 +288,8 @@
void userspace(union uml_pt_regs *regs)
{
int err, status, op, pid = userspace_pid[0];
- int local_using_sysemu; /*To prevent races if using_sysemu changes under us.*/
+ /* To prevent races if using_sysemu changes under us.*/
+ int local_using_sysemu;
while(1){
restore_registers(pid, regs);
@@ -296,7 +297,8 @@
/* Now we set local_using_sysemu to be used for one loop */
local_using_sysemu = get_using_sysemu();
- op = SELECT_PTRACE_OPERATION(local_using_sysemu, singlestepping(NULL));
+ op = SELECT_PTRACE_OPERATION(local_using_sysemu,
+ singlestepping(NULL));
err = ptrace(op, pid, 0, 0);
if(err)
@@ -490,8 +492,8 @@
void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
{
(*buf)[0].JB_IP = (unsigned long) handler;
- (*buf)[0].JB_SP = (unsigned long) stack +
- (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *);
+ (*buf)[0].JB_SP = (unsigned long) stack + UM_THREAD_SIZE -
+ sizeof(void *);
}
#define INIT_JMP_NEW_THREAD 0
@@ -533,8 +535,7 @@
case INIT_JMP_NEW_THREAD:
(*switch_buf)[0].JB_IP = (unsigned long) new_thread_handler;
(*switch_buf)[0].JB_SP = (unsigned long) stack +
- (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) -
- sizeof(void *);
+ UM_THREAD_SIZE - sizeof(void *);
break;
case INIT_JMP_CALLBACK:
(*cb_proc)(cb_arg);
diff --git a/arch/um/os-Linux/sys-i386/signal.c b/arch/um/os-Linux/sys-i386/signal.c
index 0d3eae5..f311609 100644
--- a/arch/um/os-Linux/sys-i386/signal.c
+++ b/arch/um/os-Linux/sys-i386/signal.c
@@ -1,15 +1,13 @@
/*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <signal.h>
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
void hard_handler(int sig)
{
- struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
-
- (*handlers[sig])(sig, sc);
+ handle_signal(sig, (struct sigcontext *) (&sig + 1));
}
diff --git a/arch/um/os-Linux/sys-x86_64/signal.c b/arch/um/os-Linux/sys-x86_64/signal.c
index 3f369e5..82a3888 100644
--- a/arch/um/os-Linux/sys-x86_64/signal.c
+++ b/arch/um/os-Linux/sys-x86_64/signal.c
@@ -1,16 +1,16 @@
/*
- * Copyright (C) 2006 Jeff Dike (jdike@addtoit.com)
+ * Copyright (C) 2006 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <signal.h>
-extern void (*handlers[])(int sig, struct sigcontext *sc);
+extern void handle_signal(int sig, struct sigcontext *sc);
void hard_handler(int sig)
{
struct ucontext *uc;
asm("movq %%rdx, %0" : "=r" (uc));
- (*handlers[sig])(sig, (struct sigcontext *) &uc->uc_mcontext);
+ handle_signal(sig, (struct sigcontext *) &uc->uc_mcontext);
}
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index c307a89..7cbcf48 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -33,25 +33,8 @@
void stack_protections(unsigned long address)
{
- int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
-
- if(mprotect((void *) address, UM_KERN_PAGE_SIZE, prot) < 0)
- panic("protecting stack failed, errno = %d", errno);
-}
-
-void task_protections(unsigned long address)
-{
- unsigned long guard = address + UM_KERN_PAGE_SIZE;
- unsigned long stack = guard + UM_KERN_PAGE_SIZE;
- int prot = 0, pages;
-
-#ifdef notdef
- if(mprotect((void *) stack, UM_KERN_PAGE_SIZE, prot) < 0)
- panic("protecting guard page failed, errno = %d", errno);
-#endif
- pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
- prot = PROT_READ | PROT_WRITE | PROT_EXEC;
- if(mprotect((void *) stack, pages * UM_KERN_PAGE_SIZE, prot) < 0)
+ if(mprotect((void *) address, UM_THREAD_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC) < 0)
panic("protecting stack failed, errno = %d", errno);
}
@@ -72,7 +55,7 @@
/* XXX tcsetattr could have applied only some changes
* (and cfmakeraw() is a set of changes) */
- return(0);
+ return 0;
}
void setup_machinename(char *machine_out)
diff --git a/arch/x86_64/ia32/audit.c b/arch/x86_64/ia32/audit.c
index 92d7d0c..8850fe4 100644
--- a/arch/x86_64/ia32/audit.c
+++ b/arch/x86_64/ia32/audit.c
@@ -20,6 +20,11 @@
~0U
};
+unsigned ia32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
int ia32_classify_syscall(unsigned syscall)
{
switch(syscall) {
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index f210683..52be79b 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -716,4 +716,7 @@
.quad sys_getcpu
.quad sys_epoll_pwait
.quad compat_sys_utimensat /* 320 */
+ .quad sys_signalfd
+ .quad sys_timerfd
+ .quad sys_eventfd
ia32_syscall_end:
diff --git a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c
index a52af58..a3d450d 100644
--- a/arch/x86_64/kernel/aperture.c
+++ b/arch/x86_64/kernel/aperture.c
@@ -86,7 +86,7 @@
printk("Aperture too small (%d MB)\n", aper_size>>20);
return 0;
}
- if (aper_base + aper_size >= 0xffffffff) {
+ if (aper_base + aper_size > 0x100000000UL) {
printk("Aperture beyond 4GB. Ignoring.\n");
return 0;
}
diff --git a/arch/x86_64/kernel/audit.c b/arch/x86_64/kernel/audit.c
index 21f3338..06d3e5a 100644
--- a/arch/x86_64/kernel/audit.c
+++ b/arch/x86_64/kernel/audit.c
@@ -23,6 +23,20 @@
~0U
};
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_IA32_EMULATION
+ if (arch == AUDIT_ARCH_I386)
+ return 1;
+#endif
+ return 0;
+}
+
int audit_classify_syscall(int abi, unsigned syscall)
{
#ifdef CONFIG_IA32_EMULATION
@@ -49,15 +63,18 @@
extern __u32 ia32_write_class[];
extern __u32 ia32_read_class[];
extern __u32 ia32_chattr_class[];
+ extern __u32 ia32_signal_class[];
audit_register_class(AUDIT_CLASS_WRITE_32, ia32_write_class);
audit_register_class(AUDIT_CLASS_READ_32, ia32_read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE_32, ia32_dir_class);
audit_register_class(AUDIT_CLASS_CHATTR_32, ia32_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, ia32_signal_class);
#endif
audit_register_class(AUDIT_CLASS_WRITE, write_class);
audit_register_class(AUDIT_CLASS_READ, read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
return 0;
}
diff --git a/arch/x86_64/kernel/bugs.c b/arch/x86_64/kernel/bugs.c
index 12b585b..c141e7a 100644
--- a/arch/x86_64/kernel/bugs.c
+++ b/arch/x86_64/kernel/bugs.c
@@ -13,6 +13,7 @@
void __init check_bugs(void)
{
identify_cpu(&boot_cpu_data);
+ mtrr_bp_init();
#if !defined(CONFIG_SMP)
printk("CPU: ");
print_cpu_info(&boot_cpu_data);
diff --git a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c
index 213d90e..6c34bdd 100644
--- a/arch/x86_64/kernel/head64.c
+++ b/arch/x86_64/kernel/head64.c
@@ -62,13 +62,6 @@
{
int i;
- /*
- * Make sure kernel is aligned to 2MB address. Catching it at compile
- * time is better. Change your config file and compile the kernel
- * for a 2MB aligned address (CONFIG_PHYSICAL_START)
- */
- BUILD_BUG_ON(CONFIG_PHYSICAL_START & (__KERNEL_ALIGN - 1));
-
/* clear bss before set_intr_gate with early_idt_handler */
clear_bss();
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index 373ef66..ae091cd 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -476,7 +476,7 @@
aper_base <<= 25;
aper_size = (32 * 1024 * 1024) << aper_order;
- if (aper_base + aper_size >= 0xffffffff || !aper_size)
+ if (aper_base + aper_size > 0x100000000UL || !aper_size)
aper_base = 0;
*size = aper_size;
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index db51577..eb6524f 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -891,9 +891,7 @@
#ifdef CONFIG_X86_MCE
mcheck_init(c);
#endif
- if (c == &boot_cpu_data)
- mtrr_bp_init();
- else
+ if (c != &boot_cpu_data)
mtrr_ap_init();
#ifdef CONFIG_NUMA
numa_add_cpu(smp_processor_id());
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 8c2ac41..d28f013 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -778,6 +778,7 @@
return;
if (notify_die(DIE_NMI_POST, "nmi_post", regs, reason, 2, 0)
== NOTIFY_STOP)
+ return;
if (!do_nmi_callback(regs,cpu))
unknown_nmi_error(reason, regs);
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 17e1889..74a567a 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -3116,7 +3116,7 @@
* bi_sector for remaps as it sees fit. So the values of these fields
* should NOT be depended on after the call to generic_make_request.
*/
-void generic_make_request(struct bio *bio)
+static inline void __generic_make_request(struct bio *bio)
{
request_queue_t *q;
sector_t maxsector;
@@ -3215,6 +3215,57 @@
} while (ret);
}
+/*
+ * We only want one ->make_request_fn to be active at a time,
+ * else stack usage with stacked devices could be a problem.
+ * So use current->bio_{list,tail} to keep a list of requests
+ * submited by a make_request_fn function.
+ * current->bio_tail is also used as a flag to say if
+ * generic_make_request is currently active in this task or not.
+ * If it is NULL, then no make_request is active. If it is non-NULL,
+ * then a make_request is active, and new requests should be added
+ * at the tail
+ */
+void generic_make_request(struct bio *bio)
+{
+ if (current->bio_tail) {
+ /* make_request is active */
+ *(current->bio_tail) = bio;
+ bio->bi_next = NULL;
+ current->bio_tail = &bio->bi_next;
+ return;
+ }
+ /* following loop may be a bit non-obvious, and so deserves some
+ * explanation.
+ * Before entering the loop, bio->bi_next is NULL (as all callers
+ * ensure that) so we have a list with a single bio.
+ * We pretend that we have just taken it off a longer list, so
+ * we assign bio_list to the next (which is NULL) and bio_tail
+ * to &bio_list, thus initialising the bio_list of new bios to be
+ * added. __generic_make_request may indeed add some more bios
+ * through a recursive call to generic_make_request. If it
+ * did, we find a non-NULL value in bio_list and re-enter the loop
+ * from the top. In this case we really did just take the bio
+ * of the top of the list (no pretending) and so fixup bio_list and
+ * bio_tail or bi_next, and call into __generic_make_request again.
+ *
+ * The loop was structured like this to make only one call to
+ * __generic_make_request (which is important as it is large and
+ * inlined) and to keep the structure simple.
+ */
+ BUG_ON(bio->bi_next);
+ do {
+ current->bio_list = bio->bi_next;
+ if (bio->bi_next == NULL)
+ current->bio_tail = ¤t->bio_list;
+ else
+ bio->bi_next = NULL;
+ __generic_make_request(bio);
+ bio = current->bio_list;
+ } while (bio);
+ current->bio_tail = NULL; /* deactivate */
+}
+
EXPORT_SYMBOL(generic_make_request);
/**
diff --git a/drivers/Makefile b/drivers/Makefile
index 26ca903..adad2f3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -36,6 +36,7 @@
obj-$(CONFIG_SCSI) += scsi/
obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_FUSION) += message/
+obj-$(CONFIG_FIREWIRE) += firewire/
obj-$(CONFIG_IEEE1394) += ieee1394/
obj-y += cdrom/
obj-y += auxdisplay/
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 1683e5c..1cbe619 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -231,8 +231,10 @@
* Obtain the method mutex if necessary. Do not acquire mutex for a
* recursive call.
*/
- if (acpi_os_get_thread_id() !=
- obj_desc->method.mutex->mutex.owner_thread_id) {
+ if (!walk_state ||
+ !obj_desc->method.mutex->mutex.owner_thread ||
+ (walk_state->thread !=
+ obj_desc->method.mutex->mutex.owner_thread)) {
/*
* Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns)
@@ -246,14 +248,14 @@
}
/* Update the mutex and walk info and save the original sync_level */
- obj_desc->method.mutex->mutex.owner_thread_id =
- acpi_os_get_thread_id();
if (walk_state) {
obj_desc->method.mutex->mutex.
original_sync_level =
walk_state->thread->current_sync_level;
+ obj_desc->method.mutex->mutex.owner_thread =
+ walk_state->thread;
walk_state->thread->current_sync_level =
obj_desc->method.sync_level;
} else {
@@ -567,7 +569,7 @@
acpi_os_release_mutex(method_desc->method.mutex->mutex.
os_mutex);
- method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
+ method_desc->method.mutex->mutex.owner_thread = NULL;
}
}
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 6c6104a..fc9da48 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -866,8 +866,7 @@
((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) &&
(op->common.parent->common.aml_opcode !=
AML_VAR_PACKAGE_OP)
- && (op->common.parent->common.aml_opcode !=
- AML_NAME_OP))) {
+ && (op->common.parent->common.aml_opcode != AML_NAME_OP))) {
walk_state->result_obj = obj_desc;
}
}
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index e4073e0..71503c0 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -556,10 +556,9 @@
* indicate this to the interpreter, set the
* object to the root
*/
- obj_desc =
- ACPI_CAST_PTR(union
- acpi_operand_object,
- acpi_gbl_root_node);
+ obj_desc = ACPI_CAST_PTR(union
+ acpi_operand_object,
+ acpi_gbl_root_node);
status = AE_OK;
} else {
/*
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 16c8e38..5afcdd9 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -630,12 +630,9 @@
*
******************************************************************************/
-struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
- union acpi_parse_object
- *origin,
- union acpi_operand_object
- *method_desc,
- struct acpi_thread_state
+struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object
+ *origin, union acpi_operand_object
+ *method_desc, struct acpi_thread_state
*thread)
{
struct acpi_walk_state *walk_state;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e08cf98..82f496c 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -147,9 +147,10 @@
return 0;
}
-static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, unsigned count)
+static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event,
+ unsigned count, int force_poll)
{
- if (acpi_ec_mode == EC_POLL) {
+ if (unlikely(force_poll) || acpi_ec_mode == EC_POLL) {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event, 0))
@@ -173,14 +174,15 @@
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
const u8 * wdata, unsigned wdata_len,
- u8 * rdata, unsigned rdata_len)
+ u8 * rdata, unsigned rdata_len,
+ int force_poll)
{
int result = 0;
unsigned count = atomic_read(&ec->event_count);
acpi_ec_write_cmd(ec, command);
for (; wdata_len > 0; --wdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
if (result) {
printk(KERN_ERR PREFIX
"write_cmd timeout, command = %d\n", command);
@@ -191,7 +193,7 @@
}
if (!rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, count, force_poll);
if (result) {
printk(KERN_ERR PREFIX
"finish-write timeout, command = %d\n", command);
@@ -202,7 +204,7 @@
}
for (; rdata_len > 0; --rdata_len) {
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1, count, force_poll);
if (result) {
printk(KERN_ERR PREFIX "read timeout, command = %d\n",
command);
@@ -217,7 +219,8 @@
static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
const u8 * wdata, unsigned wdata_len,
- u8 * rdata, unsigned rdata_len)
+ u8 * rdata, unsigned rdata_len,
+ int force_poll)
{
int status;
u32 glk;
@@ -240,7 +243,7 @@
/* Make sure GPE is enabled before doing transaction */
acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
if (status) {
printk(KERN_DEBUG PREFIX
"input buffer is not empty, aborting transaction\n");
@@ -249,7 +252,8 @@
status = acpi_ec_transaction_unlocked(ec, command,
wdata, wdata_len,
- rdata, rdata_len);
+ rdata, rdata_len,
+ force_poll);
end:
@@ -267,12 +271,12 @@
int acpi_ec_burst_enable(struct acpi_ec *ec)
{
u8 d;
- return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1);
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_ENABLE, NULL, 0, &d, 1, 0);
}
int acpi_ec_burst_disable(struct acpi_ec *ec)
{
- return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0);
+ return acpi_ec_transaction(ec, ACPI_EC_BURST_DISABLE, NULL, 0, NULL, 0, 0);
}
static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 * data)
@@ -281,7 +285,7 @@
u8 d;
result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
- &address, 1, &d, 1);
+ &address, 1, &d, 1, 0);
*data = d;
return result;
}
@@ -290,7 +294,7 @@
{
u8 wdata[2] = { address, data };
return acpi_ec_transaction(ec, ACPI_EC_COMMAND_WRITE,
- wdata, 2, NULL, 0);
+ wdata, 2, NULL, 0, 0);
}
/*
@@ -349,13 +353,15 @@
int ec_transaction(u8 command,
const u8 * wdata, unsigned wdata_len,
- u8 * rdata, unsigned rdata_len)
+ u8 * rdata, unsigned rdata_len,
+ int force_poll)
{
if (!first_ec)
return -ENODEV;
return acpi_ec_transaction(first_ec, command, wdata,
- wdata_len, rdata, rdata_len);
+ wdata_len, rdata, rdata_len,
+ force_poll);
}
EXPORT_SYMBOL(ec_transaction);
@@ -374,7 +380,7 @@
* bit to be cleared (and thus clearing the interrupt source).
*/
- result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1, 0);
if (result)
return result;
@@ -410,6 +416,7 @@
acpi_status status = AE_OK;
u8 value;
struct acpi_ec *ec = data;
+
atomic_inc(&ec->event_count);
if (acpi_ec_mode == EC_INTR) {
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index 635ba44..e22f4a9 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -341,9 +341,8 @@
/* A Non-NULL gpe_device means this is a GPE Block Device */
- obj_desc =
- acpi_ns_get_attached_object((struct acpi_namespace_node *)
- gpe_device);
+ obj_desc = acpi_ns_get_attached_object((struct acpi_namespace_node *)
+ gpe_device);
if (!obj_desc || !obj_desc->device.gpe_block) {
return (NULL);
}
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index ad5bc76..902c287 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -1033,8 +1033,7 @@
if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
ACPI_GPE_DISPATCH_METHOD)
- && (gpe_event_info->
- flags & ACPI_GPE_TYPE_RUNTIME)) {
+ && (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) {
gpe_enabled_count++;
}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index cae786c..21cb749 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -196,15 +196,12 @@
notify_info->notify.value = (u16) notify_value;
notify_info->notify.handler_obj = handler_obj;
- acpi_ex_exit_interpreter();
-
- acpi_ev_notify_dispatch(notify_info);
-
- status = acpi_ex_enter_interpreter();
+ status =
+ acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
+ notify_info);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ acpi_ut_delete_generic_state(notify_info);
}
-
}
if (!handler_obj) {
@@ -323,8 +320,9 @@
acpi_gbl_global_lock_acquired = TRUE;
/* Send a unit to the semaphore */
- if (ACPI_FAILURE(acpi_os_signal_semaphore(
- acpi_gbl_global_lock_semaphore, 1))) {
+ if (ACPI_FAILURE
+ (acpi_os_signal_semaphore
+ (acpi_gbl_global_lock_semaphore, 1))) {
ACPI_ERROR((AE_INFO,
"Could not signal Global Lock semaphore"));
}
@@ -450,7 +448,9 @@
}
if (ACPI_FAILURE(status)) {
- status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
+ status =
+ acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex,
+ timeout);
}
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 96b0e84..e99f0c4 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -291,7 +291,6 @@
u32 bit_width, acpi_integer * value)
{
acpi_status status;
- acpi_status status2;
acpi_adr_space_handler handler;
acpi_adr_space_setup region_setup;
union acpi_operand_object *handler_desc;
@@ -345,7 +344,7 @@
* setup will potentially execute control methods
* (e.g., _REG method for this region)
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
handler_desc->address_space.context,
@@ -353,10 +352,7 @@
/* Re-enter the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
/* Check for failure of the Region Setup */
@@ -409,7 +405,7 @@
* exit the interpreter because the handler *might* block -- we don't
* know what it will do, so we can't hold the lock on the intepreter.
*/
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
}
/* Call the handler */
@@ -430,10 +426,7 @@
* We just returned from a non-default handler, we must re-enter the
* interpreter
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index a4fa7e6..400d90f 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -228,7 +228,8 @@
/* Install a handler for this PCI root bridge */
- status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+ status =
+ acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
if (ACPI_FAILURE(status)) {
if (status == AE_SAME_HANDLER) {
/*
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index a3379ba..6d866a0 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -91,7 +91,6 @@
ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
#endif /* ACPI_FUTURE_USAGE */
-
/*******************************************************************************
*
* FUNCTION: acpi_install_fixed_event_handler
@@ -768,11 +767,9 @@
return (AE_BAD_PARAMETER);
}
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ /* Must lock interpreter to prevent race conditions */
+ acpi_ex_enter_interpreter();
status = acpi_ev_acquire_global_lock(timeout);
acpi_ex_exit_interpreter();
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 17065e9..9cbd341 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -472,7 +472,6 @@
}
ACPI_EXPORT_SYMBOL(acpi_clear_gpe)
-
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -568,7 +567,6 @@
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
#endif /* ACPI_FUTURE_USAGE */
-
/*******************************************************************************
*
* FUNCTION: acpi_install_gpe_block
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index d470e8b..79f2c0d 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -512,9 +512,8 @@
* Create a new string object and string buffer
* (-1 because of extra separator included in string_length from above)
*/
- return_desc =
- acpi_ut_create_string_object((acpi_size)
- (string_length - 1));
+ return_desc = acpi_ut_create_string_object((acpi_size)
+ (string_length - 1));
if (!return_desc) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index ae97812..6e9a23e 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -50,7 +50,6 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("excreate")
-
#ifndef ACPI_NO_METHOD_EXECUTION
/*******************************************************************************
*
@@ -583,10 +582,7 @@
* Get the sync_level. If method is serialized, a mutex will be
* created for this method when it is parsed.
*/
- if (acpi_gbl_all_methods_serialized) {
- obj_desc->method.sync_level = 0;
- obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
- } else if (method_flags & AML_METHOD_SERIALIZED) {
+ if (method_flags & AML_METHOD_SERIALIZED) {
/*
* ACPI 1.0: sync_level = 0
* ACPI 2.0: sync_level = sync_level in method declaration
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 1a73c14..51c9c29 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -134,7 +134,7 @@
static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread_id), "Owner Thread"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
"Acquire Depth"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
@@ -451,9 +451,8 @@
ACPI_FUNCTION_NAME(ex_dump_operand)
- if (!
- ((ACPI_LV_EXEC & acpi_dbg_level)
- && (_COMPONENT & acpi_dbg_layer))) {
+ if (!((ACPI_LV_EXEC & acpi_dbg_level)
+ && (_COMPONENT & acpi_dbg_layer))) {
return;
}
@@ -844,9 +843,8 @@
ACPI_FUNCTION_ENTRY();
if (!flags) {
- if (!
- ((ACPI_LV_OBJECTS & acpi_dbg_level)
- && (_COMPONENT & acpi_dbg_layer))) {
+ if (!((ACPI_LV_OBJECTS & acpi_dbg_level)
+ && (_COMPONENT & acpi_dbg_layer))) {
return;
}
}
@@ -1011,9 +1009,8 @@
}
if (!flags) {
- if (!
- ((ACPI_LV_OBJECTS & acpi_dbg_level)
- && (_COMPONENT & acpi_dbg_layer))) {
+ if (!((ACPI_LV_OBJECTS & acpi_dbg_level)
+ && (_COMPONENT & acpi_dbg_layer))) {
return_VOID;
}
}
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 4eb883b..6748e3e 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -66,9 +66,10 @@
*
******************************************************************************/
-void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc,
- struct acpi_thread_state *thread)
+void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
{
+ struct acpi_thread_state *thread = obj_desc->mutex.owner_thread;
+
if (!thread) {
return;
}
@@ -173,13 +174,16 @@
/* Support for multiple acquires by the owning thread */
- if (obj_desc->mutex.owner_thread_id == acpi_os_get_thread_id()) {
- /*
- * The mutex is already owned by this thread, just increment the
- * acquisition depth
- */
- obj_desc->mutex.acquisition_depth++;
- return_ACPI_STATUS(AE_OK);
+ if (obj_desc->mutex.owner_thread) {
+ if (obj_desc->mutex.owner_thread->thread_id ==
+ walk_state->thread->thread_id) {
+ /*
+ * The mutex is already owned by this thread, just increment the
+ * acquisition depth
+ */
+ obj_desc->mutex.acquisition_depth++;
+ return_ACPI_STATUS(AE_OK);
+ }
}
/* Acquire the mutex, wait if necessary. Special case for Global Lock */
@@ -202,7 +206,7 @@
/* Have the mutex: update mutex and walk info and save the sync_level */
- obj_desc->mutex.owner_thread_id = acpi_os_get_thread_id();
+ obj_desc->mutex.owner_thread = walk_state->thread;
obj_desc->mutex.acquisition_depth = 1;
obj_desc->mutex.original_sync_level =
walk_state->thread->current_sync_level;
@@ -242,7 +246,7 @@
/* The mutex must have been previously acquired in order to release it */
- if (!obj_desc->mutex.owner_thread_id) {
+ if (!obj_desc->mutex.owner_thread) {
ACPI_ERROR((AE_INFO,
"Cannot release Mutex [%4.4s], not acquired",
acpi_ut_get_node_name(obj_desc->mutex.node)));
@@ -262,14 +266,15 @@
* The Mutex is owned, but this thread must be the owner.
* Special case for Global Lock, any thread can release
*/
- if ((obj_desc->mutex.owner_thread_id !=
+ if ((obj_desc->mutex.owner_thread->thread_id !=
walk_state->thread->thread_id)
&& (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
(unsigned long)walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- (unsigned long)obj_desc->mutex.owner_thread_id));
+ (unsigned long)obj_desc->mutex.owner_thread->
+ thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
@@ -296,7 +301,7 @@
/* Unlink the mutex from the owner's list */
- acpi_ex_unlink_mutex(obj_desc, walk_state->thread);
+ acpi_ex_unlink_mutex(obj_desc);
/* Release the mutex, special case for Global Lock */
@@ -308,7 +313,7 @@
/* Update the mutex and restore sync_level */
- obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
+ obj_desc->mutex.owner_thread = NULL;
walk_state->thread->current_sync_level =
obj_desc->mutex.original_sync_level;
@@ -363,7 +368,7 @@
/* Mark mutex unowned */
- obj_desc->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED;
+ obj_desc->mutex.owner_thread = NULL;
/* Update Thread sync_level (Last mutex is the important one) */
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index 1ee4fb1..308eae5 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -177,8 +177,7 @@
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Bytes from stream:\n"));
- for (index = 0;
- (index < ACPI_NAME_SIZE)
+ for (index = 0; (index < ACPI_NAME_SIZE)
&& (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) {
char_buf[index] = *aml_address++;
ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index]));
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index a669662..efe5d4b 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -242,7 +242,7 @@
obj_desc->common_field.bit_length,
0xFFFFFFFF
/* Temp until we pass region_length as parameter */
- );
+ );
bit_length = byte_alignment * 8;
#endif
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index ba76186..09d897b 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -354,8 +354,7 @@
if ((opcode == AML_STORE_OP) &&
(ACPI_GET_OBJECT_TYPE(*stack_ptr) ==
ACPI_TYPE_LOCAL_REFERENCE)
- && ((*stack_ptr)->reference.opcode ==
- AML_INDEX_OP)) {
+ && ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) {
goto next_operand;
}
break;
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index b2edf62..9460baf 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -66,7 +66,6 @@
acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
@@ -79,7 +78,7 @@
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_wait_semaphore(semaphore, 1, timeout);
@@ -89,13 +88,7 @@
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -119,7 +112,6 @@
acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
{
acpi_status status;
- acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
@@ -132,7 +124,7 @@
/* We must wait, so unlock the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
status = acpi_os_acquire_mutex(mutex, timeout);
@@ -142,13 +134,7 @@
/* Reacquire the interpreter */
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status2)) {
-
- /* Report fatal error, could not acquire interpreter */
-
- return_ACPI_STATUS(status2);
- }
+ acpi_ex_reacquire_interpreter();
}
return_ACPI_STATUS(status);
@@ -209,20 +195,18 @@
acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
{
- acpi_status status;
-
ACPI_FUNCTION_ENTRY();
/* Since this thread will sleep, we must release the interpreter */
- acpi_ex_exit_interpreter();
+ acpi_ex_relinquish_interpreter();
acpi_os_sleep(how_long);
/* And now we must get the interpreter again */
- status = acpi_ex_enter_interpreter();
- return (status);
+ acpi_ex_reacquire_interpreter();
+ return (AE_OK);
}
/*******************************************************************************
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index aea461f..6b0aecc 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -76,14 +76,15 @@
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: Enter the interpreter execution region. Failure to enter
- * the interpreter region is a fatal system error
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ * the interpreter region is a fatal system error. Used in
+ * conjunction with exit_interpreter.
*
******************************************************************************/
-acpi_status acpi_ex_enter_interpreter(void)
+void acpi_ex_enter_interpreter(void)
{
acpi_status status;
@@ -91,10 +92,42 @@
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not acquire AML Interpreter mutex"));
}
- return_ACPI_STATUS(status);
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_reacquire_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Reacquire the interpreter execution region from within the
+ * interpreter code. Failure to enter the interpreter region is a
+ * fatal system error. Used in conjuction with
+ * relinquish_interpreter
+ *
+ ******************************************************************************/
+
+void acpi_ex_reacquire_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter,
+ * since it was not actually released by acpi_ex_relinquish_interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_enter_interpreter();
+ }
+
+ return_VOID;
}
/*******************************************************************************
@@ -105,17 +138,9 @@
*
* RETURN: None
*
- * DESCRIPTION: Exit the interpreter execution region
- *
- * Cases where the interpreter is unlocked:
- * 1) Completion of the execution of a control method
- * 2) Method blocked on a Sleep() AML opcode
- * 3) Method blocked on an Acquire() AML opcode
- * 4) Method blocked on a Wait() AML opcode
- * 5) Method blocked to acquire the global lock
- * 6) Method blocked to execute a serialized control method that is
- * already executing
- * 7) About to invoke a user-installed opregion handler
+ * DESCRIPTION: Exit the interpreter execution region. This is the top level
+ * routine used to exit the interpreter when all processing has
+ * been completed.
*
******************************************************************************/
@@ -127,7 +152,46 @@
status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
+ ACPI_ERROR((AE_INFO,
+ "Could not release AML Interpreter mutex"));
+ }
+
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_relinquish_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Exit the interpreter execution region, from within the
+ * interpreter - before attempting an operation that will possibly
+ * block the running thread.
+ *
+ * Cases where the interpreter is unlocked internally
+ * 1) Method to be blocked on a Sleep() AML opcode
+ * 2) Method to be blocked on an Acquire() AML opcode
+ * 3) Method to be blocked on a Wait() AML opcode
+ * 4) Method to be blocked to acquire the global lock
+ * 5) Method to be blocked waiting to execute a serialized control method
+ * that is currently executing
+ * 6) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void acpi_ex_relinquish_interpreter(void)
+{
+ ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
+
+ /*
+ * If the global serialized flag is set, do not release the interpreter.
+ * This forces the interpreter to be single threaded.
+ */
+ if (!acpi_gbl_all_methods_serialized) {
+ acpi_ex_exit_interpreter();
}
return_VOID;
@@ -141,8 +205,8 @@
*
* RETURN: none
*
- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
- * belongs to a 32-bit ACPI table.
+ * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
+ * 32-bit, as determined by the revision of the DSDT.
*
******************************************************************************/
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index c84b1fa..76c525d 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -152,7 +152,6 @@
ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector)
#endif
-
/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state_prep
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 26fd0dd..97b2ac5 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -75,7 +75,7 @@
* MUTEX: Locks interpreter
*
******************************************************************************/
-acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
+acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info)
{
acpi_status status;
@@ -154,11 +154,7 @@
* Execute the method via the interpreter. The interpreter is locked
* here before calling into the AML parser
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
+ acpi_ex_enter_interpreter();
status = acpi_ps_execute_method(info);
acpi_ex_exit_interpreter();
} else {
@@ -182,10 +178,7 @@
* resolution, we must lock it because we could access an opregion.
* The opregion access code assumes that the interpreter is locked.
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ acpi_ex_enter_interpreter();
/* Function has a strange interface */
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index c4ab615..33db224 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -214,7 +214,7 @@
u32 level, void *context, void **return_value)
{
acpi_object_type type;
- acpi_status status;
+ acpi_status status = AE_OK;
struct acpi_init_walk_info *info =
(struct acpi_init_walk_info *)context;
struct acpi_namespace_node *node =
@@ -268,10 +268,7 @@
/*
* Must lock the interpreter before executing AML code
*/
- status = acpi_ex_enter_interpreter();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
+ acpi_ex_enter_interpreter();
/*
* Each of these types can contain executable AML code within the
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index 94eb8f3..280b835 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -65,10 +65,8 @@
* within Scope is returned.
*
******************************************************************************/
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
- struct acpi_namespace_node
- *parent_node,
- struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
+ *parent_node, struct acpi_namespace_node
*child_node)
{
struct acpi_namespace_node *next_node = NULL;
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index 8904d0f..be4f289 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -48,7 +48,6 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME("nsxfeval")
-
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -73,8 +72,8 @@
acpi_status
acpi_evaluate_object_typed(acpi_handle handle,
acpi_string pathname,
- struct acpi_object_list * external_params,
- struct acpi_buffer * return_buffer,
+ struct acpi_object_list *external_params,
+ struct acpi_buffer *return_buffer,
acpi_object_type return_type)
{
acpi_status status;
@@ -143,7 +142,6 @@
ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed)
#endif /* ACPI_FUTURE_USAGE */
-
/*******************************************************************************
*
* FUNCTION: acpi_evaluate_object
@@ -170,7 +168,6 @@
struct acpi_buffer *return_buffer)
{
acpi_status status;
- acpi_status status2;
struct acpi_evaluate_info *info;
acpi_size buffer_space_needed;
u32 i;
@@ -329,14 +326,12 @@
* Delete the internal return object. NOTE: Interpreter must be
* locked to avoid race condition.
*/
- status2 = acpi_ex_enter_interpreter();
- if (ACPI_SUCCESS(status2)) {
+ acpi_ex_enter_interpreter();
- /* Remove one reference on the return object (should delete it) */
+ /* Remove one reference on the return object (should delete it) */
- acpi_ut_remove_reference(info->return_object);
- acpi_ex_exit_interpreter();
- }
+ acpi_ut_remove_reference(info->return_object);
+ acpi_ex_exit_interpreter();
}
cleanup:
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index c2bed56..b998340 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -71,6 +71,7 @@
static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;
+static struct workqueue_struct *kacpi_notify_wq;
static void __init acpi_request_region (struct acpi_generic_address *addr,
unsigned int length, char *desc)
@@ -137,8 +138,9 @@
return AE_NULL_ENTRY;
}
kacpid_wq = create_singlethread_workqueue("kacpid");
+ kacpi_notify_wq = create_singlethread_workqueue("kacpi_notify");
BUG_ON(!kacpid_wq);
-
+ BUG_ON(!kacpi_notify_wq);
return AE_OK;
}
@@ -150,6 +152,7 @@
}
destroy_workqueue(kacpid_wq);
+ destroy_workqueue(kacpi_notify_wq);
return AE_OK;
}
@@ -603,6 +606,23 @@
static void acpi_os_execute_deferred(struct work_struct *work)
{
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
+ if (!dpc) {
+ printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
+ return;
+ }
+
+ dpc->function(dpc->context);
+ kfree(dpc);
+
+ /* Yield cpu to notify thread */
+ cond_resched();
+
+ return;
+}
+
+static void acpi_os_execute_notify(struct work_struct *work)
+{
+ struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
if (!dpc) {
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
@@ -637,14 +657,12 @@
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
- ACPI_FUNCTION_TRACE("os_queue_for_execution");
-
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n",
function, context));
if (!function)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
/*
* Allocate/initialize DPC structure. Note that this memory will be
@@ -662,14 +680,21 @@
dpc->function = function;
dpc->context = context;
- INIT_WORK(&dpc->work, acpi_os_execute_deferred);
- if (!queue_work(kacpid_wq, &dpc->work)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ if (type == OSL_NOTIFY_HANDLER) {
+ INIT_WORK(&dpc->work, acpi_os_execute_notify);
+ if (!queue_work(kacpi_notify_wq, &dpc->work)) {
+ status = AE_ERROR;
+ kfree(dpc);
+ }
+ } else {
+ INIT_WORK(&dpc->work, acpi_os_execute_deferred);
+ if (!queue_work(kacpid_wq, &dpc->work)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Call to queue_work() failed.\n"));
- kfree(dpc);
- status = AE_ERROR;
+ status = AE_ERROR;
+ kfree(dpc);
+ }
}
-
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 16d8b6c..9296e86 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -185,459 +185,453 @@
/* Index Name Parser Args Interpreter Args ObjectType Class Type Flags */
/* 00 */ ACPI_OP("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, ACPI_TYPE_INTEGER,
- AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+ AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
/* 01 */ ACPI_OP("One", ARGP_ONE_OP, ARGI_ONE_OP, ACPI_TYPE_INTEGER,
- AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+ AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
/* 02 */ ACPI_OP("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP,
- ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_SIMPLE,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_SIMPLE,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 03 */ ACPI_OP("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 04 */ ACPI_OP("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP,
- ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
- AML_TYPE_LITERAL, AML_CONSTANT),
+ ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+ AML_TYPE_LITERAL, AML_CONSTANT),
/* 05 */ ACPI_OP("WordConst", ARGP_WORD_OP, ARGI_WORD_OP,
- ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
- AML_TYPE_LITERAL, AML_CONSTANT),
+ ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+ AML_TYPE_LITERAL, AML_CONSTANT),
/* 06 */ ACPI_OP("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP,
- ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
- AML_TYPE_LITERAL, AML_CONSTANT),
+ ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+ AML_TYPE_LITERAL, AML_CONSTANT),
/* 07 */ ACPI_OP("String", ARGP_STRING_OP, ARGI_STRING_OP,
- ACPI_TYPE_STRING, AML_CLASS_ARGUMENT,
- AML_TYPE_LITERAL, AML_CONSTANT),
+ ACPI_TYPE_STRING, AML_CLASS_ARGUMENT,
+ AML_TYPE_LITERAL, AML_CONSTANT),
/* 08 */ ACPI_OP("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP,
- ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_NO_OBJ,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_NO_OBJ,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 09 */ ACPI_OP("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP,
- ACPI_TYPE_BUFFER, AML_CLASS_CREATE,
- AML_TYPE_CREATE_OBJECT,
- AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
+ ACPI_TYPE_BUFFER, AML_CLASS_CREATE,
+ AML_TYPE_CREATE_OBJECT,
+ AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
/* 0A */ ACPI_OP("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP,
- ACPI_TYPE_PACKAGE, AML_CLASS_CREATE,
- AML_TYPE_CREATE_OBJECT,
- AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
+ ACPI_TYPE_PACKAGE, AML_CLASS_CREATE,
+ AML_TYPE_CREATE_OBJECT,
+ AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
/* 0B */ ACPI_OP("Method", ARGP_METHOD_OP, ARGI_METHOD_OP,
- ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_COMPLEX,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED | AML_DEFER),
+ ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_COMPLEX,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED | AML_DEFER),
/* 0C */ ACPI_OP("Local0", ARGP_LOCAL0, ARGI_LOCAL0,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 0D */ ACPI_OP("Local1", ARGP_LOCAL1, ARGI_LOCAL1,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 0E */ ACPI_OP("Local2", ARGP_LOCAL2, ARGI_LOCAL2,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 0F */ ACPI_OP("Local3", ARGP_LOCAL3, ARGI_LOCAL3,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 10 */ ACPI_OP("Local4", ARGP_LOCAL4, ARGI_LOCAL4,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 11 */ ACPI_OP("Local5", ARGP_LOCAL5, ARGI_LOCAL5,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 12 */ ACPI_OP("Local6", ARGP_LOCAL6, ARGI_LOCAL6,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 13 */ ACPI_OP("Local7", ARGP_LOCAL7, ARGI_LOCAL7,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LOCAL_VARIABLE, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LOCAL_VARIABLE, 0),
/* 14 */ ACPI_OP("Arg0", ARGP_ARG0, ARGI_ARG0,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_METHOD_ARGUMENT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_METHOD_ARGUMENT, 0),
/* 15 */ ACPI_OP("Arg1", ARGP_ARG1, ARGI_ARG1,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_METHOD_ARGUMENT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_METHOD_ARGUMENT, 0),
/* 16 */ ACPI_OP("Arg2", ARGP_ARG2, ARGI_ARG2,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_METHOD_ARGUMENT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_METHOD_ARGUMENT, 0),
/* 17 */ ACPI_OP("Arg3", ARGP_ARG3, ARGI_ARG3,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_METHOD_ARGUMENT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_METHOD_ARGUMENT, 0),
/* 18 */ ACPI_OP("Arg4", ARGP_ARG4, ARGI_ARG4,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_METHOD_ARGUMENT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_METHOD_ARGUMENT, 0),
/* 19 */ ACPI_OP("Arg5", ARGP_ARG5, ARGI_ARG5,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_METHOD_ARGUMENT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_METHOD_ARGUMENT, 0),
/* 1A */ ACPI_OP("Arg6", ARGP_ARG6, ARGI_ARG6,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_METHOD_ARGUMENT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_METHOD_ARGUMENT, 0),
/* 1B */ ACPI_OP("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R),
/* 1C */ ACPI_OP("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
- AML_FLAGS_EXEC_1A_0T_1R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
+ AML_FLAGS_EXEC_1A_0T_1R),
/* 1D */ ACPI_OP("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 1E */ ACPI_OP("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
/* 1F */ ACPI_OP("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 20 */ ACPI_OP("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_1R,
- AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_1R,
+ AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
/* 21 */ ACPI_OP("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_1R,
- AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_1R,
+ AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
/* 22 */ ACPI_OP("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 23 */ ACPI_OP("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_2T_1R,
- AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_2T_1R,
+ AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT),
/* 24 */ ACPI_OP("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 25 */ ACPI_OP("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 26 */ ACPI_OP("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 27 */ ACPI_OP("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 28 */ ACPI_OP("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 29 */ ACPI_OP("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 2A */ ACPI_OP("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
/* 2B */ ACPI_OP("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 2C */ ACPI_OP("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP,
- ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY,
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 2D */ ACPI_OP("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP,
- ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY,
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 2E */ ACPI_OP("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R),
/* 2F */ ACPI_OP("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R),
/* 30 */ ACPI_OP("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_1R,
- AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_1R,
+ AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
/* 31 */ ACPI_OP("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R),
/* 32 */ ACPI_OP("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R,
- AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R,
+ AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT),
/* 33 */ ACPI_OP("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP,
- ARGI_CREATE_DWORD_FIELD_OP,
- ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
- AML_TYPE_CREATE_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
- AML_DEFER | AML_CREATE),
+ ARGI_CREATE_DWORD_FIELD_OP,
+ ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+ AML_TYPE_CREATE_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+ AML_DEFER | AML_CREATE),
/* 34 */ ACPI_OP("CreateWordField", ARGP_CREATE_WORD_FIELD_OP,
- ARGI_CREATE_WORD_FIELD_OP,
- ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
- AML_TYPE_CREATE_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
- AML_DEFER | AML_CREATE),
+ ARGI_CREATE_WORD_FIELD_OP,
+ ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+ AML_TYPE_CREATE_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+ AML_DEFER | AML_CREATE),
/* 35 */ ACPI_OP("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP,
- ARGI_CREATE_BYTE_FIELD_OP,
- ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
- AML_TYPE_CREATE_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
- AML_DEFER | AML_CREATE),
+ ARGI_CREATE_BYTE_FIELD_OP,
+ ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+ AML_TYPE_CREATE_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+ AML_DEFER | AML_CREATE),
/* 36 */ ACPI_OP("CreateBitField", ARGP_CREATE_BIT_FIELD_OP,
- ARGI_CREATE_BIT_FIELD_OP,
- ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
- AML_TYPE_CREATE_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
- AML_DEFER | AML_CREATE),
+ ARGI_CREATE_BIT_FIELD_OP,
+ ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+ AML_TYPE_CREATE_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+ AML_DEFER | AML_CREATE),
/* 37 */ ACPI_OP("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_1R,
- AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_1R,
+ AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
/* 38 */ ACPI_OP("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
- AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC |
- AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+ AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
/* 39 */ ACPI_OP("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
- AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC |
- AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+ AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
/* 3A */ ACPI_OP("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
- AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R,
+ AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
/* 3B */ ACPI_OP("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_0T_1R,
- AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_0T_1R,
+ AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
/* 3C */ ACPI_OP("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_0T_1R,
- AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_0T_1R,
+ AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
/* 3D */ ACPI_OP("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
- AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+ AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
/* 3E */ ACPI_OP("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY,
- AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+ AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
/* 3F */ ACPI_OP("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY,
- AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+ AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
/* 40 */ ACPI_OP("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY,
- AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+ AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
/* 41 */ ACPI_OP("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY,
- AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+ AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
/* 42 */ ACPI_OP("Return", ARGP_RETURN_OP, ARGI_RETURN_OP,
- ACPI_TYPE_ANY, AML_CLASS_CONTROL,
- AML_TYPE_CONTROL, AML_HAS_ARGS),
+ ACPI_TYPE_ANY, AML_CLASS_CONTROL,
+ AML_TYPE_CONTROL, AML_HAS_ARGS),
/* 43 */ ACPI_OP("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY,
- AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+ AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
/* 44 */ ACPI_OP("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP,
- ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+ ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
/* 45 */ ACPI_OP("Ones", ARGP_ONES_OP, ARGI_ONES_OP, ACPI_TYPE_INTEGER,
- AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+ AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
/* Prefixed opcodes (Two-byte opcodes with a prefix op) */
/* 46 */ ACPI_OP("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 47 */ ACPI_OP("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
- AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+ AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
/* 48 */ ACPI_OP("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
/* 49 */ ACPI_OP("CreateField", ARGP_CREATE_FIELD_OP,
- ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD,
- AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
- AML_DEFER | AML_FIELD | AML_CREATE),
+ ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD,
+ AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+ AML_DEFER | AML_FIELD | AML_CREATE),
/* 4A */ ACPI_OP("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R,
- AML_FLAGS_EXEC_1A_1T_0R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R,
+ AML_FLAGS_EXEC_1A_1T_0R),
/* 4B */ ACPI_OP("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
- AML_FLAGS_EXEC_1A_0T_0R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
+ AML_FLAGS_EXEC_1A_0T_0R),
/* 4C */ ACPI_OP("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
- AML_FLAGS_EXEC_1A_0T_0R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
+ AML_FLAGS_EXEC_1A_0T_0R),
/* 4D */ ACPI_OP("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R),
/* 4E */ ACPI_OP("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
/* 4F */ ACPI_OP("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
- AML_FLAGS_EXEC_2A_0T_1R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R,
+ AML_FLAGS_EXEC_2A_0T_1R),
/* 50 */ ACPI_OP("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
- AML_FLAGS_EXEC_1A_0T_0R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R,
+ AML_FLAGS_EXEC_1A_0T_0R),
/* 51 */ ACPI_OP("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
/* 52 */ ACPI_OP("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 53 */ ACPI_OP("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 54 */ ACPI_OP("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
/* 55 */ ACPI_OP("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP,
- ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
- AML_TYPE_CONSTANT, 0),
+ ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+ AML_TYPE_CONSTANT, 0),
/* 56 */ ACPI_OP("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_CONSTANT, 0),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_CONSTANT, 0),
/* 57 */ ACPI_OP("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R,
- AML_FLAGS_EXEC_3A_0T_0R),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R,
+ AML_FLAGS_EXEC_3A_0T_0R),
/* 58 */ ACPI_OP("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP,
- ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_COMPLEX,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED | AML_DEFER),
+ ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_COMPLEX,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED | AML_DEFER),
/* 59 */ ACPI_OP("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_FIELD),
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
/* 5A */ ACPI_OP("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP,
- ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_NO_OBJ,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_NO_OBJ,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 5B */ ACPI_OP("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP,
- ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_SIMPLE,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_SIMPLE,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 5C */ ACPI_OP("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP,
- ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_SIMPLE,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_SIMPLE,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 5D */ ACPI_OP("ThermalZone", ARGP_THERMAL_ZONE_OP,
- ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL,
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 5E */ ACPI_OP("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP,
- ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_FIELD),
+ ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
/* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP,
- ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_FIELD),
+ ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
/* Internal opcodes that map to invalid AML opcodes */
/* 60 */ ACPI_OP("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP,
- ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
- AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
+ AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
/* 61 */ ACPI_OP("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP,
- ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
- AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
+ AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
/* 62 */ ACPI_OP("LGreaterEqual", ARGP_LGREATEREQUAL_OP,
- ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY,
- AML_CLASS_INTERNAL, AML_TYPE_BOGUS,
- AML_HAS_ARGS | AML_CONSTANT),
+ ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY,
+ AML_CLASS_INTERNAL, AML_TYPE_BOGUS,
+ AML_HAS_ARGS | AML_CONSTANT),
/* 63 */ ACPI_OP("-NamePath-", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP,
- ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
- AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE),
+ ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT,
+ AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE),
/* 64 */ ACPI_OP("-MethodCall-", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP,
- ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL,
- AML_TYPE_METHOD_CALL,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE),
+ ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL,
+ AML_TYPE_METHOD_CALL,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE),
/* 65 */ ACPI_OP("-ByteList-", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP,
- ACPI_TYPE_ANY, AML_CLASS_ARGUMENT,
- AML_TYPE_LITERAL, 0),
+ ACPI_TYPE_ANY, AML_CLASS_ARGUMENT,
+ AML_TYPE_LITERAL, 0),
/* 66 */ ACPI_OP("-ReservedField-", ARGP_RESERVEDFIELD_OP,
- ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY,
- AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+ ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY,
+ AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
/* 67 */ ACPI_OP("-NamedField-", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP,
- ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
- AML_TYPE_BOGUS,
- AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+ ACPI_TYPE_ANY, AML_CLASS_INTERNAL,
+ AML_TYPE_BOGUS,
+ AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
/* 68 */ ACPI_OP("-AccessField-", ARGP_ACCESSFIELD_OP,
- ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY,
- AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+ ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY,
+ AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
/* 69 */ ACPI_OP("-StaticString", ARGP_STATICSTRING_OP,
- ARGI_STATICSTRING_OP, ACPI_TYPE_ANY,
- AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+ ARGI_STATICSTRING_OP, ACPI_TYPE_ANY,
+ AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
/* 6A */ ACPI_OP("-Return Value-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY,
- AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN,
- AML_HAS_ARGS | AML_HAS_RETVAL),
+ AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN,
+ AML_HAS_ARGS | AML_HAS_RETVAL),
/* 6B */ ACPI_OP("-UNKNOWN_OP-", ARG_NONE, ARG_NONE, ACPI_TYPE_INVALID,
- AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS),
+ AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS),
/* 6C */ ACPI_OP("-ASCII_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY,
- AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS),
+ AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS),
/* 6D */ ACPI_OP("-PREFIX_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY,
- AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS),
+ AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS),
/* ACPI 2.0 opcodes */
/* 6E */ ACPI_OP("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP,
- ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
- AML_TYPE_LITERAL, AML_CONSTANT),
+ ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT,
+ AML_TYPE_LITERAL, AML_CONSTANT),
/* 6F */ ACPI_OP("Package", /* Var */ ARGP_VAR_PACKAGE_OP,
ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE,
AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT,
AML_HAS_ARGS | AML_DEFER),
/* 70 */ ACPI_OP("ConcatenateResTemplate", ARGP_CONCAT_RES_OP,
- ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+ ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY,
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
/* 71 */ ACPI_OP("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
/* 72 */ ACPI_OP("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP,
- ARGI_CREATE_QWORD_FIELD_OP,
- ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
- AML_TYPE_CREATE_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
- AML_DEFER | AML_CREATE),
+ ARGI_CREATE_QWORD_FIELD_OP,
+ ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE,
+ AML_TYPE_CREATE_FIELD,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE |
+ AML_DEFER | AML_CREATE),
/* 73 */ ACPI_OP("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 74 */ ACPI_OP("ToDecimalString", ARGP_TO_DEC_STR_OP,
- ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY,
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 75 */ ACPI_OP("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 76 */ ACPI_OP("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_1T_1R,
- AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_1T_1R,
+ AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
/* 77 */ ACPI_OP("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_2A_1T_1R,
- AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_2A_1T_1R,
+ AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
/* 78 */ ACPI_OP("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
/* 79 */ ACPI_OP("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R,
- AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT),
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R,
+ AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT),
/* 7A */ ACPI_OP("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP,
- ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+ ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
/* 7B */ ACPI_OP("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP,
- ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
- AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
+ ACPI_TYPE_ANY, AML_CLASS_EXECUTE,
+ AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
/* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP,
- ARGI_DATA_REGION_OP, ACPI_TYPE_REGION,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ ARGI_DATA_REGION_OP, ACPI_TYPE_REGION,
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
+ AML_NSNODE | AML_NAMED),
/* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP,
- ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
- AML_TYPE_NAMED_NO_OBJ,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE),
+ ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+ AML_TYPE_NAMED_NO_OBJ,
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE),
/* ACPI 3.0 opcodes */
/* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY,
- AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R,
- AML_FLAGS_EXEC_0A_0T_1R)
+ AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R,
+ AML_FLAGS_EXEC_0A_0T_1R)
/*! [End] no source code translation !*/
};
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index 8c6d3fd..0dd2ce8 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -567,7 +567,8 @@
(*sub_object_list)->string.
length + 1);
} else {
- temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
+ temp_size_needed +=
+ acpi_ns_get_pathname_length((*sub_object_list)->reference.node);
}
} else {
/*
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index cc48ab0..50da494 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -267,16 +267,19 @@
* If BIOS erroneously reversed the _PRT source_name and source_index,
* then reverse them back.
*/
- if (ACPI_GET_OBJECT_TYPE (sub_object_list[3]) != ACPI_TYPE_INTEGER) {
+ if (ACPI_GET_OBJECT_TYPE(sub_object_list[3]) !=
+ ACPI_TYPE_INTEGER) {
if (acpi_gbl_enable_interpreter_slack) {
source_name_index = 3;
source_index_index = 2;
- printk(KERN_WARNING "ACPI: Handling Garbled _PRT entry\n");
+ printk(KERN_WARNING
+ "ACPI: Handling Garbled _PRT entry\n");
} else {
ACPI_ERROR((AE_INFO,
- "(PRT[%X].source_index) Need Integer, found %s",
- index,
- acpi_ut_get_object_type_name(sub_object_list[3])));
+ "(PRT[%X].source_index) Need Integer, found %s",
+ index,
+ acpi_ut_get_object_type_name
+ (sub_object_list[3])));
return_ACPI_STATUS(AE_BAD_DATA);
}
}
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index de20a5d..46da116 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -46,7 +46,6 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsdump")
-
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/* Local prototypes */
static void acpi_rs_out_string(char *title, char *value);
@@ -489,10 +488,9 @@
/*
* Optional resource_source for Address resources
*/
- acpi_rs_dump_resource_source(ACPI_CAST_PTR
- (struct
- acpi_resource_source,
- target));
+ acpi_rs_dump_resource_source(ACPI_CAST_PTR(struct
+ acpi_resource_source,
+ target));
break;
default:
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 7e3c335..2c2adb6 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -142,7 +142,7 @@
};
#endif
-#endif /* ACPI_FUTURE_USAGE */
+#endif /* ACPI_FUTURE_USAGE */
/*
* Base sizes for external AML resource descriptors, indexed by internal type.
* Includes size of the descriptor header (1 byte for small descriptors,
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index a92755c..ca21e46 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -153,10 +153,9 @@
/* Perform the conversion */
- status = acpi_rs_convert_resource_to_aml(resource,
- ACPI_CAST_PTR(union
- aml_resource,
- aml),
+ status = acpi_rs_convert_resource_to_aml(resource, ACPI_CAST_PTR(union
+ aml_resource,
+ aml),
acpi_gbl_set_resource_dispatch
[resource->type]);
if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index 3b63b56..c7081af 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -46,7 +46,6 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME("rsmisc")
-
#define INIT_RESOURCE_TYPE(i) i->resource_offset
#define INIT_RESOURCE_LENGTH(i) i->aml_offset
#define INIT_TABLE_LENGTH(i) i->value
@@ -429,8 +428,7 @@
* Optional resource_source (Index and String)
*/
aml_length =
- acpi_rs_set_resource_source(aml,
- (acpi_rs_length)
+ acpi_rs_set_resource_source(aml, (acpi_rs_length)
aml_length, source);
acpi_rs_set_resource_length(aml_length, aml);
break;
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index 2442a8f..11c0bd7 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -353,10 +353,8 @@
*
* Zero the entire area of the buffer.
*/
- total_length =
- (u32)
- ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) +
- 1;
+ total_length = (u32)
+ ACPI_STRLEN(ACPI_CAST_PTR(char, &aml_resource_source[1])) + 1;
total_length = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(total_length);
ACPI_MEMSET(resource_source->string_ptr, 0, total_length);
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 991f890..f63813a 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -217,7 +217,6 @@
}
ACPI_EXPORT_SYMBOL(acpi_get_current_resources)
-
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -261,7 +260,6 @@
ACPI_EXPORT_SYMBOL(acpi_get_possible_resources)
#endif /* ACPI_FUTURE_USAGE */
-
/*******************************************************************************
*
* FUNCTION: acpi_set_current_resources
@@ -496,7 +494,6 @@
* each resource in the list.
*
******************************************************************************/
-
acpi_status
acpi_walk_resources(acpi_handle device_handle,
char *name,
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 52b2347..bc7e16e 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -222,7 +222,7 @@
.enter = acpi_hibernation_enter,
.finish = acpi_hibernation_finish,
};
-#endif /* CONFIG_SOFTWARE_SUSPEND */
+#endif /* CONFIG_SOFTWARE_SUSPEND */
/*
* Toshiba fails to preserve interrupts over S1, reinitialization
@@ -276,4 +276,3 @@
return 0;
}
-
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 76b45f0..61f1822 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -349,8 +349,7 @@
end:
return_VALUE(result ? result : count);
}
-#endif /* HAVE_ACPI_LEGACY_ALARM */
-
+#endif /* HAVE_ACPI_LEGACY_ALARM */
extern struct list_head acpi_wakeup_device_list;
extern spinlock_t acpi_device_lock;
@@ -380,8 +379,8 @@
dev->wakeup.state.enabled ? "enabled" : "disabled");
if (ldev)
seq_printf(seq, "%s:%s",
- ldev->bus ? ldev->bus->name : "no-bus",
- ldev->bus_id);
+ ldev->bus ? ldev->bus->name : "no-bus",
+ ldev->bus_id);
seq_printf(seq, "\n");
put_device(ldev);
@@ -490,7 +489,7 @@
return ACPI_INTERRUPT_HANDLED;
}
-#endif /* HAVE_ACPI_LEGACY_ALARM */
+#endif /* HAVE_ACPI_LEGACY_ALARM */
static int __init acpi_sleep_proc_init(void)
{
@@ -517,7 +516,7 @@
entry->proc_fops = &acpi_system_alarm_fops;
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
-#endif /* HAVE_ACPI_LEGACY_ALARM */
+#endif /* HAVE_ACPI_LEGACY_ALARM */
/* 'wakeup device' [R/W] */
entry =
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 1db833e..1285e91 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -334,7 +334,8 @@
(acpi_gbl_FADT.xpm1a_event_block.address +
pm1_register_length));
/* Don't forget to copy space_id of the GAS */
- acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+ acpi_gbl_xpm1a_enable.space_id =
+ acpi_gbl_FADT.xpm1a_event_block.space_id;
/* The PM1B register block is optional, ignore if not present */
@@ -344,7 +345,8 @@
(acpi_gbl_FADT.xpm1b_event_block.
address + pm1_register_length));
/* Don't forget to copy space_id of the GAS */
- acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+ acpi_gbl_xpm1b_enable.space_id =
+ acpi_gbl_FADT.xpm1a_event_block.space_id;
}
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 417ef5f..5b302c4 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -201,6 +201,7 @@
return_ACPI_STATUS(AE_OK);
}
+
/*******************************************************************************
*
* FUNCTION: acpi_load_table
@@ -262,7 +263,7 @@
acpi_status
acpi_get_table_header(char *signature,
acpi_native_uint instance,
- struct acpi_table_header *out_table_header)
+ struct acpi_table_header * out_table_header)
{
acpi_native_uint i;
acpi_native_uint j;
@@ -321,7 +322,6 @@
ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-
/******************************************************************************
*
* FUNCTION: acpi_unload_table_id
@@ -346,11 +346,11 @@
continue;
}
/*
- * Delete all namespace objects owned by this table. Note that these
- * objects can appear anywhere in the namespace by virtue of the AML
- * "Scope" operator. Thus, we need to track ownership by an ID, not
- * simply a position within the hierarchy
- */
+ * Delete all namespace objects owned by this table. Note that these
+ * objects can appear anywhere in the namespace by virtue of the AML
+ * "Scope" operator. Thus, we need to track ownership by an ID, not
+ * simply a position within the hierarchy
+ */
acpi_tb_delete_namespace_by_owner(i);
status = acpi_tb_release_owner_id(i);
acpi_tb_set_table_loaded_flag(i, FALSE);
@@ -376,7 +376,7 @@
*****************************************************************************/
acpi_status
acpi_get_table(char *signature,
- acpi_native_uint instance, struct acpi_table_header ** out_table)
+ acpi_native_uint instance, struct acpi_table_header **out_table)
{
acpi_native_uint i;
acpi_native_uint j;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 589b98b..1ada017 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -59,8 +59,6 @@
#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
#define ACPI_THERMAL_NOTIFY_HOT 0xF1
#define ACPI_THERMAL_MODE_ACTIVE 0x00
-#define ACPI_THERMAL_MODE_PASSIVE 0x01
-#define ACPI_THERMAL_MODE_CRITICAL 0xff
#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
#define ACPI_THERMAL_MAX_ACTIVE 10
@@ -86,9 +84,6 @@
static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
-static ssize_t acpi_thermal_write_trip_points(struct file *,
- const char __user *, size_t,
- loff_t *);
static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
static ssize_t acpi_thermal_write_cooling_mode(struct file *,
const char __user *, size_t,
@@ -167,7 +162,6 @@
unsigned long temperature;
unsigned long last_temperature;
unsigned long polling_frequency;
- u8 cooling_mode;
volatile u8 zombie;
struct acpi_thermal_flags flags;
struct acpi_thermal_state state;
@@ -193,7 +187,6 @@
static const struct file_operations acpi_thermal_trip_fops = {
.open = acpi_thermal_trip_open_fs,
.read = seq_read,
- .write = acpi_thermal_write_trip_points,
.llseek = seq_lseek,
.release = single_release,
};
@@ -297,11 +290,6 @@
if (ACPI_FAILURE(status))
return -ENODEV;
- tz->cooling_mode = mode;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n",
- mode ? "passive" : "active"));
-
return 0;
}
@@ -889,67 +877,6 @@
return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
}
-static ssize_t
-acpi_thermal_write_trip_points(struct file *file,
- const char __user * buffer,
- size_t count, loff_t * ppos)
-{
- struct seq_file *m = file->private_data;
- struct acpi_thermal *tz = m->private;
-
- char *limit_string;
- int num, critical, hot, passive;
- int *active;
- int i = 0;
-
-
- limit_string = kzalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
- if (!limit_string)
- return -ENOMEM;
-
- active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
- if (!active) {
- kfree(limit_string);
- return -ENOMEM;
- }
-
- if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
- count = -EINVAL;
- goto end;
- }
-
- if (copy_from_user(limit_string, buffer, count)) {
- count = -EFAULT;
- goto end;
- }
-
- limit_string[count] = '\0';
-
- num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
- &critical, &hot, &passive,
- &active[0], &active[1], &active[2], &active[3], &active[4],
- &active[5], &active[6], &active[7], &active[8],
- &active[9]);
- if (!(num >= 5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
- count = -EINVAL;
- goto end;
- }
-
- tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
- tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
- tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
- for (i = 0; i < num - 3; i++) {
- if (!(tz->trips.active[i].flags.valid))
- break;
- tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]);
- }
-
- end:
- kfree(active);
- kfree(limit_string);
- return count;
-}
-
static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_thermal *tz = seq->private;
@@ -958,15 +885,10 @@
if (!tz)
goto end;
- if (!tz->flags.cooling_mode) {
+ if (!tz->flags.cooling_mode)
seq_puts(seq, "<setting not supported>\n");
- }
-
- if (tz->cooling_mode == ACPI_THERMAL_MODE_CRITICAL)
- seq_printf(seq, "cooling mode: critical\n");
else
- seq_printf(seq, "cooling mode: %s\n",
- tz->cooling_mode ? "passive" : "active");
+ seq_puts(seq, "0 - Active; 1 - Passive\n");
end:
return 0;
@@ -1223,28 +1145,6 @@
result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
if (!result)
tz->flags.cooling_mode = 1;
- else {
- /* Oh,we have not _SCP method.
- Generally show cooling_mode by _ACx, _PSV,spec 12.2 */
- tz->flags.cooling_mode = 0;
- if (tz->trips.active[0].flags.valid
- && tz->trips.passive.flags.valid) {
- if (tz->trips.passive.temperature >
- tz->trips.active[0].temperature)
- tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
- else
- tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
- } else if (!tz->trips.active[0].flags.valid
- && tz->trips.passive.flags.valid) {
- tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
- } else if (tz->trips.active[0].flags.valid
- && !tz->trips.passive.flags.valid) {
- tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
- } else {
- /* _ACx and _PSV are optional, but _CRT is required */
- tz->cooling_mode = ACPI_THERMAL_MODE_CRITICAL;
- }
- }
/* Get default polling frequency [_TZP] (optional) */
if (tzp)
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 55a7648..6e56d5f 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -107,7 +107,6 @@
if (ACPI_FAILURE(status)) {
return (status);
}
-
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
/* Memory allocation lists */
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 870f6ed..285a0f5 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -45,7 +45,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utcache")
-
#ifdef ACPI_USE_LOCAL_CACHE
/*******************************************************************************
*
@@ -64,7 +63,7 @@
acpi_status
acpi_os_create_cache(char *cache_name,
u16 object_size,
- u16 max_depth, struct acpi_memory_list **return_cache)
+ u16 max_depth, struct acpi_memory_list ** return_cache)
{
struct acpi_memory_list *cache;
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 84d529db..4c1e008 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -814,7 +814,9 @@
/*
* Create the object array
*/
- target_object->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package.count + 1) * sizeof(void *));
+ target_object->package.elements =
+ ACPI_ALLOCATE_ZEROED(((acpi_size) source_object->package.
+ count + 1) * sizeof(void *));
if (!target_object->package.elements) {
status = AE_NO_MEMORY;
goto error_exit;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 61ad4f2d..c7e128e 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -45,7 +45,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utdebug")
-
#ifdef ACPI_DEBUG_OUTPUT
static acpi_thread_id acpi_gbl_prev_thread_id;
static char *acpi_gbl_fn_entry_str = "----Entry";
@@ -181,7 +180,8 @@
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
- (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id);
+ (unsigned long)acpi_gbl_prev_thread_id,
+ (unsigned long)thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 673a0ca..f777ceb 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -170,6 +170,7 @@
acpi_os_delete_mutex(object->mutex.os_mutex);
acpi_gbl_global_lock_mutex = NULL;
} else {
+ acpi_ex_unlink_mutex(object);
acpi_os_delete_mutex(object->mutex.os_mutex);
}
break;
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index af33358..1621655 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -55,12 +55,10 @@
* Static global variable initialization.
*
******************************************************************************/
-
/*
* We want the debug switches statically initialized so they
* are already set when the debugger is entered.
*/
-
/* Debug switch - level and trace mask */
u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
@@ -735,5 +733,5 @@
}
ACPI_EXPORT_SYMBOL(acpi_dbg_level)
-ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
-ACPI_EXPORT_SYMBOL(acpi_gpe_count)
+ ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ ACPI_EXPORT_SYMBOL(acpi_gpe_count)
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 50133ff..2d19f71 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -802,9 +802,8 @@
valid_digits++;
- if (sign_of0x
- && ((valid_digits > 16)
- || ((valid_digits > 8) && mode32))) {
+ if (sign_of0x && ((valid_digits > 16)
+ || ((valid_digits > 8) && mode32))) {
/*
* This is to_integer operation case.
* No any restrictions for string-to-integer conversion,
@@ -1049,6 +1048,7 @@
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
}
+
EXPORT_SYMBOL(acpi_ut_exception);
void ACPI_INTERNAL_VAR_XFACE
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index cbad2ef..4820bc8 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -244,7 +244,7 @@
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %lX attempting to acquire Mutex [%s]\n",
- (unsigned long) this_thread_id,
+ (unsigned long)this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
@@ -252,7 +252,7 @@
if (ACPI_SUCCESS(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %lX acquired Mutex [%s]\n",
- (unsigned long) this_thread_id,
+ (unsigned long)this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
acpi_gbl_mutex_info[mutex_id].use_count++;
@@ -260,7 +260,7 @@
} else {
ACPI_EXCEPTION((AE_INFO, status,
"Thread %lX could not acquire Mutex [%X]",
- (unsigned long) this_thread_id, mutex_id));
+ (unsigned long)this_thread_id, mutex_id));
}
return (status);
@@ -287,7 +287,7 @@
this_thread_id = acpi_os_get_thread_id();
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %lX releasing Mutex [%s]\n",
- (unsigned long) this_thread_id,
+ (unsigned long)this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
if (mutex_id > ACPI_MAX_MUTEX) {
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index e8fe1ba..cbbd331 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -46,7 +46,6 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utresrc")
-
#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
/*
* Strings used to decode resource descriptors.
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index de3276f..e9a5780 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -337,7 +337,6 @@
}
ACPI_EXPORT_SYMBOL(acpi_terminate)
-
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -470,7 +469,6 @@
ACPI_EXPORT_SYMBOL(acpi_install_initialization_handler)
#endif /* ACPI_FUTURE_USAGE */
-
/*****************************************************************************
*
* FUNCTION: acpi_purge_cached_objects
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index c721966..f031b87 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -3,6 +3,7 @@
#
menu "Serial ATA (prod) and Parallel ATA (experimental) drivers"
+ depends on HAS_IOMEM
config ATA
tristate "ATA device support"
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index 0300e7f5..2e18a63e 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -6,6 +6,7 @@
#
menu "Auxiliary Display support"
+ depends on PARPORT
config KS0108
tristate "KS0108 LCD Controller"
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 17ee97f..b4c8319 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -444,8 +444,6 @@
this option is dangerous unless the CD-RW media is known good, as we
don't do deferred write error handling yet.
-source "drivers/s390/block/Kconfig"
-
config ATA_OVER_ETH
tristate "ATA over Ethernet support"
depends on NET
@@ -453,6 +451,8 @@
This driver provides Support for ATA over Ethernet block
devices like the Coraid EtherDrive (R) Storage Blade.
+source "drivers/s390/block/Kconfig"
+
endmenu
endif
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 0f4203b..6055b9c 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -307,7 +307,9 @@
if (hu) {
struct hci_dev *hdev = hu->hdev;
- hci_uart_close(hdev);
+
+ if (hdev)
+ hci_uart_close(hdev);
if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
hu->proto->close(hu);
@@ -473,12 +475,18 @@
tty->low_latency = 1;
} else
return -EBUSY;
+ break;
case HCIUARTGETPROTO:
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
return hu->proto->id;
return -EUNATCH;
+ case HCIUARTGETDEVICE:
+ if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
+ return hu->hdev->id;
+ return -EUNATCH;
+
default:
err = n_tty_ioctl(tty, file, cmd, arg);
break;
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index b250e67..1097ce7 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -28,8 +28,9 @@
#endif
/* Ioctls */
-#define HCIUARTSETPROTO _IOW('U', 200, int)
-#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTSETPROTO _IOW('U', 200, int)
+#define HCIUARTGETPROTO _IOR('U', 201, int)
+#define HCIUARTGETDEVICE _IOR('U', 202, int)
/* UART protocols */
#define HCI_UART_MAX_PROTO 4
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 2df42fd..abcafac 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -6,6 +6,7 @@
config VT
bool "Virtual terminal" if EMBEDDED
+ depends on !S390
select INPUT
default y if !VIOCONS
---help---
@@ -81,6 +82,7 @@
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
+ depends on HAS_IOMEM
---help---
Say Y here if you have any non-standard serial boards -- boards
which aren't supported using the standard "dumb" serial driver.
@@ -765,7 +767,7 @@
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH
+ depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -813,7 +815,7 @@
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -858,6 +860,7 @@
config DTLK
tristate "Double Talk PC internal speech card support"
+ depends on ISA
help
This driver is for the DoubleTalk PC, a speech synthesizer
manufactured by RC Systems (<http://www.rcsys.com/>). It is also
@@ -1043,7 +1046,7 @@
config HANGCHECK_TIMER
tristate "Hangcheck timer"
- depends on X86 || IA64 || PPC64
+ depends on X86 || IA64 || PPC64 || S390
help
The hangcheck-timer module detects when the system has gone
out to lunch past a certain margin. It can reboot the system
@@ -1078,5 +1081,7 @@
depends on ISA || PCI
default y
+source "drivers/s390/char/Kconfig"
+
endmenu
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index c9f0f25..801abdd 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -268,7 +268,7 @@
printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20);
return 0;
}
- if (aper + size > 0xffffffff) {
+ if ((u64)aper + size > 0x100000000ULL) {
printk(KERN_ERR PFX "Aperture out of bounds\n");
return 0;
}
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index a6dcb29..b894f67 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -3,6 +3,8 @@
#
menu "IPMI"
+ depends on HAS_IOMEM
+
config IPMI_HANDLER
tristate 'IPMI top-level message handler'
help
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 6ac3ca4..b3d4ccc 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1544,21 +1544,18 @@
}
struct tty_ldisc tty_ldisc_N_TTY = {
- TTY_LDISC_MAGIC, /* magic */
- "n_tty", /* name */
- 0, /* num */
- 0, /* flags */
- n_tty_open, /* open */
- n_tty_close, /* close */
- n_tty_flush_buffer, /* flush_buffer */
- n_tty_chars_in_buffer, /* chars_in_buffer */
- read_chan, /* read */
- write_chan, /* write */
- n_tty_ioctl, /* ioctl */
- n_tty_set_termios, /* set_termios */
- normal_poll, /* poll */
- NULL, /* hangup */
- n_tty_receive_buf, /* receive_buf */
- n_tty_write_wakeup /* write_wakeup */
+ .magic = TTY_LDISC_MAGIC,
+ .name = "n_tty",
+ .open = n_tty_open,
+ .close = n_tty_close,
+ .flush_buffer = n_tty_flush_buffer,
+ .chars_in_buffer = n_tty_chars_in_buffer,
+ .read = read_chan,
+ .write = write_chan,
+ .ioctl = n_tty_ioctl,
+ .set_termios = n_tty_set_termios,
+ .poll = normal_poll,
+ .receive_buf = n_tty_receive_buf,
+ .write_wakeup = n_tty_write_wakeup
};
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 245f031..8cc60b6 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -402,7 +402,7 @@
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name);
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup);
- if (Rup >= (unsigned short) MAX_RUP) {
+ if (Rup < (unsigned short) MAX_RUP) {
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name);
} else
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name);
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 61a63da..a3fd7e7 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1014,9 +1014,6 @@
/*
* Info->count is now 1; so it's safe to sleep now.
*/
- info->session = process_session(current);
- info->pgrp = process_group(current);
-
if ((info->flags & ROCKET_INITIALIZED) == 0) {
cp = &info->channel;
sSetRxTrigger(cp, TRIG_1);
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 89b4d7b..b4c53df 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -1158,8 +1158,6 @@
int xmit_head;
int xmit_tail;
int xmit_cnt;
- int session;
- int pgrp;
int cd_status;
int ignore_status_mask;
int read_status_mask;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2a7736b..02b49bc 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1171,6 +1171,112 @@
}
/*
+ * support for 32 bit ioctl calls on 64 bit systems
+ */
+#ifdef CONFIG_COMPAT
+static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params)
+{
+ struct MGSL_PARAMS32 tmp_params;
+
+ DBGINFO(("%s get_params32\n", info->device_name));
+ tmp_params.mode = (compat_ulong_t)info->params.mode;
+ tmp_params.loopback = info->params.loopback;
+ tmp_params.flags = info->params.flags;
+ tmp_params.encoding = info->params.encoding;
+ tmp_params.clock_speed = (compat_ulong_t)info->params.clock_speed;
+ tmp_params.addr_filter = info->params.addr_filter;
+ tmp_params.crc_type = info->params.crc_type;
+ tmp_params.preamble_length = info->params.preamble_length;
+ tmp_params.preamble = info->params.preamble;
+ tmp_params.data_rate = (compat_ulong_t)info->params.data_rate;
+ tmp_params.data_bits = info->params.data_bits;
+ tmp_params.stop_bits = info->params.stop_bits;
+ tmp_params.parity = info->params.parity;
+ if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32)))
+ return -EFAULT;
+ return 0;
+}
+
+static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params)
+{
+ struct MGSL_PARAMS32 tmp_params;
+
+ DBGINFO(("%s set_params32\n", info->device_name));
+ if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32)))
+ return -EFAULT;
+
+ spin_lock(&info->lock);
+ info->params.mode = tmp_params.mode;
+ info->params.loopback = tmp_params.loopback;
+ info->params.flags = tmp_params.flags;
+ info->params.encoding = tmp_params.encoding;
+ info->params.clock_speed = tmp_params.clock_speed;
+ info->params.addr_filter = tmp_params.addr_filter;
+ info->params.crc_type = tmp_params.crc_type;
+ info->params.preamble_length = tmp_params.preamble_length;
+ info->params.preamble = tmp_params.preamble;
+ info->params.data_rate = tmp_params.data_rate;
+ info->params.data_bits = tmp_params.data_bits;
+ info->params.stop_bits = tmp_params.stop_bits;
+ info->params.parity = tmp_params.parity;
+ spin_unlock(&info->lock);
+
+ change_params(info);
+
+ return 0;
+}
+
+static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct slgt_info *info = tty->driver_data;
+ int rc = -ENOIOCTLCMD;
+
+ if (sanity_check(info, tty->name, "compat_ioctl"))
+ return -ENODEV;
+ DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
+
+ switch (cmd) {
+
+ case MGSL_IOCSPARAMS32:
+ rc = set_params32(info, compat_ptr(arg));
+ break;
+
+ case MGSL_IOCGPARAMS32:
+ rc = get_params32(info, compat_ptr(arg));
+ break;
+
+ case MGSL_IOCGPARAMS:
+ case MGSL_IOCSPARAMS:
+ case MGSL_IOCGTXIDLE:
+ case MGSL_IOCGSTATS:
+ case MGSL_IOCWAITEVENT:
+ case MGSL_IOCGIF:
+ case MGSL_IOCSGPIO:
+ case MGSL_IOCGGPIO:
+ case MGSL_IOCWAITGPIO:
+ case TIOCGICOUNT:
+ rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
+ break;
+
+ case MGSL_IOCSTXIDLE:
+ case MGSL_IOCTXENABLE:
+ case MGSL_IOCRXENABLE:
+ case MGSL_IOCTXABORT:
+ case TIOCMIWAIT:
+ case MGSL_IOCSIF:
+ rc = ioctl(tty, file, cmd, arg);
+ break;
+ }
+
+ DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
+ return rc;
+}
+#else
+#define slgt_compat_ioctl NULL
+#endif /* ifdef CONFIG_COMPAT */
+
+/*
* proc fs support
*/
static inline int line_info(char *buf, struct slgt_info *info)
@@ -3446,6 +3552,7 @@
.chars_in_buffer = chars_in_buffer,
.flush_buffer = flush_buffer,
.ioctl = ioctl,
+ .compat_ioctl = slgt_compat_ioctl,
.throttle = throttle,
.unthrottle = unthrottle,
.send_xchar = send_xchar,
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 11089be..dc4e1ff 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -3,6 +3,7 @@
#
menu "TPM devices"
+ depends on HAS_IOMEM
config TCG_TPM
tristate "TPM Hardware Support"
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index fc662e4..fe62c21 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -151,6 +151,12 @@
static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+ unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
static int tty_fasync(int fd, struct file * filp, int on);
static void release_tty(struct tty_struct *tty, int idx);
static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
@@ -1143,8 +1149,8 @@
return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
}
-static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file * file,
+ unsigned int cmd, unsigned long arg)
{
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
@@ -1155,6 +1161,7 @@
.write = tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
+ .compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
@@ -1167,6 +1174,7 @@
.write = tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
+ .compat_ioctl = tty_compat_ioctl,
.open = ptmx_open,
.release = tty_release,
.fasync = tty_fasync,
@@ -1179,6 +1187,7 @@
.write = redirected_tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
+ .compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
@@ -1189,7 +1198,8 @@
.read = hung_up_tty_read,
.write = hung_up_tty_write,
.poll = hung_up_tty_poll,
- .ioctl = hung_up_tty_ioctl,
+ .unlocked_ioctl = hung_up_tty_ioctl,
+ .compat_ioctl = hung_up_tty_ioctl,
.release = tty_release,
};
@@ -3357,6 +3367,32 @@
return retval;
}
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct tty_struct *tty = file->private_data;
+ struct tty_ldisc *ld;
+ int retval = -ENOIOCTLCMD;
+
+ if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+ return -EINVAL;
+
+ if (tty->driver->compat_ioctl) {
+ retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+ if (retval != -ENOIOCTLCMD)
+ return retval;
+ }
+
+ ld = tty_ldisc_ref_wait(tty);
+ if (ld->compat_ioctl)
+ retval = ld->compat_ioctl(tty, file, cmd, arg);
+ tty_ldisc_deref(ld);
+
+ return retval;
+}
+#endif
/*
* This implements the "Secure Attention Key" --- the idea is to
@@ -3689,6 +3725,7 @@
driver->write_room = op->write_room;
driver->chars_in_buffer = op->chars_in_buffer;
driver->ioctl = op->ioctl;
+ driver->compat_ioctl = op->compat_ioctl;
driver->set_termios = op->set_termios;
driver->throttle = op->throttle;
driver->unthrottle = op->unthrottle;
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 60198a7..1cad32c 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -2,9 +2,7 @@
# Watchdog device configuration
#
-menu "Watchdog Cards"
-
-config WATCHDOG
+menuconfig WATCHDOG
bool "Watchdog Timer Support"
---help---
If you say Y here (and to one of the following options) and create a
@@ -28,9 +26,10 @@
If unsure, say N.
+if WATCHDOG
+
config WATCHDOG_NOWAYOUT
bool "Disable watchdog shutdown on close"
- depends on WATCHDOG
help
The default watchdog behaviour (which you get if you say N here) is
to stop the timer if the process managing it closes the file
@@ -43,13 +42,11 @@
#
comment "Watchdog Device Drivers"
- depends on WATCHDOG
# Architecture Independent
config SOFT_WATCHDOG
tristate "Software watchdog"
- depends on WATCHDOG
help
A software monitoring watchdog. This will fail to reboot your system
from some situations that the hardware watchdog will recover
@@ -62,14 +59,14 @@
config AT91RM9200_WATCHDOG
tristate "AT91RM9200 watchdog"
- depends on WATCHDOG && ARCH_AT91RM9200
+ depends on ARCH_AT91RM9200
help
Watchdog timer embedded into AT91RM9200 chips. This will reboot your
system when the timeout is reached.
config 21285_WATCHDOG
tristate "DC21285 watchdog"
- depends on WATCHDOG && FOOTBRIDGE
+ depends on FOOTBRIDGE
help
The Intel Footbridge chip contains a built-in watchdog circuit. Say Y
here if you wish to use this. Alternatively say M to compile the
@@ -83,7 +80,7 @@
config 977_WATCHDOG
tristate "NetWinder WB83C977 watchdog"
- depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER
+ depends on FOOTBRIDGE && ARCH_NETWINDER
help
Say Y here to include support for the WB977 watchdog included in
NetWinder machines. Alternatively say M to compile the driver as
@@ -93,7 +90,7 @@
config IXP2000_WATCHDOG
tristate "IXP2000 Watchdog"
- depends on WATCHDOG && ARCH_IXP2000
+ depends on ARCH_IXP2000
help
Say Y here if to include support for the watchdog timer
in the Intel IXP2000(2400, 2800, 2850) network processors.
@@ -104,7 +101,7 @@
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
- depends on WATCHDOG && ARCH_IXP4XX
+ depends on ARCH_IXP4XX
help
Say Y here if to include support for the watchdog timer
in the Intel IXP4xx network processors. This driver can
@@ -120,7 +117,7 @@
config S3C2410_WATCHDOG
tristate "S3C2410 Watchdog"
- depends on WATCHDOG && ARCH_S3C2410
+ depends on ARCH_S3C2410
help
Watchdog timer block in the Samsung S3C2410 chips. This will
reboot the system when the timer expires with the watchdog
@@ -136,7 +133,7 @@
config SA1100_WATCHDOG
tristate "SA1100/PXA2xx watchdog"
- depends on WATCHDOG && ( ARCH_SA1100 || ARCH_PXA )
+ depends on ARCH_SA1100 || ARCH_PXA
help
Watchdog timer embedded into SA11x0 and PXA2xx chips. This will
reboot your system when timeout is reached.
@@ -148,7 +145,7 @@
config MPCORE_WATCHDOG
tristate "MPcore watchdog"
- depends on WATCHDOG && ARM_MPCORE_PLATFORM && LOCAL_TIMERS
+ depends on ARM_MPCORE_PLATFORM && LOCAL_TIMERS
help
Watchdog timer embedded into the MPcore system.
@@ -157,7 +154,7 @@
config EP93XX_WATCHDOG
tristate "EP93xx Watchdog"
- depends on WATCHDOG && ARCH_EP93XX
+ depends on ARCH_EP93XX
help
Say Y here if to include support for the watchdog timer
embedded in the Cirrus Logic EP93xx family of devices.
@@ -167,14 +164,14 @@
config OMAP_WATCHDOG
tristate "OMAP Watchdog"
- depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ depends on ARCH_OMAP16XX || ARCH_OMAP24XX
help
Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to
enable the OMAP1610/OMAP1710 watchdog timer.
config PNX4008_WATCHDOG
tristate "PNX4008 Watchdog"
- depends on WATCHDOG && ARCH_PNX4008
+ depends on ARCH_PNX4008
help
Say Y here if to include support for the watchdog timer
in the PNX4008 processor.
@@ -187,7 +184,7 @@
config ACQUIRE_WDT
tristate "Acquire SBC Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on Single Board
Computers produced by Acquire Inc (and others). This watchdog
@@ -201,7 +198,7 @@
config ADVANTECH_WDT
tristate "Advantech SBC Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
help
If you are configuring a Linux kernel for the Advantech single-board
computer, say `Y' here to support its built-in watchdog timer
@@ -210,7 +207,7 @@
config ALIM1535_WDT
tristate "ALi M1535 PMU Watchdog Timer"
- depends on WATCHDOG && X86 && PCI
+ depends on X86 && PCI
---help---
This is the driver for the hardware watchdog on the ALi M1535 PMU.
@@ -221,7 +218,7 @@
config ALIM7101_WDT
tristate "ALi M7101 PMU Computer Watchdog"
- depends on WATCHDOG && X86 && PCI
+ depends on X86 && PCI
help
This is the driver for the hardware watchdog on the ALi M7101 PMU
as used in the x86 Cobalt servers.
@@ -233,7 +230,7 @@
config SC520_WDT
tristate "AMD Elan SC520 processor Watchdog"
- depends on WATCHDOG && X86
+ depends on X86
help
This is the driver for the hardware watchdog built in to the
AMD "Elan" SC520 microcomputer commonly used in embedded systems.
@@ -246,7 +243,7 @@
config EUROTECH_WDT
tristate "Eurotech CPU-1220/1410 Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
help
Enable support for the watchdog timer on the Eurotech CPU-1220 and
CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product
@@ -254,7 +251,7 @@
config IB700_WDT
tristate "IB700 SBC Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on the IB700 Single
Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
@@ -270,7 +267,7 @@
config IBMASR
tristate "IBM Automatic Server Restart"
- depends on WATCHDOG && X86
+ depends on X86
help
This is the driver for the IBM Automatic Server Restart watchdog
timer built-in into some eServer xSeries machines.
@@ -280,7 +277,7 @@
config WAFER_WDT
tristate "ICP Wafer 5823 Single Board Computer Watchdog"
- depends on WATCHDOG && X86
+ depends on X86
help
This is a driver for the hardware watchdog on the ICP Wafer 5823
Single Board Computer (and probably other similar models).
@@ -290,7 +287,7 @@
config I6300ESB_WDT
tristate "Intel 6300ESB Timer/Watchdog"
- depends on WATCHDOG && X86 && PCI
+ depends on X86 && PCI
---help---
Hardware driver for the watchdog timer built into the Intel
6300ESB controller hub.
@@ -298,31 +295,9 @@
To compile this driver as a module, choose M here: the
module will be called i6300esb.
-config I8XX_TCO
- tristate "Intel i8xx TCO Timer/Watchdog"
- depends on WATCHDOG && (X86 || IA64) && PCI
- default n
- ---help---
- Hardware driver for the TCO timer built into the Intel 82801
- I/O Controller Hub family. The TCO (Total Cost of Ownership)
- timer is a watchdog timer that will reboot the machine after
- its second expiration. The expiration time can be configured
- with the "heartbeat" parameter.
-
- On some motherboards the driver may fail to reset the chipset's
- NO_REBOOT flag which prevents the watchdog from rebooting the
- machine. If this is the case you will get a kernel message like
- "failed to reset NO_REBOOT flag, reboot disabled by hardware".
-
- To compile this driver as a module, choose M here: the
- module will be called i8xx_tco.
-
- Note: This driver will be removed in the near future. Please
- use the Intel TCO Timer/Watchdog driver.
-
config ITCO_WDT
tristate "Intel TCO Timer/Watchdog"
- depends on WATCHDOG && (X86 || IA64) && PCI
+ depends on (X86 || IA64) && PCI
---help---
Hardware driver for the intel TCO timer based watchdog devices.
These drivers are included in the Intel 82801 I/O Controller
@@ -351,7 +326,7 @@
config SC1200_WDT
tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
- depends on WATCHDOG && X86
+ depends on X86
help
This is a driver for National Semiconductor PC87307/PC97307 hardware
watchdog cards as found on the SC1200. This watchdog is mainly used
@@ -365,7 +340,7 @@
config SCx200_WDT
tristate "National Semiconductor SCx200 Watchdog"
- depends on WATCHDOG && SCx200 && PCI
+ depends on SCx200 && PCI
help
Enable the built-in watchdog timer support on the National
Semiconductor SCx200 processors.
@@ -374,7 +349,7 @@
config PC87413_WDT
tristate "NS PC87413 watchdog"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on the PC87413 chipset
This watchdog simply watches your kernel to make sure it doesn't
@@ -388,7 +363,7 @@
config 60XX_WDT
tristate "SBC-60XX Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
help
This driver can be used with the watchdog timer found on some
single board computers, namely the 6010 PII based computer.
@@ -402,7 +377,7 @@
config SBC8360_WDT
tristate "SBC8360 Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on the SBC8360 Single
@@ -415,7 +390,7 @@
config CPU5_WDT
tristate "SMA CPU5 Watchdog"
- depends on WATCHDOG && X86
+ depends on X86
---help---
TBD.
To compile this driver as a module, choose M here: the
@@ -423,7 +398,7 @@
config SMSC37B787_WDT
tristate "Winbond SMsC37B787 Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog component on the
Winbond SMsC37B787 chipset as used on the NetRunner Mainboard
@@ -443,7 +418,7 @@
config W83627HF_WDT
tristate "W83627HF Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on the W83627HF chipset
as used in Advantech PC-9578 and Tyan S2721-533 motherboards
@@ -458,7 +433,7 @@
config W83697HF_WDT
tristate "W83697HF/W83697HG Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on the W83697HF/HG
chipset as used in Dedibox/VIA motherboards (and likely others).
@@ -473,7 +448,7 @@
config W83877F_WDT
tristate "W83877F (EMACS) Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on the W83877F chipset
as used in EMACS PC-104 motherboards (and likely others). This
@@ -488,7 +463,7 @@
config W83977F_WDT
tristate "W83977F (PCM-5335) Watchdog Timer"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the hardware watchdog on the W83977F I/O chip
as used in AAEON's PCM-5335 SBC (and likely others). This
@@ -501,7 +476,7 @@
config MACHZ_WDT
tristate "ZF MachZ Watchdog"
- depends on WATCHDOG && X86
+ depends on X86
---help---
If you are using a ZF Micro MachZ processor, say Y here, otherwise
N. This is the driver for the watchdog timer built-in on that
@@ -514,7 +489,7 @@
config SBC_EPX_C3_WATCHDOG
tristate "Winsystems SBC EPX-C3 watchdog"
- depends on WATCHDOG && X86
+ depends on X86
---help---
This is the driver for the built-in watchdog timer on the EPX-C3
Single-board computer made by Winsystems, Inc.
@@ -537,19 +512,19 @@
config 8xx_WDT
tristate "MPC8xx Watchdog Timer"
- depends on WATCHDOG && 8xx
+ depends on 8xx
config 83xx_WDT
tristate "MPC83xx Watchdog Timer"
- depends on WATCHDOG && PPC_83xx
+ depends on PPC_83xx
config MV64X60_WDT
tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
- depends on WATCHDOG && MV64X60
+ depends on MV64X60
config BOOKE_WDT
bool "PowerPC Book-E Watchdog Timer"
- depends on WATCHDOG && (BOOKE || 4xx)
+ depends on BOOKE || 4xx
---help---
Please see Documentation/watchdog/watchdog-api.txt for
more information.
@@ -558,7 +533,7 @@
config WATCHDOG_RTAS
tristate "RTAS watchdog"
- depends on WATCHDOG && PPC_RTAS
+ depends on PPC_RTAS
help
This driver adds watchdog support for the RTAS watchdog.
@@ -569,16 +544,23 @@
config INDYDOG
tristate "Indy/I2 Hardware Watchdog"
- depends on WATCHDOG && SGI_IP22
+ depends on SGI_IP22
help
Hardware driver for the Indy's/I2's watchdog. This is a
watchdog timer that will reboot the machine after a 60 second
timer expired and no process has written to /dev/watchdog during
that time.
+config WDT_MTX1
+ tristate "MTX-1 Hardware Watchdog"
+ depends on MIPS_MTX1
+ help
+ Hardware driver for the MTX-1 boards. This is a watchdog timer that
+ will reboot the machine after a 100 seconds timer expired.
+
config WDT_RM9K_GPI
tristate "RM9000/GPI hardware watchdog"
- depends on WATCHDOG && CPU_RM9000
+ depends on CPU_RM9000
help
Watchdog implementation using the GPI hardware found on
PMC-Sierra RM9xxx CPUs.
@@ -590,7 +572,7 @@
config ZVM_WATCHDOG
tristate "z/VM Watchdog Timer"
- depends on WATCHDOG && S390
+ depends on S390
help
IBM s/390 and zSeries machines running under z/VM 5.1 or later
provide a virtual watchdog timer to their guest that cause a
@@ -604,7 +586,7 @@
config SH_WDT
tristate "SuperH Watchdog"
- depends on WATCHDOG && SUPERH
+ depends on SUPERH
help
This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish
@@ -631,7 +613,7 @@
config WATCHDOG_CP1XXX
tristate "CP1XXX Hardware Watchdog support"
- depends on WATCHDOG && SPARC64 && PCI
+ depends on SPARC64 && PCI
---help---
This is the driver for the hardware watchdog timers present on
Sun Microsystems CompactPCI models CP1400 and CP1500.
@@ -645,7 +627,7 @@
config WATCHDOG_RIO
tristate "RIO Hardware Watchdog support"
- depends on WATCHDOG && SPARC64 && PCI
+ depends on SPARC64 && PCI
help
Say Y here to support the hardware watchdog capability on Sun RIO
machines. The watchdog timeout period is normally one minute but
@@ -656,11 +638,11 @@
#
comment "ISA-based Watchdog Cards"
- depends on WATCHDOG && ISA
+ depends on ISA
config PCWATCHDOG
tristate "Berkshire Products ISA-PC Watchdog"
- depends on WATCHDOG && ISA
+ depends on ISA
---help---
This is the driver for the Berkshire Products ISA-PC Watchdog card.
This card simply watches your kernel to make sure it doesn't freeze,
@@ -676,7 +658,7 @@
config MIXCOMWD
tristate "Mixcom Watchdog"
- depends on WATCHDOG && ISA
+ depends on ISA
---help---
This is a driver for the Mixcom hardware watchdog cards. This
watchdog simply watches your kernel to make sure it doesn't freeze,
@@ -690,7 +672,7 @@
config WDT
tristate "WDT Watchdog timer"
- depends on WATCHDOG && ISA
+ depends on ISA
---help---
If you have a WDT500P or WDT501P watchdog board, say Y here,
otherwise N. It is not possible to probe for this board, which means
@@ -720,11 +702,11 @@
#
comment "PCI-based Watchdog Cards"
- depends on WATCHDOG && PCI
+ depends on PCI
config PCIPCWATCHDOG
tristate "Berkshire Products PCI-PC Watchdog"
- depends on WATCHDOG && PCI
+ depends on PCI
---help---
This is the driver for the Berkshire Products PCI-PC Watchdog card.
This card simply watches your kernel to make sure it doesn't freeze,
@@ -739,7 +721,7 @@
config WDTPCI
tristate "PCI-WDT500/501 Watchdog timer"
- depends on WATCHDOG && PCI
+ depends on PCI
---help---
If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
@@ -766,11 +748,11 @@
#
comment "USB-based Watchdog Cards"
- depends on WATCHDOG && USB
+ depends on USB
config USBPCWATCHDOG
tristate "Berkshire Products USB-PC Watchdog"
- depends on WATCHDOG && USB
+ depends on USB
---help---
This is the driver for the Berkshire Products USB-PC Watchdog card.
This card simply watches your kernel to make sure it doesn't freeze,
@@ -783,4 +765,4 @@
Most people will say N.
-endmenu
+endif # WATCHDOG
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 2cd8ff8..8bfc00c 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -46,7 +46,6 @@
obj-$(CONFIG_IBMASR) += ibmasr.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
-obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
@@ -73,6 +72,7 @@
# MIPS Architecture
obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
# S390 Architecture
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index bcd7e36..d0d45a8 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -220,17 +220,17 @@
if ( verbose )
printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
- if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
- printk(KERN_ERR PFX "misc_register failed\n");
- goto no_misc;
- }
-
if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) {
printk(KERN_ERR PFX "request_region failed\n");
err = -EBUSY;
goto no_port;
}
+ if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
+ printk(KERN_ERR PFX "misc_register failed\n");
+ goto no_misc;
+ }
+
/* watchdog reboot? */
val = inb(port + CPU5WDT_STATUS_REG);
val = (val >> 2) & 1;
@@ -250,9 +250,9 @@
return 0;
-no_port:
- misc_deregister(&cpu5wdt_misc);
no_misc:
+ release_region(port, CPU5WDT_EXTENT);
+no_port:
return err;
}
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index f70387f..b070324 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -413,17 +413,10 @@
{
int ret;
- ret = misc_register(&eurwdt_miscdev);
- if (ret) {
- printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
- WATCHDOG_MINOR);
- goto out;
- }
-
ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
if(ret) {
printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
- goto outmisc;
+ goto out;
}
if (!request_region(io, 2, "eurwdt")) {
@@ -438,6 +431,13 @@
goto outreg;
}
+ ret = misc_register(&eurwdt_miscdev);
+ if (ret) {
+ printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
+ WATCHDOG_MINOR);
+ goto outreboot;
+ }
+
eurwdt_unlock_chip();
ret = 0;
@@ -448,14 +448,14 @@
out:
return ret;
+outreboot:
+ unregister_reboot_notifier(&eurwdt_notifier);
+
outreg:
release_region(io, 2);
outirq:
free_irq(irq, NULL);
-
-outmisc:
- misc_deregister(&eurwdt_miscdev);
goto out;
}
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
deleted file mode 100644
index a62ef48..0000000
--- a/drivers/char/watchdog/i8xx_tco.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * i8xx_tco: TCO timer driver for i8xx chipsets
- *
- * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
- * http://www.kernelconcepts.de
- *
- * 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.
- *
- * Neither kernel concepts nor Nils Faerber admit liability nor provide
- * warranty for any of this software. This material is provided
- * "AS-IS" and at no charge.
- *
- * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
- * developed for
- * Jentro AG, Haar/Munich (Germany)
- *
- * TCO timer driver for i8xx chipsets
- * based on softdog.c by Alan Cox <alan@redhat.com>
- *
- * The TCO timer is implemented in the following I/O controller hubs:
- * (See the intel documentation on http://developer.intel.com.)
- * 82801AA (ICH) : document number 290655-003, 290677-014,
- * 82801AB (ICHO) : document number 290655-003, 290677-014,
- * 82801BA (ICH2) : document number 290687-002, 298242-027,
- * 82801BAM (ICH2-M) : document number 290687-002, 298242-027,
- * 82801CA (ICH3-S) : document number 290733-003, 290739-013,
- * 82801CAM (ICH3-M) : document number 290716-001, 290718-007,
- * 82801DB (ICH4) : document number 290744-001, 290745-020,
- * 82801DBM (ICH4-M) : document number 252337-001, 252663-005,
- * 82801E (C-ICH) : document number 273599-001, 273645-002,
- * 82801EB (ICH5) : document number 252516-001, 252517-003,
- * 82801ER (ICH5R) : document number 252516-001, 252517-003,
- *
- * 20000710 Nils Faerber
- * Initial Version 0.01
- * 20000728 Nils Faerber
- * 0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
- * 20011214 Matt Domsch <Matt_Domsch@dell.com>
- * 0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- * Didn't add timeout option as i810_margin already exists.
- * 20020224 Joel Becker, Wim Van Sebroeck
- * 0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3,
- * add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
- * 20020412 Rob Radez <rob@osinvestor.com>, Wim Van Sebroeck
- * 0.05 Fix possible timer_alive race, add expect close support,
- * clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
- * WDIOC_SETOPTIONS), made i810tco_getdevice __init,
- * removed boot_status, removed tco_timer_read,
- * added support for 82801DB and 82801E chipset,
- * added support for 82801EB and 8280ER chipset,
- * general cleanup.
- * 20030921 Wim Van Sebroeck <wim@iguana.be>
- * 0.06 change i810_margin to heartbeat, use module_param,
- * added notify system support, renamed module to i8xx_tco.
- * 20050128 Wim Van Sebroeck <wim@iguana.be>
- * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW
- * chipsets. Also added support for the "undocumented" ICH7 chipset.
- * 20050807 Wim Van Sebroeck <wim@iguana.be>
- * 0.08 Make sure that the watchdog is only "armed" when started.
- * (Kernel Bug 4251)
- * 20060416 Wim Van Sebroeck <wim@iguana.be>
- * 0.09 Remove support for the ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW and
- * ICH7 chipsets. (See Kernel Bug 6031 - other code will support these
- * chipsets)
- */
-
-/*
- * Includes, defines, variables, module parameters, ...
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#include "i8xx_tco.h"
-
-/* Module and version information */
-#define TCO_VERSION "0.09"
-#define TCO_MODULE_NAME "i8xx TCO timer"
-#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
-#define PFX TCO_MODULE_NAME ": "
-
-/* internal variables */
-static unsigned int ACPIBASE;
-static spinlock_t tco_lock; /* Guards the hardware */
-static unsigned long timer_alive;
-static char tco_expect_close;
-static struct pci_dev *i8xx_tco_pci;
-
-/* module parameters */
-#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (2<heartbeat<39) */
-static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
-module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
-
-static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-
-/*
- * Some TCO specific functions
- */
-
-static inline unsigned char seconds_to_ticks(int seconds)
-{
- /* the internal timer is stored as ticks which decrement
- * every 0.6 seconds */
- return (seconds * 10) / 6;
-}
-
-static int tco_timer_start (void)
-{
- unsigned char val;
-
- spin_lock(&tco_lock);
-
- /* disable chipset's NO_REBOOT bit */
- pci_read_config_byte (i8xx_tco_pci, 0xd4, &val);
- val &= 0xfd;
- pci_write_config_byte (i8xx_tco_pci, 0xd4, val);
-
- /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
- val = inb (TCO1_CNT + 1);
- val &= 0xf7;
- outb (val, TCO1_CNT + 1);
- val = inb (TCO1_CNT + 1);
-
- spin_unlock(&tco_lock);
-
- if (val & 0x08)
- return -1;
- return 0;
-}
-
-static int tco_timer_stop (void)
-{
- unsigned char val, val1;
-
- spin_lock(&tco_lock);
- /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
- val = inb (TCO1_CNT + 1);
- val |= 0x08;
- outb (val, TCO1_CNT + 1);
- val = inb (TCO1_CNT + 1);
-
- /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
- pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
- val1 |= 0x02;
- pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-
- spin_unlock(&tco_lock);
-
- if ((val & 0x08) == 0)
- return -1;
- return 0;
-}
-
-static int tco_timer_keepalive (void)
-{
- spin_lock(&tco_lock);
- /* Reload the timer by writing to the TCO Timer Reload register */
- outb (0x01, TCO1_RLD);
- spin_unlock(&tco_lock);
- return 0;
-}
-
-static int tco_timer_set_heartbeat (int t)
-{
- unsigned char val;
- unsigned char tmrval;
-
- tmrval = seconds_to_ticks(t);
- /* from the specs: */
- /* "Values of 0h-3h are ignored and should not be attempted" */
- if (tmrval > 0x3f || tmrval < 0x04)
- return -EINVAL;
-
- /* Write new heartbeat to watchdog */
- spin_lock(&tco_lock);
- val = inb (TCO1_TMR);
- val &= 0xc0;
- val |= tmrval;
- outb (val, TCO1_TMR);
- val = inb (TCO1_TMR);
- spin_unlock(&tco_lock);
-
- if ((val & 0x3f) != tmrval)
- return -EINVAL;
-
- heartbeat = t;
- return 0;
-}
-
-static int tco_timer_get_timeleft (int *time_left)
-{
- unsigned char val;
-
- spin_lock(&tco_lock);
-
- /* read the TCO Timer */
- val = inb (TCO1_RLD);
- val &= 0x3f;
-
- spin_unlock(&tco_lock);
-
- *time_left = (int)((val * 6) / 10);
-
- return 0;
-}
-
-/*
- * /dev/watchdog handling
- */
-
-static int i8xx_tco_open (struct inode *inode, struct file *file)
-{
- /* /dev/watchdog can only be opened once */
- if (test_and_set_bit(0, &timer_alive))
- return -EBUSY;
-
- /*
- * Reload and activate timer
- */
- tco_timer_keepalive ();
- tco_timer_start ();
- return nonseekable_open(inode, file);
-}
-
-static int i8xx_tco_release (struct inode *inode, struct file *file)
-{
- /*
- * Shut off the timer.
- */
- if (tco_expect_close == 42) {
- tco_timer_stop ();
- } else {
- printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
- tco_timer_keepalive ();
- }
- clear_bit(0, &timer_alive);
- tco_expect_close = 0;
- return 0;
-}
-
-static ssize_t i8xx_tco_write (struct file *file, const char __user *data,
- size_t len, loff_t * ppos)
-{
- /* See if we got the magic character 'V' and reload the timer */
- if (len) {
- if (!nowayout) {
- size_t i;
-
- /* note: just in case someone wrote the magic character
- * five months ago... */
- tco_expect_close = 0;
-
- /* scan to see whether or not we got the magic character */
- for (i = 0; i != len; i++) {
- char c;
- if(get_user(c, data+i))
- return -EFAULT;
- if (c == 'V')
- tco_expect_close = 42;
- }
- }
-
- /* someone wrote to us, we should reload the timer */
- tco_timer_keepalive ();
- }
- return len;
-}
-
-static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int new_options, retval = -EINVAL;
- int new_heartbeat;
- int time_left;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
- static struct watchdog_info ident = {
- .options = WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE,
- .firmware_version = 0,
- .identity = TCO_MODULE_NAME,
- };
-
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user(argp, &ident,
- sizeof (ident)) ? -EFAULT : 0;
-
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- return put_user (0, p);
-
- case WDIOC_KEEPALIVE:
- tco_timer_keepalive ();
- return 0;
-
- case WDIOC_SETOPTIONS:
- {
- if (get_user (new_options, p))
- return -EFAULT;
-
- if (new_options & WDIOS_DISABLECARD) {
- tco_timer_stop ();
- retval = 0;
- }
-
- if (new_options & WDIOS_ENABLECARD) {
- tco_timer_keepalive ();
- tco_timer_start ();
- retval = 0;
- }
-
- return retval;
- }
-
- case WDIOC_SETTIMEOUT:
- {
- if (get_user(new_heartbeat, p))
- return -EFAULT;
-
- if (tco_timer_set_heartbeat(new_heartbeat))
- return -EINVAL;
-
- tco_timer_keepalive ();
- /* Fall */
- }
-
- case WDIOC_GETTIMEOUT:
- return put_user(heartbeat, p);
-
- case WDIOC_GETTIMELEFT:
- {
- if (tco_timer_get_timeleft(&time_left))
- return -EINVAL;
-
- return put_user(time_left, p);
- }
-
- default:
- return -ENOTTY;
- }
-}
-
-/*
- * Notify system
- */
-
-static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
-{
- if (code==SYS_DOWN || code==SYS_HALT) {
- /* Turn the WDT off */
- tco_timer_stop ();
- }
-
- return NOTIFY_DONE;
-}
-
-/*
- * Kernel Interfaces
- */
-
-static const struct file_operations i8xx_tco_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = i8xx_tco_write,
- .ioctl = i8xx_tco_ioctl,
- .open = i8xx_tco_open,
- .release = i8xx_tco_release,
-};
-
-static struct miscdevice i8xx_tco_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &i8xx_tco_fops,
-};
-
-static struct notifier_block i8xx_tco_notifier = {
- .notifier_call = i8xx_tco_notify_sys,
-};
-
-/*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE. We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
-static struct pci_device_id i8xx_tco_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0) },
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1) },
- { }, /* End of list */
-};
-MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
-
-/*
- * Init & exit routines
- */
-
-static unsigned char __init i8xx_tco_getdevice (void)
-{
- struct pci_dev *dev = NULL;
- u8 val1, val2;
- u16 badr;
- /*
- * Find the PCI device
- */
-
- for_each_pci_dev(dev)
- if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
- i8xx_tco_pci = dev;
- break;
- }
-
- if (i8xx_tco_pci) {
- /*
- * Find the ACPI base I/O address which is the base
- * for the TCO registers (TCOBASE=ACPIBASE + 0x60)
- * ACPIBASE is bits [15:7] from 0x40-0x43
- */
- pci_read_config_byte (i8xx_tco_pci, 0x40, &val1);
- pci_read_config_byte (i8xx_tco_pci, 0x41, &val2);
- badr = ((val2 << 1) | (val1 >> 7)) << 7;
- ACPIBASE = badr;
- /* Something's wrong here, ACPIBASE has to be set */
- if (badr == 0x0001 || badr == 0x0000) {
- printk (KERN_ERR PFX "failed to get TCOBASE address\n");
- pci_dev_put(i8xx_tco_pci);
- return 0;
- }
-
- /* Check chipset's NO_REBOOT bit */
- pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
- if (val1 & 0x02) {
- val1 &= 0xfd;
- pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
- pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
- if (val1 & 0x02) {
- printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
- pci_dev_put(i8xx_tco_pci);
- return 0; /* Cannot reset NO_REBOOT bit */
- }
- }
- /* Disable reboots untill the watchdog starts */
- val1 |= 0x02;
- pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
-
- /* Set the TCO_EN bit in SMI_EN register */
- if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) {
- printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
- SMI_EN + 1);
- pci_dev_put(i8xx_tco_pci);
- return 0;
- }
- val1 = inb (SMI_EN + 1);
- val1 &= 0xdf;
- outb (val1, SMI_EN + 1);
- release_region (SMI_EN + 1, 1);
- return 1;
- }
- return 0;
-}
-
-static int __init watchdog_init (void)
-{
- int ret;
-
- spin_lock_init(&tco_lock);
-
- /* Check whether or not the hardware watchdog is there */
- if (!i8xx_tco_getdevice () || i8xx_tco_pci == NULL)
- return -ENODEV;
-
- if (!request_region (TCOBASE, 0x10, "i8xx TCO")) {
- printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
- TCOBASE);
- ret = -EIO;
- goto out;
- }
-
- /* Clear out the (probably old) status */
- outb (0, TCO1_STS);
- outb (3, TCO2_STS);
-
- /* Check that the heartbeat value is within it's range ; if not reset to the default */
- if (tco_timer_set_heartbeat (heartbeat)) {
- heartbeat = WATCHDOG_HEARTBEAT;
- tco_timer_set_heartbeat (heartbeat);
- printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, using %d\n",
- heartbeat);
- }
-
- ret = register_reboot_notifier(&i8xx_tco_notifier);
- if (ret != 0) {
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- ret);
- goto unreg_region;
- }
-
- ret = misc_register(&i8xx_tco_miscdev);
- if (ret != 0) {
- printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
- goto unreg_notifier;
- }
-
- tco_timer_stop ();
-
- printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
- TCOBASE, heartbeat, nowayout);
-
- return 0;
-
-unreg_notifier:
- unregister_reboot_notifier(&i8xx_tco_notifier);
-unreg_region:
- release_region (TCOBASE, 0x10);
-out:
- pci_dev_put(i8xx_tco_pci);
- return ret;
-}
-
-static void __exit watchdog_cleanup (void)
-{
- /* Stop the timer before we leave */
- if (!nowayout)
- tco_timer_stop ();
-
- /* Deregister */
- misc_deregister (&i8xx_tco_miscdev);
- unregister_reboot_notifier(&i8xx_tco_notifier);
- release_region (TCOBASE, 0x10);
-
- pci_dev_put(i8xx_tco_pci);
-}
-
-module_init(watchdog_init);
-module_exit(watchdog_cleanup);
-
-MODULE_AUTHOR("Nils Faerber");
-MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/i8xx_tco.h b/drivers/char/watchdog/i8xx_tco.h
deleted file mode 100644
index cc14eb8..0000000
--- a/drivers/char/watchdog/i8xx_tco.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * i8xx_tco: TCO timer driver for i8xx chipsets
- *
- * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
- * http://www.kernelconcepts.de
- *
- * 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.
- *
- * Neither kernel concepts nor Nils Faerber admit liability nor provide
- * warranty for any of this software. This material is provided
- * "AS-IS" and at no charge.
- *
- * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>
- * developed for
- * Jentro AG, Haar/Munich (Germany)
- *
- * TCO timer driver for i8xx chipsets
- * based on softdog.c by Alan Cox <alan@redhat.com>
- *
- * For history and the complete list of supported I/O Controller Hub's
- * see i8xx_tco.c
- */
-
-
-/*
- * Some address definitions for the TCO
- */
-
-#define TCOBASE ACPIBASE + 0x60 /* TCO base address */
-#define TCO1_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */
-#define TCO1_TMR TCOBASE + 0x01 /* TCO Timer Initial Value */
-#define TCO1_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
-#define TCO1_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
-#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
-#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */
-#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */
-#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */
-
-#define SMI_EN ACPIBASE + 0x30 /* SMI Control and Enable Register */
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
index 8195f50..94155f6 100644
--- a/drivers/char/watchdog/ibmasr.c
+++ b/drivers/char/watchdog/ibmasr.c
@@ -367,18 +367,17 @@
if (!asr_type)
return -ENODEV;
+ rc = asr_get_base_address();
+ if (rc)
+ return rc;
+
rc = misc_register(&asr_miscdev);
if (rc < 0) {
+ release_region(asr_base, asr_length);
printk(KERN_ERR PFX "failed to register misc device\n");
return rc;
}
- rc = asr_get_base_address();
- if (rc) {
- misc_deregister(&asr_miscdev);
- return rc;
- }
-
return 0;
}
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 76c7fa3..a0d2716 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -440,13 +440,6 @@
spin_lock_init(&zf_lock);
spin_lock_init(&zf_port_lock);
- ret = misc_register(&zf_miscdev);
- if (ret){
- printk(KERN_ERR "can't misc_register on minor=%d\n",
- WATCHDOG_MINOR);
- goto out;
- }
-
if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
printk(KERN_ERR "cannot reserve I/O ports at %d\n",
ZF_IOBASE);
@@ -461,16 +454,23 @@
goto no_reboot;
}
+ ret = misc_register(&zf_miscdev);
+ if (ret){
+ printk(KERN_ERR "can't misc_register on minor=%d\n",
+ WATCHDOG_MINOR);
+ goto no_misc;
+ }
+
zf_set_status(0);
zf_set_control(0);
return 0;
+no_misc:
+ unregister_reboot_notifier(&zf_notifier);
no_reboot:
release_region(ZF_IOBASE, 3);
no_region:
- misc_deregister(&zf_miscdev);
-out:
return ret;
}
diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/char/watchdog/mtx-1_wdt.c
new file mode 100644
index 0000000..419ab44
--- /dev/null
+++ b/drivers/char/watchdog/mtx-1_wdt.c
@@ -0,0 +1,238 @@
+/*
+ * Driver for the MTX-1 Watchdog.
+ *
+ * (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
+ * http://www.4g-systems.biz
+ *
+ * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
+ *
+ * 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.
+ *
+ * Neither Michael Stickel nor 4G Systems admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 2005 4G Systems <info@4g-systems.biz>
+ *
+ * Release 0.01.
+ * Author: Michael Stickel michael.stickel@4g-systems.biz
+ *
+ * Release 0.02.
+ * Author: Florian Fainelli florian@openwrt.org
+ * use the Linux watchdog/timer APIs
+ *
+ * The Watchdog is configured to reset the MTX-1
+ * if it is not triggered for 100 seconds.
+ * It should not be triggered more often than 1.6 seconds.
+ *
+ * A timer triggers the watchdog every 5 seconds, until
+ * it is opened for the first time. After the first open
+ * it MUST be triggered every 2..95 seconds.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/timer.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+#include <linux/watchdog.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+#define MTX1_WDT_INTERVAL (5 * HZ)
+
+static int ticks = 100 * HZ;
+
+static struct {
+ struct completion stop;
+ volatile int running;
+ struct timer_list timer;
+ volatile int queue;
+ int default_ticks;
+ unsigned long inuse;
+} mtx1_wdt_device;
+
+static void mtx1_wdt_trigger(unsigned long unused)
+{
+ u32 tmp;
+
+ if (mtx1_wdt_device.running)
+ ticks--;
+ /*
+ * toggle GPIO2_15
+ */
+ tmp = au_readl(GPIO2_DIR);
+ tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15));
+ au_writel (tmp, GPIO2_DIR);
+
+ if (mtx1_wdt_device.queue && ticks)
+ mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
+ else {
+ complete(&mtx1_wdt_device.stop);
+ }
+}
+
+static void mtx1_wdt_reset(void)
+{
+ ticks = mtx1_wdt_device.default_ticks;
+}
+
+
+static void mtx1_wdt_start(void)
+{
+ if (!mtx1_wdt_device.queue) {
+ mtx1_wdt_device.queue = 1;
+ au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR);
+ mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
+ }
+ mtx1_wdt_device.running++;
+}
+
+static int mtx1_wdt_stop(void)
+{
+ if (mtx1_wdt_device.queue) {
+ mtx1_wdt_device.queue = 0;
+ au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR);
+ }
+
+ ticks = mtx1_wdt_device.default_ticks;
+
+ return 0;
+}
+
+/* Filesystem functions */
+
+static int mtx1_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &mtx1_wdt_device.inuse))
+ return -EBUSY;
+
+ return nonseekable_open(inode, file);
+}
+
+
+static int mtx1_wdt_release(struct inode *inode, struct file *file)
+{
+ clear_bit(0, &mtx1_wdt_device.inuse);
+ return 0;
+}
+
+static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ unsigned int value;
+ static struct watchdog_info ident =
+ {
+ .options = WDIOF_CARDRESET,
+ .identity = "MTX-1 WDT",
+ };
+
+ switch(cmd) {
+ case WDIOC_KEEPALIVE:
+ mtx1_wdt_reset();
+ break;
+ case WDIOC_GETSTATUS:
+ if ( copy_to_user(argp, &value, sizeof(int)) )
+ return -EFAULT;
+ break;
+ case WDIOC_GETSUPPORT:
+ if ( copy_to_user(argp, &ident, sizeof(ident)) )
+ return -EFAULT;
+ break;
+ case WDIOC_SETOPTIONS:
+ if ( copy_from_user(&value, argp, sizeof(int)) )
+ return -EFAULT;
+ switch(value) {
+ case WDIOS_ENABLECARD:
+ mtx1_wdt_start();
+ break;
+ case WDIOS_DISABLECARD:
+ return mtx1_wdt_stop();
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -ENOTTY;
+ }
+ return 0;
+}
+
+
+static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ if (!count)
+ return -EIO;
+
+ mtx1_wdt_reset();
+ return count;
+}
+
+static struct file_operations mtx1_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = mtx1_wdt_ioctl,
+ .open = mtx1_wdt_open,
+ .write = mtx1_wdt_write,
+ .release = mtx1_wdt_release
+};
+
+
+static struct miscdevice mtx1_wdt_misc = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mtx1_wdt_fops
+};
+
+
+static int __init mtx1_wdt_init(void)
+{
+ int ret;
+
+ if ((ret = misc_register(&mtx1_wdt_misc)) < 0) {
+ printk(KERN_ERR " mtx-1_wdt : failed to register\n");
+ return ret;
+ }
+
+ init_completion(&mtx1_wdt_device.stop);
+ mtx1_wdt_device.queue = 0;
+
+ clear_bit(0, &mtx1_wdt_device.inuse);
+
+ setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L);
+
+ mtx1_wdt_device.default_ticks = ticks;
+
+ mtx1_wdt_start();
+
+ printk(KERN_INFO "MTX-1 Watchdog driver\n");
+
+ return 0;
+}
+
+static void __exit mtx1_wdt_exit(void)
+{
+ if (mtx1_wdt_device.queue) {
+ mtx1_wdt_device.queue = 0;
+ wait_for_completion(&mtx1_wdt_device.stop);
+ }
+ misc_deregister(&mtx1_wdt_misc);
+}
+
+module_init(mtx1_wdt_init);
+module_exit(mtx1_wdt_exit);
+
+MODULE_AUTHOR("Michael Stickel, Florian Fainelli");
+MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index 6e8b570..7b41434 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -59,10 +59,10 @@
#include <linux/jiffies.h> /* For jiffies stuff */
#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
#include <linux/watchdog.h> /* For the watchdog specific items */
-#include <linux/notifier.h> /* For notifier support */
-#include <linux/reboot.h> /* For reboot_notifier stuff */
+#include <linux/reboot.h> /* For kernel_power_off() */
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/fs.h> /* For file operations */
+#include <linux/isa.h> /* For isa devices */
#include <linux/ioport.h> /* For io-port access */
#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
@@ -70,8 +70,8 @@
#include <asm/io.h> /* For inb/outb/... */
/* Module and version information */
-#define WATCHDOG_VERSION "1.18"
-#define WATCHDOG_DATE "21 Jan 2007"
+#define WATCHDOG_VERSION "1.20"
+#define WATCHDOG_DATE "18 Feb 2007"
#define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
#define WATCHDOG_NAME "pcwd"
#define PFX WATCHDOG_NAME ": "
@@ -89,6 +89,15 @@
#define PCWD_REVISION_C 2
/*
+ * These are the auto-probe addresses available.
+ *
+ * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350.
+ * Revision A has an address range of 2 addresses, while Revision C has 4.
+ */
+#define PCWD_ISA_NR_CARDS 3
+static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
+
+/*
* These are the defines that describe the control status bits for the
* PCI-PC Watchdog card.
*/
@@ -485,7 +494,7 @@
if (control_status & WD_T110) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
- printk (KERN_INFO PFX "Temperature overheat trip!\n");
+ printk(KERN_INFO PFX "Temperature overheat trip!\n");
kernel_power_off();
/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
}
@@ -497,7 +506,7 @@
if (control_status & WD_REVC_TTRP) {
*status |= WDIOF_OVERHEAT;
if (temp_panic) {
- printk (KERN_INFO PFX "Temperature overheat trip!\n");
+ printk(KERN_INFO PFX "Temperature overheat trip!\n");
kernel_power_off();
/* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
}
@@ -734,20 +743,6 @@
}
/*
- * Notify system
- */
-
-static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
-{
- if (code==SYS_DOWN || code==SYS_HALT) {
- /* Turn the WDT off */
- pcwd_stop();
- }
-
- return NOTIFY_DONE;
-}
-
-/*
* Kernel Interfaces
*/
@@ -780,10 +775,6 @@
.fops = &pcwd_temp_fops,
};
-static struct notifier_block pcwd_notifier = {
- .notifier_call = pcwd_notify_sys,
-};
-
/*
* Init & exit routines
*/
@@ -803,10 +794,67 @@
return r;
}
-static int __devinit pcwatchdog_init(int base_addr)
+/*
+ * The ISA cards have a heartbeat bit in one of the registers, which
+ * register is card dependent. The heartbeat bit is monitored, and if
+ * found, is considered proof that a Berkshire card has been found.
+ * The initial rate is once per second at board start up, then twice
+ * per second for normal operation.
+ */
+static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
+{
+ int base_addr=pcwd_ioports[id];
+ int port0, last_port0; /* Reg 0, in case it's REV A */
+ int port1, last_port1; /* Register 1 for REV C cards */
+ int i;
+ int retval;
+
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
+ id);
+
+ if (!request_region (base_addr, 4, "PCWD")) {
+ printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
+ return 0;
+ }
+
+ retval = 0;
+
+ port0 = inb_p(base_addr); /* For REV A boards */
+ port1 = inb_p(base_addr + 1); /* For REV C boards */
+ if (port0 != 0xff || port1 != 0xff) {
+ /* Not an 'ff' from a floating bus, so must be a card! */
+ for (i = 0; i < 4; ++i) {
+
+ msleep(500);
+
+ last_port0 = port0;
+ last_port1 = port1;
+
+ port0 = inb_p(base_addr);
+ port1 = inb_p(base_addr + 1);
+
+ /* Has either hearbeat bit changed? */
+ if ((port0 ^ last_port0) & WD_HRTBT ||
+ (port1 ^ last_port1) & WD_REVC_HRBT) {
+ retval = 1;
+ break;
+ }
+ }
+ }
+ release_region (base_addr, 4);
+
+ return retval;
+}
+
+static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
{
int ret;
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n",
+ id);
+
cards_found++;
if (cards_found == 1)
printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
@@ -816,11 +864,13 @@
return -ENODEV;
}
- if (base_addr == 0x0000) {
+ if (pcwd_ioports[id] == 0x0000) {
printk(KERN_ERR PFX "No I/O-Address for card detected\n");
return -ENODEV;
}
- pcwd_private.io_addr = base_addr;
+ pcwd_private.io_addr = pcwd_ioports[id];
+
+ spin_lock_init(&pcwd_private.io_lock);
/* Check card's revision */
pcwd_private.revision = get_revision();
@@ -828,8 +878,8 @@
if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
pcwd_private.io_addr);
- pcwd_private.io_addr = 0x0000;
- return -EIO;
+ ret=-EIO;
+ goto error_request_region;
}
/* Initial variables */
@@ -865,24 +915,12 @@
WATCHDOG_HEARTBEAT);
}
- ret = register_reboot_notifier(&pcwd_notifier);
- if (ret) {
- printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
- ret);
- release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
- pcwd_private.io_addr = 0x0000;
- return ret;
- }
-
if (pcwd_private.supports_temp) {
ret = misc_register(&temp_miscdev);
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
TEMP_MINOR, ret);
- unregister_reboot_notifier(&pcwd_notifier);
- release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
- pcwd_private.io_addr = 0x0000;
- return ret;
+ goto error_misc_register_temp;
}
}
@@ -890,22 +928,34 @@
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
- if (pcwd_private.supports_temp)
- misc_deregister(&temp_miscdev);
- unregister_reboot_notifier(&pcwd_notifier);
- release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
- pcwd_private.io_addr = 0x0000;
- return ret;
+ goto error_misc_register_watchdog;
}
printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
return 0;
+
+error_misc_register_watchdog:
+ if (pcwd_private.supports_temp)
+ misc_deregister(&temp_miscdev);
+error_misc_register_temp:
+ release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
+error_request_region:
+ pcwd_private.io_addr = 0x0000;
+ cards_found--;
+ return ret;
}
-static void __devexit pcwatchdog_exit(void)
+static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
{
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n",
+ id);
+
+ if (!pcwd_private.io_addr)
+ return 1;
+
/* Disable the board */
if (!nowayout)
pcwd_stop();
@@ -914,102 +964,50 @@
misc_deregister(&pcwd_miscdev);
if (pcwd_private.supports_temp)
misc_deregister(&temp_miscdev);
- unregister_reboot_notifier(&pcwd_notifier);
release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
pcwd_private.io_addr = 0x0000;
cards_found--;
-}
-
-/*
- * The ISA cards have a heartbeat bit in one of the registers, which
- * register is card dependent. The heartbeat bit is monitored, and if
- * found, is considered proof that a Berkshire card has been found.
- * The initial rate is once per second at board start up, then twice
- * per second for normal operation.
- */
-static int __init pcwd_checkcard(int base_addr)
-{
- int port0, last_port0; /* Reg 0, in case it's REV A */
- int port1, last_port1; /* Register 1 for REV C cards */
- int i;
- int retval;
-
- if (!request_region (base_addr, 4, "PCWD")) {
- printk (KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
- return 0;
- }
-
- retval = 0;
-
- port0 = inb_p(base_addr); /* For REV A boards */
- port1 = inb_p(base_addr + 1); /* For REV C boards */
- if (port0 != 0xff || port1 != 0xff) {
- /* Not an 'ff' from a floating bus, so must be a card! */
- for (i = 0; i < 4; ++i) {
-
- msleep(500);
-
- last_port0 = port0;
- last_port1 = port1;
-
- port0 = inb_p(base_addr);
- port1 = inb_p(base_addr + 1);
-
- /* Has either hearbeat bit changed? */
- if ((port0 ^ last_port0) & WD_HRTBT ||
- (port1 ^ last_port1) & WD_REVC_HRBT) {
- retval = 1;
- break;
- }
- }
- }
- release_region (base_addr, 4);
-
- return retval;
-}
-
-/*
- * These are the auto-probe addresses available.
- *
- * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350.
- * Revision A has an address range of 2 addresses, while Revision C has 4.
- */
-static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
-
-static int __init pcwd_init_module(void)
-{
- int i, found = 0;
-
- spin_lock_init(&pcwd_private.io_lock);
-
- for (i = 0; pcwd_ioports[i] != 0; i++) {
- if (pcwd_checkcard(pcwd_ioports[i])) {
- if (!(pcwatchdog_init(pcwd_ioports[i])))
- found++;
- }
- }
-
- if (!found) {
- printk (KERN_INFO PFX "No card detected, or port not available\n");
- return -ENODEV;
- }
return 0;
}
+static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
+{
+ if (debug >= DEBUG)
+ printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n",
+ id);
+
+ pcwd_stop();
+}
+
+static struct isa_driver pcwd_isa_driver = {
+ .match = pcwd_isa_match,
+ .probe = pcwd_isa_probe,
+ .remove = __devexit_p(pcwd_isa_remove),
+ .shutdown = pcwd_isa_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = WATCHDOG_NAME,
+ },
+};
+
+static int __init pcwd_init_module(void)
+{
+ return isa_register_driver(&pcwd_isa_driver, PCWD_ISA_NR_CARDS);
+}
+
static void __exit pcwd_cleanup_module(void)
{
- if (pcwd_private.io_addr)
- pcwatchdog_exit();
-
+ isa_unregister_driver(&pcwd_isa_driver);
printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
}
module_init(pcwd_init_module);
module_exit(pcwd_cleanup_module);
-MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>");
+MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>, Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
+MODULE_VERSION(WATCHDOG_VERSION);
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 31037f9..1e7a671 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -146,7 +146,7 @@
atomic_t cmd_received; /* true if we received a report after a command */
int exists; /* Wether or not the device exists */
- struct semaphore sem; /* locks this structure */
+ struct mutex mtx; /* locks this structure */
};
static struct usb_pcwd_private *usb_pcwd_device;
@@ -635,7 +635,7 @@
usb_pcwd_device = usb_pcwd;
- init_MUTEX (&usb_pcwd->sem);
+ mutex_init(&usb_pcwd->mtx);
usb_pcwd->udev = udev;
usb_pcwd->interface = interface;
usb_pcwd->interface_number = iface_desc->desc.bInterfaceNumber;
@@ -763,7 +763,7 @@
usb_pcwd = usb_get_intfdata (interface);
usb_set_intfdata (interface, NULL);
- down (&usb_pcwd->sem);
+ mutex_lock(&usb_pcwd->mtx);
/* Stop the timer before we leave */
if (!nowayout)
@@ -777,7 +777,7 @@
misc_deregister(&usb_pcwd_temperature_miscdev);
unregister_reboot_notifier(&usb_pcwd_notifier);
- up (&usb_pcwd->sem);
+ mutex_unlock(&usb_pcwd->mtx);
/* Delete the USB PCWD device */
usb_pcwd_delete(usb_pcwd);
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index dff6cb5..20fa29c 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -379,14 +379,14 @@
DBG("probe: mapped wdt_base=%p\n", wdt_base);
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (res == NULL) {
+ wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (wdt_irq == NULL) {
printk(KERN_INFO PFX "failed to get irq resource\n");
ret = -ENOENT;
goto err_map;
}
- ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
+ ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
if (ret != 0) {
printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
goto err_map;
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c
index 67ae426..285d852 100644
--- a/drivers/char/watchdog/sbc8360.c
+++ b/drivers/char/watchdog/sbc8360.c
@@ -333,18 +333,17 @@
int res;
unsigned long int mseconds = 60000;
- spin_lock_init(&sbc8360_lock);
- res = misc_register(&sbc8360_miscdev);
- if (res) {
- printk(KERN_ERR PFX "failed to register misc device\n");
- goto out_nomisc;
+ if (timeout < 0 || timeout > 63) {
+ printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
+ res = -EINVAL;
+ goto out;
}
if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
SBC8360_ENABLE);
res = -EIO;
- goto out_noenablereg;
+ goto out;
}
if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
printk(KERN_ERR PFX
@@ -360,10 +359,11 @@
goto out_noreboot;
}
- if (timeout < 0 || timeout > 63) {
- printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
- res = -EINVAL;
- goto out_noreboot;
+ spin_lock_init(&sbc8360_lock);
+ res = misc_register(&sbc8360_miscdev);
+ if (res) {
+ printk(KERN_ERR PFX "failed to register misc device\n");
+ goto out_nomisc;
}
wd_margin = wd_times[timeout][0];
@@ -383,13 +383,13 @@
return 0;
- out_noreboot:
- release_region(SBC8360_ENABLE, 1);
- release_region(SBC8360_BASETIME, 1);
- out_noenablereg:
- out_nobasetimereg:
- misc_deregister(&sbc8360_miscdev);
out_nomisc:
+ unregister_reboot_notifier(&sbc8360_notifier);
+ out_noreboot:
+ release_region(SBC8360_BASETIME, 1);
+ out_nobasetimereg:
+ release_region(SBC8360_ENABLE, 1);
+ out:
return res;
}
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index 337ee42..b46e7f4 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -1,5 +1,8 @@
/*
- * w83627hf WDT driver
+ * w83627hf/thf WDT driver
+ *
+ * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
+ * added support for W83627THF.
*
* (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
*
@@ -39,7 +42,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#define WATCHDOG_NAME "w83627hf WDT"
+#define WATCHDOG_NAME "w83627hf/thf WDT"
#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
@@ -50,7 +53,7 @@
/* You must set this - there is no sane way to probe for this board. */
static int wdt_io = 0x2E;
module_param(wdt_io, int, 0);
-MODULE_PARM_DESC(wdt_io, "w83627hf WDT io port (default 0x2E)");
+MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0);
@@ -71,9 +74,19 @@
static void
w83627hf_select_wd_register(void)
{
+ unsigned char c;
outb_p(0x87, WDT_EFER); /* Enter extended function mode */
outb_p(0x87, WDT_EFER); /* Again according to manual */
+ outb(0x20, WDT_EFER); /* check chip version */
+ c = inb(WDT_EFDR);
+ if (c == 0x82) { /* W83627THF */
+ outb_p(0x2b, WDT_EFER); /* select GPIO3 */
+ c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
+ outb_p(0x2b, WDT_EFER);
+ outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */
+ }
+
outb_p(0x07, WDT_EFER); /* point to logical device number reg */
outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
outb_p(0x30, WDT_EFER); /* select CR30 */
@@ -311,7 +324,7 @@
spin_lock_init(&io_lock);
- printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n");
+ printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n");
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
@@ -367,5 +380,5 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>");
-MODULE_DESCRIPTION("w83627hf WDT driver");
+MODULE_DESCRIPTION("w83627hf/thf WDT driver");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index f4c6345..e678a33 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -56,4 +56,26 @@
To compile this driver as a module, choose M here: the module
will be called geode-aes.
+config ZCRYPT
+ tristate "Support for PCI-attached cryptographic adapters"
+ depends on S390
+ select ZCRYPT_MONOLITHIC if ZCRYPT="y"
+ default "m"
+ help
+ Select this option if you want to use a PCI-attached cryptographic
+ adapter like:
+ + PCI Cryptographic Accelerator (PCICA)
+ + PCI Cryptographic Coprocessor (PCICC)
+ + PCI-X Cryptographic Coprocessor (PCIXCC)
+ + Crypto Express2 Coprocessor (CEX2C)
+ + Crypto Express2 Accelerator (CEX2A)
+
+config ZCRYPT_MONOLITHIC
+ bool "Monolithic zcrypt module"
+ depends on ZCRYPT="m"
+ help
+ Select this option if you want to have a single module z90crypt.ko
+ that contains all parts of the crypto device driver (ap bus,
+ request router and all the card drivers).
+
endmenu
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 30d021d..72be6c6 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -3,6 +3,7 @@
#
menu "DMA Engine support"
+ depends on !S390
config DMA_ENGINE
bool "Support for DMA engines"
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 4f08984..807c402 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -7,6 +7,7 @@
#
menu 'EDAC - error detection and reporting (RAS) (EXPERIMENTAL)'
+ depends on HAS_IOMEM
config EDAC
tristate "EDAC core system error reporting (EXPERIMENTAL)"
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
new file mode 100644
index 0000000..5932c72
--- /dev/null
+++ b/drivers/firewire/Kconfig
@@ -0,0 +1,61 @@
+# -*- shell-script -*-
+
+comment "An alternative FireWire stack is available with EXPERIMENTAL=y"
+ depends on EXPERIMENTAL=n
+
+config FIREWIRE
+ tristate "IEEE 1394 (FireWire) support (JUJU alternative stack, experimental)"
+ depends on EXPERIMENTAL
+ select CRC_ITU_T
+ help
+ IEEE 1394 describes a high performance serial bus, which is also
+ known as FireWire(tm) or i.Link(tm) and is used for connecting all
+ sorts of devices (most notably digital video cameras) to your
+ computer.
+
+ If you have FireWire hardware and want to use it, say Y here. This
+ is the core support only, you will also need to select a driver for
+ your IEEE 1394 adapter.
+
+ To compile this driver as a module, say M here: the module will be
+ called fw-core.
+
+ This is the "JUJU" FireWire stack, an alternative implementation
+ designed for robustness and simplicity. You can build either this
+ stack, or the classic stack (the ieee1394 driver, ohci1394 etc.)
+ or both.
+
+config FIREWIRE_OHCI
+ tristate "Support for OHCI FireWire host controllers"
+ depends on PCI && FIREWIRE
+ help
+ Enable this driver if you have a FireWire controller based
+ on the OHCI specification. For all practical purposes, this
+ is the only chipset in use, so say Y here.
+
+ To compile this driver as a module, say M here: The module will be
+ called fw-ohci.
+
+ If you also build ohci1394 of the classic IEEE 1394 driver stack,
+ blacklist either ohci1394 or fw-ohci to let hotplug load the desired
+ driver.
+
+config FIREWIRE_SBP2
+ tristate "Support for storage devices (SBP-2 protocol driver)"
+ depends on FIREWIRE && SCSI
+ help
+ This option enables you to use SBP-2 devices connected to a
+ FireWire bus. SBP-2 devices include storage devices like
+ harddisks and DVD drives, also some other FireWire devices
+ like scanners.
+
+ To compile this driver as a module, say M here: The module will be
+ called fw-sbp2.
+
+ You should also enable support for disks, CD-ROMs, etc. in the SCSI
+ configuration section.
+
+ If you also build sbp2 of the classic IEEE 1394 driver stack,
+ blacklist either sbp2 or fw-sbp2 to let hotplug load the desired
+ driver.
+
diff --git a/drivers/firewire/Makefile b/drivers/firewire/Makefile
new file mode 100644
index 0000000..fc7d59d
--- /dev/null
+++ b/drivers/firewire/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for the Linux IEEE 1394 implementation
+#
+
+fw-core-y += fw-card.o fw-topology.o fw-transaction.o fw-iso.o \
+ fw-device.o fw-cdev.o
+
+obj-$(CONFIG_FIREWIRE) += fw-core.o
+obj-$(CONFIG_FIREWIRE_OHCI) += fw-ohci.o
+obj-$(CONFIG_FIREWIRE_SBP2) += fw-sbp2.o
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
new file mode 100644
index 0000000..636151a
--- /dev/null
+++ b/drivers/firewire/fw-card.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/crc-itu-t.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+int fw_compute_block_crc(u32 *block)
+{
+ __be32 be32_block[256];
+ int i, length;
+
+ length = (*block >> 16) & 0xff;
+ for (i = 0; i < length; i++)
+ be32_block[i] = cpu_to_be32(block[i + 1]);
+ *block |= crc_itu_t(0, (u8 *) be32_block, length * 4);
+
+ return length;
+}
+
+static DEFINE_MUTEX(card_mutex);
+static LIST_HEAD(card_list);
+
+static LIST_HEAD(descriptor_list);
+static int descriptor_count;
+
+#define BIB_CRC(v) ((v) << 0)
+#define BIB_CRC_LENGTH(v) ((v) << 16)
+#define BIB_INFO_LENGTH(v) ((v) << 24)
+
+#define BIB_LINK_SPEED(v) ((v) << 0)
+#define BIB_GENERATION(v) ((v) << 4)
+#define BIB_MAX_ROM(v) ((v) << 8)
+#define BIB_MAX_RECEIVE(v) ((v) << 12)
+#define BIB_CYC_CLK_ACC(v) ((v) << 16)
+#define BIB_PMC ((1) << 27)
+#define BIB_BMC ((1) << 28)
+#define BIB_ISC ((1) << 29)
+#define BIB_CMC ((1) << 30)
+#define BIB_IMC ((1) << 31)
+
+static u32 *
+generate_config_rom(struct fw_card *card, size_t *config_rom_length)
+{
+ struct fw_descriptor *desc;
+ static u32 config_rom[256];
+ int i, j, length;
+
+ /*
+ * Initialize contents of config rom buffer. On the OHCI
+ * controller, block reads to the config rom accesses the host
+ * memory, but quadlet read access the hardware bus info block
+ * registers. That's just crack, but it means we should make
+ * sure the contents of bus info block in host memory mathces
+ * the version stored in the OHCI registers.
+ */
+
+ memset(config_rom, 0, sizeof(config_rom));
+ config_rom[0] = BIB_CRC_LENGTH(4) | BIB_INFO_LENGTH(4) | BIB_CRC(0);
+ config_rom[1] = 0x31333934;
+
+ config_rom[2] =
+ BIB_LINK_SPEED(card->link_speed) |
+ BIB_GENERATION(card->config_rom_generation++ % 14 + 2) |
+ BIB_MAX_ROM(2) |
+ BIB_MAX_RECEIVE(card->max_receive) |
+ BIB_BMC | BIB_ISC | BIB_CMC | BIB_IMC;
+ config_rom[3] = card->guid >> 32;
+ config_rom[4] = card->guid;
+
+ /* Generate root directory. */
+ i = 5;
+ config_rom[i++] = 0;
+ config_rom[i++] = 0x0c0083c0; /* node capabilities */
+ j = i + descriptor_count;
+
+ /* Generate root directory entries for descriptors. */
+ list_for_each_entry (desc, &descriptor_list, link) {
+ if (desc->immediate > 0)
+ config_rom[i++] = desc->immediate;
+ config_rom[i] = desc->key | (j - i);
+ i++;
+ j += desc->length;
+ }
+
+ /* Update root directory length. */
+ config_rom[5] = (i - 5 - 1) << 16;
+
+ /* End of root directory, now copy in descriptors. */
+ list_for_each_entry (desc, &descriptor_list, link) {
+ memcpy(&config_rom[i], desc->data, desc->length * 4);
+ i += desc->length;
+ }
+
+ /* Calculate CRCs for all blocks in the config rom. This
+ * assumes that CRC length and info length are identical for
+ * the bus info block, which is always the case for this
+ * implementation. */
+ for (i = 0; i < j; i += length + 1)
+ length = fw_compute_block_crc(config_rom + i);
+
+ *config_rom_length = j;
+
+ return config_rom;
+}
+
+static void
+update_config_roms(void)
+{
+ struct fw_card *card;
+ u32 *config_rom;
+ size_t length;
+
+ list_for_each_entry (card, &card_list, link) {
+ config_rom = generate_config_rom(card, &length);
+ card->driver->set_config_rom(card, config_rom, length);
+ }
+}
+
+int
+fw_core_add_descriptor(struct fw_descriptor *desc)
+{
+ size_t i;
+
+ /*
+ * Check descriptor is valid; the length of all blocks in the
+ * descriptor has to add up to exactly the length of the
+ * block.
+ */
+ i = 0;
+ while (i < desc->length)
+ i += (desc->data[i] >> 16) + 1;
+
+ if (i != desc->length)
+ return -EINVAL;
+
+ mutex_lock(&card_mutex);
+
+ list_add_tail(&desc->link, &descriptor_list);
+ descriptor_count++;
+ if (desc->immediate > 0)
+ descriptor_count++;
+ update_config_roms();
+
+ mutex_unlock(&card_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(fw_core_add_descriptor);
+
+void
+fw_core_remove_descriptor(struct fw_descriptor *desc)
+{
+ mutex_lock(&card_mutex);
+
+ list_del(&desc->link);
+ descriptor_count--;
+ if (desc->immediate > 0)
+ descriptor_count--;
+ update_config_roms();
+
+ mutex_unlock(&card_mutex);
+}
+EXPORT_SYMBOL(fw_core_remove_descriptor);
+
+static const char gap_count_table[] = {
+ 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40
+};
+
+struct bm_data {
+ struct fw_transaction t;
+ struct {
+ __be32 arg;
+ __be32 data;
+ } lock;
+ u32 old;
+ int rcode;
+ struct completion done;
+};
+
+static void
+complete_bm_lock(struct fw_card *card, int rcode,
+ void *payload, size_t length, void *data)
+{
+ struct bm_data *bmd = data;
+
+ if (rcode == RCODE_COMPLETE)
+ bmd->old = be32_to_cpu(*(__be32 *) payload);
+ bmd->rcode = rcode;
+ complete(&bmd->done);
+}
+
+static void
+fw_card_bm_work(struct work_struct *work)
+{
+ struct fw_card *card = container_of(work, struct fw_card, work.work);
+ struct fw_device *root;
+ struct bm_data bmd;
+ unsigned long flags;
+ int root_id, new_root_id, irm_id, gap_count, generation, grace;
+ int do_reset = 0;
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ generation = card->generation;
+ root = card->root_node->data;
+ root_id = card->root_node->node_id;
+ grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10));
+
+ if (card->bm_generation + 1 == generation ||
+ (card->bm_generation != generation && grace)) {
+ /*
+ * This first step is to figure out who is IRM and
+ * then try to become bus manager. If the IRM is not
+ * well defined (e.g. does not have an active link
+ * layer or does not responds to our lock request, we
+ * will have to do a little vigilante bus management.
+ * In that case, we do a goto into the gap count logic
+ * so that when we do the reset, we still optimize the
+ * gap count. That could well save a reset in the
+ * next generation.
+ */
+
+ irm_id = card->irm_node->node_id;
+ if (!card->irm_node->link_on) {
+ new_root_id = card->local_node->node_id;
+ fw_notify("IRM has link off, making local node (%02x) root.\n",
+ new_root_id);
+ goto pick_me;
+ }
+
+ bmd.lock.arg = cpu_to_be32(0x3f);
+ bmd.lock.data = cpu_to_be32(card->local_node->node_id);
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ init_completion(&bmd.done);
+ fw_send_request(card, &bmd.t, TCODE_LOCK_COMPARE_SWAP,
+ irm_id, generation,
+ SCODE_100, CSR_REGISTER_BASE + CSR_BUS_MANAGER_ID,
+ &bmd.lock, sizeof(bmd.lock),
+ complete_bm_lock, &bmd);
+ wait_for_completion(&bmd.done);
+
+ if (bmd.rcode == RCODE_GENERATION) {
+ /*
+ * Another bus reset happened. Just return,
+ * the BM work has been rescheduled.
+ */
+ return;
+ }
+
+ if (bmd.rcode == RCODE_COMPLETE && bmd.old != 0x3f)
+ /* Somebody else is BM, let them do the work. */
+ return;
+
+ spin_lock_irqsave(&card->lock, flags);
+ if (bmd.rcode != RCODE_COMPLETE) {
+ /*
+ * The lock request failed, maybe the IRM
+ * isn't really IRM capable after all. Let's
+ * do a bus reset and pick the local node as
+ * root, and thus, IRM.
+ */
+ new_root_id = card->local_node->node_id;
+ fw_notify("BM lock failed, making local node (%02x) root.\n",
+ new_root_id);
+ goto pick_me;
+ }
+ } else if (card->bm_generation != generation) {
+ /*
+ * OK, we weren't BM in the last generation, and it's
+ * less than 100ms since last bus reset. Reschedule
+ * this task 100ms from now.
+ */
+ spin_unlock_irqrestore(&card->lock, flags);
+ schedule_delayed_work(&card->work, DIV_ROUND_UP(HZ, 10));
+ return;
+ }
+
+ /*
+ * We're bus manager for this generation, so next step is to
+ * make sure we have an active cycle master and do gap count
+ * optimization.
+ */
+ card->bm_generation = generation;
+
+ if (root == NULL) {
+ /*
+ * Either link_on is false, or we failed to read the
+ * config rom. In either case, pick another root.
+ */
+ new_root_id = card->local_node->node_id;
+ } else if (atomic_read(&root->state) != FW_DEVICE_RUNNING) {
+ /*
+ * If we haven't probed this device yet, bail out now
+ * and let's try again once that's done.
+ */
+ spin_unlock_irqrestore(&card->lock, flags);
+ return;
+ } else if (root->config_rom[2] & BIB_CMC) {
+ /*
+ * FIXME: I suppose we should set the cmstr bit in the
+ * STATE_CLEAR register of this node, as described in
+ * 1394-1995, 8.4.2.6. Also, send out a force root
+ * packet for this node.
+ */
+ new_root_id = root_id;
+ } else {
+ /*
+ * Current root has an active link layer and we
+ * successfully read the config rom, but it's not
+ * cycle master capable.
+ */
+ new_root_id = card->local_node->node_id;
+ }
+
+ pick_me:
+ /* Now figure out what gap count to set. */
+ if (card->topology_type == FW_TOPOLOGY_A &&
+ card->root_node->max_hops < ARRAY_SIZE(gap_count_table))
+ gap_count = gap_count_table[card->root_node->max_hops];
+ else
+ gap_count = 63;
+
+ /*
+ * Finally, figure out if we should do a reset or not. If we've
+ * done less that 5 resets with the same physical topology and we
+ * have either a new root or a new gap count setting, let's do it.
+ */
+
+ if (card->bm_retries++ < 5 &&
+ (card->gap_count != gap_count || new_root_id != root_id))
+ do_reset = 1;
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (do_reset) {
+ fw_notify("phy config: card %d, new root=%x, gap_count=%d\n",
+ card->index, new_root_id, gap_count);
+ fw_send_phy_config(card, new_root_id, generation, gap_count);
+ fw_core_initiate_bus_reset(card, 1);
+ }
+}
+
+static void
+flush_timer_callback(unsigned long data)
+{
+ struct fw_card *card = (struct fw_card *)data;
+
+ fw_flush_transactions(card);
+}
+
+void
+fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
+ struct device *device)
+{
+ static atomic_t index = ATOMIC_INIT(-1);
+
+ kref_init(&card->kref);
+ card->index = atomic_inc_return(&index);
+ card->driver = driver;
+ card->device = device;
+ card->current_tlabel = 0;
+ card->tlabel_mask = 0;
+ card->color = 0;
+
+ INIT_LIST_HEAD(&card->transaction_list);
+ spin_lock_init(&card->lock);
+ setup_timer(&card->flush_timer,
+ flush_timer_callback, (unsigned long)card);
+
+ card->local_node = NULL;
+
+ INIT_DELAYED_WORK(&card->work, fw_card_bm_work);
+}
+EXPORT_SYMBOL(fw_card_initialize);
+
+int
+fw_card_add(struct fw_card *card,
+ u32 max_receive, u32 link_speed, u64 guid)
+{
+ u32 *config_rom;
+ size_t length;
+
+ card->max_receive = max_receive;
+ card->link_speed = link_speed;
+ card->guid = guid;
+
+ /* Activate link_on bit and contender bit in our self ID packets.*/
+ if (card->driver->update_phy_reg(card, 4, 0,
+ PHY_LINK_ACTIVE | PHY_CONTENDER) < 0)
+ return -EIO;
+
+ /*
+ * The subsystem grabs a reference when the card is added and
+ * drops it when the driver calls fw_core_remove_card.
+ */
+ fw_card_get(card);
+
+ mutex_lock(&card_mutex);
+ config_rom = generate_config_rom(card, &length);
+ list_add_tail(&card->link, &card_list);
+ mutex_unlock(&card_mutex);
+
+ return card->driver->enable(card, config_rom, length);
+}
+EXPORT_SYMBOL(fw_card_add);
+
+
+/*
+ * The next few functions implements a dummy driver that use once a
+ * card driver shuts down an fw_card. This allows the driver to
+ * cleanly unload, as all IO to the card will be handled by the dummy
+ * driver instead of calling into the (possibly) unloaded module. The
+ * dummy driver just fails all IO.
+ */
+
+static int
+dummy_enable(struct fw_card *card, u32 *config_rom, size_t length)
+{
+ BUG();
+ return -1;
+}
+
+static int
+dummy_update_phy_reg(struct fw_card *card, int address,
+ int clear_bits, int set_bits)
+{
+ return -ENODEV;
+}
+
+static int
+dummy_set_config_rom(struct fw_card *card,
+ u32 *config_rom, size_t length)
+{
+ /*
+ * We take the card out of card_list before setting the dummy
+ * driver, so this should never get called.
+ */
+ BUG();
+ return -1;
+}
+
+static void
+dummy_send_request(struct fw_card *card, struct fw_packet *packet)
+{
+ packet->callback(packet, card, -ENODEV);
+}
+
+static void
+dummy_send_response(struct fw_card *card, struct fw_packet *packet)
+{
+ packet->callback(packet, card, -ENODEV);
+}
+
+static int
+dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
+{
+ return -ENOENT;
+}
+
+static int
+dummy_enable_phys_dma(struct fw_card *card,
+ int node_id, int generation)
+{
+ return -ENODEV;
+}
+
+static struct fw_card_driver dummy_driver = {
+ .name = "dummy",
+ .enable = dummy_enable,
+ .update_phy_reg = dummy_update_phy_reg,
+ .set_config_rom = dummy_set_config_rom,
+ .send_request = dummy_send_request,
+ .cancel_packet = dummy_cancel_packet,
+ .send_response = dummy_send_response,
+ .enable_phys_dma = dummy_enable_phys_dma,
+};
+
+void
+fw_core_remove_card(struct fw_card *card)
+{
+ card->driver->update_phy_reg(card, 4,
+ PHY_LINK_ACTIVE | PHY_CONTENDER, 0);
+ fw_core_initiate_bus_reset(card, 1);
+
+ mutex_lock(&card_mutex);
+ list_del(&card->link);
+ mutex_unlock(&card_mutex);
+
+ /* Set up the dummy driver. */
+ card->driver = &dummy_driver;
+
+ fw_flush_transactions(card);
+
+ fw_destroy_nodes(card);
+
+ fw_card_put(card);
+}
+EXPORT_SYMBOL(fw_core_remove_card);
+
+struct fw_card *
+fw_card_get(struct fw_card *card)
+{
+ kref_get(&card->kref);
+
+ return card;
+}
+EXPORT_SYMBOL(fw_card_get);
+
+static void
+release_card(struct kref *kref)
+{
+ struct fw_card *card = container_of(kref, struct fw_card, kref);
+
+ kfree(card);
+}
+
+/*
+ * An assumption for fw_card_put() is that the card driver allocates
+ * the fw_card struct with kalloc and that it has been shut down
+ * before the last ref is dropped.
+ */
+void
+fw_card_put(struct fw_card *card)
+{
+ kref_put(&card->kref, release_card);
+}
+EXPORT_SYMBOL(fw_card_put);
+
+int
+fw_core_initiate_bus_reset(struct fw_card *card, int short_reset)
+{
+ int reg = short_reset ? 5 : 1;
+ int bit = short_reset ? PHY_BUS_SHORT_RESET : PHY_BUS_RESET;
+
+ return card->driver->update_phy_reg(card, reg, 0, bit);
+}
+EXPORT_SYMBOL(fw_core_initiate_bus_reset);
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
new file mode 100644
index 0000000..0fa5bd5
--- /dev/null
+++ b/drivers/firewire/fw-cdev.c
@@ -0,0 +1,961 @@
+/*
+ * Char device for device raw access
+ *
+ * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/vmalloc.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/idr.h>
+#include <linux/compat.h>
+#include <linux/firewire-cdev.h>
+#include <asm/uaccess.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+struct client;
+struct client_resource {
+ struct list_head link;
+ void (*release)(struct client *client, struct client_resource *r);
+ u32 handle;
+};
+
+/*
+ * dequeue_event() just kfree()'s the event, so the event has to be
+ * the first field in the struct.
+ */
+
+struct event {
+ struct { void *data; size_t size; } v[2];
+ struct list_head link;
+};
+
+struct bus_reset {
+ struct event event;
+ struct fw_cdev_event_bus_reset reset;
+};
+
+struct response {
+ struct event event;
+ struct fw_transaction transaction;
+ struct client *client;
+ struct client_resource resource;
+ struct fw_cdev_event_response response;
+};
+
+struct iso_interrupt {
+ struct event event;
+ struct fw_cdev_event_iso_interrupt interrupt;
+};
+
+struct client {
+ u32 version;
+ struct fw_device *device;
+ spinlock_t lock;
+ u32 resource_handle;
+ struct list_head resource_list;
+ struct list_head event_list;
+ wait_queue_head_t wait;
+ u64 bus_reset_closure;
+
+ struct fw_iso_context *iso_context;
+ u64 iso_closure;
+ struct fw_iso_buffer buffer;
+ unsigned long vm_start;
+
+ struct list_head link;
+};
+
+static inline void __user *
+u64_to_uptr(__u64 value)
+{
+ return (void __user *)(unsigned long)value;
+}
+
+static inline __u64
+uptr_to_u64(void __user *ptr)
+{
+ return (__u64)(unsigned long)ptr;
+}
+
+static int fw_device_op_open(struct inode *inode, struct file *file)
+{
+ struct fw_device *device;
+ struct client *client;
+ unsigned long flags;
+
+ device = fw_device_from_devt(inode->i_rdev);
+ if (device == NULL)
+ return -ENODEV;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+
+ client->device = fw_device_get(device);
+ INIT_LIST_HEAD(&client->event_list);
+ INIT_LIST_HEAD(&client->resource_list);
+ spin_lock_init(&client->lock);
+ init_waitqueue_head(&client->wait);
+
+ file->private_data = client;
+
+ spin_lock_irqsave(&device->card->lock, flags);
+ list_add_tail(&client->link, &device->client_list);
+ spin_unlock_irqrestore(&device->card->lock, flags);
+
+ return 0;
+}
+
+static void queue_event(struct client *client, struct event *event,
+ void *data0, size_t size0, void *data1, size_t size1)
+{
+ unsigned long flags;
+
+ event->v[0].data = data0;
+ event->v[0].size = size0;
+ event->v[1].data = data1;
+ event->v[1].size = size1;
+
+ spin_lock_irqsave(&client->lock, flags);
+
+ list_add_tail(&event->link, &client->event_list);
+ wake_up_interruptible(&client->wait);
+
+ spin_unlock_irqrestore(&client->lock, flags);
+}
+
+static int
+dequeue_event(struct client *client, char __user *buffer, size_t count)
+{
+ unsigned long flags;
+ struct event *event;
+ size_t size, total;
+ int i, retval;
+
+ retval = wait_event_interruptible(client->wait,
+ !list_empty(&client->event_list) ||
+ fw_device_is_shutdown(client->device));
+ if (retval < 0)
+ return retval;
+
+ if (list_empty(&client->event_list) &&
+ fw_device_is_shutdown(client->device))
+ return -ENODEV;
+
+ spin_lock_irqsave(&client->lock, flags);
+ event = container_of(client->event_list.next, struct event, link);
+ list_del(&event->link);
+ spin_unlock_irqrestore(&client->lock, flags);
+
+ total = 0;
+ for (i = 0; i < ARRAY_SIZE(event->v) && total < count; i++) {
+ size = min(event->v[i].size, count - total);
+ if (copy_to_user(buffer + total, event->v[i].data, size)) {
+ retval = -EFAULT;
+ goto out;
+ }
+ total += size;
+ }
+ retval = total;
+
+ out:
+ kfree(event);
+
+ return retval;
+}
+
+static ssize_t
+fw_device_op_read(struct file *file,
+ char __user *buffer, size_t count, loff_t *offset)
+{
+ struct client *client = file->private_data;
+
+ return dequeue_event(client, buffer, count);
+}
+
+static void
+fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
+ struct client *client)
+{
+ struct fw_card *card = client->device->card;
+
+ event->closure = client->bus_reset_closure;
+ event->type = FW_CDEV_EVENT_BUS_RESET;
+ event->node_id = client->device->node_id;
+ event->local_node_id = card->local_node->node_id;
+ event->bm_node_id = 0; /* FIXME: We don't track the BM. */
+ event->irm_node_id = card->irm_node->node_id;
+ event->root_node_id = card->root_node->node_id;
+ event->generation = card->generation;
+}
+
+static void
+for_each_client(struct fw_device *device,
+ void (*callback)(struct client *client))
+{
+ struct fw_card *card = device->card;
+ struct client *c;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ list_for_each_entry(c, &device->client_list, link)
+ callback(c);
+
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void
+queue_bus_reset_event(struct client *client)
+{
+ struct bus_reset *bus_reset;
+
+ bus_reset = kzalloc(sizeof(*bus_reset), GFP_ATOMIC);
+ if (bus_reset == NULL) {
+ fw_notify("Out of memory when allocating bus reset event\n");
+ return;
+ }
+
+ fill_bus_reset_event(&bus_reset->reset, client);
+
+ queue_event(client, &bus_reset->event,
+ &bus_reset->reset, sizeof(bus_reset->reset), NULL, 0);
+}
+
+void fw_device_cdev_update(struct fw_device *device)
+{
+ for_each_client(device, queue_bus_reset_event);
+}
+
+static void wake_up_client(struct client *client)
+{
+ wake_up_interruptible(&client->wait);
+}
+
+void fw_device_cdev_remove(struct fw_device *device)
+{
+ for_each_client(device, wake_up_client);
+}
+
+static int ioctl_get_info(struct client *client, void *buffer)
+{
+ struct fw_cdev_get_info *get_info = buffer;
+ struct fw_cdev_event_bus_reset bus_reset;
+
+ client->version = get_info->version;
+ get_info->version = FW_CDEV_VERSION;
+
+ if (get_info->rom != 0) {
+ void __user *uptr = u64_to_uptr(get_info->rom);
+ size_t want = get_info->rom_length;
+ size_t have = client->device->config_rom_length * 4;
+
+ if (copy_to_user(uptr, client->device->config_rom,
+ min(want, have)))
+ return -EFAULT;
+ }
+ get_info->rom_length = client->device->config_rom_length * 4;
+
+ client->bus_reset_closure = get_info->bus_reset_closure;
+ if (get_info->bus_reset != 0) {
+ void __user *uptr = u64_to_uptr(get_info->bus_reset);
+
+ fill_bus_reset_event(&bus_reset, client);
+ if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
+ return -EFAULT;
+ }
+
+ get_info->card = client->device->card->index;
+
+ return 0;
+}
+
+static void
+add_client_resource(struct client *client, struct client_resource *resource)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&client->lock, flags);
+ list_add_tail(&resource->link, &client->resource_list);
+ resource->handle = client->resource_handle++;
+ spin_unlock_irqrestore(&client->lock, flags);
+}
+
+static int
+release_client_resource(struct client *client, u32 handle,
+ struct client_resource **resource)
+{
+ struct client_resource *r;
+ unsigned long flags;
+
+ spin_lock_irqsave(&client->lock, flags);
+ list_for_each_entry(r, &client->resource_list, link) {
+ if (r->handle == handle) {
+ list_del(&r->link);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&client->lock, flags);
+
+ if (&r->link == &client->resource_list)
+ return -EINVAL;
+
+ if (resource)
+ *resource = r;
+ else
+ r->release(client, r);
+
+ return 0;
+}
+
+static void
+release_transaction(struct client *client, struct client_resource *resource)
+{
+ struct response *response =
+ container_of(resource, struct response, resource);
+
+ fw_cancel_transaction(client->device->card, &response->transaction);
+}
+
+static void
+complete_transaction(struct fw_card *card, int rcode,
+ void *payload, size_t length, void *data)
+{
+ struct response *response = data;
+ struct client *client = response->client;
+ unsigned long flags;
+
+ if (length < response->response.length)
+ response->response.length = length;
+ if (rcode == RCODE_COMPLETE)
+ memcpy(response->response.data, payload,
+ response->response.length);
+
+ spin_lock_irqsave(&client->lock, flags);
+ list_del(&response->resource.link);
+ spin_unlock_irqrestore(&client->lock, flags);
+
+ response->response.type = FW_CDEV_EVENT_RESPONSE;
+ response->response.rcode = rcode;
+ queue_event(client, &response->event,
+ &response->response, sizeof(response->response),
+ response->response.data, response->response.length);
+}
+
+static ssize_t ioctl_send_request(struct client *client, void *buffer)
+{
+ struct fw_device *device = client->device;
+ struct fw_cdev_send_request *request = buffer;
+ struct response *response;
+
+ /* What is the biggest size we'll accept, really? */
+ if (request->length > 4096)
+ return -EINVAL;
+
+ response = kmalloc(sizeof(*response) + request->length, GFP_KERNEL);
+ if (response == NULL)
+ return -ENOMEM;
+
+ response->client = client;
+ response->response.length = request->length;
+ response->response.closure = request->closure;
+
+ if (request->data &&
+ copy_from_user(response->response.data,
+ u64_to_uptr(request->data), request->length)) {
+ kfree(response);
+ return -EFAULT;
+ }
+
+ response->resource.release = release_transaction;
+ add_client_resource(client, &response->resource);
+
+ fw_send_request(device->card, &response->transaction,
+ request->tcode & 0x1f,
+ device->node->node_id,
+ request->generation,
+ device->node->max_speed,
+ request->offset,
+ response->response.data, request->length,
+ complete_transaction, response);
+
+ if (request->data)
+ return sizeof(request) + request->length;
+ else
+ return sizeof(request);
+}
+
+struct address_handler {
+ struct fw_address_handler handler;
+ __u64 closure;
+ struct client *client;
+ struct client_resource resource;
+};
+
+struct request {
+ struct fw_request *request;
+ void *data;
+ size_t length;
+ struct client_resource resource;
+};
+
+struct request_event {
+ struct event event;
+ struct fw_cdev_event_request request;
+};
+
+static void
+release_request(struct client *client, struct client_resource *resource)
+{
+ struct request *request =
+ container_of(resource, struct request, resource);
+
+ fw_send_response(client->device->card, request->request,
+ RCODE_CONFLICT_ERROR);
+ kfree(request);
+}
+
+static void
+handle_request(struct fw_card *card, struct fw_request *r,
+ int tcode, int destination, int source,
+ int generation, int speed,
+ unsigned long long offset,
+ void *payload, size_t length, void *callback_data)
+{
+ struct address_handler *handler = callback_data;
+ struct request *request;
+ struct request_event *e;
+ struct client *client = handler->client;
+
+ request = kmalloc(sizeof(*request), GFP_ATOMIC);
+ e = kmalloc(sizeof(*e), GFP_ATOMIC);
+ if (request == NULL || e == NULL) {
+ kfree(request);
+ kfree(e);
+ fw_send_response(card, r, RCODE_CONFLICT_ERROR);
+ return;
+ }
+
+ request->request = r;
+ request->data = payload;
+ request->length = length;
+
+ request->resource.release = release_request;
+ add_client_resource(client, &request->resource);
+
+ e->request.type = FW_CDEV_EVENT_REQUEST;
+ e->request.tcode = tcode;
+ e->request.offset = offset;
+ e->request.length = length;
+ e->request.handle = request->resource.handle;
+ e->request.closure = handler->closure;
+
+ queue_event(client, &e->event,
+ &e->request, sizeof(e->request), payload, length);
+}
+
+static void
+release_address_handler(struct client *client,
+ struct client_resource *resource)
+{
+ struct address_handler *handler =
+ container_of(resource, struct address_handler, resource);
+
+ fw_core_remove_address_handler(&handler->handler);
+ kfree(handler);
+}
+
+static int ioctl_allocate(struct client *client, void *buffer)
+{
+ struct fw_cdev_allocate *request = buffer;
+ struct address_handler *handler;
+ struct fw_address_region region;
+
+ handler = kmalloc(sizeof(*handler), GFP_KERNEL);
+ if (handler == NULL)
+ return -ENOMEM;
+
+ region.start = request->offset;
+ region.end = request->offset + request->length;
+ handler->handler.length = request->length;
+ handler->handler.address_callback = handle_request;
+ handler->handler.callback_data = handler;
+ handler->closure = request->closure;
+ handler->client = client;
+
+ if (fw_core_add_address_handler(&handler->handler, ®ion) < 0) {
+ kfree(handler);
+ return -EBUSY;
+ }
+
+ handler->resource.release = release_address_handler;
+ add_client_resource(client, &handler->resource);
+ request->handle = handler->resource.handle;
+
+ return 0;
+}
+
+static int ioctl_deallocate(struct client *client, void *buffer)
+{
+ struct fw_cdev_deallocate *request = buffer;
+
+ return release_client_resource(client, request->handle, NULL);
+}
+
+static int ioctl_send_response(struct client *client, void *buffer)
+{
+ struct fw_cdev_send_response *request = buffer;
+ struct client_resource *resource;
+ struct request *r;
+
+ if (release_client_resource(client, request->handle, &resource) < 0)
+ return -EINVAL;
+ r = container_of(resource, struct request, resource);
+ if (request->length < r->length)
+ r->length = request->length;
+ if (copy_from_user(r->data, u64_to_uptr(request->data), r->length))
+ return -EFAULT;
+
+ fw_send_response(client->device->card, r->request, request->rcode);
+ kfree(r);
+
+ return 0;
+}
+
+static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
+{
+ struct fw_cdev_initiate_bus_reset *request = buffer;
+ int short_reset;
+
+ short_reset = (request->type == FW_CDEV_SHORT_RESET);
+
+ return fw_core_initiate_bus_reset(client->device->card, short_reset);
+}
+
+struct descriptor {
+ struct fw_descriptor d;
+ struct client_resource resource;
+ u32 data[0];
+};
+
+static void release_descriptor(struct client *client,
+ struct client_resource *resource)
+{
+ struct descriptor *descriptor =
+ container_of(resource, struct descriptor, resource);
+
+ fw_core_remove_descriptor(&descriptor->d);
+ kfree(descriptor);
+}
+
+static int ioctl_add_descriptor(struct client *client, void *buffer)
+{
+ struct fw_cdev_add_descriptor *request = buffer;
+ struct descriptor *descriptor;
+ int retval;
+
+ if (request->length > 256)
+ return -EINVAL;
+
+ descriptor =
+ kmalloc(sizeof(*descriptor) + request->length * 4, GFP_KERNEL);
+ if (descriptor == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(descriptor->data,
+ u64_to_uptr(request->data), request->length * 4)) {
+ kfree(descriptor);
+ return -EFAULT;
+ }
+
+ descriptor->d.length = request->length;
+ descriptor->d.immediate = request->immediate;
+ descriptor->d.key = request->key;
+ descriptor->d.data = descriptor->data;
+
+ retval = fw_core_add_descriptor(&descriptor->d);
+ if (retval < 0) {
+ kfree(descriptor);
+ return retval;
+ }
+
+ descriptor->resource.release = release_descriptor;
+ add_client_resource(client, &descriptor->resource);
+ request->handle = descriptor->resource.handle;
+
+ return 0;
+}
+
+static int ioctl_remove_descriptor(struct client *client, void *buffer)
+{
+ struct fw_cdev_remove_descriptor *request = buffer;
+
+ return release_client_resource(client, request->handle, NULL);
+}
+
+static void
+iso_callback(struct fw_iso_context *context, u32 cycle,
+ size_t header_length, void *header, void *data)
+{
+ struct client *client = data;
+ struct iso_interrupt *interrupt;
+
+ interrupt = kzalloc(sizeof(*interrupt) + header_length, GFP_ATOMIC);
+ if (interrupt == NULL)
+ return;
+
+ interrupt->interrupt.type = FW_CDEV_EVENT_ISO_INTERRUPT;
+ interrupt->interrupt.closure = client->iso_closure;
+ interrupt->interrupt.cycle = cycle;
+ interrupt->interrupt.header_length = header_length;
+ memcpy(interrupt->interrupt.header, header, header_length);
+ queue_event(client, &interrupt->event,
+ &interrupt->interrupt,
+ sizeof(interrupt->interrupt) + header_length, NULL, 0);
+}
+
+static int ioctl_create_iso_context(struct client *client, void *buffer)
+{
+ struct fw_cdev_create_iso_context *request = buffer;
+
+ if (request->channel > 63)
+ return -EINVAL;
+
+ switch (request->type) {
+ case FW_ISO_CONTEXT_RECEIVE:
+ if (request->header_size < 4 || (request->header_size & 3))
+ return -EINVAL;
+
+ break;
+
+ case FW_ISO_CONTEXT_TRANSMIT:
+ if (request->speed > SCODE_3200)
+ return -EINVAL;
+
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ client->iso_closure = request->closure;
+ client->iso_context = fw_iso_context_create(client->device->card,
+ request->type,
+ request->channel,
+ request->speed,
+ request->header_size,
+ iso_callback, client);
+ if (IS_ERR(client->iso_context))
+ return PTR_ERR(client->iso_context);
+
+ /* We only support one context at this time. */
+ request->handle = 0;
+
+ return 0;
+}
+
+static int ioctl_queue_iso(struct client *client, void *buffer)
+{
+ struct fw_cdev_queue_iso *request = buffer;
+ struct fw_cdev_iso_packet __user *p, *end, *next;
+ struct fw_iso_context *ctx = client->iso_context;
+ unsigned long payload, buffer_end, header_length;
+ int count;
+ struct {
+ struct fw_iso_packet packet;
+ u8 header[256];
+ } u;
+
+ if (ctx == NULL || request->handle != 0)
+ return -EINVAL;
+
+ /*
+ * If the user passes a non-NULL data pointer, has mmap()'ed
+ * the iso buffer, and the pointer points inside the buffer,
+ * we setup the payload pointers accordingly. Otherwise we
+ * set them both to 0, which will still let packets with
+ * payload_length == 0 through. In other words, if no packets
+ * use the indirect payload, the iso buffer need not be mapped
+ * and the request->data pointer is ignored.
+ */
+
+ payload = (unsigned long)request->data - client->vm_start;
+ buffer_end = client->buffer.page_count << PAGE_SHIFT;
+ if (request->data == 0 || client->buffer.pages == NULL ||
+ payload >= buffer_end) {
+ payload = 0;
+ buffer_end = 0;
+ }
+
+ if (!access_ok(VERIFY_READ, request->packets, request->size))
+ return -EFAULT;
+
+ p = (struct fw_cdev_iso_packet __user *)u64_to_uptr(request->packets);
+ end = (void __user *)p + request->size;
+ count = 0;
+ while (p < end) {
+ if (__copy_from_user(&u.packet, p, sizeof(*p)))
+ return -EFAULT;
+
+ if (ctx->type == FW_ISO_CONTEXT_TRANSMIT) {
+ header_length = u.packet.header_length;
+ } else {
+ /*
+ * We require that header_length is a multiple of
+ * the fixed header size, ctx->header_size.
+ */
+ if (ctx->header_size == 0) {
+ if (u.packet.header_length > 0)
+ return -EINVAL;
+ } else if (u.packet.header_length % ctx->header_size != 0) {
+ return -EINVAL;
+ }
+ header_length = 0;
+ }
+
+ next = (struct fw_cdev_iso_packet __user *)
+ &p->header[header_length / 4];
+ if (next > end)
+ return -EINVAL;
+ if (__copy_from_user
+ (u.packet.header, p->header, header_length))
+ return -EFAULT;
+ if (u.packet.skip && ctx->type == FW_ISO_CONTEXT_TRANSMIT &&
+ u.packet.header_length + u.packet.payload_length > 0)
+ return -EINVAL;
+ if (payload + u.packet.payload_length > buffer_end)
+ return -EINVAL;
+
+ if (fw_iso_context_queue(ctx, &u.packet,
+ &client->buffer, payload))
+ break;
+
+ p = next;
+ payload += u.packet.payload_length;
+ count++;
+ }
+
+ request->size -= uptr_to_u64(p) - request->packets;
+ request->packets = uptr_to_u64(p);
+ request->data = client->vm_start + payload;
+
+ return count;
+}
+
+static int ioctl_start_iso(struct client *client, void *buffer)
+{
+ struct fw_cdev_start_iso *request = buffer;
+
+ if (request->handle != 0)
+ return -EINVAL;
+ if (client->iso_context->type == FW_ISO_CONTEXT_RECEIVE) {
+ if (request->tags == 0 || request->tags > 15)
+ return -EINVAL;
+
+ if (request->sync > 15)
+ return -EINVAL;
+ }
+
+ return fw_iso_context_start(client->iso_context, request->cycle,
+ request->sync, request->tags);
+}
+
+static int ioctl_stop_iso(struct client *client, void *buffer)
+{
+ struct fw_cdev_stop_iso *request = buffer;
+
+ if (request->handle != 0)
+ return -EINVAL;
+
+ return fw_iso_context_stop(client->iso_context);
+}
+
+static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
+ ioctl_get_info,
+ ioctl_send_request,
+ ioctl_allocate,
+ ioctl_deallocate,
+ ioctl_send_response,
+ ioctl_initiate_bus_reset,
+ ioctl_add_descriptor,
+ ioctl_remove_descriptor,
+ ioctl_create_iso_context,
+ ioctl_queue_iso,
+ ioctl_start_iso,
+ ioctl_stop_iso,
+};
+
+static int
+dispatch_ioctl(struct client *client, unsigned int cmd, void __user *arg)
+{
+ char buffer[256];
+ int retval;
+
+ if (_IOC_TYPE(cmd) != '#' ||
+ _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
+ return -EINVAL;
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ if (_IOC_SIZE(cmd) > sizeof(buffer) ||
+ copy_from_user(buffer, arg, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ }
+
+ retval = ioctl_handlers[_IOC_NR(cmd)](client, buffer);
+ if (retval < 0)
+ return retval;
+
+ if (_IOC_DIR(cmd) & _IOC_READ) {
+ if (_IOC_SIZE(cmd) > sizeof(buffer) ||
+ copy_to_user(arg, buffer, _IOC_SIZE(cmd)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static long
+fw_device_op_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct client *client = file->private_data;
+
+ return dispatch_ioctl(client, cmd, (void __user *) arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long
+fw_device_op_compat_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct client *client = file->private_data;
+
+ return dispatch_ioctl(client, cmd, compat_ptr(arg));
+}
+#endif
+
+static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct client *client = file->private_data;
+ enum dma_data_direction direction;
+ unsigned long size;
+ int page_count, retval;
+
+ /* FIXME: We could support multiple buffers, but we don't. */
+ if (client->buffer.pages != NULL)
+ return -EBUSY;
+
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ if (vma->vm_start & ~PAGE_MASK)
+ return -EINVAL;
+
+ client->vm_start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+ page_count = size >> PAGE_SHIFT;
+ if (size & ~PAGE_MASK)
+ return -EINVAL;
+
+ if (vma->vm_flags & VM_WRITE)
+ direction = DMA_TO_DEVICE;
+ else
+ direction = DMA_FROM_DEVICE;
+
+ retval = fw_iso_buffer_init(&client->buffer, client->device->card,
+ page_count, direction);
+ if (retval < 0)
+ return retval;
+
+ retval = fw_iso_buffer_map(&client->buffer, vma);
+ if (retval < 0)
+ fw_iso_buffer_destroy(&client->buffer, client->device->card);
+
+ return retval;
+}
+
+static int fw_device_op_release(struct inode *inode, struct file *file)
+{
+ struct client *client = file->private_data;
+ struct event *e, *next_e;
+ struct client_resource *r, *next_r;
+ unsigned long flags;
+
+ if (client->buffer.pages)
+ fw_iso_buffer_destroy(&client->buffer, client->device->card);
+
+ if (client->iso_context)
+ fw_iso_context_destroy(client->iso_context);
+
+ list_for_each_entry_safe(r, next_r, &client->resource_list, link)
+ r->release(client, r);
+
+ /*
+ * FIXME: We should wait for the async tasklets to stop
+ * running before freeing the memory.
+ */
+
+ list_for_each_entry_safe(e, next_e, &client->event_list, link)
+ kfree(e);
+
+ spin_lock_irqsave(&client->device->card->lock, flags);
+ list_del(&client->link);
+ spin_unlock_irqrestore(&client->device->card->lock, flags);
+
+ fw_device_put(client->device);
+ kfree(client);
+
+ return 0;
+}
+
+static unsigned int fw_device_op_poll(struct file *file, poll_table * pt)
+{
+ struct client *client = file->private_data;
+ unsigned int mask = 0;
+
+ poll_wait(file, &client->wait, pt);
+
+ if (fw_device_is_shutdown(client->device))
+ mask |= POLLHUP | POLLERR;
+ if (!list_empty(&client->event_list))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+const struct file_operations fw_device_ops = {
+ .owner = THIS_MODULE,
+ .open = fw_device_op_open,
+ .read = fw_device_op_read,
+ .unlocked_ioctl = fw_device_op_ioctl,
+ .poll = fw_device_op_poll,
+ .release = fw_device_op_release,
+ .mmap = fw_device_op_mmap,
+
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = fw_device_op_compat_ioctl,
+#endif
+};
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
new file mode 100644
index 0000000..c1ce465
--- /dev/null
+++ b/drivers/firewire/fw-device.c
@@ -0,0 +1,813 @@
+/*
+ * Device probing and sysfs code.
+ *
+ * Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/kthread.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/rwsem.h>
+#include <asm/semaphore.h>
+#include <linux/ctype.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 * p)
+{
+ ci->p = p + 1;
+ ci->end = ci->p + (p[0] >> 16);
+}
+EXPORT_SYMBOL(fw_csr_iterator_init);
+
+int fw_csr_iterator_next(struct fw_csr_iterator *ci, int *key, int *value)
+{
+ *key = *ci->p >> 24;
+ *value = *ci->p & 0xffffff;
+
+ return ci->p++ < ci->end;
+}
+EXPORT_SYMBOL(fw_csr_iterator_next);
+
+static int is_fw_unit(struct device *dev);
+
+static int match_unit_directory(u32 * directory, const struct fw_device_id *id)
+{
+ struct fw_csr_iterator ci;
+ int key, value, match;
+
+ match = 0;
+ fw_csr_iterator_init(&ci, directory);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ if (key == CSR_VENDOR && value == id->vendor)
+ match |= FW_MATCH_VENDOR;
+ if (key == CSR_MODEL && value == id->model)
+ match |= FW_MATCH_MODEL;
+ if (key == CSR_SPECIFIER_ID && value == id->specifier_id)
+ match |= FW_MATCH_SPECIFIER_ID;
+ if (key == CSR_VERSION && value == id->version)
+ match |= FW_MATCH_VERSION;
+ }
+
+ return (match & id->match_flags) == id->match_flags;
+}
+
+static int fw_unit_match(struct device *dev, struct device_driver *drv)
+{
+ struct fw_unit *unit = fw_unit(dev);
+ struct fw_driver *driver = fw_driver(drv);
+ int i;
+
+ /* We only allow binding to fw_units. */
+ if (!is_fw_unit(dev))
+ return 0;
+
+ for (i = 0; driver->id_table[i].match_flags != 0; i++) {
+ if (match_unit_directory(unit->directory, &driver->id_table[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)
+{
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct fw_csr_iterator ci;
+
+ int key, value;
+ int vendor = 0;
+ int model = 0;
+ int specifier_id = 0;
+ int version = 0;
+
+ fw_csr_iterator_init(&ci, &device->config_rom[5]);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ switch (key) {
+ case CSR_VENDOR:
+ vendor = value;
+ break;
+ case CSR_MODEL:
+ model = value;
+ break;
+ }
+ }
+
+ fw_csr_iterator_init(&ci, unit->directory);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ switch (key) {
+ case CSR_SPECIFIER_ID:
+ specifier_id = value;
+ break;
+ case CSR_VERSION:
+ version = value;
+ break;
+ }
+ }
+
+ return snprintf(buffer, buffer_size,
+ "ieee1394:ven%08Xmo%08Xsp%08Xver%08X",
+ vendor, model, specifier_id, version);
+}
+
+static int
+fw_unit_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct fw_unit *unit = fw_unit(dev);
+ char modalias[64];
+ int length = 0;
+ int i = 0;
+
+ get_modalias(unit, modalias, sizeof(modalias));
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "MODALIAS=%s", modalias))
+ return -ENOMEM;
+
+ envp[i] = NULL;
+
+ return 0;
+}
+
+struct bus_type fw_bus_type = {
+ .name = "firewire",
+ .match = fw_unit_match,
+};
+EXPORT_SYMBOL(fw_bus_type);
+
+struct fw_device *fw_device_get(struct fw_device *device)
+{
+ get_device(&device->device);
+
+ return device;
+}
+
+void fw_device_put(struct fw_device *device)
+{
+ put_device(&device->device);
+}
+
+static void fw_device_release(struct device *dev)
+{
+ struct fw_device *device = fw_device(dev);
+ unsigned long flags;
+
+ /*
+ * Take the card lock so we don't set this to NULL while a
+ * FW_NODE_UPDATED callback is being handled.
+ */
+ spin_lock_irqsave(&device->card->lock, flags);
+ device->node->data = NULL;
+ spin_unlock_irqrestore(&device->card->lock, flags);
+
+ fw_node_put(device->node);
+ fw_card_put(device->card);
+ kfree(device->config_rom);
+ kfree(device);
+}
+
+int fw_device_enable_phys_dma(struct fw_device *device)
+{
+ return device->card->driver->enable_phys_dma(device->card,
+ device->node_id,
+ device->generation);
+}
+EXPORT_SYMBOL(fw_device_enable_phys_dma);
+
+struct config_rom_attribute {
+ struct device_attribute attr;
+ u32 key;
+};
+
+static ssize_t
+show_immediate(struct device *dev, struct device_attribute *dattr, char *buf)
+{
+ struct config_rom_attribute *attr =
+ container_of(dattr, struct config_rom_attribute, attr);
+ struct fw_csr_iterator ci;
+ u32 *dir;
+ int key, value;
+
+ if (is_fw_unit(dev))
+ dir = fw_unit(dev)->directory;
+ else
+ dir = fw_device(dev)->config_rom + 5;
+
+ fw_csr_iterator_init(&ci, dir);
+ while (fw_csr_iterator_next(&ci, &key, &value))
+ if (attr->key == key)
+ return snprintf(buf, buf ? PAGE_SIZE : 0,
+ "0x%06x\n", value);
+
+ return -ENOENT;
+}
+
+#define IMMEDIATE_ATTR(name, key) \
+ { __ATTR(name, S_IRUGO, show_immediate, NULL), key }
+
+static ssize_t
+show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf)
+{
+ struct config_rom_attribute *attr =
+ container_of(dattr, struct config_rom_attribute, attr);
+ struct fw_csr_iterator ci;
+ u32 *dir, *block = NULL, *p, *end;
+ int length, key, value, last_key = 0;
+ char *b;
+
+ if (is_fw_unit(dev))
+ dir = fw_unit(dev)->directory;
+ else
+ dir = fw_device(dev)->config_rom + 5;
+
+ fw_csr_iterator_init(&ci, dir);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ if (attr->key == last_key &&
+ key == (CSR_DESCRIPTOR | CSR_LEAF))
+ block = ci.p - 1 + value;
+ last_key = key;
+ }
+
+ if (block == NULL)
+ return -ENOENT;
+
+ length = min(block[0] >> 16, 256U);
+ if (length < 3)
+ return -ENOENT;
+
+ if (block[1] != 0 || block[2] != 0)
+ /* Unknown encoding. */
+ return -ENOENT;
+
+ if (buf == NULL)
+ return length * 4;
+
+ b = buf;
+ end = &block[length + 1];
+ for (p = &block[3]; p < end; p++, b += 4)
+ * (u32 *) b = (__force u32) __cpu_to_be32(*p);
+
+ /* Strip trailing whitespace and add newline. */
+ while (b--, (isspace(*b) || *b == '\0') && b > buf);
+ strcpy(b + 1, "\n");
+
+ return b + 2 - buf;
+}
+
+#define TEXT_LEAF_ATTR(name, key) \
+ { __ATTR(name, S_IRUGO, show_text_leaf, NULL), key }
+
+static struct config_rom_attribute config_rom_attributes[] = {
+ IMMEDIATE_ATTR(vendor, CSR_VENDOR),
+ IMMEDIATE_ATTR(hardware_version, CSR_HARDWARE_VERSION),
+ IMMEDIATE_ATTR(specifier_id, CSR_SPECIFIER_ID),
+ IMMEDIATE_ATTR(version, CSR_VERSION),
+ IMMEDIATE_ATTR(model, CSR_MODEL),
+ TEXT_LEAF_ATTR(vendor_name, CSR_VENDOR),
+ TEXT_LEAF_ATTR(model_name, CSR_MODEL),
+ TEXT_LEAF_ATTR(hardware_version_name, CSR_HARDWARE_VERSION),
+};
+
+static void
+init_fw_attribute_group(struct device *dev,
+ struct device_attribute *attrs,
+ struct fw_attribute_group *group)
+{
+ struct device_attribute *attr;
+ int i, j;
+
+ for (j = 0; attrs[j].attr.name != NULL; j++)
+ group->attrs[j] = &attrs[j].attr;
+
+ for (i = 0; i < ARRAY_SIZE(config_rom_attributes); i++) {
+ attr = &config_rom_attributes[i].attr;
+ if (attr->show(dev, attr, NULL) < 0)
+ continue;
+ group->attrs[j++] = &attr->attr;
+ }
+
+ BUG_ON(j >= ARRAY_SIZE(group->attrs));
+ group->attrs[j++] = NULL;
+ group->groups[0] = &group->group;
+ group->groups[1] = NULL;
+ group->group.attrs = group->attrs;
+ dev->groups = group->groups;
+}
+
+static ssize_t
+modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fw_unit *unit = fw_unit(dev);
+ int length;
+
+ length = get_modalias(unit, buf, PAGE_SIZE);
+ strcpy(buf + length, "\n");
+
+ return length + 1;
+}
+
+static ssize_t
+rom_index_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fw_device *device = fw_device(dev->parent);
+ struct fw_unit *unit = fw_unit(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ (int)(unit->directory - device->config_rom));
+}
+
+static struct device_attribute fw_unit_attributes[] = {
+ __ATTR_RO(modalias),
+ __ATTR_RO(rom_index),
+ __ATTR_NULL,
+};
+
+static ssize_t
+config_rom_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct fw_device *device = fw_device(dev);
+
+ memcpy(buf, device->config_rom, device->config_rom_length * 4);
+
+ return device->config_rom_length * 4;
+}
+
+static ssize_t
+guid_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct fw_device *device = fw_device(dev);
+ u64 guid;
+
+ guid = ((u64)device->config_rom[3] << 32) | device->config_rom[4];
+
+ return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
+ (unsigned long long)guid);
+}
+
+static struct device_attribute fw_device_attributes[] = {
+ __ATTR_RO(config_rom),
+ __ATTR_RO(guid),
+ __ATTR_NULL,
+};
+
+struct read_quadlet_callback_data {
+ struct completion done;
+ int rcode;
+ u32 data;
+};
+
+static void
+complete_transaction(struct fw_card *card, int rcode,
+ void *payload, size_t length, void *data)
+{
+ struct read_quadlet_callback_data *callback_data = data;
+
+ if (rcode == RCODE_COMPLETE)
+ callback_data->data = be32_to_cpu(*(__be32 *)payload);
+ callback_data->rcode = rcode;
+ complete(&callback_data->done);
+}
+
+static int read_rom(struct fw_device *device, int index, u32 * data)
+{
+ struct read_quadlet_callback_data callback_data;
+ struct fw_transaction t;
+ u64 offset;
+
+ init_completion(&callback_data.done);
+
+ offset = 0xfffff0000400ULL + index * 4;
+ fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST,
+ device->node_id,
+ device->generation, SCODE_100,
+ offset, NULL, 4, complete_transaction, &callback_data);
+
+ wait_for_completion(&callback_data.done);
+
+ *data = callback_data.data;
+
+ return callback_data.rcode;
+}
+
+static int read_bus_info_block(struct fw_device *device)
+{
+ static u32 rom[256];
+ u32 stack[16], sp, key;
+ int i, end, length;
+
+ /* First read the bus info block. */
+ for (i = 0; i < 5; i++) {
+ if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+ return -1;
+ /*
+ * As per IEEE1212 7.2, during power-up, devices can
+ * reply with a 0 for the first quadlet of the config
+ * rom to indicate that they are booting (for example,
+ * if the firmware is on the disk of a external
+ * harddisk). In that case we just fail, and the
+ * retry mechanism will try again later.
+ */
+ if (i == 0 && rom[i] == 0)
+ return -1;
+ }
+
+ /*
+ * Now parse the config rom. The config rom is a recursive
+ * directory structure so we parse it using a stack of
+ * references to the blocks that make up the structure. We
+ * push a reference to the root directory on the stack to
+ * start things off.
+ */
+ length = i;
+ sp = 0;
+ stack[sp++] = 0xc0000005;
+ while (sp > 0) {
+ /*
+ * Pop the next block reference of the stack. The
+ * lower 24 bits is the offset into the config rom,
+ * the upper 8 bits are the type of the reference the
+ * block.
+ */
+ key = stack[--sp];
+ i = key & 0xffffff;
+ if (i >= ARRAY_SIZE(rom))
+ /*
+ * The reference points outside the standard
+ * config rom area, something's fishy.
+ */
+ return -1;
+
+ /* Read header quadlet for the block to get the length. */
+ if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+ return -1;
+ end = i + (rom[i] >> 16) + 1;
+ i++;
+ if (end > ARRAY_SIZE(rom))
+ /*
+ * This block extends outside standard config
+ * area (and the array we're reading it
+ * into). That's broken, so ignore this
+ * device.
+ */
+ return -1;
+
+ /*
+ * Now read in the block. If this is a directory
+ * block, check the entries as we read them to see if
+ * it references another block, and push it in that case.
+ */
+ while (i < end) {
+ if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE)
+ return -1;
+ if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
+ sp < ARRAY_SIZE(stack))
+ stack[sp++] = i + rom[i];
+ i++;
+ }
+ if (length < i)
+ length = i;
+ }
+
+ device->config_rom = kmalloc(length * 4, GFP_KERNEL);
+ if (device->config_rom == NULL)
+ return -1;
+ memcpy(device->config_rom, rom, length * 4);
+ device->config_rom_length = length;
+
+ return 0;
+}
+
+static void fw_unit_release(struct device *dev)
+{
+ struct fw_unit *unit = fw_unit(dev);
+
+ kfree(unit);
+}
+
+static struct device_type fw_unit_type = {
+ .uevent = fw_unit_uevent,
+ .release = fw_unit_release,
+};
+
+static int is_fw_unit(struct device *dev)
+{
+ return dev->type == &fw_unit_type;
+}
+
+static void create_units(struct fw_device *device)
+{
+ struct fw_csr_iterator ci;
+ struct fw_unit *unit;
+ int key, value, i;
+
+ i = 0;
+ fw_csr_iterator_init(&ci, &device->config_rom[5]);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ if (key != (CSR_UNIT | CSR_DIRECTORY))
+ continue;
+
+ /*
+ * Get the address of the unit directory and try to
+ * match the drivers id_tables against it.
+ */
+ unit = kzalloc(sizeof(*unit), GFP_KERNEL);
+ if (unit == NULL) {
+ fw_error("failed to allocate memory for unit\n");
+ continue;
+ }
+
+ unit->directory = ci.p + value - 1;
+ unit->device.bus = &fw_bus_type;
+ unit->device.type = &fw_unit_type;
+ unit->device.parent = &device->device;
+ snprintf(unit->device.bus_id, sizeof(unit->device.bus_id),
+ "%s.%d", device->device.bus_id, i++);
+
+ init_fw_attribute_group(&unit->device,
+ fw_unit_attributes,
+ &unit->attribute_group);
+ if (device_register(&unit->device) < 0)
+ goto skip_unit;
+
+ continue;
+
+ skip_unit:
+ kfree(unit);
+ }
+}
+
+static int shutdown_unit(struct device *device, void *data)
+{
+ device_unregister(device);
+
+ return 0;
+}
+
+static DECLARE_RWSEM(idr_rwsem);
+static DEFINE_IDR(fw_device_idr);
+int fw_cdev_major;
+
+struct fw_device *fw_device_from_devt(dev_t devt)
+{
+ struct fw_device *device;
+
+ down_read(&idr_rwsem);
+ device = idr_find(&fw_device_idr, MINOR(devt));
+ up_read(&idr_rwsem);
+
+ return device;
+}
+
+static void fw_device_shutdown(struct work_struct *work)
+{
+ struct fw_device *device =
+ container_of(work, struct fw_device, work.work);
+ int minor = MINOR(device->device.devt);
+
+ down_write(&idr_rwsem);
+ idr_remove(&fw_device_idr, minor);
+ up_write(&idr_rwsem);
+
+ fw_device_cdev_remove(device);
+ device_for_each_child(&device->device, NULL, shutdown_unit);
+ device_unregister(&device->device);
+}
+
+static struct device_type fw_device_type = {
+ .release = fw_device_release,
+};
+
+/*
+ * These defines control the retry behavior for reading the config
+ * rom. It shouldn't be necessary to tweak these; if the device
+ * doesn't respond to a config rom read within 10 seconds, it's not
+ * going to respond at all. As for the initial delay, a lot of
+ * devices will be able to respond within half a second after bus
+ * reset. On the other hand, it's not really worth being more
+ * aggressive than that, since it scales pretty well; if 10 devices
+ * are plugged in, they're all getting read within one second.
+ */
+
+#define MAX_RETRIES 10
+#define RETRY_DELAY (3 * HZ)
+#define INITIAL_DELAY (HZ / 2)
+
+static void fw_device_init(struct work_struct *work)
+{
+ struct fw_device *device =
+ container_of(work, struct fw_device, work.work);
+ int minor, err;
+
+ /*
+ * All failure paths here set node->data to NULL, so that we
+ * don't try to do device_for_each_child() on a kfree()'d
+ * device.
+ */
+
+ if (read_bus_info_block(device) < 0) {
+ if (device->config_rom_retries < MAX_RETRIES) {
+ device->config_rom_retries++;
+ schedule_delayed_work(&device->work, RETRY_DELAY);
+ } else {
+ fw_notify("giving up on config rom for node id %x\n",
+ device->node_id);
+ if (device->node == device->card->root_node)
+ schedule_delayed_work(&device->card->work, 0);
+ fw_device_release(&device->device);
+ }
+ return;
+ }
+
+ err = -ENOMEM;
+ down_write(&idr_rwsem);
+ if (idr_pre_get(&fw_device_idr, GFP_KERNEL))
+ err = idr_get_new(&fw_device_idr, device, &minor);
+ up_write(&idr_rwsem);
+ if (err < 0)
+ goto error;
+
+ device->device.bus = &fw_bus_type;
+ device->device.type = &fw_device_type;
+ device->device.parent = device->card->device;
+ device->device.devt = MKDEV(fw_cdev_major, minor);
+ snprintf(device->device.bus_id, sizeof(device->device.bus_id),
+ "fw%d", minor);
+
+ init_fw_attribute_group(&device->device,
+ fw_device_attributes,
+ &device->attribute_group);
+ if (device_add(&device->device)) {
+ fw_error("Failed to add device.\n");
+ goto error_with_cdev;
+ }
+
+ create_units(device);
+
+ /*
+ * Transition the device to running state. If it got pulled
+ * out from under us while we did the intialization work, we
+ * have to shut down the device again here. Normally, though,
+ * fw_node_event will be responsible for shutting it down when
+ * necessary. We have to use the atomic cmpxchg here to avoid
+ * racing with the FW_NODE_DESTROYED case in
+ * fw_node_event().
+ */
+ if (atomic_cmpxchg(&device->state,
+ FW_DEVICE_INITIALIZING,
+ FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN)
+ fw_device_shutdown(&device->work.work);
+ else
+ fw_notify("created new fw device %s (%d config rom retries)\n",
+ device->device.bus_id, device->config_rom_retries);
+
+ /*
+ * Reschedule the IRM work if we just finished reading the
+ * root node config rom. If this races with a bus reset we
+ * just end up running the IRM work a couple of extra times -
+ * pretty harmless.
+ */
+ if (device->node == device->card->root_node)
+ schedule_delayed_work(&device->card->work, 0);
+
+ return;
+
+ error_with_cdev:
+ down_write(&idr_rwsem);
+ idr_remove(&fw_device_idr, minor);
+ up_write(&idr_rwsem);
+ error:
+ put_device(&device->device);
+}
+
+static int update_unit(struct device *dev, void *data)
+{
+ struct fw_unit *unit = fw_unit(dev);
+ struct fw_driver *driver = (struct fw_driver *)dev->driver;
+
+ if (is_fw_unit(dev) && driver != NULL && driver->update != NULL) {
+ down(&dev->sem);
+ driver->update(unit);
+ up(&dev->sem);
+ }
+
+ return 0;
+}
+
+static void fw_device_update(struct work_struct *work)
+{
+ struct fw_device *device =
+ container_of(work, struct fw_device, work.work);
+
+ fw_device_cdev_update(device);
+ device_for_each_child(&device->device, NULL, update_unit);
+}
+
+void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
+{
+ struct fw_device *device;
+
+ switch (event) {
+ case FW_NODE_CREATED:
+ case FW_NODE_LINK_ON:
+ if (!node->link_on)
+ break;
+
+ device = kzalloc(sizeof(*device), GFP_ATOMIC);
+ if (device == NULL)
+ break;
+
+ /*
+ * Do minimal intialization of the device here, the
+ * rest will happen in fw_device_init(). We need the
+ * card and node so we can read the config rom and we
+ * need to do device_initialize() now so
+ * device_for_each_child() in FW_NODE_UPDATED is
+ * doesn't freak out.
+ */
+ device_initialize(&device->device);
+ atomic_set(&device->state, FW_DEVICE_INITIALIZING);
+ device->card = fw_card_get(card);
+ device->node = fw_node_get(node);
+ device->node_id = node->node_id;
+ device->generation = card->generation;
+ INIT_LIST_HEAD(&device->client_list);
+
+ /*
+ * Set the node data to point back to this device so
+ * FW_NODE_UPDATED callbacks can update the node_id
+ * and generation for the device.
+ */
+ node->data = device;
+
+ /*
+ * Many devices are slow to respond after bus resets,
+ * especially if they are bus powered and go through
+ * power-up after getting plugged in. We schedule the
+ * first config rom scan half a second after bus reset.
+ */
+ INIT_DELAYED_WORK(&device->work, fw_device_init);
+ schedule_delayed_work(&device->work, INITIAL_DELAY);
+ break;
+
+ case FW_NODE_UPDATED:
+ if (!node->link_on || node->data == NULL)
+ break;
+
+ device = node->data;
+ device->node_id = node->node_id;
+ device->generation = card->generation;
+ if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
+ PREPARE_DELAYED_WORK(&device->work, fw_device_update);
+ schedule_delayed_work(&device->work, 0);
+ }
+ break;
+
+ case FW_NODE_DESTROYED:
+ case FW_NODE_LINK_OFF:
+ if (!node->data)
+ break;
+
+ /*
+ * Destroy the device associated with the node. There
+ * are two cases here: either the device is fully
+ * initialized (FW_DEVICE_RUNNING) or we're in the
+ * process of reading its config rom
+ * (FW_DEVICE_INITIALIZING). If it is fully
+ * initialized we can reuse device->work to schedule a
+ * full fw_device_shutdown(). If not, there's work
+ * scheduled to read it's config rom, and we just put
+ * the device in shutdown state to have that code fail
+ * to create the device.
+ */
+ device = node->data;
+ if (atomic_xchg(&device->state,
+ FW_DEVICE_SHUTDOWN) == FW_DEVICE_RUNNING) {
+ PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
+ schedule_delayed_work(&device->work, 0);
+ }
+ break;
+ }
+}
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
new file mode 100644
index 0000000..0ba9d64
--- /dev/null
+++ b/drivers/firewire/fw-device.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __fw_device_h
+#define __fw_device_h
+
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <asm/atomic.h>
+
+enum fw_device_state {
+ FW_DEVICE_INITIALIZING,
+ FW_DEVICE_RUNNING,
+ FW_DEVICE_SHUTDOWN,
+};
+
+struct fw_attribute_group {
+ struct attribute_group *groups[2];
+ struct attribute_group group;
+ struct attribute *attrs[11];
+};
+
+struct fw_device {
+ atomic_t state;
+ struct fw_node *node;
+ int node_id;
+ int generation;
+ struct fw_card *card;
+ struct device device;
+ struct list_head link;
+ struct list_head client_list;
+ u32 *config_rom;
+ size_t config_rom_length;
+ int config_rom_retries;
+ struct delayed_work work;
+ struct fw_attribute_group attribute_group;
+};
+
+static inline struct fw_device *
+fw_device(struct device *dev)
+{
+ return container_of(dev, struct fw_device, device);
+}
+
+static inline int
+fw_device_is_shutdown(struct fw_device *device)
+{
+ return atomic_read(&device->state) == FW_DEVICE_SHUTDOWN;
+}
+
+struct fw_device *fw_device_get(struct fw_device *device);
+void fw_device_put(struct fw_device *device);
+int fw_device_enable_phys_dma(struct fw_device *device);
+
+void fw_device_cdev_update(struct fw_device *device);
+void fw_device_cdev_remove(struct fw_device *device);
+
+struct fw_device *fw_device_from_devt(dev_t devt);
+extern int fw_cdev_major;
+
+struct fw_unit {
+ struct device device;
+ u32 *directory;
+ struct fw_attribute_group attribute_group;
+};
+
+static inline struct fw_unit *
+fw_unit(struct device *dev)
+{
+ return container_of(dev, struct fw_unit, device);
+}
+
+#define CSR_OFFSET 0x40
+#define CSR_LEAF 0x80
+#define CSR_DIRECTORY 0xc0
+
+#define CSR_DESCRIPTOR 0x01
+#define CSR_VENDOR 0x03
+#define CSR_HARDWARE_VERSION 0x04
+#define CSR_NODE_CAPABILITIES 0x0c
+#define CSR_UNIT 0x11
+#define CSR_SPECIFIER_ID 0x12
+#define CSR_VERSION 0x13
+#define CSR_DEPENDENT_INFO 0x14
+#define CSR_MODEL 0x17
+#define CSR_INSTANCE 0x18
+
+#define SBP2_COMMAND_SET_SPECIFIER 0x38
+#define SBP2_COMMAND_SET 0x39
+#define SBP2_COMMAND_SET_REVISION 0x3b
+#define SBP2_FIRMWARE_REVISION 0x3c
+
+struct fw_csr_iterator {
+ u32 *p;
+ u32 *end;
+};
+
+void fw_csr_iterator_init(struct fw_csr_iterator *ci, u32 *p);
+int fw_csr_iterator_next(struct fw_csr_iterator *ci,
+ int *key, int *value);
+
+#define FW_MATCH_VENDOR 0x0001
+#define FW_MATCH_MODEL 0x0002
+#define FW_MATCH_SPECIFIER_ID 0x0004
+#define FW_MATCH_VERSION 0x0008
+
+struct fw_device_id {
+ u32 match_flags;
+ u32 vendor;
+ u32 model;
+ u32 specifier_id;
+ u32 version;
+ void *driver_data;
+};
+
+struct fw_driver {
+ struct device_driver driver;
+ /* Called when the parent device sits through a bus reset. */
+ void (*update) (struct fw_unit *unit);
+ const struct fw_device_id *id_table;
+};
+
+static inline struct fw_driver *
+fw_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct fw_driver, driver);
+}
+
+extern const struct file_operations fw_device_ops;
+
+#endif /* __fw_device_h */
diff --git a/drivers/firewire/fw-iso.c b/drivers/firewire/fw-iso.c
new file mode 100644
index 0000000..2b640e9
--- /dev/null
+++ b/drivers/firewire/fw-iso.c
@@ -0,0 +1,163 @@
+/*
+ * Isochronous IO functionality
+ *
+ * Copyright (C) 2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+int
+fw_iso_buffer_init(struct fw_iso_buffer *buffer, struct fw_card *card,
+ int page_count, enum dma_data_direction direction)
+{
+ int i, j, retval = -ENOMEM;
+ dma_addr_t address;
+
+ buffer->page_count = page_count;
+ buffer->direction = direction;
+
+ buffer->pages = kmalloc(page_count * sizeof(buffer->pages[0]),
+ GFP_KERNEL);
+ if (buffer->pages == NULL)
+ goto out;
+
+ for (i = 0; i < buffer->page_count; i++) {
+ buffer->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+ if (buffer->pages[i] == NULL)
+ goto out_pages;
+
+ address = dma_map_page(card->device, buffer->pages[i],
+ 0, PAGE_SIZE, direction);
+ if (dma_mapping_error(address)) {
+ __free_page(buffer->pages[i]);
+ goto out_pages;
+ }
+ set_page_private(buffer->pages[i], address);
+ }
+
+ return 0;
+
+ out_pages:
+ for (j = 0; j < i; j++) {
+ address = page_private(buffer->pages[j]);
+ dma_unmap_page(card->device, address,
+ PAGE_SIZE, DMA_TO_DEVICE);
+ __free_page(buffer->pages[j]);
+ }
+ kfree(buffer->pages);
+ out:
+ buffer->pages = NULL;
+ return retval;
+}
+
+int fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma)
+{
+ unsigned long uaddr;
+ int i, retval;
+
+ uaddr = vma->vm_start;
+ for (i = 0; i < buffer->page_count; i++) {
+ retval = vm_insert_page(vma, uaddr, buffer->pages[i]);
+ if (retval)
+ return retval;
+ uaddr += PAGE_SIZE;
+ }
+
+ return 0;
+}
+
+void fw_iso_buffer_destroy(struct fw_iso_buffer *buffer,
+ struct fw_card *card)
+{
+ int i;
+ dma_addr_t address;
+
+ for (i = 0; i < buffer->page_count; i++) {
+ address = page_private(buffer->pages[i]);
+ dma_unmap_page(card->device, address,
+ PAGE_SIZE, DMA_TO_DEVICE);
+ __free_page(buffer->pages[i]);
+ }
+
+ kfree(buffer->pages);
+ buffer->pages = NULL;
+}
+
+struct fw_iso_context *
+fw_iso_context_create(struct fw_card *card, int type,
+ int channel, int speed, size_t header_size,
+ fw_iso_callback_t callback, void *callback_data)
+{
+ struct fw_iso_context *ctx;
+
+ ctx = card->driver->allocate_iso_context(card, type, header_size);
+ if (IS_ERR(ctx))
+ return ctx;
+
+ ctx->card = card;
+ ctx->type = type;
+ ctx->channel = channel;
+ ctx->speed = speed;
+ ctx->header_size = header_size;
+ ctx->callback = callback;
+ ctx->callback_data = callback_data;
+
+ return ctx;
+}
+EXPORT_SYMBOL(fw_iso_context_create);
+
+void fw_iso_context_destroy(struct fw_iso_context *ctx)
+{
+ struct fw_card *card = ctx->card;
+
+ card->driver->free_iso_context(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_destroy);
+
+int
+fw_iso_context_start(struct fw_iso_context *ctx, int cycle, int sync, int tags)
+{
+ return ctx->card->driver->start_iso(ctx, cycle, sync, tags);
+}
+EXPORT_SYMBOL(fw_iso_context_start);
+
+int
+fw_iso_context_queue(struct fw_iso_context *ctx,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload)
+{
+ struct fw_card *card = ctx->card;
+
+ return card->driver->queue_iso(ctx, packet, buffer, payload);
+}
+EXPORT_SYMBOL(fw_iso_context_queue);
+
+int
+fw_iso_context_stop(struct fw_iso_context *ctx)
+{
+ return ctx->card->driver->stop_iso(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_stop);
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
new file mode 100644
index 0000000..1f5c704
--- /dev/null
+++ b/drivers/firewire/fw-ohci.c
@@ -0,0 +1,1943 @@
+/*
+ * Driver for OHCI 1394 controllers
+ *
+ * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include "fw-transaction.h"
+#include "fw-ohci.h"
+
+#define DESCRIPTOR_OUTPUT_MORE 0
+#define DESCRIPTOR_OUTPUT_LAST (1 << 12)
+#define DESCRIPTOR_INPUT_MORE (2 << 12)
+#define DESCRIPTOR_INPUT_LAST (3 << 12)
+#define DESCRIPTOR_STATUS (1 << 11)
+#define DESCRIPTOR_KEY_IMMEDIATE (2 << 8)
+#define DESCRIPTOR_PING (1 << 7)
+#define DESCRIPTOR_YY (1 << 6)
+#define DESCRIPTOR_NO_IRQ (0 << 4)
+#define DESCRIPTOR_IRQ_ERROR (1 << 4)
+#define DESCRIPTOR_IRQ_ALWAYS (3 << 4)
+#define DESCRIPTOR_BRANCH_ALWAYS (3 << 2)
+#define DESCRIPTOR_WAIT (3 << 0)
+
+struct descriptor {
+ __le16 req_count;
+ __le16 control;
+ __le32 data_address;
+ __le32 branch_address;
+ __le16 res_count;
+ __le16 transfer_status;
+} __attribute__((aligned(16)));
+
+struct db_descriptor {
+ __le16 first_size;
+ __le16 control;
+ __le16 second_req_count;
+ __le16 first_req_count;
+ __le32 branch_address;
+ __le16 second_res_count;
+ __le16 first_res_count;
+ __le32 reserved0;
+ __le32 first_buffer;
+ __le32 second_buffer;
+ __le32 reserved1;
+} __attribute__((aligned(16)));
+
+#define CONTROL_SET(regs) (regs)
+#define CONTROL_CLEAR(regs) ((regs) + 4)
+#define COMMAND_PTR(regs) ((regs) + 12)
+#define CONTEXT_MATCH(regs) ((regs) + 16)
+
+struct ar_buffer {
+ struct descriptor descriptor;
+ struct ar_buffer *next;
+ __le32 data[0];
+};
+
+struct ar_context {
+ struct fw_ohci *ohci;
+ struct ar_buffer *current_buffer;
+ struct ar_buffer *last_buffer;
+ void *pointer;
+ u32 regs;
+ struct tasklet_struct tasklet;
+};
+
+struct context;
+
+typedef int (*descriptor_callback_t)(struct context *ctx,
+ struct descriptor *d,
+ struct descriptor *last);
+struct context {
+ struct fw_ohci *ohci;
+ u32 regs;
+
+ struct descriptor *buffer;
+ dma_addr_t buffer_bus;
+ size_t buffer_size;
+ struct descriptor *head_descriptor;
+ struct descriptor *tail_descriptor;
+ struct descriptor *tail_descriptor_last;
+ struct descriptor *prev_descriptor;
+
+ descriptor_callback_t callback;
+
+ struct tasklet_struct tasklet;
+};
+
+#define IT_HEADER_SY(v) ((v) << 0)
+#define IT_HEADER_TCODE(v) ((v) << 4)
+#define IT_HEADER_CHANNEL(v) ((v) << 8)
+#define IT_HEADER_TAG(v) ((v) << 14)
+#define IT_HEADER_SPEED(v) ((v) << 16)
+#define IT_HEADER_DATA_LENGTH(v) ((v) << 16)
+
+struct iso_context {
+ struct fw_iso_context base;
+ struct context context;
+ void *header;
+ size_t header_length;
+};
+
+#define CONFIG_ROM_SIZE 1024
+
+struct fw_ohci {
+ struct fw_card card;
+
+ u32 version;
+ __iomem char *registers;
+ dma_addr_t self_id_bus;
+ __le32 *self_id_cpu;
+ struct tasklet_struct bus_reset_tasklet;
+ int node_id;
+ int generation;
+ int request_generation;
+ u32 bus_seconds;
+
+ /*
+ * Spinlock for accessing fw_ohci data. Never call out of
+ * this driver with this lock held.
+ */
+ spinlock_t lock;
+ u32 self_id_buffer[512];
+
+ /* Config rom buffers */
+ __be32 *config_rom;
+ dma_addr_t config_rom_bus;
+ __be32 *next_config_rom;
+ dma_addr_t next_config_rom_bus;
+ u32 next_header;
+
+ struct ar_context ar_request_ctx;
+ struct ar_context ar_response_ctx;
+ struct context at_request_ctx;
+ struct context at_response_ctx;
+
+ u32 it_context_mask;
+ struct iso_context *it_context_list;
+ u32 ir_context_mask;
+ struct iso_context *ir_context_list;
+};
+
+static inline struct fw_ohci *fw_ohci(struct fw_card *card)
+{
+ return container_of(card, struct fw_ohci, card);
+}
+
+#define IT_CONTEXT_CYCLE_MATCH_ENABLE 0x80000000
+#define IR_CONTEXT_BUFFER_FILL 0x80000000
+#define IR_CONTEXT_ISOCH_HEADER 0x40000000
+#define IR_CONTEXT_CYCLE_MATCH_ENABLE 0x20000000
+#define IR_CONTEXT_MULTI_CHANNEL_MODE 0x10000000
+#define IR_CONTEXT_DUAL_BUFFER_MODE 0x08000000
+
+#define CONTEXT_RUN 0x8000
+#define CONTEXT_WAKE 0x1000
+#define CONTEXT_DEAD 0x0800
+#define CONTEXT_ACTIVE 0x0400
+
+#define OHCI1394_MAX_AT_REQ_RETRIES 0x2
+#define OHCI1394_MAX_AT_RESP_RETRIES 0x2
+#define OHCI1394_MAX_PHYS_RESP_RETRIES 0x8
+
+#define FW_OHCI_MAJOR 240
+#define OHCI1394_REGISTER_SIZE 0x800
+#define OHCI_LOOP_COUNT 500
+#define OHCI1394_PCI_HCI_Control 0x40
+#define SELF_ID_BUF_SIZE 0x800
+#define OHCI_TCODE_PHY_PACKET 0x0e
+#define OHCI_VERSION_1_1 0x010010
+#define ISO_BUFFER_SIZE (64 * 1024)
+#define AT_BUFFER_SIZE 4096
+
+static char ohci_driver_name[] = KBUILD_MODNAME;
+
+static inline void reg_write(const struct fw_ohci *ohci, int offset, u32 data)
+{
+ writel(data, ohci->registers + offset);
+}
+
+static inline u32 reg_read(const struct fw_ohci *ohci, int offset)
+{
+ return readl(ohci->registers + offset);
+}
+
+static inline void flush_writes(const struct fw_ohci *ohci)
+{
+ /* Do a dummy read to flush writes. */
+ reg_read(ohci, OHCI1394_Version);
+}
+
+static int
+ohci_update_phy_reg(struct fw_card *card, int addr,
+ int clear_bits, int set_bits)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ u32 val, old;
+
+ reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
+ msleep(2);
+ val = reg_read(ohci, OHCI1394_PhyControl);
+ if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
+ fw_error("failed to set phy reg bits.\n");
+ return -EBUSY;
+ }
+
+ old = OHCI1394_PhyControl_ReadData(val);
+ old = (old & ~clear_bits) | set_bits;
+ reg_write(ohci, OHCI1394_PhyControl,
+ OHCI1394_PhyControl_Write(addr, old));
+
+ return 0;
+}
+
+static int ar_context_add_page(struct ar_context *ctx)
+{
+ struct device *dev = ctx->ohci->card.device;
+ struct ar_buffer *ab;
+ dma_addr_t ab_bus;
+ size_t offset;
+
+ ab = (struct ar_buffer *) __get_free_page(GFP_ATOMIC);
+ if (ab == NULL)
+ return -ENOMEM;
+
+ ab_bus = dma_map_single(dev, ab, PAGE_SIZE, DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(ab_bus)) {
+ free_page((unsigned long) ab);
+ return -ENOMEM;
+ }
+
+ memset(&ab->descriptor, 0, sizeof(ab->descriptor));
+ ab->descriptor.control = cpu_to_le16(DESCRIPTOR_INPUT_MORE |
+ DESCRIPTOR_STATUS |
+ DESCRIPTOR_BRANCH_ALWAYS);
+ offset = offsetof(struct ar_buffer, data);
+ ab->descriptor.req_count = cpu_to_le16(PAGE_SIZE - offset);
+ ab->descriptor.data_address = cpu_to_le32(ab_bus + offset);
+ ab->descriptor.res_count = cpu_to_le16(PAGE_SIZE - offset);
+ ab->descriptor.branch_address = 0;
+
+ dma_sync_single_for_device(dev, ab_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+ ctx->last_buffer->descriptor.branch_address = ab_bus | 1;
+ ctx->last_buffer->next = ab;
+ ctx->last_buffer = ab;
+
+ reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+ flush_writes(ctx->ohci);
+
+ return 0;
+}
+
+static __le32 *handle_ar_packet(struct ar_context *ctx, __le32 *buffer)
+{
+ struct fw_ohci *ohci = ctx->ohci;
+ struct fw_packet p;
+ u32 status, length, tcode;
+
+ p.header[0] = le32_to_cpu(buffer[0]);
+ p.header[1] = le32_to_cpu(buffer[1]);
+ p.header[2] = le32_to_cpu(buffer[2]);
+
+ tcode = (p.header[0] >> 4) & 0x0f;
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ case TCODE_READ_QUADLET_RESPONSE:
+ p.header[3] = (__force __u32) buffer[3];
+ p.header_length = 16;
+ p.payload_length = 0;
+ break;
+
+ case TCODE_READ_BLOCK_REQUEST :
+ p.header[3] = le32_to_cpu(buffer[3]);
+ p.header_length = 16;
+ p.payload_length = 0;
+ break;
+
+ case TCODE_WRITE_BLOCK_REQUEST:
+ case TCODE_READ_BLOCK_RESPONSE:
+ case TCODE_LOCK_REQUEST:
+ case TCODE_LOCK_RESPONSE:
+ p.header[3] = le32_to_cpu(buffer[3]);
+ p.header_length = 16;
+ p.payload_length = p.header[3] >> 16;
+ break;
+
+ case TCODE_WRITE_RESPONSE:
+ case TCODE_READ_QUADLET_REQUEST:
+ case OHCI_TCODE_PHY_PACKET:
+ p.header_length = 12;
+ p.payload_length = 0;
+ break;
+ }
+
+ p.payload = (void *) buffer + p.header_length;
+
+ /* FIXME: What to do about evt_* errors? */
+ length = (p.header_length + p.payload_length + 3) / 4;
+ status = le32_to_cpu(buffer[length]);
+
+ p.ack = ((status >> 16) & 0x1f) - 16;
+ p.speed = (status >> 21) & 0x7;
+ p.timestamp = status & 0xffff;
+ p.generation = ohci->request_generation;
+
+ /*
+ * The OHCI bus reset handler synthesizes a phy packet with
+ * the new generation number when a bus reset happens (see
+ * section 8.4.2.3). This helps us determine when a request
+ * was received and make sure we send the response in the same
+ * generation. We only need this for requests; for responses
+ * we use the unique tlabel for finding the matching
+ * request.
+ */
+
+ if (p.ack + 16 == 0x09)
+ ohci->request_generation = (buffer[2] >> 16) & 0xff;
+ else if (ctx == &ohci->ar_request_ctx)
+ fw_core_handle_request(&ohci->card, &p);
+ else
+ fw_core_handle_response(&ohci->card, &p);
+
+ return buffer + length + 1;
+}
+
+static void ar_context_tasklet(unsigned long data)
+{
+ struct ar_context *ctx = (struct ar_context *)data;
+ struct fw_ohci *ohci = ctx->ohci;
+ struct ar_buffer *ab;
+ struct descriptor *d;
+ void *buffer, *end;
+
+ ab = ctx->current_buffer;
+ d = &ab->descriptor;
+
+ if (d->res_count == 0) {
+ size_t size, rest, offset;
+
+ /*
+ * This descriptor is finished and we may have a
+ * packet split across this and the next buffer. We
+ * reuse the page for reassembling the split packet.
+ */
+
+ offset = offsetof(struct ar_buffer, data);
+ dma_unmap_single(ohci->card.device,
+ ab->descriptor.data_address - offset,
+ PAGE_SIZE, DMA_BIDIRECTIONAL);
+
+ buffer = ab;
+ ab = ab->next;
+ d = &ab->descriptor;
+ size = buffer + PAGE_SIZE - ctx->pointer;
+ rest = le16_to_cpu(d->req_count) - le16_to_cpu(d->res_count);
+ memmove(buffer, ctx->pointer, size);
+ memcpy(buffer + size, ab->data, rest);
+ ctx->current_buffer = ab;
+ ctx->pointer = (void *) ab->data + rest;
+ end = buffer + size + rest;
+
+ while (buffer < end)
+ buffer = handle_ar_packet(ctx, buffer);
+
+ free_page((unsigned long)buffer);
+ ar_context_add_page(ctx);
+ } else {
+ buffer = ctx->pointer;
+ ctx->pointer = end =
+ (void *) ab + PAGE_SIZE - le16_to_cpu(d->res_count);
+
+ while (buffer < end)
+ buffer = handle_ar_packet(ctx, buffer);
+ }
+}
+
+static int
+ar_context_init(struct ar_context *ctx, struct fw_ohci *ohci, u32 regs)
+{
+ struct ar_buffer ab;
+
+ ctx->regs = regs;
+ ctx->ohci = ohci;
+ ctx->last_buffer = &ab;
+ tasklet_init(&ctx->tasklet, ar_context_tasklet, (unsigned long)ctx);
+
+ ar_context_add_page(ctx);
+ ar_context_add_page(ctx);
+ ctx->current_buffer = ab.next;
+ ctx->pointer = ctx->current_buffer->data;
+
+ reg_write(ctx->ohci, COMMAND_PTR(ctx->regs), ab.descriptor.branch_address);
+ reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN);
+ flush_writes(ctx->ohci);
+
+ return 0;
+}
+
+static void context_tasklet(unsigned long data)
+{
+ struct context *ctx = (struct context *) data;
+ struct fw_ohci *ohci = ctx->ohci;
+ struct descriptor *d, *last;
+ u32 address;
+ int z;
+
+ dma_sync_single_for_cpu(ohci->card.device, ctx->buffer_bus,
+ ctx->buffer_size, DMA_TO_DEVICE);
+
+ d = ctx->tail_descriptor;
+ last = ctx->tail_descriptor_last;
+
+ while (last->branch_address != 0) {
+ address = le32_to_cpu(last->branch_address);
+ z = address & 0xf;
+ d = ctx->buffer + (address - ctx->buffer_bus) / sizeof(*d);
+ last = (z == 2) ? d : d + z - 1;
+
+ if (!ctx->callback(ctx, d, last))
+ break;
+
+ ctx->tail_descriptor = d;
+ ctx->tail_descriptor_last = last;
+ }
+}
+
+static int
+context_init(struct context *ctx, struct fw_ohci *ohci,
+ size_t buffer_size, u32 regs,
+ descriptor_callback_t callback)
+{
+ ctx->ohci = ohci;
+ ctx->regs = regs;
+ ctx->buffer_size = buffer_size;
+ ctx->buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (ctx->buffer == NULL)
+ return -ENOMEM;
+
+ tasklet_init(&ctx->tasklet, context_tasklet, (unsigned long)ctx);
+ ctx->callback = callback;
+
+ ctx->buffer_bus =
+ dma_map_single(ohci->card.device, ctx->buffer,
+ buffer_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(ctx->buffer_bus)) {
+ kfree(ctx->buffer);
+ return -ENOMEM;
+ }
+
+ ctx->head_descriptor = ctx->buffer;
+ ctx->prev_descriptor = ctx->buffer;
+ ctx->tail_descriptor = ctx->buffer;
+ ctx->tail_descriptor_last = ctx->buffer;
+
+ /*
+ * We put a dummy descriptor in the buffer that has a NULL
+ * branch address and looks like it's been sent. That way we
+ * have a descriptor to append DMA programs to. Also, the
+ * ring buffer invariant is that it always has at least one
+ * element so that head == tail means buffer full.
+ */
+
+ memset(ctx->head_descriptor, 0, sizeof(*ctx->head_descriptor));
+ ctx->head_descriptor->control = cpu_to_le16(DESCRIPTOR_OUTPUT_LAST);
+ ctx->head_descriptor->transfer_status = cpu_to_le16(0x8011);
+ ctx->head_descriptor++;
+
+ return 0;
+}
+
+static void
+context_release(struct context *ctx)
+{
+ struct fw_card *card = &ctx->ohci->card;
+
+ dma_unmap_single(card->device, ctx->buffer_bus,
+ ctx->buffer_size, DMA_TO_DEVICE);
+ kfree(ctx->buffer);
+}
+
+static struct descriptor *
+context_get_descriptors(struct context *ctx, int z, dma_addr_t *d_bus)
+{
+ struct descriptor *d, *tail, *end;
+
+ d = ctx->head_descriptor;
+ tail = ctx->tail_descriptor;
+ end = ctx->buffer + ctx->buffer_size / sizeof(*d);
+
+ if (d + z <= tail) {
+ goto has_space;
+ } else if (d > tail && d + z <= end) {
+ goto has_space;
+ } else if (d > tail && ctx->buffer + z <= tail) {
+ d = ctx->buffer;
+ goto has_space;
+ }
+
+ return NULL;
+
+ has_space:
+ memset(d, 0, z * sizeof(*d));
+ *d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d);
+
+ return d;
+}
+
+static void context_run(struct context *ctx, u32 extra)
+{
+ struct fw_ohci *ohci = ctx->ohci;
+
+ reg_write(ohci, COMMAND_PTR(ctx->regs),
+ le32_to_cpu(ctx->tail_descriptor_last->branch_address));
+ reg_write(ohci, CONTROL_CLEAR(ctx->regs), ~0);
+ reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_RUN | extra);
+ flush_writes(ohci);
+}
+
+static void context_append(struct context *ctx,
+ struct descriptor *d, int z, int extra)
+{
+ dma_addr_t d_bus;
+
+ d_bus = ctx->buffer_bus + (d - ctx->buffer) * sizeof(*d);
+
+ ctx->head_descriptor = d + z + extra;
+ ctx->prev_descriptor->branch_address = cpu_to_le32(d_bus | z);
+ ctx->prev_descriptor = z == 2 ? d : d + z - 1;
+
+ dma_sync_single_for_device(ctx->ohci->card.device, ctx->buffer_bus,
+ ctx->buffer_size, DMA_TO_DEVICE);
+
+ reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+ flush_writes(ctx->ohci);
+}
+
+static void context_stop(struct context *ctx)
+{
+ u32 reg;
+ int i;
+
+ reg_write(ctx->ohci, CONTROL_CLEAR(ctx->regs), CONTEXT_RUN);
+ flush_writes(ctx->ohci);
+
+ for (i = 0; i < 10; i++) {
+ reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
+ if ((reg & CONTEXT_ACTIVE) == 0)
+ break;
+
+ fw_notify("context_stop: still active (0x%08x)\n", reg);
+ msleep(1);
+ }
+}
+
+struct driver_data {
+ struct fw_packet *packet;
+};
+
+/*
+ * This function apppends a packet to the DMA queue for transmission.
+ * Must always be called with the ochi->lock held to ensure proper
+ * generation handling and locking around packet queue manipulation.
+ */
+static int
+at_context_queue_packet(struct context *ctx, struct fw_packet *packet)
+{
+ struct fw_ohci *ohci = ctx->ohci;
+ dma_addr_t d_bus, payload_bus;
+ struct driver_data *driver_data;
+ struct descriptor *d, *last;
+ __le32 *header;
+ int z, tcode;
+ u32 reg;
+
+ d = context_get_descriptors(ctx, 4, &d_bus);
+ if (d == NULL) {
+ packet->ack = RCODE_SEND_ERROR;
+ return -1;
+ }
+
+ d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE);
+ d[0].res_count = cpu_to_le16(packet->timestamp);
+
+ /*
+ * The DMA format for asyncronous link packets is different
+ * from the IEEE1394 layout, so shift the fields around
+ * accordingly. If header_length is 8, it's a PHY packet, to
+ * which we need to prepend an extra quadlet.
+ */
+
+ header = (__le32 *) &d[1];
+ if (packet->header_length > 8) {
+ header[0] = cpu_to_le32((packet->header[0] & 0xffff) |
+ (packet->speed << 16));
+ header[1] = cpu_to_le32((packet->header[1] & 0xffff) |
+ (packet->header[0] & 0xffff0000));
+ header[2] = cpu_to_le32(packet->header[2]);
+
+ tcode = (packet->header[0] >> 4) & 0x0f;
+ if (TCODE_IS_BLOCK_PACKET(tcode))
+ header[3] = cpu_to_le32(packet->header[3]);
+ else
+ header[3] = (__force __le32) packet->header[3];
+
+ d[0].req_count = cpu_to_le16(packet->header_length);
+ } else {
+ header[0] = cpu_to_le32((OHCI1394_phy_tcode << 4) |
+ (packet->speed << 16));
+ header[1] = cpu_to_le32(packet->header[0]);
+ header[2] = cpu_to_le32(packet->header[1]);
+ d[0].req_count = cpu_to_le16(12);
+ }
+
+ driver_data = (struct driver_data *) &d[3];
+ driver_data->packet = packet;
+ packet->driver_data = driver_data;
+
+ if (packet->payload_length > 0) {
+ payload_bus =
+ dma_map_single(ohci->card.device, packet->payload,
+ packet->payload_length, DMA_TO_DEVICE);
+ if (dma_mapping_error(payload_bus)) {
+ packet->ack = RCODE_SEND_ERROR;
+ return -1;
+ }
+
+ d[2].req_count = cpu_to_le16(packet->payload_length);
+ d[2].data_address = cpu_to_le32(payload_bus);
+ last = &d[2];
+ z = 3;
+ } else {
+ last = &d[0];
+ z = 2;
+ }
+
+ last->control |= cpu_to_le16(DESCRIPTOR_OUTPUT_LAST |
+ DESCRIPTOR_IRQ_ALWAYS |
+ DESCRIPTOR_BRANCH_ALWAYS);
+
+ /* FIXME: Document how the locking works. */
+ if (ohci->generation != packet->generation) {
+ packet->ack = RCODE_GENERATION;
+ return -1;
+ }
+
+ context_append(ctx, d, z, 4 - z);
+
+ /* If the context isn't already running, start it up. */
+ reg = reg_read(ctx->ohci, CONTROL_SET(ctx->regs));
+ if ((reg & CONTEXT_RUN) == 0)
+ context_run(ctx, 0);
+
+ return 0;
+}
+
+static int handle_at_packet(struct context *context,
+ struct descriptor *d,
+ struct descriptor *last)
+{
+ struct driver_data *driver_data;
+ struct fw_packet *packet;
+ struct fw_ohci *ohci = context->ohci;
+ dma_addr_t payload_bus;
+ int evt;
+
+ if (last->transfer_status == 0)
+ /* This descriptor isn't done yet, stop iteration. */
+ return 0;
+
+ driver_data = (struct driver_data *) &d[3];
+ packet = driver_data->packet;
+ if (packet == NULL)
+ /* This packet was cancelled, just continue. */
+ return 1;
+
+ payload_bus = le32_to_cpu(last->data_address);
+ if (payload_bus != 0)
+ dma_unmap_single(ohci->card.device, payload_bus,
+ packet->payload_length, DMA_TO_DEVICE);
+
+ evt = le16_to_cpu(last->transfer_status) & 0x1f;
+ packet->timestamp = le16_to_cpu(last->res_count);
+
+ switch (evt) {
+ case OHCI1394_evt_timeout:
+ /* Async response transmit timed out. */
+ packet->ack = RCODE_CANCELLED;
+ break;
+
+ case OHCI1394_evt_flushed:
+ /*
+ * The packet was flushed should give same error as
+ * when we try to use a stale generation count.
+ */
+ packet->ack = RCODE_GENERATION;
+ break;
+
+ case OHCI1394_evt_missing_ack:
+ /*
+ * Using a valid (current) generation count, but the
+ * node is not on the bus or not sending acks.
+ */
+ packet->ack = RCODE_NO_ACK;
+ break;
+
+ case ACK_COMPLETE + 0x10:
+ case ACK_PENDING + 0x10:
+ case ACK_BUSY_X + 0x10:
+ case ACK_BUSY_A + 0x10:
+ case ACK_BUSY_B + 0x10:
+ case ACK_DATA_ERROR + 0x10:
+ case ACK_TYPE_ERROR + 0x10:
+ packet->ack = evt - 0x10;
+ break;
+
+ default:
+ packet->ack = RCODE_SEND_ERROR;
+ break;
+ }
+
+ packet->callback(packet, &ohci->card, packet->ack);
+
+ return 1;
+}
+
+#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff)
+#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f)
+#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff)
+#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff)
+#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff)
+
+static void
+handle_local_rom(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
+{
+ struct fw_packet response;
+ int tcode, length, i;
+
+ tcode = HEADER_GET_TCODE(packet->header[0]);
+ if (TCODE_IS_BLOCK_PACKET(tcode))
+ length = HEADER_GET_DATA_LENGTH(packet->header[3]);
+ else
+ length = 4;
+
+ i = csr - CSR_CONFIG_ROM;
+ if (i + length > CONFIG_ROM_SIZE) {
+ fw_fill_response(&response, packet->header,
+ RCODE_ADDRESS_ERROR, NULL, 0);
+ } else if (!TCODE_IS_READ_REQUEST(tcode)) {
+ fw_fill_response(&response, packet->header,
+ RCODE_TYPE_ERROR, NULL, 0);
+ } else {
+ fw_fill_response(&response, packet->header, RCODE_COMPLETE,
+ (void *) ohci->config_rom + i, length);
+ }
+
+ fw_core_handle_response(&ohci->card, &response);
+}
+
+static void
+handle_local_lock(struct fw_ohci *ohci, struct fw_packet *packet, u32 csr)
+{
+ struct fw_packet response;
+ int tcode, length, ext_tcode, sel;
+ __be32 *payload, lock_old;
+ u32 lock_arg, lock_data;
+
+ tcode = HEADER_GET_TCODE(packet->header[0]);
+ length = HEADER_GET_DATA_LENGTH(packet->header[3]);
+ payload = packet->payload;
+ ext_tcode = HEADER_GET_EXTENDED_TCODE(packet->header[3]);
+
+ if (tcode == TCODE_LOCK_REQUEST &&
+ ext_tcode == EXTCODE_COMPARE_SWAP && length == 8) {
+ lock_arg = be32_to_cpu(payload[0]);
+ lock_data = be32_to_cpu(payload[1]);
+ } else if (tcode == TCODE_READ_QUADLET_REQUEST) {
+ lock_arg = 0;
+ lock_data = 0;
+ } else {
+ fw_fill_response(&response, packet->header,
+ RCODE_TYPE_ERROR, NULL, 0);
+ goto out;
+ }
+
+ sel = (csr - CSR_BUS_MANAGER_ID) / 4;
+ reg_write(ohci, OHCI1394_CSRData, lock_data);
+ reg_write(ohci, OHCI1394_CSRCompareData, lock_arg);
+ reg_write(ohci, OHCI1394_CSRControl, sel);
+
+ if (reg_read(ohci, OHCI1394_CSRControl) & 0x80000000)
+ lock_old = cpu_to_be32(reg_read(ohci, OHCI1394_CSRData));
+ else
+ fw_notify("swap not done yet\n");
+
+ fw_fill_response(&response, packet->header,
+ RCODE_COMPLETE, &lock_old, sizeof(lock_old));
+ out:
+ fw_core_handle_response(&ohci->card, &response);
+}
+
+static void
+handle_local_request(struct context *ctx, struct fw_packet *packet)
+{
+ u64 offset;
+ u32 csr;
+
+ if (ctx == &ctx->ohci->at_request_ctx) {
+ packet->ack = ACK_PENDING;
+ packet->callback(packet, &ctx->ohci->card, packet->ack);
+ }
+
+ offset =
+ ((unsigned long long)
+ HEADER_GET_OFFSET_HIGH(packet->header[1]) << 32) |
+ packet->header[2];
+ csr = offset - CSR_REGISTER_BASE;
+
+ /* Handle config rom reads. */
+ if (csr >= CSR_CONFIG_ROM && csr < CSR_CONFIG_ROM_END)
+ handle_local_rom(ctx->ohci, packet, csr);
+ else switch (csr) {
+ case CSR_BUS_MANAGER_ID:
+ case CSR_BANDWIDTH_AVAILABLE:
+ case CSR_CHANNELS_AVAILABLE_HI:
+ case CSR_CHANNELS_AVAILABLE_LO:
+ handle_local_lock(ctx->ohci, packet, csr);
+ break;
+ default:
+ if (ctx == &ctx->ohci->at_request_ctx)
+ fw_core_handle_request(&ctx->ohci->card, packet);
+ else
+ fw_core_handle_response(&ctx->ohci->card, packet);
+ break;
+ }
+
+ if (ctx == &ctx->ohci->at_response_ctx) {
+ packet->ack = ACK_COMPLETE;
+ packet->callback(packet, &ctx->ohci->card, packet->ack);
+ }
+}
+
+static void
+at_context_transmit(struct context *ctx, struct fw_packet *packet)
+{
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&ctx->ohci->lock, flags);
+
+ if (HEADER_GET_DESTINATION(packet->header[0]) == ctx->ohci->node_id &&
+ ctx->ohci->generation == packet->generation) {
+ spin_unlock_irqrestore(&ctx->ohci->lock, flags);
+ handle_local_request(ctx, packet);
+ return;
+ }
+
+ retval = at_context_queue_packet(ctx, packet);
+ spin_unlock_irqrestore(&ctx->ohci->lock, flags);
+
+ if (retval < 0)
+ packet->callback(packet, &ctx->ohci->card, packet->ack);
+
+}
+
+static void bus_reset_tasklet(unsigned long data)
+{
+ struct fw_ohci *ohci = (struct fw_ohci *)data;
+ int self_id_count, i, j, reg;
+ int generation, new_generation;
+ unsigned long flags;
+
+ reg = reg_read(ohci, OHCI1394_NodeID);
+ if (!(reg & OHCI1394_NodeID_idValid)) {
+ fw_error("node ID not valid, new bus reset in progress\n");
+ return;
+ }
+ ohci->node_id = reg & 0xffff;
+
+ /*
+ * The count in the SelfIDCount register is the number of
+ * bytes in the self ID receive buffer. Since we also receive
+ * the inverted quadlets and a header quadlet, we shift one
+ * bit extra to get the actual number of self IDs.
+ */
+
+ self_id_count = (reg_read(ohci, OHCI1394_SelfIDCount) >> 3) & 0x3ff;
+ generation = (le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
+
+ for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
+ if (ohci->self_id_cpu[i] != ~ohci->self_id_cpu[i + 1])
+ fw_error("inconsistent self IDs\n");
+ ohci->self_id_buffer[j] = le32_to_cpu(ohci->self_id_cpu[i]);
+ }
+
+ /*
+ * Check the consistency of the self IDs we just read. The
+ * problem we face is that a new bus reset can start while we
+ * read out the self IDs from the DMA buffer. If this happens,
+ * the DMA buffer will be overwritten with new self IDs and we
+ * will read out inconsistent data. The OHCI specification
+ * (section 11.2) recommends a technique similar to
+ * linux/seqlock.h, where we remember the generation of the
+ * self IDs in the buffer before reading them out and compare
+ * it to the current generation after reading them out. If
+ * the two generations match we know we have a consistent set
+ * of self IDs.
+ */
+
+ new_generation = (reg_read(ohci, OHCI1394_SelfIDCount) >> 16) & 0xff;
+ if (new_generation != generation) {
+ fw_notify("recursive bus reset detected, "
+ "discarding self ids\n");
+ return;
+ }
+
+ /* FIXME: Document how the locking works. */
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ ohci->generation = generation;
+ context_stop(&ohci->at_request_ctx);
+ context_stop(&ohci->at_response_ctx);
+ reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+
+ /*
+ * This next bit is unrelated to the AT context stuff but we
+ * have to do it under the spinlock also. If a new config rom
+ * was set up before this reset, the old one is now no longer
+ * in use and we can free it. Update the config rom pointers
+ * to point to the current config rom and clear the
+ * next_config_rom pointer so a new udpate can take place.
+ */
+
+ if (ohci->next_config_rom != NULL) {
+ dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ ohci->config_rom, ohci->config_rom_bus);
+ ohci->config_rom = ohci->next_config_rom;
+ ohci->config_rom_bus = ohci->next_config_rom_bus;
+ ohci->next_config_rom = NULL;
+
+ /*
+ * Restore config_rom image and manually update
+ * config_rom registers. Writing the header quadlet
+ * will indicate that the config rom is ready, so we
+ * do that last.
+ */
+ reg_write(ohci, OHCI1394_BusOptions,
+ be32_to_cpu(ohci->config_rom[2]));
+ ohci->config_rom[0] = cpu_to_be32(ohci->next_header);
+ reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header);
+ }
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+
+ fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
+ self_id_count, ohci->self_id_buffer);
+}
+
+static irqreturn_t irq_handler(int irq, void *data)
+{
+ struct fw_ohci *ohci = data;
+ u32 event, iso_event, cycle_time;
+ int i;
+
+ event = reg_read(ohci, OHCI1394_IntEventClear);
+
+ if (!event)
+ return IRQ_NONE;
+
+ reg_write(ohci, OHCI1394_IntEventClear, event);
+
+ if (event & OHCI1394_selfIDComplete)
+ tasklet_schedule(&ohci->bus_reset_tasklet);
+
+ if (event & OHCI1394_RQPkt)
+ tasklet_schedule(&ohci->ar_request_ctx.tasklet);
+
+ if (event & OHCI1394_RSPkt)
+ tasklet_schedule(&ohci->ar_response_ctx.tasklet);
+
+ if (event & OHCI1394_reqTxComplete)
+ tasklet_schedule(&ohci->at_request_ctx.tasklet);
+
+ if (event & OHCI1394_respTxComplete)
+ tasklet_schedule(&ohci->at_response_ctx.tasklet);
+
+ iso_event = reg_read(ohci, OHCI1394_IsoRecvIntEventClear);
+ reg_write(ohci, OHCI1394_IsoRecvIntEventClear, iso_event);
+
+ while (iso_event) {
+ i = ffs(iso_event) - 1;
+ tasklet_schedule(&ohci->ir_context_list[i].context.tasklet);
+ iso_event &= ~(1 << i);
+ }
+
+ iso_event = reg_read(ohci, OHCI1394_IsoXmitIntEventClear);
+ reg_write(ohci, OHCI1394_IsoXmitIntEventClear, iso_event);
+
+ while (iso_event) {
+ i = ffs(iso_event) - 1;
+ tasklet_schedule(&ohci->it_context_list[i].context.tasklet);
+ iso_event &= ~(1 << i);
+ }
+
+ if (event & OHCI1394_cycle64Seconds) {
+ cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ if ((cycle_time & 0x80000000) == 0)
+ ohci->bus_seconds++;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ struct pci_dev *dev = to_pci_dev(card->device);
+
+ /*
+ * When the link is not yet enabled, the atomic config rom
+ * update mechanism described below in ohci_set_config_rom()
+ * is not active. We have to update ConfigRomHeader and
+ * BusOptions manually, and the write to ConfigROMmap takes
+ * effect immediately. We tie this to the enabling of the
+ * link, so we have a valid config rom before enabling - the
+ * OHCI requires that ConfigROMhdr and BusOptions have valid
+ * values before enabling.
+ *
+ * However, when the ConfigROMmap is written, some controllers
+ * always read back quadlets 0 and 2 from the config rom to
+ * the ConfigRomHeader and BusOptions registers on bus reset.
+ * They shouldn't do that in this initial case where the link
+ * isn't enabled. This means we have to use the same
+ * workaround here, setting the bus header to 0 and then write
+ * the right values in the bus reset tasklet.
+ */
+
+ ohci->next_config_rom =
+ dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ &ohci->next_config_rom_bus, GFP_KERNEL);
+ if (ohci->next_config_rom == NULL)
+ return -ENOMEM;
+
+ memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
+ fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4);
+
+ ohci->next_header = config_rom[0];
+ ohci->next_config_rom[0] = 0;
+ reg_write(ohci, OHCI1394_ConfigROMhdr, 0);
+ reg_write(ohci, OHCI1394_BusOptions, config_rom[2]);
+ reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);
+
+ reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
+
+ if (request_irq(dev->irq, irq_handler,
+ IRQF_SHARED, ohci_driver_name, ohci)) {
+ fw_error("Failed to allocate shared interrupt %d.\n",
+ dev->irq);
+ dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ ohci->config_rom, ohci->config_rom_bus);
+ return -EIO;
+ }
+
+ reg_write(ohci, OHCI1394_HCControlSet,
+ OHCI1394_HCControl_linkEnable |
+ OHCI1394_HCControl_BIBimageValid);
+ flush_writes(ohci);
+
+ /*
+ * We are ready to go, initiate bus reset to finish the
+ * initialization.
+ */
+
+ fw_core_initiate_bus_reset(&ohci->card, 1);
+
+ return 0;
+}
+
+static int
+ohci_set_config_rom(struct fw_card *card, u32 *config_rom, size_t length)
+{
+ struct fw_ohci *ohci;
+ unsigned long flags;
+ int retval = 0;
+ __be32 *next_config_rom;
+ dma_addr_t next_config_rom_bus;
+
+ ohci = fw_ohci(card);
+
+ /*
+ * When the OHCI controller is enabled, the config rom update
+ * mechanism is a bit tricky, but easy enough to use. See
+ * section 5.5.6 in the OHCI specification.
+ *
+ * The OHCI controller caches the new config rom address in a
+ * shadow register (ConfigROMmapNext) and needs a bus reset
+ * for the changes to take place. When the bus reset is
+ * detected, the controller loads the new values for the
+ * ConfigRomHeader and BusOptions registers from the specified
+ * config rom and loads ConfigROMmap from the ConfigROMmapNext
+ * shadow register. All automatically and atomically.
+ *
+ * Now, there's a twist to this story. The automatic load of
+ * ConfigRomHeader and BusOptions doesn't honor the
+ * noByteSwapData bit, so with a be32 config rom, the
+ * controller will load be32 values in to these registers
+ * during the atomic update, even on litte endian
+ * architectures. The workaround we use is to put a 0 in the
+ * header quadlet; 0 is endian agnostic and means that the
+ * config rom isn't ready yet. In the bus reset tasklet we
+ * then set up the real values for the two registers.
+ *
+ * We use ohci->lock to avoid racing with the code that sets
+ * ohci->next_config_rom to NULL (see bus_reset_tasklet).
+ */
+
+ next_config_rom =
+ dma_alloc_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ &next_config_rom_bus, GFP_KERNEL);
+ if (next_config_rom == NULL)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ if (ohci->next_config_rom == NULL) {
+ ohci->next_config_rom = next_config_rom;
+ ohci->next_config_rom_bus = next_config_rom_bus;
+
+ memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE);
+ fw_memcpy_to_be32(ohci->next_config_rom, config_rom,
+ length * 4);
+
+ ohci->next_header = config_rom[0];
+ ohci->next_config_rom[0] = 0;
+
+ reg_write(ohci, OHCI1394_ConfigROMmap,
+ ohci->next_config_rom_bus);
+ } else {
+ dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+ next_config_rom, next_config_rom_bus);
+ retval = -EBUSY;
+ }
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+
+ /*
+ * Now initiate a bus reset to have the changes take
+ * effect. We clean up the old config rom memory and DMA
+ * mappings in the bus reset tasklet, since the OHCI
+ * controller could need to access it before the bus reset
+ * takes effect.
+ */
+ if (retval == 0)
+ fw_core_initiate_bus_reset(&ohci->card, 1);
+
+ return retval;
+}
+
+static void ohci_send_request(struct fw_card *card, struct fw_packet *packet)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+
+ at_context_transmit(&ohci->at_request_ctx, packet);
+}
+
+static void ohci_send_response(struct fw_card *card, struct fw_packet *packet)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+
+ at_context_transmit(&ohci->at_response_ctx, packet);
+}
+
+static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ struct context *ctx = &ohci->at_request_ctx;
+ struct driver_data *driver_data = packet->driver_data;
+ int retval = -ENOENT;
+
+ tasklet_disable(&ctx->tasklet);
+
+ if (packet->ack != 0)
+ goto out;
+
+ driver_data->packet = NULL;
+ packet->ack = RCODE_CANCELLED;
+ packet->callback(packet, &ohci->card, packet->ack);
+ retval = 0;
+
+ out:
+ tasklet_enable(&ctx->tasklet);
+
+ return retval;
+}
+
+static int
+ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ unsigned long flags;
+ int n, retval = 0;
+
+ /*
+ * FIXME: Make sure this bitmask is cleared when we clear the busReset
+ * interrupt bit. Clear physReqResourceAllBuses on bus reset.
+ */
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ if (ohci->generation != generation) {
+ retval = -ESTALE;
+ goto out;
+ }
+
+ /*
+ * Note, if the node ID contains a non-local bus ID, physical DMA is
+ * enabled for _all_ nodes on remote buses.
+ */
+
+ n = (node_id & 0xffc0) == LOCAL_BUS ? node_id & 0x3f : 63;
+ if (n < 32)
+ reg_write(ohci, OHCI1394_PhyReqFilterLoSet, 1 << n);
+ else
+ reg_write(ohci, OHCI1394_PhyReqFilterHiSet, 1 << (n - 32));
+
+ flush_writes(ohci);
+ out:
+ spin_unlock_irqrestore(&ohci->lock, flags);
+ return retval;
+}
+
+static u64
+ohci_get_bus_time(struct fw_card *card)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ u32 cycle_time;
+ u64 bus_time;
+
+ cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);
+ bus_time = ((u64) ohci->bus_seconds << 32) | cycle_time;
+
+ return bus_time;
+}
+
+static int handle_ir_dualbuffer_packet(struct context *context,
+ struct descriptor *d,
+ struct descriptor *last)
+{
+ struct iso_context *ctx =
+ container_of(context, struct iso_context, context);
+ struct db_descriptor *db = (struct db_descriptor *) d;
+ __le32 *ir_header;
+ size_t header_length;
+ void *p, *end;
+ int i;
+
+ if (db->first_res_count > 0 && db->second_res_count > 0)
+ /* This descriptor isn't done yet, stop iteration. */
+ return 0;
+
+ header_length = le16_to_cpu(db->first_req_count) -
+ le16_to_cpu(db->first_res_count);
+
+ i = ctx->header_length;
+ p = db + 1;
+ end = p + header_length;
+ while (p < end && i + ctx->base.header_size <= PAGE_SIZE) {
+ /*
+ * The iso header is byteswapped to little endian by
+ * the controller, but the remaining header quadlets
+ * are big endian. We want to present all the headers
+ * as big endian, so we have to swap the first
+ * quadlet.
+ */
+ *(u32 *) (ctx->header + i) = __swab32(*(u32 *) (p + 4));
+ memcpy(ctx->header + i + 4, p + 8, ctx->base.header_size - 4);
+ i += ctx->base.header_size;
+ p += ctx->base.header_size + 4;
+ }
+
+ ctx->header_length = i;
+
+ if (le16_to_cpu(db->control) & DESCRIPTOR_IRQ_ALWAYS) {
+ ir_header = (__le32 *) (db + 1);
+ ctx->base.callback(&ctx->base,
+ le32_to_cpu(ir_header[0]) & 0xffff,
+ ctx->header_length, ctx->header,
+ ctx->base.callback_data);
+ ctx->header_length = 0;
+ }
+
+ return 1;
+}
+
+static int handle_it_packet(struct context *context,
+ struct descriptor *d,
+ struct descriptor *last)
+{
+ struct iso_context *ctx =
+ container_of(context, struct iso_context, context);
+
+ if (last->transfer_status == 0)
+ /* This descriptor isn't done yet, stop iteration. */
+ return 0;
+
+ if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS)
+ ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count),
+ 0, NULL, ctx->base.callback_data);
+
+ return 1;
+}
+
+static struct fw_iso_context *
+ohci_allocate_iso_context(struct fw_card *card, int type, size_t header_size)
+{
+ struct fw_ohci *ohci = fw_ohci(card);
+ struct iso_context *ctx, *list;
+ descriptor_callback_t callback;
+ u32 *mask, regs;
+ unsigned long flags;
+ int index, retval = -ENOMEM;
+
+ if (type == FW_ISO_CONTEXT_TRANSMIT) {
+ mask = &ohci->it_context_mask;
+ list = ohci->it_context_list;
+ callback = handle_it_packet;
+ } else {
+ mask = &ohci->ir_context_mask;
+ list = ohci->ir_context_list;
+ callback = handle_ir_dualbuffer_packet;
+ }
+
+ /* FIXME: We need a fallback for pre 1.1 OHCI. */
+ if (callback == handle_ir_dualbuffer_packet &&
+ ohci->version < OHCI_VERSION_1_1)
+ return ERR_PTR(-EINVAL);
+
+ spin_lock_irqsave(&ohci->lock, flags);
+ index = ffs(*mask) - 1;
+ if (index >= 0)
+ *mask &= ~(1 << index);
+ spin_unlock_irqrestore(&ohci->lock, flags);
+
+ if (index < 0)
+ return ERR_PTR(-EBUSY);
+
+ if (type == FW_ISO_CONTEXT_TRANSMIT)
+ regs = OHCI1394_IsoXmitContextBase(index);
+ else
+ regs = OHCI1394_IsoRcvContextBase(index);
+
+ ctx = &list[index];
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->header_length = 0;
+ ctx->header = (void *) __get_free_page(GFP_KERNEL);
+ if (ctx->header == NULL)
+ goto out;
+
+ retval = context_init(&ctx->context, ohci, ISO_BUFFER_SIZE,
+ regs, callback);
+ if (retval < 0)
+ goto out_with_header;
+
+ return &ctx->base;
+
+ out_with_header:
+ free_page((unsigned long)ctx->header);
+ out:
+ spin_lock_irqsave(&ohci->lock, flags);
+ *mask |= 1 << index;
+ spin_unlock_irqrestore(&ohci->lock, flags);
+
+ return ERR_PTR(retval);
+}
+
+static int ohci_start_iso(struct fw_iso_context *base,
+ s32 cycle, u32 sync, u32 tags)
+{
+ struct iso_context *ctx = container_of(base, struct iso_context, base);
+ struct fw_ohci *ohci = ctx->context.ohci;
+ u32 control, match;
+ int index;
+
+ if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+ index = ctx - ohci->it_context_list;
+ match = 0;
+ if (cycle >= 0)
+ match = IT_CONTEXT_CYCLE_MATCH_ENABLE |
+ (cycle & 0x7fff) << 16;
+
+ reg_write(ohci, OHCI1394_IsoXmitIntEventClear, 1 << index);
+ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, 1 << index);
+ context_run(&ctx->context, match);
+ } else {
+ index = ctx - ohci->ir_context_list;
+ control = IR_CONTEXT_DUAL_BUFFER_MODE | IR_CONTEXT_ISOCH_HEADER;
+ match = (tags << 28) | (sync << 8) | ctx->base.channel;
+ if (cycle >= 0) {
+ match |= (cycle & 0x07fff) << 12;
+ control |= IR_CONTEXT_CYCLE_MATCH_ENABLE;
+ }
+
+ reg_write(ohci, OHCI1394_IsoRecvIntEventClear, 1 << index);
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, 1 << index);
+ reg_write(ohci, CONTEXT_MATCH(ctx->context.regs), match);
+ context_run(&ctx->context, control);
+ }
+
+ return 0;
+}
+
+static int ohci_stop_iso(struct fw_iso_context *base)
+{
+ struct fw_ohci *ohci = fw_ohci(base->card);
+ struct iso_context *ctx = container_of(base, struct iso_context, base);
+ int index;
+
+ if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+ index = ctx - ohci->it_context_list;
+ reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, 1 << index);
+ } else {
+ index = ctx - ohci->ir_context_list;
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, 1 << index);
+ }
+ flush_writes(ohci);
+ context_stop(&ctx->context);
+
+ return 0;
+}
+
+static void ohci_free_iso_context(struct fw_iso_context *base)
+{
+ struct fw_ohci *ohci = fw_ohci(base->card);
+ struct iso_context *ctx = container_of(base, struct iso_context, base);
+ unsigned long flags;
+ int index;
+
+ ohci_stop_iso(base);
+ context_release(&ctx->context);
+ free_page((unsigned long)ctx->header);
+
+ spin_lock_irqsave(&ohci->lock, flags);
+
+ if (ctx->base.type == FW_ISO_CONTEXT_TRANSMIT) {
+ index = ctx - ohci->it_context_list;
+ ohci->it_context_mask |= 1 << index;
+ } else {
+ index = ctx - ohci->ir_context_list;
+ ohci->ir_context_mask |= 1 << index;
+ }
+
+ spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
+static int
+ohci_queue_iso_transmit(struct fw_iso_context *base,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload)
+{
+ struct iso_context *ctx = container_of(base, struct iso_context, base);
+ struct descriptor *d, *last, *pd;
+ struct fw_iso_packet *p;
+ __le32 *header;
+ dma_addr_t d_bus, page_bus;
+ u32 z, header_z, payload_z, irq;
+ u32 payload_index, payload_end_index, next_page_index;
+ int page, end_page, i, length, offset;
+
+ /*
+ * FIXME: Cycle lost behavior should be configurable: lose
+ * packet, retransmit or terminate..
+ */
+
+ p = packet;
+ payload_index = payload;
+
+ if (p->skip)
+ z = 1;
+ else
+ z = 2;
+ if (p->header_length > 0)
+ z++;
+
+ /* Determine the first page the payload isn't contained in. */
+ end_page = PAGE_ALIGN(payload_index + p->payload_length) >> PAGE_SHIFT;
+ if (p->payload_length > 0)
+ payload_z = end_page - (payload_index >> PAGE_SHIFT);
+ else
+ payload_z = 0;
+
+ z += payload_z;
+
+ /* Get header size in number of descriptors. */
+ header_z = DIV_ROUND_UP(p->header_length, sizeof(*d));
+
+ d = context_get_descriptors(&ctx->context, z + header_z, &d_bus);
+ if (d == NULL)
+ return -ENOMEM;
+
+ if (!p->skip) {
+ d[0].control = cpu_to_le16(DESCRIPTOR_KEY_IMMEDIATE);
+ d[0].req_count = cpu_to_le16(8);
+
+ header = (__le32 *) &d[1];
+ header[0] = cpu_to_le32(IT_HEADER_SY(p->sy) |
+ IT_HEADER_TAG(p->tag) |
+ IT_HEADER_TCODE(TCODE_STREAM_DATA) |
+ IT_HEADER_CHANNEL(ctx->base.channel) |
+ IT_HEADER_SPEED(ctx->base.speed));
+ header[1] =
+ cpu_to_le32(IT_HEADER_DATA_LENGTH(p->header_length +
+ p->payload_length));
+ }
+
+ if (p->header_length > 0) {
+ d[2].req_count = cpu_to_le16(p->header_length);
+ d[2].data_address = cpu_to_le32(d_bus + z * sizeof(*d));
+ memcpy(&d[z], p->header, p->header_length);
+ }
+
+ pd = d + z - payload_z;
+ payload_end_index = payload_index + p->payload_length;
+ for (i = 0; i < payload_z; i++) {
+ page = payload_index >> PAGE_SHIFT;
+ offset = payload_index & ~PAGE_MASK;
+ next_page_index = (page + 1) << PAGE_SHIFT;
+ length =
+ min(next_page_index, payload_end_index) - payload_index;
+ pd[i].req_count = cpu_to_le16(length);
+
+ page_bus = page_private(buffer->pages[page]);
+ pd[i].data_address = cpu_to_le32(page_bus + offset);
+
+ payload_index += length;
+ }
+
+ if (p->interrupt)
+ irq = DESCRIPTOR_IRQ_ALWAYS;
+ else
+ irq = DESCRIPTOR_NO_IRQ;
+
+ last = z == 2 ? d : d + z - 1;
+ last->control |= cpu_to_le16(DESCRIPTOR_OUTPUT_LAST |
+ DESCRIPTOR_STATUS |
+ DESCRIPTOR_BRANCH_ALWAYS |
+ irq);
+
+ context_append(&ctx->context, d, z, header_z);
+
+ return 0;
+}
+
+static int
+ohci_queue_iso_receive_dualbuffer(struct fw_iso_context *base,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload)
+{
+ struct iso_context *ctx = container_of(base, struct iso_context, base);
+ struct db_descriptor *db = NULL;
+ struct descriptor *d;
+ struct fw_iso_packet *p;
+ dma_addr_t d_bus, page_bus;
+ u32 z, header_z, length, rest;
+ int page, offset, packet_count, header_size;
+
+ /*
+ * FIXME: Cycle lost behavior should be configurable: lose
+ * packet, retransmit or terminate..
+ */
+
+ if (packet->skip) {
+ d = context_get_descriptors(&ctx->context, 2, &d_bus);
+ if (d == NULL)
+ return -ENOMEM;
+
+ db = (struct db_descriptor *) d;
+ db->control = cpu_to_le16(DESCRIPTOR_STATUS |
+ DESCRIPTOR_BRANCH_ALWAYS |
+ DESCRIPTOR_WAIT);
+ db->first_size = cpu_to_le16(ctx->base.header_size + 4);
+ context_append(&ctx->context, d, 2, 0);
+ }
+
+ p = packet;
+ z = 2;
+
+ /*
+ * The OHCI controller puts the status word in the header
+ * buffer too, so we need 4 extra bytes per packet.
+ */
+ packet_count = p->header_length / ctx->base.header_size;
+ header_size = packet_count * (ctx->base.header_size + 4);
+
+ /* Get header size in number of descriptors. */
+ header_z = DIV_ROUND_UP(header_size, sizeof(*d));
+ page = payload >> PAGE_SHIFT;
+ offset = payload & ~PAGE_MASK;
+ rest = p->payload_length;
+
+ /* FIXME: OHCI 1.0 doesn't support dual buffer receive */
+ /* FIXME: make packet-per-buffer/dual-buffer a context option */
+ while (rest > 0) {
+ d = context_get_descriptors(&ctx->context,
+ z + header_z, &d_bus);
+ if (d == NULL)
+ return -ENOMEM;
+
+ db = (struct db_descriptor *) d;
+ db->control = cpu_to_le16(DESCRIPTOR_STATUS |
+ DESCRIPTOR_BRANCH_ALWAYS);
+ db->first_size = cpu_to_le16(ctx->base.header_size + 4);
+ db->first_req_count = cpu_to_le16(header_size);
+ db->first_res_count = db->first_req_count;
+ db->first_buffer = cpu_to_le32(d_bus + sizeof(*db));
+
+ if (offset + rest < PAGE_SIZE)
+ length = rest;
+ else
+ length = PAGE_SIZE - offset;
+
+ db->second_req_count = cpu_to_le16(length);
+ db->second_res_count = db->second_req_count;
+ page_bus = page_private(buffer->pages[page]);
+ db->second_buffer = cpu_to_le32(page_bus + offset);
+
+ if (p->interrupt && length == rest)
+ db->control |= cpu_to_le16(DESCRIPTOR_IRQ_ALWAYS);
+
+ context_append(&ctx->context, d, z, header_z);
+ offset = (offset + length) & ~PAGE_MASK;
+ rest -= length;
+ page++;
+ }
+
+ return 0;
+}
+
+static int
+ohci_queue_iso(struct fw_iso_context *base,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload)
+{
+ struct iso_context *ctx = container_of(base, struct iso_context, base);
+
+ if (base->type == FW_ISO_CONTEXT_TRANSMIT)
+ return ohci_queue_iso_transmit(base, packet, buffer, payload);
+ else if (ctx->context.ohci->version >= OHCI_VERSION_1_1)
+ return ohci_queue_iso_receive_dualbuffer(base, packet,
+ buffer, payload);
+ else
+ /* FIXME: Implement fallback for OHCI 1.0 controllers. */
+ return -EINVAL;
+}
+
+static const struct fw_card_driver ohci_driver = {
+ .name = ohci_driver_name,
+ .enable = ohci_enable,
+ .update_phy_reg = ohci_update_phy_reg,
+ .set_config_rom = ohci_set_config_rom,
+ .send_request = ohci_send_request,
+ .send_response = ohci_send_response,
+ .cancel_packet = ohci_cancel_packet,
+ .enable_phys_dma = ohci_enable_phys_dma,
+ .get_bus_time = ohci_get_bus_time,
+
+ .allocate_iso_context = ohci_allocate_iso_context,
+ .free_iso_context = ohci_free_iso_context,
+ .queue_iso = ohci_queue_iso,
+ .start_iso = ohci_start_iso,
+ .stop_iso = ohci_stop_iso,
+};
+
+static int software_reset(struct fw_ohci *ohci)
+{
+ int i;
+
+ reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
+
+ for (i = 0; i < OHCI_LOOP_COUNT; i++) {
+ if ((reg_read(ohci, OHCI1394_HCControlSet) &
+ OHCI1394_HCControl_softReset) == 0)
+ return 0;
+ msleep(1);
+ }
+
+ return -EBUSY;
+}
+
+static int __devinit
+pci_probe(struct pci_dev *dev, const struct pci_device_id *ent)
+{
+ struct fw_ohci *ohci;
+ u32 bus_options, max_receive, link_speed;
+ u64 guid;
+ int err;
+ size_t size;
+
+ ohci = kzalloc(sizeof(*ohci), GFP_KERNEL);
+ if (ohci == NULL) {
+ fw_error("Could not malloc fw_ohci data.\n");
+ return -ENOMEM;
+ }
+
+ fw_card_initialize(&ohci->card, &ohci_driver, &dev->dev);
+
+ err = pci_enable_device(dev);
+ if (err) {
+ fw_error("Failed to enable OHCI hardware.\n");
+ goto fail_put_card;
+ }
+
+ pci_set_master(dev);
+ pci_write_config_dword(dev, OHCI1394_PCI_HCI_Control, 0);
+ pci_set_drvdata(dev, ohci);
+
+ spin_lock_init(&ohci->lock);
+
+ tasklet_init(&ohci->bus_reset_tasklet,
+ bus_reset_tasklet, (unsigned long)ohci);
+
+ err = pci_request_region(dev, 0, ohci_driver_name);
+ if (err) {
+ fw_error("MMIO resource unavailable\n");
+ goto fail_disable;
+ }
+
+ ohci->registers = pci_iomap(dev, 0, OHCI1394_REGISTER_SIZE);
+ if (ohci->registers == NULL) {
+ fw_error("Failed to remap registers\n");
+ err = -ENXIO;
+ goto fail_iomem;
+ }
+
+ if (software_reset(ohci)) {
+ fw_error("Failed to reset ohci card.\n");
+ err = -EBUSY;
+ goto fail_registers;
+ }
+
+ /*
+ * Now enable LPS, which we need in order to start accessing
+ * most of the registers. In fact, on some cards (ALI M5251),
+ * accessing registers in the SClk domain without LPS enabled
+ * will lock up the machine. Wait 50msec to make sure we have
+ * full link enabled.
+ */
+ reg_write(ohci, OHCI1394_HCControlSet,
+ OHCI1394_HCControl_LPS |
+ OHCI1394_HCControl_postedWriteEnable);
+ flush_writes(ohci);
+ msleep(50);
+
+ reg_write(ohci, OHCI1394_HCControlClear,
+ OHCI1394_HCControl_noByteSwapData);
+
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ OHCI1394_LinkControl_rcvSelfID |
+ OHCI1394_LinkControl_cycleTimerEnable |
+ OHCI1394_LinkControl_cycleMaster);
+
+ ar_context_init(&ohci->ar_request_ctx, ohci,
+ OHCI1394_AsReqRcvContextControlSet);
+
+ ar_context_init(&ohci->ar_response_ctx, ohci,
+ OHCI1394_AsRspRcvContextControlSet);
+
+ context_init(&ohci->at_request_ctx, ohci, AT_BUFFER_SIZE,
+ OHCI1394_AsReqTrContextControlSet, handle_at_packet);
+
+ context_init(&ohci->at_response_ctx, ohci, AT_BUFFER_SIZE,
+ OHCI1394_AsRspTrContextControlSet, handle_at_packet);
+
+ reg_write(ohci, OHCI1394_ATRetries,
+ OHCI1394_MAX_AT_REQ_RETRIES |
+ (OHCI1394_MAX_AT_RESP_RETRIES << 4) |
+ (OHCI1394_MAX_PHYS_RESP_RETRIES << 8));
+
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskSet, ~0);
+ ohci->it_context_mask = reg_read(ohci, OHCI1394_IsoRecvIntMaskSet);
+ reg_write(ohci, OHCI1394_IsoRecvIntMaskClear, ~0);
+ size = sizeof(struct iso_context) * hweight32(ohci->it_context_mask);
+ ohci->it_context_list = kzalloc(size, GFP_KERNEL);
+
+ reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
+ ohci->ir_context_mask = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
+ reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
+ size = sizeof(struct iso_context) * hweight32(ohci->ir_context_mask);
+ ohci->ir_context_list = kzalloc(size, GFP_KERNEL);
+
+ if (ohci->it_context_list == NULL || ohci->ir_context_list == NULL) {
+ fw_error("Out of memory for it/ir contexts.\n");
+ err = -ENOMEM;
+ goto fail_registers;
+ }
+
+ /* self-id dma buffer allocation */
+ ohci->self_id_cpu = dma_alloc_coherent(ohci->card.device,
+ SELF_ID_BUF_SIZE,
+ &ohci->self_id_bus,
+ GFP_KERNEL);
+ if (ohci->self_id_cpu == NULL) {
+ fw_error("Out of memory for self ID buffer.\n");
+ err = -ENOMEM;
+ goto fail_registers;
+ }
+
+ reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
+ reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
+ reg_write(ohci, OHCI1394_IntEventClear, ~0);
+ reg_write(ohci, OHCI1394_IntMaskClear, ~0);
+ reg_write(ohci, OHCI1394_IntMaskSet,
+ OHCI1394_selfIDComplete |
+ OHCI1394_RQPkt | OHCI1394_RSPkt |
+ OHCI1394_reqTxComplete | OHCI1394_respTxComplete |
+ OHCI1394_isochRx | OHCI1394_isochTx |
+ OHCI1394_masterIntEnable |
+ OHCI1394_cycle64Seconds);
+
+ bus_options = reg_read(ohci, OHCI1394_BusOptions);
+ max_receive = (bus_options >> 12) & 0xf;
+ link_speed = bus_options & 0x7;
+ guid = ((u64) reg_read(ohci, OHCI1394_GUIDHi) << 32) |
+ reg_read(ohci, OHCI1394_GUIDLo);
+
+ err = fw_card_add(&ohci->card, max_receive, link_speed, guid);
+ if (err < 0)
+ goto fail_self_id;
+
+ ohci->version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
+ fw_notify("Added fw-ohci device %s, OHCI version %x.%x\n",
+ dev->dev.bus_id, ohci->version >> 16, ohci->version & 0xff);
+
+ return 0;
+
+ fail_self_id:
+ dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
+ ohci->self_id_cpu, ohci->self_id_bus);
+ fail_registers:
+ kfree(ohci->it_context_list);
+ kfree(ohci->ir_context_list);
+ pci_iounmap(dev, ohci->registers);
+ fail_iomem:
+ pci_release_region(dev, 0);
+ fail_disable:
+ pci_disable_device(dev);
+ fail_put_card:
+ fw_card_put(&ohci->card);
+
+ return err;
+}
+
+static void pci_remove(struct pci_dev *dev)
+{
+ struct fw_ohci *ohci;
+
+ ohci = pci_get_drvdata(dev);
+ reg_write(ohci, OHCI1394_IntMaskClear, ~0);
+ flush_writes(ohci);
+ fw_core_remove_card(&ohci->card);
+
+ /*
+ * FIXME: Fail all pending packets here, now that the upper
+ * layers can't queue any more.
+ */
+
+ software_reset(ohci);
+ free_irq(dev->irq, ohci);
+ dma_free_coherent(ohci->card.device, SELF_ID_BUF_SIZE,
+ ohci->self_id_cpu, ohci->self_id_bus);
+ kfree(ohci->it_context_list);
+ kfree(ohci->ir_context_list);
+ pci_iounmap(dev, ohci->registers);
+ pci_release_region(dev, 0);
+ pci_disable_device(dev);
+ fw_card_put(&ohci->card);
+
+ fw_notify("Removed fw-ohci device.\n");
+}
+
+static struct pci_device_id pci_table[] = {
+ { PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_FIREWIRE_OHCI, ~0) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, pci_table);
+
+static struct pci_driver fw_ohci_pci_driver = {
+ .name = ohci_driver_name,
+ .id_table = pci_table,
+ .probe = pci_probe,
+ .remove = pci_remove,
+};
+
+MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
+MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers");
+MODULE_LICENSE("GPL");
+
+/* Provide a module alias so root-on-sbp2 initrds don't break. */
+#ifndef CONFIG_IEEE1394_OHCI1394_MODULE
+MODULE_ALIAS("ohci1394");
+#endif
+
+static int __init fw_ohci_init(void)
+{
+ return pci_register_driver(&fw_ohci_pci_driver);
+}
+
+static void __exit fw_ohci_cleanup(void)
+{
+ pci_unregister_driver(&fw_ohci_pci_driver);
+}
+
+module_init(fw_ohci_init);
+module_exit(fw_ohci_cleanup);
diff --git a/drivers/firewire/fw-ohci.h b/drivers/firewire/fw-ohci.h
new file mode 100644
index 0000000..fa15706
--- /dev/null
+++ b/drivers/firewire/fw-ohci.h
@@ -0,0 +1,153 @@
+#ifndef __fw_ohci_h
+#define __fw_ohci_h
+
+/* OHCI register map */
+
+#define OHCI1394_Version 0x000
+#define OHCI1394_GUID_ROM 0x004
+#define OHCI1394_ATRetries 0x008
+#define OHCI1394_CSRData 0x00C
+#define OHCI1394_CSRCompareData 0x010
+#define OHCI1394_CSRControl 0x014
+#define OHCI1394_ConfigROMhdr 0x018
+#define OHCI1394_BusID 0x01C
+#define OHCI1394_BusOptions 0x020
+#define OHCI1394_GUIDHi 0x024
+#define OHCI1394_GUIDLo 0x028
+#define OHCI1394_ConfigROMmap 0x034
+#define OHCI1394_PostedWriteAddressLo 0x038
+#define OHCI1394_PostedWriteAddressHi 0x03C
+#define OHCI1394_VendorID 0x040
+#define OHCI1394_HCControlSet 0x050
+#define OHCI1394_HCControlClear 0x054
+#define OHCI1394_HCControl_BIBimageValid 0x80000000
+#define OHCI1394_HCControl_noByteSwapData 0x40000000
+#define OHCI1394_HCControl_programPhyEnable 0x00800000
+#define OHCI1394_HCControl_aPhyEnhanceEnable 0x00400000
+#define OHCI1394_HCControl_LPS 0x00080000
+#define OHCI1394_HCControl_postedWriteEnable 0x00040000
+#define OHCI1394_HCControl_linkEnable 0x00020000
+#define OHCI1394_HCControl_softReset 0x00010000
+#define OHCI1394_SelfIDBuffer 0x064
+#define OHCI1394_SelfIDCount 0x068
+#define OHCI1394_IRMultiChanMaskHiSet 0x070
+#define OHCI1394_IRMultiChanMaskHiClear 0x074
+#define OHCI1394_IRMultiChanMaskLoSet 0x078
+#define OHCI1394_IRMultiChanMaskLoClear 0x07C
+#define OHCI1394_IntEventSet 0x080
+#define OHCI1394_IntEventClear 0x084
+#define OHCI1394_IntMaskSet 0x088
+#define OHCI1394_IntMaskClear 0x08C
+#define OHCI1394_IsoXmitIntEventSet 0x090
+#define OHCI1394_IsoXmitIntEventClear 0x094
+#define OHCI1394_IsoXmitIntMaskSet 0x098
+#define OHCI1394_IsoXmitIntMaskClear 0x09C
+#define OHCI1394_IsoRecvIntEventSet 0x0A0
+#define OHCI1394_IsoRecvIntEventClear 0x0A4
+#define OHCI1394_IsoRecvIntMaskSet 0x0A8
+#define OHCI1394_IsoRecvIntMaskClear 0x0AC
+#define OHCI1394_InitialBandwidthAvailable 0x0B0
+#define OHCI1394_InitialChannelsAvailableHi 0x0B4
+#define OHCI1394_InitialChannelsAvailableLo 0x0B8
+#define OHCI1394_FairnessControl 0x0DC
+#define OHCI1394_LinkControlSet 0x0E0
+#define OHCI1394_LinkControlClear 0x0E4
+#define OHCI1394_LinkControl_rcvSelfID (1 << 9)
+#define OHCI1394_LinkControl_rcvPhyPkt (1 << 10)
+#define OHCI1394_LinkControl_cycleTimerEnable (1 << 20)
+#define OHCI1394_LinkControl_cycleMaster (1 << 21)
+#define OHCI1394_LinkControl_cycleSource (1 << 22)
+#define OHCI1394_NodeID 0x0E8
+#define OHCI1394_NodeID_idValid 0x80000000
+#define OHCI1394_PhyControl 0x0EC
+#define OHCI1394_PhyControl_Read(addr) (((addr) << 8) | 0x00008000)
+#define OHCI1394_PhyControl_ReadDone 0x80000000
+#define OHCI1394_PhyControl_ReadData(r) (((r) & 0x00ff0000) >> 16)
+#define OHCI1394_PhyControl_Write(addr, data) (((addr) << 8) | (data) | 0x00004000)
+#define OHCI1394_PhyControl_WriteDone 0x00004000
+#define OHCI1394_IsochronousCycleTimer 0x0F0
+#define OHCI1394_AsReqFilterHiSet 0x100
+#define OHCI1394_AsReqFilterHiClear 0x104
+#define OHCI1394_AsReqFilterLoSet 0x108
+#define OHCI1394_AsReqFilterLoClear 0x10C
+#define OHCI1394_PhyReqFilterHiSet 0x110
+#define OHCI1394_PhyReqFilterHiClear 0x114
+#define OHCI1394_PhyReqFilterLoSet 0x118
+#define OHCI1394_PhyReqFilterLoClear 0x11C
+#define OHCI1394_PhyUpperBound 0x120
+
+#define OHCI1394_AsReqTrContextBase 0x180
+#define OHCI1394_AsReqTrContextControlSet 0x180
+#define OHCI1394_AsReqTrContextControlClear 0x184
+#define OHCI1394_AsReqTrCommandPtr 0x18C
+
+#define OHCI1394_AsRspTrContextBase 0x1A0
+#define OHCI1394_AsRspTrContextControlSet 0x1A0
+#define OHCI1394_AsRspTrContextControlClear 0x1A4
+#define OHCI1394_AsRspTrCommandPtr 0x1AC
+
+#define OHCI1394_AsReqRcvContextBase 0x1C0
+#define OHCI1394_AsReqRcvContextControlSet 0x1C0
+#define OHCI1394_AsReqRcvContextControlClear 0x1C4
+#define OHCI1394_AsReqRcvCommandPtr 0x1CC
+
+#define OHCI1394_AsRspRcvContextBase 0x1E0
+#define OHCI1394_AsRspRcvContextControlSet 0x1E0
+#define OHCI1394_AsRspRcvContextControlClear 0x1E4
+#define OHCI1394_AsRspRcvCommandPtr 0x1EC
+
+/* Isochronous transmit registers */
+#define OHCI1394_IsoXmitContextBase(n) (0x200 + 16 * (n))
+#define OHCI1394_IsoXmitContextControlSet(n) (0x200 + 16 * (n))
+#define OHCI1394_IsoXmitContextControlClear(n) (0x204 + 16 * (n))
+#define OHCI1394_IsoXmitCommandPtr(n) (0x20C + 16 * (n))
+
+/* Isochronous receive registers */
+#define OHCI1394_IsoRcvContextBase(n) (0x400 + 32 * (n))
+#define OHCI1394_IsoRcvContextControlSet(n) (0x400 + 32 * (n))
+#define OHCI1394_IsoRcvContextControlClear(n) (0x404 + 32 * (n))
+#define OHCI1394_IsoRcvCommandPtr(n) (0x40C + 32 * (n))
+#define OHCI1394_IsoRcvContextMatch(n) (0x410 + 32 * (n))
+
+/* Interrupts Mask/Events */
+#define OHCI1394_reqTxComplete 0x00000001
+#define OHCI1394_respTxComplete 0x00000002
+#define OHCI1394_ARRQ 0x00000004
+#define OHCI1394_ARRS 0x00000008
+#define OHCI1394_RQPkt 0x00000010
+#define OHCI1394_RSPkt 0x00000020
+#define OHCI1394_isochTx 0x00000040
+#define OHCI1394_isochRx 0x00000080
+#define OHCI1394_postedWriteErr 0x00000100
+#define OHCI1394_lockRespErr 0x00000200
+#define OHCI1394_selfIDComplete 0x00010000
+#define OHCI1394_busReset 0x00020000
+#define OHCI1394_phy 0x00080000
+#define OHCI1394_cycleSynch 0x00100000
+#define OHCI1394_cycle64Seconds 0x00200000
+#define OHCI1394_cycleLost 0x00400000
+#define OHCI1394_cycleInconsistent 0x00800000
+#define OHCI1394_unrecoverableError 0x01000000
+#define OHCI1394_cycleTooLong 0x02000000
+#define OHCI1394_phyRegRcvd 0x04000000
+#define OHCI1394_masterIntEnable 0x80000000
+
+#define OHCI1394_evt_no_status 0x0
+#define OHCI1394_evt_long_packet 0x2
+#define OHCI1394_evt_missing_ack 0x3
+#define OHCI1394_evt_underrun 0x4
+#define OHCI1394_evt_overrun 0x5
+#define OHCI1394_evt_descriptor_read 0x6
+#define OHCI1394_evt_data_read 0x7
+#define OHCI1394_evt_data_write 0x8
+#define OHCI1394_evt_bus_reset 0x9
+#define OHCI1394_evt_timeout 0xa
+#define OHCI1394_evt_tcode_err 0xb
+#define OHCI1394_evt_reserved_b 0xc
+#define OHCI1394_evt_reserved_c 0xd
+#define OHCI1394_evt_unknown 0xe
+#define OHCI1394_evt_flushed 0xf
+
+#define OHCI1394_phy_tcode 0xe
+
+#endif /* __fw_ohci_h */
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
new file mode 100644
index 0000000..6830041
--- /dev/null
+++ b/drivers/firewire/fw-sbp2.c
@@ -0,0 +1,1147 @@
+/*
+ * SBP2 driver (SCSI over IEEE1394)
+ *
+ * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * The basic structure of this driver is based on the old storage driver,
+ * drivers/ieee1394/sbp2.c, originally written by
+ * James Goodwin <jamesg@filanet.com>
+ * with later contributions and ongoing maintenance from
+ * Ben Collins <bcollins@debian.org>,
+ * Stefan Richter <stefanr@s5r6.in-berlin.de>
+ * and many others.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/timer.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+/* I don't know why the SCSI stack doesn't define something like this... */
+typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
+
+static const char sbp2_driver_name[] = "sbp2";
+
+struct sbp2_device {
+ struct kref kref;
+ struct fw_unit *unit;
+ struct fw_address_handler address_handler;
+ struct list_head orb_list;
+ u64 management_agent_address;
+ u64 command_block_agent_address;
+ u32 workarounds;
+ int login_id;
+
+ /*
+ * We cache these addresses and only update them once we've
+ * logged in or reconnected to the sbp2 device. That way, any
+ * IO to the device will automatically fail and get retried if
+ * it happens in a window where the device is not ready to
+ * handle it (e.g. after a bus reset but before we reconnect).
+ */
+ int node_id;
+ int address_high;
+ int generation;
+
+ int retries;
+ struct delayed_work work;
+};
+
+#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
+#define SBP2_MAX_SECTORS 255 /* Max sectors supported */
+#define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */
+
+#define SBP2_ORB_NULL 0x80000000
+
+#define SBP2_DIRECTION_TO_MEDIA 0x0
+#define SBP2_DIRECTION_FROM_MEDIA 0x1
+
+/* Unit directory keys */
+#define SBP2_COMMAND_SET_SPECIFIER 0x38
+#define SBP2_COMMAND_SET 0x39
+#define SBP2_COMMAND_SET_REVISION 0x3b
+#define SBP2_FIRMWARE_REVISION 0x3c
+
+/* Flags for detected oddities and brokeness */
+#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
+#define SBP2_WORKAROUND_INQUIRY_36 0x2
+#define SBP2_WORKAROUND_MODE_SENSE_8 0x4
+#define SBP2_WORKAROUND_FIX_CAPACITY 0x8
+#define SBP2_WORKAROUND_OVERRIDE 0x100
+
+/* Management orb opcodes */
+#define SBP2_LOGIN_REQUEST 0x0
+#define SBP2_QUERY_LOGINS_REQUEST 0x1
+#define SBP2_RECONNECT_REQUEST 0x3
+#define SBP2_SET_PASSWORD_REQUEST 0x4
+#define SBP2_LOGOUT_REQUEST 0x7
+#define SBP2_ABORT_TASK_REQUEST 0xb
+#define SBP2_ABORT_TASK_SET 0xc
+#define SBP2_LOGICAL_UNIT_RESET 0xe
+#define SBP2_TARGET_RESET_REQUEST 0xf
+
+/* Offsets for command block agent registers */
+#define SBP2_AGENT_STATE 0x00
+#define SBP2_AGENT_RESET 0x04
+#define SBP2_ORB_POINTER 0x08
+#define SBP2_DOORBELL 0x10
+#define SBP2_UNSOLICITED_STATUS_ENABLE 0x14
+
+/* Status write response codes */
+#define SBP2_STATUS_REQUEST_COMPLETE 0x0
+#define SBP2_STATUS_TRANSPORT_FAILURE 0x1
+#define SBP2_STATUS_ILLEGAL_REQUEST 0x2
+#define SBP2_STATUS_VENDOR_DEPENDENT 0x3
+
+#define STATUS_GET_ORB_HIGH(v) ((v).status & 0xffff)
+#define STATUS_GET_SBP_STATUS(v) (((v).status >> 16) & 0xff)
+#define STATUS_GET_LEN(v) (((v).status >> 24) & 0x07)
+#define STATUS_GET_DEAD(v) (((v).status >> 27) & 0x01)
+#define STATUS_GET_RESPONSE(v) (((v).status >> 28) & 0x03)
+#define STATUS_GET_SOURCE(v) (((v).status >> 30) & 0x03)
+#define STATUS_GET_ORB_LOW(v) ((v).orb_low)
+#define STATUS_GET_DATA(v) ((v).data)
+
+struct sbp2_status {
+ u32 status;
+ u32 orb_low;
+ u8 data[24];
+};
+
+struct sbp2_pointer {
+ u32 high;
+ u32 low;
+};
+
+struct sbp2_orb {
+ struct fw_transaction t;
+ dma_addr_t request_bus;
+ int rcode;
+ struct sbp2_pointer pointer;
+ void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status);
+ struct list_head link;
+};
+
+#define MANAGEMENT_ORB_LUN(v) ((v))
+#define MANAGEMENT_ORB_FUNCTION(v) ((v) << 16)
+#define MANAGEMENT_ORB_RECONNECT(v) ((v) << 20)
+#define MANAGEMENT_ORB_EXCLUSIVE ((1) << 28)
+#define MANAGEMENT_ORB_REQUEST_FORMAT(v) ((v) << 29)
+#define MANAGEMENT_ORB_NOTIFY ((1) << 31)
+
+#define MANAGEMENT_ORB_RESPONSE_LENGTH(v) ((v))
+#define MANAGEMENT_ORB_PASSWORD_LENGTH(v) ((v) << 16)
+
+struct sbp2_management_orb {
+ struct sbp2_orb base;
+ struct {
+ struct sbp2_pointer password;
+ struct sbp2_pointer response;
+ u32 misc;
+ u32 length;
+ struct sbp2_pointer status_fifo;
+ } request;
+ __be32 response[4];
+ dma_addr_t response_bus;
+ struct completion done;
+ struct sbp2_status status;
+};
+
+#define LOGIN_RESPONSE_GET_LOGIN_ID(v) ((v).misc & 0xffff)
+#define LOGIN_RESPONSE_GET_LENGTH(v) (((v).misc >> 16) & 0xffff)
+
+struct sbp2_login_response {
+ u32 misc;
+ struct sbp2_pointer command_block_agent;
+ u32 reconnect_hold;
+};
+#define COMMAND_ORB_DATA_SIZE(v) ((v))
+#define COMMAND_ORB_PAGE_SIZE(v) ((v) << 16)
+#define COMMAND_ORB_PAGE_TABLE_PRESENT ((1) << 19)
+#define COMMAND_ORB_MAX_PAYLOAD(v) ((v) << 20)
+#define COMMAND_ORB_SPEED(v) ((v) << 24)
+#define COMMAND_ORB_DIRECTION(v) ((v) << 27)
+#define COMMAND_ORB_REQUEST_FORMAT(v) ((v) << 29)
+#define COMMAND_ORB_NOTIFY ((1) << 31)
+
+struct sbp2_command_orb {
+ struct sbp2_orb base;
+ struct {
+ struct sbp2_pointer next;
+ struct sbp2_pointer data_descriptor;
+ u32 misc;
+ u8 command_block[12];
+ } request;
+ struct scsi_cmnd *cmd;
+ scsi_done_fn_t done;
+ struct fw_unit *unit;
+
+ struct sbp2_pointer page_table[SG_ALL];
+ dma_addr_t page_table_bus;
+ dma_addr_t request_buffer_bus;
+};
+
+/*
+ * List of devices with known bugs.
+ *
+ * The firmware_revision field, masked with 0xffff00, is the best
+ * indicator for the type of bridge chip of a device. It yields a few
+ * false positives but this did not break correctly behaving devices
+ * so far. We use ~0 as a wildcard, since the 24 bit values we get
+ * from the config rom can never match that.
+ */
+static const struct {
+ u32 firmware_revision;
+ u32 model;
+ unsigned workarounds;
+} sbp2_workarounds_table[] = {
+ /* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
+ .firmware_revision = 0x002800,
+ .model = 0x001010,
+ .workarounds = SBP2_WORKAROUND_INQUIRY_36 |
+ SBP2_WORKAROUND_MODE_SENSE_8,
+ },
+ /* Initio bridges, actually only needed for some older ones */ {
+ .firmware_revision = 0x000200,
+ .model = ~0,
+ .workarounds = SBP2_WORKAROUND_INQUIRY_36,
+ },
+ /* Symbios bridge */ {
+ .firmware_revision = 0xa0b800,
+ .model = ~0,
+ .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS,
+ },
+
+ /*
+ * There are iPods (2nd gen, 3rd gen) with model_id == 0, but
+ * these iPods do not feature the read_capacity bug according
+ * to one report. Read_capacity behaviour as well as model_id
+ * could change due to Apple-supplied firmware updates though.
+ */
+
+ /* iPod 4th generation. */ {
+ .firmware_revision = 0x0a2700,
+ .model = 0x000021,
+ .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
+ },
+ /* iPod mini */ {
+ .firmware_revision = 0x0a2700,
+ .model = 0x000023,
+ .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
+ },
+ /* iPod Photo */ {
+ .firmware_revision = 0x0a2700,
+ .model = 0x00007e,
+ .workarounds = SBP2_WORKAROUND_FIX_CAPACITY,
+ }
+};
+
+static void
+sbp2_status_write(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, int speed,
+ unsigned long long offset,
+ void *payload, size_t length, void *callback_data)
+{
+ struct sbp2_device *sd = callback_data;
+ struct sbp2_orb *orb;
+ struct sbp2_status status;
+ size_t header_size;
+ unsigned long flags;
+
+ if (tcode != TCODE_WRITE_BLOCK_REQUEST ||
+ length == 0 || length > sizeof(status)) {
+ fw_send_response(card, request, RCODE_TYPE_ERROR);
+ return;
+ }
+
+ header_size = min(length, 2 * sizeof(u32));
+ fw_memcpy_from_be32(&status, payload, header_size);
+ if (length > header_size)
+ memcpy(status.data, payload + 8, length - header_size);
+ if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) {
+ fw_notify("non-orb related status write, not handled\n");
+ fw_send_response(card, request, RCODE_COMPLETE);
+ return;
+ }
+
+ /* Lookup the orb corresponding to this status write. */
+ spin_lock_irqsave(&card->lock, flags);
+ list_for_each_entry(orb, &sd->orb_list, link) {
+ if (STATUS_GET_ORB_HIGH(status) == 0 &&
+ STATUS_GET_ORB_LOW(status) == orb->request_bus &&
+ orb->rcode == RCODE_COMPLETE) {
+ list_del(&orb->link);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (&orb->link != &sd->orb_list)
+ orb->callback(orb, &status);
+ else
+ fw_error("status write for unknown orb\n");
+
+ fw_send_response(card, request, RCODE_COMPLETE);
+}
+
+static void
+complete_transaction(struct fw_card *card, int rcode,
+ void *payload, size_t length, void *data)
+{
+ struct sbp2_orb *orb = data;
+ unsigned long flags;
+
+ orb->rcode = rcode;
+ if (rcode != RCODE_COMPLETE) {
+ spin_lock_irqsave(&card->lock, flags);
+ list_del(&orb->link);
+ spin_unlock_irqrestore(&card->lock, flags);
+ orb->callback(orb, NULL);
+ }
+}
+
+static void
+sbp2_send_orb(struct sbp2_orb *orb, struct fw_unit *unit,
+ int node_id, int generation, u64 offset)
+{
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_device *sd = unit->device.driver_data;
+ unsigned long flags;
+
+ orb->pointer.high = 0;
+ orb->pointer.low = orb->request_bus;
+ fw_memcpy_to_be32(&orb->pointer, &orb->pointer, sizeof(orb->pointer));
+
+ spin_lock_irqsave(&device->card->lock, flags);
+ list_add_tail(&orb->link, &sd->orb_list);
+ spin_unlock_irqrestore(&device->card->lock, flags);
+
+ fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
+ node_id, generation,
+ device->node->max_speed, offset,
+ &orb->pointer, sizeof(orb->pointer),
+ complete_transaction, orb);
+}
+
+static int sbp2_cancel_orbs(struct fw_unit *unit)
+{
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_device *sd = unit->device.driver_data;
+ struct sbp2_orb *orb, *next;
+ struct list_head list;
+ unsigned long flags;
+ int retval = -ENOENT;
+
+ INIT_LIST_HEAD(&list);
+ spin_lock_irqsave(&device->card->lock, flags);
+ list_splice_init(&sd->orb_list, &list);
+ spin_unlock_irqrestore(&device->card->lock, flags);
+
+ list_for_each_entry_safe(orb, next, &list, link) {
+ retval = 0;
+ if (fw_cancel_transaction(device->card, &orb->t) == 0)
+ continue;
+
+ orb->rcode = RCODE_CANCELLED;
+ orb->callback(orb, NULL);
+ }
+
+ return retval;
+}
+
+static void
+complete_management_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+{
+ struct sbp2_management_orb *orb =
+ (struct sbp2_management_orb *)base_orb;
+
+ if (status)
+ memcpy(&orb->status, status, sizeof(*status));
+ complete(&orb->done);
+}
+
+static int
+sbp2_send_management_orb(struct fw_unit *unit, int node_id, int generation,
+ int function, int lun, void *response)
+{
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_device *sd = unit->device.driver_data;
+ struct sbp2_management_orb *orb;
+ int retval = -ENOMEM;
+
+ orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
+ if (orb == NULL)
+ return -ENOMEM;
+
+ /*
+ * The sbp2 device is going to send a block read request to
+ * read out the request from host memory, so map it for dma.
+ */
+ orb->base.request_bus =
+ dma_map_single(device->card->device, &orb->request,
+ sizeof(orb->request), DMA_TO_DEVICE);
+ if (dma_mapping_error(orb->base.request_bus))
+ goto out;
+
+ orb->response_bus =
+ dma_map_single(device->card->device, &orb->response,
+ sizeof(orb->response), DMA_FROM_DEVICE);
+ if (dma_mapping_error(orb->response_bus))
+ goto out;
+
+ orb->request.response.high = 0;
+ orb->request.response.low = orb->response_bus;
+
+ orb->request.misc =
+ MANAGEMENT_ORB_NOTIFY |
+ MANAGEMENT_ORB_FUNCTION(function) |
+ MANAGEMENT_ORB_LUN(lun);
+ orb->request.length =
+ MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response));
+
+ orb->request.status_fifo.high = sd->address_handler.offset >> 32;
+ orb->request.status_fifo.low = sd->address_handler.offset;
+
+ /*
+ * FIXME: Yeah, ok this isn't elegant, we hardwire exclusive
+ * login and 1 second reconnect time. The reconnect setting
+ * is probably fine, but the exclusive login should be an option.
+ */
+ if (function == SBP2_LOGIN_REQUEST) {
+ orb->request.misc |=
+ MANAGEMENT_ORB_EXCLUSIVE |
+ MANAGEMENT_ORB_RECONNECT(0);
+ }
+
+ fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
+
+ init_completion(&orb->done);
+ orb->base.callback = complete_management_orb;
+
+ sbp2_send_orb(&orb->base, unit,
+ node_id, generation, sd->management_agent_address);
+
+ wait_for_completion_timeout(&orb->done,
+ msecs_to_jiffies(SBP2_ORB_TIMEOUT));
+
+ retval = -EIO;
+ if (sbp2_cancel_orbs(unit) == 0) {
+ fw_error("orb reply timed out, rcode=0x%02x\n",
+ orb->base.rcode);
+ goto out;
+ }
+
+ if (orb->base.rcode != RCODE_COMPLETE) {
+ fw_error("management write failed, rcode 0x%02x\n",
+ orb->base.rcode);
+ goto out;
+ }
+
+ if (STATUS_GET_RESPONSE(orb->status) != 0 ||
+ STATUS_GET_SBP_STATUS(orb->status) != 0) {
+ fw_error("error status: %d:%d\n",
+ STATUS_GET_RESPONSE(orb->status),
+ STATUS_GET_SBP_STATUS(orb->status));
+ goto out;
+ }
+
+ retval = 0;
+ out:
+ dma_unmap_single(device->card->device, orb->base.request_bus,
+ sizeof(orb->request), DMA_TO_DEVICE);
+ dma_unmap_single(device->card->device, orb->response_bus,
+ sizeof(orb->response), DMA_FROM_DEVICE);
+
+ if (response)
+ fw_memcpy_from_be32(response,
+ orb->response, sizeof(orb->response));
+ kfree(orb);
+
+ return retval;
+}
+
+static void
+complete_agent_reset_write(struct fw_card *card, int rcode,
+ void *payload, size_t length, void *data)
+{
+ struct fw_transaction *t = data;
+
+ kfree(t);
+}
+
+static int sbp2_agent_reset(struct fw_unit *unit)
+{
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_device *sd = unit->device.driver_data;
+ struct fw_transaction *t;
+ static u32 zero;
+
+ t = kzalloc(sizeof(*t), GFP_ATOMIC);
+ if (t == NULL)
+ return -ENOMEM;
+
+ fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST,
+ sd->node_id, sd->generation, SCODE_400,
+ sd->command_block_agent_address + SBP2_AGENT_RESET,
+ &zero, sizeof(zero), complete_agent_reset_write, t);
+
+ return 0;
+}
+
+static void sbp2_reconnect(struct work_struct *work);
+static struct scsi_host_template scsi_driver_template;
+
+static void
+release_sbp2_device(struct kref *kref)
+{
+ struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);
+ struct Scsi_Host *host =
+ container_of((void *)sd, struct Scsi_Host, hostdata[0]);
+
+ sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
+ SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
+
+ scsi_remove_host(host);
+ fw_core_remove_address_handler(&sd->address_handler);
+ fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
+ put_device(&sd->unit->device);
+ scsi_host_put(host);
+}
+
+static void sbp2_login(struct work_struct *work)
+{
+ struct sbp2_device *sd =
+ container_of(work, struct sbp2_device, work.work);
+ struct Scsi_Host *host =
+ container_of((void *)sd, struct Scsi_Host, hostdata[0]);
+ struct fw_unit *unit = sd->unit;
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_login_response response;
+ int generation, node_id, local_node_id, lun, retval;
+
+ /* FIXME: Make this work for multi-lun devices. */
+ lun = 0;
+
+ generation = device->card->generation;
+ node_id = device->node->node_id;
+ local_node_id = device->card->local_node->node_id;
+
+ if (sbp2_send_management_orb(unit, node_id, generation,
+ SBP2_LOGIN_REQUEST, lun, &response) < 0) {
+ if (sd->retries++ < 5) {
+ schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5));
+ } else {
+ fw_error("failed to login to %s\n",
+ unit->device.bus_id);
+ kref_put(&sd->kref, release_sbp2_device);
+ }
+ return;
+ }
+
+ sd->generation = generation;
+ sd->node_id = node_id;
+ sd->address_high = local_node_id << 16;
+
+ /* Get command block agent offset and login id. */
+ sd->command_block_agent_address =
+ ((u64) (response.command_block_agent.high & 0xffff) << 32) |
+ response.command_block_agent.low;
+ sd->login_id = LOGIN_RESPONSE_GET_LOGIN_ID(response);
+
+ fw_notify("logged in to sbp2 unit %s (%d retries)\n",
+ unit->device.bus_id, sd->retries);
+ fw_notify(" - management_agent_address: 0x%012llx\n",
+ (unsigned long long) sd->management_agent_address);
+ fw_notify(" - command_block_agent_address: 0x%012llx\n",
+ (unsigned long long) sd->command_block_agent_address);
+ fw_notify(" - status write address: 0x%012llx\n",
+ (unsigned long long) sd->address_handler.offset);
+
+#if 0
+ /* FIXME: The linux1394 sbp2 does this last step. */
+ sbp2_set_busy_timeout(scsi_id);
+#endif
+
+ PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect);
+ sbp2_agent_reset(unit);
+
+ /* FIXME: Loop over luns here. */
+ lun = 0;
+ retval = scsi_add_device(host, 0, 0, lun);
+ if (retval < 0) {
+ sbp2_send_management_orb(unit, sd->node_id, sd->generation,
+ SBP2_LOGOUT_REQUEST, sd->login_id,
+ NULL);
+ /*
+ * Set this back to sbp2_login so we fall back and
+ * retry login on bus reset.
+ */
+ PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
+ }
+ kref_put(&sd->kref, release_sbp2_device);
+}
+
+static int sbp2_probe(struct device *dev)
+{
+ struct fw_unit *unit = fw_unit(dev);
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_device *sd;
+ struct fw_csr_iterator ci;
+ struct Scsi_Host *host;
+ int i, key, value, err;
+ u32 model, firmware_revision;
+
+ err = -ENOMEM;
+ host = scsi_host_alloc(&scsi_driver_template, sizeof(*sd));
+ if (host == NULL)
+ goto fail;
+
+ sd = (struct sbp2_device *) host->hostdata;
+ unit->device.driver_data = sd;
+ sd->unit = unit;
+ INIT_LIST_HEAD(&sd->orb_list);
+ kref_init(&sd->kref);
+
+ sd->address_handler.length = 0x100;
+ sd->address_handler.address_callback = sbp2_status_write;
+ sd->address_handler.callback_data = sd;
+
+ err = fw_core_add_address_handler(&sd->address_handler,
+ &fw_high_memory_region);
+ if (err < 0)
+ goto fail_host;
+
+ err = fw_device_enable_phys_dma(device);
+ if (err < 0)
+ goto fail_address_handler;
+
+ err = scsi_add_host(host, &unit->device);
+ if (err < 0)
+ goto fail_address_handler;
+
+ /*
+ * Scan unit directory to get management agent address,
+ * firmware revison and model. Initialize firmware_revision
+ * and model to values that wont match anything in our table.
+ */
+ firmware_revision = 0xff000000;
+ model = 0xff000000;
+ fw_csr_iterator_init(&ci, unit->directory);
+ while (fw_csr_iterator_next(&ci, &key, &value)) {
+ switch (key) {
+ case CSR_DEPENDENT_INFO | CSR_OFFSET:
+ sd->management_agent_address =
+ 0xfffff0000000ULL + 4 * value;
+ break;
+ case SBP2_FIRMWARE_REVISION:
+ firmware_revision = value;
+ break;
+ case CSR_MODEL:
+ model = value;
+ break;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
+ if (sbp2_workarounds_table[i].firmware_revision !=
+ (firmware_revision & 0xffffff00))
+ continue;
+ if (sbp2_workarounds_table[i].model != model &&
+ sbp2_workarounds_table[i].model != ~0)
+ continue;
+ sd->workarounds |= sbp2_workarounds_table[i].workarounds;
+ break;
+ }
+
+ if (sd->workarounds)
+ fw_notify("Workarounds for node %s: 0x%x "
+ "(firmware_revision 0x%06x, model_id 0x%06x)\n",
+ unit->device.bus_id,
+ sd->workarounds, firmware_revision, model);
+
+ get_device(&unit->device);
+
+ /*
+ * We schedule work to do the login so we can easily
+ * reschedule retries. Always get the ref before scheduling
+ * work.
+ */
+ INIT_DELAYED_WORK(&sd->work, sbp2_login);
+ if (schedule_delayed_work(&sd->work, 0))
+ kref_get(&sd->kref);
+
+ return 0;
+
+ fail_address_handler:
+ fw_core_remove_address_handler(&sd->address_handler);
+ fail_host:
+ scsi_host_put(host);
+ fail:
+ return err;
+}
+
+static int sbp2_remove(struct device *dev)
+{
+ struct fw_unit *unit = fw_unit(dev);
+ struct sbp2_device *sd = unit->device.driver_data;
+
+ kref_put(&sd->kref, release_sbp2_device);
+
+ return 0;
+}
+
+static void sbp2_reconnect(struct work_struct *work)
+{
+ struct sbp2_device *sd =
+ container_of(work, struct sbp2_device, work.work);
+ struct fw_unit *unit = sd->unit;
+ struct fw_device *device = fw_device(unit->device.parent);
+ int generation, node_id, local_node_id;
+
+ generation = device->card->generation;
+ node_id = device->node->node_id;
+ local_node_id = device->card->local_node->node_id;
+
+ if (sbp2_send_management_orb(unit, node_id, generation,
+ SBP2_RECONNECT_REQUEST,
+ sd->login_id, NULL) < 0) {
+ if (sd->retries++ >= 5) {
+ fw_error("failed to reconnect to %s\n",
+ unit->device.bus_id);
+ /* Fall back and try to log in again. */
+ sd->retries = 0;
+ PREPARE_DELAYED_WORK(&sd->work, sbp2_login);
+ }
+ schedule_delayed_work(&sd->work, DIV_ROUND_UP(HZ, 5));
+ return;
+ }
+
+ sd->generation = generation;
+ sd->node_id = node_id;
+ sd->address_high = local_node_id << 16;
+
+ fw_notify("reconnected to unit %s (%d retries)\n",
+ unit->device.bus_id, sd->retries);
+ sbp2_agent_reset(unit);
+ sbp2_cancel_orbs(unit);
+ kref_put(&sd->kref, release_sbp2_device);
+}
+
+static void sbp2_update(struct fw_unit *unit)
+{
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_device *sd = unit->device.driver_data;
+
+ sd->retries = 0;
+ fw_device_enable_phys_dma(device);
+ if (schedule_delayed_work(&sd->work, 0))
+ kref_get(&sd->kref);
+}
+
+#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
+#define SBP2_SW_VERSION_ENTRY 0x00010483
+
+static const struct fw_device_id sbp2_id_table[] = {
+ {
+ .match_flags = FW_MATCH_SPECIFIER_ID | FW_MATCH_VERSION,
+ .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY,
+ .version = SBP2_SW_VERSION_ENTRY,
+ },
+ { }
+};
+
+static struct fw_driver sbp2_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = sbp2_driver_name,
+ .bus = &fw_bus_type,
+ .probe = sbp2_probe,
+ .remove = sbp2_remove,
+ },
+ .update = sbp2_update,
+ .id_table = sbp2_id_table,
+};
+
+static unsigned int
+sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data)
+{
+ int sam_status;
+
+ sense_data[0] = 0x70;
+ sense_data[1] = 0x0;
+ sense_data[2] = sbp2_status[1];
+ sense_data[3] = sbp2_status[4];
+ sense_data[4] = sbp2_status[5];
+ sense_data[5] = sbp2_status[6];
+ sense_data[6] = sbp2_status[7];
+ sense_data[7] = 10;
+ sense_data[8] = sbp2_status[8];
+ sense_data[9] = sbp2_status[9];
+ sense_data[10] = sbp2_status[10];
+ sense_data[11] = sbp2_status[11];
+ sense_data[12] = sbp2_status[2];
+ sense_data[13] = sbp2_status[3];
+ sense_data[14] = sbp2_status[12];
+ sense_data[15] = sbp2_status[13];
+
+ sam_status = sbp2_status[0] & 0x3f;
+
+ switch (sam_status) {
+ case SAM_STAT_GOOD:
+ case SAM_STAT_CHECK_CONDITION:
+ case SAM_STAT_CONDITION_MET:
+ case SAM_STAT_BUSY:
+ case SAM_STAT_RESERVATION_CONFLICT:
+ case SAM_STAT_COMMAND_TERMINATED:
+ return DID_OK << 16 | sam_status;
+
+ default:
+ return DID_ERROR << 16;
+ }
+}
+
+static void
+complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
+{
+ struct sbp2_command_orb *orb = (struct sbp2_command_orb *)base_orb;
+ struct fw_unit *unit = orb->unit;
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct scatterlist *sg;
+ int result;
+
+ if (status != NULL) {
+ if (STATUS_GET_DEAD(*status))
+ sbp2_agent_reset(unit);
+
+ switch (STATUS_GET_RESPONSE(*status)) {
+ case SBP2_STATUS_REQUEST_COMPLETE:
+ result = DID_OK << 16;
+ break;
+ case SBP2_STATUS_TRANSPORT_FAILURE:
+ result = DID_BUS_BUSY << 16;
+ break;
+ case SBP2_STATUS_ILLEGAL_REQUEST:
+ case SBP2_STATUS_VENDOR_DEPENDENT:
+ default:
+ result = DID_ERROR << 16;
+ break;
+ }
+
+ if (result == DID_OK << 16 && STATUS_GET_LEN(*status) > 1)
+ result = sbp2_status_to_sense_data(STATUS_GET_DATA(*status),
+ orb->cmd->sense_buffer);
+ } else {
+ /*
+ * If the orb completes with status == NULL, something
+ * went wrong, typically a bus reset happened mid-orb
+ * or when sending the write (less likely).
+ */
+ result = DID_BUS_BUSY << 16;
+ }
+
+ dma_unmap_single(device->card->device, orb->base.request_bus,
+ sizeof(orb->request), DMA_TO_DEVICE);
+
+ if (orb->cmd->use_sg > 0) {
+ sg = (struct scatterlist *)orb->cmd->request_buffer;
+ dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+ orb->cmd->sc_data_direction);
+ }
+
+ if (orb->page_table_bus != 0)
+ dma_unmap_single(device->card->device, orb->page_table_bus,
+ sizeof(orb->page_table_bus), DMA_TO_DEVICE);
+
+ if (orb->request_buffer_bus != 0)
+ dma_unmap_single(device->card->device, orb->request_buffer_bus,
+ sizeof(orb->request_buffer_bus),
+ DMA_FROM_DEVICE);
+
+ orb->cmd->result = result;
+ orb->done(orb->cmd);
+ kfree(orb);
+}
+
+static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
+{
+ struct sbp2_device *sd =
+ (struct sbp2_device *)orb->cmd->device->host->hostdata;
+ struct fw_unit *unit = sd->unit;
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct scatterlist *sg;
+ int sg_len, l, i, j, count;
+ size_t size;
+ dma_addr_t sg_addr;
+
+ sg = (struct scatterlist *)orb->cmd->request_buffer;
+ count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg,
+ orb->cmd->sc_data_direction);
+ if (count == 0)
+ goto fail;
+
+ /*
+ * Handle the special case where there is only one element in
+ * the scatter list by converting it to an immediate block
+ * request. This is also a workaround for broken devices such
+ * as the second generation iPod which doesn't support page
+ * tables.
+ */
+ if (count == 1 && sg_dma_len(sg) < SBP2_MAX_SG_ELEMENT_LENGTH) {
+ orb->request.data_descriptor.high = sd->address_high;
+ orb->request.data_descriptor.low = sg_dma_address(sg);
+ orb->request.misc |=
+ COMMAND_ORB_DATA_SIZE(sg_dma_len(sg));
+ return 0;
+ }
+
+ /*
+ * Convert the scatterlist to an sbp2 page table. If any
+ * scatterlist entries are too big for sbp2, we split them as we
+ * go. Even if we ask the block I/O layer to not give us sg
+ * elements larger than 65535 bytes, some IOMMUs may merge sg elements
+ * during DMA mapping, and Linux currently doesn't prevent this.
+ */
+ for (i = 0, j = 0; i < count; i++) {
+ sg_len = sg_dma_len(sg + i);
+ sg_addr = sg_dma_address(sg + i);
+ while (sg_len) {
+ l = min(sg_len, SBP2_MAX_SG_ELEMENT_LENGTH);
+ orb->page_table[j].low = sg_addr;
+ orb->page_table[j].high = (l << 16);
+ sg_addr += l;
+ sg_len -= l;
+ j++;
+ }
+ }
+
+ size = sizeof(orb->page_table[0]) * j;
+
+ /*
+ * The data_descriptor pointer is the one case where we need
+ * to fill in the node ID part of the address. All other
+ * pointers assume that the data referenced reside on the
+ * initiator (i.e. us), but data_descriptor can refer to data
+ * on other nodes so we need to put our ID in descriptor.high.
+ */
+
+ orb->page_table_bus =
+ dma_map_single(device->card->device, orb->page_table,
+ size, DMA_TO_DEVICE);
+ if (dma_mapping_error(orb->page_table_bus))
+ goto fail_page_table;
+ orb->request.data_descriptor.high = sd->address_high;
+ orb->request.data_descriptor.low = orb->page_table_bus;
+ orb->request.misc |=
+ COMMAND_ORB_PAGE_TABLE_PRESENT |
+ COMMAND_ORB_DATA_SIZE(j);
+
+ fw_memcpy_to_be32(orb->page_table, orb->page_table, size);
+
+ return 0;
+
+ fail_page_table:
+ dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+ orb->cmd->sc_data_direction);
+ fail:
+ return -ENOMEM;
+}
+
+/* SCSI stack integration */
+
+static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
+{
+ struct sbp2_device *sd =
+ (struct sbp2_device *)cmd->device->host->hostdata;
+ struct fw_unit *unit = sd->unit;
+ struct fw_device *device = fw_device(unit->device.parent);
+ struct sbp2_command_orb *orb;
+
+ /*
+ * Bidirectional commands are not yet implemented, and unknown
+ * transfer direction not handled.
+ */
+ if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) {
+ fw_error("Cannot handle DMA_BIDIRECTIONAL - rejecting command");
+ cmd->result = DID_ERROR << 16;
+ done(cmd);
+ return 0;
+ }
+
+ orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
+ if (orb == NULL) {
+ fw_notify("failed to alloc orb\n");
+ goto fail_alloc;
+ }
+
+ /* Initialize rcode to something not RCODE_COMPLETE. */
+ orb->base.rcode = -1;
+ orb->base.request_bus =
+ dma_map_single(device->card->device, &orb->request,
+ sizeof(orb->request), DMA_TO_DEVICE);
+ if (dma_mapping_error(orb->base.request_bus))
+ goto fail_mapping;
+
+ orb->unit = unit;
+ orb->done = done;
+ orb->cmd = cmd;
+
+ orb->request.next.high = SBP2_ORB_NULL;
+ orb->request.next.low = 0x0;
+ /*
+ * At speed 100 we can do 512 bytes per packet, at speed 200,
+ * 1024 bytes per packet etc. The SBP-2 max_payload field
+ * specifies the max payload size as 2 ^ (max_payload + 2), so
+ * if we set this to max_speed + 7, we get the right value.
+ */
+ orb->request.misc =
+ COMMAND_ORB_MAX_PAYLOAD(device->node->max_speed + 7) |
+ COMMAND_ORB_SPEED(device->node->max_speed) |
+ COMMAND_ORB_NOTIFY;
+
+ if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ orb->request.misc |=
+ COMMAND_ORB_DIRECTION(SBP2_DIRECTION_FROM_MEDIA);
+ else if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ orb->request.misc |=
+ COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
+
+ if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
+ goto fail_map_payload;
+
+ fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
+
+ memset(orb->request.command_block,
+ 0, sizeof(orb->request.command_block));
+ memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+
+ orb->base.callback = complete_command_orb;
+
+ sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
+ sd->command_block_agent_address + SBP2_ORB_POINTER);
+
+ return 0;
+
+ fail_map_payload:
+ dma_unmap_single(device->card->device, orb->base.request_bus,
+ sizeof(orb->request), DMA_TO_DEVICE);
+ fail_mapping:
+ kfree(orb);
+ fail_alloc:
+ return SCSI_MLQUEUE_HOST_BUSY;
+}
+
+static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
+{
+ struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
+
+ sdev->allow_restart = 1;
+
+ if (sd->workarounds & SBP2_WORKAROUND_INQUIRY_36)
+ sdev->inquiry_len = 36;
+ return 0;
+}
+
+static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
+{
+ struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
+ struct fw_unit *unit = sd->unit;
+
+ sdev->use_10_for_rw = 1;
+
+ if (sdev->type == TYPE_ROM)
+ sdev->use_10_for_ms = 1;
+ if (sdev->type == TYPE_DISK &&
+ sd->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
+ sdev->skip_ms_page_8 = 1;
+ if (sd->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) {
+ fw_notify("setting fix_capacity for %s\n", unit->device.bus_id);
+ sdev->fix_capacity = 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Called by scsi stack when something has really gone wrong. Usually
+ * called when a command has timed-out for some reason.
+ */
+static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
+{
+ struct sbp2_device *sd =
+ (struct sbp2_device *)cmd->device->host->hostdata;
+ struct fw_unit *unit = sd->unit;
+
+ fw_notify("sbp2_scsi_abort\n");
+ sbp2_agent_reset(unit);
+ sbp2_cancel_orbs(unit);
+
+ return SUCCESS;
+}
+
+static struct scsi_host_template scsi_driver_template = {
+ .module = THIS_MODULE,
+ .name = "SBP-2 IEEE-1394",
+ .proc_name = (char *)sbp2_driver_name,
+ .queuecommand = sbp2_scsi_queuecommand,
+ .slave_alloc = sbp2_scsi_slave_alloc,
+ .slave_configure = sbp2_scsi_slave_configure,
+ .eh_abort_handler = sbp2_scsi_abort,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .use_clustering = ENABLE_CLUSTERING,
+ .cmd_per_lun = 1,
+ .can_queue = 1,
+};
+
+MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
+MODULE_DESCRIPTION("SCSI over IEEE1394");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);
+
+/* Provide a module alias so root-on-sbp2 initrds don't break. */
+#ifndef CONFIG_IEEE1394_SBP2_MODULE
+MODULE_ALIAS("sbp2");
+#endif
+
+static int __init sbp2_init(void)
+{
+ return driver_register(&sbp2_driver.driver);
+}
+
+static void __exit sbp2_cleanup(void)
+{
+ driver_unregister(&sbp2_driver.driver);
+}
+
+module_init(sbp2_init);
+module_exit(sbp2_cleanup);
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c
new file mode 100644
index 0000000..7aebb8a
--- /dev/null
+++ b/drivers/firewire/fw-topology.c
@@ -0,0 +1,537 @@
+/*
+ * Incremental bus scan, based on bus topology
+ *
+ * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include "fw-transaction.h"
+#include "fw-topology.h"
+
+#define SELF_ID_PHY_ID(q) (((q) >> 24) & 0x3f)
+#define SELF_ID_EXTENDED(q) (((q) >> 23) & 0x01)
+#define SELF_ID_LINK_ON(q) (((q) >> 22) & 0x01)
+#define SELF_ID_GAP_COUNT(q) (((q) >> 16) & 0x3f)
+#define SELF_ID_PHY_SPEED(q) (((q) >> 14) & 0x03)
+#define SELF_ID_CONTENDER(q) (((q) >> 11) & 0x01)
+#define SELF_ID_PHY_INITIATOR(q) (((q) >> 1) & 0x01)
+#define SELF_ID_MORE_PACKETS(q) (((q) >> 0) & 0x01)
+
+#define SELF_ID_EXT_SEQUENCE(q) (((q) >> 20) & 0x07)
+
+static u32 *count_ports(u32 *sid, int *total_port_count, int *child_port_count)
+{
+ u32 q;
+ int port_type, shift, seq;
+
+ *total_port_count = 0;
+ *child_port_count = 0;
+
+ shift = 6;
+ q = *sid;
+ seq = 0;
+
+ while (1) {
+ port_type = (q >> shift) & 0x03;
+ switch (port_type) {
+ case SELFID_PORT_CHILD:
+ (*child_port_count)++;
+ case SELFID_PORT_PARENT:
+ case SELFID_PORT_NCONN:
+ (*total_port_count)++;
+ case SELFID_PORT_NONE:
+ break;
+ }
+
+ shift -= 2;
+ if (shift == 0) {
+ if (!SELF_ID_MORE_PACKETS(q))
+ return sid + 1;
+
+ shift = 16;
+ sid++;
+ q = *sid;
+
+ /*
+ * Check that the extra packets actually are
+ * extended self ID packets and that the
+ * sequence numbers in the extended self ID
+ * packets increase as expected.
+ */
+
+ if (!SELF_ID_EXTENDED(q) ||
+ seq != SELF_ID_EXT_SEQUENCE(q))
+ return NULL;
+
+ seq++;
+ }
+ }
+}
+
+static int get_port_type(u32 *sid, int port_index)
+{
+ int index, shift;
+
+ index = (port_index + 5) / 8;
+ shift = 16 - ((port_index + 5) & 7) * 2;
+ return (sid[index] >> shift) & 0x03;
+}
+
+static struct fw_node *fw_node_create(u32 sid, int port_count, int color)
+{
+ struct fw_node *node;
+
+ node = kzalloc(sizeof(*node) + port_count * sizeof(node->ports[0]),
+ GFP_ATOMIC);
+ if (node == NULL)
+ return NULL;
+
+ node->color = color;
+ node->node_id = LOCAL_BUS | SELF_ID_PHY_ID(sid);
+ node->link_on = SELF_ID_LINK_ON(sid);
+ node->phy_speed = SELF_ID_PHY_SPEED(sid);
+ node->port_count = port_count;
+
+ atomic_set(&node->ref_count, 1);
+ INIT_LIST_HEAD(&node->link);
+
+ return node;
+}
+
+/*
+ * Compute the maximum hop count for this node and it's children. The
+ * maximum hop count is the maximum number of connections between any
+ * two nodes in the subtree rooted at this node. We need this for
+ * setting the gap count. As we build the tree bottom up in
+ * build_tree() below, this is fairly easy to do: for each node we
+ * maintain the max hop count and the max depth, ie the number of hops
+ * to the furthest leaf. Computing the max hop count breaks down into
+ * two cases: either the path goes through this node, in which case
+ * the hop count is the sum of the two biggest child depths plus 2.
+ * Or it could be the case that the max hop path is entirely
+ * containted in a child tree, in which case the max hop count is just
+ * the max hop count of this child.
+ */
+static void update_hop_count(struct fw_node *node)
+{
+ int depths[2] = { -1, -1 };
+ int max_child_hops = 0;
+ int i;
+
+ for (i = 0; i < node->port_count; i++) {
+ if (node->ports[i].node == NULL)
+ continue;
+
+ if (node->ports[i].node->max_hops > max_child_hops)
+ max_child_hops = node->ports[i].node->max_hops;
+
+ if (node->ports[i].node->max_depth > depths[0]) {
+ depths[1] = depths[0];
+ depths[0] = node->ports[i].node->max_depth;
+ } else if (node->ports[i].node->max_depth > depths[1])
+ depths[1] = node->ports[i].node->max_depth;
+ }
+
+ node->max_depth = depths[0] + 1;
+ node->max_hops = max(max_child_hops, depths[0] + depths[1] + 2);
+}
+
+
+/**
+ * build_tree - Build the tree representation of the topology
+ * @self_ids: array of self IDs to create the tree from
+ * @self_id_count: the length of the self_ids array
+ * @local_id: the node ID of the local node
+ *
+ * This function builds the tree representation of the topology given
+ * by the self IDs from the latest bus reset. During the construction
+ * of the tree, the function checks that the self IDs are valid and
+ * internally consistent. On succcess this funtions returns the
+ * fw_node corresponding to the local card otherwise NULL.
+ */
+static struct fw_node *build_tree(struct fw_card *card,
+ u32 *sid, int self_id_count)
+{
+ struct fw_node *node, *child, *local_node, *irm_node;
+ struct list_head stack, *h;
+ u32 *next_sid, *end, q;
+ int i, port_count, child_port_count, phy_id, parent_count, stack_depth;
+ int gap_count, topology_type;
+
+ local_node = NULL;
+ node = NULL;
+ INIT_LIST_HEAD(&stack);
+ stack_depth = 0;
+ end = sid + self_id_count;
+ phy_id = 0;
+ irm_node = NULL;
+ gap_count = SELF_ID_GAP_COUNT(*sid);
+ topology_type = 0;
+
+ while (sid < end) {
+ next_sid = count_ports(sid, &port_count, &child_port_count);
+
+ if (next_sid == NULL) {
+ fw_error("Inconsistent extended self IDs.\n");
+ return NULL;
+ }
+
+ q = *sid;
+ if (phy_id != SELF_ID_PHY_ID(q)) {
+ fw_error("PHY ID mismatch in self ID: %d != %d.\n",
+ phy_id, SELF_ID_PHY_ID(q));
+ return NULL;
+ }
+
+ if (child_port_count > stack_depth) {
+ fw_error("Topology stack underflow\n");
+ return NULL;
+ }
+
+ /*
+ * Seek back from the top of our stack to find the
+ * start of the child nodes for this node.
+ */
+ for (i = 0, h = &stack; i < child_port_count; i++)
+ h = h->prev;
+ child = fw_node(h);
+
+ node = fw_node_create(q, port_count, card->color);
+ if (node == NULL) {
+ fw_error("Out of memory while building topology.");
+ return NULL;
+ }
+
+ if (phy_id == (card->node_id & 0x3f))
+ local_node = node;
+
+ if (SELF_ID_CONTENDER(q))
+ irm_node = node;
+
+ if (node->phy_speed == SCODE_BETA)
+ topology_type |= FW_TOPOLOGY_B;
+ else
+ topology_type |= FW_TOPOLOGY_A;
+
+ parent_count = 0;
+
+ for (i = 0; i < port_count; i++) {
+ switch (get_port_type(sid, i)) {
+ case SELFID_PORT_PARENT:
+ /*
+ * Who's your daddy? We dont know the
+ * parent node at this time, so we
+ * temporarily abuse node->color for
+ * remembering the entry in the
+ * node->ports array where the parent
+ * node should be. Later, when we
+ * handle the parent node, we fix up
+ * the reference.
+ */
+ parent_count++;
+ node->color = i;
+ break;
+
+ case SELFID_PORT_CHILD:
+ node->ports[i].node = child;
+ /*
+ * Fix up parent reference for this
+ * child node.
+ */
+ child->ports[child->color].node = node;
+ child->color = card->color;
+ child = fw_node(child->link.next);
+ break;
+ }
+ }
+
+ /*
+ * Check that the node reports exactly one parent
+ * port, except for the root, which of course should
+ * have no parents.
+ */
+ if ((next_sid == end && parent_count != 0) ||
+ (next_sid < end && parent_count != 1)) {
+ fw_error("Parent port inconsistency for node %d: "
+ "parent_count=%d\n", phy_id, parent_count);
+ return NULL;
+ }
+
+ /* Pop the child nodes off the stack and push the new node. */
+ __list_del(h->prev, &stack);
+ list_add_tail(&node->link, &stack);
+ stack_depth += 1 - child_port_count;
+
+ /*
+ * If all PHYs does not report the same gap count
+ * setting, we fall back to 63 which will force a gap
+ * count reconfiguration and a reset.
+ */
+ if (SELF_ID_GAP_COUNT(q) != gap_count)
+ gap_count = 63;
+
+ update_hop_count(node);
+
+ sid = next_sid;
+ phy_id++;
+ }
+
+ card->root_node = node;
+ card->irm_node = irm_node;
+ card->gap_count = gap_count;
+ card->topology_type = topology_type;
+
+ return local_node;
+}
+
+typedef void (*fw_node_callback_t)(struct fw_card * card,
+ struct fw_node * node,
+ struct fw_node * parent);
+
+static void
+for_each_fw_node(struct fw_card *card, struct fw_node *root,
+ fw_node_callback_t callback)
+{
+ struct list_head list;
+ struct fw_node *node, *next, *child, *parent;
+ int i;
+
+ INIT_LIST_HEAD(&list);
+
+ fw_node_get(root);
+ list_add_tail(&root->link, &list);
+ parent = NULL;
+ list_for_each_entry(node, &list, link) {
+ node->color = card->color;
+
+ for (i = 0; i < node->port_count; i++) {
+ child = node->ports[i].node;
+ if (!child)
+ continue;
+ if (child->color == card->color)
+ parent = child;
+ else {
+ fw_node_get(child);
+ list_add_tail(&child->link, &list);
+ }
+ }
+
+ callback(card, node, parent);
+ }
+
+ list_for_each_entry_safe(node, next, &list, link)
+ fw_node_put(node);
+}
+
+static void
+report_lost_node(struct fw_card *card,
+ struct fw_node *node, struct fw_node *parent)
+{
+ fw_node_event(card, node, FW_NODE_DESTROYED);
+ fw_node_put(node);
+}
+
+static void
+report_found_node(struct fw_card *card,
+ struct fw_node *node, struct fw_node *parent)
+{
+ int b_path = (node->phy_speed == SCODE_BETA);
+
+ if (parent != NULL) {
+ /* min() macro doesn't work here with gcc 3.4 */
+ node->max_speed = parent->max_speed < node->phy_speed ?
+ parent->max_speed : node->phy_speed;
+ node->b_path = parent->b_path && b_path;
+ } else {
+ node->max_speed = node->phy_speed;
+ node->b_path = b_path;
+ }
+
+ fw_node_event(card, node, FW_NODE_CREATED);
+}
+
+void fw_destroy_nodes(struct fw_card *card)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ card->color++;
+ if (card->local_node != NULL)
+ for_each_fw_node(card, card->local_node, report_lost_node);
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+
+static void move_tree(struct fw_node *node0, struct fw_node *node1, int port)
+{
+ struct fw_node *tree;
+ int i;
+
+ tree = node1->ports[port].node;
+ node0->ports[port].node = tree;
+ for (i = 0; i < tree->port_count; i++) {
+ if (tree->ports[i].node == node1) {
+ tree->ports[i].node = node0;
+ break;
+ }
+ }
+}
+
+/**
+ * update_tree - compare the old topology tree for card with the new
+ * one specified by root. Queue the nodes and mark them as either
+ * found, lost or updated. Update the nodes in the card topology tree
+ * as we go.
+ */
+static void
+update_tree(struct fw_card *card, struct fw_node *root)
+{
+ struct list_head list0, list1;
+ struct fw_node *node0, *node1;
+ int i, event;
+
+ INIT_LIST_HEAD(&list0);
+ list_add_tail(&card->local_node->link, &list0);
+ INIT_LIST_HEAD(&list1);
+ list_add_tail(&root->link, &list1);
+
+ node0 = fw_node(list0.next);
+ node1 = fw_node(list1.next);
+
+ while (&node0->link != &list0) {
+
+ /* assert(node0->port_count == node1->port_count); */
+ if (node0->link_on && !node1->link_on)
+ event = FW_NODE_LINK_OFF;
+ else if (!node0->link_on && node1->link_on)
+ event = FW_NODE_LINK_ON;
+ else
+ event = FW_NODE_UPDATED;
+
+ node0->node_id = node1->node_id;
+ node0->color = card->color;
+ node0->link_on = node1->link_on;
+ node0->initiated_reset = node1->initiated_reset;
+ node0->max_hops = node1->max_hops;
+ node1->color = card->color;
+ fw_node_event(card, node0, event);
+
+ if (card->root_node == node1)
+ card->root_node = node0;
+ if (card->irm_node == node1)
+ card->irm_node = node0;
+
+ for (i = 0; i < node0->port_count; i++) {
+ if (node0->ports[i].node && node1->ports[i].node) {
+ /*
+ * This port didn't change, queue the
+ * connected node for further
+ * investigation.
+ */
+ if (node0->ports[i].node->color == card->color)
+ continue;
+ list_add_tail(&node0->ports[i].node->link,
+ &list0);
+ list_add_tail(&node1->ports[i].node->link,
+ &list1);
+ } else if (node0->ports[i].node) {
+ /*
+ * The nodes connected here were
+ * unplugged; unref the lost nodes and
+ * queue FW_NODE_LOST callbacks for
+ * them.
+ */
+
+ for_each_fw_node(card, node0->ports[i].node,
+ report_lost_node);
+ node0->ports[i].node = NULL;
+ } else if (node1->ports[i].node) {
+ /*
+ * One or more node were connected to
+ * this port. Move the new nodes into
+ * the tree and queue FW_NODE_CREATED
+ * callbacks for them.
+ */
+ move_tree(node0, node1, i);
+ for_each_fw_node(card, node0->ports[i].node,
+ report_found_node);
+ }
+ }
+
+ node0 = fw_node(node0->link.next);
+ node1 = fw_node(node1->link.next);
+ }
+}
+
+static void
+update_topology_map(struct fw_card *card, u32 *self_ids, int self_id_count)
+{
+ int node_count;
+
+ card->topology_map[1]++;
+ node_count = (card->root_node->node_id & 0x3f) + 1;
+ card->topology_map[2] = (node_count << 16) | self_id_count;
+ card->topology_map[0] = (self_id_count + 2) << 16;
+ memcpy(&card->topology_map[3], self_ids, self_id_count * 4);
+ fw_compute_block_crc(card->topology_map);
+}
+
+void
+fw_core_handle_bus_reset(struct fw_card *card,
+ int node_id, int generation,
+ int self_id_count, u32 * self_ids)
+{
+ struct fw_node *local_node;
+ unsigned long flags;
+
+ fw_flush_transactions(card);
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ /*
+ * If the new topology has a different self_id_count the topology
+ * changed, either nodes were added or removed. In that case we
+ * reset the IRM reset counter.
+ */
+ if (card->self_id_count != self_id_count)
+ card->bm_retries = 0;
+
+ card->node_id = node_id;
+ card->generation = generation;
+ card->reset_jiffies = jiffies;
+ schedule_delayed_work(&card->work, 0);
+
+ local_node = build_tree(card, self_ids, self_id_count);
+
+ update_topology_map(card, self_ids, self_id_count);
+
+ card->color++;
+
+ if (local_node == NULL) {
+ fw_error("topology build failed\n");
+ /* FIXME: We need to issue a bus reset in this case. */
+ } else if (card->local_node == NULL) {
+ card->local_node = local_node;
+ for_each_fw_node(card, local_node, report_found_node);
+ } else {
+ update_tree(card, local_node);
+ }
+
+ spin_unlock_irqrestore(&card->lock, flags);
+}
+EXPORT_SYMBOL(fw_core_handle_bus_reset);
diff --git a/drivers/firewire/fw-topology.h b/drivers/firewire/fw-topology.h
new file mode 100644
index 0000000..363b6cb
--- /dev/null
+++ b/drivers/firewire/fw-topology.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __fw_topology_h
+#define __fw_topology_h
+
+enum {
+ FW_TOPOLOGY_A = 0x01,
+ FW_TOPOLOGY_B = 0x02,
+ FW_TOPOLOGY_MIXED = 0x03,
+};
+
+enum {
+ FW_NODE_CREATED = 0x00,
+ FW_NODE_UPDATED = 0x01,
+ FW_NODE_DESTROYED = 0x02,
+ FW_NODE_LINK_ON = 0x03,
+ FW_NODE_LINK_OFF = 0x04,
+};
+
+struct fw_port {
+ struct fw_node *node;
+ unsigned speed : 3; /* S100, S200, ... S3200 */
+};
+
+struct fw_node {
+ u16 node_id;
+ u8 color;
+ u8 port_count;
+ unsigned link_on : 1;
+ unsigned initiated_reset : 1;
+ unsigned b_path : 1;
+ u8 phy_speed : 3; /* As in the self ID packet. */
+ u8 max_speed : 5; /* Minimum of all phy-speeds and port speeds on
+ * the path from the local node to this node. */
+ u8 max_depth : 4; /* Maximum depth to any leaf node */
+ u8 max_hops : 4; /* Max hops in this sub tree */
+ atomic_t ref_count;
+
+ /* For serializing node topology into a list. */
+ struct list_head link;
+
+ /* Upper layer specific data. */
+ void *data;
+
+ struct fw_port ports[0];
+};
+
+static inline struct fw_node *
+fw_node(struct list_head *l)
+{
+ return list_entry(l, struct fw_node, link);
+}
+
+static inline struct fw_node *
+fw_node_get(struct fw_node *node)
+{
+ atomic_inc(&node->ref_count);
+
+ return node;
+}
+
+static inline void
+fw_node_put(struct fw_node *node)
+{
+ if (atomic_dec_and_test(&node->ref_count))
+ kfree(node);
+}
+
+void
+fw_destroy_nodes(struct fw_card *card);
+
+int
+fw_compute_block_crc(u32 *block);
+
+
+#endif /* __fw_topology_h */
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
new file mode 100644
index 0000000..80d0121
--- /dev/null
+++ b/drivers/firewire/fw-transaction.c
@@ -0,0 +1,910 @@
+/*
+ * Core IEEE1394 transaction logic
+ *
+ * Copyright (C) 2004-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/poll.h>
+#include <linux/list.h>
+#include <linux/kthread.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+
+#include "fw-transaction.h"
+#include "fw-topology.h"
+#include "fw-device.h"
+
+#define HEADER_PRI(pri) ((pri) << 0)
+#define HEADER_TCODE(tcode) ((tcode) << 4)
+#define HEADER_RETRY(retry) ((retry) << 8)
+#define HEADER_TLABEL(tlabel) ((tlabel) << 10)
+#define HEADER_DESTINATION(destination) ((destination) << 16)
+#define HEADER_SOURCE(source) ((source) << 16)
+#define HEADER_RCODE(rcode) ((rcode) << 12)
+#define HEADER_OFFSET_HIGH(offset_high) ((offset_high) << 0)
+#define HEADER_DATA_LENGTH(length) ((length) << 16)
+#define HEADER_EXTENDED_TCODE(tcode) ((tcode) << 0)
+
+#define HEADER_GET_TCODE(q) (((q) >> 4) & 0x0f)
+#define HEADER_GET_TLABEL(q) (((q) >> 10) & 0x3f)
+#define HEADER_GET_RCODE(q) (((q) >> 12) & 0x0f)
+#define HEADER_GET_DESTINATION(q) (((q) >> 16) & 0xffff)
+#define HEADER_GET_SOURCE(q) (((q) >> 16) & 0xffff)
+#define HEADER_GET_OFFSET_HIGH(q) (((q) >> 0) & 0xffff)
+#define HEADER_GET_DATA_LENGTH(q) (((q) >> 16) & 0xffff)
+#define HEADER_GET_EXTENDED_TCODE(q) (((q) >> 0) & 0xffff)
+
+#define PHY_CONFIG_GAP_COUNT(gap_count) (((gap_count) << 16) | (1 << 22))
+#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
+#define PHY_IDENTIFIER(id) ((id) << 30)
+
+static int
+close_transaction(struct fw_transaction *transaction,
+ struct fw_card *card, int rcode,
+ u32 *payload, size_t length)
+{
+ struct fw_transaction *t;
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+ list_for_each_entry(t, &card->transaction_list, link) {
+ if (t == transaction) {
+ list_del(&t->link);
+ card->tlabel_mask &= ~(1 << t->tlabel);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (&t->link != &card->transaction_list) {
+ t->callback(card, rcode, payload, length, t->callback_data);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+/*
+ * Only valid for transactions that are potentially pending (ie have
+ * been sent).
+ */
+int
+fw_cancel_transaction(struct fw_card *card,
+ struct fw_transaction *transaction)
+{
+ /*
+ * Cancel the packet transmission if it's still queued. That
+ * will call the packet transmission callback which cancels
+ * the transaction.
+ */
+
+ if (card->driver->cancel_packet(card, &transaction->packet) == 0)
+ return 0;
+
+ /*
+ * If the request packet has already been sent, we need to see
+ * if the transaction is still pending and remove it in that case.
+ */
+
+ return close_transaction(transaction, card, RCODE_CANCELLED, NULL, 0);
+}
+EXPORT_SYMBOL(fw_cancel_transaction);
+
+static void
+transmit_complete_callback(struct fw_packet *packet,
+ struct fw_card *card, int status)
+{
+ struct fw_transaction *t =
+ container_of(packet, struct fw_transaction, packet);
+
+ switch (status) {
+ case ACK_COMPLETE:
+ close_transaction(t, card, RCODE_COMPLETE, NULL, 0);
+ break;
+ case ACK_PENDING:
+ t->timestamp = packet->timestamp;
+ break;
+ case ACK_BUSY_X:
+ case ACK_BUSY_A:
+ case ACK_BUSY_B:
+ close_transaction(t, card, RCODE_BUSY, NULL, 0);
+ break;
+ case ACK_DATA_ERROR:
+ close_transaction(t, card, RCODE_DATA_ERROR, NULL, 0);
+ break;
+ case ACK_TYPE_ERROR:
+ close_transaction(t, card, RCODE_TYPE_ERROR, NULL, 0);
+ break;
+ default:
+ /*
+ * In this case the ack is really a juju specific
+ * rcode, so just forward that to the callback.
+ */
+ close_transaction(t, card, status, NULL, 0);
+ break;
+ }
+}
+
+static void
+fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
+ int node_id, int source_id, int generation, int speed,
+ unsigned long long offset, void *payload, size_t length)
+{
+ int ext_tcode;
+
+ if (tcode > 0x10) {
+ ext_tcode = tcode - 0x10;
+ tcode = TCODE_LOCK_REQUEST;
+ } else
+ ext_tcode = 0;
+
+ packet->header[0] =
+ HEADER_RETRY(RETRY_X) |
+ HEADER_TLABEL(tlabel) |
+ HEADER_TCODE(tcode) |
+ HEADER_DESTINATION(node_id);
+ packet->header[1] =
+ HEADER_OFFSET_HIGH(offset >> 32) | HEADER_SOURCE(source_id);
+ packet->header[2] =
+ offset;
+
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ packet->header[3] = *(u32 *)payload;
+ packet->header_length = 16;
+ packet->payload_length = 0;
+ break;
+
+ case TCODE_LOCK_REQUEST:
+ case TCODE_WRITE_BLOCK_REQUEST:
+ packet->header[3] =
+ HEADER_DATA_LENGTH(length) |
+ HEADER_EXTENDED_TCODE(ext_tcode);
+ packet->header_length = 16;
+ packet->payload = payload;
+ packet->payload_length = length;
+ break;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ packet->header_length = 12;
+ packet->payload_length = 0;
+ break;
+
+ case TCODE_READ_BLOCK_REQUEST:
+ packet->header[3] =
+ HEADER_DATA_LENGTH(length) |
+ HEADER_EXTENDED_TCODE(ext_tcode);
+ packet->header_length = 16;
+ packet->payload_length = 0;
+ break;
+ }
+
+ packet->speed = speed;
+ packet->generation = generation;
+ packet->ack = 0;
+}
+
+/**
+ * This function provides low-level access to the IEEE1394 transaction
+ * logic. Most C programs would use either fw_read(), fw_write() or
+ * fw_lock() instead - those function are convenience wrappers for
+ * this function. The fw_send_request() function is primarily
+ * provided as a flexible, one-stop entry point for languages bindings
+ * and protocol bindings.
+ *
+ * FIXME: Document this function further, in particular the possible
+ * values for rcode in the callback. In short, we map ACK_COMPLETE to
+ * RCODE_COMPLETE, internal errors set errno and set rcode to
+ * RCODE_SEND_ERROR (which is out of range for standard ieee1394
+ * rcodes). All other rcodes are forwarded unchanged. For all
+ * errors, payload is NULL, length is 0.
+ *
+ * Can not expect the callback to be called before the function
+ * returns, though this does happen in some cases (ACK_COMPLETE and
+ * errors).
+ *
+ * The payload is only used for write requests and must not be freed
+ * until the callback has been called.
+ *
+ * @param card the card from which to send the request
+ * @param tcode the tcode for this transaction. Do not use
+ * TCODE_LOCK_REQUEST directly, insted use TCODE_LOCK_MASK_SWAP
+ * etc. to specify tcode and ext_tcode.
+ * @param node_id the destination node ID (bus ID and PHY ID concatenated)
+ * @param generation the generation for which node_id is valid
+ * @param speed the speed to use for sending the request
+ * @param offset the 48 bit offset on the destination node
+ * @param payload the data payload for the request subaction
+ * @param length the length in bytes of the data to read
+ * @param callback function to be called when the transaction is completed
+ * @param callback_data pointer to arbitrary data, which will be
+ * passed to the callback
+ */
+void
+fw_send_request(struct fw_card *card, struct fw_transaction *t,
+ int tcode, int node_id, int generation, int speed,
+ unsigned long long offset,
+ void *payload, size_t length,
+ fw_transaction_callback_t callback, void *callback_data)
+{
+ unsigned long flags;
+ int tlabel, source;
+
+ /*
+ * Bump the flush timer up 100ms first of all so we
+ * don't race with a flush timer callback.
+ */
+
+ mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10));
+
+ /*
+ * Allocate tlabel from the bitmap and put the transaction on
+ * the list while holding the card spinlock.
+ */
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ source = card->node_id;
+ tlabel = card->current_tlabel;
+ if (card->tlabel_mask & (1 << tlabel)) {
+ spin_unlock_irqrestore(&card->lock, flags);
+ callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
+ return;
+ }
+
+ card->current_tlabel = (card->current_tlabel + 1) & 0x1f;
+ card->tlabel_mask |= (1 << tlabel);
+
+ list_add_tail(&t->link, &card->transaction_list);
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ /* Initialize rest of transaction, fill out packet and send it. */
+ t->node_id = node_id;
+ t->tlabel = tlabel;
+ t->callback = callback;
+ t->callback_data = callback_data;
+
+ fw_fill_request(&t->packet, tcode, t->tlabel,
+ node_id, source, generation,
+ speed, offset, payload, length);
+ t->packet.callback = transmit_complete_callback;
+
+ card->driver->send_request(card, &t->packet);
+}
+EXPORT_SYMBOL(fw_send_request);
+
+static void
+transmit_phy_packet_callback(struct fw_packet *packet,
+ struct fw_card *card, int status)
+{
+ kfree(packet);
+}
+
+static void send_phy_packet(struct fw_card *card, u32 data, int generation)
+{
+ struct fw_packet *packet;
+
+ packet = kzalloc(sizeof(*packet), GFP_ATOMIC);
+ if (packet == NULL)
+ return;
+
+ packet->header[0] = data;
+ packet->header[1] = ~data;
+ packet->header_length = 8;
+ packet->payload_length = 0;
+ packet->speed = SCODE_100;
+ packet->generation = generation;
+ packet->callback = transmit_phy_packet_callback;
+
+ card->driver->send_request(card, packet);
+}
+
+void fw_send_phy_config(struct fw_card *card,
+ int node_id, int generation, int gap_count)
+{
+ u32 q;
+
+ q = PHY_IDENTIFIER(PHY_PACKET_CONFIG) |
+ PHY_CONFIG_ROOT_ID(node_id) |
+ PHY_CONFIG_GAP_COUNT(gap_count);
+
+ send_phy_packet(card, q, generation);
+}
+
+void fw_flush_transactions(struct fw_card *card)
+{
+ struct fw_transaction *t, *next;
+ struct list_head list;
+ unsigned long flags;
+
+ INIT_LIST_HEAD(&list);
+ spin_lock_irqsave(&card->lock, flags);
+ list_splice_init(&card->transaction_list, &list);
+ card->tlabel_mask = 0;
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ list_for_each_entry_safe(t, next, &list, link) {
+ card->driver->cancel_packet(card, &t->packet);
+
+ /*
+ * At this point cancel_packet will never call the
+ * transaction callback, since we just took all the
+ * transactions out of the list. So do it here.
+ */
+ t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
+ }
+}
+
+static struct fw_address_handler *
+lookup_overlapping_address_handler(struct list_head *list,
+ unsigned long long offset, size_t length)
+{
+ struct fw_address_handler *handler;
+
+ list_for_each_entry(handler, list, link) {
+ if (handler->offset < offset + length &&
+ offset < handler->offset + handler->length)
+ return handler;
+ }
+
+ return NULL;
+}
+
+static struct fw_address_handler *
+lookup_enclosing_address_handler(struct list_head *list,
+ unsigned long long offset, size_t length)
+{
+ struct fw_address_handler *handler;
+
+ list_for_each_entry(handler, list, link) {
+ if (handler->offset <= offset &&
+ offset + length <= handler->offset + handler->length)
+ return handler;
+ }
+
+ return NULL;
+}
+
+static DEFINE_SPINLOCK(address_handler_lock);
+static LIST_HEAD(address_handler_list);
+
+const struct fw_address_region fw_low_memory_region =
+ { .start = 0x000000000000ULL, .end = 0x000100000000ULL, };
+const struct fw_address_region fw_high_memory_region =
+ { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL, };
+const struct fw_address_region fw_private_region =
+ { .start = 0xffffe0000000ULL, .end = 0xfffff0000000ULL, };
+const struct fw_address_region fw_csr_region =
+ { .start = 0xfffff0000000ULL, .end = 0xfffff0000800ULL, };
+const struct fw_address_region fw_unit_space_region =
+ { .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
+EXPORT_SYMBOL(fw_low_memory_region);
+EXPORT_SYMBOL(fw_high_memory_region);
+EXPORT_SYMBOL(fw_private_region);
+EXPORT_SYMBOL(fw_csr_region);
+EXPORT_SYMBOL(fw_unit_space_region);
+
+/**
+ * Allocate a range of addresses in the node space of the OHCI
+ * controller. When a request is received that falls within the
+ * specified address range, the specified callback is invoked. The
+ * parameters passed to the callback give the details of the
+ * particular request
+ */
+int
+fw_core_add_address_handler(struct fw_address_handler *handler,
+ const struct fw_address_region *region)
+{
+ struct fw_address_handler *other;
+ unsigned long flags;
+ int ret = -EBUSY;
+
+ spin_lock_irqsave(&address_handler_lock, flags);
+
+ handler->offset = region->start;
+ while (handler->offset + handler->length <= region->end) {
+ other =
+ lookup_overlapping_address_handler(&address_handler_list,
+ handler->offset,
+ handler->length);
+ if (other != NULL) {
+ handler->offset += other->length;
+ } else {
+ list_add_tail(&handler->link, &address_handler_list);
+ ret = 0;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&address_handler_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(fw_core_add_address_handler);
+
+/**
+ * Deallocate a range of addresses allocated with fw_allocate. This
+ * will call the associated callback one last time with a the special
+ * tcode TCODE_DEALLOCATE, to let the client destroy the registered
+ * callback data. For convenience, the callback parameters offset and
+ * length are set to the start and the length respectively for the
+ * deallocated region, payload is set to NULL.
+ */
+void fw_core_remove_address_handler(struct fw_address_handler *handler)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&address_handler_lock, flags);
+ list_del(&handler->link);
+ spin_unlock_irqrestore(&address_handler_lock, flags);
+}
+EXPORT_SYMBOL(fw_core_remove_address_handler);
+
+struct fw_request {
+ struct fw_packet response;
+ u32 request_header[4];
+ int ack;
+ u32 length;
+ u32 data[0];
+};
+
+static void
+free_response_callback(struct fw_packet *packet,
+ struct fw_card *card, int status)
+{
+ struct fw_request *request;
+
+ request = container_of(packet, struct fw_request, response);
+ kfree(request);
+}
+
+void
+fw_fill_response(struct fw_packet *response, u32 *request_header,
+ int rcode, void *payload, size_t length)
+{
+ int tcode, tlabel, extended_tcode, source, destination;
+
+ tcode = HEADER_GET_TCODE(request_header[0]);
+ tlabel = HEADER_GET_TLABEL(request_header[0]);
+ source = HEADER_GET_DESTINATION(request_header[0]);
+ destination = HEADER_GET_SOURCE(request_header[1]);
+ extended_tcode = HEADER_GET_EXTENDED_TCODE(request_header[3]);
+
+ response->header[0] =
+ HEADER_RETRY(RETRY_1) |
+ HEADER_TLABEL(tlabel) |
+ HEADER_DESTINATION(destination);
+ response->header[1] =
+ HEADER_SOURCE(source) |
+ HEADER_RCODE(rcode);
+ response->header[2] = 0;
+
+ switch (tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ case TCODE_WRITE_BLOCK_REQUEST:
+ response->header[0] |= HEADER_TCODE(TCODE_WRITE_RESPONSE);
+ response->header_length = 12;
+ response->payload_length = 0;
+ break;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ response->header[0] |=
+ HEADER_TCODE(TCODE_READ_QUADLET_RESPONSE);
+ if (payload != NULL)
+ response->header[3] = *(u32 *)payload;
+ else
+ response->header[3] = 0;
+ response->header_length = 16;
+ response->payload_length = 0;
+ break;
+
+ case TCODE_READ_BLOCK_REQUEST:
+ case TCODE_LOCK_REQUEST:
+ response->header[0] |= HEADER_TCODE(tcode + 2);
+ response->header[3] =
+ HEADER_DATA_LENGTH(length) |
+ HEADER_EXTENDED_TCODE(extended_tcode);
+ response->header_length = 16;
+ response->payload = payload;
+ response->payload_length = length;
+ break;
+
+ default:
+ BUG();
+ return;
+ }
+}
+EXPORT_SYMBOL(fw_fill_response);
+
+static struct fw_request *
+allocate_request(struct fw_packet *p)
+{
+ struct fw_request *request;
+ u32 *data, length;
+ int request_tcode, t;
+
+ request_tcode = HEADER_GET_TCODE(p->header[0]);
+ switch (request_tcode) {
+ case TCODE_WRITE_QUADLET_REQUEST:
+ data = &p->header[3];
+ length = 4;
+ break;
+
+ case TCODE_WRITE_BLOCK_REQUEST:
+ case TCODE_LOCK_REQUEST:
+ data = p->payload;
+ length = HEADER_GET_DATA_LENGTH(p->header[3]);
+ break;
+
+ case TCODE_READ_QUADLET_REQUEST:
+ data = NULL;
+ length = 4;
+ break;
+
+ case TCODE_READ_BLOCK_REQUEST:
+ data = NULL;
+ length = HEADER_GET_DATA_LENGTH(p->header[3]);
+ break;
+
+ default:
+ BUG();
+ return NULL;
+ }
+
+ request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
+ if (request == NULL)
+ return NULL;
+
+ t = (p->timestamp & 0x1fff) + 4000;
+ if (t >= 8000)
+ t = (p->timestamp & ~0x1fff) + 0x2000 + t - 8000;
+ else
+ t = (p->timestamp & ~0x1fff) + t;
+
+ request->response.speed = p->speed;
+ request->response.timestamp = t;
+ request->response.generation = p->generation;
+ request->response.ack = 0;
+ request->response.callback = free_response_callback;
+ request->ack = p->ack;
+ request->length = length;
+ if (data)
+ memcpy(request->data, data, length);
+
+ memcpy(request->request_header, p->header, sizeof(p->header));
+
+ return request;
+}
+
+void
+fw_send_response(struct fw_card *card, struct fw_request *request, int rcode)
+{
+ /*
+ * Broadcast packets are reported as ACK_COMPLETE, so this
+ * check is sufficient to ensure we don't send response to
+ * broadcast packets or posted writes.
+ */
+ if (request->ack != ACK_PENDING)
+ return;
+
+ if (rcode == RCODE_COMPLETE)
+ fw_fill_response(&request->response, request->request_header,
+ rcode, request->data, request->length);
+ else
+ fw_fill_response(&request->response, request->request_header,
+ rcode, NULL, 0);
+
+ card->driver->send_response(card, &request->response);
+}
+EXPORT_SYMBOL(fw_send_response);
+
+void
+fw_core_handle_request(struct fw_card *card, struct fw_packet *p)
+{
+ struct fw_address_handler *handler;
+ struct fw_request *request;
+ unsigned long long offset;
+ unsigned long flags;
+ int tcode, destination, source;
+
+ if (p->payload_length > 2048) {
+ /* FIXME: send error response. */
+ return;
+ }
+
+ if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
+ return;
+
+ request = allocate_request(p);
+ if (request == NULL) {
+ /* FIXME: send statically allocated busy packet. */
+ return;
+ }
+
+ offset =
+ ((unsigned long long)
+ HEADER_GET_OFFSET_HIGH(p->header[1]) << 32) | p->header[2];
+ tcode = HEADER_GET_TCODE(p->header[0]);
+ destination = HEADER_GET_DESTINATION(p->header[0]);
+ source = HEADER_GET_SOURCE(p->header[0]);
+
+ spin_lock_irqsave(&address_handler_lock, flags);
+ handler = lookup_enclosing_address_handler(&address_handler_list,
+ offset, request->length);
+ spin_unlock_irqrestore(&address_handler_lock, flags);
+
+ /*
+ * FIXME: lookup the fw_node corresponding to the sender of
+ * this request and pass that to the address handler instead
+ * of the node ID. We may also want to move the address
+ * allocations to fw_node so we only do this callback if the
+ * upper layers registered it for this node.
+ */
+
+ if (handler == NULL)
+ fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ else
+ handler->address_callback(card, request,
+ tcode, destination, source,
+ p->generation, p->speed, offset,
+ request->data, request->length,
+ handler->callback_data);
+}
+EXPORT_SYMBOL(fw_core_handle_request);
+
+void
+fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
+{
+ struct fw_transaction *t;
+ unsigned long flags;
+ u32 *data;
+ size_t data_length;
+ int tcode, tlabel, destination, source, rcode;
+
+ tcode = HEADER_GET_TCODE(p->header[0]);
+ tlabel = HEADER_GET_TLABEL(p->header[0]);
+ destination = HEADER_GET_DESTINATION(p->header[0]);
+ source = HEADER_GET_SOURCE(p->header[1]);
+ rcode = HEADER_GET_RCODE(p->header[1]);
+
+ spin_lock_irqsave(&card->lock, flags);
+ list_for_each_entry(t, &card->transaction_list, link) {
+ if (t->node_id == source && t->tlabel == tlabel) {
+ list_del(&t->link);
+ card->tlabel_mask &= ~(1 << t->tlabel);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ if (&t->link == &card->transaction_list) {
+ fw_notify("Unsolicited response (source %x, tlabel %x)\n",
+ source, tlabel);
+ return;
+ }
+
+ /*
+ * FIXME: sanity check packet, is length correct, does tcodes
+ * and addresses match.
+ */
+
+ switch (tcode) {
+ case TCODE_READ_QUADLET_RESPONSE:
+ data = (u32 *) &p->header[3];
+ data_length = 4;
+ break;
+
+ case TCODE_WRITE_RESPONSE:
+ data = NULL;
+ data_length = 0;
+ break;
+
+ case TCODE_READ_BLOCK_RESPONSE:
+ case TCODE_LOCK_RESPONSE:
+ data = p->payload;
+ data_length = HEADER_GET_DATA_LENGTH(p->header[3]);
+ break;
+
+ default:
+ /* Should never happen, this is just to shut up gcc. */
+ data = NULL;
+ data_length = 0;
+ break;
+ }
+
+ t->callback(card, rcode, data, data_length, t->callback_data);
+}
+EXPORT_SYMBOL(fw_core_handle_response);
+
+const struct fw_address_region topology_map_region =
+ { .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, };
+
+static void
+handle_topology_map(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, int speed,
+ unsigned long long offset,
+ void *payload, size_t length, void *callback_data)
+{
+ int i, start, end;
+ u32 *map;
+
+ if (!TCODE_IS_READ_REQUEST(tcode)) {
+ fw_send_response(card, request, RCODE_TYPE_ERROR);
+ return;
+ }
+
+ if ((offset & 3) > 0 || (length & 3) > 0) {
+ fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ return;
+ }
+
+ start = (offset - topology_map_region.start) / 4;
+ end = start + length / 4;
+ map = payload;
+
+ for (i = 0; i < length / 4; i++)
+ map[i] = cpu_to_be32(card->topology_map[start + i]);
+
+ fw_send_response(card, request, RCODE_COMPLETE);
+}
+
+static struct fw_address_handler topology_map = {
+ .length = 0x200,
+ .address_callback = handle_topology_map,
+};
+
+const struct fw_address_region registers_region =
+ { .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, };
+
+static void
+handle_registers(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, int speed,
+ unsigned long long offset,
+ void *payload, size_t length, void *callback_data)
+{
+ int reg = offset - CSR_REGISTER_BASE;
+ unsigned long long bus_time;
+ __be32 *data = payload;
+
+ switch (reg) {
+ case CSR_CYCLE_TIME:
+ case CSR_BUS_TIME:
+ if (!TCODE_IS_READ_REQUEST(tcode) || length != 4) {
+ fw_send_response(card, request, RCODE_TYPE_ERROR);
+ break;
+ }
+
+ bus_time = card->driver->get_bus_time(card);
+ if (reg == CSR_CYCLE_TIME)
+ *data = cpu_to_be32(bus_time);
+ else
+ *data = cpu_to_be32(bus_time >> 25);
+ fw_send_response(card, request, RCODE_COMPLETE);
+ break;
+
+ case CSR_BUS_MANAGER_ID:
+ case CSR_BANDWIDTH_AVAILABLE:
+ case CSR_CHANNELS_AVAILABLE_HI:
+ case CSR_CHANNELS_AVAILABLE_LO:
+ /*
+ * FIXME: these are handled by the OHCI hardware and
+ * the stack never sees these request. If we add
+ * support for a new type of controller that doesn't
+ * handle this in hardware we need to deal with these
+ * transactions.
+ */
+ BUG();
+ break;
+
+ case CSR_BUSY_TIMEOUT:
+ /* FIXME: Implement this. */
+ default:
+ fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ break;
+ }
+}
+
+static struct fw_address_handler registers = {
+ .length = 0x400,
+ .address_callback = handle_registers,
+};
+
+MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
+MODULE_DESCRIPTION("Core IEEE1394 transaction logic");
+MODULE_LICENSE("GPL");
+
+static const u32 vendor_textual_descriptor[] = {
+ /* textual descriptor leaf () */
+ 0x00060000,
+ 0x00000000,
+ 0x00000000,
+ 0x4c696e75, /* L i n u */
+ 0x78204669, /* x F i */
+ 0x72657769, /* r e w i */
+ 0x72650000, /* r e */
+};
+
+static const u32 model_textual_descriptor[] = {
+ /* model descriptor leaf () */
+ 0x00030000,
+ 0x00000000,
+ 0x00000000,
+ 0x4a756a75, /* J u j u */
+};
+
+static struct fw_descriptor vendor_id_descriptor = {
+ .length = ARRAY_SIZE(vendor_textual_descriptor),
+ .immediate = 0x03d00d1e,
+ .key = 0x81000000,
+ .data = vendor_textual_descriptor,
+};
+
+static struct fw_descriptor model_id_descriptor = {
+ .length = ARRAY_SIZE(model_textual_descriptor),
+ .immediate = 0x17000001,
+ .key = 0x81000000,
+ .data = model_textual_descriptor,
+};
+
+static int __init fw_core_init(void)
+{
+ int retval;
+
+ retval = bus_register(&fw_bus_type);
+ if (retval < 0)
+ return retval;
+
+ fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
+ if (fw_cdev_major < 0) {
+ bus_unregister(&fw_bus_type);
+ return fw_cdev_major;
+ }
+
+ retval = fw_core_add_address_handler(&topology_map,
+ &topology_map_region);
+ BUG_ON(retval < 0);
+
+ retval = fw_core_add_address_handler(®isters,
+ ®isters_region);
+ BUG_ON(retval < 0);
+
+ /* Add the vendor textual descriptor. */
+ retval = fw_core_add_descriptor(&vendor_id_descriptor);
+ BUG_ON(retval < 0);
+ retval = fw_core_add_descriptor(&model_id_descriptor);
+ BUG_ON(retval < 0);
+
+ return 0;
+}
+
+static void __exit fw_core_cleanup(void)
+{
+ unregister_chrdev(fw_cdev_major, "firewire");
+ bus_unregister(&fw_bus_type);
+}
+
+module_init(fw_core_init);
+module_exit(fw_core_cleanup);
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
new file mode 100644
index 0000000..acdc3be
--- /dev/null
+++ b/drivers/firewire/fw-transaction.h
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2003-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __fw_transaction_h
+#define __fw_transaction_h
+
+#include <linux/device.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/dma-mapping.h>
+#include <linux/firewire-constants.h>
+
+#define TCODE_IS_READ_REQUEST(tcode) (((tcode) & ~1) == 4)
+#define TCODE_IS_BLOCK_PACKET(tcode) (((tcode) & 1) != 0)
+#define TCODE_IS_REQUEST(tcode) (((tcode) & 2) == 0)
+#define TCODE_IS_RESPONSE(tcode) (((tcode) & 2) != 0)
+#define TCODE_HAS_REQUEST_DATA(tcode) (((tcode) & 12) != 4)
+#define TCODE_HAS_RESPONSE_DATA(tcode) (((tcode) & 12) != 0)
+
+#define LOCAL_BUS 0xffc0
+
+#define SELFID_PORT_CHILD 0x3
+#define SELFID_PORT_PARENT 0x2
+#define SELFID_PORT_NCONN 0x1
+#define SELFID_PORT_NONE 0x0
+
+#define PHY_PACKET_CONFIG 0x0
+#define PHY_PACKET_LINK_ON 0x1
+#define PHY_PACKET_SELF_ID 0x2
+
+/* Bit fields _within_ the PHY registers. */
+#define PHY_LINK_ACTIVE 0x80
+#define PHY_CONTENDER 0x40
+#define PHY_BUS_RESET 0x40
+#define PHY_BUS_SHORT_RESET 0x40
+
+#define CSR_REGISTER_BASE 0xfffff0000000ULL
+
+/* register offsets relative to CSR_REGISTER_BASE */
+#define CSR_STATE_CLEAR 0x0
+#define CSR_STATE_SET 0x4
+#define CSR_NODE_IDS 0x8
+#define CSR_RESET_START 0xc
+#define CSR_SPLIT_TIMEOUT_HI 0x18
+#define CSR_SPLIT_TIMEOUT_LO 0x1c
+#define CSR_CYCLE_TIME 0x200
+#define CSR_BUS_TIME 0x204
+#define CSR_BUSY_TIMEOUT 0x210
+#define CSR_BUS_MANAGER_ID 0x21c
+#define CSR_BANDWIDTH_AVAILABLE 0x220
+#define CSR_CHANNELS_AVAILABLE 0x224
+#define CSR_CHANNELS_AVAILABLE_HI 0x224
+#define CSR_CHANNELS_AVAILABLE_LO 0x228
+#define CSR_BROADCAST_CHANNEL 0x234
+#define CSR_CONFIG_ROM 0x400
+#define CSR_CONFIG_ROM_END 0x800
+#define CSR_FCP_COMMAND 0xB00
+#define CSR_FCP_RESPONSE 0xD00
+#define CSR_FCP_END 0xF00
+#define CSR_TOPOLOGY_MAP 0x1000
+#define CSR_TOPOLOGY_MAP_END 0x1400
+#define CSR_SPEED_MAP 0x2000
+#define CSR_SPEED_MAP_END 0x3000
+
+#define fw_notify(s, args...) printk(KERN_NOTICE KBUILD_MODNAME ": " s, ## args)
+#define fw_error(s, args...) printk(KERN_ERR KBUILD_MODNAME ": " s, ## args)
+#define fw_debug(s, args...) printk(KERN_DEBUG KBUILD_MODNAME ": " s, ## args)
+
+static inline void
+fw_memcpy_from_be32(void *_dst, void *_src, size_t size)
+{
+ u32 *dst = _dst;
+ u32 *src = _src;
+ int i;
+
+ for (i = 0; i < size / 4; i++)
+ dst[i] = cpu_to_be32(src[i]);
+}
+
+static inline void
+fw_memcpy_to_be32(void *_dst, void *_src, size_t size)
+{
+ fw_memcpy_from_be32(_dst, _src, size);
+}
+
+struct fw_card;
+struct fw_packet;
+struct fw_node;
+struct fw_request;
+
+struct fw_descriptor {
+ struct list_head link;
+ size_t length;
+ u32 immediate;
+ u32 key;
+ const u32 *data;
+};
+
+int fw_core_add_descriptor(struct fw_descriptor *desc);
+void fw_core_remove_descriptor(struct fw_descriptor *desc);
+
+typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
+ struct fw_card *card, int status);
+
+typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
+ void *data,
+ size_t length,
+ void *callback_data);
+
+typedef void (*fw_address_callback_t)(struct fw_card *card,
+ struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, int speed,
+ unsigned long long offset,
+ void *data, size_t length,
+ void *callback_data);
+
+typedef void (*fw_bus_reset_callback_t)(struct fw_card *handle,
+ int node_id, int generation,
+ u32 *self_ids,
+ int self_id_count,
+ void *callback_data);
+
+struct fw_packet {
+ int speed;
+ int generation;
+ u32 header[4];
+ size_t header_length;
+ void *payload;
+ size_t payload_length;
+ u32 timestamp;
+
+ /*
+ * This callback is called when the packet transmission has
+ * completed; for successful transmission, the status code is
+ * the ack received from the destination, otherwise it's a
+ * negative errno: ENOMEM, ESTALE, ETIMEDOUT, ENODEV, EIO.
+ * The callback can be called from tasklet context and thus
+ * must never block.
+ */
+ fw_packet_callback_t callback;
+ int ack;
+ struct list_head link;
+ void *driver_data;
+};
+
+struct fw_transaction {
+ int node_id; /* The generation is implied; it is always the current. */
+ int tlabel;
+ int timestamp;
+ struct list_head link;
+
+ struct fw_packet packet;
+
+ /*
+ * The data passed to the callback is valid only during the
+ * callback.
+ */
+ fw_transaction_callback_t callback;
+ void *callback_data;
+};
+
+static inline struct fw_packet *
+fw_packet(struct list_head *l)
+{
+ return list_entry(l, struct fw_packet, link);
+}
+
+struct fw_address_handler {
+ u64 offset;
+ size_t length;
+ fw_address_callback_t address_callback;
+ void *callback_data;
+ struct list_head link;
+};
+
+
+struct fw_address_region {
+ u64 start;
+ u64 end;
+};
+
+extern const struct fw_address_region fw_low_memory_region;
+extern const struct fw_address_region fw_high_memory_region;
+extern const struct fw_address_region fw_private_region;
+extern const struct fw_address_region fw_csr_region;
+extern const struct fw_address_region fw_unit_space_region;
+
+int fw_core_add_address_handler(struct fw_address_handler *handler,
+ const struct fw_address_region *region);
+void fw_core_remove_address_handler(struct fw_address_handler *handler);
+void fw_fill_response(struct fw_packet *response, u32 *request_header,
+ int rcode, void *payload, size_t length);
+void fw_send_response(struct fw_card *card,
+ struct fw_request *request, int rcode);
+
+extern struct bus_type fw_bus_type;
+
+struct fw_card {
+ const struct fw_card_driver *driver;
+ struct device *device;
+ struct kref kref;
+
+ int node_id;
+ int generation;
+ /* This is the generation used for timestamping incoming requests. */
+ int request_generation;
+ int current_tlabel, tlabel_mask;
+ struct list_head transaction_list;
+ struct timer_list flush_timer;
+ unsigned long reset_jiffies;
+
+ unsigned long long guid;
+ int max_receive;
+ int link_speed;
+ int config_rom_generation;
+
+ /*
+ * We need to store up to 4 self ID for a maximum of 63
+ * devices plus 3 words for the topology map header.
+ */
+ int self_id_count;
+ u32 topology_map[252 + 3];
+
+ spinlock_t lock; /* Take this lock when handling the lists in
+ * this struct. */
+ struct fw_node *local_node;
+ struct fw_node *root_node;
+ struct fw_node *irm_node;
+ int color;
+ int gap_count;
+ int topology_type;
+
+ int index;
+
+ struct list_head link;
+
+ /* Work struct for BM duties. */
+ struct delayed_work work;
+ int bm_retries;
+ int bm_generation;
+};
+
+struct fw_card *fw_card_get(struct fw_card *card);
+void fw_card_put(struct fw_card *card);
+
+/*
+ * The iso packet format allows for an immediate header/payload part
+ * stored in 'header' immediately after the packet info plus an
+ * indirect payload part that is pointer to by the 'payload' field.
+ * Applications can use one or the other or both to implement simple
+ * low-bandwidth streaming (e.g. audio) or more advanced
+ * scatter-gather streaming (e.g. assembling video frame automatically).
+ */
+
+struct fw_iso_packet {
+ u16 payload_length; /* Length of indirect payload. */
+ u32 interrupt : 1; /* Generate interrupt on this packet */
+ u32 skip : 1; /* Set to not send packet at all. */
+ u32 tag : 2;
+ u32 sy : 4;
+ u32 header_length : 8; /* Length of immediate header. */
+ u32 header[0];
+};
+
+#define FW_ISO_CONTEXT_TRANSMIT 0
+#define FW_ISO_CONTEXT_RECEIVE 1
+
+#define FW_ISO_CONTEXT_MATCH_TAG0 1
+#define FW_ISO_CONTEXT_MATCH_TAG1 2
+#define FW_ISO_CONTEXT_MATCH_TAG2 4
+#define FW_ISO_CONTEXT_MATCH_TAG3 8
+#define FW_ISO_CONTEXT_MATCH_ALL_TAGS 15
+
+struct fw_iso_context;
+
+typedef void (*fw_iso_callback_t)(struct fw_iso_context *context,
+ u32 cycle,
+ size_t header_length,
+ void *header,
+ void *data);
+
+/*
+ * An iso buffer is just a set of pages mapped for DMA in the
+ * specified direction. Since the pages are to be used for DMA, they
+ * are not mapped into the kernel virtual address space. We store the
+ * DMA address in the page private. The helper function
+ * fw_iso_buffer_map() will map the pages into a given vma.
+ */
+
+struct fw_iso_buffer {
+ enum dma_data_direction direction;
+ struct page **pages;
+ int page_count;
+};
+
+struct fw_iso_context {
+ struct fw_card *card;
+ int type;
+ int channel;
+ int speed;
+ size_t header_size;
+ fw_iso_callback_t callback;
+ void *callback_data;
+};
+
+int
+fw_iso_buffer_init(struct fw_iso_buffer *buffer,
+ struct fw_card *card,
+ int page_count,
+ enum dma_data_direction direction);
+int
+fw_iso_buffer_map(struct fw_iso_buffer *buffer, struct vm_area_struct *vma);
+void
+fw_iso_buffer_destroy(struct fw_iso_buffer *buffer, struct fw_card *card);
+
+struct fw_iso_context *
+fw_iso_context_create(struct fw_card *card, int type,
+ int channel, int speed, size_t header_size,
+ fw_iso_callback_t callback, void *callback_data);
+
+void
+fw_iso_context_destroy(struct fw_iso_context *ctx);
+
+int
+fw_iso_context_queue(struct fw_iso_context *ctx,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload);
+
+int
+fw_iso_context_start(struct fw_iso_context *ctx,
+ int cycle, int sync, int tags);
+
+int
+fw_iso_context_stop(struct fw_iso_context *ctx);
+
+struct fw_card_driver {
+ const char *name;
+
+ /*
+ * Enable the given card with the given initial config rom.
+ * This function is expected to activate the card, and either
+ * enable the PHY or set the link_on bit and initiate a bus
+ * reset.
+ */
+ int (*enable)(struct fw_card *card, u32 *config_rom, size_t length);
+
+ int (*update_phy_reg)(struct fw_card *card, int address,
+ int clear_bits, int set_bits);
+
+ /*
+ * Update the config rom for an enabled card. This function
+ * should change the config rom that is presented on the bus
+ * an initiate a bus reset.
+ */
+ int (*set_config_rom)(struct fw_card *card,
+ u32 *config_rom, size_t length);
+
+ void (*send_request)(struct fw_card *card, struct fw_packet *packet);
+ void (*send_response)(struct fw_card *card, struct fw_packet *packet);
+ /* Calling cancel is valid once a packet has been submitted. */
+ int (*cancel_packet)(struct fw_card *card, struct fw_packet *packet);
+
+ /*
+ * Allow the specified node ID to do direct DMA out and in of
+ * host memory. The card will disable this for all node when
+ * a bus reset happens, so driver need to reenable this after
+ * bus reset. Returns 0 on success, -ENODEV if the card
+ * doesn't support this, -ESTALE if the generation doesn't
+ * match.
+ */
+ int (*enable_phys_dma)(struct fw_card *card,
+ int node_id, int generation);
+
+ u64 (*get_bus_time)(struct fw_card *card);
+
+ struct fw_iso_context *
+ (*allocate_iso_context)(struct fw_card *card,
+ int type, size_t header_size);
+ void (*free_iso_context)(struct fw_iso_context *ctx);
+
+ int (*start_iso)(struct fw_iso_context *ctx,
+ s32 cycle, u32 sync, u32 tags);
+
+ int (*queue_iso)(struct fw_iso_context *ctx,
+ struct fw_iso_packet *packet,
+ struct fw_iso_buffer *buffer,
+ unsigned long payload);
+
+ int (*stop_iso)(struct fw_iso_context *ctx);
+};
+
+int
+fw_core_initiate_bus_reset(struct fw_card *card, int short_reset);
+
+void
+fw_send_request(struct fw_card *card, struct fw_transaction *t,
+ int tcode, int node_id, int generation, int speed,
+ unsigned long long offset,
+ void *data, size_t length,
+ fw_transaction_callback_t callback, void *callback_data);
+
+int fw_cancel_transaction(struct fw_card *card,
+ struct fw_transaction *transaction);
+
+void fw_flush_transactions(struct fw_card *card);
+
+void fw_send_phy_config(struct fw_card *card,
+ int node_id, int generation, int gap_count);
+
+/*
+ * Called by the topology code to inform the device code of node
+ * activity; found, lost, or updated nodes.
+ */
+void
+fw_node_event(struct fw_card *card, struct fw_node *node, int event);
+
+/* API used by card level drivers */
+
+void
+fw_card_initialize(struct fw_card *card, const struct fw_card_driver *driver,
+ struct device *device);
+int
+fw_card_add(struct fw_card *card,
+ u32 max_receive, u32 link_speed, u64 guid);
+
+void
+fw_core_remove_card(struct fw_card *card);
+
+void
+fw_core_handle_bus_reset(struct fw_card *card,
+ int node_id, int generation,
+ int self_id_count, u32 *self_ids);
+void
+fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
+
+void
+fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
+
+#endif /* __fw_transaction_h */
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index a19b65e..7f81789 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -240,11 +240,94 @@
}
#endif
+static inline int match_scancode(int code, int scancode)
+{
+ if (scancode == 0)
+ return 1;
+ return ((code & (HID_USAGE_PAGE | HID_USAGE)) == scancode);
+}
+
+static inline int match_keycode(int code, int keycode)
+{
+ if (keycode == 0)
+ return 1;
+ return (code == keycode);
+}
+
+static struct hid_usage *hidinput_find_key(struct hid_device *hid,
+ int scancode, int keycode)
+{
+ int i, j, k;
+ struct hid_report *report;
+ struct hid_usage *usage;
+
+ for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+ list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
+ for (i = 0; i < report->maxfield; i++) {
+ for ( j = 0; j < report->field[i]->maxusage; j++) {
+ usage = report->field[i]->usage + j;
+ if (usage->type == EV_KEY &&
+ match_scancode(usage->hid, scancode) &&
+ match_keycode(usage->code, keycode))
+ return usage;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static int hidinput_getkeycode(struct input_dev *dev, int scancode,
+ int *keycode)
+{
+ struct hid_device *hid = dev->private;
+ struct hid_usage *usage;
+
+ usage = hidinput_find_key(hid, scancode, 0);
+ if (usage) {
+ *keycode = usage->code;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int hidinput_setkeycode(struct input_dev *dev, int scancode,
+ int keycode)
+{
+ struct hid_device *hid = dev->private;
+ struct hid_usage *usage;
+ int old_keycode;
+
+ if (keycode < 0 || keycode > KEY_MAX)
+ return -EINVAL;
+
+ usage = hidinput_find_key(hid, scancode, 0);
+ if (usage) {
+ old_keycode = usage->code;
+ usage->code = keycode;
+
+ clear_bit(old_keycode, dev->keybit);
+ set_bit(usage->code, dev->keybit);
+#ifdef CONFIG_HID_DEBUG
+ printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
+#endif
+ /* Set the keybit for the old keycode if the old keycode is used
+ * by another key */
+ if (hidinput_find_key (hid, 0, old_keycode))
+ set_bit(old_keycode, dev->keybit);
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
struct input_dev *input = hidinput->input;
- struct hid_device *device = input->private;
+ struct hid_device *device = input_get_drvdata(input);
int max = 0, code;
unsigned long *bit = NULL;
@@ -553,6 +636,7 @@
case 0x1015: map_key_clear(KEY_RECORD); break;
case 0x1016: map_key_clear(KEY_PLAYER); break;
case 0x1017: map_key_clear(KEY_EJECTCD); break;
+ case 0x1018: map_key_clear(KEY_MEDIA); break;
case 0x1019: map_key_clear(KEY_PROG1); break;
case 0x101a: map_key_clear(KEY_PROG2); break;
case 0x101b: map_key_clear(KEY_PROG3); break;
@@ -560,9 +644,12 @@
case 0x1020: map_key_clear(KEY_ZOOMOUT); break;
case 0x1021: map_key_clear(KEY_ZOOMRESET); break;
case 0x1023: map_key_clear(KEY_CLOSE); break;
+ case 0x1027: map_key_clear(KEY_MENU); break;
/* this one is marked as 'Rotate' */
case 0x1028: map_key_clear(KEY_ANGLE); break;
case 0x1029: map_key_clear(KEY_SHUFFLE); break;
+ case 0x102a: map_key_clear(KEY_BACK); break;
+ case 0x102b: map_key_clear(KEY_CYCLEWINDOWS); break;
case 0x1041: map_key_clear(KEY_BATTERY); break;
case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break;
case 0x1043: map_key_clear(KEY_SPREADSHEET); break;
@@ -855,13 +942,15 @@
static int hidinput_open(struct input_dev *dev)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
+
return hid->hid_open(hid);
}
static void hidinput_close(struct input_dev *dev)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
+
hid->hid_close(hid);
}
@@ -909,10 +998,12 @@
return -1;
}
- input_dev->private = hid;
+ input_set_drvdata(input_dev, hid);
input_dev->event = hid->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
+ input_dev->setkeycode = hidinput_setkeycode;
+ input_dev->getkeycode = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
@@ -921,7 +1012,7 @@
input_dev->id.vendor = hid->vendor;
input_dev->id.product = hid->product;
input_dev->id.version = hid->version;
- input_dev->cdev.dev = hid->dev;
+ input_dev->dev.parent = hid->dev;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
}
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 7c87bdc..1b4b572 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -25,12 +25,12 @@
depends on USB_HID && INPUT=n
config USB_HIDINPUT_POWERBOOK
- bool "Enable support for iBook/PowerBook special keys"
+ bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys"
default n
depends on USB_HID
help
Say Y here if you want support for the special keys (Fn, Numlock) on
- Apple iBooks and PowerBooks.
+ Apple iBooks, PowerBooks, MacBooks and MacBook Pros.
If unsure, say N.
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 91d6103..d91b9da 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -446,7 +446,7 @@
static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct hid_field *field;
int offset;
@@ -626,14 +626,10 @@
{
struct usbhid_device *usbhid = hid->driver_data;
- if (usbhid->inbuf)
- usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
- if (usbhid->outbuf)
- usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
- if (usbhid->cr)
- usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
- if (usbhid->ctrlbuf)
- usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
+ usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
+ usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}
/*
@@ -692,6 +688,30 @@
}
}
+/*
+ * Some USB barcode readers from cypress have usage min and usage max in
+ * the wrong order
+ */
+static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
+{
+ short fixed = 0;
+ int i;
+
+ for (i = 0; i < rsize - 4; i++) {
+ if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
+ unsigned char tmp;
+
+ rdesc[i] = 0x19; rdesc[i+2] = 0x29;
+ tmp = rdesc[i+3];
+ rdesc[i+3] = rdesc[i+1];
+ rdesc[i+1] = tmp;
+ }
+ }
+
+ if (fixed)
+ info("Fixing up Cypress report descriptor");
+}
+
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
@@ -758,6 +778,9 @@
if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
hid_fixup_logitech_descriptor(rdesc, rsize);
+ if (quirks & HID_QUIRK_SWAPPED_MIN_MAX)
+ hid_fixup_cypress_descriptor(rdesc, rsize);
+
#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++)
diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/usbhid/hid-lgff.c
index 92d2553..c5cd410 100644
--- a/drivers/hid/usbhid/hid-lgff.c
+++ b/drivers/hid/usbhid/hid-lgff.c
@@ -60,7 +60,7 @@
static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
int x, y;
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/usbhid/hid-plff.c
index 76d2e6e..d6a8f2b 100644
--- a/drivers/hid/usbhid/hid-plff.c
+++ b/drivers/hid/usbhid/hid-plff.c
@@ -37,7 +37,7 @@
static int hid_plff_play(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct plff_device *plff = data;
int left, right;
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 17a8755..f6c4145 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -92,6 +92,8 @@
#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
+#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
+#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
#define USB_VENDOR_ID_DELL 0x413c
#define USB_DEVICE_ID_DELL_W7658 0x2005
@@ -193,6 +195,7 @@
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
+#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
@@ -422,6 +425,7 @@
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -445,6 +449,9 @@
{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
+ { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX },
+ { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX },
+
{ 0, 0 }
};
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/usbhid/hid-tmff.c
index ab67331..ab5ba6e 100644
--- a/drivers/hid/usbhid/hid-tmff.c
+++ b/drivers/hid/usbhid/hid-tmff.c
@@ -59,7 +59,7 @@
static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct tmff_device *tmff = data;
int left, right; /* Rumbling */
diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/usbhid/hid-zpff.c
index 7bd8238..a7fbffc 100644
--- a/drivers/hid/usbhid/hid-zpff.c
+++ b/drivers/hid/usbhid/hid-zpff.c
@@ -37,7 +37,7 @@
static int hid_zpff_play(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct zpff_device *zpff = data;
int left, right;
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index a8b3d66..488d61b 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -51,6 +51,7 @@
wait_queue_head_t wait;
struct hid_device *hid;
struct list_head list;
+ spinlock_t list_lock;
};
struct hiddev_list {
@@ -161,7 +162,9 @@
{
struct hiddev *hiddev = hid->hiddev;
struct hiddev_list *list;
+ unsigned long flags;
+ spin_lock_irqsave(&hiddev->list_lock, flags);
list_for_each_entry(list, &hiddev->list, node) {
if (uref->field_index != HID_FIELD_INDEX_NONE ||
(list->flags & HIDDEV_FLAG_REPORT) != 0) {
@@ -171,6 +174,7 @@
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
}
+ spin_unlock_irqrestore(&hiddev->list_lock, flags);
wake_up_interruptible(&hiddev->wait);
}
@@ -235,9 +239,13 @@
static int hiddev_release(struct inode * inode, struct file * file)
{
struct hiddev_list *list = file->private_data;
+ unsigned long flags;
hiddev_fasync(-1, file, 0);
+
+ spin_lock_irqsave(&list->hiddev->list_lock, flags);
list_del(&list->node);
+ spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
if (!--list->hiddev->open) {
if (list->hiddev->exist)
@@ -257,6 +265,7 @@
static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list;
+ unsigned long flags;
int i = iminor(inode) - HIDDEV_MINOR_BASE;
@@ -267,7 +276,11 @@
return -ENOMEM;
list->hiddev = hiddev_table[i];
+
+ spin_lock_irqsave(&list->hiddev->list_lock, flags);
list_add_tail(&list->node, &hiddev_table[i]->list);
+ spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
+
file->private_data = list;
if (!list->hiddev->open++)
@@ -773,6 +786,7 @@
init_waitqueue_head(&hiddev->wait);
INIT_LIST_HEAD(&hiddev->list);
+ spin_lock_init(&hiddev->list_lock);
hiddev->hid = hid;
hiddev->exist = 1;
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index 65aa12e8..1309787 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -133,12 +133,11 @@
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
- struct usb_kbd *kbd = dev->private;
+ struct usb_kbd *kbd = input_get_drvdata(dev);
if (type != EV_LED)
return -1;
-
kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
@@ -175,7 +174,7 @@
static int usb_kbd_open(struct input_dev *dev)
{
- struct usb_kbd *kbd = dev->private;
+ struct usb_kbd *kbd = input_get_drvdata(dev);
kbd->irq->dev = kbd->usbdev;
if (usb_submit_urb(kbd->irq, GFP_KERNEL))
@@ -186,7 +185,7 @@
static void usb_kbd_close(struct input_dev *dev)
{
- struct usb_kbd *kbd = dev->private;
+ struct usb_kbd *kbd = input_get_drvdata(dev);
usb_kill_urb(kbd->irq);
}
@@ -211,12 +210,9 @@
{
usb_free_urb(kbd->irq);
usb_free_urb(kbd->led);
- if (kbd->new)
- usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
- if (kbd->cr)
- usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
- if (kbd->leds)
- usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
+ usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
+ usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
+ usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
}
static int usb_kbd_probe(struct usb_interface *iface,
@@ -274,8 +270,9 @@
input_dev->name = kbd->name;
input_dev->phys = kbd->phys;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &iface->dev;
- input_dev->private = kbd;
+ input_dev->dev.parent = &iface->dev;
+
+ input_set_drvdata(input_dev, kbd);
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 573776d..5345c73 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -96,7 +96,7 @@
static int usb_mouse_open(struct input_dev *dev)
{
- struct usb_mouse *mouse = dev->private;
+ struct usb_mouse *mouse = input_get_drvdata(dev);
mouse->irq->dev = mouse->usbdev;
if (usb_submit_urb(mouse->irq, GFP_KERNEL))
@@ -107,7 +107,7 @@
static void usb_mouse_close(struct input_dev *dev)
{
- struct usb_mouse *mouse = dev->private;
+ struct usb_mouse *mouse = input_get_drvdata(dev);
usb_kill_urb(mouse->irq);
}
@@ -171,7 +171,7 @@
input_dev->name = mouse->name;
input_dev->phys = mouse->phys;
usb_to_input_id(dev, &input_dev->id);
- input_dev->cdev.dev = &intf->dev;
+ input_dev->dev.parent = &intf->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
@@ -179,7 +179,8 @@
input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
input_dev->relbit[0] |= BIT(REL_WHEEL);
- input_dev->private = mouse;
+ input_set_drvdata(input_dev, mouse);
+
input_dev->open = usb_mouse_open;
input_dev->close = usb_mouse_close;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 3ba3a52..4d1cb5b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -4,6 +4,7 @@
menuconfig HWMON
tristate "Hardware Monitoring support"
+ depends on HAS_IOMEM
default y
help
Hardware monitoring devices let you monitor the hardware health
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c
index 1821016..ca7095d 100644
--- a/drivers/hwmon/ams/ams-input.c
+++ b/drivers/hwmon/ams/ams-input.c
@@ -87,7 +87,7 @@
ams_info.idev->id.vendor = 0;
ams_info.idev->open = ams_input_open;
ams_info.idev->close = ams_input_close;
- ams_info.idev->cdev.dev = &ams_info.of_dev->dev;
+ ams_info.idev->dev.parent = &ams_info.of_dev->dev;
input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0);
input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0);
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index b51c104..0c160675 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -1100,7 +1100,7 @@
/* initialize the input class */
applesmc_idev->name = "applesmc";
applesmc_idev->id.bustype = BUS_HOST;
- applesmc_idev->cdev.dev = &pdev->dev;
+ applesmc_idev->dev.parent = &pdev->dev;
applesmc_idev->evbit[0] = BIT(EV_ABS);
applesmc_idev->open = applesmc_idev_open;
applesmc_idev->close = applesmc_idev_close;
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index f82fa2d..e0cf5e6 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -574,7 +574,7 @@
/* initialize the input class */
hdaps_idev->name = "hdaps";
- hdaps_idev->cdev.dev = &pdev->dev;
+ hdaps_idev->dev.parent = &pdev->dev;
hdaps_idev->evbit[0] = BIT(EV_ABS);
input_set_abs_params(hdaps_idev, ABS_X,
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 434a61b..9686734 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -4,6 +4,7 @@
menuconfig I2C
tristate "I2C support"
+ depends on HAS_IOMEM
---help---
I2C (pronounce: I-square-C) is a slow serial bus protocol used in
many micro controller applications and developed by Philips. SMBus,
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index f35156c..9c8b6d5 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
+#include <linux/err.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/delay.h>
@@ -226,13 +227,14 @@
adapter->algo = &at91_algorithm;
adapter->class = I2C_CLASS_HWMON;
adapter->dev.parent = &pdev->dev;
+ /* adapter->id == 0 ... only one TWI controller for now */
platform_set_drvdata(pdev, adapter);
clk_enable(twi_clk); /* enable peripheral clock */
at91_twi_hwinit(); /* initialize TWI controller */
- rc = i2c_add_adapter(adapter);
+ rc = i2c_add_numbered_adapter(adapter);
if (rc) {
dev_err(&pdev->dev, "Adapter %s registration failed\n",
adapter->name);
@@ -295,6 +297,9 @@
#define at91_i2c_resume NULL
#endif
+/* work with "modprobe at91_i2c" from hotplugging or coldplugging */
+MODULE_ALIAS("at91_i2c");
+
static struct platform_driver at91_i2c_driver = {
.probe = at91_i2c_probe,
.remove = __devexit_p(at91_i2c_remove),
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 873544a..8a0a99b 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -548,7 +548,7 @@
*/
icr = readl(_ICR(i2c));
icr &= ~(ICR_STOP | ICR_ACKNAK);
- writel(icr, _IRC(i2c));
+ writel(icr, _ICR(i2c));
}
/*
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 1d06b41..9040809 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -7,6 +7,7 @@
if BLOCK
menu "ATA/ATAPI/MFM/RLL support"
+ depends on HAS_IOMEM
config IDE
tristate "ATA/ATAPI/MFM/RLL support"
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 61d7809..8012b3b 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -1,4 +1,7 @@
menu "IEEE 1394 (FireWire) support"
+ depends on PCI || BROKEN
+
+source "drivers/firewire/Kconfig"
config IEEE1394
tristate "IEEE 1394 (FireWire) support"
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 37deaae..994decc 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -1,4 +1,5 @@
menu "InfiniBand support"
+ depends on HAS_IOMEM
config INFINIBAND
depends on PCI || BROKEN
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 0e9b695..f814fb3 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -3,6 +3,7 @@
#
menu "Input device support"
+ depends on !S390
config INPUT
tristate "Generic input layer (needed for keyboard, mouse, ...)" if EMBEDDED
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 55a7259..b234729 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -336,7 +336,7 @@
if (compat) {
len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t);
- if (len < maxlen)
+ if (len > maxlen)
len = maxlen;
for (i = 0; i < len / sizeof(compat_long_t); i++)
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 3d4b619..e759944 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -51,7 +51,7 @@
static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
+ unsigned int pin = (unsigned int) input_get_drvdata(dev);
unsigned int count = 0;
if (type != EV_SND)
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index c90afee..d42fe89cd 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -3,6 +3,7 @@
#
menu "ISDN subsystem"
+ depends on !S390
config ISDN
tristate "ISDN support"
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 703cc88..e8e37d8 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -2,6 +2,7 @@
# KVM configuration
#
menu "Virtualization"
+ depends on X86
config KVM
tristate "Kernel-based Virtual Machine (KVM) support"
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 80acd08..87d2046 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1,5 +1,6 @@
menu "LED devices"
+ depends on HAS_IOMEM
config NEW_LEDS
bool "LED Support"
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 65814b0..c10ce91 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -5103,7 +5103,7 @@
*
* Note: the following is an unsigned comparison.
*/
- if ((curr_events - rdev->last_events + 4096) > 8192) {
+ if ((long)curr_events - (long)rdev->last_events > 4096) {
rdev->last_events = curr_events;
idle = 0;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 97ee870..3a95cc5 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -271,21 +271,25 @@
*/
update_head_pos(mirror, r1_bio);
- if (uptodate || (conf->raid_disks - conf->mddev->degraded) <= 1) {
- /*
- * Set R1BIO_Uptodate in our master bio, so that
- * we will return a good error code for to the higher
- * levels even if IO on some other mirrored buffer fails.
- *
- * The 'master' represents the composite IO operation to
- * user-side. So if something waits for IO, then it will
- * wait for the 'master' bio.
+ if (uptodate)
+ set_bit(R1BIO_Uptodate, &r1_bio->state);
+ else {
+ /* If all other devices have failed, we want to return
+ * the error upwards rather than fail the last device.
+ * Here we redefine "uptodate" to mean "Don't want to retry"
*/
- if (uptodate)
- set_bit(R1BIO_Uptodate, &r1_bio->state);
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
+ if (r1_bio->mddev->degraded == conf->raid_disks ||
+ (r1_bio->mddev->degraded == conf->raid_disks-1 &&
+ !test_bit(Faulty, &conf->mirrors[mirror].rdev->flags)))
+ uptodate = 1;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ }
+ if (uptodate)
raid_end_bio_io(r1_bio);
- } else {
+ else {
/*
* oops, read error:
*/
@@ -992,13 +996,14 @@
unsigned long flags;
spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded++;
+ set_bit(Faulty, &rdev->flags);
spin_unlock_irqrestore(&conf->device_lock, flags);
/*
* if recovery is running, make sure it aborts.
*/
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
- }
- set_bit(Faulty, &rdev->flags);
+ } else
+ set_bit(Faulty, &rdev->flags);
set_bit(MD_CHANGE_DEVS, &mddev->flags);
printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
" Operation continuing on %d devices\n",
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 91d25798..3a80e0c 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -3,6 +3,7 @@
#
menu "Multimedia devices"
+ depends on HAS_IOMEM
config VIDEO_DEV
tristate "Video For Linux"
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index 71037f9..c88cc75 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -1,5 +1,6 @@
menu "Fusion MPT device support"
+ depends on PCI
config FUSION
bool
diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig
index 6443392..f4ac21e 100644
--- a/drivers/message/i2o/Kconfig
+++ b/drivers/message/i2o/Kconfig
@@ -1,5 +1,6 @@
menu "I2O device support"
+ depends on PCI
config I2O
tristate "I2O support"
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ab6e985..a20a51e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -3,6 +3,7 @@
#
menu "Multifunction device drivers"
+ depends on HAS_IOMEM
config MFD_SM501
tristate "Support for Silicon Motion SM501"
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 877e790..2f2fbff 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -130,7 +130,7 @@
Read <file:Documentation/sony-laptop.txt> for more information.
-config SONY_LAPTOP_OLD
+config SONYPI_COMPAT
bool "Sonypi compatibility"
depends on SONY_LAPTOP
---help---
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 65c32a9..4f9060a 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -30,7 +30,7 @@
* Eric Burghard - LED display support for W1N
* Josh Green - Light Sens support
* Thomas Tuttle - His first patch for led support was very helpfull
- *
+ * Sam Lin - GPS support
*/
#include <linux/autoconf.h>
@@ -48,7 +48,7 @@
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
-#define ASUS_LAPTOP_VERSION "0.41"
+#define ASUS_LAPTOP_VERSION "0.42"
#define ASUS_HOTK_NAME "Asus Laptop Support"
#define ASUS_HOTK_CLASS "hotkey"
@@ -83,6 +83,7 @@
#define PLED_ON 0x20 //Phone LED
#define GLED_ON 0x40 //Gaming LED
#define LCD_ON 0x80 //LCD backlight
+#define GPS_ON 0x100 //GPS
#define ASUS_LOG ASUS_HOTK_FILE ": "
#define ASUS_ERR KERN_ERR ASUS_LOG
@@ -148,7 +149,7 @@
ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G
M6A M6V VX-1 V6J V6V W3Z */
"\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
- S5A M5A z33A W1Jc W2V */
+ S5A M5A z33A W1Jc W2V G1 */
"\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
"\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
"\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */
@@ -162,6 +163,12 @@
ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */
ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */
+/* GPS */
+/* R2H use different handle for GPS on/off */
+ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */
+ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */
+ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");
+
/*
* This is the main structure, we can use it to store anything interesting
* about the hotk device
@@ -278,12 +285,28 @@
return (hotk->status & mask) ? 1 : 0;
}
+static int read_gps_status(void)
+{
+ ulong status;
+ acpi_status rv = AE_OK;
+
+ rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);
+ if (ACPI_FAILURE(rv))
+ printk(ASUS_WARNING "Error reading GPS status\n");
+ else
+ return status ? 1 : 0;
+
+ return (hotk->status & GPS_ON) ? 1 : 0;
+}
+
/* Generic LED functions */
static int read_status(int mask)
{
/* There is a special method for both wireless devices */
if (mask == BT_ON || mask == WL_ON)
return read_wireless_status(mask);
+ else if (mask == GPS_ON)
+ return read_gps_status();
return (hotk->status & mask) ? 1 : 0;
}
@@ -299,6 +322,10 @@
case GLED_ON:
out = (out & 0x1) + 1;
break;
+ case GPS_ON:
+ handle = (out) ? gps_on_handle : gps_off_handle;
+ out = 0x02;
+ break;
default:
out &= 0x1;
break;
@@ -667,6 +694,21 @@
return rv;
}
+/*
+ * GPS
+ */
+static ssize_t show_gps(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", read_status(GPS_ON));
+}
+
+static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return store_status(buf, count, NULL, GPS_ON);
+}
+
static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
{
/* TODO Find a better way to handle events count. */
@@ -715,6 +757,7 @@
static ASUS_CREATE_DEVICE_ATTR(ledd);
static ASUS_CREATE_DEVICE_ATTR(ls_switch);
static ASUS_CREATE_DEVICE_ATTR(ls_level);
+static ASUS_CREATE_DEVICE_ATTR(gps);
static struct attribute *asuspf_attributes[] = {
&dev_attr_infos.attr,
@@ -724,6 +767,7 @@
&dev_attr_ledd.attr,
&dev_attr_ls_switch.attr,
&dev_attr_ls_level.attr,
+ &dev_attr_gps.attr,
NULL
};
@@ -763,6 +807,9 @@
ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
}
+
+ if (gps_status_handle && gps_on_handle && gps_off_handle)
+ ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps);
}
static int asus_handle_init(char *name, acpi_handle * handle,
@@ -890,9 +937,13 @@
/* There is a lot of models with "ALSL", but a few get
a real light sens, so we need to check it. */
- if (ASUS_HANDLE_INIT(ls_switch))
+ if (!ASUS_HANDLE_INIT(ls_switch))
ASUS_HANDLE_INIT(ls_level);
+ ASUS_HANDLE_INIT(gps_on);
+ ASUS_HANDLE_INIT(gps_off);
+ ASUS_HANDLE_INIT(gps_status);
+
kfree(model);
return AE_OK;
@@ -950,7 +1001,7 @@
* We install the handler, it will receive the hotk in parameter, so, we
* could add other data to the hotk struct
*/
- status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
asus_hotk_notify, hotk);
if (ACPI_FAILURE(status))
printk(ASUS_ERR "Error installing notify handler\n");
@@ -981,6 +1032,9 @@
if (ls_level_handle)
set_light_sens_level(hotk->light_level);
+ /* GPS is on by default */
+ write_status(NULL, 1, GPS_ON);
+
end:
if (result) {
kfree(hotk->name);
@@ -997,7 +1051,7 @@
if (!device || !acpi_driver_data(device))
return -EINVAL;
- status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY,
asus_hotk_notify);
if (ACPI_FAILURE(status))
printk(ASUS_ERR "Error removing notify handler\n");
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 68c4b58..41e901f 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -85,7 +85,7 @@
buf[0] = 0x80;
buf[1] = (u8) (level*31);
- return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0);
+ return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0, 1);
}
static int get_lcd_level(void)
@@ -93,7 +93,7 @@
u8 wdata = 0, rdata;
int result;
- result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
if (result < 0)
return result;
@@ -105,7 +105,7 @@
u8 wdata = 4, rdata;
int result;
- result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1, 1);
if (result < 0)
return result;
@@ -119,14 +119,14 @@
wdata[0] = 4;
- result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1);
+ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 1, 1);
if (result < 0)
return result;
wdata[0] = 0x84;
wdata[1] = (rdata & 0xF7) | (enable ? 8 : 0);
- return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0);
+ return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
}
static int get_wireless_state(int *wlan, int *bluetooth)
@@ -134,7 +134,7 @@
u8 wdata = 0, rdata;
int result;
- result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1);
+ result = ec_transaction(MSI_EC_COMMAND_WIRELESS, &wdata, 1, &rdata, 1, 1);
if (result < 0)
return -1;
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index c15c1f6..8ee0321 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -63,7 +63,7 @@
#include <asm/uaccess.h>
#include <linux/sonypi.h>
#include <linux/sony-laptop.h>
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
#include <linux/poll.h>
#include <linux/miscdevice.h>
#endif
@@ -114,7 +114,7 @@
"set this to 1 to enable Motion Eye camera controls "
"(only use it if you have a C1VE or C1VN model)");
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
static int minor = -1;
module_param(minor, int, 0);
MODULE_PARM_DESC(minor,
@@ -1504,7 +1504,7 @@
};
/******** SONYPI compatibility **********/
-#ifdef CONFIG_SONY_LAPTOP_OLD
+#ifdef CONFIG_SONYPI_COMPAT
/* battery / brightness / temperature addresses */
#define SONYPI_BAT_FLAGS 0x81
@@ -1798,7 +1798,7 @@
static int sonypi_compat_init(void) { return 0; }
static void sonypi_compat_exit(void) { }
static void sonypi_compat_report_event(u8 event) { }
-#endif /* CONFIG_SONY_LAPTOP_OLD */
+#endif /* CONFIG_SONYPI_COMPAT */
/*
* ACPI callbacks
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 45b7d53..c0b41e8 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -4,6 +4,7 @@
menuconfig MMC
tristate "MMC/SD card support"
+ depends on HAS_IOMEM
help
MMC is the "multi-media card" bus protocol.
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index c1b47db..fbec8cd 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -2,6 +2,7 @@
menuconfig MTD
tristate "Memory Technology Device (MTD) support"
+ depends on HAS_IOMEM
help
Memory Technology Devices are flash, RAM and similar chips, often
used for solid state file systems on embedded devices. This option
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index d0f2898..7540966 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -167,7 +167,7 @@
fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) *
sizeof(cbd_t), 8);
- if (IS_DPERR(fep->ring_mem_addr))
+ if (IS_ERR_VALUE(fep->ring_mem_addr))
return -ENOMEM;
fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr);
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 7c8ccc0..829da9a 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -141,6 +141,20 @@
To activate support for ACTiSYS IR-200L dongle you will have to
start irattach like this: "irattach -d act200l".
+config KINGSUN_DONGLE
+ tristate "KingSun/DonShine DS-620 IrDA-USB dongle"
+ depends on IRDA && USB && EXPERIMENTAL
+ help
+ Say Y or M here if you want to build support for the KingSun/DonShine
+ DS-620 IrDA-USB bridge device driver.
+
+ This USB bridge does not conform to the IrDA-USB device class
+ specification, and therefore needs its own specific driver. This
+ dongle supports SIR speed only (9600 bps).
+
+ To compile it as a module, choose M here: the module will be called
+ kingsun-sir.
+
comment "Old SIR device drivers"
config IRPORT_SIR
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 5be09f1..233a2f9 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -45,6 +45,7 @@
obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o
obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o
obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o
+obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o
# The SIR helper module
sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
new file mode 100644
index 0000000..2174291
--- /dev/null
+++ b/drivers/net/irda/kingsun-sir.c
@@ -0,0 +1,657 @@
+/*****************************************************************************
+*
+* Filename: kingsun-sir.c
+* Version: 0.1.1
+* Description: Irda KingSun/DonShine USB Dongle
+* Status: Experimental
+* Author: Alex Villac�s Lasso <a_villacis@palosanto.com>
+*
+* Based on stir4200 and mcs7780 drivers, with (strange?) differences
+*
+* 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.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*
+*****************************************************************************/
+
+/*
+ * This is my current (2007-04-25) understanding of how this dongle is supposed
+ * to work. This is based on reverse-engineering and examination of the packet
+ * data sent and received by the WinXP driver using USBSnoopy. Feel free to
+ * update here as more of this dongle is known:
+ *
+ * General: Unlike the other USB IrDA dongles, this particular dongle exposes,
+ * not two bulk (in and out) endpoints, but two *interrupt* ones. This dongle,
+ * like the bulk based ones (stir4200.c and mcs7780.c), requires polling in
+ * order to receive data.
+ * Transmission: Just like stir4200, this dongle uses a raw stream of data,
+ * which needs to be wrapped and escaped in a similar way as in stir4200.c.
+ * Reception: Poll-based, as in stir4200. Each read returns the contents of a
+ * 8-byte buffer, of which the first byte (LSB) indicates the number of bytes
+ * (1-7) of valid data contained within the remaining 7 bytes. For example, if
+ * the buffer had the following contents:
+ * 06 ff ff ff c0 01 04 aa
+ * This means that (06) there are 6 bytes of valid data. The byte 0xaa at the
+ * end is garbage (left over from a previous reception) and is discarded.
+ * If a read returns an "impossible" value as the length of valid data (such as
+ * 0x36) in the first byte, then the buffer is uninitialized (as is the case of
+ * first plug-in) and its contents should be discarded. There is currently no
+ * evidence that the top 5 bits of the 1st byte of the buffer can have values
+ * other than 0 once reception begins.
+ * Once valid bytes are collected, the assembled stream is a sequence of
+ * wrapped IrDA frames that is unwrapped and unescaped as in stir4200.c.
+ * BIG FAT WARNING: the dongle does *not* reset the RX buffer in any way after
+ * a successful read from the host, which means that in absence of further
+ * reception, repeated reads from the dongle will return the exact same
+ * contents repeatedly. Attempts to be smart and cache a previous read seem
+ * to result in corrupted packets, so this driver depends on the unwrap logic
+ * to sort out any repeated reads.
+ * Speed change: no commands observed so far to change speed, assumed fixed
+ * 9600bps (SIR).
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+/*
+ * According to lsusb, 0x07c0 is assigned to
+ * "Code Mercenaries Hard- und Software GmbH"
+ */
+#define KING_VENDOR_ID 0x07c0
+#define KING_PRODUCT_ID 0x4200
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+ /* KingSun Co,Ltd IrDA/USB Bridge */
+ { USB_DEVICE(KING_VENDOR_ID, KING_PRODUCT_ID) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+
+#define KINGSUN_FIFO_SIZE 4096
+#define KINGSUN_EP_IN 0
+#define KINGSUN_EP_OUT 1
+
+struct kingsun_cb {
+ struct usb_device *usbdev; /* init: probe_irda */
+ struct net_device *netdev; /* network layer */
+ struct irlap_cb *irlap; /* The link layer we are binded to */
+ struct net_device_stats stats; /* network statistics */
+ struct qos_info qos;
+
+ __u8 *in_buf; /* receive buffer */
+ __u8 *out_buf; /* transmit buffer */
+ __u8 max_rx; /* max. atomic read from dongle
+ (usually 8), also size of in_buf */
+ __u8 max_tx; /* max. atomic write to dongle
+ (usually 8) */
+
+ iobuff_t rx_buff; /* receive unwrap state machine */
+ struct timeval rx_time;
+ spinlock_t lock;
+ int receiving;
+
+ __u8 ep_in;
+ __u8 ep_out;
+
+ struct urb *tx_urb;
+ struct urb *rx_urb;
+};
+
+/* Callback transmission routine */
+static void kingsun_send_irq(struct urb *urb)
+{
+ struct kingsun_cb *kingsun = urb->context;
+ struct net_device *netdev = kingsun->netdev;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ err("kingsun_send_irq: Network not running!");
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("kingsun_send_irq: urb asynchronously failed - %d",
+ urb->status);
+ }
+ netif_wake_queue(netdev);
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct kingsun_cb *kingsun;
+ int wraplen;
+ int ret = 0;
+
+ if (skb == NULL || netdev == NULL)
+ return -EINVAL;
+
+ netif_stop_queue(netdev);
+
+ /* the IRDA wrapping routines don't deal with non linear skb */
+ SKB_LINEAR_ASSERT(skb);
+
+ kingsun = netdev_priv(netdev);
+
+ spin_lock(&kingsun->lock);
+
+ /* Append data to the end of whatever data remains to be transmitted */
+ wraplen = async_wrap_skb(skb,
+ kingsun->out_buf,
+ KINGSUN_FIFO_SIZE);
+
+ /* Calculate how much data can be transmitted in this urb */
+ usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
+ usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
+ kingsun->out_buf, wraplen, kingsun_send_irq,
+ kingsun, 1);
+
+ if ((ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC))) {
+ err("kingsun_hard_xmit: failed tx_urb submit: %d", ret);
+ switch (ret) {
+ case -ENODEV:
+ case -EPIPE:
+ break;
+ default:
+ kingsun->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
+ } else {
+ kingsun->stats.tx_packets++;
+ kingsun->stats.tx_bytes += skb->len;
+ }
+
+ dev_kfree_skb(skb);
+ spin_unlock(&kingsun->lock);
+
+ return ret;
+}
+
+/* Receive callback function */
+static void kingsun_rcv_irq(struct urb *urb)
+{
+ struct kingsun_cb *kingsun = urb->context;
+ int ret;
+
+ /* in process of stopping, just drop data */
+ if (!netif_running(kingsun->netdev)) {
+ kingsun->receiving = 0;
+ return;
+ }
+
+ /* unlink, shutdown, unplug, other nasties */
+ if (urb->status != 0) {
+ err("kingsun_rcv_irq: urb asynchronously failed - %d",
+ urb->status);
+ kingsun->receiving = 0;
+ return;
+ }
+
+ if (urb->actual_length == kingsun->max_rx) {
+ __u8 *bytes = urb->transfer_buffer;
+ int i;
+
+ /* The very first byte in the buffer indicates the length of
+ valid data in the read. This byte must be in the range
+ 1..kingsun->max_rx -1 . Values outside this range indicate
+ an uninitialized Rx buffer when the dongle has just been
+ plugged in. */
+ if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) {
+ for (i = 1; i <= bytes[0]; i++) {
+ async_unwrap_char(kingsun->netdev,
+ &kingsun->stats,
+ &kingsun->rx_buff, bytes[i]);
+ }
+ kingsun->netdev->last_rx = jiffies;
+ do_gettimeofday(&kingsun->rx_time);
+ kingsun->receiving =
+ (kingsun->rx_buff.state != OUTSIDE_FRAME)
+ ? 1 : 0;
+ }
+ } else if (urb->actual_length > 0) {
+ err("%s(): Unexpected response length, expected %d got %d",
+ __FUNCTION__, kingsun->max_rx, urb->actual_length);
+ }
+ /* This urb has already been filled in kingsun_net_open */
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ * Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int kingsun_net_open(struct net_device *netdev)
+{
+ struct kingsun_cb *kingsun = netdev_priv(netdev);
+ int err = -ENOMEM;
+ char hwname[16];
+
+ /* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+ kingsun->receiving = 0;
+
+ /* Initialize for SIR to copy data directly into skb. */
+ kingsun->rx_buff.in_frame = FALSE;
+ kingsun->rx_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_buff.truesize = IRDA_SKB_MAX_MTU;
+ kingsun->rx_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+ if (!kingsun->rx_buff.skb)
+ goto free_mem;
+
+ skb_reserve(kingsun->rx_buff.skb, 1);
+ kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
+ do_gettimeofday(&kingsun->rx_time);
+
+ kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->rx_urb)
+ goto free_mem;
+
+ kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!kingsun->tx_urb)
+ goto free_mem;
+
+ /*
+ * Now that everything should be initialized properly,
+ * Open new IrLAP layer instance to take care of us...
+ */
+ sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+ kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+ if (!kingsun->irlap) {
+ err("kingsun-sir: irlap_open failed");
+ goto free_mem;
+ }
+
+ /* Start first reception */
+ usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
+ usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
+ kingsun->in_buf, kingsun->max_rx,
+ kingsun_rcv_irq, kingsun, 1);
+ kingsun->rx_urb->status = 0;
+ err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ if (err) {
+ err("kingsun-sir: first urb-submit failed: %d", err);
+ goto close_irlap;
+ }
+
+ netif_start_queue(netdev);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - urbs allocated and ready to fill
+ - max rx packet known (in max_rx)
+ - unwrap state machine initialized, in state outside of any frame
+ - receive request in progress
+ - IrLAP layer started, about to hand over packets to send
+ */
+
+ return 0;
+
+ close_irlap:
+ irlap_close(kingsun->irlap);
+ free_mem:
+ if (kingsun->tx_urb) {
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ }
+ if (kingsun->rx_urb) {
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ }
+ if (kingsun->rx_buff.skb) {
+ kfree_skb(kingsun->rx_buff.skb);
+ kingsun->rx_buff.skb = NULL;
+ kingsun->rx_buff.head = NULL;
+ }
+ return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ * Network device is taken down. Usually this is done by
+ * "ifconfig irda0 down"
+ */
+static int kingsun_net_close(struct net_device *netdev)
+{
+ struct kingsun_cb *kingsun = netdev_priv(netdev);
+
+ /* Stop transmit processing */
+ netif_stop_queue(netdev);
+
+ /* Mop up receive && transmit urb's */
+ usb_kill_urb(kingsun->tx_urb);
+ usb_kill_urb(kingsun->rx_urb);
+
+ usb_free_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->rx_urb);
+
+ kingsun->tx_urb = NULL;
+ kingsun->rx_urb = NULL;
+
+ kfree_skb(kingsun->rx_buff.skb);
+ kingsun->rx_buff.skb = NULL;
+ kingsun->rx_buff.head = NULL;
+ kingsun->rx_buff.in_frame = FALSE;
+ kingsun->rx_buff.state = OUTSIDE_FRAME;
+ kingsun->receiving = 0;
+
+ /* Stop and remove instance of IrLAP */
+ if (kingsun->irlap)
+ irlap_close(kingsun->irlap);
+
+ kingsun->irlap = NULL;
+
+ return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
+ int cmd)
+{
+ struct if_irda_req *irq = (struct if_irda_req *) rq;
+ struct kingsun_cb *kingsun = netdev_priv(netdev);
+ int ret = 0;
+
+ switch (cmd) {
+ case SIOCSBANDWIDTH: /* Set bandwidth */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the device is still there */
+ if (netif_device_present(kingsun->netdev))
+ /* No observed commands for speed change */
+ ret = -EOPNOTSUPP;
+ break;
+
+ case SIOCSMEDIABUSY: /* Set media busy */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ /* Check if the IrDA stack is still there */
+ if (netif_running(kingsun->netdev))
+ irda_device_set_media_busy(kingsun->netdev, TRUE);
+ break;
+
+ case SIOCGRECEIVING:
+ /* Only approximately true */
+ irq->ifr_receiving = kingsun->receiving;
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *
+kingsun_net_get_stats(struct net_device *netdev)
+{
+ struct kingsun_cb *kingsun = netdev_priv(netdev);
+ return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int kingsun_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct kingsun_cb *kingsun = NULL;
+ struct net_device *net = NULL;
+ int ret = -ENOMEM;
+ int pipe, maxp_in, maxp_out;
+ __u8 ep_in;
+ __u8 ep_out;
+
+ /* Check that there really are two interrupt endpoints.
+ Check based on the one in drivers/usb/input/usbmouse.c
+ */
+ interface = intf->cur_altsetting;
+ if (interface->desc.bNumEndpoints != 2) {
+ err("kingsun-sir: expected 2 endpoints, found %d",
+ interface->desc.bNumEndpoints);
+ return -ENODEV;
+ }
+ endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
+ if (!usb_endpoint_is_int_in(endpoint)) {
+ err("kingsun-sir: endpoint 0 is not interrupt IN");
+ return -ENODEV;
+ }
+
+ ep_in = endpoint->bEndpointAddress;
+ pipe = usb_rcvintpipe(dev, ep_in);
+ maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+ if (maxp_in > 255 || maxp_in <= 1) {
+ err("%s: endpoint 0 has max packet size %d not in range",
+ __FILE__, maxp_in);
+ return -ENODEV;
+ }
+
+ endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
+ if (!usb_endpoint_is_int_out(endpoint)) {
+ err("kingsun-sir: endpoint 1 is not interrupt OUT");
+ return -ENODEV;
+ }
+
+ ep_out = endpoint->bEndpointAddress;
+ pipe = usb_sndintpipe(dev, ep_out);
+ maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ /* Allocate network device container. */
+ net = alloc_irdadev(sizeof(*kingsun));
+ if(!net)
+ goto err_out1;
+
+ SET_MODULE_OWNER(net);
+ SET_NETDEV_DEV(net, &intf->dev);
+ kingsun = netdev_priv(net);
+ kingsun->irlap = NULL;
+ kingsun->tx_urb = NULL;
+ kingsun->rx_urb = NULL;
+ kingsun->ep_in = ep_in;
+ kingsun->ep_out = ep_out;
+ kingsun->in_buf = NULL;
+ kingsun->out_buf = NULL;
+ kingsun->max_rx = (__u8)maxp_in;
+ kingsun->max_tx = (__u8)maxp_out;
+ kingsun->netdev = net;
+ kingsun->usbdev = dev;
+ kingsun->rx_buff.in_frame = FALSE;
+ kingsun->rx_buff.state = OUTSIDE_FRAME;
+ kingsun->rx_buff.skb = NULL;
+ kingsun->receiving = 0;
+ spin_lock_init(&kingsun->lock);
+
+ /* Allocate input buffer */
+ kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL);
+ if (!kingsun->in_buf)
+ goto free_mem;
+
+ /* Allocate output buffer */
+ kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
+ if (!kingsun->out_buf)
+ goto free_mem;
+
+ printk(KERN_INFO "KingSun/DonShine IRDA/USB found at address %d, "
+ "Vendor: %x, Product: %x\n",
+ dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies(&kingsun->qos);
+
+ /* That's the Rx capability. */
+ kingsun->qos.baud_rate.bits &= IR_9600;
+ kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+ irda_qos_bits_to_value(&kingsun->qos);
+
+ /* Override the network functions we need to use */
+ net->hard_start_xmit = kingsun_hard_xmit;
+ net->open = kingsun_net_open;
+ net->stop = kingsun_net_close;
+ net->get_stats = kingsun_net_get_stats;
+ net->do_ioctl = kingsun_net_ioctl;
+
+ ret = register_netdev(net);
+ if (ret != 0)
+ goto free_mem;
+
+ info("IrDA: Registered KingSun/DonShine device %s", net->name);
+
+ usb_set_intfdata(intf, kingsun);
+
+ /* Situation at this point:
+ - all work buffers allocated
+ - urbs not allocated, set to NULL
+ - max rx packet known (in max_rx)
+ - unwrap state machine (partially) initialized, but skb == NULL
+ */
+
+ return 0;
+
+free_mem:
+ if (kingsun->out_buf) kfree(kingsun->out_buf);
+ if (kingsun->in_buf) kfree(kingsun->in_buf);
+ free_netdev(net);
+err_out1:
+ return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void kingsun_disconnect(struct usb_interface *intf)
+{
+ struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+ if (!kingsun)
+ return;
+
+ unregister_netdev(kingsun->netdev);
+
+ /* Mop up receive && transmit urb's */
+ if (kingsun->tx_urb != NULL) {
+ usb_kill_urb(kingsun->tx_urb);
+ usb_free_urb(kingsun->tx_urb);
+ kingsun->tx_urb = NULL;
+ }
+ if (kingsun->rx_urb != NULL) {
+ usb_kill_urb(kingsun->rx_urb);
+ usb_free_urb(kingsun->rx_urb);
+ kingsun->rx_urb = NULL;
+ }
+
+ kfree(kingsun->out_buf);
+ kfree(kingsun->in_buf);
+ free_netdev(kingsun->netdev);
+
+ usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int kingsun_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+ netif_device_detach(kingsun->netdev);
+ if (kingsun->tx_urb != NULL) usb_kill_urb(kingsun->tx_urb);
+ if (kingsun->rx_urb != NULL) usb_kill_urb(kingsun->rx_urb);
+ return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int kingsun_resume(struct usb_interface *intf)
+{
+ struct kingsun_cb *kingsun = usb_get_intfdata(intf);
+
+ if (kingsun->rx_urb != NULL)
+ usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+ netif_device_attach(kingsun->netdev);
+
+ return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+ .name = "kingsun-sir",
+ .probe = kingsun_probe,
+ .disconnect = kingsun_disconnect,
+ .id_table = dongles,
+#ifdef CONFIG_PM
+ .suspend = kingsun_suspend,
+ .resume = kingsun_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init kingsun_init(void)
+{
+ return usb_register(&irda_driver);
+}
+module_init(kingsun_init);
+
+/*
+ * Module removal
+ */
+static void __exit kingsun_cleanup(void)
+{
+ /* Deregister the driver and remove all pending instances */
+ usb_deregister(&irda_driver);
+}
+module_exit(kingsun_cleanup);
+
+MODULE_AUTHOR("Alex Villac�s Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun/DonShine");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index f994f12..c0d3101 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -3,6 +3,7 @@
#
menu "PHY device support"
+ depends on !S390
config PHYLIB
tristate "PHY Device support and infrastructure"
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 1fc7730..2106bec 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -16,11 +16,13 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
+#include <linux/platform_device.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <asm/sgi/hpc3.h>
#include <asm/sgi/ip22.h>
+#include <asm/sgi/seeq.h>
#include "sgiseeq.h"
@@ -92,13 +94,9 @@
struct net_device_stats stats;
- struct net_device *next_module;
spinlock_t tx_lock;
};
-/* A list of all installed seeq devices, for removing the driver module. */
-static struct net_device *root_sgiseeq_dev;
-
static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs)
{
hregs->reset = HPC3_ERST_CRESET | HPC3_ERST_CLRIRQ;
@@ -624,9 +622,12 @@
#define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf))
-static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom)
+static int __init sgiseeq_probe(struct platform_device *pdev)
{
+ struct sgiseeq_platform_data *pd = pdev->dev.platform_data;
+ struct hpc3_regs *hpcregs = pd->hpc;
struct sgiseeq_init_block *sr;
+ unsigned int irq = pd->irq;
struct sgiseeq_private *sp;
struct net_device *dev;
int err, i;
@@ -637,6 +638,8 @@
err = -ENOMEM;
goto err_out;
}
+
+ platform_set_drvdata(pdev, dev);
sp = netdev_priv(dev);
/* Make private data page aligned */
@@ -648,15 +651,7 @@
}
sp->srings = sr;
-#define EADDR_NVOFS 250
- for (i = 0; i < 3; i++) {
- unsigned short tmp = has_eeprom ?
- ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) :
- ip22_nvram_read(EADDR_NVOFS / 2+i);
-
- dev->dev_addr[2 * i] = tmp >> 8;
- dev->dev_addr[2 * i + 1] = tmp & 0xff;
- }
+ memcpy(dev->dev_addr, pd->mac, ETH_ALEN);
#ifdef DEBUG
gpriv = sp;
@@ -720,9 +715,6 @@
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
- sp->next_module = root_sgiseeq_dev;
- root_sgiseeq_dev = dev;
-
return 0;
err_out_free_page:
@@ -734,43 +726,42 @@
return err;
}
-static int __init sgiseeq_probe(void)
+static void __exit sgiseeq_remove(struct platform_device *pdev)
{
- unsigned int tmp, ret1, ret2 = 0;
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct sgiseeq_private *sp = netdev_priv(dev);
- /* On board adapter on 1st HPC is always present */
- ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0);
- /* Let's see if second HPC is there */
- if (!(ip22_is_fullhouse()) &&
- get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) {
- sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 |
- SGIMC_GIOPAR_EXP164 |
- SGIMC_GIOPAR_HPC264;
- hpc3c1->pbus_piocfg[0][0] = 0x3ffff;
- /* interrupt/config register on Challenge S Mezz board */
- hpc3c1->pbus_extregs[0][0] = 0x30;
- ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1);
- }
-
- return (ret1 & ret2) ? ret1 : 0;
+ unregister_netdev(dev);
+ free_page((unsigned long) sp->srings);
+ free_netdev(dev);
+ platform_set_drvdata(pdev, NULL);
}
-static void __exit sgiseeq_exit(void)
-{
- struct net_device *next, *dev;
- struct sgiseeq_private *sp;
-
- for (dev = root_sgiseeq_dev; dev; dev = next) {
- sp = (struct sgiseeq_private *) netdev_priv(dev);
- next = sp->next_module;
- unregister_netdev(dev);
- free_page((unsigned long) sp->srings);
- free_netdev(dev);
+static struct platform_driver sgiseeq_driver = {
+ .probe = sgiseeq_probe,
+ .remove = __devexit_p(sgiseeq_remove),
+ .driver = {
+ .name = "sgiseeq"
}
+};
+
+static int __init sgiseeq_module_init(void)
+{
+ if (platform_driver_register(&sgiseeq_driver)) {
+ printk(KERN_ERR "Driver registration failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
}
-module_init(sgiseeq_probe);
-module_exit(sgiseeq_exit);
+static void __exit sgiseeq_module_exit(void)
+{
+ platform_driver_unregister(&sgiseeq_driver);
+}
+
+module_init(sgiseeq_module_init);
+module_exit(sgiseeq_module_exit);
MODULE_DESCRIPTION("SGI Seeq 8003 driver");
MODULE_AUTHOR("Linux/MIPS Mailing List <linux-mips@linux-mips.org>");
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index d7aff81..0f66765 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -293,7 +293,7 @@
else {
init_enet_offset =
qe_muram_alloc(thread_size, thread_alignment);
- if (IS_MURAM_ERR(init_enet_offset)) {
+ if (IS_ERR_VALUE(init_enet_offset)) {
ugeth_err
("fill_init_enet_entries: Can not allocate DPRAM memory.");
qe_put_snum((u8) snum);
@@ -2594,7 +2594,7 @@
ugeth->tx_bd_ring_offset[j] =
qe_muram_alloc(length,
UCC_GETH_TX_BD_RING_ALIGNMENT);
- if (!IS_MURAM_ERR(ugeth->tx_bd_ring_offset[j]))
+ if (!IS_ERR_VALUE(ugeth->tx_bd_ring_offset[j]))
ugeth->p_tx_bd_ring[j] =
(u8 *) qe_muram_addr(ugeth->
tx_bd_ring_offset[j]);
@@ -2629,7 +2629,7 @@
ugeth->rx_bd_ring_offset[j] =
qe_muram_alloc(length,
UCC_GETH_RX_BD_RING_ALIGNMENT);
- if (!IS_MURAM_ERR(ugeth->rx_bd_ring_offset[j]))
+ if (!IS_ERR_VALUE(ugeth->rx_bd_ring_offset[j]))
ugeth->p_rx_bd_ring[j] =
(u8 *) qe_muram_addr(ugeth->
rx_bd_ring_offset[j]);
@@ -2713,7 +2713,7 @@
ugeth->tx_glbl_pram_offset =
qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram),
UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) {
+ if (IS_ERR_VALUE(ugeth->tx_glbl_pram_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
__FUNCTION__);
@@ -2735,7 +2735,7 @@
sizeof(struct ucc_geth_thread_data_tx) +
32 * (numThreadsTxNumerical == 1),
UCC_GETH_THREAD_DATA_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) {
+ if (IS_ERR_VALUE(ugeth->thread_dat_tx_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
__FUNCTION__);
@@ -2763,7 +2763,7 @@
qe_muram_alloc(ug_info->numQueuesTx *
sizeof(struct ucc_geth_send_queue_qd),
UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) {
+ if (IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
__FUNCTION__);
@@ -2806,7 +2806,7 @@
ugeth->scheduler_offset =
qe_muram_alloc(sizeof(struct ucc_geth_scheduler),
UCC_GETH_SCHEDULER_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->scheduler_offset)) {
+ if (IS_ERR_VALUE(ugeth->scheduler_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_scheduler.",
__FUNCTION__);
@@ -2854,7 +2854,7 @@
qe_muram_alloc(sizeof
(struct ucc_geth_tx_firmware_statistics_pram),
UCC_GETH_TX_STATISTICS_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) {
+ if (IS_ERR_VALUE(ugeth->tx_fw_statistics_pram_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for"
" p_tx_fw_statistics_pram.", __FUNCTION__);
@@ -2893,7 +2893,7 @@
ugeth->rx_glbl_pram_offset =
qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram),
UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) {
+ if (IS_ERR_VALUE(ugeth->rx_glbl_pram_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
__FUNCTION__);
@@ -2914,7 +2914,7 @@
qe_muram_alloc(numThreadsRxNumerical *
sizeof(struct ucc_geth_thread_data_rx),
UCC_GETH_THREAD_DATA_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) {
+ if (IS_ERR_VALUE(ugeth->thread_dat_rx_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
__FUNCTION__);
@@ -2937,7 +2937,7 @@
qe_muram_alloc(sizeof
(struct ucc_geth_rx_firmware_statistics_pram),
UCC_GETH_RX_STATISTICS_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) {
+ if (IS_ERR_VALUE(ugeth->rx_fw_statistics_pram_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for"
" p_rx_fw_statistics_pram.", __FUNCTION__);
@@ -2959,7 +2959,7 @@
qe_muram_alloc(ug_info->numQueuesRx *
sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
+ 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
+ if (IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for"
" p_rx_irq_coalescing_tbl.", __FUNCTION__);
@@ -3027,7 +3027,7 @@
(sizeof(struct ucc_geth_rx_bd_queues_entry) +
sizeof(struct ucc_geth_rx_prefetched_bds)),
UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) {
+ if (IS_ERR_VALUE(ugeth->rx_bd_qs_tbl_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
__FUNCTION__);
@@ -3116,7 +3116,7 @@
ugeth->exf_glbl_param_offset =
qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram),
UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
- if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) {
+ if (IS_ERR_VALUE(ugeth->exf_glbl_param_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for"
" p_exf_glbl_param.", __FUNCTION__);
@@ -3258,7 +3258,7 @@
/* Allocate InitEnet command parameter structure */
init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4);
- if (IS_MURAM_ERR(init_enet_pram_offset)) {
+ if (IS_ERR_VALUE(init_enet_pram_offset)) {
ugeth_err
("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
__FUNCTION__);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index e273347..e3f5bb0 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -3,6 +3,7 @@
#
menu "Wireless LAN"
+ depends on !S390
config WLAN_PRE80211
bool "Wireless LAN (pre-802.11)"
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 36c6a1b..f46c69e4 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -6,6 +6,7 @@
#
menu "Parallel port support"
+ depends on HAS_IOMEM
config PARPORT
tristate "Parallel port support"
diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig
index c514320..1959cef 100644
--- a/drivers/pnp/Kconfig
+++ b/drivers/pnp/Kconfig
@@ -3,6 +3,7 @@
#
menu "Plug and Play support"
+ depends on HAS_IOMEM
config PNP
bool "Plug and Play support"
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 76422ed..95ce8f4 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -3,6 +3,7 @@
#
menu "Real Time Clock"
+ depends on !S390
config RTC_LIB
tristate
@@ -245,7 +246,7 @@
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
- || M32R || ATARI || POWERPC)
+ || M32R || ATARI || POWERPC || MIPS)
help
Say "yes" here to get direct support for the real time clock
found in every PC or ACPI-based system, and some other boards.
@@ -396,7 +397,7 @@
config RTC_DRV_RS5C313
tristate "Ricoh RS5C313"
- depends on RTC_CLASS && BROKEN
+ depends on RTC_CLASS && SH_LANDISK
help
If you say yes here you get support for the Ricoh RS5C313 RTC chips.
diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c
index 9d6de37..66eb133 100644
--- a/drivers/rtc/rtc-rs5c313.c
+++ b/drivers/rtc/rtc-rs5c313.c
@@ -126,7 +126,7 @@
static unsigned char rs5c313_read_data(void)
{
int i;
- unsigned char data;
+ unsigned char data = 0;
for (i = 0; i < 8; i++) {
ndelay(700);
@@ -194,7 +194,7 @@
return;
}
-static inline unsigned char rs5c313_read_cntreg(unsigned char addr)
+static inline unsigned char rs5c313_read_cntreg(void)
{
return rs5c313_read_reg(RS5C313_ADDR_CNTREG);
}
@@ -212,7 +212,9 @@
static int rs5c313_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
int data;
+ int cnt;
+ cnt = 0;
while (1) {
RS5C313_CEENABLE; /* CE:H */
@@ -225,6 +227,10 @@
RS5C313_CEDISABLE;
ndelay(700); /* CE:L */
+ if (cnt++ > 100) {
+ dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+ return -EIO;
+ }
}
data = rs5c313_read_reg(RS5C313_ADDR_SEC);
@@ -266,7 +272,9 @@
static int rs5c313_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
int data;
+ int cnt;
+ cnt = 0;
/* busy check. */
while (1) {
RS5C313_CEENABLE; /* CE:H */
@@ -279,6 +287,11 @@
RS5C313_MISCOP;
RS5C313_CEDISABLE;
ndelay(700); /* CE:L */
+
+ if (cnt++ > 100) {
+ dev_err(dev, "%s: timeout error\n", __FUNCTION__);
+ return -EIO;
+ }
}
data = BIN2BCD(tm->tm_sec);
@@ -317,6 +330,7 @@
static void rs5c313_check_xstp_bit(void)
{
struct rtc_time tm;
+ int cnt;
RS5C313_CEENABLE; /* CE:H */
if (rs5c313_read_cntreg() & RS5C313_CNTREG_WTEN_XSTP) {
@@ -326,12 +340,16 @@
rs5c313_write_cntreg(0x07);
/* busy check. */
- while (rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY)
+ for (cnt = 0; cnt < 100; cnt++) {
+ if (!(rs5c313_read_cntreg() & RS5C313_CNTREG_ADJ_BSY))
+ break;
RS5C313_MISCOP;
+ }
memset(&tm, 0, sizeof(struct rtc_time));
tm.tm_mday = 1;
- tm.tm_mon = 1;
+ tm.tm_mon = 1 - 1;
+ tm.tm_year = 2000 - 1900;
rs5c313_rtc_set_time(NULL, &tm);
printk(KERN_ERR "RICHO RS5C313: invalid value, resetting to "
@@ -356,7 +374,7 @@
platform_set_drvdata(pdev, rtc);
- return err;
+ return 0;
}
static int __devexit rs5c313_rtc_remove(struct platform_device *pdev)
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
deleted file mode 100644
index 165af39..0000000
--- a/drivers/s390/Kconfig
+++ /dev/null
@@ -1,239 +0,0 @@
-config CCW
- bool
- default y
-
-source "drivers/block/Kconfig"
-
-source "drivers/md/Kconfig"
-
-
-menu "Character device drivers"
-
-config UNIX98_PTYS
- bool "Unix98 PTY support"
- ---help---
- A pseudo terminal (PTY) is a software device consisting of two
- halves: a master and a slave. The slave device behaves identical to
- a physical terminal; the master device is used by a process to
- read data from and write data to the slave, thereby emulating a
- terminal. Typical programs for the master side are telnet servers
- and xterms.
-
- Linux has traditionally used the BSD-like names /dev/ptyxx for
- masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
- has a number of problems. The GNU C library glibc 2.1 and later,
- however, supports the Unix98 naming standard: in order to acquire a
- pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
- terminal is then made available to the process and the pseudo
- terminal slave can be accessed as /dev/pts/<number>. What was
- traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
- The entries in /dev/pts/ are created on the fly by a virtual
- file system; therefore, if you say Y here you should say Y to
- "/dev/pts file system for Unix98 PTYs" as well.
-
- If you want to say Y here, you need to have the C library glibc 2.1
- or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
- Read the instructions in <file:Documentation/Changes> pertaining to
- pseudo terminals. It's safe to say N.
-
-config UNIX98_PTY_COUNT
- int "Maximum number of Unix98 PTYs in use (0-2048)"
- depends on UNIX98_PTYS
- default "256"
- help
- The maximum number of Unix98 PTYs that can be used at any one time.
- The default is 256, and should be enough for desktop systems. Server
- machines which support incoming telnet/rlogin/ssh connections and/or
- serve several X terminals may want to increase this: every incoming
- connection and every xterm uses up one PTY.
-
- When not in use, each additional set of 256 PTYs occupy
- approximately 8 KB of kernel memory on 32-bit architectures.
-
-config HANGCHECK_TIMER
- tristate "Hangcheck timer"
- help
- The hangcheck-timer module detects when the system has gone
- out to lunch past a certain margin. It can reboot the system
- or merely print a warning.
-
-source "drivers/char/watchdog/Kconfig"
-
-comment "S/390 character device drivers"
-
-config TN3270
- tristate "Support for locally attached 3270 terminals"
- help
- Include support for IBM 3270 terminals.
-
-config TN3270_TTY
- tristate "Support for tty input/output on 3270 terminals"
- depends on TN3270
- help
- Include support for using an IBM 3270 terminal as a Linux tty.
-
-config TN3270_FS
- tristate "Support for fullscreen applications on 3270 terminals"
- depends on TN3270
- help
- Include support for fullscreen applications on an IBM 3270 terminal.
-
-config TN3270_CONSOLE
- bool "Support for console on 3270 terminal"
- depends on TN3270=y && TN3270_TTY=y
- help
- Include support for using an IBM 3270 terminal as a Linux system
- console. Available only if 3270 support is compiled in statically.
-
-config TN3215
- bool "Support for 3215 line mode terminal"
- help
- Include support for IBM 3215 line-mode terminals.
-
-config TN3215_CONSOLE
- bool "Support for console on 3215 line mode terminal"
- depends on TN3215
- help
- Include support for using an IBM 3215 line-mode terminal as a
- Linux system console.
-
-config CCW_CONSOLE
- bool
- depends on TN3215_CONSOLE || TN3270_CONSOLE
- default y
-
-config SCLP_TTY
- bool "Support for SCLP line mode terminal"
- help
- Include support for IBM SCLP line-mode terminals.
-
-config SCLP_CONSOLE
- bool "Support for console on SCLP line mode terminal"
- depends on SCLP_TTY
- help
- Include support for using an IBM HWC line-mode terminal as the Linux
- system console.
-
-config SCLP_VT220_TTY
- bool "Support for SCLP VT220-compatible terminal"
- help
- Include support for an IBM SCLP VT220-compatible terminal.
-
-config SCLP_VT220_CONSOLE
- bool "Support for console on SCLP VT220-compatible terminal"
- depends on SCLP_VT220_TTY
- help
- Include support for using an IBM SCLP VT220-compatible terminal as a
- Linux system console.
-
-config SCLP_CPI
- tristate "Control-Program Identification"
- help
- This option enables the hardware console interface for system
- identification. This is commonly used for workload management and
- gives you a nice name for the system on the service element.
- Please select this option as a module since built-in operation is
- completely untested.
- You should only select this option if you know what you are doing,
- need this feature and intend to run your kernel in LPAR.
-
-config S390_TAPE
- tristate "S/390 tape device support"
- help
- Select this option if you want to access channel-attached tape
- devices on IBM S/390 or zSeries.
- If you select this option you will also want to select at
- least one of the tape interface options and one of the tape
- hardware options in order to access a tape device.
- This option is also available as a module. The module will be
- called tape390 and include all selected interfaces and
- hardware drivers.
-
-comment "S/390 tape interface support"
- depends on S390_TAPE
-
-config S390_TAPE_BLOCK
- bool "Support for tape block devices"
- depends on S390_TAPE
- help
- Select this option if you want to access your channel-attached tape
- devices using the block device interface. This interface is similar
- to CD-ROM devices on other platforms. The tapes can only be
- accessed read-only when using this interface. Have a look at
- <file:Documentation/s390/TAPE> for further information about creating
- volumes for and using this interface. It is safe to say "Y" here.
-
-comment "S/390 tape hardware support"
- depends on S390_TAPE
-
-config S390_TAPE_34XX
- tristate "Support for 3480/3490 tape hardware"
- depends on S390_TAPE
- help
- Select this option if you want to access IBM 3480/3490 magnetic
- tape subsystems and 100% compatibles.
- It is safe to say "Y" here.
-
-config S390_TAPE_3590
- tristate "Support for 3590 tape hardware"
- depends on S390_TAPE
- help
- Select this option if you want to access IBM 3590 magnetic
- tape subsystems and 100% compatibles.
- It is safe to say "Y" here.
-
-config VMLOGRDR
- tristate "Support for the z/VM recording system services (VM only)"
- depends on IUCV
- help
- Select this option if you want to be able to receive records collected
- by the z/VM recording system services, eg. from *LOGREC, *ACCOUNT or
- *SYMPTOM.
- This driver depends on the IUCV support driver.
-
-config VMCP
- tristate "Support for the z/VM CP interface (VM only)"
- help
- Select this option if you want to be able to interact with the control
- program on z/VM
-
-
-config MONREADER
- tristate "API for reading z/VM monitor service records"
- depends on IUCV
- help
- Character device driver for reading z/VM monitor service records
-
-config MONWRITER
- tristate "API for writing z/VM monitor service records"
- default "m"
- help
- Character device driver for writing z/VM monitor service records
-
-endmenu
-
-menu "Cryptographic devices"
-
-config ZCRYPT
- tristate "Support for PCI-attached cryptographic adapters"
- select ZCRYPT_MONOLITHIC if ZCRYPT="y"
- default "m"
- help
- Select this option if you want to use a PCI-attached cryptographic
- adapter like:
- + PCI Cryptographic Accelerator (PCICA)
- + PCI Cryptographic Coprocessor (PCICC)
- + PCI-X Cryptographic Coprocessor (PCIXCC)
- + Crypto Express2 Coprocessor (CEX2C)
- + Crypto Express2 Accelerator (CEX2A)
-
-config ZCRYPT_MONOLITHIC
- bool "Monolithic zcrypt module"
- depends on ZCRYPT="m"
- help
- Select this option if you want to have a single module z90crypt.ko
- that contains all parts of the crypto device driver (ap bus,
- request router and all the card drivers).
-
-endmenu
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index b250c53..e879b21 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -1,11 +1,9 @@
-if S390 && BLOCK
-
comment "S/390 block device drivers"
- depends on S390
+ depends on S390 && BLOCK
config BLK_DEV_XPRAM
tristate "XPRAM disk support"
- depends on S390
+ depends on S390 && BLOCK
help
Select this option if you want to use your expanded storage on S/390
or zSeries as a disk. This is useful as a _fast_ swap device if you
@@ -15,12 +13,13 @@
config DCSSBLK
tristate "DCSSBLK support"
+ depends on S390 && BLOCK
help
Support for dcss block device
config DASD
tristate "Support for DASD devices"
- depends on CCW
+ depends on CCW && BLOCK
help
Enable this option if you want to access DASDs directly utilizing
S/390s channel subsystem commands. This is necessary for running
@@ -62,5 +61,3 @@
This driver provides a character device interface to the
DASD extended error reporting. This is only needed if you want to
use applications written for the EER facility.
-
-endif
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 9775210..bfeca57 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2174,9 +2174,10 @@
return ret;
}
-struct dasd_ccw_req * dasd_generic_build_rdc(struct dasd_device *device,
- void *rdc_buffer,
- int rdc_buffer_size, char *magic)
+static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
+ void *rdc_buffer,
+ int rdc_buffer_size,
+ char *magic)
{
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
@@ -2219,6 +2220,7 @@
dasd_sfree_request(cqr, cqr->device);
return ret;
}
+EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);
static int __init
dasd_init(void)
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index e810e4a..eccac1c 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -50,6 +50,7 @@
struct dasd_diag_rw_io iob;
struct dasd_diag_init_io iib;
blocknum_t pt_block;
+ struct ccw_dev_id dev_id;
};
struct dasd_diag_req {
@@ -102,7 +103,7 @@
iib = &private->iib;
memset(iib, 0, sizeof (struct dasd_diag_init_io));
- iib->dev_nr = _ccw_device_get_device_number(device->cdev);
+ iib->dev_nr = private->dev_id.devno;
iib->block_size = blocksize;
iib->offset = offset;
iib->flaga = DASD_DIAG_FLAGA_DEFAULT;
@@ -127,7 +128,7 @@
private = (struct dasd_diag_private *) device->private;
iib = &private->iib;
memset(iib, 0, sizeof (struct dasd_diag_init_io));
- iib->dev_nr = _ccw_device_get_device_number(device->cdev);
+ iib->dev_nr = private->dev_id.devno;
rc = dia250(iib, TERM_BIO);
return rc;
}
@@ -166,7 +167,7 @@
private = (struct dasd_diag_private *) device->private;
dreq = (struct dasd_diag_req *) cqr->data;
- private->iob.dev_nr = _ccw_device_get_device_number(device->cdev);
+ private->iob.dev_nr = private->dev_id.devno;
private->iob.key = 0;
private->iob.flags = DASD_DIAG_RWFLAG_ASYNC;
private->iob.block_count = dreq->block_count;
@@ -323,11 +324,12 @@
"memory allocation failed for private data");
return -ENOMEM;
}
+ ccw_device_get_id(device->cdev, &private->dev_id);
device->private = (void *) private;
}
/* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data);
- rdc_data->dev_nr = _ccw_device_get_device_number(device->cdev);
+ rdc_data->dev_nr = private->dev_id.devno;
rdc_data->rdc_len = sizeof (struct dasd_diag_characteristics);
rc = diag210((struct diag210 *) rdc_data);
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index c9583fb..418b4e6 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -450,9 +450,9 @@
return 0;
}
-struct dasd_ccw_req * dasd_eckd_build_rcd_lpm(struct dasd_device *device,
- void *rcd_buffer,
- struct ciw *ciw, __u8 lpm)
+static struct dasd_ccw_req *dasd_eckd_build_rcd_lpm(struct dasd_device *device,
+ void *rcd_buffer,
+ struct ciw *ciw, __u8 lpm)
{
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index 758cfb5..672eb0a 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -255,6 +255,7 @@
unsigned long flags;
int rc;
struct ccw_device *cdev;
+ struct ccw_dev_id dev_id;
if (!device->discipline->fill_info)
return -EINVAL;
@@ -270,8 +271,9 @@
}
cdev = device->cdev;
+ ccw_device_get_id(cdev, &dev_id);
- dasd_info->devno = _ccw_device_get_device_number(device->cdev);
+ dasd_info->devno = dev_id.devno;
dasd_info->schid = _ccw_device_get_subchannel_number(device->cdev);
dasd_info->cu_type = cdev->id.cu_type;
dasd_info->cu_model = cdev->id.cu_model;
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
new file mode 100644
index 0000000..66102a1
--- /dev/null
+++ b/drivers/s390/char/Kconfig
@@ -0,0 +1,166 @@
+comment "S/390 character device drivers"
+ depends on S390
+
+config TN3270
+ tristate "Support for locally attached 3270 terminals"
+ depends on CCW
+ help
+ Include support for IBM 3270 terminals.
+
+config TN3270_TTY
+ tristate "Support for tty input/output on 3270 terminals"
+ depends on TN3270
+ help
+ Include support for using an IBM 3270 terminal as a Linux tty.
+
+config TN3270_FS
+ tristate "Support for fullscreen applications on 3270 terminals"
+ depends on TN3270
+ help
+ Include support for fullscreen applications on an IBM 3270 terminal.
+
+config TN3270_CONSOLE
+ bool "Support for console on 3270 terminal"
+ depends on TN3270=y && TN3270_TTY=y
+ help
+ Include support for using an IBM 3270 terminal as a Linux system
+ console. Available only if 3270 support is compiled in statically.
+
+config TN3215
+ bool "Support for 3215 line mode terminal"
+ depends on CCW
+ help
+ Include support for IBM 3215 line-mode terminals.
+
+config TN3215_CONSOLE
+ bool "Support for console on 3215 line mode terminal"
+ depends on TN3215
+ help
+ Include support for using an IBM 3215 line-mode terminal as a
+ Linux system console.
+
+config CCW_CONSOLE
+ bool
+ depends on TN3215_CONSOLE || TN3270_CONSOLE
+ default y
+
+config SCLP
+ bool "Support for SCLP"
+ depends on S390
+ help
+ Include support for the SCLP interface to the service element.
+
+config SCLP_TTY
+ bool "Support for SCLP line mode terminal"
+ depends on SCLP
+ help
+ Include support for IBM SCLP line-mode terminals.
+
+config SCLP_CONSOLE
+ bool "Support for console on SCLP line mode terminal"
+ depends on SCLP_TTY
+ help
+ Include support for using an IBM HWC line-mode terminal as the Linux
+ system console.
+
+config SCLP_VT220_TTY
+ bool "Support for SCLP VT220-compatible terminal"
+ depends on SCLP
+ help
+ Include support for an IBM SCLP VT220-compatible terminal.
+
+config SCLP_VT220_CONSOLE
+ bool "Support for console on SCLP VT220-compatible terminal"
+ depends on SCLP_VT220_TTY
+ help
+ Include support for using an IBM SCLP VT220-compatible terminal as a
+ Linux system console.
+
+config SCLP_CPI
+ tristate "Control-Program Identification"
+ depends on SCLP
+ help
+ This option enables the hardware console interface for system
+ identification. This is commonly used for workload management and
+ gives you a nice name for the system on the service element.
+ Please select this option as a module since built-in operation is
+ completely untested.
+ You should only select this option if you know what you are doing,
+ need this feature and intend to run your kernel in LPAR.
+
+config S390_TAPE
+ tristate "S/390 tape device support"
+ depends on CCW
+ help
+ Select this option if you want to access channel-attached tape
+ devices on IBM S/390 or zSeries.
+ If you select this option you will also want to select at
+ least one of the tape interface options and one of the tape
+ hardware options in order to access a tape device.
+ This option is also available as a module. The module will be
+ called tape390 and include all selected interfaces and
+ hardware drivers.
+
+comment "S/390 tape interface support"
+ depends on S390_TAPE
+
+config S390_TAPE_BLOCK
+ bool "Support for tape block devices"
+ depends on S390_TAPE
+ help
+ Select this option if you want to access your channel-attached tape
+ devices using the block device interface. This interface is similar
+ to CD-ROM devices on other platforms. The tapes can only be
+ accessed read-only when using this interface. Have a look at
+ <file:Documentation/s390/TAPE> for further information about creating
+ volumes for and using this interface. It is safe to say "Y" here.
+
+comment "S/390 tape hardware support"
+ depends on S390_TAPE
+
+config S390_TAPE_34XX
+ tristate "Support for 3480/3490 tape hardware"
+ depends on S390_TAPE
+ help
+ Select this option if you want to access IBM 3480/3490 magnetic
+ tape subsystems and 100% compatibles.
+ It is safe to say "Y" here.
+
+config S390_TAPE_3590
+ tristate "Support for 3590 tape hardware"
+ depends on S390_TAPE
+ help
+ Select this option if you want to access IBM 3590 magnetic
+ tape subsystems and 100% compatibles.
+ It is safe to say "Y" here.
+
+config VMLOGRDR
+ tristate "Support for the z/VM recording system services (VM only)"
+ depends on IUCV
+ help
+ Select this option if you want to be able to receive records collected
+ by the z/VM recording system services, eg. from *LOGREC, *ACCOUNT or
+ *SYMPTOM.
+ This driver depends on the IUCV support driver.
+
+config VMCP
+ tristate "Support for the z/VM CP interface (VM only)"
+ depends on S390
+ help
+ Select this option if you want to be able to interact with the control
+ program on z/VM
+
+
+config MONREADER
+ tristate "API for reading z/VM monitor service records"
+ depends on IUCV
+ help
+ Character device driver for reading z/VM monitor service records
+
+config MONWRITER
+ tristate "API for writing z/VM monitor service records"
+ depends on S390
+ default "m"
+ help
+ Character device driver for writing z/VM monitor service records
+
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index 8df7b13..67009bf 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -97,7 +97,7 @@
* Create the 8 bytes EBCDIC DCSS segment name from
* an ASCII name, incl. padding
*/
-static inline void dcss_mkname(char *ascii_name, char *ebcdic_name)
+static void dcss_mkname(char *ascii_name, char *ebcdic_name)
{
int i;
@@ -191,7 +191,7 @@
return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8));
}
-static inline int mon_check_mca(struct mon_msg *monmsg)
+static int mon_check_mca(struct mon_msg *monmsg)
{
if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) ||
(mon_rec_start(monmsg) < mon_dcss_start) ||
@@ -209,8 +209,8 @@
return 0;
}
-static inline int mon_send_reply(struct mon_msg *monmsg,
- struct mon_private *monpriv)
+static int mon_send_reply(struct mon_msg *monmsg,
+ struct mon_private *monpriv)
{
int rc;
@@ -236,7 +236,7 @@
return 0;
}
-static inline void mon_free_mem(struct mon_private *monpriv)
+static void mon_free_mem(struct mon_private *monpriv)
{
int i;
@@ -246,7 +246,7 @@
kfree(monpriv);
}
-static inline struct mon_private *mon_alloc_mem(void)
+static struct mon_private *mon_alloc_mem(void)
{
int i;
struct mon_private *monpriv;
@@ -307,7 +307,7 @@
monmsg->pos = 0;
}
-static inline struct mon_msg *mon_next_message(struct mon_private *monpriv)
+static struct mon_msg *mon_next_message(struct mon_private *monpriv)
{
struct mon_msg *monmsg;
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 8facd14..f6ef90e 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -589,9 +589,10 @@
__raw3270_size_device_vm(struct raw3270 *rp)
{
int rc, model;
+ struct ccw_dev_id dev_id;
- raw3270_init_diag210.vrdcdvno =
- _ccw_device_get_device_number(rp->cdev);
+ ccw_device_get_id(rp->cdev, &dev_id);
+ raw3270_init_diag210.vrdcdvno = dev_id.devno;
raw3270_init_diag210.vrdclen = sizeof(struct diag210);
rc = diag210(&raw3270_init_diag210);
if (rc)
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 87ac4a3..dbb99d1 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -132,6 +132,9 @@
int sclp_reactivate(void);
int sclp_service_call(sclp_cmdw_t command, void *sccb);
+int sclp_sdias_init(void);
+void sclp_sdias_exit(void);
+
/* useful inlines */
/* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
index 52283da..1c06497 100644
--- a/drivers/s390/char/sclp_sdias.c
+++ b/drivers/s390/char/sclp_sdias.c
@@ -66,9 +66,9 @@
static void sdias_callback(struct sclp_req *request, void *data)
{
- struct sdias_sccb *sccb;
+ struct sdias_sccb *cbsccb;
- sccb = (struct sdias_sccb *) request->sccb;
+ cbsccb = (struct sdias_sccb *) request->sccb;
sclp_req_done = 1;
wake_up(&sdias_wq); /* Inform caller, that request is complete */
TRACE("callback done\n");
@@ -229,7 +229,7 @@
return rc;
}
-int __init sdias_init(void)
+int __init sclp_sdias_init(void)
{
int rc;
@@ -248,7 +248,7 @@
return 0;
}
-void __exit sdias_exit(void)
+void __exit sclp_sdias_exit(void)
{
debug_unregister(sdias_dbf);
sclp_unregister(&sclp_sdias_register);
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 89d43931..66eb068 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -21,6 +21,7 @@
#include <asm/debug.h>
#include <asm/processor.h>
#include <asm/irqflags.h>
+#include "sclp.h"
#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
#define MSG(x...) printk( KERN_ALERT x )
@@ -564,8 +565,6 @@
get_cpu_id(&hdr->cpu_id);
}
-extern int sdias_init(void);
-
static int __init zcore_init(void)
{
unsigned char arch;
@@ -582,7 +581,7 @@
TRACE("wwpn: %llx\n", (unsigned long long) ipl_info.data.fcp.wwpn);
TRACE("lun: %llx\n", (unsigned long long) ipl_info.data.fcp.lun);
- rc = sdias_init();
+ rc = sclp_sdias_init();
if (rc)
goto fail;
@@ -634,12 +633,10 @@
return rc;
}
-extern void sdias_exit(void);
-
static void __exit zcore_exit(void)
{
debug_unregister(zcore_dbf);
- sdias_exit();
+ sclp_sdias_exit();
diag308(DIAG308_REL_HSA, NULL);
}
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 27c6d9e..dfca0ef 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -191,8 +191,7 @@
return ret;
}
-int
-css_probe_device(struct subchannel_id schid)
+static int css_probe_device(struct subchannel_id schid)
{
int ret;
struct subchannel *sch;
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 71fcfdc..ed79775 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -138,9 +138,7 @@
* all css_drivers have the css_bus_type
*/
extern struct bus_type css_bus_type;
-extern struct css_driver io_subchannel_driver;
-extern int css_probe_device(struct subchannel_id);
extern int css_sch_device_register(struct subchannel *);
extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index a23ff58..a8b373f 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -129,7 +129,7 @@
static void io_subchannel_ioterm(struct device *);
static void io_subchannel_shutdown(struct subchannel *);
-struct css_driver io_subchannel_driver = {
+static struct css_driver io_subchannel_driver = {
.subchannel_type = SUBCHANNEL_TYPE_IO,
.drv = {
.name = "io_subchannel",
@@ -546,7 +546,7 @@
.attrs = ccwdev_attrs,
};
-struct attribute_group *ccwdev_attr_groups[] = {
+static struct attribute_group *ccwdev_attr_groups[] = {
&ccwdev_attr_group,
NULL,
};
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 16f59fc..a5d263f 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -616,6 +616,17 @@
return chp_get_chp_desc(chpid);
}
+/**
+ * ccw_device_get_id - obtain a ccw device id
+ * @cdev: device to obtain the id for
+ * @dev_id: where to fill in the values
+ */
+void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id)
+{
+ *dev_id = cdev->private->dev_id;
+}
+EXPORT_SYMBOL(ccw_device_get_id);
+
// FIXME: these have to go:
int
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index f770018..e70aeb7 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -1983,6 +1983,7 @@
if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
qdio_mark_q(q);
else {
+ qdio_perf_stat_dec(&perf_stats.tl_runs);
__qdio_inbound_processing(q);
}
}
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index f98fa46..eada69d 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -3,7 +3,7 @@
config LCS
tristate "Lan Channel Station Interface"
- depends on NETDEVICES && (NET_ETHERNET || TR || FDDI)
+ depends on CCW && NETDEVICES && (NET_ETHERNET || TR || FDDI)
help
Select this option if you want to use LCS networking on IBM S/390
or zSeries. This device driver supports Token Ring (IEEE 802.5),
@@ -13,7 +13,7 @@
config CTC
tristate "CTC device support"
- depends on NETDEVICES
+ depends on CCW && NETDEVICES
help
Select this option if you want to use channel-to-channel networking
on IBM S/390 or zSeries. This device driver supports real CTC
@@ -42,7 +42,7 @@
config CLAW
tristate "CLAW device support"
- depends on NETDEVICES
+ depends on CCW && NETDEVICES
help
This driver supports channel attached CLAW devices.
CLAW is Common Link Access for Workstation. Common devices
@@ -52,7 +52,7 @@
config QETH
tristate "Gigabit Ethernet device support"
- depends on NETDEVICES && IP_MULTICAST && QDIO
+ depends on CCW && NETDEVICES && IP_MULTICAST && QDIO
help
This driver supports the IBM S/390 and zSeries OSA Express adapters
in QDIO mode (all media types), HiperSockets interfaces and VM GuestLAN
diff --git a/drivers/s390/net/qeth_mpc.c b/drivers/s390/net/qeth_mpc.c
index f54fdfd..f29a4bc 100644
--- a/drivers/s390/net/qeth_mpc.c
+++ b/drivers/s390/net/qeth_mpc.c
@@ -162,7 +162,7 @@
char *msg;
};
-struct ipa_rc_msg qeth_ipa_rc_msg[] = {
+static struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_SUCCESS, "success"},
{IPA_RC_NOTSUPP, "Command not supported"},
{IPA_RC_IP_TABLE_FULL, "Add Addr IP Table Full - ipv6"},
@@ -226,7 +226,7 @@
char *name;
};
-struct ipa_cmd_names qeth_ipa_cmd_names[] = {
+static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
{IPA_CMD_STARTLAN, "startlan"},
{IPA_CMD_STOPLAN, "stoplan"},
{IPA_CMD_SETVMAC, "setvmac"},
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 324899c..ddff40c 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -607,8 +607,7 @@
* @sg_count: elements in array
* Return: size of entire scatter-gather list
*/
-size_t
-zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
+static size_t zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
{
unsigned int i;
struct scatterlist *p;
@@ -975,8 +974,7 @@
mempool_destroy(adapter->pool.data_gid_pn);
}
-void
-zfcp_dummy_release(struct device *dev)
+static void zfcp_dummy_release(struct device *dev)
{
return;
}
@@ -1336,7 +1334,7 @@
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FC
-void
+static void
zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter,
struct fsf_status_read_buffer *status_buffer)
{
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index d8191d1..5f32124 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -478,7 +478,7 @@
NULL
};
-void
+static void
_zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
u32 s_id, u32 d_id, void *buffer, int buflen)
{
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index a15752b..eef8275 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -6,87 +6,49 @@
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
* Copyright (C) 2001 Florian Lohoff (flo@rfc822.org)
- * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org)
+ * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
*
* (In all truth, Jed Schimmel wrote all this code.)
*/
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
+
+#undef DEBUG
+
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/spinlock.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/sgialib.h>
-#include <asm/sgi/sgi.h>
-#include <asm/sgi/mc.h>
#include <asm/sgi/hpc3.h>
#include <asm/sgi/ip22.h>
-#include <asm/irq.h>
-#include <asm/io.h>
+#include <asm/sgi/wd.h>
#include "scsi.h"
-#include <scsi/scsi_host.h>
#include "wd33c93.h"
-#include <linux/stat.h>
-
-#if 0
-#define DPRINTK(args...) printk(args)
-#else
-#define DPRINTK(args...)
-#endif
-
-#define HDATA(ptr) ((struct ip22_hostdata *)((ptr)->hostdata))
-
struct ip22_hostdata {
struct WD33C93_hostdata wh;
struct hpc_data {
dma_addr_t dma;
- void * cpu;
+ void *cpu;
} hd;
};
+#define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata))
+
struct hpc_chunk {
struct hpc_dma_desc desc;
u32 _padding; /* align to quadword boundary */
};
-struct Scsi_Host *sgiwd93_host;
-struct Scsi_Host *sgiwd93_host1;
-
-/* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */
-static inline void write_wd33c93_count(const wd33c93_regs regs,
- unsigned long value)
-{
- *regs.SASR = WD_TRANSFER_COUNT_MSB;
- mb();
- *regs.SCMD = ((value >> 16) & 0xff);
- *regs.SCMD = ((value >> 8) & 0xff);
- *regs.SCMD = ((value >> 0) & 0xff);
- mb();
-}
-
-static inline unsigned long read_wd33c93_count(const wd33c93_regs regs)
-{
- unsigned long value;
-
- *regs.SASR = WD_TRANSFER_COUNT_MSB;
- mb();
- value = ((*regs.SCMD & 0xff) << 16);
- value |= ((*regs.SCMD & 0xff) << 8);
- value |= ((*regs.SCMD & 0xff) << 0);
- mb();
- return value;
-}
-
static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
{
- struct Scsi_Host * host = (struct Scsi_Host *) dev_id;
+ struct Scsi_Host * host = dev_id;
unsigned long flags;
spin_lock_irqsave(host->host_lock, flags);
@@ -131,12 +93,12 @@
static int dma_setup(struct scsi_cmnd *cmd, int datainp)
{
- struct ip22_hostdata *hdata = HDATA(cmd->device->host);
+ struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host);
struct hpc3_scsiregs *hregs =
(struct hpc3_scsiregs *) cmd->device->host->base;
struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu;
- DPRINTK("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp);
+ pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp);
hdata->wh.dma_dir = datainp;
@@ -151,7 +113,7 @@
fill_hpc_entries(hcp, cmd, datainp);
- DPRINTK(" HPCGO\n");
+ pr_debug(" HPCGO\n");
/* Start up the HPC. */
hregs->ndptr = hdata->hd.dma;
@@ -166,7 +128,7 @@
static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
- struct ip22_hostdata *hdata = HDATA(instance);
+ struct ip22_hostdata *hdata = host_to_hostdata(instance);
struct hpc3_scsiregs *hregs;
if (!SCpnt)
@@ -174,7 +136,7 @@
hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base;
- DPRINTK("dma_stop: status<%d> ", status);
+ pr_debug("dma_stop: status<%d> ", status);
/* First stop the HPC and flush it's FIFO. */
if (hdata->wh.dma_dir) {
@@ -186,7 +148,7 @@
dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual,
SCpnt->sc_data_direction);
- DPRINTK("\n");
+ pr_debug("\n");
}
void sgiwd93_reset(unsigned long base)
@@ -216,96 +178,6 @@
hcp->desc.pnext = hd->dma;
}
-static struct Scsi_Host * __init sgiwd93_setup_scsi(
- struct scsi_host_template *SGIblows, int unit, int irq,
- struct hpc3_scsiregs *hregs, unsigned char *wdregs)
-{
- struct ip22_hostdata *hdata;
- struct Scsi_Host *host;
- wd33c93_regs regs;
-
- host = scsi_register(SGIblows, sizeof(struct ip22_hostdata));
- if (!host)
- return NULL;
-
- host->base = (unsigned long) hregs;
- host->irq = irq;
-
- hdata = HDATA(host);
- hdata->hd.cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &hdata->hd.dma,
- GFP_KERNEL);
- if (!hdata->hd.cpu) {
- printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
- "host %d buffer.\n", unit);
- goto out_unregister;
- }
- init_hpc_chain(&hdata->hd);
-
- regs.SASR = wdregs + 3;
- regs.SCMD = wdregs + 7;
-
- wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20));
-
- if (hdata->wh.no_sync == 0xff)
- hdata->wh.no_sync = 0;
-
- if (request_irq(irq, sgiwd93_intr, 0, "SGI WD93", (void *) host)) {
- printk(KERN_WARNING "sgiwd93: Could not register irq %d "
- "for host %d.\n", irq, unit);
- goto out_free;
- }
- return host;
-
-out_free:
- dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
- wd33c93_release();
-
-out_unregister:
- scsi_unregister(host);
-
- return NULL;
-}
-
-static int __init sgiwd93_detect(struct scsi_host_template *SGIblows)
-{
- int found = 0;
-
- SGIblows->proc_name = "SGIWD93";
- sgiwd93_host = sgiwd93_setup_scsi(SGIblows, 0, SGI_WD93_0_IRQ,
- &hpc3c0->scsi_chan0,
- (unsigned char *)hpc3c0->scsi0_ext);
- if (sgiwd93_host)
- found++;
-
- /* Set up second controller on the Indigo2 */
- if (ip22_is_fullhouse()) {
- sgiwd93_host1 = sgiwd93_setup_scsi(SGIblows, 1, SGI_WD93_1_IRQ,
- &hpc3c0->scsi_chan1,
- (unsigned char *)hpc3c0->scsi1_ext);
- if (sgiwd93_host1)
- found++;
- }
-
- return found;
-}
-
-static int sgiwd93_release(struct Scsi_Host *instance)
-{
- struct ip22_hostdata *hdata = HDATA(instance);
- int irq = 0;
-
- if (sgiwd93_host && sgiwd93_host == instance)
- irq = SGI_WD93_0_IRQ;
- else if (sgiwd93_host1 && sgiwd93_host1 == instance)
- irq = SGI_WD93_1_IRQ;
-
- free_irq(irq, sgiwd93_intr);
- dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
- wd33c93_release();
-
- return 1;
-}
-
static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
@@ -325,11 +197,10 @@
* arguments not with pointers. So this is going to blow up beautyfully
* on 64-bit systems with memory outside the compat address spaces.
*/
-static struct scsi_host_template driver_template = {
+static struct scsi_host_template sgiwd93_template = {
+ .module = THIS_MODULE,
.proc_name = "SGIWD93",
.name = "SGI WD93",
- .detect = sgiwd93_detect,
- .release = sgiwd93_release,
.queuecommand = wd33c93_queuecommand,
.eh_abort_handler = wd33c93_abort,
.eh_bus_reset_handler = sgiwd93_bus_reset,
@@ -340,4 +211,109 @@
.cmd_per_lun = 8,
.use_clustering = DISABLE_CLUSTERING,
};
-#include "scsi_module.c"
+
+static int __init sgiwd93_probe(struct platform_device *pdev)
+{
+ struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
+ unsigned char *wdregs = pd->wdregs;
+ struct hpc3_scsiregs *hregs = pd->hregs;
+ struct ip22_hostdata *hdata;
+ struct Scsi_Host *host;
+ wd33c93_regs regs;
+ unsigned int unit = pd->unit;
+ unsigned int irq = pd->irq;
+ int err;
+
+ host = scsi_host_alloc(&sgiwd93_template, sizeof(struct ip22_hostdata));
+ if (!host) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ host->base = (unsigned long) hregs;
+ host->irq = irq;
+
+ hdata = host_to_hostdata(host);
+ hdata->hd.cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
+ &hdata->hd.dma, GFP_KERNEL);
+ if (!hdata->hd.cpu) {
+ printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
+ "host %d buffer.\n", unit);
+ err = -ENOMEM;
+ goto out_put;
+ }
+
+ init_hpc_chain(&hdata->hd);
+
+ regs.SASR = wdregs + 3;
+ regs.SCMD = wdregs + 7;
+
+ wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20));
+
+ if (hdata->wh.no_sync == 0xff)
+ hdata->wh.no_sync = 0;
+
+ err = request_irq(irq, sgiwd93_intr, 0, "SGI WD93", host);
+ if (err) {
+ printk(KERN_WARNING "sgiwd93: Could not register irq %d "
+ "for host %d.\n", irq, unit);
+ goto out_free;
+ }
+
+ platform_set_drvdata(pdev, host);
+
+ err = scsi_add_host(host, NULL);
+ if (err)
+ goto out_irq;
+
+ scsi_scan_host(host);
+
+ return 0;
+
+out_irq:
+ free_irq(irq, host);
+out_free:
+ dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+out_put:
+ scsi_host_put(host);
+out:
+
+ return err;
+}
+
+static void __exit sgiwd93_remove(struct platform_device *pdev)
+{
+ struct Scsi_Host *host = platform_get_drvdata(pdev);
+ struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata;
+ struct sgiwd93_platform_data *pd = pdev->dev.platform_data;
+
+ scsi_remove_host(host);
+ free_irq(pd->irq, host);
+ dma_free_coherent(&pdev->dev, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+ scsi_host_put(host);
+}
+
+static struct platform_driver sgiwd93_driver = {
+ .probe = sgiwd93_probe,
+ .remove = __devexit_p(sgiwd93_remove),
+ .driver = {
+ .name = "sgiwd93"
+ }
+};
+
+static int __init sgiwd93_module_init(void)
+{
+ return platform_driver_register(&sgiwd93_driver);
+}
+
+static void __exit sgiwd93_module_exit(void)
+{
+ return platform_driver_unregister(&sgiwd93_driver);
+}
+
+module_init(sgiwd93_module_init);
+module_exit(sgiwd93_module_exit);
+
+MODULE_DESCRIPTION("SGI WD33C93 driver");
+MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index e8efe93..a6f5bfb 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -5,6 +5,7 @@
#
menu "Serial drivers"
+ depends on HAS_IOMEM
#
# The new 8250/16550 serial drivers
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 69715e5..a8f894c 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -88,7 +88,7 @@
/* these are located in their respective files */
void cpm_line_cr_cmd(int line, int cmd);
-int __init cpm_uart_init_portdesc(void);
+int cpm_uart_init_portdesc(void);
int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index f23972b..b63ff8d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -482,7 +482,8 @@
}
static void cpm_uart_set_termios(struct uart_port *port,
- struct termios *termios, struct termios *old)
+ struct ktermios *termios,
+ struct ktermios *old)
{
int baud;
unsigned long flags;
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 925fb60..8c6324e 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -125,7 +125,7 @@
{
int dpmemsz, memsz;
u8 *dp_mem;
- uint dp_offset;
+ unsigned long dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
@@ -133,7 +133,7 @@
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_offset = cpm_dpalloc(dpmemsz, 8);
- if (IS_DPERR(dp_offset)) {
+ if (IS_ERR_VALUE(dp_offset)) {
printk(KERN_ERR
"cpm_uart_cpm1.c: could not allocate buffer descriptors\n");
return -ENOMEM;
@@ -185,7 +185,7 @@
}
/* Setup any dynamic params in the uart desc */
-int __init cpm_uart_init_portdesc(void)
+int cpm_uart_init_portdesc(void)
{
pr_debug("CPM uart[-]:init portdesc\n");
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index fa45599..7b61d80 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -222,7 +222,7 @@
{
int dpmemsz, memsz;
u8 *dp_mem;
- uint dp_offset;
+ unsigned long dp_offset;
u8 *mem_addr;
dma_addr_t dma_addr = 0;
@@ -230,7 +230,7 @@
dpmemsz = sizeof(cbd_t) * (pinfo->rx_nrfifos + pinfo->tx_nrfifos);
dp_offset = cpm_dpalloc(dpmemsz, 8);
- if (IS_DPERR(dp_offset)) {
+ if (IS_ERR_VALUE(dp_offset)) {
printk(KERN_ERR
"cpm_uart_cpm.c: could not allocate buffer descriptors\n");
return -ENOMEM;
@@ -282,7 +282,7 @@
}
/* Setup any dynamic params in the uart desc */
-int __init cpm_uart_init_portdesc(void)
+int cpm_uart_init_portdesc(void)
{
#if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
u16 *addr;
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index da73205..0985193 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -92,6 +92,8 @@
#define SUNZILOG_FLAG_REGS_HELD 0x00000040
#define SUNZILOG_FLAG_TX_STOPPED 0x00000080
#define SUNZILOG_FLAG_TX_ACTIVE 0x00000100
+#define SUNZILOG_FLAG_ESCC 0x00000200
+#define SUNZILOG_FLAG_ISR_HANDLER 0x00000400
unsigned int cflag;
@@ -174,9 +176,11 @@
/* This function must only be called when the TX is not busy. The UART
* port lock must be held and local interrupts disabled.
*/
-static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
+static int __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *regs)
{
int i;
+ int escc;
+ unsigned char r15;
/* Let pending transmits finish. */
for (i = 0; i < 1000; i++) {
@@ -229,11 +233,25 @@
write_zsreg(channel, R14, regs[R14]);
/* External status interrupt control. */
- write_zsreg(channel, R15, regs[R15]);
+ write_zsreg(channel, R15, (regs[R15] | WR7pEN) & ~FIFOEN);
+
+ /* ESCC Extension Register */
+ r15 = read_zsreg(channel, R15);
+ if (r15 & 0x01) {
+ write_zsreg(channel, R7, regs[R7p]);
+
+ /* External status interrupt and FIFO control. */
+ write_zsreg(channel, R15, regs[R15] & ~WR7pEN);
+ escc = 1;
+ } else {
+ /* Clear FIFO bit case it is an issue */
+ regs[R15] &= ~FIFOEN;
+ escc = 0;
+ }
/* Reset external status interrupts. */
- write_zsreg(channel, R0, RES_EXT_INT);
- write_zsreg(channel, R0, RES_EXT_INT);
+ write_zsreg(channel, R0, RES_EXT_INT); /* First Latch */
+ write_zsreg(channel, R0, RES_EXT_INT); /* Second Latch */
/* Rewrite R3/R5, this time without enables masked. */
write_zsreg(channel, R3, regs[R3]);
@@ -241,6 +259,8 @@
/* Rewrite R1, this time without IRQ enabled masked. */
write_zsreg(channel, R1, regs[R1]);
+
+ return escc;
}
/* Reprogram the Zilog channel HW registers with the copies found in the
@@ -731,7 +751,7 @@
up->curregs[R15] = new_reg;
/* NOTE: Not subject to 'transmitter active' rule. */
- write_zsreg(channel, R15, up->curregs[R15]);
+ write_zsreg(channel, R15, up->curregs[R15] & ~WR7pEN);
}
}
@@ -861,44 +881,44 @@
up->curregs[R14] = BRSRC | BRENAB;
/* Character size, stop bits, and parity. */
- up->curregs[3] &= ~RxN_MASK;
- up->curregs[5] &= ~TxN_MASK;
+ up->curregs[R3] &= ~RxN_MASK;
+ up->curregs[R5] &= ~TxN_MASK;
switch (cflag & CSIZE) {
case CS5:
- up->curregs[3] |= Rx5;
- up->curregs[5] |= Tx5;
+ up->curregs[R3] |= Rx5;
+ up->curregs[R5] |= Tx5;
up->parity_mask = 0x1f;
break;
case CS6:
- up->curregs[3] |= Rx6;
- up->curregs[5] |= Tx6;
+ up->curregs[R3] |= Rx6;
+ up->curregs[R5] |= Tx6;
up->parity_mask = 0x3f;
break;
case CS7:
- up->curregs[3] |= Rx7;
- up->curregs[5] |= Tx7;
+ up->curregs[R3] |= Rx7;
+ up->curregs[R5] |= Tx7;
up->parity_mask = 0x7f;
break;
case CS8:
default:
- up->curregs[3] |= Rx8;
- up->curregs[5] |= Tx8;
+ up->curregs[R3] |= Rx8;
+ up->curregs[R5] |= Tx8;
up->parity_mask = 0xff;
break;
};
- up->curregs[4] &= ~0x0c;
+ up->curregs[R4] &= ~0x0c;
if (cflag & CSTOPB)
- up->curregs[4] |= SB2;
+ up->curregs[R4] |= SB2;
else
- up->curregs[4] |= SB1;
+ up->curregs[R4] |= SB1;
if (cflag & PARENB)
- up->curregs[4] |= PAR_ENAB;
+ up->curregs[R4] |= PAR_ENAB;
else
- up->curregs[4] &= ~PAR_ENAB;
+ up->curregs[R4] &= ~PAR_ENAB;
if (!(cflag & PARODD))
- up->curregs[4] |= PAR_EVEN;
+ up->curregs[R4] |= PAR_EVEN;
else
- up->curregs[4] &= ~PAR_EVEN;
+ up->curregs[R4] &= ~PAR_EVEN;
up->port.read_status_mask = Rx_OVR;
if (iflag & INPCK)
@@ -952,7 +972,9 @@
static const char *sunzilog_type(struct uart_port *port)
{
- return "zs";
+ struct uart_sunzilog_port *up = UART_ZILOG(port);
+
+ return (up->flags & SUNZILOG_FLAG_ESCC) ? "zs (ESCC)" : "zs";
}
/* We do not request/release mappings of the registers here, this
@@ -1170,7 +1192,7 @@
spin_lock_irqsave(&up->port.lock, flags);
- up->curregs[R15] = BRKIE;
+ up->curregs[R15] |= BRKIE;
sunzilog_convert_to_zs(up, con->cflag, 0, brg);
sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1229,7 +1251,7 @@
baud = 4800;
}
- up->curregs[R15] = BRKIE;
+ up->curregs[R15] |= BRKIE;
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
sunzilog_convert_to_zs(up, up->cflag, 0, brg);
sunzilog_set_mctrl(&up->port, TIOCM_DTR | TIOCM_RTS);
@@ -1283,8 +1305,18 @@
if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
SUNZILOG_FLAG_CONS_MOUSE)) {
+ up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+ up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+ up->curregs[R3] = RxENAB | Rx8;
+ up->curregs[R5] = TxENAB | Tx8;
+ up->curregs[R6] = 0x00; /* SDLC Address */
+ up->curregs[R7] = 0x7E; /* SDLC Flag */
+ up->curregs[R9] = NV;
+ up->curregs[R7p] = 0x00;
sunzilog_init_kbdms(up, up->port.line);
- up->curregs[R9] |= (NV | MIE);
+ /* Only enable interrupts if an ISR handler available */
+ if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+ up->curregs[R9] |= MIE;
write_zsreg(channel, R9, up->curregs[R9]);
} else {
/* Normal serial TTY. */
@@ -1293,7 +1325,9 @@
up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
up->curregs[R3] = RxENAB | Rx8;
up->curregs[R5] = TxENAB | Tx8;
- up->curregs[R9] = NV | MIE;
+ up->curregs[R6] = 0x00; /* SDLC Address */
+ up->curregs[R7] = 0x7E; /* SDLC Flag */
+ up->curregs[R9] = NV;
up->curregs[R10] = NRZ;
up->curregs[R11] = TCBR | RCBR;
baud = 9600;
@@ -1301,7 +1335,14 @@
up->curregs[R12] = (brg & 0xff);
up->curregs[R13] = (brg >> 8) & 0xff;
up->curregs[R14] = BRSRC | BRENAB;
- __load_zsregs(channel, up->curregs);
+ up->curregs[R15] = FIFOEN; /* Use FIFO if on ESCC */
+ up->curregs[R7p] = TxFIFO_LVL | RxFIFO_LVL;
+ if (__load_zsregs(channel, up->curregs)) {
+ up->flags |= SUNZILOG_FLAG_ESCC;
+ }
+ /* Only enable interrupts if an ISR handler available */
+ if (up->flags & SUNZILOG_FLAG_ISR_HANDLER)
+ up->curregs[R9] |= MIE;
write_zsreg(channel, R9, up->curregs[R9]);
}
@@ -1390,12 +1431,14 @@
return err;
}
} else {
- printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
- "is a zs\n",
- op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
- printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
- "is a zs\n",
- op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
+ printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
+ "is a %s\n",
+ op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
+ sunzilog_type (&up[0].port));
+ printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
+ "is a %s\n",
+ op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
+ sunzilog_type (&up[1].port));
}
dev_set_drvdata(&op->dev, &up[0]);
@@ -1487,10 +1530,23 @@
goto out_unregister_uart;
if (zilog_irq != -1) {
+ struct uart_sunzilog_port *up = sunzilog_irq_chain;
err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
"zs", sunzilog_irq_chain);
if (err)
goto out_unregister_driver;
+
+ /* Enable Interrupts */
+ while (up) {
+ struct zilog_channel __iomem *channel;
+
+ /* printk (KERN_INFO "Enable IRQ for ZILOG Hardware %p\n", up); */
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+ up->flags |= SUNZILOG_FLAG_ISR_HANDLER;
+ up->curregs[R9] |= MIE;
+ write_zsreg(channel, R9, up->curregs[R9]);
+ up = up->next;
+ }
}
out:
@@ -1515,6 +1571,20 @@
of_unregister_driver(&zs_driver);
if (zilog_irq != -1) {
+ struct uart_sunzilog_port *up = sunzilog_irq_chain;
+
+ /* Disable Interrupts */
+ while (up) {
+ struct zilog_channel __iomem *channel;
+
+ /* printk (KERN_INFO "Disable IRQ for ZILOG Hardware %p\n", up); */
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
+ up->flags &= ~SUNZILOG_FLAG_ISR_HANDLER;
+ up->curregs[R9] &= ~MIE;
+ write_zsreg(channel, R9, up->curregs[R9]);
+ up = up->next;
+ }
+
free_irq(zilog_irq, sunzilog_irq_chain);
zilog_irq = -1;
}
diff --git a/drivers/serial/sunzilog.h b/drivers/serial/sunzilog.h
index 7939b6d..5dec7b4 100644
--- a/drivers/serial/sunzilog.h
+++ b/drivers/serial/sunzilog.h
@@ -13,7 +13,8 @@
struct zilog_channel channelA;
};
-#define NUM_ZSREGS 16
+#define NUM_ZSREGS 17
+#define R7p 16 /* Written as R7 with P15 bit 0 set */
/* Conversion routines to/from brg time constants from/to bits
* per second.
@@ -127,6 +128,15 @@
/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+/* Write Register 7' (ESCC Only) */
+#define AUTO_TxFLAG 1 /* Automatic Tx SDLC Flag */
+#define AUTO_EOM_RST 2 /* Automatic EOM Reset */
+#define AUTOnRTS 4 /* Automatic /RTS pin deactivation */
+#define RxFIFO_LVL 8 /* Receive FIFO interrupt level */
+#define nDTRnREQ 0x10 /* /DTR/REQ timing */
+#define TxFIFO_LVL 0x20 /* Transmit FIFO interrupt level */
+#define EXT_RD_EN 0x40 /* Extended read register enable */
+
/* Write Register 8 (transmit buffer) */
/* Write Register 9 (Master interrupt control) */
@@ -135,6 +145,7 @@
#define DLC 4 /* Disable Lower Chain */
#define MIE 8 /* Master Interrupt Enable */
#define STATHI 0x10 /* Status high */
+#define SWIACK 0x20 /* Software Interrupt Ack (not on NMOS) */
#define NORESET 0 /* No reset on write to R9 */
#define CHRB 0x40 /* Reset channel B */
#define CHRA 0x80 /* Reset channel A */
@@ -187,7 +198,9 @@
#define SNRZI 0xe0 /* Set NRZI mode */
/* Write Register 15 (external/status interrupt control) */
+#define WR7pEN 1 /* WR7' Enable (ESCC only) */
#define ZCIE 2 /* Zero count IE */
+#define FIFOEN 4 /* FIFO Enable (ESCC only) */
#define DCDIE 8 /* DCD IE */
#define SYNCIE 0x10 /* Sync/hunt IE */
#define CTSIE 0x20 /* CTS IE */
@@ -241,6 +254,10 @@
#define CHATxIP 0x10 /* Channel A Tx IP */
#define CHARxIP 0x20 /* Channel A Rx IP */
+/* Read Register 6 (LSB frame byte count [Not on NMOS]) */
+
+/* Read Register 7 (MSB frame byte count and FIFO status [Not on NMOS]) */
+
/* Read Register 8 (receive data register) */
/* Read Register 10 (misc status bits) */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 07c587e..5e3f748 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -6,6 +6,7 @@
# fully appropriate there, so it'd need some thought to do well.
#
menu "SPI support"
+ depends on HAS_IOMEM
config SPI
bool "SPI support"
@@ -106,6 +107,13 @@
This enables using the Freescale iMX SPI controller in master
mode.
+config SPI_MPC52xx_PSC
+ tristate "Freescale MPC52xx PSC SPI controller"
+ depends on SPI_MASTER && PPC_MPC52xx && EXPERIMENTAL
+ help
+ This enables using the Freescale MPC52xx Programmable Serial
+ Controller in master SPI mode.
+
config SPI_MPC83xx
tristate "Freescale MPC83xx SPI controller"
depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 624b636..5788d86 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,6 +19,7 @@
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
+obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
new file mode 100644
index 0000000..052359f
--- /dev/null
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -0,0 +1,654 @@
+/*
+ * MPC52xx SPC in SPI mode driver.
+ *
+ * Maintainer: Dragos Carp
+ *
+ * Copyright (C) 2006 TOPTICA Photonics AG.
+ *
+ * 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+
+#if defined(CONFIG_PPC_MERGE)
+#include <asm/of_platform.h>
+#else
+#include <linux/platform_device.h>
+#endif
+
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/mpc52xx.h>
+#include <asm/mpc52xx_psc.h>
+
+#define MCLK 20000000 /* PSC port MClk in hz */
+
+struct mpc52xx_psc_spi {
+ /* fsl_spi_platform data */
+ void (*activate_cs)(u8, u8);
+ void (*deactivate_cs)(u8, u8);
+ u32 sysclk;
+
+ /* driver internal data */
+ struct mpc52xx_psc __iomem *psc;
+ unsigned int irq;
+ u8 bits_per_word;
+ u8 busy;
+
+ struct workqueue_struct *workqueue;
+ struct work_struct work;
+
+ struct list_head queue;
+ spinlock_t lock;
+
+ struct completion done;
+};
+
+/* controller state */
+struct mpc52xx_psc_spi_cs {
+ int bits_per_word;
+ int speed_hz;
+};
+
+/* set clock freq, clock ramp, bits per work
+ * if t is NULL then reset the values to the default values
+ */
+static int mpc52xx_psc_spi_transfer_setup(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+
+ cs->speed_hz = (t && t->speed_hz)
+ ? t->speed_hz : spi->max_speed_hz;
+ cs->bits_per_word = (t && t->bits_per_word)
+ ? t->bits_per_word : spi->bits_per_word;
+ cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
+ return 0;
+}
+
+static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
+{
+ struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+ struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+ struct mpc52xx_psc __iomem *psc = mps->psc;
+ u32 sicr;
+ u16 ccr;
+
+ sicr = in_be32(&psc->sicr);
+
+ /* Set clock phase and polarity */
+ if (spi->mode & SPI_CPHA)
+ sicr |= 0x00001000;
+ else
+ sicr &= ~0x00001000;
+ if (spi->mode & SPI_CPOL)
+ sicr |= 0x00002000;
+ else
+ sicr &= ~0x00002000;
+
+ if (spi->mode & SPI_LSB_FIRST)
+ sicr |= 0x10000000;
+ else
+ sicr &= ~0x10000000;
+ out_be32(&psc->sicr, sicr);
+
+ /* Set clock frequency and bits per word
+ * Because psc->ccr is defined as 16bit register instead of 32bit
+ * just set the lower byte of BitClkDiv
+ */
+ ccr = in_be16(&psc->ccr);
+ ccr &= 0xFF00;
+ if (cs->speed_hz)
+ ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
+ else /* by default SPI Clk 1MHz */
+ ccr |= (MCLK / 1000000 - 1) & 0xFF;
+ out_be16(&psc->ccr, ccr);
+ mps->bits_per_word = cs->bits_per_word;
+
+ if (mps->activate_cs)
+ mps->activate_cs(spi->chip_select,
+ (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+static void mpc52xx_psc_spi_deactivate_cs(struct spi_device *spi)
+{
+ struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+
+ if (mps->deactivate_cs)
+ mps->deactivate_cs(spi->chip_select,
+ (spi->mode & SPI_CS_HIGH) ? 1 : 0);
+}
+
+#define MPC52xx_PSC_BUFSIZE (MPC52xx_PSC_RFNUM_MASK + 1)
+/* wake up when 80% fifo full */
+#define MPC52xx_PSC_RFALARM (MPC52xx_PSC_BUFSIZE * 20 / 100)
+
+static int mpc52xx_psc_spi_transfer_rxtx(struct spi_device *spi,
+ struct spi_transfer *t)
+{
+ struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+ struct mpc52xx_psc __iomem *psc = mps->psc;
+ unsigned rb = 0; /* number of bytes receieved */
+ unsigned sb = 0; /* number of bytes sent */
+ unsigned char *rx_buf = (unsigned char *)t->rx_buf;
+ unsigned char *tx_buf = (unsigned char *)t->tx_buf;
+ unsigned rfalarm;
+ unsigned send_at_once = MPC52xx_PSC_BUFSIZE;
+ unsigned recv_at_once;
+ unsigned bpw = mps->bits_per_word / 8;
+
+ if (!t->tx_buf && !t->rx_buf && t->len)
+ return -EINVAL;
+
+ /* enable transmiter/receiver */
+ out_8(&psc->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+ while (rb < t->len) {
+ if (t->len - rb > MPC52xx_PSC_BUFSIZE) {
+ rfalarm = MPC52xx_PSC_RFALARM;
+ } else {
+ send_at_once = t->len - sb;
+ rfalarm = MPC52xx_PSC_BUFSIZE - (t->len - rb);
+ }
+
+ dev_dbg(&spi->dev, "send %d bytes...\n", send_at_once);
+ if (tx_buf) {
+ for (; send_at_once; sb++, send_at_once--) {
+ /* set EOF flag */
+ if (mps->bits_per_word
+ && (sb + 1) % bpw == 0)
+ out_8(&psc->ircr2, 0x01);
+ out_8(&psc->mpc52xx_psc_buffer_8, tx_buf[sb]);
+ }
+ } else {
+ for (; send_at_once; sb++, send_at_once--) {
+ /* set EOF flag */
+ if (mps->bits_per_word
+ && ((sb + 1) % bpw) == 0)
+ out_8(&psc->ircr2, 0x01);
+ out_8(&psc->mpc52xx_psc_buffer_8, 0);
+ }
+ }
+
+
+ /* enable interupts and wait for wake up
+ * if just one byte is expected the Rx FIFO genererates no
+ * FFULL interrupt, so activate the RxRDY interrupt
+ */
+ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ if (t->len - rb == 1) {
+ out_8(&psc->mode, 0);
+ } else {
+ out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+ out_be16(&psc->rfalarm, rfalarm);
+ }
+ out_be16(&psc->mpc52xx_psc_imr, MPC52xx_PSC_IMR_RXRDY);
+ wait_for_completion(&mps->done);
+ recv_at_once = in_be16(&psc->rfnum);
+ dev_dbg(&spi->dev, "%d bytes received\n", recv_at_once);
+
+ send_at_once = recv_at_once;
+ if (rx_buf) {
+ for (; recv_at_once; rb++, recv_at_once--)
+ rx_buf[rb] = in_8(&psc->mpc52xx_psc_buffer_8);
+ } else {
+ for (; recv_at_once; rb++, recv_at_once--)
+ in_8(&psc->mpc52xx_psc_buffer_8);
+ }
+ }
+ /* disable transmiter/receiver */
+ out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+ return 0;
+}
+
+static void mpc52xx_psc_spi_work(struct work_struct *work)
+{
+ struct mpc52xx_psc_spi *mps =
+ container_of(work, struct mpc52xx_psc_spi, work);
+
+ spin_lock_irq(&mps->lock);
+ mps->busy = 1;
+ while (!list_empty(&mps->queue)) {
+ struct spi_message *m;
+ struct spi_device *spi;
+ struct spi_transfer *t = NULL;
+ unsigned cs_change;
+ int status;
+
+ m = container_of(mps->queue.next, struct spi_message, queue);
+ list_del_init(&m->queue);
+ spin_unlock_irq(&mps->lock);
+
+ spi = m->spi;
+ cs_change = 1;
+ status = 0;
+ list_for_each_entry (t, &m->transfers, transfer_list) {
+ if (t->bits_per_word || t->speed_hz) {
+ status = mpc52xx_psc_spi_transfer_setup(spi, t);
+ if (status < 0)
+ break;
+ }
+
+ if (cs_change)
+ mpc52xx_psc_spi_activate_cs(spi);
+ cs_change = t->cs_change;
+
+ status = mpc52xx_psc_spi_transfer_rxtx(spi, t);
+ if (status)
+ break;
+ m->actual_length += t->len;
+
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (cs_change)
+ mpc52xx_psc_spi_deactivate_cs(spi);
+ }
+
+ m->status = status;
+ m->complete(m->context);
+
+ if (status || !cs_change)
+ mpc52xx_psc_spi_deactivate_cs(spi);
+
+ mpc52xx_psc_spi_transfer_setup(spi, NULL);
+
+ spin_lock_irq(&mps->lock);
+ }
+ mps->busy = 0;
+ spin_unlock_irq(&mps->lock);
+}
+
+static int mpc52xx_psc_spi_setup(struct spi_device *spi)
+{
+ struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+ struct mpc52xx_psc_spi_cs *cs = spi->controller_state;
+ unsigned long flags;
+
+ if (spi->bits_per_word%8)
+ return -EINVAL;
+
+ if (!cs) {
+ cs = kzalloc(sizeof *cs, GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ spi->controller_state = cs;
+ }
+
+ cs->bits_per_word = spi->bits_per_word;
+ cs->speed_hz = spi->max_speed_hz;
+
+ spin_lock_irqsave(&mps->lock, flags);
+ if (!mps->busy)
+ mpc52xx_psc_spi_deactivate_cs(spi);
+ spin_unlock_irqrestore(&mps->lock, flags);
+
+ return 0;
+}
+
+static int mpc52xx_psc_spi_transfer(struct spi_device *spi,
+ struct spi_message *m)
+{
+ struct mpc52xx_psc_spi *mps = spi_master_get_devdata(spi->master);
+ unsigned long flags;
+
+ m->actual_length = 0;
+ m->status = -EINPROGRESS;
+
+ spin_lock_irqsave(&mps->lock, flags);
+ list_add_tail(&m->queue, &mps->queue);
+ queue_work(mps->workqueue, &mps->work);
+ spin_unlock_irqrestore(&mps->lock, flags);
+
+ return 0;
+}
+
+static void mpc52xx_psc_spi_cleanup(struct spi_device *spi)
+{
+ kfree(spi->controller_state);
+}
+
+static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
+{
+ struct mpc52xx_cdm __iomem *cdm;
+ struct mpc52xx_gpio __iomem *gpio;
+ struct mpc52xx_psc __iomem *psc = mps->psc;
+ u32 ul;
+ u32 mclken_div;
+ int ret = 0;
+
+#if defined(CONFIG_PPC_MERGE)
+ cdm = mpc52xx_find_and_map("mpc52xx-cdm");
+ gpio = mpc52xx_find_and_map("mpc52xx-gpio");
+#else
+ cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
+ gpio = ioremap(MPC52xx_PA(MPC52xx_GPIO_OFFSET), MPC52xx_GPIO_SIZE);
+#endif
+ if (!cdm || !gpio) {
+ printk(KERN_ERR "Error mapping CDM/GPIO\n");
+ ret = -EFAULT;
+ goto unmap_regs;
+ }
+
+ /* default sysclk is 512MHz */
+ mclken_div = 0x8000 |
+ (((mps->sysclk ? mps->sysclk : 512000000) / MCLK) & 0x1FF);
+
+ switch (psc_id) {
+ case 1:
+ ul = in_be32(&gpio->port_config);
+ ul &= 0xFFFFFFF8;
+ ul |= 0x00000006;
+ out_be32(&gpio->port_config, ul);
+ out_be16(&cdm->mclken_div_psc1, mclken_div);
+ ul = in_be32(&cdm->clk_enables);
+ ul |= 0x00000020;
+ out_be32(&cdm->clk_enables, ul);
+ break;
+ case 2:
+ ul = in_be32(&gpio->port_config);
+ ul &= 0xFFFFFF8F;
+ ul |= 0x00000060;
+ out_be32(&gpio->port_config, ul);
+ out_be16(&cdm->mclken_div_psc2, mclken_div);
+ ul = in_be32(&cdm->clk_enables);
+ ul |= 0x00000040;
+ out_be32(&cdm->clk_enables, ul);
+ break;
+ case 3:
+ ul = in_be32(&gpio->port_config);
+ ul &= 0xFFFFF0FF;
+ ul |= 0x00000600;
+ out_be32(&gpio->port_config, ul);
+ out_be16(&cdm->mclken_div_psc3, mclken_div);
+ ul = in_be32(&cdm->clk_enables);
+ ul |= 0x00000080;
+ out_be32(&cdm->clk_enables, ul);
+ break;
+ case 6:
+ ul = in_be32(&gpio->port_config);
+ ul &= 0xFF8FFFFF;
+ ul |= 0x00700000;
+ out_be32(&gpio->port_config, ul);
+ out_be16(&cdm->mclken_div_psc6, mclken_div);
+ ul = in_be32(&cdm->clk_enables);
+ ul |= 0x00000010;
+ out_be32(&cdm->clk_enables, ul);
+ break;
+ default:
+ ret = -EINVAL;
+ goto unmap_regs;
+ }
+
+ /* Reset the PSC into a known state */
+ out_8(&psc->command, MPC52xx_PSC_RST_RX);
+ out_8(&psc->command, MPC52xx_PSC_RST_TX);
+ out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
+
+ /* Disable interrupts, interrupts are based on alarm level */
+ out_be16(&psc->mpc52xx_psc_imr, 0);
+ out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
+ out_8(&psc->rfcntl, 0);
+ out_8(&psc->mode, MPC52xx_PSC_MODE_FFULL);
+
+ /* Configure 8bit codec mode as a SPI master and use EOF flags */
+ /* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
+ out_be32(&psc->sicr, 0x0180C800);
+ out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */
+
+ /* Set 2ms DTL delay */
+ out_8(&psc->ctur, 0x00);
+ out_8(&psc->ctlr, 0x84);
+
+ mps->bits_per_word = 8;
+
+unmap_regs:
+ if (cdm)
+ iounmap(cdm);
+ if (gpio)
+ iounmap(gpio);
+
+ return ret;
+}
+
+static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
+{
+ struct mpc52xx_psc_spi *mps = (struct mpc52xx_psc_spi *)dev_id;
+ struct mpc52xx_psc __iomem *psc = mps->psc;
+
+ /* disable interrupt and wake up the work queue */
+ if (in_be16(&psc->mpc52xx_psc_isr) & MPC52xx_PSC_IMR_RXRDY) {
+ out_be16(&psc->mpc52xx_psc_imr, 0);
+ complete(&mps->done);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+/* bus_num is used only for the case dev->platform_data == NULL */
+static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
+ u32 size, unsigned int irq, s16 bus_num)
+{
+ struct fsl_spi_platform_data *pdata = dev->platform_data;
+ struct mpc52xx_psc_spi *mps;
+ struct spi_master *master;
+ int ret;
+
+ if (pdata == NULL)
+ return -ENODEV;
+
+ master = spi_alloc_master(dev, sizeof *mps);
+ if (master == NULL)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, master);
+ mps = spi_master_get_devdata(master);
+
+ mps->irq = irq;
+ if (pdata == NULL) {
+ dev_warn(dev, "probe called without platform data, no "
+ "(de)activate_cs function will be called\n");
+ mps->activate_cs = NULL;
+ mps->deactivate_cs = NULL;
+ mps->sysclk = 0;
+ master->bus_num = bus_num;
+ master->num_chipselect = 255;
+ } else {
+ mps->activate_cs = pdata->activate_cs;
+ mps->deactivate_cs = pdata->deactivate_cs;
+ mps->sysclk = pdata->sysclk;
+ master->bus_num = pdata->bus_num;
+ master->num_chipselect = pdata->max_chipselect;
+ }
+ master->setup = mpc52xx_psc_spi_setup;
+ master->transfer = mpc52xx_psc_spi_transfer;
+ master->cleanup = mpc52xx_psc_spi_cleanup;
+
+ mps->psc = ioremap(regaddr, size);
+ if (!mps->psc) {
+ dev_err(dev, "could not ioremap I/O port range\n");
+ ret = -EFAULT;
+ goto free_master;
+ }
+
+ ret = request_irq(mps->irq, mpc52xx_psc_spi_isr, 0, "mpc52xx-psc-spi",
+ mps);
+ if (ret)
+ goto free_master;
+
+ ret = mpc52xx_psc_spi_port_config(master->bus_num, mps);
+ if (ret < 0)
+ goto free_irq;
+
+ spin_lock_init(&mps->lock);
+ init_completion(&mps->done);
+ INIT_WORK(&mps->work, mpc52xx_psc_spi_work);
+ INIT_LIST_HEAD(&mps->queue);
+
+ mps->workqueue = create_singlethread_workqueue(
+ master->cdev.dev->bus_id);
+ if (mps->workqueue == NULL) {
+ ret = -EBUSY;
+ goto free_irq;
+ }
+
+ ret = spi_register_master(master);
+ if (ret < 0)
+ goto unreg_master;
+
+ return ret;
+
+unreg_master:
+ destroy_workqueue(mps->workqueue);
+free_irq:
+ free_irq(mps->irq, mps);
+free_master:
+ if (mps->psc)
+ iounmap(mps->psc);
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct mpc52xx_psc_spi *mps = spi_master_get_devdata(master);
+
+ flush_workqueue(mps->workqueue);
+ destroy_workqueue(mps->workqueue);
+ spi_unregister_master(master);
+ free_irq(mps->irq, mps);
+ if (mps->psc)
+ iounmap(mps->psc);
+
+ return 0;
+}
+
+#if !defined(CONFIG_PPC_MERGE)
+static int __init mpc52xx_psc_spi_probe(struct platform_device *dev)
+{
+ switch(dev->id) {
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ return mpc52xx_psc_spi_do_probe(&dev->dev,
+ MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)),
+ MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev)
+{
+ return mpc52xx_psc_spi_do_remove(&dev->dev);
+}
+
+static struct platform_driver mpc52xx_psc_spi_platform_driver = {
+ .remove = __exit_p(mpc52xx_psc_spi_remove),
+ .driver = {
+ .name = "mpc52xx-psc-spi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+ return platform_driver_probe(&mpc52xx_psc_spi_platform_driver,
+ mpc52xx_psc_spi_probe);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+ platform_driver_unregister(&mpc52xx_psc_spi_platform_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#else /* defined(CONFIG_PPC_MERGE) */
+
+static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ const u32 *regaddr_p;
+ u64 regaddr64, size64;
+ s16 id = -1;
+
+ regaddr_p = of_get_address(op->node, 0, &size64, NULL);
+ if (!regaddr_p) {
+ printk(KERN_ERR "Invalid PSC address\n");
+ return -EINVAL;
+ }
+ regaddr64 = of_translate_address(op->node, regaddr_p);
+
+ if (op->dev.platform_data == NULL) {
+ struct device_node *np;
+ int i = 0;
+
+ for_each_node_by_type(np, "spi") {
+ if (of_find_device_by_node(np) == op) {
+ id = i;
+ break;
+ }
+ i++;
+ }
+ }
+
+ return mpc52xx_psc_spi_do_probe(&op->dev, (u32)regaddr64, (u32)size64,
+ irq_of_parse_and_map(op->node, 0), id);
+}
+
+static int __exit mpc52xx_psc_spi_of_remove(struct of_device *op)
+{
+ return mpc52xx_psc_spi_do_remove(&op->dev);
+}
+
+static struct of_device_id mpc52xx_psc_spi_of_match[] = {
+ { .type = "spi", .compatible = "mpc52xx-psc-spi", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
+
+static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc52xx-psc-spi",
+ .match_table = mpc52xx_psc_spi_of_match,
+ .probe = mpc52xx_psc_spi_of_probe,
+ .remove = __exit_p(mpc52xx_psc_spi_of_remove),
+ .driver = {
+ .name = "mpc52xx-psc-spi",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init mpc52xx_psc_spi_init(void)
+{
+ return of_register_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_init(mpc52xx_psc_spi_init);
+
+static void __exit mpc52xx_psc_spi_exit(void)
+{
+ of_unregister_platform_driver(&mpc52xx_psc_spi_of_driver);
+}
+module_exit(mpc52xx_psc_spi_exit);
+
+#endif /* defined(CONFIG_PPC_MERGE) */
+
+MODULE_AUTHOR("Dragos Carp");
+MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/telephony/Kconfig b/drivers/telephony/Kconfig
index 7625b18..dd1d6a5 100644
--- a/drivers/telephony/Kconfig
+++ b/drivers/telephony/Kconfig
@@ -3,6 +3,7 @@
#
menu "Telephony Support"
+ depends on HAS_IOMEM
config PHONE
tristate "Linux telephony support"
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 278a22c..15499b7 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -3,6 +3,7 @@
#
menu "USB support"
+ depends on HAS_IOMEM
# Host-side USB depends on having a host controller
# NOTE: dummy_hcd is always an option, but it's ignored here ...
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 9a256d2..eebcb70 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -3,6 +3,7 @@
#
menu "Graphics support"
+ depends on HAS_IOMEM
source "drivers/video/backlight/Kconfig"
source "drivers/video/display/Kconfig"
@@ -747,6 +748,22 @@
working with S1D13806). Product specs at
<http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
+config FB_ATMEL
+ tristate "AT91/AT32 LCD Controller support"
+ depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This enables support for the AT91/AT32 LCD Controller.
+
+config FB_INTSRAM
+ bool "Frame Buffer in internal SRAM"
+ depends on FB_ATMEL && ARCH_AT91SAM9261
+ help
+ Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
+ to let frame buffer in external SDRAM.
+
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
depends on FB && PCI
@@ -779,6 +796,15 @@
independently validate video mode parameters, you should say Y
here.
+config FB_NVIDIA_DEBUG
+ bool "Lots of debug output"
+ depends on FB_NVIDIA
+ default n
+ help
+ Say Y here if you want the nVidia driver to output all sorts
+ of debugging information to provide to the maintainer when
+ something goes wrong.
+
config FB_NVIDIA_BACKLIGHT
bool "Support for backlight control"
depends on FB_NVIDIA
@@ -818,7 +844,7 @@
here.
config FB_RIVA_DEBUG
- bool "Lots of debug output from Riva(nVidia) driver"
+ bool "Lots of debug output"
depends on FB_RIVA
default n
help
@@ -1430,8 +1456,11 @@
and ICS 5342 RAMDAC.
config FB_PM3
- tristate "Permedia3 support"
- depends on FB && PCI && BROKEN
+ tristate "Permedia3 support (EXPERIMENTAL)"
+ depends on FB && PCI && EXPERIMENTAL
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
help
This is the frame buffer device driver for the 3DLabs Permedia3
chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 0b70567..bd8b052 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -87,6 +87,7 @@
obj-$(CONFIG_FB_SA1100) += sa1100fb.o
obj-$(CONFIG_FB_HIT) += hitfb.o
obj-$(CONFIG_FB_EPSON1355) += epson1355fb.o
+obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o
obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
new file mode 100644
index 0000000..e1d5bd0
--- /dev/null
+++ b/drivers/video/atmel_lcdfb.c
@@ -0,0 +1,752 @@
+/*
+ * Driver for AT91/AT32 LCD Controller
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+
+#include <video/atmel_lcdc.h>
+
+#define lcdc_readl(sinfo, reg) __raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val) __raw_writel((val), (sinfo)->mmio+(reg))
+
+/* configurable parameters */
+#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN 8
+
+#if defined(CONFIG_ARCH_AT91SAM9263)
+#define ATMEL_LCDC_FIFO_SIZE 2048
+#else
+#define ATMEL_LCDC_FIFO_SIZE 512
+#endif
+
+#if defined(CONFIG_ARCH_AT91)
+#define ATMEL_LCDFB_FBINFO_DEFAULT FBINFO_DEFAULT
+
+static inline void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+ struct fb_var_screeninfo *var)
+{
+
+}
+#elif defined(CONFIG_AVR32)
+#define ATMEL_LCDFB_FBINFO_DEFAULT (FBINFO_DEFAULT \
+ | FBINFO_PARTIAL_PAN_OK \
+ | FBINFO_HWACCEL_XPAN \
+ | FBINFO_HWACCEL_YPAN)
+
+static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo,
+ struct fb_var_screeninfo *var)
+{
+ u32 dma2dcfg;
+ u32 pixeloff;
+
+ pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f;
+
+ dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8;
+ dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET;
+ lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+
+ /* Update configuration */
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+ lcdc_readl(sinfo, ATMEL_LCDC_DMACON)
+ | ATMEL_LCDC_DMAUPDT);
+}
+#endif
+
+
+static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+
+static void atmel_lcdfb_update_dma(struct fb_info *info,
+ struct fb_var_screeninfo *var)
+{
+ struct atmel_lcdfb_info *sinfo = info->par;
+ struct fb_fix_screeninfo *fix = &info->fix;
+ unsigned long dma_addr;
+
+ dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+ + var->xoffset * var->bits_per_pixel / 8);
+
+ dma_addr &= ~3UL;
+
+ /* Set framebuffer DMA base address and pixel offset */
+ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+
+ atmel_lcdfb_update_dma2d(sinfo, var);
+}
+
+static inline void atmel_lcdfb_free_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+ struct fb_info *info = sinfo->info;
+
+ dma_free_writecombine(info->device, info->fix.smem_len,
+ info->screen_base, info->fix.smem_start);
+}
+
+/**
+ * atmel_lcdfb_alloc_video_memory - Allocate framebuffer memory
+ * @sinfo: the frame buffer to allocate memory for
+ */
+static int atmel_lcdfb_alloc_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+ struct fb_info *info = sinfo->info;
+ struct fb_var_screeninfo *var = &info->var;
+
+ info->fix.smem_len = (var->xres_virtual * var->yres_virtual
+ * ((var->bits_per_pixel + 7) / 8));
+
+ info->screen_base = dma_alloc_writecombine(info->device, info->fix.smem_len,
+ (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL);
+
+ if (!info->screen_base) {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * atmel_lcdfb_check_var - Validates a var passed in.
+ * @var: frame buffer variable screen structure
+ * @info: frame buffer structure that represents a single frame buffer
+ *
+ * Checks to see if the hardware supports the state requested by
+ * var passed in. This function does not alter the hardware
+ * state!!! This means the data stored in struct fb_info and
+ * struct atmel_lcdfb_info do not change. This includes the var
+ * inside of struct fb_info. Do NOT change these. This function
+ * can be called on its own if we intent to only test a mode and
+ * not actually set it. The stuff in modedb.c is a example of
+ * this. If the var passed in is slightly off by what the
+ * hardware can support then we alter the var PASSED in to what
+ * we can do. If the hardware doesn't support mode change a
+ * -EINVAL will be returned by the upper layers. You don't need
+ * to implement this function then. If you hardware doesn't
+ * support changing the resolution then this function is not
+ * needed. In this case the driver would just provide a var that
+ * represents the static state the screen is in.
+ *
+ * Returns negative errno on error, or zero on success.
+ */
+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct device *dev = info->device;
+ struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned long clk_value_khz;
+
+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+ dev_dbg(dev, "%s:\n", __func__);
+ dev_dbg(dev, " resolution: %ux%u\n", var->xres, var->yres);
+ dev_dbg(dev, " pixclk: %lu KHz\n", PICOS2KHZ(var->pixclock));
+ dev_dbg(dev, " bpp: %u\n", var->bits_per_pixel);
+ dev_dbg(dev, " clk: %lu KHz\n", clk_value_khz);
+
+ if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+ dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+ return -EINVAL;
+ }
+
+ /* Force same alignment for each line */
+ var->xres = (var->xres + 3) & ~3UL;
+ var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+
+ var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+ var->transp.offset = var->transp.length = 0;
+ var->xoffset = var->yoffset = 0;
+
+ switch (var->bits_per_pixel) {
+ case 2:
+ case 4:
+ case 8:
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length
+ = var->bits_per_pixel;
+ break;
+ case 15:
+ case 16:
+ var->red.offset = 0;
+ var->green.offset = 5;
+ var->blue.offset = 10;
+ var->red.length = var->green.length = var->blue.length = 5;
+ break;
+ case 24:
+ case 32:
+ var->red.offset = 0;
+ var->green.offset = 8;
+ var->blue.offset = 16;
+ var->red.length = var->green.length = var->blue.length = 8;
+ break;
+ default:
+ dev_err(dev, "color depth %d not supported\n",
+ var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * atmel_lcdfb_set_par - Alters the hardware state.
+ * @info: frame buffer structure that represents a single frame buffer
+ *
+ * Using the fb_var_screeninfo in fb_info we set the resolution
+ * of the this particular framebuffer. This function alters the
+ * par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+ * not alter var in fb_info since we are using that data. This
+ * means we depend on the data in var inside fb_info to be
+ * supported by the hardware. atmel_lcdfb_check_var is always called
+ * before atmel_lcdfb_set_par to ensure this. Again if you can't
+ * change the resolution you don't need this function.
+ *
+ */
+static int atmel_lcdfb_set_par(struct fb_info *info)
+{
+ struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned long value;
+ unsigned long clk_value_khz;
+
+ dev_dbg(info->device, "%s:\n", __func__);
+ dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n",
+ info->var.xres, info->var.yres,
+ info->var.xres_virtual, info->var.yres_virtual);
+
+ /* Turn off the LCD controller and the DMA controller */
+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+
+ if (info->var.bits_per_pixel <= 8)
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+ info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+
+ /* Re-initialize the DMA engine... */
+ dev_dbg(info->device, " * update DMA engine\n");
+ atmel_lcdfb_update_dma(info, &info->var);
+
+ /* ...set frame size and burst length = 8 words (?) */
+ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+ value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+ lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+ /* Now, the LCDC core... */
+
+ /* Set pixel clock */
+ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+ value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
+
+ if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
+ value++;
+
+ value = (value / 2) - 1;
+
+ if (value <= 0) {
+ dev_notice(info->device, "Bypassing pixel clock divider\n");
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+ } else
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+
+ /* Initialize control register 2 */
+ value = sinfo->default_lcdcon2;
+
+ if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+ value |= ATMEL_LCDC_INVLINE_INVERTED;
+ if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+ value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+ switch (info->var.bits_per_pixel) {
+ case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break;
+ case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+ case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+ case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+ case 15: /* fall through */
+ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+ case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+ case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+ default: BUG(); break;
+ }
+ dev_dbg(info->device, " * LCDCON2 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+ /* Vertical timing */
+ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+ value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+ value |= info->var.lower_margin;
+ dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+ /* Horizontal timing */
+ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+ value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+ value |= (info->var.left_margin - 1);
+ dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value);
+ lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+ /* Display size */
+ value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+ value |= info->var.yres - 1;
+ lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+ /* FIFO Threshold: Use formula from data sheet */
+ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+ lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+ /* Toggle LCD_MODE every frame */
+ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+ /* Disable all interrupts */
+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+ /* Set contrast */
+ value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
+ /* ...wait for DMA engine to become idle... */
+ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+ msleep(10);
+
+ dev_dbg(info->device, " * re-enable DMA engine\n");
+ /* ...and enable it with updated configuration */
+ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+
+ dev_dbg(info->device, " * re-enable LCDC core\n");
+ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+ (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+
+ dev_dbg(info->device, " * DONE\n");
+
+ return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan, const struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+/**
+ * atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+ * @regno: Which register in the CLUT we are programming
+ * @red: The red value which can be up to 16 bits wide
+ * @green: The green value which can be up to 16 bits wide
+ * @blue: The blue value which can be up to 16 bits wide.
+ * @transp: If supported the alpha value which can be up to 16 bits wide.
+ * @info: frame buffer info structure
+ *
+ * Set a single color register. The values supplied have a 16 bit
+ * magnitude which needs to be scaled in this function for the hardware.
+ * Things to take into consideration are how many color registers, if
+ * any, are supported with the current color visual. With truecolor mode
+ * no color palettes are supported. Here a psuedo palette is created
+ * which we store the value in pseudo_palette in struct fb_info. For
+ * pseudocolor mode we have a limited color palette. To deal with this
+ * we can program what color is displayed for a particular pixel value.
+ * DirectColor is similar in that we can program each color field. If
+ * we have a static colormap we don't need to implement this function.
+ *
+ * Returns negative errno on error, or zero on success. In an
+ * ideal world, this would have been the case, but as it turns
+ * out, the other drivers return 1 on failure, so that's what
+ * we're going to do.
+ */
+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+ unsigned int green, unsigned int blue,
+ unsigned int transp, struct fb_info *info)
+{
+ struct atmel_lcdfb_info *sinfo = info->par;
+ unsigned int val;
+ u32 *pal;
+ int ret = 1;
+
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green
+ + 7471 * blue) >> 16;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ if (regno < 16) {
+ pal = info->pseudo_palette;
+
+ val = chan_to_field(red, &info->var.red);
+ val |= chan_to_field(green, &info->var.green);
+ val |= chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_PSEUDOCOLOR:
+ if (regno < 256) {
+ val = ((red >> 11) & 0x001f);
+ val |= ((green >> 6) & 0x03e0);
+ val |= ((blue >> 1) & 0x7c00);
+
+ /*
+ * TODO: intensity bit. Maybe something like
+ * ~(red[10] ^ green[10] ^ blue[10]) & 1
+ */
+
+ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+ ret = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ dev_dbg(info->device, "%s\n", __func__);
+
+ atmel_lcdfb_update_dma(info, var);
+
+ return 0;
+}
+
+static struct fb_ops atmel_lcdfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = atmel_lcdfb_check_var,
+ .fb_set_par = atmel_lcdfb_set_par,
+ .fb_setcolreg = atmel_lcdfb_setcolreg,
+ .fb_pan_display = atmel_lcdfb_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+{
+ struct fb_info *info = dev_id;
+ struct atmel_lcdfb_info *sinfo = info->par;
+ u32 status;
+
+ status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+ lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
+ return IRQ_HANDLED;
+}
+
+static int __init atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+{
+ struct fb_info *info = sinfo->info;
+ int ret = 0;
+
+ memset_io(info->screen_base, 0, info->fix.smem_len);
+ info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+
+ dev_info(info->device,
+ "%luKiB frame buffer at %08lx (mapped at %p)\n",
+ (unsigned long)info->fix.smem_len / 1024,
+ (unsigned long)info->fix.smem_start,
+ info->screen_base);
+
+ /* Allocate colormap */
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret < 0)
+ dev_err(info->device, "Alloc color map failed\n");
+
+ return ret;
+}
+
+static void atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+ if (sinfo->bus_clk)
+ clk_enable(sinfo->bus_clk);
+ clk_enable(sinfo->lcdc_clk);
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+ if (sinfo->bus_clk)
+ clk_disable(sinfo->bus_clk);
+ clk_disable(sinfo->lcdc_clk);
+}
+
+
+static int __init atmel_lcdfb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct fb_info *info;
+ struct atmel_lcdfb_info *sinfo;
+ struct atmel_lcdfb_info *pdata_sinfo;
+ struct resource *regs = NULL;
+ struct resource *map = NULL;
+ int ret;
+
+ dev_dbg(dev, "%s BEGIN\n", __func__);
+
+ ret = -ENOMEM;
+ info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+ if (!info) {
+ dev_err(dev, "cannot allocate memory\n");
+ goto out;
+ }
+
+ sinfo = info->par;
+
+ if (dev->platform_data) {
+ pdata_sinfo = (struct atmel_lcdfb_info *)dev->platform_data;
+ sinfo->default_bpp = pdata_sinfo->default_bpp;
+ sinfo->default_dmacon = pdata_sinfo->default_dmacon;
+ sinfo->default_lcdcon2 = pdata_sinfo->default_lcdcon2;
+ sinfo->default_monspecs = pdata_sinfo->default_monspecs;
+ sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control;
+ sinfo->guard_time = pdata_sinfo->guard_time;
+ } else {
+ dev_err(dev, "cannot get default configuration\n");
+ goto free_info;
+ }
+ sinfo->info = info;
+ sinfo->pdev = pdev;
+
+ strcpy(info->fix.id, sinfo->pdev->name);
+ info->flags = ATMEL_LCDFB_FBINFO_DEFAULT;
+ info->pseudo_palette = sinfo->pseudo_palette;
+ info->fbops = &atmel_lcdfb_ops;
+
+ memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+ info->fix = atmel_lcdfb_fix;
+
+ /* Enable LCDC Clocks */
+ if (cpu_is_at91sam9261() || cpu_is_at32ap7000()) {
+ sinfo->bus_clk = clk_get(dev, "hck1");
+ if (IS_ERR(sinfo->bus_clk)) {
+ ret = PTR_ERR(sinfo->bus_clk);
+ goto free_info;
+ }
+ }
+ sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+ if (IS_ERR(sinfo->lcdc_clk)) {
+ ret = PTR_ERR(sinfo->lcdc_clk);
+ goto put_bus_clk;
+ }
+ atmel_lcdfb_start_clock(sinfo);
+
+ ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+ info->monspecs.modedb_len, info->monspecs.modedb,
+ sinfo->default_bpp);
+ if (!ret) {
+ dev_err(dev, "no suitable video mode found\n");
+ goto stop_clk;
+ }
+
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(dev, "resources unusable\n");
+ ret = -ENXIO;
+ goto stop_clk;
+ }
+
+ sinfo->irq_base = platform_get_irq(pdev, 0);
+ if (sinfo->irq_base < 0) {
+ dev_err(dev, "unable to get irq\n");
+ ret = sinfo->irq_base;
+ goto stop_clk;
+ }
+
+ /* Initialize video memory */
+ map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (map) {
+ /* use a pre-allocated memory buffer */
+ info->fix.smem_start = map->start;
+ info->fix.smem_len = map->end - map->start + 1;
+ if (!request_mem_region(info->fix.smem_start,
+ info->fix.smem_len, pdev->name)) {
+ ret = -EBUSY;
+ goto stop_clk;
+ }
+
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+ if (!info->screen_base)
+ goto release_intmem;
+ } else {
+ /* alocate memory buffer */
+ ret = atmel_lcdfb_alloc_video_memory(sinfo);
+ if (ret < 0) {
+ dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+ goto stop_clk;
+ }
+ }
+
+ /* LCDC registers */
+ info->fix.mmio_start = regs->start;
+ info->fix.mmio_len = regs->end - regs->start + 1;
+
+ if (!request_mem_region(info->fix.mmio_start,
+ info->fix.mmio_len, pdev->name)) {
+ ret = -EBUSY;
+ goto free_fb;
+ }
+
+ sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+ if (!sinfo->mmio) {
+ dev_err(dev, "cannot map LCDC registers\n");
+ goto release_mem;
+ }
+
+ /* interrupt */
+ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+ if (ret) {
+ dev_err(dev, "request_irq failed: %d\n", ret);
+ goto unmap_mmio;
+ }
+
+ ret = atmel_lcdfb_init_fbinfo(sinfo);
+ if (ret < 0) {
+ dev_err(dev, "init fbinfo failed: %d\n", ret);
+ goto unregister_irqs;
+ }
+
+ /*
+ * This makes sure that our colour bitfield
+ * descriptors are correctly initialised.
+ */
+ atmel_lcdfb_check_var(&info->var, info);
+
+ ret = fb_set_var(info, &info->var);
+ if (ret) {
+ dev_warn(dev, "unable to set display parameters\n");
+ goto free_cmap;
+ }
+
+ dev_set_drvdata(dev, info);
+
+ /*
+ * Tell the world that we're ready to go
+ */
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+ goto free_cmap;
+ }
+
+ /* Power up the LCDC screen */
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(1);
+
+ dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+ info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+
+ return 0;
+
+
+free_cmap:
+ fb_dealloc_cmap(&info->cmap);
+unregister_irqs:
+ free_irq(sinfo->irq_base, info);
+unmap_mmio:
+ iounmap(sinfo->mmio);
+release_mem:
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+free_fb:
+ if (map)
+ iounmap(info->screen_base);
+ else
+ atmel_lcdfb_free_video_memory(sinfo);
+
+release_intmem:
+ if (map)
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+stop_clk:
+ atmel_lcdfb_stop_clock(sinfo);
+ clk_put(sinfo->lcdc_clk);
+put_bus_clk:
+ if (sinfo->bus_clk)
+ clk_put(sinfo->bus_clk);
+free_info:
+ framebuffer_release(info);
+out:
+ dev_dbg(dev, "%s FAILED\n", __func__);
+ return ret;
+}
+
+static int __exit atmel_lcdfb_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct atmel_lcdfb_info *sinfo = info->par;
+
+ if (!sinfo)
+ return 0;
+
+ if (sinfo->atmel_lcdfb_power_control)
+ sinfo->atmel_lcdfb_power_control(0);
+ unregister_framebuffer(info);
+ atmel_lcdfb_stop_clock(sinfo);
+ clk_put(sinfo->lcdc_clk);
+ if (sinfo->bus_clk)
+ clk_put(sinfo->bus_clk);
+ fb_dealloc_cmap(&info->cmap);
+ free_irq(sinfo->irq_base, info);
+ iounmap(sinfo->mmio);
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+ if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+ iounmap(info->screen_base);
+ release_mem_region(info->fix.smem_start, info->fix.smem_len);
+ } else {
+ atmel_lcdfb_free_video_memory(sinfo);
+ }
+
+ dev_set_drvdata(dev, NULL);
+ framebuffer_release(info);
+
+ return 0;
+}
+
+static struct platform_driver atmel_lcdfb_driver = {
+ .remove = __exit_p(atmel_lcdfb_remove),
+ .driver = {
+ .name = "atmel_lcdfb",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init atmel_lcdfb_init(void)
+{
+ return platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe);
+}
+
+static void __exit atmel_lcdfb_exit(void)
+{
+ platform_driver_unregister(&atmel_lcdfb_driver);
+}
+
+module_init(atmel_lcdfb_init);
+module_exit(atmel_lcdfb_exit);
+
+MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_AUTHOR("Nicolas Ferre <nicolas.ferre@rfo.atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index aa3935d..63b85bf 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -19,13 +19,6 @@
Say Y.
-# if [ "$CONFIG_PCI" = "y" -a "$CONFIG_VGA_CONSOLE" = "y" ]; then
-# bool ' Allow VGA on any bus?' CONFIG_VGA_HOSE
-# if [ "$CONFIG_VGA_HOSE" = "y" ]; then
-# define_bool CONFIG_DUMMY_CONSOLE y
-# fi
-# fi
-
config VGACON_SOFT_SCROLLBACK
bool "Enable Scrollback Buffer in System RAM"
depends on VGA_CONSOLE
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index c627955..aff11bb 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -149,7 +149,9 @@
pll = NV_RD32(par->PMC, 0x4024);
M = pll & 0xFF;
N = (pll >> 8) & 0xFF;
- if (((par->Chipset & 0xfff0) == 0x0290) || ((par->Chipset & 0xfff0) == 0x0390) || ((par->Chipset & 0xfff0) == 0x02E0)) {
+ if (((par->Chipset & 0xfff0) == 0x0290) ||
+ ((par->Chipset & 0xfff0) == 0x0390) ||
+ ((par->Chipset & 0xfff0) == 0x02E0)) {
MB = 1;
NB = 1;
} else {
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index f85edf0..41f6365 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -37,7 +37,6 @@
#include "nv_proto.h"
#include "nv_dma.h"
-#undef CONFIG_FB_NVIDIA_DEBUG
#ifdef CONFIG_FB_NVIDIA_DEBUG
#define NVTRACE printk
#else
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 1ac5264..ab5e668 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -204,17 +204,6 @@
}
#endif
-static void wait_pm2(struct pm2fb_par* par) {
-
- WAIT_FIFO(par, 1);
- pm2_WR(par, PM2R_SYNC, 0);
- mb();
- do {
- while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0);
- rmb();
- } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
-}
-
/*
* partial products for the supported horizontal resolutions.
*/
@@ -1050,13 +1039,30 @@
return 0;
}
+static int pm2fb_sync(struct fb_info *info)
+{
+ struct pm2fb_par *par = info->par;
+
+ WAIT_FIFO(par, 1);
+ pm2_WR(par, PM2R_SYNC, 0);
+ mb();
+ do {
+ while (pm2_RD(par, PM2R_OUT_FIFO_WORDS) == 0)
+ udelay(10);
+ rmb();
+ } while (pm2_RD(par, PM2R_OUT_FIFO) != PM2TAG(PM2R_SYNC));
+
+ return 0;
+}
+
/*
* block operation. copy=0: rectangle fill, copy=1: rectangle copy.
*/
-static void pm2fb_block_op(struct pm2fb_par* par, int copy,
+static void pm2fb_block_op(struct fb_info* info, int copy,
s32 xsrc, s32 ysrc,
s32 x, s32 y, s32 w, s32 h,
u32 color) {
+ struct pm2fb_par *par = info->par;
if (!w || !h)
return;
@@ -1076,13 +1082,11 @@
(x<xsrc ? PM2F_INCREASE_X : 0) |
(y<ysrc ? PM2F_INCREASE_Y : 0) |
(copy ? 0 : PM2F_RENDER_FASTFILL));
- wait_pm2(par);
}
static void pm2fb_fillrect (struct fb_info *info,
const struct fb_fillrect *region)
{
- struct pm2fb_par *par = info->par;
struct fb_fillrect modded;
int vxres, vyres;
u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
@@ -1116,7 +1120,7 @@
color |= color << 16;
if(info->var.bits_per_pixel != 24)
- pm2fb_block_op(par, 0, 0, 0,
+ pm2fb_block_op(info, 0, 0, 0,
modded.dx, modded.dy,
modded.width, modded.height, color);
else
@@ -1126,7 +1130,6 @@
static void pm2fb_copyarea(struct fb_info *info,
const struct fb_copyarea *area)
{
- struct pm2fb_par *par = info->par;
struct fb_copyarea modded;
u32 vxres, vyres;
@@ -1156,7 +1159,7 @@
if(modded.dy + modded.height > vyres)
modded.height = vyres - modded.dy;
- pm2fb_block_op(par, 1, modded.sx, modded.sy,
+ pm2fb_block_op(info, 1, modded.sx, modded.sy,
modded.dx, modded.dy,
modded.width, modded.height, 0);
}
@@ -1177,6 +1180,7 @@
.fb_fillrect = pm2fb_fillrect,
.fb_copyarea = pm2fb_copyarea,
.fb_imageblit = cfb_imageblit,
+ .fb_sync = pm2fb_sync,
};
/*
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index bd787e8..6c4dfcb0 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -1,55 +1,25 @@
/*
* linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
- *
- * Copyright (C) 2001 Romain Dolbeau <dolbeau@irisa.fr>
+ *
+ * Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
+ *
+ * Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
+ * based on pm2fb.c
+ *
* Based on code written by:
- * Sven Luther, <luther@dpt-info.u-strasbg.fr>
- * Alan Hourihane, <alanh@fairlite.demon.co.uk>
- * Russell King, <rmk@arm.linux.org.uk>
+ * Sven Luther, <luther@dpt-info.u-strasbg.fr>
+ * Alan Hourihane, <alanh@fairlite.demon.co.uk>
+ * Russell King, <rmk@arm.linux.org.uk>
* Based on linux/drivers/video/skeletonfb.c:
* Copyright (C) 1997 Geert Uytterhoeven
* Based on linux/driver/video/pm2fb.c:
- * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
- * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
+ * Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
- * $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
- * CHANGELOG:
- * Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
- * Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
- * Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
- * Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
- * Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
- * Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
- * Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
- * Wed Jun 20 11:13:08 MET DST 2001, v 1.4.5: Fixed missing blinking cursor in 8bpp, code cleaning, memory erase IOCTL.
- * Mon Jun 18 16:00:27 CEST 2001, v 1.4.4: Depth 12 (RGBA 4444) support, code cleaning.
- * Fri Jun 15 13:53:01 CEST 2001, v 1.4.3: Removed warnings, depth 15 support, add 'depth' option.
- * Thu Jun 14 10:13:52 MET DST 2001, v 1.4.2: Fixed depth switching bug, preliminary 15bpp (RGB5551) support.
- * Thu Apr 12 11:16:45 MET DST 2001, v 1.4.1B: Doc updates.
- * Fri Apr 6 11:12:53 MET DST 2001, v 1.4.1: Configure.help, minor cleanup
- * Thu Mar 29 10:56:50 MET DST 2001, v 1.4.0: Module & module options support (note: linux patch changed, 2.2.19 added).
- * Thu Mar 15 15:30:31 MET 2001, v 1.3.2: Fixed mirroring bug on little-endian.
- * Wed Mar 14 21:25:54 CET 2001, v 1.3.1: Fixed bug in BlockMove (_bmov).
- * Tue Mar 13 10:53:19 MET 2001, v 1.3.0: Character drawing hardware support (in all width between 1 and 16), fixes.
- * Thu Mar 8 10:20:16 MET 2001, v 1.2.2: Better J2000 support, "font:" option.
- * Tue Mar 6 21:25:04 CET 2001, v 1.2.1: Better acceleration support.
- * Mon Mar 5 21:54:17 CET 2001, v 1.2.0: Partial acceleration support (clear & bmove)
- * Mon Mar 5 12:52:15 CET 2001, v 1.1.3: Big pan_display fix.
- * Sun Mar 4 22:21:50 CET 2001, v 1.1.2: (numerous) bug fixes.
- * Fri Mar 2 15:54:07 CET 2001, v 1.1.1: Might have Appian J2000 support, resource mangement in 2.4
- * Wed Feb 28 18:21:35 CET 2001, v 1.1.0: Might have multiple boards support (added, but not yest tested)
- * Tue Feb 27 17:31:12 CET 2001, v 1.0.6: fixes boot-time mode select, add more default mode
- * Tue Feb 27 14:01:36 CET 2001, v 1.0.5: fixes (1.0.4 was broken for 2.2), cleaning up
- * Mon Feb 26 23:17:36 CET 2001, v 1.0.4: preliminary 2.4.x support, dropped (useless on pm3) partial product, more OF fix
- * Mon Feb 26 20:59:05 CET 2001, v 1.0.3: No more shadow register (and wasted memory), endianess fix, use OF-preset resolution by default
- * Wed Feb 21 22:09:30 CET 2001, v 1.0.2: Code cleaning for future multiboard support, better OF support, bugs fix
- * Wed Feb 21 19:58:56 CET 2001, v 1.0.1: OpenFirmware support, fixed memory detection, better debug support, code cleaning
- * Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
*/
#include <linux/module.h>
@@ -58,856 +28,155 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/ctype.h>
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
#include <video/pm3fb.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_FB_OF
-#include <asm/prom.h>
+#if !defined(CONFIG_PCI)
+#error "Only generic PCI cards supported."
#endif
-/* ************************************* */
-/* ***** The various "global" data ***** */
-/* ************************************* */
+#undef PM3FB_MASTER_DEBUG
+#ifdef PM3FB_MASTER_DEBUG
+#define DPRINTK(a,b...) printk(KERN_DEBUG "pm3fb: %s: " a, __FUNCTION__ , ## b)
+#else
+#define DPRINTK(a,b...)
+#endif
-/* those will need a rework for multiple board support */
-/* Driver name */
-static const char permedia3_name[16] = "Permedia3";
+/*
+ * Driver data
+ */
+static char *mode_option __devinitdata;
-/* the fb_par struct, mandatory */
-struct pm3fb_par {
- u32 pixclock; /* pixclock in KHz */
+/*
+ * If your driver supports multiple boards, you should make the
+ * below data types arrays, or allocate them dynamically (using kmalloc()).
+ */
- u32 width; /* width of virtual screen */
- u32 height; /* height of virtual screen */
-
- u32 hsstart; /* horiz. sync start */
- u32 hsend; /* horiz. sync end */
- u32 hbend; /* horiz. blank end (also gate end) */
- u32 htotal; /* total width (w/ sync & blank) */
-
- u32 vsstart; /* vert. sync start */
- u32 vsend; /* vert. sync end */
- u32 vbend; /* vert. blank end */
- u32 vtotal; /* total height (w/ sync & blank) */
-
- u32 stride; /* screen stride */
- u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */
- /* NOTE : unlike other pm3 stuff above, stored *after* shiftbpp. don't ask */
- u32 depth; /* screen depth (8, 12, 15, 16 or 32) */
- u32 video; /* video control (hsync,vsync) */
+/*
+ * This structure defines the hardware state of the graphics card. Normally
+ * you place this in a header file in linux/include/video. This file usually
+ * also includes register information. That allows other driver subsystems
+ * and userland applications the ability to use the same header file to
+ * avoid duplicate work and easy porting of software.
+ */
+struct pm3_par {
+ unsigned char __iomem *v_regs;/* virtual address of p_regs */
+ u32 video; /* video flags before blanking */
+ u32 base; /* screen base (xoffset+yoffset) in 128 bits unit */
+ u32 palette[16];
};
-/* memory timings */
-struct pm3fb_timings
+/*
+ * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
+ * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
+ * to get a fb_var_screeninfo. Otherwise define a default var as well.
+ */
+static struct fb_fix_screeninfo pm3fb_fix __devinitdata = {
+ .id = "Permedia3",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .xpanstep = 1,
+ .ypanstep = 1,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+/*
+ * Utility functions
+ */
+
+static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
{
- unsigned long caps;
- unsigned long timings;
- unsigned long control;
- unsigned long refresh;
- unsigned long powerdown;
-};
-typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
-#define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
-#define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
-
-/* the fb_info struct, mandatory */
-struct pm3fb_info {
- struct fb_info_gen gen;
- unsigned long board_num; /* internal board number */
- unsigned long use_current;
- struct pm3fb_par *current_par;
- struct pci_dev *dev; /* PCI device */
- unsigned long board_type; /* index in the cardbase */
- unsigned char *fb_base; /* framebuffer memory base */
- u32 fb_size; /* framebuffer memory size */
- unsigned char *p_fb; /* physical address of frame buffer */
- unsigned char *v_fb; /* virtual address of frame buffer */
- unsigned char *pIOBase; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */
- unsigned char *vIOBase; /* address of registers after ioremap() */
- struct {
- u8 transp;
- u8 red;
- u8 green;
- u8 blue;
- } palette[256];
- union {
-#ifdef FBCON_HAS_CFB16
- u16 cmap12[16]; /* RGBA 4444 */
- u16 cmap15[16]; /* RGBA 5551 */
- u16 cmap16[16]; /* RGBA 5650 */
-#endif
-#ifdef FBCON_HAS_CFB32
- u32 cmap32[16];
-#endif
- } cmap;
- struct pm3fb_timings memt;
-};
-
-/* regular resolution database*/
-static struct {
- char name[16];
- struct pm3fb_par user_mode;
-} mode_base[] __initdata = {
- {
- "default-800x600", {
- 49500, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}}, {
- "1024x768-74", {
- 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
- 806, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}}, {
- "1024x768-74-32", {
- 78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
- 806, 1024, 0, 32,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_32BIT}},
-/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
- {
- "SGI1600SW", {
- 108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
- 1056, 1600, 0, 8,
- PM3VideoControl_ENABLE|
- PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
- PM3VideoControl_PIXELSIZE_32BIT}},
-/* ##### auto-generated mode, by fbtimings2pm3 */
-/* Generated mode : "640x480-60" */
- {
- "640x480-60", {
- 25174, 640, 480, 16, 112, 160, 800, 10, 12, 45,
- 525, 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-72" */
- {
- "640x480-72", {
- 31199, 640, 480, 24, 64, 192, 832, 9, 12, 40, 520,
- 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-75" */
- {
- "640x480-75", {
- 31499, 640, 480, 16, 80, 200, 840, 1, 4, 20, 500,
- 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-90" */
- {
- "640x480-90", {
- 39909, 640, 480, 32, 72, 192, 832, 25, 39, 53, 533,
- 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "640x480-100" */
- {
- "640x480-100", {
- 44899, 640, 480, 32, 160, 208, 848, 22, 34, 51,
- 531, 640, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-48-lace" */
-/* INTERLACED NOT SUPPORTED
- {"800x600-48-lace", {35999, 800, 600, 80, 208, 264, 1064, 11, 23, 102, 702, 800, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "800x600-56" */
- {
- "800x600-56", {
- 35999, 800, 600, 24, 96, 224, 1024, 1, 3, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-60" */
- {
- "800x600-60", {
- 40000, 800, 600, 40, 168, 256, 1056, 1, 5, 28, 628,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-70" */
- {
- "800x600-70", {
- 44899, 800, 600, 24, 168, 208, 1008, 9, 21, 36,
- 636, 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-72" */
- {
- "800x600-72", {
- 50000, 800, 600, 56, 176, 240, 1040, 37, 43, 66,
- 666, 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-75" */
- {
- "800x600-75", {
- 49497, 800, 600, 16, 96, 256, 1056, 1, 4, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-90" */
- {
- "800x600-90", {
- 56637, 800, 600, 8, 72, 192, 992, 8, 19, 35, 635,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "800x600-100", from /etc/fb.modes */
-/* DISABLED, hsstart == 0
- {
- "800x600-100", {
- 67499, 800, 600, 0, 64, 280, 1080, 7, 11, 25, 625,
- 800, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "800x600-100", from ??? */
- {
- "800x600-100", {
- 69650, 800, 600, 64, 128, 288, 1088, 4, 10, 40, 640, 800, 0, 8,
- PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
- PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-43-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1024x768-43-lace", {44899, 1024, 768, 8, 184, 240, 1264, 1, 9, 49, 817, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1024x768-60" */
- {
- "1024x768-60", {
- 64998, 1024, 768, 24, 160, 320, 1344, 3, 9, 38,
- 806, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-70" */
- {
- "1024x768-70", {
- 74996, 1024, 768, 24, 160, 304, 1328, 3, 9, 38,
- 806, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-72" */
- {
- "1024x768-72", {
- 74996, 10224, 768, 24, 160, 264, 10488, 3, 9, 38,
- 806, 10224, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-75" */
- {
- "1024x768-75", {
- 78746, 1024, 768, 16, 112, 288, 1312, 1, 4, 32,
- 800, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-90" */
- {
- "1024x768-90", {
- 100000, 1024, 768, 0, 96, 288, 1312, 21, 36, 77,
- 845, 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1024x768-100", from /etc/fb.modes */
-/* DISABLED, vsstart == 0
- {
- "1024x768-100", {
- 109998, 1024, 768, 0, 88, 368, 1392, 0, 8, 24, 792,
- 1024, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-*/
-/* Generated mode : "1024x768-100", from ??? */
- {
- "1024x768-100", {
- 115500, 1024, 768, 32, 224, 416, 1440, 3, 13, 34, 802, 1024, 0, 8,
- PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_LOW|
- PM3VideoControl_VSYNC_ACTIVE_LOW|PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-43-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1152x864-43-lace", {64998, 1152, 864, 72, 200, 264, 1416, 78, 87, 191, 1055, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-47-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1152x864-47-lace", {64998, 1152, 864, 88, 216, 296, 1448, 30, 39, 83, 947, 1152, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1152x864-60" */
- {
- "1152x864-60", {
- 80000, 1152, 864, 64, 176, 304, 1456, 6, 11, 52,
- 916, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-70" */
- {
- "1152x864-70", {
- 100000, 1152, 864, 40, 192, 360, 1512, 13, 24, 81,
- 945, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-75" */
- {
- "1152x864-75", {
- 109998, 1152, 864, 24, 168, 312, 1464, 45, 53, 138,
- 1002, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1152x864-80" */
- {
- "1152x864-80", {
- 109998, 1152, 864, 16, 128, 288, 1440, 30, 37, 94,
- 958, 1152, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-43-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1280x1024-43-lace", {80000, 1024, 1024, 80, 160, 320, 1344, 50, 60, 125, 1149, 1024, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-47-lace" */
-/* INTERLACED NOT SUPPORTED
- {"1280x1024-47-lace", {80000, 1280, 1024, 80, 160, 320, 1600, 1, 11, 29, 1053, 1280, 0, 8, PM3VideoControl_ENABLE|PM3VideoControl_HSYNC_ACTIVE_HIGH|PM3VideoControl_VSYNC_ACTIVE_HIGH|PM3VideoControl_PIXELSIZE_8BIT}},
- INTERLACED NOT SUPPORTED */
-/* Generated mode : "1280x1024-60" */
- {
- "1280x1024-60", {
- 107991, 1280, 1024, 48, 160, 408, 1688, 1, 4, 42,
- 1066, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-70" */
- {
- "1280x1024-70", {
- 125992, 1280, 1024, 80, 192, 408, 1688, 1, 6, 42,
- 1066, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-74" */
- {
- "1280x1024-74", {
- 134989, 1280, 1024, 32, 176, 432, 1712, 0, 30, 40,
- 1064, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1280x1024-75" */
- {
- "1280x1024-75", {
- 134989, 1280, 1024, 16, 160, 408, 1688, 1, 4, 42,
- 1066, 1280, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_HIGH
- |
- PM3VideoControl_VSYNC_ACTIVE_HIGH
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-60" */
- {
- "1600x1200-60", {
- 155981, 1600, 1200, 32, 192, 448, 2048, 10, 18, 70,
- 1270, 1600, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-66" */
- {
- "1600x1200-66", {
- 171998, 1600, 1200, 40, 176, 480, 2080, 3, 6, 53,
- 1253, 1600, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* Generated mode : "1600x1200-76" */
- {
- "1600x1200-76", {
- 197980, 1600, 1200, 40, 176, 480, 2080, 3, 8, 50,
- 1250, 1600, 0, 8,
- PM3VideoControl_ENABLE |
- PM3VideoControl_HSYNC_ACTIVE_LOW
- |
- PM3VideoControl_VSYNC_ACTIVE_LOW
- | PM3VideoControl_PIXELSIZE_8BIT}},
-/* ##### end of auto-generated mode */
- {
- "\0",}
-};
-
-/* more mandatory stuff (see skeletonfb.c + framebuffer driver HOWTO */
-static struct pm3fb_info fb_info[PM3_MAX_BOARD];
-static struct pm3fb_par current_par[PM3_MAX_BOARD];
-static int current_par_valid[PM3_MAX_BOARD];
-/* to allow explicit filtering of board */
-short bus[PM3_MAX_BOARD];
-short slot[PM3_MAX_BOARD];
-short func[PM3_MAX_BOARD];
-short disable[PM3_MAX_BOARD];
-short noaccel[PM3_MAX_BOARD];
-char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
-short depth[PM3_MAX_BOARD];
-short flatpanel[PM3_MAX_BOARD];
-static struct display disp[PM3_MAX_BOARD];
-static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
-short printtimings = 0;
-short forcesize[PM3_MAX_BOARD];
-
-/* ********************* */
-/* ***** prototype ***** */
-/* ********************* */
-/* card-specific */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
-/* permedia3-specific */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
- unsigned long r);
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */
- unsigned long refclock, /* In kHz units */
- unsigned char *prescale, /* ClkPreScale */
- unsigned char *feedback, /* ClkFeedBackScale */
- unsigned char *postscale
- /* ClkPostScale */ );
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc);
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b);
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info);
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v);
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v);
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info);
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info);
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info);
-#endif
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info);
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info);
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
- struct pm3fb_par *curpar);
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info);
-/* accelerated permedia3-specific */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info);
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info);
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width);
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width);
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width);
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only);
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
- int sy, int sx,
- int dy, int dx, int height, int width);
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
- int c, int yy, int xx);
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy,
- int xx);
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy);
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* pre-init */
-static void pm3fb_mode_setup(char *mode, unsigned long board_num);
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num);
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn);
-static void pm3fb_real_setup(char *options);
-/* fbdev */
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
- const void *par, struct fb_info_gen *info);
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
- void *par, struct fb_info_gen *info);
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d);
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
- const void *par, struct fb_info_gen *info);
-static void pm3fb_get_par(void *par, struct fb_info_gen *info);
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info);
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
- unsigned char regno, unsigned char r,
- unsigned char g, unsigned char b);
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *info);
-static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info);
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info);
-static void pm3fb_set_disp(const void *par, struct display *disp,
- struct fb_info_gen *info);
-static void pm3fb_detect(void);
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
- struct fb_info_gen *info);
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
-
-
-/* the struct that hold them together */
-struct fbgen_hwswitch pm3fb_switch = {
- pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
- pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg,
- pm3fb_pan_display, pm3fb_blank, pm3fb_set_disp
-};
-
-static struct fb_ops pm3fb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = fbgen_get_fix,
- .fb_get_var = fbgen_get_var,
- .fb_set_var = fbgen_set_var,
- .fb_get_cmap = fbgen_get_cmap,
- .fb_set_cmap = fbgen_set_cmap,
- .fb_setcolreg = pm3fb_setcolreg,
- .fb_pan_display =fbgen_pan_display,
- .fb_blank = fbgen_blank,
- .fb_ioctl = pm3fb_ioctl,
-};
-
-#ifdef PM3FB_USE_ACCEL
-#ifdef FBCON_HAS_CFB32
-static struct display_switch pm3fb_cfb32 = {
- fbcon_cfb32_setup, pm3fb_cfbX_bmove, pm3fb_cfb32_clear,
- pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
- NULL /* cursor() */ , NULL /* set_font() */ ,
- pm3fb_cfb32_clear_margins,
- FONTWIDTHRANGE(1, 16) /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static struct display_switch pm3fb_cfb16 = {
- fbcon_cfb16_setup, pm3fb_cfbX_bmove, pm3fb_cfb16_clear,
- pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
- NULL /* cursor() */ , NULL /* set_font() */ ,
- pm3fb_cfb16_clear_margins,
- FONTWIDTHRANGE(1, 16) /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static struct display_switch pm3fb_cfb8 = {
- fbcon_cfb8_setup, pm3fb_cfbX_bmove, pm3fb_cfb8_clear,
- pm3fb_cfbX_putc, pm3fb_cfbX_putcs, pm3fb_cfbX_revc,
- NULL /* cursor() */ , NULL /* set_font() */ ,
- pm3fb_cfb8_clear_margins,
- FONTWIDTHRANGE(1, 16) /* true only if accelerated... */
-};
-#endif /* FBCON_HAS_CFB8 */
-#endif /* PM3FB_USE_ACCEL */
-
-/* ****************************** */
-/* ***** card-specific data ***** */
-/* ****************************** */
-struct pm3fb_card_timings {
- unsigned long memsize; /* 0 for last value (i.e. default) */
- struct pm3fb_timings memt;
-};
-
-static struct pm3fb_card_timings t_FormacProFormance3[] = {
- { 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
- { 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
-};
-
-static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
- { 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
- { 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
-};
-
-static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
- { 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
- { 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
-};
-
-static struct {
- char cardname[32]; /* recognized card name */
- u16 subvendor; /* subvendor of the card */
- u16 subdevice; /* subdevice of the card */
- u8 func; /* function of the card to which the extra init apply */
- void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
- struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
-} cardbase[] = {
- { "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
- { "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
- t_AppianJeronimo2000
- },
- { "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
- t_AppianJeronimo2000
- },
- { "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
- t_FormacProFormance3
- },
- { "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
- { "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
- t_3DLabsOxygenVX1
- },
- { "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
- { "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
- { "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
- { "\0", 0x0, 0x0, 0, NULL, NULL }
-};
-
-/* ********************************** */
-/* ***** card-specific function ***** */
-/* ********************************** */
-static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
-{ /* the appian j2000 require more initialization of the second head */
- /* l_fb_info must point to the _second_ head of the J2000 */
-
- DTRACE;
-
- l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
-
- pm3fb_write_memory_timings(l_fb_info);
+ return fb_readl(par->v_regs + off);
}
-/* *************************************** */
-/* ***** permedia3-specific function ***** */
-/* *************************************** */
-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
{
- l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
- l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
- l_fb_info->memt.control = PM3_READ_REG(PM3LocalMemControl);
- l_fb_info->memt.refresh = PM3_READ_REG(PM3LocalMemRefresh);
- l_fb_info->memt.powerdown = PM3_READ_REG(PM3LocalMemPowerDown);
+ fb_writel(v, par->v_regs + off);
+}
- if ((l_fb_info->memt.caps == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.timings == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.control == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.refresh == PM3FB_UNKNOWN_TIMING_VALUE) ||
- (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
- {
- printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
- return(pm3fb_try_memory_timings(l_fb_info));
+static inline void PM3_WAIT(struct pm3_par *par, u32 n)
+{
+ while (PM3_READ_REG(par, PM3InFIFOSpace) < n);
+}
+
+static inline void PM3_SLOW_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
+{
+ if (par->v_regs) {
+ mb();
+ PM3_WAIT(par, 1);
+ wmb();
+ PM3_WRITE_REG(par, off, v);
}
- return(pm3fb_timing_ok);
}
-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_SET_INDEX(struct pm3_par *par, unsigned index)
{
- if (cardbase[l_fb_info->board_type].c_memt)
- {
- int i = 0, done = 0;
- while (!done)
- {
- if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
- || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
- { /* will use the 0-sized timings by default */
- done = 1;
- l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
- printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
- l_fb_info->board_num,
- cardbase[l_fb_info->board_type].cardname,
- cardbase[l_fb_info->board_type].c_memt[i].memsize);
- pm3fb_write_memory_timings(l_fb_info);
- return(pm3fb_timing_retry);
- }
- i++;
- }
- } else
- return(pm3fb_timing_problem);
- return(pm3fb_timing_ok);
+ PM3_SLOW_WRITE_REG(par, PM3RD_IndexHigh, (index >> 8) & 0xff);
+ PM3_SLOW_WRITE_REG(par, PM3RD_IndexLow, index & 0xff);
}
-static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
{
- unsigned char m, n, p;
- unsigned long clockused;
-
- PM3_SLOW_WRITE_REG(PM3LocalMemCaps, l_fb_info->memt.caps);
- PM3_SLOW_WRITE_REG(PM3LocalMemTimings, l_fb_info->memt.timings);
- PM3_SLOW_WRITE_REG(PM3LocalMemControl, l_fb_info->memt.control);
- PM3_SLOW_WRITE_REG(PM3LocalMemRefresh, l_fb_info->memt.refresh);
- PM3_SLOW_WRITE_REG(PM3LocalMemPowerDown, l_fb_info->memt.powerdown);
-
- clockused =
- pm3fb_CalculateClock(l_fb_info, 2 * 105000, PM3_REF_CLOCK, &m,
- &n, &p);
-
- PM3_WRITE_DAC_REG(PM3RD_KClkPreScale, m);
- PM3_WRITE_DAC_REG(PM3RD_KClkFeedbackScale, n);
- PM3_WRITE_DAC_REG(PM3RD_KClkPostScale, p);
- PM3_WRITE_DAC_REG(PM3RD_KClkControl,
- PM3RD_KClkControl_STATE_RUN |
- PM3RD_KClkControl_SOURCE_PLL |
- PM3RD_KClkControl_ENABLE);
- PM3_WRITE_DAC_REG(PM3RD_MClkControl,
- PM3RD_MClkControl_STATE_RUN |
- PM3RD_MClkControl_SOURCE_KCLK |
- PM3RD_MClkControl_ENABLE);
- PM3_WRITE_DAC_REG(PM3RD_SClkControl,
- PM3RD_SClkControl_STATE_RUN |
- PM3RD_SClkControl_SOURCE_PCLK |
- PM3RD_SClkControl_ENABLE);
+ PM3_SET_INDEX(par, r);
+ wmb();
+ PM3_WRITE_REG(par, PM3RD_IndexedData, v);
}
-static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
- unsigned long r)
+static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
+ unsigned char r, unsigned char g, unsigned char b)
{
- DASSERT((l_fb_info->vIOBase != (unsigned char *) (-1)),
- "l_fb_info->vIOBase mapped in read dac reg\n");
- PM3_SET_INDEX(r);
- mb();
- return (PM3_READ_REG(PM3RD_IndexedData));
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, r);
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, g);
+ PM3_SLOW_WRITE_REG(par, PM3RD_PaletteData, b);
+}
+
+static void pm3fb_clear_colormap(struct pm3_par *par,
+ unsigned char r, unsigned char g, unsigned char b)
+{
+ int i;
+
+ for (i = 0; i < 256 ; i++) /* fill color map with white */
+ pm3fb_set_color(par, i, r, g, b);
+
}
/* Calculating various clock parameter */
-static unsigned long pm3fb_CalculateClock(struct pm3fb_info *l_fb_info, unsigned long reqclock, /* In kHz units */
- unsigned long refclock, /* In kHz units */
- unsigned char *prescale, /* ClkPreScale */
- unsigned char *feedback, /* ClkFeedBackScale */
- unsigned char *postscale
- /* ClkPostScale */ )
+static void pm3fb_calculate_clock(unsigned long reqclock,
+ unsigned char *prescale,
+ unsigned char *feedback,
+ unsigned char *postscale)
{
int f, pre, post;
unsigned long freq;
long freqerr = 1000;
- unsigned long actualclock = 0;
-
- DTRACE;
+ long currerr;
for (f = 1; f < 256; f++) {
for (pre = 1; pre < 256; pre++) {
for (post = 0; post < 5; post++) {
- freq =
- ((2 * refclock * f) /
- (pre * (1 << post)));
- if ((reqclock > freq - freqerr)
- && (reqclock < freq + freqerr)) {
- freqerr =
- (reqclock >
- freq) ? reqclock -
- freq : freq - reqclock;
+ freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
+ currerr = (reqclock > freq)
+ ? reqclock - freq
+ : freq - reqclock;
+ if (currerr < freqerr) {
+ freqerr = currerr;
*feedback = f;
*prescale = pre;
*postscale = post;
- actualclock = freq;
}
}
}
}
-
- return (actualclock);
}
-static int pm3fb_Shiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v)
+static inline int pm3fb_shift_bpp(unsigned long depth, int v)
{
- DTRACE;
-
switch (depth) {
case 8:
return (v >> 4);
@@ -918,181 +187,59 @@
case 32:
return (v >> 2);
}
- DPRINTK(1, "Unsupported depth %ld\n", depth);
- return (0);
-}
-
-static int pm3fb_Unshiftbpp(struct pm3fb_info *l_fb_info,
- unsigned long depth, int v)
-{
- DTRACE;
-
- switch (depth) {
- case 8:
- return (v << 4);
- case 12:
- case 15:
- case 16:
- return (v << 3);
- case 32:
- return (v << 2);
- }
- DPRINTK(1, "Unsupported depth %ld\n", depth);
- return (0);
-}
-
-static void pm3fb_mapIO(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- l_fb_info->vIOBase =
- ioremap((unsigned long) l_fb_info->pIOBase, PM3_REGS_SIZE);
- l_fb_info->v_fb =
- ioremap((unsigned long) l_fb_info->p_fb, l_fb_info->fb_size);
- DPRINTK(2, "IO mapping : IOBase %lx / %lx, fb %lx / %lx\n",
- (unsigned long) l_fb_info->pIOBase,
- (unsigned long) l_fb_info->vIOBase,
- (unsigned long) l_fb_info->p_fb,
- (unsigned long) l_fb_info->v_fb);
-}
-
-static void pm3fb_unmapIO(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- iounmap(l_fb_info->vIOBase);
- iounmap(l_fb_info->v_fb);
- l_fb_info->vIOBase = (unsigned char *) -1;
- l_fb_info->v_fb = (unsigned char *) -1;
-}
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-static void pm3fb_show_cur_mode(struct pm3fb_info *l_fb_info)
-{
- DPRINTK(2, "PM3Aperture0: 0x%08x\n", PM3_READ_REG(PM3Aperture0));
- DPRINTK(2, "PM3Aperture1: 0x%08x\n", PM3_READ_REG(PM3Aperture1));
- DPRINTK(2, "PM3ByAperture1Mode: 0x%08x\n",
- PM3_READ_REG(PM3ByAperture1Mode));
- DPRINTK(2, "PM3ByAperture2Mode: 0x%08x\n",
- PM3_READ_REG(PM3ByAperture2Mode));
- DPRINTK(2, "PM3ChipConfig: 0x%08x\n", PM3_READ_REG(PM3ChipConfig));
- DPRINTK(2, "PM3FIFODis: 0x%08x\n", PM3_READ_REG(PM3FIFODis));
- DPRINTK(2, "PM3HTotal: 0x%08x\n", PM3_READ_REG(PM3HTotal));
- DPRINTK(2, "PM3HbEnd: 0x%08x\n", PM3_READ_REG(PM3HbEnd));
- DPRINTK(2, "PM3HgEnd: 0x%08x\n", PM3_READ_REG(PM3HgEnd));
- DPRINTK(2, "PM3HsEnd: 0x%08x\n", PM3_READ_REG(PM3HsEnd));
- DPRINTK(2, "PM3HsStart: 0x%08x\n", PM3_READ_REG(PM3HsStart));
- DPRINTK(2, "PM3MemBypassWriteMask: 0x%08x\n",
- PM3_READ_REG(PM3MemBypassWriteMask));
- DPRINTK(2, "PM3RD_IndexControl: 0x%08x\n",
- PM3_READ_REG(PM3RD_IndexControl));
- DPRINTK(2, "PM3ScreenBase: 0x%08x\n", PM3_READ_REG(PM3ScreenBase));
- DPRINTK(2, "PM3ScreenStride: 0x%08x\n",
- PM3_READ_REG(PM3ScreenStride));
- DPRINTK(2, "PM3VClkCtl: 0x%08x\n", PM3_READ_REG(PM3VClkCtl));
- DPRINTK(2, "PM3VTotal: 0x%08x\n", PM3_READ_REG(PM3VTotal));
- DPRINTK(2, "PM3VbEnd: 0x%08x\n", PM3_READ_REG(PM3VbEnd));
- DPRINTK(2, "PM3VideoControl: 0x%08x\n",
- PM3_READ_REG(PM3VideoControl));
- DPRINTK(2, "PM3VsEnd: 0x%08x\n", PM3_READ_REG(PM3VsEnd));
- DPRINTK(2, "PM3VsStart: 0x%08x\n", PM3_READ_REG(PM3VsStart));
-
- DPRINTK(2, "PM3RD_ColorFormat: %ld\n",
- PM3_READ_DAC_REG(PM3RD_ColorFormat));
- DPRINTK(2, "PM3RD_DACControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DACControl));
- DPRINTK(2, "PM3RD_DClk0FeedbackScale: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale));
- DPRINTK(2, "PM3RD_DClk0PostScale: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DClk0PostScale));
- DPRINTK(2, "PM3RD_DClk0PreScale: %ld\n",
- PM3_READ_DAC_REG(PM3RD_DClk0PreScale));
- DPRINTK(2, "[not set] PM3RD_IndexControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_IndexControl));
- DPRINTK(2, "PM3RD_MiscControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_MiscControl));
- DPRINTK(2, "PM3RD_PixelSize: %ld\n",
- PM3_READ_DAC_REG(PM3RD_PixelSize));
- DPRINTK(2, "PM3RD_SyncControl: %ld\n",
- PM3_READ_DAC_REG(PM3RD_SyncControl));
-}
-
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2) */
-static void pm3fb_show_cur_timing(struct pm3fb_info *l_fb_info)
-{
- u16 subvendor, subdevice;
-
- if ((!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
- &&
- (!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
- /* well, nothing... */
- } else {
- subvendor = subdevice = (u16)-1;
- }
-
- printk(KERN_INFO "pm3fb: memory timings for board #%ld (subvendor: 0x%hx, subdevice: 0x%hx)\n", l_fb_info->board_num, subvendor, subdevice);
- printk(KERN_INFO " PM3LocalMemCaps: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemCaps));
- printk(KERN_INFO " PM3LocalMemTimings: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemTimings));
- printk(KERN_INFO " PM3LocalMemControl: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemControl));
- printk(KERN_INFO " PM3LocalMemRefresh: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemRefresh));
- printk(KERN_INFO " PM3LocalMemPowerDown: 0x%08x\n",
- PM3_READ_REG(PM3LocalMemPowerDown));
+ DPRINTK("Unsupported depth %ld\n", depth);
+ return 0;
}
/* write the mode to registers */
-static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+static void pm3fb_write_mode(struct fb_info *info)
{
+ struct pm3_par *par = info->par;
char tempsync = 0x00, tempmisc = 0x00;
- DTRACE;
+ const u32 hsstart = info->var.right_margin;
+ const u32 hsend = hsstart + info->var.hsync_len;
+ const u32 hbend = hsend + info->var.left_margin;
+ const u32 xres = (info->var.xres + 31) & ~31;
+ const u32 htotal = xres + hbend;
+ const u32 vsstart = info->var.lower_margin;
+ const u32 vsend = vsstart + info->var.vsync_len;
+ const u32 vbend = vsend + info->var.upper_margin;
+ const u32 vtotal = info->var.yres + vbend;
+ const u32 width = (info->var.xres_virtual + 7) & ~7;
- PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
- PM3_SLOW_WRITE_REG(PM3Aperture0, 0x00000000);
- PM3_SLOW_WRITE_REG(PM3Aperture1, 0x00000000);
- PM3_SLOW_WRITE_REG(PM3FIFODis, 0x00000007);
+ PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
+ PM3_SLOW_WRITE_REG(par, PM3Aperture0, 0x00000000);
+ PM3_SLOW_WRITE_REG(par, PM3Aperture1, 0x00000000);
+ PM3_SLOW_WRITE_REG(par, PM3FIFODis, 0x00000007);
- PM3_SLOW_WRITE_REG(PM3HTotal,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->htotal -
- 1));
- PM3_SLOW_WRITE_REG(PM3HsEnd,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->hsend));
- PM3_SLOW_WRITE_REG(PM3HsStart,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->
+ PM3_SLOW_WRITE_REG(par, PM3HTotal,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ htotal - 1));
+ PM3_SLOW_WRITE_REG(par, PM3HsEnd,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ hsend));
+ PM3_SLOW_WRITE_REG(par, PM3HsStart,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
hsstart));
- PM3_SLOW_WRITE_REG(PM3HbEnd,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->hbend));
- PM3_SLOW_WRITE_REG(PM3HgEnd,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->hbend));
- PM3_SLOW_WRITE_REG(PM3ScreenStride,
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- l_fb_info->current_par->stride));
- PM3_SLOW_WRITE_REG(PM3VTotal, l_fb_info->current_par->vtotal - 1);
- PM3_SLOW_WRITE_REG(PM3VsEnd, l_fb_info->current_par->vsend - 1);
- PM3_SLOW_WRITE_REG(PM3VsStart,
- l_fb_info->current_par->vsstart - 1);
- PM3_SLOW_WRITE_REG(PM3VbEnd, l_fb_info->current_par->vbend);
+ PM3_SLOW_WRITE_REG(par, PM3HbEnd,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ hbend));
+ PM3_SLOW_WRITE_REG(par, PM3HgEnd,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ hbend));
+ PM3_SLOW_WRITE_REG(par, PM3ScreenStride,
+ pm3fb_shift_bpp(info->var.bits_per_pixel,
+ width));
+ PM3_SLOW_WRITE_REG(par, PM3VTotal, vtotal - 1);
+ PM3_SLOW_WRITE_REG(par, PM3VsEnd, vsend - 1);
+ PM3_SLOW_WRITE_REG(par, PM3VsStart, vsstart - 1);
+ PM3_SLOW_WRITE_REG(par, PM3VbEnd, vbend);
- switch (l_fb_info->current_par->depth) {
+ switch (info->var.bits_per_pixel) {
case 8:
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_8BIT);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_8BIT);
break;
@@ -1100,15 +247,15 @@
case 15:
case 16:
#ifndef __BIG_ENDIAN
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_16BIT);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_16BIT);
#else
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_16BIT |
PM3ByApertureMode_BYTESWAP_BADC);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_16BIT |
PM3ByApertureMode_BYTESWAP_BADC);
#endif /* ! __BIG_ENDIAN */
@@ -1116,23 +263,23 @@
case 32:
#ifndef __BIG_ENDIAN
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_32BIT);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_32BIT);
#else
- PM3_SLOW_WRITE_REG(PM3ByAperture1Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture1Mode,
PM3ByApertureMode_PIXELSIZE_32BIT |
PM3ByApertureMode_BYTESWAP_DCBA);
- PM3_SLOW_WRITE_REG(PM3ByAperture2Mode,
+ PM3_SLOW_WRITE_REG(par, PM3ByAperture2Mode,
PM3ByApertureMode_PIXELSIZE_32BIT |
PM3ByApertureMode_BYTESWAP_DCBA);
#endif /* ! __BIG_ENDIAN */
break;
default:
- DPRINTK(1, "Unsupported depth %d\n",
- l_fb_info->current_par->depth);
+ DPRINTK("Unsupported depth %d\n",
+ info->var.bits_per_pixel);
break;
}
@@ -1143,95 +290,86 @@
* sync options in PM3RD_SyncControl. --rmk
*/
{
- unsigned int video = l_fb_info->current_par->video;
+ unsigned int video = par->video;
video &= ~(PM3VideoControl_HSYNC_MASK |
PM3VideoControl_VSYNC_MASK);
video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
PM3VideoControl_VSYNC_ACTIVE_HIGH;
- PM3_SLOW_WRITE_REG(PM3VideoControl, video);
+ PM3_SLOW_WRITE_REG(par, PM3VideoControl, video);
}
- PM3_SLOW_WRITE_REG(PM3VClkCtl,
- (PM3_READ_REG(PM3VClkCtl) & 0xFFFFFFFC));
- PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
- PM3_SLOW_WRITE_REG(PM3ChipConfig,
- (PM3_READ_REG(PM3ChipConfig) & 0xFFFFFFFD));
+ PM3_SLOW_WRITE_REG(par, PM3VClkCtl,
+ (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
+ PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+ PM3_SLOW_WRITE_REG(par, PM3ChipConfig,
+ (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
{
- unsigned char m; /* ClkPreScale */
- unsigned char n; /* ClkFeedBackScale */
- unsigned char p; /* ClkPostScale */
- (void)pm3fb_CalculateClock(l_fb_info, l_fb_info->current_par->pixclock, PM3_REF_CLOCK, &m, &n, &p);
+ unsigned char uninitialized_var(m); /* ClkPreScale */
+ unsigned char uninitialized_var(n); /* ClkFeedBackScale */
+ unsigned char uninitialized_var(p); /* ClkPostScale */
+ unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
- DPRINTK(2,
- "Pixclock: %d, Pre: %d, Feedback: %d, Post: %d\n",
- l_fb_info->current_par->pixclock, (int) m, (int) n,
- (int) p);
+ (void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
- PM3_WRITE_DAC_REG(PM3RD_DClk0PreScale, m);
- PM3_WRITE_DAC_REG(PM3RD_DClk0FeedbackScale, n);
- PM3_WRITE_DAC_REG(PM3RD_DClk0PostScale, p);
+ DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
+ pixclock, (int) m, (int) n, (int) p);
+
+ PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
+ PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
+ PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
}
/*
- PM3_WRITE_DAC_REG(PM3RD_IndexControl, 0x00);
+ PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
*/
/*
- PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+ PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
*/
- if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+ if ((par->video & PM3VideoControl_HSYNC_MASK) ==
PM3VideoControl_HSYNC_ACTIVE_HIGH)
tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
- if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+ if ((par->video & PM3VideoControl_VSYNC_MASK) ==
PM3VideoControl_VSYNC_ACTIVE_HIGH)
tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
-
- PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
- DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
-
- if (flatpanel[l_fb_info->board_num])
- {
- PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
- PM3_WAIT(2);
- PM3_WRITE_REG(PM3VSConfiguration, 0x06);
- PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
- tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
- }
- else
- PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
- switch (l_fb_info->current_par->depth) {
+ PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
+ DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
+
+ PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
+
+ switch (info->var.bits_per_pixel) {
case 8:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_8_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_CI8_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
break;
case 12:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_16_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_4444_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
- break;
+ break;
case 15:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_16_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_5551_FRONT_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
- break;
+ break;
case 16:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_16_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_565_FRONT_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
@@ -1239,1936 +377,280 @@
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
break;
case 32:
- PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+ PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
PM3RD_PixelSize_32_BIT_PIXELS);
- PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
PM3RD_ColorFormat_8888_COLOR |
PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
break;
}
- PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
-
- PM3_SHOW_CUR_MODE;
+ PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
}
-static void pm3fb_read_mode(struct pm3fb_info *l_fb_info,
- struct pm3fb_par *curpar)
+/*
+ * hardware independent functions
+ */
+int pm3fb_init(void);
+int pm3fb_setup(char*);
+
+static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
- unsigned long pixsize1, pixsize2, clockused;
- unsigned long pre, feedback, post;
+ u32 lpitch;
- DTRACE;
-
- clockused = PM3_READ_REG(PM3VClkCtl);
-
- switch (clockused) {
- case 3:
- pre = PM3_READ_DAC_REG(PM3RD_DClk3PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk3FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk3PostScale);
-
- DPRINTK(2,
- "DClk3 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
- break;
- case 2:
- pre = PM3_READ_DAC_REG(PM3RD_DClk2PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk2FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk2PostScale);
-
- DPRINTK(2,
- "DClk2 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
- break;
- case 1:
- pre = PM3_READ_DAC_REG(PM3RD_DClk1PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk1FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk1PostScale);
-
- DPRINTK(2,
- "DClk1 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
- break;
- case 0:
- pre = PM3_READ_DAC_REG(PM3RD_DClk0PreScale);
- feedback = PM3_READ_DAC_REG(PM3RD_DClk0FeedbackScale);
- post = PM3_READ_DAC_REG(PM3RD_DClk0PostScale);
-
- DPRINTK(2,
- "DClk0 parameter: Pre: %ld, Feedback: %ld, Post: %ld ; giving pixclock: %ld\n",
- pre, feedback, post, PM3_SCALE_TO_CLOCK(pre,
- feedback,
- post));
- break;
- default:
- pre = feedback = post = 0;
- DPRINTK(1, "Unknowk D clock used : %ld\n", clockused);
- break;
- }
-
- curpar->pixclock = PM3_SCALE_TO_CLOCK(pre, feedback, post);
-
- pixsize1 =
- PM3ByApertureMode_PIXELSIZE_MASK &
- (PM3_READ_REG(PM3ByAperture1Mode));
- pixsize2 =
- PM3ByApertureMode_PIXELSIZE_MASK &
- (PM3_READ_REG(PM3ByAperture2Mode));
-
- DASSERT((pixsize1 == pixsize2),
- "pixsize the same in both aperture\n");
-
- if (pixsize1 & PM3ByApertureMode_PIXELSIZE_32BIT)
- curpar->depth = 32;
- else if (pixsize1 & PM3ByApertureMode_PIXELSIZE_16BIT)
- {
- curpar->depth = 16;
- }
- else
- curpar->depth = 8;
-
- /* not sure if I need to add one on the next ; it give better result with */
- curpar->htotal =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- 1 + PM3_READ_REG(PM3HTotal));
- curpar->hsend =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3HsEnd));
- curpar->hsstart =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3HsStart));
- curpar->hbend =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3HbEnd));
-
- curpar->stride =
- pm3fb_Unshiftbpp(l_fb_info, curpar->depth,
- PM3_READ_REG(PM3ScreenStride));
-
- curpar->vtotal = 1 + PM3_READ_REG(PM3VTotal);
- curpar->vsend = 1 + PM3_READ_REG(PM3VsEnd);
- curpar->vsstart = 1 + PM3_READ_REG(PM3VsStart);
- curpar->vbend = PM3_READ_REG(PM3VbEnd);
-
- curpar->video = PM3_READ_REG(PM3VideoControl);
-
- curpar->base = PM3_READ_REG(PM3ScreenBase);
- curpar->width = curpar->htotal - curpar->hbend; /* make virtual == displayed resolution */
- curpar->height = curpar->vtotal - curpar->vbend;
-
- DPRINTK(2, "Found : %d * %d, %d Khz, stride is %08x\n",
- curpar->width, curpar->height, curpar->pixclock,
- curpar->stride);
-}
-
-static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
-{
- unsigned long memsize = 0, tempBypass, i, temp1, temp2;
- u16 subvendor, subdevice;
- pm3fb_timing_result ptr;
-
- DTRACE;
-
- l_fb_info->fb_size = 64 * 1024 * 1024; /* pm3 aperture always 64 MB */
- pm3fb_mapIO(l_fb_info); /* temporary map IO */
-
- DASSERT((l_fb_info->vIOBase != NULL),
- "IO successfully mapped before mem detect\n");
- DASSERT((l_fb_info->v_fb != NULL),
- "FB successfully mapped before mem detect\n");
-
- /* card-specific stuff, *before* accessing *any* FB memory */
- if ((!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor))
- &&
- (!pci_read_config_word
- (l_fb_info->dev, PCI_SUBSYSTEM_ID, &subdevice))) {
- i = 0; l_fb_info->board_type = 0;
- while ((cardbase[i].cardname[0]) && !(l_fb_info->board_type)) {
- if ((cardbase[i].subvendor == subvendor) &&
- (cardbase[i].subdevice == subdevice) &&
- (cardbase[i].func == PCI_FUNC(l_fb_info->dev->devfn))) {
- DPRINTK(2, "Card #%ld is an %s\n",
- l_fb_info->board_num,
- cardbase[i].cardname);
- if (cardbase[i].specific_setup)
- cardbase[i].specific_setup(l_fb_info);
- l_fb_info->board_type = i;
- }
- i++;
- }
- if (!l_fb_info->board_type) {
- DPRINTK(1, "Card #%ld is an unknown 0x%04x / 0x%04x\n",
- l_fb_info->board_num, subvendor, subdevice);
- }
- } else {
- printk(KERN_ERR "pm3fb: Error: pci_read_config_word failed, board #%ld\n",
- l_fb_info->board_num);
- }
-
- if (printtimings)
- pm3fb_show_cur_timing(l_fb_info);
-
- /* card-specific setup is done, we preserve the final
- memory timing for future reference */
- if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
- return(0);
- }
-
- tempBypass = PM3_READ_REG(PM3MemBypassWriteMask);
-
- DPRINTK(2, "PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
-
- PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xFFFFFFFF);
-
- /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
- for (i = 0; i < 32; i++) {
- fb_writel(i * 0x00345678,
- (l_fb_info->v_fb + (i * 1048576)));
- mb();
- temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
-
- /* Let's check for wrapover, write will fail at 16MB boundary */
- if (temp1 == (i * 0x00345678))
- memsize = i;
- else
- break;
- }
-
- DPRINTK(2, "First detect pass already got %ld MB\n", memsize + 1);
-
- if (memsize == i) {
- for (i = 0; i < 32; i++) {
- /* Clear first 32MB ; 0 is 0, no need to byteswap */
- writel(0x0000000,
- (l_fb_info->v_fb + (i * 1048576)));
- mb();
- }
-
- for (i = 32; i < 64; i++) {
- fb_writel(i * 0x00345678,
- (l_fb_info->v_fb + (i * 1048576)));
- mb();
- temp1 =
- fb_readl((l_fb_info->v_fb + (i * 1048576)));
- temp2 =
- fb_readl((l_fb_info->v_fb +
- ((i - 32) * 1048576)));
- if ((temp1 == (i * 0x00345678)) && (temp2 == 0)) /* different value, different RAM... */
- memsize = i;
- else
- break;
- }
- }
-
- DPRINTK(2, "Second detect pass got %ld MB\n", memsize + 1);
-
- PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, tempBypass);
-
- pm3fb_unmapIO(l_fb_info);
- memsize = 1048576 * (memsize + 1);
-
- DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
-
- if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
- {
- printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
- memsize = 1048576 * forcesize[l_fb_info->board_num];
- }
-
- l_fb_info->fb_size = memsize;
-
- if (ptr == pm3fb_timing_retry)
- {
- printk(KERN_WARNING "pm3fb: retrying memory timings check");
- if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
- return(0);
- }
-
- return (memsize);
-}
-
-static void pm3fb_clear_memory(struct pm3fb_info *l_fb_info, u32 cc)
-{
- int i;
-
- DTRACE;
-
- for (i = 0; i < (l_fb_info->fb_size / sizeof(u32)) ; i++) /* clear entire FB memory to black */
- {
- fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
- }
-}
-
-static void pm3fb_clear_colormap(struct pm3fb_info *l_fb_info, unsigned char r, unsigned char g, unsigned char b)
-{
- int i;
-
- DTRACE;
-
- for (i = 0; i < 256 ; i++) /* fill color map with white */
- pm3fb_set_color(l_fb_info, i, r, g, b);
-
-}
-
-/* common initialisation */
-static void pm3fb_common_init(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- DPRINTK(2, "Initializing board #%ld @ %lx\n", l_fb_info->board_num,
- (unsigned long) l_fb_info);
-
- strcpy(l_fb_info->gen.info.modename, permedia3_name);
- disp[l_fb_info->board_num].scrollmode = 0; /* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
- l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
- l_fb_info->gen.info.changevar = NULL;
- l_fb_info->gen.info.fbops = &pm3fb_ops;
- l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
- if (fontn[l_fb_info->board_num][0])
- strcpy(l_fb_info->gen.info.fontname,
- fontn[l_fb_info->board_num]);
- l_fb_info->gen.info.switch_con = &fbgen_switch;
- l_fb_info->gen.info.updatevar = &fbgen_update_var; /* */
- l_fb_info->gen.info.flags = FBINFO_FLAG_DEFAULT;
-
- pm3fb_mapIO(l_fb_info);
-
- pm3fb_clear_memory(l_fb_info, 0);
- pm3fb_clear_colormap(l_fb_info, 0, 0, 0);
-
- (void) fbgen_get_var(&(disp[l_fb_info->board_num]).var, -1,
- &l_fb_info->gen.info);
-
- if (depth[l_fb_info->board_num]) /* override mode-defined depth */
- {
- pm3fb_encode_depth(&(disp[l_fb_info->board_num]).var, depth[l_fb_info->board_num]);
- (disp[l_fb_info->board_num]).var.bits_per_pixel = depth2bpp(depth[l_fb_info->board_num]);
- }
-
- (void) fbgen_do_set_var(&(disp[l_fb_info->board_num]).var, 1,
- &l_fb_info->gen);
-
- fbgen_set_disp(-1, &l_fb_info->gen);
-
- do_install_cmap(0, &l_fb_info->gen.info);
-
- if (register_framebuffer(&l_fb_info->gen.info) < 0) {
- DPRINTK(1, "Couldn't register framebuffer\n");
- return;
- }
-
- PM3_WRITE_DAC_REG(PM3RD_CursorMode,
- PM3RD_CursorMode_CURSOR_DISABLE);
-
- PM3_SHOW_CUR_MODE;
-
- pm3fb_write_mode(l_fb_info);
-
- printk("fb%d: %s, using %uK of video memory (%s)\n",
- l_fb_info->gen.info.node,
- permedia3_name, (u32) (l_fb_info->fb_size >> 10),
- cardbase[l_fb_info->board_type].cardname);
-}
-
-/* **************************************************** */
-/* ***** accelerated permedia3-specific functions ***** */
-/* **************************************************** */
-#ifdef PM3FB_USE_ACCEL
-static void pm3fb_wait_pm3(struct pm3fb_info *l_fb_info)
-{
- DTRACE;
-
- PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
- PM3_SLOW_WRITE_REG(PM3Sync, 0);
- mb();
- do {
- while ((PM3_READ_REG(PM3OutFIFOWords)) == 0);
- rmb();
- } while ((PM3_READ_REG(PM3OutputFifo)) != PM3Sync_Tag);
-}
-
-static void pm3fb_init_engine(struct pm3fb_info *l_fb_info)
-{
- PM3_SLOW_WRITE_REG(PM3FilterMode, PM3FilterModeSync);
- PM3_SLOW_WRITE_REG(PM3StatisticMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3DeltaMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3RasterizerMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3ScissorMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LineStippleMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AreaStippleMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3GIDMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3DepthMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3StencilMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3StencilData, 0x0);
- PM3_SLOW_WRITE_REG(PM3ColorDDAMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCoordMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureIndexMode0, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureIndexMode1, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureReadMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LUTMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureFilterMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureApplicationMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode1, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode1, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeColorMode0, 0x0);
- PM3_SLOW_WRITE_REG(PM3TextureCompositeAlphaMode0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FogMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3ChromaTestMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AlphaTestMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AntialiasMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3YUVMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AlphaBlendColorMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3AlphaBlendAlphaMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3DitherMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LogicalOpMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3RouterMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3Window, 0x0);
-
- PM3_SLOW_WRITE_REG(PM3Config2D, 0x0);
-
- PM3_SLOW_WRITE_REG(PM3SpanColorMask, 0xffffffff);
-
- PM3_SLOW_WRITE_REG(PM3XBias, 0x0);
- PM3_SLOW_WRITE_REG(PM3YBias, 0x0);
- PM3_SLOW_WRITE_REG(PM3DeltaControl, 0x0);
-
- PM3_SLOW_WRITE_REG(PM3BitMaskPattern, 0xffffffff);
-
- PM3_SLOW_WRITE_REG(PM3FBDestReadEnables,
- PM3FBDestReadEnables_E(0xff) |
- PM3FBDestReadEnables_R(0xff) |
- PM3FBDestReadEnables_ReferenceAlpha(0xff));
- PM3_SLOW_WRITE_REG(PM3FBDestReadBufferAddr0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBDestReadBufferOffset0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBDestReadBufferWidth0,
- PM3FBDestReadBufferWidth_Width(l_fb_info->
- current_par->
- width));
-
- PM3_SLOW_WRITE_REG(PM3FBDestReadMode,
- PM3FBDestReadMode_ReadEnable |
- PM3FBDestReadMode_Enable0);
- PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferAddr, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferOffset, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBSourceReadBufferWidth,
- PM3FBSourceReadBufferWidth_Width(l_fb_info->
- current_par->
- width));
- PM3_SLOW_WRITE_REG(PM3FBSourceReadMode,
- PM3FBSourceReadMode_Blocking |
- PM3FBSourceReadMode_ReadEnable);
-
- {
- unsigned long rm = 1;
- switch (l_fb_info->current_par->depth) {
- case 8:
- PM3_SLOW_WRITE_REG(PM3PixelSize,
- PM3PixelSize_GLOBAL_8BIT);
- break;
- case 12:
- case 15:
- case 16:
- PM3_SLOW_WRITE_REG(PM3PixelSize,
- PM3PixelSize_GLOBAL_16BIT);
- break;
- case 32:
- PM3_SLOW_WRITE_REG(PM3PixelSize,
- PM3PixelSize_GLOBAL_32BIT);
- break;
- default:
- DPRINTK(1, "Unsupported depth %d\n",
- l_fb_info->current_par->depth);
- break;
- }
- PM3_SLOW_WRITE_REG(PM3RasterizerMode, rm);
- }
-
- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
- PM3_SLOW_WRITE_REG(PM3FBWriteMode,
- PM3FBWriteMode_WriteEnable |
- PM3FBWriteMode_OpaqueSpan |
- PM3FBWriteMode_Enable0);
- PM3_SLOW_WRITE_REG(PM3FBWriteBufferAddr0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBWriteBufferOffset0, 0x0);
- PM3_SLOW_WRITE_REG(PM3FBWriteBufferWidth0,
- PM3FBWriteBufferWidth_Width(l_fb_info->
- current_par->
- width));
-
- PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 0x0);
- {
- unsigned long sofb = (8UL * l_fb_info->fb_size) /
- ((depth2bpp(l_fb_info->current_par->depth))
- * l_fb_info->current_par->width); /* size in lines of FB */
- if (sofb > 4095)
- PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
- else
- PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
-
- switch (l_fb_info->current_par->depth) {
- case 8:
- PM3_SLOW_WRITE_REG(PM3DitherMode,
- (1 << 10) | (2 << 3));
- break;
- case 12:
- case 15:
- case 16:
- PM3_SLOW_WRITE_REG(PM3DitherMode,
- (1 << 10) | (1 << 3));
- break;
- case 32:
- PM3_SLOW_WRITE_REG(PM3DitherMode,
- (1 << 10) | (0 << 3));
- break;
- default:
- DPRINTK(1, "Unsupported depth %d\n",
- l_fb_info->current_par->depth);
- break;
- }
- }
-
- PM3_SLOW_WRITE_REG(PM3dXDom, 0x0);
- PM3_SLOW_WRITE_REG(PM3dXSub, 0x0);
- PM3_SLOW_WRITE_REG(PM3dY, (1 << 16));
- PM3_SLOW_WRITE_REG(PM3StartXDom, 0x0);
- PM3_SLOW_WRITE_REG(PM3StartXSub, 0x0);
- PM3_SLOW_WRITE_REG(PM3StartY, 0x0);
- PM3_SLOW_WRITE_REG(PM3Count, 0x0);
-
-/* Disable LocalBuffer. better safe than sorry */
- PM3_SLOW_WRITE_REG(PM3LBDestReadMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LBDestReadEnables, 0x0);
- PM3_SLOW_WRITE_REG(PM3LBSourceReadMode, 0x0);
- PM3_SLOW_WRITE_REG(PM3LBWriteMode, 0x0);
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-#ifdef FBCON_HAS_CFB32
-static void pm3fb_cfb32_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u32 c;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- height = height * fontheight(p);
- c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
- /* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
- we can use 16bpp operations, but not if NoWriteMask is on (SDRAM) */
- if ((l_fb_info->current_par->width > 1600) ||
- (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
- } else {
- PM3_WAIT(8);
-
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
- PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_16BIT);
-
- PM3_WRITE_REG(PM3FBWriteBufferWidth0,
- PM3FBWriteBufferWidth_Width(l_fb_info->
- current_par->
- width << 1));
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx << 1)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(width << 1)) |
- (PM3Render2D_Height(height)));
-
- PM3_WRITE_REG(PM3FBWriteBufferWidth0,
- PM3FBWriteBufferWidth_Width(l_fb_info->
- current_par->
- width));
-
- PM3_WRITE_REG(PM3PixelSize, PM3PixelSize_GLOBAL_32BIT);
- }
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb32_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int sx, sy;
- u32 c;
-
- DTRACE;
-
- sx = conp->vc_cols * fontwidth(p); /* right margin */
- sy = conp->vc_rows * fontheight(p); /* bottom margin */
- c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-
- if (!bottom_only) { /* right margin top->bottom */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset
- (p->var.xoffset +
- sx)) | (PM3RectanglePosition_YOffset(p->
- var.
- yoffset)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
- }
-
- /* bottom margin left -> right */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(p->var.xoffset)) |
- (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB32 */
-#ifdef FBCON_HAS_CFB16
-static void pm3fb_cfb16_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u32 c;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- height = height * fontheight(p);
- c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
- c = c | (c << 16);
-
- PM3_WAIT(4);
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3ForegroundColor, c);
- else
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
- else
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb16_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int sx, sy;
- u32 c;
-
- DTRACE;
-
- sx = conp->vc_cols * fontwidth(p); /* right margin */
- sy = conp->vc_rows * fontheight(p); /* bottom margin */
- c = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
- c = c | (c << 16);
-
- if (!bottom_only) { /* right margin top->bottom */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3ForegroundColor, c);
- else
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset
- (p->var.xoffset +
- sx)) | (PM3RectanglePosition_YOffset(p->
- var.
- yoffset)));
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
- else
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
- }
-
- /* bottom margin left -> right */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3ForegroundColor, c);
- else
- PM3_WRITE_REG(PM3FBBlockColor, c);
-
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(p->var.xoffset)) |
- (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
- else
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB16 */
-#ifdef FBCON_HAS_CFB8
-static void pm3fb_cfb8_clear(struct vc_data *conp,
- struct display *p,
- int sy, int sx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u32 c;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- height = height * fontheight(p);
-
- c = attr_bgcol_ec(p, conp);
- c |= c << 8;
- c |= c << 16;
-
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(width)) |
- (PM3Render2D_Height(height)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfb8_clear_margins(struct vc_data *conp,
- struct display *p, int bottom_only)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int sx, sy;
- u32 c;
-
- DTRACE;
-
- sx = conp->vc_cols * fontwidth(p); /* right margin */
- sy = conp->vc_rows * fontheight(p); /* bottom margin */
- c = attr_bgcol_ec(p, conp);
- c |= c << 8;
- c |= c << 16;
-
- if (!bottom_only) { /* right margin top->bottom */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset
- (p->var.xoffset +
- sx)) | (PM3RectanglePosition_YOffset(p->
- var.
- yoffset)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres - sx)) |
- (PM3Render2D_Height(p->var.yres)));
- }
-
- /* bottom margin left -> right */
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ForegroundColor, c);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(p->var.xoffset)) |
- (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(p->var.xres)) |
- (PM3Render2D_Height(p->var.yres - sy)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-#endif /* FBCON_HAS_CFB8 */
-#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB32)
-static void pm3fb_cfbX_bmove(struct display *p,
- int sy, int sx,
- int dy, int dx, int height, int width)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- int x_align, o_x, o_y;
-
- DTRACE;
-
- sx = sx * fontwidth(p);
- dx = dx * fontwidth(p);
- width = width * fontwidth(p);
- sy = sy * fontheight(p);
- dy = dy * fontheight(p);
- height = height * fontheight(p);
-
- o_x = sx - dx; /*(sx > dx ) ? (sx - dx) : (dx - sx); */
- o_y = sy - dy; /*(sy > dy ) ? (sy - dy) : (dy - sy); */
-
- x_align = (sx & 0x1f);
-
- PM3_WAIT(6);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UserScissorEnable |
- PM3Config2D_ForegroundROPEnable |
- PM3Config2D_Blocking |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3ScissorMinXY,
- ((dy & 0x0fff) << 16) | (dx & 0x0fff));
- PM3_WRITE_REG(PM3ScissorMaxXY,
- (((dy + height) & 0x0fff) << 16) |
- ((dx + width) & 0x0fff));
-
- PM3_WRITE_REG(PM3FBSourceReadBufferOffset,
- PM3FBSourceReadBufferOffset_XOffset(o_x) |
- PM3FBSourceReadBufferOffset_YOffset(o_y));
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(dx - x_align)) |
- (PM3RectanglePosition_YOffset(dy)));
-
- PM3_WRITE_REG(PM3Render2D,
- ((sx > dx) ? PM3Render2D_XPositive : 0) |
- ((sy > dy) ? PM3Render2D_YPositive : 0) |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- PM3Render2D_FBSourceReadEnable |
- (PM3Render2D_Width(width + x_align)) |
- (PM3Render2D_Height(height)));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_putc(struct vc_data *conp, struct display *p,
- int c, int yy, int xx)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
- u32 fgx, bgx, ldat;
- int sx, sy, i;
-
- DTRACE;
-
- if (l_fb_info->current_par->depth == 8)
- fgx = attr_fgcol(p, c);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
- else
- fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
-
- PM3_COLOR(fgx);
-
- if (l_fb_info->current_par->depth == 8)
- bgx = attr_bgcol(p, c);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
- else
- bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
-
- PM3_COLOR(bgx);
-
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable | PM3Config2D_OpaqueSpan);
-
- PM3_WRITE_REG(PM3ForegroundColor, fgx);
- PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
- /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
- /* and 16 bits for fontwidth <= 16 */
- /* same in _putcs, same for Y and fontheight */
- if (fontwidth(p) <= 8)
- asx = 2;
- else if (fontwidth(p) <= 16)
- asx = 3; /* look OK */
- if (fontheight(p) <= 8)
- asy = 2;
- else if (fontheight(p) <= 16)
- asy = 3; /* look OK */
- else if (fontheight(p) <= 32)
- asy = 4; /* look OK */
-
- sx = xx * fontwidth(p);
- sy = yy * fontheight(p);
-
- if (fontwidth(p) <= 8)
- o_x = (8 - (sx & 0x7)) & 0x7;
- else if (fontwidth(p) <= 16)
- o_x = (16 - (sx & 0xF)) & 0xF;
- if (fontheight(p) <= 8)
- o_y = (8 - (sy & 0x7)) & 0x7;
- else if (fontheight(p) <= 16)
- o_y = (16 - (sy & 0xF)) & 0xF;
- else if (fontheight(p) <= 32)
- o_y = (32 - (sy & 0x1F)) & 0x1F;
-
- PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
- (1 << 18) | /* BE */
- 1 | (asx << 1) | (asy << 4) | /* address select x/y */
- (1 << 20)); /* OpaqueSpan */
-
- if (fontwidth(p) <= 8) {
- cdat = p->fontdata + (c & p->charmask) * fontheight(p);
- } else {
- cdat =
- p->fontdata +
- ((c & p->charmask) * (fontheight(p) << 1));
- }
-
- PM3_WAIT(2 + fontheight(p));
-
- for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
- if (fontwidth(p) <= 8) {
- ldat = *cdat++;
- } else { /* assume fontwidth <= 16 ATM */
-
- ldat = ((*cdat++) << 8);
- ldat |= *cdat++;
- }
- PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
- }
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_AreaStippleEnable |
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(fontwidth(p))) |
- (PM3Render2D_Height(fontheight(p))));
-
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_putcs(struct vc_data *conp, struct display *p,
- const unsigned short *s, int count, int yy,
- int xx)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
- u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
- u32 fgx, bgx, ldat;
- int sx, sy, i, j;
- u16 sc;
-
- DTRACE;
-
- sc = scr_readw(s);
- if (l_fb_info->current_par->depth == 8)
- fgx = attr_fgcol(p, sc);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, sc)];
- else
- fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, sc)];
-
- PM3_COLOR(fgx);
-
- if (l_fb_info->current_par->depth == 8)
- bgx = attr_bgcol(p, sc);
- else if (depth2bpp(l_fb_info->current_par->depth) == 16)
- bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, sc)];
- else
- bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, sc)];
-
- PM3_COLOR(bgx);
-
- PM3_WAIT(4);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0x3)) | /* Ox3 is GXcopy */
- PM3Config2D_FBWriteEnable |
- PM3Config2D_OpaqueSpan);
-
- PM3_WRITE_REG(PM3ForegroundColor, fgx);
- PM3_WRITE_REG(PM3FillBackgroundColor, bgx);
-
- /* WARNING : address select X need to specify 8 bits for fontwidth <= 8 */
- /* and 16 bits for fontwidth <= 16 */
- /* same in _putc, same for Y and fontheight */
- if (fontwidth(p) <= 8)
- asx = 2;
- else if (fontwidth(p) <= 16)
- asx = 3; /* look OK */
- if (fontheight(p) <= 8)
- asy = 2;
- else if (fontheight(p) <= 16)
- asy = 3; /* look OK */
- else if (fontheight(p) <= 32)
- asy = 4; /* look OK */
-
- sy = yy * fontheight(p);
-
- if (fontheight(p) <= 8)
- o_y = (8 - (sy & 0x7)) & 0x7;
- else if (fontheight(p) <= 16)
- o_y = (16 - (sy & 0xF)) & 0xF;
- else if (fontheight(p) <= 32)
- o_y = (32 - (sy & 0x1F)) & 0x1F;
-
- for (j = 0; j < count; j++) {
- sc = scr_readw(s + j);
- if (fontwidth(p) <= 8)
- cdat = p->fontdata +
- (sc & p->charmask) * fontheight(p);
- else
- cdat = p->fontdata +
- ((sc & p->charmask) * fontheight(p) << 1);
-
- sx = (xx + j) * fontwidth(p);
-
- if (fontwidth(p) <= 8)
- o_x = (8 - (sx & 0x7)) & 0x7;
- else if (fontwidth(p) <= 16)
- o_x = (16 - (sx & 0xF)) & 0xF;
-
- PM3_WAIT(3 + fontheight(p));
-
- PM3_WRITE_REG(PM3AreaStippleMode, (o_x << 7) | (o_y << 12) | /* x_offset, y_offset in pattern */
- (1 << 18) | /* BE */
- 1 | (asx << 1) | (asy << 4) | /* address select x/y */
- (1 << 20)); /* OpaqueSpan */
-
- for (i = 0; i < fontheight(p); i++) { /* assume fontheight <= 32 */
- if (fontwidth(p) <= 8) {
- ldat = *cdat++;
- } else { /* assume fontwidth <= 16 ATM */
- ldat = ((*cdat++) << 8);
- ldat |= *cdat++;
- }
- PM3_WRITE_REG(AreaStipplePattern_indexed(i), ldat);
- }
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(sx)) |
- (PM3RectanglePosition_YOffset(sy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_AreaStippleEnable |
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(fontwidth(p))) |
- (PM3Render2D_Height(fontheight(p))));
- }
- pm3fb_wait_pm3(l_fb_info);
-}
-
-static void pm3fb_cfbX_revc(struct display *p, int xx, int yy)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
-
- xx = xx * fontwidth(p);
- yy = yy * fontheight(p);
-
- if (l_fb_info->current_par->depth == 8)
- {
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
- else
- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
- }
-
- PM3_WAIT(3);
-
- PM3_WRITE_REG(PM3Config2D,
- PM3Config2D_UseConstantSource |
- PM3Config2D_ForegroundROPEnable |
- (PM3Config2D_ForegroundROP(0xa)) | /* Oxa is GXinvert */
- PM3Config2D_FBDestReadEnable |
- PM3Config2D_FBWriteEnable);
-
- PM3_WRITE_REG(PM3RectanglePosition,
- (PM3RectanglePosition_XOffset(xx)) |
- (PM3RectanglePosition_YOffset(yy)));
-
- PM3_WRITE_REG(PM3Render2D,
- PM3Render2D_XPositive |
- PM3Render2D_YPositive |
- PM3Render2D_Operation_Normal |
- PM3Render2D_SpanOperation |
- (PM3Render2D_Width(fontwidth(p))) |
- (PM3Render2D_Height(fontheight(p))));
-
- pm3fb_wait_pm3(l_fb_info);
-
- if (l_fb_info->current_par->depth == 8)
- {
- if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
- PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
- else
- PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
- }
-}
-
-#endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
-#endif /* PM3FB_USE_ACCEL */
-/* *********************************** */
-/* ***** pre-init board(s) setup ***** */
-/* *********************************** */
-
-static void pm3fb_mode_setup(char *mode, unsigned long board_num)
-{
- struct pm3fb_info *l_fb_info = &(fb_info[board_num]);
- struct pm3fb_par *l_fb_par = &(current_par[board_num]);
- unsigned long i = 0;
-
- current_par_valid[board_num] = 0;
-
- if (!strncmp(mode, "current", 7)) {
- l_fb_info->use_current = 1; /* default w/ OpenFirmware */
- } else {
- while ((mode_base[i].name[0])
- && (!current_par_valid[board_num])) {
- if (!
- (strncmp
- (mode, mode_base[i].name,
- strlen(mode_base[i].name)))) {
- memcpy(l_fb_par, &(mode_base[i].user_mode),
- sizeof(struct pm3fb_par));
- current_par_valid[board_num] = 1;
- DPRINTK(2, "Mode set to %s\n",
- mode_base[i].name);
- }
- i++;
- }
- DASSERT(current_par_valid[board_num],
- "Valid mode on command line\n");
- }
-}
-
-static void pm3fb_pciid_setup(char *pciid, unsigned long board_num)
-{
- short l_bus = -1, l_slot = -1, l_func = -1;
- char *next;
-
- if (pciid) {
- l_bus = simple_strtoul(pciid, &next, 10);
- if (next && (next[0] == ':')) {
- pciid = next + 1;
- l_slot = simple_strtoul(pciid, &next, 10);
- if (next && (next[0] == ':')) {
- pciid = next + 1;
- l_func =
- simple_strtoul(pciid, (char **) NULL,
- 10);
- }
- }
- } else
- return;
-
- if ((l_bus >= 0) && (l_slot >= 0) && (l_func >= 0)) {
- bus[board_num] = l_bus;
- slot[board_num] = l_slot;
- func[board_num] = l_func;
- DPRINTK(2, "Board #%ld will be PciId: %hd:%hd:%hd\n",
- board_num, l_bus, l_slot, l_func);
- } else {
- DPRINTK(1, "Invalid PciId: %hd:%hd:%hd for board #%ld\n",
- l_bus, l_slot, l_func, board_num);
- }
-}
-
-static void pm3fb_font_setup(char *lf, unsigned long board_num)
-{
- unsigned long lfs = strlen(lf);
-
- if (lfs > (PM3_FONTNAME_SIZE - 1)) {
- DPRINTK(1, "Fontname %s too long\n", lf);
- return;
- }
- strlcpy(fontn[board_num], lf, lfs + 1);
-}
-
-static void pm3fb_bootdepth_setup(char *bds, unsigned long board_num)
-{
- unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
-
- if (!(depth_supported(bd))) {
- printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
- bds, board_num);
- return;
- }
- depth[board_num] = bd;
-}
-
-static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
-{
- unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
-
- if (bd > 64) {
- printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
- bds, board_num);
- return;
- }
- forcesize[board_num] = bd;
-}
-
-static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
-{
- char *next;
-
- if (!(isdigit(options[0]))) {
- (*bn) = 0;
- return (options);
- }
-
- (*bn) = simple_strtoul(options, &next, 10);
-
- if (next && (next[0] == ':') && ((*bn) >= 0)
- && ((*bn) <= PM3_MAX_BOARD)) {
- DPRINTK(2, "Board_num seen as %ld\n", (*bn));
- return (next + 1);
- } else {
- (*bn) = 0;
- DPRINTK(2, "Board_num default to %ld\n", (*bn));
- return (options);
- }
-}
-
-static void pm3fb_real_setup(char *options)
-{
- char *next;
- unsigned long i, bn;
- struct pm3fb_info *l_fb_info;
-
- DTRACE;
-
- DPRINTK(2, "Options : %s\n", options);
-
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- l_fb_info = &(fb_info[i]);
- memset(l_fb_info, 0, sizeof(struct pm3fb_info));
- l_fb_info->gen.fbhw = &pm3fb_switch;
- l_fb_info->board_num = i;
- current_par_valid[i] = 0;
- slot[i] = -1;
- func[i] = -1;
- bus[i] = -1;
- disable[i] = 0;
- noaccel[i] = 0;
- fontn[i][0] = '\0';
- depth[i] = 0;
- l_fb_info->current_par = &(current_par[i]);
- }
-
- /* eat up prefix pm3fb and whatever is used as separator i.e. :,= */
- if (!strncmp(options, "pm3fb", 5)) {
- options += 5;
- while (((*options) == ',') || ((*options) == ':')
- || ((*options) == '='))
- options++;
- }
-
- while (options) {
- bn = 0;
- if ((next = strchr(options, ','))) {
- (*next) = '\0';
- next++;
- }
-
- if (!strncmp(options, "mode:", 5)) {
- options = pm3fb_boardnum_setup(options + 5, &bn);
- DPRINTK(2, "Setting mode for board #%ld\n", bn);
- pm3fb_mode_setup(options, bn);
- } else if (!strncmp(options, "off:", 4)) {
- options = pm3fb_boardnum_setup(options + 4, &bn);
- DPRINTK(2, "Disabling board #%ld\n", bn);
- disable[bn] = 1;
- } else if (!strncmp(options, "off", 3)) { /* disable everything */
- for (i = 0; i < PM3_MAX_BOARD; i++)
- disable[i] = 1;
- } else if (!strncmp(options, "disable:", 8)) {
- options = pm3fb_boardnum_setup(options + 8, &bn);
- DPRINTK(2, "Disabling board #%ld\n", bn);
- disable[bn] = 1;
- } else if (!strncmp(options, "pciid:", 6)) {
- options = pm3fb_boardnum_setup(options + 6, &bn);
- DPRINTK(2, "Setting PciID for board #%ld\n", bn);
- pm3fb_pciid_setup(options, bn);
- } else if (!strncmp(options, "noaccel:", 8)) {
- options = pm3fb_boardnum_setup(options + 8, &bn);
- noaccel[bn] = 1;
- } else if (!strncmp(options, "font:", 5)) {
- options = pm3fb_boardnum_setup(options + 5, &bn);
- pm3fb_font_setup(options, bn);
- } else if (!strncmp(options, "depth:", 6)) {
- options = pm3fb_boardnum_setup(options + 6, &bn);
- pm3fb_bootdepth_setup(options, bn);
- } else if (!strncmp(options, "printtimings", 12)) {
- printtimings = 1;
- } else if (!strncmp(options, "flatpanel:", 10)) {
- options = pm3fb_boardnum_setup(options + 10, &bn);
- flatpanel[bn] = 1;
- } else if (!strncmp(options, "forcesize:", 10)) {
- options = pm3fb_boardnum_setup(options + 10, &bn);
- pm3fb_forcesize_setup(options, bn);
- }
- options = next;
- }
-}
-
-/* ********************************************** */
-/* ***** framebuffer API standard functions ***** */
-/* ********************************************** */
-
-static int pm3fb_encode_fix(struct fb_fix_screeninfo *fix,
- const void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- struct pm3fb_par *p = (struct pm3fb_par *) par;
-
- DTRACE;
-
- strcpy(fix->id, permedia3_name);
- fix->smem_start = (unsigned long)l_fb_info->p_fb;
- fix->smem_len = l_fb_info->fb_size;
- fix->mmio_start = (unsigned long)l_fb_info->pIOBase;
- fix->mmio_len = PM3_REGS_SIZE;
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- fix->accel = FB_ACCEL_3DLABS_PERMEDIA3;
- else
-#endif /* PM3FB_USE_ACCEL */
- fix->accel = FB_ACCEL_NONE;
- fix->type = FB_TYPE_PACKED_PIXELS;
- fix->visual =
- (p->depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
- if (current_par_valid[l_fb_info->board_num])
- fix->line_length =
- l_fb_info->current_par->width *
- depth2ByPP(l_fb_info->current_par->depth);
- else
- fix->line_length = 0;
- fix->xpanstep = 64 / depth2bpp(p->depth);
- fix->ypanstep = 1;
- fix->ywrapstep = 0;
- return (0);
-}
-
-static int pm3fb_decode_var(const struct fb_var_screeninfo *var,
- void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- struct pm3fb_par *p = (struct pm3fb_par *) par;
- struct pm3fb_par temp_p;
- u32 xres;
-
- DTRACE;
-
- DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
- DASSERT((p != NULL), "pm3fb_par* not NULL");
- DASSERT((l_fb_info != NULL), "pm3fb_info* not NULL");
-
- memset(&temp_p, 0, sizeof(struct pm3fb_par));
- temp_p.width = (var->xres_virtual + 7) & ~7;
- temp_p.height = var->yres_virtual;
-
- if (!(depth_supported(var->bits_per_pixel))) /* round unsupported up to a multiple of 8 */
- temp_p.depth = depth2bpp(var->bits_per_pixel);
- else
- temp_p.depth = var->bits_per_pixel;
-
- temp_p.depth = (temp_p.depth > 32) ? 32 : temp_p.depth; /* max 32 */
- temp_p.depth = (temp_p.depth == 24) ? 32 : temp_p.depth; /* 24 unsupported, round-up to 32 */
-
- if ((temp_p.depth == 16) && (var->red.length == 5) && (var->green.length == 5) && (var->blue.length == 5))
- temp_p.depth = 15; /* RGBA 5551 is stored as depth 15 */
-
- if ((temp_p.depth == 16) && (var->red.length == 4) && (var->green.length == 4) && (var->blue.length == 4))
- temp_p.depth = 12; /* RGBA 4444 is stored as depth 12 */
-
-
- DPRINTK(2,
- "xres: %d, yres: %d, vxres: %d, vyres: %d ; xoffset:%d, yoffset: %d\n",
- var->xres, var->yres, var->xres_virtual, var->yres_virtual,
- var->xoffset, var->yoffset);
-
- xres = (var->xres + 31) & ~31;
- if (temp_p.width < xres + var->xoffset)
- temp_p.width = xres + var->xoffset;
- if (temp_p.height < var->yres + var->yoffset)
- temp_p.height = var->yres + var->yoffset;
-
- if (temp_p.width > 2048) {
- DPRINTK(1, "virtual width not supported: %u\n",
- temp_p.width);
- return (-EINVAL);
- }
- if (var->yres < 200) {
- DPRINTK(1, "height not supported: %u\n", (u32) var->yres);
- return (-EINVAL);
- }
- if (temp_p.height < 200 || temp_p.height > 4095) {
- DPRINTK(1, "virtual height not supported: %u\n",
- temp_p.height);
- return (-EINVAL);
- }
- if (!(depth_supported(temp_p.depth))) {
- DPRINTK(1, "depth not supported: %u\n", temp_p.depth);
- return (-EINVAL);
- }
- if ((temp_p.width * temp_p.height * depth2ByPP(temp_p.depth)) >
- l_fb_info->fb_size) {
- DPRINTK(1, "no memory for screen (%ux%ux%u)\n",
- temp_p.width, temp_p.height, temp_p.depth);
- return (-EINVAL);
- }
-
- if ((!var->pixclock) ||
- (!var->right_margin) ||
- (!var->hsync_len) ||
- (!var->left_margin) ||
- (!var->lower_margin) ||
- (!var->vsync_len) || (!var->upper_margin)
- ) {
- unsigned long i = 0, done = 0;
- printk(KERN_WARNING "pm3fb: refusing to use a likely wrong timing\n");
-
- while ((mode_base[i].user_mode.width) && !done) {
- if ((mode_base[i].user_mode.width == temp_p.width)
- && (mode_base[i].user_mode.height ==
- temp_p.height)) {
- printk(KERN_NOTICE "pm3fb: using close match %s\n",
- mode_base[i].name);
- temp_p = mode_base[i].user_mode;
- done = 1;
- }
- i++;
- }
- if (!done)
- return (-EINVAL);
- } else {
- temp_p.pixclock = PICOS2KHZ(var->pixclock);
- if (temp_p.pixclock > PM3_MAX_PIXCLOCK) {
- DPRINTK(1, "pixclock too high (%uKHz)\n",
- temp_p.pixclock);
- return (-EINVAL);
- }
-
- temp_p.hsstart = var->right_margin;
- temp_p.hsend = var->right_margin + var->hsync_len;
- temp_p.hbend =
- var->right_margin + var->hsync_len + var->left_margin;
- temp_p.htotal = xres + temp_p.hbend;
-
- temp_p.vsstart = var->lower_margin;
- temp_p.vsend = var->lower_margin + var->vsync_len;
- temp_p.vbend =
- var->lower_margin + var->vsync_len + var->upper_margin;
- temp_p.vtotal = var->yres + temp_p.vbend;
-
- temp_p.stride = temp_p.width;
-
- DPRINTK(2, "Using %d * %d, %d Khz, stride is %08x\n",
- temp_p.width, temp_p.height, temp_p.pixclock,
- temp_p.stride);
-
- temp_p.base =
- pm3fb_Shiftbpp(l_fb_info, temp_p.depth,
- (var->yoffset * xres) + var->xoffset);
-
- temp_p.video = 0;
-
- if (var->sync & FB_SYNC_HOR_HIGH_ACT)
- temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
- else
- temp_p.video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
-
- if (var->sync & FB_SYNC_VERT_HIGH_ACT)
- temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
- else
- temp_p.video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
-
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
- DPRINTK(1, "Interlaced mode not supported\n\n");
- return (-EINVAL);
- }
-
- if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
- temp_p.video |= PM3VideoControl_LINE_DOUBLE_ON;
- else
- temp_p.video |= PM3VideoControl_LINE_DOUBLE_OFF;
-
- if (var->activate == FB_ACTIVATE_NOW)
- temp_p.video |= PM3VideoControl_ENABLE;
- else {
- temp_p.video |= PM3VideoControl_DISABLE;
- DPRINTK(2, "PM3Video disabled\n");
- }
-
- switch (temp_p.depth) {
- case 8:
- temp_p.video |= PM3VideoControl_PIXELSIZE_8BIT;
- break;
- case 12:
- case 15:
- case 16:
- temp_p.video |= PM3VideoControl_PIXELSIZE_16BIT;
- break;
- case 32:
- temp_p.video |= PM3VideoControl_PIXELSIZE_32BIT;
- break;
- default:
- DPRINTK(1, "Unsupported depth\n");
- break;
- }
- }
- (*p) = temp_p;
-
-#ifdef PM3FB_USE_ACCEL
- if (var->accel_flags & FB_ACCELF_TEXT)
- noaccel[l_fb_info->board_num] = 0;
- else
- noaccel[l_fb_info->board_num] = 1;
-#endif /* PM3FB_USE_ACCEL */
-
- return (0);
-}
-
-static void pm3fb_encode_depth(struct fb_var_screeninfo *var, long d)
-{
- switch (d) {
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ switch(var->bits_per_pixel) {
case 8:
var->red.length = var->green.length = var->blue.length = 8;
var->red.offset = var->green.offset = var->blue.offset = 0;
- var->transp.offset = var->transp.length = 0;
break;
-
case 12:
- var->red.offset = 8;
- var->red.length = 4;
+ var->red.offset = 8;
+ var->red.length = 4;
var->green.offset = 4;
var->green.length = 4;
- var->blue.offset = 0;
- var->blue.length = 4;
+ var->blue.offset = 0;
+ var->blue.length = 4;
var->transp.offset = 12;
var->transp.length = 4;
- break;
-
case 15:
- var->red.offset = 10;
- var->red.length = 5;
+ var->red.offset = 10;
+ var->red.length = 5;
var->green.offset = 5;
var->green.length = 5;
- var->blue.offset = 0;
- var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
var->transp.offset = 15;
var->transp.length = 1;
break;
-
case 16:
- var->red.offset = 11;
- var->red.length = 5;
+ var->red.offset = 11;
+ var->red.length = 5;
var->green.offset = 5;
var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = var->transp.length = 0;
+ var->blue.offset = 0;
+ var->blue.length = 5;
break;
-
case 32:
var->transp.offset = 24;
- var->red.offset = 16;
+ var->transp.length = 8;
+ var->red.offset = 16;
var->green.offset = 8;
- var->blue.offset = 0;
- var->red.length = var->green.length =
- var->blue.length = var->transp.length = 8;
+ var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length = 8;
break;
-
default:
- DPRINTK(1, "Unsupported depth %ld\n", d);
- break;
+ DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+ return -EINVAL;
}
-}
-
-static int pm3fb_encode_var(struct fb_var_screeninfo *var,
- const void *par, struct fb_info_gen *info)
-{
- struct pm3fb_par *p = (struct pm3fb_par *) par;
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- u32 base;
-
- DTRACE;
-
- DASSERT((var != NULL), "fb_var_screeninfo* not NULL");
- DASSERT((p != NULL), "pm3fb_par* not NULL");
- DASSERT((info != NULL), "fb_info_gen* not NULL");
-
- memset(var, 0, sizeof(struct fb_var_screeninfo));
-
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- var->accel_flags |= FB_ACCELF_TEXT;
-#endif /* PM3FB_USE_ACCEL */
-
- var->xres_virtual = p->width;
- var->yres_virtual = p->height;
- var->xres = p->htotal - p->hbend;
- var->yres = p->vtotal - p->vbend;
-
- DPRINTK(2, "xres = %d, yres : %d\n", var->xres, var->yres);
-
- var->right_margin = p->hsstart;
- var->hsync_len = p->hsend - p->hsstart;
- var->left_margin = p->hbend - p->hsend;
- var->lower_margin = p->vsstart;
- var->vsync_len = p->vsend - p->vsstart;
- var->upper_margin = p->vbend - p->vsend;
- var->bits_per_pixel = depth2bpp(p->depth);
-
- pm3fb_encode_depth(var, p->depth);
-
- base = pm3fb_Unshiftbpp(l_fb_info, p->depth, p->base);
-
- var->xoffset = base % var->xres;
- var->yoffset = base / var->xres;
-
var->height = var->width = -1;
- var->pixclock = KHZ2PICOS(p->pixclock);
-
- if ((p->video & PM3VideoControl_HSYNC_MASK) ==
- PM3VideoControl_HSYNC_ACTIVE_HIGH)
- var->sync |= FB_SYNC_HOR_HIGH_ACT;
- if ((p->video & PM3VideoControl_VSYNC_MASK) ==
- PM3VideoControl_VSYNC_ACTIVE_HIGH)
- var->sync |= FB_SYNC_VERT_HIGH_ACT;
- if (p->video & PM3VideoControl_LINE_DOUBLE_ON)
- var->vmode = FB_VMODE_DOUBLE;
-
- return (0);
-}
-
-static void pm3fb_get_par(void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
-
- if (!current_par_valid[l_fb_info->board_num]) {
- if (l_fb_info->use_current)
- pm3fb_read_mode(l_fb_info, l_fb_info->current_par);
- else
- memcpy(l_fb_info->current_par,
- &(mode_base[0].user_mode),
- sizeof(struct pm3fb_par));
- current_par_valid[l_fb_info->board_num] = 1;
+ if (var->xres != var->xres_virtual) {
+ DPRINTK("virtual x resolution != physical x resolution not supported\n");
+ return -EINVAL;
}
- *((struct pm3fb_par *) par) = *(l_fb_info->current_par);
-}
-static void pm3fb_set_par(const void *par, struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
-
- *(l_fb_info->current_par) = *((struct pm3fb_par *) par);
- current_par_valid[l_fb_info->board_num] = 1;
-
- pm3fb_write_mode(l_fb_info);
-
-#ifdef PM3FB_USE_ACCEL
- pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
-}
-
-static void pm3fb_set_color(struct pm3fb_info *l_fb_info,
- unsigned char regno, unsigned char r,
- unsigned char g, unsigned char b)
-{
- DTRACE;
-
- PM3_SLOW_WRITE_REG(PM3RD_PaletteWriteAddress, regno);
- PM3_SLOW_WRITE_REG(PM3RD_PaletteData, r);
- PM3_SLOW_WRITE_REG(PM3RD_PaletteData, g);
- PM3_SLOW_WRITE_REG(PM3RD_PaletteData, b);
-}
-
-static int pm3fb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
-
- if (regno < 256) {
- *red =
- l_fb_info->palette[regno].red << 8 | l_fb_info->
- palette[regno].red;
- *green =
- l_fb_info->palette[regno].green << 8 | l_fb_info->
- palette[regno].green;
- *blue =
- l_fb_info->palette[regno].blue << 8 | l_fb_info->
- palette[regno].blue;
- *transp =
- l_fb_info->palette[regno].transp << 8 | l_fb_info->
- palette[regno].transp;
+ if (var->yres > var->yres_virtual) {
+ DPRINTK("virtual y resolution < physical y resolution not possible\n");
+ return -EINVAL;
}
- return (regno > 255);
+
+ if (var->xoffset) {
+ DPRINTK("xoffset not supported\n");
+ return -EINVAL;
+ }
+
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ DPRINTK("interlace not supported\n");
+ return -EINVAL;
+ }
+
+ var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
+ lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
+
+ if (var->xres < 200 || var->xres > 2048) {
+ DPRINTK("width not supported: %u\n", var->xres);
+ return -EINVAL;
+ }
+
+ if (var->yres < 200 || var->yres > 4095) {
+ DPRINTK("height not supported: %u\n", var->yres);
+ return -EINVAL;
+ }
+
+ if (lpitch * var->yres_virtual > info->fix.smem_len) {
+ DPRINTK("no memory for screen (%ux%ux%u)\n",
+ var->xres, var->yres_virtual, var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
+ DPRINTK("pixclock too high (%ldKHz)\n", PICOS2KHZ(var->pixclock));
+ return -EINVAL;
+ }
+
+ var->accel_flags = 0; /* Can't mmap if this is on */
+
+ DPRINTK("Checking graphics mode at %dx%d depth %d\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return 0;
+}
+
+static int pm3fb_set_par(struct fb_info *info)
+{
+ struct pm3_par *par = info->par;
+ const u32 xres = (info->var.xres + 31) & ~31;
+ const int depth = (info->var.bits_per_pixel + 7) & ~7;
+
+ par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
+ (info->var.yoffset * xres)
+ + info->var.xoffset);
+ par->video = 0;
+
+ if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
+ else
+ par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
+
+ if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
+ else
+ par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
+
+ if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+ par->video |= PM3VideoControl_LINE_DOUBLE_ON;
+ else
+ par->video |= PM3VideoControl_LINE_DOUBLE_OFF;
+
+ if (info->var.activate == FB_ACTIVATE_NOW)
+ par->video |= PM3VideoControl_ENABLE;
+ else {
+ par->video |= PM3VideoControl_DISABLE;
+ DPRINTK("PM3Video disabled\n");
+ }
+ switch (depth) {
+ case 8:
+ par->video |= PM3VideoControl_PIXELSIZE_8BIT;
+ break;
+ case 12:
+ case 15:
+ case 16:
+ par->video |= PM3VideoControl_PIXELSIZE_16BIT;
+ break;
+ case 32:
+ par->video |= PM3VideoControl_PIXELSIZE_32BIT;
+ break;
+ default:
+ DPRINTK("Unsupported depth\n");
+ break;
+ }
+
+ info->fix.visual =
+ (depth == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ info->fix.line_length = ((info->var.xres_virtual + 7) & ~7)
+ * depth / 8;
+
+/* pm3fb_clear_memory(info, 0);*/
+ pm3fb_clear_colormap(par, 0, 0, 0);
+ PM3_WRITE_DAC_REG(par, PM3RD_CursorMode,
+ PM3RD_CursorMode_CURSOR_DISABLE);
+ pm3fb_write_mode(info);
+ return 0;
}
static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
+ struct pm3_par *par = info->par;
- DTRACE;
+ if (regno >= 256) /* no. of hw registers */
+ return -EINVAL;
- if (regno < 16) {
- switch (l_fb_info->current_par->depth) {
-#ifdef FBCON_HAS_CFB8
+ /* grayscale works only partially under directcolor */
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ /* Directcolor:
+ * var->{color}.offset contains start of bitfield
+ * var->{color}.length contains length of bitfield
+ * {hardwarespecific} contains width of DAC
+ * pseudo_palette[X] is programmed to (X << red.offset) |
+ * (X << green.offset) |
+ * (X << blue.offset)
+ * RAMDAC[X] is programmed to (red, green, blue)
+ * color depth = SUM(var->{color}.length)
+ *
+ * Pseudocolor:
+ * var->{color}.offset is 0
+ * var->{color}.length contains width of DAC or the number of unique
+ * colors available (color depth)
+ * pseudo_palette is not used
+ * RAMDAC[X] is programmed to (red, green, blue)
+ * color depth = var->{color}.length
+ */
+
+ /*
+ * This is the point where the color is converted to something that
+ * is acceptable by the hardware.
+ */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+#undef CNVT_TOHW
+
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ u32 v;
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+
+ switch (info->var.bits_per_pixel) {
case 8:
break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 12:
- l_fb_info->cmap.cmap12[regno] =
- (((u32) red & 0xf000) >> 4) |
- (((u32) green & 0xf000) >> 8) |
- (((u32) blue & 0xf000) >> 12);
- break;
-
- case 15:
- l_fb_info->cmap.cmap15[regno] =
- (((u32) red & 0xf800) >> 1) |
- (((u32) green & 0xf800) >> 6) |
- (((u32) blue & 0xf800) >> 11);
- break;
-
case 16:
- l_fb_info->cmap.cmap16[regno] =
- ((u32) red & 0xf800) |
- (((u32) green & 0xfc00) >> 5) |
- (((u32) blue & 0xf800) >> 11);
- break;
-#endif
-#ifdef FBCON_HAS_CFB32
+ case 24:
case 32:
- l_fb_info->cmap.cmap32[regno] =
- (((u32) transp & 0xff00) << 16) |
- (((u32) red & 0xff00) << 8) |
- (((u32) green & 0xff00)) |
- (((u32) blue & 0xff00) >> 8);
- break;
-#endif
- default:
- DPRINTK(1, "bad depth %u\n",
- l_fb_info->current_par->depth);
+ ((u32*)(info->pseudo_palette))[regno] = v;
break;
}
+ return 0;
}
- if (regno < 256) {
- l_fb_info->palette[regno].red = red >> 8;
- l_fb_info->palette[regno].green = green >> 8;
- l_fb_info->palette[regno].blue = blue >> 8;
- l_fb_info->palette[regno].transp = transp >> 8;
- if (l_fb_info->current_par->depth == 8)
- pm3fb_set_color(l_fb_info, regno, red >> 8,
- green >> 8, blue >> 8);
- }
- return (regno > 255);
+ else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
+ pm3fb_set_color(par, regno, red, green, blue);
+
+ return 0;
}
-static int pm3fb_blank(int blank_mode, struct fb_info_gen *info)
+static int pm3fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- u32 video;
+ struct pm3_par *par = info->par;
+ const u32 xres = (var->xres + 31) & ~31;
- DTRACE;
+ par->base = pm3fb_shift_bpp(var->bits_per_pixel,
+ (var->yoffset * xres)
+ + var->xoffset);
+ PM3_SLOW_WRITE_REG(par, PM3ScreenBase, par->base);
+ return 0;
+}
- if (!current_par_valid[l_fb_info->board_num])
- return (1);
-
- video = l_fb_info->current_par->video;
+static int pm3fb_blank(int blank_mode, struct fb_info *info)
+{
+ struct pm3_par *par = info->par;
+ u32 video = par->video;
/*
* Oxygen VX1 - it appears that setting PM3VideoControl and
@@ -3181,454 +663,345 @@
video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
PM3VideoControl_VSYNC_ACTIVE_HIGH;
- if (blank_mode > 0) {
- switch (blank_mode - 1) {
-
- case VESA_NO_BLANKING: /* FIXME */
- video = video & ~(PM3VideoControl_ENABLE);
- break;
-
- case VESA_HSYNC_SUSPEND:
- video = video & ~(PM3VideoControl_HSYNC_MASK |
- PM3VideoControl_BLANK_ACTIVE_LOW);
- break;
- case VESA_VSYNC_SUSPEND:
- video = video & ~(PM3VideoControl_VSYNC_MASK |
- PM3VideoControl_BLANK_ACTIVE_LOW);
- break;
- case VESA_POWERDOWN:
- video = video & ~(PM3VideoControl_HSYNC_MASK |
- PM3VideoControl_VSYNC_MASK |
- PM3VideoControl_BLANK_ACTIVE_LOW);
- break;
- default:
- DPRINTK(1, "Unsupported blanking %d\n",
- blank_mode);
- return (1);
- break;
- }
- }
-
- PM3_SLOW_WRITE_REG(PM3VideoControl, video);
-
- return (0);
-}
-
-static void pm3fb_set_disp(const void *par, struct display *disp,
- struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- struct pm3fb_par *p = (struct pm3fb_par *) par;
- u32 flags;
-
- DTRACE;
-
- local_irq_save(flags);
- info->info.screen_base = l_fb_info->v_fb;
- switch (p->depth) {
-#ifdef FBCON_HAS_CFB8
- case 8:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb8;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb8;
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ video = video | PM3VideoControl_ENABLE;
break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 12:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb16;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb16;
- disp->dispsw_data = l_fb_info->cmap.cmap12;
+ case FB_BLANK_NORMAL: /* FIXME */
+ video = video & ~(PM3VideoControl_ENABLE);
break;
- case 15:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb16;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb16;
- disp->dispsw_data = l_fb_info->cmap.cmap15;
+ case FB_BLANK_HSYNC_SUSPEND:
+ video = video & ~(PM3VideoControl_HSYNC_MASK |
+ PM3VideoControl_BLANK_ACTIVE_LOW);
break;
- case 16:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb16;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb16;
- disp->dispsw_data = l_fb_info->cmap.cmap16;
+ case FB_BLANK_VSYNC_SUSPEND:
+ video = video & ~(PM3VideoControl_VSYNC_MASK |
+ PM3VideoControl_BLANK_ACTIVE_LOW);
break;
-#endif
-#ifdef FBCON_HAS_CFB32
- case 32:
-#ifdef PM3FB_USE_ACCEL
- if (!(noaccel[l_fb_info->board_num]))
- disp->dispsw = &pm3fb_cfb32;
- else
-#endif /* PM3FB_USE_ACCEL */
- disp->dispsw = &fbcon_cfb32;
- disp->dispsw_data = l_fb_info->cmap.cmap32;
+ case FB_BLANK_POWERDOWN:
+ video = video & ~(PM3VideoControl_HSYNC_MASK |
+ PM3VideoControl_VSYNC_MASK |
+ PM3VideoControl_BLANK_ACTIVE_LOW);
break;
-#endif /* FBCON_HAS_CFB32 */
default:
- disp->dispsw = &fbcon_dummy;
- DPRINTK(1, "Invalid depth, using fbcon_dummy\n");
- break;
- }
- local_irq_restore(flags);
-}
-
-/* */
-static void pm3fb_detect(void)
-{
- struct pci_dev *dev_array[PM3_MAX_BOARD];
- struct pci_dev *dev = NULL;
- struct pm3fb_info *l_fb_info = &(fb_info[0]);
- unsigned long i, j, done;
-
- DTRACE;
-
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- dev_array[i] = NULL;
- fb_info[i].dev = NULL;
+ DPRINTK("Unsupported blanking %d\n", blank_mode);
+ return 1;
}
- dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
- PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
+ PM3_SLOW_WRITE_REG(par,PM3VideoControl, video);
- for (i = 0; ((i < PM3_MAX_BOARD) && dev); i++) {
- dev_array[i] = dev;
- dev = pci_get_device(PCI_VENDOR_ID_3DLABS,
- PCI_DEVICE_ID_3DLABS_PERMEDIA3, dev);
- }
-
- if (dev) { /* more than PM3_MAX_BOARD */
- printk(KERN_WARNING "pm3fb: Warning: more than %d boards found\n",
- PM3_MAX_BOARD);
- }
-
- if (!dev_array[0]) { /* not a single board, abort */
- return;
- }
-
- /* allocate user-defined boards */
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- if ((bus[i] >= 0) && (slot[i] >= 0) && (func[i] >= 0)) {
- for (j = 0; j < PM3_MAX_BOARD; j++) {
- if ((dev_array[j] != NULL) &&
- (dev_array[j]->bus->number == bus[i])
- && (PCI_SLOT(dev_array[j]->devfn) ==
- slot[i])
- && (PCI_FUNC(dev_array[j]->devfn) ==
- func[i])) {
- fb_info[i].dev = dev_array[j];
- dev_array[j] = NULL;
- }
- }
- }
- }
- /* allocate remaining boards */
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- if (fb_info[i].dev == NULL) {
- done = 0;
- for (j = 0; ((j < PM3_MAX_BOARD) && (!done)); j++) {
- if (dev_array[j] != NULL) {
- fb_info[i].dev = dev_array[j];
- dev_array[j] = NULL;
- done = 1;
- }
- }
- }
- }
-
- /* at that point, all PCI Permedia3 are detected and allocated */
- /* now, initialize... or not */
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- l_fb_info = &(fb_info[i]);
- if (l_fb_info->dev && !disable[i]) { /* PCI device was found and not disabled by user */
- DPRINTK(2,
- "found @%lx Vendor %lx Device %lx ; base @ : %lx - %lx - %lx - %lx - %lx - %lx, irq %ld\n",
- (unsigned long) l_fb_info->dev,
- (unsigned long) l_fb_info->dev->vendor,
- (unsigned long) l_fb_info->dev->device,
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 0),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 1),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 2),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 3),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 4),
- (unsigned long)
- pci_resource_start(l_fb_info->dev, 5),
- (unsigned long) l_fb_info->dev->irq);
-
- l_fb_info->pIOBase =
- (unsigned char *)
- pci_resource_start(l_fb_info->dev, 0);
-#ifdef __BIG_ENDIAN
- l_fb_info->pIOBase += PM3_REGS_SIZE;
-#endif
- l_fb_info->vIOBase = (unsigned char *) -1;
- l_fb_info->p_fb =
- (unsigned char *)
- pci_resource_start(l_fb_info->dev, 1);
- l_fb_info->v_fb = (unsigned char *) -1;
-
- if (!request_mem_region
- ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
- "pm3fb")) {
- printk
- (KERN_ERR "pm3fb: Error: couldn't request framebuffer memory, board #%ld\n",
- l_fb_info->board_num);
- continue;
- }
- if (!request_mem_region
- ((unsigned long)l_fb_info->pIOBase, PM3_REGS_SIZE,
- "pm3fb I/O regs")) {
- printk
- (KERN_ERR "pm3fb: Error: couldn't request IObase memory, board #%ld\n",
- l_fb_info->board_num);
- continue;
- }
- if (forcesize[l_fb_info->board_num])
- l_fb_info->fb_size = forcesize[l_fb_info->board_num];
-
- l_fb_info->fb_size =
- pm3fb_size_memory(l_fb_info);
- if (l_fb_info->fb_size) {
- (void) pci_enable_device(l_fb_info->dev);
- pm3fb_common_init(l_fb_info);
- } else
- printk(KERN_ERR "pm3fb: memory problem, not enabling board #%ld\n", l_fb_info->board_num);
- }
- }
-}
-
-static int pm3fb_pan_display(const struct fb_var_screeninfo *var,
- struct fb_info_gen *info)
-{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
-
- DTRACE;
-
- if (!current_par_valid[l_fb_info->board_num])
- return -EINVAL;
-
- l_fb_info->current_par->base = /* in 128 bits chunk - i.e. AFTER Shiftbpp */
- pm3fb_Shiftbpp(l_fb_info,
- l_fb_info->current_par->depth,
- (var->yoffset * l_fb_info->current_par->width) +
- var->xoffset);
- PM3_SLOW_WRITE_REG(PM3ScreenBase, l_fb_info->current_par->base);
return 0;
}
-static int pm3fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
+ /*
+ * Frame buffer operations
+ */
+
+static struct fb_ops pm3fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = pm3fb_check_var,
+ .fb_set_par = pm3fb_set_par,
+ .fb_setcolreg = pm3fb_setcolreg,
+ .fb_pan_display = pm3fb_pan_display,
+ .fb_fillrect = cfb_fillrect, /* Needed !!! */
+ .fb_copyarea = cfb_copyarea, /* Needed !!! */
+ .fb_imageblit = cfb_imageblit, /* Needed !!! */
+ .fb_blank = pm3fb_blank,
+};
+
+/* ------------------------------------------------------------------------- */
+
+ /*
+ * Initialization
+ */
+
+/* mmio register are already mapped when this function is called */
+/* the pm3fb_fix.smem_start is also set */
+static unsigned long pm3fb_size_memory(struct pm3_par *par)
{
- struct pm3fb_info *l_fb_info = (struct pm3fb_info *) info;
- u32 cm, i;
-#ifdef PM3FB_MASTER_DEBUG
- char cc[3];
-#endif /* PM3FB_MASTER_DEBUG */
+ unsigned long memsize = 0, tempBypass, i, temp1, temp2;
+ unsigned char __iomem *screen_mem;
- switch(cmd)
+ pm3fb_fix.smem_len = 64 * 1024 * 1024; /* request full aperture size */
+ /* Linear frame buffer - request region and map it. */
+ if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+ "pm3fb smem")) {
+ printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+ return 0;
+ }
+ screen_mem =
+ ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ if (!screen_mem) {
+ printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ return 0;
+ }
+
+ /* TODO: card-specific stuff, *before* accessing *any* FB memory */
+ /* For Appian Jeronimo 2000 board second head */
+
+ tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
+
+ DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
+
+ PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
+
+ /* pm3 split up memory, replicates, and do a lot of nasty stuff IMHO ;-) */
+ for (i = 0; i < 32; i++) {
+ fb_writel(i * 0x00345678,
+ (screen_mem + (i * 1048576)));
+ mb();
+ temp1 = fb_readl((screen_mem + (i * 1048576)));
+
+ /* Let's check for wrapover, write will fail at 16MB boundary */
+ if (temp1 == (i * 0x00345678))
+ memsize = i;
+ else
+ break;
+ }
+
+ DPRINTK("First detect pass already got %ld MB\n", memsize + 1);
+
+ if (memsize + 1 == i) {
+ for (i = 0; i < 32; i++) {
+ /* Clear first 32MB ; 0 is 0, no need to byteswap */
+ writel(0x0000000,
+ (screen_mem + (i * 1048576)));
+ mb();
+ }
+
+ for (i = 32; i < 64; i++) {
+ fb_writel(i * 0x00345678,
+ (screen_mem + (i * 1048576)));
+ mb();
+ temp1 =
+ fb_readl((screen_mem + (i * 1048576)));
+ temp2 =
+ fb_readl((screen_mem + ((i - 32) * 1048576)));
+ /* different value, different RAM... */
+ if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
+ memsize = i;
+ else
+ break;
+ }
+ }
+ DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
+
+ PM3_SLOW_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
+
+ iounmap(screen_mem);
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ memsize = 1048576 * (memsize + 1);
+
+ DPRINTK("Returning 0x%08lx bytes\n", memsize);
+
+ return memsize;
+}
+
+static int __devinit pm3fb_probe(struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ struct fb_info *info;
+ struct pm3_par *par;
+ struct device* device = &dev->dev; /* for pci drivers */
+ int err, retval = -ENXIO;
+
+ err = pci_enable_device(dev);
+ if (err) {
+ printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);
+ return err;
+ }
+ /*
+ * Dynamically allocate info and par
+ */
+ info = framebuffer_alloc(sizeof(struct pm3_par), device);
+
+ if (!info)
+ return -ENOMEM;
+ par = info->par;
+
+ /*
+ * Here we set the screen_base to the virtual memory address
+ * for the framebuffer.
+ */
+ pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
+ pm3fb_fix.mmio_len = PM3_REGS_SIZE;
+
+ /* Registers - request region and map it. */
+ if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
+ "pm3fb regbase")) {
+ printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");
+ goto err_exit_neither;
+ }
+ par->v_regs =
+ ioremap_nocache(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ if (!par->v_regs) {
+ printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
+ pm3fb_fix.id);
+ release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ goto err_exit_neither;
+ }
+
+#if defined(__BIG_ENDIAN)
+ pm3fb_fix.mmio_start += PM3_REGS_SIZE;
+ DPRINTK("Adjusting register base for big-endian.\n");
+#endif
+ /* Linear frame buffer - request region and map it. */
+ pm3fb_fix.smem_start = pci_resource_start(dev, 1);
+ pm3fb_fix.smem_len = pm3fb_size_memory(par);
+ if (!pm3fb_fix.smem_len)
{
-#ifdef PM3FB_MASTER_DEBUG
- case PM3FBIO_CLEARMEMORY:
- if (copy_from_user(&cm, (void *)arg, sizeof(u32)))
- return(-EFAULT);
- pm3fb_clear_memory(l_fb_info, cm);
- return(0);
- break;
+ printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
+ goto err_exit_mmio;
+ }
+ if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
+ "pm3fb smem")) {
+ printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
+ goto err_exit_mmio;
+ }
+ info->screen_base =
+ ioremap_nocache(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ if (!info->screen_base) {
+ printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ goto err_exit_mmio;
+ }
+ info->screen_size = pm3fb_fix.smem_len;
- case PM3FBIO_CLEARCMAP:
- if (copy_from_user(cc, (void*)arg, 3 * sizeof(char)))
- return(-EFAULT);
- pm3fb_clear_colormap(l_fb_info, cc[0], cc[1], cc[2]);
- return(0);
- break;
-#endif /* PM3FB_MASTER_DEBUG */
+ info->fbops = &pm3fb_ops;
- case PM3FBIO_RESETCHIP:
- cm = 1;
- PM3_SLOW_WRITE_REG(PM3ResetStatus, 1);
- for (i = 0 ; (i < 10000) && cm ; i++)
- {
- PM3_DELAY(10);
- cm = PM3_READ_REG(PM3ResetStatus);
- }
- if (cm)
- {
- printk(KERN_ERR "pm3fb: chip reset failed with status 0x%x\n", cm);
- return(-EIO);
- }
- /* first thing first, reload memory timings */
- pm3fb_write_memory_timings(l_fb_info);
-#ifdef PM3FB_USE_ACCEL
- pm3fb_init_engine(l_fb_info);
-#endif /* PM3FB_USE_ACCEL */
- pm3fb_write_mode(l_fb_info);
- return(0);
- break;
+ par->video = PM3_READ_REG(par, PM3VideoControl);
- default:
- DPRINTK(2, "unknown ioctl: %d (%x)\n", cmd, cmd);
- return(-EINVAL);
+ info->fix = pm3fb_fix;
+ info->pseudo_palette = par->palette;
+ info->flags = FBINFO_DEFAULT;/* | FBINFO_HWACCEL_YPAN;*/
+
+ /*
+ * This should give a reasonable default video mode. The following is
+ * done when we can set a video mode.
+ */
+ if (!mode_option)
+ mode_option = "640x480@60";
+
+ retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
+
+ if (!retval || retval == 4) {
+ retval = -EINVAL;
+ goto err_exit_both;
+ }
+
+ /* This has to been done !!! */
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ retval = -ENOMEM;
+ goto err_exit_both;
+ }
+
+ /*
+ * For drivers that can...
+ */
+ pm3fb_check_var(&info->var, info);
+
+ if (register_framebuffer(info) < 0) {
+ retval = -EINVAL;
+ goto err_exit_all;
+ }
+ printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
+ info->fix.id);
+ pci_set_drvdata(dev, info); /* or dev_set_drvdata(device, info) */
+ return 0;
+
+ err_exit_all:
+ fb_dealloc_cmap(&info->cmap);
+ err_exit_both:
+ iounmap(info->screen_base);
+ release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
+ err_exit_mmio:
+ iounmap(par->v_regs);
+ release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
+ err_exit_neither:
+ framebuffer_release(info);
+ return retval;
+}
+
+ /*
+ * Cleanup
+ */
+static void __devexit pm3fb_remove(struct pci_dev *dev)
+{
+ struct fb_info *info = pci_get_drvdata(dev);
+
+ if (info) {
+ struct fb_fix_screeninfo *fix = &info->fix;
+ struct pm3_par *par = info->par;
+
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+
+ iounmap(info->screen_base);
+ release_mem_region(fix->smem_start, fix->smem_len);
+ iounmap(par->v_regs);
+ release_mem_region(fix->mmio_start, fix->mmio_len);
+
+ pci_set_drvdata(dev, NULL);
+ framebuffer_release(info);
}
}
-/* ****************************************** */
-/* ***** standard FB API init functions ***** */
-/* ****************************************** */
+static struct pci_device_id pm3fb_id_table[] = {
+ { PCI_VENDOR_ID_3DLABS, 0x0a,
+ PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+ 0xff0000, 0 },
+ { 0, }
+};
-int __init pm3fb_setup(char *options)
-{
- long opsi = strlen(options);
+/* For PCI drivers */
+static struct pci_driver pm3fb_driver = {
+ .name = "pm3fb",
+ .id_table = pm3fb_id_table,
+ .probe = pm3fb_probe,
+ .remove = __devexit_p(pm3fb_remove),
+};
- DTRACE;
-
- memcpy(g_options, options,
- ((opsi + 1) >
- PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
- g_options[PM3_OPTIONS_SIZE - 1] = 0;
-
- return (0);
-}
+MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
int __init pm3fb_init(void)
{
- DTRACE;
+ /*
+ * For kernel boot options (in 'video=pm3fb:<options>' format)
+ */
+#ifndef MODULE
+ char *option = NULL;
- DPRINTK(2, "This is pm3fb.c, CVS version: $Header: /cvsroot/linux/drivers/video/pm3fb.c,v 1.1 2002/02/25 19:11:06 marcelo Exp $");
+ if (fb_get_options("pm3fb", &option))
+ return -ENODEV;
+ pm3fb_setup(option);
+#endif
- pm3fb_real_setup(g_options);
-
- pm3fb_detect();
-
- if (!fb_info[0].dev) { /* not even one board ??? */
- DPRINTK(1, "No PCI Permedia3 board detected\n");
- }
- return (0);
+ return pci_register_driver(&pm3fb_driver);
}
-/* ************************* */
-/* **** Module support ***** */
-/* ************************* */
+static void __exit pm3fb_exit(void)
+{
+ pci_unregister_driver(&pm3fb_driver);
+}
#ifdef MODULE
-MODULE_AUTHOR("Romain Dolbeau");
-MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
-static char *mode[PM3_MAX_BOARD];
-module_param_array(mode, charp, NULL, 0);
-MODULE_PARM_DESC(mode,"video mode");
-module_param_array(disable, short, NULL, 0);
-MODULE_PARM_DESC(disable,"disable board");
-static short off[PM3_MAX_BOARD];
-module_param_array(off, short, NULL, 0);
-MODULE_PARM_DESC(off,"disable board");
-static char *pciid[PM3_MAX_BOARD];
-module_param_array(pciid, charp, NULL, 0);
-MODULE_PARM_DESC(pciid,"board PCI Id");
-module_param_array(noaccel, short, NULL, 0);
-MODULE_PARM_DESC(noaccel,"disable accel");
-static char *font[PM3_MAX_BOARD];
-module_param_array(font, charp, NULL, 0);
-MODULE_PARM_DESC(font,"choose font");
-module_param(depth, short, NULL, 0);
-MODULE_PARM_DESC(depth,"boot-time depth");
-module_param(printtimings, short, NULL, 0);
-MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
-module_param(forcesize, short, NULL, 0);
-MODULE_PARM_DESC(forcesize, "force specified memory size");
+ /*
+ * Setup
+ */
+
/*
-MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
-MODULE_GENERIC_TABLE(gtype,name)
-MODULE_DEVICE_TABLE(type,name)
-*/
-
-void pm3fb_build_options(void)
+ * Only necessary if your driver takes special options,
+ * otherwise we fall back on the generic fb_setup().
+ */
+int __init pm3fb_setup(char *options)
{
- int i;
- char ts[128];
-
- strcpy(g_options, "pm3fb");
- for (i = 0; i < PM3_MAX_BOARD ; i++)
- {
- if (mode[i])
- {
- sprintf(ts, ",mode:%d:%s", i, mode[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (disable[i] || off[i])
- {
- sprintf(ts, ",disable:%d:", i);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (pciid[i])
- {
- sprintf(ts, ",pciid:%d:%s", i, pciid[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (noaccel[i])
- {
- sprintf(ts, ",noaccel:%d:", i);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (font[i])
- {
- sprintf(ts, ",font:%d:%s", i, font[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- if (depth[i])
- {
- sprintf(ts, ",depth:%d:%d", i, depth[i]);
- strncat(g_options, ts, PM3_OPTIONS_SIZE - strlen(g_options));
- }
- }
- g_options[PM3_OPTIONS_SIZE - 1] = '\0';
- DPRINTK(1, "pm3fb use options: %s\n", g_options);
-}
-
-int init_module(void)
-{
- DTRACE;
-
- pm3fb_build_options();
-
- pm3fb_init();
-
+ /* Parse user speficied options (`video=pm3fb:') */
return 0;
}
-
-void cleanup_module(void)
-{
- DTRACE;
- {
- unsigned long i;
- struct pm3fb_info *l_fb_info;
- for (i = 0; i < PM3_MAX_BOARD; i++) {
- l_fb_info = &(fb_info[i]);
- pci_dev_put(l_fb_info->dev);
- if (l_fb_info->dev != NULL && !(disable[l_fb_info->board_num])) {
- if (l_fb_info->vIOBase != (unsigned char *) -1) {
- pm3fb_unmapIO(l_fb_info);
- release_mem_region(l_fb_info->p_fb,
- l_fb_info->fb_size);
- release_mem_region(l_fb_info->pIOBase,
- PM3_REGS_SIZE);
- }
- unregister_framebuffer(&l_fb_info->gen.info);
- }
- }
- }
-}
#endif /* MODULE */
+
+module_init(pm3fb_init);
+module_exit(pm3fb_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 76e6ce3..a0e22ac 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -70,8 +70,6 @@
if (VGA_RD08(par->riva.PCIO, 0x3d5) & 0x04)
val = 1;
- val = VGA_RD08(par->riva.PCIO, 0x3d5);
-
return val;
}
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index c287a9a..ca75b3a 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -1,4 +1,5 @@
menu "Dallas's 1-wire bus"
+ depends on HAS_IOMEM
config W1
tristate "Dallas's 1-wire support"
diff --git a/fs/Makefile b/fs/Makefile
index 9edf411..720c29d 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -22,6 +22,10 @@
obj-$(CONFIG_INOTIFY) += inotify.o
obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
obj-$(CONFIG_EPOLL) += eventpoll.o
+obj-$(CONFIG_ANON_INODES) += anon_inodes.o
+obj-$(CONFIG_SIGNALFD) += signalfd.o
+obj-$(CONFIG_TIMERFD) += timerfd.o
+obj-$(CONFIG_EVENTFD) += eventfd.o
obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
nfsd-$(CONFIG_NFSD) := nfsctl.o
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index 52d0752..2452579 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -16,6 +16,9 @@
#define AFS_MAXCELLNAME 64 /* maximum length of a cell name */
#define AFS_MAXVOLNAME 64 /* maximum length of a volume name */
+#define AFSNAMEMAX 256 /* maximum length of a filename plus NUL */
+#define AFSPATHMAX 1024 /* maximum length of a pathname plus NUL */
+#define AFSOPAQUEMAX 1024 /* maximum length of an opaque field */
typedef unsigned afs_volid_t;
typedef unsigned afs_vnodeid_t;
@@ -143,4 +146,24 @@
time_t creation; /* volume creation time */
};
+/*
+ * AFS volume status record
+ */
+struct afs_volume_status {
+ u32 vid; /* volume ID */
+ u32 parent_id; /* parent volume ID */
+ u8 online; /* true if volume currently online and available */
+ u8 in_service; /* true if volume currently in service */
+ u8 blessed; /* same as in_service */
+ u8 needs_salvage; /* true if consistency checking required */
+ u32 type; /* volume type (afs_voltype_t) */
+ u32 min_quota; /* minimum space set aside (blocks) */
+ u32 max_quota; /* maximum space this volume may occupy (blocks) */
+ u32 blocks_in_use; /* space this volume currently occupies (blocks) */
+ u32 part_blocks_avail; /* space available in volume's partition */
+ u32 part_max_blocks; /* size of volume's partition */
+};
+
+#define AFS_BLOCK_SIZE 1024
+
#endif /* AFS_H */
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h
index 2198006..a18c374 100644
--- a/fs/afs/afs_fs.h
+++ b/fs/afs/afs_fs.h
@@ -28,9 +28,12 @@
FSMAKEDIR = 141, /* AFS Create a directory */
FSREMOVEDIR = 142, /* AFS Remove a directory */
FSGIVEUPCALLBACKS = 147, /* AFS Discard callback promises */
- FSGETVOLUMEINFO = 148, /* AFS Get root volume information */
+ FSGETVOLUMEINFO = 148, /* AFS Get information about a volume */
+ FSGETVOLUMESTATUS = 149, /* AFS Get volume status information */
FSGETROOTVOLUME = 151, /* AFS Get root volume name */
FSLOOKUP = 161, /* AFS lookup file in directory */
+ FSFETCHDATA64 = 65537, /* AFS Fetch file data */
+ FSSTOREDATA64 = 65538, /* AFS Store file data */
};
enum AFS_FS_Errors {
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 2fb3127..719af4f 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -497,7 +497,7 @@
ASSERTCMP(dentry->d_inode, ==, NULL);
- if (dentry->d_name.len > 255) {
+ if (dentry->d_name.len >= AFSNAMEMAX) {
_leave(" = -ENAMETOOLONG");
return ERR_PTR(-ENAMETOOLONG);
}
@@ -736,7 +736,7 @@
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
ret = -ENAMETOOLONG;
- if (dentry->d_name.len > 255)
+ if (dentry->d_name.len >= AFSNAMEMAX)
goto error;
key = afs_request_key(dvnode->volume->cell);
@@ -801,7 +801,7 @@
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
ret = -ENAMETOOLONG;
- if (dentry->d_name.len > 255)
+ if (dentry->d_name.len >= AFSNAMEMAX)
goto error;
key = afs_request_key(dvnode->volume->cell);
@@ -847,7 +847,7 @@
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
ret = -ENAMETOOLONG;
- if (dentry->d_name.len > 255)
+ if (dentry->d_name.len >= AFSNAMEMAX)
goto error;
key = afs_request_key(dvnode->volume->cell);
@@ -921,7 +921,7 @@
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
ret = -ENAMETOOLONG;
- if (dentry->d_name.len > 255)
+ if (dentry->d_name.len >= AFSNAMEMAX)
goto error;
key = afs_request_key(dvnode->volume->cell);
@@ -990,7 +990,7 @@
dentry->d_name.name);
ret = -ENAMETOOLONG;
- if (dentry->d_name.len > 255)
+ if (dentry->d_name.len >= AFSNAMEMAX)
goto error;
key = afs_request_key(dvnode->volume->cell);
@@ -1038,11 +1038,11 @@
content);
ret = -ENAMETOOLONG;
- if (dentry->d_name.len > 255)
+ if (dentry->d_name.len >= AFSNAMEMAX)
goto error;
ret = -EINVAL;
- if (strlen(content) > 1023)
+ if (strlen(content) >= AFSPATHMAX)
goto error;
key = afs_request_key(dvnode->volume->cell);
@@ -1112,7 +1112,7 @@
new_dentry->d_name.name);
ret = -ENAMETOOLONG;
- if (new_dentry->d_name.len > 255)
+ if (new_dentry->d_name.len >= AFSNAMEMAX)
goto error;
key = afs_request_key(orig_dvnode->volume->cell);
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 3e25795..9c0e721 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -236,7 +236,7 @@
{
int ret = 1;
- kenter("{%lu},%lu", page->index, offset);
+ _enter("{%lu},%lu", page->index, offset);
BUG_ON(!PageLocked(page));
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 025b190..5dff130 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -202,6 +202,29 @@
}
/*
+ * decode an AFSFetchVolumeStatus block
+ */
+static void xdr_decode_AFSFetchVolumeStatus(const __be32 **_bp,
+ struct afs_volume_status *vs)
+{
+ const __be32 *bp = *_bp;
+
+ vs->vid = ntohl(*bp++);
+ vs->parent_id = ntohl(*bp++);
+ vs->online = ntohl(*bp++);
+ vs->in_service = ntohl(*bp++);
+ vs->blessed = ntohl(*bp++);
+ vs->needs_salvage = ntohl(*bp++);
+ vs->type = ntohl(*bp++);
+ vs->min_quota = ntohl(*bp++);
+ vs->max_quota = ntohl(*bp++);
+ vs->blocks_in_use = ntohl(*bp++);
+ vs->part_blocks_avail = ntohl(*bp++);
+ vs->part_max_blocks = ntohl(*bp++);
+ *_bp = bp;
+}
+
+/*
* deliver reply data to an FS.FetchStatus
*/
static int afs_deliver_fs_fetch_status(struct afs_call *call,
@@ -293,9 +316,33 @@
case 0:
call->offset = 0;
call->unmarshall++;
+ if (call->operation_ID != FSFETCHDATA64) {
+ call->unmarshall++;
+ goto no_msw;
+ }
- /* extract the returned data length */
+ /* extract the upper part of the returned data length of an
+ * FSFETCHDATA64 op (which should always be 0 using this
+ * client) */
case 1:
+ _debug("extract data length (MSW)");
+ ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ call->count = ntohl(call->tmp);
+ _debug("DATA length MSW: %u", call->count);
+ if (call->count > 0)
+ return -EBADMSG;
+ call->offset = 0;
+ call->unmarshall++;
+
+ no_msw:
+ /* extract the returned data length */
+ case 2:
_debug("extract data length");
ret = afs_extract_data(call, skb, last, &call->tmp, 4);
switch (ret) {
@@ -312,7 +359,7 @@
call->unmarshall++;
/* extract the returned data */
- case 2:
+ case 3:
_debug("extract data");
if (call->count > 0) {
page = call->reply3;
@@ -331,7 +378,7 @@
call->unmarshall++;
/* extract the metadata */
- case 3:
+ case 4:
ret = afs_extract_data(call, skb, last, call->buffer,
(21 + 3 + 6) * 4);
switch (ret) {
@@ -349,7 +396,7 @@
call->offset = 0;
call->unmarshall++;
- case 4:
+ case 5:
_debug("trailer");
if (skb->len != 0)
return -EBADMSG;
@@ -381,6 +428,56 @@
.destructor = afs_flat_call_destructor,
};
+static const struct afs_call_type afs_RXFSFetchData64 = {
+ .name = "FS.FetchData64",
+ .deliver = afs_deliver_fs_fetch_data,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * fetch data from a very large file
+ */
+static int afs_fs_fetch_data64(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ off_t offset, size_t length,
+ struct page *buffer,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter("");
+
+ ASSERTCMP(length, <, ULONG_MAX);
+
+ call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->reply2 = NULL; /* volsync */
+ call->reply3 = buffer;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+ call->operation_ID = FSFETCHDATA64;
+
+ /* marshall the parameters */
+ bp = call->request;
+ bp[0] = htonl(FSFETCHDATA64);
+ bp[1] = htonl(vnode->fid.vid);
+ bp[2] = htonl(vnode->fid.vnode);
+ bp[3] = htonl(vnode->fid.unique);
+ bp[4] = htonl(upper_32_bits(offset));
+ bp[5] = htonl((u32) offset);
+ bp[6] = 0;
+ bp[7] = htonl((u32) length);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
/*
* fetch data from a file
*/
@@ -394,6 +491,10 @@
struct afs_call *call;
__be32 *bp;
+ if (upper_32_bits(offset) || upper_32_bits(offset + length))
+ return afs_fs_fetch_data64(server, key, vnode, offset, length,
+ buffer, wait_mode);
+
_enter("");
call = afs_alloc_flat_call(&afs_RXFSFetchData, 24, (21 + 3 + 6) * 4);
@@ -406,6 +507,7 @@
call->reply3 = buffer;
call->service_id = FS_SERVICE;
call->port = htons(AFS_FS_PORT);
+ call->operation_ID = FSFETCHDATA;
/* marshall the parameters */
bp = call->request;
@@ -1032,6 +1134,73 @@
.destructor = afs_flat_call_destructor,
};
+static const struct afs_call_type afs_RXFSStoreData64 = {
+ .name = "FS.StoreData64",
+ .deliver = afs_deliver_fs_store_data,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * store a set of pages to a very large file
+ */
+static int afs_fs_store_data64(struct afs_server *server,
+ struct afs_writeback *wb,
+ pgoff_t first, pgoff_t last,
+ unsigned offset, unsigned to,
+ loff_t size, loff_t pos, loff_t i_size,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_vnode *vnode = wb->vnode;
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter(",%x,{%x:%u},,",
+ key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
+
+ call = afs_alloc_flat_call(&afs_RXFSStoreData64,
+ (4 + 6 + 3 * 2) * 4,
+ (21 + 6) * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->wb = wb;
+ call->key = wb->key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+ call->mapping = vnode->vfs_inode.i_mapping;
+ call->first = first;
+ call->last = last;
+ call->first_offset = offset;
+ call->last_to = to;
+ call->send_pages = true;
+ call->store_version = vnode->status.data_version + 1;
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSSTOREDATA64);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ *bp++ = 0; /* mask */
+ *bp++ = 0; /* mtime */
+ *bp++ = 0; /* owner */
+ *bp++ = 0; /* group */
+ *bp++ = 0; /* unix mode */
+ *bp++ = 0; /* segment size */
+
+ *bp++ = htonl(pos >> 32);
+ *bp++ = htonl((u32) pos);
+ *bp++ = htonl(size >> 32);
+ *bp++ = htonl((u32) size);
+ *bp++ = htonl(i_size >> 32);
+ *bp++ = htonl((u32) i_size);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
/*
* store a set of pages
*/
@@ -1062,7 +1231,9 @@
(unsigned long long) size, (unsigned long long) pos,
(unsigned long long) i_size);
- BUG_ON(i_size > 0xffffffff); // TODO: use 64-bit store
+ if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
+ return afs_fs_store_data64(server, wb, first, last, offset, to,
+ size, pos, i_size, wait_mode);
call = afs_alloc_flat_call(&afs_RXFSStoreData,
(4 + 6 + 3) * 4,
@@ -1158,6 +1329,61 @@
.destructor = afs_flat_call_destructor,
};
+static const struct afs_call_type afs_RXFSStoreData64_as_Status = {
+ .name = "FS.StoreData64",
+ .deliver = afs_deliver_fs_store_status,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_flat_call_destructor,
+};
+
+/*
+ * set the attributes on a very large file, using FS.StoreData rather than
+ * FS.StoreStatus so as to alter the file size also
+ */
+static int afs_fs_setattr_size64(struct afs_server *server, struct key *key,
+ struct afs_vnode *vnode, struct iattr *attr,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+
+ _enter(",%x,{%x:%u},,",
+ key_serial(key), vnode->fid.vid, vnode->fid.vnode);
+
+ ASSERT(attr->ia_valid & ATTR_SIZE);
+
+ call = afs_alloc_flat_call(&afs_RXFSStoreData64_as_Status,
+ (4 + 6 + 3 * 2) * 4,
+ (21 + 6) * 4);
+ if (!call)
+ return -ENOMEM;
+
+ call->key = key;
+ call->reply = vnode;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+ call->store_version = vnode->status.data_version + 1;
+ call->operation_ID = FSSTOREDATA;
+
+ /* marshall the parameters */
+ bp = call->request;
+ *bp++ = htonl(FSSTOREDATA64);
+ *bp++ = htonl(vnode->fid.vid);
+ *bp++ = htonl(vnode->fid.vnode);
+ *bp++ = htonl(vnode->fid.unique);
+
+ xdr_encode_AFS_StoreStatus(&bp, attr);
+
+ *bp++ = 0; /* position of start of write */
+ *bp++ = 0;
+ *bp++ = 0; /* size of write */
+ *bp++ = 0;
+ *bp++ = htonl(attr->ia_size >> 32); /* new file length */
+ *bp++ = htonl((u32) attr->ia_size);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
+
/*
* set the attributes on a file, using FS.StoreData rather than FS.StoreStatus
* so as to alter the file size also
@@ -1173,7 +1399,9 @@
key_serial(key), vnode->fid.vid, vnode->fid.vnode);
ASSERT(attr->ia_valid & ATTR_SIZE);
- ASSERTCMP(attr->ia_size, <=, 0xffffffff); // TODO: use 64-bit store
+ if (attr->ia_size >> 32)
+ return afs_fs_setattr_size64(server, key, vnode, attr,
+ wait_mode);
call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status,
(4 + 6 + 3) * 4,
@@ -1245,3 +1473,278 @@
return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
}
+
+/*
+ * deliver reply data to an FS.GetVolumeStatus
+ */
+static int afs_deliver_fs_get_volume_status(struct afs_call *call,
+ struct sk_buff *skb, bool last)
+{
+ const __be32 *bp;
+ char *p;
+ int ret;
+
+ _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+ switch (call->unmarshall) {
+ case 0:
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the returned status record */
+ case 1:
+ _debug("extract status");
+ ret = afs_extract_data(call, skb, last, call->buffer,
+ 12 * 4);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ bp = call->buffer;
+ xdr_decode_AFSFetchVolumeStatus(&bp, call->reply2);
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the volume name length */
+ case 2:
+ ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ call->count = ntohl(call->tmp);
+ _debug("volname length: %u", call->count);
+ if (call->count >= AFSNAMEMAX)
+ return -EBADMSG;
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the volume name */
+ case 3:
+ _debug("extract volname");
+ if (call->count > 0) {
+ ret = afs_extract_data(call, skb, last, call->reply3,
+ call->count);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+ }
+
+ p = call->reply3;
+ p[call->count] = 0;
+ _debug("volname '%s'", p);
+
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the volume name padding */
+ if ((call->count & 3) == 0) {
+ call->unmarshall++;
+ goto no_volname_padding;
+ }
+ call->count = 4 - (call->count & 3);
+
+ case 4:
+ ret = afs_extract_data(call, skb, last, call->buffer,
+ call->count);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ call->offset = 0;
+ call->unmarshall++;
+ no_volname_padding:
+
+ /* extract the offline message length */
+ case 5:
+ ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ call->count = ntohl(call->tmp);
+ _debug("offline msg length: %u", call->count);
+ if (call->count >= AFSNAMEMAX)
+ return -EBADMSG;
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the offline message */
+ case 6:
+ _debug("extract offline");
+ if (call->count > 0) {
+ ret = afs_extract_data(call, skb, last, call->reply3,
+ call->count);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+ }
+
+ p = call->reply3;
+ p[call->count] = 0;
+ _debug("offline '%s'", p);
+
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the offline message padding */
+ if ((call->count & 3) == 0) {
+ call->unmarshall++;
+ goto no_offline_padding;
+ }
+ call->count = 4 - (call->count & 3);
+
+ case 7:
+ ret = afs_extract_data(call, skb, last, call->buffer,
+ call->count);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ call->offset = 0;
+ call->unmarshall++;
+ no_offline_padding:
+
+ /* extract the message of the day length */
+ case 8:
+ ret = afs_extract_data(call, skb, last, &call->tmp, 4);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ call->count = ntohl(call->tmp);
+ _debug("motd length: %u", call->count);
+ if (call->count >= AFSNAMEMAX)
+ return -EBADMSG;
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the message of the day */
+ case 9:
+ _debug("extract motd");
+ if (call->count > 0) {
+ ret = afs_extract_data(call, skb, last, call->reply3,
+ call->count);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+ }
+
+ p = call->reply3;
+ p[call->count] = 0;
+ _debug("motd '%s'", p);
+
+ call->offset = 0;
+ call->unmarshall++;
+
+ /* extract the message of the day padding */
+ if ((call->count & 3) == 0) {
+ call->unmarshall++;
+ goto no_motd_padding;
+ }
+ call->count = 4 - (call->count & 3);
+
+ case 10:
+ ret = afs_extract_data(call, skb, last, call->buffer,
+ call->count);
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ call->offset = 0;
+ call->unmarshall++;
+ no_motd_padding:
+
+ case 11:
+ _debug("trailer %d", skb->len);
+ if (skb->len != 0)
+ return -EBADMSG;
+ break;
+ }
+
+ if (!last)
+ return 0;
+
+ _leave(" = 0 [done]");
+ return 0;
+}
+
+/*
+ * destroy an FS.GetVolumeStatus call
+ */
+static void afs_get_volume_status_call_destructor(struct afs_call *call)
+{
+ kfree(call->reply3);
+ call->reply3 = NULL;
+ afs_flat_call_destructor(call);
+}
+
+/*
+ * FS.GetVolumeStatus operation type
+ */
+static const struct afs_call_type afs_RXFSGetVolumeStatus = {
+ .name = "FS.GetVolumeStatus",
+ .deliver = afs_deliver_fs_get_volume_status,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_get_volume_status_call_destructor,
+};
+
+/*
+ * fetch the status of a volume
+ */
+int afs_fs_get_volume_status(struct afs_server *server,
+ struct key *key,
+ struct afs_vnode *vnode,
+ struct afs_volume_status *vs,
+ const struct afs_wait_mode *wait_mode)
+{
+ struct afs_call *call;
+ __be32 *bp;
+ void *tmpbuf;
+
+ _enter("");
+
+ tmpbuf = kmalloc(AFSOPAQUEMAX, GFP_KERNEL);
+ if (!tmpbuf)
+ return -ENOMEM;
+
+ call = afs_alloc_flat_call(&afs_RXFSGetVolumeStatus, 2 * 4, 12 * 4);
+ if (!call) {
+ kfree(tmpbuf);
+ return -ENOMEM;
+ }
+
+ call->key = key;
+ call->reply = vnode;
+ call->reply2 = vs;
+ call->reply3 = tmpbuf;
+ call->service_id = FS_SERVICE;
+ call->port = htons(AFS_FS_PORT);
+
+ /* marshall the parameters */
+ bp = call->request;
+ bp[0] = htonl(FSGETVOLUMESTATUS);
+ bp[1] = htonl(vnode->fid.vid);
+
+ return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
+}
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 515a5d1..47f5fed 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -209,11 +209,15 @@
*/
void afs_zap_data(struct afs_vnode *vnode)
{
- _enter("zap data {%x:%u}", vnode->fid.vid, vnode->fid.vnode);
+ _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
/* nuke all the non-dirty pages that aren't locked, mapped or being
- * written back */
- invalidate_remote_inode(&vnode->vfs_inode);
+ * written back in a regular file and completely discard the pages in a
+ * directory or symlink */
+ if (S_ISREG(vnode->vfs_inode.i_mode))
+ invalidate_remote_inode(&vnode->vfs_inode);
+ else
+ invalidate_inode_pages2(vnode->vfs_inode.i_mapping);
}
/*
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index a30d4fa..4953ba5 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -506,6 +506,10 @@
extern int afs_fs_setattr(struct afs_server *, struct key *,
struct afs_vnode *, struct iattr *,
const struct afs_wait_mode *);
+extern int afs_fs_get_volume_status(struct afs_server *, struct key *,
+ struct afs_vnode *,
+ struct afs_volume_status *,
+ const struct afs_wait_mode *);
/*
* inode.c
@@ -672,6 +676,8 @@
extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t,
unsigned, unsigned);
extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *);
+extern int afs_vnode_get_volume_status(struct afs_vnode *, struct key *,
+ struct afs_volume_status *);
/*
* volume.c
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c
index 04189c4..1b36f45 100644
--- a/fs/afs/rxrpc.c
+++ b/fs/afs/rxrpc.c
@@ -294,7 +294,7 @@
put_page(pages[loop]);
if (ret < 0)
break;
- } while (first < last);
+ } while (first <= last);
_leave(" = %d", ret);
return ret;
diff --git a/fs/afs/super.c b/fs/afs/super.c
index d24be33..579af63 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -21,22 +21,20 @@
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/parser.h>
+#include <linux/statfs.h>
#include "internal.h"
#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
static void afs_i_init_once(void *foo, struct kmem_cache *cachep,
unsigned long flags);
-
static int afs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data, struct vfsmount *mnt);
-
static struct inode *afs_alloc_inode(struct super_block *sb);
-
static void afs_put_super(struct super_block *sb);
-
static void afs_destroy_inode(struct inode *inode);
+static int afs_statfs(struct dentry *dentry, struct kstatfs *buf);
struct file_system_type afs_fs_type = {
.owner = THIS_MODULE,
@@ -47,7 +45,7 @@
};
static const struct super_operations afs_super_ops = {
- .statfs = simple_statfs,
+ .statfs = afs_statfs,
.alloc_inode = afs_alloc_inode,
.drop_inode = generic_delete_inode,
.write_inode = afs_write_inode,
@@ -488,6 +486,7 @@
vnode->flags = 1 << AFS_VNODE_UNSET;
vnode->cb_promised = false;
+ _leave(" = %p", &vnode->vfs_inode);
return &vnode->vfs_inode;
}
@@ -498,7 +497,7 @@
{
struct afs_vnode *vnode = AFS_FS_I(inode);
- _enter("{%lu}", inode->i_ino);
+ _enter("%p{%x:%u}", inode, vnode->fid.vid, vnode->fid.vnode);
_debug("DESTROY INODE %p", inode);
@@ -507,3 +506,36 @@
kmem_cache_free(afs_inode_cachep, vnode);
atomic_dec(&afs_count_active_inodes);
}
+
+/*
+ * return information about an AFS volume
+ */
+static int afs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct afs_volume_status vs;
+ struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+ struct key *key;
+ int ret;
+
+ key = afs_request_key(vnode->volume->cell);
+ if (IS_ERR(key))
+ return PTR_ERR(key);
+
+ ret = afs_vnode_get_volume_status(vnode, key, &vs);
+ key_put(key);
+ if (ret < 0) {
+ _leave(" = %d", ret);
+ return ret;
+ }
+
+ buf->f_type = dentry->d_sb->s_magic;
+ buf->f_bsize = AFS_BLOCK_SIZE;
+ buf->f_namelen = AFSNAMEMAX - 1;
+
+ if (vs.max_quota == 0)
+ buf->f_blocks = vs.part_max_blocks;
+ else
+ buf->f_blocks = vs.max_quota;
+ buf->f_bavail = buf->f_bfree = buf->f_blocks - vs.blocks_in_use;
+ return 0;
+}
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c
index ec81466..c36c98c 100644
--- a/fs/afs/vnode.c
+++ b/fs/afs/vnode.c
@@ -175,24 +175,33 @@
{
struct afs_server *server;
+ _enter("{%p}", vnode->server);
+
set_bit(AFS_VNODE_DELETED, &vnode->flags);
server = vnode->server;
- if (vnode->cb_promised) {
- spin_lock(&server->cb_lock);
+ if (server) {
if (vnode->cb_promised) {
- rb_erase(&vnode->cb_promise, &server->cb_promises);
- vnode->cb_promised = false;
+ spin_lock(&server->cb_lock);
+ if (vnode->cb_promised) {
+ rb_erase(&vnode->cb_promise,
+ &server->cb_promises);
+ vnode->cb_promised = false;
+ }
+ spin_unlock(&server->cb_lock);
}
- spin_unlock(&server->cb_lock);
+
+ spin_lock(&server->fs_lock);
+ rb_erase(&vnode->server_rb, &server->fs_vnodes);
+ spin_unlock(&server->fs_lock);
+
+ vnode->server = NULL;
+ afs_put_server(server);
+ } else {
+ ASSERT(!vnode->cb_promised);
}
- spin_lock(&vnode->server->fs_lock);
- rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
- spin_unlock(&vnode->server->fs_lock);
-
- vnode->server = NULL;
- afs_put_server(server);
+ _leave("");
}
/*
@@ -225,7 +234,7 @@
*/
static void afs_vnode_status_update_failed(struct afs_vnode *vnode, int ret)
{
- _enter("%p,%d", vnode, ret);
+ _enter("{%x:%u},%d", vnode->fid.vid, vnode->fid.vnode, ret);
spin_lock(&vnode->lock);
@@ -860,3 +869,55 @@
spin_unlock(&vnode->lock);
return PTR_ERR(server);
}
+
+/*
+ * get the status of a volume
+ */
+int afs_vnode_get_volume_status(struct afs_vnode *vnode, struct key *key,
+ struct afs_volume_status *vs)
+{
+ struct afs_server *server;
+ int ret;
+
+ _enter("%s{%x:%u.%u},%x,",
+ vnode->volume->vlocation->vldb.name,
+ vnode->fid.vid,
+ vnode->fid.vnode,
+ vnode->fid.unique,
+ key_serial(key));
+
+ /* this op will fetch the status */
+ spin_lock(&vnode->lock);
+ vnode->update_cnt++;
+ spin_unlock(&vnode->lock);
+
+ do {
+ /* pick a server to query */
+ server = afs_volume_pick_fileserver(vnode);
+ if (IS_ERR(server))
+ goto no_server;
+
+ _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
+
+ ret = afs_fs_get_volume_status(server, key, vnode, vs, &afs_sync_call);
+
+ } while (!afs_volume_release_fileserver(vnode, server, ret));
+
+ /* adjust the flags */
+ if (ret == 0) {
+ afs_vnode_finalise_status_update(vnode, server);
+ afs_put_server(server);
+ } else {
+ afs_vnode_status_update_failed(vnode, ret);
+ }
+
+ _leave(" = %d", ret);
+ return ret;
+
+no_server:
+ spin_lock(&vnode->lock);
+ vnode->update_cnt--;
+ ASSERTCMP(vnode->update_cnt, >=, 0);
+ spin_unlock(&vnode->lock);
+ return PTR_ERR(server);
+}
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 83ff292..28f3751 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -122,7 +122,7 @@
if (offset == 0 && to == PAGE_SIZE)
return 0;
- p = kmap(page);
+ p = kmap_atomic(page, KM_USER0);
i_size = i_size_read(&vnode->vfs_inode);
pos = (loff_t) page->index << PAGE_SHIFT;
@@ -133,7 +133,7 @@
memset(p, 0, offset);
if (to < PAGE_SIZE)
memset(p + to, 0, PAGE_SIZE - to);
- kunmap(page);
+ kunmap_atomic(p, KM_USER0);
return 0;
}
@@ -152,7 +152,7 @@
memset(p + eof, 0, PAGE_SIZE - eof);
}
- kunmap(p);
+ kunmap_atomic(p, KM_USER0);
ret = 0;
if (offset > 0 || eof > to) {
@@ -395,8 +395,9 @@
if (n == 0)
goto no_more;
if (pages[0]->index != start) {
- for (n--; n >= 0; n--)
- put_page(pages[n]);
+ do {
+ put_page(pages[--n]);
+ } while (n > 0);
goto no_more;
}
@@ -489,14 +490,6 @@
_enter("{%lx},", page->index);
- if (wbc->sync_mode != WB_SYNC_NONE)
- wait_on_page_writeback(page);
-
- if (PageWriteback(page) || !PageDirty(page)) {
- unlock_page(page);
- return 0;
- }
-
wb = (struct afs_writeback *) page_private(page);
ASSERT(wb != NULL);
@@ -677,7 +670,7 @@
pagevec_init(&pv, 0);
do {
- _debug("attach %lx-%lx", first, last);
+ _debug("done %lx-%lx", first, last);
count = last - first + 1;
if (count > PAGEVEC_SIZE)
@@ -709,7 +702,7 @@
}
__pagevec_release(&pv);
- } while (first < last);
+ } while (first <= last);
_leave("");
}
diff --git a/fs/aio.c b/fs/aio.c
index ac1c158..dbe699e 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -30,6 +30,7 @@
#include <linux/highmem.h>
#include <linux/workqueue.h>
#include <linux/security.h>
+#include <linux/eventfd.h>
#include <asm/kmap_types.h>
#include <asm/uaccess.h>
@@ -417,6 +418,7 @@
req->private = NULL;
req->ki_iovec = NULL;
INIT_LIST_HEAD(&req->ki_run_list);
+ req->ki_eventfd = ERR_PTR(-EINVAL);
/* Check if the completion queue has enough free space to
* accept an event from this io.
@@ -458,6 +460,8 @@
{
assert_spin_locked(&ctx->ctx_lock);
+ if (!IS_ERR(req->ki_eventfd))
+ fput(req->ki_eventfd);
if (req->ki_dtor)
req->ki_dtor(req);
if (req->ki_iovec != &req->ki_inline_vec)
@@ -942,6 +946,14 @@
return 1;
}
+ /*
+ * Check if the user asked us to deliver the result through an
+ * eventfd. The eventfd_signal() function is safe to be called
+ * from IRQ context.
+ */
+ if (!IS_ERR(iocb->ki_eventfd))
+ eventfd_signal(iocb->ki_eventfd, 1);
+
info = &ctx->ring_info;
/* add a completion event to the ring buffer.
@@ -1526,8 +1538,7 @@
ssize_t ret;
/* enforce forwards compatibility on users */
- if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
- iocb->aio_reserved3)) {
+ if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2)) {
pr_debug("EINVAL: io_submit: reserve field set\n");
return -EINVAL;
}
@@ -1551,6 +1562,19 @@
fput(file);
return -EAGAIN;
}
+ if (iocb->aio_flags & IOCB_FLAG_RESFD) {
+ /*
+ * If the IOCB_FLAG_RESFD flag of aio_flags is set, get an
+ * instance of the file* now. The file descriptor must be
+ * an eventfd() fd, and will be signaled for each completed
+ * event using the eventfd_signal() function.
+ */
+ req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
+ if (unlikely(IS_ERR(req->ki_eventfd))) {
+ ret = PTR_ERR(req->ki_eventfd);
+ goto out_put_req;
+ }
+ }
req->ki_filp = file;
ret = put_user(req->ki_key, &user_iocb->aio_key);
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
new file mode 100644
index 0000000..40fe3a3
--- /dev/null
+++ b/fs/anon_inodes.c
@@ -0,0 +1,200 @@
+/*
+ * fs/anon_inodes.c
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ * Thanks to Arnd Bergmann for code review and suggestions.
+ * More changes for Thomas Gleixner suggestions.
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/magic.h>
+#include <linux/anon_inodes.h>
+
+#include <asm/uaccess.h>
+
+static struct vfsmount *anon_inode_mnt __read_mostly;
+static struct inode *anon_inode_inode;
+static const struct file_operations anon_inode_fops;
+
+static int anon_inodefs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data,
+ struct vfsmount *mnt)
+{
+ return get_sb_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC,
+ mnt);
+}
+
+static int anon_inodefs_delete_dentry(struct dentry *dentry)
+{
+ /*
+ * We faked vfs to believe the dentry was hashed when we created it.
+ * Now we restore the flag so that dput() will work correctly.
+ */
+ dentry->d_flags |= DCACHE_UNHASHED;
+ return 1;
+}
+
+static struct file_system_type anon_inode_fs_type = {
+ .name = "anon_inodefs",
+ .get_sb = anon_inodefs_get_sb,
+ .kill_sb = kill_anon_super,
+};
+static struct dentry_operations anon_inodefs_dentry_operations = {
+ .d_delete = anon_inodefs_delete_dentry,
+};
+
+/**
+ * anon_inode_getfd - creates a new file instance by hooking it up to and
+ * anonymous inode, and a dentry that describe the "class"
+ * of the file
+ *
+ * @pfd: [out] pointer to the file descriptor
+ * @dpinode: [out] pointer to the inode
+ * @pfile: [out] pointer to the file struct
+ * @name: [in] name of the "class" of the new file
+ * @fops [in] file operations for the new file
+ * @priv [in] private data for the new file (will be file's private_data)
+ *
+ * Creates a new file by hooking it on a single inode. This is useful for files
+ * that do not need to have a full-fledged inode in order to operate correctly.
+ * All the files created with anon_inode_getfd() will share a single inode, by
+ * hence saving memory and avoiding code duplication for the file/inode/dentry
+ * setup.
+ */
+int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
+ const char *name, const struct file_operations *fops,
+ void *priv)
+{
+ struct qstr this;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct file *file;
+ int error, fd;
+
+ if (IS_ERR(anon_inode_inode))
+ return -ENODEV;
+ file = get_empty_filp();
+ if (!file)
+ return -ENFILE;
+
+ inode = igrab(anon_inode_inode);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto err_put_filp;
+ }
+
+ error = get_unused_fd();
+ if (error < 0)
+ goto err_iput;
+ fd = error;
+
+ /*
+ * Link the inode to a directory entry by creating a unique name
+ * using the inode sequence number.
+ */
+ error = -ENOMEM;
+ this.name = name;
+ this.len = strlen(name);
+ this.hash = 0;
+ dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this);
+ if (!dentry)
+ goto err_put_unused_fd;
+ dentry->d_op = &anon_inodefs_dentry_operations;
+ /* Do not publish this dentry inside the global dentry hash table */
+ dentry->d_flags &= ~DCACHE_UNHASHED;
+ d_instantiate(dentry, inode);
+
+ file->f_path.mnt = mntget(anon_inode_mnt);
+ file->f_path.dentry = dentry;
+ file->f_mapping = inode->i_mapping;
+
+ file->f_pos = 0;
+ file->f_flags = O_RDWR;
+ file->f_op = fops;
+ file->f_mode = FMODE_READ | FMODE_WRITE;
+ file->f_version = 0;
+ file->private_data = priv;
+
+ fd_install(fd, file);
+
+ *pfd = fd;
+ *pinode = inode;
+ *pfile = file;
+ return 0;
+
+err_put_unused_fd:
+ put_unused_fd(fd);
+err_iput:
+ iput(inode);
+err_put_filp:
+ put_filp(file);
+ return error;
+}
+
+/*
+ * A single inode exist for all anon_inode files. Contrary to pipes,
+ * anon_inode inodes has no per-instance data associated, so we can avoid
+ * the allocation of multiple of them.
+ */
+static struct inode *anon_inode_mkinode(void)
+{
+ struct inode *inode = new_inode(anon_inode_mnt->mnt_sb);
+
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ inode->i_fop = &anon_inode_fops;
+
+ /*
+ * Mark the inode dirty from the very beginning,
+ * that way it will never be moved to the dirty
+ * list because mark_inode_dirty() will think
+ * that it already _is_ on the dirty list.
+ */
+ inode->i_state = I_DIRTY;
+ inode->i_mode = S_IRUSR | S_IWUSR;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ return inode;
+}
+
+static int __init anon_inode_init(void)
+{
+ int error;
+
+ error = register_filesystem(&anon_inode_fs_type);
+ if (error)
+ goto err_exit;
+ anon_inode_mnt = kern_mount(&anon_inode_fs_type);
+ if (IS_ERR(anon_inode_mnt)) {
+ error = PTR_ERR(anon_inode_mnt);
+ goto err_unregister_filesystem;
+ }
+ anon_inode_inode = anon_inode_mkinode();
+ if (IS_ERR(anon_inode_inode)) {
+ error = PTR_ERR(anon_inode_inode);
+ goto err_mntput;
+ }
+
+ return 0;
+
+err_mntput:
+ mntput(anon_inode_mnt);
+err_unregister_filesystem:
+ unregister_filesystem(&anon_inode_fs_type);
+err_exit:
+ panic(KERN_ERR "anon_inode_init() failed (%d)\n", error);
+}
+
+fs_initcall(anon_inode_init);
+
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index 4ef5444..8b4cca3 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -101,7 +101,7 @@
struct autofs_sb_info {
u32 magic;
struct file *pipe;
- pid_t oz_pgrp;
+ struct pid *oz_pgrp;
int catatonic;
struct super_block *sb;
unsigned long exp_timeout;
@@ -122,7 +122,7 @@
filesystem without "magic".) */
static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
- return sbi->catatonic || process_group(current) == sbi->oz_pgrp;
+ return sbi->catatonic || task_pgrp(current) == sbi->oz_pgrp;
}
/* Hash operations */
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index aa0b61f..e7204d7 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -34,12 +34,14 @@
if (!sbi)
goto out_kill_sb;
- if ( !sbi->catatonic )
+ if (!sbi->catatonic)
autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */
+ put_pid(sbi->oz_pgrp);
+
autofs_hash_nuke(sbi);
- for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) {
- if ( test_bit(n, sbi->symlink_bitmap) )
+ for (n = 0; n < AUTOFS_MAX_SYMLINKS; n++) {
+ if (test_bit(n, sbi->symlink_bitmap))
kfree(sbi->symlink[n].data);
}
@@ -69,7 +71,8 @@
{Opt_err, NULL}
};
-static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto)
+static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
+ pid_t *pgrp, int *minproto, int *maxproto)
{
char *p;
substring_t args[MAX_OPT_ARGS];
@@ -138,9 +141,10 @@
int pipefd;
struct autofs_sb_info *sbi;
int minproto, maxproto;
+ pid_t pgid;
sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
- if ( !sbi )
+ if (!sbi)
goto fail_unlock;
DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
@@ -149,7 +153,6 @@
sbi->pipe = NULL;
sbi->catatonic = 1;
sbi->exp_timeout = 0;
- sbi->oz_pgrp = process_group(current);
autofs_initialize_hash(&sbi->dirhash);
sbi->queues = NULL;
memset(sbi->symlink_bitmap, 0, sizeof(long)*AUTOFS_SYMLINK_BITMAP_LEN);
@@ -169,26 +172,36 @@
goto fail_iput;
/* Can this call block? - WTF cares? s is locked. */
- if ( parse_options(data,&pipefd,&root_inode->i_uid,&root_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) {
+ if (parse_options(data, &pipefd, &root_inode->i_uid,
+ &root_inode->i_gid, &pgid, &minproto,
+ &maxproto)) {
printk("autofs: called with bogus options\n");
goto fail_dput;
}
/* Couldn't this be tested earlier? */
- if ( minproto > AUTOFS_PROTO_VERSION ||
- maxproto < AUTOFS_PROTO_VERSION ) {
+ if (minproto > AUTOFS_PROTO_VERSION ||
+ maxproto < AUTOFS_PROTO_VERSION) {
printk("autofs: kernel does not match daemon version\n");
goto fail_dput;
}
- DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, sbi->oz_pgrp));
- pipe = fget(pipefd);
-
- if ( !pipe ) {
- printk("autofs: could not open pipe file descriptor\n");
+ DPRINTK(("autofs: pipe fd = %d, pgrp = %u\n", pipefd, pgid));
+ sbi->oz_pgrp = find_get_pid(pgid);
+
+ if (!sbi->oz_pgrp) {
+ printk("autofs: could not find process group %d\n", pgid);
goto fail_dput;
}
- if ( !pipe->f_op || !pipe->f_op->write )
+
+ pipe = fget(pipefd);
+
+ if (!pipe) {
+ printk("autofs: could not open pipe file descriptor\n");
+ goto fail_put_pid;
+ }
+
+ if (!pipe->f_op || !pipe->f_op->write)
goto fail_fput;
sbi->pipe = pipe;
sbi->catatonic = 0;
@@ -202,6 +215,8 @@
fail_fput:
printk("autofs: pipe file descriptor does not contain proper ops\n");
fput(pipe);
+fail_put_pid:
+ put_pid(sbi->oz_pgrp);
fail_dput:
dput(root);
goto fail_free;
@@ -230,7 +245,7 @@
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
- if ( ino == AUTOFS_ROOT_INO ) {
+ if (ino == AUTOFS_ROOT_INO) {
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &autofs_root_inode_operations;
inode->i_fop = &autofs_root_operations;
@@ -241,12 +256,12 @@
inode->i_uid = inode->i_sb->s_root->d_inode->i_uid;
inode->i_gid = inode->i_sb->s_root->d_inode->i_gid;
- if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) {
+ if (ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO) {
/* Symlink inode - should be in symlink list */
struct autofs_symlink *sl;
n = ino - AUTOFS_FIRST_SYMLINK;
- if ( n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
+ if (n >= AUTOFS_MAX_SYMLINKS || !test_bit(n,sbi->symlink_bitmap)) {
printk("autofs: Looking for bad symlink inode %u\n", (unsigned int) ino);
return;
}
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index f259720..c148953 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -67,8 +67,8 @@
filp->f_pos = ++nr;
/* fall through */
default:
- while ( onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent) ) {
- if ( !ent->dentry || d_mountpoint(ent->dentry) ) {
+ while (onr = nr, ent = autofs_hash_enum(dirhash,&nr,ent)) {
+ if (!ent->dentry || d_mountpoint(ent->dentry)) {
if (filldir(dirent,ent->name,ent->len,onr,ent->ino,DT_UNKNOWN) < 0)
goto out;
filp->f_pos = nr;
@@ -88,10 +88,10 @@
struct autofs_dir_ent *ent;
int status = 0;
- if ( !(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) ) {
+ if (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) {
do {
- if ( status && dentry->d_inode ) {
- if ( status != -ENOENT )
+ if (status && dentry->d_inode) {
+ if (status != -ENOENT)
printk("autofs warning: lookup failure on positive dentry, status = %d, name = %s\n", status, dentry->d_name.name);
return 0; /* Try to get the kernel to invalidate this dentry */
}
@@ -106,7 +106,7 @@
return 1;
}
status = autofs_wait(sbi, &dentry->d_name);
- } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)) );
+ } while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name)));
}
/* Abuse this field as a pointer to the directory entry, used to
@@ -124,13 +124,13 @@
/* If this is a directory that isn't a mount point, bitch at the
daemon and fix it in user space */
- if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
+ if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) {
return !autofs_wait(sbi, &dentry->d_name);
}
/* We don't update the usages for the autofs daemon itself, this
is necessary for recursive autofs mounts */
- if ( !autofs_oz_mode(sbi) ) {
+ if (!autofs_oz_mode(sbi)) {
autofs_update_usage(&sbi->dirhash,ent);
}
@@ -157,7 +157,7 @@
sbi = autofs_sbi(dir->i_sb);
/* Pending dentry */
- if ( dentry->d_flags & DCACHE_AUTOFS_PENDING ) {
+ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
if (autofs_oz_mode(sbi))
res = 1;
else
@@ -173,7 +173,7 @@
}
/* Check for a non-mountpoint directory */
- if ( S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry) ) {
+ if (S_ISDIR(dentry->d_inode->i_mode) && !d_mountpoint(dentry)) {
if (autofs_oz_mode(sbi))
res = 1;
else
@@ -183,9 +183,9 @@
}
/* Update the usage list */
- if ( !autofs_oz_mode(sbi) ) {
+ if (!autofs_oz_mode(sbi)) {
ent = (struct autofs_dir_ent *) dentry->d_time;
- if ( ent )
+ if (ent)
autofs_update_usage(&sbi->dirhash,ent);
}
unlock_kernel();
@@ -213,8 +213,10 @@
sbi = autofs_sbi(dir->i_sb);
oz_mode = autofs_oz_mode(sbi);
- DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n",
- current->pid, process_group(current), sbi->catatonic, oz_mode));
+ DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, "
+ "oz_mode = %d\n", pid_nr(task_pid(current)),
+ process_group(current), sbi->catatonic,
+ oz_mode));
/*
* Mark the dentry incomplete, but add it. This is needed so
@@ -258,7 +260,7 @@
* doesn't do the right thing for all system calls, but it should
* be OK for the operations we permit from an autofs.
*/
- if ( dentry->d_inode && d_unhashed(dentry) )
+ if (dentry->d_inode && d_unhashed(dentry))
return ERR_PTR(-ENOENT);
return NULL;
@@ -277,18 +279,18 @@
autofs_say(dentry->d_name.name,dentry->d_name.len);
lock_kernel();
- if ( !autofs_oz_mode(sbi) ) {
+ if (!autofs_oz_mode(sbi)) {
unlock_kernel();
return -EACCES;
}
- if ( autofs_hash_lookup(dh, &dentry->d_name) ) {
+ if (autofs_hash_lookup(dh, &dentry->d_name)) {
unlock_kernel();
return -EEXIST;
}
n = find_first_zero_bit(sbi->symlink_bitmap,AUTOFS_MAX_SYMLINKS);
- if ( n >= AUTOFS_MAX_SYMLINKS ) {
+ if (n >= AUTOFS_MAX_SYMLINKS) {
unlock_kernel();
return -ENOSPC;
}
@@ -297,14 +299,14 @@
sl = &sbi->symlink[n];
sl->len = strlen(symname);
sl->data = kmalloc(slsize = sl->len+1, GFP_KERNEL);
- if ( !sl->data ) {
+ if (!sl->data) {
clear_bit(n,sbi->symlink_bitmap);
unlock_kernel();
return -ENOSPC;
}
ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
- if ( !ent ) {
+ if (!ent) {
kfree(sl->data);
clear_bit(n,sbi->symlink_bitmap);
unlock_kernel();
@@ -312,7 +314,7 @@
}
ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
- if ( !ent->name ) {
+ if (!ent->name) {
kfree(sl->data);
kfree(ent);
clear_bit(n,sbi->symlink_bitmap);
@@ -354,23 +356,23 @@
/* This allows root to remove symlinks */
lock_kernel();
- if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) ) {
+ if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN)) {
unlock_kernel();
return -EACCES;
}
ent = autofs_hash_lookup(dh, &dentry->d_name);
- if ( !ent ) {
+ if (!ent) {
unlock_kernel();
return -ENOENT;
}
n = ent->ino - AUTOFS_FIRST_SYMLINK;
- if ( n >= AUTOFS_MAX_SYMLINKS ) {
+ if (n >= AUTOFS_MAX_SYMLINKS) {
unlock_kernel();
return -EISDIR; /* It's a directory, dummy */
}
- if ( !test_bit(n,sbi->symlink_bitmap) ) {
+ if (!test_bit(n,sbi->symlink_bitmap)) {
unlock_kernel();
return -EINVAL; /* Nonexistent symlink? Shouldn't happen */
}
@@ -392,23 +394,23 @@
struct autofs_dir_ent *ent;
lock_kernel();
- if ( !autofs_oz_mode(sbi) ) {
+ if (!autofs_oz_mode(sbi)) {
unlock_kernel();
return -EACCES;
}
ent = autofs_hash_lookup(dh, &dentry->d_name);
- if ( !ent ) {
+ if (!ent) {
unlock_kernel();
return -ENOENT;
}
- if ( (unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO ) {
+ if ((unsigned int)ent->ino < AUTOFS_FIRST_DIR_INO) {
unlock_kernel();
return -ENOTDIR; /* Not a directory */
}
- if ( ent->dentry != dentry ) {
+ if (ent->dentry != dentry) {
printk("autofs_rmdir: odentry != dentry for entry %s\n", dentry->d_name.name);
}
@@ -429,18 +431,18 @@
ino_t ino;
lock_kernel();
- if ( !autofs_oz_mode(sbi) ) {
+ if (!autofs_oz_mode(sbi)) {
unlock_kernel();
return -EACCES;
}
ent = autofs_hash_lookup(dh, &dentry->d_name);
- if ( ent ) {
+ if (ent) {
unlock_kernel();
return -EEXIST;
}
- if ( sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO ) {
+ if (sbi->next_dir_ino < AUTOFS_FIRST_DIR_INO) {
printk("autofs: Out of inode numbers -- what the heck did you do??\n");
unlock_kernel();
return -ENOSPC;
@@ -448,13 +450,13 @@
ino = sbi->next_dir_ino++;
ent = kmalloc(sizeof(struct autofs_dir_ent), GFP_KERNEL);
- if ( !ent ) {
+ if (!ent) {
unlock_kernel();
return -ENOSPC;
}
ent->name = kmalloc(dentry->d_name.len+1, GFP_KERNEL);
- if ( !ent->name ) {
+ if (!ent->name) {
kfree(ent);
unlock_kernel();
return -ENOSPC;
@@ -483,7 +485,7 @@
put_user(sbi->exp_timeout / HZ, p))
return -EFAULT;
- if ( ntimeout > ULONG_MAX/HZ )
+ if (ntimeout > ULONG_MAX/HZ)
sbi->exp_timeout = 0;
else
sbi->exp_timeout = ntimeout * HZ;
@@ -511,15 +513,14 @@
pkt.hdr.proto_version = AUTOFS_PROTO_VERSION;
pkt.hdr.type = autofs_ptype_expire;
- if ( !sbi->exp_timeout ||
- !(ent = autofs_expire(sb,sbi,mnt)) )
+ if (!sbi->exp_timeout || !(ent = autofs_expire(sb,sbi,mnt)))
return -EAGAIN;
pkt.len = ent->len;
memcpy(pkt.name, ent->name, pkt.len);
pkt.name[pkt.len] = '\0';
- if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
+ if (copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)))
return -EFAULT;
return 0;
@@ -537,11 +538,11 @@
DPRINTK(("autofs_ioctl: cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u\n",cmd,arg,sbi,process_group(current)));
- if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
- _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+ if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+ _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
return -ENOTTY;
- if ( !autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+ if (!autofs_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
return -EPERM;
switch(cmd) {
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 5769a2f..692364e8 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -218,8 +218,7 @@
};
static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
- pid_t *pgrp, unsigned int *type,
- int *minproto, int *maxproto)
+ pid_t *pgrp, unsigned int *type, int *minproto, int *maxproto)
{
char *p;
substring_t args[MAX_OPT_ARGS];
@@ -314,7 +313,7 @@
struct autofs_info *ino;
sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
- if ( !sbi )
+ if (!sbi)
goto fail_unlock;
DPRINTK("starting up, sbi = %p",sbi);
@@ -363,10 +362,9 @@
root->d_fsdata = ino;
/* Can this call block? */
- if (parse_options(data, &pipefd,
- &root_inode->i_uid, &root_inode->i_gid,
- &sbi->oz_pgrp, &sbi->type,
- &sbi->min_proto, &sbi->max_proto)) {
+ if (parse_options(data, &pipefd, &root_inode->i_uid, &root_inode->i_gid,
+ &sbi->oz_pgrp, &sbi->type, &sbi->min_proto,
+ &sbi->max_proto)) {
printk("autofs: called with bogus options\n");
goto fail_dput;
}
@@ -396,11 +394,11 @@
DPRINTK("pipe fd = %d, pgrp = %u", pipefd, sbi->oz_pgrp);
pipe = fget(pipefd);
- if ( !pipe ) {
+ if (!pipe) {
printk("autofs: could not open pipe file descriptor\n");
goto fail_dput;
}
- if ( !pipe->f_op || !pipe->f_op->write )
+ if (!pipe->f_op || !pipe->f_op->write)
goto fail_fput;
sbi->pipe = pipe;
sbi->pipefd = pipefd;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 15170f4..2d4c8a3 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -759,7 +759,7 @@
struct autofs_info *p_ino;
/* This allows root to remove symlinks */
- if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+ if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
return -EACCES;
if (atomic_dec_and_test(&ino->count)) {
@@ -833,7 +833,7 @@
struct autofs_info *p_ino;
struct inode *inode;
- if ( !autofs4_oz_mode(sbi) )
+ if (!autofs4_oz_mode(sbi))
return -EACCES;
DPRINTK("dentry %p, creating %.*s",
@@ -871,11 +871,11 @@
int rv;
unsigned long ntimeout;
- if ( (rv = get_user(ntimeout, p)) ||
- (rv = put_user(sbi->exp_timeout/HZ, p)) )
+ if ((rv = get_user(ntimeout, p)) ||
+ (rv = put_user(sbi->exp_timeout/HZ, p)))
return rv;
- if ( ntimeout > ULONG_MAX/HZ )
+ if (ntimeout > ULONG_MAX/HZ)
sbi->exp_timeout = 0;
else
sbi->exp_timeout = ntimeout * HZ;
@@ -906,7 +906,7 @@
DPRINTK("returning %d", sbi->needs_reghost);
status = put_user(sbi->needs_reghost, p);
- if ( status )
+ if (status)
return status;
sbi->needs_reghost = 0;
@@ -975,11 +975,11 @@
DPRINTK("cmd = 0x%08x, arg = 0x%08lx, sbi = %p, pgrp = %u",
cmd,arg,sbi,process_group(current));
- if ( _IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
- _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT )
+ if (_IOC_TYPE(cmd) != _IOC_TYPE(AUTOFS_IOC_FIRST) ||
+ _IOC_NR(cmd) - _IOC_NR(AUTOFS_IOC_FIRST) >= AUTOFS_IOC_COUNT)
return -ENOTTY;
- if ( !autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN) )
+ if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
return -EPERM;
switch(cmd) {
diff --git a/fs/compat.c b/fs/compat.c
index 9cf75df..7b21b0a 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -46,6 +46,7 @@
#include <linux/tsacct_kern.h>
#include <linux/security.h>
#include <linux/highmem.h>
+#include <linux/signal.h>
#include <linux/poll.h>
#include <linux/mm.h>
#include <linux/eventpoll.h>
@@ -2199,3 +2200,51 @@
#endif /* TIF_RESTORE_SIGMASK */
#endif /* CONFIG_EPOLL */
+
+#ifdef CONFIG_SIGNALFD
+
+asmlinkage long compat_sys_signalfd(int ufd,
+ const compat_sigset_t __user *sigmask,
+ compat_size_t sigsetsize)
+{
+ compat_sigset_t ss32;
+ sigset_t tmp;
+ sigset_t __user *ksigmask;
+
+ if (sigsetsize != sizeof(compat_sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&ss32, sigmask, sizeof(ss32)))
+ return -EFAULT;
+ sigset_from_compat(&tmp, &ss32);
+ ksigmask = compat_alloc_user_space(sizeof(sigset_t));
+ if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
+ return -EFAULT;
+
+ return sys_signalfd(ufd, ksigmask, sizeof(sigset_t));
+}
+
+#endif /* CONFIG_SIGNALFD */
+
+#ifdef CONFIG_TIMERFD
+
+asmlinkage long compat_sys_timerfd(int ufd, int clockid, int flags,
+ const struct compat_itimerspec __user *utmr)
+{
+ long res;
+ struct itimerspec t;
+ struct itimerspec __user *ut;
+
+ res = -EFAULT;
+ if (get_compat_itimerspec(&t, utmr))
+ goto err_exit;
+ ut = compat_alloc_user_space(sizeof(*ut));
+ if (copy_to_user(ut, &t, sizeof(t)) )
+ goto err_exit;
+
+ res = sys_timerfd(ufd, clockid, flags, ut);
+err_exit:
+ return res;
+}
+
+#endif /* CONFIG_TIMERFD */
+
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index d92bc3e..65643de 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -3566,10 +3566,13 @@
goto found_handler;
}
+#ifdef CONFIG_NET
if (S_ISSOCK(filp->f_path.dentry->d_inode->i_mode) &&
cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
error = siocdevprivate_ioctl(fd, cmd, arg);
- } else {
+ } else
+#endif
+ {
static int count;
if (++count <= 50)
diff --git a/fs/eventfd.c b/fs/eventfd.c
new file mode 100644
index 0000000..480e2b3
--- /dev/null
+++ b/fs/eventfd.c
@@ -0,0 +1,228 @@
+/*
+ * fs/eventfd.c
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/anon_inodes.h>
+#include <linux/eventfd.h>
+
+struct eventfd_ctx {
+ spinlock_t lock;
+ wait_queue_head_t wqh;
+ /*
+ * Every time that a write(2) is performed on an eventfd, the
+ * value of the __u64 being written is added to "count" and a
+ * wakeup is performed on "wqh". A read(2) will return the "count"
+ * value to userspace, and will reset "count" to zero. The kernel
+ * size eventfd_signal() also, adds to the "count" counter and
+ * issue a wakeup.
+ */
+ __u64 count;
+};
+
+/*
+ * Adds "n" to the eventfd counter "count". Returns "n" in case of
+ * success, or a value lower then "n" in case of coutner overflow.
+ * This function is supposed to be called by the kernel in paths
+ * that do not allow sleeping. In this function we allow the counter
+ * to reach the ULLONG_MAX value, and we signal this as overflow
+ * condition by returining a POLLERR to poll(2).
+ */
+int eventfd_signal(struct file *file, int n)
+{
+ struct eventfd_ctx *ctx = file->private_data;
+ unsigned long flags;
+
+ if (n < 0)
+ return -EINVAL;
+ spin_lock_irqsave(&ctx->lock, flags);
+ if (ULLONG_MAX - ctx->count < n)
+ n = (int) (ULLONG_MAX - ctx->count);
+ ctx->count += n;
+ if (waitqueue_active(&ctx->wqh))
+ wake_up_locked(&ctx->wqh);
+ spin_unlock_irqrestore(&ctx->lock, flags);
+
+ return n;
+}
+
+static int eventfd_release(struct inode *inode, struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static unsigned int eventfd_poll(struct file *file, poll_table *wait)
+{
+ struct eventfd_ctx *ctx = file->private_data;
+ unsigned int events = 0;
+ unsigned long flags;
+
+ poll_wait(file, &ctx->wqh, wait);
+
+ spin_lock_irqsave(&ctx->lock, flags);
+ if (ctx->count > 0)
+ events |= POLLIN;
+ if (ctx->count == ULLONG_MAX)
+ events |= POLLERR;
+ if (ULLONG_MAX - 1 > ctx->count)
+ events |= POLLOUT;
+ spin_unlock_irqrestore(&ctx->lock, flags);
+
+ return events;
+}
+
+static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct eventfd_ctx *ctx = file->private_data;
+ ssize_t res;
+ __u64 ucnt;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (count < sizeof(ucnt))
+ return -EINVAL;
+ spin_lock_irq(&ctx->lock);
+ res = -EAGAIN;
+ ucnt = ctx->count;
+ if (ucnt > 0)
+ res = sizeof(ucnt);
+ else if (!(file->f_flags & O_NONBLOCK)) {
+ __add_wait_queue(&ctx->wqh, &wait);
+ for (res = 0;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (ctx->count > 0) {
+ ucnt = ctx->count;
+ res = sizeof(ucnt);
+ break;
+ }
+ if (signal_pending(current)) {
+ res = -ERESTARTSYS;
+ break;
+ }
+ spin_unlock_irq(&ctx->lock);
+ schedule();
+ spin_lock_irq(&ctx->lock);
+ }
+ __remove_wait_queue(&ctx->wqh, &wait);
+ __set_current_state(TASK_RUNNING);
+ }
+ if (res > 0) {
+ ctx->count = 0;
+ if (waitqueue_active(&ctx->wqh))
+ wake_up_locked(&ctx->wqh);
+ }
+ spin_unlock_irq(&ctx->lock);
+ if (res > 0 && put_user(ucnt, (__u64 __user *) buf))
+ return -EFAULT;
+
+ return res;
+}
+
+static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct eventfd_ctx *ctx = file->private_data;
+ ssize_t res;
+ __u64 ucnt;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (count < sizeof(ucnt))
+ return -EINVAL;
+ if (copy_from_user(&ucnt, buf, sizeof(ucnt)))
+ return -EFAULT;
+ if (ucnt == ULLONG_MAX)
+ return -EINVAL;
+ spin_lock_irq(&ctx->lock);
+ res = -EAGAIN;
+ if (ULLONG_MAX - ctx->count > ucnt)
+ res = sizeof(ucnt);
+ else if (!(file->f_flags & O_NONBLOCK)) {
+ __add_wait_queue(&ctx->wqh, &wait);
+ for (res = 0;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (ULLONG_MAX - ctx->count > ucnt) {
+ res = sizeof(ucnt);
+ break;
+ }
+ if (signal_pending(current)) {
+ res = -ERESTARTSYS;
+ break;
+ }
+ spin_unlock_irq(&ctx->lock);
+ schedule();
+ spin_lock_irq(&ctx->lock);
+ }
+ __remove_wait_queue(&ctx->wqh, &wait);
+ __set_current_state(TASK_RUNNING);
+ }
+ if (res > 0) {
+ ctx->count += ucnt;
+ if (waitqueue_active(&ctx->wqh))
+ wake_up_locked(&ctx->wqh);
+ }
+ spin_unlock_irq(&ctx->lock);
+
+ return res;
+}
+
+static const struct file_operations eventfd_fops = {
+ .release = eventfd_release,
+ .poll = eventfd_poll,
+ .read = eventfd_read,
+ .write = eventfd_write,
+};
+
+struct file *eventfd_fget(int fd)
+{
+ struct file *file;
+
+ file = fget(fd);
+ if (!file)
+ return ERR_PTR(-EBADF);
+ if (file->f_op != &eventfd_fops) {
+ fput(file);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return file;
+}
+
+asmlinkage long sys_eventfd(unsigned int count)
+{
+ int error, fd;
+ struct eventfd_ctx *ctx;
+ struct file *file;
+ struct inode *inode;
+
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ init_waitqueue_head(&ctx->wqh);
+ spin_lock_init(&ctx->lock);
+ ctx->count = count;
+
+ /*
+ * When we call this, the initialization must be complete, since
+ * anon_inode_getfd() will install the fd.
+ */
+ error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]",
+ &eventfd_fops, ctx);
+ if (!error)
+ return fd;
+
+ kfree(ctx);
+ return error;
+}
+
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index b5c7ca5..1aad34e 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -34,6 +33,7 @@
#include <linux/mount.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <linux/anon_inodes.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -41,7 +41,6 @@
#include <asm/atomic.h>
#include <asm/semaphore.h>
-
/*
* LOCKING:
* There are three level of locking required by epoll :
@@ -74,9 +73,6 @@
* a greater scalability.
*/
-
-#define EVENTPOLLFS_MAGIC 0x03111965 /* My birthday should work for this :) */
-
#define DEBUG_EPOLL 0
#if DEBUG_EPOLL > 0
@@ -106,7 +102,6 @@
#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
-
struct epoll_filefd {
struct file *file;
int fd;
@@ -224,43 +219,6 @@
struct epitem *epi;
};
-
-
-static void ep_poll_safewake_init(struct poll_safewake *psw);
-static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq);
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
- struct eventpoll *ep);
-static int ep_alloc(struct eventpoll **pep);
-static void ep_free(struct eventpoll *ep);
-static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd);
-static void ep_use_epitem(struct epitem *epi);
-static void ep_release_epitem(struct epitem *epi);
-static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead,
- poll_table *pt);
-static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi);
-static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
- struct file *tfile, int fd);
-static int ep_modify(struct eventpoll *ep, struct epitem *epi,
- struct epoll_event *event);
-static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi);
-static int ep_unlink(struct eventpoll *ep, struct epitem *epi);
-static int ep_remove(struct eventpoll *ep, struct epitem *epi);
-static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key);
-static int ep_eventpoll_close(struct inode *inode, struct file *file);
-static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait);
-static int ep_send_events(struct eventpoll *ep, struct list_head *txlist,
- struct epoll_event __user *events, int maxevents);
-static int ep_events_transfer(struct eventpoll *ep,
- struct epoll_event __user *events,
- int maxevents);
-static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
- int maxevents, long timeout);
-static int eventpollfs_delete_dentry(struct dentry *dentry);
-static struct inode *ep_eventpoll_inode(void);
-static int eventpollfs_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name,
- void *data, struct vfsmount *mnt);
-
/*
* This semaphore is used to serialize ep_free() and eventpoll_release_file().
*/
@@ -275,37 +233,6 @@
/* Slab cache used to allocate "struct eppoll_entry" */
static struct kmem_cache *pwq_cache __read_mostly;
-/* Virtual fs used to allocate inodes for eventpoll files */
-static struct vfsmount *eventpoll_mnt __read_mostly;
-
-/* File callbacks that implement the eventpoll file behaviour */
-static const struct file_operations eventpoll_fops = {
- .release = ep_eventpoll_close,
- .poll = ep_eventpoll_poll
-};
-
-/*
- * This is used to register the virtual file system from where
- * eventpoll inodes are allocated.
- */
-static struct file_system_type eventpoll_fs_type = {
- .name = "eventpollfs",
- .get_sb = eventpollfs_get_sb,
- .kill_sb = kill_anon_super,
-};
-
-/* Very basic directory entry operations for the eventpoll virtual file system */
-static struct dentry_operations eventpollfs_dentry_operations = {
- .d_delete = eventpollfs_delete_dentry,
-};
-
-
-
-/* Fast test to see if the file is an evenpoll file */
-static inline int is_file_epoll(struct file *f)
-{
- return f->f_op == &eventpoll_fops;
-}
/* Setup the structure that is used as key for the rb-tree */
static inline void ep_set_ffd(struct epoll_filefd *ffd,
@@ -374,7 +301,6 @@
spin_lock_init(&psw->lock);
}
-
/*
* Perform a safe wake up of the poll wait list. The problem is that
* with the new callback'd wake up system, it is possible that the
@@ -429,400 +355,145 @@
spin_unlock_irqrestore(&psw->lock, flags);
}
+/*
+ * This function unregister poll callbacks from the associated file descriptor.
+ * Since this must be called without holding "ep->lock" the atomic exchange trick
+ * will protect us from multiple unregister.
+ */
+static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
+{
+ int nwait;
+ struct list_head *lsthead = &epi->pwqlist;
+ struct eppoll_entry *pwq;
+
+ /* This is called without locks, so we need the atomic exchange */
+ nwait = xchg(&epi->nwait, 0);
+
+ if (nwait) {
+ while (!list_empty(lsthead)) {
+ pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
+
+ list_del_init(&pwq->llink);
+ remove_wait_queue(pwq->whead, &pwq->wait);
+ kmem_cache_free(pwq_cache, pwq);
+ }
+ }
+}
/*
- * This is called from eventpoll_release() to unlink files from the eventpoll
- * interface. We need to have this facility to cleanup correctly files that are
- * closed without being removed from the eventpoll interface.
+ * Unlink the "struct epitem" from all places it might have been hooked up.
+ * This function must be called with write IRQ lock on "ep->lock".
*/
-void eventpoll_release_file(struct file *file)
+static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
{
- struct list_head *lsthead = &file->f_ep_links;
- struct eventpoll *ep;
- struct epitem *epi;
+ int error;
/*
- * We don't want to get "file->f_ep_lock" because it is not
- * necessary. It is not necessary because we're in the "struct file"
- * cleanup path, and this means that noone is using this file anymore.
- * The only hit might come from ep_free() but by holding the semaphore
- * will correctly serialize the operation. We do need to acquire
- * "ep->sem" after "epmutex" because ep_remove() requires it when called
- * from anywhere but ep_free().
+ * It can happen that this one is called for an item already unlinked.
+ * The check protect us from doing a double unlink ( crash ).
*/
- mutex_lock(&epmutex);
+ error = -ENOENT;
+ if (!ep_rb_linked(&epi->rbn))
+ goto error_return;
- while (!list_empty(lsthead)) {
- epi = list_first_entry(lsthead, struct epitem, fllink);
+ /*
+ * Clear the event mask for the unlinked item. This will avoid item
+ * notifications to be sent after the unlink operation from inside
+ * the kernel->userspace event transfer loop.
+ */
+ epi->event.events = 0;
- ep = epi->ep;
+ /*
+ * At this point is safe to do the job, unlink the item from our rb-tree.
+ * This operation togheter with the above check closes the door to
+ * double unlinks.
+ */
+ ep_rb_erase(&epi->rbn, &ep->rbr);
+
+ /*
+ * If the item we are going to remove is inside the ready file descriptors
+ * we want to remove it from this list to avoid stale events.
+ */
+ if (ep_is_linked(&epi->rdllink))
+ list_del_init(&epi->rdllink);
+
+ error = 0;
+error_return:
+
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
+ current, ep, epi->ffd.file, error));
+
+ return error;
+}
+
+/*
+ * Increment the usage count of the "struct epitem" making it sure
+ * that the user will have a valid pointer to reference.
+ */
+static void ep_use_epitem(struct epitem *epi)
+{
+ atomic_inc(&epi->usecnt);
+}
+
+/*
+ * Decrement ( release ) the usage count by signaling that the user
+ * has finished using the structure. It might lead to freeing the
+ * structure itself if the count goes to zero.
+ */
+static void ep_release_epitem(struct epitem *epi)
+{
+ if (atomic_dec_and_test(&epi->usecnt))
+ kmem_cache_free(epi_cache, epi);
+}
+
+/*
+ * Removes a "struct epitem" from the eventpoll RB tree and deallocates
+ * all the associated resources.
+ */
+static int ep_remove(struct eventpoll *ep, struct epitem *epi)
+{
+ int error;
+ unsigned long flags;
+ struct file *file = epi->ffd.file;
+
+ /*
+ * Removes poll wait queue hooks. We _have_ to do this without holding
+ * the "ep->lock" otherwise a deadlock might occur. This because of the
+ * sequence of the lock acquisition. Here we do "ep->lock" then the wait
+ * queue head lock when unregistering the wait queue. The wakeup callback
+ * will run by holding the wait queue head lock and will call our callback
+ * that will try to get "ep->lock".
+ */
+ ep_unregister_pollwait(ep, epi);
+
+ /* Remove the current item from the list of epoll hooks */
+ spin_lock(&file->f_ep_lock);
+ if (ep_is_linked(&epi->fllink))
list_del_init(&epi->fllink);
- down_write(&ep->sem);
- ep_remove(ep, epi);
- up_write(&ep->sem);
- }
+ spin_unlock(&file->f_ep_lock);
- mutex_unlock(&epmutex);
-}
+ /* We need to acquire the write IRQ lock before calling ep_unlink() */
+ write_lock_irqsave(&ep->lock, flags);
+ /* Really unlink the item from the RB tree */
+ error = ep_unlink(ep, epi);
-/*
- * It opens an eventpoll file descriptor by suggesting a storage of "size"
- * file descriptors. The size parameter is just an hint about how to size
- * data structures. It won't prevent the user to store more than "size"
- * file descriptors inside the epoll interface. It is the kernel part of
- * the userspace epoll_create(2).
- */
-asmlinkage long sys_epoll_create(int size)
-{
- int error, fd = -1;
- struct eventpoll *ep;
- struct inode *inode;
- struct file *file;
+ write_unlock_irqrestore(&ep->lock, flags);
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
- current, size));
-
- /*
- * Sanity check on the size parameter, and create the internal data
- * structure ( "struct eventpoll" ).
- */
- error = -EINVAL;
- if (size <= 0 || (error = ep_alloc(&ep)) != 0)
- goto eexit_1;
-
- /*
- * Creates all the items needed to setup an eventpoll file. That is,
- * a file structure, and inode and a free file descriptor.
- */
- error = ep_getfd(&fd, &inode, &file, ep);
if (error)
- goto eexit_2;
+ goto error_return;
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
- current, size, fd));
+ /* At this point it is safe to free the eventpoll item */
+ ep_release_epitem(epi);
- return fd;
-
-eexit_2:
- ep_free(ep);
- kfree(ep);
-eexit_1:
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
- current, size, error));
- return error;
-}
-
-
-/*
- * The following function implements the controller interface for
- * the eventpoll file that enables the insertion/removal/change of
- * file descriptors inside the interest set. It represents
- * the kernel part of the user space epoll_ctl(2).
- */
-asmlinkage long
-sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event __user *event)
-{
- int error;
- struct file *file, *tfile;
- struct eventpoll *ep;
- struct epitem *epi;
- struct epoll_event epds;
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
- current, epfd, op, fd, event));
-
- error = -EFAULT;
- if (ep_op_has_event(op) &&
- copy_from_user(&epds, event, sizeof(struct epoll_event)))
- goto eexit_1;
-
- /* Get the "struct file *" for the eventpoll file */
- error = -EBADF;
- file = fget(epfd);
- if (!file)
- goto eexit_1;
-
- /* Get the "struct file *" for the target file */
- tfile = fget(fd);
- if (!tfile)
- goto eexit_2;
-
- /* The target file descriptor must support poll */
- error = -EPERM;
- if (!tfile->f_op || !tfile->f_op->poll)
- goto eexit_3;
-
- /*
- * We have to check that the file structure underneath the file descriptor
- * the user passed to us _is_ an eventpoll file. And also we do not permit
- * adding an epoll file descriptor inside itself.
- */
- error = -EINVAL;
- if (file == tfile || !is_file_epoll(file))
- goto eexit_3;
-
- /*
- * At this point it is safe to assume that the "private_data" contains
- * our own data structure.
- */
- ep = file->private_data;
-
- down_write(&ep->sem);
-
- /* Try to lookup the file inside our RB tree */
- epi = ep_find(ep, tfile, fd);
-
- error = -EINVAL;
- switch (op) {
- case EPOLL_CTL_ADD:
- if (!epi) {
- epds.events |= POLLERR | POLLHUP;
-
- error = ep_insert(ep, &epds, tfile, fd);
- } else
- error = -EEXIST;
- break;
- case EPOLL_CTL_DEL:
- if (epi)
- error = ep_remove(ep, epi);
- else
- error = -ENOENT;
- break;
- case EPOLL_CTL_MOD:
- if (epi) {
- epds.events |= POLLERR | POLLHUP;
- error = ep_modify(ep, epi, &epds);
- } else
- error = -ENOENT;
- break;
- }
-
- /*
- * The function ep_find() increments the usage count of the structure
- * so, if this is not NULL, we need to release it.
- */
- if (epi)
- ep_release_epitem(epi);
-
- up_write(&ep->sem);
-
-eexit_3:
- fput(tfile);
-eexit_2:
- fput(file);
-eexit_1:
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
- current, epfd, op, fd, event, error));
+ error = 0;
+error_return:
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n",
+ current, ep, file, error));
return error;
}
-
-/*
- * Implement the event wait interface for the eventpoll file. It is the kernel
- * part of the user space epoll_wait(2).
- */
-asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
- int maxevents, int timeout)
-{
- int error;
- struct file *file;
- struct eventpoll *ep;
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
- current, epfd, events, maxevents, timeout));
-
- /* The maximum number of event must be greater than zero */
- if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
- return -EINVAL;
-
- /* Verify that the area passed by the user is writeable */
- if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
- error = -EFAULT;
- goto eexit_1;
- }
-
- /* Get the "struct file *" for the eventpoll file */
- error = -EBADF;
- file = fget(epfd);
- if (!file)
- goto eexit_1;
-
- /*
- * We have to check that the file structure underneath the fd
- * the user passed to us _is_ an eventpoll file.
- */
- error = -EINVAL;
- if (!is_file_epoll(file))
- goto eexit_2;
-
- /*
- * At this point it is safe to assume that the "private_data" contains
- * our own data structure.
- */
- ep = file->private_data;
-
- /* Time to fish for events ... */
- error = ep_poll(ep, events, maxevents, timeout);
-
-eexit_2:
- fput(file);
-eexit_1:
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
- current, epfd, events, maxevents, timeout, error));
-
- return error;
-}
-
-
-#ifdef TIF_RESTORE_SIGMASK
-
-/*
- * Implement the event wait interface for the eventpoll file. It is the kernel
- * part of the user space epoll_pwait(2).
- */
-asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
- int maxevents, int timeout, const sigset_t __user *sigmask,
- size_t sigsetsize)
-{
- int error;
- sigset_t ksigmask, sigsaved;
-
- /*
- * If the caller wants a certain signal mask to be set during the wait,
- * we apply it here.
- */
- if (sigmask) {
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
- if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
- return -EFAULT;
- sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
- sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
- }
-
- error = sys_epoll_wait(epfd, events, maxevents, timeout);
-
- /*
- * If we changed the signal mask, we need to restore the original one.
- * In case we've got a signal while waiting, we do not restore the
- * signal mask yet, and we allow do_signal() to deliver the signal on
- * the way back to userspace, before the signal mask is restored.
- */
- if (sigmask) {
- if (error == -EINTR) {
- memcpy(¤t->saved_sigmask, &sigsaved,
- sizeof(sigsaved));
- set_thread_flag(TIF_RESTORE_SIGMASK);
- } else
- sigprocmask(SIG_SETMASK, &sigsaved, NULL);
- }
-
- return error;
-}
-
-#endif /* #ifdef TIF_RESTORE_SIGMASK */
-
-
-/*
- * Creates the file descriptor to be used by the epoll interface.
- */
-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
- struct eventpoll *ep)
-{
- struct qstr this;
- char name[32];
- struct dentry *dentry;
- struct inode *inode;
- struct file *file;
- int error, fd;
-
- /* Get an ready to use file */
- error = -ENFILE;
- file = get_empty_filp();
- if (!file)
- goto eexit_1;
-
- /* Allocates an inode from the eventpoll file system */
- inode = ep_eventpoll_inode();
- if (IS_ERR(inode)) {
- error = PTR_ERR(inode);
- goto eexit_2;
- }
-
- /* Allocates a free descriptor to plug the file onto */
- error = get_unused_fd();
- if (error < 0)
- goto eexit_3;
- fd = error;
-
- /*
- * Link the inode to a directory entry by creating a unique name
- * using the inode number.
- */
- error = -ENOMEM;
- sprintf(name, "[%lu]", inode->i_ino);
- this.name = name;
- this.len = strlen(name);
- this.hash = inode->i_ino;
- dentry = d_alloc(eventpoll_mnt->mnt_sb->s_root, &this);
- if (!dentry)
- goto eexit_4;
- dentry->d_op = &eventpollfs_dentry_operations;
- d_add(dentry, inode);
- file->f_path.mnt = mntget(eventpoll_mnt);
- file->f_path.dentry = dentry;
- file->f_mapping = inode->i_mapping;
-
- file->f_pos = 0;
- file->f_flags = O_RDONLY;
- file->f_op = &eventpoll_fops;
- file->f_mode = FMODE_READ;
- file->f_version = 0;
- file->private_data = ep;
-
- /* Install the new setup file into the allocated fd. */
- fd_install(fd, file);
-
- *efd = fd;
- *einode = inode;
- *efile = file;
- return 0;
-
-eexit_4:
- put_unused_fd(fd);
-eexit_3:
- iput(inode);
-eexit_2:
- put_filp(file);
-eexit_1:
- return error;
-}
-
-
-static int ep_alloc(struct eventpoll **pep)
-{
- struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL);
-
- if (!ep)
- return -ENOMEM;
-
- rwlock_init(&ep->lock);
- init_rwsem(&ep->sem);
- init_waitqueue_head(&ep->wq);
- init_waitqueue_head(&ep->poll_wait);
- INIT_LIST_HEAD(&ep->rdllist);
- ep->rbr = RB_ROOT;
-
- *pep = ep;
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
- current, ep));
- return 0;
-}
-
-
static void ep_free(struct eventpoll *ep)
{
struct rb_node *rbp;
@@ -865,6 +536,104 @@
mutex_unlock(&epmutex);
}
+static int ep_eventpoll_release(struct inode *inode, struct file *file)
+{
+ struct eventpoll *ep = file->private_data;
+
+ if (ep) {
+ ep_free(ep);
+ kfree(ep);
+ }
+
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
+ return 0;
+}
+
+static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
+{
+ unsigned int pollflags = 0;
+ unsigned long flags;
+ struct eventpoll *ep = file->private_data;
+
+ /* Insert inside our poll wait queue */
+ poll_wait(file, &ep->poll_wait, wait);
+
+ /* Check our condition */
+ read_lock_irqsave(&ep->lock, flags);
+ if (!list_empty(&ep->rdllist))
+ pollflags = POLLIN | POLLRDNORM;
+ read_unlock_irqrestore(&ep->lock, flags);
+
+ return pollflags;
+}
+
+/* File callbacks that implement the eventpoll file behaviour */
+static const struct file_operations eventpoll_fops = {
+ .release = ep_eventpoll_release,
+ .poll = ep_eventpoll_poll
+};
+
+/* Fast test to see if the file is an evenpoll file */
+static inline int is_file_epoll(struct file *f)
+{
+ return f->f_op == &eventpoll_fops;
+}
+
+/*
+ * This is called from eventpoll_release() to unlink files from the eventpoll
+ * interface. We need to have this facility to cleanup correctly files that are
+ * closed without being removed from the eventpoll interface.
+ */
+void eventpoll_release_file(struct file *file)
+{
+ struct list_head *lsthead = &file->f_ep_links;
+ struct eventpoll *ep;
+ struct epitem *epi;
+
+ /*
+ * We don't want to get "file->f_ep_lock" because it is not
+ * necessary. It is not necessary because we're in the "struct file"
+ * cleanup path, and this means that noone is using this file anymore.
+ * The only hit might come from ep_free() but by holding the semaphore
+ * will correctly serialize the operation. We do need to acquire
+ * "ep->sem" after "epmutex" because ep_remove() requires it when called
+ * from anywhere but ep_free().
+ */
+ mutex_lock(&epmutex);
+
+ while (!list_empty(lsthead)) {
+ epi = list_first_entry(lsthead, struct epitem, fllink);
+
+ ep = epi->ep;
+ list_del_init(&epi->fllink);
+ down_write(&ep->sem);
+ ep_remove(ep, epi);
+ up_write(&ep->sem);
+ }
+
+ mutex_unlock(&epmutex);
+}
+
+static int ep_alloc(struct eventpoll **pep)
+{
+ struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL);
+
+ if (!ep)
+ return -ENOMEM;
+
+ rwlock_init(&ep->lock);
+ init_rwsem(&ep->sem);
+ init_waitqueue_head(&ep->wq);
+ init_waitqueue_head(&ep->poll_wait);
+ INIT_LIST_HEAD(&ep->rdllist);
+ ep->rbr = RB_ROOT;
+
+ *pep = ep;
+
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n",
+ current, ep));
+ return 0;
+}
/*
* Search the file inside the eventpoll tree. It add usage count to
@@ -902,31 +671,59 @@
return epir;
}
-
/*
- * Increment the usage count of the "struct epitem" making it sure
- * that the user will have a valid pointer to reference.
+ * This is the callback that is passed to the wait queue wakeup
+ * machanism. It is called by the stored file descriptors when they
+ * have events to report.
*/
-static void ep_use_epitem(struct epitem *epi)
+static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
{
+ int pwake = 0;
+ unsigned long flags;
+ struct epitem *epi = ep_item_from_wait(wait);
+ struct eventpoll *ep = epi->ep;
- atomic_inc(&epi->usecnt);
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
+ current, epi->ffd.file, epi, ep));
+
+ write_lock_irqsave(&ep->lock, flags);
+
+ /*
+ * If the event mask does not contain any poll(2) event, we consider the
+ * descriptor to be disabled. This condition is likely the effect of the
+ * EPOLLONESHOT bit that disables the descriptor when an event is received,
+ * until the next EPOLL_CTL_MOD will be issued.
+ */
+ if (!(epi->event.events & ~EP_PRIVATE_BITS))
+ goto is_disabled;
+
+ /* If this file is already in the ready list we exit soon */
+ if (ep_is_linked(&epi->rdllink))
+ goto is_linked;
+
+ list_add_tail(&epi->rdllink, &ep->rdllist);
+
+is_linked:
+ /*
+ * Wake up ( if active ) both the eventpoll wait list and the ->poll()
+ * wait list.
+ */
+ if (waitqueue_active(&ep->wq))
+ __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
+ TASK_INTERRUPTIBLE);
+ if (waitqueue_active(&ep->poll_wait))
+ pwake++;
+
+is_disabled:
+ write_unlock_irqrestore(&ep->lock, flags);
+
+ /* We have to call this outside the lock */
+ if (pwake)
+ ep_poll_safewake(&psw, &ep->poll_wait);
+
+ return 1;
}
-
-/*
- * Decrement ( release ) the usage count by signaling that the user
- * has finished using the structure. It might lead to freeing the
- * structure itself if the count goes to zero.
- */
-static void ep_release_epitem(struct epitem *epi)
-{
-
- if (atomic_dec_and_test(&epi->usecnt))
- kmem_cache_free(epi_cache, epi);
-}
-
-
/*
* This is the callback that is used to add our wait queue to the
* target file wakeup lists.
@@ -950,7 +747,6 @@
}
}
-
static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi)
{
int kcmp;
@@ -970,7 +766,6 @@
rb_insert_color(&epi->rbn, &ep->rbr);
}
-
static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
struct file *tfile, int fd)
{
@@ -981,7 +776,7 @@
error = -ENOMEM;
if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL)))
- goto eexit_1;
+ goto error_return;
/* Item initialization follow here ... */
ep_rb_initnode(&epi->rbn);
@@ -1011,7 +806,7 @@
* high memory pressure.
*/
if (epi->nwait < 0)
- goto eexit_2;
+ goto error_unregister;
/* Add the current item to the list of active epoll hook for this file */
spin_lock(&tfile->f_ep_lock);
@@ -1046,7 +841,7 @@
return 0;
-eexit_2:
+error_unregister:
ep_unregister_pollwait(ep, epi);
/*
@@ -1059,11 +854,10 @@
write_unlock_irqrestore(&ep->lock, flags);
kmem_cache_free(epi_cache, epi);
-eexit_1:
+error_return:
return error;
}
-
/*
* Modify the interest event mask by dropping an event if the new mask
* has a match in the current file status.
@@ -1126,216 +920,6 @@
return 0;
}
-
-/*
- * This function unregister poll callbacks from the associated file descriptor.
- * Since this must be called without holding "ep->lock" the atomic exchange trick
- * will protect us from multiple unregister.
- */
-static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi)
-{
- int nwait;
- struct list_head *lsthead = &epi->pwqlist;
- struct eppoll_entry *pwq;
-
- /* This is called without locks, so we need the atomic exchange */
- nwait = xchg(&epi->nwait, 0);
-
- if (nwait) {
- while (!list_empty(lsthead)) {
- pwq = list_first_entry(lsthead, struct eppoll_entry, llink);
-
- list_del_init(&pwq->llink);
- remove_wait_queue(pwq->whead, &pwq->wait);
- kmem_cache_free(pwq_cache, pwq);
- }
- }
-}
-
-
-/*
- * Unlink the "struct epitem" from all places it might have been hooked up.
- * This function must be called with write IRQ lock on "ep->lock".
- */
-static int ep_unlink(struct eventpoll *ep, struct epitem *epi)
-{
- int error;
-
- /*
- * It can happen that this one is called for an item already unlinked.
- * The check protect us from doing a double unlink ( crash ).
- */
- error = -ENOENT;
- if (!ep_rb_linked(&epi->rbn))
- goto eexit_1;
-
- /*
- * Clear the event mask for the unlinked item. This will avoid item
- * notifications to be sent after the unlink operation from inside
- * the kernel->userspace event transfer loop.
- */
- epi->event.events = 0;
-
- /*
- * At this point is safe to do the job, unlink the item from our rb-tree.
- * This operation togheter with the above check closes the door to
- * double unlinks.
- */
- ep_rb_erase(&epi->rbn, &ep->rbr);
-
- /*
- * If the item we are going to remove is inside the ready file descriptors
- * we want to remove it from this list to avoid stale events.
- */
- if (ep_is_linked(&epi->rdllink))
- list_del_init(&epi->rdllink);
-
- error = 0;
-eexit_1:
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_unlink(%p, %p) = %d\n",
- current, ep, epi->ffd.file, error));
-
- return error;
-}
-
-
-/*
- * Removes a "struct epitem" from the eventpoll RB tree and deallocates
- * all the associated resources.
- */
-static int ep_remove(struct eventpoll *ep, struct epitem *epi)
-{
- int error;
- unsigned long flags;
- struct file *file = epi->ffd.file;
-
- /*
- * Removes poll wait queue hooks. We _have_ to do this without holding
- * the "ep->lock" otherwise a deadlock might occur. This because of the
- * sequence of the lock acquisition. Here we do "ep->lock" then the wait
- * queue head lock when unregistering the wait queue. The wakeup callback
- * will run by holding the wait queue head lock and will call our callback
- * that will try to get "ep->lock".
- */
- ep_unregister_pollwait(ep, epi);
-
- /* Remove the current item from the list of epoll hooks */
- spin_lock(&file->f_ep_lock);
- if (ep_is_linked(&epi->fllink))
- list_del_init(&epi->fllink);
- spin_unlock(&file->f_ep_lock);
-
- /* We need to acquire the write IRQ lock before calling ep_unlink() */
- write_lock_irqsave(&ep->lock, flags);
-
- /* Really unlink the item from the RB tree */
- error = ep_unlink(ep, epi);
-
- write_unlock_irqrestore(&ep->lock, flags);
-
- if (error)
- goto eexit_1;
-
- /* At this point it is safe to free the eventpoll item */
- ep_release_epitem(epi);
-
- error = 0;
-eexit_1:
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n",
- current, ep, file, error));
-
- return error;
-}
-
-
-/*
- * This is the callback that is passed to the wait queue wakeup
- * machanism. It is called by the stored file descriptors when they
- * have events to report.
- */
-static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key)
-{
- int pwake = 0;
- unsigned long flags;
- struct epitem *epi = ep_item_from_wait(wait);
- struct eventpoll *ep = epi->ep;
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: poll_callback(%p) epi=%p ep=%p\n",
- current, epi->ffd.file, epi, ep));
-
- write_lock_irqsave(&ep->lock, flags);
-
- /*
- * If the event mask does not contain any poll(2) event, we consider the
- * descriptor to be disabled. This condition is likely the effect of the
- * EPOLLONESHOT bit that disables the descriptor when an event is received,
- * until the next EPOLL_CTL_MOD will be issued.
- */
- if (!(epi->event.events & ~EP_PRIVATE_BITS))
- goto is_disabled;
-
- /* If this file is already in the ready list we exit soon */
- if (ep_is_linked(&epi->rdllink))
- goto is_linked;
-
- list_add_tail(&epi->rdllink, &ep->rdllist);
-
-is_linked:
- /*
- * Wake up ( if active ) both the eventpoll wait list and the ->poll()
- * wait list.
- */
- if (waitqueue_active(&ep->wq))
- __wake_up_locked(&ep->wq, TASK_UNINTERRUPTIBLE |
- TASK_INTERRUPTIBLE);
- if (waitqueue_active(&ep->poll_wait))
- pwake++;
-
-is_disabled:
- write_unlock_irqrestore(&ep->lock, flags);
-
- /* We have to call this outside the lock */
- if (pwake)
- ep_poll_safewake(&psw, &ep->poll_wait);
-
- return 1;
-}
-
-
-static int ep_eventpoll_close(struct inode *inode, struct file *file)
-{
- struct eventpoll *ep = file->private_data;
-
- if (ep) {
- ep_free(ep);
- kfree(ep);
- }
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: close() ep=%p\n", current, ep));
- return 0;
-}
-
-
-static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
-{
- unsigned int pollflags = 0;
- unsigned long flags;
- struct eventpoll *ep = file->private_data;
-
- /* Insert inside our poll wait queue */
- poll_wait(file, &ep->poll_wait, wait);
-
- /* Check our condition */
- read_lock_irqsave(&ep->lock, flags);
- if (!list_empty(&ep->rdllist))
- pollflags = POLLIN | POLLRDNORM;
- read_unlock_irqrestore(&ep->lock, flags);
-
- return pollflags;
-}
-
-
/*
* This function is called without holding the "ep->lock" since the call to
* __copy_to_user() might sleep, and also f_op->poll() might reenable the IRQ
@@ -1447,7 +1031,6 @@
return eventcnt == 0 ? error: eventcnt;
}
-
/*
* Perform the transfer of events to user space.
*/
@@ -1483,7 +1066,6 @@
return eventcnt;
}
-
static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
int maxevents, long timeout)
{
@@ -1553,52 +1135,262 @@
return res;
}
-static int eventpollfs_delete_dentry(struct dentry *dentry)
+/*
+ * It opens an eventpoll file descriptor by suggesting a storage of "size"
+ * file descriptors. The size parameter is just an hint about how to size
+ * data structures. It won't prevent the user to store more than "size"
+ * file descriptors inside the epoll interface. It is the kernel part of
+ * the userspace epoll_create(2).
+ */
+asmlinkage long sys_epoll_create(int size)
{
+ int error, fd = -1;
+ struct eventpoll *ep;
+ struct inode *inode;
+ struct file *file;
- return 1;
-}
-
-static struct inode *ep_eventpoll_inode(void)
-{
- int error = -ENOMEM;
- struct inode *inode = new_inode(eventpoll_mnt->mnt_sb);
-
- if (!inode)
- goto eexit_1;
-
- inode->i_fop = &eventpoll_fops;
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
+ current, size));
/*
- * Mark the inode dirty from the very beginning,
- * that way it will never be moved to the dirty
- * list because mark_inode_dirty() will think
- * that it already _is_ on the dirty list.
+ * Sanity check on the size parameter, and create the internal data
+ * structure ( "struct eventpoll" ).
*/
- inode->i_state = I_DIRTY;
- inode->i_mode = S_IRUSR | S_IWUSR;
- inode->i_uid = current->fsuid;
- inode->i_gid = current->fsgid;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- return inode;
+ error = -EINVAL;
+ if (size <= 0 || (error = ep_alloc(&ep)) != 0)
+ goto error_return;
-eexit_1:
- return ERR_PTR(error);
+ /*
+ * Creates all the items needed to setup an eventpoll file. That is,
+ * a file structure, and inode and a free file descriptor.
+ */
+ error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]",
+ &eventpoll_fops, ep);
+ if (error)
+ goto error_free;
+
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
+ current, size, fd));
+
+ return fd;
+
+error_free:
+ ep_free(ep);
+ kfree(ep);
+error_return:
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
+ current, size, error));
+ return error;
}
-static int
-eventpollfs_get_sb(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data, struct vfsmount *mnt)
+/*
+ * The following function implements the controller interface for
+ * the eventpoll file that enables the insertion/removal/change of
+ * file descriptors inside the interest set. It represents
+ * the kernel part of the user space epoll_ctl(2).
+ */
+asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
+ struct epoll_event __user *event)
{
- return get_sb_pseudo(fs_type, "eventpoll:", NULL, EVENTPOLLFS_MAGIC,
- mnt);
+ int error;
+ struct file *file, *tfile;
+ struct eventpoll *ep;
+ struct epitem *epi;
+ struct epoll_event epds;
+
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p)\n",
+ current, epfd, op, fd, event));
+
+ error = -EFAULT;
+ if (ep_op_has_event(op) &&
+ copy_from_user(&epds, event, sizeof(struct epoll_event)))
+ goto error_return;
+
+ /* Get the "struct file *" for the eventpoll file */
+ error = -EBADF;
+ file = fget(epfd);
+ if (!file)
+ goto error_return;
+
+ /* Get the "struct file *" for the target file */
+ tfile = fget(fd);
+ if (!tfile)
+ goto error_fput;
+
+ /* The target file descriptor must support poll */
+ error = -EPERM;
+ if (!tfile->f_op || !tfile->f_op->poll)
+ goto error_tgt_fput;
+
+ /*
+ * We have to check that the file structure underneath the file descriptor
+ * the user passed to us _is_ an eventpoll file. And also we do not permit
+ * adding an epoll file descriptor inside itself.
+ */
+ error = -EINVAL;
+ if (file == tfile || !is_file_epoll(file))
+ goto error_tgt_fput;
+
+ /*
+ * At this point it is safe to assume that the "private_data" contains
+ * our own data structure.
+ */
+ ep = file->private_data;
+
+ down_write(&ep->sem);
+
+ /* Try to lookup the file inside our RB tree */
+ epi = ep_find(ep, tfile, fd);
+
+ error = -EINVAL;
+ switch (op) {
+ case EPOLL_CTL_ADD:
+ if (!epi) {
+ epds.events |= POLLERR | POLLHUP;
+
+ error = ep_insert(ep, &epds, tfile, fd);
+ } else
+ error = -EEXIST;
+ break;
+ case EPOLL_CTL_DEL:
+ if (epi)
+ error = ep_remove(ep, epi);
+ else
+ error = -ENOENT;
+ break;
+ case EPOLL_CTL_MOD:
+ if (epi) {
+ epds.events |= POLLERR | POLLHUP;
+ error = ep_modify(ep, epi, &epds);
+ } else
+ error = -ENOENT;
+ break;
+ }
+ /*
+ * The function ep_find() increments the usage count of the structure
+ * so, if this is not NULL, we need to release it.
+ */
+ if (epi)
+ ep_release_epitem(epi);
+ up_write(&ep->sem);
+
+error_tgt_fput:
+ fput(tfile);
+error_fput:
+ fput(file);
+error_return:
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_ctl(%d, %d, %d, %p) = %d\n",
+ current, epfd, op, fd, event, error));
+
+ return error;
}
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_wait(2).
+ */
+asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
+ int maxevents, int timeout)
+{
+ int error;
+ struct file *file;
+ struct eventpoll *ep;
+
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
+ current, epfd, events, maxevents, timeout));
+
+ /* The maximum number of event must be greater than zero */
+ if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
+ return -EINVAL;
+
+ /* Verify that the area passed by the user is writeable */
+ if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) {
+ error = -EFAULT;
+ goto error_return;
+ }
+
+ /* Get the "struct file *" for the eventpoll file */
+ error = -EBADF;
+ file = fget(epfd);
+ if (!file)
+ goto error_return;
+
+ /*
+ * We have to check that the file structure underneath the fd
+ * the user passed to us _is_ an eventpoll file.
+ */
+ error = -EINVAL;
+ if (!is_file_epoll(file))
+ goto error_fput;
+
+ /*
+ * At this point it is safe to assume that the "private_data" contains
+ * our own data structure.
+ */
+ ep = file->private_data;
+
+ /* Time to fish for events ... */
+ error = ep_poll(ep, events, maxevents, timeout);
+
+error_fput:
+ fput(file);
+error_return:
+ DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d) = %d\n",
+ current, epfd, events, maxevents, timeout, error));
+
+ return error;
+}
+
+#ifdef TIF_RESTORE_SIGMASK
+
+/*
+ * Implement the event wait interface for the eventpoll file. It is the kernel
+ * part of the user space epoll_pwait(2).
+ */
+asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
+ int maxevents, int timeout, const sigset_t __user *sigmask,
+ size_t sigsetsize)
+{
+ int error;
+ sigset_t ksigmask, sigsaved;
+
+ /*
+ * If the caller wants a certain signal mask to be set during the wait,
+ * we apply it here.
+ */
+ if (sigmask) {
+ if (sigsetsize != sizeof(sigset_t))
+ return -EINVAL;
+ if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask)))
+ return -EFAULT;
+ sigdelsetmask(&ksigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+ sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved);
+ }
+
+ error = sys_epoll_wait(epfd, events, maxevents, timeout);
+
+ /*
+ * If we changed the signal mask, we need to restore the original one.
+ * In case we've got a signal while waiting, we do not restore the
+ * signal mask yet, and we allow do_signal() to deliver the signal on
+ * the way back to userspace, before the signal mask is restored.
+ */
+ if (sigmask) {
+ if (error == -EINTR) {
+ memcpy(¤t->saved_sigmask, &sigsaved,
+ sizeof(sigsaved));
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ } else
+ sigprocmask(SIG_SETMASK, &sigsaved, NULL);
+ }
+
+ return error;
+}
+
+#endif /* #ifdef TIF_RESTORE_SIGMASK */
static int __init eventpoll_init(void)
{
- int error;
-
mutex_init(&epmutex);
/* Initialize the structure used to perform safe poll wait head wake ups */
@@ -1614,39 +1406,7 @@
sizeof(struct eppoll_entry), 0,
EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);
- /*
- * Register the virtual file system that will be the source of inodes
- * for the eventpoll files
- */
- error = register_filesystem(&eventpoll_fs_type);
- if (error)
- goto epanic;
-
- /* Mount the above commented virtual file system */
- eventpoll_mnt = kern_mount(&eventpoll_fs_type);
- error = PTR_ERR(eventpoll_mnt);
- if (IS_ERR(eventpoll_mnt))
- goto epanic;
-
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: successfully initialized.\n",
- current));
return 0;
-
-epanic:
- panic("eventpoll_init() failed\n");
}
+fs_initcall(eventpoll_init);
-
-static void __exit eventpoll_exit(void)
-{
- /* Undo all operations done inside eventpoll_init() */
- unregister_filesystem(&eventpoll_fs_type);
- mntput(eventpoll_mnt);
- kmem_cache_destroy(pwq_cache);
- kmem_cache_destroy(epi_cache);
-}
-
-module_init(eventpoll_init);
-module_exit(eventpoll_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/fs/exec.c b/fs/exec.c
index 1ba85c7..70fa365 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,6 +50,7 @@
#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
#include <linux/audit.h>
+#include <linux/signalfd.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -582,6 +583,13 @@
int count;
/*
+ * Tell all the sighand listeners that this sighand has
+ * been detached. The signalfd_detach() function grabs the
+ * sighand lock, if signal listeners are present on the sighand.
+ */
+ signalfd_detach(tsk);
+
+ /*
* If we don't share sighandlers, then we aren't sharing anything
* and we can just re-use it all.
*/
@@ -702,7 +710,7 @@
*/
detach_pid(tsk, PIDTYPE_PID);
tsk->pid = leader->pid;
- attach_pid(tsk, PIDTYPE_PID, tsk->pid);
+ attach_pid(tsk, PIDTYPE_PID, find_pid(tsk->pid));
transfer_pid(leader, tsk, PIDTYPE_PGID);
transfer_pid(leader, tsk, PIDTYPE_SID);
list_replace_rcu(&leader->tasks, &tsk->tasks);
@@ -757,8 +765,7 @@
spin_unlock(&oldsighand->siglock);
write_unlock_irq(&tasklist_lock);
- if (atomic_dec_and_test(&oldsighand->count))
- kmem_cache_free(sighand_cachep, oldsighand);
+ __cleanup_sighand(oldsighand);
}
BUG_ON(!thread_group_leader(tsk));
@@ -1488,6 +1495,8 @@
int flag = 0;
int ispipe = 0;
+ audit_core_dumps(signr);
+
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
goto fail;
diff --git a/fs/locks.c b/fs/locks.c
index 671a034..8ec16ab 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -669,7 +669,6 @@
{
struct file_lock *cfl;
- fl->fl_type = F_UNLCK;
lock_kernel();
for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
if (!IS_POSIX(cfl))
@@ -681,7 +680,8 @@
__locks_copy_lock(fl, cfl);
unlock_kernel();
return 1;
- }
+ } else
+ fl->fl_type = F_UNLCK;
unlock_kernel();
return 0;
}
@@ -1632,6 +1632,7 @@
flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
fl->fl_end - fl->fl_start + 1;
flock->l_whence = 0;
+ flock->l_type = fl->fl_type;
return 0;
}
diff --git a/fs/mpage.c b/fs/mpage.c
index 0fb914f..c1698f2 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -454,11 +454,18 @@
* written, so it can intelligently allocate a suitably-sized BIO. For now,
* just allocate full-size (16-page) BIOs.
*/
-static struct bio *
-__mpage_writepage(struct bio *bio, struct page *page, get_block_t get_block,
- sector_t *last_block_in_bio, int *ret, struct writeback_control *wbc,
- writepage_t writepage_fn)
+struct mpage_data {
+ struct bio *bio;
+ sector_t last_block_in_bio;
+ get_block_t *get_block;
+ unsigned use_writepage;
+};
+
+static int __mpage_writepage(struct page *page, struct writeback_control *wbc,
+ void *data)
{
+ struct mpage_data *mpd = data;
+ struct bio *bio = mpd->bio;
struct address_space *mapping = page->mapping;
struct inode *inode = page->mapping->host;
const unsigned blkbits = inode->i_blkbits;
@@ -476,6 +483,7 @@
int length;
struct buffer_head map_bh;
loff_t i_size = i_size_read(inode);
+ int ret = 0;
if (page_has_buffers(page)) {
struct buffer_head *head = page_buffers(page);
@@ -538,7 +546,7 @@
map_bh.b_state = 0;
map_bh.b_size = 1 << blkbits;
- if (get_block(inode, block_in_file, &map_bh, 1))
+ if (mpd->get_block(inode, block_in_file, &map_bh, 1))
goto confused;
if (buffer_new(&map_bh))
unmap_underlying_metadata(map_bh.b_bdev,
@@ -584,7 +592,7 @@
/*
* This page will go to BIO. Do we need to send this BIO off first?
*/
- if (bio && *last_block_in_bio != blocks[0] - 1)
+ if (bio && mpd->last_block_in_bio != blocks[0] - 1)
bio = mpage_bio_submit(WRITE, bio);
alloc_new:
@@ -641,7 +649,7 @@
boundary_block, 1 << blkbits);
}
} else {
- *last_block_in_bio = blocks[blocks_per_page - 1];
+ mpd->last_block_in_bio = blocks[blocks_per_page - 1];
}
goto out;
@@ -649,18 +657,19 @@
if (bio)
bio = mpage_bio_submit(WRITE, bio);
- if (writepage_fn) {
- *ret = (*writepage_fn)(page, wbc);
+ if (mpd->use_writepage) {
+ ret = mapping->a_ops->writepage(page, wbc);
} else {
- *ret = -EAGAIN;
+ ret = -EAGAIN;
goto out;
}
/*
* The caller has a ref on the inode, so *mapping is stable
*/
- mapping_set_error(mapping, *ret);
+ mapping_set_error(mapping, ret);
out:
- return bio;
+ mpd->bio = bio;
+ return ret;
}
/**
@@ -683,120 +692,27 @@
* the call was made get new I/O started against them. If wbc->sync_mode is
* WB_SYNC_ALL then we were called for data integrity and we must wait for
* existing IO to complete.
- *
- * If you fix this you should check generic_writepages() also!
*/
int
mpage_writepages(struct address_space *mapping,
struct writeback_control *wbc, get_block_t get_block)
{
- struct backing_dev_info *bdi = mapping->backing_dev_info;
- struct bio *bio = NULL;
- sector_t last_block_in_bio = 0;
- int ret = 0;
- int done = 0;
- int (*writepage)(struct page *page, struct writeback_control *wbc);
- struct pagevec pvec;
- int nr_pages;
- pgoff_t index;
- pgoff_t end; /* Inclusive */
- int scanned = 0;
- int range_whole = 0;
+ int ret;
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
- wbc->encountered_congestion = 1;
- return 0;
+ if (!get_block)
+ ret = generic_writepages(mapping, wbc);
+ else {
+ struct mpage_data mpd = {
+ .bio = NULL,
+ .last_block_in_bio = 0,
+ .get_block = get_block,
+ .use_writepage = 1,
+ };
+
+ ret = write_cache_pages(mapping, wbc, __mpage_writepage, &mpd);
+ if (mpd.bio)
+ mpage_bio_submit(WRITE, mpd.bio);
}
-
- writepage = NULL;
- if (get_block == NULL)
- writepage = mapping->a_ops->writepage;
-
- pagevec_init(&pvec, 0);
- if (wbc->range_cyclic) {
- index = mapping->writeback_index; /* Start from prev offset */
- end = -1;
- } else {
- index = wbc->range_start >> PAGE_CACHE_SHIFT;
- end = wbc->range_end >> PAGE_CACHE_SHIFT;
- if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
- range_whole = 1;
- scanned = 1;
- }
-retry:
- while (!done && (index <= end) &&
- (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
- PAGECACHE_TAG_DIRTY,
- min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) {
- unsigned i;
-
- scanned = 1;
- for (i = 0; i < nr_pages; i++) {
- struct page *page = pvec.pages[i];
-
- /*
- * At this point we hold neither mapping->tree_lock nor
- * lock on the page itself: the page may be truncated or
- * invalidated (changing page->mapping to NULL), or even
- * swizzled back from swapper_space to tmpfs file
- * mapping
- */
-
- lock_page(page);
-
- if (unlikely(page->mapping != mapping)) {
- unlock_page(page);
- continue;
- }
-
- if (!wbc->range_cyclic && page->index > end) {
- done = 1;
- unlock_page(page);
- continue;
- }
-
- if (wbc->sync_mode != WB_SYNC_NONE)
- wait_on_page_writeback(page);
-
- if (PageWriteback(page) ||
- !clear_page_dirty_for_io(page)) {
- unlock_page(page);
- continue;
- }
-
- if (writepage) {
- ret = (*writepage)(page, wbc);
- mapping_set_error(mapping, ret);
- } else {
- bio = __mpage_writepage(bio, page, get_block,
- &last_block_in_bio, &ret, wbc,
- page->mapping->a_ops->writepage);
- }
- if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
- unlock_page(page);
- if (ret || (--(wbc->nr_to_write) <= 0))
- done = 1;
- if (wbc->nonblocking && bdi_write_congested(bdi)) {
- wbc->encountered_congestion = 1;
- done = 1;
- }
- }
- pagevec_release(&pvec);
- cond_resched();
- }
- if (!scanned && !done) {
- /*
- * We hit the last page and there is more work to be done: wrap
- * back to the start of the file
- */
- scanned = 1;
- index = 0;
- goto retry;
- }
- if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
- mapping->writeback_index = index;
- if (bio)
- mpage_bio_submit(WRITE, bio);
return ret;
}
EXPORT_SYMBOL(mpage_writepages);
@@ -804,15 +720,15 @@
int mpage_writepage(struct page *page, get_block_t get_block,
struct writeback_control *wbc)
{
- int ret = 0;
- struct bio *bio;
- sector_t last_block_in_bio = 0;
-
- bio = __mpage_writepage(NULL, page, get_block,
- &last_block_in_bio, &ret, wbc, NULL);
- if (bio)
- mpage_bio_submit(WRITE, bio);
-
+ struct mpage_data mpd = {
+ .bio = NULL,
+ .last_block_in_bio = 0,
+ .get_block = get_block,
+ .use_writepage = 0,
+ };
+ int ret = __mpage_writepage(page, wbc, &mpd);
+ if (mpd.bio)
+ mpage_bio_submit(WRITE, mpd.bio);
return ret;
}
EXPORT_SYMBOL(mpage_writepage);
diff --git a/fs/namei.c b/fs/namei.c
index b3780e3..5e2d98d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1719,7 +1719,7 @@
* It already exists.
*/
mutex_unlock(&dir->d_inode->i_mutex);
- audit_inode_update(path.dentry->d_inode);
+ audit_inode(pathname, path.dentry->d_inode);
error = -EEXIST;
if (flag & O_EXCL)
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index 2e975c0a..a93620c 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -144,7 +144,8 @@
};
static struct kset mlog_kset = {
- .kobj = {.name = "logmask", .ktype = &mlog_ktype},
+ .kobj = {.name = "logmask"},
+ .ktype = &mlog_ktype
};
int mlog_sys_init(struct kset *o2cb_subsys)
@@ -157,7 +158,7 @@
}
mlog_attr_ptrs[i] = NULL;
- kobj_set_kset_s(&mlog_kset, o2cb_subsys);
+ kobj_set_kset_s(&mlog_kset, *o2cb_subsys);
return kset_register(&mlog_kset);
}
diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig
index 0120704..7638a1c 100644
--- a/fs/partitions/Kconfig
+++ b/fs/partitions/Kconfig
@@ -239,7 +239,7 @@
config SYSV68_PARTITION
bool "SYSV68 partition table support" if PARTITION_ADVANCED
- default y if M68K
+ default y if VME
help
Say Y here if you would like to be able to read the hard disk
partition table format used by Motorola Delta machines (using
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
index 1bea610..e7b0700 100644
--- a/fs/partitions/efi.c
+++ b/fs/partitions/efi.c
@@ -152,7 +152,7 @@
}
static inline int
-pmbr_part_valid(struct partition *part, u64 lastlba)
+pmbr_part_valid(struct partition *part)
{
if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
le32_to_cpu(part->start_sect) == 1UL)
@@ -163,7 +163,6 @@
/**
* is_pmbr_valid(): test Protective MBR for validity
* @mbr: pointer to a legacy mbr structure
- * @lastlba: last_lba for the whole device
*
* Description: Returns 1 if PMBR is valid, 0 otherwise.
* Validity depends on two things:
@@ -171,13 +170,13 @@
* 2) One partition of type 0xEE is found
*/
static int
-is_pmbr_valid(legacy_mbr *mbr, u64 lastlba)
+is_pmbr_valid(legacy_mbr *mbr)
{
int i;
if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
return 0;
for (i = 0; i < 4; i++)
- if (pmbr_part_valid(&mbr->partition_record[i], lastlba))
+ if (pmbr_part_valid(&mbr->partition_record[i]))
return 1;
return 0;
}
@@ -516,7 +515,7 @@
int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
gpt_header *pgpt = NULL, *agpt = NULL;
gpt_entry *pptes = NULL, *aptes = NULL;
- legacy_mbr *legacymbr = NULL;
+ legacy_mbr *legacymbr;
u64 lastlba;
if (!bdev || !gpt || !ptes)
return 0;
@@ -528,9 +527,8 @@
if (legacymbr) {
read_lba(bdev, 0, (u8 *) legacymbr,
sizeof (*legacymbr));
- good_pmbr = is_pmbr_valid(legacymbr, lastlba);
+ good_pmbr = is_pmbr_valid(legacymbr);
kfree(legacymbr);
- legacymbr=NULL;
}
if (!good_pmbr)
goto fail;
diff --git a/fs/signalfd.c b/fs/signalfd.c
new file mode 100644
index 0000000..7cfeab4
--- /dev/null
+++ b/fs/signalfd.c
@@ -0,0 +1,349 @@
+/*
+ * fs/signalfd.c
+ *
+ * Copyright (C) 2003 Linus Torvalds
+ *
+ * Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org>
+ * Changed ->read() to return a siginfo strcture instead of signal number.
+ * Fixed locking in ->poll().
+ * Added sighand-detach notification.
+ * Added fd re-use in sys_signalfd() syscall.
+ * Now using anonymous inode source.
+ * Thanks to Oleg Nesterov for useful code review and suggestions.
+ * More comments and suggestions from Arnd Bergmann.
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/list.h>
+#include <linux/anon_inodes.h>
+#include <linux/signalfd.h>
+
+struct signalfd_ctx {
+ struct list_head lnk;
+ wait_queue_head_t wqh;
+ sigset_t sigmask;
+ struct task_struct *tsk;
+};
+
+struct signalfd_lockctx {
+ struct task_struct *tsk;
+ unsigned long flags;
+};
+
+/*
+ * Tries to acquire the sighand lock. We do not increment the sighand
+ * use count, and we do not even pin the task struct, so we need to
+ * do it inside an RCU read lock, and we must be prepared for the
+ * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand
+ * being detached. We return 0 if the sighand has been detached, or
+ * 1 if we were able to pin the sighand lock.
+ */
+static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk)
+{
+ struct sighand_struct *sighand = NULL;
+
+ rcu_read_lock();
+ lk->tsk = rcu_dereference(ctx->tsk);
+ if (likely(lk->tsk != NULL))
+ sighand = lock_task_sighand(lk->tsk, &lk->flags);
+ rcu_read_unlock();
+
+ if (sighand && !ctx->tsk) {
+ unlock_task_sighand(lk->tsk, &lk->flags);
+ sighand = NULL;
+ }
+
+ return sighand != NULL;
+}
+
+static void signalfd_unlock(struct signalfd_lockctx *lk)
+{
+ unlock_task_sighand(lk->tsk, &lk->flags);
+}
+
+/*
+ * This must be called with the sighand lock held.
+ */
+void signalfd_deliver(struct task_struct *tsk, int sig)
+{
+ struct sighand_struct *sighand = tsk->sighand;
+ struct signalfd_ctx *ctx, *tmp;
+
+ BUG_ON(!sig);
+ list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) {
+ /*
+ * We use a negative signal value as a way to broadcast that the
+ * sighand has been orphaned, so that we can notify all the
+ * listeners about this. Remember the ctx->sigmask is inverted,
+ * so if the user is interested in a signal, that corresponding
+ * bit will be zero.
+ */
+ if (sig < 0) {
+ if (ctx->tsk == tsk) {
+ ctx->tsk = NULL;
+ list_del_init(&ctx->lnk);
+ wake_up(&ctx->wqh);
+ }
+ } else {
+ if (!sigismember(&ctx->sigmask, sig))
+ wake_up(&ctx->wqh);
+ }
+ }
+}
+
+static void signalfd_cleanup(struct signalfd_ctx *ctx)
+{
+ struct signalfd_lockctx lk;
+
+ /*
+ * This is tricky. If the sighand is gone, we do not need to remove
+ * context from the list, the list itself won't be there anymore.
+ */
+ if (signalfd_lock(ctx, &lk)) {
+ list_del(&ctx->lnk);
+ signalfd_unlock(&lk);
+ }
+ kfree(ctx);
+}
+
+static int signalfd_release(struct inode *inode, struct file *file)
+{
+ signalfd_cleanup(file->private_data);
+ return 0;
+}
+
+static unsigned int signalfd_poll(struct file *file, poll_table *wait)
+{
+ struct signalfd_ctx *ctx = file->private_data;
+ unsigned int events = 0;
+ struct signalfd_lockctx lk;
+
+ poll_wait(file, &ctx->wqh, wait);
+
+ /*
+ * Let the caller get a POLLIN in this case, ala socket recv() when
+ * the peer disconnects.
+ */
+ if (signalfd_lock(ctx, &lk)) {
+ if (next_signal(&lk.tsk->pending, &ctx->sigmask) > 0 ||
+ next_signal(&lk.tsk->signal->shared_pending,
+ &ctx->sigmask) > 0)
+ events |= POLLIN;
+ signalfd_unlock(&lk);
+ } else
+ events |= POLLIN;
+
+ return events;
+}
+
+/*
+ * Copied from copy_siginfo_to_user() in kernel/signal.c
+ */
+static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
+ siginfo_t const *kinfo)
+{
+ long err;
+
+ BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
+
+ /*
+ * Unused memebers should be zero ...
+ */
+ err = __clear_user(uinfo, sizeof(*uinfo));
+
+ /*
+ * If you change siginfo_t structure, please be sure
+ * this code is fixed accordingly.
+ */
+ err |= __put_user(kinfo->si_signo, &uinfo->signo);
+ err |= __put_user(kinfo->si_errno, &uinfo->err);
+ err |= __put_user((short)kinfo->si_code, &uinfo->code);
+ switch (kinfo->si_code & __SI_MASK) {
+ case __SI_KILL:
+ err |= __put_user(kinfo->si_pid, &uinfo->pid);
+ err |= __put_user(kinfo->si_uid, &uinfo->uid);
+ break;
+ case __SI_TIMER:
+ err |= __put_user(kinfo->si_tid, &uinfo->tid);
+ err |= __put_user(kinfo->si_overrun, &uinfo->overrun);
+ err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
+ break;
+ case __SI_POLL:
+ err |= __put_user(kinfo->si_band, &uinfo->band);
+ err |= __put_user(kinfo->si_fd, &uinfo->fd);
+ break;
+ case __SI_FAULT:
+ err |= __put_user((long)kinfo->si_addr, &uinfo->addr);
+#ifdef __ARCH_SI_TRAPNO
+ err |= __put_user(kinfo->si_trapno, &uinfo->trapno);
+#endif
+ break;
+ case __SI_CHLD:
+ err |= __put_user(kinfo->si_pid, &uinfo->pid);
+ err |= __put_user(kinfo->si_uid, &uinfo->uid);
+ err |= __put_user(kinfo->si_status, &uinfo->status);
+ err |= __put_user(kinfo->si_utime, &uinfo->utime);
+ err |= __put_user(kinfo->si_stime, &uinfo->stime);
+ break;
+ case __SI_RT: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ: /* But this is */
+ err |= __put_user(kinfo->si_pid, &uinfo->pid);
+ err |= __put_user(kinfo->si_uid, &uinfo->uid);
+ err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
+ break;
+ default: /* this is just in case for now ... */
+ err |= __put_user(kinfo->si_pid, &uinfo->pid);
+ err |= __put_user(kinfo->si_uid, &uinfo->uid);
+ break;
+ }
+
+ return err ? -EFAULT: sizeof(*uinfo);
+}
+
+/*
+ * Returns either the size of a "struct signalfd_siginfo", or zero if the
+ * sighand we are attached to, has been orphaned. The "count" parameter
+ * must be at least the size of a "struct signalfd_siginfo".
+ */
+static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct signalfd_ctx *ctx = file->private_data;
+ ssize_t res = 0;
+ int locked, signo;
+ siginfo_t info;
+ struct signalfd_lockctx lk;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (count < sizeof(struct signalfd_siginfo))
+ return -EINVAL;
+ locked = signalfd_lock(ctx, &lk);
+ if (!locked)
+ return 0;
+ res = -EAGAIN;
+ signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
+ if (signo == 0 && !(file->f_flags & O_NONBLOCK)) {
+ add_wait_queue(&ctx->wqh, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
+ if (signo != 0)
+ break;
+ if (signal_pending(current)) {
+ res = -ERESTARTSYS;
+ break;
+ }
+ signalfd_unlock(&lk);
+ schedule();
+ locked = signalfd_lock(ctx, &lk);
+ if (unlikely(!locked)) {
+ /*
+ * Let the caller read zero byte, ala socket
+ * recv() when the peer disconnect. This test
+ * must be done before doing a dequeue_signal(),
+ * because if the sighand has been orphaned,
+ * the dequeue_signal() call is going to crash.
+ */
+ res = 0;
+ break;
+ }
+ }
+ remove_wait_queue(&ctx->wqh, &wait);
+ __set_current_state(TASK_RUNNING);
+ }
+ if (likely(locked))
+ signalfd_unlock(&lk);
+ if (likely(signo))
+ res = signalfd_copyinfo((struct signalfd_siginfo __user *) buf,
+ &info);
+
+ return res;
+}
+
+static const struct file_operations signalfd_fops = {
+ .release = signalfd_release,
+ .poll = signalfd_poll,
+ .read = signalfd_read,
+};
+
+/*
+ * Create a file descriptor that is associated with our signal
+ * state. We can pass it around to others if we want to, but
+ * it will always be _our_ signal state.
+ */
+asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
+{
+ int error;
+ sigset_t sigmask;
+ struct signalfd_ctx *ctx;
+ struct sighand_struct *sighand;
+ struct file *file;
+ struct inode *inode;
+ struct signalfd_lockctx lk;
+
+ if (sizemask != sizeof(sigset_t) ||
+ copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
+ return error = -EINVAL;
+ sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
+ signotset(&sigmask);
+
+ if (ufd == -1) {
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ init_waitqueue_head(&ctx->wqh);
+ ctx->sigmask = sigmask;
+ ctx->tsk = current;
+
+ sighand = current->sighand;
+ /*
+ * Add this fd to the list of signal listeners.
+ */
+ spin_lock_irq(&sighand->siglock);
+ list_add_tail(&ctx->lnk, &sighand->signalfd_list);
+ spin_unlock_irq(&sighand->siglock);
+
+ /*
+ * When we call this, the initialization must be complete, since
+ * anon_inode_getfd() will install the fd.
+ */
+ error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
+ &signalfd_fops, ctx);
+ if (error)
+ goto err_fdalloc;
+ } else {
+ file = fget(ufd);
+ if (!file)
+ return -EBADF;
+ ctx = file->private_data;
+ if (file->f_op != &signalfd_fops) {
+ fput(file);
+ return -EINVAL;
+ }
+ /*
+ * We need to be prepared of the fact that the sighand this fd
+ * is attached to, has been detched. In that case signalfd_lock()
+ * will return 0, and we'll just skip setting the new mask.
+ */
+ if (signalfd_lock(ctx, &lk)) {
+ ctx->sigmask = sigmask;
+ signalfd_unlock(&lk);
+ }
+ wake_up(&ctx->wqh);
+ fput(file);
+ }
+
+ return ufd;
+
+err_fdalloc:
+ signalfd_cleanup(ctx);
+ return error;
+}
+
diff --git a/fs/timerfd.c b/fs/timerfd.c
new file mode 100644
index 0000000..e329e37
--- /dev/null
+++ b/fs/timerfd.c
@@ -0,0 +1,227 @@
+/*
+ * fs/timerfd.c
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ *
+ * Thanks to Thomas Gleixner for code reviews and useful comments.
+ *
+ */
+
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/hrtimer.h>
+#include <linux/anon_inodes.h>
+#include <linux/timerfd.h>
+
+struct timerfd_ctx {
+ struct hrtimer tmr;
+ ktime_t tintv;
+ spinlock_t lock;
+ wait_queue_head_t wqh;
+ int expired;
+};
+
+/*
+ * This gets called when the timer event triggers. We set the "expired"
+ * flag, but we do not re-arm the timer (in case it's necessary,
+ * tintv.tv64 != 0) until the timer is read.
+ */
+static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
+{
+ struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->lock, flags);
+ ctx->expired = 1;
+ wake_up_locked(&ctx->wqh);
+ spin_unlock_irqrestore(&ctx->lock, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+ const struct itimerspec *ktmr)
+{
+ enum hrtimer_mode htmode;
+ ktime_t texp;
+
+ htmode = (flags & TFD_TIMER_ABSTIME) ?
+ HRTIMER_MODE_ABS: HRTIMER_MODE_REL;
+
+ texp = timespec_to_ktime(ktmr->it_value);
+ ctx->expired = 0;
+ ctx->tintv = timespec_to_ktime(ktmr->it_interval);
+ hrtimer_init(&ctx->tmr, clockid, htmode);
+ ctx->tmr.expires = texp;
+ ctx->tmr.function = timerfd_tmrproc;
+ if (texp.tv64 != 0)
+ hrtimer_start(&ctx->tmr, texp, htmode);
+}
+
+static int timerfd_release(struct inode *inode, struct file *file)
+{
+ struct timerfd_ctx *ctx = file->private_data;
+
+ hrtimer_cancel(&ctx->tmr);
+ kfree(ctx);
+ return 0;
+}
+
+static unsigned int timerfd_poll(struct file *file, poll_table *wait)
+{
+ struct timerfd_ctx *ctx = file->private_data;
+ unsigned int events = 0;
+ unsigned long flags;
+
+ poll_wait(file, &ctx->wqh, wait);
+
+ spin_lock_irqsave(&ctx->lock, flags);
+ if (ctx->expired)
+ events |= POLLIN;
+ spin_unlock_irqrestore(&ctx->lock, flags);
+
+ return events;
+}
+
+static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct timerfd_ctx *ctx = file->private_data;
+ ssize_t res;
+ u32 ticks = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (count < sizeof(ticks))
+ return -EINVAL;
+ spin_lock_irq(&ctx->lock);
+ res = -EAGAIN;
+ if (!ctx->expired && !(file->f_flags & O_NONBLOCK)) {
+ __add_wait_queue(&ctx->wqh, &wait);
+ for (res = 0;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (ctx->expired) {
+ res = 0;
+ break;
+ }
+ if (signal_pending(current)) {
+ res = -ERESTARTSYS;
+ break;
+ }
+ spin_unlock_irq(&ctx->lock);
+ schedule();
+ spin_lock_irq(&ctx->lock);
+ }
+ __remove_wait_queue(&ctx->wqh, &wait);
+ __set_current_state(TASK_RUNNING);
+ }
+ if (ctx->expired) {
+ ctx->expired = 0;
+ if (ctx->tintv.tv64 != 0) {
+ /*
+ * If tintv.tv64 != 0, this is a periodic timer that
+ * needs to be re-armed. We avoid doing it in the timer
+ * callback to avoid DoS attacks specifying a very
+ * short timer period.
+ */
+ ticks = (u32)
+ hrtimer_forward(&ctx->tmr,
+ hrtimer_cb_get_time(&ctx->tmr),
+ ctx->tintv);
+ hrtimer_restart(&ctx->tmr);
+ } else
+ ticks = 1;
+ }
+ spin_unlock_irq(&ctx->lock);
+ if (ticks)
+ res = put_user(ticks, buf) ? -EFAULT: sizeof(ticks);
+ return res;
+}
+
+static const struct file_operations timerfd_fops = {
+ .release = timerfd_release,
+ .poll = timerfd_poll,
+ .read = timerfd_read,
+};
+
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+ const struct itimerspec __user *utmr)
+{
+ int error;
+ struct timerfd_ctx *ctx;
+ struct file *file;
+ struct inode *inode;
+ struct itimerspec ktmr;
+
+ if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
+ return -EFAULT;
+
+ if (clockid != CLOCK_MONOTONIC &&
+ clockid != CLOCK_REALTIME)
+ return -EINVAL;
+ if (!timespec_valid(&ktmr.it_value) ||
+ !timespec_valid(&ktmr.it_interval))
+ return -EINVAL;
+
+ if (ufd == -1) {
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ init_waitqueue_head(&ctx->wqh);
+ spin_lock_init(&ctx->lock);
+
+ timerfd_setup(ctx, clockid, flags, &ktmr);
+
+ /*
+ * When we call this, the initialization must be complete, since
+ * anon_inode_getfd() will install the fd.
+ */
+ error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
+ &timerfd_fops, ctx);
+ if (error)
+ goto err_tmrcancel;
+ } else {
+ file = fget(ufd);
+ if (!file)
+ return -EBADF;
+ ctx = file->private_data;
+ if (file->f_op != &timerfd_fops) {
+ fput(file);
+ return -EINVAL;
+ }
+ /*
+ * We need to stop the existing timer before reprogramming
+ * it to the new values.
+ */
+ for (;;) {
+ spin_lock_irq(&ctx->lock);
+ if (hrtimer_try_to_cancel(&ctx->tmr) >= 0)
+ break;
+ spin_unlock_irq(&ctx->lock);
+ cpu_relax();
+ }
+ /*
+ * Re-program the timer to the new value ...
+ */
+ timerfd_setup(ctx, clockid, flags, &ktmr);
+
+ spin_unlock_irq(&ctx->lock);
+ fput(file);
+ }
+
+ return ufd;
+
+err_tmrcancel:
+ hrtimer_cancel(&ctx->tmr);
+ kfree(ctx);
+ return error;
+}
+
diff --git a/fs/xattr.c b/fs/xattr.c
index 9f4568b..4523aca 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -350,6 +350,7 @@
f = fget(fd);
if (!f)
return error;
+ audit_inode(NULL, f->f_path.dentry->d_inode);
error = getxattr(f->f_path.dentry, name, value, size);
fput(f);
return error;
@@ -422,6 +423,7 @@
f = fget(fd);
if (!f)
return error;
+ audit_inode(NULL, f->f_path.dentry->d_inode);
error = listxattr(f->f_path.dentry, list, size);
fput(f);
return error;
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index cb8d286..7f690bb 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -290,12 +290,9 @@
acpi_status
acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state);
-struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id,
- union acpi_parse_object
- *origin,
- union acpi_operand_object
- *mth_desc,
- struct acpi_thread_state
+struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object
+ *origin, union acpi_operand_object
+ *mth_desc, struct acpi_thread_state
*thread);
acpi_status
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 24c3f05..347a911 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -319,7 +319,7 @@
acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS];
ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head;
ACPI_EXTERN struct acpi_gpe_block_info
- *acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
+*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS];
/*****************************************************************************
*
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
index 4409830..ce7c9d6 100644
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -253,8 +253,7 @@
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread);
-void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc,
- struct acpi_thread_state *thread);
+void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc);
/*
* exprep - ACPI AML execution - prep utilities
@@ -446,10 +445,14 @@
/*
* exutils - interpreter/scanner utilities
*/
-acpi_status acpi_ex_enter_interpreter(void);
+void acpi_ex_enter_interpreter(void);
void acpi_ex_exit_interpreter(void);
+void acpi_ex_reacquire_interpreter(void);
+
+void acpi_ex_relinquish_interpreter(void);
+
void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
u8 acpi_ex_acquire_global_lock(u32 rule);
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 6f83ddb..202cd42 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -630,7 +630,7 @@
* and bytelists.
*/
struct acpi_parse_obj_named {
- ACPI_PARSE_COMMON u8 * path;
+ ACPI_PARSE_COMMON u8 *path;
u8 *data; /* AML body or bytelist data */
u32 length; /* AML length */
u32 name; /* 4-byte name or zero if no name */
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index 535b7e1..5ef38a6 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -100,10 +100,8 @@
acpi_walk_callback user_function,
void *context, void **return_value);
-struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
- struct acpi_namespace_node
- *parent,
- struct acpi_namespace_node
+struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node
+ *parent, struct acpi_namespace_node
*child);
/*
diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h
index 5206d61..7e1211a 100644
--- a/include/acpi/acobject.h
+++ b/include/acpi/acobject.h
@@ -155,7 +155,7 @@
struct acpi_object_mutex {
ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */
u16 acquisition_depth; /* Allow multiple Acquires, same thread */
- acpi_thread_id owner_thread_id; /* Current owner of the mutex */
+ struct acpi_thread_state *owner_thread; /* Current owner of the mutex */
acpi_mutex os_mutex; /* Actual OS synchronization object */
union acpi_operand_object *prev; /* Link for list of acquired mutexes */
union acpi_operand_object *next; /* Link for list of acquired mutexes */
@@ -216,7 +216,7 @@
/* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */
u8 proc_id;
u8 length;
- ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
+ ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
};
struct acpi_object_thermal_zone {
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 9cfd5b1..c6fa5e0 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -91,7 +91,8 @@
typedef int (*acpi_op_lock) (struct acpi_device * device, int type);
typedef int (*acpi_op_start) (struct acpi_device * device);
typedef int (*acpi_op_stop) (struct acpi_device * device, int type);
-typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state);
+typedef int (*acpi_op_suspend) (struct acpi_device * device,
+ pm_message_t state);
typedef int (*acpi_op_resume) (struct acpi_device * device);
typedef int (*acpi_op_scan) (struct acpi_device * device);
typedef int (*acpi_op_bind) (struct acpi_device * device);
@@ -296,7 +297,7 @@
void *driver_data;
struct device dev;
struct acpi_bus_ops bus_ops; /* workaround for different code path for hotplug */
- enum acpi_bus_removal_type removal_type; /* indicate for different removal type */
+ enum acpi_bus_removal_type removal_type; /* indicate for different removal type */
};
#define acpi_driver_data(d) ((d)->driver_data)
@@ -338,7 +339,7 @@
acpi_handle handle, int type);
int acpi_bus_trim(struct acpi_device *start, int rmdevice);
int acpi_bus_start(struct acpi_device *device);
-acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd);
+acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd);
int acpi_match_ids(struct acpi_device *device, char *ids);
int acpi_create_dir(struct acpi_device *);
void acpi_remove_dir(struct acpi_device *);
@@ -363,6 +364,6 @@
acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->archdata.acpi_handle))
-#endif /* CONFIG_ACPI */
+#endif /* CONFIG_ACPI */
#endif /*__ACPI_BUS_H__*/
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index f6275b0..5535159 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -113,7 +113,8 @@
extern int register_dock_notifier(struct notifier_block *nb);
extern void unregister_dock_notifier(struct notifier_block *nb);
extern int register_hotplug_dock_device(acpi_handle handle,
- acpi_notify_handler handler, void *context);
+ acpi_notify_handler handler,
+ void *context);
extern void unregister_hotplug_dock_device(acpi_handle handle);
#else
static inline int is_dock_device(acpi_handle handle)
@@ -128,7 +129,8 @@
{
}
static inline int register_hotplug_dock_device(acpi_handle handle,
- acpi_notify_handler handler, void *context)
+ acpi_notify_handler handler,
+ void *context)
{
return -ENODEV;
}
diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h
index 1049f2a..f9d2bde 100644
--- a/include/acpi/acpi_numa.h
+++ b/include/acpi/acpi_numa.h
@@ -8,7 +8,7 @@
#if MAX_NUMNODES > 256
#define MAX_PXM_DOMAINS MAX_NUMNODES
#else
-#define MAX_PXM_DOMAINS (256) /* Old pxm spec is defined 8 bit */
+#define MAX_PXM_DOMAINS (256) /* Old pxm spec is defined 8 bit */
#endif
extern int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS];
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 2785058..5e07db0 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -143,7 +143,8 @@
*/
void *acpi_os_allocate(acpi_size size);
-void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_native_uint length);
+void __iomem *acpi_os_map_memory(acpi_physical_address where,
+ acpi_native_uint length);
void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size);
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 56bf492..fe8abc2 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -344,7 +344,7 @@
/* 64-bit integers */
-typedef unsigned long long acpi_integer;
+typedef unsigned long long acpi_integer;
#define ACPI_INTEGER_MAX ACPI_UINT64_MAX
#define ACPI_INTEGER_BIT_SIZE 64
#define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index 883ffe9..15a8388 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -498,7 +498,8 @@
acpi_status
acpi_ut_walk_aml_resources(u8 * aml,
acpi_size aml_length,
- acpi_walk_aml_callback user_function, void **context);
+ acpi_walk_aml_callback user_function,
+ void **context);
acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index);
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 5f532d2..a568717 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -103,7 +103,10 @@
#define acpi_thread_id struct task_struct *
-static inline acpi_thread_id acpi_os_get_thread_id(void) { return current; }
+static inline acpi_thread_id acpi_os_get_thread_id(void)
+{
+ return current;
+}
/*
* The irqs_disabled() check is for resume from RAM.
@@ -112,15 +115,19 @@
* to quiet __might_sleep() in kmalloc() and resume does not.
*/
#include <acpi/actypes.h>
-static inline void *acpi_os_allocate(acpi_size size) {
- return kmalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+static inline void *acpi_os_allocate(acpi_size size)
+{
+ return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
}
-static inline void *acpi_os_allocate_zeroed(acpi_size size) {
- return kzalloc(size, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+static inline void *acpi_os_allocate_zeroed(acpi_size size)
+{
+ return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
}
-static inline void *acpi_os_acquire_object(acpi_cache_t * cache) {
- return kmem_cache_zalloc(cache, irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL);
+static inline void *acpi_os_acquire_object(acpi_cache_t * cache)
+{
+ return kmem_cache_zalloc(cache,
+ irqs_disabled()? GFP_ATOMIC : GFP_KERNEL);
}
#define ACPI_ALLOCATE(a) acpi_os_allocate(a)
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 916c010..b4b0ffd 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -18,7 +18,7 @@
#define ACPI_PDC_REVISION_ID 0x1
-#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
+#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
#define ACPI_PSD_REV0_ENTRIES 5
/*
@@ -189,8 +189,9 @@
} piix4;
};
-extern int acpi_processor_preregister_performance(
- struct acpi_processor_performance **performance);
+extern int acpi_processor_preregister_performance(struct
+ acpi_processor_performance
+ **performance);
extern int acpi_processor_register_performance(struct acpi_processor_performance
*performance, unsigned int cpu);
@@ -213,7 +214,8 @@
void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
unsigned int cpu);
int acpi_processor_ffh_cstate_probe(unsigned int cpu,
- struct acpi_processor_cx *cx, struct acpi_power_register *reg);
+ struct acpi_processor_cx *cx,
+ struct acpi_power_register *reg);
void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate);
#else
static inline void acpi_processor_power_init_bm_check(struct
@@ -224,12 +226,14 @@
return;
}
static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu,
- struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+ struct acpi_processor_cx *cx,
+ struct acpi_power_register
+ *reg)
{
return -1;
}
-static inline void acpi_processor_ffh_cstate_enter(
- struct acpi_processor_cx *cstate)
+static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx
+ *cstate)
{
return;
}
diff --git a/include/asm-alpha/poll.h b/include/asm-alpha/poll.h
index 76f8935..c98509d 100644
--- a/include/asm-alpha/poll.h
+++ b/include/asm-alpha/poll.h
@@ -1,25 +1 @@
-#ifndef __ALPHA_POLL_H
-#define __ALPHA_POLL_H
-
-#define POLLIN (1 << 0)
-#define POLLPRI (1 << 1)
-#define POLLOUT (1 << 2)
-#define POLLERR (1 << 3)
-#define POLLHUP (1 << 4)
-#define POLLNVAL (1 << 5)
-#define POLLRDNORM (1 << 6)
-#define POLLRDBAND (1 << 7)
-#define POLLWRNORM (1 << 8)
-#define POLLWRBAND (1 << 9)
-#define POLLMSG (1 << 10)
-#define POLLREMOVE (1 << 12)
-#define POLLRDHUP (1 << 13)
-
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-arm/poll.h b/include/asm-arm/poll.h
index 5030b2b..c98509d 100644
--- a/include/asm-arm/poll.h
+++ b/include/asm-arm/poll.h
@@ -1,27 +1 @@
-#ifndef __ASMARM_POLL_H
-#define __ASMARM_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-arm26/poll.h b/include/asm-arm26/poll.h
index 9ccb7f4..1170e70 100644
--- a/include/asm-arm26/poll.h
+++ b/include/asm-arm26/poll.h
@@ -1,26 +1,8 @@
#ifndef __ASMARM_POLL_H
#define __ASMARM_POLL_H
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
+#include <asm-generic/poll.h>
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#undef POLLREMOVE
#endif
diff --git a/include/asm-avr32/poll.h b/include/asm-avr32/poll.h
index 736e297..c98509d 100644
--- a/include/asm-avr32/poll.h
+++ b/include/asm-avr32/poll.h
@@ -1,27 +1 @@
-#ifndef __ASM_AVR32_POLL_H
-#define __ASM_AVR32_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif /* __ASM_AVR32_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-cris/poll.h b/include/asm-cris/poll.h
index 1b25d4c..c98509d 100644
--- a/include/asm-cris/poll.h
+++ b/include/asm-cris/poll.h
@@ -1,26 +1 @@
-#ifndef __ASM_CRIS_POLL_H
-#define __ASM_CRIS_POLL_H
-
-/* taken from asm-alpha */
-
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
-#define POLLRDBAND 128
-#define POLLWRNORM 256
-#define POLLWRBAND 512
-#define POLLMSG 1024
-#define POLLREMOVE 4096
-#define POLLRDHUP 8192
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-frv/poll.h b/include/asm-frv/poll.h
index c8fe880..0d01479 100644
--- a/include/asm-frv/poll.h
+++ b/include/asm-frv/poll.h
@@ -1,24 +1,12 @@
#ifndef _ASM_POLL_H
#define _ASM_POLL_H
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
#define POLLWRBAND 256
-#define POLLMSG 0x0400
-#define POLLRDHUP 0x2000
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
+
+#undef POLLREMOVE
#endif
diff --git a/include/asm-generic/Kbuild b/include/asm-generic/Kbuild
index fa14f8c..5bfeef7 100644
--- a/include/asm-generic/Kbuild
+++ b/include/asm-generic/Kbuild
@@ -4,6 +4,7 @@
header-y += ioctl.h
header-y += ipc.h
header-y += mman.h
+header-y += poll.h
header-y += signal.h
header-y += statfs.h
diff --git a/include/asm-generic/audit_signal.h b/include/asm-generic/audit_signal.h
new file mode 100644
index 0000000..6feab7f
--- /dev/null
+++ b/include/asm-generic/audit_signal.h
@@ -0,0 +1,3 @@
+__NR_kill,
+__NR_tgkill,
+__NR_tkill,
diff --git a/include/asm-generic/poll.h b/include/asm-generic/poll.h
new file mode 100644
index 0000000..44bce83
--- /dev/null
+++ b/include/asm-generic/poll.h
@@ -0,0 +1,37 @@
+#ifndef __ASM_GENERIC_POLL_H
+#define __ASM_GENERIC_POLL_H
+
+/* These are specified by iBCS2 */
+#define POLLIN 0x0001
+#define POLLPRI 0x0002
+#define POLLOUT 0x0004
+#define POLLERR 0x0008
+#define POLLHUP 0x0010
+#define POLLNVAL 0x0020
+
+/* The rest seem to be more-or-less nonstandard. Check them! */
+#define POLLRDNORM 0x0040
+#define POLLRDBAND 0x0080
+#ifndef POLLWRNORM
+#define POLLWRNORM 0x0100
+#endif
+#ifndef POLLWRBAND
+#define POLLWRBAND 0x0200
+#endif
+#ifndef POLLMSG
+#define POLLMSG 0x0400
+#endif
+#ifndef POLLREMOVE
+#define POLLREMOVE 0x1000
+#endif
+#ifndef POLLRDHUP
+#define POLLRDHUP 0x2000
+#endif
+
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+#endif /* __ASM_GENERIC_POLL_H */
diff --git a/include/asm-h8300/poll.h b/include/asm-h8300/poll.h
index fc52103..f61540c 100644
--- a/include/asm-h8300/poll.h
+++ b/include/asm-h8300/poll.h
@@ -1,23 +1,11 @@
#ifndef __H8300_POLL_H
#define __H8300_POLL_H
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
#define POLLWRBAND 256
-#define POLLMSG 0x0400
-#define POLLRDHUP 0x2000
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
+
+#undef POLLREMOVE
#endif
diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h
index 7ddd414..99f3c35 100644
--- a/include/asm-h8300/unistd.h
+++ b/include/asm-h8300/unistd.h
@@ -21,7 +21,7 @@
#define __NR_time 13
#define __NR_mknod 14
#define __NR_chmod 15
-#define __NR_chown 16
+#define __NR_lchown 16
#define __NR_break 17
#define __NR_oldstat 18
#define __NR_lseek 19
@@ -115,10 +115,10 @@
#define __NR_lstat 107
#define __NR_fstat 108
#define __NR_olduname 109
-#define __NR_iopl /* 110 */ not supported
+#define __NR_iopl 110
#define __NR_vhangup 111
-#define __NR_idle /* 112 */ Obsolete
-#define __NR_vm86 /* 113 */ not supported
+#define __NR_idle 112
+#define __NR_vm86old 113
#define __NR_wait4 114
#define __NR_swapoff 115
#define __NR_sysinfo 116
@@ -128,7 +128,7 @@
#define __NR_clone 120
#define __NR_setdomainname 121
#define __NR_uname 122
-#define __NR_cacheflush 123
+#define __NR_modify_ldt 123
#define __NR_adjtimex 124
#define __NR_mprotect 125
#define __NR_sigprocmask 126
@@ -171,7 +171,7 @@
#define __NR_mremap 163
#define __NR_setresuid 164
#define __NR_getresuid 165
-#define __NR_getpagesize 166
+#define __NR_vm86 166
#define __NR_query_module 167
#define __NR_poll 168
#define __NR_nfsservctl 169
@@ -187,7 +187,7 @@
#define __NR_rt_sigsuspend 179
#define __NR_pread64 180
#define __NR_pwrite64 181
-#define __NR_lchown 182
+#define __NR_chown 182
#define __NR_getcwd 183
#define __NR_capget 184
#define __NR_capset 185
@@ -203,7 +203,7 @@
#define __NR_stat64 195
#define __NR_lstat64 196
#define __NR_fstat64 197
-#define __NR_chown32 198
+#define __NR_lchown32 198
#define __NR_getuid32 199
#define __NR_getgid32 200
#define __NR_geteuid32 201
@@ -217,15 +217,18 @@
#define __NR_getresuid32 209
#define __NR_setresgid32 210
#define __NR_getresgid32 211
-#define __NR_lchown32 212
+#define __NR_chown32 212
#define __NR_setuid32 213
#define __NR_setgid32 214
#define __NR_setfsuid32 215
#define __NR_setfsgid32 216
#define __NR_pivot_root 217
+#define __NR_mincore 218
+#define __NR_madvise 219
+#define __NR_madvise1 219
#define __NR_getdents64 220
#define __NR_fcntl64 221
-#define __NR_security 223
+/* 223 is unused */
#define __NR_gettid 224
#define __NR_readahead 225
#define __NR_setxattr 226
@@ -252,13 +255,13 @@
#define __NR_io_getevents 247
#define __NR_io_submit 248
#define __NR_io_cancel 249
-#define __NR_alloc_hugepages 250
-#define __NR_free_hugepages 251
+#define __NR_fadvise64 250
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
#define __NR_exit_group 252
#define __NR_lookup_dcookie 253
-#define __NR_sys_epoll_create 254
-#define __NR_sys_epoll_ctl 255
-#define __NR_sys_epoll_wait 256
+#define __NR_epoll_create 254
+#define __NR_epoll_ctl 255
+#define __NR_epoll_wait 256
#define __NR_remap_file_pages 257
#define __NR_set_tid_address 258
#define __NR_timer_create 259
@@ -291,10 +294,41 @@
#define __NR_add_key 286
#define __NR_request_key 287
#define __NR_keyctl 288
+#define __NR_ioprio_set 289
+#define __NR_ioprio_get 290
+#define __NR_inotify_init 291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch 293
+#define __NR_migrate_pages 294
+#define __NR_openat 295
+#define __NR_mkdirat 296
+#define __NR_mknodat 297
+#define __NR_fchownat 298
+#define __NR_futimesat 299
+#define __NR_fstatat64 300
+#define __NR_unlinkat 301
+#define __NR_renameat 302
+#define __NR_linkat 303
+#define __NR_symlinkat 304
+#define __NR_readlinkat 305
+#define __NR_fchmodat 306
+#define __NR_faccessat 307
+#define __NR_pselect6 308
+#define __NR_ppoll 309
+#define __NR_unshare 310
+#define __NR_set_robust_list 311
+#define __NR_get_robust_list 312
+#define __NR_splice 313
+#define __NR_sync_file_range 314
+#define __NR_tee 315
+#define __NR_vmsplice 316
+#define __NR_move_pages 317
+#define __NR_getcpu 318
+#define __NR_epoll_pwait 319
#ifdef __KERNEL__
-#define NR_syscalls 289
+#define NR_syscalls 320
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-i386/alternative.h b/include/asm-i386/alternative.h
index 0f70b37..eb7da54 100644
--- a/include/asm-i386/alternative.h
+++ b/include/asm-i386/alternative.h
@@ -98,6 +98,12 @@
".previous" : output : [feat] "i" (feature), ##input)
/*
+ * use this macro(s) if you need more than one output parameter
+ * in alternative_io
+ */
+#define ASM_OUTPUT2(a, b) a, b
+
+/*
* Alternative inline assembly for SMP.
*
* The LOCK_PREFIX macro defined here replaces the LOCK and
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index bc5c12c..d7a0512 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -222,11 +222,6 @@
void (*iret)(void);
};
-/* Mark a paravirt probe function. */
-#define paravirt_probe(fn) \
- static asmlinkage void (*__paravirtprobe_##fn)(void) __attribute_used__ \
- __attribute__((__section__(".paravirtprobe"))) = fn
-
extern struct paravirt_ops paravirt_ops;
#define PARAVIRT_PATCH(x) \
diff --git a/include/asm-i386/poll.h b/include/asm-i386/poll.h
index 2cd4929..c98509d 100644
--- a/include/asm-i386/poll.h
+++ b/include/asm-i386/poll.h
@@ -1,27 +1 @@
-#ifndef __i386_POLL_H
-#define __i386_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-i386/tsc.h b/include/asm-i386/tsc.h
index 3f3c1fa..62c091f 100644
--- a/include/asm-i386/tsc.h
+++ b/include/asm-i386/tsc.h
@@ -35,14 +35,16 @@
static __always_inline cycles_t get_cycles_sync(void)
{
unsigned long long ret;
- unsigned eax;
+ unsigned eax, edx;
/*
* Use RDTSCP if possible; it is guaranteed to be synchronous
* and doesn't cause a VMEXIT on Hypervisors
*/
alternative_io(ASM_NOP3, ".byte 0x0f,0x01,0xf9", X86_FEATURE_RDTSCP,
- "=A" (ret), "0" (0ULL) : "ecx", "memory");
+ ASM_OUTPUT2("=a" (eax), "=d" (edx)),
+ "a" (0U), "d" (0U) : "ecx", "memory");
+ ret = (((unsigned long long)edx) << 32) | ((unsigned long long)eax);
if (ret)
return ret;
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index bd21e79..e84ace1 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -326,10 +326,13 @@
#define __NR_getcpu 318
#define __NR_epoll_pwait 319
#define __NR_utimensat 320
+#define __NR_signalfd 321
+#define __NR_timerfd 322
+#define __NR_eventfd 323
#ifdef __KERNEL__
-#define NR_syscalls 321
+#define NR_syscalls 324
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-ia64/poll.h b/include/asm-ia64/poll.h
index bcaf9f1..c98509d 100644
--- a/include/asm-ia64/poll.h
+++ b/include/asm-ia64/poll.h
@@ -1,32 +1 @@
-#ifndef _ASM_IA64_POLL_H
-#define _ASM_IA64_POLL_H
-
-/*
- * poll(2) bit definitions. Based on <asm-i386/poll.h>.
- *
- * Modified 1998, 1999, 2002
- * David Mosberger-Tang <davidm@hpl.hp.com>, Hewlett-Packard Co
- */
-
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif /* _ASM_IA64_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-m32r/pgtable-2level.h b/include/asm-m32r/pgtable-2level.h
index 7509257..bca3475 100644
--- a/include/asm-m32r/pgtable-2level.h
+++ b/include/asm-m32r/pgtable-2level.h
@@ -71,8 +71,8 @@
#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
#define PTE_FILE_MAX_BITS 29
-#define pte_to_pgoff(pte) (((pte_val(pte) >> 2) & 0xef) | (((pte_val(pte) >> 10)) << 7))
-#define pgoff_to_pte(off) ((pte_t) { (((off) & 0xef) << 2) | (((off) >> 7) << 10) | _PAGE_FILE })
+#define pte_to_pgoff(pte) (((pte_val(pte) >> 2) & 0x7f) | (((pte_val(pte) >> 10)) << 7))
+#define pgoff_to_pte(off) ((pte_t) { (((off) & 0x7f) << 2) | (((off) >> 7) << 10) | _PAGE_FILE })
#endif /* __KERNEL__ */
#endif /* _ASM_M32R_PGTABLE_2LEVEL_H */
diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h
index 8b2a2f1..6604303 100644
--- a/include/asm-m32r/pgtable.h
+++ b/include/asm-m32r/pgtable.h
@@ -366,7 +366,7 @@
#define pte_unmap_nested(pte) do { } while (0)
/* Encode and de-code a swap entry */
-#define __swp_type(x) (((x).val >> 2) & 0x3f)
+#define __swp_type(x) (((x).val >> 2) & 0x1f)
#define __swp_offset(x) ((x).val >> 10)
#define __swp_entry(type, offset) \
((swp_entry_t) { ((type) << 2) | ((offset) << 10) })
diff --git a/include/asm-m32r/poll.h b/include/asm-m32r/poll.h
index 9e0e700..c98509d 100644
--- a/include/asm-m32r/poll.h
+++ b/include/asm-m32r/poll.h
@@ -1,32 +1 @@
-#ifndef _ASM_M32R_POLL_H
-#define _ASM_M32R_POLL_H
-
-/*
- * poll(2) bit definitions. Based on <asm-i386/poll.h>.
- *
- * Modified 2004
- * Hirokazu Takata <takata at linux-m32r.org>
- */
-
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif /* _ASM_M32R_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index f62f5c9..b291b2f 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -21,12 +21,22 @@
* `next' and `prev' should be struct task_struct, but it isn't always defined
*/
+#if defined(CONFIG_FRAME_POINTER) || \
+ !defined(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER)
+#define M32R_PUSH_FP " push fp\n"
+#define M32R_POP_FP " pop fp\n"
+#else
+#define M32R_PUSH_FP ""
+#define M32R_POP_FP ""
+#endif
+
#define switch_to(prev, next, last) do { \
__asm__ __volatile__ ( \
" seth lr, #high(1f) \n" \
" or3 lr, lr, #low(1f) \n" \
" st lr, @%4 ; store old LR \n" \
" ld lr, @%5 ; load new LR \n" \
+ M32R_PUSH_FP \
" st sp, @%2 ; store old SP \n" \
" ld sp, @%3 ; load new SP \n" \
" push %1 ; store `prev' on new stack \n" \
@@ -34,6 +44,7 @@
" .fillinsn \n" \
"1: \n" \
" pop %0 ; restore `__last' from new stack \n" \
+ M32R_POP_FP \
: "=r" (last) \
: "0" (prev), \
"r" (&(prev->thread.sp)), "r" (&(next->thread.sp)), \
diff --git a/include/asm-m68k/atarihw.h b/include/asm-m68k/atarihw.h
index 6211363..ecf007d 100644
--- a/include/asm-m68k/atarihw.h
+++ b/include/asm-m68k/atarihw.h
@@ -2,7 +2,7 @@
** linux/atarihw.h -- This header defines some macros and pointers for
** the various Atari custom hardware registers.
**
-** Copyright 1994 by Bj”rn Brauel
+** Copyright 1994 by Björn Brauel
**
** 5/1/94 Roman Hodek:
** Added definitions for TT specific chips.
diff --git a/include/asm-m68k/atariints.h b/include/asm-m68k/atariints.h
index ce6c445..5748e99 100644
--- a/include/asm-m68k/atariints.h
+++ b/include/asm-m68k/atariints.h
@@ -1,7 +1,7 @@
/*
** atariints.h -- Atari Linux interrupt handling structs and prototypes
**
-** Copyright 1994 by Bj”rn Brauel
+** Copyright 1994 by Björn Brauel
**
** 5/2/94 Roman Hodek:
** TT interrupt definitions added.
diff --git a/include/asm-m68k/poll.h b/include/asm-m68k/poll.h
index 0fb8843..f080fcd 100644
--- a/include/asm-m68k/poll.h
+++ b/include/asm-m68k/poll.h
@@ -1,24 +1,9 @@
#ifndef __m68k_POLL_H
#define __m68k_POLL_H
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
#define POLLWRBAND 256
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
#endif
diff --git a/include/asm-mips/atomic.h b/include/asm-mips/atomic.h
index 62daa74..1b60624 100644
--- a/include/asm-mips/atomic.h
+++ b/include/asm-mips/atomic.h
@@ -689,7 +689,7 @@
}
#define atomic64_cmpxchg(v, o, n) \
- (((__typeof__((v)->counter)))cmpxchg(&((v)->counter), (o), (n)))
+ ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n)))
#define atomic64_xchg(v, new) (xchg(&((v)->counter), (new)))
/**
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index dbf834f..b0c3297 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -119,9 +119,9 @@
*/
#define MACH_GROUP_MOMENCO 12 /* Momentum Boards */
#define MACH_MOMENCO_OCELOT 0
-#define MACH_MOMENCO_OCELOT_G 1
+#define MACH_MOMENCO_OCELOT_G 1 /* no more supported (may 2007) */
#define MACH_MOMENCO_OCELOT_C 2
-#define MACH_MOMENCO_JAGUAR_ATX 3
+#define MACH_MOMENCO_JAGUAR_ATX 3 /* no more supported (may 2007) */
#define MACH_MOMENCO_OCELOT_3 4
/*
diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h
index b414a7d..483685b 100644
--- a/include/asm-mips/fpu.h
+++ b/include/asm-mips/fpu.h
@@ -16,6 +16,7 @@
#include <asm/mipsregs.h>
#include <asm/cpu.h>
#include <asm/cpu-features.h>
+#include <asm/hazards.h>
#include <asm/bitops.h>
#include <asm/processor.h>
#include <asm/current.h>
@@ -38,34 +39,16 @@
extern void _save_fp(struct task_struct *);
extern void _restore_fp(struct task_struct *);
-#if defined(CONFIG_CPU_SB1)
-#define __enable_fpu_hazard() \
-do { \
- asm(".set push \n\t" \
- ".set mips64 \n\t" \
- ".set noreorder \n\t" \
- "ssnop \n\t" \
- "bnezl $0, .+4 \n\t" \
- "ssnop \n\t" \
- ".set pop"); \
-} while (0)
-#else
-#define __enable_fpu_hazard() \
-do { \
- asm("nop;nop;nop;nop"); /* max. hazard */ \
-} while (0)
-#endif
-
#define __enable_fpu() \
do { \
set_c0_status(ST0_CU1); \
- __enable_fpu_hazard(); \
+ enable_fpu_hazard(); \
} while (0)
#define __disable_fpu() \
do { \
clear_c0_status(ST0_CU1); \
- /* We don't care about the c0 hazard here */ \
+ disable_fpu_hazard(); \
} while (0)
#define enable_fpu() \
diff --git a/include/asm-mips/hazards.h b/include/asm-mips/hazards.h
index e50c77e..d9119f4 100644
--- a/include/asm-mips/hazards.h
+++ b/include/asm-mips/hazards.h
@@ -178,4 +178,36 @@
#endif
+
+/* FPU hazards */
+
+#if defined(CONFIG_CPU_SB1)
+ASMMACRO(enable_fpu_hazard,
+ .set push;
+ .set mips64;
+ .set noreorder;
+ _ssnop;
+ bnezl $0,.+4;
+ _ssnop;
+ .set pop
+)
+ASMMACRO(disable_fpu_hazard,
+)
+
+#elif defined(CONFIG_CPU_MIPSR2)
+ASMMACRO(enable_fpu_hazard,
+ _ehb
+)
+ASMMACRO(disable_fpu_hazard,
+ _ehb
+)
+#else
+ASMMACRO(enable_fpu_hazard,
+ nop; nop; nop; nop
+)
+ASMMACRO(disable_fpu_hazard,
+ _ehb
+)
+#endif
+
#endif /* _ASM_HAZARDS_H */
diff --git a/include/asm-mips/highmem.h b/include/asm-mips/highmem.h
index f8c8182..4d6bd5c 100644
--- a/include/asm-mips/highmem.h
+++ b/include/asm-mips/highmem.h
@@ -48,46 +48,6 @@
extern void * kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
-/*
- * CONFIG_LIMITED_DMA is for systems with DMA limitations such as Momentum's
- * Jaguar ATX. This option exploits the highmem code in the kernel so is
- * always enabled together with CONFIG_HIGHMEM but at this time doesn't
- * actually add highmem functionality.
- */
-
-#ifdef CONFIG_LIMITED_DMA
-
-/*
- * These are the default functions for the no-highmem case from
- * <linux/highmem.h>
- */
-static inline void *kmap(struct page *page)
-{
- might_sleep();
- return page_address(page);
-}
-
-#define kunmap(page) do { (void) (page); } while (0)
-
-static inline void *kmap_atomic(struct page *page, enum km_type type)
-{
- pagefault_disable();
- return page_address(page);
-}
-
-static inline void kunmap_atomic(void *kvaddr, enum km_type type)
-{
- pagefault_enable();
-}
-
-#define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx))
-
-#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
-
-#define flush_cache_kmaps() do { } while (0)
-
-#else /* LIMITED_DMA */
-
extern void *__kmap(struct page *page);
extern void __kunmap(struct page *page);
extern void *__kmap_atomic(struct page *page, enum km_type type);
@@ -103,8 +63,6 @@
#define flush_cache_kmaps() flush_cache_all()
-#endif /* LIMITED_DMA */
-
#endif /* __KERNEL__ */
#endif /* _ASM_HIGHMEM_H */
diff --git a/include/asm-mips/mach-cobalt/cobalt.h b/include/asm-mips/mach-cobalt/cobalt.h
index 24a8d51..684a501 100644
--- a/include/asm-mips/mach-cobalt/cobalt.h
+++ b/include/asm-mips/mach-cobalt/cobalt.h
@@ -69,6 +69,8 @@
#define COBALT_BRD_ID_QUBE2 0x5
#define COBALT_BRD_ID_RAQ2 0x6
+extern int cobalt_board_id;
+
#define PCI_CFG_SET(devfn,where) \
GT_WRITE(GT_PCI0_CFGADDR_OFS, (0x80000000 | (PCI_SLOT (devfn) << 11) | \
(PCI_FUNC (devfn) << 8) | (where)))
diff --git a/include/asm-mips/mach-ja/cpu-feature-overrides.h b/include/asm-mips/mach-ja/cpu-feature-overrides.h
deleted file mode 100644
index 84b6dea..0000000
--- a/include/asm-mips/mach-ja/cpu-feature-overrides.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2003, 2004 Ralf Baechle
- */
-#ifndef __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H
-#define __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H
-
-/*
- * Momentum Jaguar ATX always has the RM9000 processor.
- */
-#define cpu_has_watch 1
-#define cpu_has_mips16 0
-#define cpu_has_divec 0
-#define cpu_has_vce 0
-#define cpu_has_cache_cdex_p 0
-#define cpu_has_cache_cdex_s 0
-#define cpu_has_prefetch 1
-#define cpu_has_mcheck 0
-#define cpu_has_ejtag 0
-
-#define cpu_has_llsc 1
-#define cpu_has_vtag_icache 0
-#define cpu_has_dc_aliases 0
-#define cpu_has_ic_fills_f_dc 0
-#define cpu_has_dsp 0
-#define cpu_icache_snoops_remote_store 0
-
-#define cpu_has_nofpuex 0
-#define cpu_has_64bits 1
-
-#define cpu_has_inclusive_pcaches 0
-
-#define cpu_dcache_line_size() 32
-#define cpu_icache_line_size() 32
-#define cpu_scache_line_size() 32
-
-#define cpu_has_mips32r1 0
-#define cpu_has_mips32r2 0
-#define cpu_has_mips64r1 0
-#define cpu_has_mips64r2 0
-
-#endif /* __ASM_MACH_JA_CPU_FEATURE_OVERRIDES_H */
diff --git a/include/asm-mips/mach-ja/spaces.h b/include/asm-mips/mach-ja/spaces.h
deleted file mode 100644
index 8466a0e..0000000
--- a/include/asm-mips/mach-ja/spaces.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1994 - 1999, 2000, 03, 04 Ralf Baechle
- * Copyright (C) 2000, 2002 Maciej W. Rozycki
- * Copyright (C) 1990, 1999, 2000 Silicon Graphics, Inc.
- */
-#ifndef __ASM_MACH_JA_SPACES_H
-#define __ASM_MACH_JA_SPACES_H
-
-/*
- * Memory above this physical address will be considered highmem.
- */
-#define HIGHMEM_START 0x08000000UL
-
-#include_next <spaces.h>
-
-#endif /* __ASM_MACH_JA_SPACES_H */
diff --git a/include/asm-mips/mips-boards/malta.h b/include/asm-mips/mips-boards/malta.h
index b0ba3c5..eec9100 100644
--- a/include/asm-mips/mips-boards/malta.h
+++ b/include/asm-mips/mips-boards/malta.h
@@ -25,6 +25,10 @@
#include <asm/mips-boards/msc01_pci.h>
#include <asm/gt64120.h>
+/* Mips interrupt controller found in SOCit variations */
+#define MIPS_MSC01_IC_REG_BASE 0x1bc40000
+#define MIPS_SOCITSC_IC_REG_BASE 0x1ffa0000
+
/*
* Malta I/O ports base address for the Galileo GT64120 and Algorithmics
* Bonito system controllers.
diff --git a/include/asm-mips/msc01_ic.h b/include/asm-mips/msc01_ic.h
index aa7ad9a..7989b9f 100644
--- a/include/asm-mips/msc01_ic.h
+++ b/include/asm-mips/msc01_ic.h
@@ -94,10 +94,7 @@
/*
* MIPS System controller interrupt register base.
*
- * FIXME - are these macros specific to Malta and co or to the MSC? If the
- * latter, they should be moved elsewhere.
*/
-#define MIPS_MSC01_IC_REG_BASE 0x1bc40000
/*****************************************************************************
* Absolute register addresses
@@ -144,7 +141,7 @@
#define MSC01_IRQ_LEVEL 0
#define MSC01_IRQ_EDGE 1
-extern void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq);
+extern void __init init_msc_irqs(unsigned long icubase, unsigned int base, msc_irqmap_t *imp, int nirq);
extern void ll_msc_irq(void);
#endif /* __ASM_MIPS_BOARDS_MSC01_IC_H */
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index d3fbd83..5c3239d 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -190,10 +190,6 @@
#define UNCAC_ADDR(addr) ((addr) - PAGE_OFFSET + UNCAC_BASE)
#define CAC_ADDR(addr) ((addr) - UNCAC_BASE + PAGE_OFFSET)
-#ifdef CONFIG_LIMITED_DMA
-#define WANT_PAGE_VIRTUAL
-#endif
-
#include <asm-generic/memory_model.h>
#include <asm-generic/page.h>
diff --git a/include/asm-mips/poll.h b/include/asm-mips/poll.h
index 70881f8..47b9520 100644
--- a/include/asm-mips/poll.h
+++ b/include/asm-mips/poll.h
@@ -1,28 +1,9 @@
#ifndef __ASM_POLL_H
#define __ASM_POLL_H
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
#define POLLWRNORM POLLOUT
#define POLLWRBAND 0x0100
-/* These seem to be more or less nonstandard ... */
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
#endif /* __ASM_POLL_H */
diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h
index d7a6513..ce51213 100644
--- a/include/asm-mips/serial.h
+++ b/include/asm-mips/serial.h
@@ -81,25 +81,6 @@
#define STD_SERIAL_PORT_DEFNS
#endif /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */
-#ifdef CONFIG_MOMENCO_JAGUAR_ATX
-/* Ordinary NS16552 duart with a 20MHz crystal. */
-#define JAGUAR_ATX_UART_CLK 20000000
-#define JAGUAR_ATX_BASE_BAUD (JAGUAR_ATX_UART_CLK / 16)
-
-#define JAGUAR_ATX_SERIAL1_IRQ 6
-#define JAGUAR_ATX_SERIAL1_BASE 0xfd000023L
-
-#define _JAGUAR_ATX_SERIAL_INIT(int, base) \
- { .baud_base = JAGUAR_ATX_BASE_BAUD, irq: int, \
- .flags = (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST), \
- .iomem_base = (u8 *) base, iomem_reg_shift: 2, \
- io_type: SERIAL_IO_MEM }
-#define MOMENCO_JAGUAR_ATX_SERIAL_PORT_DEFNS \
- _JAGUAR_ATX_SERIAL_INIT(JAGUAR_ATX_SERIAL1_IRQ, JAGUAR_ATX_SERIAL1_BASE)
-#else
-#define MOMENCO_JAGUAR_ATX_SERIAL_PORT_DEFNS
-#endif
-
#ifdef CONFIG_MOMENCO_OCELOT_3
#define OCELOT_3_BASE_BAUD ( 20000000 / 16 )
#define OCELOT_3_SERIAL_IRQ 6
@@ -134,27 +115,6 @@
#define MOMENCO_OCELOT_SERIAL_PORT_DEFNS
#endif
-#ifdef CONFIG_MOMENCO_OCELOT_G
-/* Ordinary NS16552 duart with a 20MHz crystal. */
-#define OCELOT_G_BASE_BAUD ( 20000000 / 16 )
-
-#define OCELOT_G_SERIAL1_IRQ 4
-#if 0
-#define OCELOT_G_SERIAL1_BASE 0xe0001020
-#else
-#define OCELOT_G_SERIAL1_BASE 0xfd000020
-#endif
-
-#define _OCELOT_G_SERIAL_INIT(int, base) \
- { .baud_base = OCELOT_G_BASE_BAUD, .irq = int, .flags = STD_COM_FLAGS,\
- .iomem_base = (u8 *) base, .iomem_reg_shift = 2, \
- .io_type = SERIAL_IO_MEM }
-#define MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \
- _OCELOT_G_SERIAL_INIT(OCELOT_G_SERIAL1_IRQ, OCELOT_G_SERIAL1_BASE)
-#else
-#define MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS
-#endif
-
#ifdef CONFIG_MOMENCO_OCELOT_C
/* Ordinary NS16552 duart with a 20MHz crystal. */
#define OCELOT_C_BASE_BAUD ( 20000000 / 16 )
@@ -210,7 +170,6 @@
IP32_SERIAL_PORT_DEFNS \
JAZZ_SERIAL_PORT_DEFNS \
STD_SERIAL_PORT_DEFNS \
- MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_C_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS
diff --git a/include/asm-mips/sgi/seeq.h b/include/asm-mips/sgi/seeq.h
new file mode 100644
index 0000000..af0ffd7
--- /dev/null
+++ b/include/asm-mips/sgi/seeq.h
@@ -0,0 +1,21 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 by Ralf Baechle
+ */
+#ifndef __ASM_SGI_SEEQ_H
+#define __ASM_SGI_SEEQ_H
+
+#include <linux/if_ether.h>
+
+#include <asm/sgi/hpc3.h>
+
+struct sgiseeq_platform_data {
+ struct hpc3_regs *hpc;
+ unsigned int irq;
+ unsigned char mac[ETH_ALEN];
+};
+
+#endif /* __ASM_SGI_SEEQ_H */
diff --git a/include/asm-mips/sgi/wd.h b/include/asm-mips/sgi/wd.h
new file mode 100644
index 0000000..0d6c3a4
--- /dev/null
+++ b/include/asm-mips/sgi/wd.h
@@ -0,0 +1,20 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2007 by Ralf Baechle
+ */
+#ifndef __ASM_SGI_WD_H
+#define __ASM_SGI_WD_H
+
+#include <asm/sgi/hpc3.h>
+
+struct sgiwd93_platform_data {
+ unsigned int unit;
+ unsigned int irq;
+ struct hpc3_scsiregs *hregs;
+ unsigned char *wdregs;
+};
+
+#endif /* __ASM_SGI_WD_H */
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 3713d25..bb0b289 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -464,7 +464,10 @@
extern void set_handler (unsigned long offset, void *addr, unsigned long len);
extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len);
-extern void *set_vi_handler (int n, void *addr);
+
+typedef void (*vi_handler_t)(void);
+extern void *set_vi_handler (int n, vi_handler_t addr);
+
extern void *set_except_vector(int n, void *addr);
extern unsigned long ebase;
extern void per_cpu_trap_init(void);
diff --git a/include/asm-parisc/poll.h b/include/asm-parisc/poll.h
index 20e4d03..c98509d 100644
--- a/include/asm-parisc/poll.h
+++ b/include/asm-parisc/poll.h
@@ -1,27 +1 @@
-#ifndef __PARISC_POLL_H
-#define __PARISC_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-powerpc/hw_irq.h b/include/asm-powerpc/hw_irq.h
index 9e4dd98..a7b60bf 100644
--- a/include/asm-powerpc/hw_irq.h
+++ b/include/asm-powerpc/hw_irq.h
@@ -48,8 +48,15 @@
#define irqs_disabled() (local_get_flags() == 0)
-#define hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1)
-#define hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1)
+#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1)
+#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1)
+
+#define hard_irq_disable() \
+ do { \
+ __hard_irq_disable(); \
+ get_paca()->soft_enabled = 0; \
+ get_paca()->hard_enabled = 0; \
+ } while(0)
#else
diff --git a/include/asm-powerpc/mmu-hash64.h b/include/asm-powerpc/mmu-hash64.h
index e2ca55b..b8dca30 100644
--- a/include/asm-powerpc/mmu-hash64.h
+++ b/include/asm-powerpc/mmu-hash64.h
@@ -73,8 +73,9 @@
#define HPTES_PER_GROUP 8
+#define HPTE_V_SSIZE_SHIFT 62
#define HPTE_V_AVPN_SHIFT 7
-#define HPTE_V_AVPN ASM_CONST(0xffffffffffffff80)
+#define HPTE_V_AVPN ASM_CONST(0x3fffffffffffff80)
#define HPTE_V_AVPN_VAL(x) (((x) & HPTE_V_AVPN) >> HPTE_V_AVPN_SHIFT)
#define HPTE_V_COMPARE(x,y) (!(((x) ^ (y)) & HPTE_V_AVPN))
#define HPTE_V_BOLTED ASM_CONST(0x0000000000000010)
@@ -151,6 +152,15 @@
#define MMU_PAGE_16G 5 /* 16G */
#define MMU_PAGE_COUNT 6
+/*
+ * Segment sizes.
+ * These are the values used by hardware in the B field of
+ * SLB entries and the first dword of MMU hashtable entries.
+ * The B field is 2 bits; the values 2 and 3 are unused and reserved.
+ */
+#define MMU_SEGSIZE_256M 0
+#define MMU_SEGSIZE_1T 1
+
#ifndef __ASSEMBLY__
/*
diff --git a/include/asm-powerpc/mmzone.h b/include/asm-powerpc/mmzone.h
index d484ca9..19f299b 100644
--- a/include/asm-powerpc/mmzone.h
+++ b/include/asm-powerpc/mmzone.h
@@ -43,9 +43,5 @@
#endif /* CONFIG_NEED_MULTIPLE_NODES */
-#ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
-extern int __init early_pfn_to_nid(unsigned long pfn);
-#endif
-
#endif /* __KERNEL__ */
#endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-powerpc/poll.h b/include/asm-powerpc/poll.h
index 9c7d126..c98509d 100644
--- a/include/asm-powerpc/poll.h
+++ b/include/asm-powerpc/poll.h
@@ -1,24 +1 @@
-#ifndef _ASM_POWERPC_POLL_H
-#define _ASM_POWERPC_POLL_H
-
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif /* _ASM_POWERPC_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index 6dcd7a8..8e20051 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -62,11 +62,14 @@
/**
* eeh_slot_error_detail -- record and EEH error condition to the log
- * @severity: 1 if temporary, 2 if permanent failure.
+ * @pdn: pci device node
+ * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE
*
* Obtains the EEH error details from the RTAS subsystem,
* and then logs these details with the RTAS error log system.
*/
+#define EEH_LOG_TEMP_FAILURE 1
+#define EEH_LOG_PERM_FAILURE 2
void eeh_slot_error_detail (struct pci_dn *pdn, int severity);
/**
@@ -82,6 +85,7 @@
/**
* rtas_set_slot_reset -- unfreeze a frozen slot
+ * @pdn: pci device node
*
* Clear the EEH-frozen condition on a slot. This routine
* does this by asserting the PCI #RST line for 1/8th of
@@ -95,6 +99,7 @@
/**
* eeh_restore_bars - Restore device configuration info.
+ * @pdn: pci device node
*
* A reset of a PCI device will clear out its config space.
* This routines will restore the config space for this
@@ -105,6 +110,7 @@
/**
* rtas_configure_bridge -- firmware initialization of pci bridge
+ * @pdn: pci device node
*
* Ask the firmware to configure all PCI bridges devices
* located behind the indicated node. Required after a
@@ -118,16 +124,22 @@
int rtas_read_config(struct pci_dn *, int where, int size, u32 *val);
/**
+ * eeh_mark_slot -- set mode flags for pertition endpoint
+ * @pdn: pci device node
+ *
* mark and clear slots: find "partition endpoint" PE and set or
* clear the flags for each subnode of the PE.
*/
void eeh_mark_slot (struct device_node *dn, int mode_flag);
void eeh_clear_slot (struct device_node *dn, int mode_flag);
-/* Find the associated "Partiationable Endpoint" PE */
+/**
+ * find_device_pe -- Find the associated "Partiationable Endpoint" PE
+ * @pdn: pci device node
+ */
struct device_node * find_device_pe(struct device_node *dn);
-#endif
+#endif /* CONFIG_EEH */
#else /* CONFIG_PCI */
static inline void find_and_init_phbs(void) { }
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h
index 13c372d..1e04651 100644
--- a/include/asm-powerpc/ps3.h
+++ b/include/asm-powerpc/ps3.h
@@ -377,8 +377,13 @@
/* system manager */
+#ifdef CONFIG_PS3_SYS_MANAGER
void ps3_sys_manager_restart(void);
void ps3_sys_manager_power_off(void);
+#else
+static inline void ps3_sys_manager_restart(void) {}
+static inline void ps3_sys_manager_power_off(void) {}
+#endif
struct ps3_prealloc {
const char *name;
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index a62168ec..9d304b1 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -38,11 +38,11 @@
void qe_setbrg(u32 brg, u32 rate);
int qe_get_snum(void);
void qe_put_snum(u8 snum);
-u32 qe_muram_alloc(u32 size, u32 align);
-int qe_muram_free(u32 offset);
-u32 qe_muram_alloc_fixed(u32 offset, u32 size);
+unsigned long qe_muram_alloc(int size, int align);
+int qe_muram_free(unsigned long offset);
+unsigned long qe_muram_alloc_fixed(unsigned long offset, int size);
void qe_muram_dump(void);
-void *qe_muram_addr(u32 offset);
+void *qe_muram_addr(unsigned long offset);
/* Buffer descriptors */
struct qe_bd {
@@ -448,10 +448,5 @@
#define UCC_FAST_FUNCTION_CODE_DTB_LCL 0x02
#define UCC_FAST_FUNCTION_CODE_BDB_LCL 0x01
-static inline long IS_MURAM_ERR(const u32 offset)
-{
- return offset > (u32) - 1000L;
-}
-
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_QE_H */
diff --git a/include/asm-powerpc/reg_booke.h b/include/asm-powerpc/reg_booke.h
new file mode 100644
index 0000000..064405c
--- /dev/null
+++ b/include/asm-powerpc/reg_booke.h
@@ -0,0 +1,469 @@
+/*
+ * Contains register definitions common to the Book E PowerPC
+ * specification. Notice that while the IBM-40x series of CPUs
+ * are not true Book E PowerPCs, they borrowed a number of features
+ * before Book E was finalized, and are included here as well. Unfortunatly,
+ * they sometimes used different locations than true Book E CPUs did.
+ */
+#ifdef __KERNEL__
+#ifndef __ASM_POWERPC_REG_BOOKE_H__
+#define __ASM_POWERPC_REG_BOOKE_H__
+
+#ifndef __ASSEMBLY__
+/* Performance Monitor Registers */
+#define mfpmr(rn) ({unsigned int rval; \
+ asm volatile("mfpmr %0," __stringify(rn) \
+ : "=r" (rval)); rval;})
+#define mtpmr(rn, v) asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
+#endif /* __ASSEMBLY__ */
+
+/* Freescale Book E Performance Monitor APU Registers */
+#define PMRN_PMC0 0x010 /* Performance Monitor Counter 0 */
+#define PMRN_PMC1 0x011 /* Performance Monitor Counter 1 */
+#define PMRN_PMC2 0x012 /* Performance Monitor Counter 1 */
+#define PMRN_PMC3 0x013 /* Performance Monitor Counter 1 */
+#define PMRN_PMLCA0 0x090 /* PM Local Control A0 */
+#define PMRN_PMLCA1 0x091 /* PM Local Control A1 */
+#define PMRN_PMLCA2 0x092 /* PM Local Control A2 */
+#define PMRN_PMLCA3 0x093 /* PM Local Control A3 */
+
+#define PMLCA_FC 0x80000000 /* Freeze Counter */
+#define PMLCA_FCS 0x40000000 /* Freeze in Supervisor */
+#define PMLCA_FCU 0x20000000 /* Freeze in User */
+#define PMLCA_FCM1 0x10000000 /* Freeze when PMM==1 */
+#define PMLCA_FCM0 0x08000000 /* Freeze when PMM==0 */
+#define PMLCA_CE 0x04000000 /* Condition Enable */
+
+#define PMLCA_EVENT_MASK 0x007f0000 /* Event field */
+#define PMLCA_EVENT_SHIFT 16
+
+#define PMRN_PMLCB0 0x110 /* PM Local Control B0 */
+#define PMRN_PMLCB1 0x111 /* PM Local Control B1 */
+#define PMRN_PMLCB2 0x112 /* PM Local Control B2 */
+#define PMRN_PMLCB3 0x113 /* PM Local Control B3 */
+
+#define PMLCB_THRESHMUL_MASK 0x0700 /* Threshhold Multiple Field */
+#define PMLCB_THRESHMUL_SHIFT 8
+
+#define PMLCB_THRESHOLD_MASK 0x003f /* Threshold Field */
+#define PMLCB_THRESHOLD_SHIFT 0
+
+#define PMRN_PMGC0 0x190 /* PM Global Control 0 */
+
+#define PMGC0_FAC 0x80000000 /* Freeze all Counters */
+#define PMGC0_PMIE 0x40000000 /* Interrupt Enable */
+#define PMGC0_FCECE 0x20000000 /* Freeze countes on
+ Enabled Condition or
+ Event */
+
+#define PMRN_UPMC0 0x000 /* User Performance Monitor Counter 0 */
+#define PMRN_UPMC1 0x001 /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC2 0x002 /* User Performance Monitor Counter 1 */
+#define PMRN_UPMC3 0x003 /* User Performance Monitor Counter 1 */
+#define PMRN_UPMLCA0 0x080 /* User PM Local Control A0 */
+#define PMRN_UPMLCA1 0x081 /* User PM Local Control A1 */
+#define PMRN_UPMLCA2 0x082 /* User PM Local Control A2 */
+#define PMRN_UPMLCA3 0x083 /* User PM Local Control A3 */
+#define PMRN_UPMLCB0 0x100 /* User PM Local Control B0 */
+#define PMRN_UPMLCB1 0x101 /* User PM Local Control B1 */
+#define PMRN_UPMLCB2 0x102 /* User PM Local Control B2 */
+#define PMRN_UPMLCB3 0x103 /* User PM Local Control B3 */
+#define PMRN_UPMGC0 0x180 /* User PM Global Control 0 */
+
+
+/* Machine State Register (MSR) Fields */
+#define MSR_UCLE (1<<26) /* User-mode cache lock enable */
+#define MSR_SPE (1<<25) /* Enable SPE */
+#define MSR_DWE (1<<10) /* Debug Wait Enable */
+#define MSR_UBLE (1<<10) /* BTB lock enable (e500) */
+#define MSR_IS MSR_IR /* Instruction Space */
+#define MSR_DS MSR_DR /* Data Space */
+#define MSR_PMM (1<<2) /* Performance monitor mark bit */
+
+/* Default MSR for kernel mode. */
+#if defined (CONFIG_40x)
+#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR|MSR_CE)
+#elif defined(CONFIG_BOOKE)
+#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_CE)
+#endif
+
+/* Special Purpose Registers (SPRNs)*/
+#define SPRN_DECAR 0x036 /* Decrementer Auto Reload Register */
+#define SPRN_IVPR 0x03F /* Interrupt Vector Prefix Register */
+#define SPRN_USPRG0 0x100 /* User Special Purpose Register General 0 */
+#define SPRN_SPRG4R 0x104 /* Special Purpose Register General 4 Read */
+#define SPRN_SPRG5R 0x105 /* Special Purpose Register General 5 Read */
+#define SPRN_SPRG6R 0x106 /* Special Purpose Register General 6 Read */
+#define SPRN_SPRG7R 0x107 /* Special Purpose Register General 7 Read */
+#define SPRN_SPRG4W 0x114 /* Special Purpose Register General 4 Write */
+#define SPRN_SPRG5W 0x115 /* Special Purpose Register General 5 Write */
+#define SPRN_SPRG6W 0x116 /* Special Purpose Register General 6 Write */
+#define SPRN_SPRG7W 0x117 /* Special Purpose Register General 7 Write */
+#define SPRN_DBCR2 0x136 /* Debug Control Register 2 */
+#define SPRN_IAC3 0x13A /* Instruction Address Compare 3 */
+#define SPRN_IAC4 0x13B /* Instruction Address Compare 4 */
+#define SPRN_DVC1 0x13E /* Data Value Compare Register 1 */
+#define SPRN_DVC2 0x13F /* Data Value Compare Register 2 */
+#define SPRN_IVOR0 0x190 /* Interrupt Vector Offset Register 0 */
+#define SPRN_IVOR1 0x191 /* Interrupt Vector Offset Register 1 */
+#define SPRN_IVOR2 0x192 /* Interrupt Vector Offset Register 2 */
+#define SPRN_IVOR3 0x193 /* Interrupt Vector Offset Register 3 */
+#define SPRN_IVOR4 0x194 /* Interrupt Vector Offset Register 4 */
+#define SPRN_IVOR5 0x195 /* Interrupt Vector Offset Register 5 */
+#define SPRN_IVOR6 0x196 /* Interrupt Vector Offset Register 6 */
+#define SPRN_IVOR7 0x197 /* Interrupt Vector Offset Register 7 */
+#define SPRN_IVOR8 0x198 /* Interrupt Vector Offset Register 8 */
+#define SPRN_IVOR9 0x199 /* Interrupt Vector Offset Register 9 */
+#define SPRN_IVOR10 0x19A /* Interrupt Vector Offset Register 10 */
+#define SPRN_IVOR11 0x19B /* Interrupt Vector Offset Register 11 */
+#define SPRN_IVOR12 0x19C /* Interrupt Vector Offset Register 12 */
+#define SPRN_IVOR13 0x19D /* Interrupt Vector Offset Register 13 */
+#define SPRN_IVOR14 0x19E /* Interrupt Vector Offset Register 14 */
+#define SPRN_IVOR15 0x19F /* Interrupt Vector Offset Register 15 */
+#define SPRN_SPEFSCR 0x200 /* SPE & Embedded FP Status & Control */
+#define SPRN_BBEAR 0x201 /* Branch Buffer Entry Address Register */
+#define SPRN_BBTAR 0x202 /* Branch Buffer Target Address Register */
+#define SPRN_IVOR32 0x210 /* Interrupt Vector Offset Register 32 */
+#define SPRN_IVOR33 0x211 /* Interrupt Vector Offset Register 33 */
+#define SPRN_IVOR34 0x212 /* Interrupt Vector Offset Register 34 */
+#define SPRN_IVOR35 0x213 /* Interrupt Vector Offset Register 35 */
+#define SPRN_MCSRR0 0x23A /* Machine Check Save and Restore Register 0 */
+#define SPRN_MCSRR1 0x23B /* Machine Check Save and Restore Register 1 */
+#define SPRN_MCSR 0x23C /* Machine Check Status Register */
+#define SPRN_MCAR 0x23D /* Machine Check Address Register */
+#define SPRN_DSRR0 0x23E /* Debug Save and Restore Register 0 */
+#define SPRN_DSRR1 0x23F /* Debug Save and Restore Register 1 */
+#define SPRN_MAS0 0x270 /* MMU Assist Register 0 */
+#define SPRN_MAS1 0x271 /* MMU Assist Register 1 */
+#define SPRN_MAS2 0x272 /* MMU Assist Register 2 */
+#define SPRN_MAS3 0x273 /* MMU Assist Register 3 */
+#define SPRN_MAS4 0x274 /* MMU Assist Register 4 */
+#define SPRN_MAS5 0x275 /* MMU Assist Register 5 */
+#define SPRN_MAS6 0x276 /* MMU Assist Register 6 */
+#define SPRN_MAS7 0x3b0 /* MMU Assist Register 7 */
+#define SPRN_PID1 0x279 /* Process ID Register 1 */
+#define SPRN_PID2 0x27A /* Process ID Register 2 */
+#define SPRN_TLB0CFG 0x2B0 /* TLB 0 Config Register */
+#define SPRN_TLB1CFG 0x2B1 /* TLB 1 Config Register */
+#define SPRN_CCR1 0x378 /* Core Configuration Register 1 */
+#define SPRN_ZPR 0x3B0 /* Zone Protection Register (40x) */
+#define SPRN_MMUCR 0x3B2 /* MMU Control Register */
+#define SPRN_CCR0 0x3B3 /* Core Configuration Register 0 */
+#define SPRN_SGR 0x3B9 /* Storage Guarded Register */
+#define SPRN_DCWR 0x3BA /* Data Cache Write-thru Register */
+#define SPRN_SLER 0x3BB /* Little-endian real mode */
+#define SPRN_SU0R 0x3BC /* "User 0" real mode (40x) */
+#define SPRN_DCMP 0x3D1 /* Data TLB Compare Register */
+#define SPRN_ICDBDR 0x3D3 /* Instruction Cache Debug Data Register */
+#define SPRN_EVPR 0x3D6 /* Exception Vector Prefix Register */
+#define SPRN_L1CSR0 0x3F2 /* L1 Cache Control and Status Register 0 */
+#define SPRN_L1CSR1 0x3F3 /* L1 Cache Control and Status Register 1 */
+#define SPRN_PIT 0x3DB /* Programmable Interval Timer */
+#define SPRN_DCCR 0x3FA /* Data Cache Cacheability Register */
+#define SPRN_ICCR 0x3FB /* Instruction Cache Cacheability Register */
+#define SPRN_SVR 0x3FF /* System Version Register */
+
+/*
+ * SPRs which have conflicting definitions on true Book E versus classic,
+ * or IBM 40x.
+ */
+#ifdef CONFIG_BOOKE
+#define SPRN_PID 0x030 /* Process ID */
+#define SPRN_PID0 SPRN_PID/* Process ID Register 0 */
+#define SPRN_CSRR0 0x03A /* Critical Save and Restore Register 0 */
+#define SPRN_CSRR1 0x03B /* Critical Save and Restore Register 1 */
+#define SPRN_DEAR 0x03D /* Data Error Address Register */
+#define SPRN_ESR 0x03E /* Exception Syndrome Register */
+#define SPRN_PIR 0x11E /* Processor Identification Register */
+#define SPRN_DBSR 0x130 /* Debug Status Register */
+#define SPRN_DBCR0 0x134 /* Debug Control Register 0 */
+#define SPRN_DBCR1 0x135 /* Debug Control Register 1 */
+#define SPRN_IAC1 0x138 /* Instruction Address Compare 1 */
+#define SPRN_IAC2 0x139 /* Instruction Address Compare 2 */
+#define SPRN_DAC1 0x13C /* Data Address Compare 1 */
+#define SPRN_DAC2 0x13D /* Data Address Compare 2 */
+#define SPRN_TSR 0x150 /* Timer Status Register */
+#define SPRN_TCR 0x154 /* Timer Control Register */
+#endif /* Book E */
+#ifdef CONFIG_40x
+#define SPRN_PID 0x3B1 /* Process ID */
+#define SPRN_DBCR1 0x3BD /* Debug Control Register 1 */
+#define SPRN_ESR 0x3D4 /* Exception Syndrome Register */
+#define SPRN_DEAR 0x3D5 /* Data Error Address Register */
+#define SPRN_TSR 0x3D8 /* Timer Status Register */
+#define SPRN_TCR 0x3DA /* Timer Control Register */
+#define SPRN_SRR2 0x3DE /* Save/Restore Register 2 */
+#define SPRN_SRR3 0x3DF /* Save/Restore Register 3 */
+#define SPRN_DBSR 0x3F0 /* Debug Status Register */
+#define SPRN_DBCR0 0x3F2 /* Debug Control Register 0 */
+#define SPRN_DAC1 0x3F6 /* Data Address Compare 1 */
+#define SPRN_DAC2 0x3F7 /* Data Address Compare 2 */
+#define SPRN_CSRR0 SPRN_SRR2 /* Critical Save and Restore Register 0 */
+#define SPRN_CSRR1 SPRN_SRR3 /* Critical Save and Restore Register 1 */
+#endif
+
+/* Bit definitions for CCR1. */
+#define CCR1_DPC 0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
+#define CCR1_TCS 0x00000080 /* Timer Clock Select */
+
+/* Bit definitions for the MCSR. */
+#ifdef CONFIG_440A
+#define MCSR_MCS 0x80000000 /* Machine Check Summary */
+#define MCSR_IB 0x40000000 /* Instruction PLB Error */
+#define MCSR_DRB 0x20000000 /* Data Read PLB Error */
+#define MCSR_DWB 0x10000000 /* Data Write PLB Error */
+#define MCSR_TLBP 0x08000000 /* TLB Parity Error */
+#define MCSR_ICP 0x04000000 /* I-Cache Parity Error */
+#define MCSR_DCSP 0x02000000 /* D-Cache Search Parity Error */
+#define MCSR_DCFP 0x01000000 /* D-Cache Flush Parity Error */
+#define MCSR_IMPE 0x00800000 /* Imprecise Machine Check Exception */
+#endif
+#ifdef CONFIG_E500
+#define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */
+#define MCSR_ICPERR 0x40000000UL /* I-Cache Parity Error */
+#define MCSR_DCP_PERR 0x20000000UL /* D-Cache Push Parity Error */
+#define MCSR_DCPERR 0x10000000UL /* D-Cache Parity Error */
+#define MCSR_GL_CI 0x00010000UL /* Guarded Load or Cache-Inhibited stwcx. */
+#define MCSR_BUS_IAERR 0x00000080UL /* Instruction Address Error */
+#define MCSR_BUS_RAERR 0x00000040UL /* Read Address Error */
+#define MCSR_BUS_WAERR 0x00000020UL /* Write Address Error */
+#define MCSR_BUS_IBERR 0x00000010UL /* Instruction Data Error */
+#define MCSR_BUS_RBERR 0x00000008UL /* Read Data Bus Error */
+#define MCSR_BUS_WBERR 0x00000004UL /* Write Data Bus Error */
+#define MCSR_BUS_IPERR 0x00000002UL /* Instruction parity Error */
+#define MCSR_BUS_RPERR 0x00000001UL /* Read parity Error */
+#endif
+#ifdef CONFIG_E200
+#define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */
+#define MCSR_CP_PERR 0x20000000UL /* Cache Push Parity Error */
+#define MCSR_CPERR 0x10000000UL /* Cache Parity Error */
+#define MCSR_EXCP_ERR 0x08000000UL /* ISI, ITLB, or Bus Error on 1st insn
+ fetch for an exception handler */
+#define MCSR_BUS_IRERR 0x00000010UL /* Read Bus Error on instruction fetch*/
+#define MCSR_BUS_DRERR 0x00000008UL /* Read Bus Error on data load */
+#define MCSR_BUS_WRERR 0x00000004UL /* Write Bus Error on buffered
+ store or cache line push */
+#endif
+
+/* Bit definitions for the DBSR. */
+/*
+ * DBSR bits which have conflicting definitions on true Book E versus IBM 40x.
+ */
+#ifdef CONFIG_BOOKE
+#define DBSR_IC 0x08000000 /* Instruction Completion */
+#define DBSR_BT 0x04000000 /* Branch Taken */
+#define DBSR_TIE 0x01000000 /* Trap Instruction Event */
+#define DBSR_IAC1 0x00800000 /* Instr Address Compare 1 Event */
+#define DBSR_IAC2 0x00400000 /* Instr Address Compare 2 Event */
+#define DBSR_IAC3 0x00200000 /* Instr Address Compare 3 Event */
+#define DBSR_IAC4 0x00100000 /* Instr Address Compare 4 Event */
+#define DBSR_DAC1R 0x00080000 /* Data Addr Compare 1 Read Event */
+#define DBSR_DAC1W 0x00040000 /* Data Addr Compare 1 Write Event */
+#define DBSR_DAC2R 0x00020000 /* Data Addr Compare 2 Read Event */
+#define DBSR_DAC2W 0x00010000 /* Data Addr Compare 2 Write Event */
+#endif
+#ifdef CONFIG_40x
+#define DBSR_IC 0x80000000 /* Instruction Completion */
+#define DBSR_BT 0x40000000 /* Branch taken */
+#define DBSR_TIE 0x10000000 /* Trap Instruction debug Event */
+#define DBSR_IAC1 0x04000000 /* Instruction Address Compare 1 Event */
+#define DBSR_IAC2 0x02000000 /* Instruction Address Compare 2 Event */
+#define DBSR_IAC3 0x00080000 /* Instruction Address Compare 3 Event */
+#define DBSR_IAC4 0x00040000 /* Instruction Address Compare 4 Event */
+#define DBSR_DAC1R 0x01000000 /* Data Address Compare 1 Read Event */
+#define DBSR_DAC1W 0x00800000 /* Data Address Compare 1 Write Event */
+#define DBSR_DAC2R 0x00400000 /* Data Address Compare 2 Read Event */
+#define DBSR_DAC2W 0x00200000 /* Data Address Compare 2 Write Event */
+#endif
+
+/* Bit definitions related to the ESR. */
+#define ESR_MCI 0x80000000 /* Machine Check - Instruction */
+#define ESR_IMCP 0x80000000 /* Instr. Machine Check - Protection */
+#define ESR_IMCN 0x40000000 /* Instr. Machine Check - Non-config */
+#define ESR_IMCB 0x20000000 /* Instr. Machine Check - Bus error */
+#define ESR_IMCT 0x10000000 /* Instr. Machine Check - Timeout */
+#define ESR_PIL 0x08000000 /* Program Exception - Illegal */
+#define ESR_PPR 0x04000000 /* Program Exception - Priveleged */
+#define ESR_PTR 0x02000000 /* Program Exception - Trap */
+#define ESR_FP 0x01000000 /* Floating Point Operation */
+#define ESR_DST 0x00800000 /* Storage Exception - Data miss */
+#define ESR_DIZ 0x00400000 /* Storage Exception - Zone fault */
+#define ESR_ST 0x00800000 /* Store Operation */
+#define ESR_DLK 0x00200000 /* Data Cache Locking */
+#define ESR_ILK 0x00100000 /* Instr. Cache Locking */
+#define ESR_PUO 0x00040000 /* Unimplemented Operation exception */
+#define ESR_BO 0x00020000 /* Byte Ordering */
+
+/* Bit definitions related to the DBCR0. */
+#define DBCR0_EDM 0x80000000 /* External Debug Mode */
+#define DBCR0_IDM 0x40000000 /* Internal Debug Mode */
+#define DBCR0_RST 0x30000000 /* all the bits in the RST field */
+#define DBCR0_RST_SYSTEM 0x30000000 /* System Reset */
+#define DBCR0_RST_CHIP 0x20000000 /* Chip Reset */
+#define DBCR0_RST_CORE 0x10000000 /* Core Reset */
+#define DBCR0_RST_NONE 0x00000000 /* No Reset */
+#define DBCR0_IC 0x08000000 /* Instruction Completion */
+#define DBCR0_BT 0x04000000 /* Branch Taken */
+#define DBCR0_EDE 0x02000000 /* Exception Debug Event */
+#define DBCR0_TDE 0x01000000 /* TRAP Debug Event */
+#define DBCR0_IA1 0x00800000 /* Instr Addr compare 1 enable */
+#define DBCR0_IA2 0x00400000 /* Instr Addr compare 2 enable */
+#define DBCR0_IA12 0x00200000 /* Instr Addr 1-2 range enable */
+#define DBCR0_IA12X 0x00100000 /* Instr Addr 1-2 range eXclusive */
+#define DBCR0_IA3 0x00080000 /* Instr Addr compare 3 enable */
+#define DBCR0_IA4 0x00040000 /* Instr Addr compare 4 enable */
+#define DBCR0_IA34 0x00020000 /* Instr Addr 3-4 range Enable */
+#define DBCR0_IA34X 0x00010000 /* Instr Addr 3-4 range eXclusive */
+#define DBCR0_IA12T 0x00008000 /* Instr Addr 1-2 range Toggle */
+#define DBCR0_IA34T 0x00004000 /* Instr Addr 3-4 range Toggle */
+#define DBCR0_FT 0x00000001 /* Freeze Timers on debug event */
+
+/* Bit definitions related to the TCR. */
+#define TCR_WP(x) (((x)&0x3)<<30) /* WDT Period */
+#define TCR_WP_MASK TCR_WP(3)
+#define WP_2_17 0 /* 2^17 clocks */
+#define WP_2_21 1 /* 2^21 clocks */
+#define WP_2_25 2 /* 2^25 clocks */
+#define WP_2_29 3 /* 2^29 clocks */
+#define TCR_WRC(x) (((x)&0x3)<<28) /* WDT Reset Control */
+#define TCR_WRC_MASK TCR_WRC(3)
+#define WRC_NONE 0 /* No reset will occur */
+#define WRC_CORE 1 /* Core reset will occur */
+#define WRC_CHIP 2 /* Chip reset will occur */
+#define WRC_SYSTEM 3 /* System reset will occur */
+#define TCR_WIE 0x08000000 /* WDT Interrupt Enable */
+#define TCR_PIE 0x04000000 /* PIT Interrupt Enable */
+#define TCR_DIE TCR_PIE /* DEC Interrupt Enable */
+#define TCR_FP(x) (((x)&0x3)<<24) /* FIT Period */
+#define TCR_FP_MASK TCR_FP(3)
+#define FP_2_9 0 /* 2^9 clocks */
+#define FP_2_13 1 /* 2^13 clocks */
+#define FP_2_17 2 /* 2^17 clocks */
+#define FP_2_21 3 /* 2^21 clocks */
+#define TCR_FIE 0x00800000 /* FIT Interrupt Enable */
+#define TCR_ARE 0x00400000 /* Auto Reload Enable */
+
+/* Bit definitions for the TSR. */
+#define TSR_ENW 0x80000000 /* Enable Next Watchdog */
+#define TSR_WIS 0x40000000 /* WDT Interrupt Status */
+#define TSR_WRS(x) (((x)&0x3)<<28) /* WDT Reset Status */
+#define WRS_NONE 0 /* No WDT reset occurred */
+#define WRS_CORE 1 /* WDT forced core reset */
+#define WRS_CHIP 2 /* WDT forced chip reset */
+#define WRS_SYSTEM 3 /* WDT forced system reset */
+#define TSR_PIS 0x08000000 /* PIT Interrupt Status */
+#define TSR_DIS TSR_PIS /* DEC Interrupt Status */
+#define TSR_FIS 0x04000000 /* FIT Interrupt Status */
+
+/* Bit definitions for the DCCR. */
+#define DCCR_NOCACHE 0 /* Noncacheable */
+#define DCCR_CACHE 1 /* Cacheable */
+
+/* Bit definitions for DCWR. */
+#define DCWR_COPY 0 /* Copy-back */
+#define DCWR_WRITE 1 /* Write-through */
+
+/* Bit definitions for ICCR. */
+#define ICCR_NOCACHE 0 /* Noncacheable */
+#define ICCR_CACHE 1 /* Cacheable */
+
+/* Bit definitions for L1CSR0. */
+#define L1CSR0_CLFC 0x00000100 /* Cache Lock Bits Flash Clear */
+#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */
+#define L1CSR0_CFI 0x00000002 /* Cache Flash Invalidate */
+#define L1CSR0_DCE 0x00000001 /* Data Cache Enable */
+
+/* Bit definitions for L1CSR1. */
+#define L1CSR1_ICLFR 0x00000100 /* Instr Cache Lock Bits Flash Reset */
+#define L1CSR1_ICFI 0x00000002 /* Instr Cache Flash Invalidate */
+#define L1CSR1_ICE 0x00000001 /* Instr Cache Enable */
+
+/* Bit definitions for SGR. */
+#define SGR_NORMAL 0 /* Speculative fetching allowed. */
+#define SGR_GUARDED 1 /* Speculative fetching disallowed. */
+
+/* Bit definitions for SPEFSCR. */
+#define SPEFSCR_SOVH 0x80000000 /* Summary integer overflow high */
+#define SPEFSCR_OVH 0x40000000 /* Integer overflow high */
+#define SPEFSCR_FGH 0x20000000 /* Embedded FP guard bit high */
+#define SPEFSCR_FXH 0x10000000 /* Embedded FP sticky bit high */
+#define SPEFSCR_FINVH 0x08000000 /* Embedded FP invalid operation high */
+#define SPEFSCR_FDBZH 0x04000000 /* Embedded FP div by zero high */
+#define SPEFSCR_FUNFH 0x02000000 /* Embedded FP underflow high */
+#define SPEFSCR_FOVFH 0x01000000 /* Embedded FP overflow high */
+#define SPEFSCR_FINXS 0x00200000 /* Embedded FP inexact sticky */
+#define SPEFSCR_FINVS 0x00100000 /* Embedded FP invalid op. sticky */
+#define SPEFSCR_FDBZS 0x00080000 /* Embedded FP div by zero sticky */
+#define SPEFSCR_FUNFS 0x00040000 /* Embedded FP underflow sticky */
+#define SPEFSCR_FOVFS 0x00020000 /* Embedded FP overflow sticky */
+#define SPEFSCR_MODE 0x00010000 /* Embedded FP mode */
+#define SPEFSCR_SOV 0x00008000 /* Integer summary overflow */
+#define SPEFSCR_OV 0x00004000 /* Integer overflow */
+#define SPEFSCR_FG 0x00002000 /* Embedded FP guard bit */
+#define SPEFSCR_FX 0x00001000 /* Embedded FP sticky bit */
+#define SPEFSCR_FINV 0x00000800 /* Embedded FP invalid operation */
+#define SPEFSCR_FDBZ 0x00000400 /* Embedded FP div by zero */
+#define SPEFSCR_FUNF 0x00000200 /* Embedded FP underflow */
+#define SPEFSCR_FOVF 0x00000100 /* Embedded FP overflow */
+#define SPEFSCR_FINXE 0x00000040 /* Embedded FP inexact enable */
+#define SPEFSCR_FINVE 0x00000020 /* Embedded FP invalid op. enable */
+#define SPEFSCR_FDBZE 0x00000010 /* Embedded FP div by zero enable */
+#define SPEFSCR_FUNFE 0x00000008 /* Embedded FP underflow enable */
+#define SPEFSCR_FOVFE 0x00000004 /* Embedded FP overflow enable */
+#define SPEFSCR_FRMC 0x00000003 /* Embedded FP rounding mode control */
+
+/*
+ * The IBM-403 is an even more odd special case, as it is much
+ * older than the IBM-405 series. We put these down here incase someone
+ * wishes to support these machines again.
+ */
+#ifdef CONFIG_403GCX
+/* Special Purpose Registers (SPRNs)*/
+#define SPRN_TBHU 0x3CC /* Time Base High User-mode */
+#define SPRN_TBLU 0x3CD /* Time Base Low User-mode */
+#define SPRN_CDBCR 0x3D7 /* Cache Debug Control Register */
+#define SPRN_TBHI 0x3DC /* Time Base High */
+#define SPRN_TBLO 0x3DD /* Time Base Low */
+#define SPRN_DBCR 0x3F2 /* Debug Control Regsiter */
+#define SPRN_PBL1 0x3FC /* Protection Bound Lower 1 */
+#define SPRN_PBL2 0x3FE /* Protection Bound Lower 2 */
+#define SPRN_PBU1 0x3FD /* Protection Bound Upper 1 */
+#define SPRN_PBU2 0x3FF /* Protection Bound Upper 2 */
+
+
+/* Bit definitions for the DBCR. */
+#define DBCR_EDM DBCR0_EDM
+#define DBCR_IDM DBCR0_IDM
+#define DBCR_RST(x) (((x) & 0x3) << 28)
+#define DBCR_RST_NONE 0
+#define DBCR_RST_CORE 1
+#define DBCR_RST_CHIP 2
+#define DBCR_RST_SYSTEM 3
+#define DBCR_IC DBCR0_IC /* Instruction Completion Debug Evnt */
+#define DBCR_BT DBCR0_BT /* Branch Taken Debug Event */
+#define DBCR_EDE DBCR0_EDE /* Exception Debug Event */
+#define DBCR_TDE DBCR0_TDE /* TRAP Debug Event */
+#define DBCR_FER 0x00F80000 /* First Events Remaining Mask */
+#define DBCR_FT 0x00040000 /* Freeze Timers on Debug Event */
+#define DBCR_IA1 0x00020000 /* Instr. Addr. Compare 1 Enable */
+#define DBCR_IA2 0x00010000 /* Instr. Addr. Compare 2 Enable */
+#define DBCR_D1R 0x00008000 /* Data Addr. Compare 1 Read Enable */
+#define DBCR_D1W 0x00004000 /* Data Addr. Compare 1 Write Enable */
+#define DBCR_D1S(x) (((x) & 0x3) << 12) /* Data Adrr. Compare 1 Size */
+#define DAC_BYTE 0
+#define DAC_HALF 1
+#define DAC_WORD 2
+#define DAC_QUAD 3
+#define DBCR_D2R 0x00000800 /* Data Addr. Compare 2 Read Enable */
+#define DBCR_D2W 0x00000400 /* Data Addr. Compare 2 Write Enable */
+#define DBCR_D2S(x) (((x) & 0x3) << 8) /* Data Addr. Compare 2 Size */
+#define DBCR_SBT 0x00000040 /* Second Branch Taken Debug Event */
+#define DBCR_SED 0x00000020 /* Second Exception Debug Event */
+#define DBCR_STD 0x00000010 /* Second Trap Debug Event */
+#define DBCR_SIA 0x00000008 /* Second IAC Enable */
+#define DBCR_SDA 0x00000004 /* Second DAC Enable */
+#define DBCR_JOI 0x00000002 /* JTAG Serial Outbound Int. Enable */
+#define DBCR_JII 0x00000001 /* JTAG Serial Inbound Int. Enable */
+#endif /* 403GCX */
+#endif /* __ASM_POWERPC_REG_BOOKE_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/rheap.h b/include/asm-powerpc/rheap.h
similarity index 74%
rename from include/asm-ppc/rheap.h
rename to include/asm-powerpc/rheap.h
index 39a10d8..1723817 100644
--- a/include/asm-ppc/rheap.h
+++ b/include/asm-powerpc/rheap.h
@@ -18,7 +18,7 @@
typedef struct _rh_block {
struct list_head list;
- void *start;
+ unsigned long start;
int size;
const char *owner;
} rh_block_t;
@@ -37,8 +37,8 @@
#define RHIF_STATIC_INFO 0x1
#define RHIF_STATIC_BLOCK 0x2
-typedef struct rh_stats_t {
- void *start;
+typedef struct _rh_stats {
+ unsigned long start;
int size;
const char *owner;
} rh_stats_t;
@@ -57,24 +57,24 @@
rh_block_t * block);
/* Attach a free region to manage */
-extern int rh_attach_region(rh_info_t * info, void *start, int size);
+extern int rh_attach_region(rh_info_t * info, unsigned long start, int size);
/* Detach a free region */
-extern void *rh_detach_region(rh_info_t * info, void *start, int size);
+extern unsigned long rh_detach_region(rh_info_t * info, unsigned long start, int size);
/* Allocate the given size from the remote heap (with alignment) */
-extern void *rh_alloc_align(rh_info_t * info, int size, int alignment,
+extern unsigned long rh_alloc_align(rh_info_t * info, int size, int alignment,
const char *owner);
/* Allocate the given size from the remote heap */
-extern void *rh_alloc(rh_info_t * info, int size, const char *owner);
+extern unsigned long rh_alloc(rh_info_t * info, int size, const char *owner);
/* Allocate the given size from the given address */
-extern void *rh_alloc_fixed(rh_info_t * info, void *start, int size,
+extern unsigned long rh_alloc_fixed(rh_info_t * info, unsigned long start, int size,
const char *owner);
/* Free the allocated area */
-extern int rh_free(rh_info_t * info, void *start);
+extern int rh_free(rh_info_t * info, unsigned long start);
/* Get stats for debugging purposes */
extern int rh_get_stats(rh_info_t * info, int what, int max_stats,
@@ -84,6 +84,6 @@
extern void rh_dump(rh_info_t * info);
/* Set owner of taken block */
-extern int rh_set_owner(rh_info_t * info, void *start, const char *owner);
+extern int rh_set_owner(rh_info_t * info, unsigned long start, const char *owner);
#endif /* __ASM_PPC_RHEAP_H__ */
diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h
index 0b00068..3d44446 100644
--- a/include/asm-powerpc/systbl.h
+++ b/include/asm-powerpc/systbl.h
@@ -307,3 +307,4 @@
COMPAT_SYS_SPU(move_pages)
SYSCALL_SPU(getcpu)
COMPAT_SYS(epoll_pwait)
+COMPAT_SYS_SPU(utimensat)
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index 2baedbe..21f004a 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -326,10 +326,11 @@
#define __NR_move_pages 301
#define __NR_getcpu 302
#define __NR_epoll_pwait 303
+#define __NR_utimensat 304
#ifdef __KERNEL__
-#define __NR_syscalls 304
+#define __NR_syscalls 305
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls
diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
index 4f99df1..3972487 100644
--- a/include/asm-ppc/commproc.h
+++ b/include/asm-ppc/commproc.h
@@ -63,20 +63,15 @@
#define CPM_DATAONLY_SIZE ((uint)0x0700)
#define CPM_DP_NOSPACE ((uint)0x7fffffff)
-static inline long IS_DPERR(const uint offset)
-{
- return (uint)offset > (uint)-1000L;
-}
-
/* Export the base address of the communication processor registers
* and dual port ram.
*/
extern cpm8xx_t *cpmp; /* Pointer to comm processor */
-extern uint cpm_dpalloc(uint size, uint align);
-extern int cpm_dpfree(uint offset);
-extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
+extern unsigned long cpm_dpalloc(uint size, uint align);
+extern int cpm_dpfree(unsigned long offset);
+extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align);
extern void cpm_dpdump(void);
-extern void *cpm_dpram_addr(uint offset);
+extern void *cpm_dpram_addr(unsigned long offset);
extern uint cpm_dpram_phys(u8* addr);
extern void cpm_setbrg(uint brg, uint rate);
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
index 220cc2d..12a2860 100644
--- a/include/asm-ppc/cpm2.h
+++ b/include/asm-ppc/cpm2.h
@@ -104,21 +104,16 @@
*/
#define NUM_CPM_HOST_PAGES 2
-static inline long IS_DPERR(const uint offset)
-{
- return (uint)offset > (uint)-1000L;
-}
-
/* Export the base address of the communication processor registers
* and dual port ram.
*/
extern cpm_cpm2_t *cpmp; /* Pointer to comm processor */
-extern uint cpm_dpalloc(uint size, uint align);
-extern int cpm_dpfree(uint offset);
-extern uint cpm_dpalloc_fixed(uint offset, uint size, uint align);
+extern unsigned long cpm_dpalloc(uint size, uint align);
+extern int cpm_dpfree(unsigned long offset);
+extern unsigned long cpm_dpalloc_fixed(unsigned long offset, uint size, uint align);
extern void cpm_dpdump(void);
-extern void *cpm_dpram_addr(uint offset);
+extern void *cpm_dpram_addr(unsigned long offset);
extern void cpm_setbrg(uint brg, uint rate);
extern void cpm2_fastbrg(uint brg, uint rate, int div16);
extern void cpm2_reset(void);
diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h
index 6795ece..4c2e171 100644
--- a/include/asm-s390/ccwdev.h
+++ b/include/asm-s390/ccwdev.h
@@ -16,6 +16,7 @@
/* structs from asm/cio.h */
struct irb;
struct ccw1;
+struct ccw_dev_id;
/* simplified initializers for struct ccw_device:
* CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one
@@ -175,6 +176,7 @@
extern struct ciw *ccw_device_get_ciw(struct ccw_device *, __u32 cmd);
extern __u8 ccw_device_get_path_mask(struct ccw_device *);
+extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
#define get_ccwdev_lock(x) (x)->ccwlock
@@ -184,7 +186,6 @@
extern struct ccw_device *ccw_device_probe_console(void);
// FIXME: these have to go
-extern int _ccw_device_get_device_number(struct ccw_device *);
extern int _ccw_device_get_subchannel_number(struct ccw_device *);
extern void *ccw_device_get_chp_desc(struct ccw_device *, int);
diff --git a/include/asm-s390/ipl.h b/include/asm-s390/ipl.h
index bdcd448..2c40fd3 100644
--- a/include/asm-s390/ipl.h
+++ b/include/asm-s390/ipl.h
@@ -79,8 +79,8 @@
* IPL validity flags
*/
extern u32 ipl_flags;
-
extern u32 dump_prefix_page;
+extern unsigned int zfcpdump_prefix_array[];
extern void do_reipl(void);
extern void ipl_save_parameters(void);
diff --git a/include/asm-s390/param.h b/include/asm-s390/param.h
index 085a7e2..34aaa46 100644
--- a/include/asm-s390/param.h
+++ b/include/asm-s390/param.h
@@ -10,7 +10,7 @@
#define _ASMS390_PARAM_H
#ifdef __KERNEL__
-# define HZ 100 /* Internal kernel timer frequency */
+# define HZ CONFIG_HZ /* Internal kernel timer frequency */
# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#endif
diff --git a/include/asm-s390/poll.h b/include/asm-s390/poll.h
index 6f7f65a..c98509d 100644
--- a/include/asm-s390/poll.h
+++ b/include/asm-s390/poll.h
@@ -1,35 +1 @@
-/*
- * include/asm-s390/poll.h
- *
- * S390 version
- *
- * Derived from "include/asm-i386/poll.h"
- */
-
-#ifndef __S390_POLL_H
-#define __S390_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-sh/poll.h b/include/asm-sh/poll.h
index dbca9b3..c98509d 100644
--- a/include/asm-sh/poll.h
+++ b/include/asm-sh/poll.h
@@ -1,27 +1 @@
-#ifndef __ASM_SH_POLL_H
-#define __ASM_SH_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif /* __ASM_SH_POLL_H */
+#include <asm-generic/poll.h>
diff --git a/include/asm-sh64/poll.h b/include/asm-sh64/poll.h
index 3a6cbad..ca29502 100644
--- a/include/asm-sh64/poll.h
+++ b/include/asm-sh64/poll.h
@@ -1,37 +1,8 @@
#ifndef __ASM_SH64_POLL_H
#define __ASM_SH64_POLL_H
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * include/asm-sh64/poll.h
- *
- * Copyright (C) 2000, 2001 Paolo Alberelli
- *
- */
+#include <asm-generic/poll.h>
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#undef POLLREMOVE
#endif /* __ASM_SH64_POLL_H */
diff --git a/include/asm-sparc/poll.h b/include/asm-sparc/poll.h
index 26f13fb..091d3ad 100644
--- a/include/asm-sparc/poll.h
+++ b/include/asm-sparc/poll.h
@@ -1,24 +1,12 @@
#ifndef __SPARC_POLL_H
#define __SPARC_POLL_H
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
#define POLLWRBAND 256
#define POLLMSG 512
#define POLLREMOVE 1024
#define POLLRDHUP 2048
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
#endif
diff --git a/include/asm-sparc64/openprom.h b/include/asm-sparc64/openprom.h
index e01b805..26ec046 100644
--- a/include/asm-sparc64/openprom.h
+++ b/include/asm-sparc64/openprom.h
@@ -177,7 +177,7 @@
/* More fun PROM structures for device probing. */
#define PROMREG_MAX 24
#define PROMVADDR_MAX 16
-#define PROMINTR_MAX 15
+#define PROMINTR_MAX 32
struct linux_prom_registers {
unsigned which_io; /* hi part of physical address */
diff --git a/include/asm-sparc64/poll.h b/include/asm-sparc64/poll.h
index ab6b0d1..ebeeb38 100644
--- a/include/asm-sparc64/poll.h
+++ b/include/asm-sparc64/poll.h
@@ -1,24 +1,12 @@
#ifndef __SPARC64_POLL_H
#define __SPARC64_POLL_H
-#define POLLIN 1
-#define POLLPRI 2
-#define POLLOUT 4
-#define POLLERR 8
-#define POLLHUP 16
-#define POLLNVAL 32
-#define POLLRDNORM 64
#define POLLWRNORM POLLOUT
-#define POLLRDBAND 128
#define POLLWRBAND 256
#define POLLMSG 512
#define POLLREMOVE 1024
#define POLLRDHUP 2048
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
#endif
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h
index 261e2f4..18a13ba 100644
--- a/include/asm-um/thread_info.h
+++ b/include/asm-um/thread_info.h
@@ -22,6 +22,7 @@
0-0xBFFFFFFF for user
0-0xFFFFFFFF for kernel */
struct restart_block restart_block;
+ struct thread_info *real_thread; /* Points to non-IRQ stack */
};
#define INIT_THREAD_INFO(tsk) \
@@ -35,6 +36,7 @@
.restart_block = { \
.fn = do_no_restart_syscall, \
}, \
+ .real_thread = NULL, \
}
#define init_thread_info (init_thread_union.thread_info)
diff --git a/include/asm-v850/poll.h b/include/asm-v850/poll.h
index c10176c..803cad0 100644
--- a/include/asm-v850/poll.h
+++ b/include/asm-v850/poll.h
@@ -1,24 +1,9 @@
#ifndef __V850_POLL_H__
#define __V850_POLL_H__
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-#define POLLRDNORM 0x0040
#define POLLWRNORM POLLOUT
-#define POLLRDBAND 0x0080
#define POLLWRBAND 0x0100
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
#endif /* __V850_POLL_H__ */
diff --git a/include/asm-x86_64/alternative.h b/include/asm-x86_64/alternative.h
index a09fe85..a094276 100644
--- a/include/asm-x86_64/alternative.h
+++ b/include/asm-x86_64/alternative.h
@@ -103,6 +103,12 @@
".previous" : output : [feat] "i" (feature), ##input)
/*
+ * use this macro(s) if you need more than one output parameter
+ * in alternative_io
+ */
+#define ASM_OUTPUT2(a, b) a, b
+
+/*
* Alternative inline assembly for SMP.
*
* The LOCK_PREFIX macro defined here replaces the LOCK and
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index dee632f..e327c83 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -80,6 +80,15 @@
#define __PHYSICAL_START CONFIG_PHYSICAL_START
#define __KERNEL_ALIGN 0x200000
+/*
+ * Make sure kernel is aligned to 2MB address. Catching it at compile
+ * time is better. Change your config file and compile the kernel
+ * for a 2MB aligned address (CONFIG_PHYSICAL_START)
+ */
+#if (CONFIG_PHYSICAL_START % __KERNEL_ALIGN) != 0
+#error "CONFIG_PHYSICAL_START must be a multiple of 2MB"
+#endif
+
#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
#define __START_KERNEL_map _AC(0xffffffff80000000, UL)
#define __PAGE_OFFSET _AC(0xffff810000000000, UL)
diff --git a/include/asm-x86_64/poll.h b/include/asm-x86_64/poll.h
index c0475a9..c98509d 100644
--- a/include/asm-x86_64/poll.h
+++ b/include/asm-x86_64/poll.h
@@ -1,27 +1 @@
-#ifndef __x86_64_POLL_H
-#define __x86_64_POLL_H
-
-/* These are specified by iBCS2 */
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-/* The rest seem to be more-or-less nonstandard. Check them! */
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
-#define POLLWRNORM 0x0100
-#define POLLWRBAND 0x0200
-#define POLLMSG 0x0400
-#define POLLREMOVE 0x1000
-#define POLLRDHUP 0x2000
-
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
-
-#endif
+#include <asm-generic/poll.h>
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index 5957039..ae1ed05 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -621,6 +621,15 @@
__SYSCALL(__NR_move_pages, sys_move_pages)
#define __NR_utimensat 280
__SYSCALL(__NR_utimensat, sys_utimensat)
+#define __IGNORE_getcpu /* implemented as a vsyscall */
+#define __NR_epoll_pwait 281
+__SYSCALL(__NR_epoll_pwait, sys_epoll_pwait)
+#define __NR_signalfd 282
+__SYSCALL(__NR_signalfd, sys_signalfd)
+#define __NR_timerfd 282
+__SYSCALL(__NR_timerfd, sys_timerfd)
+#define __NR_eventfd 283
+__SYSCALL(__NR_eventfd, sys_eventfd)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/include/asm-xtensa/poll.h b/include/asm-xtensa/poll.h
index 6fd9477..9d2d599 100644
--- a/include/asm-xtensa/poll.h
+++ b/include/asm-xtensa/poll.h
@@ -11,28 +11,10 @@
#ifndef _XTENSA_POLL_H
#define _XTENSA_POLL_H
-
-#define POLLIN 0x0001
-#define POLLPRI 0x0002
-#define POLLOUT 0x0004
-
-#define POLLERR 0x0008
-#define POLLHUP 0x0010
-#define POLLNVAL 0x0020
-
-#define POLLRDNORM 0x0040
-#define POLLRDBAND 0x0080
#define POLLWRNORM POLLOUT
#define POLLWRBAND 0x0100
-
-#define POLLMSG 0x0400
#define POLLREMOVE 0x0800
-#define POLLRDHUP 0x2000
-struct pollfd {
- int fd;
- short events;
- short revents;
-};
+#include <asm-generic/poll.h>
#endif /* _XTENSA_POLL_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 94cc04a..bcd01f2 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -140,7 +140,6 @@
header-y += sockios.h
header-y += som.h
header-y += sound.h
-header-y += synclink.h
header-y += taskstats.h
header-y += telephony.h
header-y += termios.h
@@ -191,6 +190,7 @@
unifdef-y += errqueue.h
unifdef-y += ethtool.h
unifdef-y += eventpoll.h
+unifdef-y += signalfd.h
unifdef-y += ext2_fs.h
unifdef-y += ext3_fs.h
unifdef-y += fb.h
@@ -320,6 +320,7 @@
unifdef-y += soundcard.h
unifdef-y += stat.h
unifdef-y += stddef.h
+unifdef-y += synclink.h
unifdef-y += sysctl.h
unifdef-y += tcp.h
unifdef-y += time.h
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 8bcfaa4..fccd8b5 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -182,7 +182,8 @@
extern int ec_write(u8 addr, u8 val);
extern int ec_transaction(u8 command,
const u8 *wdata, unsigned wdata_len,
- u8 *rdata, unsigned rdata_len);
+ u8 *rdata, unsigned rdata_len,
+ int force_poll);
#endif /*CONFIG_ACPI_EC*/
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 43dc2eb..b903fc0 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -119,6 +119,12 @@
struct list_head ki_list; /* the aio core uses this
* for cancellation */
+
+ /*
+ * If the aio_resfd field of the userspace iocb is not zero,
+ * this is the underlying file* to deliver event to.
+ */
+ struct file *ki_eventfd;
};
#define is_sync_kiocb(iocb) ((iocb)->ki_key == KIOCB_SYNC_KEY)
diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h
index e3ca0a4..9e01729 100644
--- a/include/linux/aio_abi.h
+++ b/include/linux/aio_abi.h
@@ -45,6 +45,14 @@
IOCB_CMD_PWRITEV = 8,
};
+/*
+ * Valid flags for the "aio_flags" member of the "struct iocb".
+ *
+ * IOCB_FLAG_RESFD - Set if the "aio_resfd" member of the "struct iocb"
+ * is valid.
+ */
+#define IOCB_FLAG_RESFD (1 << 0)
+
/* read() from /dev/aio returns these structures. */
struct io_event {
__u64 data; /* the data field from the iocb */
@@ -84,7 +92,15 @@
/* extra parameters */
__u64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */
- __u64 aio_reserved3;
+
+ /* flags for the "struct iocb" */
+ __u32 aio_flags;
+
+ /*
+ * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
+ * eventfd to signal AIO readiness to
+ */
+ __u32 aio_resfd;
}; /* 64 bytes */
#undef IFBIG
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
new file mode 100644
index 0000000..b2e1ba3
--- /dev/null
+++ b/include/linux/anon_inodes.h
@@ -0,0 +1,16 @@
+/*
+ * include/linux/anon_inodes.h
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_ANON_INODES_H
+#define _LINUX_ANON_INODES_H
+
+int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
+ const char *name, const struct file_operations *fops,
+ void *priv);
+
+#endif /* _LINUX_ANON_INODES_H */
+
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 773e30d..fccc6e5 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -91,6 +91,7 @@
#define AUDIT_MQ_GETSETATTR 1315 /* POSIX MQ get/set attribute record type */
#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */
#define AUDIT_FD_PAIR 1317 /* audit record for pipe/socketpair */
+#define AUDIT_OBJ_PID 1318 /* ptrace target */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -111,6 +112,7 @@
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */
+#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */
#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */
@@ -148,6 +150,8 @@
#define AUDIT_CLASS_READ_32 5
#define AUDIT_CLASS_WRITE 6
#define AUDIT_CLASS_WRITE_32 7
+#define AUDIT_CLASS_SIGNAL 8
+#define AUDIT_CLASS_SIGNAL_32 9
/* This bitmask is used to validate user input. It represents all bits that
* are currently used in an audit field constant understood by the kernel.
@@ -337,6 +341,7 @@
#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
extern int __init audit_register_class(int class, unsigned *list);
extern int audit_classify_syscall(int abi, unsigned syscall);
+extern int audit_classify_arch(int arch);
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
/* Public API */
@@ -351,7 +356,8 @@
extern void __audit_inode(const char *name, const struct inode *inode);
extern void __audit_inode_child(const char *dname, const struct inode *inode,
const struct inode *parent);
-extern void __audit_inode_update(const struct inode *inode);
+extern void __audit_ptrace(struct task_struct *t);
+
static inline int audit_dummy_context(void)
{
void *p = current->audit_context;
@@ -372,9 +378,12 @@
if (unlikely(!audit_dummy_context()))
__audit_inode_child(dname, inode, parent);
}
-static inline void audit_inode_update(const struct inode *inode) {
+void audit_core_dumps(long signr);
+
+static inline void audit_ptrace(struct task_struct *t)
+{
if (unlikely(!audit_dummy_context()))
- __audit_inode_update(inode);
+ __audit_ptrace(t);
}
/* Private API (for audit.c only) */
@@ -447,6 +456,7 @@
return 0;
}
extern int audit_n_rules;
+extern int audit_signals;
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
@@ -457,10 +467,9 @@
#define audit_putname(n) do { ; } while (0)
#define __audit_inode(n,i) do { ; } while (0)
#define __audit_inode_child(d,i,p) do { ; } while (0)
-#define __audit_inode_update(i) do { ; } while (0)
#define audit_inode(n,i) do { ; } while (0)
#define audit_inode_child(d,i,p) do { ; } while (0)
-#define audit_inode_update(i) do { ; } while (0)
+#define audit_core_dumps(i) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) do { BUG(); } while (0)
#define audit_get_loginuid(c) ({ -1; })
#define audit_log_task_context(b) do { ; } while (0)
@@ -477,7 +486,9 @@
#define audit_mq_timedreceive(d,l,p,t) ({ 0; })
#define audit_mq_notify(d,n) ({ 0; })
#define audit_mq_getsetattr(d,s) ({ 0; })
+#define audit_ptrace(t) ((void)0)
#define audit_n_rules 0
+#define audit_signals 0
#endif
#ifdef CONFIG_AUDIT
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 70a157a..636502c 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -225,6 +225,11 @@
return lhs->tv_nsec - rhs->tv_nsec;
}
+extern int get_compat_itimerspec(struct itimerspec *dst,
+ const struct compat_itimerspec __user *src);
+extern int put_compat_itimerspec(struct compat_itimerspec __user *dst,
+ const struct itimerspec *src);
+
asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
extern int compat_printk(const char *fmt, ...);
diff --git a/include/linux/crc-itu-t.h b/include/linux/crc-itu-t.h
new file mode 100644
index 0000000..84920f3
--- /dev/null
+++ b/include/linux/crc-itu-t.h
@@ -0,0 +1,28 @@
+/*
+ * crc-itu-t.h - CRC ITU-T V.41 routine
+ *
+ * Implements the standard CRC ITU-T V.41:
+ * Width 16
+ * Poly 0x0x1021 (x^16 + x^12 + x^15 + 1)
+ * Init 0
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#ifndef CRC_ITU_T_H
+#define CRC_ITU_T_H
+
+#include <linux/types.h>
+
+extern u16 const crc_itu_t_table[256];
+
+extern u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len);
+
+static inline u16 crc_itu_t_byte(u16 crc, const u8 data)
+{
+ return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
+}
+
+#endif /* CRC_ITU_T_H */
+
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
new file mode 100644
index 0000000..0d6ecc6
--- /dev/null
+++ b/include/linux/eventfd.h
@@ -0,0 +1,29 @@
+/*
+ * include/linux/eventfd.h
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_EVENTFD_H
+#define _LINUX_EVENTFD_H
+
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_EVENTFD
+
+struct file *eventfd_fget(int fd);
+int eventfd_signal(struct file *file, int n);
+
+#else /* CONFIG_EVENTFD */
+
+#define eventfd_fget(fd) ERR_PTR(-ENOSYS)
+#define eventfd_signal(f, n) 0
+
+#endif /* CONFIG_EVENTFD */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_EVENTFD_H */
+
diff --git a/include/linux/firewire-cdev.h b/include/linux/firewire-cdev.h
new file mode 100644
index 0000000..d4455eb
--- /dev/null
+++ b/include/linux/firewire-cdev.h
@@ -0,0 +1,229 @@
+/*
+ * Char device interface.
+ *
+ * Copyright (C) 2005-2006 Kristian Hoegsberg <krh@bitplanet.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _LINUX_FIREWIRE_CDEV_H
+#define _LINUX_FIREWIRE_CDEV_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/firewire-constants.h>
+
+#define FW_CDEV_EVENT_BUS_RESET 0x00
+#define FW_CDEV_EVENT_RESPONSE 0x01
+#define FW_CDEV_EVENT_REQUEST 0x02
+#define FW_CDEV_EVENT_ISO_INTERRUPT 0x03
+
+/* The 'closure' fields are for user space to use. Data passed in the
+ * 'closure' field for a request will be returned in the corresponding
+ * event. It's a 64-bit type so that it's a fixed size type big
+ * enough to hold a pointer on all platforms. */
+
+struct fw_cdev_event_common {
+ __u64 closure;
+ __u32 type;
+};
+
+struct fw_cdev_event_bus_reset {
+ __u64 closure;
+ __u32 type;
+ __u32 node_id;
+ __u32 local_node_id;
+ __u32 bm_node_id;
+ __u32 irm_node_id;
+ __u32 root_node_id;
+ __u32 generation;
+};
+
+struct fw_cdev_event_response {
+ __u64 closure;
+ __u32 type;
+ __u32 rcode;
+ __u32 length;
+ __u32 data[0];
+};
+
+struct fw_cdev_event_request {
+ __u64 closure;
+ __u32 type;
+ __u32 tcode;
+ __u64 offset;
+ __u32 handle;
+ __u32 length;
+ __u32 data[0];
+};
+
+struct fw_cdev_event_iso_interrupt {
+ __u64 closure;
+ __u32 type;
+ __u32 cycle;
+ __u32 header_length; /* Length in bytes of following headers. */
+ __u32 header[0];
+};
+
+union fw_cdev_event {
+ struct fw_cdev_event_common common;
+ struct fw_cdev_event_bus_reset bus_reset;
+ struct fw_cdev_event_response response;
+ struct fw_cdev_event_request request;
+ struct fw_cdev_event_iso_interrupt iso_interrupt;
+};
+
+#define FW_CDEV_IOC_GET_INFO _IOWR('#', 0x00, struct fw_cdev_get_info)
+#define FW_CDEV_IOC_SEND_REQUEST _IOW('#', 0x01, struct fw_cdev_send_request)
+#define FW_CDEV_IOC_ALLOCATE _IOWR('#', 0x02, struct fw_cdev_allocate)
+#define FW_CDEV_IOC_DEALLOCATE _IOW('#', 0x03, struct fw_cdev_deallocate)
+#define FW_CDEV_IOC_SEND_RESPONSE _IOW('#', 0x04, struct fw_cdev_send_response)
+#define FW_CDEV_IOC_INITIATE_BUS_RESET _IOW('#', 0x05, struct fw_cdev_initiate_bus_reset)
+#define FW_CDEV_IOC_ADD_DESCRIPTOR _IOWR('#', 0x06, struct fw_cdev_add_descriptor)
+#define FW_CDEV_IOC_REMOVE_DESCRIPTOR _IOW('#', 0x07, struct fw_cdev_remove_descriptor)
+
+#define FW_CDEV_IOC_CREATE_ISO_CONTEXT _IOWR('#', 0x08, struct fw_cdev_create_iso_context)
+#define FW_CDEV_IOC_QUEUE_ISO _IOWR('#', 0x09, struct fw_cdev_queue_iso)
+#define FW_CDEV_IOC_START_ISO _IOW('#', 0x0a, struct fw_cdev_start_iso)
+#define FW_CDEV_IOC_STOP_ISO _IOW('#', 0x0b, struct fw_cdev_stop_iso)
+
+/* FW_CDEV_VERSION History
+ *
+ * 1 Feb 18, 2007: Initial version.
+ */
+#define FW_CDEV_VERSION 1
+
+struct fw_cdev_get_info {
+ /* The version field is just a running serial number. We
+ * never break backwards compatibility. Userspace passes in
+ * the version it expects and the kernel passes back the
+ * highest version it can provide. Even if the structs in
+ * this interface are extended in a later version, the kernel
+ * will not copy back more data than what was present in the
+ * interface version userspace expects. */
+ __u32 version;
+
+ /* If non-zero, at most rom_length bytes of config rom will be
+ * copied into that user space address. In either case,
+ * rom_length is updated with the actual length of the config
+ * rom. */
+ __u32 rom_length;
+ __u64 rom;
+
+ /* If non-zero, a fw_cdev_event_bus_reset struct will be
+ * copied here with the current state of the bus. This does
+ * not cause a bus reset to happen. The value of closure in
+ * this and sub-sequent bus reset events is set to
+ * bus_reset_closure. */
+ __u64 bus_reset;
+ __u64 bus_reset_closure;
+
+ /* The index of the card this devices belongs to. */
+ __u32 card;
+};
+
+struct fw_cdev_send_request {
+ __u32 tcode;
+ __u32 length;
+ __u64 offset;
+ __u64 closure;
+ __u64 data;
+ __u32 generation;
+};
+
+struct fw_cdev_send_response {
+ __u32 rcode;
+ __u32 length;
+ __u64 data;
+ __u32 handle;
+};
+
+struct fw_cdev_allocate {
+ __u64 offset;
+ __u64 closure;
+ __u32 length;
+ __u32 handle;
+};
+
+struct fw_cdev_deallocate {
+ __u32 handle;
+};
+
+#define FW_CDEV_LONG_RESET 0
+#define FW_CDEV_SHORT_RESET 1
+
+struct fw_cdev_initiate_bus_reset {
+ __u32 type;
+};
+
+struct fw_cdev_add_descriptor {
+ __u32 immediate;
+ __u32 key;
+ __u64 data;
+ __u32 length;
+ __u32 handle;
+};
+
+struct fw_cdev_remove_descriptor {
+ __u32 handle;
+};
+
+#define FW_CDEV_ISO_CONTEXT_TRANSMIT 0
+#define FW_CDEV_ISO_CONTEXT_RECEIVE 1
+
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG0 1
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG1 2
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG2 4
+#define FW_CDEV_ISO_CONTEXT_MATCH_TAG3 8
+#define FW_CDEV_ISO_CONTEXT_MATCH_ALL_TAGS 15
+
+struct fw_cdev_create_iso_context {
+ __u32 type;
+ __u32 header_size;
+ __u32 channel;
+ __u32 speed;
+ __u64 closure;
+ __u32 handle;
+};
+
+struct fw_cdev_iso_packet {
+ __u16 payload_length; /* Length of indirect payload. */
+ __u32 interrupt : 1; /* Generate interrupt on this packet */
+ __u32 skip : 1; /* Set to not send packet at all. */
+ __u32 tag : 2;
+ __u32 sy : 4;
+ __u32 header_length : 8; /* Length of immediate header. */
+ __u32 header[0];
+};
+
+struct fw_cdev_queue_iso {
+ __u64 packets;
+ __u64 data;
+ __u32 size;
+ __u32 handle;
+};
+
+struct fw_cdev_start_iso {
+ __s32 cycle;
+ __u32 sync;
+ __u32 tags;
+ __u32 handle;
+};
+
+struct fw_cdev_stop_iso {
+ __u32 handle;
+};
+
+#endif /* _LINUX_FIREWIRE_CDEV_H */
diff --git a/include/linux/firewire-constants.h b/include/linux/firewire-constants.h
new file mode 100644
index 0000000..b316770
--- /dev/null
+++ b/include/linux/firewire-constants.h
@@ -0,0 +1,67 @@
+#ifndef _LINUX_FIREWIRE_CONSTANTS_H
+#define _LINUX_FIREWIRE_CONSTANTS_H
+
+#define TCODE_WRITE_QUADLET_REQUEST 0x0
+#define TCODE_WRITE_BLOCK_REQUEST 0x1
+#define TCODE_WRITE_RESPONSE 0x2
+#define TCODE_READ_QUADLET_REQUEST 0x4
+#define TCODE_READ_BLOCK_REQUEST 0x5
+#define TCODE_READ_QUADLET_RESPONSE 0x6
+#define TCODE_READ_BLOCK_RESPONSE 0x7
+#define TCODE_CYCLE_START 0x8
+#define TCODE_LOCK_REQUEST 0x9
+#define TCODE_STREAM_DATA 0xa
+#define TCODE_LOCK_RESPONSE 0xb
+
+#define EXTCODE_MASK_SWAP 0x1
+#define EXTCODE_COMPARE_SWAP 0x2
+#define EXTCODE_FETCH_ADD 0x3
+#define EXTCODE_LITTLE_ADD 0x4
+#define EXTCODE_BOUNDED_ADD 0x5
+#define EXTCODE_WRAP_ADD 0x6
+#define EXTCODE_VENDOR_DEPENDENT 0x7
+
+/* Juju specific tcodes */
+#define TCODE_LOCK_MASK_SWAP (0x10 | EXTCODE_MASK_SWAP)
+#define TCODE_LOCK_COMPARE_SWAP (0x10 | EXTCODE_COMPARE_SWAP)
+#define TCODE_LOCK_FETCH_ADD (0x10 | EXTCODE_FETCH_ADD)
+#define TCODE_LOCK_LITTLE_ADD (0x10 | EXTCODE_LITTLE_ADD)
+#define TCODE_LOCK_BOUNDED_ADD (0x10 | EXTCODE_BOUNDED_ADD)
+#define TCODE_LOCK_WRAP_ADD (0x10 | EXTCODE_WRAP_ADD)
+#define TCODE_LOCK_VENDOR_DEPENDENT (0x10 | EXTCODE_VENDOR_DEPENDENT)
+
+#define RCODE_COMPLETE 0x0
+#define RCODE_CONFLICT_ERROR 0x4
+#define RCODE_DATA_ERROR 0x5
+#define RCODE_TYPE_ERROR 0x6
+#define RCODE_ADDRESS_ERROR 0x7
+
+/* Juju specific rcodes */
+#define RCODE_SEND_ERROR 0x10
+#define RCODE_CANCELLED 0x11
+#define RCODE_BUSY 0x12
+#define RCODE_GENERATION 0x13
+#define RCODE_NO_ACK 0x14
+
+#define SCODE_100 0x0
+#define SCODE_200 0x1
+#define SCODE_400 0x2
+#define SCODE_800 0x3
+#define SCODE_1600 0x4
+#define SCODE_3200 0x5
+#define SCODE_BETA 0x3
+
+#define ACK_COMPLETE 0x1
+#define ACK_PENDING 0x2
+#define ACK_BUSY_X 0x4
+#define ACK_BUSY_A 0x5
+#define ACK_BUSY_B 0x6
+#define ACK_DATA_ERROR 0xd
+#define ACK_TYPE_ERROR 0xe
+
+#define RETRY_1 0x00
+#define RETRY_X 0x01
+#define RETRY_A 0x02
+#define RETRY_B 0x03
+
+#endif /* _LINUX_FIREWIRE_CONSTANTS_H */
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index f589559..4c03ee3 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -434,6 +434,10 @@
#endif
-#endif
+#else /* CONFIG_BLOCK */
+
+static inline void printk_all_partitions(void) { }
+
+#endif /* CONFIG_BLOCK */
#endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 37076b1..827ee74 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -275,6 +275,7 @@
#define HID_QUIRK_LOGITECH_DESCRIPTOR 0x00100000
#define HID_QUIRK_DUPLICATE_USAGES 0x00200000
#define HID_QUIRK_RESET_LEDS 0x00400000
+#define HID_QUIRK_SWAPPED_MIN_MAX 0x00800000
/*
* This is the global environment of the parser. This information is
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 45170b2..276ccaa 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -65,9 +65,9 @@
.posix_timers = LIST_HEAD_INIT(sig.posix_timers), \
.cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \
.rlim = INIT_RLIMITS, \
- .pgrp = 1, \
+ .pgrp = 0, \
.tty_old_pgrp = NULL, \
- { .__session = 1}, \
+ { .__session = 0}, \
}
extern struct nsproxy init_nsproxy;
@@ -84,10 +84,33 @@
.count = ATOMIC_INIT(1), \
.action = { { { .sa_handler = NULL, } }, }, \
.siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \
+ .signalfd_list = LIST_HEAD_INIT(sighand.signalfd_list), \
}
extern struct group_info init_groups;
+#define INIT_STRUCT_PID { \
+ .count = ATOMIC_INIT(1), \
+ .nr = 0, \
+ /* Don't put this struct pid in pid_hash */ \
+ .pid_chain = { .next = NULL, .pprev = NULL }, \
+ .tasks = { \
+ { .first = &init_task.pids[PIDTYPE_PID].node }, \
+ { .first = &init_task.pids[PIDTYPE_PGID].node }, \
+ { .first = &init_task.pids[PIDTYPE_SID].node }, \
+ }, \
+ .rcu = RCU_HEAD_INIT, \
+}
+
+#define INIT_PID_LINK(type) \
+{ \
+ .node = { \
+ .next = NULL, \
+ .pprev = &init_struct_pid.tasks[type].first, \
+ }, \
+ .pid = &init_struct_pid, \
+}
+
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -139,6 +162,11 @@
.cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
.fs_excl = ATOMIC_INIT(0), \
.pi_lock = __SPIN_LOCK_UNLOCKED(tsk.pi_lock), \
+ .pids = { \
+ [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \
+ [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \
+ [PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID), \
+ }, \
INIT_TRACE_IRQFLAGS \
INIT_LOCKDEP \
}
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index f7b01b9..5323f62 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -241,6 +241,16 @@
#define save_and_cli(x) save_and_cli(&x)
#endif /* CONFIG_SMP */
+/* Some architectures might implement lazy enabling/disabling of
+ * interrupts. In some cases, such as stop_machine, we might want
+ * to ensure that after a local_irq_disable(), interrupts have
+ * really been disabled in hardware. Such architectures need to
+ * implement the following hook.
+ */
+#ifndef hard_irq_disable
+#define hard_irq_disable() do { } while(0)
+#endif
+
/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
frequency threaded job scheduling. For almost all the purposes
tasklets are more than enough. F.e. all serial device BHs et
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 144b615..eec0d13 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -41,6 +41,16 @@
#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+/**
+ * upper_32_bits - return bits 32-63 of a number
+ * @n: the number we're accessing
+ *
+ * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress
+ * the "right shift count >= width of type" warning when that quantity is
+ * 32-bits.
+ */
+#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16))
+
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
@@ -203,6 +213,17 @@
extern void dump_stack(void);
+enum {
+ DUMP_PREFIX_NONE,
+ DUMP_PREFIX_ADDRESS,
+ DUMP_PREFIX_OFFSET
+};
+extern void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
+ size_t linebuflen);
+extern void print_hex_dump(const char *level, int prefix_type,
+ void *buf, size_t len);
+#define hex_asc(x) "0123456789abcdef"[x]
+
#ifdef DEBUG
/* If you are writing a driver, please use dev_dbg instead */
#define pr_debug(fmt,arg...) \
diff --git a/include/linux/magic.h b/include/linux/magic.h
index a9c6567..9d713c0 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -14,6 +14,7 @@
#define ISOFS_SUPER_MAGIC 0x9660
#define JFFS2_SUPER_MAGIC 0x72b6
#define KVMFS_SUPER_MAGIC 0x19700426
+#define ANON_INODE_FS_MAGIC 0x09041934
#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */
#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index e30687b..d5bb179 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -50,13 +50,16 @@
spinlock_t ptl;
#endif
struct { /* SLUB uses */
- struct page *first_page; /* Compound pages */
+ void **lockless_freelist;
struct kmem_cache *slab; /* Pointer to slab */
};
+ struct {
+ struct page *first_page; /* Compound pages */
+ };
};
union {
pgoff_t index; /* Our offset within mapping. */
- void *freelist; /* SLUB: pointer to free object */
+ void *freelist; /* SLUB: freelist req. slab lock */
};
struct list_head lru; /* Pageout list, eg. active_list
* protected by zone->lru_lock !
diff --git a/include/linux/module.h b/include/linux/module.h
index 792d483..e6e0f86 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -124,7 +124,7 @@
*/
#define MODULE_LICENSE(_license) MODULE_INFO(license, _license)
-/* Author, ideally of form NAME <EMAIL>[, NAME <EMAIL>]*[ and NAME <EMAIL>] */
+/* Author, ideally of form NAME[, NAME]*[ and NAME] */
#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
/* What your module does. */
diff --git a/include/linux/mpage.h b/include/linux/mpage.h
index cc5fb75..068a0c9 100644
--- a/include/linux/mpage.h
+++ b/include/linux/mpage.h
@@ -12,7 +12,6 @@
#ifdef CONFIG_BLOCK
struct writeback_control;
-typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
int mpage_readpages(struct address_space *mapping, struct list_head *pages,
unsigned nr_pages, get_block_t get_block);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 3044622..f671cd2 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -467,6 +467,8 @@
/* device index hash chain */
struct hlist_node index_hlist;
+ struct net_device *link_watch_next;
+
/* register/unregister state machine */
enum { NETREG_UNINITIALIZED=0,
NETREG_REGISTERED, /* completed register_netdevice */
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 022edfa..7e733a6 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -54,6 +54,14 @@
unsigned char data[0];
};
+#define XT_TARGET_INIT(__name, __size) \
+{ \
+ .target.u.user = { \
+ .target_size = XT_ALIGN(__size), \
+ .name = __name, \
+ }, \
+}
+
struct xt_standard_target
{
struct xt_entry_target target;
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index 24c8786d..584cd1b 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -238,6 +238,47 @@
*/
#ifdef __KERNEL__
+/* Standard entry. */
+struct arpt_standard
+{
+ struct arpt_entry entry;
+ struct arpt_standard_target target;
+};
+
+struct arpt_error_target
+{
+ struct arpt_entry_target target;
+ char errorname[ARPT_FUNCTION_MAXNAMELEN];
+};
+
+struct arpt_error
+{
+ struct arpt_entry entry;
+ struct arpt_error_target target;
+};
+
+#define ARPT_ENTRY_INIT(__size) \
+{ \
+ .target_offset = sizeof(struct arpt_entry), \
+ .next_offset = (__size), \
+}
+
+#define ARPT_STANDARD_INIT(__verdict) \
+{ \
+ .entry = ARPT_ENTRY_INIT(sizeof(struct arpt_standard)), \
+ .target = XT_TARGET_INIT(ARPT_STANDARD_TARGET, \
+ sizeof(struct arpt_standard_target)), \
+ .target.verdict = -(__verdict) - 1, \
+}
+
+#define ARPT_ERROR_INIT \
+{ \
+ .entry = ARPT_ENTRY_INIT(sizeof(struct arpt_error)), \
+ .target = XT_TARGET_INIT(ARPT_ERROR_TARGET, \
+ sizeof(struct arpt_error_target)), \
+ .target.errorname = "ERROR", \
+}
+
#define arpt_register_target(tgt) \
({ (tgt)->family = NF_ARP; \
xt_register_target(tgt); })
diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h
index 9527296..2f46dd7 100644
--- a/include/linux/netfilter_ipv4/ip_tables.h
+++ b/include/linux/netfilter_ipv4/ip_tables.h
@@ -295,6 +295,28 @@
struct ipt_error_target target;
};
+#define IPT_ENTRY_INIT(__size) \
+{ \
+ .target_offset = sizeof(struct ipt_entry), \
+ .next_offset = (__size), \
+}
+
+#define IPT_STANDARD_INIT(__verdict) \
+{ \
+ .entry = IPT_ENTRY_INIT(sizeof(struct ipt_standard)), \
+ .target = XT_TARGET_INIT(IPT_STANDARD_TARGET, \
+ sizeof(struct xt_standard_target)), \
+ .target.verdict = -(__verdict) - 1, \
+}
+
+#define IPT_ERROR_INIT \
+{ \
+ .entry = IPT_ENTRY_INIT(sizeof(struct ipt_error)), \
+ .target = XT_TARGET_INIT(IPT_ERROR_TARGET, \
+ sizeof(struct ipt_error_target)), \
+ .target.errorname = "ERROR", \
+}
+
extern unsigned int ipt_do_table(struct sk_buff **pskb,
unsigned int hook,
const struct net_device *in,
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h
index 61aa104..4686f83 100644
--- a/include/linux/netfilter_ipv6/ip6_tables.h
+++ b/include/linux/netfilter_ipv6/ip6_tables.h
@@ -123,6 +123,28 @@
struct ip6t_error_target target;
};
+#define IP6T_ENTRY_INIT(__size) \
+{ \
+ .target_offset = sizeof(struct ip6t_entry), \
+ .next_offset = (__size), \
+}
+
+#define IP6T_STANDARD_INIT(__verdict) \
+{ \
+ .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_standard)), \
+ .target = XT_TARGET_INIT(IP6T_STANDARD_TARGET, \
+ sizeof(struct ip6t_standard_target)), \
+ .target.verdict = -(__verdict) - 1, \
+}
+
+#define IP6T_ERROR_INIT \
+{ \
+ .entry = IP6T_ENTRY_INIT(sizeof(struct ip6t_error)), \
+ .target = XT_TARGET_INIT(IP6T_ERROR_TARGET, \
+ sizeof(struct ip6t_error_target)), \
+ .target.errorname = "ERROR", \
+}
+
/*
* New IP firewall options for [gs]etsockopt at the RAW IP level.
* Unlike BSD Linux inherits IP options so you don't have to use
diff --git a/include/linux/pid.h b/include/linux/pid.h
index 2ac27f9..1e0e4e3 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -51,6 +51,8 @@
struct rcu_head rcu;
};
+extern struct pid init_struct_pid;
+
struct pid_link
{
struct hlist_node node;
@@ -76,8 +78,7 @@
* write-held.
*/
extern int FASTCALL(attach_pid(struct task_struct *task,
- enum pid_type type, int nr));
-
+ enum pid_type type, struct pid *pid));
extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type));
extern void FASTCALL(transfer_pid(struct task_struct *old,
struct task_struct *new, enum pid_type));
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 37ca573..5ad913f 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -226,7 +226,7 @@
extern void pmu_backlight_init(void);
/* some code needs to know if the PMU was suspended for hibernation */
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
extern int pmu_sys_suspended;
#else
/* if power management is not configured it can't be suspended */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 17b72d8..a81897e 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -88,6 +88,7 @@
struct exec_domain;
struct futex_pi_state;
+struct bio;
/*
* List of flags we want to share for kernel threads,
@@ -391,6 +392,7 @@
atomic_t count;
struct k_sigaction action[_NSIG];
spinlock_t siglock;
+ struct list_head signalfd_list;
};
struct pacct_struct {
@@ -469,6 +471,7 @@
cputime_t utime, stime, cutime, cstime;
unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw;
unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt;
+ unsigned long inblock, oublock, cinblock, coublock;
/*
* Cumulative ns of scheduled CPU time for dead threads in the
@@ -1014,6 +1017,9 @@
/* journalling filesystem info */
void *journal_info;
+/* stacked block device info */
+ struct bio *bio_list, **bio_tail;
+
/* VM state */
struct reclaim_state *reclaim_state;
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 3fa0fab..9a5eac5 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -233,6 +233,7 @@
return sig <= _NSIG ? 1 : 0;
}
+extern int next_signal(struct sigpending *pending, sigset_t *mask);
extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
extern long do_sigpending(void __user *, unsigned long);
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h
new file mode 100644
index 0000000..5104294
--- /dev/null
+++ b/include/linux/signalfd.h
@@ -0,0 +1,97 @@
+/*
+ * include/linux/signalfd.h
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_SIGNALFD_H
+#define _LINUX_SIGNALFD_H
+
+
+struct signalfd_siginfo {
+ __u32 signo;
+ __s32 err;
+ __s32 code;
+ __u32 pid;
+ __u32 uid;
+ __s32 fd;
+ __u32 tid;
+ __u32 band;
+ __u32 overrun;
+ __u32 trapno;
+ __s32 status;
+ __s32 svint;
+ __u64 svptr;
+ __u64 utime;
+ __u64 stime;
+ __u64 addr;
+
+ /*
+ * Pad strcture to 128 bytes. Remember to update the
+ * pad size when you add new memebers. We use a fixed
+ * size structure to avoid compatibility problems with
+ * future versions, and we leave extra space for additional
+ * members. We use fixed size members because this strcture
+ * comes out of a read(2) and we really don't want to have
+ * a compat on read(2).
+ */
+ __u8 __pad[48];
+};
+
+
+#ifdef __KERNEL__
+
+#ifdef CONFIG_SIGNALFD
+
+/*
+ * Deliver the signal to listening signalfd. This must be called
+ * with the sighand lock held. Same are the following that end up
+ * calling signalfd_deliver().
+ */
+void signalfd_deliver(struct task_struct *tsk, int sig);
+
+/*
+ * No need to fall inside signalfd_deliver() if no signal listeners
+ * are available.
+ */
+static inline void signalfd_notify(struct task_struct *tsk, int sig)
+{
+ if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
+ signalfd_deliver(tsk, sig);
+}
+
+/*
+ * The signal -1 is used to notify the signalfd that the sighand
+ * is on its way to be detached.
+ */
+static inline void signalfd_detach_locked(struct task_struct *tsk)
+{
+ if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
+ signalfd_deliver(tsk, -1);
+}
+
+static inline void signalfd_detach(struct task_struct *tsk)
+{
+ struct sighand_struct *sighand = tsk->sighand;
+
+ if (unlikely(!list_empty(&sighand->signalfd_list))) {
+ spin_lock_irq(&sighand->siglock);
+ signalfd_deliver(tsk, -1);
+ spin_unlock_irq(&sighand->siglock);
+ }
+}
+
+#else /* CONFIG_SIGNALFD */
+
+#define signalfd_deliver(t, s) do { } while (0)
+#define signalfd_notify(t, s) do { } while (0)
+#define signalfd_detach_locked(t) do { } while (0)
+#define signalfd_detach(t) do { } while (0)
+
+#endif /* CONFIG_SIGNALFD */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SIGNALFD_H */
+
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index c8b0426..5562fbf 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -291,4 +291,28 @@
#define MGSL_IOCGGPIO _IOR(MGSL_MAGIC_IOC,17,struct gpio_desc)
#define MGSL_IOCWAITGPIO _IOWR(MGSL_MAGIC_IOC,18,struct gpio_desc)
+#ifdef __KERNEL__
+/* provide 32 bit ioctl compatibility on 64 bit systems */
+#ifdef CONFIG_COMPAT
+#include <linux/compat.h>
+struct MGSL_PARAMS32 {
+ compat_ulong_t mode;
+ unsigned char loopback;
+ unsigned short flags;
+ unsigned char encoding;
+ compat_ulong_t clock_speed;
+ unsigned char addr_filter;
+ unsigned short crc_type;
+ unsigned char preamble_length;
+ unsigned char preamble;
+ compat_ulong_t data_rate;
+ unsigned char data_bits;
+ unsigned char stop_bits;
+ unsigned char parity;
+};
+#define MGSL_IOCSPARAMS32 _IOW(MGSL_MAGIC_IOC,0,struct MGSL_PARAMS32)
+#define MGSL_IOCGPARAMS32 _IOR(MGSL_MAGIC_IOC,1,struct MGSL_PARAMS32)
+#endif
+#endif
+
#endif /* _SYNCLINK_H_ */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3139f44..b02070e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -604,6 +604,10 @@
asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
size_t len);
asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
+asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+ const struct itimerspec __user *utmr);
+asmlinkage long sys_eventfd(unsigned int count);
int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
diff --git a/include/linux/task_io_accounting_ops.h b/include/linux/task_io_accounting_ops.h
index df2a319..1218733 100644
--- a/include/linux/task_io_accounting_ops.h
+++ b/include/linux/task_io_accounting_ops.h
@@ -10,11 +10,29 @@
current->ioac.read_bytes += bytes;
}
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+ return p->ioac.read_bytes >> 9;
+}
+
static inline void task_io_account_write(size_t bytes)
{
current->ioac.write_bytes += bytes;
}
+/*
+ * We approximate number of blocks, because we account bytes only.
+ * A 'block' is 512 bytes
+ */
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+ return p->ioac.write_bytes >> 9;
+}
+
static inline void task_io_account_cancelled_write(size_t bytes)
{
current->ioac.cancelled_write_bytes += bytes;
@@ -31,10 +49,20 @@
{
}
+static inline unsigned long task_io_get_inblock(const struct task_struct *p)
+{
+ return 0;
+}
+
static inline void task_io_account_write(size_t bytes)
{
}
+static inline unsigned long task_io_get_oublock(const struct task_struct *p)
+{
+ return 0;
+}
+
static inline void task_io_account_cancelled_write(size_t bytes)
{
}
diff --git a/include/linux/timerfd.h b/include/linux/timerfd.h
new file mode 100644
index 0000000..cf2b10d
--- /dev/null
+++ b/include/linux/timerfd.h
@@ -0,0 +1,17 @@
+/*
+ * include/linux/timerfd.h
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _LINUX_TIMERFD_H
+#define _LINUX_TIMERFD_H
+
+
+#define TFD_TIMER_ABSTIME (1 << 0)
+
+
+
+#endif /* _LINUX_TIMERFD_H */
+
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 659487e..85c95cd 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -52,6 +52,11 @@
* This routine allows the tty driver to implement
* device-specific ioctl's. If the ioctl number passed in cmd
* is not recognized by the driver, it should return ENOIOCTLCMD.
+ *
+ * long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+ * unsigned int cmd, unsigned long arg);
+ *
+ * implement ioctl processing for 32 bit process on 64 bit system
*
* void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
@@ -132,6 +137,8 @@
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
+ long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
@@ -193,6 +200,8 @@
int (*chars_in_buffer)(struct tty_struct *tty);
int (*ioctl)(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg);
+ long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
void (*throttle)(struct tty_struct * tty);
void (*unthrottle)(struct tty_struct * tty);
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index d75932e..6226504 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -59,6 +59,11 @@
* low-level driver can "grab" an ioctl request before the line
* discpline has a chance to see it.
*
+ * long (*compat_ioctl)(struct tty_struct * tty, struct file * file,
+ * unsigned int cmd, unsigned long arg);
+ *
+ * Process ioctl calls from 32-bit process on 64-bit system
+ *
* void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
* This function notifies the line discpline that a change has
@@ -118,6 +123,8 @@
const unsigned char * buf, size_t nr);
int (*ioctl)(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg);
+ long (*compat_ioctl)(struct tty_struct * tty, struct file * file,
+ unsigned int cmd, unsigned long arg);
void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
unsigned int (*poll)(struct tty_struct *, struct file *,
struct poll_table_struct *);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index daa6c12..050915b 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -111,9 +111,15 @@
balance_dirty_pages_ratelimited_nr(mapping, 1);
}
+typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc,
+ void *data);
+
int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
-extern int generic_writepages(struct address_space *mapping,
- struct writeback_control *wbc);
+int generic_writepages(struct address_space *mapping,
+ struct writeback_control *wbc);
+int write_cache_pages(struct address_space *mapping,
+ struct writeback_control *wbc, writepage_t writepage,
+ void *data);
int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
int sync_page_range(struct inode *inode, struct address_space *mapping,
loff_t pos, loff_t count);
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 1c6b8bd..4732432 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -183,13 +183,6 @@
extern void nf_conntrack_flush(void);
-extern struct nf_conntrack_helper *
-nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
-extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
-
-extern struct nf_conntrack_helper *
-__nf_conntrack_helper_find_byname(const char *name);
-
extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_tuple *orig);
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index f32f714..96a58d8 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -56,9 +56,6 @@
*/
int (*new)(struct nf_conn *conntrack, const struct sk_buff *skb);
- /* Called when a conntrack entry is destroyed */
- void (*destroy)(struct nf_conn *conntrack);
-
/*
* Called before tracking.
* *dataoff: offset of protocol header (TCP, UDP,...) in *pskb
diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h
index e765654..f974318 100644
--- a/include/net/netfilter/nf_nat_rule.h
+++ b/include/net/netfilter/nf_nat_rule.h
@@ -10,16 +10,11 @@
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
- struct nf_conn *ct,
- struct nf_nat_info *info);
+ struct nf_conn *ct);
extern unsigned int
-alloc_null_binding(struct nf_conn *ct,
- struct nf_nat_info *info,
- unsigned int hooknum);
+alloc_null_binding(struct nf_conn *ct, unsigned int hooknum);
extern unsigned int
-alloc_null_binding_confirmed(struct nf_conn *ct,
- struct nf_nat_info *info,
- unsigned int hooknum);
+alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum);
#endif /* _NF_NAT_RULE_H */
diff --git a/include/net/udp.h b/include/net/udp.h
index 98755eb..496f89d 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -119,9 +119,16 @@
}
+struct udp_get_port_ops {
+ int (*saddr_cmp)(const struct sock *sk1, const struct sock *sk2);
+ int (*saddr_any)(const struct sock *sk);
+ unsigned int (*hash_port_and_rcv_saddr)(__u16 port,
+ const struct sock *sk);
+};
+
/* net/ipv4/udp.c */
extern int udp_get_port(struct sock *sk, unsigned short snum,
- int (*saddr_cmp)(const struct sock *, const struct sock *));
+ const struct udp_get_port_ops *ops);
extern void udp_err(struct sk_buff *, u32);
extern int udp_sendmsg(struct kiocb *iocb, struct sock *sk,
diff --git a/include/net/udplite.h b/include/net/udplite.h
index 635b0ea..50b4b42 100644
--- a/include/net/udplite.h
+++ b/include/net/udplite.h
@@ -120,5 +120,5 @@
extern void udplite4_register(void);
extern int udplite_get_port(struct sock *sk, unsigned short snum,
- int (*scmp)(const struct sock *, const struct sock *));
+ const struct udp_get_port_ops *ops);
#endif /* _UDPLITE_H */
diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h
new file mode 100644
index 0000000..4eea637
--- /dev/null
+++ b/include/video/atmel_lcdc.h
@@ -0,0 +1,196 @@
+/*
+ * Header file for AT91/AT32 LCD Controller
+ *
+ * Data structure and register user interface
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#ifndef __ATMEL_LCDC_H__
+#define __ATMEL_LCDC_H__
+
+ /* LCD Controller info data structure */
+struct atmel_lcdfb_info {
+ spinlock_t lock;
+ struct fb_info *info;
+ void __iomem *mmio;
+ unsigned long irq_base;
+
+ unsigned int guard_time;
+ struct platform_device *pdev;
+ struct clk *bus_clk;
+ struct clk *lcdc_clk;
+ unsigned int default_bpp;
+ unsigned int default_lcdcon2;
+ unsigned int default_dmacon;
+ void (*atmel_lcdfb_power_control)(int on);
+ struct fb_monspecs *default_monspecs;
+ u32 pseudo_palette[16];
+};
+
+#define ATMEL_LCDC_DMABADDR1 0x00
+#define ATMEL_LCDC_DMABADDR2 0x04
+#define ATMEL_LCDC_DMAFRMPT1 0x08
+#define ATMEL_LCDC_DMAFRMPT2 0x0c
+#define ATMEL_LCDC_DMAFRMADD1 0x10
+#define ATMEL_LCDC_DMAFRMADD2 0x14
+
+#define ATMEL_LCDC_DMAFRMCFG 0x18
+#define ATMEL_LCDC_FRSIZE (0x7fffff << 0)
+#define ATMEL_LCDC_BLENGTH_OFFSET 24
+#define ATMEL_LCDC_BLENGTH (0x7f << ATMEL_LCDC_BLENGTH_OFFSET)
+
+#define ATMEL_LCDC_DMACON 0x1c
+#define ATMEL_LCDC_DMAEN (0x1 << 0)
+#define ATMEL_LCDC_DMARST (0x1 << 1)
+#define ATMEL_LCDC_DMABUSY (0x1 << 2)
+#define ATMEL_LCDC_DMAUPDT (0x1 << 3)
+#define ATMEL_LCDC_DMA2DEN (0x1 << 4)
+
+#define ATMEL_LCDC_DMA2DCFG 0x20
+#define ATMEL_LCDC_ADDRINC_OFFSET 0
+#define ATMEL_LCDC_ADDRINC (0xffff)
+#define ATMEL_LCDC_PIXELOFF_OFFSET 24
+#define ATMEL_LCDC_PIXELOFF (0x1f << 24)
+
+#define ATMEL_LCDC_LCDCON1 0x0800
+#define ATMEL_LCDC_BYPASS (1 << 0)
+#define ATMEL_LCDC_CLKVAL_OFFSET 12
+#define ATMEL_LCDC_CLKVAL (0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
+#define ATMEL_LCDC_LINCNT (0x7ff << 21)
+
+#define ATMEL_LCDC_LCDCON2 0x0804
+#define ATMEL_LCDC_DISTYPE (3 << 0)
+#define ATMEL_LCDC_DISTYPE_STNMONO (0 << 0)
+#define ATMEL_LCDC_DISTYPE_STNCOLOR (1 << 0)
+#define ATMEL_LCDC_DISTYPE_TFT (2 << 0)
+#define ATMEL_LCDC_SCANMOD (1 << 2)
+#define ATMEL_LCDC_SCANMOD_SINGLE (0 << 2)
+#define ATMEL_LCDC_SCANMOD_DUAL (1 << 2)
+#define ATMEL_LCDC_IFWIDTH (3 << 3)
+#define ATMEL_LCDC_IFWIDTH_4 (0 << 3)
+#define ATMEL_LCDC_IFWIDTH_8 (1 << 3)
+#define ATMEL_LCDC_IFWIDTH_16 (2 << 3)
+#define ATMEL_LCDC_PIXELSIZE (7 << 5)
+#define ATMEL_LCDC_PIXELSIZE_1 (0 << 5)
+#define ATMEL_LCDC_PIXELSIZE_2 (1 << 5)
+#define ATMEL_LCDC_PIXELSIZE_4 (2 << 5)
+#define ATMEL_LCDC_PIXELSIZE_8 (3 << 5)
+#define ATMEL_LCDC_PIXELSIZE_16 (4 << 5)
+#define ATMEL_LCDC_PIXELSIZE_24 (5 << 5)
+#define ATMEL_LCDC_PIXELSIZE_32 (6 << 5)
+#define ATMEL_LCDC_INVVD (1 << 8)
+#define ATMEL_LCDC_INVVD_NORMAL (0 << 8)
+#define ATMEL_LCDC_INVVD_INVERTED (1 << 8)
+#define ATMEL_LCDC_INVFRAME (1 << 9 )
+#define ATMEL_LCDC_INVFRAME_NORMAL (0 << 9)
+#define ATMEL_LCDC_INVFRAME_INVERTED (1 << 9)
+#define ATMEL_LCDC_INVLINE (1 << 10)
+#define ATMEL_LCDC_INVLINE_NORMAL (0 << 10)
+#define ATMEL_LCDC_INVLINE_INVERTED (1 << 10)
+#define ATMEL_LCDC_INVCLK (1 << 11)
+#define ATMEL_LCDC_INVCLK_NORMAL (0 << 11)
+#define ATMEL_LCDC_INVCLK_INVERTED (1 << 11)
+#define ATMEL_LCDC_INVDVAL (1 << 12)
+#define ATMEL_LCDC_INVDVAL_NORMAL (0 << 12)
+#define ATMEL_LCDC_INVDVAL_INVERTED (1 << 12)
+#define ATMEL_LCDC_CLKMOD (1 << 15)
+#define ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY (0 << 15)
+#define ATMEL_LCDC_CLKMOD_ALWAYSACTIVE (1 << 15)
+#define ATMEL_LCDC_MEMOR (1 << 31)
+#define ATMEL_LCDC_MEMOR_BIG (0 << 31)
+#define ATMEL_LCDC_MEMOR_LITTLE (1 << 31)
+
+#define ATMEL_LCDC_TIM1 0x0808
+#define ATMEL_LCDC_VFP (0xff << 0)
+#define ATMEL_LCDC_VBP_OFFSET 8
+#define ATMEL_LCDC_VBP (0xff << ATMEL_LCDC_VBP_OFFSET)
+#define ATMEL_LCDC_VPW_OFFSET 16
+#define ATMEL_LCDC_VPW (0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define ATMEL_LCDC_VHDLY_OFFSET 24
+#define ATMEL_LCDC_VHDLY (0xf << ATMEL_LCDC_VHDLY_OFFSET)
+
+#define ATMEL_LCDC_TIM2 0x080c
+#define ATMEL_LCDC_HBP (0xff << 0)
+#define ATMEL_LCDC_HPW_OFFSET 8
+#define ATMEL_LCDC_HPW (0x3f << ATMEL_LCDC_HPW_OFFSET)
+#define ATMEL_LCDC_HFP_OFFSET 21
+#define ATMEL_LCDC_HFP (0x7ff << ATMEL_LCDC_HFP_OFFSET)
+
+#define ATMEL_LCDC_LCDFRMCFG 0x0810
+#define ATMEL_LCDC_LINEVAL (0x7ff << 0)
+#define ATMEL_LCDC_HOZVAL_OFFSET 21
+#define ATMEL_LCDC_HOZVAL (0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
+
+#define ATMEL_LCDC_FIFO 0x0814
+#define ATMEL_LCDC_FIFOTH (0xffff)
+
+#define ATMEL_LCDC_MVAL 0x0818
+
+#define ATMEL_LCDC_DP1_2 0x081c
+#define ATMEL_LCDC_DP4_7 0x0820
+#define ATMEL_LCDC_DP3_5 0x0824
+#define ATMEL_LCDC_DP2_3 0x0828
+#define ATMEL_LCDC_DP5_7 0x082c
+#define ATMEL_LCDC_DP3_4 0x0830
+#define ATMEL_LCDC_DP4_5 0x0834
+#define ATMEL_LCDC_DP6_7 0x0838
+#define ATMEL_LCDC_DP1_2_VAL (0xff)
+#define ATMEL_LCDC_DP4_7_VAL (0xfffffff)
+#define ATMEL_LCDC_DP3_5_VAL (0xfffff)
+#define ATMEL_LCDC_DP2_3_VAL (0xfff)
+#define ATMEL_LCDC_DP5_7_VAL (0xfffffff)
+#define ATMEL_LCDC_DP3_4_VAL (0xffff)
+#define ATMEL_LCDC_DP4_5_VAL (0xfffff)
+#define ATMEL_LCDC_DP6_7_VAL (0xfffffff)
+
+#define ATMEL_LCDC_PWRCON 0x083c
+#define ATMEL_LCDC_PWR (1 << 0)
+#define ATMEL_LCDC_GUARDT_OFFSET 1
+#define ATMEL_LCDC_GUARDT (0x7f << ATMEL_LCDC_GUARDT_OFFSET)
+#define ATMEL_LCDC_BUSY (1 << 31)
+
+#define ATMEL_LCDC_CONTRAST_CTR 0x0840
+#define ATMEL_LCDC_PS (3 << 0)
+#define ATMEL_LCDC_PS_DIV1 (0 << 0)
+#define ATMEL_LCDC_PS_DIV2 (1 << 0)
+#define ATMEL_LCDC_PS_DIV4 (2 << 0)
+#define ATMEL_LCDC_PS_DIV8 (3 << 0)
+#define ATMEL_LCDC_POL (1 << 2)
+#define ATMEL_LCDC_POL_NEGATIVE (0 << 2)
+#define ATMEL_LCDC_POL_POSITIVE (1 << 2)
+#define ATMEL_LCDC_ENA (1 << 3)
+#define ATMEL_LCDC_ENA_PWMDISABLE (0 << 3)
+#define ATMEL_LCDC_ENA_PWMENABLE (1 << 3)
+
+#define ATMEL_LCDC_CONTRAST_VAL 0x0844
+#define ATMEL_LCDC_CVAL (0xff)
+
+#define ATMEL_LCDC_IER 0x0848
+#define ATMEL_LCDC_IDR 0x084c
+#define ATMEL_LCDC_IMR 0x0850
+#define ATMEL_LCDC_ISR 0x0854
+#define ATMEL_LCDC_ICR 0x0858
+#define ATMEL_LCDC_LNI (1 << 0)
+#define ATMEL_LCDC_LSTLNI (1 << 1)
+#define ATMEL_LCDC_EOFI (1 << 2)
+#define ATMEL_LCDC_UFLWI (1 << 4)
+#define ATMEL_LCDC_OWRI (1 << 5)
+#define ATMEL_LCDC_MERI (1 << 6)
+
+#define ATMEL_LCDC_LUT(n) (0x0c00 + ((n)*4))
+
+#endif /* __ATMEL_LCDC_H__ */
diff --git a/include/video/pm3fb.h b/include/video/pm3fb.h
index 94c7d2d..d52e45a 100644
--- a/include/video/pm3fb.h
+++ b/include/video/pm3fb.h
@@ -7,9 +7,6 @@
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
- *
- * $Header: /cvsroot/linux/drivers/video/pm3fb.h,v 1.1 2002/02/25 19:11:06 marcelo Exp $
- *
*/
#ifndef PM3FB_H
@@ -1119,117 +1116,10 @@
/* ***** pm3fb useful define and macro ***** */
/* ***************************************** */
-/* permedia3 -specific definitions */
-#define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po))))
-
-/* in case it's not in linux/pci.h */
-#ifndef PCI_DEVICE_ID_3DLABS_PERMEDIA3
-#define PCI_DEVICE_ID_3DLABS_PERMEDIA3 0x000a
-#endif
-
-/* max number of simultaneous board */
-#define PM3_MAX_BOARD 4
-
/* max size of options */
#define PM3_OPTIONS_SIZE 256
/* max size of font name */
#define PM3_FONTNAME_SIZE 40
-/* do we want accelerated console */
-#define PM3FB_USE_ACCEL 1
-
-/* for driver debugging ONLY */
-/* 0 = assert only, 1 = error, 2 = info, 3+ = verbose */
-/* define PM3FB_MASTER_DEBUG 1 */
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3)
-#define PM3FB_TRACE
-#endif /* defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 3) */
-
-#ifdef PM3FB_MASTER_DEBUG
-#define DPRINTK(l,a,b...) do { if ((l) <= PM3FB_MASTER_DEBUG) printk("pm3fb: %s: " a, __FUNCTION__ , ## b); } while (0)
-#define DASSERT(t,a,b...) do { if (!(t)) printk("pm3fb: _assert failed: %s: " a, __FUNCTION__ , ## b); } while (0)
-#ifdef PM3FB_TRACE
-#define DTRACE printk("pm3fb: _enter %s\n", __FUNCTION__)
-#else /* PM3FB_TRACE */
-#define DTRACE
-#endif /* PM3FB_TRACE */
-#else /* PM3FB_MASTER_DEBUG */
-#define DPRINTK(l,a,b...)
-#define DASSERT(t,a,b...)
-#define DTRACE
-#endif /* PM3FB_MASTER_DEBUG */
-
-#if defined(PM3FB_MASTER_DEBUG) && (PM3FB_MASTER_DEBUG >= 2)
-#define PM3_SHOW_CUR_MODE pm3fb_show_cur_mode(l_fb_info)
-#else
-#define PM3_SHOW_CUR_MODE /* pm3fb_show_cur_mode() */
-#endif
-
-/* ******************************************** */
-/* ***** A bunch of register-access macro ***** */
-/* ******************************************** */
-
-#define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r))
-#define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r))
-
-
-#define depth2bpp(d) ((d + 7L) & ~7L)
-#define depth2ByPP(d) (depth2bpp(d) / 8)
-
-#define depth_supported(d) ((d == 8) || (d == 12) || (d == 15) || (d == 16) || (d==32))
-
-
-#define PM3_WAIT(n) \
-do{ \
- while(PM3_READ_REG(PM3InFIFOSpace)<(n)); \
-} while(0)
-
-#define PM3_DELAY(x) do { \
- int delay = x; \
- unsigned char tmp; \
- while(delay--){tmp = PM3_READ_REG(PM3InFIFOSpace);}; \
-} while(0)
-
-#define PM3_SLOW_WRITE_REG(r,v) \
-do{ \
- DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in slow write\n"); \
- mb(); \
- PM3_WAIT(1); \
- mb(); \
- PM3_WRITE_REG(r,v); \
-} while(0)
-
-#define PM3_SET_INDEX(index) \
-do{ \
- PM3_SLOW_WRITE_REG(PM3RD_IndexHigh,(((index)>>8)&0xff)); \
- PM3_SLOW_WRITE_REG(PM3RD_IndexLow,((index)&0xff)); \
-} while(0)
-
-#define PM3_WRITE_DAC_REG(r, v) \
-do { \
- DASSERT((l_fb_info->vIOBase != (unsigned char*)(-1)), "l_fb_info->vIOBase mapped in write dac reg\n"); \
- PM3_SET_INDEX(r); \
- mb(); \
- PM3_WRITE_REG(PM3RD_IndexedData, v); \
-} while (0)
-
-/* next one is really a function, added as a macro to be consistent */
-#define PM3_READ_DAC_REG(r) pm3fb_read_dac_reg(l_fb_info, r)
-
-
-#define PM3_COLOR(c) \
-do { \
- if (l_fb_info->current_par->depth == 8) \
- { \
- c = (c & 0xFF); \
- c = c | (c << 8); \
- } \
- if ((l_fb_info->current_par->depth == 8) || (depth2bpp(l_fb_info->current_par->depth) == 16)) \
- { \
- c = (c & 0xFFFF); \
- c = c | (c << 16); \
- } \
-} while (0)
-
#endif /* PM3FB_H */
diff --git a/init/Kconfig b/init/Kconfig
index e63a017..4e009fd 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -475,13 +475,53 @@
support for "fast userspace mutexes". The resulting kernel may not
run glibc-based applications correctly.
+config ANON_INODES
+ bool "Enable anonymous inode source" if EMBEDDED
+ default y
+ help
+ Anonymous inode source for pseudo-files like epoll, signalfd,
+ timerfd and eventfd.
+
+ If unsure, say Y.
+
config EPOLL
bool "Enable eventpoll support" if EMBEDDED
default y
+ depends on ANON_INODES
help
Disabling this option will cause the kernel to be built without
support for epoll family of system calls.
+config SIGNALFD
+ bool "Enable signalfd() system call" if EMBEDDED
+ depends on ANON_INODES
+ default y
+ help
+ Enable the signalfd() system call that allows to receive signals
+ on a file descriptor.
+
+ If unsure, say Y.
+
+config TIMERFD
+ bool "Enable timerfd() system call" if EMBEDDED
+ depends on ANON_INODES
+ default y
+ help
+ Enable the timerfd() system call that allows to receive timer
+ events on a file descriptor.
+
+ If unsure, say Y.
+
+config EVENTFD
+ bool "Enable eventfd() system call" if EMBEDDED
+ depends on ANON_INODES
+ default y
+ help
+ Enable the eventfd() system call that allows to receive both
+ kernel notification (ie. KAIO) or userspace notifications.
+
+ If unsure, say Y.
+
config SHMEM
bool "Use full shmem filesystem" if EMBEDDED
default y
@@ -505,6 +545,7 @@
config SLUB_DEBUG
default y
bool "Enable SLUB debugging support" if EMBEDDED
+ depends on SLUB
help
SLUB has extensive debug support features. Disabling these can
result in significant savings in code size. This also disables
diff --git a/init/main.c b/init/main.c
index e8d080c..1940fa7 100644
--- a/init/main.c
+++ b/init/main.c
@@ -801,6 +801,7 @@
*/
init_pid_ns.child_reaper = current;
+ __set_special_pids(1, 1);
cad_pid = task_pid(current);
smp_prepare_cpus(max_cpus);
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index d17821d..fab5707 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -681,6 +681,7 @@
if (oflag & O_CREAT) {
if (dentry->d_inode) { /* entry already exists */
+ audit_inode(name, dentry->d_inode);
error = -EEXIST;
if (oflag & O_EXCL)
goto out;
@@ -693,6 +694,7 @@
error = -ENOENT;
if (!dentry->d_inode)
goto out;
+ audit_inode(name, dentry->d_inode);
filp = do_open(dentry, oflag);
}
@@ -840,6 +842,7 @@
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
+ audit_inode(NULL, inode);
if (unlikely(!(filp->f_mode & FMODE_WRITE)))
goto out_fput;
@@ -923,6 +926,7 @@
if (unlikely(filp->f_op != &mqueue_file_operations))
goto out_fput;
info = MQUEUE_I(inode);
+ audit_inode(NULL, inode);
if (unlikely(!(filp->f_mode & FMODE_READ)))
goto out_fput;
diff --git a/kernel/audit.h b/kernel/audit.h
index a337023..815d6f5 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -83,6 +83,7 @@
u32 field_count;
char *filterkey; /* ties events to rules */
struct audit_field *fields;
+ struct audit_field *arch_f; /* quick access to arch field */
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct list_head rlist; /* entry in audit_watch.rules list */
@@ -131,17 +132,19 @@
extern int selinux_audit_rule_update(void);
#ifdef CONFIG_AUDITSYSCALL
-extern void __audit_signal_info(int sig, struct task_struct *t);
-static inline void audit_signal_info(int sig, struct task_struct *t)
+extern int __audit_signal_info(int sig, struct task_struct *t);
+static inline int audit_signal_info(int sig, struct task_struct *t)
{
- if (unlikely(audit_pid && t->tgid == audit_pid))
- __audit_signal_info(sig, t);
+ if (unlikely((audit_pid && t->tgid == audit_pid) ||
+ (audit_signals && !audit_dummy_context())))
+ return __audit_signal_info(sig, t);
+ return 0;
}
extern enum audit_state audit_filter_inodes(struct task_struct *,
struct audit_context *);
extern void audit_set_auditable(struct audit_context *);
#else
-#define audit_signal_info(s,t)
+#define audit_signal_info(s,t) AUDIT_DISABLED
#define audit_filter_inodes(t,c) AUDIT_DISABLED
#define audit_set_auditable(c)
#endif
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 3749193..6c61263 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -311,6 +311,43 @@
return classes[class][AUDIT_WORD(syscall)] & AUDIT_BIT(syscall);
}
+static inline int audit_match_class_bits(int class, u32 *mask)
+{
+ int i;
+
+ if (classes[class]) {
+ for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
+ if (mask[i] & classes[class][i])
+ return 0;
+ }
+ return 1;
+}
+
+static int audit_match_signal(struct audit_entry *entry)
+{
+ struct audit_field *arch = entry->rule.arch_f;
+
+ if (!arch) {
+ /* When arch is unspecified, we must check both masks on biarch
+ * as syscall number alone is ambiguous. */
+ return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,
+ entry->rule.mask) &&
+ audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,
+ entry->rule.mask));
+ }
+
+ switch(audit_classify_arch(arch->val)) {
+ case 0: /* native */
+ return (audit_match_class_bits(AUDIT_CLASS_SIGNAL,
+ entry->rule.mask));
+ case 1: /* 32bit on biarch */
+ return (audit_match_class_bits(AUDIT_CLASS_SIGNAL_32,
+ entry->rule.mask));
+ default:
+ return 1;
+ }
+}
+
/* Common user-space to kernel rule translation. */
static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule)
{
@@ -429,6 +466,7 @@
err = -EINVAL;
goto exit_free;
}
+ entry->rule.arch_f = f;
break;
case AUDIT_PERM:
if (f->val & ~15)
@@ -519,7 +557,6 @@
case AUDIT_FSGID:
case AUDIT_LOGINUID:
case AUDIT_PERS:
- case AUDIT_ARCH:
case AUDIT_MSGTYPE:
case AUDIT_PPID:
case AUDIT_DEVMAJOR:
@@ -531,6 +568,9 @@
case AUDIT_ARG2:
case AUDIT_ARG3:
break;
+ case AUDIT_ARCH:
+ entry->rule.arch_f = f;
+ break;
case AUDIT_SUBJ_USER:
case AUDIT_SUBJ_ROLE:
case AUDIT_SUBJ_TYPE:
@@ -1221,6 +1261,9 @@
#ifdef CONFIG_AUDITSYSCALL
if (!dont_count)
audit_n_rules++;
+
+ if (!audit_match_signal(entry))
+ audit_signals++;
#endif
mutex_unlock(&audit_filter_mutex);
@@ -1294,6 +1337,9 @@
#ifdef CONFIG_AUDITSYSCALL
if (!dont_count)
audit_n_rules--;
+
+ if (!audit_match_signal(entry))
+ audit_signals--;
#endif
mutex_unlock(&audit_filter_mutex);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 628c7ac..e36481e 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -78,17 +78,15 @@
* for saving names from getname(). */
#define AUDIT_NAMES 20
-/* AUDIT_NAMES_RESERVED is the number of slots we reserve in the
- * audit_context from being used for nameless inodes from
- * path_lookup. */
-#define AUDIT_NAMES_RESERVED 7
-
/* Indicates that audit should log the full pathname. */
#define AUDIT_NAME_FULL -1
/* number of audit rules */
int audit_n_rules;
+/* determines whether we collect data for signals sent */
+int audit_signals;
+
/* When fs/namei.c:getname() is called, we store the pointer in name and
* we don't let putname() free it (instead we free all of the saved
* pointers at syscall exit time).
@@ -114,6 +112,9 @@
#define AUDIT_AUX_IPCPERM 0
+/* Number of target pids per aux struct. */
+#define AUDIT_AUX_PIDS 16
+
struct audit_aux_data_mq_open {
struct audit_aux_data d;
int oflag;
@@ -181,6 +182,13 @@
struct vfsmount *mnt;
};
+struct audit_aux_data_pids {
+ struct audit_aux_data d;
+ pid_t target_pid[AUDIT_AUX_PIDS];
+ u32 target_sid[AUDIT_AUX_PIDS];
+ int pid_count;
+};
+
/* The per-task audit context. */
struct audit_context {
int dummy; /* must be the first element */
@@ -201,6 +209,7 @@
struct vfsmount * pwdmnt;
struct audit_context *previous; /* For nested syscalls */
struct audit_aux_data *aux;
+ struct audit_aux_data *aux_pids;
/* Save things to print about task_struct */
pid_t pid, ppid;
@@ -209,6 +218,9 @@
unsigned long personality;
int arch;
+ pid_t target_pid;
+ u32 target_sid;
+
#if AUDIT_DEBUG
int put_count;
int ino_count;
@@ -654,6 +666,10 @@
context->aux = aux->next;
kfree(aux);
}
+ while ((aux = context->aux_pids)) {
+ context->aux_pids = aux->next;
+ kfree(aux);
+ }
}
static inline void audit_zero_context(struct audit_context *context,
@@ -795,6 +811,29 @@
audit_log_task_context(ab);
}
+static int audit_log_pid_context(struct audit_context *context, pid_t pid,
+ u32 sid)
+{
+ struct audit_buffer *ab;
+ char *s = NULL;
+ u32 len;
+ int rc = 0;
+
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
+ if (!ab)
+ return 1;
+
+ if (selinux_sid_to_string(sid, &s, &len)) {
+ audit_log_format(ab, "opid=%d obj=(none)", pid);
+ rc = 1;
+ } else
+ audit_log_format(ab, "opid=%d obj=%s", pid, s);
+ audit_log_end(ab);
+ kfree(s);
+
+ return rc;
+}
+
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
{
int i, call_panic = 0;
@@ -973,6 +1012,21 @@
audit_log_end(ab);
}
+ for (aux = context->aux_pids; aux; aux = aux->next) {
+ struct audit_aux_data_pids *axs = (void *)aux;
+ int i;
+
+ for (i = 0; i < axs->pid_count; i++)
+ if (audit_log_pid_context(context, axs->target_pid[i],
+ axs->target_sid[i]))
+ call_panic = 1;
+ }
+
+ if (context->target_pid &&
+ audit_log_pid_context(context, context->target_pid,
+ context->target_sid))
+ call_panic = 1;
+
if (context->pwd && context->pwdmnt) {
ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);
if (ab) {
@@ -1193,6 +1247,10 @@
} else {
audit_free_names(context);
audit_free_aux(context);
+ context->aux = NULL;
+ context->aux_pids = NULL;
+ context->target_pid = 0;
+ context->target_sid = 0;
kfree(context->filterkey);
context->filterkey = NULL;
tsk->audit_context = context;
@@ -1226,6 +1284,7 @@
context->names[context->name_count].name_len = AUDIT_NAME_FULL;
context->names[context->name_count].name_put = 1;
context->names[context->name_count].ino = (unsigned long)-1;
+ context->names[context->name_count].osid = 0;
++context->name_count;
if (!context->pwd) {
read_lock(¤t->fs->lock);
@@ -1279,6 +1338,28 @@
#endif
}
+static int audit_inc_name_count(struct audit_context *context,
+ const struct inode *inode)
+{
+ if (context->name_count >= AUDIT_NAMES) {
+ if (inode)
+ printk(KERN_DEBUG "name_count maxed, losing inode data: "
+ "dev=%02x:%02x, inode=%lu",
+ MAJOR(inode->i_sb->s_dev),
+ MINOR(inode->i_sb->s_dev),
+ inode->i_ino);
+
+ else
+ printk(KERN_DEBUG "name_count maxed, losing inode data");
+ return 1;
+ }
+ context->name_count++;
+#if AUDIT_DEBUG
+ context->ino_count++;
+#endif
+ return 0;
+}
+
/* Copy inode data into an audit_names. */
static void audit_copy_inode(struct audit_names *name, const struct inode *inode)
{
@@ -1316,13 +1397,10 @@
else {
/* FIXME: how much do we care about inodes that have no
* associated name? */
- if (context->name_count >= AUDIT_NAMES - AUDIT_NAMES_RESERVED)
+ if (audit_inc_name_count(context, inode))
return;
- idx = context->name_count++;
+ idx = context->name_count - 1;
context->names[idx].name = NULL;
-#if AUDIT_DEBUG
- ++context->ino_count;
-#endif
}
audit_copy_inode(&context->names[idx], inode);
}
@@ -1346,7 +1424,7 @@
{
int idx;
struct audit_context *context = current->audit_context;
- const char *found_name = NULL;
+ const char *found_parent = NULL, *found_child = NULL;
int dirlen = 0;
if (!context->in_syscall)
@@ -1354,88 +1432,73 @@
/* determine matching parent */
if (!dname)
- goto update_context;
- for (idx = 0; idx < context->name_count; idx++)
- if (context->names[idx].ino == parent->i_ino) {
- const char *name = context->names[idx].name;
+ goto add_names;
- if (!name)
- continue;
+ /* parent is more likely, look for it first */
+ for (idx = 0; idx < context->name_count; idx++) {
+ struct audit_names *n = &context->names[idx];
- if (audit_compare_dname_path(dname, name, &dirlen) == 0) {
- context->names[idx].name_len = dirlen;
- found_name = name;
- break;
- }
+ if (!n->name)
+ continue;
+
+ if (n->ino == parent->i_ino &&
+ !audit_compare_dname_path(dname, n->name, &dirlen)) {
+ n->name_len = dirlen; /* update parent data in place */
+ found_parent = n->name;
+ goto add_names;
}
-
-update_context:
- idx = context->name_count;
- if (context->name_count == AUDIT_NAMES) {
- printk(KERN_DEBUG "name_count maxed and losing %s\n",
- found_name ?: "(null)");
- return;
}
- context->name_count++;
-#if AUDIT_DEBUG
- context->ino_count++;
-#endif
- /* Re-use the name belonging to the slot for a matching parent directory.
- * All names for this context are relinquished in audit_free_names() */
- context->names[idx].name = found_name;
- context->names[idx].name_len = AUDIT_NAME_FULL;
- context->names[idx].name_put = 0; /* don't call __putname() */
- if (!inode)
- context->names[idx].ino = (unsigned long)-1;
- else
- audit_copy_inode(&context->names[idx], inode);
+ /* no matching parent, look for matching child */
+ for (idx = 0; idx < context->name_count; idx++) {
+ struct audit_names *n = &context->names[idx];
- /* A parent was not found in audit_names, so copy the inode data for the
- * provided parent. */
- if (!found_name) {
- idx = context->name_count;
- if (context->name_count == AUDIT_NAMES) {
- printk(KERN_DEBUG
- "name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu",
- MAJOR(parent->i_sb->s_dev),
- MINOR(parent->i_sb->s_dev),
- parent->i_ino);
- return;
+ if (!n->name)
+ continue;
+
+ /* strcmp() is the more likely scenario */
+ if (!strcmp(dname, n->name) ||
+ !audit_compare_dname_path(dname, n->name, &dirlen)) {
+ if (inode)
+ audit_copy_inode(n, inode);
+ else
+ n->ino = (unsigned long)-1;
+ found_child = n->name;
+ goto add_names;
}
- context->name_count++;
-#if AUDIT_DEBUG
- context->ino_count++;
-#endif
+ }
+
+add_names:
+ if (!found_parent) {
+ if (audit_inc_name_count(context, parent))
+ return;
+ idx = context->name_count - 1;
+ context->names[idx].name = NULL;
audit_copy_inode(&context->names[idx], parent);
}
-}
-/**
- * audit_inode_update - update inode info for last collected name
- * @inode: inode being audited
- *
- * When open() is called on an existing object with the O_CREAT flag, the inode
- * data audit initially collects is incorrect. This additional hook ensures
- * audit has the inode data for the actual object to be opened.
- */
-void __audit_inode_update(const struct inode *inode)
-{
- struct audit_context *context = current->audit_context;
- int idx;
+ if (!found_child) {
+ if (audit_inc_name_count(context, inode))
+ return;
+ idx = context->name_count - 1;
- if (!context->in_syscall || !inode)
- return;
+ /* Re-use the name belonging to the slot for a matching parent
+ * directory. All names for this context are relinquished in
+ * audit_free_names() */
+ if (found_parent) {
+ context->names[idx].name = found_parent;
+ context->names[idx].name_len = AUDIT_NAME_FULL;
+ /* don't call __putname() */
+ context->names[idx].name_put = 0;
+ } else {
+ context->names[idx].name = NULL;
+ }
- if (context->name_count == 0) {
- context->name_count++;
-#if AUDIT_DEBUG
- context->ino_count++;
-#endif
+ if (inode)
+ audit_copy_inode(&context->names[idx], inode);
+ else
+ context->names[idx].ino = (unsigned long)-1;
}
- idx = context->name_count - 1;
-
- audit_copy_inode(&context->names[idx], inode);
}
/**
@@ -1880,6 +1943,14 @@
return 0;
}
+void __audit_ptrace(struct task_struct *t)
+{
+ struct audit_context *context = current->audit_context;
+
+ context->target_pid = t->pid;
+ selinux_get_task_sid(t, &context->target_sid);
+}
+
/**
* audit_avc_path - record the granting or denial of permissions
* @dentry: dentry to record
@@ -1918,15 +1989,17 @@
* If the audit subsystem is being terminated, record the task (pid)
* and uid that is doing that.
*/
-void __audit_signal_info(int sig, struct task_struct *t)
+int __audit_signal_info(int sig, struct task_struct *t)
{
+ struct audit_aux_data_pids *axp;
+ struct task_struct *tsk = current;
+ struct audit_context *ctx = tsk->audit_context;
extern pid_t audit_sig_pid;
extern uid_t audit_sig_uid;
extern u32 audit_sig_sid;
- if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
- struct task_struct *tsk = current;
- struct audit_context *ctx = tsk->audit_context;
+ if (audit_pid && t->tgid == audit_pid &&
+ (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1)) {
audit_sig_pid = tsk->pid;
if (ctx)
audit_sig_uid = ctx->loginuid;
@@ -1934,4 +2007,72 @@
audit_sig_uid = tsk->uid;
selinux_get_task_sid(tsk, &audit_sig_sid);
}
+
+ if (!audit_signals) /* audit_context checked in wrapper */
+ return 0;
+
+ /* optimize the common case by putting first signal recipient directly
+ * in audit_context */
+ if (!ctx->target_pid) {
+ ctx->target_pid = t->tgid;
+ selinux_get_task_sid(t, &ctx->target_sid);
+ return 0;
+ }
+
+ axp = (void *)ctx->aux_pids;
+ if (!axp || axp->pid_count == AUDIT_AUX_PIDS) {
+ axp = kzalloc(sizeof(*axp), GFP_ATOMIC);
+ if (!axp)
+ return -ENOMEM;
+
+ axp->d.type = AUDIT_OBJ_PID;
+ axp->d.next = ctx->aux_pids;
+ ctx->aux_pids = (void *)axp;
+ }
+ BUG_ON(axp->pid_count > AUDIT_AUX_PIDS);
+
+ axp->target_pid[axp->pid_count] = t->tgid;
+ selinux_get_task_sid(t, &axp->target_sid[axp->pid_count]);
+ axp->pid_count++;
+
+ return 0;
+}
+
+/**
+ * audit_core_dumps - record information about processes that end abnormally
+ * @sig: signal value
+ *
+ * If a process ends with a core dump, something fishy is going on and we
+ * should record the event for investigation.
+ */
+void audit_core_dumps(long signr)
+{
+ struct audit_buffer *ab;
+ u32 sid;
+
+ if (!audit_enabled)
+ return;
+
+ if (signr == SIGQUIT) /* don't care for those */
+ return;
+
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND);
+ audit_log_format(ab, "auid=%u uid=%u gid=%u",
+ audit_get_loginuid(current->audit_context),
+ current->uid, current->gid);
+ selinux_get_task_sid(current, &sid);
+ if (sid) {
+ char *ctx = NULL;
+ u32 len;
+
+ if (selinux_sid_to_string(sid, &ctx, &len))
+ audit_log_format(ab, " ssid=%u", sid);
+ else
+ audit_log_format(ab, " subj=%s", ctx);
+ kfree(ctx);
+ }
+ audit_log_format(ab, " pid=%d comm=", current->pid);
+ audit_log_untrustedstring(ab, current->comm);
+ audit_log_format(ab, " sig=%ld", signr);
+ audit_log_end(ab);
}
diff --git a/kernel/compat.c b/kernel/compat.c
index cebb4c2..3bae374 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -475,8 +475,8 @@
return min_length;
}
-static int get_compat_itimerspec(struct itimerspec *dst,
- struct compat_itimerspec __user *src)
+int get_compat_itimerspec(struct itimerspec *dst,
+ const struct compat_itimerspec __user *src)
{
if (get_compat_timespec(&dst->it_interval, &src->it_interval) ||
get_compat_timespec(&dst->it_value, &src->it_value))
@@ -484,8 +484,8 @@
return 0;
}
-static int put_compat_itimerspec(struct compat_itimerspec __user *dst,
- struct itimerspec *src)
+int put_compat_itimerspec(struct compat_itimerspec __user *dst,
+ const struct itimerspec *src)
{
if (put_compat_timespec(&src->it_interval, &dst->it_interval) ||
put_compat_timespec(&src->it_value, &dst->it_value))
diff --git a/kernel/exit.c b/kernel/exit.c
index b0c6f0c..c6d14b8 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -24,6 +24,7 @@
#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/profile.h>
+#include <linux/signalfd.h>
#include <linux/mount.h>
#include <linux/proc_fs.h>
#include <linux/kthread.h>
@@ -42,6 +43,7 @@
#include <linux/audit.h> /* for audit_free() */
#include <linux/resource.h>
#include <linux/blkdev.h>
+#include <linux/task_io_accounting_ops.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -82,6 +84,14 @@
sighand = rcu_dereference(tsk->sighand);
spin_lock(&sighand->siglock);
+ /*
+ * Notify that this sighand has been detached. This must
+ * be called with the tsk->sighand lock held. Also, this
+ * access tsk->sighand internally, so it must be called
+ * before tsk->sighand is reset.
+ */
+ signalfd_detach_locked(tsk);
+
posix_cpu_timers_exit(tsk);
if (atomic_dec_and_test(&sig->count))
posix_cpu_timers_exit_group(tsk);
@@ -113,6 +123,8 @@
sig->nvcsw += tsk->nvcsw;
sig->nivcsw += tsk->nivcsw;
sig->sched_time += tsk->sched_time;
+ sig->inblock += task_io_get_inblock(tsk);
+ sig->oublock += task_io_get_oublock(tsk);
sig = NULL; /* Marker for below. */
}
@@ -299,12 +311,12 @@
if (process_session(curr) != session) {
detach_pid(curr, PIDTYPE_SID);
set_signal_session(curr->signal, session);
- attach_pid(curr, PIDTYPE_SID, session);
+ attach_pid(curr, PIDTYPE_SID, find_pid(session));
}
if (process_group(curr) != pgrp) {
detach_pid(curr, PIDTYPE_PGID);
curr->signal->pgrp = pgrp;
- attach_pid(curr, PIDTYPE_PGID, pgrp);
+ attach_pid(curr, PIDTYPE_PGID, find_pid(pgrp));
}
}
@@ -1193,6 +1205,12 @@
p->nvcsw + sig->nvcsw + sig->cnvcsw;
psig->cnivcsw +=
p->nivcsw + sig->nivcsw + sig->cnivcsw;
+ psig->cinblock +=
+ task_io_get_inblock(p) +
+ sig->inblock + sig->cinblock;
+ psig->coublock +=
+ task_io_get_oublock(p) +
+ sig->oublock + sig->coublock;
spin_unlock_irq(&p->parent->sighand->siglock);
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 5dd3979..49530e4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -875,6 +875,7 @@
sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
sig->nvcsw = sig->nivcsw = sig->cnvcsw = sig->cnivcsw = 0;
sig->min_flt = sig->maj_flt = sig->cmin_flt = sig->cmaj_flt = 0;
+ sig->inblock = sig->oublock = sig->cinblock = sig->coublock = 0;
sig->sched_time = 0;
INIT_LIST_HEAD(&sig->cpu_timers[0]);
INIT_LIST_HEAD(&sig->cpu_timers[1]);
@@ -955,7 +956,7 @@
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr,
- int pid)
+ struct pid *pid)
{
int retval;
struct task_struct *p = NULL;
@@ -1022,7 +1023,7 @@
p->did_exec = 0;
delayacct_tsk_init(p); /* Must remain after dup_task_struct() */
copy_flags(clone_flags, p);
- p->pid = pid;
+ p->pid = pid_nr(pid);
retval = -EFAULT;
if (clone_flags & CLONE_PARENT_SETTID)
if (put_user(p->pid, parent_tidptr))
@@ -1251,13 +1252,13 @@
p->signal->tty = current->signal->tty;
p->signal->pgrp = process_group(current);
set_signal_session(p->signal, process_session(current));
- attach_pid(p, PIDTYPE_PGID, process_group(p));
- attach_pid(p, PIDTYPE_SID, process_session(p));
+ attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
+ attach_pid(p, PIDTYPE_SID, task_session(current));
list_add_tail_rcu(&p->tasks, &init_task.tasks);
__get_cpu_var(process_counts)++;
}
- attach_pid(p, PIDTYPE_PID, p->pid);
+ attach_pid(p, PIDTYPE_PID, pid);
nr_threads++;
}
@@ -1321,7 +1322,8 @@
struct task_struct *task;
struct pt_regs regs;
- task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, NULL, 0);
+ task = copy_process(CLONE_VM, 0, idle_regs(®s), 0, NULL, NULL,
+ &init_struct_pid);
if (!IS_ERR(task))
init_idle(task, cpu);
@@ -1371,7 +1373,7 @@
clone_flags |= CLONE_PTRACE;
}
- p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);
+ p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);
/*
* Do this prior waking up the new thread - the thread pointer
* might get invalid after that point, if the thread exits quickly.
@@ -1420,12 +1422,15 @@
#define ARCH_MIN_MMSTRUCT_ALIGN 0
#endif
-static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long flags)
+static void sighand_ctor(void *data, struct kmem_cache *cachep,
+ unsigned long flags)
{
struct sighand_struct *sighand = data;
- if (flags & SLAB_CTOR_CONSTRUCTOR)
+ if (flags & SLAB_CTOR_CONSTRUCTOR) {
spin_lock_init(&sighand->siglock);
+ INIT_LIST_HEAD(&sighand->signalfd_list);
+ }
}
void __init proc_caches_init(void)
@@ -1451,7 +1456,6 @@
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
}
-
/*
* Check constraints on flags passed to the unshare system call and
* force unsharing of additional process context as appropriate.
diff --git a/kernel/pid.c b/kernel/pid.c
index d3ad724..eb66bd2 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -27,11 +27,13 @@
#include <linux/bootmem.h>
#include <linux/hash.h>
#include <linux/pid_namespace.h>
+#include <linux/init_task.h>
#define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
static struct hlist_head *pid_hash;
static int pidhash_shift;
static struct kmem_cache *pid_cachep;
+struct pid init_struct_pid = INIT_STRUCT_PID;
int pid_max = PID_MAX_DEFAULT;
@@ -247,13 +249,16 @@
}
EXPORT_SYMBOL_GPL(find_pid);
-int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr)
+/*
+ * attach_pid() must be called with the tasklist_lock write-held.
+ */
+int fastcall attach_pid(struct task_struct *task, enum pid_type type,
+ struct pid *pid)
{
struct pid_link *link;
- struct pid *pid;
link = &task->pids[type];
- link->pid = pid = find_pid(nr);
+ link->pid = pid;
hlist_add_head_rcu(&link->node, &pid->tasks[type]);
return 0;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 4d50e06..ad7949a 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -18,6 +18,7 @@
#include <linux/ptrace.h>
#include <linux/security.h>
#include <linux/signal.h>
+#include <linux/audit.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -161,6 +162,8 @@
{
int retval;
+ audit_ptrace(task);
+
retval = -EPERM;
if (task->pid <= 1)
goto out;
diff --git a/kernel/signal.c b/kernel/signal.c
index 2ac3a66..364fc95 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -21,6 +21,7 @@
#include <linux/syscalls.h>
#include <linux/ptrace.h>
#include <linux/signal.h>
+#include <linux/signalfd.h>
#include <linux/capability.h>
#include <linux/freezer.h>
#include <linux/pid_namespace.h>
@@ -113,8 +114,7 @@
/* Given the mask, find the first available signal that should be serviced. */
-static int
-next_signal(struct sigpending *pending, sigset_t *mask)
+int next_signal(struct sigpending *pending, sigset_t *mask)
{
unsigned long i, *s, *m, x;
int sig = 0;
@@ -497,6 +497,11 @@
int error = -EINVAL;
if (!valid_signal(sig))
return error;
+
+ error = audit_signal_info(sig, t); /* Let audit system see the signal */
+ if (error)
+ return error;
+
error = -EPERM;
if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info)))
&& ((sig != SIGCONT) ||
@@ -506,10 +511,7 @@
&& !capable(CAP_KILL))
return error;
- error = security_task_kill(t, info, sig, 0);
- if (!error)
- audit_signal_info(sig, t); /* Let audit system see the signal */
- return error;
+ return security_task_kill(t, info, sig, 0);
}
/* forward decl */
@@ -630,6 +632,12 @@
int ret = 0;
/*
+ * Deliver the signal to listening signalfds. This must be called
+ * with the sighand lock held.
+ */
+ signalfd_notify(t, sig);
+
+ /*
* fast-pathed signals for kernel-internal things like SIGSTOP
* or SIGKILL.
*/
@@ -1280,6 +1288,11 @@
ret = 1;
goto out;
}
+ /*
+ * Deliver the signal to listening signalfds. This must be called
+ * with the sighand lock held.
+ */
+ signalfd_notify(p, sig);
list_add_tail(&q->list, &p->pending.list);
sigaddset(&p->pending.signal, sig);
@@ -1323,6 +1336,11 @@
q->info.si_overrun++;
goto out;
}
+ /*
+ * Deliver the signal to listening signalfds. This must be called
+ * with the sighand lock held.
+ */
+ signalfd_notify(p, sig);
/*
* Put this signal on the shared-pending queue.
@@ -1983,6 +2001,8 @@
/*
* If you change siginfo_t structure, please be sure
* this code is fixed accordingly.
+ * Please remember to update the signalfd_copyinfo() function
+ * inside fs/signalfd.c too, in case siginfo_t changes.
* It should never copy any pad contained in the structure
* to avoid security leaks, but must copy the generic
* 3 ints plus the relevant union member.
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index daabb74..fcee2a8 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -8,6 +8,8 @@
#include <linux/sched.h>
#include <linux/stop_machine.h>
#include <linux/syscalls.h>
+#include <linux/interrupt.h>
+
#include <asm/atomic.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -45,6 +47,7 @@
if (stopmachine_state == STOPMACHINE_DISABLE_IRQ
&& !irqs_disabled) {
local_irq_disable();
+ hard_irq_disable();
irqs_disabled = 1;
/* Ack: irqs disabled. */
smp_mb(); /* Must read state first. */
@@ -124,6 +127,7 @@
/* Make them disable irqs. */
local_irq_disable();
+ hard_irq_disable();
stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
return 0;
diff --git a/kernel/sys.c b/kernel/sys.c
index cdb7e94..872271c 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -14,6 +14,7 @@
#include <linux/prctl.h>
#include <linux/highuid.h>
#include <linux/fs.h>
+#include <linux/resource.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/workqueue.h>
@@ -29,6 +30,7 @@
#include <linux/signal.h>
#include <linux/cn_proc.h>
#include <linux/getcpu.h>
+#include <linux/task_io_accounting_ops.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -658,7 +660,7 @@
int error = -EINVAL;
struct pid *pgrp;
- if (which > 2 || which < 0)
+ if (which > PRIO_USER || which < PRIO_PROCESS)
goto out;
/* normalize: avoid signed division (rounding problems) */
@@ -722,7 +724,7 @@
long niceval, retval = -ESRCH;
struct pid *pgrp;
- if (which > 2 || which < 0)
+ if (which > PRIO_USER || which < PRIO_PROCESS)
return -EINVAL;
read_lock(&tasklist_lock);
@@ -1486,7 +1488,7 @@
if (process_group(p) != pgid) {
detach_pid(p, PIDTYPE_PGID);
p->signal->pgrp = pgid;
- attach_pid(p, PIDTYPE_PGID, pgid);
+ attach_pid(p, PIDTYPE_PGID, find_pid(pgid));
}
err = 0;
@@ -2082,6 +2084,8 @@
r->ru_nivcsw = p->signal->cnivcsw;
r->ru_minflt = p->signal->cmin_flt;
r->ru_majflt = p->signal->cmaj_flt;
+ r->ru_inblock = p->signal->cinblock;
+ r->ru_oublock = p->signal->coublock;
if (who == RUSAGE_CHILDREN)
break;
@@ -2093,6 +2097,8 @@
r->ru_nivcsw += p->signal->nivcsw;
r->ru_minflt += p->signal->min_flt;
r->ru_majflt += p->signal->maj_flt;
+ r->ru_inblock += p->signal->inblock;
+ r->ru_oublock += p->signal->oublock;
t = p;
do {
utime = cputime_add(utime, t->utime);
@@ -2101,6 +2107,8 @@
r->ru_nivcsw += t->nivcsw;
r->ru_minflt += t->min_flt;
r->ru_majflt += t->maj_flt;
+ r->ru_inblock += task_io_get_inblock(t);
+ r->ru_oublock += task_io_get_oublock(t);
t = next_thread(t);
} while (t != p);
break;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index d7306d0..b6d77a8 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -141,3 +141,8 @@
cond_syscall(sys_bdflush);
cond_syscall(sys_ioprio_set);
cond_syscall(sys_ioprio_get);
+
+/* New file descriptors */
+cond_syscall(sys_signalfd);
+cond_syscall(sys_timerfd);
+cond_syscall(sys_eventfd);
diff --git a/kernel/timer.c b/kernel/timer.c
index 59a28b1..a6c580a 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -92,24 +92,24 @@
/* Functions below help us manage 'deferrable' flag */
static inline unsigned int tbase_get_deferrable(tvec_base_t *base)
{
- return (unsigned int)((unsigned long)base & TBASE_DEFERRABLE_FLAG);
+ return ((unsigned int)(unsigned long)base & TBASE_DEFERRABLE_FLAG);
}
static inline tvec_base_t *tbase_get_base(tvec_base_t *base)
{
- return (tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG);
+ return ((tvec_base_t *)((unsigned long)base & ~TBASE_DEFERRABLE_FLAG));
}
static inline void timer_set_deferrable(struct timer_list *timer)
{
- timer->base = (tvec_base_t *)((unsigned long)timer->base |
- TBASE_DEFERRABLE_FLAG);
+ timer->base = ((tvec_base_t *)((unsigned long)(timer->base) |
+ TBASE_DEFERRABLE_FLAG));
}
static inline void
timer_set_base(struct timer_list *timer, tvec_base_t *new_base)
{
- timer->base = (tvec_base_t *)((unsigned long)new_base |
+ timer->base = (tvec_base_t *)((unsigned long)(new_base) |
tbase_get_deferrable(timer->base));
}
diff --git a/lib/Kconfig b/lib/Kconfig
index 96d6e8c..2e7ae6b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -23,6 +23,14 @@
the kernel tree does. Such modules that use library CRC16
functions require M here.
+config CRC_ITU_T
+ tristate "CRC ITU-T V.41 functions"
+ help
+ This option is provided for the case where no in-kernel-tree
+ modules require CRC ITU-T V.41 functions, but a module built outside
+ the kernel tree does. Such modules that use library CRC ITU-T V.41
+ functions require M here.
+
config CRC32
tristate "CRC32 functions"
default y
diff --git a/lib/Makefile b/lib/Makefile
index ae57f35..c8c8e20 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -13,7 +13,7 @@
lib-y += kobject.o kref.o kobject_uevent.o klist.o
obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
- bust_spinlocks.o
+ bust_spinlocks.o hexdump.o
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
@@ -41,6 +41,7 @@
obj-$(CONFIG_BITREVERSE) += bitrev.o
obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC16) += crc16.o
+obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o
obj-$(CONFIG_CRC32) += crc32.o
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
diff --git a/lib/audit.c b/lib/audit.c
index 3b1289f..8e7dc1c 100644
--- a/lib/audit.c
+++ b/lib/audit.c
@@ -23,6 +23,16 @@
~0U
};
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+ return 0;
+}
+
int audit_classify_syscall(int abi, unsigned syscall)
{
switch(syscall) {
@@ -49,6 +59,7 @@
audit_register_class(AUDIT_CLASS_READ, read_class);
audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
return 0;
}
diff --git a/lib/crc-itu-t.c b/lib/crc-itu-t.c
new file mode 100644
index 0000000..a63472b
--- /dev/null
+++ b/lib/crc-itu-t.c
@@ -0,0 +1,69 @@
+/*
+ * crc-itu-t.c
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/crc-itu-t.h>
+
+/** CRC table for the CRC ITU-T V.41 0x0x1021 (x^16 + x^12 + x^15 + 1) */
+const u16 crc_itu_t_table[256] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+EXPORT_SYMBOL(crc_itu_t_table);
+
+/**
+ * crc_itu_t - Compute the CRC-ITU-T for the data buffer
+ *
+ * @crc: previous CRC value
+ * @buffer: data pointer
+ * @len: number of bytes in the buffer
+ *
+ * Returns the updated CRC value
+ */
+u16 crc_itu_t(u16 crc, const u8 *buffer, size_t len)
+{
+ while (len--)
+ crc = crc_itu_t_byte(crc, *buffer++);
+ return crc;
+}
+EXPORT_SYMBOL(crc_itu_t);
+
+MODULE_DESCRIPTION("CRC ITU-T V.41 calculations");
+MODULE_LICENSE("GPL");
+
diff --git a/lib/hexdump.c b/lib/hexdump.c
new file mode 100644
index 0000000..e6da5b7
--- /dev/null
+++ b/lib/hexdump.c
@@ -0,0 +1,104 @@
+/*
+ * lib/hexdump.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+/**
+ * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ * @linebuf: where to put the converted data
+ * @linebuflen: total size of @linebuf, including space for terminating NUL
+ *
+ * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
+ * 16 bytes of input data converted to hex + ASCII output.
+ *
+ * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
+ * to a hex + ASCII dump at the supplied memory location.
+ * The converted output is always NUL-terminated.
+ *
+ * E.g.:
+ * hex_dump_to_buffer(frame->data, frame->len, linebuf, sizeof(linebuf));
+ *
+ * example output buffer:
+ * 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO
+ */
+void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf,
+ size_t linebuflen)
+{
+ const u8 *ptr = buf;
+ u8 ch;
+ int j, lx = 0;
+
+ for (j = 0; (j < 16) && (j < len) && (lx + 3) < linebuflen; j++) {
+ if (j && !(j % 4))
+ linebuf[lx++] = ' ';
+ ch = ptr[j];
+ linebuf[lx++] = hex_asc(ch >> 4);
+ linebuf[lx++] = hex_asc(ch & 0x0f);
+ }
+ if ((lx + 2) < linebuflen) {
+ linebuf[lx++] = ' ';
+ linebuf[lx++] = ' ';
+ }
+ for (j = 0; (j < 16) && (j < len) && (lx + 2) < linebuflen; j++)
+ linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.';
+ linebuf[lx++] = '\0';
+}
+EXPORT_SYMBOL(hex_dump_to_buffer);
+
+/**
+ * print_hex_dump - print a text hex dump to syslog for a binary blob of data
+ * @level: kernel log level (e.g. KERN_DEBUG)
+ * @prefix_type: controls whether prefix of an offset, address, or none
+ * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
+ * @buf: data blob to dump
+ * @len: number of bytes in the @buf
+ *
+ * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
+ * to the kernel log at the specified kernel log level, with an optional
+ * leading prefix.
+ *
+ * E.g.:
+ * print_hex_dump(KERN_DEBUG, DUMP_PREFIX_ADDRESS, frame->data, frame->len);
+ *
+ * Example output using %DUMP_PREFIX_OFFSET:
+ * 0009ab42: 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO
+ * Example output using %DUMP_PREFIX_ADDRESS:
+ * ffffffff88089af0: 70717273 74757677 78797a7b 7c7d7e7f pqrstuvwxyz{|}~.
+ */
+void print_hex_dump(const char *level, int prefix_type, void *buf, size_t len)
+{
+ u8 *ptr = buf;
+ int i, linelen, remaining = len;
+ unsigned char linebuf[100];
+
+ for (i = 0; i < len; i += 16) {
+ linelen = min(remaining, 16);
+ remaining -= 16;
+ hex_dump_to_buffer(ptr + i, linelen, linebuf, sizeof(linebuf));
+
+ switch (prefix_type) {
+ case DUMP_PREFIX_ADDRESS:
+ printk("%s%*p: %s\n", level,
+ (int)(2 * sizeof(void *)), ptr + i, linebuf);
+ break;
+ case DUMP_PREFIX_OFFSET:
+ printk("%s%.8x: %s\n", level, i, linebuf);
+ break;
+ default:
+ printk("%s%s\n", level, linebuf);
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL(print_hex_dump);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 63cd888..eec1481 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -588,31 +588,27 @@
}
/**
- * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them.
+ * write_cache_pages - walk the list of dirty pages of the given address space and write all of them.
* @mapping: address space structure to write
* @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ * @writepage: function called for each page
+ * @data: data passed to writepage function
*
- * This is a library function, which implements the writepages()
- * address_space_operation.
- *
- * If a page is already under I/O, generic_writepages() skips it, even
+ * If a page is already under I/O, write_cache_pages() skips it, even
* if it's dirty. This is desirable behaviour for memory-cleaning writeback,
* but it is INCORRECT for data-integrity system calls such as fsync(). fsync()
* and msync() need to guarantee that all the data which was dirty at the time
* the call was made get new I/O started against them. If wbc->sync_mode is
* WB_SYNC_ALL then we were called for data integrity and we must wait for
* existing IO to complete.
- *
- * Derived from mpage_writepages() - if you fix this you should check that
- * also!
*/
-int generic_writepages(struct address_space *mapping,
- struct writeback_control *wbc)
+int write_cache_pages(struct address_space *mapping,
+ struct writeback_control *wbc, writepage_t writepage,
+ void *data)
{
struct backing_dev_info *bdi = mapping->backing_dev_info;
int ret = 0;
int done = 0;
- int (*writepage)(struct page *page, struct writeback_control *wbc);
struct pagevec pvec;
int nr_pages;
pgoff_t index;
@@ -625,12 +621,6 @@
return 0;
}
- writepage = mapping->a_ops->writepage;
-
- /* deal with chardevs and other special file */
- if (!writepage)
- return 0;
-
pagevec_init(&pvec, 0);
if (wbc->range_cyclic) {
index = mapping->writeback_index; /* Start from prev offset */
@@ -682,8 +672,7 @@
continue;
}
- ret = (*writepage)(page, wbc);
- mapping_set_error(mapping, ret);
+ ret = (*writepage)(page, wbc, data);
if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE))
unlock_page(page);
@@ -710,6 +699,38 @@
mapping->writeback_index = index;
return ret;
}
+EXPORT_SYMBOL(write_cache_pages);
+
+/*
+ * Function used by generic_writepages to call the real writepage
+ * function and set the mapping flags on error
+ */
+static int __writepage(struct page *page, struct writeback_control *wbc,
+ void *data)
+{
+ struct address_space *mapping = data;
+ int ret = mapping->a_ops->writepage(page, wbc);
+ mapping_set_error(mapping, ret);
+ return ret;
+}
+
+/**
+ * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them.
+ * @mapping: address space structure to write
+ * @wbc: subtract the number of written pages from *@wbc->nr_to_write
+ *
+ * This is a library function, which implements the writepages()
+ * address_space_operation.
+ */
+int generic_writepages(struct address_space *mapping,
+ struct writeback_control *wbc)
+{
+ /* deal with chardevs and other special file */
+ if (!mapping->a_ops->writepage)
+ return 0;
+
+ return write_cache_pages(mapping, wbc, __writepage, mapping);
+}
EXPORT_SYMBOL(generic_writepages);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index f9b5d6d..ae96dd8 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -2284,7 +2284,7 @@
* was used and there are no special requirements, this is a convenient
* alternative
*/
-int __init early_pfn_to_nid(unsigned long pfn)
+int __meminit early_pfn_to_nid(unsigned long pfn)
{
int i;
diff --git a/mm/slub.c b/mm/slub.c
index bd2efae..b39c8a6 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -81,10 +81,14 @@
* PageActive The slab is used as a cpu cache. Allocations
* may be performed from the slab. The slab is not
* on any slab list and cannot be moved onto one.
+ * The cpu slab may be equipped with an additioanl
+ * lockless_freelist that allows lockless access to
+ * free objects in addition to the regular freelist
+ * that requires the slab lock.
*
* PageError Slab requires special handling due to debug
* options set. This moves slab handling out of
- * the fast path.
+ * the fast path and disables lockless freelists.
*/
static inline int SlabDebug(struct page *page)
@@ -1014,6 +1018,7 @@
set_freepointer(s, last, NULL);
page->freelist = start;
+ page->lockless_freelist = NULL;
page->inuse = 0;
out:
if (flags & __GFP_WAIT)
@@ -1276,6 +1281,23 @@
*/
static void deactivate_slab(struct kmem_cache *s, struct page *page, int cpu)
{
+ /*
+ * Merge cpu freelist into freelist. Typically we get here
+ * because both freelists are empty. So this is unlikely
+ * to occur.
+ */
+ while (unlikely(page->lockless_freelist)) {
+ void **object;
+
+ /* Retrieve object from cpu_freelist */
+ object = page->lockless_freelist;
+ page->lockless_freelist = page->lockless_freelist[page->offset];
+
+ /* And put onto the regular freelist */
+ object[page->offset] = page->freelist;
+ page->freelist = object;
+ page->inuse--;
+ }
s->cpu_slab[cpu] = NULL;
ClearPageActive(page);
@@ -1322,47 +1344,46 @@
}
/*
- * slab_alloc is optimized to only modify two cachelines on the fast path
- * (aside from the stack):
+ * Slow path. The lockless freelist is empty or we need to perform
+ * debugging duties.
*
- * 1. The page struct
- * 2. The first cacheline of the object to be allocated.
+ * Interrupts are disabled.
*
- * The only other cache lines that are read (apart from code) is the
- * per cpu array in the kmem_cache struct.
+ * Processing is still very fast if new objects have been freed to the
+ * regular freelist. In that case we simply take over the regular freelist
+ * as the lockless freelist and zap the regular freelist.
*
- * Fastpath is not possible if we need to get a new slab or have
- * debugging enabled (which means all slabs are marked with SlabDebug)
+ * If that is not working then we fall back to the partial lists. We take the
+ * first element of the freelist as the object to allocate now and move the
+ * rest of the freelist to the lockless freelist.
+ *
+ * And if we were unable to get a new slab from the partial slab lists then
+ * we need to allocate a new slab. This is slowest path since we may sleep.
*/
-static void *slab_alloc(struct kmem_cache *s,
- gfp_t gfpflags, int node, void *addr)
+static void *__slab_alloc(struct kmem_cache *s,
+ gfp_t gfpflags, int node, void *addr, struct page *page)
{
- struct page *page;
void **object;
- unsigned long flags;
- int cpu;
+ int cpu = smp_processor_id();
- local_irq_save(flags);
- cpu = smp_processor_id();
- page = s->cpu_slab[cpu];
if (!page)
goto new_slab;
slab_lock(page);
if (unlikely(node != -1 && page_to_nid(page) != node))
goto another_slab;
-redo:
+load_freelist:
object = page->freelist;
if (unlikely(!object))
goto another_slab;
if (unlikely(SlabDebug(page)))
goto debug;
-have_object:
- page->inuse++;
- page->freelist = object[page->offset];
+ object = page->freelist;
+ page->lockless_freelist = object[page->offset];
+ page->inuse = s->objects;
+ page->freelist = NULL;
slab_unlock(page);
- local_irq_restore(flags);
return object;
another_slab:
@@ -1370,11 +1391,11 @@
new_slab:
page = get_partial(s, gfpflags, node);
- if (likely(page)) {
+ if (page) {
have_slab:
s->cpu_slab[cpu] = page;
SetPageActive(page);
- goto redo;
+ goto load_freelist;
}
page = new_slab(s, gfpflags, node);
@@ -1397,7 +1418,7 @@
discard_slab(s, page);
page = s->cpu_slab[cpu];
slab_lock(page);
- goto redo;
+ goto load_freelist;
}
/* New slab does not fit our expectations */
flush_slab(s, s->cpu_slab[cpu], cpu);
@@ -1405,16 +1426,52 @@
slab_lock(page);
goto have_slab;
}
- local_irq_restore(flags);
return NULL;
debug:
+ object = page->freelist;
if (!alloc_object_checks(s, page, object))
goto another_slab;
if (s->flags & SLAB_STORE_USER)
set_track(s, object, TRACK_ALLOC, addr);
trace(s, page, object, 1);
init_object(s, object, 1);
- goto have_object;
+
+ page->inuse++;
+ page->freelist = object[page->offset];
+ slab_unlock(page);
+ return object;
+}
+
+/*
+ * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc)
+ * have the fastpath folded into their functions. So no function call
+ * overhead for requests that can be satisfied on the fastpath.
+ *
+ * The fastpath works by first checking if the lockless freelist can be used.
+ * If not then __slab_alloc is called for slow processing.
+ *
+ * Otherwise we can simply pick the next object from the lockless free list.
+ */
+static void __always_inline *slab_alloc(struct kmem_cache *s,
+ gfp_t gfpflags, int node, void *addr)
+{
+ struct page *page;
+ void **object;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ page = s->cpu_slab[smp_processor_id()];
+ if (unlikely(!page || !page->lockless_freelist ||
+ (node != -1 && page_to_nid(page) != node)))
+
+ object = __slab_alloc(s, gfpflags, node, addr, page);
+
+ else {
+ object = page->lockless_freelist;
+ page->lockless_freelist = object[page->offset];
+ }
+ local_irq_restore(flags);
+ return object;
}
void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
@@ -1432,20 +1489,19 @@
#endif
/*
- * The fastpath only writes the cacheline of the page struct and the first
- * cacheline of the object.
+ * Slow patch handling. This may still be called frequently since objects
+ * have a longer lifetime than the cpu slabs in most processing loads.
*
- * We read the cpu_slab cacheline to check if the slab is the per cpu
- * slab for this processor.
+ * So we still attempt to reduce cache line usage. Just take the slab
+ * lock and free the item. If there is no additional partial page
+ * handling required then we can return immediately.
*/
-static void slab_free(struct kmem_cache *s, struct page *page,
+static void __slab_free(struct kmem_cache *s, struct page *page,
void *x, void *addr)
{
void *prior;
void **object = (void *)x;
- unsigned long flags;
- local_irq_save(flags);
slab_lock(page);
if (unlikely(SlabDebug(page)))
@@ -1475,7 +1531,6 @@
out_unlock:
slab_unlock(page);
- local_irq_restore(flags);
return;
slab_empty:
@@ -1487,7 +1542,6 @@
slab_unlock(page);
discard_slab(s, page);
- local_irq_restore(flags);
return;
debug:
@@ -1502,6 +1556,34 @@
goto checks_ok;
}
+/*
+ * Fastpath with forced inlining to produce a kfree and kmem_cache_free that
+ * can perform fastpath freeing without additional function calls.
+ *
+ * The fastpath is only possible if we are freeing to the current cpu slab
+ * of this processor. This typically the case if we have just allocated
+ * the item before.
+ *
+ * If fastpath is not possible then fall back to __slab_free where we deal
+ * with all sorts of special processing.
+ */
+static void __always_inline slab_free(struct kmem_cache *s,
+ struct page *page, void *x, void *addr)
+{
+ void **object = (void *)x;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (likely(page == s->cpu_slab[smp_processor_id()] &&
+ !SlabDebug(page))) {
+ object[page->offset] = page->lockless_freelist;
+ page->lockless_freelist = object;
+ } else
+ __slab_free(s, page, x, addr);
+
+ local_irq_restore(flags);
+}
+
void kmem_cache_free(struct kmem_cache *s, void *x)
{
struct page *page;
@@ -2363,9 +2445,8 @@
register_cpu_notifier(&slab_notifier);
#endif
- if (nr_cpu_ids) /* Remove when nr_cpu_ids is fixed upstream ! */
- kmem_size = offsetof(struct kmem_cache, cpu_slab)
- + nr_cpu_ids * sizeof(struct page *);
+ kmem_size = offsetof(struct kmem_cache, cpu_slab) +
+ nr_cpu_ids * sizeof(struct page *);
printk(KERN_INFO "SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
" Processors=%d, Nodes=%d\n",
diff --git a/mm/thrash.c b/mm/thrash.c
index 9ef9071..c4c5205 100644
--- a/mm/thrash.c
+++ b/mm/thrash.c
@@ -48,9 +48,8 @@
if (current_interval < current->mm->last_interval)
current->mm->token_priority++;
else {
- current->mm->token_priority--;
- if (unlikely(current->mm->token_priority < 0))
- current->mm->token_priority = 0;
+ if (likely(current->mm->token_priority > 0))
+ current->mm->token_priority--;
}
/* Check if we deserve the token */
if (current->mm->token_priority >
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 9832d9a..8faf27e 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -698,7 +698,7 @@
{
struct delayed_work *vmstat_work = &per_cpu(vmstat_work, cpu);
- INIT_DELAYED_WORK(vmstat_work, vmstat_update);
+ INIT_DELAYED_WORK_DEFERRABLE(vmstat_work, vmstat_update);
schedule_delayed_work_on(cpu, vmstat_work, HZ + cpu);
}
diff --git a/net/Kconfig b/net/Kconfig
index caeacd1..f3de729 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -218,6 +218,7 @@
bool
menu "Wireless"
+ depends on !S390
source "net/wireless/Kconfig"
source "net/mac80211/Kconfig"
diff --git a/net/ax25/Kconfig b/net/ax25/Kconfig
index 43dd86f..2a72aa9 100644
--- a/net/ax25/Kconfig
+++ b/net/ax25/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig HAMRADIO
- depends on NET
+ depends on NET && !S390
bool "Amateur Radio support"
help
If you want to connect your Linux box to an amateur radio, answer Y
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index 6929490..7725da9 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig BT
- depends on NET
+ depends on NET && !S390
tristate "Bluetooth subsystem support"
help
Bluetooth is low-cost, low-power, short-range wireless technology.
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index d342e89..ceadfcf 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -174,7 +174,7 @@
static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct hid_device *hid = dev->private;
+ struct hid_device *hid = input_get_drvdata(dev);
struct hidp_session *session = hid->driver_data;
return hidp_queue_event(session, dev, type, code, value);
@@ -182,7 +182,7 @@
static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct hidp_session *session = dev->private;
+ struct hidp_session *session = input_get_drvdata(dev);
return hidp_queue_event(session, dev, type, code, value);
}
@@ -630,7 +630,7 @@
struct input_dev *input = session->input;
int i;
- input->private = session;
+ input_set_drvdata(input, session);
input->name = "Bluetooth HID Boot Protocol Device";
@@ -663,7 +663,7 @@
input->relbit[0] |= BIT(REL_WHEEL);
}
- input->cdev.dev = hidp_get_device(session);
+ input->dev.parent = hidp_get_device(session);
input->event = hidp_input_event;
@@ -737,10 +737,8 @@
list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
hidp_send_report(session, report);
- if (hidinput_connect(hid) == 0) {
+ if (hidinput_connect(hid) == 0)
hid->claimed |= HID_CLAIMED_INPUT;
- hid_ff_init(hid);
- }
}
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
@@ -864,7 +862,7 @@
if (session->hid)
hid_free_device(session->hid);
- kfree(session->input);
+ input_free_device(session->input);
kfree(session);
return err;
}
diff --git a/net/core/link_watch.c b/net/core/link_watch.c
index e3c26a9..a5e372b 100644
--- a/net/core/link_watch.c
+++ b/net/core/link_watch.c
@@ -19,7 +19,6 @@
#include <linux/rtnetlink.h>
#include <linux/jiffies.h>
#include <linux/spinlock.h>
-#include <linux/list.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/bitops.h>
@@ -27,8 +26,7 @@
enum lw_bits {
- LW_RUNNING = 0,
- LW_SE_USED
+ LW_URGENT = 0,
};
static unsigned long linkwatch_flags;
@@ -37,17 +35,9 @@
static void linkwatch_event(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event);
-static LIST_HEAD(lweventlist);
+static struct net_device *lweventlist;
static DEFINE_SPINLOCK(lweventlist_lock);
-struct lw_event {
- struct list_head list;
- struct net_device *dev;
-};
-
-/* Avoid kmalloc() for most systems */
-static struct lw_event singleevent;
-
static unsigned char default_operstate(const struct net_device *dev)
{
if (!netif_carrier_ok(dev))
@@ -87,25 +77,102 @@
}
-/* Must be called with the rtnl semaphore held */
-void linkwatch_run_queue(void)
+static int linkwatch_urgent_event(struct net_device *dev)
{
- struct list_head head, *n, *next;
+ return netif_running(dev) && netif_carrier_ok(dev) &&
+ dev->qdisc != dev->qdisc_sleeping;
+}
+
+
+static void linkwatch_add_event(struct net_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lweventlist_lock, flags);
+ dev->link_watch_next = lweventlist;
+ lweventlist = dev;
+ spin_unlock_irqrestore(&lweventlist_lock, flags);
+}
+
+
+static void linkwatch_schedule_work(int urgent)
+{
+ unsigned long delay = linkwatch_nextevent - jiffies;
+
+ if (test_bit(LW_URGENT, &linkwatch_flags))
+ return;
+
+ /* Minimise down-time: drop delay for up event. */
+ if (urgent) {
+ if (test_and_set_bit(LW_URGENT, &linkwatch_flags))
+ return;
+ delay = 0;
+ }
+
+ /* If we wrap around we'll delay it by at most HZ. */
+ if (delay > HZ)
+ delay = 0;
+
+ /*
+ * This is true if we've scheduled it immeditately or if we don't
+ * need an immediate execution and it's already pending.
+ */
+ if (schedule_delayed_work(&linkwatch_work, delay) == !delay)
+ return;
+
+ /* Don't bother if there is nothing urgent. */
+ if (!test_bit(LW_URGENT, &linkwatch_flags))
+ return;
+
+ /* It's already running which is good enough. */
+ if (!cancel_delayed_work(&linkwatch_work))
+ return;
+
+ /* Otherwise we reschedule it again for immediate exection. */
+ schedule_delayed_work(&linkwatch_work, 0);
+}
+
+
+static void __linkwatch_run_queue(int urgent_only)
+{
+ struct net_device *next;
+
+ /*
+ * Limit the number of linkwatch events to one
+ * per second so that a runaway driver does not
+ * cause a storm of messages on the netlink
+ * socket. This limit does not apply to up events
+ * while the device qdisc is down.
+ */
+ if (!urgent_only)
+ linkwatch_nextevent = jiffies + HZ;
+ /* Limit wrap-around effect on delay. */
+ else if (time_after(linkwatch_nextevent, jiffies + HZ))
+ linkwatch_nextevent = jiffies;
+
+ clear_bit(LW_URGENT, &linkwatch_flags);
spin_lock_irq(&lweventlist_lock);
- list_replace_init(&lweventlist, &head);
+ next = lweventlist;
+ lweventlist = NULL;
spin_unlock_irq(&lweventlist_lock);
- list_for_each_safe(n, next, &head) {
- struct lw_event *event = list_entry(n, struct lw_event, list);
- struct net_device *dev = event->dev;
+ while (next) {
+ struct net_device *dev = next;
- if (event == &singleevent) {
- clear_bit(LW_SE_USED, &linkwatch_flags);
- } else {
- kfree(event);
+ next = dev->link_watch_next;
+
+ if (urgent_only && !linkwatch_urgent_event(dev)) {
+ linkwatch_add_event(dev);
+ continue;
}
+ /*
+ * Make sure the above read is complete since it can be
+ * rewritten as soon as we clear the bit below.
+ */
+ smp_mb__before_clear_bit();
+
/* We are about to handle this device,
* so new events can be accepted
*/
@@ -124,58 +191,39 @@
dev_put(dev);
}
+
+ if (lweventlist)
+ linkwatch_schedule_work(0);
+}
+
+
+/* Must be called with the rtnl semaphore held */
+void linkwatch_run_queue(void)
+{
+ __linkwatch_run_queue(0);
}
static void linkwatch_event(struct work_struct *dummy)
{
- /* Limit the number of linkwatch events to one
- * per second so that a runaway driver does not
- * cause a storm of messages on the netlink
- * socket
- */
- linkwatch_nextevent = jiffies + HZ;
- clear_bit(LW_RUNNING, &linkwatch_flags);
-
rtnl_lock();
- linkwatch_run_queue();
+ __linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies));
rtnl_unlock();
}
void linkwatch_fire_event(struct net_device *dev)
{
+ int urgent = linkwatch_urgent_event(dev);
+
if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
- unsigned long flags;
- struct lw_event *event;
-
- if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) {
- event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC);
-
- if (unlikely(event == NULL)) {
- clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);
- return;
- }
- } else {
- event = &singleevent;
- }
-
dev_hold(dev);
- event->dev = dev;
- spin_lock_irqsave(&lweventlist_lock, flags);
- list_add_tail(&event->list, &lweventlist);
- spin_unlock_irqrestore(&lweventlist_lock, flags);
+ linkwatch_add_event(dev);
+ } else if (!urgent)
+ return;
- if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) {
- unsigned long delay = linkwatch_nextevent - jiffies;
-
- /* If we wrap around we'll delay it by at most HZ. */
- if (delay > HZ)
- delay = 0;
- schedule_delayed_work(&linkwatch_work, delay);
- }
- }
+ linkwatch_schedule_work(urgent);
}
EXPORT_SYMBOL(linkwatch_fire_event);
diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c
index 7edea2a..75c0230 100644
--- a/net/ipv4/netfilter/arptable_filter.c
+++ b/net/ipv4/netfilter/arptable_filter.c
@@ -15,128 +15,34 @@
#define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \
(1 << NF_ARP_FORWARD))
-/* Standard entry. */
-struct arpt_standard
-{
- struct arpt_entry entry;
- struct arpt_standard_target target;
-};
-
-struct arpt_error_target
-{
- struct arpt_entry_target target;
- char errorname[ARPT_FUNCTION_MAXNAMELEN];
-};
-
-struct arpt_error
-{
- struct arpt_entry entry;
- struct arpt_error_target target;
-};
-
static struct
{
struct arpt_replace repl;
struct arpt_standard entries[3];
struct arpt_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
- sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
- { [NF_ARP_IN] = 0,
- [NF_ARP_OUT] = sizeof(struct arpt_standard),
- [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), },
- { [NF_ARP_IN] = 0,
- [NF_ARP_OUT] = sizeof(struct arpt_standard),
- [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard), },
- 0, NULL, { } },
- {
- /* ARP_IN */
- {
- {
- {
- { 0 }, { 0 }, { 0 }, { 0 },
- 0, 0,
- { { 0, }, { 0, } },
- { { 0, }, { 0, } },
- 0, 0,
- 0, 0,
- 0, 0,
- "", "", { 0 }, { 0 },
- 0, 0
- },
- sizeof(struct arpt_entry),
- sizeof(struct arpt_standard),
- 0,
- { 0, 0 }, { } },
- { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 }
- },
- /* ARP_OUT */
- {
- {
- {
- { 0 }, { 0 }, { 0 }, { 0 },
- 0, 0,
- { { 0, }, { 0, } },
- { { 0, }, { 0, } },
- 0, 0,
- 0, 0,
- 0, 0,
- "", "", { 0 }, { 0 },
- 0, 0
- },
- sizeof(struct arpt_entry),
- sizeof(struct arpt_standard),
- 0,
- { 0, 0 }, { } },
- { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 }
- },
- /* ARP_FORWARD */
- {
- {
- {
- { 0 }, { 0 }, { 0 }, { 0 },
- 0, 0,
- { { 0, }, { 0, } },
- { { 0, }, { 0, } },
- 0, 0,
- 0, 0,
- 0, 0,
- "", "", { 0 }, { 0 },
- 0, 0
- },
- sizeof(struct arpt_entry),
- sizeof(struct arpt_standard),
- 0,
- { 0, 0 }, { } },
- { { { { ARPT_ALIGN(sizeof(struct arpt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 }
- }
- },
- /* ERROR */
- {
- {
- {
- { 0 }, { 0 }, { 0 }, { 0 },
- 0, 0,
- { { 0, }, { 0, } },
- { { 0, }, { 0, } },
- 0, 0,
- 0, 0,
- 0, 0,
- "", "", { 0 }, { 0 },
- 0, 0
- },
- sizeof(struct arpt_entry),
- sizeof(struct arpt_error),
- 0,
- { 0, 0 }, { } },
- { { { { ARPT_ALIGN(sizeof(struct arpt_error_target)), ARPT_ERROR_TARGET } },
- { } },
- "ERROR"
- }
- }
+} initial_table __initdata = {
+ .repl = {
+ .name = "filter",
+ .valid_hooks = FILTER_VALID_HOOKS,
+ .num_entries = 4,
+ .size = sizeof(struct arpt_standard) * 3 + sizeof(struct arpt_error),
+ .hook_entry = {
+ [NF_ARP_IN] = 0,
+ [NF_ARP_OUT] = sizeof(struct arpt_standard),
+ [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
+ },
+ .underflow = {
+ [NF_ARP_IN] = 0,
+ [NF_ARP_OUT] = sizeof(struct arpt_standard),
+ [NF_ARP_FORWARD] = 2 * sizeof(struct arpt_standard),
+ },
+ },
+ .entries = {
+ ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_IN */
+ ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_OUT */
+ ARPT_STANDARD_INIT(NF_ACCEPT), /* ARP_FORWARD */
+ },
+ .term = ARPT_ERROR_INIT,
};
static struct arpt_table packet_filter = {
diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c
index 4272890..4f51c1d 100644
--- a/net/ipv4/netfilter/iptable_filter.c
+++ b/net/ipv4/netfilter/iptable_filter.c
@@ -26,53 +26,29 @@
struct ipt_replace repl;
struct ipt_standard entries[3];
struct ipt_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
- sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
- { [NF_IP_LOCAL_IN] = 0,
- [NF_IP_FORWARD] = sizeof(struct ipt_standard),
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
- { [NF_IP_LOCAL_IN] = 0,
- [NF_IP_FORWARD] = sizeof(struct ipt_standard),
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
- 0, NULL, { } },
- {
- /* LOCAL_IN */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* FORWARD */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* LOCAL_OUT */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } }
- },
- /* ERROR */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_error),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
- { } },
- "ERROR"
- }
- }
+} initial_table __initdata = {
+ .repl = {
+ .name = "filter",
+ .valid_hooks = FILTER_VALID_HOOKS,
+ .num_entries = 4,
+ .size = sizeof(struct ipt_standard) * 3 + sizeof(struct ipt_error),
+ .hook_entry = {
+ [NF_IP_LOCAL_IN] = 0,
+ [NF_IP_FORWARD] = sizeof(struct ipt_standard),
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+ },
+ .underflow = {
+ [NF_IP_LOCAL_IN] = 0,
+ [NF_IP_FORWARD] = sizeof(struct ipt_standard),
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2,
+ },
+ },
+ .entries = {
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ },
+ .term = IPT_ERROR_INIT, /* ERROR */
};
static struct xt_table packet_filter = {
@@ -105,7 +81,8 @@
if ((*pskb)->len < sizeof(struct iphdr)
|| ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
if (net_ratelimit())
- printk("ipt_hook: happy cracking.\n");
+ printk("iptable_filter: ignoring short SOCK_RAW "
+ "packet.\n");
return NF_ACCEPT;
}
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 9278802..902446f 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -33,73 +33,35 @@
struct ipt_replace repl;
struct ipt_standard entries[5];
struct ipt_error term;
-} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 6,
- sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
- { [NF_IP_PRE_ROUTING] = 0,
- [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard),
- [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2,
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
- [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4 },
- { [NF_IP_PRE_ROUTING] = 0,
- [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard),
- [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2,
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
- [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4 },
- 0, NULL, { } },
- {
- /* PRE_ROUTING */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* LOCAL_IN */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* FORWARD */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* LOCAL_OUT */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* POST_ROUTING */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_standard),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- },
- /* ERROR */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ipt_entry),
- sizeof(struct ipt_error),
- 0, { 0, 0 }, { } },
- { { { { IPT_ALIGN(sizeof(struct ipt_error_target)), IPT_ERROR_TARGET } },
- { } },
- "ERROR"
- }
- }
+} initial_table __initdata = {
+ .repl = {
+ .name = "mangle",
+ .valid_hooks = MANGLE_VALID_HOOKS,
+ .num_entries = 6,
+ .size = sizeof(struct ipt_standard) * 5 + sizeof(struct ipt_error),
+ .hook_entry = {
+ [NF_IP_PRE_ROUTING] = 0,
+ [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard),
+ [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2,
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
+ [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4,
+ },
+ .underflow = {
+ [NF_IP_PRE_ROUTING] = 0,
+ [NF_IP_LOCAL_IN] = sizeof(struct ipt_standard),
+ [NF_IP_FORWARD] = sizeof(struct ipt_standard) * 2,
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 3,
+ [NF_IP_POST_ROUTING] = sizeof(struct ipt_standard) * 4,
+ },
+ },
+ .entries = {
+ IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
+ },
+ .term = IPT_ERROR_INIT, /* ERROR */
};
static struct xt_table packet_mangler = {
@@ -138,7 +100,8 @@
if ((*pskb)->len < sizeof(struct iphdr)
|| ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
if (net_ratelimit())
- printk("ipt_hook: happy cracking.\n");
+ printk("iptable_mangle: ignoring short SOCK_RAW "
+ "packet.\n");
return NF_ACCEPT;
}
diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c
index 18c3d4c..d6e5033 100644
--- a/net/ipv4/netfilter/iptable_raw.c
+++ b/net/ipv4/netfilter/iptable_raw.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
#include <linux/netfilter_ipv4/ip_tables.h>
+#include <net/ip.h>
#define RAW_VALID_HOOKS ((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_OUT))
@@ -21,62 +22,18 @@
.size = sizeof(struct ipt_standard) * 2 + sizeof(struct ipt_error),
.hook_entry = {
[NF_IP_PRE_ROUTING] = 0,
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) },
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard)
+ },
.underflow = {
[NF_IP_PRE_ROUTING] = 0,
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) },
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard)
+ },
},
.entries = {
- /* PRE_ROUTING */
- {
- .entry = {
- .target_offset = sizeof(struct ipt_entry),
- .next_offset = sizeof(struct ipt_standard),
- },
- .target = {
- .target = {
- .u = {
- .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
- },
- },
- .verdict = -NF_ACCEPT - 1,
- },
- },
-
- /* LOCAL_OUT */
- {
- .entry = {
- .target_offset = sizeof(struct ipt_entry),
- .next_offset = sizeof(struct ipt_standard),
- },
- .target = {
- .target = {
- .u = {
- .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
- },
- },
- .verdict = -NF_ACCEPT - 1,
- },
- },
+ IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
- /* ERROR */
- .term = {
- .entry = {
- .target_offset = sizeof(struct ipt_entry),
- .next_offset = sizeof(struct ipt_error),
- },
- .target = {
- .target = {
- .u = {
- .user = {
- .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
- .name = IPT_ERROR_TARGET,
- },
- },
- },
- .errorname = "ERROR",
- },
- }
+ .term = IPT_ERROR_INIT, /* ERROR */
};
static struct xt_table packet_raw = {
@@ -98,6 +55,24 @@
return ipt_do_table(pskb, hook, in, out, &packet_raw);
}
+static unsigned int
+ipt_local_hook(unsigned int hook,
+ struct sk_buff **pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ /* root is playing with raw sockets. */
+ if ((*pskb)->len < sizeof(struct iphdr) ||
+ ip_hdrlen(*pskb) < sizeof(struct iphdr)) {
+ if (net_ratelimit())
+ printk("iptable_raw: ignoring short SOCK_RAW"
+ "packet.\n");
+ return NF_ACCEPT;
+ }
+ return ipt_do_table(pskb, hook, in, out, &packet_raw);
+}
+
/* 'raw' is the very first table. */
static struct nf_hook_ops ipt_ops[] = {
{
@@ -108,7 +83,7 @@
.owner = THIS_MODULE,
},
{
- .hook = ipt_hook,
+ .hook = ipt_local_hook,
.pf = PF_INET,
.hooknum = NF_IP_LOCAL_OUT,
.priority = NF_IP_PRI_RAW,
diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c
index 2534f71..6740736 100644
--- a/net/ipv4/netfilter/nf_nat_rule.c
+++ b/net/ipv4/netfilter/nf_nat_rule.c
@@ -46,77 +46,20 @@
.hook_entry = {
[NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
+ },
.underflow = {
[NF_IP_PRE_ROUTING] = 0,
[NF_IP_POST_ROUTING] = sizeof(struct ipt_standard),
- [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2 },
+ [NF_IP_LOCAL_OUT] = sizeof(struct ipt_standard) * 2
+ },
},
.entries = {
- /* PRE_ROUTING */
- {
- .entry = {
- .target_offset = sizeof(struct ipt_entry),
- .next_offset = sizeof(struct ipt_standard),
- },
- .target = {
- .target = {
- .u = {
- .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
- },
- },
- .verdict = -NF_ACCEPT - 1,
- },
- },
- /* POST_ROUTING */
- {
- .entry = {
- .target_offset = sizeof(struct ipt_entry),
- .next_offset = sizeof(struct ipt_standard),
- },
- .target = {
- .target = {
- .u = {
- .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
- },
- },
- .verdict = -NF_ACCEPT - 1,
- },
- },
- /* LOCAL_OUT */
- {
- .entry = {
- .target_offset = sizeof(struct ipt_entry),
- .next_offset = sizeof(struct ipt_standard),
- },
- .target = {
- .target = {
- .u = {
- .target_size = IPT_ALIGN(sizeof(struct ipt_standard_target)),
- },
- },
- .verdict = -NF_ACCEPT - 1,
- },
- },
+ IPT_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
+ IPT_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
- /* ERROR */
- .term = {
- .entry = {
- .target_offset = sizeof(struct ipt_entry),
- .next_offset = sizeof(struct ipt_error),
- },
- .target = {
- .target = {
- .u = {
- .user = {
- .target_size = IPT_ALIGN(sizeof(struct ipt_error_target)),
- .name = IPT_ERROR_TARGET,
- },
- },
- },
- .errorname = "ERROR",
- },
- }
+ .term = IPT_ERROR_INIT, /* ERROR */
};
static struct xt_table nat_table = {
@@ -230,9 +173,7 @@
}
inline unsigned int
-alloc_null_binding(struct nf_conn *ct,
- struct nf_nat_info *info,
- unsigned int hooknum)
+alloc_null_binding(struct nf_conn *ct, unsigned int hooknum)
{
/* Force range to this IP; let proto decide mapping for
per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
@@ -251,9 +192,7 @@
}
unsigned int
-alloc_null_binding_confirmed(struct nf_conn *ct,
- struct nf_nat_info *info,
- unsigned int hooknum)
+alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum)
{
__be32 ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
@@ -275,8 +214,7 @@
unsigned int hooknum,
const struct net_device *in,
const struct net_device *out,
- struct nf_conn *ct,
- struct nf_nat_info *info)
+ struct nf_conn *ct)
{
int ret;
@@ -285,7 +223,7 @@
if (ret == NF_ACCEPT) {
if (!nf_nat_initialized(ct, HOOK2MANIP(hooknum)))
/* NUL mapping */
- ret = alloc_null_binding(ct, info, hooknum);
+ ret = alloc_null_binding(ct, hooknum);
}
return ret;
}
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c
index 64bbed2..55dac36 100644
--- a/net/ipv4/netfilter/nf_nat_standalone.c
+++ b/net/ipv4/netfilter/nf_nat_standalone.c
@@ -80,7 +80,6 @@
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
struct nf_conn_nat *nat;
- struct nf_nat_info *info;
/* maniptype == SRC for postrouting. */
enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum);
@@ -129,7 +128,6 @@
}
/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
case IP_CT_NEW:
- info = &nat->info;
/* Seen it before? This can happen for loopback, retrans,
or local packets.. */
@@ -138,14 +136,13 @@
if (unlikely(nf_ct_is_confirmed(ct)))
/* NAT module was loaded late */
- ret = alloc_null_binding_confirmed(ct, info,
- hooknum);
+ ret = alloc_null_binding_confirmed(ct, hooknum);
else if (hooknum == NF_IP_LOCAL_IN)
/* LOCAL_IN hook doesn't have a chain! */
- ret = alloc_null_binding(ct, info, hooknum);
+ ret = alloc_null_binding(ct, hooknum);
else
ret = nf_nat_rule_find(pskb, hooknum, in, out,
- ct, info);
+ ct);
if (ret != NF_ACCEPT) {
return ret;
@@ -160,10 +157,8 @@
/* ESTABLISHED */
NF_CT_ASSERT(ctinfo == IP_CT_ESTABLISHED ||
ctinfo == (IP_CT_ESTABLISHED+IP_CT_IS_REPLY));
- info = &nat->info;
}
- NF_CT_ASSERT(info);
return nf_nat_packet(ct, ctinfo, hooknum, pskb);
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 66026df..4c7e95f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -118,15 +118,15 @@
* Note about this hash function :
* Typical use is probably daddr = 0, only dport is going to vary hash
*/
-static inline unsigned int hash_port_and_addr(__u16 port, __be32 addr)
+static inline unsigned int udp_hash_port(__u16 port)
{
- addr ^= addr >> 16;
- addr ^= addr >> 8;
- return port ^ addr;
+ return port;
}
static inline int __udp_lib_port_inuse(unsigned int hash, int port,
- __be32 daddr, struct hlist_head udptable[])
+ const struct sock *this_sk,
+ struct hlist_head udptable[],
+ const struct udp_get_port_ops *ops)
{
struct sock *sk;
struct hlist_node *node;
@@ -138,7 +138,10 @@
inet = inet_sk(sk);
if (inet->num != port)
continue;
- if (inet->rcv_saddr == daddr)
+ if (this_sk) {
+ if (ops->saddr_cmp(sk, this_sk))
+ return 1;
+ } else if (ops->saddr_any(sk))
return 1;
}
return 0;
@@ -151,12 +154,11 @@
* @snum: port number to look up
* @udptable: hash list table, must be of UDP_HTABLE_SIZE
* @port_rover: pointer to record of last unallocated port
- * @saddr_comp: AF-dependent comparison of bound local IP addresses
+ * @ops: AF-dependent address operations
*/
int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_head udptable[], int *port_rover,
- int (*saddr_comp)(const struct sock *sk1,
- const struct sock *sk2 ) )
+ const struct udp_get_port_ops *ops)
{
struct hlist_node *node;
struct hlist_head *head;
@@ -176,8 +178,7 @@
for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) {
int size;
- hash = hash_port_and_addr(result,
- inet_sk(sk)->rcv_saddr);
+ hash = ops->hash_port_and_rcv_saddr(result, sk);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
if (hlist_empty(head)) {
if (result > sysctl_local_port_range[1])
@@ -203,17 +204,16 @@
result = sysctl_local_port_range[0]
+ ((result - sysctl_local_port_range[0]) &
(UDP_HTABLE_SIZE - 1));
- hash = hash_port_and_addr(result, 0);
+ hash = udp_hash_port(result);
if (__udp_lib_port_inuse(hash, result,
- 0, udptable))
+ NULL, udptable, ops))
continue;
- if (!inet_sk(sk)->rcv_saddr)
+ if (ops->saddr_any(sk))
break;
- hash = hash_port_and_addr(result,
- inet_sk(sk)->rcv_saddr);
+ hash = ops->hash_port_and_rcv_saddr(result, sk);
if (! __udp_lib_port_inuse(hash, result,
- inet_sk(sk)->rcv_saddr, udptable))
+ sk, udptable, ops))
break;
}
if (i >= (1 << 16) / UDP_HTABLE_SIZE)
@@ -221,7 +221,7 @@
gotit:
*port_rover = snum = result;
} else {
- hash = hash_port_and_addr(snum, 0);
+ hash = udp_hash_port(snum);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head)
@@ -231,12 +231,11 @@
(!sk2->sk_reuse || !sk->sk_reuse) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
- (*saddr_comp)(sk, sk2))
+ ops->saddr_cmp(sk, sk2))
goto fail;
- if (inet_sk(sk)->rcv_saddr) {
- hash = hash_port_and_addr(snum,
- inet_sk(sk)->rcv_saddr);
+ if (!ops->saddr_any(sk)) {
+ hash = ops->hash_port_and_rcv_saddr(snum, sk);
head = &udptable[hash & (UDP_HTABLE_SIZE - 1)];
sk_for_each(sk2, node, head)
@@ -248,7 +247,7 @@
!sk->sk_bound_dev_if ||
sk2->sk_bound_dev_if ==
sk->sk_bound_dev_if) &&
- (*saddr_comp)(sk, sk2))
+ ops->saddr_cmp(sk, sk2))
goto fail;
}
}
@@ -266,12 +265,12 @@
}
int udp_get_port(struct sock *sk, unsigned short snum,
- int (*scmp)(const struct sock *, const struct sock *))
+ const struct udp_get_port_ops *ops)
{
- return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, scmp);
+ return __udp_lib_get_port(sk, snum, udp_hash, &udp_port_rover, ops);
}
-int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
+static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2)
{
struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2);
@@ -280,9 +279,33 @@
inet1->rcv_saddr == inet2->rcv_saddr ));
}
+static int ipv4_rcv_saddr_any(const struct sock *sk)
+{
+ return !inet_sk(sk)->rcv_saddr;
+}
+
+static inline unsigned int ipv4_hash_port_and_addr(__u16 port, __be32 addr)
+{
+ addr ^= addr >> 16;
+ addr ^= addr >> 8;
+ return port ^ addr;
+}
+
+static unsigned int ipv4_hash_port_and_rcv_saddr(__u16 port,
+ const struct sock *sk)
+{
+ return ipv4_hash_port_and_addr(port, inet_sk(sk)->rcv_saddr);
+}
+
+const struct udp_get_port_ops udp_ipv4_ops = {
+ .saddr_cmp = ipv4_rcv_saddr_equal,
+ .saddr_any = ipv4_rcv_saddr_any,
+ .hash_port_and_rcv_saddr = ipv4_hash_port_and_rcv_saddr,
+};
+
static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
{
- return udp_get_port(sk, snum, ipv4_rcv_saddr_equal);
+ return udp_get_port(sk, snum, &udp_ipv4_ops);
}
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try
@@ -297,8 +320,8 @@
unsigned int hash, hashwild;
int score, best = -1, hport = ntohs(dport);
- hash = hash_port_and_addr(hport, daddr);
- hashwild = hash_port_and_addr(hport, 0);
+ hash = ipv4_hash_port_and_addr(hport, daddr);
+ hashwild = udp_hash_port(hport);
read_lock(&udp_hash_lock);
@@ -1198,8 +1221,8 @@
struct sock *sk, *skw, *sknext;
int dif;
int hport = ntohs(uh->dest);
- unsigned int hash = hash_port_and_addr(hport, daddr);
- unsigned int hashwild = hash_port_and_addr(hport, 0);
+ unsigned int hash = ipv4_hash_port_and_addr(hport, daddr);
+ unsigned int hashwild = udp_hash_port(hport);
dif = skb->dev->ifindex;
diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h
index 820a477..06d9419 100644
--- a/net/ipv4/udp_impl.h
+++ b/net/ipv4/udp_impl.h
@@ -5,14 +5,14 @@
#include <net/protocol.h>
#include <net/inet_common.h>
+extern const struct udp_get_port_ops udp_ipv4_ops;
+
extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int );
extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []);
extern int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_head udptable[], int *port_rover,
- int (*)(const struct sock*,const struct sock*));
-extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *);
-
+ const struct udp_get_port_ops *ops);
extern int udp_setsockopt(struct sock *sk, int level, int optname,
char __user *optval, int optlen);
diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c
index f34fd68..3653b32 100644
--- a/net/ipv4/udplite.c
+++ b/net/ipv4/udplite.c
@@ -19,14 +19,15 @@
static int udplite_port_rover;
int udplite_get_port(struct sock *sk, unsigned short p,
- int (*c)(const struct sock *, const struct sock *))
+ const struct udp_get_port_ops *ops)
{
- return __udp_lib_get_port(sk, p, udplite_hash, &udplite_port_rover, c);
+ return __udp_lib_get_port(sk, p, udplite_hash,
+ &udplite_port_rover, ops);
}
static int udplite_v4_get_port(struct sock *sk, unsigned short snum)
{
- return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal);
+ return udplite_get_port(sk, snum, &udp_ipv4_ops);
}
static int udplite_rcv(struct sk_buff *skb)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d02685c..c7ea248 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -4204,6 +4204,10 @@
return err;
ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+ ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+ ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+#endif
register_netdevice_notifier(&ipv6_dev_notf);
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 6d8e4ac..14be0b9 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -660,6 +660,14 @@
Hop-by-hop options.
**********************************/
+/*
+ * Note: we cannot rely on skb->dst before we assign it in ip6_route_input().
+ */
+static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb)
+{
+ return skb->dst ? ip6_dst_idev(skb->dst) : __in6_dev_get(skb->dev);
+}
+
/* Router Alert as of RFC 2711 */
static int ipv6_hop_ra(struct sk_buff **skbp, int optoff)
@@ -688,25 +696,25 @@
if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
nh[optoff+1]);
- IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
+ IP6_INC_STATS_BH(ipv6_skb_idev(skb),
IPSTATS_MIB_INHDRERRORS);
goto drop;
}
pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
if (pkt_len <= IPV6_MAXPLEN) {
- IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+ IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
return 0;
}
if (ipv6_hdr(skb)->payload_len) {
- IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
+ IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
return 0;
}
if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
- IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS);
+ IP6_INC_STATS_BH(ipv6_skb_idev(skb), IPSTATS_MIB_INTRUNCATEDPKTS);
goto drop;
}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index f508171..4704b5f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -463,10 +463,17 @@
*/
if (xrlim_allow(dst, 1*HZ))
ndisc_send_redirect(skb, n, target);
- } else if (ipv6_addr_type(&hdr->saddr)&(IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK
- |IPV6_ADDR_LINKLOCAL)) {
+ } else {
+ int addrtype = ipv6_addr_type(&hdr->saddr);
+
/* This check is security critical. */
- goto error;
+ if (addrtype & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LOOPBACK))
+ goto error;
+ if (addrtype & IPV6_ADDR_LINKLOCAL) {
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH,
+ ICMPV6_NOT_NEIGHBOUR, 0, skb->dev);
+ goto error;
+ }
}
if (skb->len > dst_mtu(dst)) {
diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c
index 76f0cf6..7e32e2a 100644
--- a/net/ipv6/netfilter/ip6table_filter.c
+++ b/net/ipv6/netfilter/ip6table_filter.c
@@ -24,53 +24,29 @@
struct ip6t_replace repl;
struct ip6t_standard entries[3];
struct ip6t_error term;
-} initial_table __initdata
-= { { "filter", FILTER_VALID_HOOKS, 4,
- sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
- { [NF_IP6_LOCAL_IN] = 0,
- [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
- [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 },
- { [NF_IP6_LOCAL_IN] = 0,
- [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
- [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2 },
- 0, NULL, { } },
- {
- /* LOCAL_IN */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* FORWARD */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* LOCAL_OUT */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } }
- },
- /* ERROR */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_error),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
- { } },
- "ERROR"
- }
- }
+} initial_table __initdata = {
+ .repl = {
+ .name = "filter",
+ .valid_hooks = FILTER_VALID_HOOKS,
+ .num_entries = 4,
+ .size = sizeof(struct ip6t_standard) * 3 + sizeof(struct ip6t_error),
+ .hook_entry = {
+ [NF_IP6_LOCAL_IN] = 0,
+ [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
+ [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
+ },
+ .underflow = {
+ [NF_IP6_LOCAL_IN] = 0,
+ [NF_IP6_FORWARD] = sizeof(struct ip6t_standard),
+ [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 2
+ },
+ },
+ .entries = {
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ },
+ .term = IP6T_ERROR_INIT, /* ERROR */
};
static struct xt_table packet_filter = {
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index a9f10e3..f2d2649 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -32,73 +32,35 @@
struct ip6t_replace repl;
struct ip6t_standard entries[5];
struct ip6t_error term;
-} initial_table __initdata
-= { { "mangle", MANGLE_VALID_HOOKS, 6,
- sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
- { [NF_IP6_PRE_ROUTING] = 0,
- [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard),
- [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2,
- [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
- [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4},
- { [NF_IP6_PRE_ROUTING] = 0,
- [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard),
- [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2,
- [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
- [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4},
- 0, NULL, { } },
- {
- /* PRE_ROUTING */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* LOCAL_IN */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* FORWARD */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* LOCAL_OUT */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } },
- /* POST_ROUTING */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_standard),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
- -NF_ACCEPT - 1 } }
- },
- /* ERROR */
- { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
- 0,
- sizeof(struct ip6t_entry),
- sizeof(struct ip6t_error),
- 0, { 0, 0 }, { } },
- { { { { IP6T_ALIGN(sizeof(struct ip6t_error_target)), IP6T_ERROR_TARGET } },
- { } },
- "ERROR"
- }
- }
+} initial_table __initdata = {
+ .repl = {
+ .name = "mangle",
+ .valid_hooks = MANGLE_VALID_HOOKS,
+ .num_entries = 6,
+ .size = sizeof(struct ip6t_standard) * 5 + sizeof(struct ip6t_error),
+ .hook_entry = {
+ [NF_IP6_PRE_ROUTING] = 0,
+ [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard),
+ [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2,
+ [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
+ [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4,
+ },
+ .underflow = {
+ [NF_IP6_PRE_ROUTING] = 0,
+ [NF_IP6_LOCAL_IN] = sizeof(struct ip6t_standard),
+ [NF_IP6_FORWARD] = sizeof(struct ip6t_standard) * 2,
+ [NF_IP6_LOCAL_OUT] = sizeof(struct ip6t_standard) * 3,
+ [NF_IP6_POST_ROUTING] = sizeof(struct ip6t_standard) * 4,
+ },
+ },
+ .entries = {
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_IN */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* FORWARD */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* POST_ROUTING */
+ },
+ .term = IP6T_ERROR_INIT, /* ERROR */
};
static struct xt_table packet_mangler = {
diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c
index a3eb5b8..0acda45 100644
--- a/net/ipv6/netfilter/ip6table_raw.c
+++ b/net/ipv6/netfilter/ip6table_raw.c
@@ -35,56 +35,10 @@
},
},
.entries = {
- /* PRE_ROUTING */
- {
- .entry = {
- .target_offset = sizeof(struct ip6t_entry),
- .next_offset = sizeof(struct ip6t_standard),
- },
- .target = {
- .target = {
- .u = {
- .target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
- },
- },
- .verdict = -NF_ACCEPT - 1,
- },
- },
-
- /* LOCAL_OUT */
- {
- .entry = {
- .target_offset = sizeof(struct ip6t_entry),
- .next_offset = sizeof(struct ip6t_standard),
- },
- .target = {
- .target = {
- .u = {
- .target_size = IP6T_ALIGN(sizeof(struct ip6t_standard_target)),
- },
- },
- .verdict = -NF_ACCEPT - 1,
- },
- },
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* PRE_ROUTING */
+ IP6T_STANDARD_INIT(NF_ACCEPT), /* LOCAL_OUT */
},
- /* ERROR */
- .term = {
- .entry = {
- .target_offset = sizeof(struct ip6t_entry),
- .next_offset = sizeof(struct ip6t_error),
- },
- .target = {
- .target = {
- .u = {
- .user = {
- .target_size = IP6T_ALIGN(sizeof(struct ip6t_error_target)),
- .name = IP6T_ERROR_TARGET,
- },
- },
- },
- .errorname = "ERROR",
- },
- }
+ .term = IP6T_ERROR_INIT, /* ERROR */
};
static struct xt_table packet_raw = {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index b083c09..a7ae59c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -52,9 +52,28 @@
DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
+static int ipv6_rcv_saddr_any(const struct sock *sk)
+{
+ struct ipv6_pinfo *np = inet6_sk(sk);
+
+ return ipv6_addr_any(&np->rcv_saddr);
+}
+
+static unsigned int ipv6_hash_port_and_rcv_saddr(__u16 port,
+ const struct sock *sk)
+{
+ return port;
+}
+
+const struct udp_get_port_ops udp_ipv6_ops = {
+ .saddr_cmp = ipv6_rcv_saddr_equal,
+ .saddr_any = ipv6_rcv_saddr_any,
+ .hash_port_and_rcv_saddr = ipv6_hash_port_and_rcv_saddr,
+};
+
static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
{
- return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
+ return udp_get_port(sk, snum, &udp_ipv6_ops);
}
static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h
index 6e252f3..36b0c11 100644
--- a/net/ipv6/udp_impl.h
+++ b/net/ipv6/udp_impl.h
@@ -6,6 +6,8 @@
#include <net/addrconf.h>
#include <net/inet_common.h>
+extern const struct udp_get_port_ops udp_ipv6_ops;
+
extern int __udp6_lib_rcv(struct sk_buff **, struct hlist_head [], int );
extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *,
int , int , int , __be32 , struct hlist_head []);
diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c
index f54016a..c40a513 100644
--- a/net/ipv6/udplite.c
+++ b/net/ipv6/udplite.c
@@ -37,7 +37,7 @@
static int udplite_v6_get_port(struct sock *sk, unsigned short snum)
{
- return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal);
+ return udplite_get_port(sk, snum, &udp_ipv6_ops);
}
struct proto udplitev6_prot = {
diff --git a/net/irda/Kconfig b/net/irda/Kconfig
index 9efb17b..c8671a7 100644
--- a/net/irda/Kconfig
+++ b/net/irda/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig IRDA
- depends on NET
+ depends on NET && !S390
tristate "IrDA (infrared) subsystem support"
select CRC_CCITT
---help---
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 822917d..3e07e9d 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -17,6 +17,7 @@
* scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE,
* SSID)
*/
+#include <linux/delay.h>
#include <linux/if_ether.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
@@ -27,7 +28,6 @@
#include <linux/rtnetlink.h>
#include <net/iw_handler.h>
#include <asm/types.h>
-#include <asm/delay.h>
#include <net/mac80211.h>
#include "ieee80211_i.h"
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index e132c8a..e8b5c2d 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -299,7 +299,6 @@
{
struct nf_conn *ct = (struct nf_conn *)nfct;
struct nf_conn_help *help = nfct_help(ct);
- struct nf_conntrack_l3proto *l3proto;
struct nf_conntrack_l4proto *l4proto;
typeof(nf_conntrack_destroyed) destroyed;
@@ -317,10 +316,6 @@
* destroy_conntrack() MUST NOT be called with a write lock
* to nf_conntrack_lock!!! -HW */
rcu_read_lock();
- l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num);
- if (l3proto && l3proto->destroy)
- l3proto->destroy(ct);
-
l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num,
ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum);
if (l4proto && l4proto->destroy)
@@ -893,8 +888,13 @@
NF_CT_DUMP_TUPLE(newreply);
ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply;
- if (!ct->master && help && help->expecting == 0)
- help->helper = __nf_ct_helper_find(newreply);
+ if (!ct->master && help && help->expecting == 0) {
+ struct nf_conntrack_helper *helper;
+ helper = __nf_ct_helper_find(newreply);
+ if (helper)
+ memset(&help->help, 0, sizeof(help->help));
+ help->helper = helper;
+ }
write_unlock_bh(&nf_conntrack_lock);
}
EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index aa1a97ee..d6d39e2 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -830,11 +830,6 @@
char *helpname;
int err;
- if (!help) {
- /* FIXME: we need to reallocate and rehash */
- return -EBUSY;
- }
-
/* don't change helper of sibling connections */
if (ct->master)
return -EINVAL;
@@ -843,25 +838,34 @@
if (err < 0)
return err;
- helper = __nf_conntrack_helper_find_byname(helpname);
- if (!helper) {
- if (!strcmp(helpname, ""))
- helper = NULL;
- else
- return -EINVAL;
- }
-
- if (help->helper) {
- if (!helper) {
+ if (!strcmp(helpname, "")) {
+ if (help && help->helper) {
/* we had a helper before ... */
nf_ct_remove_expectations(ct);
help->helper = NULL;
- } else {
- /* need to zero data of old helper */
- memset(&help->help, 0, sizeof(help->help));
}
+
+ return 0;
}
+ if (!help) {
+ /* FIXME: we need to reallocate and rehash */
+ return -EBUSY;
+ }
+
+ helper = __nf_conntrack_helper_find_byname(helpname);
+ if (helper == NULL)
+ return -EINVAL;
+
+ if (help->helper == helper)
+ return 0;
+
+ if (help->helper)
+ /* we had a helper before ... */
+ nf_ct_remove_expectations(ct);
+
+ /* need to zero data of old helper */
+ memset(&help->help, 0, sizeof(help->help));
help->helper = helper;
return 0;
diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c
index f4ea8fe..189ded5 100644
--- a/net/netfilter/xt_conntrack.c
+++ b/net/netfilter/xt_conntrack.c
@@ -134,12 +134,66 @@
nf_ct_l3proto_module_put(match->family);
}
+#ifdef CONFIG_COMPAT
+struct compat_xt_conntrack_info
+{
+ compat_uint_t statemask;
+ compat_uint_t statusmask;
+ struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX];
+ struct in_addr sipmsk[IP_CT_DIR_MAX];
+ struct in_addr dipmsk[IP_CT_DIR_MAX];
+ compat_ulong_t expires_min;
+ compat_ulong_t expires_max;
+ u_int8_t flags;
+ u_int8_t invflags;
+};
+
+static void compat_from_user(void *dst, void *src)
+{
+ struct compat_xt_conntrack_info *cm = src;
+ struct xt_conntrack_info m = {
+ .statemask = cm->statemask,
+ .statusmask = cm->statusmask,
+ .expires_min = cm->expires_min,
+ .expires_max = cm->expires_max,
+ .flags = cm->flags,
+ .invflags = cm->invflags,
+ };
+ memcpy(m.tuple, cm->tuple, sizeof(m.tuple));
+ memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk));
+ memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk));
+ memcpy(dst, &m, sizeof(m));
+}
+
+static int compat_to_user(void __user *dst, void *src)
+{
+ struct xt_conntrack_info *m = src;
+ struct compat_xt_conntrack_info cm = {
+ .statemask = m->statemask,
+ .statusmask = m->statusmask,
+ .expires_min = m->expires_min,
+ .expires_max = m->expires_max,
+ .flags = m->flags,
+ .invflags = m->invflags,
+ };
+ memcpy(cm.tuple, m->tuple, sizeof(cm.tuple));
+ memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk));
+ memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk));
+ return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0;
+}
+#endif
+
static struct xt_match conntrack_match = {
.name = "conntrack",
.match = match,
.checkentry = checkentry,
.destroy = destroy,
.matchsize = sizeof(struct xt_conntrack_info),
+#ifdef CONFIG_COMPAT
+ .compatsize = sizeof(struct compat_xt_conntrack_info),
+ .compat_from_user = compat_from_user,
+ .compat_to_user = compat_to_user,
+#endif
.family = AF_INET,
.me = THIS_MODULE,
};
diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c
index ce08b78..90fa107 100644
--- a/net/rxrpc/ar-peer.c
+++ b/net/rxrpc/ar-peer.c
@@ -59,14 +59,14 @@
ret = ip_route_output_key(&rt, &fl);
if (ret < 0) {
- kleave(" [route err %d]", ret);
+ _leave(" [route err %d]", ret);
return;
}
peer->if_mtu = dst_mtu(&rt->u.dst);
dst_release(&rt->u.dst);
- kleave(" [if_mtu %u]", peer->if_mtu);
+ _leave(" [if_mtu %u]", peer->if_mtu);
}
/*
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 3385ee5..f28bb2d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -71,12 +71,9 @@
/* Kick device.
- Note, that this procedure can be called by a watchdog timer, so that
- we do not check dev->tbusy flag here.
- Returns: 0 - queue is empty.
- >0 - queue is not empty, but throttled.
- <0 - queue is not empty. Device is throttled, if dev->tbusy != 0.
+ Returns: 0 - queue is empty or throttled.
+ >0 - queue is not empty.
NOTE: Called under dev->queue_lock with locally disabled BH.
*/
@@ -115,7 +112,7 @@
kfree_skb(skb);
if (net_ratelimit())
printk(KERN_DEBUG "Dead loop on netdevice %s, fix it urgently!\n", dev->name);
- return -1;
+ goto out;
}
__get_cpu_var(netdev_rx_stat).cpu_collision++;
goto requeue;
@@ -135,10 +132,12 @@
netif_tx_unlock(dev);
}
spin_lock(&dev->queue_lock);
- return -1;
+ q = dev->qdisc;
+ goto out;
}
if (ret == NETDEV_TX_LOCKED && nolock) {
spin_lock(&dev->queue_lock);
+ q = dev->qdisc;
goto collision;
}
}
@@ -163,26 +162,28 @@
*/
requeue:
- if (skb->next)
+ if (unlikely(q == &noop_qdisc))
+ kfree_skb(skb);
+ else if (skb->next)
dev->gso_skb = skb;
else
q->ops->requeue(skb, q);
netif_schedule(dev);
- return 1;
+ return 0;
}
+
+out:
BUG_ON((int) q->q.qlen < 0);
return q->q.qlen;
}
void __qdisc_run(struct net_device *dev)
{
- if (unlikely(dev->qdisc == &noop_qdisc))
- goto out;
+ do {
+ if (!qdisc_restart(dev))
+ break;
+ } while (!netif_queue_stopped(dev));
- while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
- /* NOTHING */;
-
-out:
clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
}
@@ -544,6 +545,7 @@
void dev_deactivate(struct net_device *dev)
{
struct Qdisc *qdisc;
+ struct sk_buff *skb;
spin_lock_bh(&dev->queue_lock);
qdisc = dev->qdisc;
@@ -551,8 +553,12 @@
qdisc_reset(qdisc);
+ skb = dev->gso_skb;
+ dev->gso_skb = NULL;
spin_unlock_bh(&dev->queue_lock);
+ kfree_skb(skb);
+
dev_watchdog_down(dev);
/* Wait for outstanding dev_queue_xmit calls. */
@@ -561,11 +567,6 @@
/* Wait for outstanding qdisc_run calls. */
while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
yield();
-
- if (dev->gso_skb) {
- kfree_skb(dev->gso_skb);
- dev->gso_skb = NULL;
- }
}
void dev_init_scheduler(struct net_device *dev)
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index d24914d..f05ad9a 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -94,14 +94,13 @@
struct net_device *dev = sch->dev;
struct teql_sched_data *q = qdisc_priv(sch);
- __skb_queue_tail(&q->q, skb);
- if (q->q.qlen <= dev->tx_queue_len) {
+ if (q->q.qlen < dev->tx_queue_len) {
+ __skb_queue_tail(&q->q, skb);
sch->bstats.bytes += skb->len;
sch->bstats.packets++;
return 0;
}
- __skb_unlink(skb, &q->q);
kfree_skb(skb);
sch->qstats.drops++;
return NET_XMIT_DROP;
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 83a76ba..4dcdabf 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -4164,6 +4164,7 @@
rwlock_t *addr_lock;
int err = 0;
void *addrs;
+ void *buf;
int bytes_copied = 0;
if (len != sizeof(struct sctp_getaddrs_old))
@@ -4217,13 +4218,14 @@
}
}
+ buf = addrs;
list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
- memcpy(addrs, &temp, addrlen);
- to += addrlen;
+ memcpy(buf, &temp, addrlen);
+ buf += addrlen;
bytes_copied += addrlen;
cnt ++;
if (cnt >= getaddrs.addr_num) break;
@@ -4266,6 +4268,7 @@
size_t space_left;
int bytes_copied = 0;
void *addrs;
+ void *buf;
if (len <= sizeof(struct sctp_getaddrs))
return -EINVAL;
@@ -4316,6 +4319,7 @@
}
}
+ buf = addrs;
list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
memcpy(&temp, &addr->a, sizeof(temp));
@@ -4325,8 +4329,8 @@
err = -ENOMEM; /*fixme: right error?*/
goto error;
}
- memcpy(addrs, &temp, addrlen);
- to += addrlen;
+ memcpy(buf, &temp, addrlen);
+ buf += addrlen;
bytes_copied += addrlen;
cnt ++;
space_left -= addrlen;
@@ -5227,7 +5231,12 @@
/* Allocate HMAC for generating cookie. */
if (sctp_hmac_alg) {
tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
- if (!tfm) {
+ if (IS_ERR(tfm)) {
+ if (net_ratelimit()) {
+ printk(KERN_INFO
+ "SCTP: failed to load transform for %s: %ld\n",
+ sctp_hmac_alg, PTR_ERR(tfm));
+ }
err = -ENOSYS;
goto out;
}
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 661ea2d..bfecb35 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -141,11 +141,6 @@
* an ABORT, so we need to include it in the sac_info.
*/
if (chunk) {
- /* sctp_inqu_pop() has allready pulled off the chunk
- * header. We need to put it back temporarily
- */
- skb_push(chunk->skb, sizeof(sctp_chunkhdr_t));
-
/* Copy the chunk data to a new skb and reserve enough
* head room to use as notification.
*/
@@ -155,9 +150,6 @@
if (!skb)
goto fail;
- /* put back the chunk header now that we have a copy */
- skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
-
/* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb);
sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
@@ -168,7 +160,8 @@
/* Trim the buffer to the right length. */
skb_trim(skb, sizeof(struct sctp_assoc_change) +
- ntohs(chunk->chunk_hdr->length));
+ ntohs(chunk->chunk_hdr->length) -
+ sizeof(sctp_chunkhdr_t));
} else {
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, gfp);
diff --git a/sound/Kconfig b/sound/Kconfig
index 97532bb..9ea4738 100644
--- a/sound/Kconfig
+++ b/sound/Kconfig
@@ -2,6 +2,7 @@
#
menu "Sound"
+ depends on HAS_IOMEM
config SOUND
tristate "Sound card support"