diff --git a/[refs] b/[refs] index b6d593b61fbd..56175ff41431 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 675eef66e3edcab8065533edfefbcbbacb9a30d3 +refs/heads/master: 2e885057b7f75035f0b85e02f737891482815a81 diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 31e3377d8e14..81c287fad79d 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -1885,11 +1885,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. arch_perfmon: [X86] Force use of architectural perfmon on Intel CPUs instead of the CPU specific event set. - timer: [X86] Force use of architectural NMI - timer mode (see also oprofile.timer - for generic hr timer mode) - [s390] Force legacy basic mode sampling - (report cpu_type "timer") oops=panic Always panic on oopses. Default is to just kill the process, but there is a small probability of @@ -2437,14 +2432,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted. stacktrace [FTRACE] Enabled the stack tracer on boot up. - stacktrace_filter=[function-list] - [FTRACE] Limit the functions that the stack tracer - will trace at boot up. function-list is a comma separated - list of functions. This list can be changed at run - time by the stack_trace_filter file in the debugfs - tracing directory. Note, this enables stack tracing - and the stacktrace above is not needed. - sti= [PARISC,HW] Format: Set the STI (builtin display/keyboard on the HP-PARISC diff --git a/trunk/Documentation/trace/events.txt b/trunk/Documentation/trace/events.txt index bb24c2a0e870..b510564aac7e 100644 --- a/trunk/Documentation/trace/events.txt +++ b/trunk/Documentation/trace/events.txt @@ -191,6 +191,8 @@ And for string fields they are: Currently, only exact string matches are supported. +Currently, the maximum number of predicates in a filter is 16. + 5.2 Setting filters ------------------- diff --git a/trunk/Documentation/virtual/kvm/api.txt b/trunk/Documentation/virtual/kvm/api.txt index 7945b0bd35e2..e2a4b5287361 100644 --- a/trunk/Documentation/virtual/kvm/api.txt +++ b/trunk/Documentation/virtual/kvm/api.txt @@ -1100,6 +1100,15 @@ emulate them efficiently. The fields in each entry are defined as follows: eax, ebx, ecx, edx: the values returned by the cpuid instruction for this function/index combination +The TSC deadline timer feature (CPUID leaf 1, ecx[24]) is always returned +as false, since the feature depends on KVM_CREATE_IRQCHIP for local APIC +support. Instead it is reported via + + ioctl(KVM_CHECK_EXTENSION, KVM_CAP_TSC_DEADLINE_TIMER) + +if that returns true and you use KVM_CREATE_IRQCHIP, or if you emulate the +feature in userspace, then you can enable the feature for KVM_SET_CPUID2. + 4.47 KVM_PPC_GET_PVINFO Capability: KVM_CAP_PPC_GET_PVINFO @@ -1151,6 +1160,13 @@ following flags are specified: /* Depends on KVM_CAP_IOMMU */ #define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0) +The KVM_DEV_ASSIGN_ENABLE_IOMMU flag is a mandatory option to ensure +isolation of the device. Usages not specifying this flag are deprecated. + +Only PCI header type 0 devices with PCI BAR resources are supported by +device assignment. The user requesting this ioctl must have read/write +access to the PCI sysfs resource files associated with the device. + 4.49 KVM_DEASSIGN_PCI_DEVICE Capability: KVM_CAP_DEVICE_DEASSIGNMENT diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index b9db108f01c8..62f1cd357ddf 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -1698,11 +1698,9 @@ F: arch/x86/include/asm/tce.h CAN NETWORK LAYER M: Oliver Hartkopp -M: Oliver Hartkopp -M: Urs Thuermann L: linux-can@vger.kernel.org -L: netdev@vger.kernel.org -W: http://developer.berlios.de/projects/socketcan/ +W: http://gitorious.org/linux-can +T: git git://gitorious.org/linux-can/linux-can-next.git S: Maintained F: net/can/ F: include/linux/can.h @@ -1713,9 +1711,10 @@ F: include/linux/can/gw.h CAN NETWORK DRIVERS M: Wolfgang Grandegger +M: Marc Kleine-Budde L: linux-can@vger.kernel.org -L: netdev@vger.kernel.org -W: http://developer.berlios.de/projects/socketcan/ +W: http://gitorious.org/linux-can +T: git git://gitorious.org/linux-can/linux-can-next.git S: Maintained F: drivers/net/can/ F: include/linux/can/dev.h @@ -2700,7 +2699,7 @@ FIREWIRE SUBSYSTEM M: Stefan Richter L: linux1394-devel@lists.sourceforge.net W: http://ieee1394.wiki.kernel.org/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394.git S: Maintained F: drivers/firewire/ F: include/linux/firewire*.h @@ -3101,6 +3100,7 @@ F: include/linux/hid* HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS M: Thomas Gleixner +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Maintained F: Documentation/timers/ F: kernel/hrtimer.c @@ -3610,7 +3610,7 @@ F: net/irda/ IRQ SUBSYSTEM M: Thomas Gleixner S: Maintained -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git irq/core +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core F: kernel/irq/ ISAPNP @@ -4098,7 +4098,7 @@ F: drivers/hwmon/lm90.c LOCKDEP AND LOCKSTAT M: Peter Zijlstra M: Ingo Molnar -T: git git://git.kernel.org/pub/scm/linux/kernel/git/peterz/linux-2.6-lockdep.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/locking S: Maintained F: Documentation/lockdep*.txt F: Documentation/lockstat.txt @@ -4280,7 +4280,9 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git S: Maintained F: Documentation/dvb/ F: Documentation/video4linux/ +F: Documentation/DocBook/media/ F: drivers/media/ +F: drivers/staging/media/ F: include/media/ F: include/linux/dvb/ F: include/linux/videodev*.h @@ -5086,6 +5088,7 @@ M: Peter Zijlstra M: Paul Mackerras M: Ingo Molnar M: Arnaldo Carvalho de Melo +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core S: Supported F: kernel/events/* F: include/linux/perf_event.h @@ -5165,6 +5168,7 @@ F: drivers/scsi/pm8001/ POSIX CLOCKS and TIMERS M: Thomas Gleixner +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Supported F: fs/timerfd.c F: include/linux/timer* @@ -5680,6 +5684,7 @@ F: drivers/dma/dw_dmac.c TIMEKEEPING, NTP M: John Stultz M: Thomas Gleixner +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core S: Supported F: include/linux/clocksource.h F: include/linux/time.h @@ -5704,6 +5709,7 @@ F: drivers/watchdog/sc1200wdt.c SCHEDULER M: Ingo Molnar M: Peter Zijlstra +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core S: Maintained F: kernel/sched* F: include/linux/sched.h @@ -6631,7 +6637,7 @@ TRACING M: Steven Rostedt M: Frederic Weisbecker M: Ingo Molnar -T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git perf/core +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core S: Maintained F: Documentation/trace/ftrace.txt F: arch/*/*/*/ftrace.h @@ -7381,7 +7387,7 @@ M: Thomas Gleixner M: Ingo Molnar M: "H. Peter Anvin" M: x86@kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core S: Maintained F: Documentation/x86/ F: arch/x86/ diff --git a/trunk/Makefile b/trunk/Makefile index a43733df3978..adddd11c3b3b 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 2 SUBLEVEL = 0 -EXTRAVERSION = -rc6 +EXTRAVERSION = NAME = Saber-toothed Squirrel # *DOCUMENTATION* diff --git a/trunk/arch/Kconfig b/trunk/arch/Kconfig index 2505740b81d2..4b0669cbb3b0 100644 --- a/trunk/arch/Kconfig +++ b/trunk/arch/Kconfig @@ -30,10 +30,6 @@ config OPROFILE_EVENT_MULTIPLEX config HAVE_OPROFILE bool -config OPROFILE_NMI_TIMER - def_bool y - depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI - config KPROBES bool "Kprobes" depends on MODULES diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index 776d76b8cb69..b259c7c644e3 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -1246,7 +1246,7 @@ config PL310_ERRATA_588369 config ARM_ERRATA_720789 bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID" - depends on CPU_V7 && SMP + depends on CPU_V7 help This option enables the workaround for the 720789 Cortex-A9 (prior to r2p0) erratum. A faulty ASID can be sent to the other CPUs for the @@ -1282,7 +1282,7 @@ config ARM_ERRATA_743622 config ARM_ERRATA_751472 bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation" - depends on CPU_V7 && SMP + depends on CPU_V7 help This option enables the workaround for the 751472 Cortex-A9 (prior to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the diff --git a/trunk/arch/arm/common/pl330.c b/trunk/arch/arm/common/pl330.c index f407a6b35d3d..8d8df744f7a5 100644 --- a/trunk/arch/arm/common/pl330.c +++ b/trunk/arch/arm/common/pl330.c @@ -221,17 +221,6 @@ */ #define MCODE_BUFF_PER_REQ 256 -/* - * Mark a _pl330_req as free. - * We do it by writing DMAEND as the first instruction - * because no valid request is going to have DMAEND as - * its first instruction to execute. - */ -#define MARK_FREE(req) do { \ - _emit_END(0, (req)->mc_cpu); \ - (req)->mc_len = 0; \ - } while (0) - /* If the _pl330_req is available to the client */ #define IS_FREE(req) (*((u8 *)((req)->mc_cpu)) == CMD_DMAEND) @@ -301,8 +290,10 @@ struct pl330_thread { struct pl330_dmac *dmac; /* Only two at a time */ struct _pl330_req req[2]; - /* Index of the last submitted request */ + /* Index of the last enqueued request */ unsigned lstenq; + /* Index of the last submitted request or -1 if the DMA is stopped */ + int req_running; }; enum pl330_dmac_state { @@ -778,6 +769,22 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd, writel(0, regs + DBGCMD); } +/* + * Mark a _pl330_req as free. + * We do it by writing DMAEND as the first instruction + * because no valid request is going to have DMAEND as + * its first instruction to execute. + */ +static void mark_free(struct pl330_thread *thrd, int idx) +{ + struct _pl330_req *req = &thrd->req[idx]; + + _emit_END(0, req->mc_cpu); + req->mc_len = 0; + + thrd->req_running = -1; +} + static inline u32 _state(struct pl330_thread *thrd) { void __iomem *regs = thrd->dmac->pinfo->base; @@ -836,31 +843,6 @@ static inline u32 _state(struct pl330_thread *thrd) } } -/* If the request 'req' of thread 'thrd' is currently active */ -static inline bool _req_active(struct pl330_thread *thrd, - struct _pl330_req *req) -{ - void __iomem *regs = thrd->dmac->pinfo->base; - u32 buf = req->mc_bus, pc = readl(regs + CPC(thrd->id)); - - if (IS_FREE(req)) - return false; - - return (pc >= buf && pc <= buf + req->mc_len) ? true : false; -} - -/* Returns 0 if the thread is inactive, ID of active req + 1 otherwise */ -static inline unsigned _thrd_active(struct pl330_thread *thrd) -{ - if (_req_active(thrd, &thrd->req[0])) - return 1; /* First req active */ - - if (_req_active(thrd, &thrd->req[1])) - return 2; /* Second req active */ - - return 0; -} - static void _stop(struct pl330_thread *thrd) { void __iomem *regs = thrd->dmac->pinfo->base; @@ -892,17 +874,22 @@ static bool _trigger(struct pl330_thread *thrd) struct _arg_GO go; unsigned ns; u8 insn[6] = {0, 0, 0, 0, 0, 0}; + int idx; /* Return if already ACTIVE */ if (_state(thrd) != PL330_STATE_STOPPED) return true; - if (!IS_FREE(&thrd->req[1 - thrd->lstenq])) - req = &thrd->req[1 - thrd->lstenq]; - else if (!IS_FREE(&thrd->req[thrd->lstenq])) - req = &thrd->req[thrd->lstenq]; - else - req = NULL; + idx = 1 - thrd->lstenq; + if (!IS_FREE(&thrd->req[idx])) + req = &thrd->req[idx]; + else { + idx = thrd->lstenq; + if (!IS_FREE(&thrd->req[idx])) + req = &thrd->req[idx]; + else + req = NULL; + } /* Return if no request */ if (!req || !req->r) @@ -933,6 +920,8 @@ static bool _trigger(struct pl330_thread *thrd) /* Only manager can execute GO */ _execute_DBGINSN(thrd, insn, true); + thrd->req_running = idx; + return true; } @@ -1382,8 +1371,8 @@ static void pl330_dotask(unsigned long data) thrd->req[0].r = NULL; thrd->req[1].r = NULL; - MARK_FREE(&thrd->req[0]); - MARK_FREE(&thrd->req[1]); + mark_free(thrd, 0); + mark_free(thrd, 1); /* Clear the reset flag */ pl330->dmac_tbd.reset_chan &= ~(1 << i); @@ -1461,14 +1450,12 @@ int pl330_update(const struct pl330_info *pi) thrd = &pl330->channels[id]; - active = _thrd_active(thrd); - if (!active) /* Aborted */ + active = thrd->req_running; + if (active == -1) /* Aborted */ continue; - active -= 1; - rqdone = &thrd->req[active]; - MARK_FREE(rqdone); + mark_free(thrd, active); /* Get going again ASAP */ _start(thrd); @@ -1509,7 +1496,7 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op) struct pl330_thread *thrd = ch_id; struct pl330_dmac *pl330; unsigned long flags; - int ret = 0, active; + int ret = 0, active = thrd->req_running; if (!thrd || thrd->free || thrd->dmac->state == DYING) return -EINVAL; @@ -1525,28 +1512,24 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op) thrd->req[0].r = NULL; thrd->req[1].r = NULL; - MARK_FREE(&thrd->req[0]); - MARK_FREE(&thrd->req[1]); + mark_free(thrd, 0); + mark_free(thrd, 1); break; case PL330_OP_ABORT: - active = _thrd_active(thrd); - /* Make sure the channel is stopped */ _stop(thrd); /* ABORT is only for the active req */ - if (!active) + if (active == -1) break; - active--; - thrd->req[active].r = NULL; - MARK_FREE(&thrd->req[active]); + mark_free(thrd, active); /* Start the next */ case PL330_OP_START: - if (!_thrd_active(thrd) && !_start(thrd)) + if ((active == -1) && !_start(thrd)) ret = -EIO; break; @@ -1587,14 +1570,13 @@ int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus) else pstatus->faulting = false; - active = _thrd_active(thrd); + active = thrd->req_running; - if (!active) { + if (active == -1) { /* Indicate that the thread is not running */ pstatus->top_req = NULL; pstatus->wait_req = NULL; } else { - active--; pstatus->top_req = thrd->req[active].r; pstatus->wait_req = !IS_FREE(&thrd->req[1 - active]) ? thrd->req[1 - active].r : NULL; @@ -1659,9 +1641,9 @@ void *pl330_request_channel(const struct pl330_info *pi) thrd->free = false; thrd->lstenq = 1; thrd->req[0].r = NULL; - MARK_FREE(&thrd->req[0]); + mark_free(thrd, 0); thrd->req[1].r = NULL; - MARK_FREE(&thrd->req[1]); + mark_free(thrd, 1); break; } } @@ -1767,14 +1749,14 @@ static inline void _reset_thread(struct pl330_thread *thrd) thrd->req[0].mc_bus = pl330->mcode_bus + (thrd->id * pi->mcbufsz); thrd->req[0].r = NULL; - MARK_FREE(&thrd->req[0]); + mark_free(thrd, 0); thrd->req[1].mc_cpu = thrd->req[0].mc_cpu + pi->mcbufsz / 2; thrd->req[1].mc_bus = thrd->req[0].mc_bus + pi->mcbufsz / 2; thrd->req[1].r = NULL; - MARK_FREE(&thrd->req[1]); + mark_free(thrd, 1); } static int dmac_alloc_threads(struct pl330_dmac *pl330) diff --git a/trunk/arch/arm/configs/imx_v4_v5_defconfig b/trunk/arch/arm/configs/imx_v4_v5_defconfig index 11a4192197c8..cf497ce41dfe 100644 --- a/trunk/arch/arm/configs/imx_v4_v5_defconfig +++ b/trunk/arch/arm/configs/imx_v4_v5_defconfig @@ -18,9 +18,10 @@ CONFIG_ARCH_MXC=y CONFIG_ARCH_IMX_V4_V5=y CONFIG_ARCH_MX1ADS=y CONFIG_MACH_SCB9328=y +CONFIG_MACH_APF9328=y CONFIG_MACH_MX21ADS=y CONFIG_MACH_MX25_3DS=y -CONFIG_MACH_EUKREA_CPUIMX25=y +CONFIG_MACH_EUKREA_CPUIMX25SD=y CONFIG_MACH_MX27ADS=y CONFIG_MACH_PCM038=y CONFIG_MACH_CPUIMX27=y @@ -72,17 +73,16 @@ CONFIG_MTD_CFI_GEOMETRY=y CONFIG_MTD_CFI_INTELEXT=y CONFIG_MTD_PHYSMAP=y CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_MXC=y CONFIG_MTD_UBI=y CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT25=y CONFIG_NETDEVICES=y -CONFIG_NET_ETHERNET=y -CONFIG_SMC91X=y CONFIG_DM9000=y +CONFIG_SMC91X=y CONFIG_SMC911X=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_SMSC_PHY=y # CONFIG_INPUT_MOUSEDEV is not set CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_KEYBOARD is not set @@ -100,6 +100,7 @@ CONFIG_I2C_CHARDEV=y CONFIG_I2C_IMX=y CONFIG_SPI=y CONFIG_SPI_IMX=y +CONFIG_SPI_SPIDEV=y CONFIG_W1=y CONFIG_W1_MASTER_MXC=y CONFIG_W1_SLAVE_THERM=y @@ -139,6 +140,7 @@ CONFIG_MMC=y CONFIG_MMC_MXC=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y CONFIG_LEDS_MC13783=y CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_TIMER=y diff --git a/trunk/arch/arm/mach-exynos/cpu.c b/trunk/arch/arm/mach-exynos/cpu.c index 90ec247f3b37..cc8d4bd6d0f7 100644 --- a/trunk/arch/arm/mach-exynos/cpu.c +++ b/trunk/arch/arm/mach-exynos/cpu.c @@ -110,11 +110,6 @@ static struct map_desc exynos4_iodesc[] __initdata = { .pfn = __phys_to_pfn(EXYNOS4_PA_DMC0), .length = SZ_4K, .type = MT_DEVICE, - }, { - .virtual = (unsigned long)S5P_VA_SROMC, - .pfn = __phys_to_pfn(EXYNOS4_PA_SROMC), - .length = SZ_4K, - .type = MT_DEVICE, }, { .virtual = (unsigned long)S3C_VA_USB_HSPHY, .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY), diff --git a/trunk/arch/arm/mach-imx/Kconfig b/trunk/arch/arm/mach-imx/Kconfig index c44aa974e79c..0e6f1af260b6 100644 --- a/trunk/arch/arm/mach-imx/Kconfig +++ b/trunk/arch/arm/mach-imx/Kconfig @@ -132,7 +132,7 @@ config MACH_MX25_3DS select IMX_HAVE_PLATFORM_MXC_NAND select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX -config MACH_EUKREA_CPUIMX25 +config MACH_EUKREA_CPUIMX25SD bool "Support Eukrea CPUIMX25 Platform" select SOC_IMX25 select IMX_HAVE_PLATFORM_FLEXCAN @@ -148,7 +148,7 @@ config MACH_EUKREA_CPUIMX25 choice prompt "Baseboard" - depends on MACH_EUKREA_CPUIMX25 + depends on MACH_EUKREA_CPUIMX25SD default MACH_EUKREA_MBIMXSD25_BASEBOARD config MACH_EUKREA_MBIMXSD25_BASEBOARD @@ -542,7 +542,7 @@ config MACH_MX35_3DS Include support for MX35PDK platform. This includes specific configurations for the board and its peripherals. -config MACH_EUKREA_CPUIMX35 +config MACH_EUKREA_CPUIMX35SD bool "Support Eukrea CPUIMX35 Platform" select SOC_IMX35 select IMX_HAVE_PLATFORM_FLEXCAN @@ -560,7 +560,7 @@ config MACH_EUKREA_CPUIMX35 choice prompt "Baseboard" - depends on MACH_EUKREA_CPUIMX35 + depends on MACH_EUKREA_CPUIMX35SD default MACH_EUKREA_MBIMXSD35_BASEBOARD config MACH_EUKREA_MBIMXSD35_BASEBOARD diff --git a/trunk/arch/arm/mach-imx/Makefile b/trunk/arch/arm/mach-imx/Makefile index aba73214c2a8..d97f409ce98b 100644 --- a/trunk/arch/arm/mach-imx/Makefile +++ b/trunk/arch/arm/mach-imx/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_MACH_MX21ADS) += mach-mx21ads.o # i.MX25 based machines obj-$(CONFIG_MACH_MX25_3DS) += mach-mx25_3ds.o -obj-$(CONFIG_MACH_EUKREA_CPUIMX25) += mach-eukrea_cpuimx25.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX25SD) += mach-eukrea_cpuimx25.o obj-$(CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD) += eukrea_mbimxsd25-baseboard.o # i.MX27 based machines @@ -57,7 +57,7 @@ obj-$(CONFIG_MACH_BUG) += mach-bug.o # i.MX35 based machines obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o -obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX35SD) += mach-cpuimx35.o obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o diff --git a/trunk/arch/arm/mach-imx/clock-imx35.c b/trunk/arch/arm/mach-imx/clock-imx35.c index 8116f119517d..ac8238caecb9 100644 --- a/trunk/arch/arm/mach-imx/clock-imx35.c +++ b/trunk/arch/arm/mach-imx/clock-imx35.c @@ -507,7 +507,7 @@ static struct clk_lookup lookups[] = { int __init mx35_clocks_init() { - unsigned int cgr2 = 3 << 26, cgr3 = 0; + unsigned int cgr2 = 3 << 26; #if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) cgr2 |= 3 << 16; @@ -521,6 +521,12 @@ int __init mx35_clocks_init() __raw_writel((3 << 18), CCM_BASE + CCM_CGR0); __raw_writel((3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 16), CCM_BASE + CCM_CGR1); + __raw_writel(cgr2, CCM_BASE + CCM_CGR2); + __raw_writel(0, CCM_BASE + CCM_CGR3); + + clk_enable(&iim_clk); + imx_print_silicon_rev("i.MX35", mx35_revision()); + clk_disable(&iim_clk); /* * Check if we came up in internal boot mode. If yes, we need some @@ -529,17 +535,11 @@ int __init mx35_clocks_init() */ if (!(__raw_readl(CCM_BASE + CCM_RCSR) & (3 << 10))) { /* Additionally turn on UART1, SCC, and IIM clocks */ - cgr2 |= 3 << 16 | 3 << 4; - cgr3 |= 3 << 2; + clk_enable(&iim_clk); + clk_enable(&uart1_clk); + clk_enable(&scc_clk); } - __raw_writel(cgr2, CCM_BASE + CCM_CGR2); - __raw_writel(cgr3, CCM_BASE + CCM_CGR3); - - clk_enable(&iim_clk); - imx_print_silicon_rev("i.MX35", mx35_revision()); - clk_disable(&iim_clk); - #ifdef CONFIG_MXC_USE_EPIT epit_timer_init(&epit1_clk, MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1); diff --git a/trunk/arch/arm/mach-imx/mach-cpuimx35.c b/trunk/arch/arm/mach-imx/mach-cpuimx35.c index 66af2e8f7e57..362aae780601 100644 --- a/trunk/arch/arm/mach-imx/mach-cpuimx35.c +++ b/trunk/arch/arm/mach-imx/mach-cpuimx35.c @@ -53,12 +53,18 @@ static const struct imxi2c_platform_data .bitrate = 100000, }; +#define TSC2007_IRQGPIO IMX_GPIO_NR(3, 2) +static int tsc2007_get_pendown_state(void) +{ + return !gpio_get_value(TSC2007_IRQGPIO); +} + static struct tsc2007_platform_data tsc2007_info = { .model = 2007, .x_plate_ohms = 180, + .get_pendown_state = tsc2007_get_pendown_state, }; -#define TSC2007_IRQGPIO IMX_GPIO_NR(3, 2) static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = { { I2C_BOARD_INFO("pcf8563", 0x51), diff --git a/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c index 7f8915ad5099..eef43e2e163e 100644 --- a/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c +++ b/trunk/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c @@ -3247,18 +3247,14 @@ static __initdata struct omap_hwmod *omap3xxx_hwmods[] = { /* 3430ES1-only hwmods */ static __initdata struct omap_hwmod *omap3430es1_hwmods[] = { - &omap3xxx_iva_hwmod, &omap3430es1_dss_core_hwmod, - &omap3xxx_mailbox_hwmod, NULL }; /* 3430ES2+-only hwmods */ static __initdata struct omap_hwmod *omap3430es2plus_hwmods[] = { - &omap3xxx_iva_hwmod, &omap3xxx_dss_core_hwmod, &omap3xxx_usbhsotg_hwmod, - &omap3xxx_mailbox_hwmod, NULL }; diff --git a/trunk/arch/arm/mach-shmobile/board-ag5evm.c b/trunk/arch/arm/mach-shmobile/board-ag5evm.c index b862e9f81e3e..7119b87cbfa0 100644 --- a/trunk/arch/arm/mach-shmobile/board-ag5evm.c +++ b/trunk/arch/arm/mach-shmobile/board-ag5evm.c @@ -607,6 +607,7 @@ struct sys_timer ag5evm_timer = { MACHINE_START(AG5EVM, "ag5evm") .map_io = ag5evm_map_io, + .nr_irqs = NR_IRQS_LEGACY, .init_irq = sh73a0_init_irq, .handle_irq = shmobile_handle_irq_gic, .init_machine = ag5evm_init, diff --git a/trunk/arch/arm/mach-shmobile/board-kota2.c b/trunk/arch/arm/mach-shmobile/board-kota2.c index bd9a78424d6b..f44150b5ae46 100644 --- a/trunk/arch/arm/mach-shmobile/board-kota2.c +++ b/trunk/arch/arm/mach-shmobile/board-kota2.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ static struct resource smsc9220_resources[] = { .flags = IORESOURCE_MEM, }, [1] = { - .start = gic_spi(33), /* PINTA2 @ PORT144 */ + .start = SH73A0_PINT0_IRQ(2), /* PINTA2 */ .flags = IORESOURCE_IRQ, }, }; @@ -157,10 +158,6 @@ static struct platform_device gpio_keys_device = { #define GPIO_LED(n, g) { .name = n, .gpio = g } static struct gpio_led gpio_leds[] = { - GPIO_LED("V2513", GPIO_PORT153), /* PORT153 [TPU1T02] -> V2513 */ - GPIO_LED("V2514", GPIO_PORT199), /* PORT199 [TPU4TO1] -> V2514 */ - GPIO_LED("V2515", GPIO_PORT197), /* PORT197 [TPU2TO1] -> V2515 */ - GPIO_LED("KEYLED", GPIO_PORT163), /* PORT163 [TPU3TO0] -> KEYLED */ GPIO_LED("G", GPIO_PORT20), /* PORT20 [GPO0] -> LED7 -> "G" */ GPIO_LED("H", GPIO_PORT21), /* PORT21 [GPO1] -> LED8 -> "H" */ GPIO_LED("J", GPIO_PORT22), /* PORT22 [GPO2] -> LED9 -> "J" */ @@ -179,6 +176,119 @@ static struct platform_device gpio_leds_device = { }, }; +/* TPU LED */ +static struct led_renesas_tpu_config led_renesas_tpu12_pdata = { + .name = "V2513", + .pin_gpio_fn = GPIO_FN_TPU1TO2, + .pin_gpio = GPIO_PORT153, + .channel_offset = 0x90, + .timer_bit = 2, + .max_brightness = 1000, +}; + +static struct resource tpu12_resources[] = { + [0] = { + .name = "TPU12", + .start = 0xe6610090, + .end = 0xe66100b5, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu12_device = { + .name = "leds-renesas-tpu", + .id = 12, + .dev = { + .platform_data = &led_renesas_tpu12_pdata, + }, + .num_resources = ARRAY_SIZE(tpu12_resources), + .resource = tpu12_resources, +}; + +static struct led_renesas_tpu_config led_renesas_tpu41_pdata = { + .name = "V2514", + .pin_gpio_fn = GPIO_FN_TPU4TO1, + .pin_gpio = GPIO_PORT199, + .channel_offset = 0x50, + .timer_bit = 1, + .max_brightness = 1000, +}; + +static struct resource tpu41_resources[] = { + [0] = { + .name = "TPU41", + .start = 0xe6640050, + .end = 0xe6640075, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu41_device = { + .name = "leds-renesas-tpu", + .id = 41, + .dev = { + .platform_data = &led_renesas_tpu41_pdata, + }, + .num_resources = ARRAY_SIZE(tpu41_resources), + .resource = tpu41_resources, +}; + +static struct led_renesas_tpu_config led_renesas_tpu21_pdata = { + .name = "V2515", + .pin_gpio_fn = GPIO_FN_TPU2TO1, + .pin_gpio = GPIO_PORT197, + .channel_offset = 0x50, + .timer_bit = 1, + .max_brightness = 1000, +}; + +static struct resource tpu21_resources[] = { + [0] = { + .name = "TPU21", + .start = 0xe6620050, + .end = 0xe6620075, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu21_device = { + .name = "leds-renesas-tpu", + .id = 21, + .dev = { + .platform_data = &led_renesas_tpu21_pdata, + }, + .num_resources = ARRAY_SIZE(tpu21_resources), + .resource = tpu21_resources, +}; + +static struct led_renesas_tpu_config led_renesas_tpu30_pdata = { + .name = "KEYLED", + .pin_gpio_fn = GPIO_FN_TPU3TO0, + .pin_gpio = GPIO_PORT163, + .channel_offset = 0x10, + .timer_bit = 0, + .max_brightness = 1000, +}; + +static struct resource tpu30_resources[] = { + [0] = { + .name = "TPU30", + .start = 0xe6630010, + .end = 0xe6630035, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device leds_tpu30_device = { + .name = "leds-renesas-tpu", + .id = 30, + .dev = { + .platform_data = &led_renesas_tpu30_pdata, + }, + .num_resources = ARRAY_SIZE(tpu30_resources), + .resource = tpu30_resources, +}; + /* MMCIF */ static struct resource mmcif_resources[] = { [0] = { @@ -291,6 +401,10 @@ static struct platform_device *kota2_devices[] __initdata = { &keysc_device, &gpio_keys_device, &gpio_leds_device, + &leds_tpu12_device, + &leds_tpu41_device, + &leds_tpu21_device, + &leds_tpu30_device, &mmcif_device, &sdhi0_device, &sdhi1_device, @@ -317,18 +431,6 @@ static void __init kota2_map_io(void) shmobile_setup_console(); } -#define PINTER0A 0xe69000a0 -#define PINTCR0A 0xe69000b0 - -void __init kota2_init_irq(void) -{ - sh73a0_init_irq(); - - /* setup PINT: enable PINTA2 as active low */ - __raw_writel(1 << 29, PINTER0A); - __raw_writew(2 << 10, PINTCR0A); -} - static void __init kota2_init(void) { sh73a0_pinmux_init(); @@ -447,7 +549,8 @@ struct sys_timer kota2_timer = { MACHINE_START(KOTA2, "kota2") .map_io = kota2_map_io, - .init_irq = kota2_init_irq, + .nr_irqs = NR_IRQS_LEGACY, + .init_irq = sh73a0_init_irq, .handle_irq = shmobile_handle_irq_gic, .init_machine = kota2_init, .timer = &kota2_timer, diff --git a/trunk/arch/arm/mach-shmobile/clock-sh73a0.c b/trunk/arch/arm/mach-shmobile/clock-sh73a0.c index 61a846bb30f2..1370a89ca358 100644 --- a/trunk/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/trunk/arch/arm/mach-shmobile/clock-sh73a0.c @@ -113,6 +113,12 @@ static struct clk main_clk = { .ops = &main_clk_ops, }; +/* Divide Main clock by two */ +static struct clk main_div2_clk = { + .ops = &div2_clk_ops, + .parent = &main_clk, +}; + /* PLL0, PLL1, PLL2, PLL3 */ static unsigned long pll_recalc(struct clk *clk) { @@ -181,6 +187,7 @@ static struct clk *main_clks[] = { &extal1_div2_clk, &extal2_div2_clk, &main_clk, + &main_div2_clk, &pll0_clk, &pll1_clk, &pll2_clk, @@ -243,7 +250,7 @@ static struct clk div6_clks[DIV6_NR] = { [DIV6_VCK1] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR1, 0), [DIV6_VCK2] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR2, 0), [DIV6_VCK3] = SH_CLK_DIV6(&pll1_div2_clk, VCLKCR3, 0), - [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, 0), + [DIV6_ZB1] = SH_CLK_DIV6(&pll1_div2_clk, ZBCKCR, CLK_ENABLE_ON_INIT), [DIV6_FLCTL] = SH_CLK_DIV6(&pll1_div2_clk, FLCKCR, 0), [DIV6_SDHI0] = SH_CLK_DIV6(&pll1_div2_clk, SD0CKCR, 0), [DIV6_SDHI1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0), @@ -268,6 +275,7 @@ enum { MSTP001, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, MSTP331, MSTP329, MSTP325, MSTP323, MSTP318, MSTP314, MSTP313, MSTP312, MSTP311, + MSTP303, MSTP302, MSTP301, MSTP300, MSTP411, MSTP410, MSTP403, MSTP_NR }; @@ -301,6 +309,10 @@ static struct clk mstp_clks[MSTP_NR] = { [MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */ [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */ [MSTP311] = MSTP(&div6_clks[DIV6_SDHI2], SMSTPCR3, 11, 0), /* SDHI2 */ + [MSTP303] = MSTP(&main_div2_clk, SMSTPCR3, 3, 0), /* TPU1 */ + [MSTP302] = MSTP(&main_div2_clk, SMSTPCR3, 2, 0), /* TPU2 */ + [MSTP301] = MSTP(&main_div2_clk, SMSTPCR3, 1, 0), /* TPU3 */ + [MSTP300] = MSTP(&main_div2_clk, SMSTPCR3, 0, 0), /* TPU4 */ [MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */ [MSTP410] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 10, 0), /* IIC4 */ [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */ @@ -350,6 +362,10 @@ static struct clk_lookup lookups[] = { CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */ + CLKDEV_DEV_ID("leds-renesas-tpu.12", &mstp_clks[MSTP303]), /* TPU1 */ + CLKDEV_DEV_ID("leds-renesas-tpu.21", &mstp_clks[MSTP302]), /* TPU2 */ + CLKDEV_DEV_ID("leds-renesas-tpu.30", &mstp_clks[MSTP301]), /* TPU3 */ + CLKDEV_DEV_ID("leds-renesas-tpu.41", &mstp_clks[MSTP300]), /* TPU4 */ CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */ CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ diff --git a/trunk/arch/arm/mm/proc-v7.S b/trunk/arch/arm/mm/proc-v7.S index 2c559ac38142..e70a73731eaa 100644 --- a/trunk/arch/arm/mm/proc-v7.S +++ b/trunk/arch/arm/mm/proc-v7.S @@ -363,11 +363,13 @@ __v7_setup: orreq r10, r10, #1 << 6 @ set bit #6 mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register #endif -#ifdef CONFIG_ARM_ERRATA_751472 - cmp r6, #0x30 @ present prior to r3p0 +#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP) + ALT_SMP(cmp r6, #0x30) @ present prior to r3p0 + ALT_UP_B(1f) mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register orrlt r10, r10, #1 << 11 @ set bit #11 mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register +1: #endif 3: mov r10, #0 diff --git a/trunk/arch/arm/oprofile/common.c b/trunk/arch/arm/oprofile/common.c index c074e66ad224..4e0a371630b3 100644 --- a/trunk/arch/arm/oprofile/common.c +++ b/trunk/arch/arm/oprofile/common.c @@ -116,7 +116,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) return oprofile_perf_init(ops); } -void __exit oprofile_arch_exit(void) +void oprofile_arch_exit(void) { oprofile_perf_exit(); } diff --git a/trunk/arch/arm/plat-mxc/cpufreq.c b/trunk/arch/arm/plat-mxc/cpufreq.c index adbff706ef6f..73db34bf588a 100644 --- a/trunk/arch/arm/plat-mxc/cpufreq.c +++ b/trunk/arch/arm/plat-mxc/cpufreq.c @@ -98,7 +98,7 @@ static int mxc_set_target(struct cpufreq_policy *policy, return ret; } -static int __init mxc_cpufreq_init(struct cpufreq_policy *policy) +static int mxc_cpufreq_init(struct cpufreq_policy *policy) { int ret; int i; diff --git a/trunk/arch/arm/plat-mxc/include/mach/uncompress.h b/trunk/arch/arm/plat-mxc/include/mach/uncompress.h index 88fd40452567..477971b00930 100644 --- a/trunk/arch/arm/plat-mxc/include/mach/uncompress.h +++ b/trunk/arch/arm/plat-mxc/include/mach/uncompress.h @@ -98,6 +98,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id) case MACH_TYPE_PCM043: case MACH_TYPE_LILLY1131: case MACH_TYPE_VPR200: + case MACH_TYPE_EUKREA_CPUIMX35SD: uart_base = MX3X_UART1_BASE_ADDR; break; case MACH_TYPE_MAGX_ZN5: diff --git a/trunk/arch/arm/plat-mxc/pwm.c b/trunk/arch/arm/plat-mxc/pwm.c index 845de59f07ed..e032717f7d02 100644 --- a/trunk/arch/arm/plat-mxc/pwm.c +++ b/trunk/arch/arm/plat-mxc/pwm.c @@ -77,6 +77,15 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) do_div(c, period_ns); duty_cycles = c; + /* + * according to imx pwm RM, the real period value should be + * PERIOD value in PWMPR plus 2. + */ + if (period_cycles > 2) + period_cycles -= 2; + else + period_cycles = 0; + writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR); writel(period_cycles, pwm->mmio_base + MX3_PWMPR); diff --git a/trunk/arch/arm/plat-orion/gpio.c b/trunk/arch/arm/plat-orion/gpio.c index 41ab97ebe4cf..10d160888133 100644 --- a/trunk/arch/arm/plat-orion/gpio.c +++ b/trunk/arch/arm/plat-orion/gpio.c @@ -384,12 +384,16 @@ void __init orion_gpio_init(int gpio_base, int ngpio, struct orion_gpio_chip *ochip; struct irq_chip_generic *gc; struct irq_chip_type *ct; + char gc_label[16]; if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips)) return; + snprintf(gc_label, sizeof(gc_label), "orion_gpio%d", + orion_gpio_chip_count); + ochip = orion_gpio_chips + orion_gpio_chip_count; - ochip->chip.label = "orion_gpio"; + ochip->chip.label = kstrdup(gc_label, GFP_KERNEL); ochip->chip.request = orion_gpio_request; ochip->chip.direction_input = orion_gpio_direction_input; ochip->chip.get = orion_gpio_get; diff --git a/trunk/arch/arm/plat-samsung/include/plat/cpu-freq-core.h b/trunk/arch/arm/plat-samsung/include/plat/cpu-freq-core.h index dac4760c0f0a..95509d8eb140 100644 --- a/trunk/arch/arm/plat-samsung/include/plat/cpu-freq-core.h +++ b/trunk/arch/arm/plat-samsung/include/plat/cpu-freq-core.h @@ -202,14 +202,6 @@ extern int s3c_plltab_register(struct cpufreq_frequency_table *plls, extern struct s3c_cpufreq_config *s3c_cpufreq_getconfig(void); extern struct s3c_iotimings *s3c_cpufreq_getiotimings(void); -extern void s3c2410_iotiming_debugfs(struct seq_file *seq, - struct s3c_cpufreq_config *cfg, - union s3c_iobank *iob); - -extern void s3c2412_iotiming_debugfs(struct seq_file *seq, - struct s3c_cpufreq_config *cfg, - union s3c_iobank *iob); - #ifdef CONFIG_CPU_FREQ_S3C24XX_DEBUGFS #define s3c_cpufreq_debugfs_call(x) x #else @@ -226,6 +218,10 @@ extern void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg); extern void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg); #ifdef CONFIG_S3C2410_IOTIMING +extern void s3c2410_iotiming_debugfs(struct seq_file *seq, + struct s3c_cpufreq_config *cfg, + union s3c_iobank *iob); + extern int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg, struct s3c_iotimings *iot); @@ -235,6 +231,7 @@ extern int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg, extern void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg, struct s3c_iotimings *iot); #else +#define s3c2410_iotiming_debugfs NULL #define s3c2410_iotiming_calc NULL #define s3c2410_iotiming_get NULL #define s3c2410_iotiming_set NULL @@ -242,8 +239,10 @@ extern void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg, /* S3C2412 compatible routines */ -extern int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg, - struct s3c_iotimings *timings); +#ifdef CONFIG_S3C2412_IOTIMING +extern void s3c2412_iotiming_debugfs(struct seq_file *seq, + struct s3c_cpufreq_config *cfg, + union s3c_iobank *iob); extern int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg, struct s3c_iotimings *timings); @@ -253,6 +252,12 @@ extern int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg, extern void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg, struct s3c_iotimings *iot); +#else +#define s3c2412_iotiming_debugfs NULL +#define s3c2412_iotiming_calc NULL +#define s3c2412_iotiming_get NULL +#define s3c2412_iotiming_set NULL +#endif /* CONFIG_S3C2412_IOTIMING */ #ifdef CONFIG_CPU_FREQ_S3C24XX_DEBUG #define s3c_freq_dbg(x...) printk(KERN_INFO x) diff --git a/trunk/arch/ia64/include/asm/cputime.h b/trunk/arch/ia64/include/asm/cputime.h index 6073b187528a..5a274af31b2b 100644 --- a/trunk/arch/ia64/include/asm/cputime.h +++ b/trunk/arch/ia64/include/asm/cputime.h @@ -60,6 +60,7 @@ typedef u64 cputime64_t; */ #define cputime_to_usecs(__ct) ((__ct) / NSEC_PER_USEC) #define usecs_to_cputime(__usecs) ((__usecs) * NSEC_PER_USEC) +#define usecs_to_cputime64(__usecs) usecs_to_cputime(__usecs) /* * Convert cputime <-> seconds diff --git a/trunk/arch/powerpc/include/asm/cputime.h b/trunk/arch/powerpc/include/asm/cputime.h index 1cf20bdfbeca..98b7c4b49c9d 100644 --- a/trunk/arch/powerpc/include/asm/cputime.h +++ b/trunk/arch/powerpc/include/asm/cputime.h @@ -150,6 +150,8 @@ static inline cputime_t usecs_to_cputime(const unsigned long us) return ct; } +#define usecs_to_cputime64(us) usecs_to_cputime(us) + /* * Convert cputime <-> seconds */ diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s.h b/trunk/arch/powerpc/include/asm/kvm_book3s.h index d4df013ad779..69c7377d2071 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s.h @@ -381,39 +381,6 @@ static inline bool kvmppc_critical_section(struct kvm_vcpu *vcpu) } #endif -static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r, - unsigned long pte_index) -{ - unsigned long rb, va_low; - - rb = (v & ~0x7fUL) << 16; /* AVA field */ - va_low = pte_index >> 3; - if (v & HPTE_V_SECONDARY) - va_low = ~va_low; - /* xor vsid from AVA */ - if (!(v & HPTE_V_1TB_SEG)) - va_low ^= v >> 12; - else - va_low ^= v >> 24; - va_low &= 0x7ff; - if (v & HPTE_V_LARGE) { - rb |= 1; /* L field */ - if (cpu_has_feature(CPU_FTR_ARCH_206) && - (r & 0xff000)) { - /* non-16MB large page, must be 64k */ - /* (masks depend on page size) */ - rb |= 0x1000; /* page encoding in LP field */ - rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ - rb |= (va_low & 0xfe); /* AVAL field (P7 doesn't seem to care) */ - } - } else { - /* 4kB page */ - rb |= (va_low & 0x7ff) << 12; /* remaining 11b of VA */ - } - rb |= (v >> 54) & 0x300; /* B field */ - return rb; -} - /* Magic register values loaded into r3 and r4 before the 'sc' assembly * instruction for the OSI hypercalls */ #define OSI_SC_MAGIC_R3 0x113724FA diff --git a/trunk/arch/powerpc/include/asm/kvm_book3s_64.h b/trunk/arch/powerpc/include/asm/kvm_book3s_64.h index e43fe42b9875..d0ac94f98f9e 100644 --- a/trunk/arch/powerpc/include/asm/kvm_book3s_64.h +++ b/trunk/arch/powerpc/include/asm/kvm_book3s_64.h @@ -29,4 +29,37 @@ static inline struct kvmppc_book3s_shadow_vcpu *to_svcpu(struct kvm_vcpu *vcpu) #define SPAPR_TCE_SHIFT 12 +static inline unsigned long compute_tlbie_rb(unsigned long v, unsigned long r, + unsigned long pte_index) +{ + unsigned long rb, va_low; + + rb = (v & ~0x7fUL) << 16; /* AVA field */ + va_low = pte_index >> 3; + if (v & HPTE_V_SECONDARY) + va_low = ~va_low; + /* xor vsid from AVA */ + if (!(v & HPTE_V_1TB_SEG)) + va_low ^= v >> 12; + else + va_low ^= v >> 24; + va_low &= 0x7ff; + if (v & HPTE_V_LARGE) { + rb |= 1; /* L field */ + if (cpu_has_feature(CPU_FTR_ARCH_206) && + (r & 0xff000)) { + /* non-16MB large page, must be 64k */ + /* (masks depend on page size) */ + rb |= 0x1000; /* page encoding in LP field */ + rb |= (va_low & 0x7f) << 16; /* 7b of VA in AVA/LP field */ + rb |= (va_low & 0xfe); /* AVAL field (P7 doesn't seem to care) */ + } + } else { + /* 4kB page */ + rb |= (va_low & 0x7ff) << 12; /* remaining 11b of VA */ + } + rb |= (v >> 54) & 0x300; /* B field */ + return rb; +} + #endif /* __ASM_KVM_BOOK3S_64_H__ */ diff --git a/trunk/arch/powerpc/kvm/book3s_hv.c b/trunk/arch/powerpc/kvm/book3s_hv.c index 0cb137a9b038..336983da9e72 100644 --- a/trunk/arch/powerpc/kvm/book3s_hv.c +++ b/trunk/arch/powerpc/kvm/book3s_hv.c @@ -538,7 +538,7 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu) tpaca->kvm_hstate.napping = 0; vcpu->cpu = vc->pcpu; smp_wmb(); -#ifdef CONFIG_PPC_ICP_NATIVE +#if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP) if (vcpu->arch.ptid) { tpaca->cpu_start = 0x80; wmb(); diff --git a/trunk/arch/powerpc/kvm/book3s_pr.c b/trunk/arch/powerpc/kvm/book3s_pr.c index 3c791e1eb675..e2cfb9e1e20e 100644 --- a/trunk/arch/powerpc/kvm/book3s_pr.c +++ b/trunk/arch/powerpc/kvm/book3s_pr.c @@ -658,10 +658,12 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, ulong cmd = kvmppc_get_gpr(vcpu, 3); int i; +#ifdef CONFIG_KVM_BOOK3S_64_PR if (kvmppc_h_pr(vcpu, cmd) == EMULATE_DONE) { r = RESUME_GUEST; break; } +#endif run->papr_hcall.nr = cmd; for (i = 0; i < 9; ++i) { diff --git a/trunk/arch/powerpc/kvm/e500.c b/trunk/arch/powerpc/kvm/e500.c index 26d20903f2bc..8c0d45a6faf7 100644 --- a/trunk/arch/powerpc/kvm/e500.c +++ b/trunk/arch/powerpc/kvm/e500.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/s390/include/asm/cputime.h b/trunk/arch/s390/include/asm/cputime.h index 081434878296..b9acaaa175d8 100644 --- a/trunk/arch/s390/include/asm/cputime.h +++ b/trunk/arch/s390/include/asm/cputime.h @@ -87,6 +87,8 @@ usecs_to_cputime(const unsigned int m) return (cputime_t) m * 4096; } +#define usecs_to_cputime64(m) usecs_to_cputime(m) + /* * Convert cputime to milliseconds and back. */ diff --git a/trunk/arch/s390/oprofile/hwsampler.c b/trunk/arch/s390/oprofile/hwsampler.c index 9daee91e6c3f..f43c0e4282af 100644 --- a/trunk/arch/s390/oprofile/hwsampler.c +++ b/trunk/arch/s390/oprofile/hwsampler.c @@ -22,7 +22,6 @@ #include #include "hwsampler.h" -#include "op_counter.h" #define MAX_NUM_SDB 511 #define MIN_NUM_SDB 1 @@ -897,8 +896,6 @@ static void add_samples_to_oprofile(unsigned int cpu, unsigned long *sdbt, if (sample_data_ptr->P == 1) { /* userspace sample */ unsigned int pid = sample_data_ptr->prim_asn; - if (!counter_config.user) - goto skip_sample; rcu_read_lock(); tsk = pid_task(find_vpid(pid), PIDTYPE_PID); if (tsk) @@ -906,8 +903,6 @@ static void add_samples_to_oprofile(unsigned int cpu, unsigned long *sdbt, rcu_read_unlock(); } else { /* kernelspace sample */ - if (!counter_config.kernel) - goto skip_sample; regs = task_pt_regs(current); } @@ -915,7 +910,7 @@ static void add_samples_to_oprofile(unsigned int cpu, unsigned long *sdbt, oprofile_add_ext_hw_sample(sample_data_ptr->ia, regs, 0, !sample_data_ptr->P, tsk); mutex_unlock(&hws_sem); - skip_sample: + sample_data_ptr++; } } diff --git a/trunk/arch/s390/oprofile/init.c b/trunk/arch/s390/oprofile/init.c index 6cf2286d0405..bd58b72454cf 100644 --- a/trunk/arch/s390/oprofile/init.c +++ b/trunk/arch/s390/oprofile/init.c @@ -2,11 +2,10 @@ * arch/s390/oprofile/init.c * * S390 Version - * Copyright (C) 2002-2011 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Thomas Spatzier (tspat@de.ibm.com) * Author(s): Mahesh Salgaonkar (mahesh@linux.vnet.ibm.com) * Author(s): Heinz Graalfs (graalfs@linux.vnet.ibm.com) - * Author(s): Andreas Krebbel (krebbel@linux.vnet.ibm.com) * * @remark Copyright 2002-2011 OProfile authors */ @@ -15,8 +14,6 @@ #include #include #include -#include -#include #include "../../../drivers/oprofile/oprof.h" @@ -25,7 +22,6 @@ extern void s390_backtrace(struct pt_regs * const regs, unsigned int depth); #ifdef CONFIG_64BIT #include "hwsampler.h" -#include "op_counter.h" #define DEFAULT_INTERVAL 4127518 @@ -39,41 +35,16 @@ static unsigned long oprofile_max_interval; static unsigned long oprofile_sdbt_blocks = DEFAULT_SDBT_BLOCKS; static unsigned long oprofile_sdb_blocks = DEFAULT_SDB_BLOCKS; -static int hwsampler_enabled; +static int hwsampler_file; static int hwsampler_running; /* start_mutex must be held to change */ -static int hwsampler_available; static struct oprofile_operations timer_ops; -struct op_counter_config counter_config; - -enum __force_cpu_type { - reserved = 0, /* do not force */ - timer, -}; -static int force_cpu_type; - -static int set_cpu_type(const char *str, struct kernel_param *kp) -{ - if (!strcmp(str, "timer")) { - force_cpu_type = timer; - printk(KERN_INFO "oprofile: forcing timer to be returned " - "as cpu type\n"); - } else { - force_cpu_type = 0; - } - - return 0; -} -module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0); -MODULE_PARM_DESC(cpu_type, "Force legacy basic mode sampling" - "(report cpu_type \"timer\""); - static int oprofile_hwsampler_start(void) { int retval; - hwsampler_running = hwsampler_enabled; + hwsampler_running = hwsampler_file; if (!hwsampler_running) return timer_ops.start(); @@ -101,16 +72,10 @@ static void oprofile_hwsampler_stop(void) return; } -/* - * File ops used for: - * /dev/oprofile/0/enabled - * /dev/oprofile/hwsampling/hwsampler (cpu_type = timer) - */ - static ssize_t hwsampler_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { - return oprofilefs_ulong_to_user(hwsampler_enabled, buf, count, offset); + return oprofilefs_ulong_to_user(hwsampler_file, buf, count, offset); } static ssize_t hwsampler_write(struct file *file, char const __user *buf, @@ -123,12 +88,9 @@ static ssize_t hwsampler_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; - if (val != 0 && val != 1) - return -EINVAL; - if (oprofile_started) /* * save to do without locking as we set @@ -137,7 +99,7 @@ static ssize_t hwsampler_write(struct file *file, char const __user *buf, */ return -EBUSY; - hwsampler_enabled = val; + hwsampler_file = val; return count; } @@ -147,311 +109,38 @@ static const struct file_operations hwsampler_fops = { .write = hwsampler_write, }; -/* - * File ops used for: - * /dev/oprofile/0/count - * /dev/oprofile/hwsampling/hw_interval (cpu_type = timer) - * - * Make sure that the value is within the hardware range. - */ - -static ssize_t hw_interval_read(struct file *file, char __user *buf, - size_t count, loff_t *offset) -{ - return oprofilefs_ulong_to_user(oprofile_hw_interval, buf, - count, offset); -} - -static ssize_t hw_interval_write(struct file *file, char const __user *buf, - size_t count, loff_t *offset) -{ - unsigned long val; - int retval; - - if (*offset) - return -EINVAL; - retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) - return retval; - if (val < oprofile_min_interval) - oprofile_hw_interval = oprofile_min_interval; - else if (val > oprofile_max_interval) - oprofile_hw_interval = oprofile_max_interval; - else - oprofile_hw_interval = val; - - return count; -} - -static const struct file_operations hw_interval_fops = { - .read = hw_interval_read, - .write = hw_interval_write, -}; - -/* - * File ops used for: - * /dev/oprofile/0/event - * Only a single event with number 0 is supported with this counter. - * - * /dev/oprofile/0/unit_mask - * This is a dummy file needed by the user space tools. - * No value other than 0 is accepted or returned. - */ - -static ssize_t hwsampler_zero_read(struct file *file, char __user *buf, - size_t count, loff_t *offset) -{ - return oprofilefs_ulong_to_user(0, buf, count, offset); -} - -static ssize_t hwsampler_zero_write(struct file *file, char const __user *buf, - size_t count, loff_t *offset) -{ - unsigned long val; - int retval; - - if (*offset) - return -EINVAL; - - retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) - return retval; - if (val != 0) - return -EINVAL; - return count; -} - -static const struct file_operations zero_fops = { - .read = hwsampler_zero_read, - .write = hwsampler_zero_write, -}; - -/* /dev/oprofile/0/kernel file ops. */ - -static ssize_t hwsampler_kernel_read(struct file *file, char __user *buf, - size_t count, loff_t *offset) -{ - return oprofilefs_ulong_to_user(counter_config.kernel, - buf, count, offset); -} - -static ssize_t hwsampler_kernel_write(struct file *file, char const __user *buf, - size_t count, loff_t *offset) -{ - unsigned long val; - int retval; - - if (*offset) - return -EINVAL; - - retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) - return retval; - - if (val != 0 && val != 1) - return -EINVAL; - - counter_config.kernel = val; - - return count; -} - -static const struct file_operations kernel_fops = { - .read = hwsampler_kernel_read, - .write = hwsampler_kernel_write, -}; - -/* /dev/oprofile/0/user file ops. */ - -static ssize_t hwsampler_user_read(struct file *file, char __user *buf, - size_t count, loff_t *offset) -{ - return oprofilefs_ulong_to_user(counter_config.user, - buf, count, offset); -} - -static ssize_t hwsampler_user_write(struct file *file, char const __user *buf, - size_t count, loff_t *offset) -{ - unsigned long val; - int retval; - - if (*offset) - return -EINVAL; - - retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) - return retval; - - if (val != 0 && val != 1) - return -EINVAL; - - counter_config.user = val; - - return count; -} - -static const struct file_operations user_fops = { - .read = hwsampler_user_read, - .write = hwsampler_user_write, -}; - - -/* - * File ops used for: /dev/oprofile/timer/enabled - * The value always has to be the inverted value of hwsampler_enabled. So - * no separate variable is created. That way we do not need locking. - */ - -static ssize_t timer_enabled_read(struct file *file, char __user *buf, - size_t count, loff_t *offset) -{ - return oprofilefs_ulong_to_user(!hwsampler_enabled, buf, count, offset); -} - -static ssize_t timer_enabled_write(struct file *file, char const __user *buf, - size_t count, loff_t *offset) -{ - unsigned long val; - int retval; - - if (*offset) - return -EINVAL; - - retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) - return retval; - - if (val != 0 && val != 1) - return -EINVAL; - - /* Timer cannot be disabled without having hardware sampling. */ - if (val == 0 && !hwsampler_available) - return -EINVAL; - - if (oprofile_started) - /* - * save to do without locking as we set - * hwsampler_running in start() when start_mutex is - * held - */ - return -EBUSY; - - hwsampler_enabled = !val; - - return count; -} - -static const struct file_operations timer_enabled_fops = { - .read = timer_enabled_read, - .write = timer_enabled_write, -}; - - static int oprofile_create_hwsampling_files(struct super_block *sb, - struct dentry *root) + struct dentry *root) { - struct dentry *dir; - - dir = oprofilefs_mkdir(sb, root, "timer"); - if (!dir) - return -EINVAL; - - oprofilefs_create_file(sb, dir, "enabled", &timer_enabled_fops); - - if (!hwsampler_available) - return 0; + struct dentry *hw_dir; /* reinitialize default values */ - hwsampler_enabled = 1; - counter_config.kernel = 1; - counter_config.user = 1; - - if (!force_cpu_type) { - /* - * Create the counter file system. A single virtual - * counter is created which can be used to - * enable/disable hardware sampling dynamically from - * user space. The user space will configure a single - * counter with a single event. The value of 'event' - * and 'unit_mask' are not evaluated by the kernel code - * and can only be set to 0. - */ + hwsampler_file = 1; - dir = oprofilefs_mkdir(sb, root, "0"); - if (!dir) - return -EINVAL; + hw_dir = oprofilefs_mkdir(sb, root, "hwsampling"); + if (!hw_dir) + return -EINVAL; - oprofilefs_create_file(sb, dir, "enabled", &hwsampler_fops); - oprofilefs_create_file(sb, dir, "event", &zero_fops); - oprofilefs_create_file(sb, dir, "count", &hw_interval_fops); - oprofilefs_create_file(sb, dir, "unit_mask", &zero_fops); - oprofilefs_create_file(sb, dir, "kernel", &kernel_fops); - oprofilefs_create_file(sb, dir, "user", &user_fops); - oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks", - &oprofile_sdbt_blocks); + oprofilefs_create_file(sb, hw_dir, "hwsampler", &hwsampler_fops); + oprofilefs_create_ulong(sb, hw_dir, "hw_interval", + &oprofile_hw_interval); + oprofilefs_create_ro_ulong(sb, hw_dir, "hw_min_interval", + &oprofile_min_interval); + oprofilefs_create_ro_ulong(sb, hw_dir, "hw_max_interval", + &oprofile_max_interval); + oprofilefs_create_ulong(sb, hw_dir, "hw_sdbt_blocks", + &oprofile_sdbt_blocks); - } else { - /* - * Hardware sampling can be used but the cpu_type is - * forced to timer in order to deal with legacy user - * space tools. The /dev/oprofile/hwsampling fs is - * provided in that case. - */ - dir = oprofilefs_mkdir(sb, root, "hwsampling"); - if (!dir) - return -EINVAL; - - oprofilefs_create_file(sb, dir, "hwsampler", - &hwsampler_fops); - oprofilefs_create_file(sb, dir, "hw_interval", - &hw_interval_fops); - oprofilefs_create_ro_ulong(sb, dir, "hw_min_interval", - &oprofile_min_interval); - oprofilefs_create_ro_ulong(sb, dir, "hw_max_interval", - &oprofile_max_interval); - oprofilefs_create_ulong(sb, dir, "hw_sdbt_blocks", - &oprofile_sdbt_blocks); - } return 0; } static int oprofile_hwsampler_init(struct oprofile_operations *ops) { - /* - * Initialize the timer mode infrastructure as well in order - * to be able to switch back dynamically. oprofile_timer_init - * is not supposed to fail. - */ - if (oprofile_timer_init(ops)) - BUG(); - - memcpy(&timer_ops, ops, sizeof(timer_ops)); - ops->create_files = oprofile_create_hwsampling_files; - - /* - * If the user space tools do not support newer cpu types, - * the force_cpu_type module parameter - * can be used to always return \"timer\" as cpu type. - */ - if (force_cpu_type != timer) { - struct cpuid id; - - get_cpu_id (&id); - - switch (id.machine) { - case 0x2097: case 0x2098: ops->cpu_type = "s390/z10"; break; - case 0x2817: case 0x2818: ops->cpu_type = "s390/z196"; break; - default: return -ENODEV; - } - } - if (hwsampler_setup()) return -ENODEV; /* - * Query the range for the sampling interval from the - * hardware. + * create hwsampler files only if hwsampler_setup() succeeds. */ oprofile_min_interval = hwsampler_query_min_interval(); if (oprofile_min_interval == 0) @@ -466,17 +155,23 @@ static int oprofile_hwsampler_init(struct oprofile_operations *ops) if (oprofile_hw_interval > oprofile_max_interval) oprofile_hw_interval = oprofile_max_interval; - printk(KERN_INFO "oprofile: System z hardware sampling " - "facility found.\n"); + if (oprofile_timer_init(ops)) + return -ENODEV; + + printk(KERN_INFO "oprofile: using hardware sampling\n"); + + memcpy(&timer_ops, ops, sizeof(timer_ops)); ops->start = oprofile_hwsampler_start; ops->stop = oprofile_hwsampler_stop; + ops->create_files = oprofile_create_hwsampling_files; return 0; } static void oprofile_hwsampler_exit(void) { + oprofile_timer_exit(); hwsampler_shutdown(); } @@ -487,15 +182,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ops->backtrace = s390_backtrace; #ifdef CONFIG_64BIT - - /* - * -ENODEV is not reported to the caller. The module itself - * will use the timer mode sampling as fallback and this is - * always available. - */ - hwsampler_available = oprofile_hwsampler_init(ops) == 0; - - return 0; + return oprofile_hwsampler_init(ops); #else return -ENODEV; #endif diff --git a/trunk/arch/s390/oprofile/op_counter.h b/trunk/arch/s390/oprofile/op_counter.h deleted file mode 100644 index 1a8d3ca09014..000000000000 --- a/trunk/arch/s390/oprofile/op_counter.h +++ /dev/null @@ -1,23 +0,0 @@ -/** - * arch/s390/oprofile/op_counter.h - * - * Copyright (C) 2011 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Andreas Krebbel (krebbel@linux.vnet.ibm.com) - * - * @remark Copyright 2011 OProfile authors - */ - -#ifndef OP_COUNTER_H -#define OP_COUNTER_H - -struct op_counter_config { - /* `enabled' maps to the hwsampler_file variable. */ - /* `count' maps to the oprofile_hw_interval variable. */ - /* `event' and `unit_mask' are unused. */ - unsigned long kernel; - unsigned long user; -}; - -extern struct op_counter_config counter_config; - -#endif /* OP_COUNTER_H */ diff --git a/trunk/arch/sh/boards/board-sh7757lcr.c b/trunk/arch/sh/boards/board-sh7757lcr.c index ec8c84c14b17..895e337c79b6 100644 --- a/trunk/arch/sh/boards/board-sh7757lcr.c +++ b/trunk/arch/sh/boards/board-sh7757lcr.c @@ -50,9 +50,9 @@ static struct platform_device heartbeat_device = { #define GBECONT 0xffc10100 #define GBECONT_RMII1 BIT(17) #define GBECONT_RMII0 BIT(16) -static void sh7757_eth_set_mdio_gate(unsigned long addr) +static void sh7757_eth_set_mdio_gate(void *addr) { - if ((addr & 0x00000fff) < 0x0800) + if (((unsigned long)addr & 0x00000fff) < 0x0800) writel(readl(GBECONT) | GBECONT_RMII0, GBECONT); else writel(readl(GBECONT) | GBECONT_RMII1, GBECONT); @@ -116,9 +116,9 @@ static struct platform_device sh7757_eth1_device = { }, }; -static void sh7757_eth_giga_set_mdio_gate(unsigned long addr) +static void sh7757_eth_giga_set_mdio_gate(void *addr) { - if ((addr & 0x00000fff) < 0x0800) { + if (((unsigned long)addr & 0x00000fff) < 0x0800) { gpio_set_value(GPIO_PTT4, 1); writel(readl(GBECONT) & ~GBECONT_RMII0, GBECONT); } else { @@ -210,8 +210,12 @@ static struct resource sh_mmcif_resources[] = { }; static struct sh_mmcif_dma sh7757lcr_mmcif_dma = { - .chan_priv_tx = SHDMA_SLAVE_MMCIF_TX, - .chan_priv_rx = SHDMA_SLAVE_MMCIF_RX, + .chan_priv_tx = { + .slave_id = SHDMA_SLAVE_MMCIF_TX, + }, + .chan_priv_rx = { + .slave_id = SHDMA_SLAVE_MMCIF_RX, + } }; static struct sh_mmcif_plat_data sh_mmcif_plat = { diff --git a/trunk/arch/sh/oprofile/common.c b/trunk/arch/sh/oprofile/common.c index b4c2d2b946dd..e4dd5d5a1115 100644 --- a/trunk/arch/sh/oprofile/common.c +++ b/trunk/arch/sh/oprofile/common.c @@ -49,7 +49,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) return oprofile_perf_init(ops); } -void __exit oprofile_arch_exit(void) +void oprofile_arch_exit(void) { oprofile_perf_exit(); kfree(sh_pmu_op_name); @@ -60,5 +60,5 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ops->backtrace = sh_backtrace; return -ENODEV; } -void __exit oprofile_arch_exit(void) {} +void oprofile_arch_exit(void) {} #endif /* CONFIG_HW_PERF_EVENTS */ diff --git a/trunk/arch/sparc/kernel/pci_sun4v.c b/trunk/arch/sparc/kernel/pci_sun4v.c index b272cda35a01..af5755d20fbe 100644 --- a/trunk/arch/sparc/kernel/pci_sun4v.c +++ b/trunk/arch/sparc/kernel/pci_sun4v.c @@ -849,10 +849,10 @@ static int pci_sun4v_msiq_build_irq(struct pci_pbm_info *pbm, if (!irq) return -ENOMEM; - if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE)) - return -EINVAL; if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID)) return -EINVAL; + if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE)) + return -EINVAL; return irq; } diff --git a/trunk/arch/x86/include/asm/debugreg.h b/trunk/arch/x86/include/asm/debugreg.h index b903d5ea3941..078ad0caefc6 100644 --- a/trunk/arch/x86/include/asm/debugreg.h +++ b/trunk/arch/x86/include/asm/debugreg.h @@ -101,28 +101,6 @@ extern void aout_dump_debugregs(struct user *dump); extern void hw_breakpoint_restore(void); -#ifdef CONFIG_X86_64 -DECLARE_PER_CPU(int, debug_stack_usage); -static inline void debug_stack_usage_inc(void) -{ - __get_cpu_var(debug_stack_usage)++; -} -static inline void debug_stack_usage_dec(void) -{ - __get_cpu_var(debug_stack_usage)--; -} -int is_debug_stack(unsigned long addr); -void debug_stack_set_zero(void); -void debug_stack_reset(void); -#else /* !X86_64 */ -static inline int is_debug_stack(unsigned long addr) { return 0; } -static inline void debug_stack_set_zero(void) { } -static inline void debug_stack_reset(void) { } -static inline void debug_stack_usage_inc(void) { } -static inline void debug_stack_usage_dec(void) { } -#endif /* X86_64 */ - - #endif /* __KERNEL__ */ #endif /* _ASM_X86_DEBUGREG_H */ diff --git a/trunk/arch/x86/include/asm/desc.h b/trunk/arch/x86/include/asm/desc.h index e95822d683f4..41935fadfdfc 100644 --- a/trunk/arch/x86/include/asm/desc.h +++ b/trunk/arch/x86/include/asm/desc.h @@ -35,8 +35,6 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in extern struct desc_ptr idt_descr; extern gate_desc idt_table[]; -extern struct desc_ptr nmi_idt_descr; -extern gate_desc nmi_idt_table[]; struct gdt_page { struct desc_struct gdt[GDT_ENTRIES]; @@ -309,16 +307,6 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit) desc->limit = (limit >> 16) & 0xf; } -#ifdef CONFIG_X86_64 -static inline void set_nmi_gate(int gate, void *addr) -{ - gate_desc s; - - pack_gate(&s, GATE_INTERRUPT, (unsigned long)addr, 0, 0, __KERNEL_CS); - write_idt_entry(nmi_idt_table, gate, &s); -} -#endif - static inline void _set_gate(int gate, unsigned type, void *addr, unsigned dpl, unsigned ist, unsigned seg) { diff --git a/trunk/arch/x86/include/asm/insn.h b/trunk/arch/x86/include/asm/insn.h index 74df3f1eddfd..88c765e16410 100644 --- a/trunk/arch/x86/include/asm/insn.h +++ b/trunk/arch/x86/include/asm/insn.h @@ -137,13 +137,6 @@ static inline int insn_is_avx(struct insn *insn) return (insn->vex_prefix.value != 0); } -/* Ensure this instruction is decoded completely */ -static inline int insn_complete(struct insn *insn) -{ - return insn->opcode.got && insn->modrm.got && insn->sib.got && - insn->displacement.got && insn->immediate.got; -} - static inline insn_byte_t insn_vex_m_bits(struct insn *insn) { if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ diff --git a/trunk/arch/x86/include/asm/perf_event.h b/trunk/arch/x86/include/asm/perf_event.h index 096c975e099f..f61c62f7d5d8 100644 --- a/trunk/arch/x86/include/asm/perf_event.h +++ b/trunk/arch/x86/include/asm/perf_event.h @@ -57,7 +57,6 @@ (1 << (ARCH_PERFMON_UNHALTED_CORE_CYCLES_INDEX)) #define ARCH_PERFMON_BRANCH_MISSES_RETIRED 6 -#define ARCH_PERFMON_EVENTS_COUNT 7 /* * Intel "Architectural Performance Monitoring" CPUID @@ -73,19 +72,6 @@ union cpuid10_eax { unsigned int full; }; -union cpuid10_ebx { - struct { - unsigned int no_unhalted_core_cycles:1; - unsigned int no_instructions_retired:1; - unsigned int no_unhalted_reference_cycles:1; - unsigned int no_llc_reference:1; - unsigned int no_llc_misses:1; - unsigned int no_branch_instruction_retired:1; - unsigned int no_branch_misses_retired:1; - } split; - unsigned int full; -}; - union cpuid10_edx { struct { unsigned int num_counters_fixed:5; @@ -95,15 +81,6 @@ union cpuid10_edx { unsigned int full; }; -struct x86_pmu_capability { - int version; - int num_counters_gp; - int num_counters_fixed; - int bit_width_gp; - int bit_width_fixed; - unsigned int events_mask; - int events_mask_len; -}; /* * Fixed-purpose performance events: @@ -112,24 +89,23 @@ struct x86_pmu_capability { /* * All 3 fixed-mode PMCs are configured via this single MSR: */ -#define MSR_ARCH_PERFMON_FIXED_CTR_CTRL 0x38d +#define MSR_ARCH_PERFMON_FIXED_CTR_CTRL 0x38d /* * The counts are available in three separate MSRs: */ /* Instr_Retired.Any: */ -#define MSR_ARCH_PERFMON_FIXED_CTR0 0x309 -#define X86_PMC_IDX_FIXED_INSTRUCTIONS (X86_PMC_IDX_FIXED + 0) +#define MSR_ARCH_PERFMON_FIXED_CTR0 0x309 +#define X86_PMC_IDX_FIXED_INSTRUCTIONS (X86_PMC_IDX_FIXED + 0) /* CPU_CLK_Unhalted.Core: */ -#define MSR_ARCH_PERFMON_FIXED_CTR1 0x30a -#define X86_PMC_IDX_FIXED_CPU_CYCLES (X86_PMC_IDX_FIXED + 1) +#define MSR_ARCH_PERFMON_FIXED_CTR1 0x30a +#define X86_PMC_IDX_FIXED_CPU_CYCLES (X86_PMC_IDX_FIXED + 1) /* CPU_CLK_Unhalted.Ref: */ -#define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b -#define X86_PMC_IDX_FIXED_REF_CYCLES (X86_PMC_IDX_FIXED + 2) -#define X86_PMC_MSK_FIXED_REF_CYCLES (1ULL << X86_PMC_IDX_FIXED_REF_CYCLES) +#define MSR_ARCH_PERFMON_FIXED_CTR2 0x30b +#define X86_PMC_IDX_FIXED_BUS_CYCLES (X86_PMC_IDX_FIXED + 2) /* * We model BTS tracing as another fixed-mode PMC. @@ -226,7 +202,6 @@ struct perf_guest_switch_msr { }; extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr); -extern void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap); #else static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr) { @@ -234,11 +209,6 @@ static inline perf_guest_switch_msr *perf_guest_get_msrs(int *nr) return NULL; } -static inline void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) -{ - memset(cap, 0, sizeof(*cap)); -} - static inline void perf_events_lapic_init(void) { } #endif diff --git a/trunk/arch/x86/kernel/cpu/common.c b/trunk/arch/x86/kernel/cpu/common.c index 266e4649b1da..aa003b13a831 100644 --- a/trunk/arch/x86/kernel/cpu/common.c +++ b/trunk/arch/x86/kernel/cpu/common.c @@ -1026,8 +1026,6 @@ __setup("clearcpuid=", setup_disablecpuid); #ifdef CONFIG_X86_64 struct desc_ptr idt_descr = { NR_VECTORS * 16 - 1, (unsigned long) idt_table }; -struct desc_ptr nmi_idt_descr = { NR_VECTORS * 16 - 1, - (unsigned long) nmi_idt_table }; DEFINE_PER_CPU_FIRST(union irq_stack_union, irq_stack_union) __aligned(PAGE_SIZE); @@ -1092,26 +1090,6 @@ unsigned long kernel_eflags; */ DEFINE_PER_CPU(struct orig_ist, orig_ist); -static DEFINE_PER_CPU(unsigned long, debug_stack_addr); -DEFINE_PER_CPU(int, debug_stack_usage); - -int is_debug_stack(unsigned long addr) -{ - return __get_cpu_var(debug_stack_usage) || - (addr <= __get_cpu_var(debug_stack_addr) && - addr > (__get_cpu_var(debug_stack_addr) - DEBUG_STKSZ)); -} - -void debug_stack_set_zero(void) -{ - load_idt((const struct desc_ptr *)&nmi_idt_descr); -} - -void debug_stack_reset(void) -{ - load_idt((const struct desc_ptr *)&idt_descr); -} - #else /* CONFIG_X86_64 */ DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; @@ -1230,8 +1208,6 @@ void __cpuinit cpu_init(void) estacks += exception_stack_sizes[v]; oist->ist[v] = t->x86_tss.ist[v] = (unsigned long)estacks; - if (v == DEBUG_STACK-1) - per_cpu(debug_stack_addr, cpu) = (unsigned long)estacks; } } diff --git a/trunk/arch/x86/kernel/cpu/perf_event.c b/trunk/arch/x86/kernel/cpu/perf_event.c index 5adce1040b11..2bda212a0010 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event.c +++ b/trunk/arch/x86/kernel/cpu/perf_event.c @@ -484,195 +484,18 @@ static inline int is_x86_event(struct perf_event *event) return event->pmu == &pmu; } -/* - * Event scheduler state: - * - * Assign events iterating over all events and counters, beginning - * with events with least weights first. Keep the current iterator - * state in struct sched_state. - */ -struct sched_state { - int weight; - int event; /* event index */ - int counter; /* counter index */ - int unassigned; /* number of events to be assigned left */ - unsigned long used[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; -}; - -/* Total max is X86_PMC_IDX_MAX, but we are O(n!) limited */ -#define SCHED_STATES_MAX 2 - -struct perf_sched { - int max_weight; - int max_events; - struct event_constraint **constraints; - struct sched_state state; - int saved_states; - struct sched_state saved[SCHED_STATES_MAX]; -}; - -/* - * Initialize interator that runs through all events and counters. - */ -static void perf_sched_init(struct perf_sched *sched, struct event_constraint **c, - int num, int wmin, int wmax) -{ - int idx; - - memset(sched, 0, sizeof(*sched)); - sched->max_events = num; - sched->max_weight = wmax; - sched->constraints = c; - - for (idx = 0; idx < num; idx++) { - if (c[idx]->weight == wmin) - break; - } - - sched->state.event = idx; /* start with min weight */ - sched->state.weight = wmin; - sched->state.unassigned = num; -} - -static void perf_sched_save_state(struct perf_sched *sched) -{ - if (WARN_ON_ONCE(sched->saved_states >= SCHED_STATES_MAX)) - return; - - sched->saved[sched->saved_states] = sched->state; - sched->saved_states++; -} - -static bool perf_sched_restore_state(struct perf_sched *sched) -{ - if (!sched->saved_states) - return false; - - sched->saved_states--; - sched->state = sched->saved[sched->saved_states]; - - /* continue with next counter: */ - clear_bit(sched->state.counter++, sched->state.used); - - return true; -} - -/* - * Select a counter for the current event to schedule. Return true on - * success. - */ -static bool __perf_sched_find_counter(struct perf_sched *sched) -{ - struct event_constraint *c; - int idx; - - if (!sched->state.unassigned) - return false; - - if (sched->state.event >= sched->max_events) - return false; - - c = sched->constraints[sched->state.event]; - - /* Prefer fixed purpose counters */ - if (x86_pmu.num_counters_fixed) { - idx = X86_PMC_IDX_FIXED; - for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_MAX) { - if (!__test_and_set_bit(idx, sched->state.used)) - goto done; - } - } - /* Grab the first unused counter starting with idx */ - idx = sched->state.counter; - for_each_set_bit_cont(idx, c->idxmsk, X86_PMC_IDX_FIXED) { - if (!__test_and_set_bit(idx, sched->state.used)) - goto done; - } - - return false; - -done: - sched->state.counter = idx; - - if (c->overlap) - perf_sched_save_state(sched); - - return true; -} - -static bool perf_sched_find_counter(struct perf_sched *sched) -{ - while (!__perf_sched_find_counter(sched)) { - if (!perf_sched_restore_state(sched)) - return false; - } - - return true; -} - -/* - * Go through all unassigned events and find the next one to schedule. - * Take events with the least weight first. Return true on success. - */ -static bool perf_sched_next_event(struct perf_sched *sched) -{ - struct event_constraint *c; - - if (!sched->state.unassigned || !--sched->state.unassigned) - return false; - - do { - /* next event */ - sched->state.event++; - if (sched->state.event >= sched->max_events) { - /* next weight */ - sched->state.event = 0; - sched->state.weight++; - if (sched->state.weight > sched->max_weight) - return false; - } - c = sched->constraints[sched->state.event]; - } while (c->weight != sched->state.weight); - - sched->state.counter = 0; /* start with first counter */ - - return true; -} - -/* - * Assign a counter for each event. - */ -static int perf_assign_events(struct event_constraint **constraints, int n, - int wmin, int wmax, int *assign) -{ - struct perf_sched sched; - - perf_sched_init(&sched, constraints, n, wmin, wmax); - - do { - if (!perf_sched_find_counter(&sched)) - break; /* failed */ - if (assign) - assign[sched.state.event] = sched.state.counter; - } while (perf_sched_next_event(&sched)); - - return sched.state.unassigned; -} - int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) { struct event_constraint *c, *constraints[X86_PMC_IDX_MAX]; unsigned long used_mask[BITS_TO_LONGS(X86_PMC_IDX_MAX)]; - int i, wmin, wmax, num = 0; + int i, j, w, wmax, num = 0; struct hw_perf_event *hwc; bitmap_zero(used_mask, X86_PMC_IDX_MAX); - for (i = 0, wmin = X86_PMC_IDX_MAX, wmax = 0; i < n; i++) { + for (i = 0; i < n; i++) { c = x86_pmu.get_event_constraints(cpuc, cpuc->event_list[i]); constraints[i] = c; - wmin = min(wmin, c->weight); - wmax = max(wmax, c->weight); } /* @@ -698,11 +521,59 @@ int x86_schedule_events(struct cpu_hw_events *cpuc, int n, int *assign) if (assign) assign[i] = hwc->idx; } + if (i == n) + goto done; + + /* + * begin slow path + */ + + bitmap_zero(used_mask, X86_PMC_IDX_MAX); - /* slow path */ - if (i != n) - num = perf_assign_events(constraints, n, wmin, wmax, assign); + /* + * weight = number of possible counters + * + * 1 = most constrained, only works on one counter + * wmax = least constrained, works on any counter + * + * assign events to counters starting with most + * constrained events. + */ + wmax = x86_pmu.num_counters; + /* + * when fixed event counters are present, + * wmax is incremented by 1 to account + * for one more choice + */ + if (x86_pmu.num_counters_fixed) + wmax++; + + for (w = 1, num = n; num && w <= wmax; w++) { + /* for each event */ + for (i = 0; num && i < n; i++) { + c = constraints[i]; + hwc = &cpuc->event_list[i]->hw; + + if (c->weight != w) + continue; + + for_each_set_bit(j, c->idxmsk, X86_PMC_IDX_MAX) { + if (!test_bit(j, used_mask)) + break; + } + + if (j == X86_PMC_IDX_MAX) + break; + + __set_bit(j, used_mask); + + if (assign) + assign[i] = j; + num--; + } + } +done: /* * scheduling failed or is just a simulation, * free resources if necessary @@ -1248,7 +1119,6 @@ static void __init pmu_check_apic(void) static int __init init_hw_perf_events(void) { - struct x86_pmu_quirk *quirk; struct event_constraint *c; int err; @@ -1277,8 +1147,8 @@ static int __init init_hw_perf_events(void) pr_cont("%s PMU driver.\n", x86_pmu.name); - for (quirk = x86_pmu.quirks; quirk; quirk = quirk->next) - quirk->func(); + if (x86_pmu.quirks) + x86_pmu.quirks(); if (x86_pmu.num_counters > X86_PMC_MAX_GENERIC) { WARN(1, KERN_ERR "hw perf events %d > max(%d), clipping!", @@ -1301,18 +1171,12 @@ static int __init init_hw_perf_events(void) unconstrained = (struct event_constraint) __EVENT_CONSTRAINT(0, (1ULL << x86_pmu.num_counters) - 1, - 0, x86_pmu.num_counters, 0); + 0, x86_pmu.num_counters); if (x86_pmu.event_constraints) { - /* - * event on fixed counter2 (REF_CYCLES) only works on this - * counter, so do not extend mask to generic counters - */ for_each_event_constraint(c, x86_pmu.event_constraints) { - if (c->cmask != X86_RAW_EVENT_MASK - || c->idxmsk64 == X86_PMC_MSK_FIXED_REF_CYCLES) { + if (c->cmask != X86_RAW_EVENT_MASK) continue; - } c->idxmsk64 |= (1ULL << x86_pmu.num_counters) - 1; c->weight += x86_pmu.num_counters; @@ -1702,15 +1566,3 @@ unsigned long perf_misc_flags(struct pt_regs *regs) return misc; } - -void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) -{ - cap->version = x86_pmu.version; - cap->num_counters_gp = x86_pmu.num_counters; - cap->num_counters_fixed = x86_pmu.num_counters_fixed; - cap->bit_width_gp = x86_pmu.cntval_bits; - cap->bit_width_fixed = x86_pmu.cntval_bits; - cap->events_mask = (unsigned int)x86_pmu.events_maskl; - cap->events_mask_len = x86_pmu.events_mask_len; -} -EXPORT_SYMBOL_GPL(perf_get_x86_pmu_capability); diff --git a/trunk/arch/x86/kernel/cpu/perf_event.h b/trunk/arch/x86/kernel/cpu/perf_event.h index 8944062f46e2..b9698d40ac4b 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event.h +++ b/trunk/arch/x86/kernel/cpu/perf_event.h @@ -45,7 +45,6 @@ struct event_constraint { u64 code; u64 cmask; int weight; - int overlap; }; struct amd_nb { @@ -152,40 +151,15 @@ struct cpu_hw_events { void *kfree_on_online; }; -#define __EVENT_CONSTRAINT(c, n, m, w, o) {\ +#define __EVENT_CONSTRAINT(c, n, m, w) {\ { .idxmsk64 = (n) }, \ .code = (c), \ .cmask = (m), \ .weight = (w), \ - .overlap = (o), \ } #define EVENT_CONSTRAINT(c, n, m) \ - __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 0) - -/* - * The overlap flag marks event constraints with overlapping counter - * masks. This is the case if the counter mask of such an event is not - * a subset of any other counter mask of a constraint with an equal or - * higher weight, e.g.: - * - * c_overlaps = EVENT_CONSTRAINT_OVERLAP(0, 0x09, 0); - * c_another1 = EVENT_CONSTRAINT(0, 0x07, 0); - * c_another2 = EVENT_CONSTRAINT(0, 0x38, 0); - * - * The event scheduler may not select the correct counter in the first - * cycle because it needs to know which subsequent events will be - * scheduled. It may fail to schedule the events then. So we set the - * overlap flag for such constraints to give the scheduler a hint which - * events to select for counter rescheduling. - * - * Care must be taken as the rescheduling algorithm is O(n!) which - * will increase scheduling cycles for an over-commited system - * dramatically. The number of such EVENT_CONSTRAINT_OVERLAP() macros - * and its counter masks must be kept at a minimum. - */ -#define EVENT_CONSTRAINT_OVERLAP(c, n, m) \ - __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n), 1) + __EVENT_CONSTRAINT(c, n, m, HWEIGHT(n)) /* * Constraint on the Event code. @@ -261,11 +235,6 @@ union perf_capabilities { u64 capabilities; }; -struct x86_pmu_quirk { - struct x86_pmu_quirk *next; - void (*func)(void); -}; - /* * struct x86_pmu - generic x86 pmu */ @@ -290,11 +259,6 @@ struct x86_pmu { int num_counters_fixed; int cntval_bits; u64 cntval_mask; - union { - unsigned long events_maskl; - unsigned long events_mask[BITS_TO_LONGS(ARCH_PERFMON_EVENTS_COUNT)]; - }; - int events_mask_len; int apic; u64 max_period; struct event_constraint * @@ -304,7 +268,7 @@ struct x86_pmu { void (*put_event_constraints)(struct cpu_hw_events *cpuc, struct perf_event *event); struct event_constraint *event_constraints; - struct x86_pmu_quirk *quirks; + void (*quirks)(void); int perfctr_second_write; int (*cpu_prepare)(int cpu); @@ -345,15 +309,6 @@ struct x86_pmu { struct perf_guest_switch_msr *(*guest_get_msrs)(int *nr); }; -#define x86_add_quirk(func_) \ -do { \ - static struct x86_pmu_quirk __quirk __initdata = { \ - .func = func_, \ - }; \ - __quirk.next = x86_pmu.quirks; \ - x86_pmu.quirks = &__quirk; \ -} while (0) - #define ERF_NO_HT_SHARING 1 #define ERF_HAS_RSP_1 2 diff --git a/trunk/arch/x86/kernel/cpu/perf_event_amd.c b/trunk/arch/x86/kernel/cpu/perf_event_amd.c index 0397b23be8e9..aeefd45697a2 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_amd.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_amd.c @@ -492,7 +492,7 @@ static __initconst const struct x86_pmu amd_pmu = { static struct event_constraint amd_f15_PMC0 = EVENT_CONSTRAINT(0, 0x01, 0); static struct event_constraint amd_f15_PMC20 = EVENT_CONSTRAINT(0, 0x07, 0); static struct event_constraint amd_f15_PMC3 = EVENT_CONSTRAINT(0, 0x08, 0); -static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT_OVERLAP(0, 0x09, 0); +static struct event_constraint amd_f15_PMC30 = EVENT_CONSTRAINT(0, 0x09, 0); static struct event_constraint amd_f15_PMC50 = EVENT_CONSTRAINT(0, 0x3F, 0); static struct event_constraint amd_f15_PMC53 = EVENT_CONSTRAINT(0, 0x38, 0); diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel.c b/trunk/arch/x86/kernel/cpu/perf_event_intel.c index cbfaaa2475ea..121f1be4da19 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel.c @@ -28,7 +28,6 @@ static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly = [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c4, [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c5, [PERF_COUNT_HW_BUS_CYCLES] = 0x013c, - [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding */ }; static struct event_constraint intel_core_event_constraints[] __read_mostly = @@ -46,7 +45,12 @@ static struct event_constraint intel_core2_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ - FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ + /* + * Core2 has Fixed Counter 2 listed as CPU_CLK_UNHALTED.REF and event + * 0x013c as CPU_CLK_UNHALTED.BUS and specifies there is a fixed + * ratio between these counters. + */ + /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */ INTEL_EVENT_CONSTRAINT(0x10, 0x1), /* FP_COMP_OPS_EXE */ INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */ INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */ @@ -64,7 +68,7 @@ static struct event_constraint intel_nehalem_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ - FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ + /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */ INTEL_EVENT_CONSTRAINT(0x40, 0x3), /* L1D_CACHE_LD */ INTEL_EVENT_CONSTRAINT(0x41, 0x3), /* L1D_CACHE_ST */ INTEL_EVENT_CONSTRAINT(0x42, 0x3), /* L1D_CACHE_LOCK */ @@ -86,7 +90,7 @@ static struct event_constraint intel_westmere_event_constraints[] __read_mostly { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ - FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ + /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */ INTEL_EVENT_CONSTRAINT(0x51, 0x3), /* L1D */ INTEL_EVENT_CONSTRAINT(0x60, 0x1), /* OFFCORE_REQUESTS_OUTSTANDING */ INTEL_EVENT_CONSTRAINT(0x63, 0x3), /* CACHE_LOCK_CYCLES */ @@ -98,7 +102,7 @@ static struct event_constraint intel_snb_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ - FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ + /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */ INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.PENDING */ INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ @@ -121,7 +125,7 @@ static struct event_constraint intel_gen_event_constraints[] __read_mostly = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ - FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */ + /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */ EVENT_CONSTRAINT_END }; @@ -1165,7 +1169,7 @@ __intel_shared_reg_get_constraints(struct cpu_hw_events *cpuc, */ c = &unconstrained; } else if (intel_try_alt_er(event, orig_idx)) { - raw_spin_unlock(&era->lock); + raw_spin_unlock_irqrestore(&era->lock, flags); goto again; } raw_spin_unlock_irqrestore(&era->lock, flags); @@ -1515,7 +1519,7 @@ static __initconst const struct x86_pmu intel_pmu = { .guest_get_msrs = intel_guest_get_msrs, }; -static __init void intel_clovertown_quirk(void) +static void intel_clovertown_quirks(void) { /* * PEBS is unreliable due to: @@ -1541,60 +1545,19 @@ static __init void intel_clovertown_quirk(void) x86_pmu.pebs_constraints = NULL; } -static __init void intel_sandybridge_quirk(void) +static void intel_sandybridge_quirks(void) { printk(KERN_WARNING "PEBS disabled due to CPU errata.\n"); x86_pmu.pebs = 0; x86_pmu.pebs_constraints = NULL; } -static const struct { int id; char *name; } intel_arch_events_map[] __initconst = { - { PERF_COUNT_HW_CPU_CYCLES, "cpu cycles" }, - { PERF_COUNT_HW_INSTRUCTIONS, "instructions" }, - { PERF_COUNT_HW_BUS_CYCLES, "bus cycles" }, - { PERF_COUNT_HW_CACHE_REFERENCES, "cache references" }, - { PERF_COUNT_HW_CACHE_MISSES, "cache misses" }, - { PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "branch instructions" }, - { PERF_COUNT_HW_BRANCH_MISSES, "branch misses" }, -}; - -static __init void intel_arch_events_quirk(void) -{ - int bit; - - /* disable event that reported as not presend by cpuid */ - for_each_set_bit(bit, x86_pmu.events_mask, ARRAY_SIZE(intel_arch_events_map)) { - intel_perfmon_event_map[intel_arch_events_map[bit].id] = 0; - printk(KERN_WARNING "CPUID marked event: \'%s\' unavailable\n", - intel_arch_events_map[bit].name); - } -} - -static __init void intel_nehalem_quirk(void) -{ - union cpuid10_ebx ebx; - - ebx.full = x86_pmu.events_maskl; - if (ebx.split.no_branch_misses_retired) { - /* - * Erratum AAJ80 detected, we work it around by using - * the BR_MISP_EXEC.ANY event. This will over-count - * branch-misses, but it's still much better than the - * architectural event which is often completely bogus: - */ - intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; - ebx.split.no_branch_misses_retired = 0; - x86_pmu.events_maskl = ebx.full; - printk(KERN_INFO "CPU erratum AAJ80 worked around\n"); - } -} - __init int intel_pmu_init(void) { union cpuid10_edx edx; union cpuid10_eax eax; - union cpuid10_ebx ebx; unsigned int unused; + unsigned int ebx; int version; if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { @@ -1611,8 +1574,8 @@ __init int intel_pmu_init(void) * Check whether the Architectural PerfMon supports * Branch Misses Retired hw_event or not. */ - cpuid(10, &eax.full, &ebx.full, &unused, &edx.full); - if (eax.split.mask_length < ARCH_PERFMON_EVENTS_COUNT) + cpuid(10, &eax.full, &ebx, &unused, &edx.full); + if (eax.split.mask_length <= ARCH_PERFMON_BRANCH_MISSES_RETIRED) return -ENODEV; version = eax.split.version_id; @@ -1626,9 +1589,6 @@ __init int intel_pmu_init(void) x86_pmu.cntval_bits = eax.split.bit_width; x86_pmu.cntval_mask = (1ULL << eax.split.bit_width) - 1; - x86_pmu.events_maskl = ebx.full; - x86_pmu.events_mask_len = eax.split.mask_length; - /* * Quirk: v2 perfmon does not report fixed-purpose events, so * assume at least 3 events: @@ -1648,8 +1608,6 @@ __init int intel_pmu_init(void) intel_ds_init(); - x86_add_quirk(intel_arch_events_quirk); /* Install first, so it runs last */ - /* * Install the hw-cache-events table: */ @@ -1659,7 +1617,7 @@ __init int intel_pmu_init(void) break; case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ - x86_add_quirk(intel_clovertown_quirk); + x86_pmu.quirks = intel_clovertown_quirks; case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ case 29: /* six-core 45 nm xeon "Dunnington" */ @@ -1693,8 +1651,17 @@ __init int intel_pmu_init(void) /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1; - x86_add_quirk(intel_nehalem_quirk); + if (ebx & 0x40) { + /* + * Erratum AAJ80 detected, we work it around by using + * the BR_MISP_EXEC.ANY event. This will over-count + * branch-misses, but it's still much better than the + * architectural event which is often completely bogus: + */ + intel_perfmon_event_map[PERF_COUNT_HW_BRANCH_MISSES] = 0x7f89; + pr_cont("erratum AAJ80 worked around, "); + } pr_cont("Nehalem events, "); break; @@ -1734,7 +1701,7 @@ __init int intel_pmu_init(void) break; case 42: /* SandyBridge */ - x86_add_quirk(intel_sandybridge_quirk); + x86_pmu.quirks = intel_sandybridge_quirks; case 45: /* SandyBridge, "Romely-EP" */ memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, sizeof(hw_cache_event_ids)); @@ -1771,6 +1738,5 @@ __init int intel_pmu_init(void) break; } } - return 0; } diff --git a/trunk/arch/x86/kernel/dumpstack_32.c b/trunk/arch/x86/kernel/dumpstack_32.c index 3b97a80ce329..c99f9ed013d5 100644 --- a/trunk/arch/x86/kernel/dumpstack_32.c +++ b/trunk/arch/x86/kernel/dumpstack_32.c @@ -116,16 +116,16 @@ void show_registers(struct pt_regs *regs) for (i = 0; i < code_len; i++, ip++) { if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { - printk(" Bad EIP value."); + printk(KERN_CONT " Bad EIP value."); break; } if (ip == (u8 *)regs->ip) - printk("<%02x> ", c); + printk(KERN_CONT "<%02x> ", c); else - printk("%02x ", c); + printk(KERN_CONT "%02x ", c); } } - printk("\n"); + printk(KERN_CONT "\n"); } int is_valid_bugaddr(unsigned long ip) diff --git a/trunk/arch/x86/kernel/dumpstack_64.c b/trunk/arch/x86/kernel/dumpstack_64.c index 19853ad8afc5..6d728d9284bd 100644 --- a/trunk/arch/x86/kernel/dumpstack_64.c +++ b/trunk/arch/x86/kernel/dumpstack_64.c @@ -284,16 +284,16 @@ void show_registers(struct pt_regs *regs) for (i = 0; i < code_len; i++, ip++) { if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { - printk(" Bad RIP value."); + printk(KERN_CONT " Bad RIP value."); break; } if (ip == (u8 *)regs->ip) - printk("<%02x> ", c); + printk(KERN_CONT "<%02x> ", c); else - printk("%02x ", c); + printk(KERN_CONT "%02x ", c); } } - printk("\n"); + printk(KERN_CONT "\n"); } int is_valid_bugaddr(unsigned long ip) diff --git a/trunk/arch/x86/kernel/entry_64.S b/trunk/arch/x86/kernel/entry_64.S index b62aa298df7f..faf8d5e74b0b 100644 --- a/trunk/arch/x86/kernel/entry_64.S +++ b/trunk/arch/x86/kernel/entry_64.S @@ -1475,213 +1475,61 @@ ENTRY(error_exit) CFI_ENDPROC END(error_exit) -/* - * Test if a given stack is an NMI stack or not. - */ - .macro test_in_nmi reg stack nmi_ret normal_ret - cmpq %\reg, \stack - ja \normal_ret - subq $EXCEPTION_STKSZ, %\reg - cmpq %\reg, \stack - jb \normal_ret - jmp \nmi_ret - .endm /* runs on exception stack */ ENTRY(nmi) INTR_FRAME PARAVIRT_ADJUST_EXCEPTION_FRAME - /* - * We allow breakpoints in NMIs. If a breakpoint occurs, then - * the iretq it performs will take us out of NMI context. - * This means that we can have nested NMIs where the next - * NMI is using the top of the stack of the previous NMI. We - * can't let it execute because the nested NMI will corrupt the - * stack of the previous NMI. NMI handlers are not re-entrant - * anyway. - * - * To handle this case we do the following: - * Check the a special location on the stack that contains - * a variable that is set when NMIs are executing. - * The interrupted task's stack is also checked to see if it - * is an NMI stack. - * If the variable is not set and the stack is not the NMI - * stack then: - * o Set the special variable on the stack - * o Copy the interrupt frame into a "saved" location on the stack - * o Copy the interrupt frame into a "copy" location on the stack - * o Continue processing the NMI - * If the variable is set or the previous stack is the NMI stack: - * o Modify the "copy" location to jump to the repeate_nmi - * o return back to the first NMI - * - * Now on exit of the first NMI, we first clear the stack variable - * The NMI stack will tell any nested NMIs at that point that it is - * nested. Then we pop the stack normally with iret, and if there was - * a nested NMI that updated the copy interrupt stack frame, a - * jump will be made to the repeat_nmi code that will handle the second - * NMI. - */ - - /* Use %rdx as out temp variable throughout */ - pushq_cfi %rdx - - /* - * Check the special variable on the stack to see if NMIs are - * executing. - */ - cmp $1, -8(%rsp) - je nested_nmi - - /* - * Now test if the previous stack was an NMI stack. - * We need the double check. We check the NMI stack to satisfy the - * race when the first NMI clears the variable before returning. - * We check the variable because the first NMI could be in a - * breakpoint routine using a breakpoint stack. - */ - lea 6*8(%rsp), %rdx - test_in_nmi rdx, 4*8(%rsp), nested_nmi, first_nmi - -nested_nmi: - /* - * Do nothing if we interrupted the fixup in repeat_nmi. - * It's about to repeat the NMI handler, so we are fine - * with ignoring this one. - */ - movq $repeat_nmi, %rdx - cmpq 8(%rsp), %rdx - ja 1f - movq $end_repeat_nmi, %rdx - cmpq 8(%rsp), %rdx - ja nested_nmi_out - -1: - /* Set up the interrupted NMIs stack to jump to repeat_nmi */ - leaq -6*8(%rsp), %rdx - movq %rdx, %rsp - CFI_ADJUST_CFA_OFFSET 6*8 - pushq_cfi $__KERNEL_DS - pushq_cfi %rdx - pushfq_cfi - pushq_cfi $__KERNEL_CS - pushq_cfi $repeat_nmi - - /* Put stack back */ - addq $(11*8), %rsp - CFI_ADJUST_CFA_OFFSET -11*8 - -nested_nmi_out: - popq_cfi %rdx - - /* No need to check faults here */ - INTERRUPT_RETURN - -first_nmi: - /* - * Because nested NMIs will use the pushed location that we - * stored in rdx, we must keep that space available. - * Here's what our stack frame will look like: - * +-------------------------+ - * | original SS | - * | original Return RSP | - * | original RFLAGS | - * | original CS | - * | original RIP | - * +-------------------------+ - * | temp storage for rdx | - * +-------------------------+ - * | NMI executing variable | - * +-------------------------+ - * | Saved SS | - * | Saved Return RSP | - * | Saved RFLAGS | - * | Saved CS | - * | Saved RIP | - * +-------------------------+ - * | copied SS | - * | copied Return RSP | - * | copied RFLAGS | - * | copied CS | - * | copied RIP | - * +-------------------------+ - * | pt_regs | - * +-------------------------+ - * - * The saved RIP is used to fix up the copied RIP that a nested - * NMI may zero out. The original stack frame and the temp storage - * is also used by nested NMIs and can not be trusted on exit. - */ - /* Set the NMI executing variable on the stack. */ - pushq_cfi $1 - - /* Copy the stack frame to the Saved frame */ - .rept 5 - pushq_cfi 6*8(%rsp) - .endr - - /* Make another copy, this one may be modified by nested NMIs */ - .rept 5 - pushq_cfi 4*8(%rsp) - .endr - - /* Do not pop rdx, nested NMIs will corrupt it */ - movq 11*8(%rsp), %rdx - - /* - * Everything below this point can be preempted by a nested - * NMI if the first NMI took an exception. Repeated NMIs - * caused by an exception and nested NMI will start here, and - * can still be preempted by another NMI. - */ -restart_nmi: - pushq_cfi $-1 /* ORIG_RAX: no syscall to restart */ + pushq_cfi $-1 subq $ORIG_RAX-R15, %rsp CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15 - /* - * Use save_paranoid to handle SWAPGS, but no need to use paranoid_exit - * as we should not be calling schedule in NMI context. - * Even with normal interrupts enabled. An NMI should not be - * setting NEED_RESCHED or anything that normal interrupts and - * exceptions might do. - */ call save_paranoid DEFAULT_FRAME 0 /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */ movq %rsp,%rdi movq $-1,%rsi call do_nmi +#ifdef CONFIG_TRACE_IRQFLAGS + /* paranoidexit; without TRACE_IRQS_OFF */ + /* ebx: no swapgs flag */ + DISABLE_INTERRUPTS(CLBR_NONE) testl %ebx,%ebx /* swapgs needed? */ jnz nmi_restore + testl $3,CS(%rsp) + jnz nmi_userspace nmi_swapgs: SWAPGS_UNSAFE_STACK nmi_restore: RESTORE_ALL 8 - /* Clear the NMI executing stack variable */ - movq $0, 10*8(%rsp) jmp irq_return +nmi_userspace: + GET_THREAD_INFO(%rcx) + movl TI_flags(%rcx),%ebx + andl $_TIF_WORK_MASK,%ebx + jz nmi_swapgs + movq %rsp,%rdi /* &pt_regs */ + call sync_regs + movq %rax,%rsp /* switch stack for scheduling */ + testl $_TIF_NEED_RESCHED,%ebx + jnz nmi_schedule + movl %ebx,%edx /* arg3: thread flags */ + ENABLE_INTERRUPTS(CLBR_NONE) + xorl %esi,%esi /* arg2: oldset */ + movq %rsp,%rdi /* arg1: &pt_regs */ + call do_notify_resume + DISABLE_INTERRUPTS(CLBR_NONE) + jmp nmi_userspace +nmi_schedule: + ENABLE_INTERRUPTS(CLBR_ANY) + call schedule + DISABLE_INTERRUPTS(CLBR_ANY) + jmp nmi_userspace CFI_ENDPROC -END(nmi) - - /* - * If an NMI hit an iret because of an exception or breakpoint, - * it can lose its NMI context, and a nested NMI may come in. - * In that case, the nested NMI will change the preempted NMI's - * stack to jump to here when it does the final iret. - */ -repeat_nmi: - INTR_FRAME - /* Update the stack variable to say we are still in NMI */ - movq $1, 5*8(%rsp) - - /* copy the saved stack back to copy stack */ - .rept 5 - pushq_cfi 4*8(%rsp) - .endr - - jmp restart_nmi +#else + jmp paranoid_exit CFI_ENDPROC -end_repeat_nmi: +#endif +END(nmi) ENTRY(ignore_sysret) CFI_STARTPROC diff --git a/trunk/arch/x86/kernel/head_64.S b/trunk/arch/x86/kernel/head_64.S index 40f4eb3766d1..e11e39478a49 100644 --- a/trunk/arch/x86/kernel/head_64.S +++ b/trunk/arch/x86/kernel/head_64.S @@ -417,10 +417,6 @@ ENTRY(phys_base) ENTRY(idt_table) .skip IDT_ENTRIES * 16 - .align L1_CACHE_BYTES -ENTRY(nmi_idt_table) - .skip IDT_ENTRIES * 16 - __PAGE_ALIGNED_BSS .align PAGE_SIZE ENTRY(empty_zero_page) diff --git a/trunk/arch/x86/kernel/jump_label.c b/trunk/arch/x86/kernel/jump_label.c index 2889b3d43882..ea9d5f2f13ef 100644 --- a/trunk/arch/x86/kernel/jump_label.c +++ b/trunk/arch/x86/kernel/jump_label.c @@ -50,7 +50,7 @@ void arch_jump_label_transform(struct jump_entry *entry, put_online_cpus(); } -__init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, +void arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type) { __jump_label_transform(entry, type, text_poke_early); diff --git a/trunk/arch/x86/kernel/nmi.c b/trunk/arch/x86/kernel/nmi.c index 47acaf319165..e88f37b58ddd 100644 --- a/trunk/arch/x86/kernel/nmi.c +++ b/trunk/arch/x86/kernel/nmi.c @@ -405,108 +405,9 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) unknown_nmi_error(reason, regs); } -/* - * NMIs can hit breakpoints which will cause it to lose its - * NMI context with the CPU when the breakpoint does an iret. - */ -#ifdef CONFIG_X86_32 -/* - * For i386, NMIs use the same stack as the kernel, and we can - * add a workaround to the iret problem in C. Simply have 3 states - * the NMI can be in. - * - * 1) not running - * 2) executing - * 3) latched - * - * When no NMI is in progress, it is in the "not running" state. - * When an NMI comes in, it goes into the "executing" state. - * Normally, if another NMI is triggered, it does not interrupt - * the running NMI and the HW will simply latch it so that when - * the first NMI finishes, it will restart the second NMI. - * (Note, the latch is binary, thus multiple NMIs triggering, - * when one is running, are ignored. Only one NMI is restarted.) - * - * If an NMI hits a breakpoint that executes an iret, another - * NMI can preempt it. We do not want to allow this new NMI - * to run, but we want to execute it when the first one finishes. - * We set the state to "latched", and the first NMI will perform - * an cmpxchg on the state, and if it doesn't successfully - * reset the state to "not running" it will restart the next - * NMI. - */ -enum nmi_states { - NMI_NOT_RUNNING, - NMI_EXECUTING, - NMI_LATCHED, -}; -static DEFINE_PER_CPU(enum nmi_states, nmi_state); - -#define nmi_nesting_preprocess(regs) \ - do { \ - if (__get_cpu_var(nmi_state) != NMI_NOT_RUNNING) { \ - __get_cpu_var(nmi_state) = NMI_LATCHED; \ - return; \ - } \ - nmi_restart: \ - __get_cpu_var(nmi_state) = NMI_EXECUTING; \ - } while (0) - -#define nmi_nesting_postprocess() \ - do { \ - if (cmpxchg(&__get_cpu_var(nmi_state), \ - NMI_EXECUTING, NMI_NOT_RUNNING) != NMI_EXECUTING) \ - goto nmi_restart; \ - } while (0) -#else /* x86_64 */ -/* - * In x86_64 things are a bit more difficult. This has the same problem - * where an NMI hitting a breakpoint that calls iret will remove the - * NMI context, allowing a nested NMI to enter. What makes this more - * difficult is that both NMIs and breakpoints have their own stack. - * When a new NMI or breakpoint is executed, the stack is set to a fixed - * point. If an NMI is nested, it will have its stack set at that same - * fixed address that the first NMI had, and will start corrupting the - * stack. This is handled in entry_64.S, but the same problem exists with - * the breakpoint stack. - * - * If a breakpoint is being processed, and the debug stack is being used, - * if an NMI comes in and also hits a breakpoint, the stack pointer - * will be set to the same fixed address as the breakpoint that was - * interrupted, causing that stack to be corrupted. To handle this case, - * check if the stack that was interrupted is the debug stack, and if - * so, change the IDT so that new breakpoints will use the current stack - * and not switch to the fixed address. On return of the NMI, switch back - * to the original IDT. - */ -static DEFINE_PER_CPU(int, update_debug_stack); - -static inline void nmi_nesting_preprocess(struct pt_regs *regs) -{ - /* - * If we interrupted a breakpoint, it is possible that - * the nmi handler will have breakpoints too. We need to - * change the IDT such that breakpoints that happen here - * continue to use the NMI stack. - */ - if (unlikely(is_debug_stack(regs->sp))) { - debug_stack_set_zero(); - __get_cpu_var(update_debug_stack) = 1; - } -} - -static inline void nmi_nesting_postprocess(void) -{ - if (unlikely(__get_cpu_var(update_debug_stack))) - debug_stack_reset(); -} -#endif - dotraplinkage notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code) { - nmi_nesting_preprocess(regs); - nmi_enter(); inc_irq_stat(__nmi_count); @@ -515,9 +416,6 @@ do_nmi(struct pt_regs *regs, long error_code) default_do_nmi(regs); nmi_exit(); - - /* On i386, may loop back to preprocess */ - nmi_nesting_postprocess(); } void stop_nmi(void) diff --git a/trunk/arch/x86/kernel/traps.c b/trunk/arch/x86/kernel/traps.c index 0072b38e3ea1..a8e3eb83466c 100644 --- a/trunk/arch/x86/kernel/traps.c +++ b/trunk/arch/x86/kernel/traps.c @@ -316,15 +316,9 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) return; #endif - /* - * Let others (NMI) know that the debug stack is in use - * as we may switch to the interrupt stack. - */ - debug_stack_usage_inc(); preempt_conditional_sti(regs); do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); preempt_conditional_cli(regs); - debug_stack_usage_dec(); } #ifdef CONFIG_X86_64 @@ -417,12 +411,6 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) SIGTRAP) == NOTIFY_STOP) return; - /* - * Let others (NMI) know that the debug stack is in use - * as we may switch to the interrupt stack. - */ - debug_stack_usage_inc(); - /* It's safe to allow irq's after DR6 has been saved */ preempt_conditional_sti(regs); @@ -430,7 +418,6 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); preempt_conditional_cli(regs); - debug_stack_usage_dec(); return; } @@ -450,7 +437,6 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) if (tsk->thread.debugreg6 & (DR_STEP | DR_TRAP_BITS) || user_icebp) send_sigtrap(tsk, regs, error_code, si_code); preempt_conditional_cli(regs); - debug_stack_usage_dec(); return; } @@ -737,10 +723,4 @@ void __init trap_init(void) cpu_init(); x86_init.irqs.trap_init(); - -#ifdef CONFIG_X86_64 - memcpy(&nmi_idt_table, &idt_table, IDT_ENTRIES * 16); - set_nmi_gate(1, &debug); - set_nmi_gate(3, &int3); -#endif } diff --git a/trunk/arch/x86/kvm/i8254.c b/trunk/arch/x86/kvm/i8254.c index 76e3f1cd0369..405f2620392f 100644 --- a/trunk/arch/x86/kvm/i8254.c +++ b/trunk/arch/x86/kvm/i8254.c @@ -338,11 +338,15 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) return HRTIMER_NORESTART; } -static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) +static void create_pit_timer(struct kvm *kvm, u32 val, int is_period) { + struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state; struct kvm_timer *pt = &ps->pit_timer; s64 interval; + if (!irqchip_in_kernel(kvm)) + return; + interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); pr_debug("create pit timer, interval is %llu nsec\n", interval); @@ -394,13 +398,13 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val) /* FIXME: enhance mode 4 precision */ case 4: if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)) { - create_pit_timer(ps, val, 0); + create_pit_timer(kvm, val, 0); } break; case 2: case 3: if (!(ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)){ - create_pit_timer(ps, val, 1); + create_pit_timer(kvm, val, 1); } break; default: diff --git a/trunk/arch/x86/kvm/x86.c b/trunk/arch/x86/kvm/x86.c index c38efd7b792e..4c938da2ba00 100644 --- a/trunk/arch/x86/kvm/x86.c +++ b/trunk/arch/x86/kvm/x86.c @@ -602,7 +602,6 @@ static void update_cpuid(struct kvm_vcpu *vcpu) { struct kvm_cpuid_entry2 *best; struct kvm_lapic *apic = vcpu->arch.apic; - u32 timer_mode_mask; best = kvm_find_cpuid_entry(vcpu, 1, 0); if (!best) @@ -615,15 +614,12 @@ static void update_cpuid(struct kvm_vcpu *vcpu) best->ecx |= bit(X86_FEATURE_OSXSAVE); } - if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && - best->function == 0x1) { - best->ecx |= bit(X86_FEATURE_TSC_DEADLINE_TIMER); - timer_mode_mask = 3 << 17; - } else - timer_mode_mask = 1 << 17; - - if (apic) - apic->lapic_timer.timer_mode_mask = timer_mode_mask; + if (apic) { + if (best->ecx & bit(X86_FEATURE_TSC_DEADLINE_TIMER)) + apic->lapic_timer.timer_mode_mask = 3 << 17; + else + apic->lapic_timer.timer_mode_mask = 1 << 17; + } } int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) @@ -2135,6 +2131,9 @@ int kvm_dev_ioctl_check_extension(long ext) case KVM_CAP_TSC_CONTROL: r = kvm_has_tsc_control; break; + case KVM_CAP_TSC_DEADLINE_TIMER: + r = boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER); + break; default: r = 0; break; diff --git a/trunk/arch/x86/lib/inat.c b/trunk/arch/x86/lib/inat.c index 88ad5fbda6e1..46fc4ee09fc4 100644 --- a/trunk/arch/x86/lib/inat.c +++ b/trunk/arch/x86/lib/inat.c @@ -82,16 +82,9 @@ insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, const insn_attr_t *table; if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) return 0; - /* At first, this checks the master table */ - table = inat_avx_tables[vex_m][0]; + table = inat_avx_tables[vex_m][vex_p]; if (!table) return 0; - if (!inat_is_group(table[opcode]) && vex_p) { - /* If this is not a group, get attribute directly */ - table = inat_avx_tables[vex_m][vex_p]; - if (!table) - return 0; - } return table[opcode]; } diff --git a/trunk/arch/x86/lib/insn.c b/trunk/arch/x86/lib/insn.c index 5a1f9f3e3fbb..374562ed6704 100644 --- a/trunk/arch/x86/lib/insn.c +++ b/trunk/arch/x86/lib/insn.c @@ -202,7 +202,7 @@ void insn_get_opcode(struct insn *insn) m = insn_vex_m_bits(insn); p = insn_vex_p_bits(insn); insn->attr = inat_get_avx_attribute(op, m, p); - if (!inat_accept_vex(insn->attr) && !inat_is_group(insn->attr)) + if (!inat_accept_vex(insn->attr)) insn->attr = 0; /* This instruction is bad */ goto end; /* VEX has only 1 byte for opcode */ } @@ -249,8 +249,6 @@ void insn_get_modrm(struct insn *insn) pfx = insn_last_prefix(insn); insn->attr = inat_get_group_attribute(mod, pfx, insn->attr); - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) - insn->attr = 0; /* This is bad */ } } diff --git a/trunk/arch/x86/lib/x86-opcode-map.txt b/trunk/arch/x86/lib/x86-opcode-map.txt index 5b83c51c12e0..a793da5e560e 100644 --- a/trunk/arch/x86/lib/x86-opcode-map.txt +++ b/trunk/arch/x86/lib/x86-opcode-map.txt @@ -1,11 +1,5 @@ # x86 Opcode Maps # -# This is (mostly) based on following documentations. -# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2 -# (#325383-040US, October 2011) -# - Intel(R) Advanced Vector Extensions Programming Reference -# (#319433-011,JUNE 2011). -# # # Table: table-name # Referrer: escaped-name @@ -21,13 +15,10 @@ # EndTable # # AVX Superscripts -# (v): this opcode requires VEX prefix. -# (v1): this opcode only supports 128bit VEX. -# -# Last Prefix Superscripts -# - (66): the last prefix is 0x66 -# - (F3): the last prefix is 0xF3 -# - (F2): the last prefix is 0xF2 +# (VEX): this opcode can accept VEX prefix. +# (oVEX): this opcode requires VEX prefix. +# (o128): this opcode only supports 128bit VEX. +# (o256): this opcode only supports 256bit VEX. # Table: one byte opcode @@ -208,8 +199,8 @@ a0: MOV AL,Ob a1: MOV rAX,Ov a2: MOV Ob,AL a3: MOV Ov,rAX -a4: MOVS/B Yb,Xb -a5: MOVS/W/D/Q Yv,Xv +a4: MOVS/B Xb,Yb +a5: MOVS/W/D/Q Xv,Yv a6: CMPS/B Xb,Yb a7: CMPS/W/D Xv,Yv a8: TEST AL,Ib @@ -242,8 +233,8 @@ c0: Grp2 Eb,Ib (1A) c1: Grp2 Ev,Ib (1A) c2: RETN Iw (f64) c3: RETN -c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) -c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) +c4: LES Gz,Mp (i64) | 3bytes-VEX (Prefix) +c5: LDS Gz,Mp (i64) | 2bytes-VEX (Prefix) c6: Grp11 Eb,Ib (1A) c7: Grp11 Ev,Iz (1A) c8: ENTER Iw,Ib @@ -329,19 +320,14 @@ AVXcode: 1 # 3DNow! uses the last imm byte as opcode extension. 0f: 3DNow! Pq,Qq,Ib # 0x0f 0x10-0x1f -# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands -# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. -# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. -# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming -# Reference A.1 -10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) -11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) -12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2) -13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) -14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) -15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) -16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) -17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) +10: movups Vps,Wps (VEX) | movss Vss,Wss (F3),(VEX),(o128) | movupd Vpd,Wpd (66),(VEX) | movsd Vsd,Wsd (F2),(VEX),(o128) +11: movups Wps,Vps (VEX) | movss Wss,Vss (F3),(VEX),(o128) | movupd Wpd,Vpd (66),(VEX) | movsd Wsd,Vsd (F2),(VEX),(o128) +12: movlps Vq,Mq (VEX),(o128) | movlpd Vq,Mq (66),(VEX),(o128) | movhlps Vq,Uq (VEX),(o128) | movddup Vq,Wq (F2),(VEX) | movsldup Vq,Wq (F3),(VEX) +13: mpvlps Mq,Vq (VEX),(o128) | movlpd Mq,Vq (66),(VEX),(o128) +14: unpcklps Vps,Wq (VEX) | unpcklpd Vpd,Wq (66),(VEX) +15: unpckhps Vps,Wq (VEX) | unpckhpd Vpd,Wq (66),(VEX) +16: movhps Vq,Mq (VEX),(o128) | movhpd Vq,Mq (66),(VEX),(o128) | movlsps Vq,Uq (VEX),(o128) | movshdup Vq,Wq (F3),(VEX) +17: movhps Mq,Vq (VEX),(o128) | movhpd Mq,Vq (66),(VEX),(o128) 18: Grp16 (1A) 19: 1a: @@ -359,14 +345,14 @@ AVXcode: 1 25: 26: 27: -28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) -29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) -2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) -2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) -2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) -2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) -2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) -2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) +28: movaps Vps,Wps (VEX) | movapd Vpd,Wpd (66),(VEX) +29: movaps Wps,Vps (VEX) | movapd Wpd,Vpd (66),(VEX) +2a: cvtpi2ps Vps,Qpi | cvtsi2ss Vss,Ed/q (F3),(VEX),(o128) | cvtpi2pd Vpd,Qpi (66) | cvtsi2sd Vsd,Ed/q (F2),(VEX),(o128) +2b: movntps Mps,Vps (VEX) | movntpd Mpd,Vpd (66),(VEX) +2c: cvttps2pi Ppi,Wps | cvttss2si Gd/q,Wss (F3),(VEX),(o128) | cvttpd2pi Ppi,Wpd (66) | cvttsd2si Gd/q,Wsd (F2),(VEX),(o128) +2d: cvtps2pi Ppi,Wps | cvtss2si Gd/q,Wss (F3),(VEX),(o128) | cvtpd2pi Qpi,Wpd (66) | cvtsd2si Gd/q,Wsd (F2),(VEX),(o128) +2e: ucomiss Vss,Wss (VEX),(o128) | ucomisd Vsd,Wsd (66),(VEX),(o128) +2f: comiss Vss,Wss (VEX),(o128) | comisd Vsd,Wsd (66),(VEX),(o128) # 0x0f 0x30-0x3f 30: WRMSR 31: RDTSC @@ -402,66 +388,65 @@ AVXcode: 1 4e: CMOVLE/NG Gv,Ev 4f: CMOVNLE/G Gv,Ev # 0x0f 0x50-0x5f -50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) -51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) -52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) -53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) -54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) -55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) -56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) -57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) -58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) -59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) -5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) -5b: vcvtdq2ps Vps,Wdq | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) -5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) -5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) -5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) -5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) +50: movmskps Gd/q,Ups (VEX) | movmskpd Gd/q,Upd (66),(VEX) +51: sqrtps Vps,Wps (VEX) | sqrtss Vss,Wss (F3),(VEX),(o128) | sqrtpd Vpd,Wpd (66),(VEX) | sqrtsd Vsd,Wsd (F2),(VEX),(o128) +52: rsqrtps Vps,Wps (VEX) | rsqrtss Vss,Wss (F3),(VEX),(o128) +53: rcpps Vps,Wps (VEX) | rcpss Vss,Wss (F3),(VEX),(o128) +54: andps Vps,Wps (VEX) | andpd Vpd,Wpd (66),(VEX) +55: andnps Vps,Wps (VEX) | andnpd Vpd,Wpd (66),(VEX) +56: orps Vps,Wps (VEX) | orpd Vpd,Wpd (66),(VEX) +57: xorps Vps,Wps (VEX) | xorpd Vpd,Wpd (66),(VEX) +58: addps Vps,Wps (VEX) | addss Vss,Wss (F3),(VEX),(o128) | addpd Vpd,Wpd (66),(VEX) | addsd Vsd,Wsd (F2),(VEX),(o128) +59: mulps Vps,Wps (VEX) | mulss Vss,Wss (F3),(VEX),(o128) | mulpd Vpd,Wpd (66),(VEX) | mulsd Vsd,Wsd (F2),(VEX),(o128) +5a: cvtps2pd Vpd,Wps (VEX) | cvtss2sd Vsd,Wss (F3),(VEX),(o128) | cvtpd2ps Vps,Wpd (66),(VEX) | cvtsd2ss Vsd,Wsd (F2),(VEX),(o128) +5b: cvtdq2ps Vps,Wdq (VEX) | cvtps2dq Vdq,Wps (66),(VEX) | cvttps2dq Vdq,Wps (F3),(VEX) +5c: subps Vps,Wps (VEX) | subss Vss,Wss (F3),(VEX),(o128) | subpd Vpd,Wpd (66),(VEX) | subsd Vsd,Wsd (F2),(VEX),(o128) +5d: minps Vps,Wps (VEX) | minss Vss,Wss (F3),(VEX),(o128) | minpd Vpd,Wpd (66),(VEX) | minsd Vsd,Wsd (F2),(VEX),(o128) +5e: divps Vps,Wps (VEX) | divss Vss,Wss (F3),(VEX),(o128) | divpd Vpd,Wpd (66),(VEX) | divsd Vsd,Wsd (F2),(VEX),(o128) +5f: maxps Vps,Wps (VEX) | maxss Vss,Wss (F3),(VEX),(o128) | maxpd Vpd,Wpd (66),(VEX) | maxsd Vsd,Wsd (F2),(VEX),(o128) # 0x0f 0x60-0x6f -60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) -61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) -62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) -63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) -64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) -65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) -66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) -67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) -68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) -69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) -6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) -6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) -6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) -6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) -6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) -6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqu Vx,Wx (F3) +60: punpcklbw Pq,Qd | punpcklbw Vdq,Wdq (66),(VEX),(o128) +61: punpcklwd Pq,Qd | punpcklwd Vdq,Wdq (66),(VEX),(o128) +62: punpckldq Pq,Qd | punpckldq Vdq,Wdq (66),(VEX),(o128) +63: packsswb Pq,Qq | packsswb Vdq,Wdq (66),(VEX),(o128) +64: pcmpgtb Pq,Qq | pcmpgtb Vdq,Wdq (66),(VEX),(o128) +65: pcmpgtw Pq,Qq | pcmpgtw Vdq,Wdq (66),(VEX),(o128) +66: pcmpgtd Pq,Qq | pcmpgtd Vdq,Wdq (66),(VEX),(o128) +67: packuswb Pq,Qq | packuswb Vdq,Wdq (66),(VEX),(o128) +68: punpckhbw Pq,Qd | punpckhbw Vdq,Wdq (66),(VEX),(o128) +69: punpckhwd Pq,Qd | punpckhwd Vdq,Wdq (66),(VEX),(o128) +6a: punpckhdq Pq,Qd | punpckhdq Vdq,Wdq (66),(VEX),(o128) +6b: packssdw Pq,Qd | packssdw Vdq,Wdq (66),(VEX),(o128) +6c: punpcklqdq Vdq,Wdq (66),(VEX),(o128) +6d: punpckhqdq Vdq,Wdq (66),(VEX),(o128) +6e: movd/q/ Pd,Ed/q | movd/q Vdq,Ed/q (66),(VEX),(o128) +6f: movq Pq,Qq | movdqa Vdq,Wdq (66),(VEX) | movdqu Vdq,Wdq (F3),(VEX) # 0x0f 0x70-0x7f -70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) +70: pshufw Pq,Qq,Ib | pshufd Vdq,Wdq,Ib (66),(VEX),(o128) | pshufhw Vdq,Wdq,Ib (F3),(VEX),(o128) | pshuflw VdqWdq,Ib (F2),(VEX),(o128) 71: Grp12 (1A) 72: Grp13 (1A) 73: Grp14 (1A) -74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) -75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) -76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) -# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. -77: emms | vzeroupper | vzeroall -78: VMREAD Ey,Gy -79: VMWRITE Gy,Ey +74: pcmpeqb Pq,Qq | pcmpeqb Vdq,Wdq (66),(VEX),(o128) +75: pcmpeqw Pq,Qq | pcmpeqw Vdq,Wdq (66),(VEX),(o128) +76: pcmpeqd Pq,Qq | pcmpeqd Vdq,Wdq (66),(VEX),(o128) +77: emms/vzeroupper/vzeroall (VEX) +78: VMREAD Ed/q,Gd/q +79: VMWRITE Gd/q,Ed/q 7a: 7b: -7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) -7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) -7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) -7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqu Wx,Vx (F3) +7c: haddps Vps,Wps (F2),(VEX) | haddpd Vpd,Wpd (66),(VEX) +7d: hsubps Vps,Wps (F2),(VEX) | hsubpd Vpd,Wpd (66),(VEX) +7e: movd/q Ed/q,Pd | movd/q Ed/q,Vdq (66),(VEX),(o128) | movq Vq,Wq (F3),(VEX),(o128) +7f: movq Qq,Pq | movdqa Wdq,Vdq (66),(VEX) | movdqu Wdq,Vdq (F3),(VEX) # 0x0f 0x80-0x8f 80: JO Jz (f64) 81: JNO Jz (f64) -82: JB/JC/JNAE Jz (f64) -83: JAE/JNB/JNC Jz (f64) -84: JE/JZ Jz (f64) -85: JNE/JNZ Jz (f64) +82: JB/JNAE/JC Jz (f64) +83: JNB/JAE/JNC Jz (f64) +84: JZ/JE Jz (f64) +85: JNZ/JNE Jz (f64) 86: JBE/JNA Jz (f64) -87: JA/JNBE Jz (f64) +87: JNBE/JA Jz (f64) 88: JS Jz (f64) 89: JNS Jz (f64) 8a: JP/JPE Jz (f64) @@ -517,18 +502,18 @@ b8: JMPE | POPCNT Gv,Ev (F3) b9: Grp10 (1A) ba: Grp8 Ev,Ib (1A) bb: BTC Ev,Gv -bc: BSF Gv,Ev | TZCNT Gv,Ev (F3) -bd: BSR Gv,Ev | LZCNT Gv,Ev (F3) +bc: BSF Gv,Ev +bd: BSR Gv,Ev be: MOVSX Gv,Eb bf: MOVSX Gv,Ew # 0x0f 0xc0-0xcf c0: XADD Eb,Gb c1: XADD Ev,Gv -c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1) -c3: movnti My,Gy -c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) -c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) -c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) +c2: cmpps Vps,Wps,Ib (VEX) | cmpss Vss,Wss,Ib (F3),(VEX),(o128) | cmppd Vpd,Wpd,Ib (66),(VEX) | cmpsd Vsd,Wsd,Ib (F2),(VEX) +c3: movnti Md/q,Gd/q +c4: pinsrw Pq,Rd/q/Mw,Ib | pinsrw Vdq,Rd/q/Mw,Ib (66),(VEX),(o128) +c5: pextrw Gd,Nq,Ib | pextrw Gd,Udq,Ib (66),(VEX),(o128) +c6: shufps Vps,Wps,Ib (VEX) | shufpd Vpd,Wpd,Ib (66),(VEX) c7: Grp9 (1A) c8: BSWAP RAX/EAX/R8/R8D c9: BSWAP RCX/ECX/R9/R9D @@ -539,55 +524,55 @@ cd: BSWAP RBP/EBP/R13/R13D ce: BSWAP RSI/ESI/R14/R14D cf: BSWAP RDI/EDI/R15/R15D # 0x0f 0xd0-0xdf -d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) -d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) -d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) -d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) -d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) -d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) -d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) -d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) -d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) -d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) -da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) -db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) -dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) -dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) -de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) -df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) +d0: addsubps Vps,Wps (F2),(VEX) | addsubpd Vpd,Wpd (66),(VEX) +d1: psrlw Pq,Qq | psrlw Vdq,Wdq (66),(VEX),(o128) +d2: psrld Pq,Qq | psrld Vdq,Wdq (66),(VEX),(o128) +d3: psrlq Pq,Qq | psrlq Vdq,Wdq (66),(VEX),(o128) +d4: paddq Pq,Qq | paddq Vdq,Wdq (66),(VEX),(o128) +d5: pmullw Pq,Qq | pmullw Vdq,Wdq (66),(VEX),(o128) +d6: movq Wq,Vq (66),(VEX),(o128) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) +d7: pmovmskb Gd,Nq | pmovmskb Gd,Udq (66),(VEX),(o128) +d8: psubusb Pq,Qq | psubusb Vdq,Wdq (66),(VEX),(o128) +d9: psubusw Pq,Qq | psubusw Vdq,Wdq (66),(VEX),(o128) +da: pminub Pq,Qq | pminub Vdq,Wdq (66),(VEX),(o128) +db: pand Pq,Qq | pand Vdq,Wdq (66),(VEX),(o128) +dc: paddusb Pq,Qq | paddusb Vdq,Wdq (66),(VEX),(o128) +dd: paddusw Pq,Qq | paddusw Vdq,Wdq (66),(VEX),(o128) +de: pmaxub Pq,Qq | pmaxub Vdq,Wdq (66),(VEX),(o128) +df: pandn Pq,Qq | pandn Vdq,Wdq (66),(VEX),(o128) # 0x0f 0xe0-0xef -e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) -e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) -e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) -e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) -e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) -e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) -e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtpd2dq Vx,Wpd (F2) -e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) -e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) -e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) -ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) -eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) -ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) -ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) -ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) -ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) +e0: pavgb Pq,Qq | pavgb Vdq,Wdq (66),(VEX),(o128) +e1: psraw Pq,Qq | psraw Vdq,Wdq (66),(VEX),(o128) +e2: psrad Pq,Qq | psrad Vdq,Wdq (66),(VEX),(o128) +e3: pavgw Pq,Qq | pavgw Vdq,Wdq (66),(VEX),(o128) +e4: pmulhuw Pq,Qq | pmulhuw Vdq,Wdq (66),(VEX),(o128) +e5: pmulhw Pq,Qq | pmulhw Vdq,Wdq (66),(VEX),(o128) +e6: cvtpd2dq Vdq,Wpd (F2),(VEX) | cvttpd2dq Vdq,Wpd (66),(VEX) | cvtdq2pd Vpd,Wdq (F3),(VEX) +e7: movntq Mq,Pq | movntdq Mdq,Vdq (66),(VEX) +e8: psubsb Pq,Qq | psubsb Vdq,Wdq (66),(VEX),(o128) +e9: psubsw Pq,Qq | psubsw Vdq,Wdq (66),(VEX),(o128) +ea: pminsw Pq,Qq | pminsw Vdq,Wdq (66),(VEX),(o128) +eb: por Pq,Qq | por Vdq,Wdq (66),(VEX),(o128) +ec: paddsb Pq,Qq | paddsb Vdq,Wdq (66),(VEX),(o128) +ed: paddsw Pq,Qq | paddsw Vdq,Wdq (66),(VEX),(o128) +ee: pmaxsw Pq,Qq | pmaxsw Vdq,Wdq (66),(VEX),(o128) +ef: pxor Pq,Qq | pxor Vdq,Wdq (66),(VEX),(o128) # 0x0f 0xf0-0xff -f0: vlddqu Vx,Mx (F2) -f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) -f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) -f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) -f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) -f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) -f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) -f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) -f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) -f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) -fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) -fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) -fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) -fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) -fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) +f0: lddqu Vdq,Mdq (F2),(VEX) +f1: psllw Pq,Qq | psllw Vdq,Wdq (66),(VEX),(o128) +f2: pslld Pq,Qq | pslld Vdq,Wdq (66),(VEX),(o128) +f3: psllq Pq,Qq | psllq Vdq,Wdq (66),(VEX),(o128) +f4: pmuludq Pq,Qq | pmuludq Vdq,Wdq (66),(VEX),(o128) +f5: pmaddwd Pq,Qq | pmaddwd Vdq,Wdq (66),(VEX),(o128) +f6: psadbw Pq,Qq | psadbw Vdq,Wdq (66),(VEX),(o128) +f7: maskmovq Pq,Nq | maskmovdqu Vdq,Udq (66),(VEX),(o128) +f8: psubb Pq,Qq | psubb Vdq,Wdq (66),(VEX),(o128) +f9: psubw Pq,Qq | psubw Vdq,Wdq (66),(VEX),(o128) +fa: psubd Pq,Qq | psubd Vdq,Wdq (66),(VEX),(o128) +fb: psubq Pq,Qq | psubq Vdq,Wdq (66),(VEX),(o128) +fc: paddb Pq,Qq | paddb Vdq,Wdq (66),(VEX),(o128) +fd: paddw Pq,Qq | paddw Vdq,Wdq (66),(VEX),(o128) +fe: paddd Pq,Qq | paddd Vdq,Wdq (66),(VEX),(o128) ff: EndTable @@ -595,193 +580,155 @@ Table: 3-byte opcode 1 (0x0f 0x38) Referrer: 3-byte escape 1 AVXcode: 2 # 0x0f 0x38 0x00-0x0f -00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) -01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) -02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) -03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) -04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) -05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) -06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) -07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) -08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) -09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) -0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) -0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) -0c: vpermilps Vx,Hx,Wx (66),(v) -0d: vpermilpd Vx,Hx,Wx (66),(v) -0e: vtestps Vx,Wx (66),(v) -0f: vtestpd Vx,Wx (66),(v) +00: pshufb Pq,Qq | pshufb Vdq,Wdq (66),(VEX),(o128) +01: phaddw Pq,Qq | phaddw Vdq,Wdq (66),(VEX),(o128) +02: phaddd Pq,Qq | phaddd Vdq,Wdq (66),(VEX),(o128) +03: phaddsw Pq,Qq | phaddsw Vdq,Wdq (66),(VEX),(o128) +04: pmaddubsw Pq,Qq | pmaddubsw Vdq,Wdq (66),(VEX),(o128) +05: phsubw Pq,Qq | phsubw Vdq,Wdq (66),(VEX),(o128) +06: phsubd Pq,Qq | phsubd Vdq,Wdq (66),(VEX),(o128) +07: phsubsw Pq,Qq | phsubsw Vdq,Wdq (66),(VEX),(o128) +08: psignb Pq,Qq | psignb Vdq,Wdq (66),(VEX),(o128) +09: psignw Pq,Qq | psignw Vdq,Wdq (66),(VEX),(o128) +0a: psignd Pq,Qq | psignd Vdq,Wdq (66),(VEX),(o128) +0b: pmulhrsw Pq,Qq | pmulhrsw Vdq,Wdq (66),(VEX),(o128) +0c: Vpermilps /r (66),(oVEX) +0d: Vpermilpd /r (66),(oVEX) +0e: vtestps /r (66),(oVEX) +0f: vtestpd /r (66),(oVEX) # 0x0f 0x38 0x10-0x1f 10: pblendvb Vdq,Wdq (66) 11: 12: -13: vcvtph2ps Vx,Wx,Ib (66),(v) +13: 14: blendvps Vdq,Wdq (66) 15: blendvpd Vdq,Wdq (66) -16: vpermps Vqq,Hqq,Wqq (66),(v) -17: vptest Vx,Wx (66) -18: vbroadcastss Vx,Wd (66),(v) -19: vbroadcastsd Vqq,Wq (66),(v) -1a: vbroadcastf128 Vqq,Mdq (66),(v) +16: +17: ptest Vdq,Wdq (66),(VEX) +18: vbroadcastss /r (66),(oVEX) +19: vbroadcastsd /r (66),(oVEX),(o256) +1a: vbroadcastf128 /r (66),(oVEX),(o256) 1b: -1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) -1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) -1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) +1c: pabsb Pq,Qq | pabsb Vdq,Wdq (66),(VEX),(o128) +1d: pabsw Pq,Qq | pabsw Vdq,Wdq (66),(VEX),(o128) +1e: pabsd Pq,Qq | pabsd Vdq,Wdq (66),(VEX),(o128) 1f: # 0x0f 0x38 0x20-0x2f -20: vpmovsxbw Vx,Ux/Mq (66),(v1) -21: vpmovsxbd Vx,Ux/Md (66),(v1) -22: vpmovsxbq Vx,Ux/Mw (66),(v1) -23: vpmovsxwd Vx,Ux/Mq (66),(v1) -24: vpmovsxwq Vx,Ux/Md (66),(v1) -25: vpmovsxdq Vx,Ux/Mq (66),(v1) +20: pmovsxbw Vdq,Udq/Mq (66),(VEX),(o128) +21: pmovsxbd Vdq,Udq/Md (66),(VEX),(o128) +22: pmovsxbq Vdq,Udq/Mw (66),(VEX),(o128) +23: pmovsxwd Vdq,Udq/Mq (66),(VEX),(o128) +24: pmovsxwq Vdq,Udq/Md (66),(VEX),(o128) +25: pmovsxdq Vdq,Udq/Mq (66),(VEX),(o128) 26: 27: -28: vpmuldq Vx,Hx,Wx (66),(v1) -29: vpcmpeqq Vx,Hx,Wx (66),(v1) -2a: vmovntdqa Vx,Mx (66),(v1) -2b: vpackusdw Vx,Hx,Wx (66),(v1) -2c: vmaskmovps Vx,Hx,Mx (66),(v) -2d: vmaskmovpd Vx,Hx,Mx (66),(v) -2e: vmaskmovps Mx,Hx,Vx (66),(v) -2f: vmaskmovpd Mx,Hx,Vx (66),(v) +28: pmuldq Vdq,Wdq (66),(VEX),(o128) +29: pcmpeqq Vdq,Wdq (66),(VEX),(o128) +2a: movntdqa Vdq,Mdq (66),(VEX),(o128) +2b: packusdw Vdq,Wdq (66),(VEX),(o128) +2c: vmaskmovps(ld) /r (66),(oVEX) +2d: vmaskmovpd(ld) /r (66),(oVEX) +2e: vmaskmovps(st) /r (66),(oVEX) +2f: vmaskmovpd(st) /r (66),(oVEX) # 0x0f 0x38 0x30-0x3f -30: vpmovzxbw Vx,Ux/Mq (66),(v1) -31: vpmovzxbd Vx,Ux/Md (66),(v1) -32: vpmovzxbq Vx,Ux/Mw (66),(v1) -33: vpmovzxwd Vx,Ux/Mq (66),(v1) -34: vpmovzxwq Vx,Ux/Md (66),(v1) -35: vpmovzxdq Vx,Ux/Mq (66),(v1) -36: vpermd Vqq,Hqq,Wqq (66),(v) -37: vpcmpgtq Vx,Hx,Wx (66),(v1) -38: vpminsb Vx,Hx,Wx (66),(v1) -39: vpminsd Vx,Hx,Wx (66),(v1) -3a: vpminuw Vx,Hx,Wx (66),(v1) -3b: vpminud Vx,Hx,Wx (66),(v1) -3c: vpmaxsb Vx,Hx,Wx (66),(v1) -3d: vpmaxsd Vx,Hx,Wx (66),(v1) -3e: vpmaxuw Vx,Hx,Wx (66),(v1) -3f: vpmaxud Vx,Hx,Wx (66),(v1) +30: pmovzxbw Vdq,Udq/Mq (66),(VEX),(o128) +31: pmovzxbd Vdq,Udq/Md (66),(VEX),(o128) +32: pmovzxbq Vdq,Udq/Mw (66),(VEX),(o128) +33: pmovzxwd Vdq,Udq/Mq (66),(VEX),(o128) +34: pmovzxwq Vdq,Udq/Md (66),(VEX),(o128) +35: pmovzxdq Vdq,Udq/Mq (66),(VEX),(o128) +36: +37: pcmpgtq Vdq,Wdq (66),(VEX),(o128) +38: pminsb Vdq,Wdq (66),(VEX),(o128) +39: pminsd Vdq,Wdq (66),(VEX),(o128) +3a: pminuw Vdq,Wdq (66),(VEX),(o128) +3b: pminud Vdq,Wdq (66),(VEX),(o128) +3c: pmaxsb Vdq,Wdq (66),(VEX),(o128) +3d: pmaxsd Vdq,Wdq (66),(VEX),(o128) +3e: pmaxuw Vdq,Wdq (66),(VEX),(o128) +3f: pmaxud Vdq,Wdq (66),(VEX),(o128) # 0x0f 0x38 0x40-0x8f -40: vpmulld Vx,Hx,Wx (66),(v1) -41: vphminposuw Vdq,Wdq (66),(v1) -42: -43: -44: -45: vpsrlvd/q Vx,Hx,Wx (66),(v) -46: vpsravd Vx,Hx,Wx (66),(v) -47: vpsllvd/q Vx,Hx,Wx (66),(v) -# Skip 0x48-0x57 -58: vpbroadcastd Vx,Wx (66),(v) -59: vpbroadcastq Vx,Wx (66),(v) -5a: vbroadcasti128 Vqq,Mdq (66),(v) -# Skip 0x5b-0x77 -78: vpbroadcastb Vx,Wx (66),(v) -79: vpbroadcastw Vx,Wx (66),(v) -# Skip 0x7a-0x7f -80: INVEPT Gy,Mdq (66) -81: INVPID Gy,Mdq (66) -82: INVPCID Gy,Mdq (66) -8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) -8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) +40: pmulld Vdq,Wdq (66),(VEX),(o128) +41: phminposuw Vdq,Wdq (66),(VEX),(o128) +80: INVEPT Gd/q,Mdq (66) +81: INVPID Gd/q,Mdq (66) # 0x0f 0x38 0x90-0xbf (FMA) -90: vgatherdd/q Vx,Hx,Wx (66),(v) -91: vgatherqd/q Vx,Hx,Wx (66),(v) -92: vgatherdps/d Vx,Hx,Wx (66),(v) -93: vgatherqps/d Vx,Hx,Wx (66),(v) -94: -95: -96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) -97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) -98: vfmadd132ps/d Vx,Hx,Wx (66),(v) -99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) -9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) -9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) -9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) -a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) -a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) -a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) -ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) -ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) -af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) -b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) -b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) -b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) -bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) -bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) -bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) -bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) +96: vfmaddsub132pd/ps /r (66),(VEX) +97: vfmsubadd132pd/ps /r (66),(VEX) +98: vfmadd132pd/ps /r (66),(VEX) +99: vfmadd132sd/ss /r (66),(VEX),(o128) +9a: vfmsub132pd/ps /r (66),(VEX) +9b: vfmsub132sd/ss /r (66),(VEX),(o128) +9c: vfnmadd132pd/ps /r (66),(VEX) +9d: vfnmadd132sd/ss /r (66),(VEX),(o128) +9e: vfnmsub132pd/ps /r (66),(VEX) +9f: vfnmsub132sd/ss /r (66),(VEX),(o128) +a6: vfmaddsub213pd/ps /r (66),(VEX) +a7: vfmsubadd213pd/ps /r (66),(VEX) +a8: vfmadd213pd/ps /r (66),(VEX) +a9: vfmadd213sd/ss /r (66),(VEX),(o128) +aa: vfmsub213pd/ps /r (66),(VEX) +ab: vfmsub213sd/ss /r (66),(VEX),(o128) +ac: vfnmadd213pd/ps /r (66),(VEX) +ad: vfnmadd213sd/ss /r (66),(VEX),(o128) +ae: vfnmsub213pd/ps /r (66),(VEX) +af: vfnmsub213sd/ss /r (66),(VEX),(o128) +b6: vfmaddsub231pd/ps /r (66),(VEX) +b7: vfmsubadd231pd/ps /r (66),(VEX) +b8: vfmadd231pd/ps /r (66),(VEX) +b9: vfmadd231sd/ss /r (66),(VEX),(o128) +ba: vfmsub231pd/ps /r (66),(VEX) +bb: vfmsub231sd/ss /r (66),(VEX),(o128) +bc: vfnmadd231pd/ps /r (66),(VEX) +bd: vfnmadd231sd/ss /r (66),(VEX),(o128) +be: vfnmsub231pd/ps /r (66),(VEX) +bf: vfnmsub231sd/ss /r (66),(VEX),(o128) # 0x0f 0x38 0xc0-0xff -db: VAESIMC Vdq,Wdq (66),(v1) -dc: VAESENC Vdq,Hdq,Wdq (66),(v1) -dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) -de: VAESDEC Vdq,Hdq,Wdq (66),(v1) -df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) -f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) -f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) -f3: ANDN Gy,By,Ey (v) -f4: Grp17 (1A) -f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) -f6: MULX By,Gy,rDX,Ey (F2),(v) -f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) +db: aesimc Vdq,Wdq (66),(VEX),(o128) +dc: aesenc Vdq,Wdq (66),(VEX),(o128) +dd: aesenclast Vdq,Wdq (66),(VEX),(o128) +de: aesdec Vdq,Wdq (66),(VEX),(o128) +df: aesdeclast Vdq,Wdq (66),(VEX),(o128) +f0: MOVBE Gv,Mv | CRC32 Gd,Eb (F2) +f1: MOVBE Mv,Gv | CRC32 Gd,Ev (F2) EndTable Table: 3-byte opcode 2 (0x0f 0x3a) Referrer: 3-byte escape 2 AVXcode: 3 # 0x0f 0x3a 0x00-0xff -00: vpermq Vqq,Wqq,Ib (66),(v) -01: vpermpd Vqq,Wqq,Ib (66),(v) -02: vpblendd Vx,Hx,Wx,Ib (66),(v) -03: -04: vpermilps Vx,Wx,Ib (66),(v) -05: vpermilpd Vx,Wx,Ib (66),(v) -06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) -07: -08: vroundps Vx,Wx,Ib (66) -09: vroundpd Vx,Wx,Ib (66) -0a: vroundss Vss,Wss,Ib (66),(v1) -0b: vroundsd Vsd,Wsd,Ib (66),(v1) -0c: vblendps Vx,Hx,Wx,Ib (66) -0d: vblendpd Vx,Hx,Wx,Ib (66) -0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) -0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) -14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) -15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) -16: vpextrd/q Ey,Vdq,Ib (66),(v1) -17: vextractps Ed,Vdq,Ib (66),(v1) -18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) -19: vextractf128 Wdq,Vqq,Ib (66),(v) -1d: vcvtps2ph Wx,Vx,Ib (66),(v) -20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) -21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) -22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) -38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) -39: vextracti128 Wdq,Vqq,Ib (66),(v) -40: vdpps Vx,Hx,Wx,Ib (66) -41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) -42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) -44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) -46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) -4a: vblendvps Vx,Hx,Wx,Lx (66),(v) -4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) -4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) -60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) -61: vpcmpestri Vdq,Wdq,Ib (66),(v1) -62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) -63: vpcmpistri Vdq,Wdq,Ib (66),(v1) -df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) -f0: RORX Gy,Ey,Ib (F2),(v) +04: vpermilps /r,Ib (66),(oVEX) +05: vpermilpd /r,Ib (66),(oVEX) +06: vperm2f128 /r,Ib (66),(oVEX),(o256) +08: roundps Vdq,Wdq,Ib (66),(VEX) +09: roundpd Vdq,Wdq,Ib (66),(VEX) +0a: roundss Vss,Wss,Ib (66),(VEX),(o128) +0b: roundsd Vsd,Wsd,Ib (66),(VEX),(o128) +0c: blendps Vdq,Wdq,Ib (66),(VEX) +0d: blendpd Vdq,Wdq,Ib (66),(VEX) +0e: pblendw Vdq,Wdq,Ib (66),(VEX),(o128) +0f: palignr Pq,Qq,Ib | palignr Vdq,Wdq,Ib (66),(VEX),(o128) +14: pextrb Rd/Mb,Vdq,Ib (66),(VEX),(o128) +15: pextrw Rd/Mw,Vdq,Ib (66),(VEX),(o128) +16: pextrd/pextrq Ed/q,Vdq,Ib (66),(VEX),(o128) +17: extractps Ed,Vdq,Ib (66),(VEX),(o128) +18: vinsertf128 /r,Ib (66),(oVEX),(o256) +19: vextractf128 /r,Ib (66),(oVEX),(o256) +20: pinsrb Vdq,Rd/q/Mb,Ib (66),(VEX),(o128) +21: insertps Vdq,Udq/Md,Ib (66),(VEX),(o128) +22: pinsrd/pinsrq Vdq,Ed/q,Ib (66),(VEX),(o128) +40: dpps Vdq,Wdq,Ib (66),(VEX) +41: dppd Vdq,Wdq,Ib (66),(VEX),(o128) +42: mpsadbw Vdq,Wdq,Ib (66),(VEX),(o128) +44: pclmulq Vdq,Wdq,Ib (66),(VEX),(o128) +4a: vblendvps /r,Ib (66),(oVEX) +4b: vblendvpd /r,Ib (66),(oVEX) +4c: vpblendvb /r,Ib (66),(oVEX),(o128) +60: pcmpestrm Vdq,Wdq,Ib (66),(VEX),(o128) +61: pcmpestri Vdq,Wdq,Ib (66),(VEX),(o128) +62: pcmpistrm Vdq,Wdq,Ib (66),(VEX),(o128) +63: pcmpistri Vdq,Wdq,Ib (66),(VEX),(o128) +df: aeskeygenassist Vdq,Wdq,Ib (66),(VEX),(o128) EndTable GrpTable: Grp1 @@ -843,7 +790,7 @@ GrpTable: Grp5 2: CALLN Ev (f64) 3: CALLF Ep 4: JMPN Ev (f64) -5: JMPF Mp +5: JMPF Ep 6: PUSH Ev (d64) 7: EndTable @@ -860,7 +807,7 @@ EndTable GrpTable: Grp7 0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) 1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001) -2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) +2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) 3: LIDT Ms 4: SMSW Mw/Rv 5: @@ -877,45 +824,44 @@ EndTable GrpTable: Grp9 1: CMPXCHG8B/16B Mq/Mdq -6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) -7: VMPTRST Mq | VMPTRST Mq (F3) +6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) +7: VMPTRST Mq EndTable GrpTable: Grp10 EndTable GrpTable: Grp11 -# Note: the operands are given by group opcode 0: MOV EndTable GrpTable: Grp12 -2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) -4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) -6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) +2: psrlw Nq,Ib (11B) | psrlw Udq,Ib (66),(11B),(VEX),(o128) +4: psraw Nq,Ib (11B) | psraw Udq,Ib (66),(11B),(VEX),(o128) +6: psllw Nq,Ib (11B) | psllw Udq,Ib (66),(11B),(VEX),(o128) EndTable GrpTable: Grp13 -2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) -4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) -6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) +2: psrld Nq,Ib (11B) | psrld Udq,Ib (66),(11B),(VEX),(o128) +4: psrad Nq,Ib (11B) | psrad Udq,Ib (66),(11B),(VEX),(o128) +6: pslld Nq,Ib (11B) | pslld Udq,Ib (66),(11B),(VEX),(o128) EndTable GrpTable: Grp14 -2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) -3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) -6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) -7: vpslldq Hx,Ux,Ib (66),(11B),(v1) +2: psrlq Nq,Ib (11B) | psrlq Udq,Ib (66),(11B),(VEX),(o128) +3: psrldq Udq,Ib (66),(11B),(VEX),(o128) +6: psllq Nq,Ib (11B) | psllq Udq,Ib (66),(11B),(VEX),(o128) +7: pslldq Udq,Ib (66),(11B),(VEX),(o128) EndTable GrpTable: Grp15 -0: fxsave | RDFSBASE Ry (F3),(11B) -1: fxstor | RDGSBASE Ry (F3),(11B) -2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) -3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) +0: fxsave +1: fxstor +2: ldmxcsr (VEX) +3: stmxcsr (VEX) 4: XSAVE 5: XRSTOR | lfence (11B) -6: XSAVEOPT | mfence (11B) +6: mfence (11B) 7: clflush | sfence (11B) EndTable @@ -926,12 +872,6 @@ GrpTable: Grp16 3: prefetch T2 EndTable -GrpTable: Grp17 -1: BLSR By,Ey (v) -2: BLSMSK By,Ey (v) -3: BLSI By,Ey (v) -EndTable - # AMD's Prefetch Group GrpTable: GrpP 0: PREFETCH diff --git a/trunk/arch/x86/net/bpf_jit_comp.c b/trunk/arch/x86/net/bpf_jit_comp.c index bfab3fa10edc..7b65f752c5f8 100644 --- a/trunk/arch/x86/net/bpf_jit_comp.c +++ b/trunk/arch/x86/net/bpf_jit_comp.c @@ -568,8 +568,8 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; break; } if (filter[i].jt != 0) { - if (filter[i].jf) - t_offset += is_near(f_offset) ? 2 : 6; + if (filter[i].jf && f_offset) + t_offset += is_near(f_offset) ? 2 : 5; EMIT_COND_JMP(t_op, t_offset); if (filter[i].jf) EMIT_JMP(f_offset); diff --git a/trunk/arch/x86/oprofile/Makefile b/trunk/arch/x86/oprofile/Makefile index 1599f568f0e2..446902b2a6b6 100644 --- a/trunk/arch/x86/oprofile/Makefile +++ b/trunk/arch/x86/oprofile/Makefile @@ -4,8 +4,9 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprof.o cpu_buffer.o buffer_sync.o \ event_buffer.o oprofile_files.o \ oprofilefs.o oprofile_stats.o \ - timer_int.o nmi_timer_int.o ) + timer_int.o ) oprofile-y := $(DRIVER_OBJS) init.o backtrace.o oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_amd.o \ op_model_ppro.o op_model_p4.o +oprofile-$(CONFIG_X86_IO_APIC) += nmi_timer_int.o diff --git a/trunk/arch/x86/oprofile/init.c b/trunk/arch/x86/oprofile/init.c index 9e138d00ad36..f148cf652678 100644 --- a/trunk/arch/x86/oprofile/init.c +++ b/trunk/arch/x86/oprofile/init.c @@ -16,23 +16,37 @@ * with the NMI mode driver. */ -#ifdef CONFIG_X86_LOCAL_APIC extern int op_nmi_init(struct oprofile_operations *ops); +extern int op_nmi_timer_init(struct oprofile_operations *ops); extern void op_nmi_exit(void); -#else -static int op_nmi_init(struct oprofile_operations *ops) { return -ENODEV; } -static void op_nmi_exit(void) { } -#endif - extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth); +static int nmi_timer; + int __init oprofile_arch_init(struct oprofile_operations *ops) { + int ret; + + ret = -ENODEV; + +#ifdef CONFIG_X86_LOCAL_APIC + ret = op_nmi_init(ops); +#endif + nmi_timer = (ret != 0); +#ifdef CONFIG_X86_IO_APIC + if (nmi_timer) + ret = op_nmi_timer_init(ops); +#endif ops->backtrace = x86_backtrace; - return op_nmi_init(ops); + + return ret; } + void oprofile_arch_exit(void) { - op_nmi_exit(); +#ifdef CONFIG_X86_LOCAL_APIC + if (!nmi_timer) + op_nmi_exit(); +#endif } diff --git a/trunk/arch/x86/oprofile/nmi_int.c b/trunk/arch/x86/oprofile/nmi_int.c index 26b8a8514ee5..75f9528e0372 100644 --- a/trunk/arch/x86/oprofile/nmi_int.c +++ b/trunk/arch/x86/oprofile/nmi_int.c @@ -595,36 +595,24 @@ static int __init p4_init(char **cpu_type) return 0; } -enum __force_cpu_type { - reserved = 0, /* do not force */ - timer, - arch_perfmon, -}; - -static int force_cpu_type; - -static int set_cpu_type(const char *str, struct kernel_param *kp) +static int force_arch_perfmon; +static int force_cpu_type(const char *str, struct kernel_param *kp) { - if (!strcmp(str, "timer")) { - force_cpu_type = timer; - printk(KERN_INFO "oprofile: forcing NMI timer mode\n"); - } else if (!strcmp(str, "arch_perfmon")) { - force_cpu_type = arch_perfmon; + if (!strcmp(str, "arch_perfmon")) { + force_arch_perfmon = 1; printk(KERN_INFO "oprofile: forcing architectural perfmon\n"); - } else { - force_cpu_type = 0; } return 0; } -module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0); +module_param_call(cpu_type, force_cpu_type, NULL, NULL, 0); static int __init ppro_init(char **cpu_type) { __u8 cpu_model = boot_cpu_data.x86_model; struct op_x86_model_spec *spec = &op_ppro_spec; /* default */ - if (force_cpu_type == arch_perfmon && cpu_has_arch_perfmon) + if (force_arch_perfmon && cpu_has_arch_perfmon) return 0; /* @@ -691,9 +679,6 @@ int __init op_nmi_init(struct oprofile_operations *ops) if (!cpu_has_apic) return -ENODEV; - if (force_cpu_type == timer) - return -ENODEV; - switch (vendor) { case X86_VENDOR_AMD: /* Needs to be at least an Athlon (or hammer in 32bit mode) */ diff --git a/trunk/arch/x86/oprofile/nmi_timer_int.c b/trunk/arch/x86/oprofile/nmi_timer_int.c new file mode 100644 index 000000000000..7f8052cd6620 --- /dev/null +++ b/trunk/arch/x86/oprofile/nmi_timer_int.c @@ -0,0 +1,50 @@ +/** + * @file nmi_timer_int.c + * + * @remark Copyright 2003 OProfile authors + * @remark Read the file COPYING + * + * @author Zwane Mwaikambo + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int profile_timer_exceptions_notify(unsigned int val, struct pt_regs *regs) +{ + oprofile_add_sample(regs, 0); + return NMI_HANDLED; +} + +static int timer_start(void) +{ + if (register_nmi_handler(NMI_LOCAL, profile_timer_exceptions_notify, + 0, "oprofile-timer")) + return 1; + return 0; +} + + +static void timer_stop(void) +{ + unregister_nmi_handler(NMI_LOCAL, "oprofile-timer"); + synchronize_sched(); /* Allow already-started NMIs to complete. */ +} + + +int __init op_nmi_timer_init(struct oprofile_operations *ops) +{ + ops->start = timer_start; + ops->stop = timer_stop; + ops->cpu_type = "timer"; + printk(KERN_INFO "oprofile: using NMI timer interrupt.\n"); + return 0; +} diff --git a/trunk/arch/x86/tools/Makefile b/trunk/arch/x86/tools/Makefile index d511aa97533a..f82082677337 100644 --- a/trunk/arch/x86/tools/Makefile +++ b/trunk/arch/x86/tools/Makefile @@ -18,21 +18,14 @@ chkobjdump = $(srctree)/arch/x86/tools/chkobjdump.awk quiet_cmd_posttest = TEST $@ cmd_posttest = ($(OBJDUMP) -v | $(AWK) -f $(chkobjdump)) || $(OBJDUMP) -d -j .text $(objtree)/vmlinux | $(AWK) -f $(distill_awk) | $(obj)/test_get_len $(posttest_64bit) $(posttest_verbose) -quiet_cmd_sanitytest = TEST $@ - cmd_sanitytest = $(obj)/insn_sanity $(posttest_64bit) -m 1000000 - -posttest: $(obj)/test_get_len vmlinux $(obj)/insn_sanity +posttest: $(obj)/test_get_len vmlinux $(call cmd,posttest) - $(call cmd,sanitytest) -hostprogs-y += test_get_len insn_sanity +hostprogs-y := test_get_len # -I needed for generated C source and C source which in the kernel tree. HOSTCFLAGS_test_get_len.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/ -HOSTCFLAGS_insn_sanity.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x86/include/ -I$(srctree)/arch/x86/lib/ -I$(srctree)/include/ - # Dependencies are also needed. $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c -$(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c diff --git a/trunk/arch/x86/tools/gen-insn-attr-x86.awk b/trunk/arch/x86/tools/gen-insn-attr-x86.awk index 5f6a5b6c3a15..eaf11f52fc0b 100644 --- a/trunk/arch/x86/tools/gen-insn-attr-x86.awk +++ b/trunk/arch/x86/tools/gen-insn-attr-x86.awk @@ -47,7 +47,7 @@ BEGIN { sep_expr = "^\\|$" group_expr = "^Grp[0-9A-Za-z]+" - imm_expr = "^[IJAOL][a-z]" + imm_expr = "^[IJAO][a-z]" imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" @@ -59,7 +59,6 @@ BEGIN { imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" imm_flag["Ob"] = "INAT_MOFFSET" imm_flag["Ov"] = "INAT_MOFFSET" - imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" force64_expr = "\\([df]64\\)" @@ -71,12 +70,8 @@ BEGIN { lprefix3_expr = "\\(F2\\)" max_lprefix = 4 - # All opcodes starting with lower-case 'v' or with (v1) superscript - # accepts VEX prefix - vexok_opcode_expr = "^v.*" - vexok_expr = "\\(v1\\)" - # All opcodes with (v) superscript supports *only* VEX prefix - vexonly_expr = "\\(v\\)" + vexok_expr = "\\(VEX\\)" + vexonly_expr = "\\(oVEX\\)" prefix_expr = "\\(Prefix\\)" prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" @@ -90,8 +85,8 @@ BEGIN { prefix_num["SEG=GS"] = "INAT_PFX_GS" prefix_num["SEG=SS"] = "INAT_PFX_SS" prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" - prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" - prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" + prefix_num["2bytes-VEX"] = "INAT_PFX_VEX2" + prefix_num["3bytes-VEX"] = "INAT_PFX_VEX3" clear_vars() } @@ -315,10 +310,12 @@ function convert_operands(count,opnd, i,j,imm,mod) if (match(opcode, fpu_expr)) flags = add_flags(flags, "INAT_MODRM") - # check VEX codes + # check VEX only code if (match(ext, vexonly_expr)) flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") - else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) + + # check VEX only code + if (match(ext, vexok_expr)) flags = add_flags(flags, "INAT_VEXOK") # check prefixes diff --git a/trunk/arch/x86/tools/insn_sanity.c b/trunk/arch/x86/tools/insn_sanity.c deleted file mode 100644 index cc2f8c131286..000000000000 --- a/trunk/arch/x86/tools/insn_sanity.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * x86 decoder sanity test - based on test_get_insn.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2009 - * Copyright (C) Hitachi, Ltd., 2011 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define unlikely(cond) (cond) -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) - -#include -#include -#include - -/* - * Test of instruction analysis against tampering. - * Feed random binary to instruction decoder and ensure not to - * access out-of-instruction-buffer. - */ - -#define DEFAULT_MAX_ITER 10000 -#define INSN_NOP 0x90 - -static const char *prog; /* Program name */ -static int verbose; /* Verbosity */ -static int x86_64; /* x86-64 bit mode flag */ -static unsigned int seed; /* Random seed */ -static unsigned long iter_start; /* Start of iteration number */ -static unsigned long iter_end = DEFAULT_MAX_ITER; /* End of iteration number */ -static FILE *input_file; /* Input file name */ - -static void usage(const char *err) -{ - if (err) - fprintf(stderr, "Error: %s\n\n", err); - fprintf(stderr, "Usage: %s [-y|-n|-v] [-s seed[,no]] [-m max] [-i input]\n", prog); - fprintf(stderr, "\t-y 64bit mode\n"); - fprintf(stderr, "\t-n 32bit mode\n"); - fprintf(stderr, "\t-v Verbosity(-vv dumps any decoded result)\n"); - fprintf(stderr, "\t-s Give a random seed (and iteration number)\n"); - fprintf(stderr, "\t-m Give a maximum iteration number\n"); - fprintf(stderr, "\t-i Give an input file with decoded binary\n"); - exit(1); -} - -static void dump_field(FILE *fp, const char *name, const char *indent, - struct insn_field *field) -{ - fprintf(fp, "%s.%s = {\n", indent, name); - fprintf(fp, "%s\t.value = %d, bytes[] = {%x, %x, %x, %x},\n", - indent, field->value, field->bytes[0], field->bytes[1], - field->bytes[2], field->bytes[3]); - fprintf(fp, "%s\t.got = %d, .nbytes = %d},\n", indent, - field->got, field->nbytes); -} - -static void dump_insn(FILE *fp, struct insn *insn) -{ - fprintf(fp, "Instruction = {\n"); - dump_field(fp, "prefixes", "\t", &insn->prefixes); - dump_field(fp, "rex_prefix", "\t", &insn->rex_prefix); - dump_field(fp, "vex_prefix", "\t", &insn->vex_prefix); - dump_field(fp, "opcode", "\t", &insn->opcode); - dump_field(fp, "modrm", "\t", &insn->modrm); - dump_field(fp, "sib", "\t", &insn->sib); - dump_field(fp, "displacement", "\t", &insn->displacement); - dump_field(fp, "immediate1", "\t", &insn->immediate1); - dump_field(fp, "immediate2", "\t", &insn->immediate2); - fprintf(fp, "\t.attr = %x, .opnd_bytes = %d, .addr_bytes = %d,\n", - insn->attr, insn->opnd_bytes, insn->addr_bytes); - fprintf(fp, "\t.length = %d, .x86_64 = %d, .kaddr = %p}\n", - insn->length, insn->x86_64, insn->kaddr); -} - -static void dump_stream(FILE *fp, const char *msg, unsigned long nr_iter, - unsigned char *insn_buf, struct insn *insn) -{ - int i; - - fprintf(fp, "%s:\n", msg); - - dump_insn(fp, insn); - - fprintf(fp, "You can reproduce this with below command(s);\n"); - - /* Input a decoded instruction sequence directly */ - fprintf(fp, " $ echo "); - for (i = 0; i < MAX_INSN_SIZE; i++) - fprintf(fp, " %02x", insn_buf[i]); - fprintf(fp, " | %s -i -\n", prog); - - if (!input_file) { - fprintf(fp, "Or \n"); - /* Give a seed and iteration number */ - fprintf(fp, " $ %s -s 0x%x,%lu\n", prog, seed, nr_iter); - } -} - -static void init_random_seed(void) -{ - int fd; - - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) - goto fail; - - if (read(fd, &seed, sizeof(seed)) != sizeof(seed)) - goto fail; - - close(fd); - return; -fail: - usage("Failed to open /dev/urandom"); -} - -/* Read given instruction sequence from the input file */ -static int read_next_insn(unsigned char *insn_buf) -{ - char buf[256] = "", *tmp; - int i; - - tmp = fgets(buf, ARRAY_SIZE(buf), input_file); - if (tmp == NULL || feof(input_file)) - return 0; - - for (i = 0; i < MAX_INSN_SIZE; i++) { - insn_buf[i] = (unsigned char)strtoul(tmp, &tmp, 16); - if (*tmp != ' ') - break; - } - - return i; -} - -static int generate_insn(unsigned char *insn_buf) -{ - int i; - - if (input_file) - return read_next_insn(insn_buf); - - /* Fills buffer with random binary up to MAX_INSN_SIZE */ - for (i = 0; i < MAX_INSN_SIZE - 1; i += 2) - *(unsigned short *)(&insn_buf[i]) = random() & 0xffff; - - while (i < MAX_INSN_SIZE) - insn_buf[i++] = random() & 0xff; - - return i; -} - -static void parse_args(int argc, char **argv) -{ - int c; - char *tmp = NULL; - int set_seed = 0; - - prog = argv[0]; - while ((c = getopt(argc, argv, "ynvs:m:i:")) != -1) { - switch (c) { - case 'y': - x86_64 = 1; - break; - case 'n': - x86_64 = 0; - break; - case 'v': - verbose++; - break; - case 'i': - if (strcmp("-", optarg) == 0) - input_file = stdin; - else - input_file = fopen(optarg, "r"); - if (!input_file) - usage("Failed to open input file"); - break; - case 's': - seed = (unsigned int)strtoul(optarg, &tmp, 0); - if (*tmp == ',') { - optarg = tmp + 1; - iter_start = strtoul(optarg, &tmp, 0); - } - if (*tmp != '\0' || tmp == optarg) - usage("Failed to parse seed"); - set_seed = 1; - break; - case 'm': - iter_end = strtoul(optarg, &tmp, 0); - if (*tmp != '\0' || tmp == optarg) - usage("Failed to parse max_iter"); - break; - default: - usage(NULL); - } - } - - /* Check errors */ - if (iter_end < iter_start) - usage("Max iteration number must be bigger than iter-num"); - - if (set_seed && input_file) - usage("Don't use input file (-i) with random seed (-s)"); - - /* Initialize random seed */ - if (!input_file) { - if (!set_seed) /* No seed is given */ - init_random_seed(); - srand(seed); - } -} - -int main(int argc, char **argv) -{ - struct insn insn; - int insns = 0; - int errors = 0; - unsigned long i; - unsigned char insn_buf[MAX_INSN_SIZE * 2]; - - parse_args(argc, argv); - - /* Prepare stop bytes with NOPs */ - memset(insn_buf + MAX_INSN_SIZE, INSN_NOP, MAX_INSN_SIZE); - - for (i = 0; i < iter_end; i++) { - if (generate_insn(insn_buf) <= 0) - break; - - if (i < iter_start) /* Skip to given iteration number */ - continue; - - /* Decode an instruction */ - insn_init(&insn, insn_buf, x86_64); - insn_get_length(&insn); - - if (insn.next_byte <= insn.kaddr || - insn.kaddr + MAX_INSN_SIZE < insn.next_byte) { - /* Access out-of-range memory */ - dump_stream(stderr, "Error: Found an access violation", i, insn_buf, &insn); - errors++; - } else if (verbose && !insn_complete(&insn)) - dump_stream(stdout, "Info: Found an undecodable input", i, insn_buf, &insn); - else if (verbose >= 2) - dump_insn(stdout, &insn); - insns++; - } - - fprintf(stdout, "%s: decoded and checked %d %s instructions with %d errors (seed:0x%x)\n", (errors) ? "Failure" : "Success", insns, (input_file) ? "given" : "random", errors, seed); - - return errors ? 1 : 0; -} diff --git a/trunk/block/blk-map.c b/trunk/block/blk-map.c index 164cd0059706..623e1cd4cffe 100644 --- a/trunk/block/blk-map.c +++ b/trunk/block/blk-map.c @@ -311,7 +311,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, if (IS_ERR(bio)) return PTR_ERR(bio); - if (rq_data_dir(rq) == WRITE) + if (!reading) bio->bi_rw |= REQ_WRITE; if (do_copy) diff --git a/trunk/block/blk-tag.c b/trunk/block/blk-tag.c index e74d6d13838f..4af6f5cc1167 100644 --- a/trunk/block/blk-tag.c +++ b/trunk/block/blk-tag.c @@ -282,18 +282,9 @@ EXPORT_SYMBOL(blk_queue_resize_tags); void blk_queue_end_tag(struct request_queue *q, struct request *rq) { struct blk_queue_tag *bqt = q->queue_tags; - int tag = rq->tag; + unsigned tag = rq->tag; /* negative tags invalid */ - BUG_ON(tag == -1); - - if (unlikely(tag >= bqt->max_depth)) { - /* - * This can happen after tag depth has been reduced. - * But tag shouldn't be larger than real_max_depth. - */ - WARN_ON(tag >= bqt->real_max_depth); - return; - } + BUG_ON(tag >= bqt->real_max_depth); list_del_init(&rq->queuelist); rq->cmd_flags &= ~REQ_QUEUED; diff --git a/trunk/block/cfq-iosched.c b/trunk/block/cfq-iosched.c index 4c12869fcf77..3548705b04e4 100644 --- a/trunk/block/cfq-iosched.c +++ b/trunk/block/cfq-iosched.c @@ -1655,6 +1655,8 @@ cfq_merged_requests(struct request_queue *q, struct request *rq, struct request *next) { struct cfq_queue *cfqq = RQ_CFQQ(rq); + struct cfq_data *cfqd = q->elevator->elevator_data; + /* * reposition in fifo if next is older than rq */ @@ -1669,6 +1671,16 @@ cfq_merged_requests(struct request_queue *q, struct request *rq, cfq_remove_request(next); cfq_blkiocg_update_io_merged_stats(&(RQ_CFQG(rq))->blkg, rq_data_dir(next), rq_is_sync(next)); + + cfqq = RQ_CFQQ(next); + /* + * all requests of this queue are merged to other queues, delete it + * from the service tree. If it's the active_queue, + * cfq_dispatch_requests() will choose to expire it or do idle + */ + if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list) && + cfqq != cfqd->active_queue) + cfq_del_cfqq_rr(cfqd, cfqq); } static int cfq_allow_merge(struct request_queue *q, struct request *rq, diff --git a/trunk/drivers/ata/Kconfig b/trunk/drivers/ata/Kconfig index 6bdedd7cca2c..cf047c406d92 100644 --- a/trunk/drivers/ata/Kconfig +++ b/trunk/drivers/ata/Kconfig @@ -820,7 +820,7 @@ config PATA_PLATFORM config PATA_OF_PLATFORM tristate "OpenFirmware platform device PATA support" - depends on PATA_PLATFORM && OF + depends on PATA_PLATFORM && OF && OF_IRQ help This option enables support for generic directly connected ATA devices commonly found on embedded systems with OpenFirmware diff --git a/trunk/drivers/char/ipmi/ipmi_watchdog.c b/trunk/drivers/char/ipmi/ipmi_watchdog.c index c2917ffad2c2..34767a6d7f42 100644 --- a/trunk/drivers/char/ipmi/ipmi_watchdog.c +++ b/trunk/drivers/char/ipmi/ipmi_watchdog.c @@ -139,6 +139,8 @@ #define IPMI_WDOG_SET_TIMER 0x24 #define IPMI_WDOG_GET_TIMER 0x25 +#define IPMI_WDOG_TIMER_NOT_INIT_RESP 0x80 + /* These are here until the real ones get into the watchdog.h interface. */ #ifndef WDIOC_GETTIMEOUT #define WDIOC_GETTIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 20, int) @@ -596,6 +598,7 @@ static int ipmi_heartbeat(void) struct kernel_ipmi_msg msg; int rv; struct ipmi_system_interface_addr addr; + int timeout_retries = 0; if (ipmi_ignore_heartbeat) return 0; @@ -616,6 +619,7 @@ static int ipmi_heartbeat(void) mutex_lock(&heartbeat_lock); +restart: atomic_set(&heartbeat_tofree, 2); /* @@ -653,7 +657,33 @@ static int ipmi_heartbeat(void) /* Wait for the heartbeat to be sent. */ wait_for_completion(&heartbeat_wait); - if (heartbeat_recv_msg.msg.data[0] != 0) { + if (heartbeat_recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) { + timeout_retries++; + if (timeout_retries > 3) { + printk(KERN_ERR PFX ": Unable to restore the IPMI" + " watchdog's settings, giving up.\n"); + rv = -EIO; + goto out_unlock; + } + + /* + * The timer was not initialized, that means the BMC was + * probably reset and lost the watchdog information. Attempt + * to restore the timer's info. Note that we still hold + * the heartbeat lock, to keep a heartbeat from happening + * in this process, so must say no heartbeat to avoid a + * deadlock on this mutex. + */ + rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); + if (rv) { + printk(KERN_ERR PFX ": Unable to send the command to" + " set the watchdog's settings, giving up.\n"); + goto out_unlock; + } + + /* We might need a new heartbeat, so do it now */ + goto restart; + } else if (heartbeat_recv_msg.msg.data[0] != 0) { /* * Got an error in the heartbeat response. It was already * reported in ipmi_wdog_msg_handler, but we should return @@ -662,6 +692,7 @@ static int ipmi_heartbeat(void) rv = -EINVAL; } +out_unlock: mutex_unlock(&heartbeat_lock); return rv; @@ -922,11 +953,15 @@ static struct miscdevice ipmi_wdog_miscdev = { static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) { - if (msg->msg.data[0] != 0) { + if (msg->msg.cmd == IPMI_WDOG_RESET_TIMER && + msg->msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) + printk(KERN_INFO PFX "response: The IPMI controller appears" + " to have been reset, will attempt to reinitialize" + " the watchdog timer\n"); + else if (msg->msg.data[0] != 0) printk(KERN_ERR PFX "response: Error %x on cmd %x\n", msg->msg.data[0], msg->msg.cmd); - } ipmi_free_recv_msg(msg); } diff --git a/trunk/drivers/dma/Kconfig b/trunk/drivers/dma/Kconfig index ab8f469f5cf8..5a99bb3f255a 100644 --- a/trunk/drivers/dma/Kconfig +++ b/trunk/drivers/dma/Kconfig @@ -124,7 +124,7 @@ config MV_XOR config MX3_IPU bool "MX3x Image Processing Unit support" - depends on ARCH_MX3 + depends on SOC_IMX31 || SOC_IMX35 select DMA_ENGINE default y help @@ -216,7 +216,7 @@ config PCH_DMA config IMX_SDMA tristate "i.MX SDMA support" - depends on ARCH_MX25 || ARCH_MX3 || ARCH_MX5 + depends on ARCH_MX25 || SOC_IMX31 || SOC_IMX35 || ARCH_MX5 select DMA_ENGINE help Support the i.MX SDMA engine. This engine is integrated into diff --git a/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c681dc149d2a..b9da8900ae4e 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -756,9 +756,9 @@ intel_enable_semaphores(struct drm_device *dev) if (i915_semaphores >= 0) return i915_semaphores; - /* Enable semaphores on SNB when IO remapping is off */ + /* Disable semaphores on SNB */ if (INTEL_INFO(dev)->gen == 6) - return !intel_iommu_enabled; + return 0; return 1; } diff --git a/trunk/drivers/gpu/drm/i915/intel_display.c b/trunk/drivers/gpu/drm/i915/intel_display.c index d809b038ca88..daa5743ccbd6 100644 --- a/trunk/drivers/gpu/drm/i915/intel_display.c +++ b/trunk/drivers/gpu/drm/i915/intel_display.c @@ -7922,13 +7922,11 @@ static bool intel_enable_rc6(struct drm_device *dev) return 0; /* - * Enable rc6 on Sandybridge if DMA remapping is disabled + * Disable rc6 on Sandybridge */ if (INTEL_INFO(dev)->gen == 6) { - DRM_DEBUG_DRIVER("Sandybridge: intel_iommu_enabled %s -- RC6 %sabled\n", - intel_iommu_enabled ? "true" : "false", - !intel_iommu_enabled ? "en" : "dis"); - return !intel_iommu_enabled; + DRM_DEBUG_DRIVER("Sandybridge: RC6 disabled\n"); + return 0; } DRM_DEBUG_DRIVER("RC6 enabled\n"); return 1; diff --git a/trunk/drivers/gpu/drm/radeon/evergreen.c b/trunk/drivers/gpu/drm/radeon/evergreen.c index 5e00d1670aa9..92c9628c572d 100644 --- a/trunk/drivers/gpu/drm/radeon/evergreen.c +++ b/trunk/drivers/gpu/drm/radeon/evergreen.c @@ -3276,6 +3276,18 @@ int evergreen_init(struct radeon_device *rdev) rdev->accel_working = false; } } + + /* Don't start up if the MC ucode is missing on BTC parts. + * The default clocks and voltages before the MC ucode + * is loaded are not suffient for advanced operations. + */ + if (ASIC_IS_DCE5(rdev)) { + if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) { + DRM_ERROR("radeon: MC ucode required for NI+.\n"); + return -EINVAL; + } + } + return 0; } diff --git a/trunk/drivers/gpu/drm/radeon/radeon_atombios.c b/trunk/drivers/gpu/drm/radeon/radeon_atombios.c index d24baf30efcb..5082d17d14dc 100644 --- a/trunk/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/trunk/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2560,7 +2560,11 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; - rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + if (rdev->pm.default_power_state_index >= 0) + rdev->pm.current_vddc = + rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + else + rdev->pm.current_vddc = 0; } void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 8cca91a93bde..dc279706ca70 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -390,6 +390,11 @@ extern int vmw_context_check(struct vmw_private *dev_priv, struct ttm_object_file *tfile, int id, struct vmw_resource **p_res); +extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t handle, + struct vmw_surface **out_surf, + struct vmw_dma_buffer **out_buf); extern void vmw_surface_res_free(struct vmw_resource *res); extern int vmw_surface_init(struct vmw_private *dev_priv, struct vmw_surface *srf, diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 03bbc2a6f9a7..a0c2f12b1e1b 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -33,6 +33,7 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t fifo_min, hwversion; + const struct vmw_fifo_state *fifo = &dev_priv->fifo; if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) return false; @@ -41,7 +42,12 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) return false; - hwversion = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); + hwversion = ioread32(fifo_mem + + ((fifo->capabilities & + SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? + SVGA_FIFO_3D_HWVERSION_REVISED : + SVGA_FIFO_3D_HWVERSION)); + if (hwversion == 0) return false; diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 5ff561d4e0b4..66917c6c3813 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -58,8 +58,14 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_FIFO_HW_VERSION: { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; - - param->value = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); + const struct vmw_fifo_state *fifo = &dev_priv->fifo; + + param->value = + ioread32(fifo_mem + + ((fifo->capabilities & + SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? + SVGA_FIFO_3D_HWVERSION_REVISED : + SVGA_FIFO_3D_HWVERSION)); break; } default: @@ -166,13 +172,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; goto out_no_fb; } - vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); - if (!vfb->dmabuf) { - DRM_ERROR("Framebuffer not dmabuf backed.\n"); - ret = -EINVAL; - goto out_no_fb; - } ret = ttm_read_lock(&vmaster->lock, true); if (unlikely(ret != 0)) diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 37d40545ed77..f94b33ae2215 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -31,6 +31,44 @@ /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) + +struct vmw_clip_rect { + int x1, x2, y1, y2; +}; + +/** + * Clip @num_rects number of @rects against @clip storing the + * results in @out_rects and the number of passed rects in @out_num. + */ +void vmw_clip_cliprects(struct drm_clip_rect *rects, + int num_rects, + struct vmw_clip_rect clip, + SVGASignedRect *out_rects, + int *out_num) +{ + int i, k; + + for (i = 0, k = 0; i < num_rects; i++) { + int x1 = max_t(int, clip.x1, rects[i].x1); + int y1 = max_t(int, clip.y1, rects[i].y1); + int x2 = min_t(int, clip.x2, rects[i].x2); + int y2 = min_t(int, clip.y2, rects[i].y2); + + if (x1 >= x2) + continue; + if (y1 >= y2) + continue; + + out_rects[k].left = x1; + out_rects[k].top = y1; + out_rects[k].right = x2; + out_rects[k].bottom = y2; + k++; + } + + *out_num = k; +} + void vmw_display_unit_cleanup(struct vmw_display_unit *du) { if (du->cursor_surface) @@ -82,6 +120,43 @@ int vmw_cursor_update_image(struct vmw_private *dev_priv, return 0; } +int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, + struct vmw_dma_buffer *dmabuf, + u32 width, u32 height, + u32 hotspotX, u32 hotspotY) +{ + struct ttm_bo_kmap_obj map; + unsigned long kmap_offset; + unsigned long kmap_num; + void *virtual; + bool dummy; + int ret; + + kmap_offset = 0; + kmap_num = (width*height*4 + PAGE_SIZE - 1) >> PAGE_SHIFT; + + ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0); + if (unlikely(ret != 0)) { + DRM_ERROR("reserve failed\n"); + return -EINVAL; + } + + ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map); + if (unlikely(ret != 0)) + goto err_unreserve; + + virtual = ttm_kmap_obj_virtual(&map, &dummy); + ret = vmw_cursor_update_image(dev_priv, virtual, width, height, + hotspotX, hotspotY); + + ttm_bo_kunmap(&map); +err_unreserve: + ttm_bo_unreserve(&dmabuf->base); + + return ret; +} + + void vmw_cursor_update_position(struct vmw_private *dev_priv, bool show, int x, int y) { @@ -110,24 +185,21 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, return -EINVAL; if (handle) { - ret = vmw_user_surface_lookup_handle(dev_priv, tfile, - handle, &surface); - if (!ret) { - if (!surface->snooper.image) { - DRM_ERROR("surface not suitable for cursor\n"); - vmw_surface_unreference(&surface); - return -EINVAL; - } - } else { - ret = vmw_user_dmabuf_lookup(tfile, - handle, &dmabuf); - if (ret) { - DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); - return -EINVAL; - } + ret = vmw_user_lookup_handle(dev_priv, tfile, + handle, &surface, &dmabuf); + if (ret) { + DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); + return -EINVAL; } } + /* need to do this before taking down old image */ + if (surface && !surface->snooper.image) { + DRM_ERROR("surface not suitable for cursor\n"); + vmw_surface_unreference(&surface); + return -EINVAL; + } + /* takedown old cursor */ if (du->cursor_surface) { du->cursor_surface->snooper.crtc = NULL; @@ -146,36 +218,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, vmw_cursor_update_image(dev_priv, surface->snooper.image, 64, 64, du->hotspot_x, du->hotspot_y); } else if (dmabuf) { - struct ttm_bo_kmap_obj map; - unsigned long kmap_offset; - unsigned long kmap_num; - void *virtual; - bool dummy; - /* vmw_user_surface_lookup takes one reference */ du->cursor_dmabuf = dmabuf; - kmap_offset = 0; - kmap_num = (64*64*4) >> PAGE_SHIFT; - - ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0); - if (unlikely(ret != 0)) { - DRM_ERROR("reserve failed\n"); - return -EINVAL; - } - - ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map); - if (unlikely(ret != 0)) - goto err_unreserve; - - virtual = ttm_kmap_obj_virtual(&map, &dummy); - vmw_cursor_update_image(dev_priv, virtual, 64, 64, - du->hotspot_x, du->hotspot_y); - - ttm_bo_kunmap(&map); -err_unreserve: - ttm_bo_unreserve(&dmabuf->base); - + ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height, + du->hotspot_x, du->hotspot_y); } else { vmw_cursor_update_position(dev_priv, false, 0, 0); return 0; @@ -377,8 +424,9 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, struct drm_clip_rect *clips, unsigned num_clips, int inc) { - struct drm_clip_rect *clips_ptr; struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *clips_ptr; + struct drm_clip_rect *tmp; struct drm_crtc *crtc; size_t fifo_size; int i, num_units; @@ -391,7 +439,6 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, } *cmd; SVGASignedRect *blits; - num_units = 0; list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { @@ -402,13 +449,24 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, BUG_ON(!clips || !num_clips); + tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); + if (unlikely(tmp == NULL)) { + DRM_ERROR("Temporary cliprect memory alloc failed.\n"); + return -ENOMEM; + } + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; cmd = kzalloc(fifo_size, GFP_KERNEL); if (unlikely(cmd == NULL)) { DRM_ERROR("Temporary fifo memory alloc failed.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_free_tmp; } + /* setup blits pointer */ + blits = (SVGASignedRect *)&cmd[1]; + + /* initial clip region */ left = clips->x1; right = clips->x2; top = clips->y1; @@ -434,45 +492,60 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, cmd->body.srcRect.bottom = bottom; clips_ptr = clips; - blits = (SVGASignedRect *)&cmd[1]; for (i = 0; i < num_clips; i++, clips_ptr += inc) { - blits[i].left = clips_ptr->x1 - left; - blits[i].right = clips_ptr->x2 - left; - blits[i].top = clips_ptr->y1 - top; - blits[i].bottom = clips_ptr->y2 - top; + tmp[i].x1 = clips_ptr->x1 - left; + tmp[i].x2 = clips_ptr->x2 - left; + tmp[i].y1 = clips_ptr->y1 - top; + tmp[i].y2 = clips_ptr->y2 - top; } /* do per unit writing, reuse fifo for each */ for (i = 0; i < num_units; i++) { struct vmw_display_unit *unit = units[i]; - int clip_x1 = left - unit->crtc.x; - int clip_y1 = top - unit->crtc.y; - int clip_x2 = right - unit->crtc.x; - int clip_y2 = bottom - unit->crtc.y; + struct vmw_clip_rect clip; + int num; + + clip.x1 = left - unit->crtc.x; + clip.y1 = top - unit->crtc.y; + clip.x2 = right - unit->crtc.x; + clip.y2 = bottom - unit->crtc.y; /* skip any crtcs that misses the clip region */ - if (clip_x1 >= unit->crtc.mode.hdisplay || - clip_y1 >= unit->crtc.mode.vdisplay || - clip_x2 <= 0 || clip_y2 <= 0) + if (clip.x1 >= unit->crtc.mode.hdisplay || + clip.y1 >= unit->crtc.mode.vdisplay || + clip.x2 <= 0 || clip.y2 <= 0) continue; + /* + * In order for the clip rects to be correctly scaled + * the src and dest rects needs to be the same size. + */ + cmd->body.destRect.left = clip.x1; + cmd->body.destRect.right = clip.x2; + cmd->body.destRect.top = clip.y1; + cmd->body.destRect.bottom = clip.y2; + + /* create a clip rect of the crtc in dest coords */ + clip.x2 = unit->crtc.mode.hdisplay - clip.x1; + clip.y2 = unit->crtc.mode.vdisplay - clip.y1; + clip.x1 = 0 - clip.x1; + clip.y1 = 0 - clip.y1; + /* need to reset sid as it is changed by execbuf */ cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); - cmd->body.destScreenId = unit->unit; - /* - * The blit command is a lot more resilient then the - * readback command when it comes to clip rects. So its - * okay to go out of bounds. - */ + /* clip and write blits to cmd stream */ + vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); - cmd->body.destRect.left = clip_x1; - cmd->body.destRect.right = clip_x2; - cmd->body.destRect.top = clip_y1; - cmd->body.destRect.bottom = clip_y2; + /* if no cliprects hit skip this */ + if (num == 0) + continue; + /* recalculate package length */ + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, 0, NULL); @@ -480,7 +553,10 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, break; } + kfree(cmd); +out_free_tmp: + kfree(tmp); return ret; } @@ -556,6 +632,10 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, * Sanity checks. */ + /* Surface must be marked as a scanout. */ + if (unlikely(!surface->scanout)) + return -EINVAL; + if (unlikely(surface->mip_levels[0] != 1 || surface->num_sizes != 1 || surface->sizes[0].width < mode_cmd->width || @@ -782,6 +862,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, int clip_y1 = clips_ptr->y1 - unit->crtc.y; int clip_x2 = clips_ptr->x2 - unit->crtc.x; int clip_y2 = clips_ptr->y2 - unit->crtc.y; + int move_x, move_y; /* skip any crtcs that misses the clip region */ if (clip_x1 >= unit->crtc.mode.hdisplay || @@ -789,12 +870,21 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, clip_x2 <= 0 || clip_y2 <= 0) continue; + /* clip size to crtc size */ + clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay); + clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay); + + /* translate both src and dest to bring clip into screen */ + move_x = min_t(int, clip_x1, 0); + move_y = min_t(int, clip_y1, 0); + + /* actual translate done here */ blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; blits[hit_num].body.destScreenId = unit->unit; - blits[hit_num].body.srcOrigin.x = clips_ptr->x1; - blits[hit_num].body.srcOrigin.y = clips_ptr->y1; - blits[hit_num].body.destRect.left = clip_x1; - blits[hit_num].body.destRect.top = clip_y1; + blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x; + blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y; + blits[hit_num].body.destRect.left = clip_x1 - move_x; + blits[hit_num].body.destRect.top = clip_y1 - move_y; blits[hit_num].body.destRect.right = clip_x2; blits[hit_num].body.destRect.bottom = clip_y2; hit_num++; @@ -1003,7 +1093,6 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct vmw_surface *surface = NULL; struct vmw_dma_buffer *bo = NULL; struct ttm_base_object *user_obj; - u64 required_size; int ret; /** @@ -1012,8 +1101,9 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, * requested framebuffer. */ - required_size = mode_cmd->pitch * mode_cmd->height; - if (unlikely(required_size > (u64) dev_priv->vram_size)) { + if (!vmw_kms_validate_mode_vram(dev_priv, + mode_cmd->pitch, + mode_cmd->height)) { DRM_ERROR("VRAM size is too small for requested mode.\n"); return ERR_PTR(-ENOMEM); } @@ -1033,46 +1123,29 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, return ERR_PTR(-ENOENT); } - /** - * End conditioned code. - */ - - ret = vmw_user_surface_lookup_handle(dev_priv, tfile, - mode_cmd->handle, &surface); + /* returns either a dmabuf or surface */ + ret = vmw_user_lookup_handle(dev_priv, tfile, + mode_cmd->handle, + &surface, &bo); if (ret) - goto try_dmabuf; - - if (!surface->scanout) - goto err_not_scanout; - - ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface, - &vfb, mode_cmd); - - /* vmw_user_surface_lookup takes one ref so does new_fb */ - vmw_surface_unreference(&surface); - - if (ret) { - DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); - ttm_base_object_unref(&user_obj); - return ERR_PTR(ret); - } else - vfb->user_obj = user_obj; - return &vfb->base; - -try_dmabuf: - DRM_INFO("%s: trying buffer\n", __func__); - - ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo); - if (ret) { - DRM_ERROR("failed to find buffer: %i\n", ret); - return ERR_PTR(-ENOENT); - } - - ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, - mode_cmd); + goto err_out; + + /* Create the new framebuffer depending one what we got back */ + if (bo) + ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, + mode_cmd); + else if (surface) + ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, + surface, &vfb, mode_cmd); + else + BUG(); - /* vmw_user_dmabuf_lookup takes one ref so does new_fb */ - vmw_dmabuf_unreference(&bo); +err_out: + /* vmw_user_lookup_handle takes one ref so does new_fb */ + if (bo) + vmw_dmabuf_unreference(&bo); + if (surface) + vmw_surface_unreference(&surface); if (ret) { DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); @@ -1082,14 +1155,6 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, vfb->user_obj = user_obj; return &vfb->base; - -err_not_scanout: - DRM_ERROR("surface not marked as scanout\n"); - /* vmw_user_surface_lookup takes one ref */ - vmw_surface_unreference(&surface); - ttm_base_object_unref(&user_obj); - - return ERR_PTR(-EINVAL); } static struct drm_mode_config_funcs vmw_kms_funcs = { @@ -1106,10 +1171,12 @@ int vmw_kms_present(struct vmw_private *dev_priv, uint32_t num_clips) { struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *tmp; struct drm_crtc *crtc; size_t fifo_size; int i, k, num_units; int ret = 0; /* silence warning */ + int left, right, top, bottom; struct { SVGA3dCmdHeader header; @@ -1127,60 +1194,95 @@ int vmw_kms_present(struct vmw_private *dev_priv, BUG_ON(surface == NULL); BUG_ON(!clips || !num_clips); + tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); + if (unlikely(tmp == NULL)) { + DRM_ERROR("Temporary cliprect memory alloc failed.\n"); + return -ENOMEM; + } + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; cmd = kmalloc(fifo_size, GFP_KERNEL); if (unlikely(cmd == NULL)) { DRM_ERROR("Failed to allocate temporary fifo memory.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_free_tmp; + } + + left = clips->x; + right = clips->x + clips->w; + top = clips->y; + bottom = clips->y + clips->h; + + for (i = 1; i < num_clips; i++) { + left = min_t(int, left, (int)clips[i].x); + right = max_t(int, right, (int)clips[i].x + clips[i].w); + top = min_t(int, top, (int)clips[i].y); + bottom = max_t(int, bottom, (int)clips[i].y + clips[i].h); } /* only need to do this once */ memset(cmd, 0, fifo_size); cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - - cmd->body.srcRect.left = 0; - cmd->body.srcRect.right = surface->sizes[0].width; - cmd->body.srcRect.top = 0; - cmd->body.srcRect.bottom = surface->sizes[0].height; blits = (SVGASignedRect *)&cmd[1]; + + cmd->body.srcRect.left = left; + cmd->body.srcRect.right = right; + cmd->body.srcRect.top = top; + cmd->body.srcRect.bottom = bottom; + for (i = 0; i < num_clips; i++) { - blits[i].left = clips[i].x; - blits[i].right = clips[i].x + clips[i].w; - blits[i].top = clips[i].y; - blits[i].bottom = clips[i].y + clips[i].h; + tmp[i].x1 = clips[i].x - left; + tmp[i].x2 = clips[i].x + clips[i].w - left; + tmp[i].y1 = clips[i].y - top; + tmp[i].y2 = clips[i].y + clips[i].h - top; } for (k = 0; k < num_units; k++) { struct vmw_display_unit *unit = units[k]; - int clip_x1 = destX - unit->crtc.x; - int clip_y1 = destY - unit->crtc.y; - int clip_x2 = clip_x1 + surface->sizes[0].width; - int clip_y2 = clip_y1 + surface->sizes[0].height; + struct vmw_clip_rect clip; + int num; + + clip.x1 = left + destX - unit->crtc.x; + clip.y1 = top + destY - unit->crtc.y; + clip.x2 = right + destX - unit->crtc.x; + clip.y2 = bottom + destY - unit->crtc.y; /* skip any crtcs that misses the clip region */ - if (clip_x1 >= unit->crtc.mode.hdisplay || - clip_y1 >= unit->crtc.mode.vdisplay || - clip_x2 <= 0 || clip_y2 <= 0) + if (clip.x1 >= unit->crtc.mode.hdisplay || + clip.y1 >= unit->crtc.mode.vdisplay || + clip.x2 <= 0 || clip.y2 <= 0) continue; + /* + * In order for the clip rects to be correctly scaled + * the src and dest rects needs to be the same size. + */ + cmd->body.destRect.left = clip.x1; + cmd->body.destRect.right = clip.x2; + cmd->body.destRect.top = clip.y1; + cmd->body.destRect.bottom = clip.y2; + + /* create a clip rect of the crtc in dest coords */ + clip.x2 = unit->crtc.mode.hdisplay - clip.x1; + clip.y2 = unit->crtc.mode.vdisplay - clip.y1; + clip.x1 = 0 - clip.x1; + clip.y1 = 0 - clip.y1; + /* need to reset sid as it is changed by execbuf */ cmd->body.srcImage.sid = sid; - cmd->body.destScreenId = unit->unit; - /* - * The blit command is a lot more resilient then the - * readback command when it comes to clip rects. So its - * okay to go out of bounds. - */ + /* clip and write blits to cmd stream */ + vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); - cmd->body.destRect.left = clip_x1; - cmd->body.destRect.right = clip_x2; - cmd->body.destRect.top = clip_y1; - cmd->body.destRect.bottom = clip_y2; + /* if no cliprects hit skip this */ + if (num == 0) + continue; + /* recalculate package length */ + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, 0, NULL); @@ -1189,6 +1291,8 @@ int vmw_kms_present(struct vmw_private *dev_priv, } kfree(cmd); +out_free_tmp: + kfree(tmp); return ret; } diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index af8e6e5bd964..e1cb8556355f 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -62,9 +62,14 @@ struct vmw_framebuffer { int vmw_cursor_update_image(struct vmw_private *dev_priv, u32 *image, u32 width, u32 height, u32 hotspotX, u32 hotspotY); +int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, + struct vmw_dma_buffer *dmabuf, + u32 width, u32 height, + u32 hotspotX, u32 hotspotY); void vmw_cursor_update_position(struct vmw_private *dev_priv, bool show, int x, int y); + /** * Base class display unit. * diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 90c5e3928491..8f8dbd43c33d 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -74,9 +74,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) { struct vmw_legacy_display *lds = dev_priv->ldu_priv; struct vmw_legacy_display_unit *entry; + struct vmw_display_unit *du = NULL; struct drm_framebuffer *fb = NULL; struct drm_crtc *crtc = NULL; - int i = 0; + int i = 0, ret; /* If there is no display topology the host just assumes * that the guest will set the same layout as the host. @@ -129,6 +130,25 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) lds->last_num_active = lds->num_active; + + /* Find the first du with a cursor. */ + list_for_each_entry(entry, &lds->active, active) { + du = &entry->base; + + if (!du->cursor_dmabuf) + continue; + + ret = vmw_cursor_update_dmabuf(dev_priv, + du->cursor_dmabuf, + 64, 64, + du->hotspot_x, + du->hotspot_y); + if (ret == 0) + break; + + DRM_ERROR("Could not update cursor image\n"); + } + return 0; } diff --git a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 86c5e4cceb31..1c7f09e26819 100644 --- a/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/trunk/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1190,6 +1190,29 @@ void vmw_resource_unreserve(struct list_head *list) write_unlock(lock); } +/** + * Helper function that looks either a surface or dmabuf. + * + * The pointer this pointed at by out_surf and out_buf needs to be null. + */ +int vmw_user_lookup_handle(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t handle, + struct vmw_surface **out_surf, + struct vmw_dma_buffer **out_buf) +{ + int ret; + + BUG_ON(*out_surf || *out_buf); + + ret = vmw_user_surface_lookup_handle(dev_priv, tfile, handle, out_surf); + if (!ret) + return 0; + + ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf); + return ret; +} + int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, diff --git a/trunk/drivers/i2c/busses/i2c-eg20t.c b/trunk/drivers/i2c/busses/i2c-eg20t.c index 8cebef49aeac..18936ac9d51c 100644 --- a/trunk/drivers/i2c/busses/i2c-eg20t.c +++ b/trunk/drivers/i2c/busses/i2c-eg20t.c @@ -893,6 +893,13 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, /* Set the number of I2C channel instance */ adap_info->ch_num = id->driver_data; + ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, + KBUILD_MODNAME, adap_info); + if (ret) { + pch_pci_err(pdev, "request_irq FAILED\n"); + goto err_request_irq; + } + for (i = 0; i < adap_info->ch_num; i++) { pch_adap = &adap_info->pch_data[i].pch_adapter; adap_info->pch_i2c_suspended = false; @@ -910,28 +917,23 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, pch_adap->dev.parent = &pdev->dev; + pch_i2c_init(&adap_info->pch_data[i]); ret = i2c_add_adapter(pch_adap); if (ret) { pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i); - goto err_i2c_add_adapter; + goto err_add_adapter; } - - pch_i2c_init(&adap_info->pch_data[i]); - } - ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, - KBUILD_MODNAME, adap_info); - if (ret) { - pch_pci_err(pdev, "request_irq FAILED\n"); - goto err_i2c_add_adapter; } pci_set_drvdata(pdev, adap_info); pch_pci_dbg(pdev, "returns %d.\n", ret); return 0; -err_i2c_add_adapter: +err_add_adapter: for (j = 0; j < i; j++) i2c_del_adapter(&adap_info->pch_data[j].pch_adapter); + free_irq(pdev->irq, adap_info); +err_request_irq: pci_iounmap(pdev, base_addr); err_pci_iomap: pci_release_regions(pdev); diff --git a/trunk/drivers/i2c/busses/i2c-omap.c b/trunk/drivers/i2c/busses/i2c-omap.c index a43d0023446a..fa23faa20f0e 100644 --- a/trunk/drivers/i2c/busses/i2c-omap.c +++ b/trunk/drivers/i2c/busses/i2c-omap.c @@ -1047,13 +1047,14 @@ omap_i2c_probe(struct platform_device *pdev) * size. This is to ensure that we can handle the status on int * call back latencies. */ - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) { - dev->fifo_size = 0; + + dev->fifo_size = (dev->fifo_size / 2); + + if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) dev->b_hw = 0; /* Disable hardware fixes */ - } else { - dev->fifo_size = (dev->fifo_size / 2); + else dev->b_hw = 1; /* Enable hardware fixes */ - } + /* calculate wakeup latency constraint for MPU */ if (dev->set_mpu_wkup_lat != NULL) dev->latency = (1000000 * dev->fifo_size) / diff --git a/trunk/drivers/i2c/busses/i2c-s3c2410.c b/trunk/drivers/i2c/busses/i2c-s3c2410.c index 2754cef86a06..4c1718081685 100644 --- a/trunk/drivers/i2c/busses/i2c-s3c2410.c +++ b/trunk/drivers/i2c/busses/i2c-s3c2410.c @@ -534,6 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, /* first, try busy waiting briefly */ do { + cpu_relax(); iicstat = readl(i2c->regs + S3C2410_IICSTAT); } while ((iicstat & S3C2410_IICSTAT_START) && --spins); @@ -786,7 +787,7 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) #else static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) { - return -EINVAL; + return 0; } static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) diff --git a/trunk/drivers/infiniband/core/cma.c b/trunk/drivers/infiniband/core/cma.c index 75ff821c0af0..d0d4aa9f4802 100644 --- a/trunk/drivers/infiniband/core/cma.c +++ b/trunk/drivers/infiniband/core/cma.c @@ -2513,6 +2513,9 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, req.private_data_len = sizeof(struct cma_hdr) + conn_param->private_data_len; + if (req.private_data_len < conn_param->private_data_len) + return -EINVAL; + req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); if (!req.private_data) return -ENOMEM; @@ -2562,6 +2565,9 @@ static int cma_connect_ib(struct rdma_id_private *id_priv, memset(&req, 0, sizeof req); offset = cma_user_data_offset(id_priv->id.ps); req.private_data_len = offset + conn_param->private_data_len; + if (req.private_data_len < conn_param->private_data_len) + return -EINVAL; + private_data = kzalloc(req.private_data_len, GFP_ATOMIC); if (!private_data) return -ENOMEM; diff --git a/trunk/drivers/infiniband/hw/mlx4/main.c b/trunk/drivers/infiniband/hw/mlx4/main.c index 77f3dbc0aaa1..18836cdf1e10 100644 --- a/trunk/drivers/infiniband/hw/mlx4/main.c +++ b/trunk/drivers/infiniband/hw/mlx4/main.c @@ -1244,7 +1244,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) err_counter: for (; i; --i) - mlx4_counter_free(ibdev->dev, ibdev->counters[i - 1]); + if (ibdev->counters[i - 1] != -1) + mlx4_counter_free(ibdev->dev, ibdev->counters[i - 1]); err_map: iounmap(ibdev->uar_map); @@ -1275,7 +1276,8 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) } iounmap(ibdev->uar_map); for (p = 0; p < ibdev->num_ports; ++p) - mlx4_counter_free(ibdev->dev, ibdev->counters[p]); + if (ibdev->counters[p] != -1) + mlx4_counter_free(ibdev->dev, ibdev->counters[p]); mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB) mlx4_CLOSE_PORT(dev, p); diff --git a/trunk/drivers/infiniband/hw/qib/qib_file_ops.c b/trunk/drivers/infiniband/hw/qib/qib_file_ops.c index 574600ef5b42..a7403248d83d 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/trunk/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1285,7 +1285,7 @@ static int setup_ctxt(struct qib_pportdata *ppd, int ctxt, strlcpy(rcd->comm, current->comm, sizeof(rcd->comm)); ctxt_fp(fp) = rcd; qib_stats.sps_ctxts++; - dd->freectxts++; + dd->freectxts--; ret = 0; goto bail; @@ -1794,7 +1794,7 @@ static int qib_close(struct inode *in, struct file *fp) if (dd->pageshadow) unlock_expected_tids(rcd); qib_stats.sps_ctxts--; - dd->freectxts--; + dd->freectxts++; } mutex_unlock(&qib_mutex); diff --git a/trunk/drivers/input/misc/cma3000_d0x.c b/trunk/drivers/input/misc/cma3000_d0x.c index 80793f1608eb..06517e60e50c 100644 --- a/trunk/drivers/input/misc/cma3000_d0x.c +++ b/trunk/drivers/input/misc/cma3000_d0x.c @@ -115,8 +115,8 @@ static void decode_mg(struct cma3000_accl_data *data, int *datax, static irqreturn_t cma3000_thread_irq(int irq, void *dev_id) { struct cma3000_accl_data *data = dev_id; - int datax, datay, dataz; - u8 ctrl, mode, range, intr_status; + int datax, datay, dataz, intr_status; + u8 ctrl, mode, range; intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status"); if (intr_status < 0) diff --git a/trunk/drivers/input/mouse/sentelic.c b/trunk/drivers/input/mouse/sentelic.c index c5b12d2e955a..86d6f39178b0 100644 --- a/trunk/drivers/input/mouse/sentelic.c +++ b/trunk/drivers/input/mouse/sentelic.c @@ -2,7 +2,7 @@ * Finger Sensing Pad PS/2 mouse driver. * * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. - * Copyright (C) 2005-2010 Tai-hwa Liang, Sentelic Corporation. + * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -162,7 +162,7 @@ static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) - return -1; + goto out; if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { /* inversion is required */ @@ -261,7 +261,7 @@ static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) - return -1; + goto out; if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); @@ -309,7 +309,7 @@ static int fsp_get_buttons(struct psmouse *psmouse, int *btn) }; int val; - if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1) + if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS, &val) == -1) return -EIO; *btn = buttons[(val & 0x30) >> 4]; diff --git a/trunk/drivers/input/mouse/sentelic.h b/trunk/drivers/input/mouse/sentelic.h index ed1395ac7b8b..2e4af24f8c15 100644 --- a/trunk/drivers/input/mouse/sentelic.h +++ b/trunk/drivers/input/mouse/sentelic.h @@ -2,7 +2,7 @@ * Finger Sensing Pad PS/2 mouse driver. * * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. - * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,6 +33,7 @@ /* Finger-sensing Pad control registers */ #define FSP_REG_SYSCTL1 0x10 #define FSP_BIT_EN_REG_CLK BIT(5) +#define FSP_REG_TMOD_STATUS 0x20 #define FSP_REG_OPC_QDOWN 0x31 #define FSP_BIT_EN_OPC_TAG BIT(7) #define FSP_REG_OPTZ_XLO 0x34 diff --git a/trunk/drivers/input/mouse/synaptics.c b/trunk/drivers/input/mouse/synaptics.c index c080b828e5dc..a6dcd18e9adf 100644 --- a/trunk/drivers/input/mouse/synaptics.c +++ b/trunk/drivers/input/mouse/synaptics.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -1220,6 +1221,16 @@ static int synaptics_reconnect(struct psmouse *psmouse) do { psmouse_reset(psmouse); + if (retry) { + /* + * On some boxes, right after resuming, the touchpad + * needs some time to finish initializing (I assume + * it needs time to calibrate) and start responding + * to Synaptics-specific queries, so let's wait a + * bit. + */ + ssleep(1); + } error = synaptics_detect(psmouse, 0); } while (error && ++retry < 3); diff --git a/trunk/drivers/input/tablet/wacom_wac.c b/trunk/drivers/input/tablet/wacom_wac.c index da0d8761e778..2ee47d01a3b4 100644 --- a/trunk/drivers/input/tablet/wacom_wac.c +++ b/trunk/drivers/input/tablet/wacom_wac.c @@ -1470,6 +1470,9 @@ static const struct wacom_features wacom_features_0xE3 = static const struct wacom_features wacom_features_0xE6 = { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0xEC = + { "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1611,6 +1614,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE3) }, { USB_DEVICE_WACOM(0xE6) }, + { USB_DEVICE_WACOM(0xEC) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_LENOVO(0x6004) }, { } diff --git a/trunk/drivers/iommu/iommu.c b/trunk/drivers/iommu/iommu.c index 2fb2963df553..5b5fa5cdaa31 100644 --- a/trunk/drivers/iommu/iommu.c +++ b/trunk/drivers/iommu/iommu.c @@ -90,7 +90,7 @@ struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) if (bus == NULL || bus->iommu_ops == NULL) return NULL; - domain = kmalloc(sizeof(*domain), GFP_KERNEL); + domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; diff --git a/trunk/drivers/md/bitmap.c b/trunk/drivers/md/bitmap.c index b6907118283a..6d03774b176e 100644 --- a/trunk/drivers/md/bitmap.c +++ b/trunk/drivers/md/bitmap.c @@ -1393,9 +1393,6 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto atomic_read(&bitmap->behind_writes), bitmap->mddev->bitmap_info.max_write_behind); } - if (bitmap->mddev->degraded) - /* Never clear bits or update events_cleared when degraded */ - success = 0; while (sectors) { sector_t blocks; @@ -1409,7 +1406,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto return; } - if (success && + if (success && !bitmap->mddev->degraded && bitmap->events_cleared < bitmap->mddev->events) { bitmap->events_cleared = bitmap->mddev->events; bitmap->need_sync = 1; diff --git a/trunk/drivers/md/linear.c b/trunk/drivers/md/linear.c index c3273efd08cb..627456542fb3 100644 --- a/trunk/drivers/md/linear.c +++ b/trunk/drivers/md/linear.c @@ -230,6 +230,7 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev) return -EINVAL; rdev->raid_disk = rdev->saved_raid_disk; + rdev->saved_raid_disk = -1; newconf = linear_conf(mddev,mddev->raid_disks+1); diff --git a/trunk/drivers/md/md.c b/trunk/drivers/md/md.c index ee981737edfc..f47f1f8ac44b 100644 --- a/trunk/drivers/md/md.c +++ b/trunk/drivers/md/md.c @@ -7360,8 +7360,7 @@ static int remove_and_add_spares(struct mddev *mddev) spares++; md_new_event(mddev); set_bit(MD_CHANGE_DEVS, &mddev->flags); - } else - break; + } } } } diff --git a/trunk/drivers/md/raid5.c b/trunk/drivers/md/raid5.c index 31670f8d6b65..858fdbb7eb07 100644 --- a/trunk/drivers/md/raid5.c +++ b/trunk/drivers/md/raid5.c @@ -3065,11 +3065,17 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) } } else if (test_bit(In_sync, &rdev->flags)) set_bit(R5_Insync, &dev->flags); - else { + else if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) /* in sync if before recovery_offset */ - if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) - set_bit(R5_Insync, &dev->flags); - } + set_bit(R5_Insync, &dev->flags); + else if (test_bit(R5_UPTODATE, &dev->flags) && + test_bit(R5_Expanded, &dev->flags)) + /* If we've reshaped into here, we assume it is Insync. + * We will shortly update recovery_offset to make + * it official. + */ + set_bit(R5_Insync, &dev->flags); + if (rdev && test_bit(R5_WriteError, &dev->flags)) { clear_bit(R5_Insync, &dev->flags); if (!test_bit(Faulty, &rdev->flags)) { diff --git a/trunk/drivers/media/common/tuners/mxl5007t.c b/trunk/drivers/media/common/tuners/mxl5007t.c index 7eb1bf75cd07..5d02221e99dd 100644 --- a/trunk/drivers/media/common/tuners/mxl5007t.c +++ b/trunk/drivers/media/common/tuners/mxl5007t.c @@ -488,9 +488,10 @@ static int mxl5007t_write_regs(struct mxl5007t_state *state, static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) { + u8 buf[2] = { 0xfb, reg }; struct i2c_msg msg[] = { { .addr = state->i2c_props.addr, .flags = 0, - .buf = ®, .len = 1 }, + .buf = buf, .len = 2 }, { .addr = state->i2c_props.addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, }; diff --git a/trunk/drivers/media/common/tuners/tda18218.c b/trunk/drivers/media/common/tuners/tda18218.c index aacfe2387e28..4fc29730a12c 100644 --- a/trunk/drivers/media/common/tuners/tda18218.c +++ b/trunk/drivers/media/common/tuners/tda18218.c @@ -141,7 +141,7 @@ static int tda18218_set_params(struct dvb_frontend *fe, switch (params->u.ofdm.bandwidth) { case BANDWIDTH_6_MHZ: LP_Fc = 0; - LO_Frac = params->frequency + 4000000; + LO_Frac = params->frequency + 3000000; break; case BANDWIDTH_7_MHZ: LP_Fc = 1; diff --git a/trunk/drivers/media/rc/ati_remote.c b/trunk/drivers/media/rc/ati_remote.c index 303f22ea04c0..01bb8daf4b09 100644 --- a/trunk/drivers/media/rc/ati_remote.c +++ b/trunk/drivers/media/rc/ati_remote.c @@ -189,7 +189,7 @@ struct ati_remote { dma_addr_t inbuf_dma; dma_addr_t outbuf_dma; - unsigned char old_data[2]; /* Detect duplicate events */ + unsigned char old_data; /* Detect duplicate events */ unsigned long old_jiffies; unsigned long acc_jiffies; /* handle acceleration */ unsigned long first_jiffies; @@ -221,35 +221,35 @@ struct ati_remote { /* Translation table from hardware messages to input events. */ static const struct { short kind; - unsigned char data1, data2; + unsigned char data; int type; unsigned int code; int value; } ati_remote_tbl[] = { /* Directional control pad axes */ - {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ - {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ - {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ - {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ + {KIND_ACCEL, 0x70, EV_REL, REL_X, -1}, /* left */ + {KIND_ACCEL, 0x71, EV_REL, REL_X, 1}, /* right */ + {KIND_ACCEL, 0x72, EV_REL, REL_Y, -1}, /* up */ + {KIND_ACCEL, 0x73, EV_REL, REL_Y, 1}, /* down */ /* Directional control pad diagonals */ - {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ - {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ - {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ - {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ + {KIND_LU, 0x74, EV_REL, 0, 0}, /* left up */ + {KIND_RU, 0x75, EV_REL, 0, 0}, /* right up */ + {KIND_LD, 0x77, EV_REL, 0, 0}, /* left down */ + {KIND_RD, 0x76, EV_REL, 0, 0}, /* right down */ /* "Mouse button" buttons */ - {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ - {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ - {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ - {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ + {KIND_LITERAL, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ + {KIND_LITERAL, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ + {KIND_LITERAL, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ + {KIND_LITERAL, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ /* Artificial "doubleclick" events are generated by the hardware. * They are mapped to the "side" and "extra" mouse buttons here. */ - {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ - {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ + {KIND_FILTERED, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ + {KIND_FILTERED, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ /* Non-mouse events are handled by rc-core */ - {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} + {KIND_END, 0x00, EV_MAX + 1, 0, 0} }; /* Local function prototypes */ @@ -396,25 +396,6 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne return retval; } -/* - * ati_remote_event_lookup - */ -static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) -{ - int i; - - for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { - /* - * Decide if the table entry matches the remote input. - */ - if (ati_remote_tbl[i].data1 == d1 && - ati_remote_tbl[i].data2 == d2) - return i; - - } - return -1; -} - /* * ati_remote_compute_accel * @@ -463,7 +444,15 @@ static void ati_remote_input_report(struct urb *urb) int index = -1; int acc; int remote_num; - unsigned char scancode[2]; + unsigned char scancode; + int i; + + /* + * data[0] = 0x14 + * data[1] = data[2] + data[3] + 0xd5 (a checksum byte) + * data[2] = the key code (with toggle bit in MSB with some models) + * data[3] = channel << 4 (the low 4 bits must be zero) + */ /* Deal with strange looking inputs */ if ( (urb->actual_length != 4) || (data[0] != 0x14) || @@ -472,6 +461,13 @@ static void ati_remote_input_report(struct urb *urb) return; } + if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) { + dbginfo(&ati_remote->interface->dev, + "wrong checksum in input: %02x %02x %02x %02x\n", + data[0], data[1], data[2], data[3]); + return; + } + /* Mask unwanted remote channels. */ /* note: remote_num is 0-based, channel 1 on remote == 0 here */ remote_num = (data[3] >> 4) & 0x0f; @@ -482,31 +478,30 @@ static void ati_remote_input_report(struct urb *urb) return; } - scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f)); - /* - * Some devices (e.g. SnapStream Firefly) use 8080 as toggle code, - * so we have to clear them. The first bit is a bit tricky as the - * "non-toggled" state depends on remote_num, so we xor it with the - * second bit which is only used for toggle. + * MSB is a toggle code, though only used by some devices + * (e.g. SnapStream Firefly) */ - scancode[0] ^= (data[2] & 0x80); - - scancode[1] = data[2] & ~0x80; + scancode = data[2] & 0x7f; - /* Look up event code index in mouse translation table. */ - index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]); + /* Look up event code index in the mouse translation table. */ + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { + if (scancode == ati_remote_tbl[i].data) { + index = i; + break; + } + } if (index >= 0) { dbginfo(&ati_remote->interface->dev, - "channel 0x%02x; mouse data %02x,%02x; index %d; keycode %d\n", - remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + "channel 0x%02x; mouse data %02x; index %d; keycode %d\n", + remote_num, data[2], index, ati_remote_tbl[index].code); if (!dev) return; /* no mouse device */ } else dbginfo(&ati_remote->interface->dev, - "channel 0x%02x; key data %02x,%02x, scancode %02x,%02x\n", - remote_num, data[1], data[2], scancode[0], scancode[1]); + "channel 0x%02x; key data %02x, scancode %02x\n", + remote_num, data[2], scancode); if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) { @@ -523,8 +518,7 @@ static void ati_remote_input_report(struct urb *urb) unsigned long now = jiffies; /* Filter duplicate events which happen "too close" together. */ - if (ati_remote->old_data[0] == data[1] && - ati_remote->old_data[1] == data[2] && + if (ati_remote->old_data == data[2] && time_before(now, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) { ati_remote->repeat_count++; @@ -533,8 +527,7 @@ static void ati_remote_input_report(struct urb *urb) ati_remote->first_jiffies = now; } - ati_remote->old_data[0] = data[1]; - ati_remote->old_data[1] = data[2]; + ati_remote->old_data = data[2]; ati_remote->old_jiffies = now; /* Ensure we skip at least the 4 first duplicate events (generated @@ -549,14 +542,13 @@ static void ati_remote_input_report(struct urb *urb) if (index < 0) { /* Not a mouse event, hand it to rc-core. */ - u32 rc_code = (scancode[0] << 8) | scancode[1]; /* * We don't use the rc-core repeat handling yet as * it would cause ghost repeats which would be a * regression for this driver. */ - rc_keydown_notimeout(ati_remote->rdev, rc_code, + rc_keydown_notimeout(ati_remote->rdev, scancode, data[2]); rc_keyup(ati_remote->rdev); return; @@ -607,8 +599,7 @@ static void ati_remote_input_report(struct urb *urb) input_sync(dev); ati_remote->old_jiffies = jiffies; - ati_remote->old_data[0] = data[1]; - ati_remote->old_data[1] = data[2]; + ati_remote->old_data = data[2]; } } diff --git a/trunk/drivers/media/rc/keymaps/rc-ati-x10.c b/trunk/drivers/media/rc/keymaps/rc-ati-x10.c index e1b8b2605c48..81506440eded 100644 --- a/trunk/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/trunk/drivers/media/rc/keymaps/rc-ati-x10.c @@ -27,55 +27,55 @@ #include static struct rc_map_table ati_x10[] = { - { 0xd20d, KEY_1 }, - { 0xd30e, KEY_2 }, - { 0xd40f, KEY_3 }, - { 0xd510, KEY_4 }, - { 0xd611, KEY_5 }, - { 0xd712, KEY_6 }, - { 0xd813, KEY_7 }, - { 0xd914, KEY_8 }, - { 0xda15, KEY_9 }, - { 0xdc17, KEY_0 }, - { 0xc500, KEY_A }, - { 0xc601, KEY_B }, - { 0xde19, KEY_C }, - { 0xe01b, KEY_D }, - { 0xe621, KEY_E }, - { 0xe823, KEY_F }, + { 0x0d, KEY_1 }, + { 0x0e, KEY_2 }, + { 0x0f, KEY_3 }, + { 0x10, KEY_4 }, + { 0x11, KEY_5 }, + { 0x12, KEY_6 }, + { 0x13, KEY_7 }, + { 0x14, KEY_8 }, + { 0x15, KEY_9 }, + { 0x17, KEY_0 }, + { 0x00, KEY_A }, + { 0x01, KEY_B }, + { 0x19, KEY_C }, + { 0x1b, KEY_D }, + { 0x21, KEY_E }, + { 0x23, KEY_F }, - { 0xdd18, KEY_KPENTER }, /* "check" */ - { 0xdb16, KEY_MENU }, /* "menu" */ - { 0xc702, KEY_POWER }, /* Power */ - { 0xc803, KEY_TV }, /* TV */ - { 0xc904, KEY_DVD }, /* DVD */ - { 0xca05, KEY_WWW }, /* WEB */ - { 0xcb06, KEY_BOOKMARKS }, /* "book" */ - { 0xcc07, KEY_EDIT }, /* "hand" */ - { 0xe11c, KEY_COFFEE }, /* "timer" */ - { 0xe520, KEY_FRONT }, /* "max" */ - { 0xe21d, KEY_LEFT }, /* left */ - { 0xe41f, KEY_RIGHT }, /* right */ - { 0xe722, KEY_DOWN }, /* down */ - { 0xdf1a, KEY_UP }, /* up */ - { 0xe31e, KEY_OK }, /* "OK" */ - { 0xce09, KEY_VOLUMEDOWN }, /* VOL + */ - { 0xcd08, KEY_VOLUMEUP }, /* VOL - */ - { 0xcf0a, KEY_MUTE }, /* MUTE */ - { 0xd00b, KEY_CHANNELUP }, /* CH + */ - { 0xd10c, KEY_CHANNELDOWN },/* CH - */ - { 0xec27, KEY_RECORD }, /* ( o) red */ - { 0xea25, KEY_PLAY }, /* ( >) */ - { 0xe924, KEY_REWIND }, /* (<<) */ - { 0xeb26, KEY_FORWARD }, /* (>>) */ - { 0xed28, KEY_STOP }, /* ([]) */ - { 0xee29, KEY_PAUSE }, /* ('') */ - { 0xf02b, KEY_PREVIOUS }, /* (<-) */ - { 0xef2a, KEY_NEXT }, /* (>+) */ - { 0xf22d, KEY_INFO }, /* PLAYING */ - { 0xf32e, KEY_HOME }, /* TOP */ - { 0xf42f, KEY_END }, /* END */ - { 0xf530, KEY_SELECT }, /* SELECT */ + { 0x18, KEY_KPENTER }, /* "check" */ + { 0x16, KEY_MENU }, /* "menu" */ + { 0x02, KEY_POWER }, /* Power */ + { 0x03, KEY_TV }, /* TV */ + { 0x04, KEY_DVD }, /* DVD */ + { 0x05, KEY_WWW }, /* WEB */ + { 0x06, KEY_BOOKMARKS }, /* "book" */ + { 0x07, KEY_EDIT }, /* "hand" */ + { 0x1c, KEY_COFFEE }, /* "timer" */ + { 0x20, KEY_FRONT }, /* "max" */ + { 0x1d, KEY_LEFT }, /* left */ + { 0x1f, KEY_RIGHT }, /* right */ + { 0x22, KEY_DOWN }, /* down */ + { 0x1a, KEY_UP }, /* up */ + { 0x1e, KEY_OK }, /* "OK" */ + { 0x09, KEY_VOLUMEDOWN }, /* VOL + */ + { 0x08, KEY_VOLUMEUP }, /* VOL - */ + { 0x0a, KEY_MUTE }, /* MUTE */ + { 0x0b, KEY_CHANNELUP }, /* CH + */ + { 0x0c, KEY_CHANNELDOWN },/* CH - */ + { 0x27, KEY_RECORD }, /* ( o) red */ + { 0x25, KEY_PLAY }, /* ( >) */ + { 0x24, KEY_REWIND }, /* (<<) */ + { 0x26, KEY_FORWARD }, /* (>>) */ + { 0x28, KEY_STOP }, /* ([]) */ + { 0x29, KEY_PAUSE }, /* ('') */ + { 0x2b, KEY_PREVIOUS }, /* (<-) */ + { 0x2a, KEY_NEXT }, /* (>+) */ + { 0x2d, KEY_INFO }, /* PLAYING */ + { 0x2e, KEY_HOME }, /* TOP */ + { 0x2f, KEY_END }, /* END */ + { 0x30, KEY_SELECT }, /* SELECT */ }; static struct rc_map_list ati_x10_map = { diff --git a/trunk/drivers/media/rc/keymaps/rc-medion-x10.c b/trunk/drivers/media/rc/keymaps/rc-medion-x10.c index 09e2cc01d110..479cdb897810 100644 --- a/trunk/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/trunk/drivers/media/rc/keymaps/rc-medion-x10.c @@ -25,70 +25,70 @@ #include static struct rc_map_table medion_x10[] = { - { 0xf12c, KEY_TV }, /* TV */ - { 0xf22d, KEY_VCR }, /* VCR */ - { 0xc904, KEY_DVD }, /* DVD */ - { 0xcb06, KEY_AUDIO }, /* MUSIC */ - - { 0xf32e, KEY_RADIO }, /* RADIO */ - { 0xca05, KEY_DIRECTORY }, /* PHOTO */ - { 0xf42f, KEY_INFO }, /* TV-PREVIEW */ - { 0xf530, KEY_LIST }, /* CHANNEL-LST */ - - { 0xe01b, KEY_SETUP }, /* SETUP */ - { 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */ - - { 0xcd08, KEY_VOLUMEDOWN }, /* VOL - */ - { 0xce09, KEY_VOLUMEUP }, /* VOL + */ - { 0xd00b, KEY_CHANNELUP }, /* CHAN + */ - { 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */ - { 0xc500, KEY_MUTE }, /* MUTE */ - - { 0xf732, KEY_RED }, /* red */ - { 0xf833, KEY_GREEN }, /* green */ - { 0xf934, KEY_YELLOW }, /* yellow */ - { 0xfa35, KEY_BLUE }, /* blue */ - { 0xdb16, KEY_TEXT }, /* TXT */ - - { 0xd20d, KEY_1 }, - { 0xd30e, KEY_2 }, - { 0xd40f, KEY_3 }, - { 0xd510, KEY_4 }, - { 0xd611, KEY_5 }, - { 0xd712, KEY_6 }, - { 0xd813, KEY_7 }, - { 0xd914, KEY_8 }, - { 0xda15, KEY_9 }, - { 0xdc17, KEY_0 }, - { 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */ - { 0xe520, KEY_DELETE }, /* DELETE */ - - { 0xfb36, KEY_KEYBOARD }, /* RENAME */ - { 0xdd18, KEY_SCREEN }, /* SNAPSHOT */ - - { 0xdf1a, KEY_UP }, /* up */ - { 0xe722, KEY_DOWN }, /* down */ - { 0xe21d, KEY_LEFT }, /* left */ - { 0xe41f, KEY_RIGHT }, /* right */ - { 0xe31e, KEY_OK }, /* OK */ - - { 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */ - { 0xfd38, KEY_EDIT }, /* EDIT IMAGE */ - - { 0xe924, KEY_REWIND }, /* rewind (<<) */ - { 0xea25, KEY_PLAY }, /* play ( >) */ - { 0xeb26, KEY_FORWARD }, /* forward (>>) */ - { 0xec27, KEY_RECORD }, /* record ( o) */ - { 0xed28, KEY_STOP }, /* stop ([]) */ - { 0xee29, KEY_PAUSE }, /* pause ('') */ - - { 0xe621, KEY_PREVIOUS }, /* prev */ - { 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */ - { 0xe823, KEY_NEXT }, /* next */ - { 0xde19, KEY_MENU }, /* MENU */ - { 0xff3a, KEY_LANGUAGE }, /* AUDIO */ - - { 0xc702, KEY_POWER }, /* POWER */ + { 0x2c, KEY_TV }, /* TV */ + { 0x2d, KEY_VCR }, /* VCR */ + { 0x04, KEY_DVD }, /* DVD */ + { 0x06, KEY_AUDIO }, /* MUSIC */ + + { 0x2e, KEY_RADIO }, /* RADIO */ + { 0x05, KEY_DIRECTORY }, /* PHOTO */ + { 0x2f, KEY_INFO }, /* TV-PREVIEW */ + { 0x30, KEY_LIST }, /* CHANNEL-LST */ + + { 0x1b, KEY_SETUP }, /* SETUP */ + { 0x31, KEY_VIDEO }, /* VIDEO DESKTOP */ + + { 0x08, KEY_VOLUMEDOWN }, /* VOL - */ + { 0x09, KEY_VOLUMEUP }, /* VOL + */ + { 0x0b, KEY_CHANNELUP }, /* CHAN + */ + { 0x0c, KEY_CHANNELDOWN }, /* CHAN - */ + { 0x00, KEY_MUTE }, /* MUTE */ + + { 0x32, KEY_RED }, /* red */ + { 0x33, KEY_GREEN }, /* green */ + { 0x34, KEY_YELLOW }, /* yellow */ + { 0x35, KEY_BLUE }, /* blue */ + { 0x16, KEY_TEXT }, /* TXT */ + + { 0x0d, KEY_1 }, + { 0x0e, KEY_2 }, + { 0x0f, KEY_3 }, + { 0x10, KEY_4 }, + { 0x11, KEY_5 }, + { 0x12, KEY_6 }, + { 0x13, KEY_7 }, + { 0x14, KEY_8 }, + { 0x15, KEY_9 }, + { 0x17, KEY_0 }, + { 0x1c, KEY_SEARCH }, /* TV/RAD, CH SRC */ + { 0x20, KEY_DELETE }, /* DELETE */ + + { 0x36, KEY_KEYBOARD }, /* RENAME */ + { 0x18, KEY_SCREEN }, /* SNAPSHOT */ + + { 0x1a, KEY_UP }, /* up */ + { 0x22, KEY_DOWN }, /* down */ + { 0x1d, KEY_LEFT }, /* left */ + { 0x1f, KEY_RIGHT }, /* right */ + { 0x1e, KEY_OK }, /* OK */ + + { 0x37, KEY_SELECT }, /* ACQUIRE IMAGE */ + { 0x38, KEY_EDIT }, /* EDIT IMAGE */ + + { 0x24, KEY_REWIND }, /* rewind (<<) */ + { 0x25, KEY_PLAY }, /* play ( >) */ + { 0x26, KEY_FORWARD }, /* forward (>>) */ + { 0x27, KEY_RECORD }, /* record ( o) */ + { 0x28, KEY_STOP }, /* stop ([]) */ + { 0x29, KEY_PAUSE }, /* pause ('') */ + + { 0x21, KEY_PREVIOUS }, /* prev */ + { 0x39, KEY_SWITCHVIDEOMODE }, /* F SCR */ + { 0x23, KEY_NEXT }, /* next */ + { 0x19, KEY_MENU }, /* MENU */ + { 0x3a, KEY_LANGUAGE }, /* AUDIO */ + + { 0x02, KEY_POWER }, /* POWER */ }; static struct rc_map_list medion_x10_map = { diff --git a/trunk/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/trunk/drivers/media/rc/keymaps/rc-snapstream-firefly.c index ef146520931c..c7f33ec719b4 100644 --- a/trunk/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/trunk/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -22,63 +22,63 @@ #include static struct rc_map_table snapstream_firefly[] = { - { 0xf12c, KEY_ZOOM }, /* Maximize */ - { 0xc702, KEY_CLOSE }, - - { 0xd20d, KEY_1 }, - { 0xd30e, KEY_2 }, - { 0xd40f, KEY_3 }, - { 0xd510, KEY_4 }, - { 0xd611, KEY_5 }, - { 0xd712, KEY_6 }, - { 0xd813, KEY_7 }, - { 0xd914, KEY_8 }, - { 0xda15, KEY_9 }, - { 0xdc17, KEY_0 }, - { 0xdb16, KEY_BACK }, - { 0xdd18, KEY_KPENTER }, /* ent */ - - { 0xce09, KEY_VOLUMEUP }, - { 0xcd08, KEY_VOLUMEDOWN }, - { 0xcf0a, KEY_MUTE }, - { 0xd00b, KEY_CHANNELUP }, - { 0xd10c, KEY_CHANNELDOWN }, - { 0xc500, KEY_VENDOR }, /* firefly */ - - { 0xf32e, KEY_INFO }, - { 0xf42f, KEY_OPTION }, - - { 0xe21d, KEY_LEFT }, - { 0xe41f, KEY_RIGHT }, - { 0xe722, KEY_DOWN }, - { 0xdf1a, KEY_UP }, - { 0xe31e, KEY_OK }, - - { 0xe11c, KEY_MENU }, - { 0xe520, KEY_EXIT }, - - { 0xec27, KEY_RECORD }, - { 0xea25, KEY_PLAY }, - { 0xed28, KEY_STOP }, - { 0xe924, KEY_REWIND }, - { 0xeb26, KEY_FORWARD }, - { 0xee29, KEY_PAUSE }, - { 0xf02b, KEY_PREVIOUS }, - { 0xef2a, KEY_NEXT }, - - { 0xcb06, KEY_AUDIO }, /* Music */ - { 0xca05, KEY_IMAGES }, /* Photos */ - { 0xc904, KEY_DVD }, - { 0xc803, KEY_TV }, - { 0xcc07, KEY_VIDEO }, - - { 0xc601, KEY_HELP }, - { 0xf22d, KEY_MODE }, /* Mouse */ - - { 0xde19, KEY_A }, - { 0xe01b, KEY_B }, - { 0xe621, KEY_C }, - { 0xe823, KEY_D }, + { 0x2c, KEY_ZOOM }, /* Maximize */ + { 0x02, KEY_CLOSE }, + + { 0x0d, KEY_1 }, + { 0x0e, KEY_2 }, + { 0x0f, KEY_3 }, + { 0x10, KEY_4 }, + { 0x11, KEY_5 }, + { 0x12, KEY_6 }, + { 0x13, KEY_7 }, + { 0x14, KEY_8 }, + { 0x15, KEY_9 }, + { 0x17, KEY_0 }, + { 0x16, KEY_BACK }, + { 0x18, KEY_KPENTER }, /* ent */ + + { 0x09, KEY_VOLUMEUP }, + { 0x08, KEY_VOLUMEDOWN }, + { 0x0a, KEY_MUTE }, + { 0x0b, KEY_CHANNELUP }, + { 0x0c, KEY_CHANNELDOWN }, + { 0x00, KEY_VENDOR }, /* firefly */ + + { 0x2e, KEY_INFO }, + { 0x2f, KEY_OPTION }, + + { 0x1d, KEY_LEFT }, + { 0x1f, KEY_RIGHT }, + { 0x22, KEY_DOWN }, + { 0x1a, KEY_UP }, + { 0x1e, KEY_OK }, + + { 0x1c, KEY_MENU }, + { 0x20, KEY_EXIT }, + + { 0x27, KEY_RECORD }, + { 0x25, KEY_PLAY }, + { 0x28, KEY_STOP }, + { 0x24, KEY_REWIND }, + { 0x26, KEY_FORWARD }, + { 0x29, KEY_PAUSE }, + { 0x2b, KEY_PREVIOUS }, + { 0x2a, KEY_NEXT }, + + { 0x06, KEY_AUDIO }, /* Music */ + { 0x05, KEY_IMAGES }, /* Photos */ + { 0x04, KEY_DVD }, + { 0x03, KEY_TV }, + { 0x07, KEY_VIDEO }, + + { 0x01, KEY_HELP }, + { 0x2d, KEY_MODE }, /* Mouse */ + + { 0x19, KEY_A }, + { 0x1b, KEY_B }, + { 0x21, KEY_C }, + { 0x23, KEY_D }, }; static struct rc_map_list snapstream_firefly_map = { diff --git a/trunk/drivers/media/video/au0828/au0828-cards.c b/trunk/drivers/media/video/au0828/au0828-cards.c index 39fc923fc46b..1c6015a04f96 100644 --- a/trunk/drivers/media/video/au0828/au0828-cards.c +++ b/trunk/drivers/media/video/au0828/au0828-cards.c @@ -162,11 +162,14 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) switch (tv.model) { case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */ case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ break; @@ -324,6 +327,10 @@ struct usb_device_id au0828_usb_id_table[] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, { USB_DEVICE(0x2040, 0x8200), .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, + { USB_DEVICE(0x2040, 0x7260), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7213), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { }, }; diff --git a/trunk/drivers/media/video/gspca/gspca.c b/trunk/drivers/media/video/gspca/gspca.c index 881e04c7ffe6..2ca10dfec91f 100644 --- a/trunk/drivers/media/video/gspca/gspca.c +++ b/trunk/drivers/media/video/gspca/gspca.c @@ -838,13 +838,13 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->usb_err = 0; /* do the specific subdriver stuff before endpoint selection */ - gspca_dev->alt = 0; + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + gspca_dev->alt = gspca_dev->cam.bulk ? intf->num_altsetting : 0; if (gspca_dev->sd_desc->isoc_init) { ret = gspca_dev->sd_desc->isoc_init(gspca_dev); if (ret < 0) goto unlock; } - intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK : USB_ENDPOINT_XFER_ISOC; @@ -957,7 +957,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) ret = -EIO; goto out; } - alt = ep_tb[--alt_idx].alt; + gspca_dev->alt = ep_tb[--alt_idx].alt; } } out: diff --git a/trunk/drivers/media/video/m5mols/m5mols.h b/trunk/drivers/media/video/m5mols/m5mols.h index 89d09a8914f8..82c8817bd32d 100644 --- a/trunk/drivers/media/video/m5mols/m5mols.h +++ b/trunk/drivers/media/video/m5mols/m5mols.h @@ -162,7 +162,6 @@ struct m5mols_version { * @pad: media pad * @ffmt: current fmt according to resolution type * @res_type: current resolution type - * @code: current code * @irq_waitq: waitqueue for the capture * @work_irq: workqueue for the IRQ * @flags: state variable for the interrupt handler @@ -192,7 +191,6 @@ struct m5mols_info { struct media_pad pad; struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; int res_type; - enum v4l2_mbus_pixelcode code; wait_queue_head_t irq_waitq; struct work_struct work_irq; unsigned long flags; diff --git a/trunk/drivers/media/video/m5mols/m5mols_core.c b/trunk/drivers/media/video/m5mols/m5mols_core.c index 05ab3700647e..e0f09e531800 100644 --- a/trunk/drivers/media/video/m5mols/m5mols_core.c +++ b/trunk/drivers/media/video/m5mols/m5mols_core.c @@ -334,7 +334,7 @@ int m5mols_mode(struct m5mols_info *info, u8 mode) int ret = -EINVAL; u8 reg; - if (mode < REG_PARAMETER && mode > REG_CAPTURE) + if (mode < REG_PARAMETER || mode > REG_CAPTURE) return ret; ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); @@ -511,9 +511,6 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct m5mols_info *info = to_m5mols(sd); struct v4l2_mbus_framefmt *format; - if (fmt->pad != 0) - return -EINVAL; - format = __find_format(info, fh, fmt->which, info->res_type); if (!format) return -EINVAL; @@ -532,9 +529,6 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, u32 resolution = 0; int ret; - if (fmt->pad != 0) - return -EINVAL; - ret = __find_resolution(sd, format, &type, &resolution); if (ret < 0) return ret; @@ -543,13 +537,14 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (!sfmt) return 0; - *sfmt = m5mols_default_ffmt[type]; - sfmt->width = format->width; - sfmt->height = format->height; + + format->code = m5mols_default_ffmt[type].code; + format->colorspace = V4L2_COLORSPACE_JPEG; + format->field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + *sfmt = *format; info->resolution = resolution; - info->code = format->code; info->res_type = type; } @@ -626,13 +621,14 @@ static int m5mols_start_monitor(struct m5mols_info *info) static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) { struct m5mols_info *info = to_m5mols(sd); + u32 code = info->ffmt[info->res_type].code; if (enable) { int ret = -EINVAL; - if (is_code(info->code, M5MOLS_RESTYPE_MONITOR)) + if (is_code(code, M5MOLS_RESTYPE_MONITOR)) ret = m5mols_start_monitor(info); - if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE)) + if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) ret = m5mols_start_capture(info); return ret; diff --git a/trunk/drivers/media/video/mt9m111.c b/trunk/drivers/media/video/mt9m111.c index cf2c0fb95f2f..398f96ffd35e 100644 --- a/trunk/drivers/media/video/mt9m111.c +++ b/trunk/drivers/media/video/mt9m111.c @@ -955,6 +955,7 @@ static int mt9m111_probe(struct i2c_client *client, mt9m111->rect.height = MT9M111_MAX_HEIGHT; mt9m111->fmt = &mt9m111_colour_fmts[0]; mt9m111->lastpage = -1; + mutex_init(&mt9m111->power_lock); ret = mt9m111_video_probe(client); if (ret) { diff --git a/trunk/drivers/media/video/mt9t112.c b/trunk/drivers/media/video/mt9t112.c index 32114a3c0ca7..7b34b11daf24 100644 --- a/trunk/drivers/media/video/mt9t112.c +++ b/trunk/drivers/media/video/mt9t112.c @@ -1083,8 +1083,10 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); ret = mt9t112_camera_probe(client); - if (ret) + if (ret) { kfree(priv); + return ret; + } /* Cannot fail: using the default supported pixel code */ mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); diff --git a/trunk/drivers/media/video/omap/omap_vout.c b/trunk/drivers/media/video/omap/omap_vout.c index 9c5c19f142de..ee0d0b39cd17 100644 --- a/trunk/drivers/media/video/omap/omap_vout.c +++ b/trunk/drivers/media/video/omap/omap_vout.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -2169,6 +2170,14 @@ static int __init omap_vout_probe(struct platform_device *pdev) vid_dev->num_displays = 0; for_each_dss_dev(dssdev) { omap_dss_get_device(dssdev); + + if (!dssdev->driver) { + dev_warn(&pdev->dev, "no driver for display: %s\n", + dssdev->name); + omap_dss_put_device(dssdev); + continue; + } + vid_dev->displays[vid_dev->num_displays++] = dssdev; } diff --git a/trunk/drivers/media/video/omap1_camera.c b/trunk/drivers/media/video/omap1_camera.c index e87ae2f634b2..6a6cf388bae4 100644 --- a/trunk/drivers/media/video/omap1_camera.c +++ b/trunk/drivers/media/video/omap1_camera.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/trunk/drivers/media/video/omap24xxcam-dma.c b/trunk/drivers/media/video/omap24xxcam-dma.c index 1d54b86c936b..3ea38a8def8e 100644 --- a/trunk/drivers/media/video/omap24xxcam-dma.c +++ b/trunk/drivers/media/video/omap24xxcam-dma.c @@ -506,7 +506,7 @@ int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma, unsigned long flags; struct sgdma_state *sg_state; - if ((sglen < 0) || ((sglen > 0) & !sglist)) + if ((sglen < 0) || ((sglen > 0) && !sglist)) return -EINVAL; spin_lock_irqsave(&sgdma->lock, flags); diff --git a/trunk/drivers/media/video/omap3isp/ispccdc.c b/trunk/drivers/media/video/omap3isp/ispccdc.c index b0b0fa5a3572..54a4a3f22e2e 100644 --- a/trunk/drivers/media/video/omap3isp/ispccdc.c +++ b/trunk/drivers/media/video/omap3isp/ispccdc.c @@ -1408,7 +1408,7 @@ static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) { struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->video_out.video.entity); - struct video_device *vdev = &ccdc->subdev.devnode; + struct video_device *vdev = ccdc->subdev.devnode; struct v4l2_event event; memset(&event, 0, sizeof(event)); diff --git a/trunk/drivers/media/video/omap3isp/ispstat.c b/trunk/drivers/media/video/omap3isp/ispstat.c index 68d539456c55..bc0b2c7349b9 100644 --- a/trunk/drivers/media/video/omap3isp/ispstat.c +++ b/trunk/drivers/media/video/omap3isp/ispstat.c @@ -496,7 +496,7 @@ static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) static void isp_stat_queue_event(struct ispstat *stat, int err) { - struct video_device *vdev = &stat->subdev.devnode; + struct video_device *vdev = stat->subdev.devnode; struct v4l2_event event; struct omap3isp_stat_event_status *status = (void *)event.u.data; diff --git a/trunk/drivers/media/video/omap3isp/ispvideo.c b/trunk/drivers/media/video/omap3isp/ispvideo.c index d1000723c5ae..f2290578448c 100644 --- a/trunk/drivers/media/video/omap3isp/ispvideo.c +++ b/trunk/drivers/media/video/omap3isp/ispvideo.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/ov6650.c b/trunk/drivers/media/video/ov6650.c index 9f2d26b1d4cb..6806345ec2f0 100644 --- a/trunk/drivers/media/video/ov6650.c +++ b/trunk/drivers/media/video/ov6650.c @@ -540,7 +540,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; + struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); struct soc_camera_sense *sense = icd->sense; struct ov6650 *priv = to_ov6650(client); bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); diff --git a/trunk/drivers/media/video/s5p-fimc/fimc-capture.c b/trunk/drivers/media/video/s5p-fimc/fimc-capture.c index c8d91b0cd9bd..2cc3b9166724 100644 --- a/trunk/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/trunk/drivers/media/video/s5p-fimc/fimc-capture.c @@ -98,6 +98,10 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } set_bit(ST_CAPT_SUSPENDED, &fimc->state); + + fimc_hw_reset(fimc); + cap->buf_index = 0; + spin_unlock_irqrestore(&fimc->slock, flags); if (streaming) @@ -137,7 +141,7 @@ int fimc_capture_config_update(struct fimc_ctx *ctx) struct fimc_dev *fimc = ctx->fimc_dev; int ret; - if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) + if (!test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) return 0; spin_lock(&ctx->slock); @@ -150,7 +154,7 @@ int fimc_capture_config_update(struct fimc_ctx *ctx) fimc_hw_set_rotation(ctx); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_hw_set_out_dma(ctx); - set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock(&ctx->slock); return ret; @@ -164,7 +168,6 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) int min_bufs; int ret; - fimc_hw_reset(fimc); vid_cap->frame_count = 0; ret = fimc_init_capture(fimc); @@ -523,7 +526,7 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w; min_w = ctx->state & FIMC_DST_CROP ? dst->width : var->min_out_pixsize; min_h = ctx->state & FIMC_DST_CROP ? dst->height : var->min_out_pixsize; - if (fimc->id == 1 && var->pix_hoff) + if (var->min_vsize_align == 1 && !rotation) align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1; depth = fimc_get_format_depth(ffmt); @@ -1239,6 +1242,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, mutex_lock(&fimc->lock); set_frame_bounds(ff, mf->width, mf->height); + fimc->vid_cap.mf = *mf; ff->fmt = ffmt; /* Reset the crop rectangle if required. */ @@ -1375,7 +1379,7 @@ static void fimc_destroy_capture_subdev(struct fimc_dev *fimc) media_entity_cleanup(&sd->entity); v4l2_device_unregister_subdev(sd); kfree(sd); - sd = NULL; + fimc->vid_cap.subdev = NULL; } /* Set default format at the sensor and host interface */ diff --git a/trunk/drivers/media/video/s5p-fimc/fimc-core.c b/trunk/drivers/media/video/s5p-fimc/fimc-core.c index 19ca6db38b2f..07c6254faee3 100644 --- a/trunk/drivers/media/video/s5p-fimc/fimc-core.c +++ b/trunk/drivers/media/video/s5p-fimc/fimc-core.c @@ -37,7 +37,7 @@ static char *fimc_clocks[MAX_FIMC_CLOCKS] = { static struct fimc_fmt fimc_formats[] = { { .name = "RGB565", - .fourcc = V4L2_PIX_FMT_RGB565X, + .fourcc = V4L2_PIX_FMT_RGB565, .depth = { 16 }, .color = S5P_FIMC_RGB565, .memplanes = 1, @@ -1038,12 +1038,11 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) mod_x = 6; /* 64 x 32 pixels tile */ mod_y = 5; } else { - if (fimc->id == 1 && variant->pix_hoff) + if (variant->min_vsize_align == 1) mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; else - mod_y = mod_x; + mod_y = ffs(variant->min_vsize_align) - 1; } - dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_w); v4l_bound_align_image(&pix->width, 16, max_w, mod_x, &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); @@ -1226,10 +1225,10 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; /* Get pixel alignment constraints. */ - if (fimc->id == 1 && fimc->variant->pix_hoff) + if (fimc->variant->min_vsize_align == 1) halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; else - halign = ffs(min_size) - 1; + halign = ffs(fimc->variant->min_vsize_align) - 1; for (i = 0; i < f->fmt->colplanes; i++) depth += f->fmt->depth[i]; @@ -1615,7 +1614,6 @@ static int fimc_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; fimc->pdata = pdata; - set_bit(ST_LPM, &fimc->state); init_waitqueue_head(&fimc->irq_queue); spin_lock_init(&fimc->slock); @@ -1707,8 +1705,6 @@ static int fimc_runtime_resume(struct device *dev) /* Enable clocks and perform basic initalization */ clk_enable(fimc->clock[CLK_GATE]); fimc_hw_reset(fimc); - if (fimc->variant->out_buf_count > 4) - fimc_hw_set_dma_seq(fimc, 0xF); /* Resume the capture or mem-to-mem device */ if (fimc_capture_busy(fimc)) @@ -1750,8 +1746,6 @@ static int fimc_resume(struct device *dev) return 0; } fimc_hw_reset(fimc); - if (fimc->variant->out_buf_count > 4) - fimc_hw_set_dma_seq(fimc, 0xF); spin_unlock_irqrestore(&fimc->slock, flags); if (fimc_capture_busy(fimc)) @@ -1780,7 +1774,6 @@ static int __devexit fimc_remove(struct platform_device *pdev) struct fimc_dev *fimc = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); - fimc_runtime_suspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); @@ -1840,6 +1833,7 @@ static struct samsung_fimc_variant fimc0_variant_s5p = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[0], }; @@ -1849,6 +1843,7 @@ static struct samsung_fimc_variant fimc2_variant_s5p = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[1], }; @@ -1861,6 +1856,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv210 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[1], }; @@ -1874,6 +1870,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 1, + .min_vsize_align = 1, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[2], }; @@ -1884,6 +1881,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[2], }; @@ -1898,6 +1896,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, + .min_vsize_align = 1, .out_buf_count = 32, .pix_limit = &s5p_pix_limit[1], }; @@ -1910,6 +1909,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, + .min_vsize_align = 1, .out_buf_count = 32, .pix_limit = &s5p_pix_limit[3], }; diff --git a/trunk/drivers/media/video/s5p-fimc/fimc-core.h b/trunk/drivers/media/video/s5p-fimc/fimc-core.h index a6936dad5b10..c7f01c47b20f 100644 --- a/trunk/drivers/media/video/s5p-fimc/fimc-core.h +++ b/trunk/drivers/media/video/s5p-fimc/fimc-core.h @@ -377,6 +377,7 @@ struct fimc_pix_limit { * @min_inp_pixsize: minimum input pixel size * @min_out_pixsize: minimum output pixel size * @hor_offs_align: horizontal pixel offset aligment + * @min_vsize_align: minimum vertical pixel size alignment * @out_buf_count: the number of buffers in output DMA sequence */ struct samsung_fimc_variant { @@ -390,6 +391,7 @@ struct samsung_fimc_variant { u16 min_inp_pixsize; u16 min_out_pixsize; u16 hor_offs_align; + u16 min_vsize_align; u16 out_buf_count; }; diff --git a/trunk/drivers/media/video/s5p-fimc/fimc-mdevice.c b/trunk/drivers/media/video/s5p-fimc/fimc-mdevice.c index cc337b1de913..615c862f0360 100644 --- a/trunk/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/trunk/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -220,6 +220,7 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter, s_info->pdata->board_info, NULL); if (IS_ERR_OR_NULL(sd)) { + i2c_put_adapter(adapter); v4l2_err(&fmd->v4l2_dev, "Failed to acquire subdev\n"); return NULL; } @@ -234,12 +235,15 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct i2c_adapter *adapter; if (!client) return; v4l2_device_unregister_subdev(sd); + adapter = client->adapter; i2c_unregister_device(client); - i2c_put_adapter(client->adapter); + if (adapter) + i2c_put_adapter(adapter); } static int fimc_md_register_sensor_entities(struct fimc_md *fmd) @@ -381,20 +385,28 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) static int fimc_md_register_video_nodes(struct fimc_md *fmd) { + struct video_device *vdev; int i, ret = 0; for (i = 0; i < FIMC_MAX_DEVS && !ret; i++) { if (!fmd->fimc[i]) continue; - if (fmd->fimc[i]->m2m.vfd) - ret = video_register_device(fmd->fimc[i]->m2m.vfd, - VFL_TYPE_GRABBER, -1); - if (ret) - break; - if (fmd->fimc[i]->vid_cap.vfd) - ret = video_register_device(fmd->fimc[i]->vid_cap.vfd, - VFL_TYPE_GRABBER, -1); + vdev = fmd->fimc[i]->m2m.vfd; + if (vdev) { + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) + break; + v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n", + vdev->name, video_device_node_name(vdev)); + } + + vdev = fmd->fimc[i]->vid_cap.vfd; + if (vdev == NULL) + continue; + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n", + vdev->name, video_device_node_name(vdev)); } return ret; @@ -502,7 +514,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) if (WARN(csis == NULL, "MIPI-CSI interface specified " "but s5p-csis module is not loaded!\n")) - continue; + return -EINVAL; ret = media_entity_create_link(&sensor->entity, 0, &csis->entity, CSIS_PAD_SINK, @@ -742,9 +754,6 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) struct fimc_md *fmd; int ret; - if (WARN(!pdev->dev.platform_data, "Platform data not specified!\n")) - return -EINVAL; - fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL); if (!fmd) return -ENOMEM; @@ -782,9 +791,11 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) if (ret) goto err3; - ret = fimc_md_register_sensor_entities(fmd); - if (ret) - goto err3; + if (pdev->dev.platform_data) { + ret = fimc_md_register_sensor_entities(fmd); + if (ret) + goto err3; + } ret = fimc_md_create_links(fmd); if (ret) goto err3; diff --git a/trunk/drivers/media/video/s5p-fimc/fimc-reg.c b/trunk/drivers/media/video/s5p-fimc/fimc-reg.c index 20e664e34163..44f5c2d1920b 100644 --- a/trunk/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/trunk/drivers/media/video/s5p-fimc/fimc-reg.c @@ -35,6 +35,9 @@ void fimc_hw_reset(struct fimc_dev *dev) cfg = readl(dev->regs + S5P_CIGCTRL); cfg &= ~S5P_CIGCTRL_SWRST; writel(cfg, dev->regs + S5P_CIGCTRL); + + if (dev->variant->out_buf_count > 4) + fimc_hw_set_dma_seq(dev, 0xF); } static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) @@ -251,7 +254,14 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx) struct fimc_scaler *sc = &ctx->scaler; struct fimc_frame *src_frame = &ctx->s_frame; struct fimc_frame *dst_frame = &ctx->d_frame; - u32 cfg = 0; + + u32 cfg = readl(dev->regs + S5P_CISCCTRL); + + cfg &= ~(S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE | + S5P_CISCCTRL_SCALEUP_H | S5P_CISCCTRL_SCALEUP_V | + S5P_CISCCTRL_SCALERBYPASS | S5P_CISCCTRL_ONE2ONE | + S5P_CISCCTRL_INRGB_FMT_MASK | S5P_CISCCTRL_OUTRGB_FMT_MASK | + S5P_CISCCTRL_INTERLACE | S5P_CISCCTRL_RGB_EXT); if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE); @@ -308,9 +318,9 @@ void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) fimc_hw_set_scaler(ctx); cfg = readl(dev->regs + S5P_CISCCTRL); + cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); if (variant->has_mainscaler_ext) { - cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio); cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio); writel(cfg, dev->regs + S5P_CISCCTRL); @@ -323,7 +333,6 @@ void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio); writel(cfg, dev->regs + S5P_CIEXTEN); } else { - cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio); cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio); writel(cfg, dev->regs + S5P_CISCCTRL); diff --git a/trunk/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/trunk/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index 1e8cdb77d4b8..dff9dc798795 100644 --- a/trunk/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/trunk/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -61,7 +61,7 @@ static struct s5p_mfc_fmt formats[] = { .num_planes = 1, }, { - .name = "H264 Encoded Stream", + .name = "H263 Encoded Stream", .fourcc = V4L2_PIX_FMT_H263, .codec_mode = S5P_FIMV_CODEC_H263_ENC, .type = MFC_FMT_ENC, diff --git a/trunk/drivers/media/video/s5p-tv/mixer_video.c b/trunk/drivers/media/video/s5p-tv/mixer_video.c index e16d3a4bc1dc..b47d0c06ecf5 100644 --- a/trunk/drivers/media/video/s5p-tv/mixer_video.c +++ b/trunk/drivers/media/video/s5p-tv/mixer_video.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/trunk/drivers/media/video/sh_mobile_ceu_camera.c b/trunk/drivers/media/video/sh_mobile_ceu_camera.c index f390682629cf..c51decfcae19 100644 --- a/trunk/drivers/media/video/sh_mobile_ceu_camera.c +++ b/trunk/drivers/media/video/sh_mobile_ceu_camera.c @@ -566,8 +566,10 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) ret = sh_mobile_ceu_soft_reset(pcdev); csi2_sd = find_csi2(pcdev); - if (csi2_sd) - csi2_sd->grp_id = (long)icd; + if (csi2_sd) { + csi2_sd->grp_id = soc_camera_grp_id(icd); + v4l2_set_subdev_hostdata(csi2_sd, icd); + } ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { @@ -768,7 +770,7 @@ static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, { if (pcdev->csi2_pdev) { struct v4l2_subdev *csi2_sd = find_csi2(pcdev); - if (csi2_sd && csi2_sd->grp_id == (u32)icd) + if (csi2_sd && csi2_sd->grp_id == soc_camera_grp_id(icd)) return csi2_sd; } @@ -1089,8 +1091,9 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int /* Try 2560x1920, 1280x960, 640x480, 320x240 */ mf.width = 2560 >> shift; mf.height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, - s_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + s_mbus_fmt, &mf); if (ret < 0) return ret; shift++; @@ -1389,7 +1392,8 @@ static int client_s_fmt(struct soc_camera_device *icd, bool ceu_1to1; int ret; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, s_mbus_fmt, mf); if (ret < 0) return ret; @@ -1426,8 +1430,9 @@ static int client_s_fmt(struct soc_camera_device *icd, tmp_h = min(2 * tmp_h, max_height); mf->width = tmp_w; mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, - s_mbus_fmt, mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + s_mbus_fmt, mf); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); if (ret < 0) { @@ -1580,8 +1585,9 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, } if (interm_width < icd->user_width || interm_height < icd->user_height) { - ret = v4l2_device_call_until_err(sd->v4l2_dev, (int)icd, video, - s_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + s_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1867,7 +1873,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, mf.code = xlate->code; mf.colorspace = pix->colorspace; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), + video, try_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1891,8 +1898,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, */ mf.width = 2560; mf.height = 1920; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, - try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + try_mbus_fmt, &mf); if (ret < 0) { /* Shouldn't actually happen... */ dev_err(icd->parent, diff --git a/trunk/drivers/media/video/sh_mobile_csi2.c b/trunk/drivers/media/video/sh_mobile_csi2.c index ea4f0473ed3b..8a652b53ff7e 100644 --- a/trunk/drivers/media/video/sh_mobile_csi2.c +++ b/trunk/drivers/media/video/sh_mobile_csi2.c @@ -143,7 +143,7 @@ static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); - struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; + struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2, .flags = priv->mipi_flags}; @@ -202,7 +202,7 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) static int sh_csi2_client_connect(struct sh_csi2 *priv) { struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; - struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; + struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev); struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); struct device *dev = v4l2_get_subdevdata(&priv->subdev); struct v4l2_mbus_config cfg; diff --git a/trunk/drivers/media/video/soc_camera.c b/trunk/drivers/media/video/soc_camera.c index b72580c38957..62e4312515cb 100644 --- a/trunk/drivers/media/video/soc_camera.c +++ b/trunk/drivers/media/video/soc_camera.c @@ -1103,7 +1103,8 @@ static int soc_camera_probe(struct soc_camera_device *icd) } sd = soc_camera_to_subdev(icd); - sd->grp_id = (long)icd; + sd->grp_id = soc_camera_grp_id(icd); + v4l2_set_subdev_hostdata(sd, icd); if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler)) goto ectrl; diff --git a/trunk/drivers/mfd/ab5500-debugfs.c b/trunk/drivers/mfd/ab5500-debugfs.c index 43c0ebb81956..b7b2d3483fd4 100644 --- a/trunk/drivers/mfd/ab5500-debugfs.c +++ b/trunk/drivers/mfd/ab5500-debugfs.c @@ -4,7 +4,7 @@ * Debugfs support for the AB5500 MFD driver */ -#include +#include #include #include #include diff --git a/trunk/drivers/mfd/ab8500-core.c b/trunk/drivers/mfd/ab8500-core.c index 1e9173804ede..d3d572b2317b 100644 --- a/trunk/drivers/mfd/ab8500-core.c +++ b/trunk/drivers/mfd/ab8500-core.c @@ -620,6 +620,7 @@ static struct resource __devinitdata ab8500_fg_resources[] = { static struct resource __devinitdata ab8500_chargalg_resources[] = {}; +#ifdef CONFIG_DEBUG_FS static struct resource __devinitdata ab8500_debug_resources[] = { { .name = "IRQ_FIRST", @@ -634,6 +635,7 @@ static struct resource __devinitdata ab8500_debug_resources[] = { .flags = IORESOURCE_IRQ, }, }; +#endif static struct resource __devinitdata ab8500_usb_resources[] = { { diff --git a/trunk/drivers/mfd/adp5520.c b/trunk/drivers/mfd/adp5520.c index f1d88483112c..8d816cce8322 100644 --- a/trunk/drivers/mfd/adp5520.c +++ b/trunk/drivers/mfd/adp5520.c @@ -109,7 +109,7 @@ int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask) ret = __adp5520_read(chip->client, reg, ®_val); - if (!ret && ((reg_val & bit_mask) == 0)) { + if (!ret && ((reg_val & bit_mask) != bit_mask)) { reg_val |= bit_mask; ret = __adp5520_write(chip->client, reg, reg_val); } diff --git a/trunk/drivers/mfd/da903x.c b/trunk/drivers/mfd/da903x.c index 1b79c37fd599..1924b857a0fb 100644 --- a/trunk/drivers/mfd/da903x.c +++ b/trunk/drivers/mfd/da903x.c @@ -182,7 +182,7 @@ int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask) if (ret) goto out; - if ((reg_val & bit_mask) == 0) { + if ((reg_val & bit_mask) != bit_mask) { reg_val |= bit_mask; ret = __da903x_write(chip->client, reg, reg_val); } @@ -549,6 +549,7 @@ static int __devexit da903x_remove(struct i2c_client *client) struct da903x_chip *chip = i2c_get_clientdata(client); da903x_remove_subdevs(chip); + free_irq(client->irq, chip); kfree(chip); return 0; } diff --git a/trunk/drivers/mfd/jz4740-adc.c b/trunk/drivers/mfd/jz4740-adc.c index 1e9ee533eacb..ef39528088f2 100644 --- a/trunk/drivers/mfd/jz4740-adc.c +++ b/trunk/drivers/mfd/jz4740-adc.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/mfd/tps6586x.c b/trunk/drivers/mfd/tps6586x.c index bba26d96c240..a5ddf31b60ca 100644 --- a/trunk/drivers/mfd/tps6586x.c +++ b/trunk/drivers/mfd/tps6586x.c @@ -197,7 +197,7 @@ int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask) if (ret) goto out; - if ((reg_val & bit_mask) == 0) { + if ((reg_val & bit_mask) != bit_mask) { reg_val |= bit_mask; ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val); } diff --git a/trunk/drivers/mfd/tps65910.c b/trunk/drivers/mfd/tps65910.c index 6f5b8cf2f652..c1da84bc1573 100644 --- a/trunk/drivers/mfd/tps65910.c +++ b/trunk/drivers/mfd/tps65910.c @@ -120,7 +120,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) goto out; } - data &= mask; + data &= ~mask; err = tps65910_i2c_write(tps65910, reg, 1, &data); if (err) dev_err(tps65910->dev, "write to reg %x failed\n", reg); diff --git a/trunk/drivers/mfd/twl-core.c b/trunk/drivers/mfd/twl-core.c index bfbd66021afd..61e70cfaa774 100644 --- a/trunk/drivers/mfd/twl-core.c +++ b/trunk/drivers/mfd/twl-core.c @@ -363,13 +363,13 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); return -EPERM; } - sid = twl_map[mod_no].sid; - twl = &twl_modules[sid]; - if (unlikely(!inuse)) { - pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); + pr_err("%s: not initialized\n", DRIVER_NAME); return -EPERM; } + sid = twl_map[mod_no].sid; + twl = &twl_modules[sid]; + mutex_lock(&twl->xfer_lock); /* * [MSG1]: fill the register address data @@ -420,13 +420,13 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); return -EPERM; } - sid = twl_map[mod_no].sid; - twl = &twl_modules[sid]; - if (unlikely(!inuse)) { - pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); + pr_err("%s: not initialized\n", DRIVER_NAME); return -EPERM; } + sid = twl_map[mod_no].sid; + twl = &twl_modules[sid]; + mutex_lock(&twl->xfer_lock); /* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0]; diff --git a/trunk/drivers/mfd/twl4030-irq.c b/trunk/drivers/mfd/twl4030-irq.c index f062c8cc6c38..29f11e0765fe 100644 --- a/trunk/drivers/mfd/twl4030-irq.c +++ b/trunk/drivers/mfd/twl4030-irq.c @@ -432,6 +432,7 @@ struct sih_agent { u32 edge_change; struct mutex irq_lock; + char *irq_name; }; /*----------------------------------------------------------------------*/ @@ -589,7 +590,7 @@ static inline int sih_read_isr(const struct sih *sih) * Generic handler for SIH interrupts ... we "know" this is called * in task context, with IRQs enabled. */ -static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) +static irqreturn_t handle_twl4030_sih(int irq, void *data) { struct sih_agent *agent = irq_get_handler_data(irq); const struct sih *sih = agent->sih; @@ -602,7 +603,7 @@ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) pr_err("twl4030: %s SIH, read ISR error %d\n", sih->name, isr); /* REVISIT: recover; eventually mask it all, etc */ - return; + return IRQ_HANDLED; } while (isr) { @@ -616,6 +617,7 @@ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) pr_err("twl4030: %s SIH, invalid ISR bit %d\n", sih->name, irq); } + return IRQ_HANDLED; } static unsigned twl4030_irq_next; @@ -668,18 +670,19 @@ int twl4030_sih_setup(int module) activate_irq(irq); } - status = irq_base; twl4030_irq_next += i; /* replace generic PIH handler (handle_simple_irq) */ irq = sih_mod + twl4030_irq_base; irq_set_handler_data(irq, agent); - irq_set_chained_handler(irq, handle_twl4030_sih); + agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name); + status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0, + agent->irq_name ?: sih->name, NULL); pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, irq, irq_base, twl4030_irq_next - 1); - return status; + return status < 0 ? status : irq_base; } /* FIXME need a call to reverse twl4030_sih_setup() ... */ @@ -733,8 +736,9 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) } /* install an irq handler to demultiplex the TWL4030 interrupt */ - status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih, 0, - "TWL4030-PIH", NULL); + status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih, + IRQF_ONESHOT, + "TWL4030-PIH", NULL); if (status < 0) { pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status); goto fail_rqirq; diff --git a/trunk/drivers/mfd/wm8994-core.c b/trunk/drivers/mfd/wm8994-core.c index 5d6ba132837e..61894fced8ea 100644 --- a/trunk/drivers/mfd/wm8994-core.c +++ b/trunk/drivers/mfd/wm8994-core.c @@ -239,6 +239,7 @@ static int wm8994_suspend(struct device *dev) switch (wm8994->type) { case WM8958: + case WM1811: ret = wm8994_reg_read(wm8994, WM8958_MIC_DETECT_1); if (ret < 0) { dev_err(dev, "Failed to read power status: %d\n", ret); diff --git a/trunk/drivers/mmc/core/host.c b/trunk/drivers/mmc/core/host.c index e8a5eb38748b..d31c78b72b0f 100644 --- a/trunk/drivers/mmc/core/host.c +++ b/trunk/drivers/mmc/core/host.c @@ -302,17 +302,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_size = 512; host->max_blk_count = PAGE_CACHE_SIZE / 512; - /* - * Enable runtime power management by default. This flag was added due - * to runtime power management causing disruption for some users, but - * the power on/off code has been improved since then. - * - * We'll enable this flag by default as an experiment, and if no - * problems are reported, we will follow up later and remove the flag - * altogether. - */ - host->caps = MMC_CAP_POWER_OFF_CARD; - return host; free: diff --git a/trunk/drivers/mmc/host/mmci.c b/trunk/drivers/mmc/host/mmci.c index 50b5f9926f64..0726e59fd418 100644 --- a/trunk/drivers/mmc/host/mmci.c +++ b/trunk/drivers/mmc/host/mmci.c @@ -675,7 +675,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { /* First check for errors */ - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| + MCI_TXUNDERRUN|MCI_RXOVERRUN)) { u32 remain, success; /* Terminate the DMA transfer */ @@ -754,8 +755,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, } if (!cmd->data || cmd->error) { - if (host->data) + if (host->data) { + /* Terminate the DMA transfer */ + if (dma_inprogress(host)) + mmci_dma_data_error(host); mmci_stop_data(host); + } mmci_request_end(host, cmd->mrq); } else if (!(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); @@ -955,8 +960,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); data = host->data; - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| - MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| + MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND| + MCI_DATABLOCKEND) && data) mmci_data_irq(host, data, status); cmd = host->cmd; diff --git a/trunk/drivers/mmc/host/sdhci-cns3xxx.c b/trunk/drivers/mmc/host/sdhci-cns3xxx.c index 87b6f079b6e0..b4257e700617 100644 --- a/trunk/drivers/mmc/host/sdhci-cns3xxx.c +++ b/trunk/drivers/mmc/host/sdhci-cns3xxx.c @@ -109,13 +109,10 @@ static struct platform_driver sdhci_cns3xxx_driver = { .driver = { .name = "sdhci-cns3xxx", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_cns3xxx_probe, .remove = __devexit_p(sdhci_cns3xxx_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_cns3xxx_init(void) diff --git a/trunk/drivers/mmc/host/sdhci-dove.c b/trunk/drivers/mmc/host/sdhci-dove.c index f2d29dca4420..a81312c91f70 100644 --- a/trunk/drivers/mmc/host/sdhci-dove.c +++ b/trunk/drivers/mmc/host/sdhci-dove.c @@ -82,13 +82,10 @@ static struct platform_driver sdhci_dove_driver = { .driver = { .name = "sdhci-dove", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_dove_probe, .remove = __devexit_p(sdhci_dove_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_dove_init(void) diff --git a/trunk/drivers/mmc/host/sdhci-esdhc-imx.c b/trunk/drivers/mmc/host/sdhci-esdhc-imx.c index 4b976f00ea85..38ebc4ea259f 100644 --- a/trunk/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/trunk/drivers/mmc/host/sdhci-esdhc-imx.c @@ -599,14 +599,11 @@ static struct platform_driver sdhci_esdhc_imx_driver = { .name = "sdhci-esdhc-imx", .owner = THIS_MODULE, .of_match_table = imx_esdhc_dt_ids, + .pm = SDHCI_PLTFM_PMOPS, }, .id_table = imx_esdhc_devtype, .probe = sdhci_esdhc_imx_probe, .remove = __devexit_p(sdhci_esdhc_imx_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_esdhc_imx_init(void) diff --git a/trunk/drivers/mmc/host/sdhci-of-esdhc.c b/trunk/drivers/mmc/host/sdhci-of-esdhc.c index 59e9d003e589..01e5f627e0f0 100644 --- a/trunk/drivers/mmc/host/sdhci-of-esdhc.c +++ b/trunk/drivers/mmc/host/sdhci-of-esdhc.c @@ -125,13 +125,10 @@ static struct platform_driver sdhci_esdhc_driver = { .name = "sdhci-esdhc", .owner = THIS_MODULE, .of_match_table = sdhci_esdhc_of_match, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_esdhc_probe, .remove = __devexit_p(sdhci_esdhc_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_esdhc_init(void) diff --git a/trunk/drivers/mmc/host/sdhci-of-hlwd.c b/trunk/drivers/mmc/host/sdhci-of-hlwd.c index 9b0d794a4f69..3619adc7d9fc 100644 --- a/trunk/drivers/mmc/host/sdhci-of-hlwd.c +++ b/trunk/drivers/mmc/host/sdhci-of-hlwd.c @@ -87,13 +87,10 @@ static struct platform_driver sdhci_hlwd_driver = { .name = "sdhci-hlwd", .owner = THIS_MODULE, .of_match_table = sdhci_hlwd_of_match, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_hlwd_probe, .remove = __devexit_p(sdhci_hlwd_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_hlwd_init(void) diff --git a/trunk/drivers/mmc/host/sdhci-pci.c b/trunk/drivers/mmc/host/sdhci-pci.c index d833d9c2f7e3..6878a94626bc 100644 --- a/trunk/drivers/mmc/host/sdhci-pci.c +++ b/trunk/drivers/mmc/host/sdhci-pci.c @@ -54,8 +54,7 @@ struct sdhci_pci_fixes { int (*probe_slot) (struct sdhci_pci_slot *); void (*remove_slot) (struct sdhci_pci_slot *, int); - int (*suspend) (struct sdhci_pci_chip *, - pm_message_t); + int (*suspend) (struct sdhci_pci_chip *); int (*resume) (struct sdhci_pci_chip *); }; @@ -549,7 +548,7 @@ static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) jmicron_enable_mmc(slot->host, 0); } -static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state) +static int jmicron_suspend(struct sdhci_pci_chip *chip) { int i; @@ -993,8 +992,9 @@ static struct sdhci_ops sdhci_pci_ops = { #ifdef CONFIG_PM -static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int sdhci_pci_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; mmc_pm_flag_t slot_pm_flags; @@ -1010,7 +1010,7 @@ static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) if (!slot) continue; - ret = sdhci_suspend_host(slot->host, state); + ret = sdhci_suspend_host(slot->host); if (ret) { for (i--; i >= 0; i--) @@ -1026,7 +1026,7 @@ static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) } if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip, state); + ret = chip->fixes->suspend(chip); if (ret) { for (i = chip->num_slots - 1; i >= 0; i--) sdhci_resume_host(chip->slots[i]->host); @@ -1042,16 +1042,17 @@ static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) } pci_set_power_state(pdev, PCI_D3hot); } else { - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + pci_enable_wake(pdev, PCI_D3hot, 0); pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + pci_set_power_state(pdev, PCI_D3hot); } return 0; } -static int sdhci_pci_resume(struct pci_dev *pdev) +static int sdhci_pci_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; int i, ret; @@ -1099,7 +1100,6 @@ static int sdhci_pci_runtime_suspend(struct device *dev) struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; - pm_message_t state = { .event = PM_EVENT_SUSPEND }; int i, ret; chip = pci_get_drvdata(pdev); @@ -1121,7 +1121,7 @@ static int sdhci_pci_runtime_suspend(struct device *dev) } if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip, state); + ret = chip->fixes->suspend(chip); if (ret) { for (i = chip->num_slots - 1; i >= 0; i--) sdhci_runtime_resume_host(chip->slots[i]->host); @@ -1176,6 +1176,8 @@ static int sdhci_pci_runtime_idle(struct device *dev) #endif static const struct dev_pm_ops sdhci_pci_pm_ops = { + .suspend = sdhci_pci_suspend, + .resume = sdhci_pci_resume, .runtime_suspend = sdhci_pci_runtime_suspend, .runtime_resume = sdhci_pci_runtime_resume, .runtime_idle = sdhci_pci_runtime_idle, @@ -1428,8 +1430,6 @@ static struct pci_driver sdhci_driver = { .id_table = pci_ids, .probe = sdhci_pci_probe, .remove = __devexit_p(sdhci_pci_remove), - .suspend = sdhci_pci_suspend, - .resume = sdhci_pci_resume, .driver = { .pm = &sdhci_pci_pm_ops }, diff --git a/trunk/drivers/mmc/host/sdhci-pltfm.c b/trunk/drivers/mmc/host/sdhci-pltfm.c index a9e12ea05583..03970bcb3495 100644 --- a/trunk/drivers/mmc/host/sdhci-pltfm.c +++ b/trunk/drivers/mmc/host/sdhci-pltfm.c @@ -194,21 +194,25 @@ int sdhci_pltfm_unregister(struct platform_device *pdev) EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister); #ifdef CONFIG_PM -int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state) +static int sdhci_pltfm_suspend(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); - return sdhci_suspend_host(host, state); + return sdhci_suspend_host(host); } -EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend); -int sdhci_pltfm_resume(struct platform_device *dev) +static int sdhci_pltfm_resume(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); return sdhci_resume_host(host); } -EXPORT_SYMBOL_GPL(sdhci_pltfm_resume); + +const struct dev_pm_ops sdhci_pltfm_pmops = { + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +}; +EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops); #endif /* CONFIG_PM */ static int __init sdhci_pltfm_drv_init(void) diff --git a/trunk/drivers/mmc/host/sdhci-pltfm.h b/trunk/drivers/mmc/host/sdhci-pltfm.h index 3a9fc3f40840..37e0e184a0bb 100644 --- a/trunk/drivers/mmc/host/sdhci-pltfm.h +++ b/trunk/drivers/mmc/host/sdhci-pltfm.h @@ -99,8 +99,10 @@ extern int sdhci_pltfm_register(struct platform_device *pdev, extern int sdhci_pltfm_unregister(struct platform_device *pdev); #ifdef CONFIG_PM -extern int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state); -extern int sdhci_pltfm_resume(struct platform_device *dev); +extern const struct dev_pm_ops sdhci_pltfm_pmops; +#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops) +#else +#define SDHCI_PLTFM_PMOPS NULL #endif #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/trunk/drivers/mmc/host/sdhci-pxav2.c b/trunk/drivers/mmc/host/sdhci-pxav2.c index d4bf6d30c7ba..7a039c3cb1f1 100644 --- a/trunk/drivers/mmc/host/sdhci-pxav2.c +++ b/trunk/drivers/mmc/host/sdhci-pxav2.c @@ -218,13 +218,10 @@ static struct platform_driver sdhci_pxav2_driver = { .driver = { .name = "sdhci-pxav2", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav2_probe, .remove = __devexit_p(sdhci_pxav2_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_pxav2_init(void) { diff --git a/trunk/drivers/mmc/host/sdhci-pxav3.c b/trunk/drivers/mmc/host/sdhci-pxav3.c index cff4ad3e7a59..15673a7ee6a5 100644 --- a/trunk/drivers/mmc/host/sdhci-pxav3.c +++ b/trunk/drivers/mmc/host/sdhci-pxav3.c @@ -264,13 +264,10 @@ static struct platform_driver sdhci_pxav3_driver = { .driver = { .name = "sdhci-pxav3", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav3_probe, .remove = __devexit_p(sdhci_pxav3_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_pxav3_init(void) { diff --git a/trunk/drivers/mmc/host/sdhci-s3c.c b/trunk/drivers/mmc/host/sdhci-s3c.c index cb60c4197e0a..0d33ff0d67fb 100644 --- a/trunk/drivers/mmc/host/sdhci-s3c.c +++ b/trunk/drivers/mmc/host/sdhci-s3c.c @@ -622,23 +622,29 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) #ifdef CONFIG_PM -static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm) +static int sdhci_s3c_suspend(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); - return sdhci_suspend_host(host, pm); + return sdhci_suspend_host(host); } -static int sdhci_s3c_resume(struct platform_device *dev) +static int sdhci_s3c_resume(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); return sdhci_resume_host(host); } +static const struct dev_pm_ops sdhci_s3c_pmops = { + .suspend = sdhci_s3c_suspend, + .resume = sdhci_s3c_resume, +}; + +#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) + #else -#define sdhci_s3c_suspend NULL -#define sdhci_s3c_resume NULL +#define SDHCI_S3C_PMOPS NULL #endif static struct platform_driver sdhci_s3c_driver = { @@ -647,6 +653,7 @@ static struct platform_driver sdhci_s3c_driver = { .driver = { .owner = THIS_MODULE, .name = "s3c-sdhci", + .pm = SDHCI_S3C_PMOPS, }, }; diff --git a/trunk/drivers/mmc/host/sdhci-tegra.c b/trunk/drivers/mmc/host/sdhci-tegra.c index 89699e861fc1..e2e18d3f949c 100644 --- a/trunk/drivers/mmc/host/sdhci-tegra.c +++ b/trunk/drivers/mmc/host/sdhci-tegra.c @@ -318,13 +318,10 @@ static struct platform_driver sdhci_tegra_driver = { .name = "sdhci-tegra", .owner = THIS_MODULE, .of_match_table = sdhci_tegra_dt_match, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_tegra_probe, .remove = __devexit_p(sdhci_tegra_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_tegra_init(void) diff --git a/trunk/drivers/mmc/host/sdhci.c b/trunk/drivers/mmc/host/sdhci.c index 6d8eea323541..19ed580f2cab 100644 --- a/trunk/drivers/mmc/host/sdhci.c +++ b/trunk/drivers/mmc/host/sdhci.c @@ -2327,7 +2327,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) #ifdef CONFIG_PM -int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) +int sdhci_suspend_host(struct sdhci_host *host) { int ret; diff --git a/trunk/drivers/mmc/host/sdhci.h b/trunk/drivers/mmc/host/sdhci.h index 0a5b65460d8a..a04d4d0c6fd2 100644 --- a/trunk/drivers/mmc/host/sdhci.h +++ b/trunk/drivers/mmc/host/sdhci.h @@ -374,7 +374,7 @@ extern int sdhci_add_host(struct sdhci_host *host); extern void sdhci_remove_host(struct sdhci_host *host, int dead); #ifdef CONFIG_PM -extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state); +extern int sdhci_suspend_host(struct sdhci_host *host); extern int sdhci_resume_host(struct sdhci_host *host); extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); #endif diff --git a/trunk/drivers/mmc/host/vub300.c b/trunk/drivers/mmc/host/vub300.c index e8f6e65183d7..2ec978bc32ba 100644 --- a/trunk/drivers/mmc/host/vub300.c +++ b/trunk/drivers/mmc/host/vub300.c @@ -259,7 +259,7 @@ static int firmware_rom_wait_states = 0x04; static int firmware_rom_wait_states = 0x1C; #endif -module_param(firmware_rom_wait_states, bool, 0644); +module_param(firmware_rom_wait_states, int, 0644); MODULE_PARM_DESC(firmware_rom_wait_states, "ROM wait states byte=RRRIIEEE (Reserved Internal External)"); diff --git a/trunk/drivers/mtd/maps/plat-ram.c b/trunk/drivers/mtd/maps/plat-ram.c index 94f553489725..45876d0e5b8e 100644 --- a/trunk/drivers/mtd/maps/plat-ram.c +++ b/trunk/drivers/mtd/maps/plat-ram.c @@ -227,10 +227,14 @@ static int platram_probe(struct platform_device *pdev) if (!err) dev_info(&pdev->dev, "registered mtd device\n"); - /* add the whole device. */ - err = mtd_device_register(info->mtd, NULL, 0); - if (err) - dev_err(&pdev->dev, "failed to register the entire device\n"); + if (pdata->nr_partitions) { + /* add the whole device. */ + err = mtd_device_register(info->mtd, NULL, 0); + if (err) { + dev_err(&pdev->dev, + "failed to register the entire device\n"); + } + } return err; diff --git a/trunk/drivers/mtd/maps/pxa2xx-flash.c b/trunk/drivers/mtd/maps/pxa2xx-flash.c index 411a17df9fc1..2a25b6789af4 100644 --- a/trunk/drivers/mtd/maps/pxa2xx-flash.c +++ b/trunk/drivers/mtd/maps/pxa2xx-flash.c @@ -98,7 +98,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) } info->mtd->owner = THIS_MODULE; - mtd_device_parse_register(info->mtd, probes, 0, NULL, 0); + mtd_device_parse_register(info->mtd, probes, 0, flash->parts, flash->nr_parts); platform_set_drvdata(pdev, info); return 0; diff --git a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 071b63420f0e..493ec2fcf97f 100644 --- a/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/trunk/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -21,9 +21,9 @@ #include #include #include +#include #include #include - #include "gpmi-nand.h" /* add our owner bbt descriptor */ diff --git a/trunk/drivers/mtd/nand/ndfc.c b/trunk/drivers/mtd/nand/ndfc.c index ee1713907b92..f8aacf48ecdd 100644 --- a/trunk/drivers/mtd/nand/ndfc.c +++ b/trunk/drivers/mtd/nand/ndfc.c @@ -188,7 +188,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (!flash_np) return -ENODEV; - ppdata->of_node = flash_np; + ppdata.of_node = flash_np; ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev), flash_np->name); if (!ndfc->mtd.name) { diff --git a/trunk/drivers/net/ethernet/freescale/Kconfig b/trunk/drivers/net/ethernet/freescale/Kconfig index 5272f9d4dda9..9de37642f09f 100644 --- a/trunk/drivers/net/ethernet/freescale/Kconfig +++ b/trunk/drivers/net/ethernet/freescale/Kconfig @@ -23,8 +23,8 @@ if NET_VENDOR_FREESCALE config FEC bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS) - default ARCH_MXC || ARCH_MXS if ARM + ARCH_MXC || SOC_IMX28) + default ARCH_MXC || SOC_IMX28 if ARM select PHYLIB ---help--- Say Y here if you want to use the built-in 10/100 Fast ethernet diff --git a/trunk/drivers/net/ethernet/marvell/skge.c b/trunk/drivers/net/ethernet/marvell/skge.c index c7b60839ac99..dea0cb4400e2 100644 --- a/trunk/drivers/net/ethernet/marvell/skge.c +++ b/trunk/drivers/net/ethernet/marvell/skge.c @@ -2606,6 +2606,9 @@ static int skge_up(struct net_device *dev) spin_unlock_irq(&hw->hw_lock); napi_enable(&skge->napi); + + skge_set_multicast(dev); + return 0; free_tx_ring: diff --git a/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 227997d775e8..5829e0b47e7e 100644 --- a/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/trunk/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -147,6 +147,7 @@ void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); if (priv->mdev->dev->caps.comp_pool && cq->vector) mlx4_release_eq(priv->mdev->dev, cq->vector); + cq->vector = 0; cq->buf_size = 0; cq->buf = NULL; } diff --git a/trunk/drivers/net/ethernet/realtek/r8169.c b/trunk/drivers/net/ethernet/realtek/r8169.c index 67bf07819992..c8f47f17186f 100644 --- a/trunk/drivers/net/ethernet/realtek/r8169.c +++ b/trunk/drivers/net/ethernet/realtek/r8169.c @@ -477,7 +477,6 @@ enum rtl_register_content { /* Config1 register p.24 */ LEDS1 = (1 << 7), LEDS0 = (1 << 6), - MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ Speed_down = (1 << 4), MEMMAP = (1 << 3), IOMAP = (1 << 2), @@ -485,6 +484,7 @@ enum rtl_register_content { PMEnable = (1 << 0), /* Power Management Enable */ /* Config2 register p. 25 */ + MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */ PCI_Clock_66MHz = 0x01, PCI_Clock_33MHz = 0x00, @@ -3426,22 +3426,24 @@ static const struct rtl_cfg_info { }; /* Cfg9346_Unlock assumed. */ -static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr, +static unsigned rtl_try_msi(struct rtl8169_private *tp, const struct rtl_cfg_info *cfg) { + void __iomem *ioaddr = tp->mmio_addr; unsigned msi = 0; u8 cfg2; cfg2 = RTL_R8(Config2) & ~MSIEnable; if (cfg->features & RTL_FEATURE_MSI) { - if (pci_enable_msi(pdev)) { - dev_info(&pdev->dev, "no MSI. Back to INTx.\n"); + if (pci_enable_msi(tp->pci_dev)) { + netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n"); } else { cfg2 |= MSIEnable; msi = RTL_FEATURE_MSI; } } - RTL_W8(Config2, cfg2); + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) + RTL_W8(Config2, cfg2); return msi; } @@ -4077,7 +4079,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->features |= RTL_FEATURE_WOL; if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0) tp->features |= RTL_FEATURE_WOL; - tp->features |= rtl_try_msi(pdev, ioaddr, cfg); + tp->features |= rtl_try_msi(tp, cfg); RTL_W8(Cfg9346, Cfg9346_Lock); if (rtl_tbi_enabled(tp)) { diff --git a/trunk/drivers/net/ethernet/ti/davinci_cpdma.c b/trunk/drivers/net/ethernet/ti/davinci_cpdma.c index dca9d3369cdd..c97d2f590855 100644 --- a/trunk/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/trunk/drivers/net/ethernet/ti/davinci_cpdma.c @@ -836,11 +836,13 @@ int cpdma_chan_stop(struct cpdma_chan *chan) chan_write(chan, cp, CPDMA_TEARDOWN_VALUE); /* handle completed packets */ + spin_unlock_irqrestore(&chan->lock, flags); do { ret = __cpdma_chan_process(chan); if (ret < 0) break; } while ((ret & CPDMA_DESC_TD_COMPLETE) == 0); + spin_lock_irqsave(&chan->lock, flags); /* remaining packets haven't been tx/rx'ed, clean them up */ while (chan->head) { diff --git a/trunk/drivers/net/usb/asix.c b/trunk/drivers/net/usb/asix.c index e6fed4d4cb77..e95f0e60a9bc 100644 --- a/trunk/drivers/net/usb/asix.c +++ b/trunk/drivers/net/usb/asix.c @@ -1655,6 +1655,10 @@ static const struct usb_device_id products [] = { // ASIX 88772a USB_DEVICE(0x0db0, 0xa877), .driver_info = (unsigned long) &ax88772_info, +}, { + // Asus USB Ethernet Adapter + USB_DEVICE (0x0b95, 0x7e2b), + .driver_info = (unsigned long) &ax88772_info, }, { }, // END }; diff --git a/trunk/drivers/net/wireless/ath/ath9k/main.c b/trunk/drivers/net/wireless/ath/ath9k/main.c index d2348a5a7809..a9c5ae75277e 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/main.c +++ b/trunk/drivers/net/wireless/ath/ath9k/main.c @@ -1843,6 +1843,9 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an = (struct ath_node *) sta->drv_priv; + if (!(sc->sc_flags & SC_OP_TXAGGR)) + return; + switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; diff --git a/trunk/drivers/net/wireless/ath/ath9k/rc.c b/trunk/drivers/net/wireless/ath/ath9k/rc.c index 888abc2be3a5..528d5f3e868c 100644 --- a/trunk/drivers/net/wireless/ath/ath9k/rc.c +++ b/trunk/drivers/net/wireless/ath/ath9k/rc.c @@ -1271,7 +1271,9 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + ath_rc_priv->rate_max_phy = (k > 4) ? + ath_rc_priv->valid_rate_index[k-4] : + ath_rc_priv->valid_rate_index[k-1]; ath_rc_priv->rate_table = rate_table; ath_dbg(common, ATH_DBG_CONFIG, diff --git a/trunk/drivers/net/wireless/b43/pio.c b/trunk/drivers/net/wireless/b43/pio.c index fcff923b3c18..279a53eae4c5 100644 --- a/trunk/drivers/net/wireless/b43/pio.c +++ b/trunk/drivers/net/wireless/b43/pio.c @@ -617,9 +617,19 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) const char *err_msg = NULL; struct b43_rxhdr_fw4 *rxhdr = (struct b43_rxhdr_fw4 *)wl->pio_scratchspace; + size_t rxhdr_size = sizeof(*rxhdr); BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr)); - memset(rxhdr, 0, sizeof(*rxhdr)); + switch (dev->fw.hdr_format) { + case B43_FW_HDR_410: + case B43_FW_HDR_351: + rxhdr_size -= sizeof(rxhdr->format_598) - + sizeof(rxhdr->format_351); + break; + case B43_FW_HDR_598: + break; + } + memset(rxhdr, 0, rxhdr_size); /* Check if we have data and wait for it to get ready. */ if (q->rev >= 8) { @@ -657,11 +667,11 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) /* Get the preamble (RX header) */ if (q->rev >= 8) { - b43_block_read(dev, rxhdr, sizeof(*rxhdr), + b43_block_read(dev, rxhdr, rxhdr_size, q->mmio_base + B43_PIO8_RXDATA, sizeof(u32)); } else { - b43_block_read(dev, rxhdr, sizeof(*rxhdr), + b43_block_read(dev, rxhdr, rxhdr_size, q->mmio_base + B43_PIO_RXDATA, sizeof(u16)); } diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index a7a6def40d05..5c7c17c7166a 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -606,8 +606,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (ctx->ht.enabled) { /* if HT40 is used, it should not change * after associated except channel switch */ - if (iwl_is_associated_ctx(ctx) && - !ctx->ht.is_40mhz) + if (!ctx->ht.is_40mhz || + !iwl_is_associated_ctx(ctx)) iwlagn_config_ht40(conf, ctx); } else ctx->ht.is_40mhz = false; diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 35a6b71f358c..df1540ca6102 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -91,7 +91,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + else + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c index bacc06c95e7a..e0e9a3dfbc00 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2850,6 +2850,9 @@ static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, int ret; u8 sta_id; + if (ctx->ctxid != IWL_RXON_CTX_PAN) + return 0; + IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); @@ -2898,6 +2901,9 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; + if (ctx->ctxid != IWL_RXON_CTX_PAN) + return; + IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index ce918980e977..5f17ab8e76ba 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -1197,9 +1197,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ - if (is_agg) - iwl_trans_txq_update_byte_cnt_tbl(trans, txq, - le16_to_cpu(tx_cmd->len)); + iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen, DMA_BIDIRECTIONAL); diff --git a/trunk/drivers/net/wireless/mwifiex/cmdevt.c b/trunk/drivers/net/wireless/mwifiex/cmdevt.c index ac278156d390..6e0a3eaecf70 100644 --- a/trunk/drivers/net/wireless/mwifiex/cmdevt.c +++ b/trunk/drivers/net/wireless/mwifiex/cmdevt.c @@ -939,7 +939,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; unsigned long cmd_flags; - unsigned long cmd_pending_q_flags; unsigned long scan_pending_q_flags; uint16_t cancel_scan_cmd = false; @@ -949,12 +948,9 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) cmd_node = adapter->curr_cmd; cmd_node->wait_q_enabled = false; cmd_node->cmd_flag |= CMD_F_CANCELED; - spin_lock_irqsave(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); - list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); + adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } @@ -981,7 +977,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter, adapter->curr_cmd); } /* diff --git a/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c b/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c index ea4a29b7e331..1679c2593b7b 100644 --- a/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/trunk/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -55,9 +55,14 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { bool cancel_flag = false; int status = adapter->cmd_wait_q.status; - struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued; + struct cmd_ctrl_node *cmd_queued; + if (!adapter->cmd_queued) + return 0; + + cmd_queued = adapter->cmd_queued; adapter->cmd_queued = NULL; + dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); diff --git a/trunk/drivers/of/platform.c b/trunk/drivers/of/platform.c index cbd5d701c7e0..63b3ec48c203 100644 --- a/trunk/drivers/of/platform.c +++ b/trunk/drivers/of/platform.c @@ -314,7 +314,7 @@ static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *l if (!lookup) return NULL; - for(; lookup->name != NULL; lookup++) { + for(; lookup->compatible != NULL; lookup++) { if (!of_device_is_compatible(np, lookup->compatible)) continue; if (of_address_to_resource(np, 0, &res)) diff --git a/trunk/drivers/oprofile/nmi_timer_int.c b/trunk/drivers/oprofile/nmi_timer_int.c deleted file mode 100644 index 76f1c9357f39..000000000000 --- a/trunk/drivers/oprofile/nmi_timer_int.c +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @file nmi_timer_int.c - * - * @remark Copyright 2011 Advanced Micro Devices, Inc. - * - * @author Robert Richter - */ - -#include -#include -#include -#include -#include - -#ifdef CONFIG_OPROFILE_NMI_TIMER - -static DEFINE_PER_CPU(struct perf_event *, nmi_timer_events); -static int ctr_running; - -static struct perf_event_attr nmi_timer_attr = { - .type = PERF_TYPE_HARDWARE, - .config = PERF_COUNT_HW_CPU_CYCLES, - .size = sizeof(struct perf_event_attr), - .pinned = 1, - .disabled = 1, -}; - -static void nmi_timer_callback(struct perf_event *event, - struct perf_sample_data *data, - struct pt_regs *regs) -{ - event->hw.interrupts = 0; /* don't throttle interrupts */ - oprofile_add_sample(regs, 0); -} - -static int nmi_timer_start_cpu(int cpu) -{ - struct perf_event *event = per_cpu(nmi_timer_events, cpu); - - if (!event) { - event = perf_event_create_kernel_counter(&nmi_timer_attr, cpu, NULL, - nmi_timer_callback, NULL); - if (IS_ERR(event)) - return PTR_ERR(event); - per_cpu(nmi_timer_events, cpu) = event; - } - - if (event && ctr_running) - perf_event_enable(event); - - return 0; -} - -static void nmi_timer_stop_cpu(int cpu) -{ - struct perf_event *event = per_cpu(nmi_timer_events, cpu); - - if (event && ctr_running) - perf_event_disable(event); -} - -static int nmi_timer_cpu_notifier(struct notifier_block *b, unsigned long action, - void *data) -{ - int cpu = (unsigned long)data; - switch (action) { - case CPU_DOWN_FAILED: - case CPU_ONLINE: - nmi_timer_start_cpu(cpu); - break; - case CPU_DOWN_PREPARE: - nmi_timer_stop_cpu(cpu); - break; - } - return NOTIFY_DONE; -} - -static struct notifier_block nmi_timer_cpu_nb = { - .notifier_call = nmi_timer_cpu_notifier -}; - -static int nmi_timer_start(void) -{ - int cpu; - - get_online_cpus(); - ctr_running = 1; - for_each_online_cpu(cpu) - nmi_timer_start_cpu(cpu); - put_online_cpus(); - - return 0; -} - -static void nmi_timer_stop(void) -{ - int cpu; - - get_online_cpus(); - for_each_online_cpu(cpu) - nmi_timer_stop_cpu(cpu); - ctr_running = 0; - put_online_cpus(); -} - -static void nmi_timer_shutdown(void) -{ - struct perf_event *event; - int cpu; - - get_online_cpus(); - unregister_cpu_notifier(&nmi_timer_cpu_nb); - for_each_possible_cpu(cpu) { - event = per_cpu(nmi_timer_events, cpu); - if (!event) - continue; - perf_event_disable(event); - per_cpu(nmi_timer_events, cpu) = NULL; - perf_event_release_kernel(event); - } - - put_online_cpus(); -} - -static int nmi_timer_setup(void) -{ - int cpu, err; - u64 period; - - /* clock cycles per tick: */ - period = (u64)cpu_khz * 1000; - do_div(period, HZ); - nmi_timer_attr.sample_period = period; - - get_online_cpus(); - err = register_cpu_notifier(&nmi_timer_cpu_nb); - if (err) - goto out; - /* can't attach events to offline cpus: */ - for_each_online_cpu(cpu) { - err = nmi_timer_start_cpu(cpu); - if (err) - break; - } - if (err) - nmi_timer_shutdown(); -out: - put_online_cpus(); - return err; -} - -int __init op_nmi_timer_init(struct oprofile_operations *ops) -{ - int err = 0; - - err = nmi_timer_setup(); - if (err) - return err; - nmi_timer_shutdown(); /* only check, don't alloc */ - - ops->create_files = NULL; - ops->setup = nmi_timer_setup; - ops->shutdown = nmi_timer_shutdown; - ops->start = nmi_timer_start; - ops->stop = nmi_timer_stop; - ops->cpu_type = "timer"; - - printk(KERN_INFO "oprofile: using NMI timer interrupt.\n"); - - return 0; -} - -#endif diff --git a/trunk/drivers/oprofile/oprof.c b/trunk/drivers/oprofile/oprof.c index ed2c3ec07024..f8c752e408a6 100644 --- a/trunk/drivers/oprofile/oprof.c +++ b/trunk/drivers/oprofile/oprof.c @@ -246,31 +246,37 @@ static int __init oprofile_init(void) int err; /* always init architecture to setup backtrace support */ - timer_mode = 0; err = oprofile_arch_init(&oprofile_ops); - if (!err) { - if (!timer && !oprofilefs_register()) - return 0; - oprofile_arch_exit(); - } - /* setup timer mode: */ - timer_mode = 1; - /* no nmi timer mode if oprofile.timer is set */ - if (timer || op_nmi_timer_init(&oprofile_ops)) { + timer_mode = err || timer; /* fall back to timer mode on errors */ + if (timer_mode) { + if (!err) + oprofile_arch_exit(); err = oprofile_timer_init(&oprofile_ops); if (err) return err; } - return oprofilefs_register(); + err = oprofilefs_register(); + if (!err) + return 0; + + /* failed */ + if (timer_mode) + oprofile_timer_exit(); + else + oprofile_arch_exit(); + + return err; } static void __exit oprofile_exit(void) { oprofilefs_unregister(); - if (!timer_mode) + if (timer_mode) + oprofile_timer_exit(); + else oprofile_arch_exit(); } diff --git a/trunk/drivers/oprofile/oprof.h b/trunk/drivers/oprofile/oprof.h index d32ef816337c..177b73de5e5f 100644 --- a/trunk/drivers/oprofile/oprof.h +++ b/trunk/drivers/oprofile/oprof.h @@ -35,15 +35,7 @@ struct dentry; void oprofile_create_files(struct super_block *sb, struct dentry *root); int oprofile_timer_init(struct oprofile_operations *ops); -#ifdef CONFIG_OPROFILE_NMI_TIMER -int op_nmi_timer_init(struct oprofile_operations *ops); -#else -static inline int op_nmi_timer_init(struct oprofile_operations *ops) -{ - return -ENODEV; -} -#endif - +void oprofile_timer_exit(void); int oprofile_set_ulong(unsigned long *addr, unsigned long val); int oprofile_set_timeout(unsigned long time); diff --git a/trunk/drivers/oprofile/oprofile_files.c b/trunk/drivers/oprofile/oprofile_files.c index 89f63456646f..84a208dbed93 100644 --- a/trunk/drivers/oprofile/oprofile_files.c +++ b/trunk/drivers/oprofile/oprofile_files.c @@ -45,7 +45,7 @@ static ssize_t timeout_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_timeout(val); @@ -84,7 +84,7 @@ static ssize_t depth_write(struct file *file, char const __user *buf, size_t cou return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_ulong(&oprofile_backtrace_depth, val); @@ -141,9 +141,10 @@ static ssize_t enable_write(struct file *file, char const __user *buf, size_t co return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; + retval = 0; if (val) retval = oprofile_start(); else diff --git a/trunk/drivers/oprofile/oprofilefs.c b/trunk/drivers/oprofile/oprofilefs.c index d0de6cc2d7a5..2f0aa0f700e6 100644 --- a/trunk/drivers/oprofile/oprofilefs.c +++ b/trunk/drivers/oprofile/oprofilefs.c @@ -60,6 +60,13 @@ ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user *buf, size_t cou } +/* + * Note: If oprofilefs_ulong_from_user() returns 0, then *val remains + * unchanged and might be uninitialized. This follows write syscall + * implementation when count is zero: "If count is zero ... [and if] + * no errors are detected, 0 will be returned without causing any + * other effect." (man 2 write) + */ int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count) { char tmpbuf[TMPBUFSIZE]; @@ -79,7 +86,7 @@ int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_ raw_spin_lock_irqsave(&oprofilefs_lock, flags); *val = simple_strtoul(tmpbuf, NULL, 0); raw_spin_unlock_irqrestore(&oprofilefs_lock, flags); - return 0; + return count; } @@ -99,7 +106,7 @@ static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_ return -EINVAL; retval = oprofilefs_ulong_from_user(&value, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_ulong(file->private_data, value); diff --git a/trunk/drivers/oprofile/timer_int.c b/trunk/drivers/oprofile/timer_int.c index 93404f72dfa8..878fba126582 100644 --- a/trunk/drivers/oprofile/timer_int.c +++ b/trunk/drivers/oprofile/timer_int.c @@ -97,24 +97,24 @@ static struct notifier_block __refdata oprofile_cpu_notifier = { .notifier_call = oprofile_cpu_notify, }; -static int oprofile_hrtimer_setup(void) +int oprofile_timer_init(struct oprofile_operations *ops) { - return register_hotcpu_notifier(&oprofile_cpu_notifier); + int rc; + + rc = register_hotcpu_notifier(&oprofile_cpu_notifier); + if (rc) + return rc; + ops->create_files = NULL; + ops->setup = NULL; + ops->shutdown = NULL; + ops->start = oprofile_hrtimer_start; + ops->stop = oprofile_hrtimer_stop; + ops->cpu_type = "timer"; + printk(KERN_INFO "oprofile: using timer interrupt.\n"); + return 0; } -static void oprofile_hrtimer_shutdown(void) +void oprofile_timer_exit(void) { unregister_hotcpu_notifier(&oprofile_cpu_notifier); } - -int oprofile_timer_init(struct oprofile_operations *ops) -{ - ops->create_files = NULL; - ops->setup = oprofile_hrtimer_setup; - ops->shutdown = oprofile_hrtimer_shutdown; - ops->start = oprofile_hrtimer_start; - ops->stop = oprofile_hrtimer_stop; - ops->cpu_type = "timer"; - printk(KERN_INFO "oprofile: using timer interrupt.\n"); - return 0; -} diff --git a/trunk/drivers/pci/ats.c b/trunk/drivers/pci/ats.c index 7ec56fb0bd78..b0dd08e6a9da 100644 --- a/trunk/drivers/pci/ats.c +++ b/trunk/drivers/pci/ats.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "pci.h" diff --git a/trunk/drivers/pci/hotplug/acpiphp_glue.c b/trunk/drivers/pci/hotplug/acpiphp_glue.c index fce1c54a0c8d..9ddf69e3bbef 100644 --- a/trunk/drivers/pci/hotplug/acpiphp_glue.c +++ b/trunk/drivers/pci/hotplug/acpiphp_glue.c @@ -132,6 +132,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) return AE_OK; + pdev = pbus->self; + if (pdev && pci_is_pcie(pdev)) { + tmp = acpi_find_root_bridge_handle(pdev); + if (tmp) { + struct acpi_pci_root *root = acpi_pci_find_root(tmp); + + if (root && (root->osc_control_set & + OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) + return AE_OK; + } + } + acpi_evaluate_integer(handle, "_ADR", NULL, &adr); device = (adr >> 16) & 0xffff; function = adr & 0xffff; @@ -213,7 +225,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); if (pdev) { - pdev->current_state = PCI_D0; slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); pci_dev_put(pdev); } @@ -459,17 +470,8 @@ static int add_bridge(acpi_handle handle) { acpi_status status; unsigned long long tmp; - struct acpi_pci_root *root; acpi_handle dummy_handle; - /* - * We shouldn't use this bridge if PCIe native hotplug control has been - * granted by the BIOS for it. - */ - root = acpi_pci_find_root(handle); - if (root && (root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) - return -ENODEV; - /* if the bridge doesn't have _STA, we assume it is always there */ status = acpi_get_handle(handle, "_STA", &dummy_handle); if (ACPI_SUCCESS(status)) { @@ -1385,19 +1387,11 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, static acpi_status find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) { - struct acpi_pci_root *root; int *count = (int *)context; if (!acpi_is_root_bridge(handle)) return AE_OK; - root = acpi_pci_find_root(handle); - if (!root) - return AE_OK; - - if (root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL) - return AE_OK; - (*count)++; acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, handle_hotplug_event_bridge, NULL); diff --git a/trunk/drivers/pci/iov.c b/trunk/drivers/pci/iov.c index b82c155d7b37..1969a3ee3058 100644 --- a/trunk/drivers/pci/iov.c +++ b/trunk/drivers/pci/iov.c @@ -283,6 +283,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) struct resource *res; struct pci_dev *pdev; struct pci_sriov *iov = dev->sriov; + int bars = 0; if (!nr_virtfn) return 0; @@ -307,6 +308,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) nres = 0; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + bars |= (1 << (i + PCI_IOV_RESOURCES)); res = dev->resource + PCI_IOV_RESOURCES + i; if (res->parent) nres++; @@ -324,6 +326,11 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) return -ENOMEM; } + if (pci_enable_resources(dev, bars)) { + dev_err(&dev->dev, "SR-IOV: IOV BARS not allocated\n"); + return -ENOMEM; + } + if (iov->link != dev->devfn) { pdev = pci_get_slot(dev->bus, iov->link); if (!pdev) diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index 6f45a73c6e9f..6d4a5319148d 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -664,6 +664,9 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state) error = platform_pci_set_power_state(dev, state); if (!error) pci_update_current_state(dev, state); + /* Fall back to PCI_D0 if native PM is not supported */ + if (!dev->pm_cap) + dev->current_state = PCI_D0; } else { error = -ENODEV; /* Fall back to PCI_D0 if native PM is not supported */ @@ -1126,7 +1129,11 @@ static int __pci_enable_device_flags(struct pci_dev *dev, if (atomic_add_return(1, &dev->enable_cnt) > 1) return 0; /* already enabled */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + /* only skip sriov related */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++) if (dev->resource[i].flags & flags) bars |= (1 << i); diff --git a/trunk/drivers/rtc/interface.c b/trunk/drivers/rtc/interface.c index fa4d9f324189..8e286259a007 100644 --- a/trunk/drivers/rtc/interface.c +++ b/trunk/drivers/rtc/interface.c @@ -319,20 +319,6 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_read_alarm); -static int ___rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) -{ - int err; - - if (!rtc->ops) - err = -ENODEV; - else if (!rtc->ops->set_alarm) - err = -EINVAL; - else - err = rtc->ops->set_alarm(rtc->dev.parent, alarm); - - return err; -} - static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { struct rtc_time tm; @@ -356,7 +342,14 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) * over right here, before we set the alarm. */ - return ___rtc_set_alarm(rtc, alarm); + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->set_alarm) + err = -EINVAL; + else + err = rtc->ops->set_alarm(rtc->dev.parent, alarm); + + return err; } int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) @@ -770,20 +763,6 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) return 0; } -static void rtc_alarm_disable(struct rtc_device *rtc) -{ - struct rtc_wkalrm alarm; - struct rtc_time tm; - - __rtc_read_time(rtc, &tm); - - alarm.time = rtc_ktime_to_tm(ktime_add(rtc_tm_to_ktime(tm), - ktime_set(300, 0))); - alarm.enabled = 0; - - ___rtc_set_alarm(rtc, &alarm); -} - /** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device @@ -805,10 +784,8 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) struct rtc_wkalrm alarm; int err; next = timerqueue_getnext(&rtc->timerqueue); - if (!next) { - rtc_alarm_disable(rtc); + if (!next) return; - } alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); @@ -870,8 +847,7 @@ void rtc_timer_do_work(struct work_struct *work) err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) goto again; - } else - rtc_alarm_disable(rtc); + } mutex_unlock(&rtc->ops_lock); } diff --git a/trunk/drivers/rtc/rtc-m41t80.c b/trunk/drivers/rtc/rtc-m41t80.c index eda128fc1d38..64aedd8cc095 100644 --- a/trunk/drivers/rtc/rtc-m41t80.c +++ b/trunk/drivers/rtc/rtc-m41t80.c @@ -357,10 +357,19 @@ static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) static struct rtc_class_ops m41t80_rtc_ops = { .read_time = m41t80_rtc_read_time, .set_time = m41t80_rtc_set_time, + /* + * XXX - m41t80 alarm functionality is reported broken. + * until it is fixed, don't register alarm functions. + * .read_alarm = m41t80_rtc_read_alarm, .set_alarm = m41t80_rtc_set_alarm, + */ .proc = m41t80_rtc_proc, + /* + * See above comment on broken alarm + * .alarm_irq_enable = m41t80_rtc_alarm_irq_enable, + */ }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) diff --git a/trunk/drivers/s390/scsi/zfcp_scsi.c b/trunk/drivers/s390/scsi/zfcp_scsi.c index 11f07f888223..b79576b64f45 100644 --- a/trunk/drivers/s390/scsi/zfcp_scsi.c +++ b/trunk/drivers/s390/scsi/zfcp_scsi.c @@ -55,6 +55,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + /* if previous slave_alloc returned early, there is nothing to do */ + if (!zfcp_sdev->port) + return; + zfcp_erp_lun_shutdown_wait(sdev, "scssd_1"); put_device(&zfcp_sdev->port->dev); } diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c index dba72a4e6a1c..1ad0b8225560 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1906,18 +1906,19 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, spin_lock(&session->lock); task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, cqe->itt & ISCSI_CMD_RESPONSE_INDEX); - if (!task) { + if (!task || !task->sc) { spin_unlock(&session->lock); return -EINVAL; } sc = task->sc; - spin_unlock(&session->lock); if (!blk_rq_cpu_valid(sc->request)) cpu = smp_processor_id(); else cpu = sc->request->cpu; + spin_unlock(&session->lock); + p = &per_cpu(bnx2i_percpu, cpu); spin_lock(&p->p_work_lock); if (unlikely(!p->iothread)) { diff --git a/trunk/drivers/scsi/fcoe/fcoe.c b/trunk/drivers/scsi/fcoe/fcoe.c index cefbe44bb84a..8d67467dd9ce 100644 --- a/trunk/drivers/scsi/fcoe/fcoe.c +++ b/trunk/drivers/scsi/fcoe/fcoe.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -101,6 +103,8 @@ static int fcoe_ddp_done(struct fc_lport *, u16); static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, unsigned int); static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); +static int fcoe_dcb_app_notification(struct notifier_block *notifier, + ulong event, void *ptr); static bool fcoe_match(struct net_device *netdev); static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode); @@ -129,6 +133,11 @@ static struct notifier_block fcoe_cpu_notifier = { .notifier_call = fcoe_cpu_callback, }; +/* notification function for DCB events */ +static struct notifier_block dcb_notifier = { + .notifier_call = fcoe_dcb_app_notification, +}; + static struct scsi_transport_template *fcoe_nport_scsi_transport; static struct scsi_transport_template *fcoe_vport_scsi_transport; @@ -1522,6 +1531,8 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); + skb->priority = port->priority; + if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN && fcoe->realdev->features & NETIF_F_HW_VLAN_TX) { skb->vlan_tci = VLAN_TAG_PRESENT | @@ -1624,6 +1635,7 @@ static inline int fcoe_filter_frames(struct fc_lport *lport, stats->InvalidCRCCount++; if (stats->InvalidCRCCount < 5) printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); + put_cpu(); return -EINVAL; } @@ -1746,6 +1758,7 @@ int fcoe_percpu_receive_thread(void *arg) */ static void fcoe_dev_setup(void) { + register_dcbevent_notifier(&dcb_notifier); register_netdevice_notifier(&fcoe_notifier); } @@ -1754,9 +1767,69 @@ static void fcoe_dev_setup(void) */ static void fcoe_dev_cleanup(void) { + unregister_dcbevent_notifier(&dcb_notifier); unregister_netdevice_notifier(&fcoe_notifier); } +static struct fcoe_interface * +fcoe_hostlist_lookup_realdev_port(struct net_device *netdev) +{ + struct fcoe_interface *fcoe; + struct net_device *real_dev; + + list_for_each_entry(fcoe, &fcoe_hostlist, list) { + if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) + real_dev = vlan_dev_real_dev(fcoe->netdev); + else + real_dev = fcoe->netdev; + + if (netdev == real_dev) + return fcoe; + } + return NULL; +} + +static int fcoe_dcb_app_notification(struct notifier_block *notifier, + ulong event, void *ptr) +{ + struct dcb_app_type *entry = ptr; + struct fcoe_interface *fcoe; + struct net_device *netdev; + struct fcoe_port *port; + int prio; + + if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) + return NOTIFY_OK; + + netdev = dev_get_by_index(&init_net, entry->ifindex); + if (!netdev) + return NOTIFY_OK; + + fcoe = fcoe_hostlist_lookup_realdev_port(netdev); + dev_put(netdev); + if (!fcoe) + return NOTIFY_OK; + + if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) + prio = ffs(entry->app.priority) - 1; + else + prio = entry->app.priority; + + if (prio < 0) + return NOTIFY_OK; + + if (entry->app.protocol == ETH_P_FIP || + entry->app.protocol == ETH_P_FCOE) + fcoe->ctlr.priority = prio; + + if (entry->app.protocol == ETH_P_FCOE) { + port = lport_priv(fcoe->ctlr.lp); + port->priority = prio; + } + + return NOTIFY_OK; +} + /** * fcoe_device_notification() - Handler for net device events * @notifier: The context of the notification @@ -1964,6 +2037,46 @@ static bool fcoe_match(struct net_device *netdev) return true; } +/** + * fcoe_dcb_create() - Initialize DCB attributes and hooks + * @netdev: The net_device object of the L2 link that should be queried + * @port: The fcoe_port to bind FCoE APP priority with + * @ + */ +static void fcoe_dcb_create(struct fcoe_interface *fcoe) +{ +#ifdef CONFIG_DCB + int dcbx; + u8 fup, up; + struct net_device *netdev = fcoe->realdev; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + struct dcb_app app = { + .priority = 0, + .protocol = ETH_P_FCOE + }; + + /* setup DCB priority attributes. */ + if (netdev && netdev->dcbnl_ops && netdev->dcbnl_ops->getdcbx) { + dcbx = netdev->dcbnl_ops->getdcbx(netdev); + + if (dcbx & DCB_CAP_DCBX_VER_IEEE) { + app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; + up = dcb_ieee_getapp_mask(netdev, &app); + app.protocol = ETH_P_FIP; + fup = dcb_ieee_getapp_mask(netdev, &app); + } else { + app.selector = DCB_APP_IDTYPE_ETHTYPE; + up = dcb_getapp(netdev, &app); + app.protocol = ETH_P_FIP; + fup = dcb_getapp(netdev, &app); + } + + port->priority = ffs(up) ? ffs(up) - 1 : 0; + fcoe->ctlr.priority = ffs(fup) ? ffs(fup) - 1 : port->priority; + } +#endif +} + /** * fcoe_create() - Create a fcoe interface * @netdev : The net_device object the Ethernet interface to create on @@ -2007,6 +2120,9 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) /* Make this the "master" N_Port */ fcoe->ctlr.lp = lport; + /* setup DCB priority attributes. */ + fcoe_dcb_create(fcoe); + /* add to lports list */ fcoe_hostlist_add(lport); diff --git a/trunk/drivers/scsi/fcoe/fcoe_ctlr.c b/trunk/drivers/scsi/fcoe/fcoe_ctlr.c index c74c4b8e71ef..e7522dcc296e 100644 --- a/trunk/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/trunk/drivers/scsi/fcoe/fcoe_ctlr.c @@ -320,6 +320,7 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) skb_put(skb, sizeof(*sol)); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -474,6 +475,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, } skb_put(skb, len); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -566,6 +568,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, cap->fip.fip_dl_len = htons(dlen / FIP_BPW); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); return 0; @@ -1911,6 +1914,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, skb_put(skb, len); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); diff --git a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 4e041f6d808c..d570573b7963 100644 --- a/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/trunk/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -4335,7 +4335,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) /* insert into event log */ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_KERNEL); + event_reply = kzalloc(sz, GFP_ATOMIC); if (!event_reply) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); diff --git a/trunk/drivers/scsi/qla2xxx/qla_attr.c b/trunk/drivers/scsi/qla2xxx/qla_attr.c index ac326c41e931..6465dae5883a 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_attr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_attr.c @@ -1762,12 +1762,31 @@ qla2x00_get_host_port_state(struct Scsi_Host *shost) scsi_qla_host_t *vha = shost_priv(shost); struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev); - if (!base_vha->flags.online) + if (!base_vha->flags.online) { fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - else if (atomic_read(&base_vha->loop_state) == LOOP_TIMEOUT) - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - else + return; + } + + switch (atomic_read(&base_vha->loop_state)) { + case LOOP_UPDATE: + fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; + break; + case LOOP_DOWN: + if (test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags)) + fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; + else + fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; + break; + case LOOP_DEAD: + fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; + break; + case LOOP_READY: fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; + break; + default: + fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; + break; + } } static int diff --git a/trunk/drivers/scsi/qla2xxx/qla_dbg.c b/trunk/drivers/scsi/qla2xxx/qla_dbg.c index 9df4787715c0..f3cddd5800c3 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_dbg.c +++ b/trunk/drivers/scsi/qla2xxx/qla_dbg.c @@ -12,17 +12,17 @@ * | Level | Last Value Used | Holes | * ---------------------------------------------------------------------- * | Module Init and Probe | 0x0116 | | - * | Mailbox commands | 0x1129 | | + * | Mailbox commands | 0x112b | | * | Device Discovery | 0x2083 | | * | Queue Command and IO tracing | 0x302e | 0x3008 | * | DPC Thread | 0x401c | | * | Async Events | 0x5059 | | - * | Timer Routines | 0x600d | | + * | Timer Routines | 0x6010 | 0x600e,0x600f | * | User Space Interactions | 0x709d | | - * | Task Management | 0x8041 | | + * | Task Management | 0x8041 | 0x800b | * | AER/EEH | 0x900f | | * | Virtual Port | 0xa007 | | - * | ISP82XX Specific | 0xb051 | | + * | ISP82XX Specific | 0xb052 | | * | MultiQ | 0xc00b | | * | Misc | 0xd00b | | * ---------------------------------------------------------------------- diff --git a/trunk/drivers/scsi/qla2xxx/qla_gbl.h b/trunk/drivers/scsi/qla2xxx/qla_gbl.h index ce32d8135c9e..c0c11afb685c 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_gbl.h +++ b/trunk/drivers/scsi/qla2xxx/qla_gbl.h @@ -578,6 +578,7 @@ extern int qla82xx_check_md_needed(scsi_qla_host_t *); extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *); extern int qla82xx_mbx_beacon_ctl(scsi_qla_host_t *, int); extern char *qdev_state(uint32_t); +extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *); /* BSG related functions */ extern int qla24xx_bsg_request(struct fc_bsg_job *); diff --git a/trunk/drivers/scsi/qla2xxx/qla_init.c b/trunk/drivers/scsi/qla2xxx/qla_init.c index f03e915f1877..54ea68cec4c5 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_init.c +++ b/trunk/drivers/scsi/qla2xxx/qla_init.c @@ -1509,7 +1509,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) &ha->fw_xcb_count, NULL, NULL, &ha->max_npiv_vports, NULL); - if (!fw_major_version && ql2xallocfwdump) + if (!fw_major_version && ql2xallocfwdump + && !IS_QLA82XX(ha)) qla2x00_alloc_fw_dump(vha); } } else { diff --git a/trunk/drivers/scsi/qla2xxx/qla_iocb.c b/trunk/drivers/scsi/qla2xxx/qla_iocb.c index dbec89622a0f..a4b267e60a35 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_iocb.c +++ b/trunk/drivers/scsi/qla2xxx/qla_iocb.c @@ -120,11 +120,10 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) * Returns a pointer to the continuation type 1 IOCB packet. */ static inline cont_a64_entry_t * -qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha) +qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) { cont_a64_entry_t *cont_pkt; - struct req_que *req = vha->req; /* Adjust ring index. */ req->ring_index++; if (req->ring_index == req->length) { @@ -292,7 +291,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -684,7 +683,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -2070,7 +2069,8 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) * Five DSDs are available in the Cont. * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, + vha->hw->req_q_map[0]); cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; avail_dsds = 5; cont_iocb_prsnt = 1; @@ -2096,6 +2096,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) int index; uint16_t tot_dsds; scsi_qla_host_t *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job; int loop_iterartion = 0; int cont_iocb_prsnt = 0; @@ -2141,7 +2142,8 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) * Five DSDs are available in the Cont. * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, + ha->req_q_map[0]); cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; avail_dsds = 5; cont_iocb_prsnt = 1; diff --git a/trunk/drivers/scsi/qla2xxx/qla_isr.c b/trunk/drivers/scsi/qla2xxx/qla_isr.c index 2516adf1aeea..7b91b290ffd6 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_isr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_isr.c @@ -1741,7 +1741,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) resid, scsi_bufflen(cp)); cp->result = DID_ERROR << 16 | lscsi_status; - break; + goto check_scsi_status; } if (!lscsi_status && diff --git a/trunk/drivers/scsi/qla2xxx/qla_mbx.c b/trunk/drivers/scsi/qla2xxx/qla_mbx.c index 3b3cec9f6ac2..82a33533ed26 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_mbx.c +++ b/trunk/drivers/scsi/qla2xxx/qla_mbx.c @@ -79,8 +79,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) mcp->mb[0] = MBS_LINK_DOWN_ERROR; ql_log(ql_log_warn, base_vha, 0x1004, "FW hung = %d.\n", ha->flags.isp82xx_fw_hung); - rval = QLA_FUNCTION_FAILED; - goto premature_exit; + return QLA_FUNCTION_TIMEOUT; } /* @@ -163,6 +162,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) HINT_MBX_INT_PENDING) { spin_unlock_irqrestore(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; ql_dbg(ql_dbg_mbx, base_vha, 0x1010, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -188,6 +188,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) HINT_MBX_INT_PENDING) { spin_unlock_irqrestore(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; ql_dbg(ql_dbg_mbx, base_vha, 0x1012, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -302,7 +303,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - + if (IS_QLA82XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0x112a, + "disabling pause transmit on port " + "0 & 1.\n"); + qla82xx_wr_32(ha, + QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0| + CRB_NIU_XG_PAUSE_CTL_P1); + } ql_log(ql_log_info, base_vha, 0x101c, "Mailbox cmd timeout occured. " "Scheduling ISP abort eeh_busy=0x%x.\n", @@ -318,7 +327,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - + if (IS_QLA82XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0x112b, + "disabling pause transmit on port " + "0 & 1.\n"); + qla82xx_wr_32(ha, + QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0| + CRB_NIU_XG_PAUSE_CTL_P1); + } ql_log(ql_log_info, base_vha, 0x101e, "Mailbox cmd timeout occured. " "Scheduling ISP abort.\n"); diff --git a/trunk/drivers/scsi/qla2xxx/qla_nx.c b/trunk/drivers/scsi/qla2xxx/qla_nx.c index 94bded5ddce4..03554934b0a5 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_nx.c +++ b/trunk/drivers/scsi/qla2xxx/qla_nx.c @@ -3817,6 +3817,20 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha) return rval; } +void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + + if (ha->flags.mbox_busy) { + ha->flags.mbox_int = 1; + ha->flags.mbox_busy = 0; + ql_log(ql_log_warn, vha, 0x6010, + "Doing premature completion of mbx command.\n"); + if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags)) + complete(&ha->mbx_intr_comp); + } +} + void qla82xx_watchdog(scsi_qla_host_t *vha) { uint32_t dev_state, halt_status; @@ -3839,9 +3853,13 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) qla2xxx_wake_dpc(vha); } else { if (qla82xx_check_fw_alive(vha)) { + ql_dbg(ql_dbg_timer, vha, 0x6011, + "disabling pause transmit on port 0 & 1.\n"); + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0|CRB_NIU_XG_PAUSE_CTL_P1); halt_status = qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); - ql_dbg(ql_dbg_timer, vha, 0x6005, + ql_log(ql_log_info, vha, 0x6005, "dumping hw/fw registers:.\n " " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,.\n " " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,.\n " @@ -3858,6 +3876,11 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) QLA82XX_CRB_PEG_NET_3 + 0x3c), qla82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c)); + if (LSW(MSB(halt_status)) == 0x67) + ql_log(ql_log_warn, vha, 0xb052, + "Firmware aborted with " + "error code 0x00006700. Device is " + "being reset.\n"); if (halt_status & HALT_STATUS_UNRECOVERABLE) { set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); @@ -3869,16 +3892,8 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) } qla2xxx_wake_dpc(vha); ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - ql_log(ql_log_warn, vha, 0x6007, - "Due to FW hung, doing " - "premature completion of mbx " - "command.\n"); - if (test_bit(MBX_INTR_WAIT, - &ha->mbx_cmd_flags)) - complete(&ha->mbx_intr_comp); - } + ql_log(ql_log_warn, vha, 0x6007, "Firmware hung.\n"); + qla82xx_clear_pending_mbx(vha); } } } @@ -4073,10 +4088,7 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) msleep(1000); if (qla82xx_check_fw_alive(vha)) { ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - complete(&ha->mbx_intr_comp); - } + qla82xx_clear_pending_mbx(vha); break; } } diff --git a/trunk/drivers/scsi/qla2xxx/qla_nx.h b/trunk/drivers/scsi/qla2xxx/qla_nx.h index 57820c199bc2..57a226be339a 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_nx.h +++ b/trunk/drivers/scsi/qla2xxx/qla_nx.h @@ -1173,4 +1173,8 @@ struct qla82xx_md_entry_queue { static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC }; + +#define CRB_NIU_XG_PAUSE_CTL_P0 0x1 +#define CRB_NIU_XG_PAUSE_CTL_P1 0x8 + #endif diff --git a/trunk/drivers/scsi/qla2xxx/qla_os.c b/trunk/drivers/scsi/qla2xxx/qla_os.c index fd14c7bfc626..f9e5b85e84d8 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_os.c +++ b/trunk/drivers/scsi/qla2xxx/qla_os.c @@ -201,12 +201,12 @@ MODULE_PARM_DESC(ql2xmdcapmask, "Set the Minidump driver capture mask level. " "Default is 0x7F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F."); -int ql2xmdenable; +int ql2xmdenable = 1; module_param(ql2xmdenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xmdenable, "Enable/disable MiniDump. " - "0 (Default) - MiniDump disabled. " - "1 - MiniDump enabled."); + "0 - MiniDump disabled. " + "1 (Default) - MiniDump enabled."); /* * SCSI host template entry points @@ -423,6 +423,7 @@ static int qla25xx_setup_mode(struct scsi_qla_host *vha) qla25xx_delete_queues(vha); destroy_workqueue(ha->wq); ha->wq = NULL; + vha->req = ha->req_q_map[0]; fail: ha->mqenable = 0; kfree(ha->req_q_map); @@ -814,49 +815,6 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) return return_status; } -/* - * qla2x00_wait_for_loop_ready - * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop - * to be in LOOP_READY state. - * Input: - * ha - pointer to host adapter structure - * - * Note: - * Does context switching-Release SPIN_LOCK - * (if any) before calling this routine. - * - * - * Return: - * Success (LOOP_READY) : 0 - * Failed (LOOP_NOT_READY) : 1 - */ -static inline int -qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) -{ - int return_status = QLA_SUCCESS; - unsigned long loop_timeout ; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - /* wait for 5 min at the max for loop to be ready */ - loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); - - while ((!atomic_read(&base_vha->loop_down_timer) && - atomic_read(&base_vha->loop_state) == LOOP_DOWN) || - atomic_read(&base_vha->loop_state) != LOOP_READY) { - if (atomic_read(&base_vha->loop_state) == LOOP_DEAD) { - return_status = QLA_FUNCTION_FAILED; - break; - } - msleep(1000); - if (time_after_eq(jiffies, loop_timeout)) { - return_status = QLA_FUNCTION_FAILED; - break; - } - } - return (return_status); -} - static void sp_get(struct srb *sp) { @@ -1035,12 +993,6 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, "Wait for hba online failed for cmd=%p.\n", cmd); goto eh_reset_failed; } - err = 1; - if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x800b, - "Wait for loop ready failed for cmd=%p.\n", cmd); - goto eh_reset_failed; - } err = 2; if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1) != QLA_SUCCESS) { @@ -1137,10 +1089,9 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) goto eh_bus_reset_done; } - if (qla2x00_wait_for_loop_ready(vha) == QLA_SUCCESS) { - if (qla2x00_loop_reset(vha) == QLA_SUCCESS) - ret = SUCCESS; - } + if (qla2x00_loop_reset(vha) == QLA_SUCCESS) + ret = SUCCESS; + if (ret == FAILED) goto eh_bus_reset_done; @@ -1206,15 +1157,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS) goto eh_host_reset_lock; - /* - * Fixme-may be dpc thread is active and processing - * loop_resync,so wait a while for it to - * be completed and then issue big hammer.Otherwise - * it may cause I/O failure as big hammer marks the - * devices as lost kicking of the port_down_timer - * while dpc is stuck for the mailbox to complete. - */ - qla2x00_wait_for_loop_ready(vha); if (vha != base_vha) { if (qla2x00_vp_abort_isp(vha)) goto eh_host_reset_lock; @@ -1297,16 +1239,13 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) atomic_set(&vha->loop_state, LOOP_DOWN); atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); qla2x00_mark_all_devices_lost(vha, 0); - qla2x00_wait_for_loop_ready(vha); } if (ha->flags.enable_lip_reset) { ret = qla2x00_lip_reset(vha); - if (ret != QLA_SUCCESS) { + if (ret != QLA_SUCCESS) ql_dbg(ql_dbg_taskm, vha, 0x802e, "lip_reset failed (%d).\n", ret); - } else - qla2x00_wait_for_loop_ready(vha); } /* Issue marker command only when we are going to start the I/O */ @@ -4070,13 +4009,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) /* For ISP82XX complete any pending mailbox cmd */ if (IS_QLA82XX(ha)) { ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - ql_dbg(ql_dbg_aer, vha, 0x9001, - "Due to pci channel io frozen, doing premature " - "completion of mbx command.\n"); - complete(&ha->mbx_intr_comp); - } + ql_dbg(ql_dbg_aer, vha, 0x9001, "Pci channel io frozen\n"); + qla82xx_clear_pending_mbx(vha); } qla2x00_free_irqs(vha); pci_disable_device(pdev); diff --git a/trunk/drivers/scsi/qla2xxx/qla_version.h b/trunk/drivers/scsi/qla2xxx/qla_version.h index 13b6357c1fa2..23f33a6d52d7 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_version.h +++ b/trunk/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.07.07-k" +#define QLA2XXX_VERSION "8.03.07.12-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 diff --git a/trunk/drivers/scsi/qla4xxx/ql4_def.h b/trunk/drivers/scsi/qla4xxx/ql4_def.h index ace637bf254e..fd5edc6e166d 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_def.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_def.h @@ -147,7 +147,7 @@ #define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ #define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */ -#define QL4_SESS_RECOVERY_TMO 30 /* iSCSI session */ +#define QL4_SESS_RECOVERY_TMO 120 /* iSCSI session */ /* recovery timeout */ #define LSDW(x) ((u32)((u64)(x))) @@ -173,6 +173,8 @@ #define ISNS_DEREG_TOV 5 #define HBA_ONLINE_TOV 30 #define DISABLE_ACB_TOV 30 +#define IP_CONFIG_TOV 30 +#define LOGIN_TOV 12 #define MAX_RESET_HA_RETRIES 2 @@ -240,6 +242,45 @@ struct ddb_entry { uint16_t fw_ddb_index; /* DDB firmware index */ uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ + uint16_t ddb_type; +#define FLASH_DDB 0x01 + + struct dev_db_entry fw_ddb_entry; + int (*unblock_sess)(struct iscsi_cls_session *cls_session); + int (*ddb_change)(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); + + /* Driver Re-login */ + unsigned long flags; /* DDB Flags */ + uint16_t default_relogin_timeout; /* Max time to wait for + * relogin to complete */ + atomic_t retry_relogin_timer; /* Min Time between relogins + * (4000 only) */ + atomic_t relogin_timer; /* Max Time to wait for + * relogin to complete */ + atomic_t relogin_retry_count; /* Num of times relogin has been + * retried */ + uint32_t default_time2wait; /* Default Min time between + * relogins (+aens) */ + +}; + +struct qla_ddb_index { + struct list_head list; + uint16_t fw_ddb_idx; + struct dev_db_entry fw_ddb; +}; + +#define DDB_IPADDR_LEN 64 + +struct ql4_tuple_ddb { + int port; + int tpgt; + char ip_addr[DDB_IPADDR_LEN]; + char iscsi_name[ISCSI_NAME_SIZE]; + uint16_t options; +#define DDB_OPT_IPV6 0x0e0e +#define DDB_OPT_IPV4 0x0f0f }; /* @@ -411,7 +452,7 @@ struct scsi_qla_host { #define AF_FW_RECOVERY 19 /* 0x00080000 */ #define AF_EEH_BUSY 20 /* 0x00100000 */ #define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ - +#define AF_BUILD_DDB_LIST 22 /* 0x00400000 */ unsigned long dpc_flags; #define DPC_RESET_HA 1 /* 0x00000002 */ @@ -604,6 +645,7 @@ struct scsi_qla_host { uint16_t bootload_minor; uint16_t bootload_patch; uint16_t bootload_build; + uint16_t def_timeout; /* Default login timeout */ uint32_t flash_state; #define QLFLASH_WAITING 0 @@ -623,6 +665,11 @@ struct scsi_qla_host { uint16_t iscsi_pci_func_cnt; uint8_t model_name[16]; struct completion disable_acb_comp; + struct dma_pool *fw_ddb_dma_pool; +#define DDB_DMA_BLOCK_SIZE 512 + uint16_t pri_ddb_idx; + uint16_t sec_ddb_idx; + int is_reset; }; struct ql4_task_data { @@ -835,6 +882,10 @@ static inline int ql4xxx_reset_active(struct scsi_qla_host *ha) /*---------------------------------------------------------------------------*/ /* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */ + +#define INIT_ADAPTER 0 +#define RESET_ADAPTER 1 + #define PRESERVE_DDB_LIST 0 #define REBUILD_DDB_LIST 1 diff --git a/trunk/drivers/scsi/qla4xxx/ql4_fw.h b/trunk/drivers/scsi/qla4xxx/ql4_fw.h index cbd5a20dbbd1..4ac07f882521 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_fw.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_fw.h @@ -12,6 +12,7 @@ #define MAX_PRST_DEV_DB_ENTRIES 64 #define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES #define MAX_DEV_DB_ENTRIES 512 +#define MAX_DEV_DB_ENTRIES_40XX 256 /************************************************************************* * @@ -604,6 +605,13 @@ struct addr_ctrl_blk { uint8_t res14[140]; /* 274-2FF */ }; +#define IP_ADDR_COUNT 4 /* Total 4 IP address supported in one interface + * One IPv4, one IPv6 link local and 2 IPv6 + */ + +#define IP_STATE_MASK 0x0F000000 +#define IP_STATE_SHIFT 24 + struct init_fw_ctrl_blk { struct addr_ctrl_blk pri; /* struct addr_ctrl_blk sec;*/ diff --git a/trunk/drivers/scsi/qla4xxx/ql4_glbl.h b/trunk/drivers/scsi/qla4xxx/ql4_glbl.h index 160db9d5ea21..d0dd4b330206 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_glbl.h @@ -13,7 +13,7 @@ struct iscsi_cls_conn; int qla4xxx_hw_reset(struct scsi_qla_host *ha); int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb *srb); -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha); +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset); int qla4xxx_soft_reset(struct scsi_qla_host *ha); irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); @@ -153,10 +153,13 @@ int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index, uint32_t *mbx_sts); int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index); int qla4xxx_send_passthru0(struct iscsi_task *task); +void qla4xxx_free_ddb_index(struct scsi_qla_host *ha); int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index, uint16_t stats_size, dma_addr_t stats_dma); void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry); +void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry); int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, struct dev_db_entry *fw_ddb_entry, dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); @@ -169,11 +172,22 @@ int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, int qla4xxx_restore_factory_defaults(struct scsi_qla_host *ha, uint32_t region, uint32_t field0, uint32_t field1); +int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index); +void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); +int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset); /* BSG Functions */ int qla4xxx_bsg_request(struct bsg_job *bsg_job); int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); +void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry); + extern int ql4xextended_error_logging; extern int ql4xdontresethba; extern int ql4xenablemsix; diff --git a/trunk/drivers/scsi/qla4xxx/ql4_init.c b/trunk/drivers/scsi/qla4xxx/ql4_init.c index 3075fbaef553..1bdfa8120ac8 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_init.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_init.c @@ -773,22 +773,24 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha) * be freed so that when login happens from user space there are free DDB * indices available. **/ -static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) +void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) { int max_ddbs; int ret; uint32_t idx = 0, next_idx = 0; uint32_t state = 0, conn_err = 0; - max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : MAX_DEV_DB_ENTRIES; for (idx = 0; idx < max_ddbs; idx = next_idx) { ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL, &next_idx, &state, &conn_err, NULL, NULL); - if (ret == QLA_ERROR) + if (ret == QLA_ERROR) { + next_idx++; continue; + } if (state == DDB_DS_NO_CONNECTION_ACTIVE || state == DDB_DS_SESSION_FAILED) { DEBUG2(ql4_printk(KERN_INFO, ha, @@ -804,7 +806,6 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) } } - /** * qla4xxx_initialize_adapter - initiailizes hba * @ha: Pointer to host adapter structure. @@ -812,7 +813,7 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) * This routine parforms all of the steps necessary to initialize the adapter. * **/ -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) { int status = QLA_ERROR; @@ -840,7 +841,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) if (status == QLA_ERROR) goto exit_init_hba; - qla4xxx_free_ddb_index(ha); + if (is_reset == RESET_ADAPTER) + qla4xxx_build_ddb_list(ha, is_reset); set_bit(AF_ONLINE, &ha->flags); exit_init_hba: @@ -855,38 +857,12 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) return status; } -/** - * qla4xxx_process_ddb_changed - process ddb state change - * @ha - Pointer to host adapter structure. - * @fw_ddb_index - Firmware's device database index - * @state - Device state - * - * This routine processes a Decive Database Changed AEN Event. - **/ -int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - uint32_t state, uint32_t conn_err) +int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state) { - struct ddb_entry * ddb_entry; uint32_t old_fw_ddb_device_state; int status = QLA_ERROR; - /* check for out of range index */ - if (fw_ddb_index >= MAX_DDB_ENTRIES) - goto exit_ddb_event; - - /* Get the corresponging ddb entry */ - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); - /* Device does not currently exist in our database. */ - if (ddb_entry == NULL) { - ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", - __func__, fw_ddb_index); - - if (state == DDB_DS_NO_CONNECTION_ACTIVE) - clear_bit(fw_ddb_index, ha->ddb_idx_map); - - goto exit_ddb_event; - } - old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB - old state = 0x%x, new state = 0x%x for " @@ -900,9 +876,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); qla4xxx_update_session_conn_param(ha, ddb_entry); status = QLA_SUCCESS; break; @@ -936,9 +910,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); qla4xxx_update_session_conn_param(ha, ddb_entry); status = QLA_SUCCESS; break; @@ -954,7 +926,198 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, __func__)); break; } + return status; +} + +void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry) +{ + /* + * This triggers a relogin. After the relogin_timer + * expires, the relogin gets scheduled. We must wait a + * minimum amount of time since receiving an 0x8014 AEN + * with failed device_state or a logout response before + * we can issue another relogin. + * + * Firmware pads this timeout: (time2wait +1). + * Driver retry to login should be longer than F/W. + * Otherwise F/W will fail + * set_ddb() mbx cmd with 0x4005 since it still + * counting down its time2wait. + */ + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); + +} + +int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state) +{ + uint32_t old_fw_ddb_device_state; + int status = QLA_ERROR; + + old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: DDB - old state = 0x%x, new state = 0x%x for " + "index [%d]\n", __func__, + ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); + + ddb_entry->fw_ddb_device_state = state; + + switch (old_fw_ddb_device_state) { + case DDB_DS_LOGIN_IN_PROCESS: + case DDB_DS_NO_CONNECTION_ACTIVE: + switch (state) { + case DDB_DS_SESSION_ACTIVE: + ddb_entry->unblock_sess(ddb_entry->sess); + qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); + status = QLA_SUCCESS; + break; + case DDB_DS_SESSION_FAILED: + iscsi_block_session(ddb_entry->sess); + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + case DDB_DS_SESSION_ACTIVE: + switch (state) { + case DDB_DS_SESSION_FAILED: + iscsi_block_session(ddb_entry->sess); + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + case DDB_DS_SESSION_FAILED: + switch (state) { + case DDB_DS_SESSION_ACTIVE: + ddb_entry->unblock_sess(ddb_entry->sess); + qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); + status = QLA_SUCCESS; + break; + case DDB_DS_SESSION_FAILED: + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + default: + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", + __func__)); + break; + } + return status; +} + +/** + * qla4xxx_process_ddb_changed - process ddb state change + * @ha - Pointer to host adapter structure. + * @fw_ddb_index - Firmware's device database index + * @state - Device state + * + * This routine processes a Decive Database Changed AEN Event. + **/ +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, + uint32_t fw_ddb_index, + uint32_t state, uint32_t conn_err) +{ + struct ddb_entry *ddb_entry; + int status = QLA_ERROR; + + /* check for out of range index */ + if (fw_ddb_index >= MAX_DDB_ENTRIES) + goto exit_ddb_event; + + /* Get the corresponging ddb entry */ + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); + /* Device does not currently exist in our database. */ + if (ddb_entry == NULL) { + ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", + __func__, fw_ddb_index); + + if (state == DDB_DS_NO_CONNECTION_ACTIVE) + clear_bit(fw_ddb_index, ha->ddb_idx_map); + + goto exit_ddb_event; + } + + ddb_entry->ddb_change(ha, fw_ddb_index, ddb_entry, state); exit_ddb_event: return status; } + +/** + * qla4xxx_login_flash_ddb - Login to target (DDB) + * @cls_session: Pointer to the session to login + * + * This routine logins to the target. + * Issues setddb and conn open mbx + **/ +void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_dma; + uint32_t mbx_sts = 0; + int ret; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!test_bit(AF_LINK_UP, &ha->flags)) + return; + + if (ddb_entry->ddb_type != FLASH_DDB) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Skipping login to non FLASH DB")); + goto exit_login; + } + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_login; + } + + if (ddb_entry->fw_ddb_index == INVALID_ENTRY) { + ret = qla4xxx_get_ddb_index(ha, &ddb_entry->fw_ddb_index); + if (ret == QLA_ERROR) + goto exit_login; + + ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; + ha->tot_ddbs++; + } + + memcpy(fw_ddb_entry, &ddb_entry->fw_ddb_entry, + sizeof(struct dev_db_entry)); + ddb_entry->sess->target_id = ddb_entry->fw_ddb_index; + + ret = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, + fw_ddb_dma, &mbx_sts); + if (ret == QLA_ERROR) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Set DDB failed\n")); + goto exit_login; + } + + ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; + ret = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); + if (ret == QLA_ERROR) { + ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, + sess->targetname); + goto exit_login; + } + +exit_login: + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + diff --git a/trunk/drivers/scsi/qla4xxx/ql4_mbx.c b/trunk/drivers/scsi/qla4xxx/ql4_mbx.c index 4c2b84870392..c2593782fbbe 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_mbx.c @@ -41,6 +41,16 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, return status; } + if (is_qla40XX(ha)) { + if (test_bit(AF_HA_REMOVAL, &ha->flags)) { + DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " + "prematurely completing mbx cmd as " + "adapter removal detected\n", + ha->host_no, __func__)); + return status; + } + } + if (is_qla8022(ha)) { if (test_bit(AF_FW_RECOVERY, &ha->flags)) { DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " @@ -413,6 +423,7 @@ qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, memcpy(ha->name_string, init_fw_cb->iscsi_name, min(sizeof(ha->name_string), sizeof(init_fw_cb->iscsi_name))); + ha->def_timeout = le16_to_cpu(init_fw_cb->def_timeout); /*memcpy(ha->alias, init_fw_cb->Alias, min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ diff --git a/trunk/drivers/scsi/qla4xxx/ql4_os.c b/trunk/drivers/scsi/qla4xxx/ql4_os.c index 30f31b127f33..4169c8baa112 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_os.c +++ b/trunk/drivers/scsi/qla4xxx/ql4_os.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -31,6 +32,13 @@ static struct kmem_cache *srb_cachep; /* * Module parameter information and variables */ +int ql4xdisablesysfsboot = 1; +module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ql4xdisablesysfsboot, + "Set to disable exporting boot targets to sysfs\n" + " 0 - Export boot targets\n" + " 1 - Do not export boot targets (Default)"); + int ql4xdontresethba = 0; module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdontresethba, @@ -63,7 +71,7 @@ static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; module_param(ql4xsess_recovery_tmo, int, S_IRUGO); MODULE_PARM_DESC(ql4xsess_recovery_tmo, "Target Session Recovery Timeout.\n" - " Default: 30 sec."); + " Default: 120 sec."); static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); /* @@ -415,7 +423,7 @@ static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) qla_ep = ep->dd_data; ha = to_qla_host(qla_ep->host); - if (adapter_up(ha)) + if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags)) ret = 1; return ret; @@ -975,6 +983,150 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, } +int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index) +{ + uint32_t mbx_sts = 0; + uint16_t tmp_ddb_index; + int ret; + +get_ddb_index: + tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); + + if (tmp_ddb_index >= MAX_DDB_ENTRIES) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Free DDB index not available\n")); + ret = QLA_ERROR; + goto exit_get_ddb_index; + } + + if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map)) + goto get_ddb_index; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Found a free DDB index at %d\n", tmp_ddb_index)); + ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts); + if (ret == QLA_ERROR) { + if (mbx_sts == MBOX_STS_COMMAND_ERROR) { + ql4_printk(KERN_INFO, ha, + "DDB index = %d not available trying next\n", + tmp_ddb_index); + goto get_ddb_index; + } + DEBUG2(ql4_printk(KERN_INFO, ha, + "Free FW DDB not available\n")); + } + + *ddb_index = tmp_ddb_index; + +exit_get_ddb_index: + return ret; +} + +static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, + char *existing_ipaddr, + char *user_ipaddr) +{ + uint8_t dst_ipaddr[IPv6_ADDR_LEN]; + char formatted_ipaddr[DDB_IPADDR_LEN]; + int status = QLA_SUCCESS, ret = 0; + + if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) { + ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, + '\0', NULL); + if (ret == 0) { + status = QLA_ERROR; + goto out_match; + } + ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr); + } else { + ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, + '\0', NULL); + if (ret == 0) { + status = QLA_ERROR; + goto out_match; + } + ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr); + } + + if (strcmp(existing_ipaddr, formatted_ipaddr)) + status = QLA_ERROR; + +out_match: + return status; +} + +static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha, + struct iscsi_cls_conn *cls_conn) +{ + int idx = 0, max_ddbs, rval; + struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); + struct iscsi_session *sess, *existing_sess; + struct iscsi_conn *conn, *existing_conn; + struct ddb_entry *ddb_entry; + + sess = cls_sess->dd_data; + conn = cls_conn->dd_data; + + if (sess->targetname == NULL || + conn->persistent_address == NULL || + conn->persistent_port == 0) + return QLA_ERROR; + + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + + for (idx = 0; idx < max_ddbs; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + if (ddb_entry->ddb_type != FLASH_DDB) + continue; + + existing_sess = ddb_entry->sess->dd_data; + existing_conn = ddb_entry->conn->dd_data; + + if (existing_sess->targetname == NULL || + existing_conn->persistent_address == NULL || + existing_conn->persistent_port == 0) + continue; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "IQN = %s User IQN = %s\n", + existing_sess->targetname, + sess->targetname)); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "IP = %s User IP = %s\n", + existing_conn->persistent_address, + conn->persistent_address)); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port = %d User Port = %d\n", + existing_conn->persistent_port, + conn->persistent_port)); + + if (strcmp(existing_sess->targetname, sess->targetname)) + continue; + rval = qla4xxx_match_ipaddress(ha, ddb_entry, + existing_conn->persistent_address, + conn->persistent_address); + if (rval == QLA_ERROR) + continue; + if (existing_conn->persistent_port != conn->persistent_port) + continue; + break; + } + + if (idx == max_ddbs) + return QLA_ERROR; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Match found in fwdb sessions\n")); + return QLA_SUCCESS; +} + static struct iscsi_cls_session * qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, uint16_t qdepth, @@ -984,8 +1136,7 @@ qla4xxx_session_create(struct iscsi_endpoint *ep, struct scsi_qla_host *ha; struct qla_endpoint *qla_ep; struct ddb_entry *ddb_entry; - uint32_t ddb_index; - uint32_t mbx_sts = 0; + uint16_t ddb_index; struct iscsi_session *sess; struct sockaddr *dst_addr; int ret; @@ -1000,32 +1151,9 @@ qla4xxx_session_create(struct iscsi_endpoint *ep, dst_addr = (struct sockaddr *)&qla_ep->dst_addr; ha = to_qla_host(qla_ep->host); -get_ddb_index: - ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); - - if (ddb_index >= MAX_DDB_ENTRIES) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free DDB index not available\n")); - return NULL; - } - - if (test_and_set_bit(ddb_index, ha->ddb_idx_map)) - goto get_ddb_index; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Found a free DDB index at %d\n", ddb_index)); - ret = qla4xxx_req_ddb_entry(ha, ddb_index, &mbx_sts); - if (ret == QLA_ERROR) { - if (mbx_sts == MBOX_STS_COMMAND_ERROR) { - ql4_printk(KERN_INFO, ha, - "DDB index = %d not available trying next\n", - ddb_index); - goto get_ddb_index; - } - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free FW DDB not available\n")); + ret = qla4xxx_get_ddb_index(ha, &ddb_index); + if (ret == QLA_ERROR) return NULL; - } cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, cmds_max, sizeof(struct ddb_entry), @@ -1040,6 +1168,8 @@ qla4xxx_session_create(struct iscsi_endpoint *ep, ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; ddb_entry->ha = ha; ddb_entry->sess = cls_sess; + ddb_entry->unblock_sess = qla4xxx_unblock_ddb; + ddb_entry->ddb_change = qla4xxx_ddb_change; cls_sess->recovery_tmo = ql4xsess_recovery_tmo; ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; ha->tot_ddbs++; @@ -1077,6 +1207,9 @@ qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_idx); + if (!cls_conn) + return NULL; + sess = cls_sess->dd_data; ddb_entry = sess->dd_data; ddb_entry->conn = cls_conn; @@ -1109,7 +1242,7 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) struct iscsi_session *sess; struct ddb_entry *ddb_entry; struct scsi_qla_host *ha; - struct dev_db_entry *fw_ddb_entry; + struct dev_db_entry *fw_ddb_entry = NULL; dma_addr_t fw_ddb_entry_dma; uint32_t mbx_sts = 0; int ret = 0; @@ -1120,12 +1253,25 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) ddb_entry = sess->dd_data; ha = ddb_entry->ha; + /* Check if we have matching FW DDB, if yes then do not + * login to this target. This could cause target to logout previous + * connection + */ + ret = qla4xxx_match_fwdb_session(ha, cls_conn); + if (ret == QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, + "Session already exist in FW.\n"); + ret = -EEXIST; + goto exit_conn_start; + } + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, GFP_KERNEL); if (!fw_ddb_entry) { ql4_printk(KERN_ERR, ha, "%s: Unable to allocate dma buffer\n", __func__); - return -ENOMEM; + ret = -ENOMEM; + goto exit_conn_start; } ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); @@ -1138,9 +1284,7 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) if (mbx_sts) if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); goto exit_set_param; } @@ -1167,8 +1311,9 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) ret = 0; exit_conn_start: - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); return ret; } @@ -1344,6 +1489,101 @@ static int qla4xxx_task_xmit(struct iscsi_task *task) return -ENOSYS; } +static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + struct iscsi_cls_session *cls_sess, + struct iscsi_cls_conn *cls_conn) +{ + int buflen = 0; + struct iscsi_session *sess; + struct iscsi_conn *conn; + char ip_addr[DDB_IPADDR_LEN]; + uint16_t options = 0; + + sess = cls_sess->dd_data; + conn = cls_conn->dd_data; + + conn->max_recv_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); + + conn->max_xmit_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); + + sess->initial_r2t_en = + (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); + + sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); + + sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); + + sess->first_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); + + sess->max_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); + + sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + + sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); + + conn->persistent_port = le16_to_cpu(fw_ddb_entry->port); + + sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + + options = le16_to_cpu(fw_ddb_entry->options); + if (options & DDB_OPT_IPV6_DEVICE) + sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr); + else + sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr); + + iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME, + (char *)fw_ddb_entry->iscsi_name, buflen); + iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME, + (char *)ha->name_string, buflen); + iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, + (char *)ip_addr, buflen); +} + +void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + struct iscsi_cls_session *cls_sess; + struct iscsi_cls_conn *cls_conn; + uint32_t ddb_state; + dma_addr_t fw_ddb_entry_dma; + struct dev_db_entry *fw_ddb_entry; + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", __func__); + goto exit_session_conn_fwddb_param; + } + + if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma, NULL, NULL, &ddb_state, + NULL, NULL, NULL) == QLA_ERROR) { + DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " + "get_ddb_entry for fw_ddb_index %d\n", + ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + goto exit_session_conn_fwddb_param; + } + + cls_sess = ddb_entry->sess; + + cls_conn = ddb_entry->conn; + + /* Update params */ + qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); + +exit_session_conn_fwddb_param: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); +} + void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) { @@ -1360,7 +1600,7 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, if (!fw_ddb_entry) { ql4_printk(KERN_ERR, ha, "%s: Unable to allocate dma buffer\n", __func__); - return; + goto exit_session_conn_param; } if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, @@ -1370,7 +1610,7 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, "get_ddb_entry for fw_ddb_index %d\n", ha->host_no, __func__, ddb_entry->fw_ddb_index)); - return; + goto exit_session_conn_param; } cls_sess = ddb_entry->sess; @@ -1379,6 +1619,12 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, cls_conn = ddb_entry->conn; conn = cls_conn->dd_data; + /* Update timers after login */ + ddb_entry->default_relogin_timeout = + le16_to_cpu(fw_ddb_entry->def_timeout); + ddb_entry->default_time2wait = + le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + /* Update params */ conn->max_recv_dlength = BYTE_UNITS * le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); @@ -1407,6 +1653,11 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, memcpy(sess->initiatorname, ha->name_string, min(sizeof(ha->name_string), sizeof(sess->initiatorname))); + +exit_session_conn_param: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); } /* @@ -1607,6 +1858,9 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) vfree(ha->chap_list); ha->chap_list = NULL; + if (ha->fw_ddb_dma_pool) + dma_pool_destroy(ha->fw_ddb_dma_pool); + /* release io space registers */ if (is_qla8022(ha)) { if (ha->nx_pcibase) @@ -1689,6 +1943,16 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) goto mem_alloc_error_exit; } + ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev, + DDB_DMA_BLOCK_SIZE, 8, 0); + + if (ha->fw_ddb_dma_pool == NULL) { + ql4_printk(KERN_WARNING, ha, + "%s: fw_ddb_dma_pool allocation failed..\n", + __func__); + goto mem_alloc_error_exit; + } + return QLA_SUCCESS; mem_alloc_error_exit: @@ -1800,6 +2064,60 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) } } +void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!(ddb_entry->ddb_type == FLASH_DDB)) + return; + + if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && + !iscsi_is_session_online(cls_sess)) { + if (atomic_read(&ddb_entry->retry_relogin_timer) != + INVALID_ENTRY) { + if (atomic_read(&ddb_entry->retry_relogin_timer) == + 0) { + atomic_set(&ddb_entry->retry_relogin_timer, + INVALID_ENTRY); + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: index [%d] login device\n", + __func__, ddb_entry->fw_ddb_index)); + } else + atomic_dec(&ddb_entry->retry_relogin_timer); + } + } + + /* Wait for relogin to timeout */ + if (atomic_read(&ddb_entry->relogin_timer) && + (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { + /* + * If the relogin times out and the device is + * still NOT ONLINE then try and relogin again. + */ + if (!iscsi_is_session_online(cls_sess)) { + /* Reset retry relogin timer */ + atomic_inc(&ddb_entry->relogin_retry_count); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: index[%d] relogin timed out-retrying" + " relogin (%d), retry (%d)\n", __func__, + ddb_entry->fw_ddb_index, + atomic_read(&ddb_entry->relogin_retry_count), + ddb_entry->default_time2wait + 4)); + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); + } + } +} + /** * qla4xxx_timer - checks every second for work to do. * @ha: Pointer to host adapter structure. @@ -1809,6 +2127,8 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) int start_dpc = 0; uint16_t w; + iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb); + /* If we are in the middle of AER/EEH processing * skip any processing and reschedule the timer */ @@ -2078,7 +2398,12 @@ static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) sess = cls_session->dd_data; ddb_entry = sess->dd_data; ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; - iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); + + if (ddb_entry->ddb_type == FLASH_DDB) + iscsi_block_session(ddb_entry->sess); + else + iscsi_session_failure(cls_session->dd_data, + ISCSI_ERR_CONN_FAILED); } /** @@ -2163,7 +2488,7 @@ static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) /* NOTE: AF_ONLINE flag set upon successful completion of * qla4xxx_initialize_adapter */ - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); } /* Retry failed adapter initialization, if necessary @@ -2245,17 +2570,108 @@ static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) iscsi_unblock_session(ddb_entry->sess); } else { /* Trigger relogin */ - iscsi_session_failure(cls_session->dd_data, - ISCSI_ERR_CONN_FAILED); + if (ddb_entry->ddb_type == FLASH_DDB) { + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + } else + iscsi_session_failure(cls_session->dd_data, + ISCSI_ERR_CONN_FAILED); } } } +int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " unblock session\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + + iscsi_unblock_session(ddb_entry->sess); + + /* Start scan target */ + if (test_bit(AF_ONLINE, &ha->flags)) { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " start scan\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + scsi_queue_work(ha->host, &ddb_entry->sess->scan_work); + } + return QLA_SUCCESS; +} + +int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " unblock user space session\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + iscsi_conn_start(ddb_entry->conn); + iscsi_conn_login_event(ddb_entry->conn, + ISCSI_CONN_STATE_LOGGED_IN); + + return QLA_SUCCESS; +} + static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) { iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); } +static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) +{ + uint16_t relogin_timer; + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + relogin_timer = max(ddb_entry->default_relogin_timeout, + (uint16_t)RELOGIN_TOV); + atomic_set(&ddb_entry->relogin_timer, relogin_timer); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, + ddb_entry->fw_ddb_index, relogin_timer)); + + qla4xxx_login_flash_ddb(cls_sess); +} + +static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!(ddb_entry->ddb_type == FLASH_DDB)) + return; + + if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && + !iscsi_is_session_online(cls_sess)) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "relogin issued\n")); + qla4xxx_relogin_flash_ddb(cls_sess); + } +} + void qla4xxx_wake_dpc(struct scsi_qla_host *ha) { if (ha->dpc_thread) @@ -2356,6 +2772,12 @@ static void qla4xxx_do_dpc(struct work_struct *work) if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) qla4xxx_get_dhcp_ip_address(ha); + /* ---- relogin device? --- */ + if (adapter_up(ha) && + test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { + iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin); + } + /* ---- link change? --- */ if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { if (!test_bit(AF_LINK_UP, &ha->flags)) { @@ -2368,8 +2790,12 @@ static void qla4xxx_do_dpc(struct work_struct *work) * fatal error recovery. Therefore, the driver must * manually relogin to devices when recovering from * connection failures, logouts, expired KATO, etc. */ - - qla4xxx_relogin_all_devices(ha); + if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) { + qla4xxx_build_ddb_list(ha, ha->is_reset); + iscsi_host_for_each_session(ha->host, + qla4xxx_login_flash_ddb); + } else + qla4xxx_relogin_all_devices(ha); } } } @@ -2867,6 +3293,9 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) " target ID %d\n", __func__, ddb_index[0], ddb_index[1])); + ha->pri_ddb_idx = ddb_index[0]; + ha->sec_ddb_idx = ddb_index[1]; + exit_boot_info_free: dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); exit_boot_info: @@ -3034,6 +3463,9 @@ static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) return ret; } + if (ql4xdisablesysfsboot) + return QLA_SUCCESS; + if (ddb_index[0] == 0xffff) goto sec_target; @@ -3066,7 +3498,15 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) struct iscsi_boot_kobj *boot_kobj; if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) - return 0; + return QLA_ERROR; + + if (ql4xdisablesysfsboot) { + ql4_printk(KERN_INFO, ha, + "%s: syfsboot disabled - driver will trigger login" + "and publish session for discovery .\n", __func__); + return QLA_SUCCESS; + } + ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); if (!ha->boot_kset) @@ -3108,7 +3548,7 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) if (!boot_kobj) goto put_host; - return 0; + return QLA_SUCCESS; put_host: scsi_host_put(ha->host); @@ -3174,9 +3614,507 @@ static void qla4xxx_create_chap_list(struct scsi_qla_host *ha) exit_chap_list: dma_free_coherent(&ha->pdev->dev, chap_size, chap_flash_data, chap_dma); - return; } +static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, + struct ql4_tuple_ddb *tddb) +{ + struct scsi_qla_host *ha; + struct iscsi_cls_session *cls_sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_session *sess; + struct iscsi_conn *conn; + + DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); + ha = ddb_entry->ha; + cls_sess = ddb_entry->sess; + sess = cls_sess->dd_data; + cls_conn = ddb_entry->conn; + conn = cls_conn->dd_data; + + tddb->tpgt = sess->tpgt; + tddb->port = conn->persistent_port; + strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE); + strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN); +} + +static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, + struct ql4_tuple_ddb *tddb) +{ + uint16_t options = 0; + + tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], + min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); + + options = le16_to_cpu(fw_ddb_entry->options); + if (options & DDB_OPT_IPV6_DEVICE) + sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr); + else + sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); + + tddb->port = le16_to_cpu(fw_ddb_entry->port); +} + +static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, + struct ql4_tuple_ddb *old_tddb, + struct ql4_tuple_ddb *new_tddb) +{ + if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) + return QLA_ERROR; + + if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr)) + return QLA_ERROR; + + if (old_tddb->port != new_tddb->port) + return QLA_ERROR; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", + old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, + old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt, + new_tddb->ip_addr, new_tddb->iscsi_name)); + + return QLA_SUCCESS; +} + +static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry) +{ + struct ddb_entry *ddb_entry; + struct ql4_tuple_ddb *fw_tddb = NULL; + struct ql4_tuple_ddb *tmp_tddb = NULL; + int idx; + int ret = QLA_ERROR; + + fw_tddb = vzalloc(sizeof(*fw_tddb)); + if (!fw_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + tmp_tddb = vzalloc(sizeof(*tmp_tddb)); + if (!tmp_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + + for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); + if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { + ret = QLA_SUCCESS; /* found */ + goto exit_check; + } + } + +exit_check: + if (fw_tddb) + vfree(fw_tddb); + if (tmp_tddb) + vfree(tmp_tddb); + return ret; +} + +static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, + struct list_head *list_nt, + struct dev_db_entry *fw_ddb_entry) +{ + struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; + struct ql4_tuple_ddb *fw_tddb = NULL; + struct ql4_tuple_ddb *tmp_tddb = NULL; + int ret = QLA_ERROR; + + fw_tddb = vzalloc(sizeof(*fw_tddb)); + if (!fw_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + tmp_tddb = vzalloc(sizeof(*tmp_tddb)); + if (!tmp_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + + list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { + qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); + if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { + ret = QLA_SUCCESS; /* found */ + goto exit_check; + } + } + +exit_check: + if (fw_tddb) + vfree(fw_tddb); + if (tmp_tddb) + vfree(tmp_tddb); + return ret; +} + +static void qla4xxx_free_nt_list(struct list_head *list_nt) +{ + struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; + + /* Free up the normaltargets list */ + list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { + list_del_init(&nt_ddb_idx->list); + vfree(nt_ddb_idx); + } + +} + +static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry) +{ + struct iscsi_endpoint *ep; + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + struct sockaddr *dst_addr; + char *ip; + + /* TODO: need to destroy on unload iscsi_endpoint*/ + dst_addr = vmalloc(sizeof(*dst_addr)); + if (!dst_addr) + return NULL; + + if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) { + dst_addr->sa_family = AF_INET6; + addr6 = (struct sockaddr_in6 *)dst_addr; + ip = (char *)&addr6->sin6_addr; + memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); + addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port)); + + } else { + dst_addr->sa_family = AF_INET; + addr = (struct sockaddr_in *)dst_addr; + ip = (char *)&addr->sin_addr; + memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN); + addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port)); + } + + ep = qla4xxx_ep_connect(ha->host, dst_addr, 0); + vfree(dst_addr); + return ep; +} + +static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) +{ + if (ql4xdisablesysfsboot) + return QLA_SUCCESS; + if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx) + return QLA_ERROR; + return QLA_SUCCESS; +} + +static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + ddb_entry->ddb_type = FLASH_DDB; + ddb_entry->fw_ddb_index = INVALID_ENTRY; + ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; + ddb_entry->ha = ha; + ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb; + ddb_entry->ddb_change = qla4xxx_flash_ddb_change; + + atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->relogin_retry_count, 0); + + ddb_entry->default_relogin_timeout = + le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); + ddb_entry->default_time2wait = + le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); +} + +static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) +{ + uint32_t idx = 0; + uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */ + uint32_t sts[MBOX_REG_COUNT]; + uint32_t ip_state; + unsigned long wtime; + int ret; + + wtime = jiffies + (HZ * IP_CONFIG_TOV); + do { + for (idx = 0; idx < IP_ADDR_COUNT; idx++) { + if (ip_idx[idx] == -1) + continue; + + ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts); + + if (ret == QLA_ERROR) { + ip_idx[idx] = -1; + continue; + } + + ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Waiting for IP state for idx = %d, state = 0x%x\n", + ip_idx[idx], ip_state)); + if (ip_state == IP_ADDRSTATE_UNCONFIGURED || + ip_state == IP_ADDRSTATE_INVALID || + ip_state == IP_ADDRSTATE_PREFERRED || + ip_state == IP_ADDRSTATE_DEPRICATED || + ip_state == IP_ADDRSTATE_DISABLING) + ip_idx[idx] = -1; + + } + + /* Break if all IP states checked */ + if ((ip_idx[0] == -1) && + (ip_idx[1] == -1) && + (ip_idx[2] == -1) && + (ip_idx[3] == -1)) + break; + schedule_timeout_uninterruptible(HZ); + } while (time_after(wtime, jiffies)); +} + +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) +{ + int max_ddbs; + int ret; + uint32_t idx = 0, next_idx = 0; + uint32_t state = 0, conn_err = 0; + uint16_t conn_id; + struct dev_db_entry *fw_ddb_entry; + struct ddb_entry *ddb_entry = NULL; + dma_addr_t fw_ddb_dma; + struct iscsi_cls_session *cls_sess; + struct iscsi_session *sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_endpoint *ep; + uint16_t cmds_max = 32, tmo = 0; + uint32_t initial_cmdsn = 0; + struct list_head list_st, list_nt; /* List of sendtargets */ + struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; + int fw_idx_size; + unsigned long wtime; + struct qla_ddb_index *nt_ddb_idx; + + if (!test_bit(AF_LINK_UP, &ha->flags)) { + set_bit(AF_BUILD_DDB_LIST, &ha->flags); + ha->is_reset = is_reset; + return; + } + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_ddb_list; + } + + INIT_LIST_HEAD(&list_st); + INIT_LIST_HEAD(&list_nt); + fw_idx_size = sizeof(struct qla_ddb_index); + + for (idx = 0; idx < max_ddbs; idx = next_idx) { + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, + fw_ddb_dma, NULL, + &next_idx, &state, &conn_err, + NULL, &conn_id); + if (ret == QLA_ERROR) + break; + + if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) + goto continue_next_st; + + /* Check if ST, add to the list_st */ + if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) + goto continue_next_st; + + st_ddb_idx = vzalloc(fw_idx_size); + if (!st_ddb_idx) + break; + + st_ddb_idx->fw_ddb_idx = idx; + + list_add_tail(&st_ddb_idx->list, &list_st); +continue_next_st: + if (next_idx == 0) + break; + } + + /* Before issuing conn open mbox, ensure all IPs states are configured + * Note, conn open fails if IPs are not configured + */ + qla4xxx_wait_for_ip_configuration(ha); + + /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { + qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); + } + + /* Wait to ensure all sendtargets are done for min 12 sec wait */ + tmo = ((ha->def_timeout < LOGIN_TOV) ? LOGIN_TOV : ha->def_timeout); + DEBUG2(ql4_printk(KERN_INFO, ha, + "Default time to wait for build ddb %d\n", tmo)); + + wtime = jiffies + (HZ * tmo); + do { + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, + list) { + ret = qla4xxx_get_fwddb_entry(ha, + st_ddb_idx->fw_ddb_idx, + NULL, 0, NULL, &next_idx, + &state, &conn_err, NULL, + NULL); + if (ret == QLA_ERROR) + continue; + + if (state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED) { + list_del_init(&st_ddb_idx->list); + vfree(st_ddb_idx); + } + } + schedule_timeout_uninterruptible(HZ / 10); + } while (time_after(wtime, jiffies)); + + /* Free up the sendtargets list */ + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { + list_del_init(&st_ddb_idx->list); + vfree(st_ddb_idx); + } + + for (idx = 0; idx < max_ddbs; idx = next_idx) { + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, + fw_ddb_dma, NULL, + &next_idx, &state, &conn_err, + NULL, &conn_id); + if (ret == QLA_ERROR) + break; + + if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) + goto continue_next_nt; + + /* Check if NT, then add to list it */ + if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) + goto continue_next_nt; + + if (state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Adding DDB to session = 0x%x\n", + idx)); + if (is_reset == INIT_ADAPTER) { + nt_ddb_idx = vmalloc(fw_idx_size); + if (!nt_ddb_idx) + break; + + nt_ddb_idx->fw_ddb_idx = idx; + + memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, + sizeof(struct dev_db_entry)); + + if (qla4xxx_is_flash_ddb_exists(ha, &list_nt, + fw_ddb_entry) == QLA_SUCCESS) { + vfree(nt_ddb_idx); + goto continue_next_nt; + } + list_add_tail(&nt_ddb_idx->list, &list_nt); + } else if (is_reset == RESET_ADAPTER) { + if (qla4xxx_is_session_exists(ha, + fw_ddb_entry) == QLA_SUCCESS) + goto continue_next_nt; + } + + /* Create session object, with INVALID_ENTRY, + * the targer_id would get set when we issue the login + */ + cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, + ha->host, cmds_max, + sizeof(struct ddb_entry), + sizeof(struct ql4_task_data), + initial_cmdsn, INVALID_ENTRY); + if (!cls_sess) + goto exit_ddb_list; + + /* + * iscsi_session_setup increments the driver reference + * count which wouldn't let the driver to be unloaded. + * so calling module_put function to decrement the + * reference count. + **/ + module_put(qla4xxx_iscsi_transport.owner); + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ddb_entry->sess = cls_sess; + + cls_sess->recovery_tmo = ql4xsess_recovery_tmo; + memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, + sizeof(struct dev_db_entry)); + + qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); + + cls_conn = iscsi_conn_setup(cls_sess, + sizeof(struct qla_conn), + conn_id); + if (!cls_conn) + goto exit_ddb_list; + + ddb_entry->conn = cls_conn; + + /* Setup ep, for displaying attributes in sysfs */ + ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); + if (ep) { + ep->conn = cls_conn; + cls_conn->ep = ep; + } else { + DEBUG2(ql4_printk(KERN_ERR, ha, + "Unable to get ep\n")); + } + + /* Update sess/conn params */ + qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, + cls_conn); + + if (is_reset == RESET_ADAPTER) { + iscsi_block_session(cls_sess); + /* Use the relogin path to discover new devices + * by short-circuting the logic of setting + * timer to relogin - instead set the flags + * to initiate login right away. + */ + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + } + } +continue_next_nt: + if (next_idx == 0) + break; + } +exit_ddb_list: + qla4xxx_free_nt_list(&list_nt); + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); + + qla4xxx_free_ddb_index(ha); +} + + /** * qla4xxx_probe_adapter - callback function to probe HBA * @pdev: pointer to pci_dev structure @@ -3298,7 +4236,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, * firmware * NOTE: interrupts enabled upon successful completion */ - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); while ((!test_bit(AF_ONLINE, &ha->flags)) && init_retry_count++ < MAX_INIT_RETRIES) { @@ -3319,7 +4257,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) continue; - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); } if (!test_bit(AF_ONLINE, &ha->flags)) { @@ -3386,12 +4324,16 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - qla4xxx_create_chap_list(ha); - if (qla4xxx_setup_boot_info(ha)) ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", __func__); + /* Perform the build ddb list and login to each */ + qla4xxx_build_ddb_list(ha, INIT_ADAPTER); + iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); + + qla4xxx_create_chap_list(ha); + qla4xxx_create_ifaces(ha); return 0; @@ -3449,6 +4391,38 @@ static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) } } +static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry; + int options; + int idx; + + for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { + + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if ((ddb_entry != NULL) && + (ddb_entry->ddb_type == FLASH_DDB)) { + + options = LOGOUT_OPTION_CLOSE_SESSION; + if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) + == QLA_ERROR) + ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", + __func__); + + qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); + /* + * we have decremented the reference count of the driver + * when we setup the session to have the driver unload + * to be seamless without actually destroying the + * session + **/ + try_module_get(qla4xxx_iscsi_transport.owner); + iscsi_destroy_endpoint(ddb_entry->conn->ep); + qla4xxx_free_ddb(ha, ddb_entry); + iscsi_session_teardown(ddb_entry->sess); + } + } +} /** * qla4xxx_remove_adapter - calback function to remove adapter. * @pci_dev: PCI device pointer @@ -3465,9 +4439,11 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) /* destroy iface from sysfs */ qla4xxx_destroy_ifaces(ha); - if (ha->boot_kset) + if ((!ql4xdisablesysfsboot) && ha->boot_kset) iscsi_boot_destroy_kset(ha->boot_kset); + qla4xxx_destroy_fw_ddb_session(ha); + scsi_remove_host(ha->host); qla4xxx_free_adapter(ha); @@ -4115,7 +5091,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) qla4_8xxx_idc_unlock(ha); clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha); + rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); qla4_8xxx_idc_lock(ha); if (rval != QLA_SUCCESS) { @@ -4151,7 +5127,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == QLA82XX_DEV_READY)) { clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha); + rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); if (rval == QLA_SUCCESS) { ret = qla4xxx_request_irqs(ha); if (ret) { diff --git a/trunk/drivers/scsi/qla4xxx/ql4_version.h b/trunk/drivers/scsi/qla4xxx/ql4_version.h index c15347d3f532..5254e57968f5 100644 --- a/trunk/drivers/scsi/qla4xxx/ql4_version.h +++ b/trunk/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k8" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k9" diff --git a/trunk/drivers/usb/dwc3/core.c b/trunk/drivers/usb/dwc3/core.c index 717ebc9ff941..600d82348511 100644 --- a/trunk/drivers/usb/dwc3/core.c +++ b/trunk/drivers/usb/dwc3/core.c @@ -264,7 +264,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) ret = -ENODEV; goto err0; } - dwc->revision = reg & DWC3_GSNPSREV_MASK; + dwc->revision = reg; dwc3_core_soft_reset(dwc); diff --git a/trunk/drivers/usb/gadget/epautoconf.c b/trunk/drivers/usb/gadget/epautoconf.c index 596a0b464e61..4dff83d2f265 100644 --- a/trunk/drivers/usb/gadget/epautoconf.c +++ b/trunk/drivers/usb/gadget/epautoconf.c @@ -130,9 +130,6 @@ ep_matches ( num_req_streams = ep_comp->bmAttributes & 0x1f; if (num_req_streams > ep->max_streams) return 0; - /* Update the ep_comp descriptor if needed */ - if (num_req_streams != ep->max_streams) - ep_comp->bmAttributes = ep->max_streams; } } diff --git a/trunk/drivers/usb/host/isp1760-if.c b/trunk/drivers/usb/host/isp1760-if.c index a7dc1e1d45f2..2ac4ac2e4ef9 100644 --- a/trunk/drivers/usb/host/isp1760-if.c +++ b/trunk/drivers/usb/host/isp1760-if.c @@ -18,7 +18,7 @@ #include "isp1760-hcd.h" -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) #include #include #include @@ -31,7 +31,7 @@ #include #endif -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) struct isp1760 { struct usb_hcd *hcd; int rst_gpio; @@ -437,7 +437,7 @@ static int __init isp1760_init(void) ret = platform_driver_register(&isp1760_plat_driver); if (!ret) any_ret = 0; -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) ret = platform_driver_register(&isp1760_of_driver); if (!ret) any_ret = 0; @@ -457,7 +457,7 @@ module_init(isp1760_init); static void __exit isp1760_exit(void) { platform_driver_unregister(&isp1760_plat_driver); -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) platform_driver_unregister(&isp1760_of_driver); #endif #ifdef CONFIG_PCI diff --git a/trunk/drivers/usb/musb/musb_host.c b/trunk/drivers/usb/musb/musb_host.c index 60ddba8066ea..79cb0af779fa 100644 --- a/trunk/drivers/usb/musb/musb_host.c +++ b/trunk/drivers/usb/musb/musb_host.c @@ -774,6 +774,10 @@ static void musb_ep_program(struct musb *musb, u8 epnum, if (musb->double_buffer_not_ok) musb_writew(epio, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); + else if (can_bulk_split(musb, qh->type)) + musb_writew(epio, MUSB_TXMAXP, packet_sz + | ((hw_ep->max_packet_sz_tx / + packet_sz) - 1) << 11); else musb_writew(epio, MUSB_TXMAXP, qh->maxpacket | diff --git a/trunk/drivers/watchdog/coh901327_wdt.c b/trunk/drivers/watchdog/coh901327_wdt.c index 03f449a430d2..5b89f7d6cd0f 100644 --- a/trunk/drivers/watchdog/coh901327_wdt.c +++ b/trunk/drivers/watchdog/coh901327_wdt.c @@ -76,8 +76,6 @@ static int irq; static void __iomem *virtbase; static unsigned long coh901327_users; static unsigned long boot_status; -static u16 wdogenablestore; -static u16 irqmaskstore; static struct device *parent; /* @@ -461,6 +459,10 @@ static int __init coh901327_probe(struct platform_device *pdev) } #ifdef CONFIG_PM + +static u16 wdogenablestore; +static u16 irqmaskstore; + static int coh901327_suspend(struct platform_device *pdev, pm_message_t state) { irqmaskstore = readw(virtbase + U300_WDOG_IMR) & 0x0001U; diff --git a/trunk/drivers/watchdog/hpwdt.c b/trunk/drivers/watchdog/hpwdt.c index 3774c9b8dac9..8464ea1c36a1 100644 --- a/trunk/drivers/watchdog/hpwdt.c +++ b/trunk/drivers/watchdog/hpwdt.c @@ -231,6 +231,7 @@ static int __devinit cru_detect(unsigned long map_entry, cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; + set_memory_x((unsigned long)bios32_entrypoint, (2 * PAGE_SIZE)); asminline_call(&cmn_regs, bios32_entrypoint); if (cmn_regs.u1.ral != 0) { @@ -248,8 +249,10 @@ static int __devinit cru_detect(unsigned long map_entry, if ((physical_bios_base + physical_bios_offset)) { cru_rom_addr = ioremap(cru_physical_address, cru_length); - if (cru_rom_addr) + if (cru_rom_addr) { + set_memory_x((unsigned long)cru_rom_addr, cru_length); retval = 0; + } } printk(KERN_DEBUG "hpwdt: CRU Base Address: 0x%lx\n", diff --git a/trunk/drivers/watchdog/iTCO_wdt.c b/trunk/drivers/watchdog/iTCO_wdt.c index ba6ad662635a..99796c5d913d 100644 --- a/trunk/drivers/watchdog/iTCO_wdt.c +++ b/trunk/drivers/watchdog/iTCO_wdt.c @@ -384,10 +384,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -static int turn_SMI_watchdog_clear_off = 0; +static int turn_SMI_watchdog_clear_off = 1; module_param(turn_SMI_watchdog_clear_off, int, 0); MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, - "Turn off SMI clearing watchdog (default=0)"); + "Turn off SMI clearing watchdog (depends on TCO-version)(default=1)"); /* * Some TCO specific functions @@ -813,7 +813,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ret = -EIO; goto out_unmap; } - if (turn_SMI_watchdog_clear_off) { + if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) { /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ val32 = inl(SMI_EN); val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ diff --git a/trunk/drivers/watchdog/sp805_wdt.c b/trunk/drivers/watchdog/sp805_wdt.c index cc2cfbe33b30..bfaf9bb1ee0d 100644 --- a/trunk/drivers/watchdog/sp805_wdt.c +++ b/trunk/drivers/watchdog/sp805_wdt.c @@ -351,7 +351,7 @@ static int __devexit sp805_wdt_remove(struct amba_device *adev) return 0; } -static struct amba_id sp805_wdt_ids[] __initdata = { +static struct amba_id sp805_wdt_ids[] = { { .id = 0x00141805, .mask = 0x00ffffff, diff --git a/trunk/drivers/xen/xenbus/xenbus_xs.c b/trunk/drivers/xen/xenbus/xenbus_xs.c index b3b8f2f3ad10..ede860f921df 100644 --- a/trunk/drivers/xen/xenbus/xenbus_xs.c +++ b/trunk/drivers/xen/xenbus/xenbus_xs.c @@ -621,15 +621,6 @@ static struct xenbus_watch *find_watch(const char *token) return NULL; } -static void xs_reset_watches(void) -{ - int err; - - err = xs_error(xs_single(XBT_NIL, XS_RESET_WATCHES, "", NULL)); - if (err && err != -EEXIST) - printk(KERN_WARNING "xs_reset_watches failed: %d\n", err); -} - /* Register callback to watch this node. */ int register_xenbus_watch(struct xenbus_watch *watch) { @@ -906,9 +897,5 @@ int xs_init(void) if (IS_ERR(task)) return PTR_ERR(task); - /* shutdown watches for kexec boot */ - if (xen_hvm_domain()) - xs_reset_watches(); - return 0; } diff --git a/trunk/firmware/README.AddingFirmware b/trunk/firmware/README.AddingFirmware index e24cd8986d8b..ea78c3a17eec 100644 --- a/trunk/firmware/README.AddingFirmware +++ b/trunk/firmware/README.AddingFirmware @@ -12,7 +12,7 @@ here. This directory is _NOT_ for adding arbitrary new firmware images. The place to add those is the separate linux-firmware repository: - git://git.kernel.org/pub/scm/linux/kernel/git/dwmw2/linux-firmware.git + git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git That repository contains all these firmware images which have been extracted from older drivers, as well various new firmware images which @@ -22,6 +22,7 @@ been permitted to redistribute under separate cover. To submit firmware to that repository, please send either a git binary diff or preferably a git pull request to: David Woodhouse + Ben Hutchings Your commit should include an update to the WHENCE file clearly identifying the licence under which the firmware is available, and diff --git a/trunk/fs/btrfs/async-thread.c b/trunk/fs/btrfs/async-thread.c index cb97174e2366..0b394580d860 100644 --- a/trunk/fs/btrfs/async-thread.c +++ b/trunk/fs/btrfs/async-thread.c @@ -563,8 +563,8 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) struct list_head *fallback; int ret; -again: spin_lock_irqsave(&workers->lock, flags); +again: worker = next_worker(workers); if (!worker) { @@ -579,6 +579,7 @@ static struct btrfs_worker_thread *find_worker(struct btrfs_workers *workers) spin_unlock_irqrestore(&workers->lock, flags); /* we're below the limit, start another worker */ ret = __btrfs_start_workers(workers); + spin_lock_irqsave(&workers->lock, flags); if (ret) goto fallback; goto again; diff --git a/trunk/fs/btrfs/inode.c b/trunk/fs/btrfs/inode.c index 0a6b928813a4..fd1a06df5bc6 100644 --- a/trunk/fs/btrfs/inode.c +++ b/trunk/fs/btrfs/inode.c @@ -4590,10 +4590,6 @@ static int btrfs_add_nondir(struct btrfs_trans_handle *trans, int err = btrfs_add_link(trans, dir, inode, dentry->d_name.name, dentry->d_name.len, backref, index); - if (!err) { - d_instantiate(dentry, inode); - return 0; - } if (err > 0) err = -EEXIST; return err; @@ -4655,6 +4651,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, else { init_special_inode(inode, inode->i_mode, rdev); btrfs_update_inode(trans, root, inode); + d_instantiate(dentry, inode); } out_unlock: nr = trans->blocks_used; @@ -4722,6 +4719,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, inode->i_mapping->a_ops = &btrfs_aops; inode->i_mapping->backing_dev_info = &root->fs_info->bdi; BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; + d_instantiate(dentry, inode); } out_unlock: nr = trans->blocks_used; @@ -4779,6 +4777,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *parent = dentry->d_parent; err = btrfs_update_inode(trans, root, inode); BUG_ON(err); + d_instantiate(dentry, inode); btrfs_log_new_name(trans, inode, NULL, parent); } @@ -7245,6 +7244,8 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, drop_inode = 1; out_unlock: + if (!err) + d_instantiate(dentry, inode); nr = trans->blocks_used; btrfs_end_transaction_throttle(trans, root); if (drop_inode) { diff --git a/trunk/fs/ceph/dir.c b/trunk/fs/ceph/dir.c index 3eeb97661262..98954003a8d3 100644 --- a/trunk/fs/ceph/dir.c +++ b/trunk/fs/ceph/dir.c @@ -1094,42 +1094,19 @@ static int ceph_snapdir_d_revalidate(struct dentry *dentry, /* * Set/clear/test dir complete flag on the dir's dentry. */ -static struct dentry * __d_find_any_alias(struct inode *inode) -{ - struct dentry *alias; - - if (list_empty(&inode->i_dentry)) - return NULL; - alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias); - return alias; -} - void ceph_dir_set_complete(struct inode *inode) { - struct dentry *dentry = __d_find_any_alias(inode); - - if (dentry && ceph_dentry(dentry)) { - dout(" marking %p (%p) complete\n", inode, dentry); - set_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); - } + /* not yet implemented */ } void ceph_dir_clear_complete(struct inode *inode) { - struct dentry *dentry = __d_find_any_alias(inode); - - if (dentry && ceph_dentry(dentry)) { - dout(" marking %p (%p) NOT complete\n", inode, dentry); - clear_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); - } + /* not yet implemented */ } bool ceph_dir_test_complete(struct inode *inode) { - struct dentry *dentry = __d_find_any_alias(inode); - - if (dentry && ceph_dentry(dentry)) - return test_bit(CEPH_D_COMPLETE, &ceph_dentry(dentry)->flags); + /* not yet implemented */ return false; } diff --git a/trunk/fs/cifs/connect.c b/trunk/fs/cifs/connect.c index 8cd4b52d4217..f3670cf72587 100644 --- a/trunk/fs/cifs/connect.c +++ b/trunk/fs/cifs/connect.c @@ -282,7 +282,7 @@ static int coalesce_t2(struct smb_hdr *psecond, struct smb_hdr *pTargetSMB) byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); byte_count += total_in_buf2; /* don't allow buffer to overflow */ - if (byte_count > CIFSMaxBufSize) + if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) return -ENOBUFS; pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); @@ -2122,7 +2122,7 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) warned_on_ntlm = true; cERROR(1, "default security mechanism requested. The default " "security mechanism will be upgraded from ntlm to " - "ntlmv2 in kernel release 3.2"); + "ntlmv2 in kernel release 3.3"); } ses->overrideSecFlg = volume_info->secFlg; diff --git a/trunk/fs/fs-writeback.c b/trunk/fs/fs-writeback.c index ac86f8b3e3cb..517f211a3bd4 100644 --- a/trunk/fs/fs-writeback.c +++ b/trunk/fs/fs-writeback.c @@ -47,17 +47,6 @@ struct wb_writeback_work { struct completion *done; /* set if the caller waits */ }; -const char *wb_reason_name[] = { - [WB_REASON_BACKGROUND] = "background", - [WB_REASON_TRY_TO_FREE_PAGES] = "try_to_free_pages", - [WB_REASON_SYNC] = "sync", - [WB_REASON_PERIODIC] = "periodic", - [WB_REASON_LAPTOP_TIMER] = "laptop_timer", - [WB_REASON_FREE_MORE_MEM] = "free_more_memory", - [WB_REASON_FS_FREE_SPACE] = "fs_free_space", - [WB_REASON_FORKER_THREAD] = "forker_thread" -}; - /* * Include the creation of the trace points after defining the * wb_writeback_work structure so that the definition remains local to this diff --git a/trunk/fs/locks.c b/trunk/fs/locks.c index 3b0d05dcd7c1..637694bf3a03 100644 --- a/trunk/fs/locks.c +++ b/trunk/fs/locks.c @@ -1205,6 +1205,8 @@ int __break_lease(struct inode *inode, unsigned int mode) int want_write = (mode & O_ACCMODE) != O_RDONLY; new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK); + if (IS_ERR(new_fl)) + return PTR_ERR(new_fl); lock_flocks(); @@ -1221,12 +1223,6 @@ int __break_lease(struct inode *inode, unsigned int mode) if (fl->fl_owner == current->files) i_have_this_lease = 1; - if (IS_ERR(new_fl) && !i_have_this_lease - && ((mode & O_NONBLOCK) == 0)) { - error = PTR_ERR(new_fl); - goto out; - } - break_time = 0; if (lease_break_time > 0) { break_time = jiffies + lease_break_time * HZ; @@ -1284,8 +1280,7 @@ int __break_lease(struct inode *inode, unsigned int mode) out: unlock_flocks(); - if (!IS_ERR(new_fl)) - locks_free_lock(new_fl); + locks_free_lock(new_fl); return error; } diff --git a/trunk/fs/minix/inode.c b/trunk/fs/minix/inode.c index 1d9e33966db0..4d46a6a59070 100644 --- a/trunk/fs/minix/inode.c +++ b/trunk/fs/minix/inode.c @@ -263,23 +263,6 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) goto out_no_root; } - ret = -ENOMEM; - s->s_root = d_alloc_root(root_inode); - if (!s->s_root) - goto out_iput; - - if (!(s->s_flags & MS_RDONLY)) { - if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ - ms->s_state &= ~MINIX_VALID_FS; - mark_buffer_dirty(bh); - } - if (!(sbi->s_mount_state & MINIX_VALID_FS)) - printk("MINIX-fs: mounting unchecked file system, " - "running fsck is recommended\n"); - else if (sbi->s_mount_state & MINIX_ERROR_FS) - printk("MINIX-fs: mounting file system with errors, " - "running fsck is recommended\n"); - /* Apparently minix can create filesystems that allocate more blocks for * the bitmaps than needed. We simply ignore that, but verify it didn't * create one with not enough blocks and bail out if so. @@ -300,6 +283,23 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) goto out_iput; } + ret = -ENOMEM; + s->s_root = d_alloc_root(root_inode); + if (!s->s_root) + goto out_iput; + + if (!(s->s_flags & MS_RDONLY)) { + if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ + ms->s_state &= ~MINIX_VALID_FS; + mark_buffer_dirty(bh); + } + if (!(sbi->s_mount_state & MINIX_VALID_FS)) + printk("MINIX-fs: mounting unchecked file system, " + "running fsck is recommended\n"); + else if (sbi->s_mount_state & MINIX_ERROR_FS) + printk("MINIX-fs: mounting file system with errors, " + "running fsck is recommended\n"); + return 0; out_iput: diff --git a/trunk/fs/nfs/file.c b/trunk/fs/nfs/file.c index eca56d4b39c0..606ef0f20aed 100644 --- a/trunk/fs/nfs/file.c +++ b/trunk/fs/nfs/file.c @@ -147,7 +147,7 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) * origin == SEEK_END || SEEK_DATA || SEEK_HOLE => we must revalidate * the cached file length */ - if (origin != SEEK_SET || origin != SEEK_CUR) { + if (origin != SEEK_SET && origin != SEEK_CUR) { struct inode *inode = filp->f_mapping->host; int retval = nfs_revalidate_file_size(inode, filp); diff --git a/trunk/fs/nfs/nfs4proc.c b/trunk/fs/nfs/nfs4proc.c index be2bbac13817..d9f4d78c3413 100644 --- a/trunk/fs/nfs/nfs4proc.c +++ b/trunk/fs/nfs/nfs4proc.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include @@ -894,6 +896,8 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode) { + if (delegation == NULL) + return 0; if ((delegation->type & fmode) != fmode) return 0; if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags)) @@ -1036,8 +1040,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) } rcu_read_lock(); delegation = rcu_dereference(nfsi->delegation); - if (delegation == NULL || - !can_open_delegated(delegation, fmode)) { + if (!can_open_delegated(delegation, fmode)) { rcu_read_unlock(); break; } @@ -1091,7 +1094,12 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data if (delegation) delegation_flags = delegation->flags; rcu_read_unlock(); - if ((delegation_flags & 1UL<o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) { + pr_err_ratelimited("NFS: Broken NFSv4 server %s is " + "returning a delegation for " + "OPEN(CLAIM_DELEGATE_CUR)\n", + NFS_CLIENT(inode)->cl_server); + } else if ((delegation_flags & 1UL<inode, data->owner->so_cred, &data->o_res); @@ -1423,11 +1431,9 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) goto out_no_action; rcu_read_lock(); delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); - if (delegation != NULL && - test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) == 0) { - rcu_read_unlock(); - goto out_no_action; - } + if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR && + can_open_delegated(delegation, data->o_arg.fmode)) + goto unlock_no_action; rcu_read_unlock(); } /* Update sequence id. */ @@ -1444,6 +1450,8 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) return; rpc_call_start(task); return; +unlock_no_action: + rcu_read_unlock(); out_no_action: task->tk_action = NULL; diff --git a/trunk/fs/nfs/nfs4state.c b/trunk/fs/nfs/nfs4state.c index 39914be40b03..6a7107ae6b72 100644 --- a/trunk/fs/nfs/nfs4state.c +++ b/trunk/fs/nfs/nfs4state.c @@ -1156,11 +1156,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs if (status >= 0) { status = nfs4_reclaim_locks(state, ops); if (status >= 0) { + spin_lock(&state->state_lock); list_for_each_entry(lock, &state->lock_states, ls_locks) { if (!(lock->ls_flags & NFS_LOCK_INITIALIZED)) printk("%s: Lock reclaim failed!\n", __func__); } + spin_unlock(&state->state_lock); nfs4_put_open_state(state); goto restart; } @@ -1224,10 +1226,12 @@ static void nfs4_clear_open_state(struct nfs4_state *state) clear_bit(NFS_O_RDONLY_STATE, &state->flags); clear_bit(NFS_O_WRONLY_STATE, &state->flags); clear_bit(NFS_O_RDWR_STATE, &state->flags); + spin_lock(&state->state_lock); list_for_each_entry(lock, &state->lock_states, ls_locks) { lock->ls_seqid.flags = 0; lock->ls_flags &= ~NFS_LOCK_INITIALIZED; } + spin_unlock(&state->state_lock); } static void nfs4_reset_seqids(struct nfs_server *server, @@ -1350,12 +1354,14 @@ static void nfs4_warn_keyexpired(const char *s) static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) { switch (error) { + case 0: + break; case -NFS4ERR_CB_PATH_DOWN: nfs_handle_cb_pathdown(clp); - return 0; + break; case -NFS4ERR_NO_GRACE: nfs4_state_end_reclaim_reboot(clp); - return 0; + break; case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_LEASE_MOVED: set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); @@ -1375,13 +1381,15 @@ static int nfs4_recovery_handle_error(struct nfs_client *clp, int error) case -NFS4ERR_SEQ_MISORDERED: set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state); /* Zero session reset errors */ - return 0; + break; case -EKEYEXPIRED: /* Nothing we can do */ nfs4_warn_keyexpired(clp->cl_hostname); - return 0; + break; + default: + return error; } - return error; + return 0; } static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops) @@ -1428,7 +1436,7 @@ static int nfs4_check_lease(struct nfs_client *clp) struct rpc_cred *cred; const struct nfs4_state_maintenance_ops *ops = clp->cl_mvops->state_renewal_ops; - int status = -NFS4ERR_EXPIRED; + int status; /* Is the client already known to have an expired lease? */ if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) @@ -1438,6 +1446,7 @@ static int nfs4_check_lease(struct nfs_client *clp) spin_unlock(&clp->cl_lock); if (cred == NULL) { cred = nfs4_get_setclientid_cred(clp); + status = -ENOKEY; if (cred == NULL) goto out; } @@ -1525,16 +1534,16 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) { if (!flags) return; - else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) + if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) nfs41_handle_server_reboot(clp); - else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | + if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | SEQ4_STATUS_ADMIN_STATE_REVOKED | SEQ4_STATUS_LEASE_MOVED)) nfs41_handle_state_revoked(clp); - else if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) + if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) nfs41_handle_recallable_state_revoked(clp); - else if (flags & (SEQ4_STATUS_CB_PATH_DOWN | + if (flags & (SEQ4_STATUS_CB_PATH_DOWN | SEQ4_STATUS_BACKCHANNEL_FAULT | SEQ4_STATUS_CB_PATH_DOWN_SESSION)) nfs41_handle_cb_path_down(clp); @@ -1662,10 +1671,10 @@ static void nfs4_state_manager(struct nfs_client *clp) if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) { status = nfs4_check_lease(clp); + if (status < 0) + goto out_error; if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) continue; - if (status < 0 && status != -NFS4ERR_CB_PATH_DOWN) - goto out_error; } /* Initialize or reset the session */ diff --git a/trunk/fs/nilfs2/ioctl.c b/trunk/fs/nilfs2/ioctl.c index 41d6743d303c..ac258beeda3c 100644 --- a/trunk/fs/nilfs2/ioctl.c +++ b/trunk/fs/nilfs2/ioctl.c @@ -625,6 +625,9 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, if (argv[n].v_nmembs > nsegs * nilfs->ns_blocks_per_segment) goto out_free; + if (argv[n].v_nmembs >= UINT_MAX / argv[n].v_size) + goto out_free; + len = argv[n].v_size * argv[n].v_nmembs; base = (void __user *)(unsigned long)argv[n].v_base; if (len == 0) { @@ -842,6 +845,19 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case FS_IOC32_GETVERSION: cmd = FS_IOC_GETVERSION; break; + case NILFS_IOCTL_CHANGE_CPMODE: + case NILFS_IOCTL_DELETE_CHECKPOINT: + case NILFS_IOCTL_GET_CPINFO: + case NILFS_IOCTL_GET_CPSTAT: + case NILFS_IOCTL_GET_SUINFO: + case NILFS_IOCTL_GET_SUSTAT: + case NILFS_IOCTL_GET_VINFO: + case NILFS_IOCTL_GET_BDESCS: + case NILFS_IOCTL_CLEAN_SEGMENTS: + case NILFS_IOCTL_SYNC: + case NILFS_IOCTL_RESIZE: + case NILFS_IOCTL_SET_ALLOC_RANGE: + break; default: return -ENOIOCTLCMD; } diff --git a/trunk/fs/proc/stat.c b/trunk/fs/proc/stat.c index 2a30d67dd6b8..0855e6f20391 100644 --- a/trunk/fs/proc/stat.c +++ b/trunk/fs/proc/stat.c @@ -32,7 +32,7 @@ static cputime64_t get_idle_time(int cpu) idle = kstat_cpu(cpu).cpustat.idle; idle = cputime64_add(idle, arch_idle_time(cpu)); } else - idle = nsecs_to_jiffies64(1000 * idle_time); + idle = usecs_to_cputime64(idle_time); return idle; } @@ -46,7 +46,7 @@ static cputime64_t get_iowait_time(int cpu) /* !NO_HZ so we can rely on cpustat.iowait */ iowait = kstat_cpu(cpu).cpustat.iowait; else - iowait = nsecs_to_jiffies64(1000 * iowait_time); + iowait = usecs_to_cputime64(iowait_time); return iowait; } diff --git a/trunk/fs/xfs/xfs_super.c b/trunk/fs/xfs/xfs_super.c index 3eca58f51ae9..8a899496fd5f 100644 --- a/trunk/fs/xfs/xfs_super.c +++ b/trunk/fs/xfs/xfs_super.c @@ -868,27 +868,6 @@ xfs_fs_dirty_inode( XFS_I(inode)->i_update_core = 1; } -STATIC int -xfs_log_inode( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error; - - tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); - error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); - if (error) { - xfs_trans_cancel(tp, 0); - return error; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - return xfs_trans_commit(tp, 0); -} - STATIC int xfs_fs_write_inode( struct inode *inode, @@ -902,10 +881,8 @@ xfs_fs_write_inode( if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); - if (!ip->i_update_core) - return 0; - if (wbc->sync_mode == WB_SYNC_ALL) { + if (wbc->sync_mode == WB_SYNC_ALL || wbc->for_kupdate) { /* * Make sure the inode has made it it into the log. Instead * of forcing it all the way to stable storage using a @@ -913,11 +890,14 @@ xfs_fs_write_inode( * ->sync_fs call do that for thus, which reduces the number * of synchronous log forces dramatically. */ - error = xfs_log_inode(ip); + error = xfs_log_dirty_inode(ip, NULL, 0); if (error) goto out; return 0; } else { + if (!ip->i_update_core) + return 0; + /* * We make this non-blocking if the inode is contended, return * EAGAIN to indicate to the caller that they did not succeed. diff --git a/trunk/fs/xfs/xfs_sync.c b/trunk/fs/xfs/xfs_sync.c index be5c51d8f757..f0994aedcd15 100644 --- a/trunk/fs/xfs/xfs_sync.c +++ b/trunk/fs/xfs/xfs_sync.c @@ -336,6 +336,32 @@ xfs_sync_fsdata( return error; } +int +xfs_log_dirty_inode( + struct xfs_inode *ip, + struct xfs_perag *pag, + int flags) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_trans *tp; + int error; + + if (!ip->i_update_core) + return 0; + + tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); + error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return error; + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + return xfs_trans_commit(tp, 0); +} + /* * When remounting a filesystem read-only or freezing the filesystem, we have * two phases to execute. This first phase is syncing the data before we @@ -359,6 +385,16 @@ xfs_quiesce_data( { int error, error2 = 0; + /* + * Log all pending size and timestamp updates. The vfs writeback + * code is supposed to do this, but due to its overagressive + * livelock detection it will skip inodes where appending writes + * were written out in the first non-blocking sync phase if their + * completion took long enough that it happened after taking the + * timestamp for the cut-off in the blocking phase. + */ + xfs_inode_ag_iterator(mp, xfs_log_dirty_inode, 0); + xfs_qm_sync(mp, SYNC_TRYLOCK); xfs_qm_sync(mp, SYNC_WAIT); diff --git a/trunk/fs/xfs/xfs_sync.h b/trunk/fs/xfs/xfs_sync.h index 941202e7ac6e..fa965479d788 100644 --- a/trunk/fs/xfs/xfs_sync.h +++ b/trunk/fs/xfs/xfs_sync.h @@ -34,6 +34,8 @@ void xfs_quiesce_attr(struct xfs_mount *mp); void xfs_flush_inodes(struct xfs_inode *ip); +int xfs_log_dirty_inode(struct xfs_inode *ip, struct xfs_perag *pag, int flags); + int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); int xfs_reclaim_inodes_count(struct xfs_mount *mp); void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan); diff --git a/trunk/include/asm-generic/cputime.h b/trunk/include/asm-generic/cputime.h index 62ce6823c0f2..12a1764f612b 100644 --- a/trunk/include/asm-generic/cputime.h +++ b/trunk/include/asm-generic/cputime.h @@ -40,6 +40,7 @@ typedef u64 cputime64_t; */ #define cputime_to_usecs(__ct) jiffies_to_usecs(__ct) #define usecs_to_cputime(__msecs) usecs_to_jiffies(__msecs) +#define usecs_to_cputime64(__msecs) nsecs_to_jiffies64((__msecs) * 1000) /* * Convert cputime to seconds and back. diff --git a/trunk/include/linux/bitops.h b/trunk/include/linux/bitops.h index 3c1063acb2ab..a3ef66a2a083 100644 --- a/trunk/include/linux/bitops.h +++ b/trunk/include/linux/bitops.h @@ -22,14 +22,8 @@ extern unsigned long __sw_hweight64(__u64 w); #include #define for_each_set_bit(bit, addr, size) \ - for ((bit) = find_first_bit((addr), (size)); \ - (bit) < (size); \ - (bit) = find_next_bit((addr), (size), (bit) + 1)) - -/* same as for_each_set_bit() but use bit as value to start with */ -#define for_each_set_bit_cont(bit, addr, size) \ - for ((bit) = find_next_bit((addr), (size), (bit)); \ - (bit) < (size); \ + for ((bit) = find_first_bit((addr), (size)); \ + (bit) < (size); \ (bit) = find_next_bit((addr), (size), (bit) + 1)) static __inline__ int get_bitmask_order(unsigned int count) diff --git a/trunk/include/linux/clocksource.h b/trunk/include/linux/clocksource.h index c86c940d1de3..081147da0564 100644 --- a/trunk/include/linux/clocksource.h +++ b/trunk/include/linux/clocksource.h @@ -71,7 +71,7 @@ struct timecounter { /** * cyclecounter_cyc2ns - converts cycle counter cycles to nanoseconds - * @tc: Pointer to cycle counter. + * @cc: Pointer to cycle counter. * @cycles: Cycles * * XXX - This could use some mult_lxl_ll() asm optimization. Same code @@ -114,7 +114,7 @@ extern u64 timecounter_read(struct timecounter *tc); * time base as values returned by * timecounter_read() * @tc: Pointer to time counter. - * @cycle: a value returned by tc->cc->read() + * @cycle_tstamp: a value returned by tc->cc->read() * * Cycle counts that are converted correctly as long as they * fall into the interval [-1/2 max cycle count, +1/2 max cycle count], @@ -156,11 +156,12 @@ extern u64 timecounter_cyc2time(struct timecounter *tc, * @mult: cycle to nanosecond multiplier * @shift: cycle to nanosecond divisor (power of two) * @max_idle_ns: max idle time permitted by the clocksource (nsecs) - * @maxadj maximum adjustment value to mult (~11%) + * @maxadj: maximum adjustment value to mult (~11%) * @flags: flags describing special properties * @archdata: arch-specific data * @suspend: suspend function for the clocksource, if necessary * @resume: resume function for the clocksource, if necessary + * @cycle_last: most recent cycle counter value seen by ::read() */ struct clocksource { /* @@ -187,6 +188,7 @@ struct clocksource { void (*suspend)(struct clocksource *cs); void (*resume)(struct clocksource *cs); + /* private: */ #ifdef CONFIG_CLOCKSOURCE_WATCHDOG /* Watchdog related data, used by the framework */ struct list_head wd_list; @@ -261,6 +263,9 @@ static inline u32 clocksource_hz2mult(u32 hz, u32 shift_constant) /** * clocksource_cyc2ns - converts clocksource cycles to nanoseconds + * @cycles: cycles + * @mult: cycle to nanosecond multiplier + * @shift: cycle to nanosecond divisor (power of two) * * Converts cycles to nanoseconds, using the given mult and shift. * diff --git a/trunk/include/linux/compiler-gcc.h b/trunk/include/linux/compiler-gcc.h index 3fd17c249221..59e4028e833d 100644 --- a/trunk/include/linux/compiler-gcc.h +++ b/trunk/include/linux/compiler-gcc.h @@ -50,11 +50,6 @@ # define inline inline __attribute__((always_inline)) # define __inline__ __inline__ __attribute__((always_inline)) # define __inline __inline __attribute__((always_inline)) -#else -/* A lot of inline functions can cause havoc with function tracing */ -# define inline inline notrace -# define __inline__ __inline__ notrace -# define __inline __inline notrace #endif #define __deprecated __attribute__((deprecated)) diff --git a/trunk/include/linux/ftrace.h b/trunk/include/linux/ftrace.h index 028e26f0bf08..26eafcef75be 100644 --- a/trunk/include/linux/ftrace.h +++ b/trunk/include/linux/ftrace.h @@ -133,8 +133,6 @@ struct ftrace_func_command { int ftrace_arch_code_modify_prepare(void); int ftrace_arch_code_modify_post_process(void); -void ftrace_bug(int err, unsigned long ip); - struct seq_file; struct ftrace_probe_ops { @@ -163,6 +161,7 @@ extern int ftrace_text_reserved(void *start, void *end); enum { FTRACE_FL_ENABLED = (1 << 30), + FTRACE_FL_FREE = (1 << 31), }; #define FTRACE_FL_MASK (0x3UL << 30) @@ -173,7 +172,10 @@ struct dyn_ftrace { unsigned long ip; /* address of mcount call-site */ struct dyn_ftrace *freelist; }; - unsigned long flags; + union { + unsigned long flags; + struct dyn_ftrace *newlist; + }; struct dyn_arch_ftrace arch; }; @@ -188,56 +190,6 @@ void ftrace_set_global_notrace(unsigned char *buf, int len, int reset); int register_ftrace_command(struct ftrace_func_command *cmd); int unregister_ftrace_command(struct ftrace_func_command *cmd); -enum { - FTRACE_UPDATE_CALLS = (1 << 0), - FTRACE_DISABLE_CALLS = (1 << 1), - FTRACE_UPDATE_TRACE_FUNC = (1 << 2), - FTRACE_START_FUNC_RET = (1 << 3), - FTRACE_STOP_FUNC_RET = (1 << 4), -}; - -enum { - FTRACE_UPDATE_IGNORE, - FTRACE_UPDATE_MAKE_CALL, - FTRACE_UPDATE_MAKE_NOP, -}; - -enum { - FTRACE_ITER_FILTER = (1 << 0), - FTRACE_ITER_NOTRACE = (1 << 1), - FTRACE_ITER_PRINTALL = (1 << 2), - FTRACE_ITER_DO_HASH = (1 << 3), - FTRACE_ITER_HASH = (1 << 4), - FTRACE_ITER_ENABLED = (1 << 5), -}; - -void arch_ftrace_update_code(int command); - -struct ftrace_rec_iter; - -struct ftrace_rec_iter *ftrace_rec_iter_start(void); -struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter); -struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter); - -int ftrace_update_record(struct dyn_ftrace *rec, int enable); -int ftrace_test_record(struct dyn_ftrace *rec, int enable); -void ftrace_run_stop_machine(int command); -int ftrace_location(unsigned long ip); - -extern ftrace_func_t ftrace_trace_function; - -int ftrace_regex_open(struct ftrace_ops *ops, int flag, - struct inode *inode, struct file *file); -ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos); -ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos); -loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin); -int ftrace_regex_release(struct inode *inode, struct file *file); - -void __init -ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable); - /* defined in arch */ extern int ftrace_ip_converted(unsigned long ip); extern int ftrace_dyn_arch_init(void *data); @@ -332,25 +284,6 @@ static inline int ftrace_text_reserved(void *start, void *end) { return 0; } - -/* - * Again users of functions that have ftrace_ops may not - * have them defined when ftrace is not enabled, but these - * functions may still be called. Use a macro instead of inline. - */ -#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) -#define ftrace_set_early_filter(ops, buf, enable) do { } while (0) - -static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos) { return -ENODEV; } -static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos) { return -ENODEV; } -static inline loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin) -{ - return -ENODEV; -} -static inline int -ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; } #endif /* CONFIG_DYNAMIC_FTRACE */ /* totally disable ftrace - can not re-enable after this */ diff --git a/trunk/include/linux/jump_label.h b/trunk/include/linux/jump_label.h index 5ce8b140428f..388b0d425b50 100644 --- a/trunk/include/linux/jump_label.h +++ b/trunk/include/linux/jump_label.h @@ -3,7 +3,6 @@ #include #include -#include #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) @@ -15,12 +14,6 @@ struct jump_label_key { #endif }; -struct jump_label_key_deferred { - struct jump_label_key key; - unsigned long timeout; - struct delayed_work work; -}; - # include # define HAVE_JUMP_LABEL #endif /* CC_HAVE_ASM_GOTO && CONFIG_JUMP_LABEL */ @@ -58,11 +51,8 @@ extern void arch_jump_label_transform_static(struct jump_entry *entry, extern int jump_label_text_reserved(void *start, void *end); extern void jump_label_inc(struct jump_label_key *key); extern void jump_label_dec(struct jump_label_key *key); -extern void jump_label_dec_deferred(struct jump_label_key_deferred *key); extern bool jump_label_enabled(struct jump_label_key *key); extern void jump_label_apply_nops(struct module *mod); -extern void jump_label_rate_limit(struct jump_label_key_deferred *key, - unsigned long rl); #else /* !HAVE_JUMP_LABEL */ @@ -78,10 +68,6 @@ static __always_inline void jump_label_init(void) { } -struct jump_label_key_deferred { - struct jump_label_key key; -}; - static __always_inline bool static_branch(struct jump_label_key *key) { if (unlikely(atomic_read(&key->enabled))) @@ -99,11 +85,6 @@ static inline void jump_label_dec(struct jump_label_key *key) atomic_dec(&key->enabled); } -static inline void jump_label_dec_deferred(struct jump_label_key_deferred *key) -{ - jump_label_dec(&key->key); -} - static inline int jump_label_text_reserved(void *start, void *end) { return 0; @@ -121,14 +102,6 @@ static inline int jump_label_apply_nops(struct module *mod) { return 0; } - -static inline void jump_label_rate_limit(struct jump_label_key_deferred *key, - unsigned long rl) -{ -} #endif /* HAVE_JUMP_LABEL */ -#define jump_label_key_enabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(1), }) -#define jump_label_key_disabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(0), }) - #endif /* _LINUX_JUMP_LABEL_H */ diff --git a/trunk/include/linux/kvm.h b/trunk/include/linux/kvm.h index c3892fc1d538..68e67e50d028 100644 --- a/trunk/include/linux/kvm.h +++ b/trunk/include/linux/kvm.h @@ -557,6 +557,7 @@ struct kvm_ppc_pvinfo { #define KVM_CAP_MAX_VCPUS 66 /* returns max vcpus per vm */ #define KVM_CAP_PPC_PAPR 68 #define KVM_CAP_S390_GMAP 71 +#define KVM_CAP_TSC_DEADLINE_TIMER 72 #ifdef KVM_CAP_IRQ_ROUTING diff --git a/trunk/include/linux/lglock.h b/trunk/include/linux/lglock.h index f549056fb20b..87f402ccec55 100644 --- a/trunk/include/linux/lglock.h +++ b/trunk/include/linux/lglock.h @@ -22,6 +22,7 @@ #include #include #include +#include /* can make br locks by using local lock for read side, global lock for write */ #define br_lock_init(name) name##_lock_init() @@ -72,9 +73,31 @@ #define DEFINE_LGLOCK(name) \ \ + DEFINE_SPINLOCK(name##_cpu_lock); \ + cpumask_t name##_cpus __read_mostly; \ DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \ DEFINE_LGLOCK_LOCKDEP(name); \ \ + static int \ + name##_lg_cpu_callback(struct notifier_block *nb, \ + unsigned long action, void *hcpu) \ + { \ + switch (action & ~CPU_TASKS_FROZEN) { \ + case CPU_UP_PREPARE: \ + spin_lock(&name##_cpu_lock); \ + cpu_set((unsigned long)hcpu, name##_cpus); \ + spin_unlock(&name##_cpu_lock); \ + break; \ + case CPU_UP_CANCELED: case CPU_DEAD: \ + spin_lock(&name##_cpu_lock); \ + cpu_clear((unsigned long)hcpu, name##_cpus); \ + spin_unlock(&name##_cpu_lock); \ + } \ + return NOTIFY_OK; \ + } \ + static struct notifier_block name##_lg_cpu_notifier = { \ + .notifier_call = name##_lg_cpu_callback, \ + }; \ void name##_lock_init(void) { \ int i; \ LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \ @@ -83,6 +106,11 @@ lock = &per_cpu(name##_lock, i); \ *lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \ } \ + register_hotcpu_notifier(&name##_lg_cpu_notifier); \ + get_online_cpus(); \ + for_each_online_cpu(i) \ + cpu_set(i, name##_cpus); \ + put_online_cpus(); \ } \ EXPORT_SYMBOL(name##_lock_init); \ \ @@ -124,9 +152,9 @@ \ void name##_global_lock_online(void) { \ int i; \ - preempt_disable(); \ + spin_lock(&name##_cpu_lock); \ rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \ - for_each_online_cpu(i) { \ + for_each_cpu(i, &name##_cpus) { \ arch_spinlock_t *lock; \ lock = &per_cpu(name##_lock, i); \ arch_spin_lock(lock); \ @@ -137,12 +165,12 @@ void name##_global_unlock_online(void) { \ int i; \ rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \ - for_each_online_cpu(i) { \ + for_each_cpu(i, &name##_cpus) { \ arch_spinlock_t *lock; \ lock = &per_cpu(name##_lock, i); \ arch_spin_unlock(lock); \ } \ - preempt_enable(); \ + spin_unlock(&name##_cpu_lock); \ } \ EXPORT_SYMBOL(name##_global_unlock_online); \ \ diff --git a/trunk/include/linux/perf_event.h b/trunk/include/linux/perf_event.h index 08855613ceb3..b1f89122bf6a 100644 --- a/trunk/include/linux/perf_event.h +++ b/trunk/include/linux/perf_event.h @@ -54,7 +54,6 @@ enum perf_hw_id { PERF_COUNT_HW_BUS_CYCLES = 6, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7, PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8, - PERF_COUNT_HW_REF_CPU_CYCLES = 9, PERF_COUNT_HW_MAX, /* non-ABI */ }; @@ -891,7 +890,6 @@ struct perf_event_context { int nr_active; int is_active; int nr_stat; - int nr_freq; int rotate_disable; atomic_t refcount; struct task_struct *task; @@ -1065,12 +1063,12 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) } } -extern struct jump_label_key_deferred perf_sched_events; +extern struct jump_label_key perf_sched_events; static inline void perf_event_task_sched_in(struct task_struct *prev, struct task_struct *task) { - if (static_branch(&perf_sched_events.key)) + if (static_branch(&perf_sched_events)) __perf_event_task_sched_in(prev, task); } @@ -1079,7 +1077,7 @@ static inline void perf_event_task_sched_out(struct task_struct *prev, { perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); - if (static_branch(&perf_sched_events.key)) + if (static_branch(&perf_sched_events)) __perf_event_task_sched_out(prev, next); } diff --git a/trunk/include/linux/security.h b/trunk/include/linux/security.h index 19d8e04e1688..e8c619d39291 100644 --- a/trunk/include/linux/security.h +++ b/trunk/include/linux/security.h @@ -2056,7 +2056,7 @@ static inline int security_old_inode_init_security(struct inode *inode, char **name, void **value, size_t *len) { - return 0; + return -EOPNOTSUPP; } static inline int security_inode_create(struct inode *dir, diff --git a/trunk/include/media/soc_camera.h b/trunk/include/media/soc_camera.h index b1377b931eb7..5fb2c3d10c05 100644 --- a/trunk/include/media/soc_camera.h +++ b/trunk/include/media/soc_camera.h @@ -254,7 +254,7 @@ unsigned long soc_camera_apply_board_flags(struct soc_camera_link *icl, static inline struct video_device *soc_camera_i2c_to_vdev(const struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; + struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); return icd ? icd->vdev : NULL; } @@ -279,6 +279,11 @@ static inline struct soc_camera_device *soc_camera_from_vbq(const struct videobu return container_of(vq, struct soc_camera_device, vb_vidq); } +static inline u32 soc_camera_grp_id(const struct soc_camera_device *icd) +{ + return (icd->iface << 8) | (icd->devnum + 1); +} + void soc_camera_lock(struct vb2_queue *vq); void soc_camera_unlock(struct vb2_queue *vq); diff --git a/trunk/include/net/dst.h b/trunk/include/net/dst.h index 6faec1a60216..75766b42660e 100644 --- a/trunk/include/net/dst.h +++ b/trunk/include/net/dst.h @@ -53,6 +53,7 @@ struct dst_entry { #define DST_NOHASH 0x0008 #define DST_NOCACHE 0x0010 #define DST_NOCOUNT 0x0020 +#define DST_NOPEER 0x0040 short error; short obsolete; diff --git a/trunk/include/net/flow.h b/trunk/include/net/flow.h index a09447749e2d..57f15a7f1cdd 100644 --- a/trunk/include/net/flow.h +++ b/trunk/include/net/flow.h @@ -207,6 +207,7 @@ extern struct flow_cache_object *flow_cache_lookup( u8 dir, flow_resolve_t resolver, void *ctx); extern void flow_cache_flush(void); +extern void flow_cache_flush_deferred(void); extern atomic_t flow_cache_genid; #endif diff --git a/trunk/include/net/ip_vs.h b/trunk/include/net/ip_vs.h index 873d5be7926c..e5a7b9aaf552 100644 --- a/trunk/include/net/ip_vs.h +++ b/trunk/include/net/ip_vs.h @@ -1207,7 +1207,7 @@ extern void ip_vs_control_cleanup(void); extern struct ip_vs_dest * ip_vs_find_dest(struct net *net, int af, const union nf_inet_addr *daddr, __be16 dport, const union nf_inet_addr *vaddr, __be16 vport, - __u16 protocol, __u32 fwmark); + __u16 protocol, __u32 fwmark, __u32 flags); extern struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp); diff --git a/trunk/include/net/sctp/structs.h b/trunk/include/net/sctp/structs.h index e90e7a9935dd..a15432da27c3 100644 --- a/trunk/include/net/sctp/structs.h +++ b/trunk/include/net/sctp/structs.h @@ -241,6 +241,9 @@ extern struct sctp_globals { * bits is an indicator of when to send and window update SACK. */ int rwnd_update_shift; + + /* Threshold for autoclose timeout, in seconds. */ + unsigned long max_autoclose; } sctp_globals; #define sctp_rto_initial (sctp_globals.rto_initial) @@ -281,6 +284,7 @@ extern struct sctp_globals { #define sctp_auth_enable (sctp_globals.auth_enable) #define sctp_checksum_disable (sctp_globals.checksum_disable) #define sctp_rwnd_upd_shift (sctp_globals.rwnd_update_shift) +#define sctp_max_autoclose (sctp_globals.max_autoclose) /* SCTP Socket type: UDP or TCP style. */ typedef enum { diff --git a/trunk/include/net/sock.h b/trunk/include/net/sock.h index abb6e0f0c3c3..32e39371fba6 100644 --- a/trunk/include/net/sock.h +++ b/trunk/include/net/sock.h @@ -637,12 +637,14 @@ static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb) /* * Take into account size of receive queue and backlog queue + * Do not take into account this skb truesize, + * to allow even a single big packet to come. */ static inline bool sk_rcvqueues_full(const struct sock *sk, const struct sk_buff *skb) { unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc); - return qsize + skb->truesize > sk->sk_rcvbuf; + return qsize > sk->sk_rcvbuf; } /* The per-socket spinlock must be held here. */ diff --git a/trunk/include/scsi/libfcoe.h b/trunk/include/scsi/libfcoe.h index d1e95c6ac776..5a35a2a2d3c5 100644 --- a/trunk/include/scsi/libfcoe.h +++ b/trunk/include/scsi/libfcoe.h @@ -147,6 +147,7 @@ struct fcoe_ctlr { u8 map_dest; u8 spma; u8 probe_tries; + u8 priority; u8 dest_addr[ETH_ALEN]; u8 ctl_src_addr[ETH_ALEN]; @@ -301,6 +302,7 @@ struct fcoe_percpu_s { * @lport: The associated local port * @fcoe_pending_queue: The pending Rx queue of skbs * @fcoe_pending_queue_active: Indicates if the pending queue is active + * @priority: Packet priority (DCB) * @max_queue_depth: Max queue depth of pending queue * @min_queue_depth: Min queue depth of pending queue * @timer: The queue timer @@ -316,6 +318,7 @@ struct fcoe_port { struct fc_lport *lport; struct sk_buff_head fcoe_pending_queue; u8 fcoe_pending_queue_active; + u8 priority; u32 max_queue_depth; u32 min_queue_depth; struct timer_list timer; diff --git a/trunk/include/trace/events/writeback.h b/trunk/include/trace/events/writeback.h index b99caa8b780c..99d1d0decf88 100644 --- a/trunk/include/trace/events/writeback.h +++ b/trunk/include/trace/events/writeback.h @@ -21,6 +21,16 @@ {I_REFERENCED, "I_REFERENCED"} \ ) +#define WB_WORK_REASON \ + {WB_REASON_BACKGROUND, "background"}, \ + {WB_REASON_TRY_TO_FREE_PAGES, "try_to_free_pages"}, \ + {WB_REASON_SYNC, "sync"}, \ + {WB_REASON_PERIODIC, "periodic"}, \ + {WB_REASON_LAPTOP_TIMER, "laptop_timer"}, \ + {WB_REASON_FREE_MORE_MEM, "free_more_memory"}, \ + {WB_REASON_FS_FREE_SPACE, "fs_free_space"}, \ + {WB_REASON_FORKER_THREAD, "forker_thread"} + struct wb_writeback_work; DECLARE_EVENT_CLASS(writeback_work_class, @@ -55,7 +65,7 @@ DECLARE_EVENT_CLASS(writeback_work_class, __entry->for_kupdate, __entry->range_cyclic, __entry->for_background, - wb_reason_name[__entry->reason] + __print_symbolic(__entry->reason, WB_WORK_REASON) ) ); #define DEFINE_WRITEBACK_WORK_EVENT(name) \ @@ -184,7 +194,8 @@ TRACE_EVENT(writeback_queue_io, __entry->older, /* older_than_this in jiffies */ __entry->age, /* older_than_this in relative milliseconds */ __entry->moved, - wb_reason_name[__entry->reason]) + __print_symbolic(__entry->reason, WB_WORK_REASON) + ) ); TRACE_EVENT(global_dirty_state, diff --git a/trunk/include/xen/interface/io/xs_wire.h b/trunk/include/xen/interface/io/xs_wire.h index f0b6890370be..f6f07aa35af5 100644 --- a/trunk/include/xen/interface/io/xs_wire.h +++ b/trunk/include/xen/interface/io/xs_wire.h @@ -29,8 +29,7 @@ enum xsd_sockmsg_type XS_IS_DOMAIN_INTRODUCED, XS_RESUME, XS_SET_TARGET, - XS_RESTRICT, - XS_RESET_WATCHES + XS_RESTRICT }; #define XS_WRITE_NONE "NONE" diff --git a/trunk/kernel/cgroup.c b/trunk/kernel/cgroup.c index d9d5648f3cdc..a184470cf9b5 100644 --- a/trunk/kernel/cgroup.c +++ b/trunk/kernel/cgroup.c @@ -2098,11 +2098,6 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) continue; /* get old css_set pointer */ task_lock(tsk); - if (tsk->flags & PF_EXITING) { - /* ignore this task if it's going away */ - task_unlock(tsk); - continue; - } oldcg = tsk->cgroups; get_css_set(oldcg); task_unlock(tsk); diff --git a/trunk/kernel/cpuset.c b/trunk/kernel/cpuset.c index 9fe58c46a426..0b1712dba587 100644 --- a/trunk/kernel/cpuset.c +++ b/trunk/kernel/cpuset.c @@ -123,6 +123,19 @@ static inline struct cpuset *task_cs(struct task_struct *task) struct cpuset, css); } +#ifdef CONFIG_NUMA +static inline bool task_has_mempolicy(struct task_struct *task) +{ + return task->mempolicy; +} +#else +static inline bool task_has_mempolicy(struct task_struct *task) +{ + return false; +} +#endif + + /* bits in struct cpuset flags field */ typedef enum { CS_CPU_EXCLUSIVE, @@ -949,7 +962,7 @@ static void cpuset_migrate_mm(struct mm_struct *mm, const nodemask_t *from, static void cpuset_change_task_nodemask(struct task_struct *tsk, nodemask_t *newmems) { - bool masks_disjoint = !nodes_intersects(*newmems, tsk->mems_allowed); + bool need_loop; repeat: /* @@ -962,6 +975,14 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk, return; task_lock(tsk); + /* + * Determine if a loop is necessary if another thread is doing + * get_mems_allowed(). If at least one node remains unchanged and + * tsk does not have a mempolicy, then an empty nodemask will not be + * possible when mems_allowed is larger than a word. + */ + need_loop = task_has_mempolicy(tsk) || + !nodes_intersects(*newmems, tsk->mems_allowed); nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems); mpol_rebind_task(tsk, newmems, MPOL_REBIND_STEP1); @@ -981,11 +1002,9 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk, /* * Allocation of memory is very fast, we needn't sleep when waiting - * for the read-side. No wait is necessary, however, if at least one - * node remains unchanged. + * for the read-side. */ - while (masks_disjoint && - ACCESS_ONCE(tsk->mems_allowed_change_disable)) { + while (need_loop && ACCESS_ONCE(tsk->mems_allowed_change_disable)) { task_unlock(tsk); if (!task_curr(tsk)) yield(); diff --git a/trunk/kernel/events/Makefile b/trunk/kernel/events/Makefile index 22d901f9caf4..89e5e8aa4c36 100644 --- a/trunk/kernel/events/Makefile +++ b/trunk/kernel/events/Makefile @@ -2,5 +2,5 @@ ifdef CONFIG_FUNCTION_TRACER CFLAGS_REMOVE_core.o = -pg endif -obj-y := core.o ring_buffer.o callchain.o +obj-y := core.o ring_buffer.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o diff --git a/trunk/kernel/events/callchain.c b/trunk/kernel/events/callchain.c deleted file mode 100644 index 057e24b665cf..000000000000 --- a/trunk/kernel/events/callchain.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Performance events callchain code, extracted from core.c: - * - * Copyright (C) 2008 Thomas Gleixner - * Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra - * Copyright © 2009 Paul Mackerras, IBM Corp. - * - * For licensing details see kernel-base/COPYING - */ - -#include -#include -#include "internal.h" - -struct callchain_cpus_entries { - struct rcu_head rcu_head; - struct perf_callchain_entry *cpu_entries[0]; -}; - -static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); -static atomic_t nr_callchain_events; -static DEFINE_MUTEX(callchain_mutex); -static struct callchain_cpus_entries *callchain_cpus_entries; - - -__weak void perf_callchain_kernel(struct perf_callchain_entry *entry, - struct pt_regs *regs) -{ -} - -__weak void perf_callchain_user(struct perf_callchain_entry *entry, - struct pt_regs *regs) -{ -} - -static void release_callchain_buffers_rcu(struct rcu_head *head) -{ - struct callchain_cpus_entries *entries; - int cpu; - - entries = container_of(head, struct callchain_cpus_entries, rcu_head); - - for_each_possible_cpu(cpu) - kfree(entries->cpu_entries[cpu]); - - kfree(entries); -} - -static void release_callchain_buffers(void) -{ - struct callchain_cpus_entries *entries; - - entries = callchain_cpus_entries; - rcu_assign_pointer(callchain_cpus_entries, NULL); - call_rcu(&entries->rcu_head, release_callchain_buffers_rcu); -} - -static int alloc_callchain_buffers(void) -{ - int cpu; - int size; - struct callchain_cpus_entries *entries; - - /* - * We can't use the percpu allocation API for data that can be - * accessed from NMI. Use a temporary manual per cpu allocation - * until that gets sorted out. - */ - size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]); - - entries = kzalloc(size, GFP_KERNEL); - if (!entries) - return -ENOMEM; - - size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS; - - for_each_possible_cpu(cpu) { - entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, - cpu_to_node(cpu)); - if (!entries->cpu_entries[cpu]) - goto fail; - } - - rcu_assign_pointer(callchain_cpus_entries, entries); - - return 0; - -fail: - for_each_possible_cpu(cpu) - kfree(entries->cpu_entries[cpu]); - kfree(entries); - - return -ENOMEM; -} - -int get_callchain_buffers(void) -{ - int err = 0; - int count; - - mutex_lock(&callchain_mutex); - - count = atomic_inc_return(&nr_callchain_events); - if (WARN_ON_ONCE(count < 1)) { - err = -EINVAL; - goto exit; - } - - if (count > 1) { - /* If the allocation failed, give up */ - if (!callchain_cpus_entries) - err = -ENOMEM; - goto exit; - } - - err = alloc_callchain_buffers(); - if (err) - release_callchain_buffers(); -exit: - mutex_unlock(&callchain_mutex); - - return err; -} - -void put_callchain_buffers(void) -{ - if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) { - release_callchain_buffers(); - mutex_unlock(&callchain_mutex); - } -} - -static struct perf_callchain_entry *get_callchain_entry(int *rctx) -{ - int cpu; - struct callchain_cpus_entries *entries; - - *rctx = get_recursion_context(__get_cpu_var(callchain_recursion)); - if (*rctx == -1) - return NULL; - - entries = rcu_dereference(callchain_cpus_entries); - if (!entries) - return NULL; - - cpu = smp_processor_id(); - - return &entries->cpu_entries[cpu][*rctx]; -} - -static void -put_callchain_entry(int rctx) -{ - put_recursion_context(__get_cpu_var(callchain_recursion), rctx); -} - -struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) -{ - int rctx; - struct perf_callchain_entry *entry; - - - entry = get_callchain_entry(&rctx); - if (rctx == -1) - return NULL; - - if (!entry) - goto exit_put; - - entry->nr = 0; - - if (!user_mode(regs)) { - perf_callchain_store(entry, PERF_CONTEXT_KERNEL); - perf_callchain_kernel(entry, regs); - if (current->mm) - regs = task_pt_regs(current); - else - regs = NULL; - } - - if (regs) { - perf_callchain_store(entry, PERF_CONTEXT_USER); - perf_callchain_user(entry, regs); - } - -exit_put: - put_callchain_entry(rctx); - - return entry; -} diff --git a/trunk/kernel/events/core.c b/trunk/kernel/events/core.c index 2f8f3f103cb4..58690af323e4 100644 --- a/trunk/kernel/events/core.c +++ b/trunk/kernel/events/core.c @@ -128,7 +128,7 @@ enum event_type_t { * perf_sched_events : >0 events exist * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu */ -struct jump_label_key_deferred perf_sched_events __read_mostly; +struct jump_label_key perf_sched_events __read_mostly; static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); static atomic_t nr_mmap_events __read_mostly; @@ -1130,8 +1130,6 @@ event_sched_out(struct perf_event *event, if (!is_software_event(event)) cpuctx->active_oncpu--; ctx->nr_active--; - if (event->attr.freq && event->attr.sample_freq) - ctx->nr_freq--; if (event->attr.exclusive || !cpuctx->active_oncpu) cpuctx->exclusive = 0; } @@ -1327,7 +1325,6 @@ void perf_event_disable(struct perf_event *event) } raw_spin_unlock_irq(&ctx->lock); } -EXPORT_SYMBOL_GPL(perf_event_disable); static void perf_set_shadow_time(struct perf_event *event, struct perf_event_context *ctx, @@ -1409,8 +1406,6 @@ event_sched_in(struct perf_event *event, if (!is_software_event(event)) cpuctx->active_oncpu++; ctx->nr_active++; - if (event->attr.freq && event->attr.sample_freq) - ctx->nr_freq++; if (event->attr.exclusive) cpuctx->exclusive = 1; @@ -1667,7 +1662,8 @@ perf_install_in_context(struct perf_event_context *ctx, * Note: this works for group members as well as group leaders * since the non-leader members' sibling_lists will be empty. */ -static void __perf_event_mark_enabled(struct perf_event *event) +static void __perf_event_mark_enabled(struct perf_event *event, + struct perf_event_context *ctx) { struct perf_event *sub; u64 tstamp = perf_event_time(event); @@ -1705,7 +1701,7 @@ static int __perf_event_enable(void *info) */ perf_cgroup_set_timestamp(current, ctx); - __perf_event_mark_enabled(event); + __perf_event_mark_enabled(event, ctx); if (!event_filter_match(event)) { if (is_cgroup_event(event)) @@ -1786,7 +1782,7 @@ void perf_event_enable(struct perf_event *event) retry: if (!ctx->is_active) { - __perf_event_mark_enabled(event); + __perf_event_mark_enabled(event, ctx); goto out; } @@ -1813,7 +1809,6 @@ void perf_event_enable(struct perf_event *event) out: raw_spin_unlock_irq(&ctx->lock); } -EXPORT_SYMBOL_GPL(perf_event_enable); int perf_event_refresh(struct perf_event *event, int refresh) { @@ -2332,9 +2327,6 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period) u64 interrupts, now; s64 delta; - if (!ctx->nr_freq) - return; - list_for_each_entry_rcu(event, &ctx->event_list, event_entry) { if (event->state != PERF_EVENT_STATE_ACTIVE) continue; @@ -2390,14 +2382,12 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) { u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC; struct perf_event_context *ctx = NULL; - int rotate = 0, remove = 1, freq = 0; + int rotate = 0, remove = 1; if (cpuctx->ctx.nr_events) { remove = 0; if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active) rotate = 1; - if (cpuctx->ctx.nr_freq) - freq = 1; } ctx = cpuctx->task_ctx; @@ -2405,40 +2395,33 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) remove = 0; if (ctx->nr_events != ctx->nr_active) rotate = 1; - if (ctx->nr_freq) - freq = 1; } - if (!rotate && !freq) - goto done; - perf_ctx_lock(cpuctx, cpuctx->task_ctx); perf_pmu_disable(cpuctx->ctx.pmu); + perf_ctx_adjust_freq(&cpuctx->ctx, interval); + if (ctx) + perf_ctx_adjust_freq(ctx, interval); - if (freq) { - perf_ctx_adjust_freq(&cpuctx->ctx, interval); - if (ctx) - perf_ctx_adjust_freq(ctx, interval); - } - - if (rotate) { - cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); - if (ctx) - ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE); + if (!rotate) + goto done; - rotate_ctx(&cpuctx->ctx); - if (ctx) - rotate_ctx(ctx); + cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); + if (ctx) + ctx_sched_out(ctx, cpuctx, EVENT_FLEXIBLE); - perf_event_sched_in(cpuctx, ctx, current); - } + rotate_ctx(&cpuctx->ctx); + if (ctx) + rotate_ctx(ctx); - perf_pmu_enable(cpuctx->ctx.pmu); - perf_ctx_unlock(cpuctx, cpuctx->task_ctx); + perf_event_sched_in(cpuctx, ctx, current); done: if (remove) list_del_init(&cpuctx->rotation_list); + + perf_pmu_enable(cpuctx->ctx.pmu); + perf_ctx_unlock(cpuctx, cpuctx->task_ctx); } void perf_event_task_tick(void) @@ -2465,7 +2448,7 @@ static int event_enable_on_exec(struct perf_event *event, if (event->state >= PERF_EVENT_STATE_INACTIVE) return 0; - __perf_event_mark_enabled(event); + __perf_event_mark_enabled(event, ctx); return 1; } @@ -2497,7 +2480,13 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx) raw_spin_lock(&ctx->lock); task_ctx_sched_out(ctx); - list_for_each_entry(event, &ctx->event_list, event_entry) { + list_for_each_entry(event, &ctx->pinned_groups, group_entry) { + ret = event_enable_on_exec(event, ctx); + if (ret) + enabled = 1; + } + + list_for_each_entry(event, &ctx->flexible_groups, group_entry) { ret = event_enable_on_exec(event, ctx); if (ret) enabled = 1; @@ -2584,6 +2573,215 @@ static u64 perf_event_read(struct perf_event *event) return perf_event_count(event); } +/* + * Callchain support + */ + +struct callchain_cpus_entries { + struct rcu_head rcu_head; + struct perf_callchain_entry *cpu_entries[0]; +}; + +static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]); +static atomic_t nr_callchain_events; +static DEFINE_MUTEX(callchain_mutex); +struct callchain_cpus_entries *callchain_cpus_entries; + + +__weak void perf_callchain_kernel(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ +} + +__weak void perf_callchain_user(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ +} + +static void release_callchain_buffers_rcu(struct rcu_head *head) +{ + struct callchain_cpus_entries *entries; + int cpu; + + entries = container_of(head, struct callchain_cpus_entries, rcu_head); + + for_each_possible_cpu(cpu) + kfree(entries->cpu_entries[cpu]); + + kfree(entries); +} + +static void release_callchain_buffers(void) +{ + struct callchain_cpus_entries *entries; + + entries = callchain_cpus_entries; + rcu_assign_pointer(callchain_cpus_entries, NULL); + call_rcu(&entries->rcu_head, release_callchain_buffers_rcu); +} + +static int alloc_callchain_buffers(void) +{ + int cpu; + int size; + struct callchain_cpus_entries *entries; + + /* + * We can't use the percpu allocation API for data that can be + * accessed from NMI. Use a temporary manual per cpu allocation + * until that gets sorted out. + */ + size = offsetof(struct callchain_cpus_entries, cpu_entries[nr_cpu_ids]); + + entries = kzalloc(size, GFP_KERNEL); + if (!entries) + return -ENOMEM; + + size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS; + + for_each_possible_cpu(cpu) { + entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL, + cpu_to_node(cpu)); + if (!entries->cpu_entries[cpu]) + goto fail; + } + + rcu_assign_pointer(callchain_cpus_entries, entries); + + return 0; + +fail: + for_each_possible_cpu(cpu) + kfree(entries->cpu_entries[cpu]); + kfree(entries); + + return -ENOMEM; +} + +static int get_callchain_buffers(void) +{ + int err = 0; + int count; + + mutex_lock(&callchain_mutex); + + count = atomic_inc_return(&nr_callchain_events); + if (WARN_ON_ONCE(count < 1)) { + err = -EINVAL; + goto exit; + } + + if (count > 1) { + /* If the allocation failed, give up */ + if (!callchain_cpus_entries) + err = -ENOMEM; + goto exit; + } + + err = alloc_callchain_buffers(); + if (err) + release_callchain_buffers(); +exit: + mutex_unlock(&callchain_mutex); + + return err; +} + +static void put_callchain_buffers(void) +{ + if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) { + release_callchain_buffers(); + mutex_unlock(&callchain_mutex); + } +} + +static int get_recursion_context(int *recursion) +{ + int rctx; + + if (in_nmi()) + rctx = 3; + else if (in_irq()) + rctx = 2; + else if (in_softirq()) + rctx = 1; + else + rctx = 0; + + if (recursion[rctx]) + return -1; + + recursion[rctx]++; + barrier(); + + return rctx; +} + +static inline void put_recursion_context(int *recursion, int rctx) +{ + barrier(); + recursion[rctx]--; +} + +static struct perf_callchain_entry *get_callchain_entry(int *rctx) +{ + int cpu; + struct callchain_cpus_entries *entries; + + *rctx = get_recursion_context(__get_cpu_var(callchain_recursion)); + if (*rctx == -1) + return NULL; + + entries = rcu_dereference(callchain_cpus_entries); + if (!entries) + return NULL; + + cpu = smp_processor_id(); + + return &entries->cpu_entries[cpu][*rctx]; +} + +static void +put_callchain_entry(int rctx) +{ + put_recursion_context(__get_cpu_var(callchain_recursion), rctx); +} + +static struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) +{ + int rctx; + struct perf_callchain_entry *entry; + + + entry = get_callchain_entry(&rctx); + if (rctx == -1) + return NULL; + + if (!entry) + goto exit_put; + + entry->nr = 0; + + if (!user_mode(regs)) { + perf_callchain_store(entry, PERF_CONTEXT_KERNEL); + perf_callchain_kernel(entry, regs); + if (current->mm) + regs = task_pt_regs(current); + else + regs = NULL; + } + + if (regs) { + perf_callchain_store(entry, PERF_CONTEXT_USER); + perf_callchain_user(entry, regs); + } + +exit_put: + put_callchain_entry(rctx); + + return entry; +} + /* * Initialize the perf_event context in a task_struct: */ @@ -2748,7 +2946,7 @@ static void free_event(struct perf_event *event) if (!event->parent) { if (event->attach_state & PERF_ATTACH_TASK) - jump_label_dec_deferred(&perf_sched_events); + jump_label_dec(&perf_sched_events); if (event->attr.mmap || event->attr.mmap_data) atomic_dec(&nr_mmap_events); if (event->attr.comm) @@ -2759,7 +2957,7 @@ static void free_event(struct perf_event *event) put_callchain_buffers(); if (is_cgroup_event(event)) { atomic_dec(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_dec_deferred(&perf_sched_events); + jump_label_dec(&perf_sched_events); } } @@ -3360,9 +3558,13 @@ static void ring_buffer_wakeup(struct perf_event *event) rcu_read_lock(); rb = rcu_dereference(event->rb); - list_for_each_entry_rcu(event, &rb->event_list, rb_entry) { + if (!rb) + goto unlock; + + list_for_each_entry_rcu(event, &rb->event_list, rb_entry) wake_up_all(&event->waitq); - } + +unlock: rcu_read_unlock(); } @@ -4618,6 +4820,7 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow, struct hw_perf_event *hwc = &event->hw; int throttle = 0; + data->period = event->hw.last_period; if (!overflow) overflow = perf_swevent_set_period(event); @@ -4651,12 +4854,6 @@ static void perf_swevent_event(struct perf_event *event, u64 nr, if (!is_sampling_event(event)) return; - if ((event->attr.sample_type & PERF_SAMPLE_PERIOD) && !event->attr.freq) { - data->period = nr; - return perf_swevent_overflow(event, 1, data, regs); - } else - data->period = event->hw.last_period; - if (nr == 1 && hwc->sample_period == 1 && !event->attr.freq) return perf_swevent_overflow(event, 1, data, regs); @@ -5784,7 +5981,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, if (!event->parent) { if (event->attach_state & PERF_ATTACH_TASK) - jump_label_inc(&perf_sched_events.key); + jump_label_inc(&perf_sched_events); if (event->attr.mmap || event->attr.mmap_data) atomic_inc(&nr_mmap_events); if (event->attr.comm) @@ -6022,7 +6219,7 @@ SYSCALL_DEFINE5(perf_event_open, * - that may need work on context switch */ atomic_inc(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_inc(&perf_sched_events.key); + jump_label_inc(&perf_sched_events); } /* @@ -6868,9 +7065,6 @@ void __init perf_event_init(void) ret = init_hw_breakpoint(); WARN(ret, "hw_breakpoint initialization failed with: %d", ret); - - /* do not patch jump label more than once per second */ - jump_label_rate_limit(&perf_sched_events, HZ); } static int __init perf_event_sysfs_init(void) diff --git a/trunk/kernel/events/internal.h b/trunk/kernel/events/internal.h index b0b107f90afc..64568a699375 100644 --- a/trunk/kernel/events/internal.h +++ b/trunk/kernel/events/internal.h @@ -1,10 +1,6 @@ #ifndef _KERNEL_EVENTS_INTERNAL_H #define _KERNEL_EVENTS_INTERNAL_H -#include - -/* Buffer handling */ - #define RING_BUFFER_WRITABLE 0x01 struct ring_buffer { @@ -71,7 +67,7 @@ static inline int page_order(struct ring_buffer *rb) } #endif -static inline unsigned long perf_data_size(struct ring_buffer *rb) +static unsigned long perf_data_size(struct ring_buffer *rb) { return rb->nr_pages << (PAGE_SHIFT + page_order(rb)); } @@ -100,37 +96,4 @@ __output_copy(struct perf_output_handle *handle, } while (len); } -/* Callchain handling */ -extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs); -extern int get_callchain_buffers(void); -extern void put_callchain_buffers(void); - -static inline int get_recursion_context(int *recursion) -{ - int rctx; - - if (in_nmi()) - rctx = 3; - else if (in_irq()) - rctx = 2; - else if (in_softirq()) - rctx = 1; - else - rctx = 0; - - if (recursion[rctx]) - return -1; - - recursion[rctx]++; - barrier(); - - return rctx; -} - -static inline void put_recursion_context(int *recursion, int rctx) -{ - barrier(); - recursion[rctx]--; -} - #endif /* _KERNEL_EVENTS_INTERNAL_H */ diff --git a/trunk/kernel/exit.c b/trunk/kernel/exit.c index d0b7d988f873..e6e01b959a0e 100644 --- a/trunk/kernel/exit.c +++ b/trunk/kernel/exit.c @@ -1540,8 +1540,15 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, } /* dead body doesn't have much to contribute */ - if (p->exit_state == EXIT_DEAD) + if (unlikely(p->exit_state == EXIT_DEAD)) { + /* + * But do not ignore this task until the tracer does + * wait_task_zombie()->do_notify_parent(). + */ + if (likely(!ptrace) && unlikely(ptrace_reparented(p))) + wo->notask_error = 0; return 0; + } /* slay zombie? */ if (p->exit_state == EXIT_ZOMBIE) { diff --git a/trunk/kernel/futex.c b/trunk/kernel/futex.c index ea87f4d2f455..1614be20173d 100644 --- a/trunk/kernel/futex.c +++ b/trunk/kernel/futex.c @@ -314,17 +314,29 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) #endif lock_page(page_head); + + /* + * If page_head->mapping is NULL, then it cannot be a PageAnon + * page; but it might be the ZERO_PAGE or in the gate area or + * in a special mapping (all cases which we are happy to fail); + * or it may have been a good file page when get_user_pages_fast + * found it, but truncated or holepunched or subjected to + * invalidate_complete_page2 before we got the page lock (also + * cases which we are happy to fail). And we hold a reference, + * so refcount care in invalidate_complete_page's remove_mapping + * prevents drop_caches from setting mapping to NULL beneath us. + * + * The case we do have to guard against is when memory pressure made + * shmem_writepage move it from filecache to swapcache beneath us: + * an unlikely race, but we do need to retry for page_head->mapping. + */ if (!page_head->mapping) { + int shmem_swizzled = PageSwapCache(page_head); unlock_page(page_head); put_page(page_head); - /* - * ZERO_PAGE pages don't have a mapping. Avoid a busy loop - * trying to find one. RW mapping would have COW'd (and thus - * have a mapping) so this page is RO and won't ever change. - */ - if ((page_head == ZERO_PAGE(address))) - return -EFAULT; - goto again; + if (shmem_swizzled) + goto again; + return -EFAULT; } /* diff --git a/trunk/kernel/hung_task.c b/trunk/kernel/hung_task.c index 8b1748d0172c..2e48ec0c2e91 100644 --- a/trunk/kernel/hung_task.c +++ b/trunk/kernel/hung_task.c @@ -74,11 +74,17 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) /* * Ensure the task is not frozen. - * Also, when a freshly created task is scheduled once, changes - * its state to TASK_UNINTERRUPTIBLE without having ever been - * switched out once, it musn't be checked. + * Also, skip vfork and any other user process that freezer should skip. */ - if (unlikely(t->flags & PF_FROZEN || !switch_count)) + if (unlikely(t->flags & (PF_FROZEN | PF_FREEZER_SKIP))) + return; + + /* + * When a freshly created task is scheduled once, changes its state to + * TASK_UNINTERRUPTIBLE without having ever been switched out once, it + * musn't be checked. + */ + if (unlikely(!switch_count)) return; if (switch_count != t->last_switch_count) { diff --git a/trunk/kernel/jump_label.c b/trunk/kernel/jump_label.c index 30c3c7708132..66ff7109f697 100644 --- a/trunk/kernel/jump_label.c +++ b/trunk/kernel/jump_label.c @@ -72,46 +72,15 @@ void jump_label_inc(struct jump_label_key *key) jump_label_unlock(); } -static void __jump_label_dec(struct jump_label_key *key, - unsigned long rate_limit, struct delayed_work *work) +void jump_label_dec(struct jump_label_key *key) { if (!atomic_dec_and_mutex_lock(&key->enabled, &jump_label_mutex)) return; - if (rate_limit) { - atomic_inc(&key->enabled); - schedule_delayed_work(work, rate_limit); - } else - jump_label_update(key, JUMP_LABEL_DISABLE); - + jump_label_update(key, JUMP_LABEL_DISABLE); jump_label_unlock(); } -static void jump_label_update_timeout(struct work_struct *work) -{ - struct jump_label_key_deferred *key = - container_of(work, struct jump_label_key_deferred, work.work); - __jump_label_dec(&key->key, 0, NULL); -} - -void jump_label_dec(struct jump_label_key *key) -{ - __jump_label_dec(key, 0, NULL); -} - -void jump_label_dec_deferred(struct jump_label_key_deferred *key) -{ - __jump_label_dec(&key->key, key->timeout, &key->work); -} - - -void jump_label_rate_limit(struct jump_label_key_deferred *key, - unsigned long rl) -{ - key->timeout = rl; - INIT_DELAYED_WORK(&key->work, jump_label_update_timeout); -} - static int addr_conflict(struct jump_entry *entry, void *start, void *end) { if (entry->code <= (unsigned long)end && @@ -142,7 +111,7 @@ static int __jump_label_text_reserved(struct jump_entry *iter_start, * running code can override this to make the non-live update case * cheaper. */ -void __weak __init_or_module arch_jump_label_transform_static(struct jump_entry *entry, +void __weak arch_jump_label_transform_static(struct jump_entry *entry, enum jump_label_type type) { arch_jump_label_transform(entry, type); @@ -248,13 +217,8 @@ void jump_label_apply_nops(struct module *mod) if (iter_start == iter_stop) return; - for (iter = iter_start; iter < iter_stop; iter++) { - struct jump_label_key *iterk; - - iterk = (struct jump_label_key *)(unsigned long)iter->key; - arch_jump_label_transform_static(iter, jump_label_enabled(iterk) ? - JUMP_LABEL_ENABLE : JUMP_LABEL_DISABLE); - } + for (iter = iter_start; iter < iter_stop; iter++) + arch_jump_label_transform_static(iter, JUMP_LABEL_DISABLE); } static int jump_label_add_module(struct module *mod) @@ -294,7 +258,8 @@ static int jump_label_add_module(struct module *mod) key->next = jlm; if (jump_label_enabled(key)) - __jump_label_update(key, iter, iter_stop, JUMP_LABEL_ENABLE); + __jump_label_update(key, iter, iter_stop, + JUMP_LABEL_ENABLE); } return 0; diff --git a/trunk/kernel/lockdep.c b/trunk/kernel/lockdep.c index 24f176c9fc9f..b2e08c932d91 100644 --- a/trunk/kernel/lockdep.c +++ b/trunk/kernel/lockdep.c @@ -499,32 +499,36 @@ void get_usage_chars(struct lock_class *class, char usage[LOCK_USAGE_CHARS]) usage[i] = '\0'; } -static void __print_lock_name(struct lock_class *class) +static int __print_lock_name(struct lock_class *class) { char str[KSYM_NAME_LEN]; const char *name; name = class->name; - if (!name) { + if (!name) name = __get_key_name(class->key, str); - printk("%s", name); - } else { - printk("%s", name); - if (class->name_version > 1) - printk("#%d", class->name_version); - if (class->subclass) - printk("/%d", class->subclass); - } + + return printk("%s", name); } static void print_lock_name(struct lock_class *class) { - char usage[LOCK_USAGE_CHARS]; + char str[KSYM_NAME_LEN], usage[LOCK_USAGE_CHARS]; + const char *name; get_usage_chars(class, usage); - printk(" ("); - __print_lock_name(class); + name = class->name; + if (!name) { + name = __get_key_name(class->key, str); + printk(" (%s", name); + } else { + printk(" (%s", name); + if (class->name_version > 1) + printk("#%d", class->name_version); + if (class->subclass) + printk("/%d", class->subclass); + } printk("){%s}", usage); } diff --git a/trunk/kernel/ptrace.c b/trunk/kernel/ptrace.c index 24d04477b257..78ab24a7b0e4 100644 --- a/trunk/kernel/ptrace.c +++ b/trunk/kernel/ptrace.c @@ -96,9 +96,20 @@ void __ptrace_unlink(struct task_struct *child) */ if (!(child->flags & PF_EXITING) && (child->signal->flags & SIGNAL_STOP_STOPPED || - child->signal->group_stop_count)) + child->signal->group_stop_count)) { child->jobctl |= JOBCTL_STOP_PENDING; + /* + * This is only possible if this thread was cloned by the + * traced task running in the stopped group, set the signal + * for the future reports. + * FIXME: we should change ptrace_init_task() to handle this + * case. + */ + if (!(child->jobctl & JOBCTL_STOP_SIGMASK)) + child->jobctl |= SIGSTOP; + } + /* * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick * @child in the butt. Note that @resume should be used iff @child diff --git a/trunk/kernel/sched_fair.c b/trunk/kernel/sched_fair.c index a78ed2736ba7..8a39fa3e3c6c 100644 --- a/trunk/kernel/sched_fair.c +++ b/trunk/kernel/sched_fair.c @@ -2352,13 +2352,11 @@ static int select_idle_sibling(struct task_struct *p, int target) if (!smt && (sd->flags & SD_SHARE_CPUPOWER)) continue; - if (!(sd->flags & SD_SHARE_PKG_RESOURCES)) { - if (!smt) { - smt = 1; - goto again; - } + if (smt && !(sd->flags & SD_SHARE_CPUPOWER)) + break; + + if (!(sd->flags & SD_SHARE_PKG_RESOURCES)) break; - } sg = sd->groups; do { @@ -2378,6 +2376,10 @@ static int select_idle_sibling(struct task_struct *p, int target) sg = sg->next; } while (sg != sd->groups); } + if (!smt) { + smt = 1; + goto again; + } done: rcu_read_unlock(); diff --git a/trunk/kernel/signal.c b/trunk/kernel/signal.c index b3f78d09a105..206551563cce 100644 --- a/trunk/kernel/signal.c +++ b/trunk/kernel/signal.c @@ -1994,8 +1994,6 @@ static bool do_signal_stop(int signr) */ if (!(sig->flags & SIGNAL_STOP_STOPPED)) sig->group_exit_code = signr; - else - WARN_ON_ONCE(!current->ptrace); sig->group_stop_count = 0; diff --git a/trunk/kernel/sysctl_binary.c b/trunk/kernel/sysctl_binary.c index 6318b511afa1..a650694883a1 100644 --- a/trunk/kernel/sysctl_binary.c +++ b/trunk/kernel/sysctl_binary.c @@ -1354,7 +1354,7 @@ static ssize_t binary_sysctl(const int *name, int nlen, fput(file); out_putname: - putname(pathname); + __putname(pathname); out: return result; } diff --git a/trunk/kernel/time/clockevents.c b/trunk/kernel/time/clockevents.c index c4eb71c8b2ea..1ecd6ba36d6c 100644 --- a/trunk/kernel/time/clockevents.c +++ b/trunk/kernel/time/clockevents.c @@ -387,7 +387,6 @@ void clockevents_exchange_device(struct clock_event_device *old, * released list and do a notify add later. */ if (old) { - old->event_handler = clockevents_handle_noop; clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); list_del(&old->list); list_add(&old->list, &clockevents_released); diff --git a/trunk/kernel/time/clocksource.c b/trunk/kernel/time/clocksource.c index da2f760e780c..d3ad022136e5 100644 --- a/trunk/kernel/time/clocksource.c +++ b/trunk/kernel/time/clocksource.c @@ -647,7 +647,7 @@ static void clocksource_enqueue(struct clocksource *cs) /** * __clocksource_updatefreq_scale - Used update clocksource with new freq - * @t: clocksource to be registered + * @cs: clocksource to be registered * @scale: Scale factor multiplied against freq to get clocksource hz * @freq: clocksource frequency (cycles per second) divided by scale * @@ -699,7 +699,7 @@ EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale); /** * __clocksource_register_scale - Used to install new clocksources - * @t: clocksource to be registered + * @cs: clocksource to be registered * @scale: Scale factor multiplied against freq to get clocksource hz * @freq: clocksource frequency (cycles per second) divided by scale * @@ -727,7 +727,7 @@ EXPORT_SYMBOL_GPL(__clocksource_register_scale); /** * clocksource_register - Used to install new clocksources - * @t: clocksource to be registered + * @cs: clocksource to be registered * * Returns -EBUSY if registration fails, zero otherwise. */ @@ -761,6 +761,8 @@ static void __clocksource_change_rating(struct clocksource *cs, int rating) /** * clocksource_change_rating - Change the rating of a registered clocksource + * @cs: clocksource to be changed + * @rating: new rating */ void clocksource_change_rating(struct clocksource *cs, int rating) { @@ -772,6 +774,7 @@ EXPORT_SYMBOL(clocksource_change_rating); /** * clocksource_unregister - remove a registered clocksource + * @cs: clocksource to be unregistered */ void clocksource_unregister(struct clocksource *cs) { @@ -787,6 +790,7 @@ EXPORT_SYMBOL(clocksource_unregister); /** * sysfs_show_current_clocksources - sysfs interface for current clocksource * @dev: unused + * @attr: unused * @buf: char buffer to be filled with clocksource list * * Provides sysfs interface for listing current clocksource. @@ -807,6 +811,7 @@ sysfs_show_current_clocksources(struct sys_device *dev, /** * sysfs_override_clocksource - interface for manually overriding clocksource * @dev: unused + * @attr: unused * @buf: name of override clocksource * @count: length of buffer * @@ -842,6 +847,7 @@ static ssize_t sysfs_override_clocksource(struct sys_device *dev, /** * sysfs_show_available_clocksources - sysfs interface for listing clocksource * @dev: unused + * @attr: unused * @buf: char buffer to be filled with clocksource list * * Provides sysfs interface for listing registered clocksources diff --git a/trunk/kernel/trace/ftrace.c b/trunk/kernel/trace/ftrace.c index 683d559a0eef..b1e8943fed1d 100644 --- a/trunk/kernel/trace/ftrace.c +++ b/trunk/kernel/trace/ftrace.c @@ -22,13 +22,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -949,6 +947,13 @@ struct ftrace_func_probe { struct rcu_head rcu; }; +enum { + FTRACE_ENABLE_CALLS = (1 << 0), + FTRACE_DISABLE_CALLS = (1 << 1), + FTRACE_UPDATE_TRACE_FUNC = (1 << 2), + FTRACE_START_FUNC_RET = (1 << 3), + FTRACE_STOP_FUNC_RET = (1 << 4), +}; struct ftrace_func_entry { struct hlist_node hlist; unsigned long ip; @@ -979,19 +984,18 @@ static struct ftrace_ops global_ops = { .filter_hash = EMPTY_HASH, }; +static struct dyn_ftrace *ftrace_new_addrs; + static DEFINE_MUTEX(ftrace_regex_lock); struct ftrace_page { struct ftrace_page *next; - struct dyn_ftrace *records; int index; - int size; + struct dyn_ftrace records[]; }; -static struct ftrace_page *ftrace_new_pgs; - -#define ENTRY_SIZE sizeof(struct dyn_ftrace) -#define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE) +#define ENTRIES_PER_PAGE \ + ((PAGE_SIZE - sizeof(struct ftrace_page)) / sizeof(struct dyn_ftrace)) /* estimate from running different kernels */ #define NR_TO_INIT 10000 @@ -999,10 +1003,7 @@ static struct ftrace_page *ftrace_new_pgs; static struct ftrace_page *ftrace_pages_start; static struct ftrace_page *ftrace_pages; -static bool ftrace_hash_empty(struct ftrace_hash *hash) -{ - return !hash || !hash->count; -} +static struct dyn_ftrace *ftrace_free_records; static struct ftrace_func_entry * ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip) @@ -1012,7 +1013,7 @@ ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip) struct hlist_head *hhd; struct hlist_node *n; - if (ftrace_hash_empty(hash)) + if (!hash->count) return NULL; if (hash->size_bits > 0) @@ -1156,7 +1157,7 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash) return NULL; /* Empty hash? */ - if (ftrace_hash_empty(hash)) + if (!hash || !hash->count) return new_hash; size = 1 << hash->size_bits; @@ -1281,9 +1282,9 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) filter_hash = rcu_dereference_raw(ops->filter_hash); notrace_hash = rcu_dereference_raw(ops->notrace_hash); - if ((ftrace_hash_empty(filter_hash) || + if ((!filter_hash || !filter_hash->count || ftrace_lookup_ip(filter_hash, ip)) && - (ftrace_hash_empty(notrace_hash) || + (!notrace_hash || !notrace_hash->count || !ftrace_lookup_ip(notrace_hash, ip))) ret = 1; else @@ -1306,47 +1307,6 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) } \ } - -static int ftrace_cmp_recs(const void *a, const void *b) -{ - const struct dyn_ftrace *reca = a; - const struct dyn_ftrace *recb = b; - - if (reca->ip > recb->ip) - return 1; - if (reca->ip < recb->ip) - return -1; - return 0; -} - -/** - * ftrace_location - return true if the ip giving is a traced location - * @ip: the instruction pointer to check - * - * Returns 1 if @ip given is a pointer to a ftrace location. - * That is, the instruction that is either a NOP or call to - * the function tracer. It checks the ftrace internal tables to - * determine if the address belongs or not. - */ -int ftrace_location(unsigned long ip) -{ - struct ftrace_page *pg; - struct dyn_ftrace *rec; - struct dyn_ftrace key; - - key.ip = ip; - - for (pg = ftrace_pages_start; pg; pg = pg->next) { - rec = bsearch(&key, pg->records, pg->index, - sizeof(struct dyn_ftrace), - ftrace_cmp_recs); - if (rec) - return 1; - } - - return 0; -} - static void __ftrace_hash_rec_update(struct ftrace_ops *ops, int filter_hash, bool inc) @@ -1376,7 +1336,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, if (filter_hash) { hash = ops->filter_hash; other_hash = ops->notrace_hash; - if (ftrace_hash_empty(hash)) + if (!hash || !hash->count) all = 1; } else { inc = !inc; @@ -1386,7 +1346,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, * If the notrace hash has no items, * then there's nothing to do. */ - if (ftrace_hash_empty(hash)) + if (hash && !hash->count) return; } @@ -1403,8 +1363,8 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, if (!other_hash || !ftrace_lookup_ip(other_hash, rec->ip)) match = 1; } else { - in_hash = !!ftrace_lookup_ip(hash, rec->ip); - in_other_hash = !!ftrace_lookup_ip(other_hash, rec->ip); + in_hash = hash && !!ftrace_lookup_ip(hash, rec->ip); + in_other_hash = other_hash && !!ftrace_lookup_ip(other_hash, rec->ip); /* * @@ -1412,7 +1372,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, if (filter_hash && in_hash && !in_other_hash) match = 1; else if (!filter_hash && in_hash && - (in_other_hash || ftrace_hash_empty(other_hash))) + (in_other_hash || !other_hash->count)) match = 1; } if (!match) @@ -1446,12 +1406,40 @@ static void ftrace_hash_rec_enable(struct ftrace_ops *ops, __ftrace_hash_rec_update(ops, filter_hash, 1); } +static void ftrace_free_rec(struct dyn_ftrace *rec) +{ + rec->freelist = ftrace_free_records; + ftrace_free_records = rec; + rec->flags |= FTRACE_FL_FREE; +} + static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip) { - if (ftrace_pages->index == ftrace_pages->size) { - /* We should have allocated enough */ - if (WARN_ON(!ftrace_pages->next)) + struct dyn_ftrace *rec; + + /* First check for freed records */ + if (ftrace_free_records) { + rec = ftrace_free_records; + + if (unlikely(!(rec->flags & FTRACE_FL_FREE))) { + FTRACE_WARN_ON_ONCE(1); + ftrace_free_records = NULL; return NULL; + } + + ftrace_free_records = rec->freelist; + memset(rec, 0, sizeof(*rec)); + return rec; + } + + if (ftrace_pages->index == ENTRIES_PER_PAGE) { + if (!ftrace_pages->next) { + /* allocate another page */ + ftrace_pages->next = + (void *)get_zeroed_page(GFP_KERNEL); + if (!ftrace_pages->next) + return NULL; + } ftrace_pages = ftrace_pages->next; } @@ -1471,6 +1459,8 @@ ftrace_record_ip(unsigned long ip) return NULL; rec->ip = ip; + rec->newlist = ftrace_new_addrs; + ftrace_new_addrs = rec; return rec; } @@ -1485,19 +1475,7 @@ static void print_ip_ins(const char *fmt, unsigned char *p) printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]); } -/** - * ftrace_bug - report and shutdown function tracer - * @failed: The failed type (EFAULT, EINVAL, EPERM) - * @ip: The address that failed - * - * The arch code that enables or disables the function tracing - * can call ftrace_bug() when it has detected a problem in - * modifying the code. @failed should be one of either: - * EFAULT - if the problem happens on reading the @ip address - * EINVAL - if what is read at @ip is not what was expected - * EPERM - if the problem happens on writting to the @ip address - */ -void ftrace_bug(int failed, unsigned long ip) +static void ftrace_bug(int failed, unsigned long ip) { switch (failed) { case -EFAULT: @@ -1539,19 +1517,24 @@ int ftrace_text_reserved(void *start, void *end) return 0; } -static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update) + +static int +__ftrace_replace_code(struct dyn_ftrace *rec, int enable) { + unsigned long ftrace_addr; unsigned long flag = 0UL; + ftrace_addr = (unsigned long)FTRACE_ADDR; + /* - * If we are updating calls: + * If we are enabling tracing: * * If the record has a ref count, then we need to enable it * because someone is using it. * * Otherwise we make sure its disabled. * - * If we are disabling calls, then disable all records that + * If we are disabling tracing, then disable all records that * are enabled. */ if (enable && (rec->flags & ~FTRACE_FL_MASK)) @@ -1559,72 +1542,18 @@ static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update) /* If the state of this record hasn't changed, then do nothing */ if ((rec->flags & FTRACE_FL_ENABLED) == flag) - return FTRACE_UPDATE_IGNORE; - - if (flag) { - if (update) - rec->flags |= FTRACE_FL_ENABLED; - return FTRACE_UPDATE_MAKE_CALL; - } - - if (update) - rec->flags &= ~FTRACE_FL_ENABLED; - - return FTRACE_UPDATE_MAKE_NOP; -} - -/** - * ftrace_update_record, set a record that now is tracing or not - * @rec: the record to update - * @enable: set to 1 if the record is tracing, zero to force disable - * - * The records that represent all functions that can be traced need - * to be updated when tracing has been enabled. - */ -int ftrace_update_record(struct dyn_ftrace *rec, int enable) -{ - return ftrace_check_record(rec, enable, 1); -} - -/** - * ftrace_test_record, check if the record has been enabled or not - * @rec: the record to test - * @enable: set to 1 to check if enabled, 0 if it is disabled - * - * The arch code may need to test if a record is already set to - * tracing to determine how to modify the function code that it - * represents. - */ -int ftrace_test_record(struct dyn_ftrace *rec, int enable) -{ - return ftrace_check_record(rec, enable, 0); -} - -static int -__ftrace_replace_code(struct dyn_ftrace *rec, int enable) -{ - unsigned long ftrace_addr; - int ret; - - ftrace_addr = (unsigned long)FTRACE_ADDR; - - ret = ftrace_update_record(rec, enable); - - switch (ret) { - case FTRACE_UPDATE_IGNORE: return 0; - case FTRACE_UPDATE_MAKE_CALL: + if (flag) { + rec->flags |= FTRACE_FL_ENABLED; return ftrace_make_call(rec, ftrace_addr); - - case FTRACE_UPDATE_MAKE_NOP: - return ftrace_make_nop(NULL, rec, ftrace_addr); } - return -1; /* unknow ftrace bug */ + rec->flags &= ~FTRACE_FL_ENABLED; + return ftrace_make_nop(NULL, rec, ftrace_addr); } -static void ftrace_replace_code(int update) +static void ftrace_replace_code(int enable) { struct dyn_ftrace *rec; struct ftrace_page *pg; @@ -1634,7 +1563,11 @@ static void ftrace_replace_code(int update) return; do_for_each_ftrace_rec(pg, rec) { - failed = __ftrace_replace_code(rec, update); + /* Skip over free records */ + if (rec->flags & FTRACE_FL_FREE) + continue; + + failed = __ftrace_replace_code(rec, enable); if (failed) { ftrace_bug(failed, rec->ip); /* Stop processing */ @@ -1643,78 +1576,6 @@ static void ftrace_replace_code(int update) } while_for_each_ftrace_rec(); } -struct ftrace_rec_iter { - struct ftrace_page *pg; - int index; -}; - -/** - * ftrace_rec_iter_start, start up iterating over traced functions - * - * Returns an iterator handle that is used to iterate over all - * the records that represent address locations where functions - * are traced. - * - * May return NULL if no records are available. - */ -struct ftrace_rec_iter *ftrace_rec_iter_start(void) -{ - /* - * We only use a single iterator. - * Protected by the ftrace_lock mutex. - */ - static struct ftrace_rec_iter ftrace_rec_iter; - struct ftrace_rec_iter *iter = &ftrace_rec_iter; - - iter->pg = ftrace_pages_start; - iter->index = 0; - - /* Could have empty pages */ - while (iter->pg && !iter->pg->index) - iter->pg = iter->pg->next; - - if (!iter->pg) - return NULL; - - return iter; -} - -/** - * ftrace_rec_iter_next, get the next record to process. - * @iter: The handle to the iterator. - * - * Returns the next iterator after the given iterator @iter. - */ -struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter) -{ - iter->index++; - - if (iter->index >= iter->pg->index) { - iter->pg = iter->pg->next; - iter->index = 0; - - /* Could have empty pages */ - while (iter->pg && !iter->pg->index) - iter->pg = iter->pg->next; - } - - if (!iter->pg) - return NULL; - - return iter; -} - -/** - * ftrace_rec_iter_record, get the record at the iterator location - * @iter: The current iterator location - * - * Returns the record that the current @iter is at. - */ -struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter) -{ - return &iter->pg->records[iter->index]; -} - static int ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec) { @@ -1756,7 +1617,13 @@ static int __ftrace_modify_code(void *data) { int *command = data; - if (*command & FTRACE_UPDATE_CALLS) + /* + * Do not call function tracer while we update the code. + * We are in stop machine, no worrying about races. + */ + function_trace_stop++; + + if (*command & FTRACE_ENABLE_CALLS) ftrace_replace_code(1); else if (*command & FTRACE_DISABLE_CALLS) ftrace_replace_code(0); @@ -1769,31 +1636,19 @@ static int __ftrace_modify_code(void *data) else if (*command & FTRACE_STOP_FUNC_RET) ftrace_disable_ftrace_graph_caller(); - return 0; -} - -/** - * ftrace_run_stop_machine, go back to the stop machine method - * @command: The command to tell ftrace what to do - * - * If an arch needs to fall back to the stop machine method, the - * it can call this function. - */ -void ftrace_run_stop_machine(int command) -{ - stop_machine(__ftrace_modify_code, &command, NULL); -} +#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST + /* + * For archs that call ftrace_test_stop_func(), we must + * wait till after we update all the function callers + * before we update the callback. This keeps different + * ops that record different functions from corrupting + * each other. + */ + __ftrace_trace_function = __ftrace_trace_function_delay; +#endif + function_trace_stop--; -/** - * arch_ftrace_update_code, modify the code to trace or not trace - * @command: The command that needs to be done - * - * Archs can override this function if it does not need to - * run stop_machine() to modify code. - */ -void __weak arch_ftrace_update_code(int command) -{ - ftrace_run_stop_machine(command); + return 0; } static void ftrace_run_update_code(int command) @@ -1804,31 +1659,8 @@ static void ftrace_run_update_code(int command) FTRACE_WARN_ON(ret); if (ret) return; - /* - * Do not call function tracer while we update the code. - * We are in stop machine. - */ - function_trace_stop++; - /* - * By default we use stop_machine() to modify the code. - * But archs can do what ever they want as long as it - * is safe. The stop_machine() is the safest, but also - * produces the most overhead. - */ - arch_ftrace_update_code(command); - -#ifndef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST - /* - * For archs that call ftrace_test_stop_func(), we must - * wait till after we update all the function callers - * before we update the callback. This keeps different - * ops that record different functions from corrupting - * each other. - */ - __ftrace_trace_function = __ftrace_trace_function_delay; -#endif - function_trace_stop--; + stop_machine(__ftrace_modify_code, &command, NULL); ret = ftrace_arch_code_modify_post_process(); FTRACE_WARN_ON(ret); @@ -1859,7 +1691,7 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) return -ENODEV; ftrace_start_up++; - command |= FTRACE_UPDATE_CALLS; + command |= FTRACE_ENABLE_CALLS; /* ops marked global share the filter hashes */ if (ops->flags & FTRACE_OPS_FL_GLOBAL) { @@ -1911,7 +1743,8 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command) if (ops != &global_ops || !global_start_up) ops->flags &= ~FTRACE_OPS_FL_ENABLED; - command |= FTRACE_UPDATE_CALLS; + if (!ftrace_start_up) + command |= FTRACE_DISABLE_CALLS; if (saved_ftrace_func != ftrace_trace_function) { saved_ftrace_func = ftrace_trace_function; @@ -1933,7 +1766,7 @@ static void ftrace_startup_sysctl(void) saved_ftrace_func = NULL; /* ftrace_start_up is true if we want ftrace running */ if (ftrace_start_up) - ftrace_run_update_code(FTRACE_UPDATE_CALLS); + ftrace_run_update_code(FTRACE_ENABLE_CALLS); } static void ftrace_shutdown_sysctl(void) @@ -1955,16 +1788,14 @@ static int ops_traces_mod(struct ftrace_ops *ops) struct ftrace_hash *hash; hash = ops->filter_hash; - return ftrace_hash_empty(hash); + return !!(!hash || !hash->count); } static int ftrace_update_code(struct module *mod) { - struct ftrace_page *pg; struct dyn_ftrace *p; cycle_t start, stop; unsigned long ref = 0; - int i; /* * When adding a module, we need to check if tracers are @@ -1986,44 +1817,46 @@ static int ftrace_update_code(struct module *mod) start = ftrace_now(raw_smp_processor_id()); ftrace_update_cnt = 0; - for (pg = ftrace_new_pgs; pg; pg = pg->next) { + while (ftrace_new_addrs) { - for (i = 0; i < pg->index; i++) { - /* If something went wrong, bail without enabling anything */ - if (unlikely(ftrace_disabled)) - return -1; + /* If something went wrong, bail without enabling anything */ + if (unlikely(ftrace_disabled)) + return -1; - p = &pg->records[i]; - p->flags = ref; + p = ftrace_new_addrs; + ftrace_new_addrs = p->newlist; + p->flags = ref; - /* - * Do the initial record conversion from mcount jump - * to the NOP instructions. - */ - if (!ftrace_code_disable(mod, p)) - break; + /* + * Do the initial record conversion from mcount jump + * to the NOP instructions. + */ + if (!ftrace_code_disable(mod, p)) { + ftrace_free_rec(p); + /* Game over */ + break; + } - ftrace_update_cnt++; + ftrace_update_cnt++; - /* - * If the tracing is enabled, go ahead and enable the record. - * - * The reason not to enable the record immediatelly is the - * inherent check of ftrace_make_nop/ftrace_make_call for - * correct previous instructions. Making first the NOP - * conversion puts the module to the correct state, thus - * passing the ftrace_make_call check. - */ - if (ftrace_start_up && ref) { - int failed = __ftrace_replace_code(p, 1); - if (failed) - ftrace_bug(failed, p->ip); + /* + * If the tracing is enabled, go ahead and enable the record. + * + * The reason not to enable the record immediatelly is the + * inherent check of ftrace_make_nop/ftrace_make_call for + * correct previous instructions. Making first the NOP + * conversion puts the module to the correct state, thus + * passing the ftrace_make_call check. + */ + if (ftrace_start_up && ref) { + int failed = __ftrace_replace_code(p, 1); + if (failed) { + ftrace_bug(failed, p->ip); + ftrace_free_rec(p); } } } - ftrace_new_pgs = NULL; - stop = ftrace_now(raw_smp_processor_id()); ftrace_update_time = stop - start; ftrace_update_tot_cnt += ftrace_update_cnt; @@ -2031,109 +1864,58 @@ static int ftrace_update_code(struct module *mod) return 0; } -static int ftrace_allocate_records(struct ftrace_page *pg, int count) +static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) { - int order; + struct ftrace_page *pg; int cnt; + int i; - if (WARN_ON(!count)) - return -EINVAL; - - order = get_count_order(DIV_ROUND_UP(count, ENTRIES_PER_PAGE)); + /* allocate a few pages */ + ftrace_pages_start = (void *)get_zeroed_page(GFP_KERNEL); + if (!ftrace_pages_start) + return -1; /* - * We want to fill as much as possible. No more than a page - * may be empty. + * Allocate a few more pages. + * + * TODO: have some parser search vmlinux before + * final linking to find all calls to ftrace. + * Then we can: + * a) know how many pages to allocate. + * and/or + * b) set up the table then. + * + * The dynamic code is still necessary for + * modules. */ - while ((PAGE_SIZE << order) / ENTRY_SIZE >= count + ENTRIES_PER_PAGE) - order--; - - again: - pg->records = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); - if (!pg->records) { - /* if we can't allocate this size, try something smaller */ - if (!order) - return -ENOMEM; - order >>= 1; - goto again; - } - - cnt = (PAGE_SIZE << order) / ENTRY_SIZE; - pg->size = cnt; - - if (cnt > count) - cnt = count; - - return cnt; -} - -static struct ftrace_page * -ftrace_allocate_pages(unsigned long num_to_init) -{ - struct ftrace_page *start_pg; - struct ftrace_page *pg; - int order; - int cnt; + pg = ftrace_pages = ftrace_pages_start; - if (!num_to_init) - return 0; - - start_pg = pg = kzalloc(sizeof(*pg), GFP_KERNEL); - if (!pg) - return NULL; - - /* - * Try to allocate as much as possible in one continues - * location that fills in all of the space. We want to - * waste as little space as possible. - */ - for (;;) { - cnt = ftrace_allocate_records(pg, num_to_init); - if (cnt < 0) - goto free_pages; + cnt = num_to_init / ENTRIES_PER_PAGE; + pr_info("ftrace: allocating %ld entries in %d pages\n", + num_to_init, cnt + 1); - num_to_init -= cnt; - if (!num_to_init) - break; + for (i = 0; i < cnt; i++) { + pg->next = (void *)get_zeroed_page(GFP_KERNEL); - pg->next = kzalloc(sizeof(*pg), GFP_KERNEL); + /* If we fail, we'll try later anyway */ if (!pg->next) - goto free_pages; + break; pg = pg->next; } - return start_pg; - - free_pages: - while (start_pg) { - order = get_count_order(pg->size / ENTRIES_PER_PAGE); - free_pages((unsigned long)pg->records, order); - start_pg = pg->next; - kfree(pg); - pg = start_pg; - } - pr_info("ftrace: FAILED to allocate memory for functions\n"); - return NULL; -} - -static int __init ftrace_dyn_table_alloc(unsigned long num_to_init) -{ - int cnt; - - if (!num_to_init) { - pr_info("ftrace: No functions to be traced?\n"); - return -1; - } - - cnt = num_to_init / ENTRIES_PER_PAGE; - pr_info("ftrace: allocating %ld entries in %d pages\n", - num_to_init, cnt + 1); - return 0; } +enum { + FTRACE_ITER_FILTER = (1 << 0), + FTRACE_ITER_NOTRACE = (1 << 1), + FTRACE_ITER_PRINTALL = (1 << 2), + FTRACE_ITER_HASH = (1 << 3), + FTRACE_ITER_ENABLED = (1 << 4), +}; + #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */ struct ftrace_iterator { @@ -2198,9 +1980,6 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos) void *p = NULL; loff_t l; - if (!(iter->flags & FTRACE_ITER_DO_HASH)) - return NULL; - if (iter->func_pos > *pos) return NULL; @@ -2244,7 +2023,7 @@ static void * t_next(struct seq_file *m, void *v, loff_t *pos) { struct ftrace_iterator *iter = m->private; - struct ftrace_ops *ops = iter->ops; + struct ftrace_ops *ops = &global_ops; struct dyn_ftrace *rec = NULL; if (unlikely(ftrace_disabled)) @@ -2268,7 +2047,9 @@ t_next(struct seq_file *m, void *v, loff_t *pos) } } else { rec = &iter->pg->records[iter->idx++]; - if (((iter->flags & FTRACE_ITER_FILTER) && + if ((rec->flags & FTRACE_FL_FREE) || + + ((iter->flags & FTRACE_ITER_FILTER) && !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) || ((iter->flags & FTRACE_ITER_NOTRACE) && @@ -2300,7 +2081,7 @@ static void reset_iter_read(struct ftrace_iterator *iter) static void *t_start(struct seq_file *m, loff_t *pos) { struct ftrace_iterator *iter = m->private; - struct ftrace_ops *ops = iter->ops; + struct ftrace_ops *ops = &global_ops; void *p = NULL; loff_t l; @@ -2320,8 +2101,7 @@ static void *t_start(struct seq_file *m, loff_t *pos) * off, we can short cut and just print out that all * functions are enabled. */ - if (iter->flags & FTRACE_ITER_FILTER && - ftrace_hash_empty(ops->filter_hash)) { + if (iter->flags & FTRACE_ITER_FILTER && !ops->filter_hash->count) { if (*pos > 0) return t_hash_start(m, pos); iter->flags |= FTRACE_ITER_PRINTALL; @@ -2346,8 +2126,12 @@ static void *t_start(struct seq_file *m, loff_t *pos) break; } - if (!p) - return t_hash_start(m, pos); + if (!p) { + if (iter->flags & FTRACE_ITER_FILTER) + return t_hash_start(m, pos); + + return NULL; + } return iter; } @@ -2405,7 +2189,6 @@ ftrace_avail_open(struct inode *inode, struct file *file) return -ENOMEM; iter->pg = ftrace_pages_start; - iter->ops = &global_ops; ret = seq_open(file, &show_ftrace_seq_ops); if (!ret) { @@ -2434,7 +2217,6 @@ ftrace_enabled_open(struct inode *inode, struct file *file) iter->pg = ftrace_pages_start; iter->flags = FTRACE_ITER_ENABLED; - iter->ops = &global_ops; ret = seq_open(file, &show_ftrace_seq_ops); if (!ret) { @@ -2455,23 +2237,7 @@ static void ftrace_filter_reset(struct ftrace_hash *hash) mutex_unlock(&ftrace_lock); } -/** - * ftrace_regex_open - initialize function tracer filter files - * @ops: The ftrace_ops that hold the hash filters - * @flag: The type of filter to process - * @inode: The inode, usually passed in to your open routine - * @file: The file, usually passed in to your open routine - * - * ftrace_regex_open() initializes the filter files for the - * @ops. Depending on @flag it may process the filter hash or - * the notrace hash of @ops. With this called from the open - * routine, you can use ftrace_filter_write() for the write - * routine if @flag has FTRACE_ITER_FILTER set, or - * ftrace_notrace_write() if @flag has FTRACE_ITER_NOTRACE set. - * ftrace_regex_lseek() should be used as the lseek routine, and - * release must call ftrace_regex_release(). - */ -int +static int ftrace_regex_open(struct ftrace_ops *ops, int flag, struct inode *inode, struct file *file) { @@ -2540,9 +2306,8 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag, static int ftrace_filter_open(struct inode *inode, struct file *file) { - return ftrace_regex_open(&global_ops, - FTRACE_ITER_FILTER | FTRACE_ITER_DO_HASH, - inode, file); + return ftrace_regex_open(&global_ops, FTRACE_ITER_FILTER, + inode, file); } static int @@ -2552,7 +2317,7 @@ ftrace_notrace_open(struct inode *inode, struct file *file) inode, file); } -loff_t +static loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin) { loff_t ret; @@ -2661,6 +2426,7 @@ match_records(struct ftrace_hash *hash, char *buff, goto out_unlock; do_for_each_ftrace_rec(pg, rec) { + if (ftrace_match_record(rec, mod, search, search_len, type)) { ret = enter_record(hash, rec, not); if (ret < 0) { @@ -3105,14 +2871,14 @@ ftrace_regex_write(struct file *file, const char __user *ubuf, return ret; } -ssize_t +static ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos) { return ftrace_regex_write(file, ubuf, cnt, ppos, 1); } -ssize_t +static ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, size_t cnt, loff_t *ppos) { @@ -3153,7 +2919,7 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, ret = ftrace_hash_move(ops, enable, orig_hash, hash); if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) - ftrace_run_update_code(FTRACE_UPDATE_CALLS); + ftrace_run_update_code(FTRACE_ENABLE_CALLS); mutex_unlock(&ftrace_lock); @@ -3279,8 +3045,8 @@ static void __init set_ftrace_early_graph(char *buf) } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ -void __init -ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable) +static void __init +set_ftrace_early_filter(struct ftrace_ops *ops, char *buf, int enable) { char *func; @@ -3293,16 +3059,17 @@ ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable) static void __init set_ftrace_early_filters(void) { if (ftrace_filter_buf[0]) - ftrace_set_early_filter(&global_ops, ftrace_filter_buf, 1); + set_ftrace_early_filter(&global_ops, ftrace_filter_buf, 1); if (ftrace_notrace_buf[0]) - ftrace_set_early_filter(&global_ops, ftrace_notrace_buf, 0); + set_ftrace_early_filter(&global_ops, ftrace_notrace_buf, 0); #ifdef CONFIG_FUNCTION_GRAPH_TRACER if (ftrace_graph_buf[0]) set_ftrace_early_graph(ftrace_graph_buf); #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ } -int ftrace_regex_release(struct inode *inode, struct file *file) +static int +ftrace_regex_release(struct inode *inode, struct file *file) { struct seq_file *m = (struct seq_file *)file->private_data; struct ftrace_iterator *iter; @@ -3340,7 +3107,7 @@ int ftrace_regex_release(struct inode *inode, struct file *file) orig_hash, iter->hash); if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) && ftrace_enabled) - ftrace_run_update_code(FTRACE_UPDATE_CALLS); + ftrace_run_update_code(FTRACE_ENABLE_CALLS); mutex_unlock(&ftrace_lock); } @@ -3503,6 +3270,9 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) do_for_each_ftrace_rec(pg, rec) { + if (rec->flags & FTRACE_FL_FREE) + continue; + if (ftrace_match_record(rec, NULL, search, search_len, type)) { /* if it is in the array */ exists = false; @@ -3611,62 +3381,15 @@ static __init int ftrace_init_dyn_debugfs(struct dentry *d_tracer) return 0; } -static void ftrace_swap_recs(void *a, void *b, int size) -{ - struct dyn_ftrace *reca = a; - struct dyn_ftrace *recb = b; - struct dyn_ftrace t; - - t = *reca; - *reca = *recb; - *recb = t; -} - static int ftrace_process_locs(struct module *mod, unsigned long *start, unsigned long *end) { - struct ftrace_page *pg; - unsigned long count; unsigned long *p; unsigned long addr; unsigned long flags = 0; /* Shut up gcc */ - int ret = -ENOMEM; - - count = end - start; - - if (!count) - return 0; - - pg = ftrace_allocate_pages(count); - if (!pg) - return -ENOMEM; mutex_lock(&ftrace_lock); - - /* - * Core and each module needs their own pages, as - * modules will free them when they are removed. - * Force a new page to be allocated for modules. - */ - if (!mod) { - WARN_ON(ftrace_pages || ftrace_pages_start); - /* First initialization */ - ftrace_pages = ftrace_pages_start = pg; - } else { - if (!ftrace_pages) - goto out; - - if (WARN_ON(ftrace_pages->next)) { - /* Hmm, we have free pages? */ - while (ftrace_pages->next) - ftrace_pages = ftrace_pages->next; - } - - ftrace_pages->next = pg; - ftrace_pages = pg; - } - p = start; while (p < end) { addr = ftrace_call_adjust(*p++); @@ -3678,18 +3401,9 @@ static int ftrace_process_locs(struct module *mod, */ if (!addr) continue; - if (!ftrace_record_ip(addr)) - break; + ftrace_record_ip(addr); } - /* These new locations need to be initialized */ - ftrace_new_pgs = pg; - - /* Make each individual set of pages sorted by ips */ - for (; pg; pg = pg->next) - sort(pg->records, pg->index, sizeof(struct dyn_ftrace), - ftrace_cmp_recs, ftrace_swap_recs); - /* * We only need to disable interrupts on start up * because we are modifying code that an interrupt @@ -3703,55 +3417,32 @@ static int ftrace_process_locs(struct module *mod, ftrace_update_code(mod); if (!mod) local_irq_restore(flags); - ret = 0; - out: mutex_unlock(&ftrace_lock); - return ret; + return 0; } #ifdef CONFIG_MODULES - -#define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next) - void ftrace_release_mod(struct module *mod) { struct dyn_ftrace *rec; - struct ftrace_page **last_pg; struct ftrace_page *pg; - int order; mutex_lock(&ftrace_lock); if (ftrace_disabled) goto out_unlock; - /* - * Each module has its own ftrace_pages, remove - * them from the list. - */ - last_pg = &ftrace_pages_start; - for (pg = ftrace_pages_start; pg; pg = *last_pg) { - rec = &pg->records[0]; + do_for_each_ftrace_rec(pg, rec) { if (within_module_core(rec->ip, mod)) { /* - * As core pages are first, the first - * page should never be a module page. + * rec->ip is changed in ftrace_free_rec() + * It should not between s and e if record was freed. */ - if (WARN_ON(pg == ftrace_pages_start)) - goto out_unlock; - - /* Check if we are deleting the last page */ - if (pg == ftrace_pages) - ftrace_pages = next_to_ftrace_page(last_pg); - - *last_pg = pg->next; - order = get_count_order(pg->size / ENTRIES_PER_PAGE); - free_pages((unsigned long)pg->records, order); - kfree(pg); - } else - last_pg = &pg->next; - } + FTRACE_WARN_ON(rec->flags & FTRACE_FL_FREE); + ftrace_free_rec(rec); + } + } while_for_each_ftrace_rec(); out_unlock: mutex_unlock(&ftrace_lock); } diff --git a/trunk/kernel/trace/trace.c b/trunk/kernel/trace/trace.c index 7392070ffc39..f2bd275bb60f 100644 --- a/trunk/kernel/trace/trace.c +++ b/trunk/kernel/trace/trace.c @@ -338,8 +338,7 @@ static DECLARE_WAIT_QUEUE_HEAD(trace_wait); /* trace_flags holds trace_options default values */ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | TRACE_ITER_ANNOTATE | TRACE_ITER_CONTEXT_INFO | TRACE_ITER_SLEEP_TIME | - TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE | - TRACE_ITER_IRQ_INFO; + TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE; static int trace_stop_count; static DEFINE_RAW_SPINLOCK(tracing_start_lock); @@ -427,7 +426,6 @@ static const char *trace_options[] = { "record-cmd", "overwrite", "disable_on_free", - "irq-info", NULL }; @@ -1845,33 +1843,6 @@ static void s_stop(struct seq_file *m, void *p) trace_event_read_unlock(); } -static void -get_total_entries(struct trace_array *tr, unsigned long *total, unsigned long *entries) -{ - unsigned long count; - int cpu; - - *total = 0; - *entries = 0; - - for_each_tracing_cpu(cpu) { - count = ring_buffer_entries_cpu(tr->buffer, cpu); - /* - * If this buffer has skipped entries, then we hold all - * entries for the trace and we need to ignore the - * ones before the time stamp. - */ - if (tr->data[cpu]->skipped_entries) { - count -= tr->data[cpu]->skipped_entries; - /* total is the same as the entries */ - *total += count; - } else - *total += count + - ring_buffer_overrun_cpu(tr->buffer, cpu); - *entries += count; - } -} - static void print_lat_help_header(struct seq_file *m) { seq_puts(m, "# _------=> CPU# \n"); @@ -1884,35 +1855,12 @@ static void print_lat_help_header(struct seq_file *m) seq_puts(m, "# \\ / ||||| \\ | / \n"); } -static void print_event_info(struct trace_array *tr, struct seq_file *m) -{ - unsigned long total; - unsigned long entries; - - get_total_entries(tr, &total, &entries); - seq_printf(m, "# entries-in-buffer/entries-written: %lu/%lu #P:%d\n", - entries, total, num_online_cpus()); - seq_puts(m, "#\n"); -} - -static void print_func_help_header(struct trace_array *tr, struct seq_file *m) +static void print_func_help_header(struct seq_file *m) { - print_event_info(tr, m); - seq_puts(m, "# TASK-PID CPU# TIMESTAMP FUNCTION\n"); + seq_puts(m, "# TASK-PID CPU# TIMESTAMP FUNCTION\n"); seq_puts(m, "# | | | | |\n"); } -static void print_func_help_header_irq(struct trace_array *tr, struct seq_file *m) -{ - print_event_info(tr, m); - seq_puts(m, "# _-----=> irqs-off\n"); - seq_puts(m, "# / _----=> need-resched\n"); - seq_puts(m, "# | / _---=> hardirq/softirq\n"); - seq_puts(m, "# || / _--=> preempt-depth\n"); - seq_puts(m, "# ||| / delay\n"); - seq_puts(m, "# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n"); - seq_puts(m, "# | | | |||| | |\n"); -} void print_trace_header(struct seq_file *m, struct trace_iterator *iter) @@ -1921,14 +1869,32 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter) struct trace_array *tr = iter->tr; struct trace_array_cpu *data = tr->data[tr->cpu]; struct tracer *type = current_trace; - unsigned long entries; - unsigned long total; + unsigned long entries = 0; + unsigned long total = 0; + unsigned long count; const char *name = "preemption"; + int cpu; if (type) name = type->name; - get_total_entries(tr, &total, &entries); + + for_each_tracing_cpu(cpu) { + count = ring_buffer_entries_cpu(tr->buffer, cpu); + /* + * If this buffer has skipped entries, then we hold all + * entries for the trace and we need to ignore the + * ones before the time stamp. + */ + if (tr->data[cpu]->skipped_entries) { + count -= tr->data[cpu]->skipped_entries; + /* total is the same as the entries */ + total += count; + } else + total += count + + ring_buffer_overrun_cpu(tr->buffer, cpu); + entries += count; + } seq_printf(m, "# %s latency trace v1.1.5 on %s\n", name, UTS_RELEASE); @@ -2174,21 +2140,6 @@ enum print_line_t print_trace_line(struct trace_iterator *iter) return print_trace_fmt(iter); } -void trace_latency_header(struct seq_file *m) -{ - struct trace_iterator *iter = m->private; - - /* print nothing if the buffers are empty */ - if (trace_empty(iter)) - return; - - if (iter->iter_flags & TRACE_FILE_LAT_FMT) - print_trace_header(m, iter); - - if (!(trace_flags & TRACE_ITER_VERBOSE)) - print_lat_help_header(m); -} - void trace_default_header(struct seq_file *m) { struct trace_iterator *iter = m->private; @@ -2204,12 +2155,8 @@ void trace_default_header(struct seq_file *m) if (!(trace_flags & TRACE_ITER_VERBOSE)) print_lat_help_header(m); } else { - if (!(trace_flags & TRACE_ITER_VERBOSE)) { - if (trace_flags & TRACE_ITER_IRQ_INFO) - print_func_help_header_irq(iter->tr, m); - else - print_func_help_header(iter->tr, m); - } + if (!(trace_flags & TRACE_ITER_VERBOSE)) + print_func_help_header(m); } } diff --git a/trunk/kernel/trace/trace.h b/trunk/kernel/trace/trace.h index 2c2657462ac3..092e1f8d18dc 100644 --- a/trunk/kernel/trace/trace.h +++ b/trunk/kernel/trace/trace.h @@ -370,7 +370,6 @@ void trace_graph_function(struct trace_array *tr, unsigned long ip, unsigned long parent_ip, unsigned long flags, int pc); -void trace_latency_header(struct seq_file *m); void trace_default_header(struct seq_file *m); void print_trace_header(struct seq_file *m, struct trace_iterator *iter); int trace_empty(struct trace_iterator *iter); @@ -655,7 +654,6 @@ enum trace_iterator_flags { TRACE_ITER_RECORD_CMD = 0x100000, TRACE_ITER_OVERWRITE = 0x200000, TRACE_ITER_STOP_ON_FREE = 0x400000, - TRACE_ITER_IRQ_INFO = 0x800000, }; /* diff --git a/trunk/kernel/trace/trace_events_filter.c b/trunk/kernel/trace/trace_events_filter.c index 24aee7127451..95dc31efd6dd 100644 --- a/trunk/kernel/trace/trace_events_filter.c +++ b/trunk/kernel/trace/trace_events_filter.c @@ -27,12 +27,6 @@ #include "trace.h" #include "trace_output.h" -#define DEFAULT_SYS_FILTER_MESSAGE \ - "### global filter ###\n" \ - "# Use this to set filters for multiple events.\n" \ - "# Only events with the given fields will be affected.\n" \ - "# If no events are modified, an error message will be displayed here" - enum filter_op_ids { OP_OR, @@ -652,7 +646,7 @@ void print_subsystem_event_filter(struct event_subsystem *system, if (filter && filter->filter_string) trace_seq_printf(s, "%s\n", filter->filter_string); else - trace_seq_printf(s, DEFAULT_SYS_FILTER_MESSAGE "\n"); + trace_seq_printf(s, "none\n"); mutex_unlock(&event_mutex); } @@ -1738,121 +1732,11 @@ static int replace_system_preds(struct event_subsystem *system, return -ENOMEM; } -static int create_filter_start(char *filter_str, bool set_str, - struct filter_parse_state **psp, - struct event_filter **filterp) -{ - struct event_filter *filter; - struct filter_parse_state *ps = NULL; - int err = 0; - - WARN_ON_ONCE(*psp || *filterp); - - /* allocate everything, and if any fails, free all and fail */ - filter = __alloc_filter(); - if (filter && set_str) - err = replace_filter_string(filter, filter_str); - - ps = kzalloc(sizeof(*ps), GFP_KERNEL); - - if (!filter || !ps || err) { - kfree(ps); - __free_filter(filter); - return -ENOMEM; - } - - /* we're committed to creating a new filter */ - *filterp = filter; - *psp = ps; - - parse_init(ps, filter_ops, filter_str); - err = filter_parse(ps); - if (err && set_str) - append_filter_err(ps, filter); - return err; -} - -static void create_filter_finish(struct filter_parse_state *ps) -{ - if (ps) { - filter_opstack_clear(ps); - postfix_clear(ps); - kfree(ps); - } -} - -/** - * create_filter - create a filter for a ftrace_event_call - * @call: ftrace_event_call to create a filter for - * @filter_str: filter string - * @set_str: remember @filter_str and enable detailed error in filter - * @filterp: out param for created filter (always updated on return) - * - * Creates a filter for @call with @filter_str. If @set_str is %true, - * @filter_str is copied and recorded in the new filter. - * - * On success, returns 0 and *@filterp points to the new filter. On - * failure, returns -errno and *@filterp may point to %NULL or to a new - * filter. In the latter case, the returned filter contains error - * information if @set_str is %true and the caller is responsible for - * freeing it. - */ -static int create_filter(struct ftrace_event_call *call, - char *filter_str, bool set_str, - struct event_filter **filterp) -{ - struct event_filter *filter = NULL; - struct filter_parse_state *ps = NULL; - int err; - - err = create_filter_start(filter_str, set_str, &ps, &filter); - if (!err) { - err = replace_preds(call, filter, ps, filter_str, false); - if (err && set_str) - append_filter_err(ps, filter); - } - create_filter_finish(ps); - - *filterp = filter; - return err; -} - -/** - * create_system_filter - create a filter for an event_subsystem - * @system: event_subsystem to create a filter for - * @filter_str: filter string - * @filterp: out param for created filter (always updated on return) - * - * Identical to create_filter() except that it creates a subsystem filter - * and always remembers @filter_str. - */ -static int create_system_filter(struct event_subsystem *system, - char *filter_str, struct event_filter **filterp) -{ - struct event_filter *filter = NULL; - struct filter_parse_state *ps = NULL; - int err; - - err = create_filter_start(filter_str, true, &ps, &filter); - if (!err) { - err = replace_system_preds(system, ps, filter_str); - if (!err) { - /* System filters just show a default message */ - kfree(filter->filter_string); - filter->filter_string = NULL; - } else { - append_filter_err(ps, filter); - } - } - create_filter_finish(ps); - - *filterp = filter; - return err; -} - int apply_event_filter(struct ftrace_event_call *call, char *filter_string) { + struct filter_parse_state *ps; struct event_filter *filter; + struct event_filter *tmp; int err = 0; mutex_lock(&event_mutex); @@ -1869,30 +1753,49 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) goto out_unlock; } - err = create_filter(call, filter_string, true, &filter); + err = -ENOMEM; + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) + goto out_unlock; + + filter = __alloc_filter(); + if (!filter) { + kfree(ps); + goto out_unlock; + } + + replace_filter_string(filter, filter_string); + + parse_init(ps, filter_ops, filter_string); + err = filter_parse(ps); + if (err) { + append_filter_err(ps, filter); + goto out; + } + err = replace_preds(call, filter, ps, filter_string, false); + if (err) { + filter_disable(call); + append_filter_err(ps, filter); + } else + call->flags |= TRACE_EVENT_FL_FILTERED; +out: /* * Always swap the call filter with the new filter * even if there was an error. If there was an error * in the filter, we disable the filter and show the error * string */ - if (filter) { - struct event_filter *tmp = call->filter; - - if (!err) - call->flags |= TRACE_EVENT_FL_FILTERED; - else - filter_disable(call); - - rcu_assign_pointer(call->filter, filter); - - if (tmp) { - /* Make sure the call is done with the filter */ - synchronize_sched(); - __free_filter(tmp); - } + tmp = call->filter; + rcu_assign_pointer(call->filter, filter); + if (tmp) { + /* Make sure the call is done with the filter */ + synchronize_sched(); + __free_filter(tmp); } + filter_opstack_clear(ps); + postfix_clear(ps); + kfree(ps); out_unlock: mutex_unlock(&event_mutex); @@ -1902,6 +1805,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) int apply_subsystem_event_filter(struct event_subsystem *system, char *filter_string) { + struct filter_parse_state *ps; struct event_filter *filter; int err = 0; @@ -1925,15 +1829,38 @@ int apply_subsystem_event_filter(struct event_subsystem *system, goto out_unlock; } - err = create_system_filter(system, filter_string, &filter); - if (filter) { - /* - * No event actually uses the system filter - * we can free it without synchronize_sched(). - */ - __free_filter(system->filter); - system->filter = filter; + err = -ENOMEM; + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) + goto out_unlock; + + filter = __alloc_filter(); + if (!filter) + goto out; + + replace_filter_string(filter, filter_string); + /* + * No event actually uses the system filter + * we can free it without synchronize_sched(). + */ + __free_filter(system->filter); + system->filter = filter; + + parse_init(ps, filter_ops, filter_string); + err = filter_parse(ps); + if (err) { + append_filter_err(ps, system->filter); + goto out; } + + err = replace_system_preds(system, ps, filter_string); + if (err) + append_filter_err(ps, system->filter); + +out: + filter_opstack_clear(ps); + postfix_clear(ps); + kfree(ps); out_unlock: mutex_unlock(&event_mutex); @@ -1955,6 +1882,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, { int err; struct event_filter *filter; + struct filter_parse_state *ps; struct ftrace_event_call *call; mutex_lock(&event_mutex); @@ -1969,10 +1897,33 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, if (event->filter) goto out_unlock; - err = create_filter(call, filter_str, false, &filter); + filter = __alloc_filter(); + if (!filter) { + err = PTR_ERR(filter); + goto out_unlock; + } + + err = -ENOMEM; + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) + goto free_filter; + + parse_init(ps, filter_ops, filter_str); + err = filter_parse(ps); + if (err) + goto free_ps; + + err = replace_preds(call, filter, ps, filter_str, false); if (!err) event->filter = filter; - else + +free_ps: + filter_opstack_clear(ps); + postfix_clear(ps); + kfree(ps); + +free_filter: + if (err) __free_filter(filter); out_unlock: @@ -1991,6 +1942,43 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, #define CREATE_TRACE_POINTS #include "trace_events_filter_test.h" +static int test_get_filter(char *filter_str, struct ftrace_event_call *call, + struct event_filter **pfilter) +{ + struct event_filter *filter; + struct filter_parse_state *ps; + int err = -ENOMEM; + + filter = __alloc_filter(); + if (!filter) + goto out; + + ps = kzalloc(sizeof(*ps), GFP_KERNEL); + if (!ps) + goto free_filter; + + parse_init(ps, filter_ops, filter_str); + err = filter_parse(ps); + if (err) + goto free_ps; + + err = replace_preds(call, filter, ps, filter_str, false); + if (!err) + *pfilter = filter; + + free_ps: + filter_opstack_clear(ps); + postfix_clear(ps); + kfree(ps); + + free_filter: + if (err) + __free_filter(filter); + + out: + return err; +} + #define DATA_REC(m, va, vb, vc, vd, ve, vf, vg, vh, nvisit) \ { \ .filter = FILTER, \ @@ -2109,13 +2097,12 @@ static __init int ftrace_test_event_filter(void) struct test_filter_data_t *d = &test_filter_data[i]; int err; - err = create_filter(&event_ftrace_test_filter, d->filter, - false, &filter); + err = test_get_filter(d->filter, &event_ftrace_test_filter, + &filter); if (err) { printk(KERN_INFO "Failed to get filter for '%s', err %d\n", d->filter, err); - __free_filter(filter); break; } diff --git a/trunk/kernel/trace/trace_irqsoff.c b/trunk/kernel/trace/trace_irqsoff.c index 99d20e920368..20dad0d7a163 100644 --- a/trunk/kernel/trace/trace_irqsoff.c +++ b/trunk/kernel/trace/trace_irqsoff.c @@ -280,20 +280,9 @@ static enum print_line_t irqsoff_print_line(struct trace_iterator *iter) } static void irqsoff_graph_return(struct ftrace_graph_ret *trace) { } +static void irqsoff_print_header(struct seq_file *s) { } static void irqsoff_trace_open(struct trace_iterator *iter) { } static void irqsoff_trace_close(struct trace_iterator *iter) { } - -#ifdef CONFIG_FUNCTION_TRACER -static void irqsoff_print_header(struct seq_file *s) -{ - trace_default_header(s); -} -#else -static void irqsoff_print_header(struct seq_file *s) -{ - trace_latency_header(s); -} -#endif /* CONFIG_FUNCTION_TRACER */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ /* diff --git a/trunk/kernel/trace/trace_output.c b/trunk/kernel/trace/trace_output.c index 0d6ff3555942..51999309a6cf 100644 --- a/trunk/kernel/trace/trace_output.c +++ b/trunk/kernel/trace/trace_output.c @@ -627,23 +627,11 @@ int trace_print_context(struct trace_iterator *iter) unsigned long usec_rem = do_div(t, USEC_PER_SEC); unsigned long secs = (unsigned long)t; char comm[TASK_COMM_LEN]; - int ret; trace_find_cmdline(entry->pid, comm); - ret = trace_seq_printf(s, "%16s-%-5d [%03d] ", - comm, entry->pid, iter->cpu); - if (!ret) - return 0; - - if (trace_flags & TRACE_ITER_IRQ_INFO) { - ret = trace_print_lat_fmt(s, entry); - if (!ret) - return 0; - } - - return trace_seq_printf(s, " %5lu.%06lu: ", - secs, usec_rem); + return trace_seq_printf(s, "%16s-%-5d [%03d] %5lu.%06lu: ", + comm, entry->pid, iter->cpu, secs, usec_rem); } int trace_print_lat_context(struct trace_iterator *iter) diff --git a/trunk/kernel/trace/trace_sched_wakeup.c b/trunk/kernel/trace/trace_sched_wakeup.c index ff791ea48b57..e4a70c0c71b6 100644 --- a/trunk/kernel/trace/trace_sched_wakeup.c +++ b/trunk/kernel/trace/trace_sched_wakeup.c @@ -280,20 +280,9 @@ static enum print_line_t wakeup_print_line(struct trace_iterator *iter) } static void wakeup_graph_return(struct ftrace_graph_ret *trace) { } +static void wakeup_print_header(struct seq_file *s) { } static void wakeup_trace_open(struct trace_iterator *iter) { } static void wakeup_trace_close(struct trace_iterator *iter) { } - -#ifdef CONFIG_FUNCTION_TRACER -static void wakeup_print_header(struct seq_file *s) -{ - trace_default_header(s); -} -#else -static void wakeup_print_header(struct seq_file *s) -{ - trace_latency_header(s); -} -#endif /* CONFIG_FUNCTION_TRACER */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ /* diff --git a/trunk/kernel/trace/trace_stack.c b/trunk/kernel/trace/trace_stack.c index d4545f49242e..77575b386d97 100644 --- a/trunk/kernel/trace/trace_stack.c +++ b/trunk/kernel/trace/trace_stack.c @@ -13,9 +13,6 @@ #include #include #include - -#include - #include "trace.h" #define STACK_TRACE_ENTRIES 500 @@ -136,6 +133,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip) static struct ftrace_ops trace_ops __read_mostly = { .func = stack_trace_call, + .flags = FTRACE_OPS_FL_GLOBAL, }; static ssize_t @@ -313,21 +311,6 @@ static const struct file_operations stack_trace_fops = { .release = seq_release, }; -static int -stack_trace_filter_open(struct inode *inode, struct file *file) -{ - return ftrace_regex_open(&trace_ops, FTRACE_ITER_FILTER, - inode, file); -} - -static const struct file_operations stack_trace_filter_fops = { - .open = stack_trace_filter_open, - .read = seq_read, - .write = ftrace_filter_write, - .llseek = ftrace_regex_lseek, - .release = ftrace_regex_release, -}; - int stack_trace_sysctl(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, @@ -355,13 +338,8 @@ stack_trace_sysctl(struct ctl_table *table, int write, return ret; } -static char stack_trace_filter_buf[COMMAND_LINE_SIZE+1] __initdata; - static __init int enable_stacktrace(char *str) { - if (strncmp(str, "_filter=", 8) == 0) - strncpy(stack_trace_filter_buf, str+8, COMMAND_LINE_SIZE); - stack_tracer_enabled = 1; last_stack_tracer_enabled = 1; return 1; @@ -380,12 +358,6 @@ static __init int stack_trace_init(void) trace_create_file("stack_trace", 0444, d_tracer, NULL, &stack_trace_fops); - trace_create_file("stack_trace_filter", 0444, d_tracer, - NULL, &stack_trace_filter_fops); - - if (stack_trace_filter_buf[0]) - ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1); - if (stack_tracer_enabled) register_ftrace_function(&trace_ops); diff --git a/trunk/mm/filemap.c b/trunk/mm/filemap.c index c106d3b3cc64..5f0a3c91fdac 100644 --- a/trunk/mm/filemap.c +++ b/trunk/mm/filemap.c @@ -1828,7 +1828,7 @@ static struct page *__read_cache_page(struct address_space *mapping, page = __page_cache_alloc(gfp | __GFP_COLD); if (!page) return ERR_PTR(-ENOMEM); - err = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL); + err = add_to_page_cache_lru(page, mapping, index, gfp); if (unlikely(err)) { page_cache_release(page); if (err == -EEXIST) @@ -1925,10 +1925,7 @@ static struct page *wait_on_page_read(struct page *page) * @gfp: the page allocator flags to use if allocating * * This is the same as "read_mapping_page(mapping, index, NULL)", but with - * any new page allocations done using the specified allocation flags. Note - * that the Radix tree operations will still use GFP_KERNEL, so you can't - * expect to do this atomically or anything like that - but you can pass in - * other page requirements. + * any new page allocations done using the specified allocation flags. * * If the page does not get brought uptodate, return -EIO. */ diff --git a/trunk/mm/hugetlb.c b/trunk/mm/hugetlb.c index 73f17c0293c0..2316840b337a 100644 --- a/trunk/mm/hugetlb.c +++ b/trunk/mm/hugetlb.c @@ -901,7 +901,6 @@ static int gather_surplus_pages(struct hstate *h, int delta) h->resv_huge_pages += delta; ret = 0; - spin_unlock(&hugetlb_lock); /* Free the needed pages to the hugetlb pool */ list_for_each_entry_safe(page, tmp, &surplus_list, lru) { if ((--needed) < 0) @@ -915,6 +914,7 @@ static int gather_surplus_pages(struct hstate *h, int delta) VM_BUG_ON(page_count(page)); enqueue_huge_page(h, page); } + spin_unlock(&hugetlb_lock); /* Free unnecessary surplus pages to the buddy allocator */ free: diff --git a/trunk/mm/memcontrol.c b/trunk/mm/memcontrol.c index 6aff93c98aca..b63f5f7dfa07 100644 --- a/trunk/mm/memcontrol.c +++ b/trunk/mm/memcontrol.c @@ -4907,9 +4907,9 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) int cpu; enable_swap_cgroup(); parent = NULL; - root_mem_cgroup = memcg; if (mem_cgroup_soft_limit_tree_init()) goto free_out; + root_mem_cgroup = memcg; for_each_possible_cpu(cpu) { struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu); @@ -4948,7 +4948,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) return &memcg->css; free_out: __mem_cgroup_free(memcg); - root_mem_cgroup = NULL; return ERR_PTR(error); } diff --git a/trunk/mm/mempolicy.c b/trunk/mm/mempolicy.c index adc395481813..c3fdbcb17658 100644 --- a/trunk/mm/mempolicy.c +++ b/trunk/mm/mempolicy.c @@ -636,6 +636,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, struct vm_area_struct *prev; struct vm_area_struct *vma; int err = 0; + pgoff_t pgoff; unsigned long vmstart; unsigned long vmend; @@ -643,13 +644,21 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, if (!vma || vma->vm_start > start) return -EFAULT; + if (start > vma->vm_start) + prev = vma; + for (; vma && vma->vm_start < end; prev = vma, vma = next) { next = vma->vm_next; vmstart = max(start, vma->vm_start); vmend = min(end, vma->vm_end); + if (mpol_equal(vma_policy(vma), new_pol)) + continue; + + pgoff = vma->vm_pgoff + + ((vmstart - vma->vm_start) >> PAGE_SHIFT); prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, - vma->anon_vma, vma->vm_file, vma->vm_pgoff, + vma->anon_vma, vma->vm_file, pgoff, new_pol); if (prev) { vma = prev; diff --git a/trunk/mm/oom_kill.c b/trunk/mm/oom_kill.c index 76f2c5ae908e..069b64e521fc 100644 --- a/trunk/mm/oom_kill.c +++ b/trunk/mm/oom_kill.c @@ -176,7 +176,7 @@ static bool oom_unkillable_task(struct task_struct *p, unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem, const nodemask_t *nodemask, unsigned long totalpages) { - int points; + long points; if (oom_unkillable_task(p, mem, nodemask)) return 0; diff --git a/trunk/mm/percpu.c b/trunk/mm/percpu.c index 3bb810a72006..716eb4acf2fc 100644 --- a/trunk/mm/percpu.c +++ b/trunk/mm/percpu.c @@ -1023,9 +1023,11 @@ phys_addr_t per_cpu_ptr_to_phys(void *addr) if (!is_vmalloc_addr(addr)) return __pa(addr); else - return page_to_phys(vmalloc_to_page(addr)); + return page_to_phys(vmalloc_to_page(addr)) + + offset_in_page(addr); } else - return page_to_phys(pcpu_addr_to_page(addr)); + return page_to_phys(pcpu_addr_to_page(addr)) + + offset_in_page(addr); } /** diff --git a/trunk/mm/vmalloc.c b/trunk/mm/vmalloc.c index 1d8b32f07139..27be2f0d4cb7 100644 --- a/trunk/mm/vmalloc.c +++ b/trunk/mm/vmalloc.c @@ -1290,7 +1290,7 @@ static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long align, unsigned long flags, unsigned long start, unsigned long end, int node, gfp_t gfp_mask, void *caller) { - static struct vmap_area *va; + struct vmap_area *va; struct vm_struct *area; BUG_ON(in_interrupt()); diff --git a/trunk/net/bluetooth/hci_conn.c b/trunk/net/bluetooth/hci_conn.c index e0af7237cd92..c1c597e3e198 100644 --- a/trunk/net/bluetooth/hci_conn.c +++ b/trunk/net/bluetooth/hci_conn.c @@ -673,7 +673,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) goto encrypt; auth: - if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) + if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return 0; if (!hci_conn_auth(conn, sec_level, auth_type)) diff --git a/trunk/net/bluetooth/hci_core.c b/trunk/net/bluetooth/hci_core.c index be84ae33ae36..b84458dcc226 100644 --- a/trunk/net/bluetooth/hci_core.c +++ b/trunk/net/bluetooth/hci_core.c @@ -613,7 +613,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (!test_bit(HCI_RAW, &hdev->flags)) { set_bit(HCI_INIT, &hdev->flags); __hci_request(hdev, hci_reset_req, 0, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(250)); clear_bit(HCI_INIT, &hdev->flags); } diff --git a/trunk/net/bluetooth/l2cap_core.c b/trunk/net/bluetooth/l2cap_core.c index 5ea94a1eecf2..17b5b1cd9657 100644 --- a/trunk/net/bluetooth/l2cap_core.c +++ b/trunk/net/bluetooth/l2cap_core.c @@ -2152,7 +2152,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi void *ptr = req->data; int type, olen; unsigned long val; - struct l2cap_conf_rfc rfc; + struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); @@ -2271,6 +2271,16 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) } } + /* Use sane default values in case a misbehaving remote device + * did not send an RFC option. + */ + rfc.mode = chan->mode; + rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc.max_pdu_size = cpu_to_le16(chan->imtu); + + BT_ERR("Expected RFC option was not found, using defaults"); + done: switch (rfc.mode) { case L2CAP_MODE_ERTM: diff --git a/trunk/net/bluetooth/rfcomm/core.c b/trunk/net/bluetooth/rfcomm/core.c index 4e32e18211f9..2d28dfe98389 100644 --- a/trunk/net/bluetooth/rfcomm/core.c +++ b/trunk/net/bluetooth/rfcomm/core.c @@ -1146,6 +1146,7 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) if (list_empty(&s->dlcs)) { s->state = BT_DISCONN; rfcomm_send_disc(s, 0); + rfcomm_session_clear_timer(s); } break; diff --git a/trunk/net/bridge/br_netfilter.c b/trunk/net/bridge/br_netfilter.c index d6ec3720c77e..fa8b8f763580 100644 --- a/trunk/net/bridge/br_netfilter.c +++ b/trunk/net/bridge/br_netfilter.c @@ -114,12 +114,18 @@ static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst, const vo return NULL; } +static unsigned int fake_mtu(const struct dst_entry *dst) +{ + return dst->dev->mtu; +} + static struct dst_ops fake_dst_ops = { .family = AF_INET, .protocol = cpu_to_be16(ETH_P_IP), .update_pmtu = fake_update_pmtu, .cow_metrics = fake_cow_metrics, .neigh_lookup = fake_neigh_lookup, + .mtu = fake_mtu, }; /* @@ -141,7 +147,7 @@ void br_netfilter_rtable_init(struct net_bridge *br) rt->dst.dev = br->dev; rt->dst.path = &rt->dst; dst_init_metrics(&rt->dst, br_dst_default_metrics, true); - rt->dst.flags = DST_NOXFRM; + rt->dst.flags = DST_NOXFRM | DST_NOPEER; rt->dst.ops = &fake_dst_ops; } diff --git a/trunk/net/core/flow.c b/trunk/net/core/flow.c index 8ae42de9c79e..e318c7e98042 100644 --- a/trunk/net/core/flow.c +++ b/trunk/net/core/flow.c @@ -358,6 +358,18 @@ void flow_cache_flush(void) put_online_cpus(); } +static void flow_cache_flush_task(struct work_struct *work) +{ + flow_cache_flush(); +} + +static DECLARE_WORK(flow_cache_flush_work, flow_cache_flush_task); + +void flow_cache_flush_deferred(void) +{ + schedule_work(&flow_cache_flush_work); +} + static int __cpuinit flow_cache_cpu_prepare(struct flow_cache *fc, int cpu) { struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu); diff --git a/trunk/net/core/net-sysfs.c b/trunk/net/core/net-sysfs.c index c71c434a4c05..385aefe53648 100644 --- a/trunk/net/core/net-sysfs.c +++ b/trunk/net/core/net-sysfs.c @@ -665,11 +665,14 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, if (count) { int i; - if (count > 1<<30) { + if (count > INT_MAX) + return -EINVAL; + count = roundup_pow_of_two(count); + if (count > (ULONG_MAX - sizeof(struct rps_dev_flow_table)) + / sizeof(struct rps_dev_flow)) { /* Enforce a limit to prevent overflow */ return -EINVAL; } - count = roundup_pow_of_two(count); table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(count)); if (!table) return -ENOMEM; diff --git a/trunk/net/core/sock.c b/trunk/net/core/sock.c index 4ed7b1d12f5e..b23f174ab84c 100644 --- a/trunk/net/core/sock.c +++ b/trunk/net/core/sock.c @@ -288,11 +288,7 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) unsigned long flags; struct sk_buff_head *list = &sk->sk_receive_queue; - /* Cast sk->rcvbuf to unsigned... It's pointless, but reduces - number of warnings when compiling with -W --ANK - */ - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned)sk->sk_rcvbuf) { + if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) { atomic_inc(&sk->sk_drops); trace_sock_rcvqueue_full(sk, skb); return -ENOMEM; diff --git a/trunk/net/ipv4/ipconfig.c b/trunk/net/ipv4/ipconfig.c index 0da2afc97f32..99ec116bef14 100644 --- a/trunk/net/ipv4/ipconfig.c +++ b/trunk/net/ipv4/ipconfig.c @@ -253,6 +253,10 @@ static int __init ic_open_devs(void) } } + /* no point in waiting if we could not bring up at least one device */ + if (!ic_first_dev) + goto have_carrier; + /* wait for a carrier on at least one device */ start = jiffies; while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) { diff --git a/trunk/net/ipv4/route.c b/trunk/net/ipv4/route.c index 46af62363b8c..94cdbc55ca7e 100644 --- a/trunk/net/ipv4/route.c +++ b/trunk/net/ipv4/route.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -120,6 +121,7 @@ static int ip_rt_max_size; static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; +static int ip_rt_gc_interval __read_mostly = 60 * HZ; static int ip_rt_gc_min_interval __read_mostly = HZ / 2; static int ip_rt_redirect_number __read_mostly = 9; static int ip_rt_redirect_load __read_mostly = HZ / 50; @@ -133,6 +135,9 @@ static int ip_rt_min_advmss __read_mostly = 256; static int rt_chain_length_max __read_mostly = 20; static int redirect_genid; +static struct delayed_work expires_work; +static unsigned long expires_ljiffies; + /* * Interface to generic destination cache. */ @@ -830,6 +835,97 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth) return ONE; } +static void rt_check_expire(void) +{ + static unsigned int rover; + unsigned int i = rover, goal; + struct rtable *rth; + struct rtable __rcu **rthp; + unsigned long samples = 0; + unsigned long sum = 0, sum2 = 0; + unsigned long delta; + u64 mult; + + delta = jiffies - expires_ljiffies; + expires_ljiffies = jiffies; + mult = ((u64)delta) << rt_hash_log; + if (ip_rt_gc_timeout > 1) + do_div(mult, ip_rt_gc_timeout); + goal = (unsigned int)mult; + if (goal > rt_hash_mask) + goal = rt_hash_mask + 1; + for (; goal > 0; goal--) { + unsigned long tmo = ip_rt_gc_timeout; + unsigned long length; + + i = (i + 1) & rt_hash_mask; + rthp = &rt_hash_table[i].chain; + + if (need_resched()) + cond_resched(); + + samples++; + + if (rcu_dereference_raw(*rthp) == NULL) + continue; + length = 0; + spin_lock_bh(rt_hash_lock_addr(i)); + while ((rth = rcu_dereference_protected(*rthp, + lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) { + prefetch(rth->dst.rt_next); + if (rt_is_expired(rth)) { + *rthp = rth->dst.rt_next; + rt_free(rth); + continue; + } + if (rth->dst.expires) { + /* Entry is expired even if it is in use */ + if (time_before_eq(jiffies, rth->dst.expires)) { +nofree: + tmo >>= 1; + rthp = &rth->dst.rt_next; + /* + * We only count entries on + * a chain with equal hash inputs once + * so that entries for different QOS + * levels, and other non-hash input + * attributes don't unfairly skew + * the length computation + */ + length += has_noalias(rt_hash_table[i].chain, rth); + continue; + } + } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) + goto nofree; + + /* Cleanup aged off entries. */ + *rthp = rth->dst.rt_next; + rt_free(rth); + } + spin_unlock_bh(rt_hash_lock_addr(i)); + sum += length; + sum2 += length*length; + } + if (samples) { + unsigned long avg = sum / samples; + unsigned long sd = int_sqrt(sum2 / samples - avg*avg); + rt_chain_length_max = max_t(unsigned long, + ip_rt_gc_elasticity, + (avg + 4*sd) >> FRACT_BITS); + } + rover = i; +} + +/* + * rt_worker_func() is run in process context. + * we call rt_check_expire() to scan part of the hash table + */ +static void rt_worker_func(struct work_struct *work) +{ + rt_check_expire(); + schedule_delayed_work(&expires_work, ip_rt_gc_interval); +} + /* * Perturbation of rt_genid by a small quantity [1..256] * Using 8 bits of shuffling ensure we can call rt_cache_invalidate() @@ -1271,7 +1367,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) { struct rtable *rt = (struct rtable *) dst; - if (rt) { + if (rt && !(rt->dst.flags & DST_NOPEER)) { if (rt->peer == NULL) rt_bind_peer(rt, rt->rt_dst, 1); @@ -1282,7 +1378,7 @@ void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more) iph->id = htons(inet_getid(rt->peer, more)); return; } - } else + } else if (!rt) printk(KERN_DEBUG "rt_bind_peer(0) @%p\n", __builtin_return_address(0)); @@ -3178,6 +3274,13 @@ static ctl_table ipv4_route_table[] = { .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, + { + .procname = "gc_interval", + .data = &ip_rt_gc_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, { .procname = "redirect_load", .data = &ip_rt_redirect_load, @@ -3388,6 +3491,11 @@ int __init ip_rt_init(void) devinet_init(); ip_fib_init(); + INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func); + expires_ljiffies = jiffies; + schedule_delayed_work(&expires_work, + net_random() % ip_rt_gc_interval + ip_rt_gc_interval); + if (ip_rt_proc_init()) printk(KERN_ERR "Unable to create route proc files\n"); #ifdef CONFIG_XFRM diff --git a/trunk/net/ipv6/ip6_output.c b/trunk/net/ipv6/ip6_output.c index 84d0bd5cac93..ec562713db9b 100644 --- a/trunk/net/ipv6/ip6_output.c +++ b/trunk/net/ipv6/ip6_output.c @@ -603,7 +603,7 @@ void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt) static atomic_t ipv6_fragmentation_id; int old, new; - if (rt) { + if (rt && !(rt->dst.flags & DST_NOPEER)) { struct inet_peer *peer; if (!rt->rt6i_peer) diff --git a/trunk/net/llc/af_llc.c b/trunk/net/llc/af_llc.c index dfd3a648a551..a18e6c3d36e3 100644 --- a/trunk/net/llc/af_llc.c +++ b/trunk/net/llc/af_llc.c @@ -833,15 +833,15 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, copied += used; len -= used; + /* For non stream protcols we get one packet per recvmsg call */ + if (sk->sk_type != SOCK_STREAM) + goto copy_uaddr; + if (!(flags & MSG_PEEK)) { sk_eat_skb(sk, skb, 0); *seq = 0; } - /* For non stream protcols we get one packet per recvmsg call */ - if (sk->sk_type != SOCK_STREAM) - goto copy_uaddr; - /* Partial read */ if (used + offset < skb->len) continue; @@ -857,6 +857,12 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, } if (llc_sk(sk)->cmsg_flags) llc_cmsg_rcv(msg, skb); + + if (!(flags & MSG_PEEK)) { + sk_eat_skb(sk, skb, 0); + *seq = 0; + } + goto out; } diff --git a/trunk/net/netfilter/ipvs/ip_vs_conn.c b/trunk/net/netfilter/ipvs/ip_vs_conn.c index 12571fb2881c..29fa5badde75 100644 --- a/trunk/net/netfilter/ipvs/ip_vs_conn.c +++ b/trunk/net/netfilter/ipvs/ip_vs_conn.c @@ -616,7 +616,7 @@ struct ip_vs_dest *ip_vs_try_bind_dest(struct ip_vs_conn *cp) if ((cp) && (!cp->dest)) { dest = ip_vs_find_dest(ip_vs_conn_net(cp), cp->af, &cp->daddr, cp->dport, &cp->vaddr, cp->vport, - cp->protocol, cp->fwmark); + cp->protocol, cp->fwmark, cp->flags); ip_vs_bind_dest(cp, dest); return dest; } else diff --git a/trunk/net/netfilter/ipvs/ip_vs_ctl.c b/trunk/net/netfilter/ipvs/ip_vs_ctl.c index 008bf97cc91a..e1a66cf37f9a 100644 --- a/trunk/net/netfilter/ipvs/ip_vs_ctl.c +++ b/trunk/net/netfilter/ipvs/ip_vs_ctl.c @@ -619,15 +619,21 @@ struct ip_vs_dest *ip_vs_find_dest(struct net *net, int af, const union nf_inet_addr *daddr, __be16 dport, const union nf_inet_addr *vaddr, - __be16 vport, __u16 protocol, __u32 fwmark) + __be16 vport, __u16 protocol, __u32 fwmark, + __u32 flags) { struct ip_vs_dest *dest; struct ip_vs_service *svc; + __be16 port = dport; svc = ip_vs_service_get(net, af, fwmark, protocol, vaddr, vport); if (!svc) return NULL; - dest = ip_vs_lookup_dest(svc, daddr, dport); + if (fwmark && (flags & IP_VS_CONN_F_FWD_MASK) != IP_VS_CONN_F_MASQ) + port = 0; + dest = ip_vs_lookup_dest(svc, daddr, port); + if (!dest) + dest = ip_vs_lookup_dest(svc, daddr, port ^ dport); if (dest) atomic_inc(&dest->refcnt); ip_vs_service_put(svc); diff --git a/trunk/net/netfilter/ipvs/ip_vs_sync.c b/trunk/net/netfilter/ipvs/ip_vs_sync.c index 3cdd479f9b5d..2b6678c0ce14 100644 --- a/trunk/net/netfilter/ipvs/ip_vs_sync.c +++ b/trunk/net/netfilter/ipvs/ip_vs_sync.c @@ -740,7 +740,7 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, * but still handled. */ dest = ip_vs_find_dest(net, type, daddr, dport, param->vaddr, - param->vport, protocol, fwmark); + param->vport, protocol, fwmark, flags); /* Set the approprite ativity flag */ if (protocol == IPPROTO_TCP) { diff --git a/trunk/net/netfilter/nf_conntrack_netlink.c b/trunk/net/netfilter/nf_conntrack_netlink.c index ef21b221f036..257e77256c5c 100644 --- a/trunk/net/netfilter/nf_conntrack_netlink.c +++ b/trunk/net/netfilter/nf_conntrack_netlink.c @@ -135,7 +135,7 @@ ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct) static inline int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct) { - long timeout = (ct->timeout.expires - jiffies) / HZ; + long timeout = ((long)ct->timeout.expires - (long)jiffies) / HZ; if (timeout < 0) timeout = 0; @@ -1358,12 +1358,15 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, nf_ct_protonum(ct)); if (helper == NULL) { rcu_read_unlock(); + spin_unlock_bh(&nf_conntrack_lock); #ifdef CONFIG_MODULES if (request_module("nfct-helper-%s", helpname) < 0) { + spin_lock_bh(&nf_conntrack_lock); err = -EOPNOTSUPP; goto err1; } + spin_lock_bh(&nf_conntrack_lock); rcu_read_lock(); helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), @@ -1638,7 +1641,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { struct nf_conn *master = exp->master; - long timeout = (exp->timeout.expires - jiffies) / HZ; + long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ; struct nf_conn_help *help; if (timeout < 0) @@ -1869,25 +1872,30 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, err = -ENOMEM; skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (skb2 == NULL) + if (skb2 == NULL) { + nf_ct_expect_put(exp); goto out; + } rcu_read_lock(); err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp); rcu_read_unlock(); + nf_ct_expect_put(exp); if (err <= 0) goto free; - nf_ct_expect_put(exp); + err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); + if (err < 0) + goto out; - return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); + return 0; free: kfree_skb(skb2); out: - nf_ct_expect_put(exp); - return err; + /* this avoids a loop in nfnetlink. */ + return err == -EAGAIN ? -ENOBUFS : err; } static int diff --git a/trunk/net/netfilter/xt_connbytes.c b/trunk/net/netfilter/xt_connbytes.c index 5b138506690e..9ddf1c3bfb39 100644 --- a/trunk/net/netfilter/xt_connbytes.c +++ b/trunk/net/netfilter/xt_connbytes.c @@ -87,10 +87,10 @@ connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par) break; } - if (sinfo->count.to) + if (sinfo->count.to >= sinfo->count.from) return what <= sinfo->count.to && what >= sinfo->count.from; - else - return what >= sinfo->count.from; + else /* inverted */ + return what < sinfo->count.to || what > sinfo->count.from; } static int connbytes_mt_check(const struct xt_mtchk_param *par) diff --git a/trunk/net/nfc/nci/core.c b/trunk/net/nfc/nci/core.c index 3925c6578767..ea66034499ce 100644 --- a/trunk/net/nfc/nci/core.c +++ b/trunk/net/nfc/nci/core.c @@ -69,7 +69,7 @@ static int __nci_request(struct nci_dev *ndev, __u32 timeout) { int rc = 0; - unsigned long completion_rc; + long completion_rc; ndev->req_status = NCI_REQ_PEND; diff --git a/trunk/net/packet/af_packet.c b/trunk/net/packet/af_packet.c index 82a6f34d39d0..d9d4970b9b07 100644 --- a/trunk/net/packet/af_packet.c +++ b/trunk/net/packet/af_packet.c @@ -1630,8 +1630,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, if (snaplen > res) snaplen = res; - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned)sk->sk_rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) goto drop_n_acct; if (skb_shared(skb)) { @@ -1762,8 +1761,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, if (po->tp_version <= TPACKET_V2) { if (macoff + snaplen > po->rx_ring.frame_size) { if (po->copy_thresh && - atomic_read(&sk->sk_rmem_alloc) + skb->truesize - < (unsigned)sk->sk_rcvbuf) { + atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) { if (skb_shared(skb)) { copy_skb = skb_clone(skb, GFP_ATOMIC); } else { @@ -2450,8 +2448,12 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protoc { struct packet_sock *po = pkt_sk(sk); - if (po->fanout) + if (po->fanout) { + if (dev) + dev_put(dev); + return -EINVAL; + } lock_sock(sk); diff --git a/trunk/net/sched/sch_mqprio.c b/trunk/net/sched/sch_mqprio.c index f88256cbacbf..28de43092330 100644 --- a/trunk/net/sched/sch_mqprio.c +++ b/trunk/net/sched/sch_mqprio.c @@ -107,7 +107,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) if (!netif_is_multiqueue(dev)) return -EOPNOTSUPP; - if (nla_len(opt) < sizeof(*qopt)) + if (!opt || nla_len(opt) < sizeof(*qopt)) return -EINVAL; qopt = nla_data(opt); diff --git a/trunk/net/sched/sch_netem.c b/trunk/net/sched/sch_netem.c index eb3b9a86c6ed..a4ab207cdc59 100644 --- a/trunk/net/sched/sch_netem.c +++ b/trunk/net/sched/sch_netem.c @@ -488,7 +488,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) return -EINVAL; s = sizeof(struct disttable) + n * sizeof(s16); - d = kmalloc(s, GFP_KERNEL); + d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN); if (!d) d = vmalloc(s); if (!d) @@ -501,9 +501,10 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) root_lock = qdisc_root_sleeping_lock(sch); spin_lock_bh(root_lock); - dist_free(q->delay_dist); - q->delay_dist = d; + swap(q->delay_dist, d); spin_unlock_bh(root_lock); + + dist_free(d); return 0; } diff --git a/trunk/net/sched/sch_qfq.c b/trunk/net/sched/sch_qfq.c index 103343408593..7b0325459e71 100644 --- a/trunk/net/sched/sch_qfq.c +++ b/trunk/net/sched/sch_qfq.c @@ -817,11 +817,11 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch) static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl) { unsigned long mask; - uint32_t limit, roundedF; + u64 limit, roundedF; int slot_shift = cl->grp->slot_shift; roundedF = qfq_round_down(cl->F, slot_shift); - limit = qfq_round_down(q->V, slot_shift) + (1UL << slot_shift); + limit = qfq_round_down(q->V, slot_shift) + (1ULL << slot_shift); if (!qfq_gt(cl->F, q->V) || qfq_gt(roundedF, limit)) { /* timestamp was stale */ diff --git a/trunk/net/sctp/associola.c b/trunk/net/sctp/associola.c index 152b5b3c3fff..acd2edbc073e 100644 --- a/trunk/net/sctp/associola.c +++ b/trunk/net/sctp/associola.c @@ -173,7 +173,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = - (unsigned long)sp->autoclose * HZ; + min_t(unsigned long, sp->autoclose, sctp_max_autoclose) * HZ; /* Initializes the timers */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) diff --git a/trunk/net/sctp/output.c b/trunk/net/sctp/output.c index 08b3cead6503..817174eb5f41 100644 --- a/trunk/net/sctp/output.c +++ b/trunk/net/sctp/output.c @@ -697,13 +697,7 @@ static void sctp_packet_append_data(struct sctp_packet *packet, /* Keep track of how many bytes are in flight to the receiver. */ asoc->outqueue.outstanding_bytes += datasize; - /* Update our view of the receiver's rwnd. Include sk_buff overhead - * while updating peer.rwnd so that it reduces the chances of a - * receiver running out of receive buffer space even when receive - * window is still open. This can happen when a sender is sending - * sending small messages. - */ - datasize += sizeof(struct sk_buff); + /* Update our view of the receiver's rwnd. */ if (datasize < rwnd) rwnd -= datasize; else diff --git a/trunk/net/sctp/outqueue.c b/trunk/net/sctp/outqueue.c index 14c2b06028ff..cfeb1d4a1ee6 100644 --- a/trunk/net/sctp/outqueue.c +++ b/trunk/net/sctp/outqueue.c @@ -411,8 +411,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, chunk->transport->flight_size -= sctp_data_size(chunk); q->outstanding_bytes -= sctp_data_size(chunk); - q->asoc->peer.rwnd += (sctp_data_size(chunk) + - sizeof(struct sk_buff)); + q->asoc->peer.rwnd += sctp_data_size(chunk); } continue; } @@ -432,8 +431,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, * (Section 7.2.4)), add the data size of those * chunks to the rwnd. */ - q->asoc->peer.rwnd += (sctp_data_size(chunk) + - sizeof(struct sk_buff)); + q->asoc->peer.rwnd += sctp_data_size(chunk); q->outstanding_bytes -= sctp_data_size(chunk); if (chunk->transport) transport->flight_size -= sctp_data_size(chunk); diff --git a/trunk/net/sctp/protocol.c b/trunk/net/sctp/protocol.c index 61b9fca5a173..6f6ad8686833 100644 --- a/trunk/net/sctp/protocol.c +++ b/trunk/net/sctp/protocol.c @@ -1285,6 +1285,9 @@ SCTP_STATIC __init int sctp_init(void) sctp_max_instreams = SCTP_DEFAULT_INSTREAMS; sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS; + /* Initialize maximum autoclose timeout. */ + sctp_max_autoclose = INT_MAX / HZ; + /* Initialize handle used for association ids. */ idr_init(&sctp_assocs_id); diff --git a/trunk/net/sctp/socket.c b/trunk/net/sctp/socket.c index 13bf5fcdbff1..54a7cd2fdd7a 100644 --- a/trunk/net/sctp/socket.c +++ b/trunk/net/sctp/socket.c @@ -2200,8 +2200,6 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, return -EINVAL; if (copy_from_user(&sp->autoclose, optval, optlen)) return -EFAULT; - /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */ - sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ); return 0; } diff --git a/trunk/net/sctp/sysctl.c b/trunk/net/sctp/sysctl.c index 6b3952961b85..60ffbd067ff7 100644 --- a/trunk/net/sctp/sysctl.c +++ b/trunk/net/sctp/sysctl.c @@ -53,6 +53,10 @@ static int sack_timer_min = 1; static int sack_timer_max = 500; static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ static int rwnd_scale_max = 16; +static unsigned long max_autoclose_min = 0; +static unsigned long max_autoclose_max = + (MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX) + ? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ; extern long sysctl_sctp_mem[3]; extern int sysctl_sctp_rmem[3]; @@ -258,6 +262,15 @@ static ctl_table sctp_table[] = { .extra1 = &one, .extra2 = &rwnd_scale_max, }, + { + .procname = "max_autoclose", + .data = &sctp_max_autoclose, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + .extra1 = &max_autoclose_min, + .extra2 = &max_autoclose_max, + }, { /* sentinel */ } }; diff --git a/trunk/net/sunrpc/sched.c b/trunk/net/sunrpc/sched.c index d12ffa545811..00a1a2acd587 100644 --- a/trunk/net/sunrpc/sched.c +++ b/trunk/net/sunrpc/sched.c @@ -590,6 +590,27 @@ void rpc_prepare_task(struct rpc_task *task) task->tk_ops->rpc_call_prepare(task, task->tk_calldata); } +static void +rpc_init_task_statistics(struct rpc_task *task) +{ + /* Initialize retry counters */ + task->tk_garb_retry = 2; + task->tk_cred_retry = 2; + task->tk_rebind_retry = 2; + + /* starting timestamp */ + task->tk_start = ktime_get(); +} + +static void +rpc_reset_task_statistics(struct rpc_task *task) +{ + task->tk_timeouts = 0; + task->tk_flags &= ~(RPC_CALL_MAJORSEEN|RPC_TASK_KILLED|RPC_TASK_SENT); + + rpc_init_task_statistics(task); +} + /* * Helper that calls task->tk_ops->rpc_call_done if it exists */ @@ -602,6 +623,7 @@ void rpc_exit_task(struct rpc_task *task) WARN_ON(RPC_ASSASSINATED(task)); /* Always release the RPC slot and buffer memory */ xprt_release(task); + rpc_reset_task_statistics(task); } } } @@ -804,11 +826,6 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta task->tk_calldata = task_setup_data->callback_data; INIT_LIST_HEAD(&task->tk_task); - /* Initialize retry counters */ - task->tk_garb_retry = 2; - task->tk_cred_retry = 2; - task->tk_rebind_retry = 2; - task->tk_priority = task_setup_data->priority - RPC_PRIORITY_LOW; task->tk_owner = current->tgid; @@ -818,8 +835,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta if (task->tk_ops->rpc_call_prepare != NULL) task->tk_action = rpc_prepare_task; - /* starting timestamp */ - task->tk_start = ktime_get(); + rpc_init_task_statistics(task); dprintk("RPC: new task initialized, procpid %u\n", task_pid_nr(current)); diff --git a/trunk/net/sunrpc/xprt.c b/trunk/net/sunrpc/xprt.c index f4385e45a5fc..c64c0ef519b5 100644 --- a/trunk/net/sunrpc/xprt.c +++ b/trunk/net/sunrpc/xprt.c @@ -995,13 +995,11 @@ static void xprt_alloc_slot(struct rpc_task *task) static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) { - if (xprt_dynamic_free_slot(xprt, req)) - return; - - memset(req, 0, sizeof(*req)); /* mark unused */ - spin_lock(&xprt->reserve_lock); - list_add(&req->rq_list, &xprt->free); + if (!xprt_dynamic_free_slot(xprt, req)) { + memset(req, 0, sizeof(*req)); /* mark unused */ + list_add(&req->rq_list, &xprt->free); + } rpc_wake_up_next(&xprt->backlog); spin_unlock(&xprt->reserve_lock); } diff --git a/trunk/net/xfrm/xfrm_policy.c b/trunk/net/xfrm/xfrm_policy.c index 2118d6446630..9049a5caeb25 100644 --- a/trunk/net/xfrm/xfrm_policy.c +++ b/trunk/net/xfrm/xfrm_policy.c @@ -2276,8 +2276,6 @@ static void __xfrm_garbage_collect(struct net *net) { struct dst_entry *head, *next; - flow_cache_flush(); - spin_lock_bh(&xfrm_policy_sk_bundle_lock); head = xfrm_policy_sk_bundles; xfrm_policy_sk_bundles = NULL; @@ -2290,6 +2288,18 @@ static void __xfrm_garbage_collect(struct net *net) } } +static void xfrm_garbage_collect(struct net *net) +{ + flow_cache_flush(); + __xfrm_garbage_collect(net); +} + +static void xfrm_garbage_collect_deferred(struct net *net) +{ + flow_cache_flush_deferred(); + __xfrm_garbage_collect(net); +} + static void xfrm_init_pmtu(struct dst_entry *dst) { do { @@ -2422,7 +2432,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) if (likely(dst_ops->neigh_lookup == NULL)) dst_ops->neigh_lookup = xfrm_neigh_lookup; if (likely(afinfo->garbage_collect == NULL)) - afinfo->garbage_collect = __xfrm_garbage_collect; + afinfo->garbage_collect = xfrm_garbage_collect_deferred; xfrm_policy_afinfo[afinfo->family] = afinfo; } write_unlock_bh(&xfrm_policy_afinfo_lock); @@ -2516,7 +2526,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void switch (event) { case NETDEV_DOWN: - __xfrm_garbage_collect(dev_net(dev)); + xfrm_garbage_collect(dev_net(dev)); } return NOTIFY_DONE; } diff --git a/trunk/scripts/kconfig/Makefile b/trunk/scripts/kconfig/Makefile index ba573fe7c74d..914833d99b06 100644 --- a/trunk/scripts/kconfig/Makefile +++ b/trunk/scripts/kconfig/Makefile @@ -60,8 +60,8 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h --directory=$(srctree) --directory=$(objtree) \ --output $(obj)/config.pot $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot - $(Q)ln -fs Kconfig.x86 arch/um/Kconfig - $(Q)(for i in `ls $(srctree)/arch/*/Kconfig`; \ + $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ + $(srctree)/arch/*/um/Kconfig`; \ do \ echo " GEN $$i"; \ $(obj)/kxgettext $$i \ @@ -69,7 +69,6 @@ update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h done ) $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ --output $(obj)/linux.pot - $(Q)rm -f $(srctree)/arch/um/Kconfig $(Q)rm -f $(obj)/config.pot PHONY += allnoconfig allyesconfig allmodconfig alldefconfig randconfig diff --git a/trunk/scripts/recordmcount.h b/trunk/scripts/recordmcount.h index f40a6af6bf40..54e35c1e5948 100644 --- a/trunk/scripts/recordmcount.h +++ b/trunk/scripts/recordmcount.h @@ -462,7 +462,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ succeed_file(); } if (w(txthdr->sh_type) != SHT_PROGBITS || - !(w(txthdr->sh_flags) & SHF_EXECINSTR)) + !(_w(txthdr->sh_flags) & SHF_EXECINSTR)) return NULL; return txtname; } diff --git a/trunk/security/integrity/evm/evm_crypto.c b/trunk/security/integrity/evm/evm_crypto.c index 5dd5b140242c..8738deff26fa 100644 --- a/trunk/security/integrity/evm/evm_crypto.c +++ b/trunk/security/integrity/evm/evm_crypto.c @@ -27,20 +27,35 @@ static int evmkey_len = MAX_KEY_SIZE; struct crypto_shash *hmac_tfm; +static DEFINE_MUTEX(mutex); + static struct shash_desc *init_desc(void) { int rc; struct shash_desc *desc; if (hmac_tfm == NULL) { + mutex_lock(&mutex); + if (hmac_tfm) + goto out; hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC); if (IS_ERR(hmac_tfm)) { pr_err("Can not allocate %s (reason: %ld)\n", evm_hmac, PTR_ERR(hmac_tfm)); rc = PTR_ERR(hmac_tfm); hmac_tfm = NULL; + mutex_unlock(&mutex); + return ERR_PTR(rc); + } + rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len); + if (rc) { + crypto_free_shash(hmac_tfm); + hmac_tfm = NULL; + mutex_unlock(&mutex); return ERR_PTR(rc); } +out: + mutex_unlock(&mutex); } desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm), @@ -51,11 +66,7 @@ static struct shash_desc *init_desc(void) desc->tfm = hmac_tfm; desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; - rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len); - if (rc) - goto out; rc = crypto_shash_init(desc); -out: if (rc) { kfree(desc); return ERR_PTR(rc); diff --git a/trunk/security/security.c b/trunk/security/security.c index 0c6cc69c8f86..e2f684aeb70c 100644 --- a/trunk/security/security.c +++ b/trunk/security/security.c @@ -381,7 +381,7 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir, void **value, size_t *len) { if (unlikely(IS_PRIVATE(inode))) - return 0; + return -EOPNOTSUPP; return security_ops->inode_init_security(inode, dir, qstr, name, value, len); } diff --git a/trunk/security/selinux/netport.c b/trunk/security/selinux/netport.c index 0b62bd112461..7b9eb1faf68b 100644 --- a/trunk/security/selinux/netport.c +++ b/trunk/security/selinux/netport.c @@ -123,7 +123,9 @@ static void sel_netport_insert(struct sel_netport *port) if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { struct sel_netport *tail; tail = list_entry( - rcu_dereference(sel_netport_hash[idx].list.prev), + rcu_dereference_protected( + sel_netport_hash[idx].list.prev, + lockdep_is_held(&sel_netport_lock)), struct sel_netport, list); list_del_rcu(&tail->list); kfree_rcu(tail, rcu); diff --git a/trunk/sound/atmel/ac97c.c b/trunk/sound/atmel/ac97c.c index 6e5addeb236b..73516f69ac7c 100644 --- a/trunk/sound/atmel/ac97c.c +++ b/trunk/sound/atmel/ac97c.c @@ -899,6 +899,10 @@ static void atmel_ac97c_reset(struct atmel_ac97c *chip) /* AC97 v2.2 specifications says minimum 1 us. */ udelay(2); gpio_set_value(chip->reset_pin, 1); + } else { + ac97c_writel(chip, MR, AC97C_MR_WRST | AC97C_MR_ENA); + udelay(2); + ac97c_writel(chip, MR, AC97C_MR_ENA); } } diff --git a/trunk/sound/soc/codecs/wm8776.c b/trunk/sound/soc/codecs/wm8776.c index bfdc52370ad0..d3b0a20744f1 100644 --- a/trunk/sound/soc/codecs/wm8776.c +++ b/trunk/sound/soc/codecs/wm8776.c @@ -235,6 +235,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream, switch (snd_pcm_format_width(params_format(params))) { case 16: iface = 0; + break; case 20: iface = 0x10; break; diff --git a/trunk/tools/perf/Documentation/perf-annotate.txt b/trunk/tools/perf/Documentation/perf-annotate.txt index c89f9e1453f7..fe6762ed56bd 100644 --- a/trunk/tools/perf/Documentation/perf-annotate.txt +++ b/trunk/tools/perf/Documentation/perf-annotate.txt @@ -22,7 +22,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data unless stdin is a fifo) + Input file name. (default: perf.data) -d:: --dsos=:: @@ -66,7 +66,7 @@ OPTIONS used. This interfaces starts by centering on the line with more samples, TAB/UNTAB cycles through the lines with more samples. --C:: +-c:: --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can be provided as a comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. Default is to report samples on all diff --git a/trunk/tools/perf/Documentation/perf-buildid-list.txt b/trunk/tools/perf/Documentation/perf-buildid-list.txt index 25c52efcc7f0..cc22325ffd1b 100644 --- a/trunk/tools/perf/Documentation/perf-buildid-list.txt +++ b/trunk/tools/perf/Documentation/perf-buildid-list.txt @@ -26,7 +26,7 @@ OPTIONS Show only DSOs with hits. -i:: --input=:: - Input file name. (default: perf.data unless stdin is a fifo) + Input file name. (default: perf.data) -f:: --force:: Don't do ownership validation. diff --git a/trunk/tools/perf/Documentation/perf-evlist.txt b/trunk/tools/perf/Documentation/perf-evlist.txt index 0507ec7bad71..0cada9e053dc 100644 --- a/trunk/tools/perf/Documentation/perf-evlist.txt +++ b/trunk/tools/perf/Documentation/perf-evlist.txt @@ -18,7 +18,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data unless stdin is a fifo) + Input file name. (default: perf.data) SEE ALSO -------- diff --git a/trunk/tools/perf/Documentation/perf-kmem.txt b/trunk/tools/perf/Documentation/perf-kmem.txt index 7c8fbbf3f61c..a52fcde894c7 100644 --- a/trunk/tools/perf/Documentation/perf-kmem.txt +++ b/trunk/tools/perf/Documentation/perf-kmem.txt @@ -23,7 +23,7 @@ OPTIONS ------- -i :: --input=:: - Select the input file (default: perf.data unless stdin is a fifo) + Select the input file (default: perf.data) --caller:: Show per-callsite statistics diff --git a/trunk/tools/perf/Documentation/perf-lock.txt b/trunk/tools/perf/Documentation/perf-lock.txt index d6b2a4f2108b..4a26a2f3a6a3 100644 --- a/trunk/tools/perf/Documentation/perf-lock.txt +++ b/trunk/tools/perf/Documentation/perf-lock.txt @@ -29,7 +29,7 @@ COMMON OPTIONS -i:: --input=:: - Input file name. (default: perf.data unless stdin is a fifo) + Input file name. -v:: --verbose:: diff --git a/trunk/tools/perf/Documentation/perf-record.txt b/trunk/tools/perf/Documentation/perf-record.txt index 2937f7e14bb7..5a520f825295 100644 --- a/trunk/tools/perf/Documentation/perf-record.txt +++ b/trunk/tools/perf/Documentation/perf-record.txt @@ -89,7 +89,7 @@ OPTIONS -m:: --mmap-pages=:: - Number of mmap data pages. Must be a power of two. + Number of mmap data pages. -g:: --call-graph:: diff --git a/trunk/tools/perf/Documentation/perf-report.txt b/trunk/tools/perf/Documentation/perf-report.txt index 9b430e98712e..212f24d672e1 100644 --- a/trunk/tools/perf/Documentation/perf-report.txt +++ b/trunk/tools/perf/Documentation/perf-report.txt @@ -19,7 +19,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data unless stdin is a fifo) + Input file name. (default: perf.data) -v:: --verbose:: @@ -39,7 +39,7 @@ OPTIONS -T:: --threads:: Show per-thread event counters --c:: +-C:: --comms=:: Only consider symbols in these comms. CSV that understands file://filename entries. @@ -80,10 +80,9 @@ OPTIONS --dump-raw-trace:: Dump raw trace in ASCII. --g [type,min[,limit],order]:: +-g [type,min,order]:: --call-graph:: - Display call chains using type, min percent threshold, optional print - limit and order. + Display call chains using type, min percent threshold and order. type can be either: - flat: single column, linear exposure of call chains. - graph: use a graph tree, displaying absolute overhead rates. @@ -129,7 +128,7 @@ OPTIONS --symfs=:: Look for files with symbols relative to this directory. --C:: +-c:: --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can be provided as a comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. Default is to report samples on all diff --git a/trunk/tools/perf/Documentation/perf-sched.txt b/trunk/tools/perf/Documentation/perf-sched.txt index 8ff4df956951..5b212b57f70b 100644 --- a/trunk/tools/perf/Documentation/perf-sched.txt +++ b/trunk/tools/perf/Documentation/perf-sched.txt @@ -40,7 +40,7 @@ OPTIONS ------- -i:: --input=:: - Input file name. (default: perf.data unless stdin is a fifo) + Input file name. (default: perf.data) -v:: --verbose:: diff --git a/trunk/tools/perf/Documentation/perf-script.txt b/trunk/tools/perf/Documentation/perf-script.txt index 2f6cef43da25..dec87ecb530e 100644 --- a/trunk/tools/perf/Documentation/perf-script.txt +++ b/trunk/tools/perf/Documentation/perf-script.txt @@ -106,7 +106,7 @@ OPTIONS -i:: --input=:: - Input file name. (default: perf.data unless stdin is a fifo) + Input file name. -d:: --debug-mode:: @@ -182,17 +182,12 @@ OPTIONS --hide-call-graph:: When printing symbols do not display call chain. --C:: +-c:: --cpu:: Only report samples for the list of CPUs provided. Multiple CPUs can be provided as a comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-2. Default is to report samples on all CPUs. --c:: ---comms=:: - Only display events for these comms. CSV that understands - file://filename entries. - -I:: --show-info:: Display extended information about the perf.data file. This adds diff --git a/trunk/tools/perf/Documentation/perf-test.txt b/trunk/tools/perf/Documentation/perf-test.txt index b24ac40fcd58..2c3b462f64b0 100644 --- a/trunk/tools/perf/Documentation/perf-test.txt +++ b/trunk/tools/perf/Documentation/perf-test.txt @@ -8,19 +8,13 @@ perf-test - Runs sanity tests. SYNOPSIS -------- [verse] -'perf test [] [{list |[|]}]' +'perf test ' DESCRIPTION ----------- This command does assorted sanity tests, initially through linked routines but also will look for a directory with more tests in the form of scripts. -To get a list of available tests use 'perf test list', specifying a test name -fragment will show all tests that have it. - -To run just specific tests, inform test name fragments or the numbers obtained -from 'perf test list'. - OPTIONS ------- -v:: diff --git a/trunk/tools/perf/Documentation/perf-timechart.txt b/trunk/tools/perf/Documentation/perf-timechart.txt index 1632b0efc757..d7b79e2ba2ad 100644 --- a/trunk/tools/perf/Documentation/perf-timechart.txt +++ b/trunk/tools/perf/Documentation/perf-timechart.txt @@ -27,7 +27,7 @@ OPTIONS Select the output file (default: output.svg) -i:: --input=:: - Select the input file (default: perf.data unless stdin is a fifo) + Select the input file (default: perf.data) -w:: --width=:: Select the width of the SVG file (default: 1000) diff --git a/trunk/tools/perf/Makefile b/trunk/tools/perf/Makefile index ac86d67b636e..b98e3075646b 100644 --- a/trunk/tools/perf/Makefile +++ b/trunk/tools/perf/Makefile @@ -278,7 +278,6 @@ LIB_H += util/strbuf.h LIB_H += util/strlist.h LIB_H += util/strfilter.h LIB_H += util/svghelper.h -LIB_H += util/tool.h LIB_H += util/run-command.h LIB_H += util/sigchain.h LIB_H += util/symbol.h diff --git a/trunk/tools/perf/builtin-annotate.c b/trunk/tools/perf/builtin-annotate.c index 214ba7f9f577..46b4c24f338e 100644 --- a/trunk/tools/perf/builtin-annotate.c +++ b/trunk/tools/perf/builtin-annotate.c @@ -27,32 +27,32 @@ #include "util/sort.h" #include "util/hist.h" #include "util/session.h" -#include "util/tool.h" #include -struct perf_annotate { - struct perf_tool tool; - char const *input_name; - bool force, use_tui, use_stdio; - bool full_paths; - bool print_line; - const char *sym_hist_filter; - const char *cpu_list; - DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -}; +static char const *input_name = "perf.data"; + +static bool force, use_tui, use_stdio; + +static bool full_paths; + +static bool print_line; -static int perf_evsel__add_sample(struct perf_evsel *evsel, - struct perf_sample *sample, - struct addr_location *al, - struct perf_annotate *ann) +static const char *sym_hist_filter; + +static const char *cpu_list; +static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); + +static int perf_evlist__add_sample(struct perf_evlist *evlist, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct addr_location *al) { struct hist_entry *he; int ret; - if (ann->sym_hist_filter != NULL && - (al->sym == NULL || - strcmp(ann->sym_hist_filter, al->sym->name) != 0)) { + if (sym_hist_filter != NULL && + (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { /* We're only interested in a symbol named sym_hist_filter */ if (al->sym != NULL) { rb_erase(&al->sym->rb_node, @@ -69,7 +69,8 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, ret = 0; if (he->ms.sym != NULL) { struct annotation *notes = symbol__annotation(he->ms.sym); - if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) + if (notes->src == NULL && + symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0) return -ENOMEM; ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); @@ -80,26 +81,25 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, return ret; } -static int process_sample_event(struct perf_tool *tool, - union perf_event *event, +static int process_sample_event(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine) + struct perf_session *session) { - struct perf_annotate *ann = container_of(tool, struct perf_annotate, tool); struct addr_location al; - if (perf_event__preprocess_sample(event, machine, &al, sample, + if (perf_event__preprocess_sample(event, session, &al, sample, symbol__annotate_init) < 0) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); return -1; } - if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap)) + if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) return 0; - if (!al.filtered && perf_evsel__add_sample(evsel, sample, &al, ann)) { + if (!al.filtered && + perf_evlist__add_sample(session->evlist, sample, evsel, &al)) { pr_warning("problem incrementing symbol count, " "skipping event\n"); return -1; @@ -108,15 +108,14 @@ static int process_sample_event(struct perf_tool *tool, return 0; } -static int hist_entry__tty_annotate(struct hist_entry *he, int evidx, - struct perf_annotate *ann) +static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) { return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, - ann->print_line, ann->full_paths, 0, 0); + print_line, full_paths, 0, 0); } static void hists__find_annotations(struct hists *self, int evidx, - struct perf_annotate *ann) + int nr_events) { struct rb_node *nd = rb_first(&self->entries), *next; int key = K_RIGHT; @@ -139,7 +138,8 @@ static void hists__find_annotations(struct hists *self, int evidx, } if (use_browser > 0) { - key = hist_entry__tui_annotate(he, evidx, NULL, NULL, 0); + key = hist_entry__tui_annotate(he, evidx, nr_events, + NULL, NULL, 0); switch (key) { case K_RIGHT: next = rb_next(nd); @@ -154,7 +154,7 @@ static void hists__find_annotations(struct hists *self, int evidx, if (next != NULL) nd = next; } else { - hist_entry__tty_annotate(he, evidx, ann); + hist_entry__tty_annotate(he, evidx); nd = rb_next(nd); /* * Since we have a hist_entry per IP for the same @@ -167,26 +167,33 @@ static void hists__find_annotations(struct hists *self, int evidx, } } -static int __cmd_annotate(struct perf_annotate *ann) +static struct perf_event_ops event_ops = { + .sample = process_sample_event, + .mmap = perf_event__process_mmap, + .comm = perf_event__process_comm, + .fork = perf_event__process_task, + .ordered_samples = true, + .ordering_requires_timestamps = true, +}; + +static int __cmd_annotate(void) { int ret; struct perf_session *session; struct perf_evsel *pos; u64 total_nr_samples; - session = perf_session__new(ann->input_name, O_RDONLY, - ann->force, false, &ann->tool); + session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); if (session == NULL) return -ENOMEM; - if (ann->cpu_list) { - ret = perf_session__cpu_bitmap(session, ann->cpu_list, - ann->cpu_bitmap); + if (cpu_list) { + ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); if (ret) goto out_delete; } - ret = perf_session__process_events(session, &ann->tool); + ret = perf_session__process_events(session, &event_ops); if (ret) goto out_delete; @@ -210,12 +217,13 @@ static int __cmd_annotate(struct perf_annotate *ann) total_nr_samples += nr_samples; hists__collapse_resort(hists); hists__output_resort(hists); - hists__find_annotations(hists, pos->idx, ann); + hists__find_annotations(hists, pos->idx, + session->evlist->nr_entries); } } if (total_nr_samples == 0) { - ui__warning("The %s file has no samples!\n", session->filename); + ui__warning("The %s file has no samples!\n", input_name); goto out_delete; } out_delete: @@ -239,41 +247,29 @@ static const char * const annotate_usage[] = { NULL }; -int cmd_annotate(int argc, const char **argv, const char *prefix __used) -{ - struct perf_annotate annotate = { - .tool = { - .sample = process_sample_event, - .mmap = perf_event__process_mmap, - .comm = perf_event__process_comm, - .fork = perf_event__process_task, - .ordered_samples = true, - .ordering_requires_timestamps = true, - }, - }; - const struct option options[] = { - OPT_STRING('i', "input", &annotate.input_name, "file", +static const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), - OPT_STRING('s', "symbol", &annotate.sym_hist_filter, "symbol", + OPT_STRING('s', "symbol", &sym_hist_filter, "symbol", "symbol to annotate"), - OPT_BOOLEAN('f', "force", &annotate.force, "don't complain, do it"), + OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, "dump raw trace in ASCII"), - OPT_BOOLEAN(0, "tui", &annotate.use_tui, "Use the TUI interface"), - OPT_BOOLEAN(0, "stdio", &annotate.use_stdio, "Use the stdio interface"), + OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), + OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), - OPT_BOOLEAN('l', "print-line", &annotate.print_line, + OPT_BOOLEAN('l', "print-line", &print_line, "print matching source lines (may be slow)"), - OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, + OPT_BOOLEAN('P', "full-paths", &full_paths, "Don't shorten the displayed pathnames"), - OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"), + OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, @@ -283,13 +279,15 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_END() - }; +}; +int cmd_annotate(int argc, const char **argv, const char *prefix __used) +{ argc = parse_options(argc, argv, options, annotate_usage, 0); - if (annotate.use_stdio) + if (use_stdio) use_browser = 0; - else if (annotate.use_tui) + else if (use_tui) use_browser = 1; setup_browser(true); @@ -310,7 +308,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) if (argc > 1) usage_with_options(annotate_usage, options); - annotate.sym_hist_filter = argv[0]; + sym_hist_filter = argv[0]; } if (field_sep && *field_sep == '.') { @@ -318,5 +316,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) return -1; } - return __cmd_annotate(&annotate); + return __cmd_annotate(); } diff --git a/trunk/tools/perf/builtin-buildid-list.c b/trunk/tools/perf/builtin-buildid-list.c index 52480467e9ff..cb690a65bf02 100644 --- a/trunk/tools/perf/builtin-buildid-list.c +++ b/trunk/tools/perf/builtin-buildid-list.c @@ -18,7 +18,7 @@ #include -static const char *input_name; +static char const *input_name = "perf.data"; static bool force; static bool show_kernel; static bool with_hits; @@ -39,6 +39,24 @@ static const struct option options[] = { OPT_END() }; +static int perf_session__list_build_ids(void) +{ + struct perf_session *session; + + session = perf_session__new(input_name, O_RDONLY, force, false, + &build_id__mark_dso_hit_ops); + if (session == NULL) + return -1; + + if (with_hits) + perf_session__process_events(session, &build_id__mark_dso_hit_ops); + + perf_session__fprintf_dsos_buildid(session, stdout, with_hits); + + perf_session__delete(session); + return 0; +} + static int sysfs__fprintf_build_id(FILE *fp) { u8 kallsyms_build_id[BUILD_ID_SIZE]; @@ -67,37 +85,18 @@ static int filename__fprintf_build_id(const char *name, FILE *fp) return fprintf(fp, "%s\n", sbuild_id); } -static int perf_session__list_build_ids(void) -{ - struct perf_session *session; - - elf_version(EV_CURRENT); - - session = perf_session__new(input_name, O_RDONLY, force, false, - &build_id__mark_dso_hit_ops); - if (session == NULL) - return -1; - - /* - * See if this is an ELF file first: - */ - if (filename__fprintf_build_id(session->filename, stdout)) - goto out; - - if (with_hits) - perf_session__process_events(session, &build_id__mark_dso_hit_ops); - - perf_session__fprintf_dsos_buildid(session, stdout, with_hits); -out: - perf_session__delete(session); - return 0; -} - static int __cmd_buildid_list(void) { if (show_kernel) return sysfs__fprintf_build_id(stdout); + elf_version(EV_CURRENT); + /* + * See if this is an ELF file first: + */ + if (filename__fprintf_build_id(input_name, stdout)) + return 0; + return perf_session__list_build_ids(); } diff --git a/trunk/tools/perf/builtin-diff.c b/trunk/tools/perf/builtin-diff.c index 4f19513d7dda..b39f3a1ee7dc 100644 --- a/trunk/tools/perf/builtin-diff.c +++ b/trunk/tools/perf/builtin-diff.c @@ -9,9 +9,7 @@ #include "util/debug.h" #include "util/event.h" #include "util/hist.h" -#include "util/evsel.h" #include "util/session.h" -#include "util/tool.h" #include "util/sort.h" #include "util/symbol.h" #include "util/util.h" @@ -32,15 +30,14 @@ static int hists__add_entry(struct hists *self, return -ENOMEM; } -static int diff__process_sample_event(struct perf_tool *tool __used, - union perf_event *event, +static int diff__process_sample_event(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct machine *machine) + struct perf_session *session) { struct addr_location al; - if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) { + if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); return -1; @@ -49,16 +46,16 @@ static int diff__process_sample_event(struct perf_tool *tool __used, if (al.filtered || al.sym == NULL) return 0; - if (hists__add_entry(&evsel->hists, &al, sample->period)) { + if (hists__add_entry(&session->hists, &al, sample->period)) { pr_warning("problem incrementing symbol period, skipping event\n"); return -1; } - evsel->hists.stats.total_period += sample->period; + session->hists.stats.total_period += sample->period; return 0; } -static struct perf_tool perf_diff = { +static struct perf_event_ops event_ops = { .sample = diff__process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, @@ -148,13 +145,13 @@ static int __cmd_diff(void) int ret, i; struct perf_session *session[2]; - session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff); - session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff); + session[0] = perf_session__new(input_old, O_RDONLY, force, false, &event_ops); + session[1] = perf_session__new(input_new, O_RDONLY, force, false, &event_ops); if (session[0] == NULL || session[1] == NULL) return -ENOMEM; for (i = 0; i < 2; ++i) { - ret = perf_session__process_events(session[i], &perf_diff); + ret = perf_session__process_events(session[i], &event_ops); if (ret) goto out_delete; } diff --git a/trunk/tools/perf/builtin-evlist.c b/trunk/tools/perf/builtin-evlist.c index 26760322c4f4..4c5e9e04a41f 100644 --- a/trunk/tools/perf/builtin-evlist.c +++ b/trunk/tools/perf/builtin-evlist.c @@ -15,7 +15,7 @@ #include "util/parse-options.h" #include "util/session.h" -static const char *input_name; +static char const *input_name = "perf.data"; static int __cmd_evlist(void) { diff --git a/trunk/tools/perf/builtin-inject.c b/trunk/tools/perf/builtin-inject.c index 09c106193e65..8dfc12bb119b 100644 --- a/trunk/tools/perf/builtin-inject.c +++ b/trunk/tools/perf/builtin-inject.c @@ -9,7 +9,6 @@ #include "perf.h" #include "util/session.h" -#include "util/tool.h" #include "util/debug.h" #include "util/parse-options.h" @@ -17,9 +16,8 @@ static char const *input_name = "-"; static bool inject_build_ids; -static int perf_event__repipe_synth(struct perf_tool *tool __used, - union perf_event *event, - struct machine *machine __used) +static int perf_event__repipe_synth(union perf_event *event, + struct perf_session *session __used) { uint32_t size; void *buf = event; @@ -38,70 +36,41 @@ static int perf_event__repipe_synth(struct perf_tool *tool __used, return 0; } -static int perf_event__repipe_op2_synth(struct perf_tool *tool, - union perf_event *event, - struct perf_session *session __used) -{ - return perf_event__repipe_synth(tool, event, NULL); -} - -static int perf_event__repipe_event_type_synth(struct perf_tool *tool, - union perf_event *event) -{ - return perf_event__repipe_synth(tool, event, NULL); -} - -static int perf_event__repipe_tracing_data_synth(union perf_event *event, - struct perf_session *session __used) -{ - return perf_event__repipe_synth(NULL, event, NULL); -} - -static int perf_event__repipe_attr(union perf_event *event, - struct perf_evlist **pevlist __used) -{ - return perf_event__repipe_synth(NULL, event, NULL); -} - -static int perf_event__repipe(struct perf_tool *tool, - union perf_event *event, +static int perf_event__repipe(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine) + struct perf_session *session) { - return perf_event__repipe_synth(tool, event, machine); + return perf_event__repipe_synth(event, session); } -static int perf_event__repipe_sample(struct perf_tool *tool, - union perf_event *event, +static int perf_event__repipe_sample(union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, - struct machine *machine) + struct perf_session *session) { - return perf_event__repipe_synth(tool, event, machine); + return perf_event__repipe_synth(event, session); } -static int perf_event__repipe_mmap(struct perf_tool *tool, - union perf_event *event, +static int perf_event__repipe_mmap(union perf_event *event, struct perf_sample *sample, - struct machine *machine) + struct perf_session *session) { int err; - err = perf_event__process_mmap(tool, event, sample, machine); - perf_event__repipe(tool, event, sample, machine); + err = perf_event__process_mmap(event, sample, session); + perf_event__repipe(event, sample, session); return err; } -static int perf_event__repipe_task(struct perf_tool *tool, - union perf_event *event, +static int perf_event__repipe_task(union perf_event *event, struct perf_sample *sample, - struct machine *machine) + struct perf_session *session) { int err; - err = perf_event__process_task(tool, event, sample, machine); - perf_event__repipe(tool, event, sample, machine); + err = perf_event__process_task(event, sample, session); + perf_event__repipe(event, sample, session); return err; } @@ -111,7 +80,7 @@ static int perf_event__repipe_tracing_data(union perf_event *event, { int err; - perf_event__repipe_synth(NULL, event, NULL); + perf_event__repipe_synth(event, session); err = perf_event__process_tracing_data(event, session); return err; @@ -131,10 +100,10 @@ static int dso__read_build_id(struct dso *self) return -1; } -static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, - struct machine *machine) +static int dso__inject_build_id(struct dso *self, struct perf_session *session) { u16 misc = PERF_RECORD_MISC_USER; + struct machine *machine; int err; if (dso__read_build_id(self) < 0) { @@ -142,11 +111,17 @@ static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, return -1; } + machine = perf_session__find_host_machine(session); + if (machine == NULL) { + pr_err("Can't find machine for session\n"); + return -1; + } + if (self->kernel) misc = PERF_RECORD_MISC_KERNEL; - err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe, - machine); + err = perf_event__synthesize_build_id(self, misc, perf_event__repipe, + machine, session); if (err) { pr_err("Can't synthesize build_id event for %s\n", self->long_name); return -1; @@ -155,11 +130,10 @@ static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, return 0; } -static int perf_event__inject_buildid(struct perf_tool *tool, - union perf_event *event, +static int perf_event__inject_buildid(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct machine *machine) + struct perf_session *session) { struct addr_location al; struct thread *thread; @@ -167,21 +141,21 @@ static int perf_event__inject_buildid(struct perf_tool *tool, cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - thread = machine__findnew_thread(machine, event->ip.pid); + thread = perf_session__findnew(session, event->ip.pid); if (thread == NULL) { pr_err("problem processing %d event, skipping it.\n", event->header.type); goto repipe; } - thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, - event->ip.ip, &al); + thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, + event->ip.pid, event->ip.ip, &al); if (al.map != NULL) { if (!al.map->dso->hit) { al.map->dso->hit = 1; if (map__load(al.map, NULL) >= 0) { - dso__inject_build_id(al.map->dso, tool, machine); + dso__inject_build_id(al.map->dso, session); /* * If this fails, too bad, let the other side * account this as unresolved. @@ -194,24 +168,24 @@ static int perf_event__inject_buildid(struct perf_tool *tool, } repipe: - perf_event__repipe(tool, event, sample, machine); + perf_event__repipe(event, sample, session); return 0; } -struct perf_tool perf_inject = { +struct perf_event_ops inject_ops = { .sample = perf_event__repipe_sample, .mmap = perf_event__repipe, .comm = perf_event__repipe, .fork = perf_event__repipe, .exit = perf_event__repipe, .lost = perf_event__repipe, - .read = perf_event__repipe_sample, + .read = perf_event__repipe, .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, - .attr = perf_event__repipe_attr, - .event_type = perf_event__repipe_event_type_synth, - .tracing_data = perf_event__repipe_tracing_data_synth, - .build_id = perf_event__repipe_op2_synth, + .attr = perf_event__repipe_synth, + .event_type = perf_event__repipe_synth, + .tracing_data = perf_event__repipe_synth, + .build_id = perf_event__repipe_synth, }; extern volatile int session_done; @@ -229,17 +203,17 @@ static int __cmd_inject(void) signal(SIGINT, sig_handler); if (inject_build_ids) { - perf_inject.sample = perf_event__inject_buildid; - perf_inject.mmap = perf_event__repipe_mmap; - perf_inject.fork = perf_event__repipe_task; - perf_inject.tracing_data = perf_event__repipe_tracing_data; + inject_ops.sample = perf_event__inject_buildid; + inject_ops.mmap = perf_event__repipe_mmap; + inject_ops.fork = perf_event__repipe_task; + inject_ops.tracing_data = perf_event__repipe_tracing_data; } - session = perf_session__new(input_name, O_RDONLY, false, true, &perf_inject); + session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); if (session == NULL) return -ENOMEM; - ret = perf_session__process_events(session, &perf_inject); + ret = perf_session__process_events(session, &inject_ops); perf_session__delete(session); diff --git a/trunk/tools/perf/builtin-kmem.c b/trunk/tools/perf/builtin-kmem.c index fe1ad8f21961..225e963df105 100644 --- a/trunk/tools/perf/builtin-kmem.c +++ b/trunk/tools/perf/builtin-kmem.c @@ -7,7 +7,6 @@ #include "util/thread.h" #include "util/header.h" #include "util/session.h" -#include "util/tool.h" #include "util/parse-options.h" #include "util/trace-event.h" @@ -19,7 +18,7 @@ struct alloc_stat; typedef int (*sort_fn_t)(struct alloc_stat *, struct alloc_stat *); -static const char *input_name; +static char const *input_name = "perf.data"; static int alloc_flag; static int caller_flag; @@ -304,13 +303,12 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, } } -static int process_sample_event(struct perf_tool *tool __used, - union perf_event *event, +static int process_sample_event(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct machine *machine) + struct perf_session *session) { - struct thread *thread = machine__findnew_thread(machine, event->ip.pid); + struct thread *thread = perf_session__findnew(session, event->ip.pid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", @@ -326,7 +324,7 @@ static int process_sample_event(struct perf_tool *tool __used, return 0; } -static struct perf_tool perf_kmem = { +static struct perf_event_ops event_ops = { .sample = process_sample_event, .comm = perf_event__process_comm, .ordered_samples = true, @@ -485,7 +483,7 @@ static int __cmd_kmem(void) { int err = -EINVAL; struct perf_session *session = perf_session__new(input_name, O_RDONLY, - 0, false, &perf_kmem); + 0, false, &event_ops); if (session == NULL) return -ENOMEM; @@ -496,7 +494,7 @@ static int __cmd_kmem(void) goto out_delete; setup_pager(); - err = perf_session__process_events(session, &perf_kmem); + err = perf_session__process_events(session, &event_ops); if (err != 0) goto out_delete; sort_result(); diff --git a/trunk/tools/perf/builtin-kvm.c b/trunk/tools/perf/builtin-kvm.c index 032324a76b87..34d1e853829d 100644 --- a/trunk/tools/perf/builtin-kvm.c +++ b/trunk/tools/perf/builtin-kvm.c @@ -38,7 +38,7 @@ static const struct option kvm_options[] = { OPT_BOOLEAN(0, "guest", &perf_guest, "Collect guest os data"), OPT_BOOLEAN(0, "host", &perf_host, - "Collect host os data"), + "Collect guest os data"), OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory", "guest mount directory under which every guest os" " instance has a subdir"), diff --git a/trunk/tools/perf/builtin-lock.c b/trunk/tools/perf/builtin-lock.c index 2296c391d0f5..899080ace267 100644 --- a/trunk/tools/perf/builtin-lock.c +++ b/trunk/tools/perf/builtin-lock.c @@ -12,7 +12,6 @@ #include "util/debug.h" #include "util/session.h" -#include "util/tool.h" #include #include @@ -326,7 +325,7 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name) die("memory allocation failed\n"); } -static const char *input_name; +static char const *input_name = "perf.data"; struct raw_event_sample { u32 size; @@ -846,13 +845,12 @@ static void dump_info(void) die("Unknown type of information\n"); } -static int process_sample_event(struct perf_tool *tool __used, - union perf_event *event, +static int process_sample_event(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel __used, - struct machine *machine) + struct perf_session *s) { - struct thread *thread = machine__findnew_thread(machine, sample->tid); + struct thread *thread = perf_session__findnew(s, sample->tid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", @@ -865,7 +863,7 @@ static int process_sample_event(struct perf_tool *tool __used, return 0; } -static struct perf_tool eops = { +static struct perf_event_ops eops = { .sample = process_sample_event, .comm = perf_event__process_comm, .ordered_samples = true, diff --git a/trunk/tools/perf/builtin-probe.c b/trunk/tools/perf/builtin-probe.c index 59d43abfbfec..710ae3d0a489 100644 --- a/trunk/tools/perf/builtin-probe.c +++ b/trunk/tools/perf/builtin-probe.c @@ -46,6 +46,7 @@ #define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" #define DEFAULT_FUNC_FILTER "!_*" +#define MAX_PATH_LEN 256 /* Session management structure */ static struct { diff --git a/trunk/tools/perf/builtin-record.c b/trunk/tools/perf/builtin-record.c index 0abfb18b911f..6ab58cc99d53 100644 --- a/trunk/tools/perf/builtin-record.c +++ b/trunk/tools/perf/builtin-record.c @@ -22,7 +22,6 @@ #include "util/evsel.h" #include "util/debug.h" #include "util/session.h" -#include "util/tool.h" #include "util/symbol.h" #include "util/cpumap.h" #include "util/thread_map.h" @@ -36,36 +35,55 @@ enum write_mode_t { WRITE_APPEND }; -struct perf_record { - struct perf_tool tool; - struct perf_record_opts opts; - u64 bytes_written; - const char *output_name; - struct perf_evlist *evlist; - struct perf_session *session; - const char *progname; - int output; - unsigned int page_size; - int realtime_prio; - enum write_mode_t write_mode; - bool no_buildid; - bool no_buildid_cache; - bool force; - bool file_new; - bool append_file; - long samples; - off_t post_processing_offset; -}; - -static void advance_output(struct perf_record *rec, size_t size) +static u64 user_interval = ULLONG_MAX; +static u64 default_interval = 0; + +static unsigned int page_size; +static unsigned int mmap_pages = UINT_MAX; +static unsigned int user_freq = UINT_MAX; +static int freq = 1000; +static int output; +static int pipe_output = 0; +static const char *output_name = NULL; +static bool group = false; +static int realtime_prio = 0; +static bool nodelay = false; +static bool raw_samples = false; +static bool sample_id_all_avail = true; +static bool system_wide = false; +static pid_t target_pid = -1; +static pid_t target_tid = -1; +static pid_t child_pid = -1; +static bool no_inherit = false; +static enum write_mode_t write_mode = WRITE_FORCE; +static bool call_graph = false; +static bool inherit_stat = false; +static bool no_samples = false; +static bool sample_address = false; +static bool sample_time = false; +static bool no_buildid = false; +static bool no_buildid_cache = false; +static struct perf_evlist *evsel_list; + +static long samples = 0; +static u64 bytes_written = 0; + +static int file_new = 1; +static off_t post_processing_offset; + +static struct perf_session *session; +static const char *cpu_list; +static const char *progname; + +static void advance_output(size_t size) { - rec->bytes_written += size; + bytes_written += size; } -static void write_output(struct perf_record *rec, void *buf, size_t size) +static void write_output(void *buf, size_t size) { while (size) { - int ret = write(rec->output, buf, size); + int ret = write(output, buf, size); if (ret < 0) die("failed to write"); @@ -73,33 +91,30 @@ static void write_output(struct perf_record *rec, void *buf, size_t size) size -= ret; buf += ret; - rec->bytes_written += ret; + bytes_written += ret; } } -static int process_synthesized_event(struct perf_tool *tool, - union perf_event *event, +static int process_synthesized_event(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine __used) + struct perf_session *self __used) { - struct perf_record *rec = container_of(tool, struct perf_record, tool); - write_output(rec, event, event->header.size); + write_output(event, event->header.size); return 0; } -static void perf_record__mmap_read(struct perf_record *rec, - struct perf_mmap *md) +static void mmap_read(struct perf_mmap *md) { unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; - unsigned char *data = md->base + rec->page_size; + unsigned char *data = md->base + page_size; unsigned long size; void *buf; if (old == head) return; - rec->samples++; + samples++; size = head - old; @@ -108,14 +123,14 @@ static void perf_record__mmap_read(struct perf_record *rec, size = md->mask + 1 - (old & md->mask); old += size; - write_output(rec, buf, size); + write_output(buf, size); } buf = &data[old & md->mask]; size = head - old; old += size; - write_output(rec, buf, size); + write_output(buf, size); md->prev = old; perf_mmap__write_tail(md, old); @@ -134,18 +149,17 @@ static void sig_handler(int sig) signr = sig; } -static void perf_record__sig_exit(int exit_status __used, void *arg) +static void sig_atexit(void) { - struct perf_record *rec = arg; int status; - if (rec->evlist->workload.pid > 0) { + if (child_pid > 0) { if (!child_finished) - kill(rec->evlist->workload.pid, SIGTERM); + kill(child_pid, SIGTERM); wait(&status); if (WIFSIGNALED(status)) - psignal(WTERMSIG(status), rec->progname); + psignal(WTERMSIG(status), progname); } if (signr == -1 || signr == SIGUSR1) @@ -155,6 +169,78 @@ static void perf_record__sig_exit(int exit_status __used, void *arg) kill(getpid(), signr); } +static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) +{ + struct perf_event_attr *attr = &evsel->attr; + int track = !evsel->idx; /* only the first counter needs these */ + + attr->disabled = 1; + attr->inherit = !no_inherit; + attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | + PERF_FORMAT_TOTAL_TIME_RUNNING | + PERF_FORMAT_ID; + + attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; + + if (evlist->nr_entries > 1) + attr->sample_type |= PERF_SAMPLE_ID; + + /* + * We default some events to a 1 default interval. But keep + * it a weak assumption overridable by the user. + */ + if (!attr->sample_period || (user_freq != UINT_MAX && + user_interval != ULLONG_MAX)) { + if (freq) { + attr->sample_type |= PERF_SAMPLE_PERIOD; + attr->freq = 1; + attr->sample_freq = freq; + } else { + attr->sample_period = default_interval; + } + } + + if (no_samples) + attr->sample_freq = 0; + + if (inherit_stat) + attr->inherit_stat = 1; + + if (sample_address) { + attr->sample_type |= PERF_SAMPLE_ADDR; + attr->mmap_data = track; + } + + if (call_graph) + attr->sample_type |= PERF_SAMPLE_CALLCHAIN; + + if (system_wide) + attr->sample_type |= PERF_SAMPLE_CPU; + + if (sample_id_all_avail && + (sample_time || system_wide || !no_inherit || cpu_list)) + attr->sample_type |= PERF_SAMPLE_TIME; + + if (raw_samples) { + attr->sample_type |= PERF_SAMPLE_TIME; + attr->sample_type |= PERF_SAMPLE_RAW; + attr->sample_type |= PERF_SAMPLE_CPU; + } + + if (nodelay) { + attr->watermark = 0; + attr->wakeup_events = 1; + } + + attr->mmap = track; + attr->comm = track; + + if (target_pid == -1 && target_tid == -1 && !system_wide) { + attr->disabled = 1; + attr->enable_on_exec = 1; + } +} + static bool perf_evlist__equal(struct perf_evlist *evlist, struct perf_evlist *other) { @@ -174,16 +260,14 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, return true; } -static void perf_record__open(struct perf_record *rec) +static void open_counters(struct perf_evlist *evlist) { struct perf_evsel *pos, *first; - struct perf_evlist *evlist = rec->evlist; - struct perf_session *session = rec->session; - struct perf_record_opts *opts = &rec->opts; - first = list_entry(evlist->entries.next, struct perf_evsel, node); + if (evlist->cpus->map[0] < 0) + no_inherit = true; - perf_evlist__config_attrs(evlist, opts); + first = list_entry(evlist->entries.next, struct perf_evsel, node); list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; @@ -202,27 +286,29 @@ static void perf_record__open(struct perf_record *rec) */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - if (opts->group && pos != first) + if (group && pos != first) group_fd = first->fd; + + config_attr(pos, evlist); retry_sample_id: - attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; + attr->sample_id_all = sample_id_all_avail ? 1 : 0; try_again: - if (perf_evsel__open(pos, evlist->cpus, evlist->threads, - opts->group, group_fd) < 0) { + if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, + group_fd) < 0) { int err = errno; if (err == EPERM || err == EACCES) { ui__error_paranoid(); exit(EXIT_FAILURE); - } else if (err == ENODEV && opts->cpu_list) { + } else if (err == ENODEV && cpu_list) { die("No such device - did you specify" " an out-of-range profile CPU?\n"); - } else if (err == EINVAL && opts->sample_id_all_avail) { + } else if (err == EINVAL && sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field */ - opts->sample_id_all_avail = false; - if (!opts->sample_time && !opts->raw_samples && !time_needed) + sample_id_all_avail = false; + if (!sample_time && !raw_samples && !time_needed) attr->sample_type &= ~PERF_SAMPLE_TIME; goto retry_sample_id; @@ -272,20 +358,10 @@ static void perf_record__open(struct perf_record *rec) exit(-1); } - if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { - if (errno == EPERM) - die("Permission error mapping pages.\n" - "Consider increasing " - "/proc/sys/kernel/perf_event_mlock_kb,\n" - "or try again with a smaller value of -m/--mmap_pages.\n" - "(current value: %d)\n", opts->mmap_pages); - else if (!is_power_of_2(opts->mmap_pages)) - die("--mmap_pages/-m value must be a power of two."); - + if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); - } - if (rec->file_new) + if (file_new) session->evlist = evlist; else { if (!perf_evlist__equal(session->evlist, evlist)) { @@ -297,32 +373,29 @@ static void perf_record__open(struct perf_record *rec) perf_session__update_sample_type(session); } -static int process_buildids(struct perf_record *rec) +static int process_buildids(void) { - u64 size = lseek(rec->output, 0, SEEK_CUR); + u64 size = lseek(output, 0, SEEK_CUR); if (size == 0) return 0; - rec->session->fd = rec->output; - return __perf_session__process_events(rec->session, rec->post_processing_offset, - size - rec->post_processing_offset, + session->fd = output; + return __perf_session__process_events(session, post_processing_offset, + size - post_processing_offset, size, &build_id__mark_dso_hit_ops); } -static void perf_record__exit(int status __used, void *arg) +static void atexit_header(void) { - struct perf_record *rec = arg; - - if (!rec->opts.pipe_output) { - rec->session->header.data_size += rec->bytes_written; - - if (!rec->no_buildid) - process_buildids(rec); - perf_session__write_header(rec->session, rec->evlist, - rec->output, true); - perf_session__delete(rec->session); - perf_evlist__delete(rec->evlist); + if (!pipe_output) { + session->header.data_size += bytes_written; + + if (!no_buildid) + process_buildids(); + perf_session__write_header(session, evsel_list, output, true); + perf_session__delete(session); + perf_evlist__delete(evsel_list); symbol__exit(); } } @@ -330,7 +403,7 @@ static void perf_record__exit(int status __used, void *arg) static void perf_event__synthesize_guest_os(struct machine *machine, void *data) { int err; - struct perf_tool *tool = data; + struct perf_session *psession = data; if (machine__is_host(machine)) return; @@ -343,8 +416,8 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) *method is used to avoid symbol missing when the first addr is *in module instead of in guest kernel. */ - err = perf_event__synthesize_modules(tool, process_synthesized_event, - machine); + err = perf_event__synthesize_modules(process_synthesized_event, + psession, machine); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" " relocation symbol.\n", machine->pid); @@ -353,11 +426,12 @@ static void perf_event__synthesize_guest_os(struct machine *machine, void *data) * We use _stext for guest kernel because guest kernel's /proc/kallsyms * have no _text sometimes. */ - err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, - machine, "_text"); + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + psession, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, - machine, "_stext"); + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + psession, machine, + "_stext"); if (err < 0) pr_err("Couldn't record guest kernel [%d]'s reference" " relocation symbol.\n", machine->pid); @@ -368,71 +442,73 @@ static struct perf_event_header finished_round_event = { .type = PERF_RECORD_FINISHED_ROUND, }; -static void perf_record__mmap_read_all(struct perf_record *rec) +static void mmap_read_all(void) { int i; - for (i = 0; i < rec->evlist->nr_mmaps; i++) { - if (rec->evlist->mmap[i].base) - perf_record__mmap_read(rec, &rec->evlist->mmap[i]); + for (i = 0; i < evsel_list->nr_mmaps; i++) { + if (evsel_list->mmap[i].base) + mmap_read(&evsel_list->mmap[i]); } - if (perf_header__has_feat(&rec->session->header, HEADER_TRACE_INFO)) - write_output(rec, &finished_round_event, sizeof(finished_round_event)); + if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) + write_output(&finished_round_event, sizeof(finished_round_event)); } -static int __cmd_record(struct perf_record *rec, int argc, const char **argv) +static int __cmd_record(int argc, const char **argv) { struct stat st; int flags; - int err, output; + int err; unsigned long waking = 0; + int child_ready_pipe[2], go_pipe[2]; const bool forks = argc > 0; + char buf; struct machine *machine; - struct perf_tool *tool = &rec->tool; - struct perf_record_opts *opts = &rec->opts; - struct perf_evlist *evsel_list = rec->evlist; - const char *output_name = rec->output_name; - struct perf_session *session; - rec->progname = argv[0]; + progname = argv[0]; - rec->page_size = sysconf(_SC_PAGE_SIZE); + page_size = sysconf(_SC_PAGE_SIZE); - on_exit(perf_record__sig_exit, rec); + atexit(sig_atexit); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); signal(SIGUSR1, sig_handler); + if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { + perror("failed to create pipes"); + exit(-1); + } + if (!output_name) { if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) - opts->pipe_output = true; + pipe_output = 1; else - rec->output_name = output_name = "perf.data"; + output_name = "perf.data"; } if (output_name) { if (!strcmp(output_name, "-")) - opts->pipe_output = true; + pipe_output = 1; else if (!stat(output_name, &st) && st.st_size) { - if (rec->write_mode == WRITE_FORCE) { + if (write_mode == WRITE_FORCE) { char oldname[PATH_MAX]; snprintf(oldname, sizeof(oldname), "%s.old", output_name); unlink(oldname); rename(output_name, oldname); } - } else if (rec->write_mode == WRITE_APPEND) { - rec->write_mode = WRITE_FORCE; + } else if (write_mode == WRITE_APPEND) { + write_mode = WRITE_FORCE; } } flags = O_CREAT|O_RDWR; - if (rec->write_mode == WRITE_APPEND) - rec->file_new = 0; + if (write_mode == WRITE_APPEND) + file_new = 0; else flags |= O_TRUNC; - if (opts->pipe_output) + if (pipe_output) output = STDOUT_FILENO; else output = open(output_name, flags, S_IRUSR | S_IWUSR); @@ -441,21 +517,17 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) exit(-1); } - rec->output = output; - session = perf_session__new(output_name, O_WRONLY, - rec->write_mode == WRITE_FORCE, false, NULL); + write_mode == WRITE_FORCE, false, NULL); if (session == NULL) { pr_err("Not enough memory for reading perf file header\n"); return -1; } - rec->session = session; - - if (!rec->no_buildid) + if (!no_buildid) perf_header__set_feat(&session->header, HEADER_BUILD_ID); - if (!rec->file_new) { + if (!file_new) { err = perf_session__read_header(session, output); if (err < 0) goto out_delete_session; @@ -477,57 +549,94 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) perf_header__set_feat(&session->header, HEADER_NUMA_TOPOLOGY); perf_header__set_feat(&session->header, HEADER_CPUID); + /* 512 kiB: default amount of unprivileged mlocked memory */ + if (mmap_pages == UINT_MAX) + mmap_pages = (512 * 1024) / page_size; + if (forks) { - err = perf_evlist__prepare_workload(evsel_list, opts, argv); - if (err < 0) { - pr_err("Couldn't run the workload!\n"); - goto out_delete_session; + child_pid = fork(); + if (child_pid < 0) { + perror("failed to fork"); + exit(-1); + } + + if (!child_pid) { + if (pipe_output) + dup2(2, 1); + close(child_ready_pipe[0]); + close(go_pipe[1]); + fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); + + /* + * Do a dummy execvp to get the PLT entry resolved, + * so we avoid the resolver overhead on the real + * execvp call. + */ + execvp("", (char **)argv); + + /* + * Tell the parent we're ready to go + */ + close(child_ready_pipe[1]); + + /* + * Wait until the parent tells us to go. + */ + if (read(go_pipe[0], &buf, 1) == -1) + perror("unable to read pipe"); + + execvp(argv[0], (char **)argv); + + perror(argv[0]); + kill(getppid(), SIGUSR1); + exit(-1); } + + if (!system_wide && target_tid == -1 && target_pid == -1) + evsel_list->threads->map[0] = child_pid; + + close(child_ready_pipe[1]); + close(go_pipe[0]); + /* + * wait for child to settle + */ + if (read(child_ready_pipe[0], &buf, 1) == -1) { + perror("unable to read pipe"); + exit(-1); + } + close(child_ready_pipe[0]); } - perf_record__open(rec); + open_counters(evsel_list); /* - * perf_session__delete(session) will be called at perf_record__exit() + * perf_session__delete(session) will be called at atexit_header() */ - on_exit(perf_record__exit, rec); + atexit(atexit_header); - if (opts->pipe_output) { + if (pipe_output) { err = perf_header__write_pipe(output); if (err < 0) return err; - } else if (rec->file_new) { + } else if (file_new) { err = perf_session__write_header(session, evsel_list, output, false); if (err < 0) return err; } - if (!!rec->no_buildid - && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { - pr_err("Couldn't generating buildids. " - "Use --no-buildid to profile anyway.\n"); - return -1; - } + post_processing_offset = lseek(output, 0, SEEK_CUR); - rec->post_processing_offset = lseek(output, 0, SEEK_CUR); - - machine = perf_session__find_host_machine(session); - if (!machine) { - pr_err("Couldn't find native kernel information.\n"); - return -1; - } - - if (opts->pipe_output) { - err = perf_event__synthesize_attrs(tool, session, - process_synthesized_event); + if (pipe_output) { + err = perf_session__synthesize_attrs(session, + process_synthesized_event); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); return err; } - err = perf_event__synthesize_event_types(tool, process_synthesized_event, - machine); + err = perf_event__synthesize_event_types(process_synthesized_event, + session); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); return err; @@ -542,49 +651,56 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ - err = perf_event__synthesize_tracing_data(tool, output, evsel_list, - process_synthesized_event); + err = perf_event__synthesize_tracing_data(output, evsel_list, + process_synthesized_event, + session); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); return err; } - advance_output(rec, err); + advance_output(err); } } - err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, - machine, "_text"); + machine = perf_session__find_host_machine(session); + if (!machine) { + pr_err("Couldn't find native kernel information.\n"); + return -1; + } + + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + session, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, - machine, "_stext"); + err = perf_event__synthesize_kernel_mmap(process_synthesized_event, + session, machine, "_stext"); if (err < 0) pr_err("Couldn't record kernel reference relocation symbol\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/kallsyms permission or run as root.\n"); - err = perf_event__synthesize_modules(tool, process_synthesized_event, - machine); + err = perf_event__synthesize_modules(process_synthesized_event, + session, machine); if (err < 0) pr_err("Couldn't record kernel module information.\n" "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" "Check /proc/modules permission or run as root.\n"); if (perf_guest) - perf_session__process_machines(session, tool, + perf_session__process_machines(session, perf_event__synthesize_guest_os); - if (!opts->system_wide) - perf_event__synthesize_thread_map(tool, evsel_list->threads, + if (!system_wide) + perf_event__synthesize_thread_map(evsel_list->threads, process_synthesized_event, - machine); + session); else - perf_event__synthesize_threads(tool, process_synthesized_event, - machine); + perf_event__synthesize_threads(process_synthesized_event, + session); - if (rec->realtime_prio) { + if (realtime_prio) { struct sched_param param; - param.sched_priority = rec->realtime_prio; + param.sched_priority = realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { pr_err("Could not set realtime priority.\n"); exit(-1); @@ -597,14 +713,14 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) * Let the child rip */ if (forks) - perf_evlist__start_workload(evsel_list); + close(go_pipe[1]); for (;;) { - int hits = rec->samples; + int hits = samples; - perf_record__mmap_read_all(rec); + mmap_read_all(); - if (hits == rec->samples) { + if (hits == samples) { if (done) break; err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); @@ -625,9 +741,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) */ fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n", - (double)rec->bytes_written / 1024.0 / 1024.0, + (double)bytes_written / 1024.0 / 1024.0, output_name, - rec->bytes_written / 24); + bytes_written / 24); return 0; @@ -642,89 +758,58 @@ static const char * const record_usage[] = { NULL }; -/* - * XXX Ideally would be local to cmd_record() and passed to a perf_record__new - * because we need to have access to it in perf_record__exit, that is called - * after cmd_record() exits, but since record_options need to be accessible to - * builtin-script, leave it here. - * - * At least we don't ouch it in all the other functions here directly. - * - * Just say no to tons of global variables, sigh. - */ -static struct perf_record record = { - .opts = { - .target_pid = -1, - .target_tid = -1, - .mmap_pages = UINT_MAX, - .user_freq = UINT_MAX, - .user_interval = ULLONG_MAX, - .freq = 1000, - .sample_id_all_avail = true, - }, - .write_mode = WRITE_FORCE, - .file_new = true, -}; +static bool force, append_file; -/* - * XXX Will stay a global variable till we fix builtin-script.c to stop messing - * with it and switch to use the library functions in perf_evlist that came - * from builtin-record.c, i.e. use perf_record_opts, - * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', - * using pipes, etc. - */ const struct option record_options[] = { - OPT_CALLBACK('e', "event", &record.evlist, "event", + OPT_CALLBACK('e', "event", &evsel_list, "event", "event selector. use 'perf list' to list available events", parse_events_option), - OPT_CALLBACK(0, "filter", &record.evlist, "filter", + OPT_CALLBACK(0, "filter", &evsel_list, "filter", "event filter", parse_filter), - OPT_INTEGER('p', "pid", &record.opts.target_pid, + OPT_INTEGER('p', "pid", &target_pid, "record events on existing process id"), - OPT_INTEGER('t', "tid", &record.opts.target_tid, + OPT_INTEGER('t', "tid", &target_tid, "record events on existing thread id"), - OPT_INTEGER('r', "realtime", &record.realtime_prio, + OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), - OPT_BOOLEAN('D', "no-delay", &record.opts.no_delay, + OPT_BOOLEAN('D', "no-delay", &nodelay, "collect data without buffering"), - OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, + OPT_BOOLEAN('R', "raw-samples", &raw_samples, "collect raw sample records from all opened counters"), - OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide, + OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), - OPT_BOOLEAN('A', "append", &record.append_file, + OPT_BOOLEAN('A', "append", &append_file, "append to the output file to do incremental profiling"), - OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu", + OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to monitor"), - OPT_BOOLEAN('f', "force", &record.force, + OPT_BOOLEAN('f', "force", &force, "overwrite existing data file (deprecated)"), - OPT_U64('c', "count", &record.opts.user_interval, "event period to sample"), - OPT_STRING('o', "output", &record.output_name, "file", + OPT_U64('c', "count", &user_interval, "event period to sample"), + OPT_STRING('o', "output", &output_name, "file", "output file name"), - OPT_BOOLEAN('i', "no-inherit", &record.opts.no_inherit, + OPT_BOOLEAN('i', "no-inherit", &no_inherit, "child tasks do not inherit counters"), - OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"), - OPT_UINTEGER('m', "mmap-pages", &record.opts.mmap_pages, - "number of mmap data pages"), - OPT_BOOLEAN(0, "group", &record.opts.group, + OPT_UINTEGER('F', "freq", &user_freq, "profile at this frequency"), + OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), + OPT_BOOLEAN(0, "group", &group, "put the counters into a counter group"), - OPT_BOOLEAN('g', "call-graph", &record.opts.call_graph, + OPT_BOOLEAN('g', "call-graph", &call_graph, "do call-graph (stack chain/backtrace) recording"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"), - OPT_BOOLEAN('s', "stat", &record.opts.inherit_stat, + OPT_BOOLEAN('s', "stat", &inherit_stat, "per thread counts"), - OPT_BOOLEAN('d', "data", &record.opts.sample_address, + OPT_BOOLEAN('d', "data", &sample_address, "Sample addresses"), - OPT_BOOLEAN('T', "timestamp", &record.opts.sample_time, "Sample timestamps"), - OPT_BOOLEAN('P', "period", &record.opts.period, "Sample period"), - OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, + OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"), + OPT_BOOLEAN('n', "no-samples", &no_samples, "don't sample"), - OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, + OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, "do not update the buildid cache"), - OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, + OPT_BOOLEAN('B', "no-buildid", &no_buildid, "do not collect buildids in perf.data"), - OPT_CALLBACK('G', "cgroup", &record.evlist, "name", + OPT_CALLBACK('G', "cgroup", &evsel_list, "name", "monitor event in cgroup name only", parse_cgroups), OPT_END() @@ -734,8 +819,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) { int err = -ENOMEM; struct perf_evsel *pos; - struct perf_evlist *evsel_list; - struct perf_record *rec = &record; perf_header__set_cmdline(argc, argv); @@ -743,25 +826,23 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (evsel_list == NULL) return -ENOMEM; - rec->evlist = evsel_list; - argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); - if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && - !rec->opts.system_wide && !rec->opts.cpu_list) + if (!argc && target_pid == -1 && target_tid == -1 && + !system_wide && !cpu_list) usage_with_options(record_usage, record_options); - if (rec->force && rec->append_file) { + if (force && append_file) { fprintf(stderr, "Can't overwrite and append at the same time." " You need to choose between -f and -A"); usage_with_options(record_usage, record_options); - } else if (rec->append_file) { - rec->write_mode = WRITE_APPEND; + } else if (append_file) { + write_mode = WRITE_APPEND; } else { - rec->write_mode = WRITE_FORCE; + write_mode = WRITE_FORCE; } - if (nr_cgroups && !rec->opts.system_wide) { + if (nr_cgroups && !system_wide) { fprintf(stderr, "cgroup monitoring only available in" " system-wide mode\n"); usage_with_options(record_usage, record_options); @@ -779,7 +860,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" "even with a suitable vmlinux or kallsyms file.\n\n"); - if (rec->no_buildid_cache || rec->no_buildid) + if (no_buildid_cache || no_buildid) disable_buildid_cache(); if (evsel_list->nr_entries == 0 && @@ -788,37 +869,43 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) goto out_symbol_exit; } - if (rec->opts.target_pid != -1) - rec->opts.target_tid = rec->opts.target_pid; + if (target_pid != -1) + target_tid = target_pid; - if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, - rec->opts.target_tid, rec->opts.cpu_list) < 0) + if (perf_evlist__create_maps(evsel_list, target_pid, + target_tid, cpu_list) < 0) usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { + if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, + evsel_list->threads->nr) < 0) + goto out_free_fd; if (perf_header__push_event(pos->attr.config, event_name(pos))) goto out_free_fd; } - if (rec->opts.user_interval != ULLONG_MAX) - rec->opts.default_interval = rec->opts.user_interval; - if (rec->opts.user_freq != UINT_MAX) - rec->opts.freq = rec->opts.user_freq; + if (perf_evlist__alloc_pollfd(evsel_list) < 0) + goto out_free_fd; + + if (user_interval != ULLONG_MAX) + default_interval = user_interval; + if (user_freq != UINT_MAX) + freq = user_freq; /* * User specified count overrides default frequency. */ - if (rec->opts.default_interval) - rec->opts.freq = 0; - else if (rec->opts.freq) { - rec->opts.default_interval = rec->opts.freq; + if (default_interval) + freq = 0; + else if (freq) { + default_interval = freq; } else { fprintf(stderr, "frequency and count are zero, aborting\n"); err = -EINVAL; goto out_free_fd; } - err = __cmd_record(&record, argc, argv); + err = __cmd_record(argc, argv); out_free_fd: perf_evlist__delete_maps(evsel_list); out_symbol_exit: diff --git a/trunk/tools/perf/builtin-report.c b/trunk/tools/perf/builtin-report.c index 25d34d483e49..4d7c8340c326 100644 --- a/trunk/tools/perf/builtin-report.c +++ b/trunk/tools/perf/builtin-report.c @@ -25,7 +25,6 @@ #include "util/evsel.h" #include "util/header.h" #include "util/session.h" -#include "util/tool.h" #include "util/parse-options.h" #include "util/parse-events.h" @@ -36,35 +35,38 @@ #include -struct perf_report { - struct perf_tool tool; - struct perf_session *session; - char const *input_name; - bool force, use_tui, use_stdio; - bool hide_unresolved; - bool dont_use_callchains; - bool show_full_info; - bool show_threads; - bool inverted_callchain; - struct perf_read_values show_threads_values; - const char *pretty_printing_style; - symbol_filter_t annotate_init; - const char *cpu_list; - DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -}; +static char const *input_name = "perf.data"; + +static bool force, use_tui, use_stdio; +static bool hide_unresolved; +static bool dont_use_callchains; +static bool show_full_info; + +static bool show_threads; +static struct perf_read_values show_threads_values; + +static const char default_pretty_printing_style[] = "normal"; +static const char *pretty_printing_style = default_pretty_printing_style; + +static char callchain_default_opt[] = "fractal,0.5,callee"; +static bool inverted_callchain; +static symbol_filter_t annotate_init; + +static const char *cpu_list; +static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); -static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, - struct addr_location *al, - struct perf_sample *sample, - struct machine *machine) +static int perf_session__add_hist_entry(struct perf_session *session, + struct addr_location *al, + struct perf_sample *sample, + struct perf_evsel *evsel) { struct symbol *parent = NULL; int err = 0; struct hist_entry *he; if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = machine__resolve_callchain(machine, evsel, al->thread, - sample->callchain, &parent); + err = perf_session__resolve_callchain(session, al->thread, + sample->callchain, &parent); if (err) return err; } @@ -74,8 +76,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, return -ENOMEM; if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, - &evsel->hists.callchain_cursor, + err = callchain_append(he->callchain, &session->callchain_cursor, sample->period); if (err) return err; @@ -91,7 +92,8 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, assert(evsel != NULL); err = -ENOMEM; - if (notes->src == NULL && symbol__alloc_hist(he->ms.sym) < 0) + if (notes->src == NULL && + symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0) goto out; err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); @@ -104,32 +106,30 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, } -static int process_sample_event(struct perf_tool *tool, - union perf_event *event, +static int process_sample_event(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine) + struct perf_session *session) { - struct perf_report *rep = container_of(tool, struct perf_report, tool); struct addr_location al; - if (perf_event__preprocess_sample(event, machine, &al, sample, - rep->annotate_init) < 0) { + if (perf_event__preprocess_sample(event, session, &al, sample, + annotate_init) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", event->header.type); return -1; } - if (al.filtered || (rep->hide_unresolved && al.sym == NULL)) + if (al.filtered || (hide_unresolved && al.sym == NULL)) return 0; - if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap)) + if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) return 0; if (al.map != NULL) al.map->dso->hit = 1; - if (perf_evsel__add_hist_entry(evsel, &al, sample, machine)) { + if (perf_session__add_hist_entry(session, &al, sample, evsel)) { pr_debug("problem incrementing symbol period, skipping event\n"); return -1; } @@ -137,17 +137,15 @@ static int process_sample_event(struct perf_tool *tool, return 0; } -static int process_read_event(struct perf_tool *tool, - union perf_event *event, +static int process_read_event(union perf_event *event, struct perf_sample *sample __used, - struct perf_evsel *evsel, - struct machine *machine __used) + struct perf_session *session) { - struct perf_report *rep = container_of(tool, struct perf_report, tool); - - if (rep->show_threads) { + struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist, + event->read.id); + if (show_threads) { const char *name = evsel ? event_name(evsel) : "unknown"; - perf_read_values_add_value(&rep->show_threads_values, + perf_read_values_add_value(&show_threads_values, event->read.pid, event->read.tid, event->read.id, name, @@ -161,10 +159,8 @@ static int process_read_event(struct perf_tool *tool, return 0; } -static int perf_report__setup_sample_type(struct perf_report *rep) +static int perf_session__setup_sample_type(struct perf_session *self) { - struct perf_session *self = rep->session; - if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { if (sort__has_parent) { ui__warning("Selected --sort parent, but no " @@ -177,8 +173,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep) "you call 'perf record' without -g?\n"); return -1; } - } else if (!rep->dont_use_callchains && - callchain_param.mode != CHAIN_NONE && + } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { symbol_conf.use_callchain = true; if (callchain_register_param(&callchain_param) < 0) { @@ -191,6 +186,22 @@ static int perf_report__setup_sample_type(struct perf_report *rep) return 0; } +static struct perf_event_ops event_ops = { + .sample = process_sample_event, + .mmap = perf_event__process_mmap, + .comm = perf_event__process_comm, + .exit = perf_event__process_task, + .fork = perf_event__process_task, + .lost = perf_event__process_lost, + .read = process_read_event, + .attr = perf_event__process_attr, + .event_type = perf_event__process_event_type, + .tracing_data = perf_event__process_tracing_data, + .build_id = perf_event__process_build_id, + .ordered_samples = true, + .ordering_requires_timestamps = true, +}; + extern volatile int session_done; static void sig_handler(int sig __used) @@ -213,7 +224,6 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, } static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, - struct perf_report *rep, const char *help) { struct perf_evsel *pos; @@ -231,18 +241,18 @@ static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist, parent_pattern == default_parent_pattern) { fprintf(stdout, "#\n# (%s)\n#\n", help); - if (rep->show_threads) { - bool style = !strcmp(rep->pretty_printing_style, "raw"); - perf_read_values_display(stdout, &rep->show_threads_values, + if (show_threads) { + bool style = !strcmp(pretty_printing_style, "raw"); + perf_read_values_display(stdout, &show_threads_values, style); - perf_read_values_destroy(&rep->show_threads_values); + perf_read_values_destroy(&show_threads_values); } } return 0; } -static int __cmd_report(struct perf_report *rep) +static int __cmd_report(void) { int ret = -EINVAL; u64 nr_samples; @@ -254,31 +264,27 @@ static int __cmd_report(struct perf_report *rep) signal(SIGINT, sig_handler); - session = perf_session__new(rep->input_name, O_RDONLY, - rep->force, false, &rep->tool); + session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops); if (session == NULL) return -ENOMEM; - rep->session = session; - - if (rep->cpu_list) { - ret = perf_session__cpu_bitmap(session, rep->cpu_list, - rep->cpu_bitmap); + if (cpu_list) { + ret = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); if (ret) goto out_delete; } if (use_browser <= 0) - perf_session__fprintf_info(session, stdout, rep->show_full_info); + perf_session__fprintf_info(session, stdout, show_full_info); - if (rep->show_threads) - perf_read_values_init(&rep->show_threads_values); + if (show_threads) + perf_read_values_init(&show_threads_values); - ret = perf_report__setup_sample_type(rep); + ret = perf_session__setup_sample_type(session); if (ret) goto out_delete; - ret = perf_session__process_events(session, &rep->tool); + ret = perf_session__process_events(session, &event_ops); if (ret) goto out_delete; @@ -321,7 +327,7 @@ static int __cmd_report(struct perf_report *rep) } if (nr_samples == 0) { - ui__warning("The %s file has no samples!\n", session->filename); + ui__warning("The %s file has no samples!\n", input_name); goto out_delete; } @@ -329,7 +335,7 @@ static int __cmd_report(struct perf_report *rep) perf_evlist__tui_browse_hists(session->evlist, help, NULL, NULL, 0); } else - perf_evlist__tty_browse_hists(session->evlist, rep, help); + perf_evlist__tty_browse_hists(session->evlist, help); out_delete: /* @@ -348,9 +354,9 @@ static int __cmd_report(struct perf_report *rep) } static int -parse_callchain_opt(const struct option *opt, const char *arg, int unset) +parse_callchain_opt(const struct option *opt __used, const char *arg, + int unset) { - struct perf_report *rep = (struct perf_report *)opt->value; char *tok, *tok2; char *endptr; @@ -358,7 +364,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) * --no-call-graph */ if (unset) { - rep->dont_use_callchains = true; + dont_use_callchains = true; return 0; } @@ -406,7 +412,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) goto setup; if (tok2[0] != 'c') { - callchain_param.print_limit = strtoul(tok2, &endptr, 0); + callchain_param.print_limit = strtod(tok2, &endptr); tok2 = strtok(NULL, ","); if (!tok2) goto setup; @@ -427,34 +433,13 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) return 0; } -int cmd_report(int argc, const char **argv, const char *prefix __used) -{ - struct stat st; - char callchain_default_opt[] = "fractal,0.5,callee"; - const char * const report_usage[] = { - "perf report []", - NULL - }; - struct perf_report report = { - .tool = { - .sample = process_sample_event, - .mmap = perf_event__process_mmap, - .comm = perf_event__process_comm, - .exit = perf_event__process_task, - .fork = perf_event__process_task, - .lost = perf_event__process_lost, - .read = process_read_event, - .attr = perf_event__process_attr, - .event_type = perf_event__process_event_type, - .tracing_data = perf_event__process_tracing_data, - .build_id = perf_event__process_build_id, - .ordered_samples = true, - .ordering_requires_timestamps = true, - }, - .pretty_printing_style = "normal", - }; - const struct option options[] = { - OPT_STRING('i', "input", &report.input_name, "file", +static const char * const report_usage[] = { + "perf report [] ", + NULL +}; + +static const struct option options[] = { + OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), @@ -464,18 +449,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) "file", "vmlinux pathname"), OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", "kallsyms pathname"), - OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"), + OPT_BOOLEAN('f', "force", &force, "don't complain, do it"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, "Show a column with the number of samples"), - OPT_BOOLEAN('T', "threads", &report.show_threads, + OPT_BOOLEAN('T', "threads", &show_threads, "Show per-thread event counters"), - OPT_STRING(0, "pretty", &report.pretty_printing_style, "key", + OPT_STRING(0, "pretty", &pretty_printing_style, "key", "pretty printing style key: normal raw"), - OPT_BOOLEAN(0, "tui", &report.use_tui, "Use the TUI interface"), - OPT_BOOLEAN(0, "stdio", &report.use_stdio, - "Use the stdio interface"), + OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), + OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, @@ -484,14 +468,13 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) "regex filter to identify parent, see: '--sort parent'"), OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, "Only display entries with parent-match"), - OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order", - "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit and callchain order. " + OPT_CALLBACK_DEFAULT('g', "call-graph", NULL, "output_type,min_percent, call_order", + "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold and callchain order. " "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), - OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, - "alias for inverted call graph"), + OPT_BOOLEAN('G', "inverted", &inverted_callchain, "alias for inverted call graph"), OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", "only consider symbols in these dsos"), - OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", + OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", "only consider symbols in these comms"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", "only consider these symbols"), @@ -501,13 +484,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", "separator for columns, no spaces will be added between " "columns '.' is reserved."), - OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved, + OPT_BOOLEAN('U', "hide-unresolved", &hide_unresolved, "Only display entries resolved to a symbol"), OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", "Look for files with symbols relative to this directory"), - OPT_STRING('C', "cpu", &report.cpu_list, "cpu", - "list of cpus to profile"), - OPT_BOOLEAN('I', "show-info", &report.show_full_info, + OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), + OPT_BOOLEAN('I', "show-info", &show_full_info, "Display extended information about perf.data file"), OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, "Interleave source code with assembly code (default)"), @@ -518,30 +500,24 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), OPT_END() - }; +}; +int cmd_report(int argc, const char **argv, const char *prefix __used) +{ argc = parse_options(argc, argv, options, report_usage, 0); - if (report.use_stdio) + if (use_stdio) use_browser = 0; - else if (report.use_tui) + else if (use_tui) use_browser = 1; - if (report.inverted_callchain) + if (inverted_callchain) callchain_param.order = ORDER_CALLER; - if (!report.input_name || !strlen(report.input_name)) { - if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) - report.input_name = "-"; - else - report.input_name = "perf.data"; - } - - if (strcmp(report.input_name, "-") != 0) + if (strcmp(input_name, "-") != 0) setup_browser(true); else use_browser = 0; - /* * Only in the newt browser we are doing integrated annotation, * so don't allocate extra space that won't be used in the stdio @@ -549,7 +525,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) */ if (use_browser > 0) { symbol_conf.priv_size = sizeof(struct annotation); - report.annotate_init = symbol__annotate_init; + annotate_init = symbol__annotate_init; /* * For searching by name on the "Browse map details". * providing it only in verbose mode not to bloat too @@ -596,5 +572,5 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout); sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout); - return __cmd_report(&report); + return __cmd_report(); } diff --git a/trunk/tools/perf/builtin-sched.c b/trunk/tools/perf/builtin-sched.c index fb8b5f83b4a0..5177964943e7 100644 --- a/trunk/tools/perf/builtin-sched.c +++ b/trunk/tools/perf/builtin-sched.c @@ -2,14 +2,11 @@ #include "perf.h" #include "util/util.h" -#include "util/evlist.h" #include "util/cache.h" -#include "util/evsel.h" #include "util/symbol.h" #include "util/thread.h" #include "util/header.h" #include "util/session.h" -#include "util/tool.h" #include "util/parse-options.h" #include "util/trace-event.h" @@ -22,7 +19,7 @@ #include #include -static const char *input_name; +static char const *input_name = "perf.data"; static char default_sort_order[] = "avg, max, switch, runtime"; static const char *sort_order = default_sort_order; @@ -726,21 +723,21 @@ struct trace_migrate_task_event { struct trace_sched_handler { void (*switch_event)(struct trace_switch_event *, - struct machine *, + struct perf_session *, struct event *, int cpu, u64 timestamp, struct thread *thread); void (*runtime_event)(struct trace_runtime_event *, - struct machine *, + struct perf_session *, struct event *, int cpu, u64 timestamp, struct thread *thread); void (*wakeup_event)(struct trace_wakeup_event *, - struct machine *, + struct perf_session *, struct event *, int cpu, u64 timestamp, @@ -753,7 +750,7 @@ struct trace_sched_handler { struct thread *thread); void (*migrate_task_event)(struct trace_migrate_task_event *, - struct machine *machine, + struct perf_session *session, struct event *, int cpu, u64 timestamp, @@ -763,7 +760,7 @@ struct trace_sched_handler { static void replay_wakeup_event(struct trace_wakeup_event *wakeup_event, - struct machine *machine __used, + struct perf_session *session __used, struct event *event, int cpu __used, u64 timestamp __used, @@ -790,7 +787,7 @@ static u64 cpu_last_switched[MAX_CPUS]; static void replay_switch_event(struct trace_switch_event *switch_event, - struct machine *machine __used, + struct perf_session *session __used, struct event *event, int cpu, u64 timestamp, @@ -1024,7 +1021,7 @@ add_sched_in_event(struct work_atoms *atoms, u64 timestamp) static void latency_switch_event(struct trace_switch_event *switch_event, - struct machine *machine, + struct perf_session *session, struct event *event __used, int cpu, u64 timestamp, @@ -1048,8 +1045,8 @@ latency_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %" PRIu64 " < 0 ?\n", delta); - sched_out = machine__findnew_thread(machine, switch_event->prev_pid); - sched_in = machine__findnew_thread(machine, switch_event->next_pid); + sched_out = perf_session__findnew(session, switch_event->prev_pid); + sched_in = perf_session__findnew(session, switch_event->next_pid); out_events = thread_atoms_search(&atom_root, sched_out, &cmp_pid); if (!out_events) { @@ -1077,13 +1074,13 @@ latency_switch_event(struct trace_switch_event *switch_event, static void latency_runtime_event(struct trace_runtime_event *runtime_event, - struct machine *machine, + struct perf_session *session, struct event *event __used, int cpu, u64 timestamp, struct thread *this_thread __used) { - struct thread *thread = machine__findnew_thread(machine, runtime_event->pid); + struct thread *thread = perf_session__findnew(session, runtime_event->pid); struct work_atoms *atoms = thread_atoms_search(&atom_root, thread, &cmp_pid); BUG_ON(cpu >= MAX_CPUS || cpu < 0); @@ -1100,7 +1097,7 @@ latency_runtime_event(struct trace_runtime_event *runtime_event, static void latency_wakeup_event(struct trace_wakeup_event *wakeup_event, - struct machine *machine, + struct perf_session *session, struct event *__event __used, int cpu __used, u64 timestamp, @@ -1114,7 +1111,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, if (!wakeup_event->success) return; - wakee = machine__findnew_thread(machine, wakeup_event->pid); + wakee = perf_session__findnew(session, wakeup_event->pid); atoms = thread_atoms_search(&atom_root, wakee, &cmp_pid); if (!atoms) { thread_atoms_insert(wakee); @@ -1148,7 +1145,7 @@ latency_wakeup_event(struct trace_wakeup_event *wakeup_event, static void latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, - struct machine *machine, + struct perf_session *session, struct event *__event __used, int cpu __used, u64 timestamp, @@ -1164,7 +1161,7 @@ latency_migrate_task_event(struct trace_migrate_task_event *migrate_task_event, if (profile_cpu == -1) return; - migrant = machine__findnew_thread(machine, migrate_task_event->pid); + migrant = perf_session__findnew(session, migrate_task_event->pid); atoms = thread_atoms_search(&atom_root, migrant, &cmp_pid); if (!atoms) { thread_atoms_insert(migrant); @@ -1359,13 +1356,12 @@ static void sort_lat(void) static struct trace_sched_handler *trace_handler; static void -process_sched_wakeup_event(struct perf_tool *tool __used, +process_sched_wakeup_event(void *data, struct perf_session *session, struct event *event, - struct perf_sample *sample, - struct machine *machine, - struct thread *thread) + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) { - void *data = sample->raw_data; struct trace_wakeup_event wakeup_event; FILL_COMMON_FIELDS(wakeup_event, event, data); @@ -1377,8 +1373,8 @@ process_sched_wakeup_event(struct perf_tool *tool __used, FILL_FIELD(wakeup_event, cpu, event, data); if (trace_handler->wakeup_event) - trace_handler->wakeup_event(&wakeup_event, machine, event, - sample->cpu, sample->time, thread); + trace_handler->wakeup_event(&wakeup_event, session, event, + cpu, timestamp, thread); } /* @@ -1396,7 +1392,7 @@ static char next_shortname2 = '0'; static void map_switch_event(struct trace_switch_event *switch_event, - struct machine *machine, + struct perf_session *session, struct event *event __used, int this_cpu, u64 timestamp, @@ -1424,8 +1420,8 @@ map_switch_event(struct trace_switch_event *switch_event, die("hm, delta: %" PRIu64 " < 0 ?\n", delta); - sched_out = machine__findnew_thread(machine, switch_event->prev_pid); - sched_in = machine__findnew_thread(machine, switch_event->next_pid); + sched_out = perf_session__findnew(session, switch_event->prev_pid); + sched_in = perf_session__findnew(session, switch_event->next_pid); curr_thread[this_cpu] = sched_in; @@ -1473,15 +1469,14 @@ map_switch_event(struct trace_switch_event *switch_event, } } + static void -process_sched_switch_event(struct perf_tool *tool __used, +process_sched_switch_event(void *data, struct perf_session *session, struct event *event, - struct perf_sample *sample, - struct machine *machine, - struct thread *thread) + int this_cpu, + u64 timestamp __used, + struct thread *thread __used) { - int this_cpu = sample->cpu; - void *data = sample->raw_data; struct trace_switch_event switch_event; FILL_COMMON_FIELDS(switch_event, event, data); @@ -1503,20 +1498,19 @@ process_sched_switch_event(struct perf_tool *tool __used, nr_context_switch_bugs++; } if (trace_handler->switch_event) - trace_handler->switch_event(&switch_event, machine, event, - this_cpu, sample->time, thread); + trace_handler->switch_event(&switch_event, session, event, + this_cpu, timestamp, thread); curr_pid[this_cpu] = switch_event.next_pid; } static void -process_sched_runtime_event(struct perf_tool *tool __used, - struct event *event, - struct perf_sample *sample, - struct machine *machine, - struct thread *thread) +process_sched_runtime_event(void *data, struct perf_session *session, + struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) { - void *data = sample->raw_data; struct trace_runtime_event runtime_event; FILL_ARRAY(runtime_event, comm, event, data); @@ -1525,18 +1519,16 @@ process_sched_runtime_event(struct perf_tool *tool __used, FILL_FIELD(runtime_event, vruntime, event, data); if (trace_handler->runtime_event) - trace_handler->runtime_event(&runtime_event, machine, event, - sample->cpu, sample->time, thread); + trace_handler->runtime_event(&runtime_event, session, event, cpu, timestamp, thread); } static void -process_sched_fork_event(struct perf_tool *tool __used, +process_sched_fork_event(void *data, struct event *event, - struct perf_sample *sample, - struct machine *machine __used, - struct thread *thread) + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) { - void *data = sample->raw_data; struct trace_fork_event fork_event; FILL_COMMON_FIELDS(fork_event, event, data); @@ -1548,14 +1540,13 @@ process_sched_fork_event(struct perf_tool *tool __used, if (trace_handler->fork_event) trace_handler->fork_event(&fork_event, event, - sample->cpu, sample->time, thread); + cpu, timestamp, thread); } static void -process_sched_exit_event(struct perf_tool *tool __used, - struct event *event, - struct perf_sample *sample __used, - struct machine *machine __used, +process_sched_exit_event(struct event *event, + int cpu __used, + u64 timestamp __used, struct thread *thread __used) { if (verbose) @@ -1563,13 +1554,12 @@ process_sched_exit_event(struct perf_tool *tool __used, } static void -process_sched_migrate_task_event(struct perf_tool *tool __used, - struct event *event, - struct perf_sample *sample, - struct machine *machine, - struct thread *thread) +process_sched_migrate_task_event(void *data, struct perf_session *session, + struct event *event, + int cpu __used, + u64 timestamp __used, + struct thread *thread __used) { - void *data = sample->raw_data; struct trace_migrate_task_event migrate_task_event; FILL_COMMON_FIELDS(migrate_task_event, event, data); @@ -1580,47 +1570,67 @@ process_sched_migrate_task_event(struct perf_tool *tool __used, FILL_FIELD(migrate_task_event, cpu, event, data); if (trace_handler->migrate_task_event) - trace_handler->migrate_task_event(&migrate_task_event, machine, - event, sample->cpu, - sample->time, thread); + trace_handler->migrate_task_event(&migrate_task_event, session, + event, cpu, timestamp, thread); } -typedef void (*tracepoint_handler)(struct perf_tool *tool, struct event *event, - struct perf_sample *sample, - struct machine *machine, - struct thread *thread); +static void process_raw_event(union perf_event *raw_event __used, + struct perf_session *session, void *data, int cpu, + u64 timestamp, struct thread *thread) +{ + struct event *event; + int type; + + + type = trace_parse_common_type(data); + event = trace_find_event(type); + + if (!strcmp(event->name, "sched_switch")) + process_sched_switch_event(data, session, event, cpu, timestamp, thread); + if (!strcmp(event->name, "sched_stat_runtime")) + process_sched_runtime_event(data, session, event, cpu, timestamp, thread); + if (!strcmp(event->name, "sched_wakeup")) + process_sched_wakeup_event(data, session, event, cpu, timestamp, thread); + if (!strcmp(event->name, "sched_wakeup_new")) + process_sched_wakeup_event(data, session, event, cpu, timestamp, thread); + if (!strcmp(event->name, "sched_process_fork")) + process_sched_fork_event(data, event, cpu, timestamp, thread); + if (!strcmp(event->name, "sched_process_exit")) + process_sched_exit_event(event, cpu, timestamp, thread); + if (!strcmp(event->name, "sched_migrate_task")) + process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); +} -static int perf_sched__process_tracepoint_sample(struct perf_tool *tool, - union perf_event *event __used, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine) +static int process_sample_event(union perf_event *event, + struct perf_sample *sample, + struct perf_evsel *evsel __used, + struct perf_session *session) { - struct thread *thread = machine__findnew_thread(machine, sample->pid); + struct thread *thread; + + if (!(session->sample_type & PERF_SAMPLE_RAW)) + return 0; + thread = perf_session__findnew(session, sample->pid); if (thread == NULL) { - pr_debug("problem processing %s event, skipping it.\n", - evsel->name); + pr_debug("problem processing %d event, skipping it.\n", + event->header.type); return -1; } - evsel->hists.stats.total_period += sample->period; - hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); + dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); - if (evsel->handler.func != NULL) { - tracepoint_handler f = evsel->handler.func; + if (profile_cpu != -1 && profile_cpu != (int)sample->cpu) + return 0; - if (evsel->handler.data == NULL) - evsel->handler.data = trace_find_event(evsel->attr.config); - - f(tool, evsel->handler.data, sample, machine, thread); - } + process_raw_event(event, session, sample->raw_data, sample->cpu, + sample->time, thread); return 0; } -static struct perf_tool perf_sched = { - .sample = perf_sched__process_tracepoint_sample, +static struct perf_event_ops event_ops = { + .sample = process_sample_event, .comm = perf_event__process_comm, .lost = perf_event__process_lost, .fork = perf_event__process_task, @@ -1630,25 +1640,13 @@ static struct perf_tool perf_sched = { static void read_events(bool destroy, struct perf_session **psession) { int err = -EINVAL; - const struct perf_evsel_str_handler handlers[] = { - { "sched:sched_switch", process_sched_switch_event, }, - { "sched:sched_stat_runtime", process_sched_runtime_event, }, - { "sched:sched_wakeup", process_sched_wakeup_event, }, - { "sched:sched_wakeup_new", process_sched_wakeup_event, }, - { "sched:sched_process_fork", process_sched_fork_event, }, - { "sched:sched_process_exit", process_sched_exit_event, }, - { "sched:sched_migrate_task", process_sched_migrate_task_event, }, - }; struct perf_session *session = perf_session__new(input_name, O_RDONLY, - 0, false, &perf_sched); + 0, false, &event_ops); if (session == NULL) die("No Memory"); - err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers); - assert(err == 0); - if (perf_session__has_traces(session, "record -R")) { - err = perf_session__process_events(session, &perf_sched); + err = perf_session__process_events(session, &event_ops); if (err) die("Failed to process events, error %d", err); diff --git a/trunk/tools/perf/builtin-script.c b/trunk/tools/perf/builtin-script.c index fd1909afcfd6..2f62a2952269 100644 --- a/trunk/tools/perf/builtin-script.c +++ b/trunk/tools/perf/builtin-script.c @@ -7,7 +7,6 @@ #include "util/header.h" #include "util/parse-options.h" #include "util/session.h" -#include "util/tool.h" #include "util/symbol.h" #include "util/thread.h" #include "util/trace-event.h" @@ -24,7 +23,6 @@ static u64 nr_unordered; extern const struct option record_options[]; static bool no_callchain; static bool show_full_info; -static bool system_wide; static const char *cpu_list; static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); @@ -317,7 +315,7 @@ static bool sample_addr_correlates_sym(struct perf_event_attr *attr) static void print_sample_addr(union perf_event *event, struct perf_sample *sample, - struct machine *machine, + struct perf_session *session, struct thread *thread, struct perf_event_attr *attr) { @@ -330,11 +328,11 @@ static void print_sample_addr(union perf_event *event, if (!sample_addr_correlates_sym(attr)) return; - thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, - sample->addr, &al); + thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, + event->ip.pid, sample->addr, &al); if (!al.map) - thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE, - sample->addr, &al); + thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE, + event->ip.pid, sample->addr, &al); al.cpu = sample->cpu; al.sym = NULL; @@ -364,7 +362,7 @@ static void print_sample_addr(union perf_event *event, static void process_event(union perf_event *event __unused, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine, + struct perf_session *session, struct thread *thread) { struct perf_event_attr *attr = &evsel->attr; @@ -379,15 +377,15 @@ static void process_event(union perf_event *event __unused, sample->raw_size); if (PRINT_FIELD(ADDR)) - print_sample_addr(event, sample, machine, thread, attr); + print_sample_addr(event, sample, session, thread, attr); if (PRINT_FIELD(IP)) { if (!symbol_conf.use_callchain) printf(" "); else printf("\n"); - perf_event__print_ip(event, sample, machine, evsel, - PRINT_FIELD(SYM), PRINT_FIELD(DSO)); + perf_session__print_ip(event, sample, session, + PRINT_FIELD(SYM), PRINT_FIELD(DSO)); } printf("\n"); @@ -434,16 +432,14 @@ static int cleanup_scripting(void) return scripting_ops->stop_script(); } -static const char *input_name; +static char const *input_name = "perf.data"; -static int process_sample_event(struct perf_tool *tool __used, - union perf_event *event, +static int process_sample_event(union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine) + struct perf_session *session) { - struct addr_location al; - struct thread *thread = machine__findnew_thread(machine, event->ip.tid); + struct thread *thread = perf_session__findnew(session, event->ip.pid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", @@ -462,25 +458,16 @@ static int process_sample_event(struct perf_tool *tool __used, return 0; } - if (perf_event__preprocess_sample(event, machine, &al, sample, 0) < 0) { - pr_err("problem processing %d event, skipping it.\n", - event->header.type); - return -1; - } - - if (al.filtered) - return 0; - if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) return 0; - scripting_ops->process_event(event, sample, evsel, machine, thread); + scripting_ops->process_event(event, sample, evsel, session, thread); - evsel->hists.stats.total_period += sample->period; + session->hists.stats.total_period += sample->period; return 0; } -static struct perf_tool perf_script = { +static struct perf_event_ops event_ops = { .sample = process_sample_event, .mmap = perf_event__process_mmap, .comm = perf_event__process_comm, @@ -507,7 +494,7 @@ static int __cmd_script(struct perf_session *session) signal(SIGINT, sig_handler); - ret = perf_session__process_events(session, &perf_script); + ret = perf_session__process_events(session, &event_ops); if (debug_mode) pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); @@ -536,6 +523,12 @@ static struct script_spec *script_spec__new(const char *spec, return s; } +static void script_spec__delete(struct script_spec *s) +{ + free(s->spec); + free(s); +} + static void script_spec__add(struct script_spec *s) { list_add_tail(&s->node, &script_specs); @@ -561,11 +554,16 @@ static struct script_spec *script_spec__findnew(const char *spec, s = script_spec__new(spec, ops); if (!s) - return NULL; + goto out_delete_spec; script_spec__add(s); return s; + +out_delete_spec: + script_spec__delete(s); + + return NULL; } int script_spec_register(const char *spec, struct scripting_ops *ops) @@ -683,8 +681,7 @@ static int parse_output_fields(const struct option *opt __used, type = PERF_TYPE_RAW; else { fprintf(stderr, "Invalid event type in field string.\n"); - rc = -EINVAL; - goto out; + return -EINVAL; } if (output[type].user_set) @@ -926,24 +923,6 @@ static int read_script_info(struct script_desc *desc, const char *filename) return 0; } -static char *get_script_root(struct dirent *script_dirent, const char *suffix) -{ - char *script_root, *str; - - script_root = strdup(script_dirent->d_name); - if (!script_root) - return NULL; - - str = (char *)ends_with(script_root, suffix); - if (!str) { - free(script_root); - return NULL; - } - - *str = '\0'; - return script_root; -} - static int list_available_scripts(const struct option *opt __used, const char *s __used, int unset __used) { @@ -955,6 +934,7 @@ static int list_available_scripts(const struct option *opt __used, struct script_desc *desc; char first_half[BUFSIZ]; char *script_root; + char *str; snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); @@ -970,14 +950,16 @@ static int list_available_scripts(const struct option *opt __used, continue; for_each_script(lang_path, lang_dir, script_dirent, script_next) { - script_root = get_script_root(&script_dirent, REPORT_SUFFIX); - if (script_root) { + script_root = strdup(script_dirent.d_name); + str = (char *)ends_with(script_root, REPORT_SUFFIX); + if (str) { + *str = '\0'; desc = script_desc__findnew(script_root); snprintf(script_path, MAXPATHLEN, "%s/%s", lang_path, script_dirent.d_name); read_script_info(desc, script_path); - free(script_root); } + free(script_root); } } @@ -999,7 +981,8 @@ static char *get_script_path(const char *script_root, const char *suffix) char script_path[MAXPATHLEN]; DIR *scripts_dir, *lang_dir; char lang_path[MAXPATHLEN]; - char *__script_root; + char *str, *__script_root; + char *path = NULL; snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); @@ -1015,18 +998,23 @@ static char *get_script_path(const char *script_root, const char *suffix) continue; for_each_script(lang_path, lang_dir, script_dirent, script_next) { - __script_root = get_script_root(&script_dirent, suffix); - if (__script_root && !strcmp(script_root, __script_root)) { - free(__script_root); + __script_root = strdup(script_dirent.d_name); + str = (char *)ends_with(__script_root, suffix); + if (str) { + *str = '\0'; + if (strcmp(__script_root, script_root)) + continue; snprintf(script_path, MAXPATHLEN, "%s/%s", lang_path, script_dirent.d_name); - return strdup(script_path); + path = strdup(script_path); + free(__script_root); + break; } free(__script_root); } } - return NULL; + return path; } static bool is_top_script(const char *script_path) @@ -1095,11 +1083,7 @@ static const struct option options[] = { OPT_CALLBACK('f', "fields", NULL, "str", "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr", parse_output_fields), - OPT_BOOLEAN('a', "all-cpus", &system_wide, - "system-wide collection from all CPUs"), - OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), - OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", - "only display events for these comms"), + OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), OPT_BOOLEAN('I', "show-info", &show_full_info, "display extended information from perf.data file"), OPT_END() @@ -1126,6 +1110,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) struct perf_session *session; char *script_path = NULL; const char **__argv; + bool system_wide; int i, j, err; setup_scripting(); @@ -1193,17 +1178,15 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) } if (!pid) { + system_wide = true; j = 0; dup2(live_pipe[1], 1); close(live_pipe[0]); - if (is_top_script(argv[0])) { - system_wide = true; - } else if (!system_wide) { + if (!is_top_script(argv[0])) system_wide = !have_cmd(argc - rep_args, &argv[rep_args]); - } __argv = malloc((argc + 6) * sizeof(const char *)); if (!__argv) @@ -1251,11 +1234,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) script_path = rep_script_path; if (script_path) { + system_wide = false; j = 0; - if (!rec_script_path) - system_wide = false; - else if (!system_wide) + if (rec_script_path) system_wide = !have_cmd(argc - 1, &argv[1]); __argv = malloc((argc + 2) * sizeof(const char *)); @@ -1279,7 +1261,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) if (!script_name) setup_pager(); - session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script); + session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops); if (session == NULL) return -ENOMEM; @@ -1305,7 +1287,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __used) return -1; } - input = open(session->filename, O_RDONLY); /* input_name */ + input = open(input_name, O_RDONLY); if (input < 0) { perror("failed to open file"); exit(-1); diff --git a/trunk/tools/perf/builtin-stat.c b/trunk/tools/perf/builtin-stat.c index f5d2a63eba66..955930e0a5c3 100644 --- a/trunk/tools/perf/builtin-stat.c +++ b/trunk/tools/perf/builtin-stat.c @@ -578,33 +578,6 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) avg / avg_stats(&walltime_nsecs_stats)); } -/* used for get_ratio_color() */ -enum grc_type { - GRC_STALLED_CYCLES_FE, - GRC_STALLED_CYCLES_BE, - GRC_CACHE_MISSES, - GRC_MAX_NR -}; - -static const char *get_ratio_color(enum grc_type type, double ratio) -{ - static const double grc_table[GRC_MAX_NR][3] = { - [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 }, - [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 }, - [GRC_CACHE_MISSES] = { 20.0, 10.0, 5.0 }, - }; - const char *color = PERF_COLOR_NORMAL; - - if (ratio > grc_table[type][0]) - color = PERF_COLOR_RED; - else if (ratio > grc_table[type][1]) - color = PERF_COLOR_MAGENTA; - else if (ratio > grc_table[type][2]) - color = PERF_COLOR_YELLOW; - - return color; -} - static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg) { double total, ratio = 0.0; @@ -615,7 +588,13 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 50.0) + color = PERF_COLOR_RED; + else if (ratio > 30.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 10.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -632,7 +611,13 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 75.0) + color = PERF_COLOR_RED; + else if (ratio > 50.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 20.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -649,7 +634,13 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_CACHE_MISSES, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -666,7 +657,13 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_CACHE_MISSES, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -683,7 +680,13 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_CACHE_MISSES, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -700,7 +703,13 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_CACHE_MISSES, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -717,7 +726,13 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_CACHE_MISSES, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -734,7 +749,13 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub if (total) ratio = avg / total * 100.0; - color = get_ratio_color(GRC_CACHE_MISSES, ratio); + color = PERF_COLOR_NORMAL; + if (ratio > 20.0) + color = PERF_COLOR_RED; + else if (ratio > 10.0) + color = PERF_COLOR_MAGENTA; + else if (ratio > 5.0) + color = PERF_COLOR_YELLOW; fprintf(output, " # "); color_fprintf(output, color, "%6.2f%%", ratio); @@ -1087,13 +1108,22 @@ static const struct option options[] = { */ static int add_default_attributes(void) { + struct perf_evsel *pos; + size_t attr_nr = 0; + size_t c; + /* Set attrs if no event is selected and !null_run: */ if (null_run) return 0; if (!evsel_list->nr_entries) { - if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0) - return -1; + for (c = 0; c < ARRAY_SIZE(default_attrs); c++) { + pos = perf_evsel__new(default_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } + attr_nr += c; } /* Detailed events get appended to the event list: */ @@ -1102,21 +1132,38 @@ static int add_default_attributes(void) return 0; /* Append detailed run extra attributes: */ - if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0) - return -1; + for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) { + pos = perf_evsel__new(detailed_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } + attr_nr += c; if (detailed_run < 2) return 0; /* Append very detailed run extra attributes: */ - if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0) - return -1; + for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) { + pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } if (detailed_run < 3) return 0; /* Append very, very detailed run extra attributes: */ - return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs); + for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) { + pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr); + if (pos == NULL) + return -1; + perf_evlist__add(evsel_list, pos); + } + + + return 0; } int cmd_stat(int argc, const char **argv, const char *prefix __used) @@ -1220,7 +1267,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) list_for_each_entry(pos, &evsel_list->entries, node) { if (perf_evsel__alloc_stat_priv(pos) < 0 || - perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0) + perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 || + perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0) goto out_free_fd; } diff --git a/trunk/tools/perf/builtin-test.c b/trunk/tools/perf/builtin-test.c index 2b9a7f497a20..831d1baeac37 100644 --- a/trunk/tools/perf/builtin-test.c +++ b/trunk/tools/perf/builtin-test.c @@ -7,7 +7,6 @@ #include "util/cache.h" #include "util/debug.h" -#include "util/debugfs.h" #include "util/evlist.h" #include "util/parse-options.h" #include "util/parse-events.h" @@ -15,6 +14,8 @@ #include "util/thread_map.h" #include "../../include/linux/hw_breakpoint.h" +static long page_size; + static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) { bool *visited = symbol__priv(sym); @@ -30,7 +31,6 @@ static int test__vmlinux_matches_kallsyms(void) struct map *kallsyms_map, *vmlinux_map; struct machine kallsyms, vmlinux; enum map_type type = MAP__FUNCTION; - long page_size = sysconf(_SC_PAGE_SIZE); struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", }; /* @@ -247,7 +247,7 @@ static int trace_event__id(const char *evname) if (asprintf(&filename, "%s/syscalls/%s/id", - tracing_events_path, evname) < 0) + debugfs_path, evname) < 0) return -1; fd = open(filename, O_RDONLY); @@ -603,7 +603,7 @@ static int test__basic_mmap(void) #define TEST_ASSERT_VAL(text, cond) \ do { \ - if (!(cond)) { \ + if (!cond) { \ pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ return -1; \ } \ @@ -759,103 +759,6 @@ static int test__checkevent_breakpoint_w(struct perf_evlist *evlist) return 0; } -static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_tracepoint(evlist); -} - -static int -test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1); - - list_for_each_entry(evsel, &evlist->entries, node) { - TEST_ASSERT_VAL("wrong exclude_user", - !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", - evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - } - - return test__checkevent_tracepoint_multi(evlist); -} - -static int test__checkevent_raw_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_raw(evlist); -} - -static int test__checkevent_numeric_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_numeric(evlist); -} - -static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_symbolic_name(evlist); -} - -static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); - - return test__checkevent_symbolic_alias(evlist); -} - -static int test__checkevent_genhw_modifier(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel = list_entry(evlist->entries.next, - struct perf_evsel, node); - - TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user); - TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel); - TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); - TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); - - return test__checkevent_genhw(evlist); -} - static struct test__event_st { const char *name; __u32 type; @@ -905,34 +808,6 @@ static struct test__event_st { .name = "mem:0:w", .check = test__checkevent_breakpoint_w, }, - { - .name = "syscalls:sys_enter_open:k", - .check = test__checkevent_tracepoint_modifier, - }, - { - .name = "syscalls:*:u", - .check = test__checkevent_tracepoint_multi_modifier, - }, - { - .name = "r1:kp", - .check = test__checkevent_raw_modifier, - }, - { - .name = "1:1:hp", - .check = test__checkevent_numeric_modifier, - }, - { - .name = "instructions:h", - .check = test__checkevent_symbolic_name_modifier, - }, - { - .name = "faults:u", - .check = test__checkevent_symbolic_alias_modifier, - }, - { - .name = "L1-dcache-load-miss:kp", - .check = test__checkevent_genhw_modifier, - }, }; #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) @@ -966,336 +841,6 @@ static int test__parse_events(void) return ret; } - -static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, - size_t *sizep) -{ - cpu_set_t *mask; - size_t size; - int i, cpu = -1, nrcpus = 1024; -realloc: - mask = CPU_ALLOC(nrcpus); - size = CPU_ALLOC_SIZE(nrcpus); - CPU_ZERO_S(size, mask); - - if (sched_getaffinity(pid, size, mask) == -1) { - CPU_FREE(mask); - if (errno == EINVAL && nrcpus < (1024 << 8)) { - nrcpus = nrcpus << 2; - goto realloc; - } - perror("sched_getaffinity"); - return -1; - } - - for (i = 0; i < nrcpus; i++) { - if (CPU_ISSET_S(i, size, mask)) { - if (cpu == -1) { - cpu = i; - *maskp = mask; - *sizep = size; - } else - CPU_CLR_S(i, size, mask); - } - } - - if (cpu == -1) - CPU_FREE(mask); - - return cpu; -} - -static int test__PERF_RECORD(void) -{ - struct perf_record_opts opts = { - .target_pid = -1, - .target_tid = -1, - .no_delay = true, - .freq = 10, - .mmap_pages = 256, - .sample_id_all_avail = true, - }; - cpu_set_t *cpu_mask = NULL; - size_t cpu_mask_size = 0; - struct perf_evlist *evlist = perf_evlist__new(NULL, NULL); - struct perf_evsel *evsel; - struct perf_sample sample; - const char *cmd = "sleep"; - const char *argv[] = { cmd, "1", NULL, }; - char *bname; - u64 sample_type, prev_time = 0; - bool found_cmd_mmap = false, - found_libc_mmap = false, - found_vdso_mmap = false, - found_ld_mmap = false; - int err = -1, errs = 0, i, wakeups = 0, sample_size; - u32 cpu; - int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, }; - - if (evlist == NULL || argv == NULL) { - pr_debug("Not enough memory to create evlist\n"); - goto out; - } - - /* - * We need at least one evsel in the evlist, use the default - * one: "cycles". - */ - err = perf_evlist__add_default(evlist); - if (err < 0) { - pr_debug("Not enough memory to create evsel\n"); - goto out_delete_evlist; - } - - /* - * Create maps of threads and cpus to monitor. In this case - * we start with all threads and cpus (-1, -1) but then in - * perf_evlist__prepare_workload we'll fill in the only thread - * we're monitoring, the one forked there. - */ - err = perf_evlist__create_maps(evlist, opts.target_pid, - opts.target_tid, opts.cpu_list); - if (err < 0) { - pr_debug("Not enough memory to create thread/cpu maps\n"); - goto out_delete_evlist; - } - - /* - * Prepare the workload in argv[] to run, it'll fork it, and then wait - * for perf_evlist__start_workload() to exec it. This is done this way - * so that we have time to open the evlist (calling sys_perf_event_open - * on all the fds) and then mmap them. - */ - err = perf_evlist__prepare_workload(evlist, &opts, argv); - if (err < 0) { - pr_debug("Couldn't run the workload!\n"); - goto out_delete_evlist; - } - - /* - * Config the evsels, setting attr->comm on the first one, etc. - */ - evsel = list_entry(evlist->entries.next, struct perf_evsel, node); - evsel->attr.sample_type |= PERF_SAMPLE_CPU; - evsel->attr.sample_type |= PERF_SAMPLE_TID; - evsel->attr.sample_type |= PERF_SAMPLE_TIME; - perf_evlist__config_attrs(evlist, &opts); - - err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask, - &cpu_mask_size); - if (err < 0) { - pr_debug("sched__get_first_possible_cpu: %s\n", strerror(errno)); - goto out_delete_evlist; - } - - cpu = err; - - /* - * So that we can check perf_sample.cpu on all the samples. - */ - if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, cpu_mask) < 0) { - pr_debug("sched_setaffinity: %s\n", strerror(errno)); - goto out_free_cpu_mask; - } - - /* - * Call sys_perf_event_open on all the fds on all the evsels, - * grouping them if asked to. - */ - err = perf_evlist__open(evlist, opts.group); - if (err < 0) { - pr_debug("perf_evlist__open: %s\n", strerror(errno)); - goto out_delete_evlist; - } - - /* - * mmap the first fd on a given CPU and ask for events for the other - * fds in the same CPU to be injected in the same mmap ring buffer - * (using ioctl(PERF_EVENT_IOC_SET_OUTPUT)). - */ - err = perf_evlist__mmap(evlist, opts.mmap_pages, false); - if (err < 0) { - pr_debug("perf_evlist__mmap: %s\n", strerror(errno)); - goto out_delete_evlist; - } - - /* - * We'll need these two to parse the PERF_SAMPLE_* fields in each - * event. - */ - sample_type = perf_evlist__sample_type(evlist); - sample_size = __perf_evsel__sample_size(sample_type); - - /* - * Now that all is properly set up, enable the events, they will - * count just on workload.pid, which will start... - */ - perf_evlist__enable(evlist); - - /* - * Now! - */ - perf_evlist__start_workload(evlist); - - while (1) { - int before = total_events; - - for (i = 0; i < evlist->nr_mmaps; i++) { - union perf_event *event; - - while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) { - const u32 type = event->header.type; - const char *name = perf_event__name(type); - - ++total_events; - if (type < PERF_RECORD_MAX) - nr_events[type]++; - - err = perf_event__parse_sample(event, sample_type, - sample_size, true, - &sample, false); - if (err < 0) { - if (verbose) - perf_event__fprintf(event, stderr); - pr_debug("Couldn't parse sample\n"); - goto out_err; - } - - if (verbose) { - pr_info("%" PRIu64" %d ", sample.time, sample.cpu); - perf_event__fprintf(event, stderr); - } - - if (prev_time > sample.time) { - pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n", - name, prev_time, sample.time); - ++errs; - } - - prev_time = sample.time; - - if (sample.cpu != cpu) { - pr_debug("%s with unexpected cpu, expected %d, got %d\n", - name, cpu, sample.cpu); - ++errs; - } - - if ((pid_t)sample.pid != evlist->workload.pid) { - pr_debug("%s with unexpected pid, expected %d, got %d\n", - name, evlist->workload.pid, sample.pid); - ++errs; - } - - if ((pid_t)sample.tid != evlist->workload.pid) { - pr_debug("%s with unexpected tid, expected %d, got %d\n", - name, evlist->workload.pid, sample.tid); - ++errs; - } - - if ((type == PERF_RECORD_COMM || - type == PERF_RECORD_MMAP || - type == PERF_RECORD_FORK || - type == PERF_RECORD_EXIT) && - (pid_t)event->comm.pid != evlist->workload.pid) { - pr_debug("%s with unexpected pid/tid\n", name); - ++errs; - } - - if ((type == PERF_RECORD_COMM || - type == PERF_RECORD_MMAP) && - event->comm.pid != event->comm.tid) { - pr_debug("%s with different pid/tid!\n", name); - ++errs; - } - - switch (type) { - case PERF_RECORD_COMM: - if (strcmp(event->comm.comm, cmd)) { - pr_debug("%s with unexpected comm!\n", name); - ++errs; - } - break; - case PERF_RECORD_EXIT: - goto found_exit; - case PERF_RECORD_MMAP: - bname = strrchr(event->mmap.filename, '/'); - if (bname != NULL) { - if (!found_cmd_mmap) - found_cmd_mmap = !strcmp(bname + 1, cmd); - if (!found_libc_mmap) - found_libc_mmap = !strncmp(bname + 1, "libc", 4); - if (!found_ld_mmap) - found_ld_mmap = !strncmp(bname + 1, "ld", 2); - } else if (!found_vdso_mmap) - found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]"); - break; - - case PERF_RECORD_SAMPLE: - /* Just ignore samples for now */ - break; - default: - pr_debug("Unexpected perf_event->header.type %d!\n", - type); - ++errs; - } - } - } - - /* - * We don't use poll here because at least at 3.1 times the - * PERF_RECORD_{!SAMPLE} events don't honour - * perf_event_attr.wakeup_events, just PERF_EVENT_SAMPLE does. - */ - if (total_events == before && false) - poll(evlist->pollfd, evlist->nr_fds, -1); - - sleep(1); - if (++wakeups > 5) { - pr_debug("No PERF_RECORD_EXIT event!\n"); - break; - } - } - -found_exit: - if (nr_events[PERF_RECORD_COMM] > 1) { - pr_debug("Excessive number of PERF_RECORD_COMM events!\n"); - ++errs; - } - - if (nr_events[PERF_RECORD_COMM] == 0) { - pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd); - ++errs; - } - - if (!found_cmd_mmap) { - pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd); - ++errs; - } - - if (!found_libc_mmap) { - pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc"); - ++errs; - } - - if (!found_ld_mmap) { - pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld"); - ++errs; - } - - if (!found_vdso_mmap) { - pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]"); - ++errs; - } -out_err: - perf_evlist__munmap(evlist); -out_free_cpu_mask: - CPU_FREE(cpu_mask); -out_delete_evlist: - perf_evlist__delete(evlist); -out: - return (err < 0 || errs > 0) ? -1 : 0; -} - static struct test { const char *desc; int (*func)(void); @@ -1320,90 +865,46 @@ static struct test { .desc = "parse events tests", .func = test__parse_events, }, - { - .desc = "Validate PERF_RECORD_* events & perf_sample fields", - .func = test__PERF_RECORD, - }, { .func = NULL, }, }; -static bool perf_test__matches(int curr, int argc, const char *argv[]) -{ - int i; - - if (argc == 0) - return true; - - for (i = 0; i < argc; ++i) { - char *end; - long nr = strtoul(argv[i], &end, 10); - - if (*end == '\0') { - if (nr == curr + 1) - return true; - continue; - } - - if (strstr(tests[curr].desc, argv[i])) - return true; - } - - return false; -} - -static int __cmd_test(int argc, const char *argv[]) +static int __cmd_test(void) { int i = 0; - while (tests[i].func) { - int curr = i++, err; - - if (!perf_test__matches(curr, argc, argv)) - continue; + page_size = sysconf(_SC_PAGE_SIZE); - pr_info("%2d: %s:", i, tests[curr].desc); + while (tests[i].func) { + int err; + pr_info("%2d: %s:", i + 1, tests[i].desc); pr_debug("\n--- start ---\n"); - err = tests[curr].func(); - pr_debug("---- end ----\n%s:", tests[curr].desc); + err = tests[i].func(); + pr_debug("---- end ----\n%s:", tests[i].desc); pr_info(" %s\n", err ? "FAILED!\n" : "Ok"); + ++i; } return 0; } -static int perf_test__list(int argc, const char **argv) -{ - int i = 0; - - while (tests[i].func) { - int curr = i++; - - if (argc > 1 && !strstr(tests[curr].desc, argv[1])) - continue; - - pr_info("%2d: %s\n", i, tests[curr].desc); - } - - return 0; -} - -int cmd_test(int argc, const char **argv, const char *prefix __used) -{ - const char * const test_usage[] = { - "perf test [] [{list |[|]}]", +static const char * const test_usage[] = { + "perf test []", NULL, - }; - const struct option test_options[] = { +}; + +static const struct option test_options[] = { OPT_INTEGER('v', "verbose", &verbose, "be more verbose (show symbol address, etc)"), OPT_END() - }; +}; +int cmd_test(int argc, const char **argv, const char *prefix __used) +{ argc = parse_options(argc, argv, test_options, test_usage, 0); - if (argc >= 1 && !strcmp(argv[0], "list")) - return perf_test__list(argc, argv); + if (argc) + usage_with_options(test_usage, test_options); symbol_conf.priv_size = sizeof(int); symbol_conf.sort_by_name = true; @@ -1414,5 +915,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used) setup_pager(); - return __cmd_test(argc, argv); + return __cmd_test(); } diff --git a/trunk/tools/perf/builtin-timechart.c b/trunk/tools/perf/builtin-timechart.c index 3b75b2e21ea5..aa26f4d66d10 100644 --- a/trunk/tools/perf/builtin-timechart.c +++ b/trunk/tools/perf/builtin-timechart.c @@ -19,7 +19,6 @@ #include "util/color.h" #include #include "util/cache.h" -#include "util/evsel.h" #include #include "util/symbol.h" #include "util/callchain.h" @@ -32,14 +31,13 @@ #include "util/event.h" #include "util/session.h" #include "util/svghelper.h" -#include "util/tool.h" #define SUPPORT_OLD_POWER_EVENTS 1 #define PWR_EVENT_EXIT -1 -static const char *input_name; -static const char *output_name = "output.svg"; +static char const *input_name = "perf.data"; +static char const *output_name = "output.svg"; static unsigned int numcpus; static u64 min_freq; /* Lowest CPU frequency seen */ @@ -275,28 +273,25 @@ static int cpus_cstate_state[MAX_CPUS]; static u64 cpus_pstate_start_times[MAX_CPUS]; static u64 cpus_pstate_state[MAX_CPUS]; -static int process_comm_event(struct perf_tool *tool __used, - union perf_event *event, +static int process_comm_event(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine __used) + struct perf_session *session __used) { pid_set_comm(event->comm.tid, event->comm.comm); return 0; } -static int process_fork_event(struct perf_tool *tool __used, - union perf_event *event, +static int process_fork_event(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine __used) + struct perf_session *session __used) { pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); return 0; } -static int process_exit_event(struct perf_tool *tool __used, - union perf_event *event, +static int process_exit_event(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine __used) + struct perf_session *session __used) { pid_exit(event->fork.pid, event->fork.time); return 0; @@ -491,15 +486,14 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) } -static int process_sample_event(struct perf_tool *tool __used, - union perf_event *event __used, +static int process_sample_event(union perf_event *event __used, struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine __used) + struct perf_evsel *evsel __used, + struct perf_session *session) { struct trace_entry *te; - if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { + if (session->sample_type & PERF_SAMPLE_TIME) { if (!first_time || first_time > sample->time) first_time = sample->time; if (last_time < sample->time) @@ -507,7 +501,7 @@ static int process_sample_event(struct perf_tool *tool __used, } te = (void *)sample->raw_data; - if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { + if (session->sample_type & PERF_SAMPLE_RAW && sample->raw_size > 0) { char *event_str; #ifdef SUPPORT_OLD_POWER_EVENTS struct power_entry_old *peo; @@ -980,7 +974,7 @@ static void write_svg_file(const char *filename) svg_close(); } -static struct perf_tool perf_timechart = { +static struct perf_event_ops event_ops = { .comm = process_comm_event, .fork = process_fork_event, .exit = process_exit_event, @@ -991,7 +985,7 @@ static struct perf_tool perf_timechart = { static int __cmd_timechart(void) { struct perf_session *session = perf_session__new(input_name, O_RDONLY, - 0, false, &perf_timechart); + 0, false, &event_ops); int ret = -EINVAL; if (session == NULL) @@ -1000,7 +994,7 @@ static int __cmd_timechart(void) if (!perf_session__has_traces(session, "timechart record")) goto out_delete; - ret = perf_session__process_events(session, &perf_timechart); + ret = perf_session__process_events(session, &event_ops); if (ret) goto out_delete; diff --git a/trunk/tools/perf/builtin-top.c b/trunk/tools/perf/builtin-top.c index 4f81eeb99875..c9cdedb58134 100644 --- a/trunk/tools/perf/builtin-top.c +++ b/trunk/tools/perf/builtin-top.c @@ -64,6 +64,44 @@ #include #include +static struct perf_top top = { + .count_filter = 5, + .delay_secs = 2, + .target_pid = -1, + .target_tid = -1, + .freq = 1000, /* 1 KHz */ +}; + +static bool system_wide = false; + +static bool use_tui, use_stdio; + +static bool sort_has_symbols; + +static bool dont_use_callchains; +static char callchain_default_opt[] = "fractal,0.5,callee"; + + +static int default_interval = 0; + +static bool kptr_restrict_warned; +static bool vmlinux_warned; +static bool inherit = false; +static int realtime_prio = 0; +static bool group = false; +static bool sample_id_all_avail = true; +static unsigned int mmap_pages = 128; + +static bool dump_symtab = false; + +static struct winsize winsize; + +static const char *sym_filter = NULL; +static int sym_pcnt_filter = 5; + +/* + * Source functions + */ void get_term_dimensions(struct winsize *ws) { @@ -87,23 +125,21 @@ void get_term_dimensions(struct winsize *ws) ws->ws_col = 80; } -static void perf_top__update_print_entries(struct perf_top *top) +static void update_print_entries(struct winsize *ws) { - top->print_entries = top->winsize.ws_row; + top.print_entries = ws->ws_row; - if (top->print_entries > 9) - top->print_entries -= 9; + if (top.print_entries > 9) + top.print_entries -= 9; } -static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg) +static void sig_winch_handler(int sig __used) { - struct perf_top *top = arg; - - get_term_dimensions(&top->winsize); - perf_top__update_print_entries(top); + get_term_dimensions(&winsize); + update_print_entries(&winsize); } -static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) +static int parse_source(struct hist_entry *he) { struct symbol *sym; struct annotation *notes; @@ -134,7 +170,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) pthread_mutex_lock(¬es->lock); - if (symbol__alloc_hist(sym) < 0) { + if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); @@ -145,7 +181,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) err = symbol__annotate(sym, map, 0); if (err == 0) { out_assign: - top->sym_filter_entry = he; + top.sym_filter_entry = he; } pthread_mutex_unlock(¬es->lock); @@ -158,16 +194,14 @@ static void __zero_source_counters(struct hist_entry *he) symbol__annotate_zero_histograms(sym); } -static void perf_top__record_precise_ip(struct perf_top *top, - struct hist_entry *he, - int counter, u64 ip) +static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) { struct annotation *notes; struct symbol *sym; if (he == NULL || he->ms.sym == NULL || - ((top->sym_filter_entry == NULL || - top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) + ((top.sym_filter_entry == NULL || + top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) return; sym = he->ms.sym; @@ -176,7 +210,8 @@ static void perf_top__record_precise_ip(struct perf_top *top, if (pthread_mutex_trylock(¬es->lock)) return; - if (notes->src == NULL && symbol__alloc_hist(sym) < 0) { + if (notes->src == NULL && + symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); @@ -190,9 +225,8 @@ static void perf_top__record_precise_ip(struct perf_top *top, pthread_mutex_unlock(¬es->lock); } -static void perf_top__show_details(struct perf_top *top) +static void show_details(struct hist_entry *he) { - struct hist_entry *he = top->sym_filter_entry; struct annotation *notes; struct symbol *symbol; int more; @@ -208,15 +242,15 @@ static void perf_top__show_details(struct perf_top *top) if (notes->src == NULL) goto out_unlock; - printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name); - printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); + printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); + printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); - more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, - 0, top->sym_pcnt_filter, top->print_entries, 4); - if (top->zero) - symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); + more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx, + 0, sym_pcnt_filter, top.print_entries, 4); + if (top.zero) + symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); else - symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); + symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); if (more != 0) printf("%d lines not displayed, maybe increase display entries [e]\n", more); out_unlock: @@ -225,9 +259,11 @@ static void perf_top__show_details(struct perf_top *top) static const char CONSOLE_CLEAR[] = ""; -static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, - struct addr_location *al, - struct perf_sample *sample) +static struct hist_entry * + perf_session__add_hist_entry(struct perf_session *session, + struct addr_location *al, + struct perf_sample *sample, + struct perf_evsel *evsel) { struct hist_entry *he; @@ -235,51 +271,50 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, if (he == NULL) return NULL; - evsel->hists.stats.total_period += sample->period; + session->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); return he; } -static void perf_top__print_sym_table(struct perf_top *top) +static void print_sym_table(void) { char bf[160]; int printed = 0; - const int win_width = top->winsize.ws_col - 1; + const int win_width = winsize.ws_col - 1; puts(CONSOLE_CLEAR); - perf_top__header_snprintf(top, bf, sizeof(bf)); + perf_top__header_snprintf(&top, bf, sizeof(bf)); printf("%s\n", bf); - perf_top__reset_sample_counters(top); + perf_top__reset_sample_counters(&top); printf("%-*.*s\n", win_width, win_width, graph_dotted_line); - if (top->sym_evsel->hists.stats.nr_lost_warned != - top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { - top->sym_evsel->hists.stats.nr_lost_warned = - top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; + if (top.sym_evsel->hists.stats.nr_lost_warned != + top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { + top.sym_evsel->hists.stats.nr_lost_warned = + top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; color_fprintf(stdout, PERF_COLOR_RED, "WARNING: LOST %d chunks, Check IO/CPU overload", - top->sym_evsel->hists.stats.nr_lost_warned); + top.sym_evsel->hists.stats.nr_lost_warned); ++printed; } - if (top->sym_filter_entry) { - perf_top__show_details(top); + if (top.sym_filter_entry) { + show_details(top.sym_filter_entry); return; } - hists__collapse_resort_threaded(&top->sym_evsel->hists); - hists__output_resort_threaded(&top->sym_evsel->hists); - hists__decay_entries_threaded(&top->sym_evsel->hists, - top->hide_user_symbols, - top->hide_kernel_symbols); - hists__output_recalc_col_len(&top->sym_evsel->hists, - top->winsize.ws_row - 3); + hists__collapse_resort_threaded(&top.sym_evsel->hists); + hists__output_resort_threaded(&top.sym_evsel->hists); + hists__decay_entries_threaded(&top.sym_evsel->hists, + top.hide_user_symbols, + top.hide_kernel_symbols); + hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); putchar('\n'); - hists__fprintf(&top->sym_evsel->hists, NULL, false, false, - top->winsize.ws_row - 4 - printed, win_width, stdout); + hists__fprintf(&top.sym_evsel->hists, NULL, false, false, + winsize.ws_row - 4 - printed, win_width, stdout); } static void prompt_integer(int *target, const char *msg) @@ -317,17 +352,17 @@ static void prompt_percent(int *target, const char *msg) *target = tmp; } -static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) +static void prompt_symbol(struct hist_entry **target, const char *msg) { char *buf = malloc(0), *p; - struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; + struct hist_entry *syme = *target, *n, *found = NULL; struct rb_node *next; size_t dummy = 0; /* zero counters of active symbol */ if (syme) { __zero_source_counters(syme); - top->sym_filter_entry = NULL; + *target = NULL; } fprintf(stdout, "\n%s: ", msg); @@ -338,7 +373,7 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) if (p) *p = 0; - next = rb_first(&top->sym_evsel->hists.entries); + next = rb_first(&top.sym_evsel->hists.entries); while (next) { n = rb_entry(next, struct hist_entry, rb_node); if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { @@ -351,46 +386,47 @@ static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) if (!found) { fprintf(stderr, "Sorry, %s is not active.\n", buf); sleep(1); + return; } else - perf_top__parse_source(top, found); + parse_source(found); out_free: free(buf); } -static void perf_top__print_mapped_keys(struct perf_top *top) +static void print_mapped_keys(void) { char *name = NULL; - if (top->sym_filter_entry) { - struct symbol *sym = top->sym_filter_entry->ms.sym; + if (top.sym_filter_entry) { + struct symbol *sym = top.sym_filter_entry->ms.sym; name = sym->name; } fprintf(stdout, "\nMapped keys:\n"); - fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); - fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); + fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs); + fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries); - if (top->evlist->nr_entries > 1) - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel)); + if (top.evlist->nr_entries > 1) + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel)); - fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); + fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter); - fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); + fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); fprintf(stdout, "\t[K] hide kernel_symbols symbols. \t(%s)\n", - top->hide_kernel_symbols ? "yes" : "no"); + top.hide_kernel_symbols ? "yes" : "no"); fprintf(stdout, "\t[U] hide user symbols. \t(%s)\n", - top->hide_user_symbols ? "yes" : "no"); - fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0); + top.hide_user_symbols ? "yes" : "no"); + fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0); fprintf(stdout, "\t[qQ] quit.\n"); } -static int perf_top__key_mapped(struct perf_top *top, int c) +static int key_mapped(int c) { switch (c) { case 'd': @@ -406,7 +442,7 @@ static int perf_top__key_mapped(struct perf_top *top, int c) case 'S': return 1; case 'E': - return top->evlist->nr_entries > 1 ? 1 : 0; + return top.evlist->nr_entries > 1 ? 1 : 0; default: break; } @@ -414,13 +450,13 @@ static int perf_top__key_mapped(struct perf_top *top, int c) return 0; } -static void perf_top__handle_keypress(struct perf_top *top, int c) +static void handle_keypress(int c) { - if (!perf_top__key_mapped(top, c)) { + if (!key_mapped(c)) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; struct termios tc, save; - perf_top__print_mapped_keys(top); + print_mapped_keys(); fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); fflush(stdout); @@ -435,86 +471,81 @@ static void perf_top__handle_keypress(struct perf_top *top, int c) c = getc(stdin); tcsetattr(0, TCSAFLUSH, &save); - if (!perf_top__key_mapped(top, c)) + if (!key_mapped(c)) return; } switch (c) { case 'd': - prompt_integer(&top->delay_secs, "Enter display delay"); - if (top->delay_secs < 1) - top->delay_secs = 1; + prompt_integer(&top.delay_secs, "Enter display delay"); + if (top.delay_secs < 1) + top.delay_secs = 1; break; case 'e': - prompt_integer(&top->print_entries, "Enter display entries (lines)"); - if (top->print_entries == 0) { - struct sigaction act = { - .sa_sigaction = perf_top__sig_winch, - .sa_flags = SA_SIGINFO, - }; - perf_top__sig_winch(SIGWINCH, NULL, top); - sigaction(SIGWINCH, &act, NULL); + prompt_integer(&top.print_entries, "Enter display entries (lines)"); + if (top.print_entries == 0) { + sig_winch_handler(SIGWINCH); + signal(SIGWINCH, sig_winch_handler); } else signal(SIGWINCH, SIG_DFL); break; case 'E': - if (top->evlist->nr_entries > 1) { + if (top.evlist->nr_entries > 1) { /* Select 0 as the default event: */ int counter = 0; fprintf(stderr, "\nAvailable events:"); - list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) - fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel)); + list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) + fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); prompt_integer(&counter, "Enter details event counter"); - if (counter >= top->evlist->nr_entries) { - top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); - fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel)); + if (counter >= top.evlist->nr_entries) { + top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); sleep(1); break; } - list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) - if (top->sym_evsel->idx == counter) + list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) + if (top.sym_evsel->idx == counter) break; } else - top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); + top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); break; case 'f': - prompt_integer(&top->count_filter, "Enter display event count filter"); + prompt_integer(&top.count_filter, "Enter display event count filter"); break; case 'F': - prompt_percent(&top->sym_pcnt_filter, - "Enter details display event filter (percent)"); + prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); break; case 'K': - top->hide_kernel_symbols = !top->hide_kernel_symbols; + top.hide_kernel_symbols = !top.hide_kernel_symbols; break; case 'q': case 'Q': printf("exiting.\n"); - if (top->dump_symtab) - perf_session__fprintf_dsos(top->session, stderr); + if (dump_symtab) + perf_session__fprintf_dsos(top.session, stderr); exit(0); case 's': - perf_top__prompt_symbol(top, "Enter details symbol"); + prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); break; case 'S': - if (!top->sym_filter_entry) + if (!top.sym_filter_entry) break; else { - struct hist_entry *syme = top->sym_filter_entry; + struct hist_entry *syme = top.sym_filter_entry; - top->sym_filter_entry = NULL; + top.sym_filter_entry = NULL; __zero_source_counters(syme); } break; case 'U': - top->hide_user_symbols = !top->hide_user_symbols; + top.hide_user_symbols = !top.hide_user_symbols; break; case 'z': - top->zero = !top->zero; + top.zero = !top.zero; break; default: break; @@ -532,30 +563,28 @@ static void perf_top__sort_new_samples(void *arg) hists__collapse_resort_threaded(&t->sym_evsel->hists); hists__output_resort_threaded(&t->sym_evsel->hists); hists__decay_entries_threaded(&t->sym_evsel->hists, - t->hide_user_symbols, - t->hide_kernel_symbols); + top.hide_user_symbols, + top.hide_kernel_symbols); } -static void *display_thread_tui(void *arg) +static void *display_thread_tui(void *arg __used) { - struct perf_top *top = arg; const char *help = "For a higher level overview, try: perf top --sort comm,dso"; - perf_top__sort_new_samples(top); - perf_evlist__tui_browse_hists(top->evlist, help, + perf_top__sort_new_samples(&top); + perf_evlist__tui_browse_hists(top.evlist, help, perf_top__sort_new_samples, - top, top->delay_secs); + &top, top.delay_secs); exit_browser(0); exit(0); return NULL; } -static void *display_thread(void *arg) +static void *display_thread(void *arg __used) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; struct termios tc, save; - struct perf_top *top = arg; int delay_msecs, c; tcgetattr(0, &save); @@ -566,13 +595,13 @@ static void *display_thread(void *arg) pthread__unblock_sigwinch(); repeat: - delay_msecs = top->delay_secs * 1000; + delay_msecs = top.delay_secs * 1000; tcsetattr(0, TCSANOW, &tc); /* trash return*/ getc(stdin); while (1) { - perf_top__print_sym_table(top); + print_sym_table(); /* * Either timeout expired or we got an EINTR due to SIGWINCH, * refresh screen in both cases. @@ -592,7 +621,7 @@ static void *display_thread(void *arg) c = getc(stdin); tcsetattr(0, TCSAFLUSH, &save); - perf_top__handle_keypress(top, c); + handle_keypress(c); goto repeat; return NULL; @@ -644,17 +673,47 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) return 0; } -static void perf_event__process_sample(struct perf_tool *tool, - const union perf_event *event, +static void perf_event__process_sample(const union perf_event *event, struct perf_evsel *evsel, struct perf_sample *sample, - struct machine *machine) + struct perf_session *session) { - struct perf_top *top = container_of(tool, struct perf_top, tool); struct symbol *parent = NULL; u64 ip = event->ip.ip; struct addr_location al; + struct machine *machine; int err; + u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + + ++top.samples; + + switch (origin) { + case PERF_RECORD_MISC_USER: + ++top.us_samples; + if (top.hide_user_symbols) + return; + machine = perf_session__find_host_machine(session); + break; + case PERF_RECORD_MISC_KERNEL: + ++top.kernel_samples; + if (top.hide_kernel_symbols) + return; + machine = perf_session__find_host_machine(session); + break; + case PERF_RECORD_MISC_GUEST_KERNEL: + ++top.guest_kernel_samples; + machine = perf_session__find_machine(session, event->ip.pid); + break; + case PERF_RECORD_MISC_GUEST_USER: + ++top.guest_us_samples; + /* + * TODO: we don't process guest user from host side + * except simple counting. + */ + return; + default: + return; + } if (!machine && perf_guest) { pr_err("Can't find guest [%d]'s kernel information\n", @@ -663,14 +722,14 @@ static void perf_event__process_sample(struct perf_tool *tool, } if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) - top->exact_samples++; + top.exact_samples++; - if (perf_event__preprocess_sample(event, machine, &al, sample, + if (perf_event__preprocess_sample(event, session, &al, sample, symbol_filter) < 0 || al.filtered) return; - if (!top->kptr_restrict_warned && + if (!kptr_restrict_warned && symbol_conf.kptr_restrict && al.cpumode == PERF_RECORD_MISC_KERNEL) { ui__warning( @@ -681,7 +740,7 @@ static void perf_event__process_sample(struct perf_tool *tool, " modules" : ""); if (use_browser <= 0) sleep(5); - top->kptr_restrict_warned = true; + kptr_restrict_warned = true; } if (al.sym == NULL) { @@ -697,7 +756,7 @@ static void perf_event__process_sample(struct perf_tool *tool, * --hide-kernel-symbols, even if the user specifies an * invalid --vmlinux ;-) */ - if (!top->kptr_restrict_warned && !top->vmlinux_warned && + if (!kptr_restrict_warned && !vmlinux_warned && al.map == machine->vmlinux_maps[MAP__FUNCTION] && RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { if (symbol_conf.vmlinux_name) { @@ -710,7 +769,7 @@ static void perf_event__process_sample(struct perf_tool *tool, if (use_browser <= 0) sleep(5); - top->vmlinux_warned = true; + vmlinux_warned = true; } } @@ -719,109 +778,70 @@ static void perf_event__process_sample(struct perf_tool *tool, if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = machine__resolve_callchain(machine, evsel, al.thread, - sample->callchain, &parent); + err = perf_session__resolve_callchain(session, al.thread, + sample->callchain, &parent); if (err) return; } - he = perf_evsel__add_hist_entry(evsel, &al, sample); + he = perf_session__add_hist_entry(session, &al, sample, evsel); if (he == NULL) { pr_err("Problem incrementing symbol period, skipping event\n"); return; } if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, &evsel->hists.callchain_cursor, + err = callchain_append(he->callchain, &session->callchain_cursor, sample->period); if (err) return; } - if (top->sort_has_symbols) - perf_top__record_precise_ip(top, he, evsel->idx, ip); + if (sort_has_symbols) + record_precise_ip(he, evsel->idx, ip); } return; } -static void perf_top__mmap_read_idx(struct perf_top *top, int idx) +static void perf_session__mmap_read_idx(struct perf_session *self, int idx) { struct perf_sample sample; struct perf_evsel *evsel; - struct perf_session *session = top->session; union perf_event *event; - struct machine *machine; - u8 origin; int ret; - while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { - ret = perf_session__parse_sample(session, event, &sample); + while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { + ret = perf_session__parse_sample(self, event, &sample); if (ret) { pr_err("Can't parse sample, err = %d\n", ret); continue; } - evsel = perf_evlist__id2evsel(session->evlist, sample.id); + evsel = perf_evlist__id2evsel(self->evlist, sample.id); assert(evsel != NULL); - origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - if (event->header.type == PERF_RECORD_SAMPLE) - ++top->samples; - - switch (origin) { - case PERF_RECORD_MISC_USER: - ++top->us_samples; - if (top->hide_user_symbols) - continue; - machine = perf_session__find_host_machine(session); - break; - case PERF_RECORD_MISC_KERNEL: - ++top->kernel_samples; - if (top->hide_kernel_symbols) - continue; - machine = perf_session__find_host_machine(session); - break; - case PERF_RECORD_MISC_GUEST_KERNEL: - ++top->guest_kernel_samples; - machine = perf_session__find_machine(session, event->ip.pid); - break; - case PERF_RECORD_MISC_GUEST_USER: - ++top->guest_us_samples; - /* - * TODO: we don't process guest user from host side - * except simple counting. - */ - /* Fall thru */ - default: - continue; - } - - - if (event->header.type == PERF_RECORD_SAMPLE) { - perf_event__process_sample(&top->tool, event, evsel, - &sample, machine); - } else if (event->header.type < PERF_RECORD_MAX) { + perf_event__process_sample(event, evsel, &sample, self); + else if (event->header.type < PERF_RECORD_MAX) { hists__inc_nr_events(&evsel->hists, event->header.type); - perf_event__process(&top->tool, event, &sample, machine); + perf_event__process(event, &sample, self); } else - ++session->hists.stats.nr_unknown_events; + ++self->hists.stats.nr_unknown_events; } } -static void perf_top__mmap_read(struct perf_top *top) +static void perf_session__mmap_read(struct perf_session *self) { int i; - for (i = 0; i < top->evlist->nr_mmaps; i++) - perf_top__mmap_read_idx(top, i); + for (i = 0; i < top.evlist->nr_mmaps; i++) + perf_session__mmap_read_idx(self, i); } -static void perf_top__start_counters(struct perf_top *top) +static void start_counters(struct perf_evlist *evlist) { struct perf_evsel *counter, *first; - struct perf_evlist *evlist = top->evlist; first = list_entry(evlist->entries.next, struct perf_evsel, node); @@ -829,15 +849,15 @@ static void perf_top__start_counters(struct perf_top *top) struct perf_event_attr *attr = &counter->attr; struct xyarray *group_fd = NULL; - if (top->group && counter != first) + if (group && counter != first) group_fd = first->fd; attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; - if (top->freq) { + if (top.freq) { attr->sample_type |= PERF_SAMPLE_PERIOD; attr->freq = 1; - attr->sample_freq = top->freq; + attr->sample_freq = top.freq; } if (evlist->nr_entries > 1) { @@ -850,23 +870,23 @@ static void perf_top__start_counters(struct perf_top *top) attr->mmap = 1; attr->comm = 1; - attr->inherit = top->inherit; + attr->inherit = inherit; retry_sample_id: - attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; + attr->sample_id_all = sample_id_all_avail ? 1 : 0; try_again: - if (perf_evsel__open(counter, top->evlist->cpus, - top->evlist->threads, top->group, + if (perf_evsel__open(counter, top.evlist->cpus, + top.evlist->threads, group, group_fd) < 0) { int err = errno; if (err == EPERM || err == EACCES) { ui__error_paranoid(); goto out_err; - } else if (err == EINVAL && top->sample_id_all_avail) { + } else if (err == EINVAL && sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field */ - top->sample_id_all_avail = false; + sample_id_all_avail = false; goto retry_sample_id; } /* @@ -900,7 +920,7 @@ static void perf_top__start_counters(struct perf_top *top) } } - if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { + if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) { ui__warning("Failed to mmap with %d (%s)\n", errno, strerror(errno)); goto out_err; @@ -913,14 +933,14 @@ static void perf_top__start_counters(struct perf_top *top) exit(0); } -static int perf_top__setup_sample_type(struct perf_top *top) +static int setup_sample_type(void) { - if (!top->sort_has_symbols) { + if (!sort_has_symbols) { if (symbol_conf.use_callchain) { ui__warning("Selected -g but \"sym\" not present in --sort/-s."); return -EINVAL; } - } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { + } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) { if (callchain_register_param(&callchain_param) < 0) { ui__warning("Can't register callchain params.\n"); return -EINVAL; @@ -930,7 +950,7 @@ static int perf_top__setup_sample_type(struct perf_top *top) return 0; } -static int __cmd_top(struct perf_top *top) +static int __cmd_top(void) { pthread_t thread; int ret; @@ -938,40 +958,39 @@ static int __cmd_top(struct perf_top *top) * FIXME: perf_session__new should allow passing a O_MMAP, so that all this * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. */ - top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL); - if (top->session == NULL) + top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL); + if (top.session == NULL) return -ENOMEM; - ret = perf_top__setup_sample_type(top); + ret = setup_sample_type(); if (ret) goto out_delete; - if (top->target_tid != -1) - perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, - perf_event__process, - &top->session->host_machine); + if (top.target_tid != -1) + perf_event__synthesize_thread_map(top.evlist->threads, + perf_event__process, top.session); else - perf_event__synthesize_threads(&top->tool, perf_event__process, - &top->session->host_machine); - perf_top__start_counters(top); - top->session->evlist = top->evlist; - perf_session__update_sample_type(top->session); + perf_event__synthesize_threads(perf_event__process, top.session); + + start_counters(top.evlist); + top.session->evlist = top.evlist; + perf_session__update_sample_type(top.session); /* Wait for a minimal set of events before starting the snapshot */ - poll(top->evlist->pollfd, top->evlist->nr_fds, 100); + poll(top.evlist->pollfd, top.evlist->nr_fds, 100); - perf_top__mmap_read(top); + perf_session__mmap_read(top.session); if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : - display_thread), top)) { + display_thread), NULL)) { printf("Could not create display thread.\n"); exit(-1); } - if (top->realtime_prio) { + if (realtime_prio) { struct sched_param param; - param.sched_priority = top->realtime_prio; + param.sched_priority = realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { printf("Could not set realtime priority.\n"); exit(-1); @@ -979,25 +998,25 @@ static int __cmd_top(struct perf_top *top) } while (1) { - u64 hits = top->samples; + u64 hits = top.samples; - perf_top__mmap_read(top); + perf_session__mmap_read(top.session); - if (hits == top->samples) - ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); + if (hits == top.samples) + ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); } out_delete: - perf_session__delete(top->session); - top->session = NULL; + perf_session__delete(top.session); + top.session = NULL; return 0; } static int -parse_callchain_opt(const struct option *opt, const char *arg, int unset) +parse_callchain_opt(const struct option *opt __used, const char *arg, + int unset) { - struct perf_top *top = (struct perf_top *)opt->value; char *tok, *tok2; char *endptr; @@ -1005,7 +1024,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) * --no-call-graph */ if (unset) { - top->dont_use_callchains = true; + dont_use_callchains = true; return 0; } @@ -1033,7 +1052,9 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) symbol_conf.use_callchain = false; return 0; - } else + } + + else return -1; /* get the min percentage */ @@ -1077,32 +1098,17 @@ static const char * const top_usage[] = { NULL }; -int cmd_top(int argc, const char **argv, const char *prefix __used) -{ - struct perf_evsel *pos; - int status = -ENOMEM; - struct perf_top top = { - .count_filter = 5, - .delay_secs = 2, - .target_pid = -1, - .target_tid = -1, - .freq = 1000, /* 1 KHz */ - .sample_id_all_avail = true, - .mmap_pages = 128, - .sym_pcnt_filter = 5, - }; - char callchain_default_opt[] = "fractal,0.5,callee"; - const struct option options[] = { +static const struct option options[] = { OPT_CALLBACK('e', "event", &top.evlist, "event", "event selector. use 'perf list' to list available events", parse_events_option), - OPT_INTEGER('c', "count", &top.default_interval, + OPT_INTEGER('c', "count", &default_interval, "event period to sample"), OPT_INTEGER('p', "pid", &top.target_pid, "profile events on existing process id"), OPT_INTEGER('t', "tid", &top.target_tid, "profile events on existing thread id"), - OPT_BOOLEAN('a', "all-cpus", &top.system_wide, + OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_STRING('C', "cpu", &top.cpu_list, "cpu", "list of cpus to monitor"), @@ -1110,20 +1116,20 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) "file", "vmlinux pathname"), OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, "hide kernel symbols"), - OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), - OPT_INTEGER('r', "realtime", &top.realtime_prio, + OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), + OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), OPT_INTEGER('d', "delay", &top.delay_secs, "number of seconds to delay between refreshes"), - OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab, + OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, "dump the symbol table used for profiling"), OPT_INTEGER('f', "count-filter", &top.count_filter, "only display functions with more events than this"), - OPT_BOOLEAN('g', "group", &top.group, + OPT_BOOLEAN('g', "group", &group, "put the counters into a counter group"), - OPT_BOOLEAN('i', "inherit", &top.inherit, + OPT_BOOLEAN('i', "inherit", &inherit, "child tasks inherit counters"), - OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", + OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name", "symbol to annotate"), OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), @@ -1133,15 +1139,15 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) "display this many functions"), OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, "hide user symbols"), - OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"), - OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"), + OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), + OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_STRING('s', "sort", &sort_order, "key[,key2...]", "sort by key(s): pid, comm, dso, symbol, parent"), OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, "Show a column with the number of samples"), - OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", + OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order", "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), @@ -1160,7 +1166,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_END() - }; +}; + +int cmd_top(int argc, const char **argv, const char *prefix __used) +{ + struct perf_evsel *pos; + int status = -ENOMEM; top.evlist = perf_evlist__new(NULL, NULL); if (top.evlist == NULL) @@ -1177,9 +1188,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) setup_sorting(top_usage, options); - if (top.use_stdio) + if (use_stdio) use_browser = 0; - else if (top.use_tui) + else if (use_tui) use_browser = 1; setup_browser(false); @@ -1204,31 +1215,38 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) return -ENOMEM; } - symbol_conf.nr_events = top.evlist->nr_entries; - if (top.delay_secs < 1) top.delay_secs = 1; /* * User specified count overrides default frequency. */ - if (top.default_interval) + if (default_interval) top.freq = 0; else if (top.freq) { - top.default_interval = top.freq; + default_interval = top.freq; } else { fprintf(stderr, "frequency and count are zero, aborting\n"); exit(EXIT_FAILURE); } list_for_each_entry(pos, &top.evlist->entries, node) { + if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr, + top.evlist->threads->nr) < 0) + goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: */ - if (!pos->attr.sample_period) - pos->attr.sample_period = top.default_interval; + if (pos->attr.sample_period) + continue; + + pos->attr.sample_period = default_interval; } + if (perf_evlist__alloc_pollfd(top.evlist) < 0 || + perf_evlist__alloc_mmap(top.evlist) < 0) + goto out_free_fd; + top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); symbol_conf.priv_size = sizeof(struct annotation); @@ -1245,20 +1263,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) * Avoid annotation data structures overhead when symbols aren't on the * sort list. */ - top.sort_has_symbols = sort_sym.list.next != NULL; + sort_has_symbols = sort_sym.list.next != NULL; - get_term_dimensions(&top.winsize); + get_term_dimensions(&winsize); if (top.print_entries == 0) { - struct sigaction act = { - .sa_sigaction = perf_top__sig_winch, - .sa_flags = SA_SIGINFO, - }; - perf_top__update_print_entries(&top); - sigaction(SIGWINCH, &act, NULL); + update_print_entries(&winsize); + signal(SIGWINCH, sig_winch_handler); } - status = __cmd_top(&top); - + status = __cmd_top(); +out_free_fd: perf_evlist__delete(top.evlist); return status; diff --git a/trunk/tools/perf/perf.c b/trunk/tools/perf/perf.c index 2b2e225a4d4c..73d0cac8b67e 100644 --- a/trunk/tools/perf/perf.c +++ b/trunk/tools/perf/perf.c @@ -29,6 +29,8 @@ struct pager_config { int val; }; +static char debugfs_mntpt[MAXPATHLEN]; + static int pager_command_config(const char *var, const char *value, void *data) { struct pager_config *c = data; @@ -79,6 +81,15 @@ static void commit_pager_choice(void) } } +static void set_debugfs_path(void) +{ + char *path; + + path = getenv(PERF_DEBUGFS_ENVIRONMENT); + snprintf(debugfs_path, MAXPATHLEN, "%s/%s", path ?: debugfs_mntpt, + "tracing/events"); +} + static int handle_options(const char ***argv, int *argc, int *envchanged) { int handled = 0; @@ -150,14 +161,15 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) fprintf(stderr, "No directory given for --debugfs-dir.\n"); usage(perf_usage_string); } - debugfs_set_path((*argv)[1]); + strncpy(debugfs_mntpt, (*argv)[1], MAXPATHLEN); + debugfs_mntpt[MAXPATHLEN - 1] = '\0'; if (envchanged) *envchanged = 1; (*argv)++; (*argc)--; } else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) { - debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR)); - fprintf(stderr, "dir: %s\n", debugfs_mountpoint); + strncpy(debugfs_mntpt, cmd + strlen(CMD_DEBUGFS_DIR), MAXPATHLEN); + debugfs_mntpt[MAXPATHLEN - 1] = '\0'; if (envchanged) *envchanged = 1; } else { @@ -269,6 +281,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) if (use_pager == -1 && p->option & USE_PAGER) use_pager = 1; commit_pager_choice(); + set_debugfs_path(); status = p->fn(argc, argv, prefix); exit_browser(status); @@ -403,6 +416,17 @@ static int run_argv(int *argcp, const char ***argv) return done_alias; } +/* mini /proc/mounts parser: searching for "^blah /mount/point debugfs" */ +static void get_debugfs_mntpt(void) +{ + const char *path = debugfs_mount(NULL); + + if (path) + strncpy(debugfs_mntpt, path, sizeof(debugfs_mntpt)); + else + debugfs_mntpt[0] = '\0'; +} + static void pthread__block_sigwinch(void) { sigset_t set; @@ -429,7 +453,7 @@ int main(int argc, const char **argv) if (!cmd) cmd = "perf-help"; /* get debugfs mount point from /proc/mounts */ - debugfs_mount(NULL); + get_debugfs_mntpt(); /* * "perf-xxxx" is the same as "perf xxxx", but we obviously: * @@ -452,6 +476,7 @@ int main(int argc, const char **argv) argc--; handle_options(&argv, &argc, NULL); commit_pager_choice(); + set_debugfs_path(); set_buildid_dir(); if (argc > 0) { diff --git a/trunk/tools/perf/perf.h b/trunk/tools/perf/perf.h index 64f8bee31ced..914c895510f7 100644 --- a/trunk/tools/perf/perf.h +++ b/trunk/tools/perf/perf.h @@ -185,28 +185,4 @@ extern const char perf_version_string[]; void pthread__unblock_sigwinch(void); -struct perf_record_opts { - pid_t target_pid; - pid_t target_tid; - bool call_graph; - bool group; - bool inherit_stat; - bool no_delay; - bool no_inherit; - bool no_samples; - bool pipe_output; - bool raw_samples; - bool sample_address; - bool sample_time; - bool sample_id_all_avail; - bool system_wide; - bool period; - unsigned int freq; - unsigned int mmap_pages; - unsigned int user_freq; - u64 default_interval; - u64 user_interval; - const char *cpu_list; -}; - #endif diff --git a/trunk/tools/perf/util/annotate.c b/trunk/tools/perf/util/annotate.c index 011ed2676604..119e996035c8 100644 --- a/trunk/tools/perf/util/annotate.c +++ b/trunk/tools/perf/util/annotate.c @@ -25,17 +25,17 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym) return 0; } -int symbol__alloc_hist(struct symbol *sym) +int symbol__alloc_hist(struct symbol *sym, int nevents) { struct annotation *notes = symbol__annotation(sym); size_t sizeof_sym_hist = (sizeof(struct sym_hist) + (sym->end - sym->start) * sizeof(u64)); - notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); + notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist); if (notes->src == NULL) return -1; notes->src->sizeof_sym_hist = sizeof_sym_hist; - notes->src->nr_histograms = symbol_conf.nr_events; + notes->src->nr_histograms = nevents; INIT_LIST_HEAD(¬es->src->source); return 0; } @@ -334,7 +334,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) disassembler_style ? "-M " : "", disassembler_style ? disassembler_style : "", map__rip_2objdump(map, sym->start), - map__rip_2objdump(map, sym->end+1), + map__rip_2objdump(map, sym->end), symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", symbol_conf.annotate_src ? "-S" : "", symfs_filename, filename); diff --git a/trunk/tools/perf/util/annotate.h b/trunk/tools/perf/util/annotate.h index efa5dc82bfae..d9072523d342 100644 --- a/trunk/tools/perf/util/annotate.h +++ b/trunk/tools/perf/util/annotate.h @@ -72,7 +72,7 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) int symbol__inc_addr_samples(struct symbol *sym, struct map *map, int evidx, u64 addr); -int symbol__alloc_hist(struct symbol *sym); +int symbol__alloc_hist(struct symbol *sym, int nevents); void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); @@ -99,7 +99,8 @@ static inline int symbol__tui_annotate(struct symbol *sym __used, } #else int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - void(*timer)(void *arg), void *arg, int delay_secs); + int nr_events, void(*timer)(void *arg), void *arg, + int delay_secs); #endif extern const char *disassembler_style; diff --git a/trunk/tools/perf/util/build-id.c b/trunk/tools/perf/util/build-id.c index dff9c7a725f4..a91cd99f26ea 100644 --- a/trunk/tools/perf/util/build-id.c +++ b/trunk/tools/perf/util/build-id.c @@ -13,18 +13,15 @@ #include "symbol.h" #include #include "debug.h" -#include "session.h" -#include "tool.h" -static int build_id__mark_dso_hit(struct perf_tool *tool __used, - union perf_event *event, +static int build_id__mark_dso_hit(union perf_event *event, struct perf_sample *sample __used, struct perf_evsel *evsel __used, - struct machine *machine) + struct perf_session *session) { struct addr_location al; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - struct thread *thread = machine__findnew_thread(machine, event->ip.pid); + struct thread *thread = perf_session__findnew(session, event->ip.pid); if (thread == NULL) { pr_err("problem processing %d event, skipping it.\n", @@ -32,8 +29,8 @@ static int build_id__mark_dso_hit(struct perf_tool *tool __used, return -1; } - thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, - event->ip.ip, &al); + thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, + event->ip.pid, event->ip.ip, &al); if (al.map != NULL) al.map->dso->hit = 1; @@ -41,26 +38,25 @@ static int build_id__mark_dso_hit(struct perf_tool *tool __used, return 0; } -static int perf_event__exit_del_thread(struct perf_tool *tool __used, - union perf_event *event, +static int perf_event__exit_del_thread(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine) + struct perf_session *session) { - struct thread *thread = machine__findnew_thread(machine, event->fork.tid); + struct thread *thread = perf_session__findnew(session, event->fork.tid); dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, event->fork.ppid, event->fork.ptid); if (thread) { - rb_erase(&thread->rb_node, &machine->threads); - machine->last_match = NULL; + rb_erase(&thread->rb_node, &session->threads); + session->last_match = NULL; thread__delete(thread); } return 0; } -struct perf_tool build_id__mark_dso_hit_ops = { +struct perf_event_ops build_id__mark_dso_hit_ops = { .sample = build_id__mark_dso_hit, .mmap = perf_event__process_mmap, .fork = perf_event__process_task, diff --git a/trunk/tools/perf/util/build-id.h b/trunk/tools/perf/util/build-id.h index a993ba87d996..5dafb00eaa06 100644 --- a/trunk/tools/perf/util/build-id.h +++ b/trunk/tools/perf/util/build-id.h @@ -3,7 +3,7 @@ #include "session.h" -extern struct perf_tool build_id__mark_dso_hit_ops; +extern struct perf_event_ops build_id__mark_dso_hit_ops; char *dso__build_id_filename(struct dso *self, char *bf, size_t size); diff --git a/trunk/tools/perf/util/callchain.h b/trunk/tools/perf/util/callchain.h index 7f9c0f1ae3a9..9b4ff16cac96 100644 --- a/trunk/tools/perf/util/callchain.h +++ b/trunk/tools/perf/util/callchain.h @@ -101,9 +101,6 @@ int callchain_append(struct callchain_root *root, int callchain_merge(struct callchain_cursor *cursor, struct callchain_root *dst, struct callchain_root *src); -struct ip_callchain; -union perf_event; - bool ip_callchain__valid(struct ip_callchain *chain, const union perf_event *event); /* diff --git a/trunk/tools/perf/util/cgroup.c b/trunk/tools/perf/util/cgroup.c index dbe2f16b1a1a..96bee5c46008 100644 --- a/trunk/tools/perf/util/cgroup.c +++ b/trunk/tools/perf/util/cgroup.c @@ -3,6 +3,7 @@ #include "parse-options.h" #include "evsel.h" #include "cgroup.h" +#include "debugfs.h" /* MAX_PATH, STR() */ #include "evlist.h" int nr_cgroups; @@ -11,7 +12,7 @@ static int cgroupfs_find_mountpoint(char *buf, size_t maxlen) { FILE *fp; - char mountpoint[PATH_MAX + 1], tokens[PATH_MAX + 1], type[PATH_MAX + 1]; + char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; char *token, *saved_ptr = NULL; int found = 0; @@ -24,8 +25,8 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen) * and inspect every cgroupfs mount point to find one that has * perf_event subsystem */ - while (fscanf(fp, "%*s %"STR(PATH_MAX)"s %"STR(PATH_MAX)"s %" - STR(PATH_MAX)"s %*d %*d\n", + while (fscanf(fp, "%*s %"STR(MAX_PATH)"s %"STR(MAX_PATH)"s %" + STR(MAX_PATH)"s %*d %*d\n", mountpoint, type, tokens) == 3) { if (!strcmp(type, "cgroup")) { @@ -56,15 +57,15 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen) static int open_cgroup(char *name) { - char path[PATH_MAX + 1]; - char mnt[PATH_MAX + 1]; + char path[MAX_PATH+1]; + char mnt[MAX_PATH+1]; int fd; - if (cgroupfs_find_mountpoint(mnt, PATH_MAX + 1)) + if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1)) return -1; - snprintf(path, PATH_MAX, "%s/%s", mnt, name); + snprintf(path, MAX_PATH, "%s/%s", mnt, name); fd = open(path, O_RDONLY); if (fd == -1) diff --git a/trunk/tools/perf/util/config.c b/trunk/tools/perf/util/config.c index 0deac6a14b65..80d9598db31a 100644 --- a/trunk/tools/perf/util/config.c +++ b/trunk/tools/perf/util/config.c @@ -1,8 +1,5 @@ /* - * config.c - * - * Helper functions for parsing config items. - * Originally copied from GIT source. + * GIT - The information manager from hell * * Copyright (C) Linus Torvalds, 2005 * Copyright (C) Johannes Schindelin, 2005 diff --git a/trunk/tools/perf/util/debugfs.c b/trunk/tools/perf/util/debugfs.c index ffc35e748e89..a88fefc0cc0a 100644 --- a/trunk/tools/perf/util/debugfs.c +++ b/trunk/tools/perf/util/debugfs.c @@ -2,12 +2,8 @@ #include "debugfs.h" #include "cache.h" -#include -#include - static int debugfs_premounted; -char debugfs_mountpoint[PATH_MAX + 1] = "/sys/kernel/debug"; -char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events"; +static char debugfs_mountpoint[MAX_PATH+1]; static const char *debugfs_known_mountpoints[] = { "/sys/kernel/debug/", @@ -66,9 +62,11 @@ const char *debugfs_find_mountpoint(void) /* give up and parse /proc/mounts */ fp = fopen("/proc/mounts", "r"); if (fp == NULL) - return NULL; + die("Can't open /proc/mounts for read"); - while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", + while (fscanf(fp, "%*s %" + STR(MAX_PATH) + "s %99s %*s %*d %*d\n", debugfs_mountpoint, type) == 2) { if (strcmp(type, "debugfs") == 0) break; @@ -108,12 +106,6 @@ int debugfs_valid_entry(const char *path) return 0; } -static void debugfs_set_tracing_events_path(const char *mountpoint) -{ - snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s", - mountpoint, "tracing/events"); -} - /* mount the debugfs somewhere if it's not mounted */ char *debugfs_mount(const char *mountpoint) @@ -121,7 +113,7 @@ char *debugfs_mount(const char *mountpoint) /* see if it's already mounted */ if (debugfs_find_mountpoint()) { debugfs_premounted = 1; - goto out; + return debugfs_mountpoint; } /* if not mounted and no argument */ @@ -137,17 +129,10 @@ char *debugfs_mount(const char *mountpoint) return NULL; /* save the mountpoint */ - debugfs_found = 1; strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); -out: - debugfs_set_tracing_events_path(debugfs_mountpoint); - return debugfs_mountpoint; -} + debugfs_found = 1; -void debugfs_set_path(const char *mountpoint) -{ - snprintf(debugfs_mountpoint, sizeof(debugfs_mountpoint), "%s", mountpoint); - debugfs_set_tracing_events_path(mountpoint); + return debugfs_mountpoint; } /* umount the debugfs */ @@ -173,7 +158,7 @@ int debugfs_umount(void) int debugfs_write(const char *entry, const char *value) { - char path[PATH_MAX + 1]; + char path[MAX_PATH+1]; int ret, count; int fd; @@ -218,7 +203,7 @@ int debugfs_write(const char *entry, const char *value) */ int debugfs_read(const char *entry, char *buffer, size_t size) { - char path[PATH_MAX + 1]; + char path[MAX_PATH+1]; int ret; int fd; diff --git a/trunk/tools/perf/util/debugfs.h b/trunk/tools/perf/util/debugfs.h index 4a878f735eb0..83a02879745f 100644 --- a/trunk/tools/perf/util/debugfs.h +++ b/trunk/tools/perf/util/debugfs.h @@ -1,18 +1,25 @@ #ifndef __DEBUGFS_H__ #define __DEBUGFS_H__ -const char *debugfs_find_mountpoint(void); -int debugfs_valid_mountpoint(const char *debugfs); -int debugfs_valid_entry(const char *path); -char *debugfs_mount(const char *mountpoint); -int debugfs_umount(void); -void debugfs_set_path(const char *mountpoint); -int debugfs_write(const char *entry, const char *value); -int debugfs_read(const char *entry, char *buffer, size_t size); -void debugfs_force_cleanup(void); -int debugfs_make_path(const char *element, char *buffer, int size); +#include -extern char debugfs_mountpoint[]; -extern char tracing_events_path[]; +#ifndef MAX_PATH +# define MAX_PATH 256 +#endif + +#ifndef STR +# define _STR(x) #x +# define STR(x) _STR(x) +#endif + +extern const char *debugfs_find_mountpoint(void); +extern int debugfs_valid_mountpoint(const char *debugfs); +extern int debugfs_valid_entry(const char *path); +extern char *debugfs_mount(const char *mountpoint); +extern int debugfs_umount(void); +extern int debugfs_write(const char *entry, const char *value); +extern int debugfs_read(const char *entry, char *buffer, size_t size); +extern void debugfs_force_cleanup(void); +extern int debugfs_make_path(const char *element, char *buffer, int size); #endif /* __DEBUGFS_H__ */ diff --git a/trunk/tools/perf/util/event.c b/trunk/tools/perf/util/event.c index 73ddaf06b8e7..437f8ca679a0 100644 --- a/trunk/tools/perf/util/event.c +++ b/trunk/tools/perf/util/event.c @@ -1,6 +1,7 @@ #include #include "event.h" #include "debug.h" +#include "session.h" #include "sort.h" #include "string.h" #include "strlist.h" @@ -43,27 +44,36 @@ static struct perf_sample synth_sample = { .period = 1, }; -static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) +static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, + int full, perf_event__handler_t process, + struct perf_session *session) { char filename[PATH_MAX]; char bf[BUFSIZ]; FILE *fp; size_t size = 0; - pid_t tgid = -1; + DIR *tasks; + struct dirent dirent, *next; + pid_t tgid = 0; snprintf(filename, sizeof(filename), "/proc/%d/status", pid); fp = fopen(filename, "r"); if (fp == NULL) { +out_race: + /* + * We raced with a task exiting - just return: + */ pr_debug("couldn't open %s\n", filename); return 0; } - while (!comm[0] || (tgid < 0)) { + memset(&event->comm, 0, sizeof(event->comm)); + + while (!event->comm.comm[0] || !event->comm.pid) { if (fgets(bf, sizeof(bf), fp) == NULL) { - pr_warning("couldn't get COMM and pgid, malformed %s\n", - filename); - break; + pr_warning("couldn't get COMM and pgid, malformed %s\n", filename); + goto out; } if (memcmp(bf, "Name:", 5) == 0) { @@ -71,65 +81,33 @@ static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len) while (*name && isspace(*name)) ++name; size = strlen(name) - 1; - if (size >= len) - size = len - 1; - memcpy(comm, name, size); - + memcpy(event->comm.comm, name, size++); } else if (memcmp(bf, "Tgid:", 5) == 0) { char *tgids = bf + 5; while (*tgids && isspace(*tgids)) ++tgids; - tgid = atoi(tgids); + tgid = event->comm.pid = atoi(tgids); } } - fclose(fp); - - return tgid; -} - -static pid_t perf_event__synthesize_comm(struct perf_tool *tool, - union perf_event *event, pid_t pid, - int full, - perf_event__handler_t process, - struct machine *machine) -{ - char filename[PATH_MAX]; - size_t size; - DIR *tasks; - struct dirent dirent, *next; - pid_t tgid; - - memset(&event->comm, 0, sizeof(event->comm)); - - tgid = perf_event__get_comm_tgid(pid, event->comm.comm, - sizeof(event->comm.comm)); - if (tgid < 0) - goto out; - - event->comm.pid = tgid; event->comm.header.type = PERF_RECORD_COMM; - - size = strlen(event->comm.comm) + 1; size = ALIGN(size, sizeof(u64)); - memset(event->comm.comm + size, 0, machine->id_hdr_size); + memset(event->comm.comm + size, 0, session->id_hdr_size); event->comm.header.size = (sizeof(event->comm) - (sizeof(event->comm.comm) - size) + - machine->id_hdr_size); + session->id_hdr_size); if (!full) { event->comm.tid = pid; - process(tool, event, &synth_sample, machine); + process(event, &synth_sample, session); goto out; } snprintf(filename, sizeof(filename), "/proc/%d/task", pid); tasks = opendir(filename); - if (tasks == NULL) { - pr_debug("couldn't open %s\n", filename); - return 0; - } + if (tasks == NULL) + goto out_race; while (!readdir_r(tasks, &dirent, &next) && next) { char *end; @@ -137,32 +115,22 @@ static pid_t perf_event__synthesize_comm(struct perf_tool *tool, if (*end) continue; - /* already have tgid; jut want to update the comm */ - (void) perf_event__get_comm_tgid(pid, event->comm.comm, - sizeof(event->comm.comm)); - - size = strlen(event->comm.comm) + 1; - size = ALIGN(size, sizeof(u64)); - memset(event->comm.comm + size, 0, machine->id_hdr_size); - event->comm.header.size = (sizeof(event->comm) - - (sizeof(event->comm.comm) - size) + - machine->id_hdr_size); - event->comm.tid = pid; - process(tool, event, &synth_sample, machine); + process(event, &synth_sample, session); } closedir(tasks); out: + fclose(fp); + return tgid; } -static int perf_event__synthesize_mmap_events(struct perf_tool *tool, - union perf_event *event, +static int perf_event__synthesize_mmap_events(union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, - struct machine *machine) + struct perf_session *session) { char filename[PATH_MAX]; FILE *fp; @@ -225,12 +193,12 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, event->mmap.len -= event->mmap.start; event->mmap.header.size = (sizeof(event->mmap) - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, machine->id_hdr_size); - event->mmap.header.size += machine->id_hdr_size; + memset(event->mmap.filename + size, 0, session->id_hdr_size); + event->mmap.header.size += session->id_hdr_size; event->mmap.pid = tgid; event->mmap.tid = pid; - process(tool, event, &synth_sample, machine); + process(event, &synth_sample, session); } } @@ -238,14 +206,14 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool, return 0; } -int perf_event__synthesize_modules(struct perf_tool *tool, - perf_event__handler_t process, +int perf_event__synthesize_modules(perf_event__handler_t process, + struct perf_session *session, struct machine *machine) { struct rb_node *nd; struct map_groups *kmaps = &machine->kmaps; union perf_event *event = zalloc((sizeof(event->mmap) + - machine->id_hdr_size)); + session->id_hdr_size)); if (event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); @@ -275,15 +243,15 @@ int perf_event__synthesize_modules(struct perf_tool *tool, event->mmap.header.type = PERF_RECORD_MMAP; event->mmap.header.size = (sizeof(event->mmap) - (sizeof(event->mmap.filename) - size)); - memset(event->mmap.filename + size, 0, machine->id_hdr_size); - event->mmap.header.size += machine->id_hdr_size; + memset(event->mmap.filename + size, 0, session->id_hdr_size); + event->mmap.header.size += session->id_hdr_size; event->mmap.start = pos->start; event->mmap.len = pos->end - pos->start; event->mmap.pid = machine->pid; memcpy(event->mmap.filename, pos->dso->long_name, pos->dso->long_name_len + 1); - process(tool, event, &synth_sample, machine); + process(event, &synth_sample, session); } free(event); @@ -292,69 +260,40 @@ int perf_event__synthesize_modules(struct perf_tool *tool, static int __event__synthesize_thread(union perf_event *comm_event, union perf_event *mmap_event, - pid_t pid, int full, - perf_event__handler_t process, - struct perf_tool *tool, - struct machine *machine) + pid_t pid, perf_event__handler_t process, + struct perf_session *session) { - pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full, - process, machine); + pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process, + session); if (tgid == -1) return -1; - return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, - process, machine); + return perf_event__synthesize_mmap_events(mmap_event, pid, tgid, + process, session); } -int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct thread_map *threads, +int perf_event__synthesize_thread_map(struct thread_map *threads, perf_event__handler_t process, - struct machine *machine) + struct perf_session *session) { union perf_event *comm_event, *mmap_event; - int err = -1, thread, j; + int err = -1, thread; - comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); + comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); if (comm_event == NULL) goto out; - mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); + mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); if (mmap_event == NULL) goto out_free_comm; err = 0; for (thread = 0; thread < threads->nr; ++thread) { if (__event__synthesize_thread(comm_event, mmap_event, - threads->map[thread], 0, - process, tool, machine)) { + threads->map[thread], + process, session)) { err = -1; break; } - - /* - * comm.pid is set to thread group id by - * perf_event__synthesize_comm - */ - if ((int) comm_event->comm.pid != threads->map[thread]) { - bool need_leader = true; - - /* is thread group leader in thread_map? */ - for (j = 0; j < threads->nr; ++j) { - if ((int) comm_event->comm.pid == threads->map[j]) { - need_leader = false; - break; - } - } - - /* if not, generate events for it */ - if (need_leader && - __event__synthesize_thread(comm_event, - mmap_event, - comm_event->comm.pid, 0, - process, tool, machine)) { - err = -1; - break; - } - } } free(mmap_event); out_free_comm: @@ -363,20 +302,19 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, return err; } -int perf_event__synthesize_threads(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) +int perf_event__synthesize_threads(perf_event__handler_t process, + struct perf_session *session) { DIR *proc; struct dirent dirent, *next; union perf_event *comm_event, *mmap_event; int err = -1; - comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); + comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); if (comm_event == NULL) goto out; - mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); + mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size); if (mmap_event == NULL) goto out_free_comm; @@ -391,8 +329,8 @@ int perf_event__synthesize_threads(struct perf_tool *tool, if (*end) /* only interested in proper numerical dirents */ continue; - __event__synthesize_thread(comm_event, mmap_event, pid, 1, - process, tool, machine); + __event__synthesize_thread(comm_event, mmap_event, pid, + process, session); } closedir(proc); @@ -427,8 +365,8 @@ static int find_symbol_cb(void *arg, const char *name, char type, return 1; } -int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, - perf_event__handler_t process, +int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, + struct perf_session *session, struct machine *machine, const char *symbol_name) { @@ -445,7 +383,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, */ struct process_symbol_args args = { .name = symbol_name, }; union perf_event *event = zalloc((sizeof(event->mmap) + - machine->id_hdr_size)); + session->id_hdr_size)); if (event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); @@ -479,32 +417,25 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, size = ALIGN(size, sizeof(u64)); event->mmap.header.type = PERF_RECORD_MMAP; event->mmap.header.size = (sizeof(event->mmap) - - (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); + (sizeof(event->mmap.filename) - size) + session->id_hdr_size); event->mmap.pgoff = args.start; event->mmap.start = map->start; event->mmap.len = map->end - event->mmap.start; event->mmap.pid = machine->pid; - err = process(tool, event, &synth_sample, machine); + err = process(event, &synth_sample, session); free(event); return err; } -size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) -{ - return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); -} - -int perf_event__process_comm(struct perf_tool *tool __used, - union perf_event *event, +int perf_event__process_comm(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine) + struct perf_session *session) { - struct thread *thread = machine__findnew_thread(machine, event->comm.tid); + struct thread *thread = perf_session__findnew(session, event->comm.tid); - if (dump_trace) - perf_event__fprintf_comm(event, stdout); + dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid); if (thread == NULL || thread__set_comm(thread, event->comm.comm)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); @@ -514,13 +445,13 @@ int perf_event__process_comm(struct perf_tool *tool __used, return 0; } -int perf_event__process_lost(struct perf_tool *tool __used, - union perf_event *event, +int perf_event__process_lost(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine __used) + struct perf_session *session) { dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", event->lost.id, event->lost.lost); + session->hists.stats.total_lost += event->lost.lost; return 0; } @@ -537,15 +468,21 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event, maps[MAP__FUNCTION]->end = ~0ULL; } -static int perf_event__process_kernel_mmap(struct perf_tool *tool __used, - union perf_event *event, - struct machine *machine) +static int perf_event__process_kernel_mmap(union perf_event *event, + struct perf_session *session) { struct map *map; char kmmap_prefix[PATH_MAX]; + struct machine *machine; enum dso_kernel_type kernel_type; bool is_kernel_mmap; + machine = perf_session__findnew_machine(session, event->mmap.pid); + if (!machine) { + pr_err("Can't find id %d's machine\n", event->mmap.pid); + goto out_problem; + } + machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix)); if (machine__is_host(machine)) kernel_type = DSO_TYPE_KERNEL; @@ -612,9 +549,9 @@ static int perf_event__process_kernel_mmap(struct perf_tool *tool __used, * time /proc/sys/kernel/kptr_restrict was non zero. */ if (event->mmap.pgoff != 0) { - maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, - symbol_name, - event->mmap.pgoff); + perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, + symbol_name, + event->mmap.pgoff); } if (machine__is_default_guest(machine)) { @@ -630,35 +567,32 @@ static int perf_event__process_kernel_mmap(struct perf_tool *tool __used, return -1; } -size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) -{ - return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", - event->mmap.pid, event->mmap.tid, event->mmap.start, - event->mmap.len, event->mmap.pgoff, event->mmap.filename); -} - -int perf_event__process_mmap(struct perf_tool *tool, - union perf_event *event, +int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine) + struct perf_session *session) { + struct machine *machine; struct thread *thread; struct map *map; u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; int ret = 0; - if (dump_trace) - perf_event__fprintf_mmap(event, stdout); + dump_printf(" %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", + event->mmap.pid, event->mmap.tid, event->mmap.start, + event->mmap.len, event->mmap.pgoff, event->mmap.filename); if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || cpumode == PERF_RECORD_MISC_KERNEL) { - ret = perf_event__process_kernel_mmap(tool, event, machine); + ret = perf_event__process_kernel_mmap(event, session); if (ret < 0) goto out_problem; return 0; } - thread = machine__findnew_thread(machine, event->mmap.pid); + machine = perf_session__find_host_machine(session); + if (machine == NULL) + goto out_problem; + thread = perf_session__findnew(session, event->mmap.pid); if (thread == NULL) goto out_problem; map = map__new(&machine->user_dsos, event->mmap.start, @@ -676,26 +610,18 @@ int perf_event__process_mmap(struct perf_tool *tool, return 0; } -size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) -{ - return fprintf(fp, "(%d:%d):(%d:%d)\n", - event->fork.pid, event->fork.tid, - event->fork.ppid, event->fork.ptid); -} - -int perf_event__process_task(struct perf_tool *tool __used, - union perf_event *event, +int perf_event__process_task(union perf_event *event, struct perf_sample *sample __used, - struct machine *machine) + struct perf_session *session) { - struct thread *thread = machine__findnew_thread(machine, event->fork.tid); - struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); + struct thread *thread = perf_session__findnew(session, event->fork.tid); + struct thread *parent = perf_session__findnew(session, event->fork.ptid); - if (dump_trace) - perf_event__fprintf_task(event, stdout); + dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, + event->fork.ppid, event->fork.ptid); if (event->header.type == PERF_RECORD_EXIT) { - machine__remove_thread(machine, thread); + perf_session__remove_thread(session, thread); return 0; } @@ -708,45 +634,22 @@ int perf_event__process_task(struct perf_tool *tool __used, return 0; } -size_t perf_event__fprintf(union perf_event *event, FILE *fp) -{ - size_t ret = fprintf(fp, "PERF_RECORD_%s", - perf_event__name(event->header.type)); - - switch (event->header.type) { - case PERF_RECORD_COMM: - ret += perf_event__fprintf_comm(event, fp); - break; - case PERF_RECORD_FORK: - case PERF_RECORD_EXIT: - ret += perf_event__fprintf_task(event, fp); - break; - case PERF_RECORD_MMAP: - ret += perf_event__fprintf_mmap(event, fp); - break; - default: - ret += fprintf(fp, "\n"); - } - - return ret; -} - -int perf_event__process(struct perf_tool *tool, union perf_event *event, - struct perf_sample *sample, struct machine *machine) +int perf_event__process(union perf_event *event, struct perf_sample *sample, + struct perf_session *session) { switch (event->header.type) { case PERF_RECORD_COMM: - perf_event__process_comm(tool, event, sample, machine); + perf_event__process_comm(event, sample, session); break; case PERF_RECORD_MMAP: - perf_event__process_mmap(tool, event, sample, machine); + perf_event__process_mmap(event, sample, session); break; case PERF_RECORD_FORK: case PERF_RECORD_EXIT: - perf_event__process_task(tool, event, sample, machine); + perf_event__process_task(event, sample, session); break; case PERF_RECORD_LOST: - perf_event__process_lost(tool, event, sample, machine); + perf_event__process_lost(event, sample, session); default: break; } @@ -755,29 +658,36 @@ int perf_event__process(struct perf_tool *tool, union perf_event *event, } void thread__find_addr_map(struct thread *self, - struct machine *machine, u8 cpumode, - enum map_type type, u64 addr, + struct perf_session *session, u8 cpumode, + enum map_type type, pid_t pid, u64 addr, struct addr_location *al) { struct map_groups *mg = &self->mg; + struct machine *machine = NULL; al->thread = self; al->addr = addr; al->cpumode = cpumode; al->filtered = false; - if (machine == NULL) { - al->map = NULL; - return; - } - if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { al->level = 'k'; + machine = perf_session__find_host_machine(session); + if (machine == NULL) { + al->map = NULL; + return; + } mg = &machine->kmaps; } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { al->level = '.'; + machine = perf_session__find_host_machine(session); } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { al->level = 'g'; + machine = perf_session__find_machine(session, pid); + if (machine == NULL) { + al->map = NULL; + return; + } mg = &machine->kmaps; } else { /* @@ -823,12 +733,13 @@ void thread__find_addr_map(struct thread *self, al->addr = al->map->map_ip(al->map, al->addr); } -void thread__find_addr_location(struct thread *thread, struct machine *machine, - u8 cpumode, enum map_type type, u64 addr, +void thread__find_addr_location(struct thread *self, + struct perf_session *session, u8 cpumode, + enum map_type type, pid_t pid, u64 addr, struct addr_location *al, symbol_filter_t filter) { - thread__find_addr_map(thread, machine, cpumode, type, addr, al); + thread__find_addr_map(self, session, cpumode, type, pid, addr, al); if (al->map != NULL) al->sym = map__find_symbol(al->map, al->addr, filter); else @@ -836,13 +747,13 @@ void thread__find_addr_location(struct thread *thread, struct machine *machine, } int perf_event__preprocess_sample(const union perf_event *event, - struct machine *machine, + struct perf_session *session, struct addr_location *al, struct perf_sample *sample, symbol_filter_t filter) { u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - struct thread *thread = machine__findnew_thread(machine, event->ip.pid); + struct thread *thread = perf_session__findnew(session, event->ip.pid); if (thread == NULL) return -1; @@ -853,18 +764,18 @@ int perf_event__preprocess_sample(const union perf_event *event, dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); /* - * Have we already created the kernel maps for this machine? + * Have we already created the kernel maps for the host machine? * * This should have happened earlier, when we processed the kernel MMAP * events, but for older perf.data files there was no such thing, so do * it now. */ if (cpumode == PERF_RECORD_MISC_KERNEL && - machine->vmlinux_maps[MAP__FUNCTION] == NULL) - machine__create_kernel_maps(machine); + session->host_machine.vmlinux_maps[MAP__FUNCTION] == NULL) + machine__create_kernel_maps(&session->host_machine); - thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, - event->ip.ip, al); + thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, + event->ip.pid, event->ip.ip, al); dump_printf(" ...... dso: %s\n", al->map ? al->map->dso->long_name : al->level == 'H' ? "[hypervisor]" : ""); @@ -872,14 +783,13 @@ int perf_event__preprocess_sample(const union perf_event *event, al->cpu = sample->cpu; if (al->map) { - struct dso *dso = al->map->dso; - if (symbol_conf.dso_list && - (!dso || !(strlist__has_entry(symbol_conf.dso_list, - dso->short_name) || - (dso->short_name != dso->long_name && - strlist__has_entry(symbol_conf.dso_list, - dso->long_name))))) + (!al->map || !al->map->dso || + !(strlist__has_entry(symbol_conf.dso_list, + al->map->dso->short_name) || + (al->map->dso->short_name != al->map->dso->long_name && + strlist__has_entry(symbol_conf.dso_list, + al->map->dso->long_name))))) goto out_filtered; al->sym = map__find_symbol(al->map, al->addr, filter); diff --git a/trunk/tools/perf/util/event.h b/trunk/tools/perf/util/event.h index cbdeaad9c5e5..357a85b85248 100644 --- a/trunk/tools/perf/util/event.h +++ b/trunk/tools/perf/util/event.h @@ -2,7 +2,6 @@ #define __PERF_RECORD_H #include -#include #include "../perf.h" #include "map.h" @@ -142,54 +141,43 @@ union perf_event { void perf_event__print_totals(void); -struct perf_tool; +struct perf_session; struct thread_map; -typedef int (*perf_event__handler_t)(struct perf_tool *tool, - union perf_event *event, +typedef int (*perf_event__handler_synth_t)(union perf_event *event, + struct perf_session *session); +typedef int (*perf_event__handler_t)(union perf_event *event, struct perf_sample *sample, - struct machine *machine); + struct perf_session *session); -int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct thread_map *threads, +int perf_event__synthesize_thread_map(struct thread_map *threads, perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_threads(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, - perf_event__handler_t process, + struct perf_session *session); +int perf_event__synthesize_threads(perf_event__handler_t process, + struct perf_session *session); +int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, + struct perf_session *session, struct machine *machine, const char *symbol_name); -int perf_event__synthesize_modules(struct perf_tool *tool, - perf_event__handler_t process, +int perf_event__synthesize_modules(perf_event__handler_t process, + struct perf_session *session, struct machine *machine); -int perf_event__process_comm(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); -int perf_event__process_lost(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); -int perf_event__process_mmap(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); -int perf_event__process_task(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); -int perf_event__process(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); +int perf_event__process_comm(union perf_event *event, struct perf_sample *sample, + struct perf_session *session); +int perf_event__process_lost(union perf_event *event, struct perf_sample *sample, + struct perf_session *session); +int perf_event__process_mmap(union perf_event *event, struct perf_sample *sample, + struct perf_session *session); +int perf_event__process_task(union perf_event *event, struct perf_sample *sample, + struct perf_session *session); +int perf_event__process(union perf_event *event, struct perf_sample *sample, + struct perf_session *session); struct addr_location; int perf_event__preprocess_sample(const union perf_event *self, - struct machine *machine, + struct perf_session *session, struct addr_location *al, struct perf_sample *sample, symbol_filter_t filter); @@ -199,13 +187,5 @@ const char *perf_event__name(unsigned int id); int perf_event__parse_sample(const union perf_event *event, u64 type, int sample_size, bool sample_id_all, struct perf_sample *sample, bool swapped); -int perf_event__synthesize_sample(union perf_event *event, u64 type, - const struct perf_sample *sample, - bool swapped); - -size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); -size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); -size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); -size_t perf_event__fprintf(union perf_event *event, FILE *fp); #endif /* __PERF_RECORD_H */ diff --git a/trunk/tools/perf/util/evlist.c b/trunk/tools/perf/util/evlist.c index fa1837088ca8..fbb4b4ab9cc6 100644 --- a/trunk/tools/perf/util/evlist.c +++ b/trunk/tools/perf/util/evlist.c @@ -6,16 +6,12 @@ * * Released under the GPL v2. (and only v2, not any later version) */ -#include "util.h" -#include "debugfs.h" #include #include "cpumap.h" #include "thread_map.h" #include "evlist.h" #include "evsel.h" -#include - -#include "parse-events.h" +#include "util.h" #include @@ -34,7 +30,6 @@ void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, INIT_HLIST_HEAD(&evlist->heads[i]); INIT_LIST_HEAD(&evlist->entries); perf_evlist__set_maps(evlist, cpus, threads); - evlist->workload.pid = -1; } struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, @@ -48,22 +43,6 @@ struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, return evlist; } -void perf_evlist__config_attrs(struct perf_evlist *evlist, - struct perf_record_opts *opts) -{ - struct perf_evsel *evsel; - - if (evlist->cpus->map[0] < 0) - opts->no_inherit = true; - - list_for_each_entry(evsel, &evlist->entries, node) { - perf_evsel__config(evsel, opts); - - if (evlist->nr_entries > 1) - evsel->attr.sample_type |= PERF_SAMPLE_ID; - } -} - static void perf_evlist__purge(struct perf_evlist *evlist) { struct perf_evsel *pos, *n; @@ -97,14 +76,6 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) ++evlist->nr_entries; } -static void perf_evlist__splice_list_tail(struct perf_evlist *evlist, - struct list_head *list, - int nr_entries) -{ - list_splice_tail(list, &evlist->entries); - evlist->nr_entries += nr_entries; -} - int perf_evlist__add_default(struct perf_evlist *evlist) { struct perf_event_attr attr = { @@ -129,126 +100,6 @@ int perf_evlist__add_default(struct perf_evlist *evlist) return -ENOMEM; } -int perf_evlist__add_attrs(struct perf_evlist *evlist, - struct perf_event_attr *attrs, size_t nr_attrs) -{ - struct perf_evsel *evsel, *n; - LIST_HEAD(head); - size_t i; - - for (i = 0; i < nr_attrs; i++) { - evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i); - if (evsel == NULL) - goto out_delete_partial_list; - list_add_tail(&evsel->node, &head); - } - - perf_evlist__splice_list_tail(evlist, &head, nr_attrs); - - return 0; - -out_delete_partial_list: - list_for_each_entry_safe(evsel, n, &head, node) - perf_evsel__delete(evsel); - return -1; -} - -static int trace_event__id(const char *evname) -{ - char *filename, *colon; - int err = -1, fd; - - if (asprintf(&filename, "%s/%s/id", tracing_events_path, evname) < 0) - return -1; - - colon = strrchr(filename, ':'); - if (colon != NULL) - *colon = '/'; - - fd = open(filename, O_RDONLY); - if (fd >= 0) { - char id[16]; - if (read(fd, id, sizeof(id)) > 0) - err = atoi(id); - close(fd); - } - - free(filename); - return err; -} - -int perf_evlist__add_tracepoints(struct perf_evlist *evlist, - const char *tracepoints[], - size_t nr_tracepoints) -{ - int err; - size_t i; - struct perf_event_attr *attrs = zalloc(nr_tracepoints * sizeof(*attrs)); - - if (attrs == NULL) - return -1; - - for (i = 0; i < nr_tracepoints; i++) { - err = trace_event__id(tracepoints[i]); - - if (err < 0) - goto out_free_attrs; - - attrs[i].type = PERF_TYPE_TRACEPOINT; - attrs[i].config = err; - attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | - PERF_SAMPLE_CPU); - attrs[i].sample_period = 1; - } - - err = perf_evlist__add_attrs(evlist, attrs, nr_tracepoints); -out_free_attrs: - free(attrs); - return err; -} - -static struct perf_evsel * - perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) -{ - struct perf_evsel *evsel; - - list_for_each_entry(evsel, &evlist->entries, node) { - if (evsel->attr.type == PERF_TYPE_TRACEPOINT && - (int)evsel->attr.config == id) - return evsel; - } - - return NULL; -} - -int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, - const struct perf_evsel_str_handler *assocs, - size_t nr_assocs) -{ - struct perf_evsel *evsel; - int err; - size_t i; - - for (i = 0; i < nr_assocs; i++) { - err = trace_event__id(assocs[i].name); - if (err < 0) - goto out; - - evsel = perf_evlist__find_tracepoint_by_id(evlist, err); - if (evsel == NULL) - continue; - - err = -EEXIST; - if (evsel->handler.func != NULL) - goto out; - evsel->handler.func = assocs[i].handler; - } - - err = 0; -out: - return err; -} - void perf_evlist__disable(struct perf_evlist *evlist) { int cpu, thread; @@ -275,7 +126,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) } } -static int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) +int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) { int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); @@ -431,7 +282,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist) evlist->mmap = NULL; } -static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) +int perf_evlist__alloc_mmap(struct perf_evlist *evlist) { evlist->nr_mmaps = evlist->cpus->nr; if (evlist->cpus->map[0] == -1) @@ -447,10 +298,8 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, evlist->mmap[idx].mask = mask; evlist->mmap[idx].base = mmap(NULL, evlist->mmap_len, prot, MAP_SHARED, fd, 0); - if (evlist->mmap[idx].base == MAP_FAILED) { - evlist->mmap[idx].base = NULL; + if (evlist->mmap[idx].base == MAP_FAILED) return -1; - } perf_evlist__add_pollfd(evlist, fd); return 0; @@ -551,22 +400,14 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in * * Using perf_evlist__read_on_cpu does this automatically. */ -int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, - bool overwrite) +int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) { unsigned int page_size = sysconf(_SC_PAGE_SIZE); + int mask = pages * page_size - 1; struct perf_evsel *evsel; const struct cpu_map *cpus = evlist->cpus; const struct thread_map *threads = evlist->threads; - int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE), mask; - - /* 512 kiB: default amount of unprivileged mlocked memory */ - if (pages == UINT_MAX) - pages = (512 * 1024) / page_size; - else if (!is_power_of_2(pages)) - return -EINVAL; - - mask = pages * page_size - 1; + int prot = PROT_READ | (overwrite ? 0 : PROT_WRITE); if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) return -ENOMEM; @@ -671,38 +512,6 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist) return first->attr.sample_type; } -u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist) -{ - struct perf_evsel *first; - struct perf_sample *data; - u64 sample_type; - u16 size = 0; - - first = list_entry(evlist->entries.next, struct perf_evsel, node); - - if (!first->attr.sample_id_all) - goto out; - - sample_type = first->attr.sample_type; - - if (sample_type & PERF_SAMPLE_TID) - size += sizeof(data->tid) * 2; - - if (sample_type & PERF_SAMPLE_TIME) - size += sizeof(data->time); - - if (sample_type & PERF_SAMPLE_ID) - size += sizeof(data->id); - - if (sample_type & PERF_SAMPLE_STREAM_ID) - size += sizeof(data->stream_id); - - if (sample_type & PERF_SAMPLE_CPU) - size += sizeof(data->cpu) * 2; -out: - return size; -} - bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist) { struct perf_evsel *pos, *first; @@ -760,97 +569,3 @@ int perf_evlist__open(struct perf_evlist *evlist, bool group) return err; } - -int perf_evlist__prepare_workload(struct perf_evlist *evlist, - struct perf_record_opts *opts, - const char *argv[]) -{ - int child_ready_pipe[2], go_pipe[2]; - char bf; - - if (pipe(child_ready_pipe) < 0) { - perror("failed to create 'ready' pipe"); - return -1; - } - - if (pipe(go_pipe) < 0) { - perror("failed to create 'go' pipe"); - goto out_close_ready_pipe; - } - - evlist->workload.pid = fork(); - if (evlist->workload.pid < 0) { - perror("failed to fork"); - goto out_close_pipes; - } - - if (!evlist->workload.pid) { - if (opts->pipe_output) - dup2(2, 1); - - close(child_ready_pipe[0]); - close(go_pipe[1]); - fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC); - - /* - * Do a dummy execvp to get the PLT entry resolved, - * so we avoid the resolver overhead on the real - * execvp call. - */ - execvp("", (char **)argv); - - /* - * Tell the parent we're ready to go - */ - close(child_ready_pipe[1]); - - /* - * Wait until the parent tells us to go. - */ - if (read(go_pipe[0], &bf, 1) == -1) - perror("unable to read pipe"); - - execvp(argv[0], (char **)argv); - - perror(argv[0]); - kill(getppid(), SIGUSR1); - exit(-1); - } - - if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) - evlist->threads->map[0] = evlist->workload.pid; - - close(child_ready_pipe[1]); - close(go_pipe[0]); - /* - * wait for child to settle - */ - if (read(child_ready_pipe[0], &bf, 1) == -1) { - perror("unable to read pipe"); - goto out_close_pipes; - } - - evlist->workload.cork_fd = go_pipe[1]; - close(child_ready_pipe[0]); - return 0; - -out_close_pipes: - close(go_pipe[0]); - close(go_pipe[1]); -out_close_ready_pipe: - close(child_ready_pipe[0]); - close(child_ready_pipe[1]); - return -1; -} - -int perf_evlist__start_workload(struct perf_evlist *evlist) -{ - if (evlist->workload.cork_fd > 0) { - /* - * Remove the cork, let it rip! - */ - return close(evlist->workload.cork_fd); - } - - return 0; -} diff --git a/trunk/tools/perf/util/evlist.h b/trunk/tools/perf/util/evlist.h index 8922aeed0467..1779ffef7828 100644 --- a/trunk/tools/perf/util/evlist.h +++ b/trunk/tools/perf/util/evlist.h @@ -2,16 +2,12 @@ #define __PERF_EVLIST_H 1 #include -#include #include "../perf.h" #include "event.h" -#include "util.h" -#include struct pollfd; struct thread_map; struct cpu_map; -struct perf_record_opts; #define PERF_EVLIST__HLIST_BITS 8 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) @@ -23,10 +19,6 @@ struct perf_evlist { int nr_fds; int nr_mmaps; int mmap_len; - struct { - int cork_fd; - pid_t pid; - } workload; bool overwrite; union perf_event event_copy; struct perf_mmap *mmap; @@ -36,11 +28,6 @@ struct perf_evlist { struct perf_evsel *selected; }; -struct perf_evsel_str_handler { - const char *name; - void *handler; -}; - struct perf_evsel; struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, @@ -52,26 +39,11 @@ void perf_evlist__delete(struct perf_evlist *evlist); void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); int perf_evlist__add_default(struct perf_evlist *evlist); -int perf_evlist__add_attrs(struct perf_evlist *evlist, - struct perf_event_attr *attrs, size_t nr_attrs); -int perf_evlist__add_tracepoints(struct perf_evlist *evlist, - const char *tracepoints[], size_t nr_tracepoints); -int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, - const struct perf_evsel_str_handler *assocs, - size_t nr_assocs); - -#define perf_evlist__add_attrs_array(evlist, array) \ - perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) - -#define perf_evlist__add_tracepoints_array(evlist, array) \ - perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) - -#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ - perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, int cpu, int thread, u64 id); +int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); @@ -80,16 +52,8 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *self, int idx); int perf_evlist__open(struct perf_evlist *evlist, bool group); -void perf_evlist__config_attrs(struct perf_evlist *evlist, - struct perf_record_opts *opts); - -int perf_evlist__prepare_workload(struct perf_evlist *evlist, - struct perf_record_opts *opts, - const char *argv[]); -int perf_evlist__start_workload(struct perf_evlist *evlist); - -int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, - bool overwrite); +int perf_evlist__alloc_mmap(struct perf_evlist *evlist); +int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); void perf_evlist__munmap(struct perf_evlist *evlist); void perf_evlist__disable(struct perf_evlist *evlist); @@ -113,7 +77,6 @@ int perf_evlist__set_filters(struct perf_evlist *evlist); u64 perf_evlist__sample_type(const struct perf_evlist *evlist); bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist); -u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist); bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist); bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist); diff --git a/trunk/tools/perf/util/evsel.c b/trunk/tools/perf/util/evsel.c index 667f3b78bb2c..d7915d4e77cb 100644 --- a/trunk/tools/perf/util/evsel.c +++ b/trunk/tools/perf/util/evsel.c @@ -63,79 +63,6 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) return evsel; } -void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts) -{ - struct perf_event_attr *attr = &evsel->attr; - int track = !evsel->idx; /* only the first counter needs these */ - - attr->sample_id_all = opts->sample_id_all_avail ? 1 : 0; - attr->inherit = !opts->no_inherit; - attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | - PERF_FORMAT_TOTAL_TIME_RUNNING | - PERF_FORMAT_ID; - - attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; - - /* - * We default some events to a 1 default interval. But keep - * it a weak assumption overridable by the user. - */ - if (!attr->sample_period || (opts->user_freq != UINT_MAX && - opts->user_interval != ULLONG_MAX)) { - if (opts->freq) { - attr->sample_type |= PERF_SAMPLE_PERIOD; - attr->freq = 1; - attr->sample_freq = opts->freq; - } else { - attr->sample_period = opts->default_interval; - } - } - - if (opts->no_samples) - attr->sample_freq = 0; - - if (opts->inherit_stat) - attr->inherit_stat = 1; - - if (opts->sample_address) { - attr->sample_type |= PERF_SAMPLE_ADDR; - attr->mmap_data = track; - } - - if (opts->call_graph) - attr->sample_type |= PERF_SAMPLE_CALLCHAIN; - - if (opts->system_wide) - attr->sample_type |= PERF_SAMPLE_CPU; - - if (opts->period) - attr->sample_type |= PERF_SAMPLE_PERIOD; - - if (opts->sample_id_all_avail && - (opts->sample_time || opts->system_wide || - !opts->no_inherit || opts->cpu_list)) - attr->sample_type |= PERF_SAMPLE_TIME; - - if (opts->raw_samples) { - attr->sample_type |= PERF_SAMPLE_TIME; - attr->sample_type |= PERF_SAMPLE_RAW; - attr->sample_type |= PERF_SAMPLE_CPU; - } - - if (opts->no_delay) { - attr->watermark = 0; - attr->wakeup_events = 1; - } - - attr->mmap = track; - attr->comm = track; - - if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { - attr->disabled = 1; - attr->enable_on_exec = 1; - } -} - int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) { int cpu, thread; @@ -460,7 +387,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, u32 val32[2]; } u; - memset(data, 0, sizeof(*data)); + data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; @@ -577,82 +504,3 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, return 0; } - -int perf_event__synthesize_sample(union perf_event *event, u64 type, - const struct perf_sample *sample, - bool swapped) -{ - u64 *array; - - /* - * used for cross-endian analysis. See git commit 65014ab3 - * for why this goofiness is needed. - */ - union { - u64 val64; - u32 val32[2]; - } u; - - array = event->sample.array; - - if (type & PERF_SAMPLE_IP) { - event->ip.ip = sample->ip; - array++; - } - - if (type & PERF_SAMPLE_TID) { - u.val32[0] = sample->pid; - u.val32[1] = sample->tid; - if (swapped) { - /* - * Inverse of what is done in perf_event__parse_sample - */ - u.val32[0] = bswap_32(u.val32[0]); - u.val32[1] = bswap_32(u.val32[1]); - u.val64 = bswap_64(u.val64); - } - - *array = u.val64; - array++; - } - - if (type & PERF_SAMPLE_TIME) { - *array = sample->time; - array++; - } - - if (type & PERF_SAMPLE_ADDR) { - *array = sample->addr; - array++; - } - - if (type & PERF_SAMPLE_ID) { - *array = sample->id; - array++; - } - - if (type & PERF_SAMPLE_STREAM_ID) { - *array = sample->stream_id; - array++; - } - - if (type & PERF_SAMPLE_CPU) { - u.val32[0] = sample->cpu; - if (swapped) { - /* - * Inverse of what is done in perf_event__parse_sample - */ - u.val32[0] = bswap_32(u.val32[0]); - u.val64 = bswap_64(u.val64); - } - *array = u.val64; - array++; - } - - if (type & PERF_SAMPLE_PERIOD) { - *array = sample->period; - array++; - } - - return 0; -} diff --git a/trunk/tools/perf/util/evsel.h b/trunk/tools/perf/util/evsel.h index 326b8e4d5035..b1d15e6f7ae3 100644 --- a/trunk/tools/perf/util/evsel.h +++ b/trunk/tools/perf/util/evsel.h @@ -61,17 +61,12 @@ struct perf_evsel { off_t id_offset; }; struct cgroup_sel *cgrp; - struct { - void *func; - void *data; - } handler; bool supported; }; struct cpu_map; struct thread_map; struct perf_evlist; -struct perf_record_opts; struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); void perf_evsel__init(struct perf_evsel *evsel, @@ -79,9 +74,6 @@ void perf_evsel__init(struct perf_evsel *evsel, void perf_evsel__exit(struct perf_evsel *evsel); void perf_evsel__delete(struct perf_evsel *evsel); -void perf_evsel__config(struct perf_evsel *evsel, - struct perf_record_opts *opts); - int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); diff --git a/trunk/tools/perf/util/header.c b/trunk/tools/perf/util/header.c index 3e7e0b09c12c..33c17a2b2a81 100644 --- a/trunk/tools/perf/util/header.c +++ b/trunk/tools/perf/util/header.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "evlist.h" @@ -29,6 +28,9 @@ static struct perf_trace_event_type *events; static u32 header_argc; static const char **header_argv; +static int dsos__write_buildid_table(struct perf_header *header, int fd); +static int perf_session__cache_build_ids(struct perf_session *session); + int perf_header__push_event(u64 id, const char *name) { if (strlen(name) > MAX_EVENT_NAME) @@ -185,252 +187,6 @@ perf_header__set_cmdline(int argc, const char **argv) return 0; } -#define dsos__for_each_with_build_id(pos, head) \ - list_for_each_entry(pos, head, node) \ - if (!pos->has_build_id) \ - continue; \ - else - -static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, - u16 misc, int fd) -{ - struct dso *pos; - - dsos__for_each_with_build_id(pos, head) { - int err; - struct build_id_event b; - size_t len; - - if (!pos->hit) - continue; - len = pos->long_name_len + 1; - len = ALIGN(len, NAME_ALIGN); - memset(&b, 0, sizeof(b)); - memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); - b.pid = pid; - b.header.misc = misc; - b.header.size = sizeof(b) + len; - err = do_write(fd, &b, sizeof(b)); - if (err < 0) - return err; - err = write_padded(fd, pos->long_name, - pos->long_name_len + 1, len); - if (err < 0) - return err; - } - - return 0; -} - -static int machine__write_buildid_table(struct machine *machine, int fd) -{ - int err; - u16 kmisc = PERF_RECORD_MISC_KERNEL, - umisc = PERF_RECORD_MISC_USER; - - if (!machine__is_host(machine)) { - kmisc = PERF_RECORD_MISC_GUEST_KERNEL; - umisc = PERF_RECORD_MISC_GUEST_USER; - } - - err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, - kmisc, fd); - if (err == 0) - err = __dsos__write_buildid_table(&machine->user_dsos, - machine->pid, umisc, fd); - return err; -} - -static int dsos__write_buildid_table(struct perf_header *header, int fd) -{ - struct perf_session *session = container_of(header, - struct perf_session, header); - struct rb_node *nd; - int err = machine__write_buildid_table(&session->host_machine, fd); - - if (err) - return err; - - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - err = machine__write_buildid_table(pos, fd); - if (err) - break; - } - return err; -} - -int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, - const char *name, bool is_kallsyms) -{ - const size_t size = PATH_MAX; - char *realname, *filename = zalloc(size), - *linkname = zalloc(size), *targetname; - int len, err = -1; - - if (is_kallsyms) { - if (symbol_conf.kptr_restrict) { - pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); - return 0; - } - realname = (char *)name; - } else - realname = realpath(name, NULL); - - if (realname == NULL || filename == NULL || linkname == NULL) - goto out_free; - - len = snprintf(filename, size, "%s%s%s", - debugdir, is_kallsyms ? "/" : "", realname); - if (mkdir_p(filename, 0755)) - goto out_free; - - snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); - - if (access(filename, F_OK)) { - if (is_kallsyms) { - if (copyfile("/proc/kallsyms", filename)) - goto out_free; - } else if (link(realname, filename) && copyfile(name, filename)) - goto out_free; - } - - len = snprintf(linkname, size, "%s/.build-id/%.2s", - debugdir, sbuild_id); - - if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) - goto out_free; - - snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); - targetname = filename + strlen(debugdir) - 5; - memcpy(targetname, "../..", 5); - - if (symlink(targetname, linkname) == 0) - err = 0; -out_free: - if (!is_kallsyms) - free(realname); - free(filename); - free(linkname); - return err; -} - -static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, - const char *name, const char *debugdir, - bool is_kallsyms) -{ - char sbuild_id[BUILD_ID_SIZE * 2 + 1]; - - build_id__sprintf(build_id, build_id_size, sbuild_id); - - return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); -} - -int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) -{ - const size_t size = PATH_MAX; - char *filename = zalloc(size), - *linkname = zalloc(size); - int err = -1; - - if (filename == NULL || linkname == NULL) - goto out_free; - - snprintf(linkname, size, "%s/.build-id/%.2s/%s", - debugdir, sbuild_id, sbuild_id + 2); - - if (access(linkname, F_OK)) - goto out_free; - - if (readlink(linkname, filename, size - 1) < 0) - goto out_free; - - if (unlink(linkname)) - goto out_free; - - /* - * Since the link is relative, we must make it absolute: - */ - snprintf(linkname, size, "%s/.build-id/%.2s/%s", - debugdir, sbuild_id, filename); - - if (unlink(linkname)) - goto out_free; - - err = 0; -out_free: - free(filename); - free(linkname); - return err; -} - -static int dso__cache_build_id(struct dso *dso, const char *debugdir) -{ - bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; - - return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), - dso->long_name, debugdir, is_kallsyms); -} - -static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) -{ - struct dso *pos; - int err = 0; - - dsos__for_each_with_build_id(pos, head) - if (dso__cache_build_id(pos, debugdir)) - err = -1; - - return err; -} - -static int machine__cache_build_ids(struct machine *machine, const char *debugdir) -{ - int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); - ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); - return ret; -} - -static int perf_session__cache_build_ids(struct perf_session *session) -{ - struct rb_node *nd; - int ret; - char debugdir[PATH_MAX]; - - snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); - - if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) - return -1; - - ret = machine__cache_build_ids(&session->host_machine, debugdir); - - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret |= machine__cache_build_ids(pos, debugdir); - } - return ret ? -1 : 0; -} - -static bool machine__read_build_ids(struct machine *machine, bool with_hits) -{ - bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); - ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); - return ret; -} - -static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) -{ - struct rb_node *nd; - bool ret = machine__read_build_ids(&session->host_machine, with_hits); - - for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { - struct machine *pos = rb_entry(nd, struct machine, rb_node); - ret |= machine__read_build_ids(pos, with_hits); - } - - return ret; -} - static int write_trace_info(int fd, struct perf_header *h __used, struct perf_evlist *evlist) { @@ -446,9 +202,6 @@ static int write_build_id(int fd, struct perf_header *h, session = container_of(h, struct perf_session, header); - if (!perf_session__read_build_ids(session, true)) - return -1; - err = dsos__write_buildid_table(h, fd); if (err < 0) { pr_debug("failed to write buildid table\n"); @@ -1312,30 +1065,26 @@ struct feature_ops { bool full_only; }; -#define FEAT_OPA(n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func } -#define FEAT_OPF(n, func) \ - [n] = { .name = #n, .write = write_##func, .print = print_##func, .full_only = true } - -/* feature_ops not implemented: */ -#define print_trace_info NULL -#define print_build_id NULL +#define FEAT_OPA(n, w, p) \ + [n] = { .name = #n, .write = w, .print = p } +#define FEAT_OPF(n, w, p) \ + [n] = { .name = #n, .write = w, .print = p, .full_only = true } static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { - FEAT_OPA(HEADER_TRACE_INFO, trace_info), - FEAT_OPA(HEADER_BUILD_ID, build_id), - FEAT_OPA(HEADER_HOSTNAME, hostname), - FEAT_OPA(HEADER_OSRELEASE, osrelease), - FEAT_OPA(HEADER_VERSION, version), - FEAT_OPA(HEADER_ARCH, arch), - FEAT_OPA(HEADER_NRCPUS, nrcpus), - FEAT_OPA(HEADER_CPUDESC, cpudesc), - FEAT_OPA(HEADER_CPUID, cpuid), - FEAT_OPA(HEADER_TOTAL_MEM, total_mem), - FEAT_OPA(HEADER_EVENT_DESC, event_desc), - FEAT_OPA(HEADER_CMDLINE, cmdline), - FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), - FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), + FEAT_OPA(HEADER_TRACE_INFO, write_trace_info, NULL), + FEAT_OPA(HEADER_BUILD_ID, write_build_id, NULL), + FEAT_OPA(HEADER_HOSTNAME, write_hostname, print_hostname), + FEAT_OPA(HEADER_OSRELEASE, write_osrelease, print_osrelease), + FEAT_OPA(HEADER_VERSION, write_version, print_version), + FEAT_OPA(HEADER_ARCH, write_arch, print_arch), + FEAT_OPA(HEADER_NRCPUS, write_nrcpus, print_nrcpus), + FEAT_OPA(HEADER_CPUDESC, write_cpudesc, print_cpudesc), + FEAT_OPA(HEADER_CPUID, write_cpuid, print_cpuid), + FEAT_OPA(HEADER_TOTAL_MEM, write_total_mem, print_total_mem), + FEAT_OPA(HEADER_EVENT_DESC, write_event_desc, print_event_desc), + FEAT_OPA(HEADER_CMDLINE, write_cmdline, print_cmdline), + FEAT_OPF(HEADER_CPU_TOPOLOGY, write_cpu_topology, print_cpu_topology), + FEAT_OPF(HEADER_NUMA_TOPOLOGY, write_numa_topology, print_numa_topology), }; struct header_print_data { @@ -1354,9 +1103,9 @@ static int perf_file_section__fprintf_info(struct perf_file_section *section, "%d, continuing...\n", section->offset, feat); return 0; } - if (feat >= HEADER_LAST_FEATURE) { + if (feat < HEADER_TRACE_INFO || feat >= HEADER_LAST_FEATURE) { pr_warning("unknown feature %d\n", feat); - return 0; + return -1; } if (!feat_ops[feat].print) return 0; @@ -1383,16 +1132,260 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) return 0; } -static int do_write_feat(int fd, struct perf_header *h, int type, - struct perf_file_section **p, - struct perf_evlist *evlist) -{ +#define dsos__for_each_with_build_id(pos, head) \ + list_for_each_entry(pos, head, node) \ + if (!pos->has_build_id) \ + continue; \ + else + +static int __dsos__write_buildid_table(struct list_head *head, pid_t pid, + u16 misc, int fd) +{ + struct dso *pos; + + dsos__for_each_with_build_id(pos, head) { + int err; + struct build_id_event b; + size_t len; + + if (!pos->hit) + continue; + len = pos->long_name_len + 1; + len = ALIGN(len, NAME_ALIGN); + memset(&b, 0, sizeof(b)); + memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id)); + b.pid = pid; + b.header.misc = misc; + b.header.size = sizeof(b) + len; + err = do_write(fd, &b, sizeof(b)); + if (err < 0) + return err; + err = write_padded(fd, pos->long_name, + pos->long_name_len + 1, len); + if (err < 0) + return err; + } + + return 0; +} + +static int machine__write_buildid_table(struct machine *machine, int fd) +{ + int err; + u16 kmisc = PERF_RECORD_MISC_KERNEL, + umisc = PERF_RECORD_MISC_USER; + + if (!machine__is_host(machine)) { + kmisc = PERF_RECORD_MISC_GUEST_KERNEL; + umisc = PERF_RECORD_MISC_GUEST_USER; + } + + err = __dsos__write_buildid_table(&machine->kernel_dsos, machine->pid, + kmisc, fd); + if (err == 0) + err = __dsos__write_buildid_table(&machine->user_dsos, + machine->pid, umisc, fd); + return err; +} + +static int dsos__write_buildid_table(struct perf_header *header, int fd) +{ + struct perf_session *session = container_of(header, + struct perf_session, header); + struct rb_node *nd; + int err = machine__write_buildid_table(&session->host_machine, fd); + + if (err) + return err; + + for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + err = machine__write_buildid_table(pos, fd); + if (err) + break; + } + return err; +} + +int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, + const char *name, bool is_kallsyms) +{ + const size_t size = PATH_MAX; + char *realname, *filename = zalloc(size), + *linkname = zalloc(size), *targetname; + int len, err = -1; + + if (is_kallsyms) { + if (symbol_conf.kptr_restrict) { + pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n"); + return 0; + } + realname = (char *)name; + } else + realname = realpath(name, NULL); + + if (realname == NULL || filename == NULL || linkname == NULL) + goto out_free; + + len = snprintf(filename, size, "%s%s%s", + debugdir, is_kallsyms ? "/" : "", realname); + if (mkdir_p(filename, 0755)) + goto out_free; + + snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); + + if (access(filename, F_OK)) { + if (is_kallsyms) { + if (copyfile("/proc/kallsyms", filename)) + goto out_free; + } else if (link(realname, filename) && copyfile(name, filename)) + goto out_free; + } + + len = snprintf(linkname, size, "%s/.build-id/%.2s", + debugdir, sbuild_id); + + if (access(linkname, X_OK) && mkdir_p(linkname, 0755)) + goto out_free; + + snprintf(linkname + len, size - len, "/%s", sbuild_id + 2); + targetname = filename + strlen(debugdir) - 5; + memcpy(targetname, "../..", 5); + + if (symlink(targetname, linkname) == 0) + err = 0; +out_free: + if (!is_kallsyms) + free(realname); + free(filename); + free(linkname); + return err; +} + +static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size, + const char *name, const char *debugdir, + bool is_kallsyms) +{ + char sbuild_id[BUILD_ID_SIZE * 2 + 1]; + + build_id__sprintf(build_id, build_id_size, sbuild_id); + + return build_id_cache__add_s(sbuild_id, debugdir, name, is_kallsyms); +} + +int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir) +{ + const size_t size = PATH_MAX; + char *filename = zalloc(size), + *linkname = zalloc(size); + int err = -1; + + if (filename == NULL || linkname == NULL) + goto out_free; + + snprintf(linkname, size, "%s/.build-id/%.2s/%s", + debugdir, sbuild_id, sbuild_id + 2); + + if (access(linkname, F_OK)) + goto out_free; + + if (readlink(linkname, filename, size - 1) < 0) + goto out_free; + + if (unlink(linkname)) + goto out_free; + + /* + * Since the link is relative, we must make it absolute: + */ + snprintf(linkname, size, "%s/.build-id/%.2s/%s", + debugdir, sbuild_id, filename); + + if (unlink(linkname)) + goto out_free; + + err = 0; +out_free: + free(filename); + free(linkname); + return err; +} + +static int dso__cache_build_id(struct dso *dso, const char *debugdir) +{ + bool is_kallsyms = dso->kernel && dso->long_name[0] != '/'; + + return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), + dso->long_name, debugdir, is_kallsyms); +} + +static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir) +{ + struct dso *pos; + int err = 0; + + dsos__for_each_with_build_id(pos, head) + if (dso__cache_build_id(pos, debugdir)) + err = -1; + + return err; +} + +static int machine__cache_build_ids(struct machine *machine, const char *debugdir) +{ + int ret = __dsos__cache_build_ids(&machine->kernel_dsos, debugdir); + ret |= __dsos__cache_build_ids(&machine->user_dsos, debugdir); + return ret; +} + +static int perf_session__cache_build_ids(struct perf_session *session) +{ + struct rb_node *nd; + int ret; + char debugdir[PATH_MAX]; + + snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir); + + if (mkdir(debugdir, 0755) != 0 && errno != EEXIST) + return -1; + + ret = machine__cache_build_ids(&session->host_machine, debugdir); + + for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + ret |= machine__cache_build_ids(pos, debugdir); + } + return ret ? -1 : 0; +} + +static bool machine__read_build_ids(struct machine *machine, bool with_hits) +{ + bool ret = __dsos__read_build_ids(&machine->kernel_dsos, with_hits); + ret |= __dsos__read_build_ids(&machine->user_dsos, with_hits); + return ret; +} + +static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits) +{ + struct rb_node *nd; + bool ret = machine__read_build_ids(&session->host_machine, with_hits); + + for (nd = rb_first(&session->machines); nd; nd = rb_next(nd)) { + struct machine *pos = rb_entry(nd, struct machine, rb_node); + ret |= machine__read_build_ids(pos, with_hits); + } + + return ret; +} + +static int do_write_feat(int fd, struct perf_header *h, int type, + struct perf_file_section **p, + struct perf_evlist *evlist) +{ int err; int ret = 0; if (perf_header__has_feat(h, type)) { - if (!feat_ops[type].write) - return -1; (*p)->offset = lseek(fd, 0, SEEK_CUR); @@ -1415,12 +1408,18 @@ static int perf_header__adds_write(struct perf_header *header, struct perf_evlist *evlist, int fd) { int nr_sections; + struct perf_session *session; struct perf_file_section *feat_sec, *p; int sec_size; u64 sec_start; - int feat; int err; + session = container_of(header, struct perf_session, header); + + if (perf_header__has_feat(header, HEADER_BUILD_ID && + !perf_session__read_build_ids(session, true))) + perf_header__clear_feat(header, HEADER_BUILD_ID); + nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); if (!nr_sections) return 0; @@ -1434,11 +1433,64 @@ static int perf_header__adds_write(struct perf_header *header, sec_start = header->data_offset + header->data_size; lseek(fd, sec_start + sec_size, SEEK_SET); - for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { - if (do_write_feat(fd, header, feat, &p, evlist)) - perf_header__clear_feat(header, feat); + err = do_write_feat(fd, header, HEADER_TRACE_INFO, &p, evlist); + if (err) + goto out_free; + + err = do_write_feat(fd, header, HEADER_BUILD_ID, &p, evlist); + if (err) { + perf_header__clear_feat(header, HEADER_BUILD_ID); + goto out_free; } + err = do_write_feat(fd, header, HEADER_HOSTNAME, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_HOSTNAME); + + err = do_write_feat(fd, header, HEADER_OSRELEASE, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_OSRELEASE); + + err = do_write_feat(fd, header, HEADER_VERSION, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_VERSION); + + err = do_write_feat(fd, header, HEADER_ARCH, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_ARCH); + + err = do_write_feat(fd, header, HEADER_NRCPUS, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_NRCPUS); + + err = do_write_feat(fd, header, HEADER_CPUDESC, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_CPUDESC); + + err = do_write_feat(fd, header, HEADER_CPUID, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_CPUID); + + err = do_write_feat(fd, header, HEADER_TOTAL_MEM, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_TOTAL_MEM); + + err = do_write_feat(fd, header, HEADER_CMDLINE, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_CMDLINE); + + err = do_write_feat(fd, header, HEADER_EVENT_DESC, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_EVENT_DESC); + + err = do_write_feat(fd, header, HEADER_CPU_TOPOLOGY, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_CPU_TOPOLOGY); + + err = do_write_feat(fd, header, HEADER_NUMA_TOPOLOGY, &p, evlist); + if (err) + perf_header__clear_feat(header, HEADER_NUMA_TOPOLOGY); + lseek(fd, sec_start, SEEK_SET); /* * may write more than needed due to dropped feature, but @@ -1447,6 +1499,7 @@ static int perf_header__adds_write(struct perf_header *header, err = do_write(fd, feat_sec, sec_size); if (err < 0) pr_debug("failed to write feature section\n"); +out_free: free(feat_sec); return err; } @@ -1584,20 +1637,20 @@ static int perf_header__getbuffer64(struct perf_header *header, int perf_header__process_sections(struct perf_header *header, int fd, void *data, int (*process)(struct perf_file_section *section, - struct perf_header *ph, - int feat, int fd, void *data)) + struct perf_header *ph, + int feat, int fd, void *data)) { - struct perf_file_section *feat_sec, *sec; + struct perf_file_section *feat_sec; int nr_sections; int sec_size; - int feat; - int err; + int idx = 0; + int err = -1, feat = 1; nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); if (!nr_sections) return 0; - feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); + feat_sec = calloc(sizeof(*feat_sec), nr_sections); if (!feat_sec) return -1; @@ -1605,16 +1658,20 @@ int perf_header__process_sections(struct perf_header *header, int fd, lseek(fd, header->data_offset + header->data_size, SEEK_SET); - err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); - if (err < 0) + if (perf_header__getbuffer64(header, fd, feat_sec, sec_size)) goto out_free; - for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) { - err = process(sec++, header, feat, fd, data); - if (err < 0) - goto out_free; - } err = 0; + while (idx < nr_sections && feat < HEADER_LAST_FEATURE) { + if (perf_header__has_feat(header, feat)) { + struct perf_file_section *sec = &feat_sec[idx++]; + + err = process(sec, header, feat, fd, data); + if (err < 0) + break; + } + ++feat; + } out_free: free(feat_sec); return err; @@ -1849,21 +1906,32 @@ static int perf_file_section__process(struct perf_file_section *section, return 0; } - if (feat >= HEADER_LAST_FEATURE) { - pr_debug("unknown feature %d, continuing...\n", feat); - return 0; - } - switch (feat) { case HEADER_TRACE_INFO: trace_report(fd, false); break; + case HEADER_BUILD_ID: if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) pr_debug("Failed to read buildids, continuing...\n"); break; - default: + + case HEADER_HOSTNAME: + case HEADER_OSRELEASE: + case HEADER_VERSION: + case HEADER_ARCH: + case HEADER_NRCPUS: + case HEADER_CPUDESC: + case HEADER_CPUID: + case HEADER_TOTAL_MEM: + case HEADER_CMDLINE: + case HEADER_EVENT_DESC: + case HEADER_CPU_TOPOLOGY: + case HEADER_NUMA_TOPOLOGY: break; + + default: + pr_debug("unknown feature %d, continuing...\n", feat); } return 0; @@ -1973,8 +2041,6 @@ int perf_session__read_header(struct perf_session *session, int fd) lseek(fd, tmp, SEEK_SET); } - symbol_conf.nr_events = nr_attrs; - if (f_header.event_types.size) { lseek(fd, f_header.event_types.offset, SEEK_SET); events = malloc(f_header.event_types.size); @@ -2002,9 +2068,9 @@ int perf_session__read_header(struct perf_session *session, int fd) return -ENOMEM; } -int perf_event__synthesize_attr(struct perf_tool *tool, - struct perf_event_attr *attr, u16 ids, u64 *id, - perf_event__handler_t process) +int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, + perf_event__handler_t process, + struct perf_session *session) { union perf_event *ev; size_t size; @@ -2026,23 +2092,22 @@ int perf_event__synthesize_attr(struct perf_tool *tool, ev->attr.header.type = PERF_RECORD_HEADER_ATTR; ev->attr.header.size = size; - err = process(tool, ev, NULL, NULL); + err = process(ev, NULL, session); free(ev); return err; } -int perf_event__synthesize_attrs(struct perf_tool *tool, - struct perf_session *session, +int perf_session__synthesize_attrs(struct perf_session *session, perf_event__handler_t process) { struct perf_evsel *attr; int err = 0; list_for_each_entry(attr, &session->evlist->entries, node) { - err = perf_event__synthesize_attr(tool, &attr->attr, attr->ids, - attr->id, process); + err = perf_event__synthesize_attr(&attr->attr, attr->ids, + attr->id, process, session); if (err) { pr_debug("failed to create perf header attribute\n"); return err; @@ -2053,23 +2118,23 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, } int perf_event__process_attr(union perf_event *event, - struct perf_evlist **pevlist) + struct perf_session *session) { unsigned int i, ids, n_ids; struct perf_evsel *evsel; - struct perf_evlist *evlist = *pevlist; - if (evlist == NULL) { - *pevlist = evlist = perf_evlist__new(NULL, NULL); - if (evlist == NULL) + if (session->evlist == NULL) { + session->evlist = perf_evlist__new(NULL, NULL); + if (session->evlist == NULL) return -ENOMEM; } - evsel = perf_evsel__new(&event->attr.attr, evlist->nr_entries); + evsel = perf_evsel__new(&event->attr.attr, + session->evlist->nr_entries); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(evlist, evsel); + perf_evlist__add(session->evlist, evsel); ids = event->header.size; ids -= (void *)&event->attr.id - (void *)event; @@ -2083,16 +2148,18 @@ int perf_event__process_attr(union perf_event *event, return -ENOMEM; for (i = 0; i < n_ids; i++) { - perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); + perf_evlist__id_add(session->evlist, evsel, 0, i, + event->attr.id[i]); } + perf_session__update_sample_type(session); + return 0; } -int perf_event__synthesize_event_type(struct perf_tool *tool, - u64 event_id, char *name, +int perf_event__synthesize_event_type(u64 event_id, char *name, perf_event__handler_t process, - struct machine *machine) + struct perf_session *session) { union perf_event ev; size_t size = 0; @@ -2110,14 +2177,13 @@ int perf_event__synthesize_event_type(struct perf_tool *tool, ev.event_type.header.size = sizeof(ev.event_type) - (sizeof(ev.event_type.event_type.name) - size); - err = process(tool, &ev, NULL, machine); + err = process(&ev, NULL, session); return err; } -int perf_event__synthesize_event_types(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine) +int perf_event__synthesize_event_types(perf_event__handler_t process, + struct perf_session *session) { struct perf_trace_event_type *type; int i, err = 0; @@ -2125,9 +2191,9 @@ int perf_event__synthesize_event_types(struct perf_tool *tool, for (i = 0; i < event_count; i++) { type = &events[i]; - err = perf_event__synthesize_event_type(tool, type->event_id, + err = perf_event__synthesize_event_type(type->event_id, type->name, process, - machine); + session); if (err) { pr_debug("failed to create perf header event type\n"); return err; @@ -2137,8 +2203,8 @@ int perf_event__synthesize_event_types(struct perf_tool *tool, return err; } -int perf_event__process_event_type(struct perf_tool *tool __unused, - union perf_event *event) +int perf_event__process_event_type(union perf_event *event, + struct perf_session *session __unused) { if (perf_header__push_event(event->event_type.event_type.event_id, event->event_type.event_type.name) < 0) @@ -2147,9 +2213,9 @@ int perf_event__process_event_type(struct perf_tool *tool __unused, return 0; } -int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, - struct perf_evlist *evlist, - perf_event__handler_t process) +int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, + perf_event__handler_t process, + struct perf_session *session __unused) { union perf_event ev; struct tracing_data *tdata; @@ -2180,7 +2246,7 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, ev.tracing_data.header.size = sizeof(ev.tracing_data); ev.tracing_data.size = aligned_size; - process(tool, &ev, NULL, NULL); + process(&ev, NULL, session); /* * The put function will copy all the tracing data @@ -2222,10 +2288,10 @@ int perf_event__process_tracing_data(union perf_event *event, return size_read + padding; } -int perf_event__synthesize_build_id(struct perf_tool *tool, - struct dso *pos, u16 misc, +int perf_event__synthesize_build_id(struct dso *pos, u16 misc, perf_event__handler_t process, - struct machine *machine) + struct machine *machine, + struct perf_session *session) { union perf_event ev; size_t len; @@ -2245,13 +2311,12 @@ int perf_event__synthesize_build_id(struct perf_tool *tool, ev.build_id.header.size = sizeof(ev.build_id) + len; memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); - err = process(tool, &ev, NULL, machine); + err = process(&ev, NULL, session); return err; } -int perf_event__process_build_id(struct perf_tool *tool __used, - union perf_event *event, +int perf_event__process_build_id(union perf_event *event, struct perf_session *session) { __event_process_build_id(&event->build_id, diff --git a/trunk/tools/perf/util/header.h b/trunk/tools/perf/util/header.h index ac4ec956024e..3d5a742f4a2a 100644 --- a/trunk/tools/perf/util/header.h +++ b/trunk/tools/perf/util/header.h @@ -10,8 +10,7 @@ #include enum { - HEADER_RESERVED = 0, /* always cleared */ - HEADER_TRACE_INFO = 1, + HEADER_TRACE_INFO = 1, HEADER_BUILD_ID, HEADER_HOSTNAME, @@ -28,9 +27,10 @@ enum { HEADER_NUMA_TOPOLOGY, HEADER_LAST_FEATURE, - HEADER_FEAT_BITS = 256, }; +#define HEADER_FEAT_BITS 256 + struct perf_file_section { u64 offset; u64 size; @@ -68,7 +68,6 @@ struct perf_header { }; struct perf_evlist; -struct perf_session; int perf_session__read_header(struct perf_session *session, int fd); int perf_session__write_header(struct perf_session *session, @@ -97,36 +96,32 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir, const char *name, bool is_kallsyms); int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir); -int perf_event__synthesize_attr(struct perf_tool *tool, - struct perf_event_attr *attr, u16 ids, u64 *id, - perf_event__handler_t process); -int perf_event__synthesize_attrs(struct perf_tool *tool, - struct perf_session *session, - perf_event__handler_t process); -int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); +int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, + perf_event__handler_t process, + struct perf_session *session); +int perf_session__synthesize_attrs(struct perf_session *session, + perf_event__handler_t process); +int perf_event__process_attr(union perf_event *event, struct perf_session *session); -int perf_event__synthesize_event_type(struct perf_tool *tool, - u64 event_id, char *name, +int perf_event__synthesize_event_type(u64 event_id, char *name, perf_event__handler_t process, - struct machine *machine); -int perf_event__synthesize_event_types(struct perf_tool *tool, - perf_event__handler_t process, - struct machine *machine); -int perf_event__process_event_type(struct perf_tool *tool, - union perf_event *event); - -int perf_event__synthesize_tracing_data(struct perf_tool *tool, - int fd, struct perf_evlist *evlist, - perf_event__handler_t process); + struct perf_session *session); +int perf_event__synthesize_event_types(perf_event__handler_t process, + struct perf_session *session); +int perf_event__process_event_type(union perf_event *event, + struct perf_session *session); + +int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, + perf_event__handler_t process, + struct perf_session *session); int perf_event__process_tracing_data(union perf_event *event, struct perf_session *session); -int perf_event__synthesize_build_id(struct perf_tool *tool, - struct dso *pos, u16 misc, +int perf_event__synthesize_build_id(struct dso *pos, u16 misc, perf_event__handler_t process, - struct machine *machine); -int perf_event__process_build_id(struct perf_tool *tool, - union perf_event *event, + struct machine *machine, + struct perf_session *session); +int perf_event__process_build_id(union perf_event *event, struct perf_session *session); /* diff --git a/trunk/tools/perf/util/hist.h b/trunk/tools/perf/util/hist.h index ff6f9d56ea41..89289c8e935e 100644 --- a/trunk/tools/perf/util/hist.h +++ b/trunk/tools/perf/util/hist.h @@ -117,6 +117,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __used, static inline int hist_entry__tui_annotate(struct hist_entry *self __used, int evidx __used, + int nr_events __used, void(*timer)(void *arg) __used, void *arg __used, int delay_secs __used) @@ -127,7 +128,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used, #define K_RIGHT -2 #else #include "ui/keysyms.h" -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, void(*timer)(void *arg), void *arg, int delay_secs); int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, diff --git a/trunk/tools/perf/util/include/linux/bitops.h b/trunk/tools/perf/util/include/linux/bitops.h index 62cdee78db7b..305c8484f200 100644 --- a/trunk/tools/perf/util/include/linux/bitops.h +++ b/trunk/tools/perf/util/include/linux/bitops.h @@ -9,17 +9,6 @@ #define BITS_PER_BYTE 8 #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) -#define for_each_set_bit(bit, addr, size) \ - for ((bit) = find_first_bit((addr), (size)); \ - (bit) < (size); \ - (bit) = find_next_bit((addr), (size), (bit) + 1)) - -/* same as for_each_set_bit() but use bit as value to start with */ -#define for_each_set_bit_cont(bit, addr, size) \ - for ((bit) = find_next_bit((addr), (size), (bit)); \ - (bit) < (size); \ - (bit) = find_next_bit((addr), (size), (bit) + 1)) - static inline void set_bit(int nr, unsigned long *addr) { addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); @@ -41,111 +30,4 @@ static inline unsigned long hweight_long(unsigned long w) return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } -#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) - -/** - * __ffs - find first bit in word. - * @word: The word to search - * - * Undefined if no bit exists, so code should check against 0 first. - */ -static __always_inline unsigned long __ffs(unsigned long word) -{ - int num = 0; - -#if BITS_PER_LONG == 64 - if ((word & 0xffffffff) == 0) { - num += 32; - word >>= 32; - } -#endif - if ((word & 0xffff) == 0) { - num += 16; - word >>= 16; - } - if ((word & 0xff) == 0) { - num += 8; - word >>= 8; - } - if ((word & 0xf) == 0) { - num += 4; - word >>= 4; - } - if ((word & 0x3) == 0) { - num += 2; - word >>= 2; - } - if ((word & 0x1) == 0) - num += 1; - return num; -} - -/* - * Find the first set bit in a memory region. - */ -static inline unsigned long -find_first_bit(const unsigned long *addr, unsigned long size) -{ - const unsigned long *p = addr; - unsigned long result = 0; - unsigned long tmp; - - while (size & ~(BITS_PER_LONG-1)) { - if ((tmp = *(p++))) - goto found; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - - tmp = (*p) & (~0UL >> (BITS_PER_LONG - size)); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ -found: - return result + __ffs(tmp); -} - -/* - * Find the next set bit in a memory region. - */ -static inline unsigned long -find_next_bit(const unsigned long *addr, unsigned long size, unsigned long offset) -{ - const unsigned long *p = addr + BITOP_WORD(offset); - unsigned long result = offset & ~(BITS_PER_LONG-1); - unsigned long tmp; - - if (offset >= size) - return size; - size -= result; - offset %= BITS_PER_LONG; - if (offset) { - tmp = *(p++); - tmp &= (~0UL << offset); - if (size < BITS_PER_LONG) - goto found_first; - if (tmp) - goto found_middle; - size -= BITS_PER_LONG; - result += BITS_PER_LONG; - } - while (size & ~(BITS_PER_LONG-1)) { - if ((tmp = *(p++))) - goto found_middle; - result += BITS_PER_LONG; - size -= BITS_PER_LONG; - } - if (!size) - return result; - tmp = *p; - -found_first: - tmp &= (~0UL >> (BITS_PER_LONG - size)); - if (tmp == 0UL) /* Are any bits set? */ - return result + size; /* Nope. */ -found_middle: - return result + __ffs(tmp); -} - #endif diff --git a/trunk/tools/perf/util/map.c b/trunk/tools/perf/util/map.c index 316aa0ab7122..78284b13e808 100644 --- a/trunk/tools/perf/util/map.c +++ b/trunk/tools/perf/util/map.c @@ -562,10 +562,6 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid) INIT_LIST_HEAD(&self->user_dsos); INIT_LIST_HEAD(&self->kernel_dsos); - self->threads = RB_ROOT; - INIT_LIST_HEAD(&self->dead_threads); - self->last_match = NULL; - self->kmaps.machine = self; self->pid = pid; self->root_dir = strdup(root_dir); diff --git a/trunk/tools/perf/util/map.h b/trunk/tools/perf/util/map.h index 2b8017f8a930..890d85545d0f 100644 --- a/trunk/tools/perf/util/map.h +++ b/trunk/tools/perf/util/map.h @@ -18,11 +18,9 @@ enum map_type { extern const char *map_type__name[MAP__NR_TYPES]; struct dso; -struct ip_callchain; struct ref_reloc_sym; struct map_groups; struct machine; -struct perf_evsel; struct map { union { @@ -63,11 +61,7 @@ struct map_groups { struct machine { struct rb_node rb_node; pid_t pid; - u16 id_hdr_size; char *root_dir; - struct rb_root threads; - struct list_head dead_threads; - struct thread *last_match; struct list_head user_dsos; struct list_head kernel_dsos; struct map_groups kmaps; @@ -154,13 +148,6 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid); void machine__exit(struct machine *self); void machine__delete(struct machine *self); -int machine__resolve_callchain(struct machine *machine, - struct perf_evsel *evsel, struct thread *thread, - struct ip_callchain *chain, - struct symbol **parent); -int maps__set_kallsyms_ref_reloc_sym(struct map **maps, const char *symbol_name, - u64 addr); - /* * Default guest kernel is defined by parameter --guestkallsyms * and --guestmodules @@ -203,12 +190,6 @@ struct symbol *map_groups__find_symbol_by_name(struct map_groups *mg, struct map **mapp, symbol_filter_t filter); - -struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); -void machine__remove_thread(struct machine *machine, struct thread *th); - -size_t machine__fprintf(struct machine *machine, FILE *fp); - static inline struct symbol *machine__find_kernel_symbol(struct machine *self, enum map_type type, u64 addr, diff --git a/trunk/tools/perf/util/parse-events.c b/trunk/tools/perf/util/parse-events.c index 531c283fc0c5..928918b796b2 100644 --- a/trunk/tools/perf/util/parse-events.c +++ b/trunk/tools/perf/util/parse-events.c @@ -25,6 +25,8 @@ enum event_result { EVT_HANDLED_ALL }; +char debugfs_path[MAXPATHLEN]; + #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x @@ -38,7 +40,6 @@ static struct event_symbol event_symbols[] = { { CHW(BRANCH_INSTRUCTIONS), "branch-instructions", "branches" }, { CHW(BRANCH_MISSES), "branch-misses", "" }, { CHW(BUS_CYCLES), "bus-cycles", "" }, - { CHW(REF_CPU_CYCLES), "ref-cycles", "" }, { CSW(CPU_CLOCK), "cpu-clock", "" }, { CSW(TASK_CLOCK), "task-clock", "" }, @@ -69,7 +70,6 @@ static const char *hw_event_names[PERF_COUNT_HW_MAX] = { "bus-cycles", "stalled-cycles-frontend", "stalled-cycles-backend", - "ref-cycles", }; static const char *sw_event_names[PERF_COUNT_SW_MAX] = { @@ -140,7 +140,7 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) char evt_path[MAXPATHLEN]; int fd; - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, sys_dir->d_name, evt_dir->d_name); fd = open(evt_path, O_RDONLY); if (fd < 0) @@ -171,16 +171,16 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; - if (debugfs_valid_mountpoint(tracing_events_path)) + if (debugfs_valid_mountpoint(debugfs_path)) return NULL; - sys_dir = opendir(tracing_events_path); + sys_dir = opendir(debugfs_path); if (!sys_dir) return NULL; for_each_subsystem(sys_dir, sys_dirent, sys_next) { - snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, + snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) @@ -447,7 +447,7 @@ parse_single_tracepoint_event(char *sys_name, u64 id; int fd; - snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", tracing_events_path, + snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, sys_name, evt_name); fd = open(evt_path, O_RDONLY); @@ -485,7 +485,7 @@ parse_multiple_tracepoint_event(struct perf_evlist *evlist, char *sys_name, struct dirent *evt_ent; DIR *evt_dir; - snprintf(evt_path, MAXPATHLEN, "%s/%s", tracing_events_path, sys_name); + snprintf(evt_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_name); evt_dir = opendir(evt_path); if (!evt_dir) { @@ -528,7 +528,7 @@ parse_tracepoint_event(struct perf_evlist *evlist, const char **strp, char sys_name[MAX_EVENT_LENGTH]; unsigned int sys_length, evt_length; - if (debugfs_valid_mountpoint(tracing_events_path)) + if (debugfs_valid_mountpoint(debugfs_path)) return 0; evt_name = strchr(*strp, ':'); @@ -920,10 +920,10 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; - if (debugfs_valid_mountpoint(tracing_events_path)) + if (debugfs_valid_mountpoint(debugfs_path)) return; - sys_dir = opendir(tracing_events_path); + sys_dir = opendir(debugfs_path); if (!sys_dir) return; @@ -932,7 +932,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) !strglobmatch(sys_dirent.d_name, subsys_glob)) continue; - snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, + snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) @@ -964,16 +964,16 @@ int is_valid_tracepoint(const char *event_string) char evt_path[MAXPATHLEN]; char dir_path[MAXPATHLEN]; - if (debugfs_valid_mountpoint(tracing_events_path)) + if (debugfs_valid_mountpoint(debugfs_path)) return 0; - sys_dir = opendir(tracing_events_path); + sys_dir = opendir(debugfs_path); if (!sys_dir) return 0; for_each_subsystem(sys_dir, sys_dirent, sys_next) { - snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, + snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_dirent.d_name); evt_dir = opendir(dir_path); if (!evt_dir) diff --git a/trunk/tools/perf/util/parse-events.h b/trunk/tools/perf/util/parse-events.h index 7e0cbe75d5f1..2f8e375e038d 100644 --- a/trunk/tools/perf/util/parse-events.h +++ b/trunk/tools/perf/util/parse-events.h @@ -39,6 +39,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob); int print_hwcache_events(const char *event_glob); extern int is_valid_tracepoint(const char *event_string); +extern char debugfs_path[]; extern int valid_debugfs_mount(const char *debugfs); #endif /* __PERF_PARSE_EVENTS_H */ diff --git a/trunk/tools/perf/util/probe-finder.h b/trunk/tools/perf/util/probe-finder.h index 17e94d0c36f9..1132c8f0ce89 100644 --- a/trunk/tools/perf/util/probe-finder.h +++ b/trunk/tools/perf/util/probe-finder.h @@ -5,6 +5,7 @@ #include "util.h" #include "probe-event.h" +#define MAX_PATH_LEN 256 #define MAX_PROBE_BUFFER 1024 #define MAX_PROBES 128 diff --git a/trunk/tools/perf/util/scripting-engines/trace-event-perl.c b/trunk/tools/perf/util/scripting-engines/trace-event-perl.c index e30749e38a9b..74350ffb57fe 100644 --- a/trunk/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/trunk/tools/perf/util/scripting-engines/trace-event-perl.c @@ -27,10 +27,7 @@ #include "../../perf.h" #include "../util.h" -#include "../thread.h" -#include "../event.h" #include "../trace-event.h" -#include "../evsel.h" #include #include @@ -248,11 +245,11 @@ static inline struct event *find_cache_event(int type) return event; } -static void perl_process_tracepoint(union perf_event *pevent __unused, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine __unused, - struct thread *thread) +static void perl_process_event(union perf_event *pevent __unused, + struct perf_sample *sample, + struct perf_evsel *evsel, + struct perf_session *session __unused, + struct thread *thread) { struct format_field *field; static char handler[256]; @@ -268,9 +265,6 @@ static void perl_process_tracepoint(union perf_event *pevent __unused, dSP; - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) - return; - type = trace_parse_common_type(data); event = find_cache_event(type); @@ -338,42 +332,6 @@ static void perl_process_tracepoint(union perf_event *pevent __unused, LEAVE; } -static void perl_process_event_generic(union perf_event *pevent __unused, - struct perf_sample *sample, - struct perf_evsel *evsel __unused, - struct machine *machine __unused, - struct thread *thread __unused) -{ - dSP; - - if (!get_cv("process_event", 0)) - return; - - ENTER; - SAVETMPS; - PUSHMARK(SP); - XPUSHs(sv_2mortal(newSVpvn((const char *)pevent, pevent->header.size))); - XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->attr, sizeof(evsel->attr)))); - XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample)))); - XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size))); - PUTBACK; - call_pv("process_event", G_SCALAR); - SPAGAIN; - PUTBACK; - FREETMPS; - LEAVE; -} - -static void perl_process_event(union perf_event *pevent, - struct perf_sample *sample, - struct perf_evsel *evsel, - struct machine *machine, - struct thread *thread) -{ - perl_process_tracepoint(pevent, sample, evsel, machine, thread); - perl_process_event_generic(pevent, sample, evsel, machine, thread); -} - static void run_start_sub(void) { dSP; /* access to Perl stack */ @@ -595,28 +553,7 @@ static int perl_generate_script(const char *outfile) fprintf(ofp, "sub print_header\n{\n" "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" "\tprintf(\"%%-20s %%5u %%05u.%%09u %%8u %%-20s \",\n\t " - "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}\n"); - - fprintf(ofp, - "\n# Packed byte string args of process_event():\n" - "#\n" - "# $event:\tunion perf_event\tutil/event.h\n" - "# $attr:\tstruct perf_event_attr\tlinux/perf_event.h\n" - "# $sample:\tstruct perf_sample\tutil/event.h\n" - "# $raw_data:\tperf_sample->raw_data\tutil/event.h\n" - "\n" - "sub process_event\n" - "{\n" - "\tmy ($event, $attr, $sample, $raw_data) = @_;\n" - "\n" - "\tmy @event\t= unpack(\"LSS\", $event);\n" - "\tmy @attr\t= unpack(\"LLQQQQQLLQQ\", $attr);\n" - "\tmy @sample\t= unpack(\"QLLQQQQQLL\", $sample);\n" - "\tmy @raw_data\t= unpack(\"C*\", $raw_data);\n" - "\n" - "\tuse Data::Dumper;\n" - "\tprint Dumper \\@event, \\@attr, \\@sample, \\@raw_data;\n" - "}\n"); + "$event_name, $cpu, $secs, $nsecs, $pid, $comm);\n}"); fclose(ofp); diff --git a/trunk/tools/perf/util/scripting-engines/trace-event-python.c b/trunk/tools/perf/util/scripting-engines/trace-event-python.c index 0b2a48783172..6ccf70e8d8f2 100644 --- a/trunk/tools/perf/util/scripting-engines/trace-event-python.c +++ b/trunk/tools/perf/util/scripting-engines/trace-event-python.c @@ -29,8 +29,6 @@ #include "../../perf.h" #include "../util.h" -#include "../event.h" -#include "../thread.h" #include "../trace-event.h" PyMODINIT_FUNC initperf_trace_context(void); @@ -209,7 +207,7 @@ static inline struct event *find_cache_event(int type) static void python_process_event(union perf_event *pevent __unused, struct perf_sample *sample, struct perf_evsel *evsel __unused, - struct machine *machine __unused, + struct perf_session *session __unused, struct thread *thread) { PyObject *handler, *retval, *context, *t, *obj, *dict = NULL; diff --git a/trunk/tools/perf/util/session.c b/trunk/tools/perf/util/session.c index b5ca2558c7bb..0f4555ce9063 100644 --- a/trunk/tools/perf/util/session.c +++ b/trunk/tools/perf/util/session.c @@ -10,7 +10,6 @@ #include "evlist.h" #include "evsel.h" #include "session.h" -#include "tool.h" #include "sort.h" #include "util.h" #include "cpumap.h" @@ -79,13 +78,39 @@ static int perf_session__open(struct perf_session *self, bool force) return -1; } +static void perf_session__id_header_size(struct perf_session *session) +{ + struct perf_sample *data; + u64 sample_type = session->sample_type; + u16 size = 0; + + if (!session->sample_id_all) + goto out; + + if (sample_type & PERF_SAMPLE_TID) + size += sizeof(data->tid) * 2; + + if (sample_type & PERF_SAMPLE_TIME) + size += sizeof(data->time); + + if (sample_type & PERF_SAMPLE_ID) + size += sizeof(data->id); + + if (sample_type & PERF_SAMPLE_STREAM_ID) + size += sizeof(data->stream_id); + + if (sample_type & PERF_SAMPLE_CPU) + size += sizeof(data->cpu) * 2; +out: + session->id_hdr_size = size; +} + void perf_session__update_sample_type(struct perf_session *self) { self->sample_type = perf_evlist__sample_type(self->evlist); self->sample_size = __perf_evsel__sample_size(self->sample_type); self->sample_id_all = perf_evlist__sample_id_all(self->evlist); - self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); - self->host_machine.id_hdr_size = self->id_hdr_size; + perf_session__id_header_size(self); } int perf_session__create_kernel_maps(struct perf_session *self) @@ -105,26 +130,18 @@ static void perf_session__destroy_kernel_maps(struct perf_session *self) struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, - struct perf_tool *tool) + struct perf_event_ops *ops) { - struct perf_session *self; - struct stat st; - size_t len; - - if (!filename || !strlen(filename)) { - if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode)) - filename = "-"; - else - filename = "perf.data"; - } - - len = strlen(filename); - self = zalloc(sizeof(*self) + len); + size_t len = filename ? strlen(filename) + 1 : 0; + struct perf_session *self = zalloc(sizeof(*self) + len); if (self == NULL) goto out; memcpy(self->filename, filename, len); + self->threads = RB_ROOT; + INIT_LIST_HEAD(&self->dead_threads); + self->last_match = NULL; /* * On 64bit we can mmap the data file in one go. No need for tiny mmap * slices. On 32bit we use 32MB. @@ -154,10 +171,10 @@ struct perf_session *perf_session__new(const char *filename, int mode, goto out_delete; } - if (tool && tool->ordering_requires_timestamps && - tool->ordered_samples && !self->sample_id_all) { + if (ops && ops->ordering_requires_timestamps && + ops->ordered_samples && !self->sample_id_all) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); - tool->ordered_samples = false; + ops->ordered_samples = false; } out: @@ -167,22 +184,17 @@ struct perf_session *perf_session__new(const char *filename, int mode, return NULL; } -static void machine__delete_dead_threads(struct machine *machine) +static void perf_session__delete_dead_threads(struct perf_session *self) { struct thread *n, *t; - list_for_each_entry_safe(t, n, &machine->dead_threads, node) { + list_for_each_entry_safe(t, n, &self->dead_threads, node) { list_del(&t->node); thread__delete(t); } } -static void perf_session__delete_dead_threads(struct perf_session *session) -{ - machine__delete_dead_threads(&session->host_machine); -} - -static void machine__delete_threads(struct machine *self) +static void perf_session__delete_threads(struct perf_session *self) { struct rb_node *nd = rb_first(&self->threads); @@ -195,11 +207,6 @@ static void machine__delete_threads(struct machine *self) } } -static void perf_session__delete_threads(struct perf_session *session) -{ - machine__delete_threads(&session->host_machine); -} - void perf_session__delete(struct perf_session *self) { perf_session__destroy_kernel_maps(self); @@ -210,7 +217,7 @@ void perf_session__delete(struct perf_session *self) free(self); } -void machine__remove_thread(struct machine *self, struct thread *th) +void perf_session__remove_thread(struct perf_session *self, struct thread *th) { self->last_match = NULL; rb_erase(&th->rb_node, &self->threads); @@ -229,16 +236,16 @@ static bool symbol__match_parent_regex(struct symbol *sym) return 0; } -int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, - struct thread *thread, - struct ip_callchain *chain, - struct symbol **parent) +int perf_session__resolve_callchain(struct perf_session *self, + struct thread *thread, + struct ip_callchain *chain, + struct symbol **parent) { u8 cpumode = PERF_RECORD_MISC_USER; unsigned int i; int err; - callchain_cursor_reset(&evsel->hists.callchain_cursor); + callchain_cursor_reset(&self->callchain_cursor); for (i = 0; i < chain->nr; i++) { u64 ip; @@ -265,7 +272,7 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, al.filtered = false; thread__find_addr_location(thread, self, cpumode, - MAP__FUNCTION, ip, &al, NULL); + MAP__FUNCTION, thread->pid, ip, &al, NULL); if (al.sym != NULL) { if (sort__has_parent && !*parent && symbol__match_parent_regex(al.sym)) @@ -274,7 +281,7 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, break; } - err = callchain_cursor_append(&evsel->hists.callchain_cursor, + err = callchain_cursor_append(&self->callchain_cursor, ip, al.map, al.sym); if (err) return err; @@ -283,91 +290,75 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, return 0; } -static int process_event_synth_tracing_data_stub(union perf_event *event __used, - struct perf_session *session __used) -{ - dump_printf(": unhandled!\n"); - return 0; -} - -static int process_event_synth_attr_stub(union perf_event *event __used, - struct perf_evlist **pevlist __used) +static int process_event_synth_stub(union perf_event *event __used, + struct perf_session *session __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_event_sample_stub(struct perf_tool *tool __used, - union perf_event *event __used, +static int process_event_sample_stub(union perf_event *event __used, struct perf_sample *sample __used, struct perf_evsel *evsel __used, - struct machine *machine __used) + struct perf_session *session __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_event_stub(struct perf_tool *tool __used, - union perf_event *event __used, +static int process_event_stub(union perf_event *event __used, struct perf_sample *sample __used, - struct machine *machine __used) + struct perf_session *session __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_finished_round_stub(struct perf_tool *tool __used, - union perf_event *event __used, - struct perf_session *perf_session __used) +static int process_finished_round_stub(union perf_event *event __used, + struct perf_session *session __used, + struct perf_event_ops *ops __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_event_type_stub(struct perf_tool *tool __used, - union perf_event *event __used) -{ - dump_printf(": unhandled!\n"); - return 0; -} +static int process_finished_round(union perf_event *event, + struct perf_session *session, + struct perf_event_ops *ops); -static int process_finished_round(struct perf_tool *tool, - union perf_event *event, - struct perf_session *session); - -static void perf_tool__fill_defaults(struct perf_tool *tool) +static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) { - if (tool->sample == NULL) - tool->sample = process_event_sample_stub; - if (tool->mmap == NULL) - tool->mmap = process_event_stub; - if (tool->comm == NULL) - tool->comm = process_event_stub; - if (tool->fork == NULL) - tool->fork = process_event_stub; - if (tool->exit == NULL) - tool->exit = process_event_stub; - if (tool->lost == NULL) - tool->lost = perf_event__process_lost; - if (tool->read == NULL) - tool->read = process_event_sample_stub; - if (tool->throttle == NULL) - tool->throttle = process_event_stub; - if (tool->unthrottle == NULL) - tool->unthrottle = process_event_stub; - if (tool->attr == NULL) - tool->attr = process_event_synth_attr_stub; - if (tool->event_type == NULL) - tool->event_type = process_event_type_stub; - if (tool->tracing_data == NULL) - tool->tracing_data = process_event_synth_tracing_data_stub; - if (tool->build_id == NULL) - tool->build_id = process_finished_round_stub; - if (tool->finished_round == NULL) { - if (tool->ordered_samples) - tool->finished_round = process_finished_round; + if (handler->sample == NULL) + handler->sample = process_event_sample_stub; + if (handler->mmap == NULL) + handler->mmap = process_event_stub; + if (handler->comm == NULL) + handler->comm = process_event_stub; + if (handler->fork == NULL) + handler->fork = process_event_stub; + if (handler->exit == NULL) + handler->exit = process_event_stub; + if (handler->lost == NULL) + handler->lost = perf_event__process_lost; + if (handler->read == NULL) + handler->read = process_event_stub; + if (handler->throttle == NULL) + handler->throttle = process_event_stub; + if (handler->unthrottle == NULL) + handler->unthrottle = process_event_stub; + if (handler->attr == NULL) + handler->attr = process_event_synth_stub; + if (handler->event_type == NULL) + handler->event_type = process_event_synth_stub; + if (handler->tracing_data == NULL) + handler->tracing_data = process_event_synth_stub; + if (handler->build_id == NULL) + handler->build_id = process_event_synth_stub; + if (handler->finished_round == NULL) { + if (handler->ordered_samples) + handler->finished_round = process_finished_round; else - tool->finished_round = process_finished_round_stub; + handler->finished_round = process_finished_round_stub; } } @@ -499,11 +490,11 @@ static void perf_session_free_sample_buffers(struct perf_session *session) static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, - struct perf_tool *tool, + struct perf_event_ops *ops, u64 file_offset); static void flush_sample_queue(struct perf_session *s, - struct perf_tool *tool) + struct perf_event_ops *ops) { struct ordered_samples *os = &s->ordered_samples; struct list_head *head = &os->samples; @@ -514,7 +505,7 @@ static void flush_sample_queue(struct perf_session *s, unsigned idx = 0, progress_next = os->nr_samples / 16; int ret; - if (!tool->ordered_samples || !limit) + if (!ops->ordered_samples || !limit) return; list_for_each_entry_safe(iter, tmp, head, list) { @@ -525,7 +516,7 @@ static void flush_sample_queue(struct perf_session *s, if (ret) pr_err("Can't parse sample, err = %d\n", ret); else - perf_session_deliver_event(s, iter->event, &sample, tool, + perf_session_deliver_event(s, iter->event, &sample, ops, iter->file_offset); os->last_flush = iter->timestamp; @@ -587,11 +578,11 @@ static void flush_sample_queue(struct perf_session *s, * Flush every events below timestamp 7 * etc... */ -static int process_finished_round(struct perf_tool *tool, - union perf_event *event __used, - struct perf_session *session) +static int process_finished_round(union perf_event *event __used, + struct perf_session *session, + struct perf_event_ops *ops) { - flush_sample_queue(session, tool); + flush_sample_queue(session, ops); session->ordered_samples.next_flush = session->ordered_samples.max_timestamp; return 0; @@ -746,26 +737,13 @@ static void dump_sample(struct perf_session *session, union perf_event *event, callchain__printf(sample); } -static struct machine * - perf_session__find_machine_for_cpumode(struct perf_session *session, - union perf_event *event) -{ - const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - - if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) - return perf_session__find_machine(session, event->ip.pid); - - return perf_session__find_host_machine(session); -} - static int perf_session_deliver_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, - struct perf_tool *tool, + struct perf_event_ops *ops, u64 file_offset) { struct perf_evsel *evsel; - struct machine *machine; dump_event(session, event, file_offset, sample); @@ -787,8 +765,6 @@ static int perf_session_deliver_event(struct perf_session *session, hists__inc_nr_events(&evsel->hists, event->header.type); } - machine = perf_session__find_machine_for_cpumode(session, event); - switch (event->header.type) { case PERF_RECORD_SAMPLE: dump_sample(session, event, sample); @@ -796,25 +772,23 @@ static int perf_session_deliver_event(struct perf_session *session, ++session->hists.stats.nr_unknown_id; return -1; } - return tool->sample(tool, event, sample, evsel, machine); + return ops->sample(event, sample, evsel, session); case PERF_RECORD_MMAP: - return tool->mmap(tool, event, sample, machine); + return ops->mmap(event, sample, session); case PERF_RECORD_COMM: - return tool->comm(tool, event, sample, machine); + return ops->comm(event, sample, session); case PERF_RECORD_FORK: - return tool->fork(tool, event, sample, machine); + return ops->fork(event, sample, session); case PERF_RECORD_EXIT: - return tool->exit(tool, event, sample, machine); + return ops->exit(event, sample, session); case PERF_RECORD_LOST: - if (tool->lost == perf_event__process_lost) - session->hists.stats.total_lost += event->lost.lost; - return tool->lost(tool, event, sample, machine); + return ops->lost(event, sample, session); case PERF_RECORD_READ: - return tool->read(tool, event, sample, evsel, machine); + return ops->read(event, sample, session); case PERF_RECORD_THROTTLE: - return tool->throttle(tool, event, sample, machine); + return ops->throttle(event, sample, session); case PERF_RECORD_UNTHROTTLE: - return tool->unthrottle(tool, event, sample, machine); + return ops->unthrottle(event, sample, session); default: ++session->hists.stats.nr_unknown_events; return -1; @@ -838,29 +812,24 @@ static int perf_session__preprocess_sample(struct perf_session *session, } static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, - struct perf_tool *tool, u64 file_offset) + struct perf_event_ops *ops, u64 file_offset) { - int err; - dump_event(session, event, file_offset, NULL); /* These events are processed right away */ switch (event->header.type) { case PERF_RECORD_HEADER_ATTR: - err = tool->attr(event, &session->evlist); - if (err == 0) - perf_session__update_sample_type(session); - return err; + return ops->attr(event, session); case PERF_RECORD_HEADER_EVENT_TYPE: - return tool->event_type(tool, event); + return ops->event_type(event, session); case PERF_RECORD_HEADER_TRACING_DATA: /* setup for reading amidst mmap */ lseek(session->fd, file_offset, SEEK_SET); - return tool->tracing_data(event, session); + return ops->tracing_data(event, session); case PERF_RECORD_HEADER_BUILD_ID: - return tool->build_id(tool, event, session); + return ops->build_id(event, session); case PERF_RECORD_FINISHED_ROUND: - return tool->finished_round(tool, event, session); + return ops->finished_round(event, session, ops); default: return -EINVAL; } @@ -868,7 +837,7 @@ static int perf_session__process_user_event(struct perf_session *session, union static int perf_session__process_event(struct perf_session *session, union perf_event *event, - struct perf_tool *tool, + struct perf_event_ops *ops, u64 file_offset) { struct perf_sample sample; @@ -884,7 +853,7 @@ static int perf_session__process_event(struct perf_session *session, hists__inc_nr_events(&session->hists, event->header.type); if (event->header.type >= PERF_RECORD_USER_TYPE_START) - return perf_session__process_user_event(session, event, tool, file_offset); + return perf_session__process_user_event(session, event, ops, file_offset); /* * For all kernel events we get the sample data @@ -897,14 +866,14 @@ static int perf_session__process_event(struct perf_session *session, if (perf_session__preprocess_sample(session, event, &sample)) return 0; - if (tool->ordered_samples) { + if (ops->ordered_samples) { ret = perf_session_queue_event(session, event, &sample, file_offset); if (ret != -ETIME) return ret; } - return perf_session_deliver_event(session, event, &sample, tool, + return perf_session_deliver_event(session, event, &sample, ops, file_offset); } @@ -915,11 +884,6 @@ void perf_event_header__bswap(struct perf_event_header *self) self->size = bswap_16(self->size); } -struct thread *perf_session__findnew(struct perf_session *session, pid_t pid) -{ - return machine__findnew_thread(&session->host_machine, pid); -} - static struct thread *perf_session__register_idle_thread(struct perf_session *self) { struct thread *thread = perf_session__findnew(self, 0); @@ -933,9 +897,9 @@ static struct thread *perf_session__register_idle_thread(struct perf_session *se } static void perf_session__warn_about_errors(const struct perf_session *session, - const struct perf_tool *tool) + const struct perf_event_ops *ops) { - if (tool->lost == perf_event__process_lost && + if (ops->lost == perf_event__process_lost && session->hists.stats.nr_events[PERF_RECORD_LOST] != 0) { ui__warning("Processed %d events and lost %d chunks!\n\n" "Check IO/CPU overload!\n\n", @@ -970,7 +934,7 @@ static void perf_session__warn_about_errors(const struct perf_session *session, volatile int session_done; static int __perf_session__process_pipe_events(struct perf_session *self, - struct perf_tool *tool) + struct perf_event_ops *ops) { union perf_event event; uint32_t size; @@ -979,7 +943,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self, int err; void *p; - perf_tool__fill_defaults(tool); + perf_event_ops__fill_defaults(ops); head = 0; more: @@ -1015,7 +979,8 @@ static int __perf_session__process_pipe_events(struct perf_session *self, } } - if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { + if (size == 0 || + (skip = perf_session__process_event(self, &event, ops, head)) < 0) { dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", head, event.header.size, event.header.type); /* @@ -1038,7 +1003,7 @@ static int __perf_session__process_pipe_events(struct perf_session *self, done: err = 0; out_err: - perf_session__warn_about_errors(self, tool); + perf_session__warn_about_errors(self, ops); perf_session_free_sample_buffers(self); return err; } @@ -1069,7 +1034,7 @@ fetch_mmaped_event(struct perf_session *session, int __perf_session__process_events(struct perf_session *session, u64 data_offset, u64 data_size, - u64 file_size, struct perf_tool *tool) + u64 file_size, struct perf_event_ops *ops) { u64 head, page_offset, file_offset, file_pos, progress_next; int err, mmap_prot, mmap_flags, map_idx = 0; @@ -1078,7 +1043,7 @@ int __perf_session__process_events(struct perf_session *session, union perf_event *event; uint32_t size; - perf_tool__fill_defaults(tool); + perf_event_ops__fill_defaults(ops); page_size = sysconf(_SC_PAGESIZE); @@ -1133,7 +1098,7 @@ int __perf_session__process_events(struct perf_session *session, size = event->header.size; if (size == 0 || - perf_session__process_event(session, event, tool, file_pos) < 0) { + perf_session__process_event(session, event, ops, file_pos) < 0) { dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", file_offset + head, event->header.size, event->header.type); @@ -1162,15 +1127,15 @@ int __perf_session__process_events(struct perf_session *session, err = 0; /* do the final flush for ordered samples */ session->ordered_samples.next_flush = ULLONG_MAX; - flush_sample_queue(session, tool); + flush_sample_queue(session, ops); out_err: - perf_session__warn_about_errors(session, tool); + perf_session__warn_about_errors(session, ops); perf_session_free_sample_buffers(session); return err; } int perf_session__process_events(struct perf_session *self, - struct perf_tool *tool) + struct perf_event_ops *ops) { int err; @@ -1181,9 +1146,9 @@ int perf_session__process_events(struct perf_session *self, err = __perf_session__process_events(self, self->header.data_offset, self->header.data_size, - self->size, tool); + self->size, ops); else - err = __perf_session__process_pipe_events(self, tool); + err = __perf_session__process_pipe_events(self, ops); return err; } @@ -1198,8 +1163,9 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg) return true; } -int maps__set_kallsyms_ref_reloc_sym(struct map **maps, - const char *symbol_name, u64 addr) +int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, + const char *symbol_name, + u64 addr) { char *bracket; enum map_type i; @@ -1258,27 +1224,6 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) return ret; } -size_t perf_session__fprintf(struct perf_session *session, FILE *fp) -{ - /* - * FIXME: Here we have to actually print all the machines in this - * session, not just the host... - */ - return machine__fprintf(&session->host_machine, fp); -} - -void perf_session__remove_thread(struct perf_session *session, - struct thread *th) -{ - /* - * FIXME: This one makes no sense, we need to remove the thread from - * the machine it belongs to, perf_session can have many machines, so - * doing it always on ->host_machine is wrong. Fix when auditing all - * the 'perf kvm' code. - */ - machine__remove_thread(&session->host_machine, th); -} - struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type) { @@ -1291,16 +1236,17 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, return NULL; } -void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, - struct machine *machine, struct perf_evsel *evsel, - int print_sym, int print_dso) +void perf_session__print_ip(union perf_event *event, + struct perf_sample *sample, + struct perf_session *session, + int print_sym, int print_dso) { struct addr_location al; const char *symname, *dsoname; - struct callchain_cursor *cursor = &evsel->hists.callchain_cursor; + struct callchain_cursor *cursor = &session->callchain_cursor; struct callchain_cursor_node *node; - if (perf_event__preprocess_sample(event, machine, &al, sample, + if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { error("problem processing %d event, skipping it.\n", event->header.type); @@ -1309,7 +1255,7 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, if (symbol_conf.use_callchain && sample->callchain) { - if (machine__resolve_callchain(machine, evsel, al.thread, + if (perf_session__resolve_callchain(session, al.thread, sample->callchain, NULL) != 0) { if (verbose) error("Failed to resolve callchain. Skipping\n"); diff --git a/trunk/tools/perf/util/session.h b/trunk/tools/perf/util/session.h index 37bc38381fb6..6e393c98eb34 100644 --- a/trunk/tools/perf/util/session.h +++ b/trunk/tools/perf/util/session.h @@ -30,6 +30,9 @@ struct perf_session { struct perf_header header; unsigned long size; unsigned long mmap_window; + struct rb_root threads; + struct list_head dead_threads; + struct thread *last_match; struct machine host_machine; struct rb_root machines; struct perf_evlist *evlist; @@ -50,31 +53,65 @@ struct perf_session { int cwdlen; char *cwd; struct ordered_samples ordered_samples; - char filename[1]; + struct callchain_cursor callchain_cursor; + char filename[0]; }; -struct perf_tool; +struct perf_evsel; +struct perf_event_ops; + +typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session); +typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, + struct perf_session *session); +typedef int (*event_synth_op)(union perf_event *self, + struct perf_session *session); +typedef int (*event_op2)(union perf_event *self, struct perf_session *session, + struct perf_event_ops *ops); + +struct perf_event_ops { + event_sample sample; + event_op mmap, + comm, + fork, + exit, + lost, + read, + throttle, + unthrottle; + event_synth_op attr, + event_type, + tracing_data, + build_id; + event_op2 finished_round; + bool ordered_samples; + bool ordering_requires_timestamps; +}; struct perf_session *perf_session__new(const char *filename, int mode, bool force, bool repipe, - struct perf_tool *tool); + struct perf_event_ops *ops); void perf_session__delete(struct perf_session *self); void perf_event_header__bswap(struct perf_event_header *self); int __perf_session__process_events(struct perf_session *self, u64 data_offset, u64 data_size, u64 size, - struct perf_tool *tool); + struct perf_event_ops *ops); int perf_session__process_events(struct perf_session *self, - struct perf_tool *tool); + struct perf_event_ops *event_ops); -int perf_session__resolve_callchain(struct perf_session *self, struct perf_evsel *evsel, +int perf_session__resolve_callchain(struct perf_session *self, struct thread *thread, struct ip_callchain *chain, struct symbol **parent); bool perf_session__has_traces(struct perf_session *self, const char *msg); +int perf_session__set_kallsyms_ref_reloc_sym(struct map **maps, + const char *symbol_name, + u64 addr); + void mem_bswap_64(void *src, int byte_size); void perf_event__attr_swap(struct perf_event_attr *attr); @@ -107,16 +144,12 @@ struct machine *perf_session__findnew_machine(struct perf_session *self, pid_t p static inline void perf_session__process_machines(struct perf_session *self, - struct perf_tool *tool, machine__process_t process) { - process(&self->host_machine, tool); - return machines__process(&self->machines, process, tool); + process(&self->host_machine, self); + return machines__process(&self->machines, process, self); } -struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); -size_t perf_session__fprintf(struct perf_session *self, FILE *fp); - size_t perf_session__fprintf_dsos(struct perf_session *self, FILE *fp); size_t perf_session__fprintf_dsos_buildid(struct perf_session *self, @@ -134,20 +167,13 @@ static inline int perf_session__parse_sample(struct perf_session *session, session->header.needs_swap); } -static inline int perf_session__synthesize_sample(struct perf_session *session, - union perf_event *event, - const struct perf_sample *sample) -{ - return perf_event__synthesize_sample(event, session->sample_type, - sample, session->header.needs_swap); -} - struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); -void perf_event__print_ip(union perf_event *event, struct perf_sample *sample, - struct machine *machine, struct perf_evsel *evsel, - int print_sym, int print_dso); +void perf_session__print_ip(union perf_event *event, + struct perf_sample *sample, + struct perf_session *session, + int print_sym, int print_dso); int perf_session__cpu_bitmap(struct perf_session *session, const char *cpu_list, unsigned long *cpu_bitmap); diff --git a/trunk/tools/perf/util/setup.py b/trunk/tools/perf/util/setup.py index 36d4c5619575..95d370074928 100644 --- a/trunk/tools/perf/util/setup.py +++ b/trunk/tools/perf/util/setup.py @@ -27,8 +27,7 @@ def finalize_options(self): perf = Extension('perf', sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', - 'util/util.c', 'util/xyarray.c', 'util/cgroup.c', - 'util/debugfs.c'], + 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], include_dirs = ['util/include'], extra_compile_args = cflags, ) diff --git a/trunk/tools/perf/util/symbol.c b/trunk/tools/perf/util/symbol.c index 215d50f2042e..632b50c7bc26 100644 --- a/trunk/tools/perf/util/symbol.c +++ b/trunk/tools/perf/util/symbol.c @@ -1757,7 +1757,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, struct stat st; /*sshfs might return bad dent->d_type, so we have to stat*/ - snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); + sprintf(path, "%s/%s", dir_name, dent->d_name); if (stat(path, &st)) continue; @@ -1766,6 +1766,8 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, !strcmp(dent->d_name, "..")) continue; + snprintf(path, sizeof(path), "%s/%s", + dir_name, dent->d_name); ret = map_groups__set_modules_path_dir(mg, path); if (ret < 0) goto out; @@ -1786,6 +1788,9 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg, if (map == NULL) continue; + snprintf(path, sizeof(path), "%s/%s", + dir_name, dent->d_name); + long_name = strdup(path); if (long_name == NULL) { ret = -1; @@ -2604,10 +2609,10 @@ int symbol__init(void) symbol_conf.initialized = true; return 0; -out_free_comm_list: - strlist__delete(symbol_conf.comm_list); out_free_dso_list: strlist__delete(symbol_conf.dso_list); +out_free_comm_list: + strlist__delete(symbol_conf.comm_list); return -1; } diff --git a/trunk/tools/perf/util/symbol.h b/trunk/tools/perf/util/symbol.h index 123c2e14353e..29f8d742e92f 100644 --- a/trunk/tools/perf/util/symbol.h +++ b/trunk/tools/perf/util/symbol.h @@ -68,7 +68,6 @@ struct strlist; struct symbol_conf { unsigned short priv_size; - unsigned short nr_events; bool try_vmlinux_path, use_modules, sort_by_name, diff --git a/trunk/tools/perf/util/thread.c b/trunk/tools/perf/util/thread.c index fb4b7ea6752f..d5d3b22250f3 100644 --- a/trunk/tools/perf/util/thread.c +++ b/trunk/tools/perf/util/thread.c @@ -61,7 +61,7 @@ static size_t thread__fprintf(struct thread *self, FILE *fp) map_groups__fprintf(&self->mg, verbose, fp); } -struct thread *machine__findnew_thread(struct machine *self, pid_t pid) +struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) { struct rb_node **p = &self->threads.rb_node; struct rb_node *parent = NULL; @@ -125,12 +125,12 @@ int thread__fork(struct thread *self, struct thread *parent) return 0; } -size_t machine__fprintf(struct machine *machine, FILE *fp) +size_t perf_session__fprintf(struct perf_session *self, FILE *fp) { size_t ret = 0; struct rb_node *nd; - for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { + for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) { struct thread *pos = rb_entry(nd, struct thread, rb_node); ret += thread__fprintf(pos, fp); diff --git a/trunk/tools/perf/util/thread.h b/trunk/tools/perf/util/thread.h index 70c2c13ff679..e5f2401c1b5e 100644 --- a/trunk/tools/perf/util/thread.h +++ b/trunk/tools/perf/util/thread.h @@ -18,14 +18,16 @@ struct thread { int comm_len; }; -struct machine; +struct perf_session; void thread__delete(struct thread *self); int thread__set_comm(struct thread *self, const char *comm); int thread__comm_len(struct thread *self); +struct thread *perf_session__findnew(struct perf_session *self, pid_t pid); void thread__insert_map(struct thread *self, struct map *map); int thread__fork(struct thread *self, struct thread *parent); +size_t perf_session__fprintf(struct perf_session *self, FILE *fp); static inline struct map *thread__find_map(struct thread *self, enum map_type type, u64 addr) @@ -33,12 +35,14 @@ static inline struct map *thread__find_map(struct thread *self, return self ? map_groups__find(&self->mg, type, addr) : NULL; } -void thread__find_addr_map(struct thread *thread, struct machine *machine, - u8 cpumode, enum map_type type, u64 addr, +void thread__find_addr_map(struct thread *self, + struct perf_session *session, u8 cpumode, + enum map_type type, pid_t pid, u64 addr, struct addr_location *al); -void thread__find_addr_location(struct thread *thread, struct machine *machine, - u8 cpumode, enum map_type type, u64 addr, +void thread__find_addr_location(struct thread *self, + struct perf_session *session, u8 cpumode, + enum map_type type, pid_t pid, u64 addr, struct addr_location *al, symbol_filter_t filter); #endif /* __PERF_THREAD_H */ diff --git a/trunk/tools/perf/util/tool.h b/trunk/tools/perf/util/tool.h deleted file mode 100644 index b0e1aadba8d5..000000000000 --- a/trunk/tools/perf/util/tool.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef __PERF_TOOL_H -#define __PERF_TOOL_H - -#include - -struct perf_session; -union perf_event; -struct perf_evlist; -struct perf_evsel; -struct perf_sample; -struct perf_tool; -struct machine; - -typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, - struct perf_sample *sample, - struct perf_evsel *evsel, struct machine *machine); - -typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, - struct perf_sample *sample, struct machine *machine); - -typedef int (*event_attr_op)(union perf_event *event, - struct perf_evlist **pevlist); -typedef int (*event_simple_op)(struct perf_tool *tool, union perf_event *event); - -typedef int (*event_synth_op)(union perf_event *event, - struct perf_session *session); - -typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event, - struct perf_session *session); - -struct perf_tool { - event_sample sample, - read; - event_op mmap, - comm, - fork, - exit, - lost, - throttle, - unthrottle; - event_attr_op attr; - event_synth_op tracing_data; - event_simple_op event_type; - event_op2 finished_round, - build_id; - bool ordered_samples; - bool ordering_requires_timestamps; -}; - -#endif /* __PERF_TOOL_H */ diff --git a/trunk/tools/perf/util/top.h b/trunk/tools/perf/util/top.h index a248f3c2c60d..399650967958 100644 --- a/trunk/tools/perf/util/top.h +++ b/trunk/tools/perf/util/top.h @@ -1,17 +1,15 @@ #ifndef __PERF_TOP_H #define __PERF_TOP_H 1 -#include "tool.h" #include "types.h" +#include "../perf.h" #include -#include struct perf_evlist; struct perf_evsel; struct perf_session; struct perf_top { - struct perf_tool tool; struct perf_evlist *evlist; /* * Symbols will be added here in perf_event__process_sample and will @@ -25,26 +23,10 @@ struct perf_top { int freq; pid_t target_pid, target_tid; bool hide_kernel_symbols, hide_user_symbols, zero; - bool system_wide; - bool use_tui, use_stdio; - bool sort_has_symbols; - bool dont_use_callchains; - bool kptr_restrict_warned; - bool vmlinux_warned; - bool inherit; - bool group; - bool sample_id_all_avail; - bool dump_symtab; const char *cpu_list; struct hist_entry *sym_filter_entry; struct perf_evsel *sym_evsel; struct perf_session *session; - struct winsize winsize; - unsigned int mmap_pages; - int default_interval; - int realtime_prio; - int sym_pcnt_filter; - const char *sym_filter; }; size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); diff --git a/trunk/tools/perf/util/trace-event-info.c b/trunk/tools/perf/util/trace-event-info.c index ac6830d8292b..d2655f08bcc0 100644 --- a/trunk/tools/perf/util/trace-event-info.c +++ b/trunk/tools/perf/util/trace-event-info.c @@ -18,8 +18,7 @@ * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -#include -#include "util.h" +#define _GNU_SOURCE #include #include #include @@ -32,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +44,10 @@ #define VERSION "0.5" +#define _STR(x) #x +#define STR(x) _STR(x) +#define MAX_PATH 256 + #define TRACE_CTRL "tracing_on" #define TRACE "trace" #define AVAILABLE "available_tracers" @@ -69,6 +73,26 @@ struct events { }; + +static void die(const char *fmt, ...) +{ + va_list ap; + int ret = errno; + + if (errno) + perror("perf"); + else + ret = -1; + + va_start(ap, fmt); + fprintf(stderr, " "); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + exit(ret); +} + void *malloc_or_die(unsigned int size) { void *data; diff --git a/trunk/tools/perf/util/trace-event-scripting.c b/trunk/tools/perf/util/trace-event-scripting.c index a3fdf55f317b..c9dcbec7d800 100644 --- a/trunk/tools/perf/util/trace-event-scripting.c +++ b/trunk/tools/perf/util/trace-event-scripting.c @@ -39,7 +39,7 @@ static int stop_script_unsupported(void) static void process_event_unsupported(union perf_event *event __unused, struct perf_sample *sample __unused, struct perf_evsel *evsel __unused, - struct machine *machine __unused, + struct perf_session *session __unused, struct thread *thread __unused) { } diff --git a/trunk/tools/perf/util/trace-event.h b/trunk/tools/perf/util/trace-event.h index 58ae14c5baac..a84100817649 100644 --- a/trunk/tools/perf/util/trace-event.h +++ b/trunk/tools/perf/util/trace-event.h @@ -3,11 +3,7 @@ #include #include "parse-events.h" - -struct machine; -struct perf_sample; -union perf_event; -struct thread; +#include "session.h" #define __unused __attribute__((unused)) @@ -296,7 +292,7 @@ struct scripting_ops { void (*process_event) (union perf_event *event, struct perf_sample *sample, struct perf_evsel *evsel, - struct machine *machine, + struct perf_session *session, struct thread *thread); int (*generate_script) (const char *outfile); }; diff --git a/trunk/tools/perf/util/ui/browsers/annotate.c b/trunk/tools/perf/util/ui/browsers/annotate.c index 295a9c93f945..0575905d1205 100644 --- a/trunk/tools/perf/util/ui/browsers/annotate.c +++ b/trunk/tools/perf/util/ui/browsers/annotate.c @@ -224,7 +224,7 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser) } static int annotate_browser__run(struct annotate_browser *self, int evidx, - void(*timer)(void *arg), + int nr_events, void(*timer)(void *arg), void *arg, int delay_secs) { struct rb_node *nd = NULL; @@ -328,7 +328,8 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, notes = symbol__annotation(target); pthread_mutex_lock(¬es->lock); - if (notes->src == NULL && symbol__alloc_hist(target) < 0) { + if (notes->src == NULL && + symbol__alloc_hist(target, nr_events) < 0) { pthread_mutex_unlock(¬es->lock); ui__warning("Not enough memory for annotating '%s' symbol!\n", target->name); @@ -336,7 +337,7 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, } pthread_mutex_unlock(¬es->lock); - symbol__tui_annotate(target, ms->map, evidx, + symbol__tui_annotate(target, ms->map, evidx, nr_events, timer, arg, delay_secs); } continue; @@ -357,15 +358,15 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, return key; } -int hist_entry__tui_annotate(struct hist_entry *he, int evidx, +int hist_entry__tui_annotate(struct hist_entry *he, int evidx, int nr_events, void(*timer)(void *arg), void *arg, int delay_secs) { - return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, + return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, nr_events, timer, arg, delay_secs); } int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - void(*timer)(void *arg), void *arg, + int nr_events, void(*timer)(void *arg), void *arg, int delay_secs) { struct objdump_line *pos, *n; @@ -418,7 +419,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ - ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); + ret = annotate_browser__run(&browser, evidx, nr_events, + timer, arg, delay_secs); list_for_each_entry_safe(pos, n, ¬es->src->source, node) { list_del(&pos->node); objdump_line__free(pos); diff --git a/trunk/tools/perf/util/ui/browsers/hists.c b/trunk/tools/perf/util/ui/browsers/hists.c index 1212a386a033..d0c94b459685 100644 --- a/trunk/tools/perf/util/ui/browsers/hists.c +++ b/trunk/tools/perf/util/ui/browsers/hists.c @@ -1020,7 +1020,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, * Don't let this be freed, say, by hists__decay_entry. */ he->used = true; - err = hist_entry__tui_annotate(he, evsel->idx, + err = hist_entry__tui_annotate(he, evsel->idx, nr_events, timer, arg, delay_secs); he->used = false; ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries); diff --git a/trunk/tools/perf/util/ui/progress.c b/trunk/tools/perf/util/ui/progress.c index 13aa64e50e11..295e366b6311 100644 --- a/trunk/tools/perf/util/ui/progress.c +++ b/trunk/tools/perf/util/ui/progress.c @@ -14,9 +14,6 @@ void ui_progress__update(u64 curr, u64 total, const char *title) if (use_browser <= 0) return; - if (total == 0) - return; - ui__refresh_dimensions(true); pthread_mutex_lock(&ui__lock); y = SLtt_Screen_Rows / 2 - 2; diff --git a/trunk/tools/perf/util/usage.c b/trunk/tools/perf/util/usage.c index d76d1c0ff98f..e16bf9a707e8 100644 --- a/trunk/tools/perf/util/usage.c +++ b/trunk/tools/perf/util/usage.c @@ -1,8 +1,5 @@ /* - * usage.c - * - * Various reporting routines. - * Originally copied from GIT source. + * GIT - The information manager from hell * * Copyright (C) Linus Torvalds, 2005 */ diff --git a/trunk/tools/perf/util/util.h b/trunk/tools/perf/util/util.h index 37be34dff798..0128906bac88 100644 --- a/trunk/tools/perf/util/util.h +++ b/trunk/tools/perf/util/util.h @@ -245,15 +245,4 @@ int readn(int fd, void *buf, size_t size); #define _STR(x) #x #define STR(x) _STR(x) -/* - * Determine whether some value is a power of two, where zero is - * *not* considered a power of two. - */ - -static inline __attribute__((const)) -bool is_power_of_2(unsigned long n) -{ - return (n != 0 && ((n & (n - 1)) == 0)); -} - #endif diff --git a/trunk/tools/perf/util/values.c b/trunk/tools/perf/util/values.c index 697c8b4e59cc..bdd33470b235 100644 --- a/trunk/tools/perf/util/values.c +++ b/trunk/tools/perf/util/values.c @@ -32,7 +32,6 @@ void perf_read_values_destroy(struct perf_read_values *values) for (i = 0; i < values->threads; i++) free(values->value[i]); - free(values->value); free(values->pid); free(values->tid); free(values->counterrawid); diff --git a/trunk/virt/kvm/assigned-dev.c b/trunk/virt/kvm/assigned-dev.c index 3ad0925d23a9..758e3b36d4cf 100644 --- a/trunk/virt/kvm/assigned-dev.c +++ b/trunk/virt/kvm/assigned-dev.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "irq.h" static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head, @@ -480,12 +482,76 @@ static int kvm_vm_ioctl_deassign_dev_irq(struct kvm *kvm, return r; } +/* + * We want to test whether the caller has been granted permissions to + * use this device. To be able to configure and control the device, + * the user needs access to PCI configuration space and BAR resources. + * These are accessed through PCI sysfs. PCI config space is often + * passed to the process calling this ioctl via file descriptor, so we + * can't rely on access to that file. We can check for permissions + * on each of the BAR resource files, which is a pretty clear + * indicator that the user has been granted access to the device. + */ +static int probe_sysfs_permissions(struct pci_dev *dev) +{ +#ifdef CONFIG_SYSFS + int i; + bool bar_found = false; + + for (i = PCI_STD_RESOURCES; i <= PCI_STD_RESOURCE_END; i++) { + char *kpath, *syspath; + struct path path; + struct inode *inode; + int r; + + if (!pci_resource_len(dev, i)) + continue; + + kpath = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); + if (!kpath) + return -ENOMEM; + + /* Per sysfs-rules, sysfs is always at /sys */ + syspath = kasprintf(GFP_KERNEL, "/sys%s/resource%d", kpath, i); + kfree(kpath); + if (!syspath) + return -ENOMEM; + + r = kern_path(syspath, LOOKUP_FOLLOW, &path); + kfree(syspath); + if (r) + return r; + + inode = path.dentry->d_inode; + + r = inode_permission(inode, MAY_READ | MAY_WRITE | MAY_ACCESS); + path_put(&path); + if (r) + return r; + + bar_found = true; + } + + /* If no resources, probably something special */ + if (!bar_found) + return -EPERM; + + return 0; +#else + return -EINVAL; /* No way to control the device without sysfs */ +#endif +} + static int kvm_vm_ioctl_assign_device(struct kvm *kvm, struct kvm_assigned_pci_dev *assigned_dev) { int r = 0, idx; struct kvm_assigned_dev_kernel *match; struct pci_dev *dev; + u8 header_type; + + if (!(assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU)) + return -EINVAL; mutex_lock(&kvm->lock); idx = srcu_read_lock(&kvm->srcu); @@ -513,6 +579,18 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, r = -EINVAL; goto out_free; } + + /* Don't allow bridges to be assigned */ + pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); + if ((header_type & PCI_HEADER_TYPE) != PCI_HEADER_TYPE_NORMAL) { + r = -EPERM; + goto out_put; + } + + r = probe_sysfs_permissions(dev); + if (r) + goto out_put; + if (pci_enable_device(dev)) { printk(KERN_INFO "%s: Could not enable PCI device\n", __func__); r = -EBUSY; @@ -544,16 +622,14 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, list_add(&match->list, &kvm->arch.assigned_dev_head); - if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) { - if (!kvm->arch.iommu_domain) { - r = kvm_iommu_map_guest(kvm); - if (r) - goto out_list_del; - } - r = kvm_assign_device(kvm, match); + if (!kvm->arch.iommu_domain) { + r = kvm_iommu_map_guest(kvm); if (r) goto out_list_del; } + r = kvm_assign_device(kvm, match); + if (r) + goto out_list_del; out: srcu_read_unlock(&kvm->srcu, idx); @@ -593,8 +669,7 @@ static int kvm_vm_ioctl_deassign_device(struct kvm *kvm, goto out; } - if (match->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) - kvm_deassign_device(kvm, match); + kvm_deassign_device(kvm, match); kvm_free_assigned_device(kvm, match);