aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/proc.txt7
-rw-r--r--arch/mips/kernel/head.S2
-rw-r--r--arch/mips/mm/Makefile3
-rw-r--r--arch/mips/mm/tlbex.c1300
-rw-r--r--arch/mips/mm/uasm.c576
-rw-r--r--arch/mips/mm/uasm.h192
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--arch/x86/boot/compressed/vmlinux_64.lds2
-rw-r--r--arch/x86/kernel/acpi/boot.c8
-rw-r--r--arch/x86/kernel/cpu/common.c20
-rw-r--r--arch/x86/kernel/cpuid.c2
-rw-r--r--arch/x86/kernel/e820_64.c23
-rw-r--r--arch/x86/kernel/early_printk.c2
-rw-r--r--arch/x86/kernel/efi_64.c2
-rw-r--r--arch/x86/kernel/head64.c6
-rw-r--r--arch/x86/kernel/microcode.c2
-rw-r--r--arch/x86/kernel/msr.c2
-rw-r--r--arch/x86/kernel/pci-calgary_64.c4
-rw-r--r--arch/x86/kernel/setup_64.c3
-rw-r--r--arch/x86/kernel/smpboot_64.c2
-rw-r--r--arch/x86/kernel/topology.c3
-rw-r--r--arch/x86/mm/fault.c2
-rw-r--r--arch/x86/mm/init_64.c13
-rw-r--r--arch/x86/mm/ioremap.c3
-rw-r--r--arch/x86/mm/numa_64.c34
-rw-r--r--arch/x86/mm/pageattr-test.c4
-rw-r--r--drivers/ata/Kconfig2
-rw-r--r--drivers/ata/ahci.c2
-rw-r--r--drivers/ata/ata_piix.c10
-rw-r--r--drivers/ata/pata_bf54x.c53
-rw-r--r--drivers/ata/pata_sl82c105.c33
-rw-r--r--drivers/ata/sata_mv.c486
-rw-r--r--drivers/ata/sata_nv.c18
-rw-r--r--drivers/char/tty_audit.c19
-rw-r--r--drivers/pci/pci.c3
-rw-r--r--fs/proc/base.c2
-rw-r--r--include/asm-x86/cpu.h3
-rw-r--r--include/asm-x86/e820_64.h4
-rw-r--r--include/asm-x86/futex.h6
-rw-r--r--include/linux/audit.h13
-rw-r--r--include/linux/futex.h10
-rw-r--r--include/linux/init_task.h8
-rw-r--r--include/linux/sched.h4
-rw-r--r--include/linux/thread_info.h1
-rw-r--r--include/linux/tick.h4
-rw-r--r--include/linux/time.h1
-rw-r--r--kernel/audit.c434
-rw-r--r--kernel/auditfilter.c54
-rw-r--r--kernel/auditsc.c349
-rw-r--r--kernel/futex.c42
-rw-r--r--kernel/futex_compat.c3
-rw-r--r--kernel/hrtimer.c2
-rw-r--r--kernel/sysctl.c11
-rw-r--r--kernel/time.c1
-rw-r--r--kernel/time/tick-sched.c2
-rw-r--r--kernel/time/timekeeping.c6
-rw-r--r--kernel/time/timer_list.c2
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--net/core/dev.c15
-rw-r--r--net/key/af_key.c14
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/xfrm/xfrm_state.c2
-rw-r--r--security/selinux/selinuxfs.c17
-rw-r--r--security/selinux/ss/services.c5
64 files changed, 2181 insertions, 1684 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 11fe51c036b..194c8f35132 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1134,13 +1134,6 @@ check the amount of free space (value is in seconds). Default settings are: 4,
resume it if we have a value of 3 or more percent; consider information about
the amount of free space valid for 30 seconds
-audit_argv_kb
--------------
-
-The file contains a single value denoting the limit on the argv array size
-for execve (in KiB). This limit is only applied when system call auditing for
-execve is enabled, otherwise the value is ignored.
-
ctrl-alt-del
------------
diff --git a/arch/mips/kernel/head.S b/arch/mips/kernel/head.S
index 50be56c9e9e..a24fb790090 100644
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -140,7 +140,7 @@ FEXPORT(__kernel_entry)
j kernel_entry
#endif
- __INIT_REFOK
+ __REF
NESTED(kernel_entry, 16, sp) # kernel entry point
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index 32fd5db9577..c6f832e0f41 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -3,7 +3,8 @@
#
obj-y += cache.o dma-default.o extable.o fault.o \
- init.o pgtable.o tlbex.o tlbex-fault.o
+ init.o pgtable.o tlbex.o tlbex-fault.o \
+ uasm.o
obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o
obj-$(CONFIG_64BIT) += pgtable-64.o
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index d026302e0ec..218a6cc415e 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -5,7 +5,7 @@
*
* Synthesize TLB refill handlers at runtime.
*
- * Copyright (C) 2004,2005,2006 by Thiemo Seufer
+ * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
* Copyright (C) 2005, 2007 Maciej W. Rozycki
* Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
*
@@ -24,12 +24,11 @@
#include <linux/string.h>
#include <linux/init.h>
-#include <asm/bugs.h>
#include <asm/mmu_context.h>
-#include <asm/inst.h>
-#include <asm/elf.h>
#include <asm/war.h>
+#include "uasm.h"
+
static inline int r45k_bvahwbug(void)
{
/* XXX: We should probe for the presence of this bug, but we don't. */
@@ -67,371 +66,9 @@ static int __init m4kc_tlbp_war(void)
(PRID_COMP_MIPS | PRID_IMP_4KC);
}
-/*
- * A little micro-assembler, intended for TLB refill handler
- * synthesizing. It is intentionally kept simple, does only support
- * a subset of instructions, and does not try to hide pipeline effects
- * like branch delay slots.
- */
-
-enum fields
-{
- RS = 0x001,
- RT = 0x002,
- RD = 0x004,
- RE = 0x008,
- SIMM = 0x010,
- UIMM = 0x020,
- BIMM = 0x040,
- JIMM = 0x080,
- FUNC = 0x100,
- SET = 0x200
-};
-
-#define OP_MASK 0x3f
-#define OP_SH 26
-#define RS_MASK 0x1f
-#define RS_SH 21
-#define RT_MASK 0x1f
-#define RT_SH 16
-#define RD_MASK 0x1f
-#define RD_SH 11
-#define RE_MASK 0x1f
-#define RE_SH 6
-#define IMM_MASK 0xffff
-#define IMM_SH 0
-#define JIMM_MASK 0x3ffffff
-#define JIMM_SH 0
-#define FUNC_MASK 0x3f
-#define FUNC_SH 0
-#define SET_MASK 0x7
-#define SET_SH 0
-
-enum opcode {
- insn_invalid,
- insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
- insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
- insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
- insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
- insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
- insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
- insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
- insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
- insn_tlbwr, insn_xor, insn_xori
-};
-
-struct insn {
- enum opcode opcode;
- u32 match;
- enum fields fields;
-};
-
-/* This macro sets the non-variable bits of an instruction. */
-#define M(a, b, c, d, e, f) \
- ((a) << OP_SH \
- | (b) << RS_SH \
- | (c) << RT_SH \
- | (d) << RD_SH \
- | (e) << RE_SH \
- | (f) << FUNC_SH)
-
-static struct insn insn_table[] __initdata = {
- { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
- { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
- { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
- { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
- { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
- { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
- { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
- { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
- { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
- { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
- { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
- { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
- { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
- { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
- { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
- { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
- { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
- { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
- { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
- { insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
- { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
- { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
- { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
- { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM },
- { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
- { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
- { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
- { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
- { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE },
- { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE },
- { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE },
- { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD },
- { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
- { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 },
- { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 },
- { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 },
- { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
- { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
- { insn_invalid, 0, 0 }
-};
-
-#undef M
-
-static u32 __init build_rs(u32 arg)
-{
- if (arg & ~RS_MASK)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return (arg & RS_MASK) << RS_SH;
-}
-
-static u32 __init build_rt(u32 arg)
-{
- if (arg & ~RT_MASK)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return (arg & RT_MASK) << RT_SH;
-}
-
-static u32 __init build_rd(u32 arg)
-{
- if (arg & ~RD_MASK)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return (arg & RD_MASK) << RD_SH;
-}
-
-static u32 __init build_re(u32 arg)
-{
- if (arg & ~RE_MASK)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return (arg & RE_MASK) << RE_SH;
-}
-
-static u32 __init build_simm(s32 arg)
-{
- if (arg > 0x7fff || arg < -0x8000)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return arg & 0xffff;
-}
-
-static u32 __init build_uimm(u32 arg)
-{
- if (arg & ~IMM_MASK)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return arg & IMM_MASK;
-}
-
-static u32 __init build_bimm(s32 arg)
-{
- if (arg > 0x1ffff || arg < -0x20000)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- if (arg & 0x3)
- printk(KERN_WARNING "Invalid TLB synthesizer branch target\n");
-
- return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
-}
-
-static u32 __init build_jimm(u32 arg)
-{
- if (arg & ~((JIMM_MASK) << 2))
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return (arg >> 2) & JIMM_MASK;
-}
-
-static u32 __init build_func(u32 arg)
-{
- if (arg & ~FUNC_MASK)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return arg & FUNC_MASK;
-}
-
-static u32 __init build_set(u32 arg)
-{
- if (arg & ~SET_MASK)
- printk(KERN_WARNING "TLB synthesizer field overflow\n");
-
- return arg & SET_MASK;
-}
-
-/*
- * The order of opcode arguments is implicitly left to right,
- * starting with RS and ending with FUNC or IMM.
- */
-static void __init build_insn(u32 **buf, enum opcode opc, ...)
-{
- struct insn *ip = NULL;
- unsigned int i;
- va_list ap;
- u32 op;
-
- for (i = 0; insn_table[i].opcode != insn_invalid; i++)
- if (insn_table[i].opcode == opc) {
- ip = &insn_table[i];
- break;
- }
-
- if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
- panic("Unsupported TLB synthesizer instruction %d", opc);
-
- op = ip->match;
- va_start(ap, opc);
- if (ip->fields & RS) op |= build_rs(va_arg(ap, u32));
- if (ip->fields & RT) op |= build_rt(va_arg(ap, u32));
- if (ip->fields & RD) op |= build_rd(va_arg(ap, u32));
- if (ip->fields & RE) op |= build_re(va_arg(ap, u32));
- if (ip->fields & SIMM) op |= build_simm(va_arg(ap, s32));
- if (ip->fields & UIMM) op |= build_uimm(va_arg(ap, u32));
- if (ip->fields & BIMM) op |= build_bimm(va_arg(ap, s32));
- if (ip->fields & JIMM) op |= build_jimm(va_arg(ap, u32));
- if (ip->fields & FUNC) op |= build_func(va_arg(ap, u32));
- if (ip->fields & SET) op |= build_set(va_arg(ap, u32));
- va_end(ap);
-
- **buf = op;
- (*buf)++;
-}
-
-#define I_u1u2u3(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- unsigned int b, unsigned int c) \
- { \
- build_insn(buf, insn##op, a, b, c); \
- }
-
-#define I_u2u1u3(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- unsigned int b, unsigned int c) \
- { \
- build_insn(buf, insn##op, b, a, c); \
- }
-
-#define I_u3u1u2(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- unsigned int b, unsigned int c) \
- { \
- build_insn(buf, insn##op, b, c, a); \
- }
-
-#define I_u1u2s3(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- unsigned int b, signed int c) \
- { \
- build_insn(buf, insn##op, a, b, c); \
- }
-
-#define I_u2s3u1(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- signed int b, unsigned int c) \
- { \
- build_insn(buf, insn##op, c, a, b); \
- }
-
-#define I_u2u1s3(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- unsigned int b, signed int c) \
- { \
- build_insn(buf, insn##op, b, a, c); \
- }
-
-#define I_u1u2(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- unsigned int b) \
- { \
- build_insn(buf, insn##op, a, b); \
- }
-
-#define I_u1s2(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a, \
- signed int b) \
- { \
- build_insn(buf, insn##op, a, b); \
- }
-
-#define I_u1(op) \
- static void __init __maybe_unused i##op(u32 **buf, unsigned int a) \
- { \
- build_insn(buf, insn##op, a); \
- }
-
-#define I_0(op) \
- static void __init __maybe_unused i##op(u32 **buf) \
- { \
- build_insn(buf, insn##op); \
- }
-
-I_u2u1s3(_addiu);
-I_u3u1u2(_addu);
-I_u2u1u3(_andi);
-I_u3u1u2(_and);
-I_u1u2s3(_beq);
-I_u1u2s3(_beql);
-I_u1s2(_bgez);
-I_u1s2(_bgezl);
-I_u1s2(_bltz);
-I_u1s2(_bltzl);
-I_u1u2s3(_bne);
-I_u1u2u3(_dmfc0);
-I_u1u2u3(_dmtc0);
-I_u2u1s3(_daddiu);
-I_u3u1u2(_daddu);
-I_u2u1u3(_dsll);
-I_u2u1u3(_dsll32);
-I_u2u1u3(_dsra);
-I_u2u1u3(_dsrl);
-I_u2u1u3(_dsrl32);
-I_u3u1u2(_dsubu);
-I_0(_eret);
-I_u1(_j);
-I_u1(_jal);
-I_u1(_jr);
-I_u2s3u1(_ld);
-I_u2s3u1(_ll);
-I_u2s3u1(_lld);
-I_u1s2(_lui);
-I_u2s3u1(_lw);
-I_u1u2u3(_mfc0);
-I_u1u2u3(_mtc0);
-I_u2u1u3(_ori);
-I_0(_rfe);
-I_u2s3u1(_sc);
-I_u2s3u1(_scd);
-I_u2s3u1(_sd);
-I_u2u1u3(_sll);
-I_u2u1u3(_sra);
-I_u2u1u3(_srl);
-I_u3u1u2(_subu);
-I_u2s3u1(_sw);
-I_0(_tlbp);
-I_0(_tlbwi);
-I_0(_tlbwr);
-I_u3u1u2(_xor)
-I_u2u1u3(_xori);
-
-/*
- * handling labels
- */
-
+/* Handle labels (which must be positive integers). */
enum label_id {
- label_invalid,
- label_second_part,
+ label_second_part = 1,
label_leave,
#ifdef MODULE_START
label_module_alloc,
@@ -447,278 +84,20 @@ enum label_id {
label_r3000_write_probe_fail,
};
-struct label {
- u32 *addr;
- enum label_id lab;
-};
-
-static void __init build_label(struct label **lab, u32 *addr,
- enum label_id l)
-{
- (*lab)->addr = addr;
- (*lab)->lab = l;
- (*lab)++;
-}
-
-#define L_LA(lb) \
- static inline void __init l##lb(struct label **lab, u32 *addr) \
- { \
- build_label(lab, addr, label##lb); \
- }
-
-L_LA(_second_part)
-L_LA(_leave)
+UASM_L_LA(_second_part)
+UASM_L_LA(_leave)
#ifdef MODULE_START
-L_LA(_module_alloc)
-#endif
-L_LA(_vmalloc)
-L_LA(_vmalloc_done)
-L_LA(_tlbw_hazard)
-L_LA(_split)
-L_LA(_nopage_tlbl)
-L_LA(_nopage_tlbs)
-L_LA(_nopage_tlbm)
-L_LA(_smp_pgtable_change)
-L_LA(_r3000_write_probe_fail)
-
-/* convenience macros for instructions */
-#ifdef CONFIG_64BIT
-# define i_LW(buf, rs, rt, off) i_ld(buf, rs, rt, off)
-# define i_SW(buf, rs, rt, off) i_sd(buf, rs, rt, off)
-# define i_SLL(buf, rs, rt, sh) i_dsll(buf, rs, rt, sh)
-# define i_SRA(buf, rs, rt, sh) i_dsra(buf, rs, rt, sh)
-# define i_SRL(buf, rs, rt, sh) i_dsrl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd...) i_dmfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd...) i_dmtc0(buf, rt, rd)
-# define i_ADDIU(buf, rs, rt, val) i_daddiu(buf, rs, rt, val)
-# define i_ADDU(buf, rs, rt, rd) i_daddu(buf, rs, rt, rd)
-# define i_SUBU(buf, rs, rt, rd) i_dsubu(buf, rs, rt, rd)
-# define i_LL(buf, rs, rt, off) i_lld(buf, rs, rt, off)
-# define i_SC(buf, rs, rt, off) i_scd(buf, rs, rt, off)
-#else
-# define i_LW(buf, rs, rt, off) i_lw(buf, rs, rt, off)
-# define i_SW(buf, rs, rt, off) i_sw(buf, rs, rt, off)
-# define i_SLL(buf, rs, rt, sh) i_sll(buf, rs, rt, sh)
-# define i_SRA(buf, rs, rt, sh) i_sra(buf, rs, rt, sh)
-# define i_SRL(buf, rs, rt, sh) i_srl(buf, rs, rt, sh)
-# define i_MFC0(buf, rt, rd...) i_mfc0(buf, rt, rd)
-# define i_MTC0(buf, rt, rd...) i_mtc0(buf, rt, rd)
-# define i_ADDIU(buf, rs, rt, val) i_addiu(buf, rs, rt, val)
-# define i_ADDU(buf, rs, rt, rd) i_addu(buf, rs, rt, rd)
-# define i_SUBU(buf, rs, rt, rd) i_subu(buf, rs, rt, rd)
-# define i_LL(buf, rs, rt, off) i_ll(buf, rs, rt, off)
-# define i_SC(buf, rs, rt, off) i_sc(buf, rs, rt, off)
-#endif
-
-#define i_b(buf, off) i_beq(buf, 0, 0, off)
-#define i_beqz(buf, rs, off) i_beq(buf, rs, 0, off)
-#define i_beqzl(buf, rs, off) i_beql(buf, rs, 0, off)
-#define i_bnez(buf, rs, off) i_bne(buf, rs, 0, off)
-#define i_bnezl(buf, rs, off) i_bnel(buf, rs, 0, off)
-#define i_move(buf, a, b) i_ADDU(buf, a, 0, b)
-#define i_nop(buf) i_sll(buf, 0, 0, 0)
-#define i_ssnop(buf) i_sll(buf, 0, 0, 1)
-#define i_ehb(buf) i_sll(buf, 0, 0, 3)
-
-static int __init __maybe_unused in_compat_space_p(long addr)
-{
- /* Is this address in 32bit compat space? */
-#ifdef CONFIG_64BIT
- return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
-#else
- return 1;
+UASM_L_LA(_module_alloc)
#endif
-}
-
-static int __init __maybe_unused rel_highest(long val)
-{
-#ifdef CONFIG_64BIT
- return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
-#else
- return 0;
-#endif
-}
-
-static int __init __maybe_unused rel_higher(long val)
-{
-#ifdef CONFIG_64BIT
- return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
-#else
- return 0;
-#endif
-}
-
-static int __init rel_hi(long val)
-{
- return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
-}
-
-static int __init rel_lo(long val)
-{
- return ((val & 0xffff) ^ 0x8000) - 0x8000;
-}
-
-static void __init i_LA_mostly(u32 **buf, unsigned int rs, long addr)
-{
- if (!in_compat_space_p(addr)) {
- i_lui(buf, rs, rel_highest(addr));
- if (rel_higher(addr))
- i_daddiu(buf, rs, rs, rel_higher(addr));
- if (rel_hi(addr)) {
- i_dsll(buf, rs, rs, 16);
- i_daddiu(buf, rs, rs, rel_hi(addr));
- i_dsll(buf, rs, rs, 16);
- } else
- i_dsll32(buf, rs, rs, 0);
- } else
- i_lui(buf, rs, rel_hi(addr));
-}
-
-static void __init __maybe_unused i_LA(u32 **buf, unsigned int rs, long addr)
-{
- i_LA_mostly(buf, rs, addr);
- if (rel_lo(addr)) {
- if (!in_compat_space_p(addr))
- i_daddiu(buf, rs, rs, rel_lo(addr));
- else
- i_addiu(buf, rs, rs, rel_lo(addr));
- }
-}
-
-/*
- * handle relocations
- */
-
-struct reloc {
- u32 *addr;
- unsigned int type;
- enum label_id lab;
-};
-
-static void __init r_mips_pc16(struct reloc **rel, u32 *addr,
- enum label_id l)
-{
- (*rel)->addr = addr;
- (*rel)->type = R_MIPS_PC16;
- (*rel)->lab = l;
- (*rel)++;
-}
-
-static inline void __resolve_relocs(struct reloc *rel, struct label *lab)
-{
- long laddr = (long)lab->addr;
- long raddr = (long)rel->addr;
-
- switch (rel->type) {
- case R_MIPS_PC16:
- *rel->addr |= build_bimm(laddr - (raddr + 4));
- break;
-
- default:
- panic("Unsupported TLB synthesizer relocation %d",
- rel->type);
- }
-}
-
-static void __init resolve_relocs(struct reloc *rel, struct label *lab)
-{
- struct label *l;
-
- for (; rel->lab != label_invalid; rel++)
- for (l = lab; l->lab != label_invalid; l++)
- if (rel->lab == l->lab)
- __resolve_relocs(rel, l);
-}
-
-static void __init move_relocs(struct reloc *rel, u32 *first, u32 *end,
- long off)
-{
- for (; rel->lab != label_invalid; rel++)
- if (rel->addr >= first && rel->addr < end)
- rel->addr += off;
-}
-
-static void __init move_labels(struct label *lab, u32 *first, u32 *end,
- long off)
-{
- for (; lab->lab != label_invalid; lab++)
- if (lab->addr >= first && lab->addr < end)
- lab->addr += off;
-}
-
-static void __init copy_handler(struct reloc *rel, struct label *lab,
- u32 *first, u32 *end, u32 *target)
-{
- long off = (long)(target - first);
-
- memcpy(target, first, (end - first) * sizeof(u32));
-
- move_relocs(rel, first, end, off);
- move_labels(lab, first, end, off);
-}
-
-static int __init __maybe_unused insn_has_bdelay(struct reloc *rel,
- u32 *addr)
-{
- for (; rel->lab != label_invalid; rel++) {
- if (rel->addr == addr
- && (rel->type == R_MIPS_PC16
- || rel->type == R_MIPS_26))
- return 1;
- }
-
- return 0;
-}
-
-/* convenience functions for labeled branches */
-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 __maybe_unused il_b(u32 **p, struct reloc **r,
- enum label_id l)
-{
- r_mips_pc16(r, *p, l);
- i_b(p, 0);
-}
-
-static void __init il_beqz(u32 **p, struct reloc **r, unsigned int reg,
- enum label_id l)
-{
- r_mips_pc16(r, *p, l);
- i_beqz(p, reg, 0);
-}
-
-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);
- i_beqzl(p, reg, 0);
-}
-
-static void __init il_bnez(u32 **p, struct reloc **r, unsigned int reg,
- enum label_id l)
-{
- r_mips_pc16(r, *p, l);
- i_bnez(p, reg, 0);
-}
-
-static void __init il_bgezl(u32 **p, struct reloc **r, unsigned int reg,
- enum label_id l)
-{
- r_mips_pc16(r, *p, l);
- i_bgezl(p, reg, 0);
-}
-
-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);
- i_bgez(p, reg, 0);
-}
+UASM_L_LA(_vmalloc)
+UASM_L_LA(_vmalloc_done)
+UASM_L_LA(_tlbw_hazard)
+UASM_L_LA(_split)
+UASM_L_LA(_nopage_tlbl)
+UASM_L_LA(_nopage_tlbs)
+UASM_L_LA(_nopage_tlbm)
+UASM_L_LA(_smp_pgtable_change)
+UASM_L_LA(_r3000_write_probe_fail)
/*
* For debug purposes.
@@ -752,9 +131,9 @@ static inline void dump_handler(const u32 *handler, int count)
#define C0_XCONTEXT 20, 0
#ifdef CONFIG_64BIT
-# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_XCONTEXT)
+# define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_XCONTEXT)
#else
-# define GET_CONTEXT(buf, reg) i_MFC0(buf, reg, C0_CONTEXT)
+# define GET_CONTEXT(buf, reg) UASM_i_MFC0(buf, reg, C0_CONTEXT)
#endif
/* The worst case length of the handler is around 18 instructions for
@@ -768,8 +147,8 @@ static inline void dump_handler(const u32 *handler, int count)
static u32 tlb_handler[128] __initdata;
/* simply assume worst case size for labels and relocs */
-static struct label labels[128] __initdata;
-static struct reloc relocs[128] __initdata;
+static struct uasm_label labels[128] __initdata;
+static struct uasm_reloc relocs[128] __initdata;
/*
* The R3000 TLB handler is simple.
@@ -782,29 +161,29 @@ static void __init build_r3000_tlb_refill_handler(void)
memset(tlb_handler, 0, sizeof(tlb_handler));
p = tlb_handler;
- i_mfc0(&p, K0, C0_BADVADDR);
- i_lui(&p, K1, rel_hi(pgdc)); /* cp0 delay */
- i_lw(&p, K1, rel_lo(pgdc), K1);
- i_srl(&p, K0, K0, 22); /* load delay */
- i_sll(&p, K0, K0, 2);
- i_addu(&p, K1, K1, K0);
- i_mfc0(&p, K0, C0_CONTEXT);
- i_lw(&p, K1, 0, K1); /* cp0 delay */
- i_andi(&p, K0, K0, 0xffc); /* load delay */
- i_addu(&p, K1, K1, K0);
- i_lw(&p, K0, 0, K1);
- i_nop(&p); /* load delay */
- i_mtc0(&p, K0, C0_ENTRYLO0);
- i_mfc0(&p, K1, C0_EPC); /* cp0 delay */
- i_tlbwr(&p); /* cp0 delay */
- i_jr(&p, K1);
- i_rfe(&p); /* branch delay */
+ uasm_i_mfc0(&p, K0, C0_BADVADDR);
+ uasm_i_lui(&p, K1, uasm_rel_hi(pgdc)); /* cp0 delay */
+ uasm_i_lw(&p, K1, uasm_rel_lo(pgdc), K1);
+ uasm_i_srl(&p, K0, K0, 22); /* load delay */
+ uasm_i_sll(&p, K0, K0, 2);
+ uasm_i_addu(&p, K1, K1, K0);
+ uasm_i_mfc0(&p, K0, C0_CONTEXT);
+ uasm_i_lw(&p, K1, 0, K1); /* cp0 delay */
+ uasm_i_andi(&p, K0, K0, 0xffc); /* load delay */
+ uasm_i_addu(&p, K1, K1, K0);
+ uasm_i_lw(&p, K0, 0, K1);
+ uasm_i_nop(&p); /* load delay */
+ uasm_i_mtc0(&p, K0, C0_ENTRYLO0);
+ uasm_i_mfc0(&p, K1, C0_EPC); /* cp0 delay */
+ uasm_i_tlbwr(&p); /* cp0 delay */
+ uasm_i_jr(&p, K1);
+ uasm_i_rfe(&p); /* branch delay */
if (p > tlb_handler + 32)
panic("TLB refill handler space exceeded");
- pr_info("Synthesized TLB refill handler (%u instructions).\n",
- (unsigned int)(p - tlb_handler));
+ pr_debug("Wrote TLB refill handler (%u instructions).\n",
+ (unsigned int)(p - tlb_handler));
memcpy((void *)ebase, tlb_handler, 0x80);
@@ -850,12 +229,12 @@ static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
case CPU_R5000:
case CPU_R5000A:
case CPU_NEVADA:
- i_nop(p);
- i_tlbp(p);
+ uasm_i_nop(p);
+ uasm_i_tlbp(p);
break;
default:
- i_tlbp(p);
+ uasm_i_tlbp(p);
break;
}
}
@@ -866,19 +245,19 @@ static void __init __maybe_unused build_tlb_probe_entry(u32 **p)
*/
enum tlb_write_entry { tlb_random, tlb_indexed };
-static void __init build_tlb_write_entry(u32 **p, struct label **l,
- struct reloc **r,
+static void __init build_tlb_write_entry(u32 **p, struct uasm_label **l,
+ struct uasm_reloc **r,
enum tlb_write_entry wmode)
{
void(*tlbw)(u32 **) = NULL;
switch (wmode) {
- case tlb_random: tlbw = i_tlbwr; break;
- case tlb_indexed: tlbw = i_tlbwi; break;
+ case tlb_random: tlbw = uasm_i_tlbwr; break;
+ case tlb_indexed: tlbw = uasm_i_tlbwi; break;
}
if (cpu_has_mips_r2) {
- i_ehb(p);
+ uasm_i_ehb(p);
tlbw(p);
return;
}
@@ -894,19 +273,19 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
* This branch uses up a mtc0 hazard nop slot and saves
* two nops after the tlbw instruction.
*/
- il_bgezl(p, r, 0, label_tlbw_hazard);
+ uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
tlbw(p);
- l_tlbw_hazard(l, *p);
- i_nop(p);
+ uasm_l_tlbw_hazard(l, *p);
+ uasm_i_nop(p);
break;
case CPU_R4600:
case CPU_R4700:
case CPU_R5000:
case CPU_R5000A:
- i_nop(p);
+ uasm_i_nop(p);
tlbw(p);
- i_nop(p);
+ uasm_i_nop(p);
break;
case CPU_R4300:
@@ -920,7 +299,7 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
case CPU_AU1210:
case CPU_AU1250:
case CPU_PR4450:
- i_nop(p);
+ uasm_i_nop(p);
tlbw(p);
break;
@@ -937,26 +316,26 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
case CPU_BCM4710:
case CPU_LOONGSON2:
if (m4kc_tlbp_war())
- i_nop(p);
+ uasm_i_nop(p);
tlbw(p);
break;
case CPU_NEVADA:
- i_nop(p); /* QED specifies 2 nops hazard */
+ uasm_i_nop(p); /* QED specifies 2 nops hazard */
/*
* This branch uses up a mtc0 hazard nop slot and saves
* a nop after the tlbw instruction.
*/
- il_bgezl(p, r, 0, label_tlbw_hazard);
+ uasm_il_bgezl(p, r, 0, label_tlbw_hazard);
tlbw(p);
- l_tlbw_hazard(l, *p);
+ uasm_l_tlbw_hazard(l, *p);
break;
case CPU_RM7000:
- i_nop(p);
- i_nop(p);
- i_nop(p);
- i_nop(p);
+ uasm_i_nop(p);
+ uasm_i_nop(p);
+ uasm_i_nop(p);
+ uasm_i_nop(p);
tlbw(p);
break;
@@ -967,15 +346,15 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
* cpu cycles and use for data translations should not occur
* for 3 cpu cycles.
*/
- i_ssnop(p);
- i_ssnop(p);
- i_ssnop(p);
- i_ssnop(p);
+ uasm_i_ssnop(p);
+ uasm_i_ssnop(p);
+ uasm_i_ssnop(p);
+ uasm_i_ssnop(p);
tlbw(p);
- i_ssnop(p);
- i_ssnop(p);
- i_ssnop(p);
- i_ssnop(p);
+ uasm_i_ssnop(p);
+ uasm_i_ssnop(p);
+ uasm_i_ssnop(p);
+ uasm_i_ssnop(p);
break;
case CPU_VR4111:
@@ -983,18 +362,18 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
case CPU_VR4122:
case CPU_VR4181:
case CPU_VR4181A:
- i_nop(p);
- i_nop(p);
+ uasm_i_nop(p);
+ uasm_i_nop(p);
tlbw(p);
- i_nop(p);
- i_nop(p);
+ uasm_i_nop(p);
+ uasm_i_nop(p);
break;
case CPU_VR4131:
case CPU_VR4133:
case CPU_R5432:
- i_nop(p);
- i_nop(p);
+ uasm_i_nop(p);
+ uasm_i_nop(p);
tlbw(p);
break;
@@ -1011,7 +390,7 @@ static void __init build_tlb_write_entry(u32 **p, struct label **l,
* TMP will be clobbered, PTR will hold the pmd entry.
*/
static void __init
-build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
+build_get_pmde64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
unsigned int tmp, unsigned int ptr)
{
long pgdc = (long)pgd_current;
@@ -1019,52 +398,52 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
/*
* The vmalloc handling is not in the hotpath.
*/
- i_dmfc0(p, tmp, C0_BADVADDR);
+ uasm_i_dmfc0(p, tmp, C0_BADVADDR);
#ifdef MODULE_START
- il_bltz(p, r, tmp, label_module_alloc);
+ uasm_il_bltz(p, r, tmp, label_module_alloc);
#else
- il_bltz(p, r, tmp, label_vmalloc);
+ uasm_il_bltz(p, r, tmp, label_vmalloc);
#endif
- /* No i_nop needed here, since the next insn doesn't touch TMP. */
+ /* No uasm_i_nop needed here, since the next insn doesn't touch TMP. */
#ifdef CONFIG_SMP
# ifdef CONFIG_MIPS_MT_SMTC
/*
* SMTC uses TCBind value as "CPU" index
*/
- i_mfc0(p, ptr, C0_TCBIND);
- i_dsrl(p, ptr, ptr, 19);
+ uasm_i_mfc0(p, ptr, C0_TCBIND);
+ uasm_i_dsrl(p, ptr, ptr, 19);
# else
/*
* 64 bit SMP running in XKPHYS has smp_processor_id() << 3
* stored in CONTEXT.
*/
- i_dmfc0(p, ptr, C0_CONTEXT);
- i_dsrl(p, ptr, ptr, 23);
+ uasm_i_dmfc0(p, ptr, C0_CONTEXT);
+ uasm_i_dsrl(p, ptr, ptr, 23);
#endif
- i_LA_mostly(p, tmp, pgdc);
- i_daddu(p, ptr, ptr, tmp);
- i_dmfc0(p, tmp, C0_BADVADDR);
- i_ld(p, ptr, rel_lo(pgdc), ptr);
+ UASM_i_LA_mostly(p, tmp, pgdc);
+ uasm_i_daddu(p, ptr, ptr, tmp);
+ uasm_i_dmfc0(p, tmp, C0_BADVADDR);
+ uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
#else
- i_LA_mostly(p, ptr, pgdc);
- i_ld(p, ptr, rel_lo(pgdc), ptr);
+ UASM_i_LA_mostly(p, ptr, pgdc);
+ uasm_i_ld(p, ptr, uasm_rel_lo(pgdc), ptr);
#endif
- l_vmalloc_done(l, *p);
+ uasm_l_vmalloc_done(l, *p);
if (PGDIR_SHIFT - 3 < 32) /* get pgd offset in bytes */
- i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3);
+ uasm_i_dsrl(p, tmp, tmp, PGDIR_SHIFT-3);
else
- i_dsrl32(p, tmp, tmp, PGDIR_SHIFT - 3 - 32);
-
- i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
- i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
- i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
- i_ld(p, ptr, 0, ptr); /* get pmd pointer */
- i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
- i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
- i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
+ uasm_i_dsrl32(p, tmp, tmp, PGDIR_SHIFT - 3 - 32);
+
+ uasm_i_andi(p, tmp, tmp, (PTRS_PER_PGD - 1)<<3);
+ uasm_i_daddu(p, ptr, ptr, tmp); /* add in pgd offset */
+ uasm_i_dmfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+ uasm_i_ld(p, ptr, 0, ptr); /* get pmd pointer */
+ uasm_i_dsrl(p, tmp, tmp, PMD_SHIFT-3); /* get pmd offset in bytes */
+ uasm_i_andi(p, tmp, tmp, (PTRS_PER_PMD - 1)<<3);
+ uasm_i_daddu(p, ptr, ptr, tmp); /* add in pmd offset */
}
/*
@@ -1072,7 +451,7 @@ build_get_pmde64(u32 **p, struct label **l, struct reloc **r,
* PTR will hold the pgd for vmalloc.
*/
static void __init
-build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
+build_get_pgd_vmalloc64(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
unsigned int bvaddr, unsigned int ptr)
{
long swpd = (long)swapper_pg_dir;
@@ -1080,58 +459,60 @@ build_get_pgd_vmalloc64(u32 **p, struct label **l, struct reloc **r,
#ifdef MODULE_START
long modd = (long)module_pg_dir;
- l_module_alloc(l, *p);
+ uasm_l_module_alloc(l, *p);
/*
* Assumption:
* VMALLOC_START >= 0xc000000000000000UL
* MODULE_START >= 0xe000000000000000UL
*/
- i_SLL(p, ptr, bvaddr, 2);
- il_bgez(p, r, ptr, label_vmalloc);
+ UASM_i_SLL(p, ptr, bvaddr, 2);
+ uasm_il_bgez(p, r, ptr, label_vmalloc);
- if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START)) {
- i_lui(p, ptr, rel_hi(MODULE_START)); /* delay slot */
+ if (uasm_in_compat_space_p(MODULE_START) &&
+ !uasm_rel_lo(MODULE_START)) {
+ uasm_i_lui(p, ptr, uasm_rel_hi(MODULE_START)); /* delay slot */
} else {
/* unlikely configuration */
- i_nop(p); /* delay slot */
- i_LA(p, ptr, MODULE_START);
+ uasm_i_nop(p); /* delay slot */
+ UASM_i_LA(p, ptr, MODULE_START);
}
- i_dsubu(p, bvaddr, bvaddr, ptr);
+ uasm_i_dsubu(p, bvaddr, bvaddr, ptr);
- if (in_compat_space_p(modd) && !rel_lo(modd)) {
- il_b(p, r, label_vmalloc_done);
- i_lui(p, ptr, rel_hi(modd));
+ if (uasm_in_compat_space_p(modd) && !uasm_rel_lo(modd)) {
+ uasm_il_b(p, r, label_vmalloc_done);
+ uasm_i_lui(p, ptr, uasm_rel_hi(modd));
} else {
- i_LA_mostly(p, ptr, modd);
- il_b(p, r, label_vmalloc_done);
- if (in_compat_space_p(modd))
- i_addiu(p, ptr, ptr, rel_lo(modd));
+ UASM_i_LA_mostly(p, ptr, modd);
+ uasm_il_b(p, r, label_vmalloc_done);
+ if (uasm_in_compat_space_p(modd))
+ uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(modd));
else
- i_daddiu(p, ptr, ptr, rel_lo(modd));
+ uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(modd));
}
- l_vmalloc(l, *p);
- if (in_compat_space_p(MODULE_START) && !rel_lo(MODULE_START) &&
+ uasm_l_vmalloc(l, *p);
+ if (uasm_in_compat_space_p(MODULE_START) &&
+ !uasm_rel_lo(MODULE_START) &&
MODULE_START << 32 == VMALLOC_START)
- i_dsll32(p, ptr, ptr, 0); /* typical case */
+ uasm_i_dsll32(p, ptr, ptr, 0); /* typical case */
else
- i_LA(p, ptr, VMALLOC_START);
+ UASM_i_LA(p, ptr, VMALLOC_START);
#else
- l_vmalloc(l, *p);
- i_LA(p, ptr, VMALLOC_START);
+ uasm_l_vmalloc(l, *p);
+ UASM_i_LA(p, ptr, VMALLOC_START);
#endif
- i_dsubu(p, bvaddr, bvaddr, ptr);
+ uasm_i_dsubu(p, bvaddr, bvaddr, ptr);
- if (in_compat_space_p(swpd) && !rel_lo(swpd)) {
- il_b(p, r, label_vmalloc_done);
- i_lui(p, ptr, rel_hi(swpd));
+ if (uasm_in_compat_space_p(swpd) && !uasm_rel_lo(swpd)) {
+ uasm_il_b(p, r, label_vmalloc_done);
+ uasm_i_lui(p, ptr, uasm_rel_hi(swpd));
} else {
- i_LA_mostly(p, ptr, swpd);
- il_b(p, r, label_vmalloc_done);
- if (in_compat_space_p(swpd))
- i_addiu(p, ptr, ptr, rel_lo(swpd));
+ UASM_i_LA_mostly(p, ptr, swpd);
+ uasm_il_b(p, r, label_vmalloc_done);
+ if (uasm_in_compat_space_p(swpd))
+ uasm_i_addiu(p, ptr, ptr, uasm_rel_lo(swpd));
else
- i_daddiu(p, ptr, ptr, rel_lo(swpd));
+ uasm_i_daddiu(p, ptr, ptr, uasm_rel_lo(swpd));
}
}
@@ -1152,26 +533,26 @@ build_get_pgde32(u32 **p, unsigned int tmp, unsigned int ptr)
/*
* SMTC uses TCBind value as "CPU" index
*/
- i_mfc0(p, ptr, C0_TCBIND);
- i_LA_mostly(p, tmp, pgdc);
- i_srl(p, ptr, ptr, 19);
+ uasm_i_mfc0(p, ptr, C0_TCBIND);
+ UASM_i_LA_mostly(p, tmp, pgdc);
+ uasm_i_srl(p, ptr, ptr, 19);
#else
/*
* smp_processor_id() << 3 is stored in CONTEXT.
*/
- i_mfc0(p, ptr, C0_CONTEXT);
- i_LA_mostly(p, tmp, pgdc);
- i_srl(p, ptr, ptr, 23);
+ uasm_i_mfc0(p, ptr, C0_CONTEXT);
+ UASM_i_LA_mostly(p, tmp, pgdc);
+ uasm_i_srl(p, ptr, ptr, 23);
#endif
- i_addu(p, ptr, tmp, ptr);
+ uasm_i_addu(p, ptr, tmp, ptr);
#else
- i_LA_mostly(p, ptr, pgdc);
+ UASM_i_LA_mostly(p, ptr, pgdc);
#endif
- i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
- i_lw(p, ptr, rel_lo(pgdc), ptr);
- i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
- i_sll(p, tmp, tmp, PGD_T_LOG2);
- i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
+ uasm_i_mfc0(p, tmp, C0_BADVADDR); /* get faulting address */
+ uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+ uasm_i_srl(p, tmp, tmp, PGDIR_SHIFT); /* get pgd only bits */
+ uasm_i_sll(p, tmp, tmp, PGD_T_LOG2);
+ uasm_i_addu(p, ptr, ptr, tmp); /* add in pgd offset */
}
#endif /* !CONFIG_64BIT */
@@ -1198,8 +579,8 @@ static void __init build_adjust_context(u32 **p, unsigned int ctx)
}
if (shift)
- i_SRL(p, ctx, ctx, shift);
- i_andi(p, ctx, ctx, mask);
+ UASM_i_SRL(p, ctx, ctx, shift);
+ uasm_i_andi(p, ctx, ctx, mask);
}
static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
@@ -1213,18 +594,18 @@ static void __init build_get_ptep(u32 **p, unsigned int tmp, unsigned int ptr)
*/
switch (current_cpu_type()) {
case CPU_NEVADA:
- i_LW(p, ptr, 0, ptr);
+ UASM_i_LW(p, ptr, 0, ptr);
GET_CONTEXT(p, tmp); /* get context reg */
break;
default:
GET_CONTEXT(p, tmp); /* get context reg */
- i_LW(p, ptr, 0, ptr);
+ UASM_i_LW(p, ptr, 0, ptr);
break;
}
build_adjust_context(p, tmp);
- i_ADDU(p, ptr, ptr, tmp); /* add in offset */
+ UASM_i_ADDU(p, ptr, ptr, tmp); /* add in offset */
}
static void __init build_update_entries(u32 **p, unsigned int tmp,
@@ -1236,45 +617,45 @@ static void __init build_update_entries(u32 **p, unsigned int tmp,
*/
#ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits) {
- i_ld(p, tmp, 0, ptep); /* get even pte */
- i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
- i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
- i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
- i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
- i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+ uasm_i_ld(p, tmp, 0, ptep); /* get even pte */
+ uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+ uasm_i_dsrl(p, tmp, tmp, 6); /* convert to entrylo0 */
+ uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+ uasm_i_dsrl(p, ptep, ptep, 6); /* convert to entrylo1 */
+ uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
} else {
int pte_off_even = sizeof(pte_t) / 2;
int pte_off_odd = pte_off_even + sizeof(pte_t);
/* The pte entries are pre-shifted */
- i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
- i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
- i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
- i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+ uasm_i_lw(p, tmp, pte_off_even, ptep); /* get even pte */
+ uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+ uasm_i_lw(p, ptep, pte_off_odd, ptep); /* get odd pte */
+ uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
}
#else
- i_LW(p, tmp, 0, ptep); /* get even pte */
- i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
+ UASM_i_LW(p, tmp, 0, ptep); /* get even pte */
+ UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
if (r45k_bvahwbug())
build_tlb_probe_entry(p);
- i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
+ UASM_i_SRL(p, tmp, tmp, 6); /* convert to entrylo0 */
if (r4k_250MHZhwbug())
- i_mtc0(p, 0, C0_ENTRYLO0);
- i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
- i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
+ uasm_i_mtc0(p, 0, C0_ENTRYLO0);
+ uasm_i_mtc0(p, tmp, C0_ENTRYLO0); /* load it */
+ UASM_i_SRL(p, ptep, ptep, 6); /* convert to entrylo1 */
if (r45k_bvahwbug())
- i_mfc0(p, tmp, C0_INDEX);
+ uasm_i_mfc0(p, tmp, C0_INDEX);
if (r4k_250MHZhwbug())
- i_mtc0(p, 0, C0_ENTRYLO1);
- i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
+ uasm_i_mtc0(p, 0, C0_ENTRYLO1);
+ uasm_i_mtc0(p, ptep, C0_ENTRYLO1); /* load it */
#endif
}
static void __init build_r4000_tlb_refill_handler(void)
{
u32 *p = tlb_handler;
- struct label *l = labels;
- struct reloc *r = relocs;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
u32 *f;
unsigned int final_len;
@@ -1287,12 +668,12 @@ static void __init build_r4000_tlb_refill_handler(void)
* create the plain linear handler
*/
if (bcm1250_m3_war()) {
- i_MFC0(&p, K0, C0_BADVADDR);
- i_MFC0(&p, K1, C0_ENTRYHI);
- i_xor(&p, K0, K0, K1);
- i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
- il_bnez(&p, &r, K0, label_leave);
- /* No need for i_nop */
+ UASM_i_MFC0(&p, K0, C0_BADVADDR);
+ UASM_i_MFC0(&p, K1, C0_ENTRYHI);
+ uasm_i_xor(&p, K0, K0, K1);
+ UASM_i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
+ uasm_il_bnez(&p, &r, K0, label_leave);
+ /* No need for uasm_i_nop */
}
#ifdef CONFIG_64BIT
@@ -1304,8 +685,8 @@ static void __init build_r4000_tlb_refill_handler(void)
build_get_ptep(&p, K0, K1);
build_update_entries(&p, K0, K1);
build_tlb_write_entry(&p, &l, &r, tlb_random);
- l_leave(&l, p);
- i_eret(&p); /* return from trap */
+ uasm_l_leave(&l, p);
+ uasm_i_eret(&p); /* return from trap */
#ifdef CONFIG_64BIT
build_get_pgd_vmalloc64(&p, &l, &r, K0, K1);
@@ -1325,7 +706,7 @@ static void __init build_r4000_tlb_refill_handler(void)
#else
if (((p - tlb_handler) > 63)
|| (((p - tlb_handler) > 61)
- && insn_has_bdelay(relocs, tlb_handler + 29)))
+ && uasm_insn_has_bdelay(relocs, tlb_handler + 29)))
panic("TLB refill handler space exceeded");
#endif
@@ -1335,13 +716,13 @@ static void __init build_r4000_tlb_refill_handler(void)
#if defined(CONFIG_32BIT) || defined(CONFIG_CPU_LOONGSON2)
f = final_handler;
/* Simplest case, just copy the handler. */
- copy_handler(relocs, labels, tlb_handler, p, f);
+ uasm_copy_handler(relocs, labels, tlb_handler, p, f);
final_len = p - tlb_handler;
#else /* CONFIG_64BIT */
f = final_handler + 32;
if ((p - tlb_handler) <= 32) {
/* Just copy the handler. */
- copy_handler(relocs, labels, tlb_handler, p, f);
+ uasm_copy_handler(relocs, labels, tlb_handler, p, f);
final_len = p - tlb_handler;
} else {
u32 *split = tlb_handler + 30;
@@ -1349,34 +730,34 @@ static void __init build_r4000_tlb_refill_handler(void)
/*
* Find the split point.
*/
- if (insn_has_bdelay(relocs, split - 1))
+ if (uasm_insn_has_bdelay(relocs, split - 1))
split--;
/* Copy first part of the handler. */
- copy_handler(relocs, labels, tlb_handler, split, f);
+ uasm_copy_handler(relocs, labels, tlb_handler, split, f);
f += split - tlb_handler;
/* Insert branch. */
- l_split(&l, final_handler);
- il_b(&f, &r, label_split);
- if (insn_has_bdelay(relocs, split))
- i_nop(&f);
+ uasm_l_split(&l, final_handler);
+ uasm_il_b(&f, &r, label_split);
+ if (uasm_insn_has_bdelay(relocs, split))
+ uasm_i_nop(&f);
else {
- copy_handler(relocs, labels, split, split + 1, f);
- move_labels(labels, f, f + 1, -1);
+ uasm_copy_handler(relocs, labels, split, split + 1, f);
+ uasm_move_labels(labels, f, f + 1, -1);
f++;
split++;
}
/* Copy the rest of the handler. */
- copy_handler(relocs, labels, split, p, final_handler);
+ uasm_copy_handler(relocs, labels, split, p, final_handler);
final_len = (f - (final_handler + 32)) + (p - split);
}
#endif /* CONFIG_64BIT */
- resolve_relocs(relocs, labels);
- pr_info("Synthesized TLB refill handler (%u instructions).\n",
- final_len);
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote TLB refill handler (%u instructions).\n",
+ final_len);
memcpy((void *)ebase, final_handler, 0x100);
@@ -1403,75 +784,75 @@ u32 handle_tlbs[FASTPATH_SIZE] __cacheline_aligned;
u32 handle_tlbm[FASTPATH_SIZE] __cacheline_aligned;
static void __init
-iPTE_LW(u32 **p, struct label **l, unsigned int pte, unsigned int ptr)
+iPTE_LW(u32 **p, struct uasm_label **l, unsigned int pte, unsigned int ptr)
{
#ifdef CONFIG_SMP
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
- i_lld(p, pte, 0, ptr);
+ uasm_i_lld(p, pte, 0, ptr);
else
# endif
- i_LL(p, pte, 0, ptr);
+ UASM_i_LL(p, pte, 0, ptr);
#else
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
- i_ld(p, pte, 0, ptr);
+ uasm_i_ld(p, pte, 0, ptr);
else
# endif
- i_LW(p, pte, 0, ptr);
+ UASM_i_LW(p, pte, 0, ptr);
#endif
}
static void __init
-iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr,
+iPTE_SW(u32 **p, struct uasm_reloc **r, unsigned int pte, unsigned int ptr,
unsigned int mode)
{
#ifdef CONFIG_64BIT_PHYS_ADDR
unsigned int hwmode = mode & (_PAGE_VALID | _PAGE_DIRTY);
#endif
- i_ori(p, pte, pte, mode);
+ uasm_i_ori(p, pte, pte, mode);
#ifdef CONFIG_SMP
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
- i_scd(p, pte, 0, ptr);
+ uasm_i_scd(p, pte, 0, ptr);
else
# endif
- i_SC(p, pte, 0, ptr);
+ UASM_i_SC(p, pte, 0, ptr);
if (r10000_llsc_war())
- il_beqzl(p, r, pte, label_smp_pgtable_change);
+ uasm_il_beqzl(p, r, pte, label_smp_pgtable_change);
else
- il_beqz(p, r, pte, label_smp_pgtable_change);
+ uasm_il_beqz(p, r, pte, label_smp_pgtable_change);
# ifdef CONFIG_64BIT_PHYS_ADDR
if (!cpu_has_64bits) {
- /* no i_nop needed */
- i_ll(p, pte, sizeof(pte_t) / 2, ptr);
- i_ori(p, pte, pte, hwmode);
- i_sc(p, pte, sizeof(pte_t) / 2, ptr);
- il_beqz(p, r, pte, label_smp_pgtable_change);
- /* no i_nop needed */
- i_lw(p, pte, 0, ptr);
+ /* no uasm_i_nop needed */
+ uasm_i_ll(p, pte, sizeof(pte_t) / 2, ptr);
+ uasm_i_ori(p, pte, pte, hwmode);
+ uasm_i_sc(p, pte, sizeof(pte_t) / 2, ptr);
+ uasm_il_beqz(p, r, pte, label_smp_pgtable_change);
+ /* no uasm_i_nop needed */
+ uasm_i_lw(p, pte, 0, ptr);
} else
- i_nop(p);
+ uasm_i_nop(p);
# else
- i_nop(p);
+ uasm_i_nop(p);
# endif
#else
# ifdef CONFIG_64BIT_PHYS_ADDR
if (cpu_has_64bits)
- i_sd(p, pte, 0, ptr);
+ uasm_i_sd(p, pte, 0, ptr);
else
# endif
- i_SW(p, pte, 0, ptr);
+ UASM_i_SW(p, pte, 0, ptr);
# ifdef CONFIG_64BIT_PHYS_ADDR
if (!cpu_has_64bits) {
- i_lw(p, pte, sizeof(pte_t) / 2, ptr);
- i_ori(p, pte, pte, hwmode);
- i_sw(p, pte, sizeof(pte_t) / 2, ptr);
- i_lw(p, pte, 0, ptr);
+ uasm_i_lw(p, pte, sizeof(pte_t) / 2, ptr);
+ uasm_i_ori(p, pte, pte, hwmode);
+ uasm_i_sw(p, pte, sizeof(pte_t) / 2, ptr);
+ uasm_i_lw(p, pte, 0, ptr);
}
# endif
#endif
@@ -1483,18 +864,18 @@ iPTE_SW(u32 **p, struct reloc **r, unsigned int pte, unsigned int ptr,
* with it's original value.
*/
static void __init
-build_pte_present(u32 **p, struct label **l, struct reloc **r,
+build_pte_present(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
- i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
- i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
- il_bnez(p, r, pte, lid);
+ uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
+ uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_READ);
+ uasm_il_bnez(p, r, pte, lid);
iPTE_LW(p, l, pte, ptr);
}
/* Make PTE valid, store result in PTR. */
static void __init
-build_make_valid(u32 **p, struct reloc **r, unsigned int pte,
+build_make_valid(u32 **p, struct uasm_reloc **r, unsigned int pte,
unsigned int ptr)
{
unsigned int mode = _PAGE_VALID | _PAGE_ACCESSED;
@@ -1507,12 +888,12 @@ build_make_valid(u32 **p, struct reloc **r, unsigned int pte,
* restore PTE with value from PTR when done.
*/
static void __init
-build_pte_writable(u32 **p, struct label **l, struct reloc **r,
+build_pte_writable(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
- i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
- i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
- il_bnez(p, r, pte, lid);
+ uasm_i_andi(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+ uasm_i_xori(p, pte, pte, _PAGE_PRESENT | _PAGE_WRITE);
+ uasm_il_bnez(p, r, pte, lid);
iPTE_LW(p, l, pte, ptr);
}
@@ -1520,7 +901,7 @@ build_pte_writable(u32 **p, struct label **l, struct reloc **r,
* at PTR.
*/
static void __init
-build_make_write(u32 **p, struct reloc **r, unsigned int pte,
+build_make_write(u32 **p, struct uasm_reloc **r, unsigned int pte,
unsigned int ptr)
{
unsigned int mode = (_PAGE_ACCESSED | _PAGE_MODIFIED | _PAGE_VALID
@@ -1534,11 +915,11 @@ build_make_write(u32 **p, struct reloc **r, unsigned int pte,
* restore PTE with value from PTR when done.
*/
static void __init
-build_pte_modifiable(u32 **p, struct label **l, struct reloc **r,
+build_pte_modifiable(u32 **p, struct uasm_label **l, struct uasm_reloc **r,
unsigned int pte, unsigned int ptr, enum label_id lid)
{
- i_andi(p, pte, pte, _PAGE_WRITE);
- il_beqz(p, r, pte, lid);
+ uasm_i_andi(p, pte, pte, _PAGE_WRITE);
+ uasm_il_beqz(p, r, pte, lid);
iPTE_LW(p, l, pte, ptr);
}
@@ -1553,11 +934,11 @@ build_pte_modifiable(u32 **p, struct label **l, struct reloc **r,
static void __init
build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp)
{
- i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
- i_mfc0(p, tmp, C0_EPC); /* cp0 delay */
- i_tlbwi(p);
- i_jr(p, tmp);
- i_rfe(p); /* branch delay */
+ uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
+ uasm_i_mfc0(p, tmp, C0_EPC); /* cp0 delay */
+ uasm_i_tlbwi(p);
+ uasm_i_jr(p, tmp);
+ uasm_i_rfe(p); /* branch delay */
}
/*
@@ -1567,20 +948,21 @@ build_r3000_pte_reload_tlbwi(u32 **p, unsigned int pte, unsigned int tmp)
* kseg2 access, i.e. without refill. Then it returns.
*/
static void __init
-build_r3000_tlb_reload_write(u32 **p, struct label **l, struct reloc **r,
- unsigned int pte, unsigned int tmp)
-{
- i_mfc0(p, tmp, C0_INDEX);
- i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
- il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */
- i_mfc0(p, tmp, C0_EPC); /* branch delay */
- i_tlbwi(p); /* cp0 delay */
- i_jr(p, tmp);
- i_rfe(p); /* branch delay */
- l_r3000_write_probe_fail(l, *p);
- i_tlbwr(p); /* cp0 delay */
- i_jr(p, tmp);
- i_rfe(p); /* branch delay */
+build_r3000_tlb_reload_write(u32 **p, struct uasm_label **l,
+ struct uasm_reloc **r, unsigned int pte,
+ unsigned int tmp)
+{
+ uasm_i_mfc0(p, tmp, C0_INDEX);
+ uasm_i_mtc0(p, pte, C0_ENTRYLO0); /* cp0 delay */
+ uasm_il_bltz(p, r, tmp, label_r3000_write_probe_fail); /* cp0 delay */
+ uasm_i_mfc0(p, tmp, C0_EPC); /* branch delay */
+ uasm_i_tlbwi(p); /* cp0 delay */
+ uasm_i_jr(p, tmp);
+ uasm_i_rfe(p); /* branch delay */
+ uasm_l_r3000_write_probe_fail(l, *p);
+ uasm_i_tlbwr(p); /* cp0 delay */
+ uasm_i_jr(p, tmp);
+ uasm_i_rfe(p); /* branch delay */
}
static void __init
@@ -1589,25 +971,25 @@ build_r3000_tlbchange_handler_head(u32 **p, unsigned int pte,
{
long pgdc = (long)pgd_current;
- i_mfc0(p, pte, C0_BADVADDR);
- i_lui(p, ptr, rel_hi(pgdc)); /* cp0 delay */
- i_lw(p, ptr, rel_lo(pgdc), ptr);
- i_srl(p, pte, pte, 22); /* load delay */
- i_sll(p, pte, pte, 2);
- i_addu(p, ptr, ptr, pte);
- i_mfc0(p, pte, C0_CONTEXT);
- i_lw(p, ptr, 0, ptr); /* cp0 delay */
- i_andi(p, pte, pte, 0xffc); /* load delay */
- i_addu(p, ptr, ptr, pte);
- i_lw(p, pte, 0, ptr);
- i_tlbp(p); /* load delay */
+ uasm_i_mfc0(p, pte, C0_BADVADDR);
+ uasm_i_lui(p, ptr, uasm_rel_hi(pgdc)); /* cp0 delay */
+ uasm_i_lw(p, ptr, uasm_rel_lo(pgdc), ptr);
+ uasm_i_srl(p, pte, pte, 22); /* load delay */
+ uasm_i_sll(p, pte, pte, 2);
+ uasm_i_addu(p, ptr, ptr, pte);
+ uasm_i_mfc0(p, pte, C0_CONTEXT);
+ uasm_i_lw(p, ptr, 0, ptr); /* cp0 delay */
+ uasm_i_andi(p, pte, pte, 0xffc); /* load delay */
+ uasm_i_addu(p, ptr, ptr, pte);
+ uasm_i_lw(p, pte, 0, ptr);
+ uasm_i_tlbp(p); /* load delay */
}
static void __init build_r3000_tlb_load_handler(void)
{
u32 *p = handle_tlbl;
- struct label *l = labels;
- struct reloc *r = relocs;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
memset(handle_tlbl, 0, sizeof(handle_tlbl));
memset(labels, 0, sizeof(labels));
@@ -1615,20 +997,20 @@ static void __init build_r3000_tlb_load_handler(void)
build_r3000_tlbchange_handler_head(&p, K0, K1);
build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
- i_nop(&p); /* load delay */
+ uasm_i_nop(&p); /* load delay */
build_make_valid(&p, &r, K0, K1);
build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
- l_nopage_tlbl(&l, p);
- i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
- i_nop(&p);
+ uasm_l_nopage_tlbl(&l, p);
+ uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
+ uasm_i_nop(&p);
if ((p - handle_tlbl) > FASTPATH_SIZE)
panic("TLB load handler fastpath space exceeded");
- resolve_relocs(relocs, labels);
- pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbl));
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbl));
dump_handler(handle_tlbl, ARRAY_SIZE(handle_tlbl));
}
@@ -1636,8 +1018,8 @@ static void __init build_r3000_tlb_load_handler(void)
static void __init build_r3000_tlb_store_handler(void)
{
u32 *p = handle_tlbs;
- struct label *l = labels;
- struct reloc *r = relocs;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
memset(handle_tlbs, 0, sizeof(handle_tlbs));
memset(labels, 0, sizeof(labels));
@@ -1645,20 +1027,20 @@ static void __init build_r3000_tlb_store_handler(void)
build_r3000_tlbchange_handler_head(&p, K0, K1);
build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
- i_nop(&p); /* load delay */
+ uasm_i_nop(&p); /* load delay */
build_make_write(&p, &r, K0, K1);
build_r3000_tlb_reload_write(&p, &l, &r, K0, K1);
- l_nopage_tlbs(&l, p);
- i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
- i_nop(&p);
+ uasm_l_nopage_tlbs(&l, p);
+ uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+ uasm_i_nop(&p);
if ((p - handle_tlbs) > FASTPATH_SIZE)
panic("TLB store handler fastpath space exceeded");
- resolve_relocs(relocs, labels);
- pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbs));
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbs));
dump_handler(handle_tlbs, ARRAY_SIZE(handle_tlbs));
}
@@ -1666,8 +1048,8 @@ static void __init build_r3000_tlb_store_handler(void)
static void __init build_r3000_tlb_modify_handler(void)
{
u32 *p = handle_tlbm;
- struct label *l = labels;
- struct reloc *r = relocs;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
memset(handle_tlbm, 0, sizeof(handle_tlbm));
memset(labels, 0, sizeof(labels));
@@ -1675,20 +1057,20 @@ static void __init build_r3000_tlb_modify_handler(void)
build_r3000_tlbchange_handler_head(&p, K0, K1);
build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
- i_nop(&p); /* load delay */
+ uasm_i_nop(&p); /* load delay */
build_make_write(&p, &r, K0, K1);
build_r3000_pte_reload_tlbwi(&p, K0, K1);
- l_nopage_tlbm(&l, p);
- i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
- i_nop(&p);
+ uasm_l_nopage_tlbm(&l, p);
+ uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+ uasm_i_nop(&p);
if ((p - handle_tlbm) > FASTPATH_SIZE)
panic("TLB modify handler fastpath space exceeded");
- resolve_relocs(relocs, labels);
- pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbm));
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbm));
dump_handler(handle_tlbm, ARRAY_SIZE(handle_tlbm));
}
@@ -1697,8 +1079,8 @@ static void __init build_r3000_tlb_modify_handler(void)
* R4000 style TLB load/store/modify handlers.
*/
static void __init
-build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
- struct reloc **r, unsigned int pte,
+build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l,
+ struct uasm_reloc **r, unsigned int pte,
unsigned int ptr)
{
#ifdef CONFIG_64BIT
@@ -1707,31 +1089,31 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
build_get_pgde32(p, pte, ptr); /* get pgd in ptr */
#endif
- i_MFC0(p, pte, C0_BADVADDR);
- i_LW(p, ptr, 0, ptr);
- i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
- i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
- i_ADDU(p, ptr, ptr, pte);
+ UASM_i_MFC0(p, pte, C0_BADVADDR);
+ UASM_i_LW(p, ptr, 0, ptr);
+ UASM_i_SRL(p, pte, pte, PAGE_SHIFT + PTE_ORDER - PTE_T_LOG2);
+ uasm_i_andi(p, pte, pte, (PTRS_PER_PTE - 1) << PTE_T_LOG2);
+ UASM_i_ADDU(p, ptr, ptr, pte);
#ifdef CONFIG_SMP
- l_smp_pgtable_change(l, *p);
-# endif
+ uasm_l_smp_pgtable_change(l, *p);
+#endif
iPTE_LW(p, l, pte, ptr); /* get even pte */
if (!m4kc_tlbp_war())
build_tlb_probe_entry(p);
}
static void __init
-build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
- struct reloc **r, unsigned int tmp,
+build_r4000_tlbchange_handler_tail(u32 **p, struct uasm_label **l,
+ struct uasm_reloc **r, unsigned int tmp,
unsigned int ptr)
{
- i_ori(p, ptr, ptr, sizeof(pte_t));
- i_xori(p, ptr, ptr, sizeof(pte_t));
+ uasm_i_ori(p, ptr, ptr, sizeof(pte_t));
+ uasm_i_xori(p, ptr, ptr, sizeof(pte_t));
build_update_entries(p, tmp, ptr);
build_tlb_write_entry(p, l, r, tlb_indexed);
- l_leave(l, *p);
- i_eret(p); /* return from trap */
+ uasm_l_leave(l, *p);
+ uasm_i_eret(p); /* return from trap */
#ifdef CONFIG_64BIT
build_get_pgd_vmalloc64(p, l, r, tmp, ptr);
@@ -1741,20 +1123,20 @@ build_r4000_tlbchange_handler_tail(u32 **p, struct label **l,
static void __init build_r4000_tlb_load_handler(void)
{
u32 *p = handle_tlbl;
- struct label *l = labels;
- struct reloc *r = relocs;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
memset(handle_tlbl, 0, sizeof(handle_tlbl));
memset(labels, 0, sizeof(labels));
memset(relocs, 0, sizeof(relocs));
if (bcm1250_m3_war()) {
- i_MFC0(&p, K0, C0_BADVADDR);
- i_MFC0(&p, K1, C0_ENTRYHI);
- i_xor(&p, K0, K0, K1);
- i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
- il_bnez(&p, &r, K0, label_leave);
- /* No need for i_nop */
+ UASM_i_MFC0(&p, K0, C0_BADVADDR);
+ UASM_i_MFC0(&p, K1, C0_ENTRYHI);
+ uasm_i_xor(&p, K0, K0, K1);
+ UASM_i_SRL(&p, K0, K0, PAGE_SHIFT + 1);
+ uasm_il_bnez(&p, &r, K0, label_leave);
+ /* No need for uasm_i_nop */
}
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
@@ -1764,16 +1146,16 @@ static void __init build_r4000_tlb_load_handler(void)
build_make_valid(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
- l_nopage_tlbl(&l, p);
- i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
- i_nop(&p);
+ uasm_l_nopage_tlbl(&l, p);
+ uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
+ uasm_i_nop(&p);
if ((p - handle_tlbl) > FASTPATH_SIZE)
panic("TLB load handler fastpath space exceeded");
- resolve_relocs(relocs, labels);
- pr_info("Synthesized TLB load handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbl));
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote TLB load handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbl));
dump_handler(handle_tlbl, ARRAY_SIZE(handle_tlbl));
}
@@ -1781,8 +1163,8 @@ static void __init build_r4000_tlb_load_handler(void)
static void __init build_r4000_tlb_store_handler(void)
{
u32 *p = handle_tlbs;
- struct label *l = labels;
- struct reloc *r = relocs;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
memset(handle_tlbs, 0, sizeof(handle_tlbs));
memset(labels, 0, sizeof(labels));
@@ -1795,16 +1177,16 @@ static void __init build_r4000_tlb_store_handler(void)
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
- l_nopage_tlbs(&l, p);
- i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
- i_nop(&p);
+ uasm_l_nopage_tlbs(&l, p);
+ uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+ uasm_i_nop(&p);
if ((p - handle_tlbs) > FASTPATH_SIZE)
panic("TLB store handler fastpath space exceeded");
- resolve_relocs(relocs, labels);
- pr_info("Synthesized TLB store handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbs));
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote TLB store handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbs));
dump_handler(handle_tlbs, ARRAY_SIZE(handle_tlbs));
}
@@ -1812,8 +1194,8 @@ static void __init build_r4000_tlb_store_handler(void)
static void __init build_r4000_tlb_modify_handler(void)
{
u32 *p = handle_tlbm;
- struct label *l = labels;
- struct reloc *r = relocs;
+ struct uasm_label *l = labels;
+ struct uasm_reloc *r = relocs;
memset(handle_tlbm, 0, sizeof(handle_tlbm));
memset(labels, 0, sizeof(labels));
@@ -1827,16 +1209,16 @@ static void __init build_r4000_tlb_modify_handler(void)
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
- l_nopage_tlbm(&l, p);
- i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
- i_nop(&p);
+ uasm_l_nopage_tlbm(&l, p);
+ uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
+ uasm_i_nop(&p);
if ((p - handle_tlbm) > FASTPATH_SIZE)
panic("TLB modify handler fastpath space exceeded");
- resolve_relocs(relocs, labels);
- pr_info("Synthesized TLB modify handler fastpath (%u instructions).\n",
- (unsigned int)(p - handle_tlbm));
+ uasm_resolve_relocs(relocs, labels);
+ pr_debug("Wrote TLB modify handler fastpath (%u instructions).\n",
+ (unsigned int)(p - handle_tlbm));
dump_handler(handle_tlbm, ARRAY_SIZE(handle_tlbm));
}
diff --git a/arch/mips/mm/uasm.c b/arch/mips/mm/uasm.c
new file mode 100644
index 00000000000..e3f74ed5f70
--- /dev/null
+++ b/arch/mips/mm/uasm.c
@@ -0,0 +1,576 @@
+/*
+ * 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.
+ *
+ * A small micro-assembler. It is intentionally kept simple, does only
+ * support a subset of instructions, and does not try to hide pipeline
+ * effects like branch delay slots.
+ *
+ * Copyright (C) 2004, 2005, 2006, 2008 Thiemo Seufer
+ * Copyright (C) 2005, 2007 Maciej W. Rozycki
+ * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#include <asm/inst.h>
+#include <asm/elf.h>
+#include <asm/bugs.h>
+
+#include "uasm.h"
+
+enum fields {
+ RS = 0x001,
+ RT = 0x002,
+ RD = 0x004,
+ RE = 0x008,
+ SIMM = 0x010,
+ UIMM = 0x020,
+ BIMM = 0x040,
+ JIMM = 0x080,
+ FUNC = 0x100,
+ SET = 0x200
+};
+
+#define OP_MASK 0x3f
+#define OP_SH 26
+#define RS_MASK 0x1f
+#define RS_SH 21
+#define RT_MASK 0x1f
+#define RT_SH 16
+#define RD_MASK 0x1f
+#define RD_SH 11
+#define RE_MASK 0x1f
+#define RE_SH 6
+#define IMM_MASK 0xffff
+#define IMM_SH 0
+#define JIMM_MASK 0x3ffffff
+#define JIMM_SH 0
+#define FUNC_MASK 0x3f
+#define FUNC_SH 0
+#define SET_MASK 0x7
+#define SET_SH 0
+
+enum opcode {
+ insn_invalid,
+ insn_addu, insn_addiu, insn_and, insn_andi, insn_beq,
+ insn_beql, insn_bgez, insn_bgezl, insn_bltz, insn_bltzl,
+ insn_bne, insn_daddu, insn_daddiu, insn_dmfc0, insn_dmtc0,
+ insn_dsll, insn_dsll32, insn_dsra, insn_dsrl, insn_dsrl32,
+ insn_dsubu, insn_eret, insn_j, insn_jal, insn_jr, insn_ld,
+ insn_ll, insn_lld, insn_lui, insn_lw, insn_mfc0, insn_mtc0,
+ insn_ori, insn_rfe, insn_sc, insn_scd, insn_sd, insn_sll,
+ insn_sra, insn_srl, insn_subu, insn_sw, insn_tlbp, insn_tlbwi,
+ insn_tlbwr, insn_xor, insn_xori
+};
+
+struct insn {
+ enum opcode opcode;
+ u32 match;
+ enum fields fields;
+};
+
+/* This macro sets the non-variable bits of an instruction. */
+#define M(a, b, c, d, e, f) \
+ ((a) << OP_SH \
+ | (b) << RS_SH \
+ | (c) << RT_SH \
+ | (d) << RD_SH \
+ | (e) << RE_SH \
+ | (f) << FUNC_SH)
+
+static struct insn insn_table[] __initdata = {
+ { insn_addiu, M(addiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_addu, M(spec_op, 0, 0, 0, 0, addu_op), RS | RT | RD },
+ { insn_and, M(spec_op, 0, 0, 0, 0, and_op), RS | RT | RD },
+ { insn_andi, M(andi_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
+ { insn_beq, M(beq_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+ { insn_beql, M(beql_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+ { insn_bgez, M(bcond_op, 0, bgez_op, 0, 0, 0), RS | BIMM },
+ { insn_bgezl, M(bcond_op, 0, bgezl_op, 0, 0, 0), RS | BIMM },
+ { insn_bltz, M(bcond_op, 0, bltz_op, 0, 0, 0), RS | BIMM },
+ { insn_bltzl, M(bcond_op, 0, bltzl_op, 0, 0, 0), RS | BIMM },
+ { insn_bne, M(bne_op, 0, 0, 0, 0, 0), RS | RT | BIMM },
+ { insn_daddiu, M(daddiu_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_daddu, M(spec_op, 0, 0, 0, 0, daddu_op), RS | RT | RD },
+ { insn_dmfc0, M(cop0_op, dmfc_op, 0, 0, 0, 0), RT | RD | SET},
+ { insn_dmtc0, M(cop0_op, dmtc_op, 0, 0, 0, 0), RT | RD | SET},
+ { insn_dsll, M(spec_op, 0, 0, 0, 0, dsll_op), RT | RD | RE },
+ { insn_dsll32, M(spec_op, 0, 0, 0, 0, dsll32_op), RT | RD | RE },
+ { insn_dsra, M(spec_op, 0, 0, 0, 0, dsra_op), RT | RD | RE },
+ { insn_dsrl, M(spec_op, 0, 0, 0, 0, dsrl_op), RT | RD | RE },
+ { insn_dsrl32, M(spec_op, 0, 0, 0, 0, dsrl32_op), RT | RD | RE },
+ { insn_dsubu, M(spec_op, 0, 0, 0, 0, dsubu_op), RS | RT | RD },
+ { insn_eret, M(cop0_op, cop_op, 0, 0, 0, eret_op), 0 },
+ { insn_j, M(j_op, 0, 0, 0, 0, 0), JIMM },
+ { insn_jal, M(jal_op, 0, 0, 0, 0, 0), JIMM },
+ { insn_jr, M(spec_op, 0, 0, 0, 0, jr_op), RS },
+ { insn_ld, M(ld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_ll, M(ll_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_lld, M(lld_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_lui, M(lui_op, 0, 0, 0, 0, 0), RT | SIMM },
+ { insn_lw, M(lw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_mfc0, M(cop0_op, mfc_op, 0, 0, 0, 0), RT | RD | SET},
+ { insn_mtc0, M(cop0_op, mtc_op, 0, 0, 0, 0), RT | RD | SET},
+ { insn_ori, M(ori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
+ { insn_rfe, M(cop0_op, cop_op, 0, 0, 0, rfe_op), 0 },
+ { insn_sc, M(sc_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_scd, M(scd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_sd, M(sd_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_sll, M(spec_op, 0, 0, 0, 0, sll_op), RT | RD | RE },
+ { insn_sra, M(spec_op, 0, 0, 0, 0, sra_op), RT | RD | RE },
+ { insn_srl, M(spec_op, 0, 0, 0, 0, srl_op), RT | RD | RE },
+ { insn_subu, M(spec_op, 0, 0, 0, 0, subu_op), RS | RT | RD },
+ { insn_sw, M(sw_op, 0, 0, 0, 0, 0), RS | RT | SIMM },
+ { insn_tlbp, M(cop0_op, cop_op, 0, 0, 0, tlbp_op), 0 },
+ { insn_tlbwi, M(cop0_op, cop_op, 0, 0, 0, tlbwi_op), 0 },
+ { insn_tlbwr, M(cop0_op, cop_op, 0, 0, 0, tlbwr_op), 0 },
+ { insn_xor, M(spec_op, 0, 0, 0, 0, xor_op), RS | RT | RD },
+ { insn_xori, M(xori_op, 0, 0, 0, 0, 0), RS | RT | UIMM },
+ { insn_invalid, 0, 0 }
+};
+
+#undef M
+
+static inline __init u32 build_rs(u32 arg)
+{
+ if (arg & ~RS_MASK)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return (arg & RS_MASK) << RS_SH;
+}
+
+static inline __init u32 build_rt(u32 arg)
+{
+ if (arg & ~RT_MASK)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return (arg & RT_MASK) << RT_SH;
+}
+
+static inline __init u32 build_rd(u32 arg)
+{
+ if (arg & ~RD_MASK)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return (arg & RD_MASK) << RD_SH;
+}
+
+static inline __init u32 build_re(u32 arg)
+{
+ if (arg & ~RE_MASK)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return (arg & RE_MASK) << RE_SH;
+}
+
+static inline __init u32 build_simm(s32 arg)
+{
+ if (arg > 0x7fff || arg < -0x8000)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return arg & 0xffff;
+}
+
+static inline __init u32 build_uimm(u32 arg)
+{
+ if (arg & ~IMM_MASK)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return arg & IMM_MASK;
+}
+
+static inline __init u32 build_bimm(s32 arg)
+{
+ if (arg > 0x1ffff || arg < -0x20000)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ if (arg & 0x3)
+ printk(KERN_WARNING "Invalid micro-assembler branch target\n");
+
+ return ((arg < 0) ? (1 << 15) : 0) | ((arg >> 2) & 0x7fff);
+}
+
+static inline __init u32 build_jimm(u32 arg)
+{
+ if (arg & ~((JIMM_MASK) << 2))
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return (arg >> 2) & JIMM_MASK;
+}
+
+static inline __init u32 build_func(u32 arg)
+{
+ if (arg & ~FUNC_MASK)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return arg & FUNC_MASK;
+}
+
+static inline __init u32 build_set(u32 arg)
+{
+ if (arg & ~SET_MASK)
+ printk(KERN_WARNING "Micro-assembler field overflow\n");
+
+ return arg & SET_MASK;
+}
+
+/*
+ * The order of opcode arguments is implicitly left to right,
+ * starting with RS and ending with FUNC or IMM.
+ */
+static void __init build_insn(u32 **buf, enum opcode opc, ...)
+{
+ struct insn *ip = NULL;
+ unsigned int i;
+ va_list ap;
+ u32 op;
+
+ for (i = 0; insn_table[i].opcode != insn_invalid; i++)
+ if (insn_table[i].opcode == opc) {
+ ip = &insn_table[i];
+ break;
+ }
+
+ if (!ip || (opc == insn_daddiu && r4k_daddiu_bug()))
+ panic("Unsupported Micro-assembler instruction %d", opc);
+
+ op = ip->match;
+ va_start(ap, opc);
+ if (ip->fields & RS)
+ op |= build_rs(va_arg(ap, u32));
+ if (ip->fields & RT)
+ op |= build_rt(va_arg(ap, u32));
+ if (ip->fields & RD)
+ op |= build_rd(va_arg(ap, u32));
+ if (ip->fields & RE)
+ op |= build_re(va_arg(ap, u32));
+ if (ip->fields & SIMM)
+ op |= build_simm(va_arg(ap, s32));
+ if (ip->fields & UIMM)
+ op |= build_uimm(va_arg(ap, u32));
+ if (ip->fields & BIMM)
+ op |= build_bimm(va_arg(ap, s32));
+ if (ip->fields & JIMM)
+ op |= build_jimm(va_arg(ap, u32));
+ if (ip->fields & FUNC)
+ op |= build_func(va_arg(ap, u32));
+ if (ip->fields & SET)
+ op |= build_set(va_arg(ap, u32));
+ va_end(ap);
+
+ **buf = op;
+ (*buf)++;
+}
+
+#define I_u1u2u3(op) \
+Ip_u1u2u3(op) \
+{ \
+ build_insn(buf, insn##op, a, b, c); \
+}
+
+#define I_u2u1u3(op) \
+Ip_u2u1u3(op) \
+{ \
+ build_insn(buf, insn##op, b, a, c); \
+}
+
+#define I_u3u1u2(op) \
+Ip_u3u1u2(op) \
+{ \
+ build_insn(buf, insn##op, b, c, a); \
+}
+
+#define I_u1u2s3(op) \
+Ip_u1u2s3(op) \
+{ \
+ build_insn(buf, insn##op, a, b, c); \
+}
+
+#define I_u2s3u1(op) \
+Ip_u2s3u1(op) \
+{ \
+ build_insn(buf, insn##op, c, a, b); \
+}
+
+#define I_u2u1s3(op) \
+Ip_u2u1s3(op) \
+{ \
+ build_insn(buf, insn##op, b, a, c); \
+}
+
+#define I_u1u2(op) \
+Ip_u1u2(op) \
+{ \
+ build_insn(buf, insn##op, a, b); \
+}
+
+#define I_u1s2(op) \
+Ip_u1s2(op) \
+{ \
+ build_insn(buf, insn##op, a, b); \
+}
+
+#define I_u1(op) \
+Ip_u1(op) \
+{ \
+ build_insn(buf, insn##op, a); \
+}
+
+#define I_0(op) \
+Ip_0(op) \
+{ \
+ build_insn(buf, insn##op); \
+}
+
+I_u2u1s3(_addiu)
+I_u3u1u2(_addu)
+I_u2u1u3(_andi)
+I_u3u1u2(_and)
+I_u1u2s3(_beq)
+I_u1u2s3(_beql)
+I_u1s2(_bgez)
+I_u1s2(_bgezl)
+I_u1s2(_bltz)
+I_u1s2(_bltzl)
+I_u1u2s3(_bne)
+I_u1u2u3(_dmfc0)
+I_u1u2u3(_dmtc0)
+I_u2u1s3(_daddiu)
+I_u3u1u2(_daddu)
+I_u2u1u3(_dsll)
+I_u2u1u3(_dsll32)
+I_u2u1u3(_dsra)
+I_u2u1u3(_dsrl)
+I_u2u1u3(_dsrl32)
+I_u3u1u2(_dsubu)
+I_0(_eret)
+I_u1(_j)
+I_u1(_jal)
+I_u1(_jr)
+I_u2s3u1(_ld)
+I_u2s3u1(_ll)
+I_u2s3u1(_lld)
+I_u1s2(_lui)
+I_u2s3u1(_lw)
+I_u1u2u3(_mfc0)
+I_u1u2u3(_mtc0)
+I_u2u1u3(_ori)
+I_0(_rfe)
+I_u2s3u1(_sc)
+I_u2s3u1(_scd)
+I_u2s3u1(_sd)
+I_u2u1u3(_sll)
+I_u2u1u3(_sra)
+I_u2u1u3(_srl)
+I_u3u1u2(_subu)
+I_u2s3u1(_sw)
+I_0(_tlbp)
+I_0(_tlbwi)
+I_0(_tlbwr)
+I_u3u1u2(_xor)
+I_u2u1u3(_xori)
+
+/* Handle labels. */
+void __init uasm_build_label(struct uasm_label **lab, u32 *addr, int lid)
+{
+ (*lab)->addr = addr;
+ (*lab)->lab = lid;
+ (*lab)++;
+}
+
+int __init uasm_in_compat_space_p(long addr)
+{
+ /* Is this address in 32bit compat space? */
+#ifdef CONFIG_64BIT
+ return (((addr) & 0xffffffff00000000L) == 0xffffffff00000000L);
+#else
+ return 1;
+#endif
+}
+
+int __init uasm_rel_highest(long val)
+{
+#ifdef CONFIG_64BIT
+ return ((((val + 0x800080008000L) >> 48) & 0xffff) ^ 0x8000) - 0x8000;
+#else
+ return 0;
+#endif
+}
+
+int __init uasm_rel_higher(long val)
+{
+#ifdef CONFIG_64BIT
+ return ((((val + 0x80008000L) >> 32) & 0xffff) ^ 0x8000) - 0x8000;
+#else
+ return 0;
+#endif
+}
+
+int __init uasm_rel_hi(long val)
+{
+ return ((((val + 0x8000L) >> 16) & 0xffff) ^ 0x8000) - 0x8000;
+}
+
+int __init uasm_rel_lo(long val)
+{
+ return ((val & 0xffff) ^ 0x8000) - 0x8000;
+}
+
+void __init UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr)
+{
+ if (!uasm_in_compat_space_p(addr)) {
+ uasm_i_lui(buf, rs, uasm_rel_highest(addr));
+ if (uasm_rel_higher(addr))
+ uasm_i_daddiu(buf, rs, rs, uasm_rel_higher(addr));
+ if (uasm_rel_hi(addr)) {
+ uasm_i_dsll(buf, rs, rs, 16);
+ uasm_i_daddiu(buf, rs, rs, uasm_rel_hi(addr));
+ uasm_i_dsll(buf, rs, rs, 16);
+ } else
+ uasm_i_dsll32(buf, rs, rs, 0);
+ } else
+ uasm_i_lui(buf, rs, uasm_rel_hi(addr));
+}
+
+void __init UASM_i_LA(u32 **buf, unsigned int rs, long addr)
+{
+ UASM_i_LA_mostly(buf, rs, addr);
+ if (uasm_rel_lo(addr)) {
+ if (!uasm_in_compat_space_p(addr))
+ uasm_i_daddiu(buf, rs, rs, uasm_rel_lo(addr));
+ else
+ uasm_i_addiu(buf, rs, rs, uasm_rel_lo(addr));
+ }
+}
+
+/* Handle relocations. */
+void __init
+uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid)
+{
+ (*rel)->addr = addr;
+ (*rel)->type = R_MIPS_PC16;
+ (*rel)->lab = lid;
+ (*rel)++;
+}
+
+static inline void __init
+__resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
+{
+ long laddr = (long)lab->addr;
+ long raddr = (long)rel->addr;
+
+ switch (rel->type) {
+ case R_MIPS_PC16:
+ *rel->addr |= build_bimm(laddr - (raddr + 4));
+ break;
+
+ default:
+ panic("Unsupported Micro-assembler relocation %d",
+ rel->type);
+ }
+}
+
+void __init
+uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab)
+{
+ struct uasm_label *l;
+
+ for (; rel->lab != UASM_LABEL_INVALID; rel++)
+ for (l = lab; l->lab != UASM_LABEL_INVALID; l++)
+ if (rel->lab == l->lab)
+ __resolve_relocs(rel, l);
+}
+
+void __init
+uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off)
+{
+ for (; rel->lab != UASM_LABEL_INVALID; rel++)
+ if (rel->addr >= first && rel->addr < end)
+ rel->addr += off;
+}
+
+void __init
+uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off)
+{
+ for (; lab->lab != UASM_LABEL_INVALID; lab++)
+ if (lab->addr >= first && lab->addr < end)
+ lab->addr += off;
+}
+
+void __init
+uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
+ u32 *end, u32 *target)
+{
+ long off = (long)(target - first);
+
+ memcpy(target, first, (end - first) * sizeof(u32));
+
+ uasm_move_relocs(rel, first, end, off);
+ uasm_move_labels(lab, first, end, off);
+}
+
+int __init uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr)
+{
+ for (; rel->lab != UASM_LABEL_INVALID; rel++) {
+ if (rel->addr == addr
+ && (rel->type == R_MIPS_PC16
+ || rel->type == R_MIPS_26))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Convenience functions for labeled branches. */
+void __init
+uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_bltz(p, reg, 0);
+}
+
+void __init
+uasm_il_b(u32 **p, struct uasm_reloc **r, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_b(p, 0);
+}
+
+void __init
+uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_beqz(p, reg, 0);
+}
+
+void __init
+uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_beqzl(p, reg, 0);
+}
+
+void __init
+uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_bnez(p, reg, 0);
+}
+
+void __init
+uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_bgezl(p, reg, 0);
+}
+
+void __init
+uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid)
+{
+ uasm_r_mips_pc16(r, *p, lid);
+ uasm_i_bgez(p, reg, 0);
+}
diff --git a/arch/mips/mm/uasm.h b/arch/mips/mm/uasm.h
new file mode 100644
index 00000000000..a10fc1135c7
--- /dev/null
+++ b/arch/mips/mm/uasm.h
@@ -0,0 +1,192 @@
+/*
+ * 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, 2005, 2006, 2008 Thiemo Seufer
+ * Copyright (C) 2005 Maciej W. Rozycki
+ * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#include <linux/types.h>
+
+#define Ip_u1u2u3(op) \
+void __init \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
+
+#define Ip_u2u1u3(op) \
+void __init \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
+
+#define Ip_u3u1u2(op) \
+void __init \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, unsigned int c)
+
+#define Ip_u1u2s3(op) \
+void __init \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
+
+#define Ip_u2s3u1(op) \
+void __init \
+uasm_i##op(u32 **buf, unsigned int a, signed int b, unsigned int c)
+
+#define Ip_u2u1s3(op) \
+void __init \
+uasm_i##op(u32 **buf, unsigned int a, unsigned int b, signed int c)
+
+#define Ip_u1u2(op) \
+void __init uasm_i##op(u32 **buf, unsigned int a, unsigned int b)
+
+#define Ip_u1s2(op) \
+void __init uasm_i##op(u32 **buf, unsigned int a, signed int b)
+
+#define Ip_u1(op) void __init uasm_i##op(u32 **buf, unsigned int a)
+
+#define Ip_0(op) void __init uasm_i##op(u32 **buf)
+
+Ip_u2u1s3(_addiu);
+Ip_u3u1u2(_addu);
+Ip_u2u1u3(_andi);
+Ip_u3u1u2(_and);
+Ip_u1u2s3(_beq);
+Ip_u1u2s3(_beql);
+Ip_u1s2(_bgez);
+Ip_u1s2(_bgezl);
+Ip_u1s2(_bltz);
+Ip_u1s2(_bltzl);
+Ip_u1u2s3(_bne);
+Ip_u1u2u3(_dmfc0);
+Ip_u1u2u3(_dmtc0);
+Ip_u2u1s3(_daddiu);
+Ip_u3u1u2(_daddu);
+Ip_u2u1u3(_dsll);
+Ip_u2u1u3(_dsll32);
+Ip_u2u1u3(_dsra);
+Ip_u2u1u3(_dsrl);
+Ip_u2u1u3(_dsrl32);
+Ip_u3u1u2(_dsubu);
+Ip_0(_eret);
+Ip_u1(_j);
+Ip_u1(_jal);
+Ip_u1(_jr);
+Ip_u2s3u1(_ld);
+Ip_u2s3u1(_ll);
+Ip_u2s3u1(_lld);
+Ip_u1s2(_lui);
+Ip_u2s3u1(_lw);
+Ip_u1u2u3(_mfc0);
+Ip_u1u2u3(_mtc0);
+Ip_u2u1u3(_ori);
+Ip_0(_rfe);
+Ip_u2s3u1(_sc);
+Ip_u2s3u1(_scd);
+Ip_u2s3u1(_sd);
+Ip_u2u1u3(_sll);
+Ip_u2u1u3(_sra);
+Ip_u2u1u3(_srl);
+Ip_u3u1u2(_subu);
+Ip_u2s3u1(_sw);
+Ip_0(_tlbp);
+Ip_0(_tlbwi);
+Ip_0(_tlbwr);
+Ip_u3u1u2(_xor);
+Ip_u2u1u3(_xori);
+
+/* Handle labels. */
+struct uasm_label {
+ u32 *addr;
+ int lab;
+};
+
+void __init uasm_build_label(struct uasm_label **lab, u32 *addr, int lid);
+#ifdef CONFIG_64BIT
+int __init uasm_in_compat_space_p(long addr);
+int __init uasm_rel_highest(long val);
+int __init uasm_rel_higher(long val);
+#endif
+int __init uasm_rel_hi(long val);
+int __init uasm_rel_lo(long val);
+void __init UASM_i_LA_mostly(u32 **buf, unsigned int rs, long addr);
+void __init UASM_i_LA(u32 **buf, unsigned int rs, long addr);
+
+#define UASM_L_LA(lb) \
+static inline void __init uasm_l##lb(struct uasm_label **lab, u32 *addr) \
+{ \
+ uasm_build_label(lab, addr, label##lb); \
+}
+
+/* convenience macros for instructions */
+#ifdef CONFIG_64BIT
+# define UASM_i_LW(buf, rs, rt, off) uasm_i_ld(buf, rs, rt, off)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sd(buf, rs, rt, off)
+# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_dsll(buf, rs, rt, sh)
+# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_dsra(buf, rs, rt, sh)
+# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_dsrl(buf, rs, rt, sh)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_dmfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_dmtc0(buf, rt, rd)
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_daddiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_daddu(buf, rs, rt, rd)
+# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_dsubu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_lld(buf, rs, rt, off)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_scd(buf, rs, rt, off)
+#else
+# define UASM_i_LW(buf, rs, rt, off) uasm_i_lw(buf, rs, rt, off)
+# define UASM_i_SW(buf, rs, rt, off) uasm_i_sw(buf, rs, rt, off)
+# define UASM_i_SLL(buf, rs, rt, sh) uasm_i_sll(buf, rs, rt, sh)
+# define UASM_i_SRA(buf, rs, rt, sh) uasm_i_sra(buf, rs, rt, sh)
+# define UASM_i_SRL(buf, rs, rt, sh) uasm_i_srl(buf, rs, rt, sh)
+# define UASM_i_MFC0(buf, rt, rd...) uasm_i_mfc0(buf, rt, rd)
+# define UASM_i_MTC0(buf, rt, rd...) uasm_i_mtc0(buf, rt, rd)
+# define UASM_i_ADDIU(buf, rs, rt, val) uasm_i_addiu(buf, rs, rt, val)
+# define UASM_i_ADDU(buf, rs, rt, rd) uasm_i_addu(buf, rs, rt, rd)
+# define UASM_i_SUBU(buf, rs, rt, rd) uasm_i_subu(buf, rs, rt, rd)
+# define UASM_i_LL(buf, rs, rt, off) uasm_i_ll(buf, rs, rt, off)
+# define UASM_i_SC(buf, rs, rt, off) uasm_i_sc(buf, rs, rt, off)
+#endif
+
+#define uasm_i_b(buf, off) uasm_i_beq(buf, 0, 0, off)
+#define uasm_i_beqz(buf, rs, off) uasm_i_beq(buf, rs, 0, off)
+#define uasm_i_beqzl(buf, rs, off) uasm_i_beql(buf, rs, 0, off)
+#define uasm_i_bnez(buf, rs, off) uasm_i_bne(buf, rs, 0, off)
+#define uasm_i_bnezl(buf, rs, off) uasm_i_bnel(buf, rs, 0, off)
+#define uasm_i_move(buf, a, b) UASM_i_ADDU(buf, a, 0, b)
+#define uasm_i_nop(buf) uasm_i_sll(buf, 0, 0, 0)
+#define uasm_i_ssnop(buf) uasm_i_sll(buf, 0, 0, 1)
+#define uasm_i_ehb(buf) uasm_i_sll(buf, 0, 0, 3)
+
+/* Handle relocations. */
+struct uasm_reloc {
+ u32 *addr;
+ unsigned int type;
+ int lab;
+};
+
+/* This is zero so we can use zeroed label arrays. */
+#define UASM_LABEL_INVALID 0
+
+void __init uasm_r_mips_pc16(struct uasm_reloc **rel, u32 *addr, int lid);
+void __init
+uasm_resolve_relocs(struct uasm_reloc *rel, struct uasm_label *lab);
+void __init
+uasm_move_relocs(struct uasm_reloc *rel, u32 *first, u32 *end, long off);
+void __init
+uasm_move_labels(struct uasm_label *lab, u32 *first, u32 *end, long off);
+void __init
+uasm_copy_handler(struct uasm_reloc *rel, struct uasm_label *lab, u32 *first,
+ u32 *end, u32 *target);
+int __init uasm_insn_has_bdelay(struct uasm_reloc *rel, u32 *addr);
+
+/* Convenience functions for labeled branches. */
+void __init
+uasm_il_bltz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init uasm_il_b(u32 **p, struct uasm_reloc **r, int lid);
+void __init
+uasm_il_beqz(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_beqzl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_bnez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_bgezl(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
+void __init
+uasm_il_bgez(u32 **p, struct uasm_reloc **r, unsigned int reg, int lid);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 65b449134cf..93e66678e15 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -44,6 +44,9 @@ config LOCKDEP_SUPPORT
config STACKTRACE_SUPPORT
def_bool y
+config HAVE_LATENCYTOP_SUPPORT
+ def_bool y
+
config SEMAPHORE_SLEEPERS
def_bool y
diff --git a/arch/x86/boot/compressed/vmlinux_64.lds b/arch/x86/boot/compressed/vmlinux_64.lds
index f6e5b445f45..7e5c7209f6c 100644
--- a/arch/x86/boot/compressed/vmlinux_64.lds
+++ b/arch/x86/boot/compressed/vmlinux_64.lds
@@ -3,7 +3,7 @@ OUTPUT_ARCH(i386:x86-64)
ENTRY(startup_64)
SECTIONS
{
- /* Be careful parts of head_64.S assume startup_64 is at
+ /* Be careful parts of head_64.S assume startup_32 is at
* address 0.
*/
. = 0;
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 0ca27c7b0e8..d2a58431a07 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -496,7 +496,8 @@ EXPORT_SYMBOL(acpi_register_gsi);
* ACPI based hotplug support for CPU
*/
#ifdef CONFIG_ACPI_HOTPLUG_CPU
-int acpi_map_lsapic(acpi_handle handle, int *pcpu)
+
+static int __cpuinit _acpi_map_lsapic(acpi_handle handle, int *pcpu)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
@@ -551,6 +552,11 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
return 0;
}
+/* wrapper to silence section mismatch warning */
+int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu)
+{
+ return _acpi_map_lsapic(handle, pcpu);
+}
EXPORT_SYMBOL(acpi_map_lsapic);
int acpi_unmap_lsapic(int cpu)
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index d608c9ebbfe..b7b2142b58e 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -258,10 +258,10 @@ static int __cpuinit have_cpuid_p(void)
void __init cpu_detect(struct cpuinfo_x86 *c)
{
/* Get vendor name */
- cpuid(0x00000000, &c->cpuid_level,
- (int *)&c->x86_vendor_id[0],
- (int *)&c->x86_vendor_id[8],
- (int *)&c->x86_vendor_id[4]);
+ cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
+ (unsigned int *)&c->x86_vendor_id[0],
+ (unsigned int *)&c->x86_vendor_id[8],
+ (unsigned int *)&c->x86_vendor_id[4]);
c->x86 = 4;
if (c->cpuid_level >= 0x00000001) {
@@ -283,7 +283,7 @@ void __init cpu_detect(struct cpuinfo_x86 *c)
static void __cpuinit early_get_cap(struct cpuinfo_x86 *c)
{
u32 tfms, xlvl;
- int ebx;
+ unsigned int ebx;
memset(&c->x86_capability, 0, sizeof c->x86_capability);
if (have_cpuid_p()) {
@@ -343,14 +343,14 @@ static void __init early_cpu_detect(void)
static void __cpuinit generic_identify(struct cpuinfo_x86 * c)
{
u32 tfms, xlvl;
- int ebx;
+ unsigned int ebx;
if (have_cpuid_p()) {
/* Get vendor name */
- cpuid(0x00000000, &c->cpuid_level,
- (int *)&c->x86_vendor_id[0],
- (int *)&c->x86_vendor_id[8],
- (int *)&c->x86_vendor_id[4]);
+ cpuid(0x00000000, (unsigned int *)&c->cpuid_level,
+ (unsigned int *)&c->x86_vendor_id[0],
+ (unsigned int *)&c->x86_vendor_id[8],
+ (unsigned int *)&c->x86_vendor_id[4]);
get_cpu_vendor(c, 0);
/* Initialize the standard set of capabilities */
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index dec66e45281..a63432d800f 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -170,7 +170,7 @@ static int __cpuinit cpuid_class_cpu_callback(struct notifier_block *nfb,
return err ? NOTIFY_BAD : NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier =
+static struct notifier_block __refdata cpuid_class_cpu_notifier =
{
.notifier_call = cpuid_class_cpu_callback,
};
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
index c617174e896..9f65b4cc323 100644
--- a/arch/x86/kernel/e820_64.c
+++ b/arch/x86/kernel/e820_64.c
@@ -54,30 +54,33 @@ static unsigned long __initdata end_user_pfn = MAXMEM>>PAGE_SHIFT;
struct early_res {
unsigned long start, end;
+ char name[16];
};
static struct early_res early_res[MAX_EARLY_RES] __initdata = {
- { 0, PAGE_SIZE }, /* BIOS data page */
+ { 0, PAGE_SIZE, "BIOS data page" }, /* BIOS data page */
#ifdef CONFIG_SMP
- { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE },
+ { SMP_TRAMPOLINE_BASE, SMP_TRAMPOLINE_BASE + 2*PAGE_SIZE, "SMP_TRAMPOLINE" },
#endif
{}
};
-void __init reserve_early(unsigned long start, unsigned long end)
+void __init reserve_early(unsigned long start, unsigned long end, char *name)
{
int i;
struct early_res *r;
for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
r = &early_res[i];
if (end > r->start && start < r->end)
- panic("Overlapping early reservations %lx-%lx to %lx-%lx\n",
- start, end, r->start, r->end);
+ panic("Overlapping early reservations %lx-%lx %s to %lx-%lx %s\n",
+ start, end - 1, name?name:"", r->start, r->end - 1, r->name);
}
if (i >= MAX_EARLY_RES)
panic("Too many early reservations");
r = &early_res[i];
r->start = start;
r->end = end;
+ if (name)
+ strncpy(r->name, name, sizeof(r->name) - 1);
}
void __init early_res_to_bootmem(void)
@@ -85,6 +88,8 @@ void __init early_res_to_bootmem(void)
int i;
for (i = 0; i < MAX_EARLY_RES && early_res[i].end; i++) {
struct early_res *r = &early_res[i];
+ printk(KERN_INFO "early res: %d [%lx-%lx] %s\n", i,
+ r->start, r->end - 1, r->name);
reserve_bootmem_generic(r->start, r->end - r->start);
}
}
@@ -166,12 +171,13 @@ int __init e820_all_mapped(unsigned long start, unsigned long end,
}
/*
- * Find a free area in a specific range.
+ * Find a free area with specified alignment in a specific range.
*/
unsigned long __init find_e820_area(unsigned long start, unsigned long end,
- unsigned size)
+ unsigned size, unsigned long align)
{
int i;
+ unsigned long mask = ~(align - 1);
for (i = 0; i < e820.nr_map; i++) {
struct e820entry *ei = &e820.map[i];
@@ -185,7 +191,8 @@ unsigned long __init find_e820_area(unsigned long start, unsigned long end,
continue;
while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size)
;
- last = PAGE_ALIGN(addr) + size;
+ addr = (addr + align - 1) & mask;
+ last = addr + size;
if (last > ei->addr + ei->size)
continue;
if (last > end)
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index b7d6c23f287..cff84cd9987 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -193,7 +193,7 @@ static struct console simnow_console = {
};
/* Direct interface for emergencies */
-struct console *early_console = &early_vga_console;
+static struct console *early_console = &early_vga_console;
static int early_console_initialized = 0;
void early_printk(const char *fmt, ...)
diff --git a/arch/x86/kernel/efi_64.c b/arch/x86/kernel/efi_64.c
index 4b73992c1e1..674f2379480 100644
--- a/arch/x86/kernel/efi_64.c
+++ b/arch/x86/kernel/efi_64.c
@@ -44,7 +44,7 @@ static void __init early_mapping_set_exec(unsigned long start,
int executable)
{
pte_t *kpte;
- int level;
+ unsigned int level;
while (start < end) {
kpte = lookup_address((unsigned long)__va(start), &level);
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index a317336cdea..24dbf56928d 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -75,7 +75,7 @@ static __init void reserve_ebda(void)
if (ebda_size > 64*1024)
ebda_size = 64*1024;
- reserve_early(ebda_addr, ebda_addr + ebda_size);
+ reserve_early(ebda_addr, ebda_addr + ebda_size, "EBDA");
}
void __init x86_64_start_kernel(char * real_mode_data)
@@ -105,14 +105,14 @@ void __init x86_64_start_kernel(char * real_mode_data)
pda_init(0);
copy_bootdata(__va(real_mode_data));
- reserve_early(__pa_symbol(&_text), __pa_symbol(&_end));
+ reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS");
/* Reserve INITRD */
if (boot_params.hdr.type_of_loader && boot_params.hdr.ramdisk_image) {
unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
unsigned long ramdisk_size = boot_params.hdr.ramdisk_size;
unsigned long ramdisk_end = ramdisk_image + ramdisk_size;
- reserve_early(ramdisk_image, ramdisk_end);
+ reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
}
reserve_ebda();
diff --git a/arch/x86/kernel/microcode.c b/arch/x86/kernel/microcode.c
index 6ff447f9fda..f2702d01b8a 100644
--- a/arch/x86/kernel/microcode.c
+++ b/arch/x86/kernel/microcode.c
@@ -797,7 +797,7 @@ mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata mc_cpu_notifier = {
+static struct notifier_block __refdata mc_cpu_notifier = {
.notifier_call = mc_cpu_callback,
};
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index 21f6e3c0be1..bd82850e651 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -168,7 +168,7 @@ static int __cpuinit msr_class_cpu_callback(struct notifier_block *nfb,
return err ? NOTIFY_BAD : NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata msr_class_cpu_notifier = {
+static struct notifier_block __refdata msr_class_cpu_notifier = {
.notifier_call = msr_class_cpu_callback,
};
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 21f34db2c03..1fe7f043ebd 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -1006,7 +1006,7 @@ static void __init calgary_set_split_completion_timeout(void __iomem *bbar,
readq(target); /* flush */
}
-static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+static void __init calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
{
unsigned char busnum = dev->bus->number;
void __iomem *bbar = tbl->bbar;
@@ -1022,7 +1022,7 @@ static void calioc2_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
writel(cpu_to_be32(val), target);
}
-static void calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
+static void __init calgary_handle_quirks(struct iommu_table *tbl, struct pci_dev *dev)
{
unsigned char busnum = dev->bus->number;
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index 77fb87bf6e5..18df70c534b 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -182,7 +182,8 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
unsigned long bootmap_size, bootmap;
bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
- bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size);
+ bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
+ PAGE_SIZE);
if (bootmap == -1L)
panic("Cannot find bootmem map of size %ld\n", bootmap_size);
bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
diff --git a/arch/x86/kernel/smpboot_64.c b/arch/x86/kernel/smpboot_64.c
index cc64b8085c2..d53bd6fcb42 100644
--- a/arch/x86/kernel/smpboot_64.c
+++ b/arch/x86/kernel/smpboot_64.c
@@ -1019,7 +1019,7 @@ static void remove_siblinginfo(int cpu)
cpu_clear(cpu, cpu_sibling_setup_map);
}
-void remove_cpu_from_maps(void)
+static void __ref remove_cpu_from_maps(void)
{
int cpu = smp_processor_id();
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c
index 78cbb655aa7..e6757aaa202 100644
--- a/arch/x86/kernel/topology.c
+++ b/arch/x86/kernel/topology.c
@@ -57,11 +57,10 @@ void arch_unregister_cpu(int num)
}
EXPORT_SYMBOL(arch_unregister_cpu);
#else
-int arch_register_cpu(int num)
+static int __init arch_register_cpu(int num)
{
return register_cpu(&per_cpu(cpu_devices, num).cpu, num);
}
-EXPORT_SYMBOL(arch_register_cpu);
#endif /*CONFIG_HOTPLUG_CPU*/
static int __init topology_init(void)
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index e28cc5277b1..e4440d0abf8 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -382,7 +382,7 @@ static void show_fault_oops(struct pt_regs *regs, unsigned long error_code,
#ifdef CONFIG_X86_PAE
if (error_code & PF_INSTR) {
- int level;
+ unsigned int level;
pte_t *pte = lookup_address(address, &level);
if (pte && pte_present(*pte) && !pte_exec(*pte))
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index cc50a13ce8d..eabcaed76c2 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -354,17 +354,10 @@ static void __init find_early_table_space(unsigned long end)
* need roughly 0.5KB per GB.
*/
start = 0x8000;
- table_start = find_e820_area(start, end, tables);
+ table_start = find_e820_area(start, end, tables, PAGE_SIZE);
if (table_start == -1UL)
panic("Cannot find space for the kernel page tables");
- /*
- * When you have a lot of RAM like 256GB, early_table will not fit
- * into 0x8000 range, find_e820_area() will find area after kernel
- * bss but the table_start is not page aligned, so need to round it
- * up to avoid overlap with bss:
- */
- table_start = round_up(table_start, PAGE_SIZE);
table_start >>= PAGE_SHIFT;
table_end = table_start;
@@ -420,7 +413,9 @@ void __init_refok init_memory_mapping(unsigned long start, unsigned long end)
mmu_cr4_features = read_cr4();
__flush_tlb_all();
- reserve_early(table_start << PAGE_SHIFT, table_end << PAGE_SHIFT);
+ if (!after_bootmem)
+ reserve_early(table_start << PAGE_SHIFT,
+ table_end << PAGE_SHIFT, "PGTABLE");
}
#ifndef CONFIG_NUMA
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index a177d76e1c5..c004d94608f 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -75,7 +75,8 @@ static int ioremap_change_attr(unsigned long paddr, unsigned long size,
{
unsigned long vaddr = (unsigned long)__va(paddr);
unsigned long nrpages = size >> PAGE_SHIFT;
- int err, level;
+ unsigned int level;
+ int err;
/* No change for pages after the last mapping */
if ((paddr + size - 1) >= (max_pfn_mapped << PAGE_SHIFT))
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index dc3b1f7e145..a920d09b919 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -84,26 +84,24 @@ static int __init populate_memnodemap(const struct bootnode *nodes,
static int __init allocate_cachealigned_memnodemap(void)
{
- unsigned long pad, pad_addr;
+ unsigned long addr;
memnodemap = memnode.embedded_map;
if (memnodemapsize <= ARRAY_SIZE(memnode.embedded_map))
return 0;
- pad = L1_CACHE_BYTES - 1;
- pad_addr = 0x8000;
- nodemap_size = pad + sizeof(s16) * memnodemapsize;
- nodemap_addr = find_e820_area(pad_addr, end_pfn<<PAGE_SHIFT,
- nodemap_size);
+ addr = 0x8000;
+ nodemap_size = round_up(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
+ nodemap_addr = find_e820_area(addr, end_pfn<<PAGE_SHIFT,
+ nodemap_size, L1_CACHE_BYTES);
if (nodemap_addr == -1UL) {
printk(KERN_ERR
"NUMA: Unable to allocate Memory to Node hash map\n");
nodemap_addr = nodemap_size = 0;
return -1;
}
- pad_addr = (nodemap_addr + pad) & ~pad;
- memnodemap = phys_to_virt(pad_addr);
- reserve_early(nodemap_addr, nodemap_addr + nodemap_size);
+ memnodemap = phys_to_virt(nodemap_addr);
+ reserve_early(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n",
nodemap_addr, nodemap_addr + nodemap_size);
@@ -164,15 +162,16 @@ int early_pfn_to_nid(unsigned long pfn)
}
static void * __init early_node_mem(int nodeid, unsigned long start,
- unsigned long end, unsigned long size)
+ unsigned long end, unsigned long size,
+ unsigned long align)
{
- unsigned long mem = find_e820_area(start, end, size);
+ unsigned long mem = find_e820_area(start, end, size, align);
void *ptr;
if (mem != -1L)
return __va(mem);
- ptr = __alloc_bootmem_nopanic(size,
- SMP_CACHE_BYTES, __pa(MAX_DMA_ADDRESS));
+
+ ptr = __alloc_bootmem_nopanic(size, align, __pa(MAX_DMA_ADDRESS));
if (ptr == NULL) {
printk(KERN_ERR "Cannot find %lu bytes in node %d\n",
size, nodeid);
@@ -198,7 +197,8 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
start_pfn = start >> PAGE_SHIFT;
end_pfn = end >> PAGE_SHIFT;
- node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size);
+ node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size,
+ SMP_CACHE_BYTES);
if (node_data[nodeid] == NULL)
return;
nodedata_phys = __pa(node_data[nodeid]);
@@ -211,8 +211,12 @@ void __init setup_node_bootmem(int nodeid, unsigned long start,
/* Find a place for the bootmem map */
bootmap_pages = bootmem_bootmap_pages(end_pfn - start_pfn);
bootmap_start = round_up(nodedata_phys + pgdat_size, PAGE_SIZE);
+ /*
+ * SMP_CAHCE_BYTES could be enough, but init_bootmem_node like
+ * to use that to align to PAGE_SIZE
+ */
bootmap = early_node_mem(nodeid, bootmap_start, end,
- bootmap_pages<<PAGE_SHIFT);
+ bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
if (bootmap == NULL) {
if (nodedata_phys < start || nodedata_phys >= end)
free_bootmem((unsigned long)node_data[nodeid],
diff --git a/arch/x86/mm/pageattr-test.c b/arch/x86/mm/pageattr-test.c
index 06353d43f72..7573e786d2f 100644
--- a/arch/x86/mm/pageattr-test.c
+++ b/arch/x86/mm/pageattr-test.c
@@ -42,7 +42,7 @@ static __init int print_split(struct split_state *s)
s->max_exec = 0;
for (i = 0; i < max_pfn_mapped; ) {
unsigned long addr = (unsigned long)__va(i << PAGE_SHIFT);
- int level;
+ unsigned int level;
pte_t *pte;
pte = lookup_address(addr, &level);
@@ -106,7 +106,7 @@ static __init int exercise_pageattr(void)
unsigned long *bm;
pte_t *pte, pte0;
int failed = 0;
- int level;
+ unsigned int level;
int i, k;
int err;
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index ae19c9b30d1..ba8f7f4dfa1 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -69,7 +69,7 @@ config ATA_PIIX
config SATA_MV
tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ depends on EXPERIMENTAL
help
This option enables support for the Marvell Serial ATA family.
Currently supports 88SX[56]0[48][01] chips.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 6f089b899a1..27c8d56111c 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -475,6 +475,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
+ { PCI_VDEVICE(INTEL, 0x3a05), board_ahci }, /* ICH10 */
+ { PCI_VDEVICE(INTEL, 0x3a25), board_ahci }, /* ICH10 */
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index a65c8ae5c46..47892e6f5de 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -267,6 +267,14 @@ static const struct pci_device_id piix_pci_tbl[] = {
{ 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller IDE (Tolapai) */
{ 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata_ahci },
+ /* SATA Controller IDE (ICH10) */
+ { 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH10) */
+ { 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+ /* SATA Controller IDE (ICH10) */
+ { 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+ /* SATA Controller IDE (ICH10) */
+ { 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
{ } /* terminate list */
};
@@ -1068,7 +1076,7 @@ static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
}
-u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
+static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
{
u32 val = 0;
int i, mi;
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index a32e3c44a60..7f87f105c2f 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -299,7 +299,7 @@ static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
*/
n6 = num_clocks_min(t6min, fsclk);
if (mode >= 0 && mode <= 4 && n6 >= 1) {
- pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+ dev_dbg(adev->link->ap->dev, "set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
/* calculate the timing values for register transfers. */
while (mode > 0 && pio_fsclk[mode] > fsclk)
mode--;
@@ -376,7 +376,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
mode = adev->dma_mode - XFER_UDMA_0;
if (mode >= 0 && mode <= 5) {
- pr_debug("set udmamode: mode=%d\n", mode);
+ dev_dbg(adev->link->ap->dev, "set udmamode: mode=%d\n", mode);
/* the most restrictive timing value is t6 and tc,
* the DIOW - data hold. If one SCLK pulse is longer
* than this minimum value then register
@@ -433,7 +433,7 @@ static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
mode = adev->dma_mode - XFER_MW_DMA_0;
if (mode >= 0 && mode <= 2) {
- pr_debug("set mdmamode: mode=%d\n", mode);
+ dev_dbg(adev->link->ap->dev, "set mdmamode: mode=%d\n", mode);
/* the most restrictive timing value is tf, the DMACK to
* read data released. If one SCLK pulse is longer than
* this maximum value then the MDMA mode
@@ -697,7 +697,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
- pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
+ dev_dbg(ap->dev, "hob: feat 0x%X nsect 0x%X, lba 0x%X "
"0x%X 0x%X\n",
tf->hob_feature,
tf->hob_nsect,
@@ -711,7 +711,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
- pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ dev_dbg(ap->dev, "feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
tf->feature,
tf->nsect,
tf->lbal,
@@ -721,7 +721,7 @@ static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
if (tf->flags & ATA_TFLAG_DEVICE) {
write_atapi_register(base, ATA_REG_DEVICE, tf->device);
- pr_debug("device 0x%X\n", tf->device);
+ dev_dbg(ap->dev, "device 0x%X\n", tf->device);
}
ata_wait_idle(ap);
@@ -782,7 +782,7 @@ static void bfin_exec_command(struct ata_port *ap,
const struct ata_taskfile *tf)
{
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
- pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+ dev_dbg(ap->dev, "ata%u: cmd 0x%X\n", ap->print_id, tf->command);
write_atapi_register(base, ATA_REG_CMD, tf->command);
ata_pause(ap);
@@ -834,7 +834,7 @@ static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
struct scatterlist *sg;
unsigned int si;
- pr_debug("in atapi dma setup\n");
+ dev_dbg(qc->ap->dev, "in atapi dma setup\n");
/* Program the ATA_CTRL register with dir */
if (qc->tf.flags & ATA_TFLAG_WRITE) {
/* fill the ATAPI DMA controller */
@@ -870,7 +870,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
struct scatterlist *sg;
unsigned int si;
- pr_debug("in atapi dma start\n");
+ dev_dbg(qc->ap->dev, "in atapi dma start\n");
if (!(ap->udma_mask || ap->mwdma_mask))
return;
@@ -888,7 +888,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
sg_dma_address(sg) + sg_dma_len(sg));
}
enable_dma(CH_ATAPI_TX);
- pr_debug("enable udma write\n");
+ dev_dbg(qc->ap->dev, "enable udma write\n");
/* Send ATA DMA write command */
bfin_exec_command(ap, &qc->tf);
@@ -898,7 +898,7 @@ static void bfin_bmdma_start(struct ata_queued_cmd *qc)
| XFER_DIR));
} else {
enable_dma(CH_ATAPI_RX);
- pr_debug("enable udma read\n");
+ dev_dbg(qc->ap->dev, "enable udma read\n");
/* Send ATA DMA read command */
bfin_exec_command(ap, &qc->tf);
@@ -936,7 +936,7 @@ static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
struct scatterlist *sg;
unsigned int si;
- pr_debug("in atapi dma stop\n");
+ dev_dbg(qc->ap->dev, "in atapi dma stop\n");
if (!(ap->udma_mask || ap->mwdma_mask))
return;
@@ -1147,15 +1147,15 @@ static unsigned char bfin_bmdma_status(struct ata_port *ap)
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
unsigned short int_status = ATAPI_GET_INT_STATUS(base);
- if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
+ if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON))
host_stat |= ATA_DMA_ACTIVE;
- }
- if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
+ if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT|
+ ATAPI_DEV_INT))
host_stat |= ATA_DMA_INTR;
- }
- if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
- host_stat |= ATA_DMA_ERR;
- }
+ if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT))
+ host_stat |= ATA_DMA_ERR|ATA_DMA_INTR;
+
+ dev_dbg(ap->dev, "ATAPI: host_stat=0x%x\n", host_stat);
return host_stat;
}
@@ -1213,8 +1213,7 @@ static void bfin_irq_clear(struct ata_port *ap)
{
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
- pr_debug("in atapi irq clear\n");
-
+ dev_dbg(ap->dev, "in atapi irq clear\n");
ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
| MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
| MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
@@ -1232,7 +1231,7 @@ static unsigned char bfin_irq_on(struct ata_port *ap)
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
u8 tmp;
- pr_debug("in atapi irq on\n");
+ dev_dbg(ap->dev, "in atapi irq on\n");
ap->ctl &= ~ATA_NIEN;
ap->last_ctl = ap->ctl;
@@ -1255,7 +1254,7 @@ static void bfin_bmdma_freeze(struct ata_port *ap)
{
void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
- pr_debug("in atapi dma freeze\n");
+ dev_dbg(ap->dev, "in atapi dma freeze\n");
ap->ctl |= ATA_NIEN;
ap->last_ctl = ap->ctl;
@@ -1328,7 +1327,7 @@ static void bfin_error_handler(struct ata_port *ap)
static void bfin_port_stop(struct ata_port *ap)
{
- pr_debug("in atapi port stop\n");
+ dev_dbg(ap->dev, "in atapi port stop\n");
if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
free_dma(CH_ATAPI_RX);
free_dma(CH_ATAPI_TX);
@@ -1337,7 +1336,7 @@ static void bfin_port_stop(struct ata_port *ap)
static int bfin_port_start(struct ata_port *ap)
{
- pr_debug("in atapi port start\n");
+ dev_dbg(ap->dev, "in atapi port start\n");
if (!(ap->udma_mask || ap->mwdma_mask))
return 0;
@@ -1373,10 +1372,6 @@ static struct scsi_host_template bfin_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
-#ifdef CONFIG_PM
- .resume = ata_scsi_device_resume,
- .suspend = ata_scsi_device_suspend,
-#endif
};
static const struct ata_port_operations bfin_pata_ops = {
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 1388cef52c0..81ef207f826 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -26,7 +26,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sl82c105"
-#define DRV_VERSION "0.3.2"
+#define DRV_VERSION "0.3.3"
enum {
/*
@@ -206,6 +206,34 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
sl82c105_set_piomode(ap, qc->dev);
}
+/**
+ * sl82c105_qc_defer - implement serialization
+ * @qc: command
+ *
+ * We must issue one command per host not per channel because
+ * of the reset bug.
+ *
+ * Q: is the scsi host lock sufficient ?
+ */
+
+static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_host *host = qc->ap->host;
+ struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
+ int rc;
+
+ /* First apply the usual rules */
+ rc = ata_std_qc_defer(qc);
+ if (rc != 0)
+ return rc;
+
+ /* Now apply serialization rules. Only allow a command if the
+ other channel state machine is idle */
+ if (alt && alt->qc_active)
+ return ATA_DEFER_PORT;
+ return 0;
+}
+
static struct scsi_host_template sl82c105_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -245,6 +273,7 @@ static struct ata_port_operations sl82c105_port_ops = {
.bmdma_stop = sl82c105_bmdma_stop,
.bmdma_status = ata_bmdma_status,
+ .qc_defer = sl82c105_qc_defer,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
@@ -312,7 +341,7 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
};
/* for now use only the first port */
const struct ata_port_info *ppi[] = { &info_early,
- &ata_dummy_port_info };
+ NULL };
u32 val;
int rev;
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 7e72463a90e..3c1b5c9027d 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -29,7 +29,13 @@
I distinctly remember a couple workarounds (one related to PCI-X)
are still needed.
- 4) Add NCQ support (easy to intermediate, once new-EH support appears)
+ 2) Improve/fix IRQ and error handling sequences.
+
+ 3) ATAPI support (Marvell claims the 60xx/70xx chips can do it).
+
+ 4) Think about TCQ support here, and for libata in general
+ with controllers that suppport it via host-queuing hardware
+ (a software-only implementation could be a nightmare).
5) Investigate problems with PCI Message Signalled Interrupts (MSI).
@@ -53,8 +59,6 @@
Target mode, for those without docs, is the ability to directly
connect two SATA controllers.
- 13) Verify that 7042 is fully supported. I only have a 6042.
-
*/
@@ -73,7 +77,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_mv"
-#define DRV_VERSION "1.01"
+#define DRV_VERSION "1.20"
enum {
/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -107,14 +111,12 @@ enum {
/* CRQB needs alignment on a 1KB boundary. Size == 1KB
* CRPB needs alignment on a 256B boundary. Size == 256B
- * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
* ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
*/
MV_CRQB_Q_SZ = (32 * MV_MAX_Q_DEPTH),
MV_CRPB_Q_SZ = (8 * MV_MAX_Q_DEPTH),
- MV_MAX_SG_CT = 176,
+ MV_MAX_SG_CT = 256,
MV_SG_TBL_SZ = (16 * MV_MAX_SG_CT),
- MV_PORT_PRIV_DMA_SZ = (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
MV_PORTS_PER_HC = 4,
/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
@@ -125,6 +127,9 @@ enum {
/* Host Flags */
MV_FLAG_DUAL_HC = (1 << 30), /* two SATA Host Controllers */
MV_FLAG_IRQ_COALESCE = (1 << 29), /* IRQ coalescing capability */
+ /* SoC integrated controllers, no PCI interface */
+ MV_FLAG_SOC = (1 << 28),
+
MV_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_NO_ATAPI |
ATA_FLAG_PIO_POLLING,
@@ -170,7 +175,7 @@ enum {
PCIE_IRQ_CAUSE_OFS = 0x1900,
PCIE_IRQ_MASK_OFS = 0x1910,
- PCIE_UNMASK_ALL_IRQS = 0x70a, /* assorted bits */
+ PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */
HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
HC_MAIN_IRQ_MASK_OFS = 0x1d64,
@@ -210,6 +215,7 @@ enum {
/* SATA registers */
SATA_STATUS_OFS = 0x300, /* ctrl, err regs follow status */
SATA_ACTIVE_OFS = 0x350,
+ SATA_FIS_IRQ_CAUSE_OFS = 0x364,
PHY_MODE3 = 0x310,
PHY_MODE4 = 0x314,
PHY_MODE2 = 0x330,
@@ -222,11 +228,11 @@ enum {
/* Port registers */
EDMA_CFG_OFS = 0,
- EDMA_CFG_Q_DEPTH = 0, /* queueing disabled */
- EDMA_CFG_NCQ = (1 << 5),
- EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
- EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */
- EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */
+ EDMA_CFG_Q_DEPTH = 0x1f, /* max device queue depth */
+ EDMA_CFG_NCQ = (1 << 5), /* for R/W FPDMA queued */
+ EDMA_CFG_NCQ_GO_ON_ERR = (1 << 14), /* continue on error */
+ EDMA_CFG_RD_BRST_EXT = (1 << 11), /* read burst 512B */
+ EDMA_CFG_WR_BUFF_LEN = (1 << 13), /* write buffer 512B */
EDMA_ERR_IRQ_CAUSE_OFS = 0x8,
EDMA_ERR_IRQ_MASK_OFS = 0xc,
@@ -244,14 +250,33 @@ enum {
EDMA_ERR_CRPB_PAR = (1 << 10), /* CRPB parity error */
EDMA_ERR_INTRL_PAR = (1 << 11), /* internal parity error */
EDMA_ERR_IORDY = (1 << 12), /* IORdy timeout */
+
EDMA_ERR_LNK_CTRL_RX = (0xf << 13), /* link ctrl rx error */
- EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15),
+ EDMA_ERR_LNK_CTRL_RX_0 = (1 << 13), /* transient: CRC err */
+ EDMA_ERR_LNK_CTRL_RX_1 = (1 << 14), /* transient: FIFO err */
+ EDMA_ERR_LNK_CTRL_RX_2 = (1 << 15), /* fatal: caught SYNC */
+ EDMA_ERR_LNK_CTRL_RX_3 = (1 << 16), /* transient: FIS rx err */
+
EDMA_ERR_LNK_DATA_RX = (0xf << 17), /* link data rx error */
+
EDMA_ERR_LNK_CTRL_TX = (0x1f << 21), /* link ctrl tx error */
+ EDMA_ERR_LNK_CTRL_TX_0 = (1 << 21), /* transient: CRC err */
+ EDMA_ERR_LNK_CTRL_TX_1 = (1 << 22), /* transient: FIFO err */
+ EDMA_ERR_LNK_CTRL_TX_2 = (1 << 23), /* transient: caught SYNC */
+ EDMA_ERR_LNK_CTRL_TX_3 = (1 << 24), /* transient: caught DMAT */
+ EDMA_ERR_LNK_CTRL_TX_4 = (1 << 25), /* transient: FIS collision */
+
EDMA_ERR_LNK_DATA_TX = (0x1f << 26), /* link data tx error */
+
EDMA_ERR_TRANS_PROTO = (1 << 31), /* transport protocol error */
EDMA_ERR_OVERRUN_5 = (1 << 5),
EDMA_ERR_UNDERRUN_5 = (1 << 6),
+
+ EDMA_ERR_IRQ_TRANSIENT = EDMA_ERR_LNK_CTRL_RX_0 |
+ EDMA_ERR_LNK_CTRL_RX_1 |
+ EDMA_ERR_LNK_CTRL_RX_3 |
+ EDMA_ERR_LNK_CTRL_TX,
+
EDMA_EH_FREEZE = EDMA_ERR_D_PAR |
EDMA_ERR_PRD_PAR |
EDMA_ERR_DEV_DCON |
@@ -311,12 +336,14 @@ enum {
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
+ MV_PP_FLAG_NCQ_EN = (1 << 1), /* is EDMA set up for NCQ? */
MV_PP_FLAG_HAD_A_RESET = (1 << 2), /* 1st hard reset complete? */
};
#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
+#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
enum {
/* DMA boundary 0xffff is required by the s/g splitting
@@ -379,8 +406,8 @@ struct mv_port_priv {
dma_addr_t crqb_dma;
struct mv_crpb *crpb;
dma_addr_t crpb_dma;
- struct mv_sg *sg_tbl;
- dma_addr_t sg_tbl_dma;
+ struct mv_sg *sg_tbl[MV_MAX_Q_DEPTH];
+ dma_addr_t sg_tbl_dma[MV_MAX_Q_DEPTH];
unsigned int req_idx;
unsigned int resp_idx;
@@ -400,6 +427,14 @@ struct mv_host_priv {
u32 irq_cause_ofs;
u32 irq_mask_ofs;
u32 unmask_all_irqs;
+ /*
+ * These consistent DMA memory pools give us guaranteed
+ * alignment for hardware-accessed data structures,
+ * and less memory waste in accomplishing the alignment.
+ */
+ struct dma_pool *crqb_pool;
+ struct dma_pool *crpb_pool;
+ struct dma_pool *sg_tbl_pool;
};
struct mv_hw_ops {
@@ -411,7 +446,7 @@ struct mv_hw_ops {
int (*reset_hc)(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int n_hc);
void (*reset_flash)(struct mv_host_priv *hpriv, void __iomem *mmio);
- void (*reset_bus)(struct pci_dev *pdev, void __iomem *mmio);
+ void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
};
static void mv_irq_clear(struct ata_port *ap);
@@ -425,10 +460,9 @@ static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
static void mv_error_handler(struct ata_port *ap);
-static void mv_post_int_cmd(struct ata_queued_cmd *qc);
static void mv_eh_freeze(struct ata_port *ap);
static void mv_eh_thaw(struct ata_port *ap);
-static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void mv6_dev_config(struct ata_device *dev);
static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port);
@@ -438,7 +472,7 @@ static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int n_hc);
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio);
+static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio);
static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port);
@@ -448,10 +482,17 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
static int mv6_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int n_hc);
static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio);
-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio);
+static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio);
static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no);
+static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
+ void __iomem *port_mmio, int want_ncq);
+static int __mv_stop_dma(struct ata_port *ap);
+/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
+ * because we have to allow room for worst case splitting of
+ * PRDs for 64K boundaries in mv_fill_sg().
+ */
static struct scsi_host_template mv5_sht = {
.module = THIS_MODULE,
.name = DRV_NAME,
@@ -475,7 +516,8 @@ static struct scsi_host_template mv6_sht = {
.name = DRV_NAME,
.ioctl = ata_scsi_ioctl,
.queuecommand = ata_scsi_queuecmd,
- .can_queue = ATA_DEF_QUEUE,
+ .change_queue_depth = ata_scsi_change_queue_depth,
+ .can_queue = MV_MAX_Q_DEPTH - 1,
.this_id = ATA_SHT_THIS_ID,
.sg_tablesize = MV_MAX_SG_CT / 2,
.cmd_per_lun = ATA_SHT_CMD_PER_LUN,
@@ -505,7 +547,6 @@ static const struct ata_port_operations mv5_ops = {
.irq_on = ata_irq_on,
.error_handler = mv_error_handler,
- .post_internal_cmd = mv_post_int_cmd,
.freeze = mv_eh_freeze,
.thaw = mv_eh_thaw,
@@ -517,6 +558,7 @@ static const struct ata_port_operations mv5_ops = {
};
static const struct ata_port_operations mv6_ops = {
+ .dev_config = mv6_dev_config,
.tf_load = ata_tf_load,
.tf_read = ata_tf_read,
.check_status = ata_check_status,
@@ -533,9 +575,9 @@ static const struct ata_port_operations mv6_ops = {
.irq_on = ata_irq_on,
.error_handler = mv_error_handler,
- .post_internal_cmd = mv_post_int_cmd,
.freeze = mv_eh_freeze,
.thaw = mv_eh_thaw,
+ .qc_defer = ata_std_qc_defer,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
@@ -561,9 +603,9 @@ static const struct ata_port_operations mv_iie_ops = {
.irq_on = ata_irq_on,
.error_handler = mv_error_handler,
- .post_internal_cmd = mv_post_int_cmd,
.freeze = mv_eh_freeze,
.thaw = mv_eh_thaw,
+ .qc_defer = ata_std_qc_defer,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
@@ -592,26 +634,29 @@ static const struct ata_port_info mv_port_info[] = {
.port_ops = &mv5_ops,
},
{ /* chip_604x */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ ATA_FLAG_NCQ,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv6_ops,
},
{ /* chip_608x */
.flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
- MV_FLAG_DUAL_HC,
+ ATA_FLAG_NCQ | MV_FLAG_DUAL_HC,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv6_ops,
},
{ /* chip_6042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ ATA_FLAG_NCQ,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
- .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS,
+ .flags = MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ ATA_FLAG_NCQ,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = ATA_UDMA6,
.port_ops = &mv_iie_ops,
@@ -648,13 +693,6 @@ static const struct pci_device_id mv_pci_tbl[] = {
{ } /* terminate list */
};
-static struct pci_driver mv_pci_driver = {
- .name = DRV_NAME,
- .id_table = mv_pci_tbl,
- .probe = mv_init_one,
- .remove = ata_pci_remove_one,
-};
-
static const struct mv_hw_ops mv5xxx_ops = {
.phy_errata = mv5_phy_errata,
.enable_leds = mv5_enable_leds,
@@ -674,45 +712,6 @@ static const struct mv_hw_ops mv6xxx_ops = {
};
/*
- * module options
- */
-static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
-
-
-/* move to PCI layer or libata core? */
-static int pci_go_64(struct pci_dev *pdev)
-{
- int rc;
-
- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
- if (rc) {
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "64-bit DMA enable failed\n");
- return rc;
- }
- }
- } else {
- rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit DMA enable failed\n");
- return rc;
- }
- rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
- if (rc) {
- dev_printk(KERN_ERR, &pdev->dev,
- "32-bit consistent DMA enable failed\n");
- return rc;
- }
- }
-
- return rc;
-}
-
-/*
* Functions
*/
@@ -815,19 +814,46 @@ static void mv_set_edma_ptrs(void __iomem *port_mmio,
* LOCKING:
* Inherited from caller.
*/
-static void mv_start_dma(void __iomem *base, struct mv_host_priv *hpriv,
- struct mv_port_priv *pp)
+static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
+ struct mv_port_priv *pp, u8 protocol)
{
+ int want_ncq = (protocol == ATA_PROT_NCQ);
+
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+ int using_ncq = ((pp->pp_flags & MV_PP_FLAG_NCQ_EN) != 0);
+ if (want_ncq != using_ncq)
+ __mv_stop_dma(ap);
+ }
if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ int hard_port = mv_hardport_from_port(ap->port_no);
+ void __iomem *hc_mmio = mv_hc_base_from_port(
+ ap->host->iomap[MV_PRIMARY_BAR], hard_port);
+ u32 hc_irq_cause, ipending;
+
/* clear EDMA event indicators, if any */
- writelfl(0, base + EDMA_ERR_IRQ_CAUSE_OFS);
+ writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+ /* clear EDMA interrupt indicator, if any */
+ hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
+ ipending = (DEV_IRQ << hard_port) |
+ (CRPB_DMA_DONE << hard_port);
+ if (hc_irq_cause & ipending) {
+ writelfl(hc_irq_cause & ~ipending,
+ hc_mmio + HC_IRQ_CAUSE_OFS);
+ }
+
+ mv_edma_cfg(pp, hpriv, port_mmio, want_ncq);
+
+ /* clear FIS IRQ Cause */
+ writelfl(0, port_mmio + SATA_FIS_IRQ_CAUSE_OFS);
- mv_set_edma_ptrs(base, hpriv, pp);
+ mv_set_edma_ptrs(port_mmio, hpriv, pp);
- writelfl(EDMA_EN, base + EDMA_CMD_OFS);
+ writelfl(EDMA_EN, port_mmio + EDMA_CMD_OFS);
pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
}
- WARN_ON(!(EDMA_EN & readl(base + EDMA_CMD_OFS)));
+ WARN_ON(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
}
/**
@@ -1003,38 +1029,76 @@ static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
return -EINVAL;
}
-static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
- void __iomem *port_mmio)
+static void mv6_dev_config(struct ata_device *adev)
{
- u32 cfg = readl(port_mmio + EDMA_CFG_OFS);
+ /*
+ * We don't have hob_nsect when doing NCQ commands on Gen-II.
+ * See mv_qc_prep() for more info.
+ */
+ if (adev->flags & ATA_DFLAG_NCQ)
+ if (adev->max_sectors > ATA_MAX_SECTORS)
+ adev->max_sectors = ATA_MAX_SECTORS;
+}
+
+static void mv_edma_cfg(struct mv_port_priv *pp, struct mv_host_priv *hpriv,
+ void __iomem *port_mmio, int want_ncq)
+{
+ u32 cfg;
/* set up non-NCQ EDMA configuration */
- cfg &= ~(1 << 9); /* disable eQue */
+ cfg = EDMA_CFG_Q_DEPTH; /* always 0x1f for *all* chips */
- if (IS_GEN_I(hpriv)) {
- cfg &= ~0x1f; /* clear queue depth */
+ if (IS_GEN_I(hpriv))
cfg |= (1 << 8); /* enab config burst size mask */
- }
- else if (IS_GEN_II(hpriv)) {
- cfg &= ~0x1f; /* clear queue depth */
+ else if (IS_GEN_II(hpriv))
cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
- cfg &= ~(EDMA_CFG_NCQ | EDMA_CFG_NCQ_GO_ON_ERR); /* clear NCQ */
- }
else if (IS_GEN_IIE(hpriv)) {
cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
cfg |= (1 << 22); /* enab 4-entry host queue cache */
- cfg &= ~(1 << 19); /* dis 128-entry queue (for now?) */
cfg |= (1 << 18); /* enab early completion */
cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
- cfg &= ~(1 << 16); /* dis FIS-based switching (for now) */
- cfg &= ~(EDMA_CFG_NCQ); /* clear NCQ */
}
+ if (want_ncq) {
+ cfg |= EDMA_CFG_NCQ;
+ pp->pp_flags |= MV_PP_FLAG_NCQ_EN;
+ } else
+ pp->pp_flags &= ~MV_PP_FLAG_NCQ_EN;
+
writelfl(cfg, port_mmio + EDMA_CFG_OFS);
}
+static void mv_port_free_dma_mem(struct ata_port *ap)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ struct mv_port_priv *pp = ap->private_data;
+ int tag;
+
+ if (pp->crqb) {
+ dma_pool_free(hpriv->crqb_pool, pp->crqb, pp->crqb_dma);
+ pp->crqb = NULL;
+ }
+ if (pp->crpb) {
+ dma_pool_free(hpriv->crpb_pool, pp->crpb, pp->crpb_dma);
+ pp->crpb = NULL;
+ }
+ /*
+ * For GEN_I, there's no NCQ, so we have only a single sg_tbl.
+ * For later hardware, we have one unique sg_tbl per NCQ tag.
+ */
+ for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
+ if (pp->sg_tbl[tag]) {
+ if (tag == 0 || !IS_GEN_I(hpriv))
+ dma_pool_free(hpriv->sg_tbl_pool,
+ pp->sg_tbl[tag],
+ pp->sg_tbl_dma[tag]);
+ pp->sg_tbl[tag] = NULL;
+ }
+ }
+}
+
/**
* mv_port_start - Port specific init/start routine.
* @ap: ATA channel to manipulate
@@ -1051,51 +1115,47 @@ static int mv_port_start(struct ata_port *ap)
struct mv_host_priv *hpriv = ap->host->private_data;
struct mv_port_priv *pp;
void __iomem *port_mmio = mv_ap_base(ap);
- void *mem;
- dma_addr_t mem_dma;
unsigned long flags;
- int rc;
+ int tag, rc;
pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
-
- mem = dmam_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma,
- GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
- memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
+ ap->private_data = pp;
rc = ata_pad_alloc(ap, dev);
if (rc)
return rc;
- /* First item in chunk of DMA memory:
- * 32-slot command request table (CRQB), 32 bytes each in size
- */
- pp->crqb = mem;
- pp->crqb_dma = mem_dma;
- mem += MV_CRQB_Q_SZ;
- mem_dma += MV_CRQB_Q_SZ;
+ pp->crqb = dma_pool_alloc(hpriv->crqb_pool, GFP_KERNEL, &pp->crqb_dma);
+ if (!pp->crqb)
+ return -ENOMEM;
+ memset(pp->crqb, 0, MV_CRQB_Q_SZ);
- /* Second item:
- * 32-slot command response table (CRPB), 8 bytes each in size
- */
- pp->crpb = mem;
- pp->crpb_dma = mem_dma;
- mem += MV_CRPB_Q_SZ;
- mem_dma += MV_CRPB_Q_SZ;
+ pp->crpb = dma_pool_alloc(hpriv->crpb_pool, GFP_KERNEL, &pp->crpb_dma);
+ if (!pp->crpb)
+ goto out_port_free_dma_mem;
+ memset(pp->crpb, 0, MV_CRPB_Q_SZ);
- /* Third item:
- * Table of scatter-gather descriptors (ePRD), 16 bytes each
+ /*
+ * For GEN_I, there's no NCQ, so we only allocate a single sg_tbl.
+ * For later hardware, we need one unique sg_tbl per NCQ tag.
*/
- pp->sg_tbl = mem;
- pp->sg_tbl_dma = mem_dma;
+ for (tag = 0; tag < MV_MAX_Q_DEPTH; ++tag) {
+ if (tag == 0 || !IS_GEN_I(hpriv)) {
+ pp->sg_tbl[tag] = dma_pool_alloc(hpriv->sg_tbl_pool,
+ GFP_KERNEL, &pp->sg_tbl_dma[tag]);
+ if (!pp->sg_tbl[tag])
+ goto out_port_free_dma_mem;
+ } else {
+ pp->sg_tbl[tag] = pp->sg_tbl[0];
+ pp->sg_tbl_dma[tag] = pp->sg_tbl_dma[0];
+ }
+ }
spin_lock_irqsave(&ap->host->lock, flags);
- mv_edma_cfg(ap, hpriv, port_mmio);
-
+ mv_edma_cfg(pp, hpriv, port_mmio, 0);
mv_set_edma_ptrs(port_mmio, hpriv, pp);
spin_unlock_irqrestore(&ap->host->lock, flags);
@@ -1104,8 +1164,11 @@ static int mv_port_start(struct ata_port *ap)
* we'll be unable to send non-data, PIO, etc due to restricted access
* to shadow regs.
*/
- ap->private_data = pp;
return 0;
+
+out_port_free_dma_mem:
+ mv_port_free_dma_mem(ap);
+ return -ENOMEM;
}
/**
@@ -1120,6 +1183,7 @@ static int mv_port_start(struct ata_port *ap)
static void mv_port_stop(struct ata_port *ap)
{
mv_stop_dma(ap);
+ mv_port_free_dma_mem(ap);
}
/**
@@ -1138,7 +1202,7 @@ static void mv_fill_sg(struct ata_queued_cmd *qc)
struct mv_sg *mv_sg, *last_sg = NULL;
unsigned int si;
- mv_sg = pp->sg_tbl;
+ mv_sg = pp->sg_tbl[qc->tag];
for_each_sg(qc->sg, sg, qc->n_elem, si) {
dma_addr_t addr = sg_dma_address(sg);
u32 sg_len = sg_dma_len(sg);
@@ -1194,7 +1258,8 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
u16 flags = 0;
unsigned in_index;
- if (qc->tf.protocol != ATA_PROT_DMA)
+ if ((qc->tf.protocol != ATA_PROT_DMA) &&
+ (qc->tf.protocol != ATA_PROT_NCQ))
return;
/* Fill in command request block
@@ -1203,15 +1268,14 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
flags |= CRQB_FLAG_READ;
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
- flags |= qc->tag << CRQB_IOID_SHIFT; /* 50xx appears to ignore this*/
/* get current queue index from software */
in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
pp->crqb[in_index].sg_addr =
- cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+ cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
pp->crqb[in_index].sg_addr_hi =
- cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+ cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
pp->crqb[in_index].ctrl_flags = cpu_to_le16(flags);
cw = &pp->crqb[in_index].ata_cmd[0];
@@ -1231,13 +1295,11 @@ static void mv_qc_prep(struct ata_queued_cmd *qc)
case ATA_CMD_WRITE_FUA_EXT:
mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
break;
-#ifdef LIBATA_NCQ /* FIXME: remove this line when NCQ added */
case ATA_CMD_FPDMA_READ:
case ATA_CMD_FPDMA_WRITE:
mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0);
mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
break;
-#endif /* FIXME: remove this line when NCQ added */
default:
/* The only other commands EDMA supports in non-queued and
* non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
@@ -1286,7 +1348,8 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
unsigned in_index;
u32 flags = 0;
- if (qc->tf.protocol != ATA_PROT_DMA)
+ if ((qc->tf.protocol != ATA_PROT_DMA) &&
+ (qc->tf.protocol != ATA_PROT_NCQ))
return;
/* Fill in Gen IIE command request block
@@ -1296,15 +1359,14 @@ static void mv_qc_prep_iie(struct ata_queued_cmd *qc)
WARN_ON(MV_MAX_Q_DEPTH <= qc->tag);
flags |= qc->tag << CRQB_TAG_SHIFT;
- flags |= qc->tag << CRQB_IOID_SHIFT; /* "I/O Id" is -really-
- what we use as our tag */
+ flags |= qc->tag << CRQB_HOSTQ_SHIFT;
/* get current queue index from software */
in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
crqb = (struct mv_crqb_iie *) &pp->crqb[in_index];
- crqb->addr = cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
- crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+ crqb->addr = cpu_to_le32(pp->sg_tbl_dma[qc->tag] & 0xffffffff);
+ crqb->addr_hi = cpu_to_le32((pp->sg_tbl_dma[qc->tag] >> 16) >> 16);
crqb->flags = cpu_to_le32(flags);
tf = &qc->tf;
@@ -1351,10 +1413,10 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
void __iomem *port_mmio = mv_ap_base(ap);
struct mv_port_priv *pp = ap->private_data;
- struct mv_host_priv *hpriv = ap->host->private_data;
u32 in_index;
- if (qc->tf.protocol != ATA_PROT_DMA) {
+ if ((qc->tf.protocol != ATA_PROT_DMA) &&
+ (qc->tf.protocol != ATA_PROT_NCQ)) {
/* We're about to send a non-EDMA capable command to the
* port. Turn off EDMA so there won't be problems accessing
* shadow block, etc registers.
@@ -1363,13 +1425,7 @@ static unsigned int mv_qc_issue(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
- mv_start_dma(port_mmio, hpriv, pp);
-
- in_index = pp->req_idx & MV_MAX_Q_DEPTH_MASK;
-
- /* until we do queuing, the queue should be empty at this point */
- WARN_ON(in_index != ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS)
- >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+ mv_start_dma(ap, port_mmio, pp, qc->tf.protocol);
pp->req_idx++;
@@ -1437,6 +1493,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
ata_ehi_hotplugged(ehi);
ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
"dev disconnect" : "dev connect");
+ action |= ATA_EH_HARDRESET;
}
if (IS_GEN_I(hpriv)) {
@@ -1465,7 +1522,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
}
/* Clear EDMA now that SERR cleanup done */
- writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+ writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
if (!err_mask) {
err_mask = AC_ERR_OTHER;
@@ -1538,23 +1595,17 @@ static void mv_intr_edma(struct ata_port *ap)
* support for queueing. this works transparently for
* queued and non-queued modes.
*/
- else if (IS_GEN_II(hpriv))
- tag = (le16_to_cpu(pp->crpb[out_index].id)
- >> CRPB_IOID_SHIFT_6) & 0x3f;
-
- else /* IS_GEN_IIE */
- tag = (le16_to_cpu(pp->crpb[out_index].id)
- >> CRPB_IOID_SHIFT_7) & 0x3f;
+ else
+ tag = le16_to_cpu(pp->crpb[out_index].id) & 0x1f;
qc = ata_qc_from_tag(ap, tag);
- /* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
- * bits (WARNING: might not necessarily be associated
- * with this command), which -should- be clear
- * if all is well
+ /* For non-NCQ mode, the lower 8 bits of status
+ * are from EDMA_ERR_IRQ_CAUSE_OFS,
+ * which should be zero if all went well.
*/
status = le16_to_cpu(pp->crpb[out_index].flags);
- if (unlikely(status & 0xff)) {
+ if ((status & 0xff) && !(pp->pp_flags & MV_PP_FLAG_NCQ_EN)) {
mv_err_intr(ap, qc);
return;
}
@@ -1715,20 +1766,21 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
struct ata_host *host = dev_instance;
unsigned int hc, handled = 0, n_hcs;
void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
- u32 irq_stat;
+ u32 irq_stat, irq_mask;
+ spin_lock(&host->lock);
irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
+ irq_mask = readl(mmio + HC_MAIN_IRQ_MASK_OFS);
/* check the cases where we either have nothing pending or have read
* a bogus register value which can indicate HW removal or PCI fault
*/
- if (!irq_stat || (0xffffffffU == irq_stat))
- return IRQ_NONE;
+ if (!(irq_stat & irq_mask) || (0xffffffffU == irq_stat))
+ goto out_unlock;
n_hcs = mv_get_hc_count(host->ports[0]->flags);
- spin_lock(&host->lock);
- if (unlikely(irq_stat & PCI_ERR)) {
+ if (unlikely((irq_stat & PCI_ERR) && HAS_PCI(host))) {
mv_pci_error(host, mmio);
handled = 1;
goto out_unlock; /* skip all other HC irq handling */
@@ -1799,8 +1851,9 @@ static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
return -EINVAL;
}
-static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
+static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
{
+ struct pci_dev *pdev = to_pci_dev(host->dev);
int early_5080;
early_5080 = (pdev->device == 0x5080) && (pdev->revision == 0);
@@ -1811,7 +1864,7 @@ static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
writel(tmp, mmio + MV_PCI_EXP_ROM_BAR_CTL);
}
- mv_reset_pci_bus(pdev, mmio);
+ mv_reset_pci_bus(host, mmio);
}
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
@@ -1935,9 +1988,8 @@ static int mv5_reset_hc(struct mv_host_priv *hpriv, void __iomem *mmio,
#undef ZERO
#define ZERO(reg) writel(0, mmio + (reg))
-static void mv_reset_pci_bus(struct pci_dev *pdev, void __iomem *mmio)
+static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
{
- struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct mv_host_priv *hpriv = host->private_data;
u32 tmp;
@@ -2329,11 +2381,6 @@ static void mv_error_handler(struct ata_port *ap)
mv_hardreset, mv_postreset);
}
-static void mv_post_int_cmd(struct ata_queued_cmd *qc)
-{
- mv_stop_dma(qc->ap);
-}
-
static void mv_eh_freeze(struct ata_port *ap)
{
void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
@@ -2427,8 +2474,8 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- /* unmask all EDMA error interrupts */
- writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
+ /* unmask all non-transient EDMA error interrupts */
+ writelfl(~EDMA_ERR_IRQ_TRANSIENT, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n",
readl(port_mmio + EDMA_CFG_OFS),
@@ -2586,7 +2633,6 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
static int mv_init_host(struct ata_host *host, unsigned int board_idx)
{
int rc = 0, n_hc, port, hc;
- struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[MV_PRIMARY_BAR];
struct mv_host_priv *hpriv = host->private_data;
@@ -2607,7 +2653,7 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
goto done;
hpriv->ops->reset_flash(hpriv, mmio);
- hpriv->ops->reset_bus(pdev, mmio);
+ hpriv->ops->reset_bus(host, mmio);
hpriv->ops->enable_leds(hpriv, mmio);
for (port = 0; port < host->n_ports; port++) {
@@ -2630,8 +2676,10 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
mv_port_init(&ap->ioaddr, port_mmio);
+#ifdef CONFIG_PCI
ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
+#endif
}
for (hc = 0; hc < n_hc; hc++) {
@@ -2668,6 +2716,55 @@ done:
return rc;
}
+#ifdef CONFIG_PCI
+static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+
+static struct pci_driver mv_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = mv_pci_tbl,
+ .probe = mv_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+/*
+ * module options
+ */
+static int msi; /* Use PCI msi; either zero (off, default) or non-zero */
+
+
+/* move to PCI layer or libata core? */
+static int pci_go_64(struct pci_dev *pdev)
+{
+ int rc;
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (rc) {
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "64-bit DMA enable failed\n");
+ return rc;
+ }
+ }
+ } else {
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit DMA enable failed\n");
+ return rc;
+ }
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (rc) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "32-bit consistent DMA enable failed\n");
+ return rc;
+ }
+ }
+
+ return rc;
+}
+
/**
* mv_print_info - Dump key info to kernel log for perusal.
* @host: ATA host to print info about
@@ -2710,6 +2807,26 @@ static void mv_print_info(struct ata_host *host)
scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
}
+static int mv_create_dma_pools(struct mv_host_priv *hpriv, struct device *dev)
+{
+ hpriv->crqb_pool = dmam_pool_create("crqb_q", dev, MV_CRQB_Q_SZ,
+ MV_CRQB_Q_SZ, 0);
+ if (!hpriv->crqb_pool)
+ return -ENOMEM;
+
+ hpriv->crpb_pool = dmam_pool_create("crpb_q", dev, MV_CRPB_Q_SZ,
+ MV_CRPB_Q_SZ, 0);
+ if (!hpriv->crpb_pool)
+ return -ENOMEM;
+
+ hpriv->sg_tbl_pool = dmam_pool_create("sg_tbl", dev, MV_SG_TBL_SZ,
+ MV_SG_TBL_SZ, 0);
+ if (!hpriv->sg_tbl_pool)
+ return -ENOMEM;
+
+ return 0;
+}
+
/**
* mv_init_one - handle a positive probe of a Marvell host
* @pdev: PCI device found
@@ -2755,6 +2872,10 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
return rc;
+ rc = mv_create_dma_pools(hpriv, &pdev->dev);
+ if (rc)
+ return rc;
+
/* initialize adapter */
rc = mv_init_host(host, board_idx);
if (rc)
@@ -2772,15 +2893,22 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return ata_host_activate(host, pdev->irq, mv_interrupt, IRQF_SHARED,
IS_GEN_I(hpriv) ? &mv5_sht : &mv6_sht);
}
+#endif
static int __init mv_init(void)
{
- return pci_register_driver(&mv_pci_driver);
+ int rc = -ENODEV;
+#ifdef CONFIG_PCI
+ rc = pci_register_driver(&mv_pci_driver);
+#endif
+ return rc;
}
static void __exit mv_exit(void)
{
+#ifdef CONFIG_PCI
pci_unregister_driver(&mv_pci_driver);
+#endif
}
MODULE_AUTHOR("Brett Russ");
@@ -2789,8 +2917,10 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, mv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
+#ifdef CONFIG_PCI
module_param(msi, int, 0444);
MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
+#endif
module_init(mv_init);
module_exit(mv_exit);
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index a0f98fdab7a..bfe92a43cf8 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1011,14 +1011,20 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
}
if (status & (NV_ADMA_STAT_DONE |
- NV_ADMA_STAT_CPBERR)) {
- u32 check_commands;
+ NV_ADMA_STAT_CPBERR |
+ NV_ADMA_STAT_CMD_COMPLETE)) {
+ u32 check_commands = notifier_clears[i];
int pos, error = 0;
- if (ata_tag_valid(ap->link.active_tag))
- check_commands = 1 << ap->link.active_tag;
- else
- check_commands = ap->link.sactive;
+ if (status & NV_ADMA_STAT_CPBERR) {
+ /* Check all active commands */
+ if (ata_tag_valid(ap->link.active_tag))
+ check_commands = 1 <<
+ ap->link.active_tag;
+ else
+ check_commands = ap->
+ link.sactive;
+ }
/** Check CPBs for completed commands */
while ((pos = ffs(check_commands)) && !error) {
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index d222012c1b0..bacded0eefa 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -73,6 +73,7 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf)
* @tsk with @loginuid. @buf->mutex must be locked.
*/
static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
+ unsigned int sessionid,
struct tty_audit_buf *buf)
{
struct audit_buffer *ab;
@@ -85,9 +86,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
if (ab) {
char name[sizeof(tsk->comm)];
- audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d "
- "minor=%d comm=", tsk->pid, tsk->uid,
- loginuid, buf->major, buf->minor);
+ audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u "
+ "major=%d minor=%d comm=", tsk->pid, tsk->uid,
+ loginuid, sessionid, buf->major, buf->minor);
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
audit_log_format(ab, " data=");
@@ -105,8 +106,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid,
*/
static void tty_audit_buf_push_current(struct tty_audit_buf *buf)
{
- tty_audit_buf_push(current, audit_get_loginuid(current->audit_context),
- buf);
+ uid_t auid = audit_get_loginuid(current);
+ unsigned int sessionid = audit_get_sessionid(current);
+ tty_audit_buf_push(current, auid, sessionid, buf);
}
/**
@@ -152,6 +154,11 @@ void tty_audit_fork(struct signal_struct *sig)
void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
{
struct tty_audit_buf *buf;
+ /* FIXME I think this is correct. Check against netlink once that is
+ * I really need to read this code more closely. But that's for
+ * another patch.
+ */
+ unsigned int sessionid = audit_get_sessionid(tsk);
spin_lock_irq(&tsk->sighand->siglock);
buf = tsk->signal->tty_audit_buf;
@@ -162,7 +169,7 @@ void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
return;
mutex_lock(&buf->mutex);
- tty_audit_buf_push(tsk, loginuid, buf);
+ tty_audit_buf_push(tsk, loginuid, sessionid, buf);
mutex_unlock(&buf->mutex);
tty_audit_buf_put(buf);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 71d561fda0a..7d4ce906d20 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -823,7 +823,8 @@ int pcim_enable_device(struct pci_dev *pdev)
dr = get_pci_dr(pdev);
if (unlikely(!dr))
return -ENOMEM;
- WARN_ON(!!dr->enabled);
+ if (dr->enabled)
+ return 0;
rc = pci_enable_device(pdev);
if (!rc) {
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 9fa9708cc71..33537487f5a 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -984,7 +984,7 @@ static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
if (!task)
return -ESRCH;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
- audit_get_loginuid(task->audit_context));
+ audit_get_loginuid(task));
put_task_struct(task);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
diff --git a/include/asm-x86/cpu.h b/include/asm-x86/cpu.h
index 85ece5f10e9..73f2ea84fd7 100644
--- a/include/asm-x86/cpu.h
+++ b/include/asm-x86/cpu.h
@@ -10,8 +10,9 @@
struct x86_cpu {
struct cpu cpu;
};
-extern int arch_register_cpu(int num);
+
#ifdef CONFIG_HOTPLUG_CPU
+extern int arch_register_cpu(int num);
extern void arch_unregister_cpu(int);
#endif
diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h
index 51e4170f9ca..a560c4f5d50 100644
--- a/include/asm-x86/e820_64.h
+++ b/include/asm-x86/e820_64.h
@@ -15,7 +15,7 @@
#ifndef __ASSEMBLY__
extern unsigned long find_e820_area(unsigned long start, unsigned long end,
- unsigned size);
+ unsigned size, unsigned long align);
extern void add_memory_region(unsigned long start, unsigned long size,
int type);
extern void setup_memory_region(void);
@@ -41,7 +41,7 @@ extern void finish_e820_parsing(void);
extern struct e820map e820;
extern void update_e820(void);
-extern void reserve_early(unsigned long start, unsigned long end);
+extern void reserve_early(unsigned long start, unsigned long end, char *name);
extern void early_res_to_bootmem(void);
#endif/*!__ASSEMBLY__*/
diff --git a/include/asm-x86/futex.h b/include/asm-x86/futex.h
index 62828d63f1b..9d919264923 100644
--- a/include/asm-x86/futex.h
+++ b/include/asm-x86/futex.h
@@ -30,7 +30,7 @@
"1: movl %2, %0\n \
movl %0, %3\n" \
insn "\n" \
-"2: " LOCK_PREFIX "cmpxchgl %3, %2\n \
+"2: lock; cmpxchgl %3, %2\n \
jnz 1b\n \
3: .section .fixup,\"ax\"\n \
4: mov %5, %1\n \
@@ -72,7 +72,7 @@ futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
__futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg);
break;
case FUTEX_OP_ADD:
- __futex_atomic_op1(LOCK_PREFIX "xaddl %0, %2", ret, oldval,
+ __futex_atomic_op1("lock; xaddl %0, %2", ret, oldval,
uaddr, oparg);
break;
case FUTEX_OP_OR:
@@ -111,8 +111,8 @@ futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
return -EFAULT;
__asm__ __volatile__(
- "1: " LOCK_PREFIX "cmpxchgl %3, %1 \n"
+ "1: lock; cmpxchgl %3, %1 \n"
"2: .section .fixup, \"ax\" \n"
"3: mov %2, %0 \n"
" jmp 2b \n"
diff --git a/include/linux/audit.h b/include/linux/audit.h
index bdd6f5de5fc..97153027207 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -98,6 +98,7 @@
#define AUDIT_FD_PAIR 1317 /* audit record for pipe/socketpair */
#define AUDIT_OBJ_PID 1318 /* ptrace target */
#define AUDIT_TTY 1319 /* Input on an administrative TTY */
+#define AUDIT_EOE 1320 /* End of multi-record event */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -409,7 +410,8 @@ extern unsigned int audit_serial(void);
extern void auditsc_get_stamp(struct audit_context *ctx,
struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
-extern uid_t audit_get_loginuid(struct audit_context *ctx);
+#define audit_get_loginuid(t) ((t)->loginuid)
+#define audit_get_sessionid(t) ((t)->sessionid)
extern void audit_log_task_context(struct audit_buffer *ab);
extern int __audit_ipc_obj(struct kern_ipc_perm *ipcp);
extern int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
@@ -488,7 +490,8 @@ extern int audit_signals;
#define audit_inode_child(d,i,p) 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_get_loginuid(t) (-1)
+#define audit_get_sessionid(t) (-1)
#define audit_log_task_context(b) do { ; } while (0)
#define audit_ipc_obj(i) ({ 0; })
#define audit_ipc_set_perm(q,u,g,m) ({ 0; })
@@ -522,9 +525,11 @@ extern void audit_log_end(struct audit_buffer *ab);
extern void audit_log_hex(struct audit_buffer *ab,
const unsigned char *buf,
size_t len);
-extern const char * audit_log_untrustedstring(struct audit_buffer *ab,
+extern int audit_string_contains_control(const char *string,
+ size_t len);
+extern void audit_log_untrustedstring(struct audit_buffer *ab,
const char *string);
-extern const char * audit_log_n_untrustedstring(struct audit_buffer *ab,
+extern void audit_log_n_untrustedstring(struct audit_buffer *ab,
size_t n,
const char *string);
extern void audit_log_d_path(struct audit_buffer *ab,
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 1a15f8e237a..90048fb28a3 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -21,6 +21,8 @@ union ktime;
#define FUTEX_LOCK_PI 6
#define FUTEX_UNLOCK_PI 7
#define FUTEX_TRYLOCK_PI 8
+#define FUTEX_WAIT_BITSET 9
+#define FUTEX_WAKE_BITSET 10
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG
@@ -33,6 +35,8 @@ union ktime;
#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITS | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITS | FUTEX_PRIVATE_FLAG)
/*
* Support for robust futexes: the kernel cleans up held futexes at
@@ -111,6 +115,12 @@ struct robust_list_head {
*/
#define ROBUST_LIST_LIMIT 2048
+/*
+ * bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a
+ * match of any bit.
+ */
+#define FUTEX_BITSET_MATCH_ANY 0xffffffff
+
#ifdef __KERNEL__
long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout,
u32 __user *uaddr2, u32 val2, u32 val3);
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index e6b3f708067..f42663eaf65 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -114,6 +114,13 @@ extern struct group_info init_groups;
.pid = &init_struct_pid, \
}
+#ifdef CONFIG_AUDITSYSCALL
+#define INIT_IDS \
+ .loginuid = -1, \
+ .sessionid = -1,
+#else
+#define INIT_IDS
+#endif
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -173,6 +180,7 @@ extern struct group_info init_groups;
[PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID), \
}, \
.dirties = INIT_PROP_LOCAL_SINGLE(dirties), \
+ INIT_IDS \
INIT_TRACE_IRQFLAGS \
INIT_LOCKDEP \
}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 6c333579d9d..af6947e69b4 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1139,6 +1139,10 @@ struct task_struct {
void *security;
#endif
struct audit_context *audit_context;
+#ifdef CONFIG_AUDITSYSCALL
+ uid_t loginuid;
+ unsigned int sessionid;
+#endif
seccomp_t seccomp;
/* Thread group tracking */
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index dfbdfb9836f..421323e5a2d 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -23,6 +23,7 @@ struct restart_block {
u32 *uaddr;
u32 val;
u32 flags;
+ u32 bitset;
u64 time;
} futex;
};
diff --git a/include/linux/tick.h b/include/linux/tick.h
index 0fadf95debe..a881c652f7e 100644
--- a/include/linux/tick.h
+++ b/include/linux/tick.h
@@ -39,6 +39,8 @@ enum tick_nohz_mode {
* @idle_calls: Total number of idle calls
* @idle_sleeps: Number of idle calls, where the sched tick was stopped
* @idle_entrytime: Time when the idle call was entered
+ * @idle_waketime: Time when the idle was interrupted
+ * @idle_exittime: Time when the idle state was left
* @idle_sleeptime: Sum of the time slept in idle with sched tick stopped
* @sleep_length: Duration of the current idle sleep
*/
@@ -53,6 +55,8 @@ struct tick_sched {
unsigned long idle_sleeps;
int idle_active;
ktime_t idle_entrytime;
+ ktime_t idle_waketime;
+ ktime_t idle_exittime;
ktime_t idle_sleeptime;
ktime_t idle_lastupdate;
ktime_t sleep_length;
diff --git a/include/linux/time.h b/include/linux/time.h
index b04136d60a2..ceaab9fff15 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -122,6 +122,7 @@ extern void monotonic_to_bootbased(struct timespec *ts);
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
extern int timekeeping_is_continuous(void);
extern void update_wall_time(void);
+extern void update_xtime_cache(u64 nsec);
/**
* timespec_to_ns - Convert timespec to nanoseconds
diff --git a/kernel/audit.c b/kernel/audit.c
index 801c946dd24..c8555b18021 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -66,10 +66,11 @@
* (Initialization happens after skb_init is called.) */
static int audit_initialized;
-/* 0 - no auditing
- * 1 - auditing enabled
- * 2 - auditing enabled and configuration is locked/unchangeable. */
+#define AUDIT_OFF 0
+#define AUDIT_ON 1
+#define AUDIT_LOCKED 2
int audit_enabled;
+int audit_ever_enabled;
/* Default state when kernel boots without any parameters. */
static int audit_default;
@@ -152,8 +153,10 @@ struct audit_buffer {
static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
{
- struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
- nlh->nlmsg_pid = pid;
+ if (ab) {
+ struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
+ nlh->nlmsg_pid = pid;
+ }
}
void audit_panic(const char *message)
@@ -163,7 +166,8 @@ void audit_panic(const char *message)
case AUDIT_FAIL_SILENT:
break;
case AUDIT_FAIL_PRINTK:
- printk(KERN_ERR "audit: %s\n", message);
+ if (printk_ratelimit())
+ printk(KERN_ERR "audit: %s\n", message);
break;
case AUDIT_FAIL_PANIC:
panic("audit: %s\n", message);
@@ -231,161 +235,107 @@ void audit_log_lost(const char *message)
}
if (print) {
- printk(KERN_WARNING
- "audit: audit_lost=%d audit_rate_limit=%d audit_backlog_limit=%d\n",
- atomic_read(&audit_lost),
- audit_rate_limit,
- audit_backlog_limit);
+ if (printk_ratelimit())
+ printk(KERN_WARNING
+ "audit: audit_lost=%d audit_rate_limit=%d "
+ "audit_backlog_limit=%d\n",
+ atomic_read(&audit_lost),
+ audit_rate_limit,
+ audit_backlog_limit);
audit_panic(message);
}
}
-static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
+static int audit_log_config_change(char *function_name, int new, int old,
+ uid_t loginuid, u32 sid, int allow_changes)
{
- int res, rc = 0, old = audit_rate_limit;
-
- /* check if we are locked */
- if (audit_enabled == 2)
- res = 0;
- else
- res = 1;
+ struct audit_buffer *ab;
+ int rc = 0;
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
+ audit_log_format(ab, "%s=%d old=%d by auid=%u", function_name, new,
+ old, loginuid);
if (sid) {
char *ctx = NULL;
u32 len;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_rate_limit=%d old=%d by auid=%u"
- " subj=%s res=%d",
- limit, old, loginuid, ctx, res);
+
+ rc = selinux_sid_to_string(sid, &ctx, &len);
+ if (rc) {
+ audit_log_format(ab, " sid=%u", sid);
+ allow_changes = 0; /* Something weird, deny request */
+ } else {
+ audit_log_format(ab, " subj=%s", ctx);
kfree(ctx);
- } else
- res = 0; /* Something weird, deny request */
+ }
}
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_rate_limit=%d old=%d by auid=%u res=%d",
- limit, old, loginuid, res);
-
- /* If we are allowed, make the change */
- if (res == 1)
- audit_rate_limit = limit;
- /* Not allowed, update reason */
- else if (rc == 0)
- rc = -EPERM;
+ audit_log_format(ab, " res=%d", allow_changes);
+ audit_log_end(ab);
return rc;
}
-static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
+static int audit_do_config_change(char *function_name, int *to_change,
+ int new, uid_t loginuid, u32 sid)
{
- int res, rc = 0, old = audit_backlog_limit;
+ int allow_changes, rc = 0, old = *to_change;
/* check if we are locked */
- if (audit_enabled == 2)
- res = 0;
+ if (audit_enabled == AUDIT_LOCKED)
+ allow_changes = 0;
else
- res = 1;
+ allow_changes = 1;
- if (sid) {
- char *ctx = NULL;
- u32 len;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_backlog_limit=%d old=%d by auid=%u"
- " subj=%s res=%d",
- limit, old, loginuid, ctx, res);
- kfree(ctx);
- } else
- res = 0; /* Something weird, deny request */
+ if (audit_enabled != AUDIT_OFF) {
+ rc = audit_log_config_change(function_name, new, old,
+ loginuid, sid, allow_changes);
+ if (rc)
+ allow_changes = 0;
}
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_backlog_limit=%d old=%d by auid=%u res=%d",
- limit, old, loginuid, res);
/* If we are allowed, make the change */
- if (res == 1)
- audit_backlog_limit = limit;
+ if (allow_changes == 1)
+ *to_change = new;
/* Not allowed, update reason */
else if (rc == 0)
rc = -EPERM;
return rc;
}
-static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
+static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
+{
+ return audit_do_config_change("audit_rate_limit", &audit_rate_limit,
+ limit, loginuid, sid);
+}
+
+static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
{
- int res, rc = 0, old = audit_enabled;
+ return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit,
+ limit, loginuid, sid);
+}
- if (state < 0 || state > 2)
+static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
+{
+ int rc;
+ if (state < AUDIT_OFF || state > AUDIT_LOCKED)
return -EINVAL;
- /* check if we are locked */
- if (audit_enabled == 2)
- res = 0;
- else
- res = 1;
+ rc = audit_do_config_change("audit_enabled", &audit_enabled, state,
+ loginuid, sid);
- if (sid) {
- char *ctx = NULL;
- u32 len;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_enabled=%d old=%d by auid=%u"
- " subj=%s res=%d",
- state, old, loginuid, ctx, res);
- kfree(ctx);
- } else
- res = 0; /* Something weird, deny request */
- }
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_enabled=%d old=%d by auid=%u res=%d",
- state, old, loginuid, res);
+ if (!rc)
+ audit_ever_enabled |= !!state;
- /* If we are allowed, make the change */
- if (res == 1)
- audit_enabled = state;
- /* Not allowed, update reason */
- else if (rc == 0)
- rc = -EPERM;
return rc;
}
static int audit_set_failure(int state, uid_t loginuid, u32 sid)
{
- int res, rc = 0, old = audit_failure;
-
if (state != AUDIT_FAIL_SILENT
&& state != AUDIT_FAIL_PRINTK
&& state != AUDIT_FAIL_PANIC)
return -EINVAL;
- /* check if we are locked */
- if (audit_enabled == 2)
- res = 0;
- else
- res = 1;
-
- if (sid) {
- char *ctx = NULL;
- u32 len;
- if ((rc = selinux_sid_to_string(sid, &ctx, &len)) == 0) {
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_failure=%d old=%d by auid=%u"
- " subj=%s res=%d",
- state, old, loginuid, ctx, res);
- kfree(ctx);
- } else
- res = 0; /* Something weird, deny request */
- }
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_failure=%d old=%d by auid=%u res=%d",
- state, old, loginuid, res);
-
- /* If we are allowed, make the change */
- if (res == 1)
- audit_failure = state;
- /* Not allowed, update reason */
- else if (rc == 0)
- rc = -EPERM;
- return rc;
+ return audit_do_config_change("audit_failure", &audit_failure, state,
+ loginuid, sid);
}
static int kauditd_thread(void *dummy)
@@ -405,7 +355,11 @@ static int kauditd_thread(void *dummy)
audit_pid = 0;
}
} else {
- printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0));
+ if (printk_ratelimit())
+ printk(KERN_NOTICE "%s\n", skb->data +
+ NLMSG_SPACE(0));
+ else
+ audit_log_lost("printk limit exceeded\n");
kfree_skb(skb);
}
} else {
@@ -573,6 +527,33 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)
return err;
}
+static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
+ u32 pid, u32 uid, uid_t auid, u32 sid)
+{
+ int rc = 0;
+ char *ctx = NULL;
+ u32 len;
+
+ if (!audit_enabled) {
+ *ab = NULL;
+ return rc;
+ }
+
+ *ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
+ audit_log_format(*ab, "user pid=%d uid=%u auid=%u",
+ pid, uid, auid);
+ if (sid) {
+ rc = selinux_sid_to_string(sid, &ctx, &len);
+ if (rc)
+ audit_log_format(*ab, " ssid=%u", sid);
+ else
+ audit_log_format(*ab, " subj=%s", ctx);
+ kfree(ctx);
+ }
+
+ return rc;
+}
+
static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
u32 uid, pid, seq, sid;
@@ -583,7 +564,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
u16 msg_type = nlh->nlmsg_type;
uid_t loginuid; /* loginuid of sender */
struct audit_sig_info *sig_data;
- char *ctx;
+ char *ctx = NULL;
u32 len;
err = audit_netlink_ok(skb, msg_type);
@@ -634,23 +615,14 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (err < 0) return err;
}
if (status_get->mask & AUDIT_STATUS_PID) {
- int old = audit_pid;
- if (sid) {
- if ((err = selinux_sid_to_string(
- sid, &ctx, &len)))
- return err;
- else
- audit_log(NULL, GFP_KERNEL,
- AUDIT_CONFIG_CHANGE,
- "audit_pid=%d old=%d by auid=%u subj=%s",
- status_get->pid, old,
- loginuid, ctx);
- kfree(ctx);
- } else
- audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE,
- "audit_pid=%d old=%d by auid=%u",
- status_get->pid, old, loginuid);
- audit_pid = status_get->pid;
+ int new_pid = status_get->pid;
+
+ if (audit_enabled != AUDIT_OFF)
+ audit_log_config_change("audit_pid", new_pid,
+ audit_pid, loginuid,
+ sid, 1);
+
+ audit_pid = new_pid;
}
if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
err = audit_set_rate_limit(status_get->rate_limit,
@@ -673,64 +645,35 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
if (err)
break;
}
- ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
- if (ab) {
- audit_log_format(ab,
- "user pid=%d uid=%u auid=%u",
- pid, uid, loginuid);
- if (sid) {
- if (selinux_sid_to_string(
- sid, &ctx, &len)) {
- audit_log_format(ab,
- " ssid=%u", sid);
- /* Maybe call audit_panic? */
- } else
- audit_log_format(ab,
- " subj=%s", ctx);
- kfree(ctx);
- }
- if (msg_type != AUDIT_USER_TTY)
- audit_log_format(ab, " msg='%.1024s'",
- (char *)data);
- else {
- int size;
-
- audit_log_format(ab, " msg=");
- size = nlmsg_len(nlh);
- audit_log_n_untrustedstring(ab, size,
- data);
- }
- audit_set_pid(ab, pid);
- audit_log_end(ab);
+ audit_log_common_recv_msg(&ab, msg_type, pid, uid,
+ loginuid, sid);
+
+ if (msg_type != AUDIT_USER_TTY)
+ audit_log_format(ab, " msg='%.1024s'",
+ (char *)data);
+ else {
+ int size;
+
+ audit_log_format(ab, " msg=");
+ size = nlmsg_len(nlh);
+ audit_log_n_untrustedstring(ab, size,
+ data);
}
+ audit_set_pid(ab, pid);
+ audit_log_end(ab);
}
break;
case AUDIT_ADD:
case AUDIT_DEL:
if (nlmsg_len(nlh) < sizeof(struct audit_rule))
return -EINVAL;
- if (audit_enabled == 2) {
- ab = audit_log_start(NULL, GFP_KERNEL,
- AUDIT_CONFIG_CHANGE);
- if (ab) {
- audit_log_format(ab,
- "pid=%d uid=%u auid=%u",
- pid, uid, loginuid);
- if (sid) {
- if (selinux_sid_to_string(
- sid, &ctx, &len)) {
- audit_log_format(ab,
- " ssid=%u", sid);
- /* Maybe call audit_panic? */
- } else
- audit_log_format(ab,
- " subj=%s", ctx);
- kfree(ctx);
- }
- audit_log_format(ab, " audit_enabled=%d res=0",
- audit_enabled);
- audit_log_end(ab);
- }
+ if (audit_enabled == AUDIT_LOCKED) {
+ audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+ uid, loginuid, sid);
+
+ audit_log_format(ab, " audit_enabled=%d res=0",
+ audit_enabled);
+ audit_log_end(ab);
return -EPERM;
}
/* fallthrough */
@@ -743,28 +686,13 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case AUDIT_DEL_RULE:
if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))
return -EINVAL;
- if (audit_enabled == 2) {
- ab = audit_log_start(NULL, GFP_KERNEL,
- AUDIT_CONFIG_CHANGE);
- if (ab) {
- audit_log_format(ab,
- "pid=%d uid=%u auid=%u",
- pid, uid, loginuid);
- if (sid) {
- if (selinux_sid_to_string(
- sid, &ctx, &len)) {
- audit_log_format(ab,
- " ssid=%u", sid);
- /* Maybe call audit_panic? */
- } else
- audit_log_format(ab,
- " subj=%s", ctx);
- kfree(ctx);
- }
- audit_log_format(ab, " audit_enabled=%d res=0",
- audit_enabled);
- audit_log_end(ab);
- }
+ if (audit_enabled == AUDIT_LOCKED) {
+ audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+ uid, loginuid, sid);
+
+ audit_log_format(ab, " audit_enabled=%d res=0",
+ audit_enabled);
+ audit_log_end(ab);
return -EPERM;
}
/* fallthrough */
@@ -775,19 +703,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
break;
case AUDIT_TRIM:
audit_trim_trees();
- ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
- if (!ab)
- break;
- audit_log_format(ab, "auid=%u", loginuid);
- if (sid) {
- u32 len;
- ctx = NULL;
- 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_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+ uid, loginuid, sid);
+
audit_log_format(ab, " op=trim res=1");
audit_log_end(ab);
break;
@@ -817,22 +736,9 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
/* OK, here comes... */
err = audit_tag_tree(old, new);
- ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
- if (!ab) {
- kfree(old);
- kfree(new);
- break;
- }
- audit_log_format(ab, "auid=%u", loginuid);
- if (sid) {
- u32 len;
- ctx = NULL;
- 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_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
+ uid, loginuid, sid);
+
audit_log_format(ab, " op=make_equiv old=");
audit_log_untrustedstring(ab, old);
audit_log_format(ab, " new=");
@@ -965,6 +871,7 @@ static int __init audit_init(void)
skb_queue_head_init(&audit_skb_queue);
audit_initialized = 1;
audit_enabled = audit_default;
+ audit_ever_enabled |= !!audit_default;
/* Register the callback with selinux. This callback will be invoked
* when a new policy is loaded. */
@@ -992,8 +899,10 @@ static int __init audit_enable(char *str)
printk(KERN_INFO "audit: %s%s\n",
audit_default ? "enabled" : "disabled",
audit_initialized ? "" : " (after initialization)");
- if (audit_initialized)
+ if (audit_initialized) {
audit_enabled = audit_default;
+ audit_ever_enabled |= !!audit_default;
+ }
return 1;
}
@@ -1130,7 +1039,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
{
struct audit_buffer *ab = NULL;
struct timespec t;
- unsigned int serial;
+ unsigned int uninitialized_var(serial);
int reserve;
unsigned long timeout_start = jiffies;
@@ -1164,7 +1073,7 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,
remove_wait_queue(&audit_backlog_wait, &wait);
continue;
}
- if (audit_rate_check())
+ if (audit_rate_check() && printk_ratelimit())
printk(KERN_WARNING
"audit: audit_backlog=%d > "
"audit_backlog_limit=%d\n",
@@ -1249,6 +1158,7 @@ static void audit_log_vformat(struct audit_buffer *ab, const char *fmt,
goto out;
len = vsnprintf(skb_tail_pointer(skb), avail, fmt, args2);
}
+ va_end(args2);
if (len > 0)
skb_put(skb, len);
out:
@@ -1350,6 +1260,21 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
}
/**
+ * audit_string_contains_control - does a string need to be logged in hex
+ * @string - string to be checked
+ * @len - max length of the string to check
+ */
+int audit_string_contains_control(const char *string, size_t len)
+{
+ const unsigned char *p;
+ for (p = string; p < (const unsigned char *)string + len && *p; p++) {
+ if (*p == '"' || *p < 0x21 || *p > 0x7f)
+ return 1;
+ }
+ return 0;
+}
+
+/**
* audit_log_n_untrustedstring - log a string that may contain random characters
* @ab: audit_buffer
* @len: lenth of string (not including trailing null)
@@ -1363,19 +1288,13 @@ static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
* The caller specifies the number of characters in the string to log, which may
* or may not be the entire string.
*/
-const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
- const char *string)
+void audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
+ const char *string)
{
- const unsigned char *p;
-
- for (p = string; p < (const unsigned char *)string + len && *p; p++) {
- if (*p == '"' || *p < 0x21 || *p > 0x7f) {
- audit_log_hex(ab, string, len);
- return string + len + 1;
- }
- }
- audit_log_n_string(ab, len, string);
- return p + 1;
+ if (audit_string_contains_control(string, len))
+ audit_log_hex(ab, string, len);
+ else
+ audit_log_n_string(ab, len, string);
}
/**
@@ -1386,9 +1305,9 @@ const char *audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
* Same as audit_log_n_untrustedstring(), except that strlen is used to
* determine string length.
*/
-const char *audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
+void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
{
- return audit_log_n_untrustedstring(ab, strlen(string), string);
+ audit_log_n_untrustedstring(ab, strlen(string), string);
}
/* This is a helper-function to print the escaped d_path */
@@ -1437,8 +1356,11 @@ void audit_log_end(struct audit_buffer *ab)
skb_queue_tail(&audit_skb_queue, ab->skb);
ab->skb = NULL;
wake_up_interruptible(&kauditd_wait);
+ } else if (printk_ratelimit()) {
+ struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
+ printk(KERN_NOTICE "type=%d %s\n", nlh->nlmsg_type, ab->skb->data + NLMSG_SPACE(0));
} else {
- printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0));
+ audit_log_lost("printk limit exceeded\n");
}
}
audit_buffer_free(ab);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 5d96f2cc7be..6f19fd477aa 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -95,6 +95,8 @@ extern struct inotify_handle *audit_ih;
/* Inotify events we care about. */
#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
+extern int audit_enabled;
+
void audit_free_parent(struct inotify_watch *i_watch)
{
struct audit_parent *parent;
@@ -974,7 +976,6 @@ static void audit_update_watch(struct audit_parent *parent,
struct audit_watch *owatch, *nwatch, *nextw;
struct audit_krule *r, *nextr;
struct audit_entry *oentry, *nentry;
- struct audit_buffer *ab;
mutex_lock(&audit_filter_mutex);
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
@@ -1014,13 +1015,18 @@ static void audit_update_watch(struct audit_parent *parent,
call_rcu(&oentry->rcu, audit_free_rule_rcu);
}
- ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
- audit_log_format(ab, "op=updated rules specifying path=");
- audit_log_untrustedstring(ab, owatch->path);
- audit_log_format(ab, " with dev=%u ino=%lu\n", dev, ino);
- audit_log_format(ab, " list=%d res=1", r->listnr);
- audit_log_end(ab);
-
+ if (audit_enabled) {
+ struct audit_buffer *ab;
+ ab = audit_log_start(NULL, GFP_KERNEL,
+ AUDIT_CONFIG_CHANGE);
+ audit_log_format(ab,
+ "op=updated rules specifying path=");
+ audit_log_untrustedstring(ab, owatch->path);
+ audit_log_format(ab, " with dev=%u ino=%lu\n",
+ dev, ino);
+ audit_log_format(ab, " list=%d res=1", r->listnr);
+ audit_log_end(ab);
+ }
audit_remove_watch(owatch);
goto add_watch_to_parent; /* event applies to a single watch */
}
@@ -1039,25 +1045,28 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
struct audit_watch *w, *nextw;
struct audit_krule *r, *nextr;
struct audit_entry *e;
- struct audit_buffer *ab;
mutex_lock(&audit_filter_mutex);
parent->flags |= AUDIT_PARENT_INVALID;
list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
e = container_of(r, struct audit_entry, rule);
-
- ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
- audit_log_format(ab, "op=remove rule path=");
- audit_log_untrustedstring(ab, w->path);
- if (r->filterkey) {
- audit_log_format(ab, " key=");
- audit_log_untrustedstring(ab, r->filterkey);
- } else
- audit_log_format(ab, " key=(null)");
- audit_log_format(ab, " list=%d res=1", r->listnr);
- audit_log_end(ab);
-
+ if (audit_enabled) {
+ struct audit_buffer *ab;
+ ab = audit_log_start(NULL, GFP_KERNEL,
+ AUDIT_CONFIG_CHANGE);
+ audit_log_format(ab, "op=remove rule path=");
+ audit_log_untrustedstring(ab, w->path);
+ if (r->filterkey) {
+ audit_log_format(ab, " key=");
+ audit_log_untrustedstring(ab,
+ r->filterkey);
+ } else
+ audit_log_format(ab, " key=(null)");
+ audit_log_format(ab, " list=%d res=1",
+ r->listnr);
+ audit_log_end(ab);
+ }
list_del(&r->rlist);
list_del_rcu(&e->list);
call_rcu(&e->rcu, audit_free_rule_rcu);
@@ -1495,6 +1504,9 @@ static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
{
struct audit_buffer *ab;
+ if (!audit_enabled)
+ return;
+
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
if (!ab)
return;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index bce9ecdb771..1c06ecf38d7 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -70,6 +70,7 @@
#include "audit.h"
extern struct list_head audit_filter_list[];
+extern int audit_ever_enabled;
/* AUDIT_NAMES is the number of slots we reserve in the audit_context
* for saving names from getname(). */
@@ -78,6 +79,9 @@ extern struct list_head audit_filter_list[];
/* Indicates that audit should log the full pathname. */
#define AUDIT_NAME_FULL -1
+/* no execve audit message should be longer than this (userspace limits) */
+#define MAX_EXECVE_AUDIT_LEN 7500
+
/* number of audit rules */
int audit_n_rules;
@@ -176,7 +180,11 @@ struct audit_aux_data_fd_pair {
struct audit_aux_data_pids {
struct audit_aux_data d;
pid_t target_pid[AUDIT_AUX_PIDS];
+ uid_t target_auid[AUDIT_AUX_PIDS];
+ uid_t target_uid[AUDIT_AUX_PIDS];
+ unsigned int target_sessionid[AUDIT_AUX_PIDS];
u32 target_sid[AUDIT_AUX_PIDS];
+ char target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN];
int pid_count;
};
@@ -192,7 +200,6 @@ struct audit_context {
enum audit_state state;
unsigned int serial; /* serial number for record */
struct timespec ctime; /* time of syscall entry */
- uid_t loginuid; /* login uid (identity) */
int major; /* syscall number */
unsigned long argv[4]; /* syscall arguments */
int return_valid; /* return code is valid */
@@ -215,7 +222,11 @@ struct audit_context {
int arch;
pid_t target_pid;
+ uid_t target_auid;
+ uid_t target_uid;
+ unsigned int target_sessionid;
u32 target_sid;
+ char target_comm[TASK_COMM_LEN];
struct audit_tree_refs *trees, *first_trees;
int tree_count;
@@ -506,7 +517,7 @@ static int audit_filter_rules(struct task_struct *tsk,
case AUDIT_LOGINUID:
result = 0;
if (ctx)
- result = audit_comparator(ctx->loginuid, f->op, f->val);
+ result = audit_comparator(tsk->loginuid, f->op, f->val);
break;
case AUDIT_SUBJ_USER:
case AUDIT_SUBJ_ROLE:
@@ -702,7 +713,24 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
if (likely(!context))
return NULL;
context->return_valid = return_valid;
- context->return_code = return_code;
+
+ /*
+ * we need to fix up the return code in the audit logs if the actual
+ * return codes are later going to be fixed up by the arch specific
+ * signal handlers
+ *
+ * This is actually a test for:
+ * (rc == ERESTARTSYS ) || (rc == ERESTARTNOINTR) ||
+ * (rc == ERESTARTNOHAND) || (rc == ERESTART_RESTARTBLOCK)
+ *
+ * but is faster than a bunch of ||
+ */
+ if (unlikely(return_code <= -ERESTARTSYS) &&
+ (return_code >= -ERESTART_RESTARTBLOCK) &&
+ (return_code != -ENOIOCTLCMD))
+ context->return_code = -EINTR;
+ else
+ context->return_code = return_code;
if (context->in_syscall && !context->dummy && !context->auditable) {
enum audit_state state;
@@ -783,11 +811,8 @@ static inline void audit_free_aux(struct audit_context *context)
static inline void audit_zero_context(struct audit_context *context,
enum audit_state state)
{
- uid_t loginuid = context->loginuid;
-
memset(context, 0, sizeof(*context));
context->state = state;
- context->loginuid = loginuid;
}
static inline struct audit_context *audit_alloc_context(enum audit_state state)
@@ -814,7 +839,7 @@ int audit_alloc(struct task_struct *tsk)
struct audit_context *context;
enum audit_state state;
- if (likely(!audit_enabled))
+ if (likely(!audit_ever_enabled))
return 0; /* Return if not auditing. */
state = audit_filter_task(tsk);
@@ -826,11 +851,6 @@ int audit_alloc(struct task_struct *tsk)
return -ENOMEM;
}
- /* Preserve login uid */
- context->loginuid = -1;
- if (current->audit_context)
- context->loginuid = current->audit_context->loginuid;
-
tsk->audit_context = context;
set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
return 0;
@@ -922,7 +942,8 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk
}
static int audit_log_pid_context(struct audit_context *context, pid_t pid,
- u32 sid)
+ uid_t auid, uid_t uid, unsigned int sessionid,
+ u32 sid, char *comm)
{
struct audit_buffer *ab;
char *s = NULL;
@@ -931,68 +952,204 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
ab = audit_log_start(context, GFP_KERNEL, AUDIT_OBJ_PID);
if (!ab)
- return 1;
+ return rc;
+ audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid,
+ uid, sessionid);
if (selinux_sid_to_string(sid, &s, &len)) {
- audit_log_format(ab, "opid=%d obj=(none)", pid);
+ audit_log_format(ab, " obj=(none)");
rc = 1;
} else
- audit_log_format(ab, "opid=%d obj=%s", pid, s);
+ audit_log_format(ab, " obj=%s", s);
+ audit_log_format(ab, " ocomm=");
+ audit_log_untrustedstring(ab, comm);
audit_log_end(ab);
kfree(s);
return rc;
}
-static void audit_log_execve_info(struct audit_buffer *ab,
- struct audit_aux_data_execve *axi)
+/*
+ * to_send and len_sent accounting are very loose estimates. We aren't
+ * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
+ * within about 500 bytes (next page boundry)
+ *
+ * why snprintf? an int is up to 12 digits long. if we just assumed when
+ * logging that a[%d]= was going to be 16 characters long we would be wasting
+ * space in every audit message. In one 7500 byte message we can log up to
+ * about 1000 min size arguments. That comes down to about 50% waste of space
+ * if we didn't do the snprintf to find out how long arg_num_len was.
+ */
+static int audit_log_single_execve_arg(struct audit_context *context,
+ struct audit_buffer **ab,
+ int arg_num,
+ size_t *len_sent,
+ const char __user *p,
+ char *buf)
{
- int i;
- long len, ret;
- const char __user *p;
- char *buf;
+ char arg_num_len_buf[12];
+ const char __user *tmp_p = p;
+ /* how many digits are in arg_num? 3 is the length of a=\n */
+ size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 3;
+ size_t len, len_left, to_send;
+ size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
+ unsigned int i, has_cntl = 0, too_long = 0;
+ int ret;
+
+ /* strnlen_user includes the null we don't want to send */
+ len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
- if (axi->mm != current->mm)
- return; /* execve failed, no additional info */
-
- p = (const char __user *)axi->mm->arg_start;
+ /*
+ * We just created this mm, if we can't find the strings
+ * we just copied into it something is _very_ wrong. Similar
+ * for strings that are too long, we should not have created
+ * any.
+ */
+ if (unlikely((len = -1) || len > MAX_ARG_STRLEN - 1)) {
+ WARN_ON(1);
+ send_sig(SIGKILL, current, 0);
+ }
- for (i = 0; i < axi->argc; i++, p += len) {
- len = strnlen_user(p, MAX_ARG_STRLEN);
+ /* walk the whole argument looking for non-ascii chars */
+ do {
+ if (len_left > MAX_EXECVE_AUDIT_LEN)
+ to_send = MAX_EXECVE_AUDIT_LEN;
+ else
+ to_send = len_left;
+ ret = copy_from_user(buf, tmp_p, to_send);
/*
- * We just created this mm, if we can't find the strings
- * we just copied into it something is _very_ wrong. Similar
- * for strings that are too long, we should not have created
- * any.
+ * There is no reason for this copy to be short. We just
+ * copied them here, and the mm hasn't been exposed to user-
+ * space yet.
*/
- if (!len || len > MAX_ARG_STRLEN) {
+ if (ret) {
WARN_ON(1);
send_sig(SIGKILL, current, 0);
}
-
- buf = kmalloc(len, GFP_KERNEL);
- if (!buf) {
- audit_panic("out of memory for argv string\n");
+ buf[to_send] = '\0';
+ has_cntl = audit_string_contains_control(buf, to_send);
+ if (has_cntl) {
+ /*
+ * hex messages get logged as 2 bytes, so we can only
+ * send half as much in each message
+ */
+ max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
break;
}
+ len_left -= to_send;
+ tmp_p += to_send;
+ } while (len_left > 0);
+
+ len_left = len;
+
+ if (len > max_execve_audit_len)
+ too_long = 1;
+
+ /* rewalk the argument actually logging the message */
+ for (i = 0; len_left > 0; i++) {
+ int room_left;
+
+ if (len_left > max_execve_audit_len)
+ to_send = max_execve_audit_len;
+ else
+ to_send = len_left;
+
+ /* do we have space left to send this argument in this ab? */
+ room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
+ if (has_cntl)
+ room_left -= (to_send * 2);
+ else
+ room_left -= to_send;
+ if (room_left < 0) {
+ *len_sent = 0;
+ audit_log_end(*ab);
+ *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
+ if (!*ab)
+ return 0;
+ }
- ret = copy_from_user(buf, p, len);
/*
- * There is no reason for this copy to be short. We just
- * copied them here, and the mm hasn't been exposed to user-
- * space yet.
+ * first record needs to say how long the original string was
+ * so we can be sure nothing was lost.
+ */
+ if ((i == 0) && (too_long))
+ audit_log_format(*ab, "a%d_len=%ld ", arg_num,
+ has_cntl ? 2*len : len);
+
+ /*
+ * normally arguments are small enough to fit and we already
+ * filled buf above when we checked for control characters
+ * so don't bother with another copy_from_user
*/
+ if (len >= max_execve_audit_len)
+ ret = copy_from_user(buf, p, to_send);
+ else
+ ret = 0;
if (ret) {
WARN_ON(1);
send_sig(SIGKILL, current, 0);
}
+ buf[to_send] = '\0';
+
+ /* actually log it */
+ audit_log_format(*ab, "a%d", arg_num);
+ if (too_long)
+ audit_log_format(*ab, "[%d]", i);
+ audit_log_format(*ab, "=");
+ if (has_cntl)
+ audit_log_hex(*ab, buf, to_send);
+ else
+ audit_log_format(*ab, "\"%s\"", buf);
+ audit_log_format(*ab, "\n");
+
+ p += to_send;
+ len_left -= to_send;
+ *len_sent += arg_num_len;
+ if (has_cntl)
+ *len_sent += to_send * 2;
+ else
+ *len_sent += to_send;
+ }
+ /* include the null we didn't log */
+ return len + 1;
+}
- audit_log_format(ab, "a%d=", i);
- audit_log_untrustedstring(ab, buf);
- audit_log_format(ab, "\n");
+static void audit_log_execve_info(struct audit_context *context,
+ struct audit_buffer **ab,
+ struct audit_aux_data_execve *axi)
+{
+ int i;
+ size_t len, len_sent = 0;
+ const char __user *p;
+ char *buf;
+
+ if (axi->mm != current->mm)
+ return; /* execve failed, no additional info */
+
+ p = (const char __user *)axi->mm->arg_start;
+
+ audit_log_format(*ab, "argc=%d ", axi->argc);
+
+ /*
+ * we need some kernel buffer to hold the userspace args. Just
+ * allocate one big one rather than allocating one of the right size
+ * for every single argument inside audit_log_single_execve_arg()
+ * should be <8k allocation so should be pretty safe.
+ */
+ buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
+ if (!buf) {
+ audit_panic("out of memory for argv string\n");
+ return;
+ }
- kfree(buf);
+ for (i = 0; i < axi->argc; i++) {
+ len = audit_log_single_execve_arg(context, ab, i,
+ &len_sent, p, buf);
+ if (len <= 0)
+ break;
+ p += len;
}
+ kfree(buf);
}
static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)
@@ -1039,7 +1196,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
" ppid=%d pid=%d auid=%u uid=%u gid=%u"
" euid=%u suid=%u fsuid=%u"
- " egid=%u sgid=%u fsgid=%u tty=%s",
+ " egid=%u sgid=%u fsgid=%u tty=%s ses=%u",
context->argv[0],
context->argv[1],
context->argv[2],
@@ -1047,11 +1204,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
context->name_count,
context->ppid,
context->pid,
- context->loginuid,
+ tsk->loginuid,
context->uid,
context->gid,
context->euid, context->suid, context->fsuid,
- context->egid, context->sgid, context->fsgid, tty);
+ context->egid, context->sgid, context->fsgid, tty,
+ tsk->sessionid);
mutex_unlock(&tty_mutex);
@@ -1135,7 +1293,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
case AUDIT_EXECVE: {
struct audit_aux_data_execve *axi = (void *)aux;
- audit_log_execve_info(ab, axi);
+ audit_log_execve_info(context, &ab, axi);
break; }
case AUDIT_SOCKETCALL: {
@@ -1168,13 +1326,19 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
for (i = 0; i < axs->pid_count; i++)
if (audit_log_pid_context(context, axs->target_pid[i],
- axs->target_sid[i]))
+ axs->target_auid[i],
+ axs->target_uid[i],
+ axs->target_sessionid[i],
+ axs->target_sid[i],
+ axs->target_comm[i]))
call_panic = 1;
}
if (context->target_pid &&
audit_log_pid_context(context, context->target_pid,
- context->target_sid))
+ context->target_auid, context->target_uid,
+ context->target_sessionid,
+ context->target_sid, context->target_comm))
call_panic = 1;
if (context->pwd && context->pwdmnt) {
@@ -1242,6 +1406,11 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_end(ab);
}
+
+ /* Send end of event record to help user space know we are finished */
+ ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);
+ if (ab)
+ audit_log_end(ab);
if (call_panic)
audit_panic("error converting sid to string");
}
@@ -1766,6 +1935,9 @@ void auditsc_get_stamp(struct audit_context *ctx,
ctx->auditable = 1;
}
+/* global counter which is incremented every time something logs in */
+static atomic_t session_id = ATOMIC_INIT(0);
+
/**
* audit_set_loginuid - set a task's audit_context loginuid
* @task: task whose audit context is being modified
@@ -1777,41 +1949,29 @@ void auditsc_get_stamp(struct audit_context *ctx,
*/
int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
{
+ unsigned int sessionid = atomic_inc_return(&session_id);
struct audit_context *context = task->audit_context;
- if (context) {
- /* Only log if audit is enabled */
- if (context->in_syscall) {
- struct audit_buffer *ab;
-
- ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
- if (ab) {
- audit_log_format(ab, "login pid=%d uid=%u "
- "old auid=%u new auid=%u",
- task->pid, task->uid,
- context->loginuid, loginuid);
- audit_log_end(ab);
- }
+ if (context && context->in_syscall) {
+ struct audit_buffer *ab;
+
+ ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN);
+ if (ab) {
+ audit_log_format(ab, "login pid=%d uid=%u "
+ "old auid=%u new auid=%u"
+ " old ses=%u new ses=%u",
+ task->pid, task->uid,
+ task->loginuid, loginuid,
+ task->sessionid, sessionid);
+ audit_log_end(ab);
}
- context->loginuid = loginuid;
}
+ task->sessionid = sessionid;
+ task->loginuid = loginuid;
return 0;
}
/**
- * audit_get_loginuid - get the loginuid for an audit_context
- * @ctx: the audit_context
- *
- * Returns the context's loginuid or -1 if @ctx is NULL.
- */
-uid_t audit_get_loginuid(struct audit_context *ctx)
-{
- return ctx ? ctx->loginuid : -1;
-}
-
-EXPORT_SYMBOL(audit_get_loginuid);
-
-/**
* __audit_mq_open - record audit data for a POSIX MQ open
* @oflag: open flag
* @mode: mode bits
@@ -2070,8 +2230,6 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
return 0;
}
-int audit_argv_kb = 32;
-
int audit_bprm(struct linux_binprm *bprm)
{
struct audit_aux_data_execve *ax;
@@ -2080,14 +2238,6 @@ int audit_bprm(struct linux_binprm *bprm)
if (likely(!audit_enabled || !context || context->dummy))
return 0;
- /*
- * Even though the stack code doesn't limit the arg+env size any more,
- * the audit code requires that _all_ arguments be logged in a single
- * netlink skb. Hence cap it :-(
- */
- if (bprm->argv_len > (audit_argv_kb << 10))
- return -E2BIG;
-
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
if (!ax)
return -ENOMEM;
@@ -2193,7 +2343,11 @@ void __audit_ptrace(struct task_struct *t)
struct audit_context *context = current->audit_context;
context->target_pid = t->pid;
+ context->target_auid = audit_get_loginuid(t);
+ context->target_uid = t->uid;
+ context->target_sessionid = audit_get_sessionid(t);
selinux_get_task_sid(t, &context->target_sid);
+ memcpy(context->target_comm, t->comm, TASK_COMM_LEN);
}
/**
@@ -2216,8 +2370,8 @@ int __audit_signal_info(int sig, struct task_struct *t)
if (audit_pid && t->tgid == audit_pid) {
if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
audit_sig_pid = tsk->pid;
- if (ctx)
- audit_sig_uid = ctx->loginuid;
+ if (tsk->loginuid != -1)
+ audit_sig_uid = tsk->loginuid;
else
audit_sig_uid = tsk->uid;
selinux_get_task_sid(tsk, &audit_sig_sid);
@@ -2230,7 +2384,11 @@ int __audit_signal_info(int sig, struct task_struct *t)
* in audit_context */
if (!ctx->target_pid) {
ctx->target_pid = t->tgid;
+ ctx->target_auid = audit_get_loginuid(t);
+ ctx->target_uid = t->uid;
+ ctx->target_sessionid = audit_get_sessionid(t);
selinux_get_task_sid(t, &ctx->target_sid);
+ memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN);
return 0;
}
@@ -2247,7 +2405,11 @@ int __audit_signal_info(int sig, struct task_struct *t)
BUG_ON(axp->pid_count >= AUDIT_AUX_PIDS);
axp->target_pid[axp->pid_count] = t->tgid;
+ axp->target_auid[axp->pid_count] = audit_get_loginuid(t);
+ axp->target_uid[axp->pid_count] = t->uid;
+ axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t);
selinux_get_task_sid(t, &axp->target_sid[axp->pid_count]);
+ memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN);
axp->pid_count++;
return 0;
@@ -2264,6 +2426,8 @@ void audit_core_dumps(long signr)
{
struct audit_buffer *ab;
u32 sid;
+ uid_t auid = audit_get_loginuid(current);
+ unsigned int sessionid = audit_get_sessionid(current);
if (!audit_enabled)
return;
@@ -2272,9 +2436,8 @@ void audit_core_dumps(long signr)
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);
+ audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u",
+ auid, current->uid, current->gid, sessionid);
selinux_get_task_sid(current, &sid);
if (sid) {
char *ctx = NULL;
diff --git a/kernel/futex.c b/kernel/futex.c
index db9824de8bf..a6baaec44b8 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -109,6 +109,9 @@ struct futex_q {
/* Optional priority inheritance state: */
struct futex_pi_state *pi_state;
struct task_struct *task;
+
+ /* Bitset for the optional bitmasked wakeup */
+ u32 bitset;
};
/*
@@ -722,7 +725,7 @@ double_lock_hb(struct futex_hash_bucket *hb1, struct futex_hash_bucket *hb2)
* to this virtual address:
*/
static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
- int nr_wake)
+ int nr_wake, u32 bitset)
{
struct futex_hash_bucket *hb;
struct futex_q *this, *next;
@@ -730,6 +733,9 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
union futex_key key;
int ret;
+ if (!bitset)
+ return -EINVAL;
+
futex_lock_mm(fshared);
ret = get_futex_key(uaddr, fshared, &key);
@@ -746,6 +752,11 @@ static int futex_wake(u32 __user *uaddr, struct rw_semaphore *fshared,
ret = -EINVAL;
break;
}
+
+ /* Check if one of the bits is set in both bitsets */
+ if (!(this->bitset & bitset))
+ continue;
+
wake_futex(this);
if (++ret >= nr_wake)
break;
@@ -1156,7 +1167,7 @@ static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
static long futex_wait_restart(struct restart_block *restart);
static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
- u32 val, ktime_t *abs_time)
+ u32 val, ktime_t *abs_time, u32 bitset)
{
struct task_struct *curr = current;
DECLARE_WAITQUEUE(wait, curr);
@@ -1167,7 +1178,11 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
struct hrtimer_sleeper t;
int rem = 0;
+ if (!bitset)
+ return -EINVAL;
+
q.pi_state = NULL;
+ q.bitset = bitset;
retry:
futex_lock_mm(fshared);
@@ -1252,6 +1267,8 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
t.timer.expires = *abs_time;
hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
+ if (!hrtimer_active(&t.timer))
+ t.task = NULL;
/*
* the timer could have already expired, in which
@@ -1293,6 +1310,7 @@ static int futex_wait(u32 __user *uaddr, struct rw_semaphore *fshared,
restart->futex.uaddr = (u32 *)uaddr;
restart->futex.val = val;
restart->futex.time = abs_time->tv64;
+ restart->futex.bitset = bitset;
restart->futex.flags = 0;
if (fshared)
@@ -1319,7 +1337,8 @@ static long futex_wait_restart(struct restart_block *restart)
restart->fn = do_no_restart_syscall;
if (restart->futex.flags & FLAGS_SHARED)
fshared = &current->mm->mmap_sem;
- return (long)futex_wait(uaddr, fshared, restart->futex.val, &t);
+ return (long)futex_wait(uaddr, fshared, restart->futex.val, &t,
+ restart->futex.bitset);
}
@@ -1535,9 +1554,6 @@ static int futex_lock_pi(u32 __user *uaddr, struct rw_semaphore *fshared,
owner = rt_mutex_owner(&q.pi_state->pi_mutex);
res = fixup_pi_state_owner(uaddr, &q, owner);
- WARN_ON(rt_mutex_owner(&q.pi_state->pi_mutex) !=
- owner);
-
/* propagate -EFAULT, if the fixup failed */
if (res)
ret = res;
@@ -1943,7 +1959,8 @@ retry:
* PI futexes happens in exit_pi_state():
*/
if (!pi && (uval & FUTEX_WAITERS))
- futex_wake(uaddr, &curr->mm->mmap_sem, 1);
+ futex_wake(uaddr, &curr->mm->mmap_sem, 1,
+ FUTEX_BITSET_MATCH_ANY);
}
return 0;
}
@@ -2043,10 +2060,14 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
switch (cmd) {
case FUTEX_WAIT:
- ret = futex_wait(uaddr, fshared, val, timeout);
+ val3 = FUTEX_BITSET_MATCH_ANY;
+ case FUTEX_WAIT_BITSET:
+ ret = futex_wait(uaddr, fshared, val, timeout, val3);
break;
case FUTEX_WAKE:
- ret = futex_wake(uaddr, fshared, val);
+ val3 = FUTEX_BITSET_MATCH_ANY;
+ case FUTEX_WAKE_BITSET:
+ ret = futex_wake(uaddr, fshared, val, val3);
break;
case FUTEX_FD:
/* non-zero val means F_SETOWN(getpid()) & F_SETSIG(val) */
@@ -2086,7 +2107,8 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val,
u32 val2 = 0;
int cmd = op & FUTEX_CMD_MASK;
- if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+ if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+ cmd == FUTEX_WAIT_BITSET)) {
if (copy_from_user(&ts, utime, sizeof(ts)) != 0)
return -EFAULT;
if (!timespec_valid(&ts))
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index 0a43def6fee..133d558db45 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -167,7 +167,8 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
int val2 = 0;
int cmd = op & FUTEX_CMD_MASK;
- if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) {
+ if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
+ cmd == FUTEX_WAIT_BITSET)) {
if (get_compat_timespec(&ts, utime))
return -EFAULT;
if (!timespec_valid(&ts))
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index bd5d6b5060b..1069998fe25 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -1315,6 +1315,8 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
} while (t->task && !signal_pending(current));
+ __set_current_state(TASK_RUNNING);
+
return t->task == NULL;
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 357b68ba23e..7cb1ac3e6ff 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -81,7 +81,6 @@ extern int percpu_pagelist_fraction;
extern int compat_log;
extern int maps_protect;
extern int sysctl_stat_interval;
-extern int audit_argv_kb;
extern int latencytop_enabled;
/* Constants used for minimum and maximum */
@@ -390,16 +389,6 @@ static struct ctl_table kern_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
-#ifdef CONFIG_AUDITSYSCALL
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "audit_argv_kb",
- .data = &audit_argv_kb,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
-#endif
{
.ctl_name = KERN_CORE_PATTERN,
.procname = "core_pattern",
diff --git a/kernel/time.c b/kernel/time.c
index 09d3c45c4da..4064c0566e7 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -129,6 +129,7 @@ static inline void warp_clock(void)
write_seqlock_irq(&xtime_lock);
wall_to_monotonic.tv_sec -= sys_tz.tz_minuteswest * 60;
xtime.tv_sec += sys_tz.tz_minuteswest * 60;
+ update_xtime_cache(0);
write_sequnlock_irq(&xtime_lock);
clock_was_set();
}
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 63f24b55069..88267f0a847 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -137,6 +137,7 @@ void tick_nohz_update_jiffies(void)
cpu_clear(cpu, nohz_cpu_mask);
now = ktime_get();
+ ts->idle_waketime = now;
local_irq_save(flags);
tick_do_update_jiffies64(now);
@@ -400,6 +401,7 @@ void tick_nohz_restart_sched_tick(void)
* Cancel the scheduled timer and restore the tick
*/
ts->tick_stopped = 0;
+ ts->idle_exittime = now;
hrtimer_cancel(&ts->sched_timer);
ts->sched_timer.expires = ts->idle_tick;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 092a2366b5a..cd5dbc4579c 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -47,7 +47,7 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
static unsigned long total_sleep_time; /* seconds */
static struct timespec xtime_cache __attribute__ ((aligned (16)));
-static inline void update_xtime_cache(u64 nsec)
+void update_xtime_cache(u64 nsec)
{
xtime_cache = xtime;
timespec_add_ns(&xtime_cache, nsec);
@@ -145,6 +145,7 @@ int do_settimeofday(struct timespec *tv)
set_normalized_timespec(&xtime, sec, nsec);
set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
+ update_xtime_cache(0);
clock->error = 0;
ntp_clear();
@@ -252,8 +253,8 @@ void __init timekeeping_init(void)
xtime.tv_nsec = 0;
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
+ update_xtime_cache(0);
total_sleep_time = 0;
-
write_sequnlock_irqrestore(&xtime_lock, flags);
}
@@ -290,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev)
}
/* Make sure that we have the correct xtime reference */
timespec_add_ns(&xtime, timekeeping_suspend_nsecs);
+ update_xtime_cache(0);
/* re-base the last cycle value */
clock->cycle_last = clocksource_read(clock);
clock->error = 0;
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 12c5f4cb6b8..d3d94c1a0fd 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -166,6 +166,8 @@ static void print_cpu(struct seq_file *m, int cpu, u64 now)
P(idle_calls);
P(idle_sleeps);
P_ns(idle_entrytime);
+ P_ns(idle_waketime);
+ P_ns(idle_exittime);
P_ns(idle_sleeptime);
P(last_jiffies);
P(next_jiffies);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 89f4035b526..0d8a5a4a789 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -581,7 +581,7 @@ config LATENCYTOP
select STACKTRACE
select SCHEDSTATS
select SCHED_DEBUG
- depends on X86 || X86_64
+ depends on HAVE_LATENCYTOP_SUPPORT
help
Enable this option if you want to use the LatencyTOP tool
to find out which userspace is blocking on what kernel operations.
diff --git a/net/core/dev.c b/net/core/dev.c
index edaff2720e1..9549417250b 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2752,12 +2752,15 @@ static void __dev_set_promiscuity(struct net_device *dev, int inc)
printk(KERN_INFO "device %s %s promiscuous mode\n",
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
"left");
- audit_log(current->audit_context, GFP_ATOMIC,
- AUDIT_ANOM_PROMISCUOUS,
- "dev=%s prom=%d old_prom=%d auid=%u",
- dev->name, (dev->flags & IFF_PROMISC),
- (old_flags & IFF_PROMISC),
- audit_get_loginuid(current->audit_context));
+ if (audit_enabled)
+ audit_log(current->audit_context, GFP_ATOMIC,
+ AUDIT_ANOM_PROMISCUOUS,
+ "dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u",
+ dev->name, (dev->flags & IFF_PROMISC),
+ (old_flags & IFF_PROMISC),
+ audit_get_loginuid(current),
+ current->uid, current->gid,
+ audit_get_sessionid(current));
if (dev->change_rx_flags)
dev->change_rx_flags(dev, IFF_PROMISC);
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 16b72b5570c..45c3c27d279 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1466,7 +1466,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
err = xfrm_state_update(x);
xfrm_audit_state_add(x, err ? 0 : 1,
- audit_get_loginuid(current->audit_context), 0);
+ audit_get_loginuid(current), 0);
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
@@ -1520,7 +1520,7 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
km_state_notify(x, &c);
out:
xfrm_audit_state_delete(x, err ? 0 : 1,
- audit_get_loginuid(current->audit_context), 0);
+ audit_get_loginuid(current), 0);
xfrm_state_put(x);
return err;
@@ -1695,7 +1695,7 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd
if (proto == 0)
return -EINVAL;
- audit_info.loginuid = audit_get_loginuid(current->audit_context);
+ audit_info.loginuid = audit_get_loginuid(current);
audit_info.secid = 0;
err = xfrm_state_flush(proto, &audit_info);
if (err)
@@ -2273,7 +2273,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
hdr->sadb_msg_type != SADB_X_SPDUPDATE);
xfrm_audit_policy_add(xp, err ? 0 : 1,
- audit_get_loginuid(current->audit_context), 0);
+ audit_get_loginuid(current), 0);
if (err)
goto out;
@@ -2356,7 +2356,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
return -ENOENT;
xfrm_audit_policy_delete(xp, err ? 0 : 1,
- audit_get_loginuid(current->audit_context), 0);
+ audit_get_loginuid(current), 0);
if (err)
goto out;
@@ -2617,7 +2617,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
if (delete) {
xfrm_audit_policy_delete(xp, err ? 0 : 1,
- audit_get_loginuid(current->audit_context), 0);
+ audit_get_loginuid(current), 0);
if (err)
goto out;
@@ -2694,7 +2694,7 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg
struct xfrm_audit audit_info;
int err;
- audit_info.loginuid = audit_get_loginuid(current->audit_context);
+ audit_info.loginuid = audit_get_loginuid(current);
audit_info.secid = 0;
err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
if (err)
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index ff9fb6ba0c5..1ab0da2632e 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1238,7 +1238,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
NETLINK_CB(skb).pid = nlk->pid;
NETLINK_CB(skb).dst_group = dst_group;
- NETLINK_CB(skb).loginuid = audit_get_loginuid(current->audit_context);
+ NETLINK_CB(skb).loginuid = audit_get_loginuid(current);
selinux_get_task_sid(current, &(NETLINK_CB(skb).sid));
memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 3ff76e84d54..7ba65e82941 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -493,7 +493,7 @@ expired:
km_state_expired(x, 1, 0);
xfrm_audit_state_delete(x, err ? 0 : 1,
- audit_get_loginuid(current->audit_context), 0);
+ audit_get_loginuid(current), 0);
out:
spin_unlock(&x->lock);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index a85740530af..0341567665b 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -172,9 +172,10 @@ static ssize_t sel_write_enforce(struct file * file, const char __user * buf,
if (length)
goto out;
audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
- "enforcing=%d old_enforcing=%d auid=%u", new_value,
- selinux_enforcing,
- audit_get_loginuid(current->audit_context));
+ "enforcing=%d old_enforcing=%d auid=%u ses=%u",
+ new_value, selinux_enforcing,
+ audit_get_loginuid(current),
+ audit_get_sessionid(current));
selinux_enforcing = new_value;
if (selinux_enforcing)
avc_ss_reset(0);
@@ -243,8 +244,9 @@ static ssize_t sel_write_disable(struct file * file, const char __user * buf,
if (length < 0)
goto out;
audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
- "selinux=0 auid=%u",
- audit_get_loginuid(current->audit_context));
+ "selinux=0 auid=%u ses=%u",
+ audit_get_loginuid(current),
+ audit_get_sessionid(current));
}
length = count;
@@ -356,8 +358,9 @@ out1:
(security_get_allow_unknown() ? "allow" : "deny")));
audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
- "policy loaded auid=%u",
- audit_get_loginuid(current->audit_context));
+ "policy loaded auid=%u ses=%u",
+ audit_get_loginuid(current),
+ audit_get_sessionid(current));
out:
mutex_unlock(&sel_mutex);
vfree(data);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 880d455aa65..fced6bccee7 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1905,11 +1905,12 @@ int security_set_bools(int len, int *values)
if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
audit_log(current->audit_context, GFP_ATOMIC,
AUDIT_MAC_CONFIG_CHANGE,
- "bool=%s val=%d old_val=%d auid=%u",
+ "bool=%s val=%d old_val=%d auid=%u ses=%u",
policydb.p_bool_val_to_name[i],
!!values[i],
policydb.bool_val_to_struct[i]->state,
- audit_get_loginuid(current->audit_context));
+ audit_get_loginuid(current),
+ audit_get_sessionid(current));
}
if (values[i]) {
policydb.bool_val_to_struct[i]->state = 1;