diff --git a/[refs] b/[refs] index 30dfd8c4a746..fb682f641d54 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: cfff2d909cbdaf8c467bd321aa0502a548ec8f7e +refs/heads/master: b06b3d49699a52e8f9ca056c4f96e81b1987d78e diff --git a/trunk/.gitignore b/trunk/.gitignore index 8faa6c02b39e..5d56a3fd0de6 100644 --- a/trunk/.gitignore +++ b/trunk/.gitignore @@ -28,6 +28,7 @@ modules.builtin *.gz *.bz2 *.lzma +*.xz *.lzo *.patch *.gcno diff --git a/trunk/Documentation/DocBook/filesystems.tmpl b/trunk/Documentation/DocBook/filesystems.tmpl index 5e87ad58c0b5..f51f28531b8d 100644 --- a/trunk/Documentation/DocBook/filesystems.tmpl +++ b/trunk/Documentation/DocBook/filesystems.tmpl @@ -82,6 +82,11 @@ + + Events based on file descriptors +!Efs/eventfd.c + + The Filesystem for Exporting Kernel Objects !Efs/sysfs/file.c diff --git a/trunk/Documentation/hwmon/jc42 b/trunk/Documentation/hwmon/jc42 index 0e76ef12e4c6..a22ecf48f255 100644 --- a/trunk/Documentation/hwmon/jc42 +++ b/trunk/Documentation/hwmon/jc42 @@ -51,7 +51,8 @@ Supported chips: * JEDEC JC 42.4 compliant temperature sensor chips Prefix: 'jc42' Addresses scanned: I2C 0x18 - 0x1f - Datasheet: - + Datasheet: + http://www.jedec.org/sites/default/files/docs/4_01_04R19.pdf Author: Guenter Roeck @@ -60,7 +61,11 @@ Author: Description ----------- -This driver implements support for JEDEC JC 42.4 compliant temperature sensors. +This driver implements support for JEDEC JC 42.4 compliant temperature sensors, +which are used on many DDR3 memory modules for mobile devices and servers. Some +systems use the sensor to prevent memory overheating by automatically throttling +the memory controller. + The driver auto-detects the chips listed above, but can be manually instantiated to support other JC 42.4 compliant chips. @@ -81,15 +86,19 @@ limits. The chip supports only a single register to configure the hysteresis, which applies to all limits. This register can be written by writing into temp1_crit_hyst. Other hysteresis attributes are read-only. +If the BIOS has configured the sensor for automatic temperature management, it +is likely that it has locked the registers, i.e., that the temperature limits +cannot be changed. + Sysfs entries ------------- temp1_input Temperature (RO) -temp1_min Minimum temperature (RW) -temp1_max Maximum temperature (RW) -temp1_crit Critical high temperature (RW) +temp1_min Minimum temperature (RO or RW) +temp1_max Maximum temperature (RO or RW) +temp1_crit Critical high temperature (RO or RW) -temp1_crit_hyst Critical hysteresis temperature (RW) +temp1_crit_hyst Critical hysteresis temperature (RO or RW) temp1_max_hyst Maximum hysteresis temperature (RO) temp1_min_alarm Temperature low alarm diff --git a/trunk/Documentation/hwmon/k10temp b/trunk/Documentation/hwmon/k10temp index 6526eee525a6..d2b56a4fd1f5 100644 --- a/trunk/Documentation/hwmon/k10temp +++ b/trunk/Documentation/hwmon/k10temp @@ -9,6 +9,8 @@ Supported chips: Socket S1G3: Athlon II, Sempron, Turion II * AMD Family 11h processors: Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra) +* AMD Family 12h processors: "Llano" +* AMD Family 14h processors: "Brazos" (C/E/G-Series) Prefix: 'k10temp' Addresses scanned: PCI space @@ -17,10 +19,14 @@ Supported chips: http://support.amd.com/us/Processor_TechDocs/31116.pdf BIOS and Kernel Developer's Guide (BKDG) for AMD Family 11h Processors: http://support.amd.com/us/Processor_TechDocs/41256.pdf + BIOS and Kernel Developer's Guide (BKDG) for AMD Family 14h Models 00h-0Fh Processors: + http://support.amd.com/us/Processor_TechDocs/43170.pdf Revision Guide for AMD Family 10h Processors: http://support.amd.com/us/Processor_TechDocs/41322.pdf Revision Guide for AMD Family 11h Processors: http://support.amd.com/us/Processor_TechDocs/41788.pdf + Revision Guide for AMD Family 14h Models 00h-0Fh Processors: + http://support.amd.com/us/Processor_TechDocs/47534.pdf AMD Family 11h Processor Power and Thermal Data Sheet for Notebooks: http://support.amd.com/us/Processor_TechDocs/43373.pdf AMD Family 10h Server and Workstation Processor Power and Thermal Data Sheet: @@ -34,7 +40,7 @@ Description ----------- This driver permits reading of the internal temperature sensor of AMD -Family 10h and 11h processors. +Family 10h/11h/12h/14h processors. All these processors have a sensor, but on those for Socket F or AM2+, the sensor may return inconsistent values (erratum 319). The driver diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 89835a4766a6..f4a04c0c7edc 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -144,6 +144,11 @@ a fixed number of characters. This limit depends on the architecture and is between 256 and 4096 characters. It is defined in the file ./include/asm/setup.h as COMMAND_LINE_SIZE. +Finally, the [KMG] suffix is commonly described after a number of kernel +parameter values. These 'K', 'M', and 'G' letters represent the _binary_ +multipliers 'Kilo', 'Mega', and 'Giga', equalling 2^10, 2^20, and 2^30 +bytes respectively. Such letter suffixes can also be entirely omitted. + acpi= [HW,ACPI,X86] Advanced Configuration and Power Interface @@ -545,16 +550,20 @@ and is between 256 and 4096 characters. It is defined in the file Format: ,,,[,] - crashkernel=nn[KMG]@ss[KMG] - [KNL] Reserve a chunk of physical memory to - hold a kernel to switch to with kexec on panic. + crashkernel=size[KMG][@offset[KMG]] + [KNL] Using kexec, Linux can switch to a 'crash kernel' + upon panic. This parameter reserves the physical + memory region [offset, offset + size] for that kernel + image. If '@offset' is omitted, then a suitable offset + is selected automatically. Check + Documentation/kdump/kdump.txt for further details. crashkernel=range1:size1[,range2:size2,...][@offset] [KNL] Same as above, but depends on the memory in the running system. The syntax of range is start-[end] where start and end are both a memory unit (amount[KMG]). See also - Documentation/kdump/kdump.txt for a example. + Documentation/kdump/kdump.txt for an example. cs89x0_dma= [HW,NET] Format: @@ -1262,10 +1271,9 @@ and is between 256 and 4096 characters. It is defined in the file 6 (KERN_INFO) informational 7 (KERN_DEBUG) debug-level messages - log_buf_len=n Sets the size of the printk ring buffer, in bytes. - Format: { n | nk | nM } - n must be a power of two. The default size - is set in the kernel config file. + log_buf_len=n[KMG] Sets the size of the printk ring buffer, + in bytes. n must be a power of two. The default + size is set in the kernel config file. logo.nologo [FB] Disables display of the built-in Linux logo. This may be used to provide more screen space for diff --git a/trunk/Documentation/networking/Makefile b/trunk/Documentation/networking/Makefile index 5aba7a33aeeb..24c308dd3fd1 100644 --- a/trunk/Documentation/networking/Makefile +++ b/trunk/Documentation/networking/Makefile @@ -4,6 +4,8 @@ obj- := dummy.o # List of programs to build hostprogs-y := ifenslave +HOSTCFLAGS_ifenslave.o += -I$(objtree)/usr/include + # Tell kbuild to always build the programs always := $(hostprogs-y) diff --git a/trunk/Documentation/trace/ftrace-design.txt b/trunk/Documentation/trace/ftrace-design.txt index 79fcafc7fd64..dc52bd442c92 100644 --- a/trunk/Documentation/trace/ftrace-design.txt +++ b/trunk/Documentation/trace/ftrace-design.txt @@ -247,13 +247,6 @@ You need very few things to get the syscalls tracing in an arch. - Support the TIF_SYSCALL_TRACEPOINT thread flags. - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace in the ptrace syscalls tracing path. -- If the system call table on this arch is more complicated than a simple array - of addresses of the system calls, implement an arch_syscall_addr to return - the address of a given system call. -- If the symbol names of the system calls do not match the function names on - this arch, define ARCH_HAS_SYSCALL_MATCH_SYM_NAME in asm/ftrace.h and - implement arch_syscall_match_sym_name with the appropriate logic to return - true if the function name corresponds with the symbol name. - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. diff --git a/trunk/Documentation/trace/ftrace.txt b/trunk/Documentation/trace/ftrace.txt index 67f1cc473257..557c1edeccaf 100644 --- a/trunk/Documentation/trace/ftrace.txt +++ b/trunk/Documentation/trace/ftrace.txt @@ -80,11 +80,11 @@ of ftrace. Here is a list of some of the key files: tracers listed here can be configured by echoing their name into current_tracer. - tracing_on: + tracing_enabled: - This sets or displays whether writing to the trace - ring buffer is enabled. Echo 0 into this file to disable - the tracer or 1 to enable it. + This sets or displays whether the current_tracer + is activated and tracing or not. Echo 0 into this + file to disable the tracer or 1 to enable it. trace: @@ -202,6 +202,10 @@ Here is the list of current tracers that may be configured. to draw a graph of function calls similar to C code source. + "sched_switch" + + Traces the context switches and wakeups between tasks. + "irqsoff" Traces the areas that disable interrupts and saves @@ -269,6 +273,39 @@ format, the function name that was traced "path_put" and the parent function that called this function "path_walk". The timestamp is the time at which the function was entered. +The sched_switch tracer also includes tracing of task wakeups +and context switches. + + ksoftirqd/1-7 [01] 1453.070013: 7:115:R + 2916:115:S + ksoftirqd/1-7 [01] 1453.070013: 7:115:R + 10:115:S + ksoftirqd/1-7 [01] 1453.070013: 7:115:R ==> 10:115:R + events/1-10 [01] 1453.070013: 10:115:S ==> 2916:115:R + kondemand/1-2916 [01] 1453.070013: 2916:115:S ==> 7:115:R + ksoftirqd/1-7 [01] 1453.070013: 7:115:S ==> 0:140:R + +Wake ups are represented by a "+" and the context switches are +shown as "==>". The format is: + + Context switches: + + Previous task Next Task + + :: ==> :: + + Wake ups: + + Current task Task waking up + + :: + :: + +The prio is the internal kernel priority, which is the inverse +of the priority that is usually displayed by user-space tools. +Zero represents the highest priority (99). Prio 100 starts the +"nice" priorities with 100 being equal to nice -20 and 139 being +nice 19. The prio "140" is reserved for the idle task which is +the lowest priority thread (pid 0). + + Latency trace format -------------------- @@ -454,6 +491,79 @@ x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6] latencies, as described in "Latency trace format". +sched_switch +------------ + +This tracer simply records schedule switches. Here is an example +of how to use it. + + # echo sched_switch > current_tracer + # echo 1 > tracing_enabled + # sleep 1 + # echo 0 > tracing_enabled + # cat trace + +# tracer: sched_switch +# +# TASK-PID CPU# TIMESTAMP FUNCTION +# | | | | | + bash-3997 [01] 240.132281: 3997:120:R + 4055:120:R + bash-3997 [01] 240.132284: 3997:120:R ==> 4055:120:R + sleep-4055 [01] 240.132371: 4055:120:S ==> 3997:120:R + bash-3997 [01] 240.132454: 3997:120:R + 4055:120:S + bash-3997 [01] 240.132457: 3997:120:R ==> 4055:120:R + sleep-4055 [01] 240.132460: 4055:120:D ==> 3997:120:R + bash-3997 [01] 240.132463: 3997:120:R + 4055:120:D + bash-3997 [01] 240.132465: 3997:120:R ==> 4055:120:R + -0 [00] 240.132589: 0:140:R + 4:115:S + -0 [00] 240.132591: 0:140:R ==> 4:115:R + ksoftirqd/0-4 [00] 240.132595: 4:115:S ==> 0:140:R + -0 [00] 240.132598: 0:140:R + 4:115:S + -0 [00] 240.132599: 0:140:R ==> 4:115:R + ksoftirqd/0-4 [00] 240.132603: 4:115:S ==> 0:140:R + sleep-4055 [01] 240.133058: 4055:120:S ==> 3997:120:R + [...] + + +As we have discussed previously about this format, the header +shows the name of the trace and points to the options. The +"FUNCTION" is a misnomer since here it represents the wake ups +and context switches. + +The sched_switch file only lists the wake ups (represented with +'+') and context switches ('==>') with the previous task or +current task first followed by the next task or task waking up. +The format for both of these is PID:KERNEL-PRIO:TASK-STATE. +Remember that the KERNEL-PRIO is the inverse of the actual +priority with zero (0) being the highest priority and the nice +values starting at 100 (nice -20). Below is a quick chart to map +the kernel priority to user land priorities. + + Kernel Space User Space + =============================================================== + 0(high) to 98(low) user RT priority 99(high) to 1(low) + with SCHED_RR or SCHED_FIFO + --------------------------------------------------------------- + 99 sched_priority is not used in scheduling + decisions(it must be specified as 0) + --------------------------------------------------------------- + 100(high) to 139(low) user nice -20(high) to 19(low) + --------------------------------------------------------------- + 140 idle task priority + --------------------------------------------------------------- + +The task states are: + + R - running : wants to run, may not actually be running + S - sleep : process is waiting to be woken up (handles signals) + D - disk sleep (uninterruptible sleep) : process must be woken up + (ignores signals) + T - stopped : process suspended + t - traced : process is being traced (with something like gdb) + Z - zombie : process waiting to be cleaned up + X - unknown + + ftrace_enabled -------------- @@ -497,10 +607,10 @@ an example: # echo irqsoff > current_tracer # echo latency-format > trace_options # echo 0 > tracing_max_latency - # echo 1 > tracing_on + # echo 1 > tracing_enabled # ls -ltr [...] - # echo 0 > tracing_on + # echo 0 > tracing_enabled # cat trace # tracer: irqsoff # @@ -605,10 +715,10 @@ is much like the irqsoff tracer. # echo preemptoff > current_tracer # echo latency-format > trace_options # echo 0 > tracing_max_latency - # echo 1 > tracing_on + # echo 1 > tracing_enabled # ls -ltr [...] - # echo 0 > tracing_on + # echo 0 > tracing_enabled # cat trace # tracer: preemptoff # @@ -753,10 +863,10 @@ tracers. # echo preemptirqsoff > current_tracer # echo latency-format > trace_options # echo 0 > tracing_max_latency - # echo 1 > tracing_on + # echo 1 > tracing_enabled # ls -ltr [...] - # echo 0 > tracing_on + # echo 0 > tracing_enabled # cat trace # tracer: preemptirqsoff # @@ -916,9 +1026,9 @@ Instead of performing an 'ls', we will run 'sleep 1' under # echo wakeup > current_tracer # echo latency-format > trace_options # echo 0 > tracing_max_latency - # echo 1 > tracing_on + # echo 1 > tracing_enabled # chrt -f 5 sleep 1 - # echo 0 > tracing_on + # echo 0 > tracing_enabled # cat trace # tracer: wakeup # @@ -1030,9 +1140,9 @@ ftrace_enabled is set; otherwise this tracer is a nop. # sysctl kernel.ftrace_enabled=1 # echo function > current_tracer - # echo 1 > tracing_on + # echo 1 > tracing_enabled # usleep 1 - # echo 0 > tracing_on + # echo 0 > tracing_enabled # cat trace # tracer: function # @@ -1070,7 +1180,7 @@ int trace_fd; [...] int main(int argc, char *argv[]) { [...] - trace_fd = open(tracing_file("tracing_on"), O_WRONLY); + trace_fd = open(tracing_file("tracing_enabled"), O_WRONLY); [...] if (condition_hit()) { write(trace_fd, "0", 1); @@ -1521,9 +1631,9 @@ If I am only interested in sys_nanosleep and hrtimer_interrupt: # echo sys_nanosleep hrtimer_interrupt \ > set_ftrace_filter # echo function > current_tracer - # echo 1 > tracing_on + # echo 1 > tracing_enabled # usleep 1 - # echo 0 > tracing_on + # echo 0 > tracing_enabled # cat trace # tracer: ftrace # @@ -1769,9 +1879,9 @@ different. The trace is live. # echo function > current_tracer # cat trace_pipe > /tmp/trace.out & [1] 4153 - # echo 1 > tracing_on + # echo 1 > tracing_enabled # usleep 1 - # echo 0 > tracing_on + # echo 0 > tracing_enabled # cat trace # tracer: function # diff --git a/trunk/Documentation/trace/kprobetrace.txt b/trunk/Documentation/trace/kprobetrace.txt index 6d27ab8d6e9f..5f77d94598dd 100644 --- a/trunk/Documentation/trace/kprobetrace.txt +++ b/trunk/Documentation/trace/kprobetrace.txt @@ -42,25 +42,11 @@ Synopsis of kprobe_events +|-offs(FETCHARG) : Fetch memory at FETCHARG +|- offs address.(**) NAME=FETCHARG : Set NAME as the argument name of FETCHARG. FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types - (u8/u16/u32/u64/s8/s16/s32/s64), "string" and bitfield - are supported. + (u8/u16/u32/u64/s8/s16/s32/s64) and string are supported. (*) only for return probe. (**) this is useful for fetching a field of data structures. -Types ------ -Several types are supported for fetch-args. Kprobe tracer will access memory -by given type. Prefix 's' and 'u' means those types are signed and unsigned -respectively. Traced arguments are shown in decimal (signed) or hex (unsigned). -String type is a special type, which fetches a "null-terminated" string from -kernel space. This means it will fail and store NULL if the string container -has been paged out. -Bitfield is another special type, which takes 3 parameters, bit-width, bit- -offset, and container-size (usually 32). The syntax is; - - b@/ - Per-Probe Event Filtering ------------------------- diff --git a/trunk/Documentation/workqueue.txt b/trunk/Documentation/workqueue.txt index 996a27d9b8db..01c513fac40e 100644 --- a/trunk/Documentation/workqueue.txt +++ b/trunk/Documentation/workqueue.txt @@ -190,9 +190,9 @@ resources, scheduled and executed. * Long running CPU intensive workloads which can be better managed by the system scheduler. - WQ_FREEZEABLE + WQ_FREEZABLE - A freezeable wq participates in the freeze phase of the system + A freezable wq participates in the freeze phase of the system suspend operations. Work items on the wq are drained and no new work item starts execution until thawed. diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 5dd6c751e6a6..6f99e1260db8 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -885,7 +885,7 @@ S: Supported ARM/QUALCOMM MSM MACHINE SUPPORT M: David Brown -M: Daniel Walker +M: Daniel Walker M: Bryan Huntsman L: linux-arm-msm@vger.kernel.org F: arch/arm/mach-msm/ @@ -2873,7 +2873,6 @@ M: Guenter Roeck L: lm-sensors@lm-sensors.org W: http://www.lm-sensors.org/ T: quilt kernel.org/pub/linux/kernel/people/jdelvare/linux-2.6/jdelvare-hwmon/ -T: quilt kernel.org/pub/linux/kernel/people/groeck/linux-staging/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git S: Maintained F: Documentation/hwmon/ diff --git a/trunk/Makefile b/trunk/Makefile index 5e40aa2acbff..26d7d824db51 100644 --- a/trunk/Makefile +++ b/trunk/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 38 -EXTRAVERSION = -rc5 +EXTRAVERSION = -rc6 NAME = Flesh-Eating Bats with Fangs # *DOCUMENTATION* diff --git a/trunk/arch/arm/Kconfig b/trunk/arch/arm/Kconfig index 26d45e5b636b..166efa2a19cd 100644 --- a/trunk/arch/arm/Kconfig +++ b/trunk/arch/arm/Kconfig @@ -1177,6 +1177,31 @@ config ARM_ERRATA_743622 visible impact on the overall performance or power consumption of the processor. +config ARM_ERRATA_751472 + bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation" + depends on CPU_V7 && SMP + help + This option enables the workaround for the 751472 Cortex-A9 (prior + to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the + completion of a following broadcasted operation if the second + operation is received by a CPU before the ICIALLUIS has completed, + potentially leading to corrupted entries in the cache or TLB. + +config ARM_ERRATA_753970 + bool "ARM errata: cache sync operation may be faulty" + depends on CACHE_PL310 + help + This option enables the workaround for the 753970 PL310 (r3p0) erratum. + + Under some condition the effect of cache sync operation on + the store buffer still remains when the operation completes. + This means that the store buffer is always asked to drain and + this prevents it from merging any further writes. The workaround + is to replace the normal offset of cache sync operation (0x730) + by another offset targeting an unmapped PL310 register 0x740. + This has the same effect as the cache sync operation: store buffer + drain and waiting for all buffers empty. + endmenu source "arch/arm/common/Kconfig" diff --git a/trunk/arch/arm/Makefile b/trunk/arch/arm/Makefile index c22c1adfedd6..6f7b29294c80 100644 --- a/trunk/arch/arm/Makefile +++ b/trunk/arch/arm/Makefile @@ -15,7 +15,7 @@ ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) LDFLAGS_vmlinux += --be8 endif -OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment -S +OBJCOPYFLAGS :=-O binary -R .comment -S GZFLAGS :=-9 #KBUILD_CFLAGS +=-pipe # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: diff --git a/trunk/arch/arm/boot/compressed/.gitignore b/trunk/arch/arm/boot/compressed/.gitignore index ab204db594d3..c6028967d336 100644 --- a/trunk/arch/arm/boot/compressed/.gitignore +++ b/trunk/arch/arm/boot/compressed/.gitignore @@ -1,3 +1,7 @@ font.c -piggy.gz +lib1funcs.S +piggy.gzip +piggy.lzo +piggy.lzma +vmlinux vmlinux.lds diff --git a/trunk/arch/arm/include/asm/hardware/cache-l2x0.h b/trunk/arch/arm/include/asm/hardware/cache-l2x0.h index 5aeec1e1735c..16bd48031583 100644 --- a/trunk/arch/arm/include/asm/hardware/cache-l2x0.h +++ b/trunk/arch/arm/include/asm/hardware/cache-l2x0.h @@ -36,6 +36,7 @@ #define L2X0_RAW_INTR_STAT 0x21C #define L2X0_INTR_CLEAR 0x220 #define L2X0_CACHE_SYNC 0x730 +#define L2X0_DUMMY_REG 0x740 #define L2X0_INV_LINE_PA 0x770 #define L2X0_INV_WAY 0x77C #define L2X0_CLEAN_LINE_PA 0x7B0 diff --git a/trunk/arch/arm/include/asm/hardware/sp810.h b/trunk/arch/arm/include/asm/hardware/sp810.h index 721847dc68ab..e0d1c0cfa548 100644 --- a/trunk/arch/arm/include/asm/hardware/sp810.h +++ b/trunk/arch/arm/include/asm/hardware/sp810.h @@ -58,6 +58,9 @@ static inline void sysctl_soft_reset(void __iomem *base) { + /* switch to slow mode */ + writel(0x2, base + SCCTRL); + /* writing any value to SCSYSSTAT reg will reset system */ writel(0, base + SCSYSSTAT); } diff --git a/trunk/arch/arm/include/asm/tlb.h b/trunk/arch/arm/include/asm/tlb.h index f41a6f57cd12..82dfe5d0c41e 100644 --- a/trunk/arch/arm/include/asm/tlb.h +++ b/trunk/arch/arm/include/asm/tlb.h @@ -18,16 +18,34 @@ #define __ASMARM_TLB_H #include -#include #ifndef CONFIG_MMU #include + +#define tlb_flush(tlb) ((void) tlb) + #include #else /* !CONFIG_MMU */ +#include #include +#include + +/* + * We need to delay page freeing for SMP as other CPUs can access pages + * which have been removed but not yet had their TLB entries invalidated. + * Also, as ARMv7 speculative prefetch can drag new entries into the TLB, + * we need to apply this same delaying tactic to ensure correct operation. + */ +#if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7) +#define tlb_fast_mode(tlb) 0 +#define FREE_PTE_NR 500 +#else +#define tlb_fast_mode(tlb) 1 +#define FREE_PTE_NR 0 +#endif /* * TLB handling. This allows us to remove pages from the page @@ -36,12 +54,58 @@ struct mmu_gather { struct mm_struct *mm; unsigned int fullmm; + struct vm_area_struct *vma; unsigned long range_start; unsigned long range_end; + unsigned int nr; + struct page *pages[FREE_PTE_NR]; }; DECLARE_PER_CPU(struct mmu_gather, mmu_gathers); +/* + * This is unnecessarily complex. There's three ways the TLB shootdown + * code is used: + * 1. Unmapping a range of vmas. See zap_page_range(), unmap_region(). + * tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called. + * tlb->vma will be non-NULL. + * 2. Unmapping all vmas. See exit_mmap(). + * tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called. + * tlb->vma will be non-NULL. Additionally, page tables will be freed. + * 3. Unmapping argument pages. See shift_arg_pages(). + * tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called. + * tlb->vma will be NULL. + */ +static inline void tlb_flush(struct mmu_gather *tlb) +{ + if (tlb->fullmm || !tlb->vma) + flush_tlb_mm(tlb->mm); + else if (tlb->range_end > 0) { + flush_tlb_range(tlb->vma, tlb->range_start, tlb->range_end); + tlb->range_start = TASK_SIZE; + tlb->range_end = 0; + } +} + +static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr) +{ + if (!tlb->fullmm) { + if (addr < tlb->range_start) + tlb->range_start = addr; + if (addr + PAGE_SIZE > tlb->range_end) + tlb->range_end = addr + PAGE_SIZE; + } +} + +static inline void tlb_flush_mmu(struct mmu_gather *tlb) +{ + tlb_flush(tlb); + if (!tlb_fast_mode(tlb)) { + free_pages_and_swap_cache(tlb->pages, tlb->nr); + tlb->nr = 0; + } +} + static inline struct mmu_gather * tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) { @@ -49,6 +113,8 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) tlb->mm = mm; tlb->fullmm = full_mm_flush; + tlb->vma = NULL; + tlb->nr = 0; return tlb; } @@ -56,8 +122,7 @@ tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) static inline void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) { - if (tlb->fullmm) - flush_tlb_mm(tlb->mm); + tlb_flush_mmu(tlb); /* keep the page table cache within bounds */ check_pgt_cache(); @@ -71,12 +136,7 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) static inline void tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long addr) { - if (!tlb->fullmm) { - if (addr < tlb->range_start) - tlb->range_start = addr; - if (addr + PAGE_SIZE > tlb->range_end) - tlb->range_end = addr + PAGE_SIZE; - } + tlb_add_flush(tlb, addr); } /* @@ -89,6 +149,7 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) { if (!tlb->fullmm) { flush_cache_range(vma, vma->vm_start, vma->vm_end); + tlb->vma = vma; tlb->range_start = TASK_SIZE; tlb->range_end = 0; } @@ -97,12 +158,30 @@ tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) static inline void tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) { - if (!tlb->fullmm && tlb->range_end > 0) - flush_tlb_range(vma, tlb->range_start, tlb->range_end); + if (!tlb->fullmm) + tlb_flush(tlb); +} + +static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ + if (tlb_fast_mode(tlb)) { + free_page_and_swap_cache(page); + } else { + tlb->pages[tlb->nr++] = page; + if (tlb->nr >= FREE_PTE_NR) + tlb_flush_mmu(tlb); + } +} + +static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte, + unsigned long addr) +{ + pgtable_page_dtor(pte); + tlb_add_flush(tlb, addr); + tlb_remove_page(tlb, pte); } -#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page) -#define pte_free_tlb(tlb, ptep, addr) pte_free((tlb)->mm, ptep) +#define pte_free_tlb(tlb, ptep, addr) __pte_free_tlb(tlb, ptep, addr) #define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp) #define tlb_migrate_finish(mm) do { } while (0) diff --git a/trunk/arch/arm/include/asm/tlbflush.h b/trunk/arch/arm/include/asm/tlbflush.h index ce7378ea15a2..d2005de383b8 100644 --- a/trunk/arch/arm/include/asm/tlbflush.h +++ b/trunk/arch/arm/include/asm/tlbflush.h @@ -10,12 +10,7 @@ #ifndef _ASMARM_TLBFLUSH_H #define _ASMARM_TLBFLUSH_H - -#ifndef CONFIG_MMU - -#define tlb_flush(tlb) ((void) tlb) - -#else /* CONFIG_MMU */ +#ifdef CONFIG_MMU #include diff --git a/trunk/arch/arm/kernel/kprobes-decode.c b/trunk/arch/arm/kernel/kprobes-decode.c index 2c1f0050c9c4..8f6ed43861f1 100644 --- a/trunk/arch/arm/kernel/kprobes-decode.c +++ b/trunk/arch/arm/kernel/kprobes-decode.c @@ -1437,7 +1437,7 @@ arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) return space_cccc_1100_010x(insn, asi); - } else if ((insn & 0x0e000000) == 0x0c400000) { + } else if ((insn & 0x0e000000) == 0x0c000000) { return space_cccc_110x(insn, asi); diff --git a/trunk/arch/arm/kernel/pmu.c b/trunk/arch/arm/kernel/pmu.c index b8af96ea62e6..2c79eec19262 100644 --- a/trunk/arch/arm/kernel/pmu.c +++ b/trunk/arch/arm/kernel/pmu.c @@ -97,28 +97,34 @@ set_irq_affinity(int irq, irq, cpu); return err; #else - return 0; + return -EINVAL; #endif } static int init_cpu_pmu(void) { - int i, err = 0; + int i, irqs, err = 0; struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; - if (!pdev) { - err = -ENODEV; - goto out; - } + if (!pdev) + return -ENODEV; + + irqs = pdev->num_resources; + + /* + * If we have a single PMU interrupt that we can't shift, assume that + * we're running on a uniprocessor machine and continue. + */ + if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0))) + return 0; - for (i = 0; i < pdev->num_resources; ++i) { + for (i = 0; i < irqs; ++i) { err = set_irq_affinity(platform_get_irq(pdev, i), i); if (err) break; } -out: return err; } diff --git a/trunk/arch/arm/kernel/setup.c b/trunk/arch/arm/kernel/setup.c index 420b8d6485d6..5ea4fb718b97 100644 --- a/trunk/arch/arm/kernel/setup.c +++ b/trunk/arch/arm/kernel/setup.c @@ -226,8 +226,8 @@ int cpu_architecture(void) * Register 0 and check for VMSAv7 or PMSAv7 */ asm("mrc p15, 0, %0, c0, c1, 4" : "=r" (mmfr0)); - if ((mmfr0 & 0x0000000f) == 0x00000003 || - (mmfr0 & 0x000000f0) == 0x00000030) + if ((mmfr0 & 0x0000000f) >= 0x00000003 || + (mmfr0 & 0x000000f0) >= 0x00000030) cpu_arch = CPU_ARCH_ARMv7; else if ((mmfr0 & 0x0000000f) == 0x00000002 || (mmfr0 & 0x000000f0) == 0x00000020) diff --git a/trunk/arch/arm/kernel/signal.c b/trunk/arch/arm/kernel/signal.c index 907d5a620bca..abaf8445ce25 100644 --- a/trunk/arch/arm/kernel/signal.c +++ b/trunk/arch/arm/kernel/signal.c @@ -474,7 +474,9 @@ setup_return(struct pt_regs *regs, struct k_sigaction *ka, unsigned long handler = (unsigned long)ka->sa.sa_handler; unsigned long retcode; int thumb = 0; - unsigned long cpsr = regs->ARM_cpsr & ~PSR_f; + unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT); + + cpsr |= PSR_ENDSTATE; /* * Maybe we need to deliver a 32-bit signal to a 26-bit task. diff --git a/trunk/arch/arm/kernel/vmlinux.lds.S b/trunk/arch/arm/kernel/vmlinux.lds.S index 86b66f3f2031..61462790757f 100644 --- a/trunk/arch/arm/kernel/vmlinux.lds.S +++ b/trunk/arch/arm/kernel/vmlinux.lds.S @@ -21,6 +21,12 @@ #define ARM_CPU_KEEP(x) #endif +#if defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK) +#define ARM_EXIT_KEEP(x) x +#else +#define ARM_EXIT_KEEP(x) +#endif + OUTPUT_ARCH(arm) ENTRY(stext) @@ -43,6 +49,7 @@ SECTIONS _sinittext = .; HEAD_TEXT INIT_TEXT + ARM_EXIT_KEEP(EXIT_TEXT) _einittext = .; ARM_CPU_DISCARD(PROC_INFO) __arch_info_begin = .; @@ -67,6 +74,7 @@ SECTIONS #ifndef CONFIG_XIP_KERNEL __init_begin = _stext; INIT_DATA + ARM_EXIT_KEEP(EXIT_DATA) #endif } @@ -162,6 +170,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_begin = .; INIT_DATA + ARM_EXIT_KEEP(EXIT_DATA) . = ALIGN(PAGE_SIZE); __init_end = .; #endif @@ -247,6 +256,8 @@ SECTIONS } #endif + NOTES + BSS_SECTION(0, 0, 0) _end = .; diff --git a/trunk/arch/arm/mach-s5p6442/include/mach/map.h b/trunk/arch/arm/mach-s5p6442/include/mach/map.h index 203dd5a18bd5..058dab4482a1 100644 --- a/trunk/arch/arm/mach-s5p6442/include/mach/map.h +++ b/trunk/arch/arm/mach-s5p6442/include/mach/map.h @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s5p6442/include/mach/map.h * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * S5P6442 - Memory map definitions @@ -16,56 +16,61 @@ #include #include -#define S5P6442_PA_CHIPID (0xE0000000) -#define S5P_PA_CHIPID S5P6442_PA_CHIPID +#define S5P6442_PA_SDRAM 0x20000000 -#define S5P6442_PA_SYSCON (0xE0100000) -#define S5P_PA_SYSCON S5P6442_PA_SYSCON +#define S5P6442_PA_I2S0 0xC0B00000 +#define S5P6442_PA_I2S1 0xF2200000 -#define S5P6442_PA_GPIO (0xE0200000) +#define S5P6442_PA_CHIPID 0xE0000000 -#define S5P6442_PA_VIC0 (0xE4000000) -#define S5P6442_PA_VIC1 (0xE4100000) -#define S5P6442_PA_VIC2 (0xE4200000) +#define S5P6442_PA_SYSCON 0xE0100000 -#define S5P6442_PA_SROMC (0xE7000000) -#define S5P_PA_SROMC S5P6442_PA_SROMC +#define S5P6442_PA_GPIO 0xE0200000 -#define S5P6442_PA_MDMA 0xE8000000 -#define S5P6442_PA_PDMA 0xE9000000 +#define S5P6442_PA_VIC0 0xE4000000 +#define S5P6442_PA_VIC1 0xE4100000 +#define S5P6442_PA_VIC2 0xE4200000 -#define S5P6442_PA_TIMER (0xEA000000) -#define S5P_PA_TIMER S5P6442_PA_TIMER +#define S5P6442_PA_SROMC 0xE7000000 -#define S5P6442_PA_SYSTIMER (0xEA100000) +#define S5P6442_PA_MDMA 0xE8000000 +#define S5P6442_PA_PDMA 0xE9000000 -#define S5P6442_PA_WATCHDOG (0xEA200000) +#define S5P6442_PA_TIMER 0xEA000000 -#define S5P6442_PA_UART (0xEC000000) +#define S5P6442_PA_SYSTIMER 0xEA100000 -#define S5P_PA_UART0 (S5P6442_PA_UART + 0x0) -#define S5P_PA_UART1 (S5P6442_PA_UART + 0x400) -#define S5P_PA_UART2 (S5P6442_PA_UART + 0x800) -#define S5P_SZ_UART SZ_256 +#define S5P6442_PA_WATCHDOG 0xEA200000 -#define S5P6442_PA_IIC0 (0xEC100000) +#define S5P6442_PA_UART 0xEC000000 -#define S5P6442_PA_SDRAM (0x20000000) -#define S5P_PA_SDRAM S5P6442_PA_SDRAM +#define S5P6442_PA_IIC0 0xEC100000 #define S5P6442_PA_SPI 0xEC300000 -/* I2S */ -#define S5P6442_PA_I2S0 0xC0B00000 -#define S5P6442_PA_I2S1 0xF2200000 - -/* PCM */ #define S5P6442_PA_PCM0 0xF2400000 #define S5P6442_PA_PCM1 0xF2500000 -/* compatibiltiy defines. */ +/* Compatibiltiy Defines */ + +#define S3C_PA_IIC S5P6442_PA_IIC0 #define S3C_PA_WDT S5P6442_PA_WATCHDOG + +#define S5P_PA_CHIPID S5P6442_PA_CHIPID +#define S5P_PA_SDRAM S5P6442_PA_SDRAM +#define S5P_PA_SROMC S5P6442_PA_SROMC +#define S5P_PA_SYSCON S5P6442_PA_SYSCON +#define S5P_PA_TIMER S5P6442_PA_TIMER + +/* UART */ + #define S3C_PA_UART S5P6442_PA_UART -#define S3C_PA_IIC S5P6442_PA_IIC0 + +#define S5P_PA_UART(x) (S3C_PA_UART + ((x) * S3C_UART_OFFSET)) +#define S5P_PA_UART0 S5P_PA_UART(0) +#define S5P_PA_UART1 S5P_PA_UART(1) +#define S5P_PA_UART2 S5P_PA_UART(2) + +#define S5P_SZ_UART SZ_256 #endif /* __ASM_ARCH_MAP_H */ diff --git a/trunk/arch/arm/mach-s5p64x0/include/mach/map.h b/trunk/arch/arm/mach-s5p64x0/include/mach/map.h index a9365e5ba614..95c91257c7ca 100644 --- a/trunk/arch/arm/mach-s5p64x0/include/mach/map.h +++ b/trunk/arch/arm/mach-s5p64x0/include/mach/map.h @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s5p64x0/include/mach/map.h * - * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. + * Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com * * S5P64X0 - Memory map definitions @@ -16,64 +16,46 @@ #include #include -#define S5P64X0_PA_SDRAM (0x20000000) +#define S5P64X0_PA_SDRAM 0x20000000 -#define S5P64X0_PA_CHIPID (0xE0000000) -#define S5P_PA_CHIPID S5P64X0_PA_CHIPID - -#define S5P64X0_PA_SYSCON (0xE0100000) -#define S5P_PA_SYSCON S5P64X0_PA_SYSCON - -#define S5P64X0_PA_GPIO (0xE0308000) - -#define S5P64X0_PA_VIC0 (0xE4000000) -#define S5P64X0_PA_VIC1 (0xE4100000) +#define S5P64X0_PA_CHIPID 0xE0000000 -#define S5P64X0_PA_SROMC (0xE7000000) -#define S5P_PA_SROMC S5P64X0_PA_SROMC - -#define S5P64X0_PA_PDMA (0xE9000000) - -#define S5P64X0_PA_TIMER (0xEA000000) -#define S5P_PA_TIMER S5P64X0_PA_TIMER +#define S5P64X0_PA_SYSCON 0xE0100000 -#define S5P64X0_PA_RTC (0xEA100000) +#define S5P64X0_PA_GPIO 0xE0308000 -#define S5P64X0_PA_WDT (0xEA200000) +#define S5P64X0_PA_VIC0 0xE4000000 +#define S5P64X0_PA_VIC1 0xE4100000 -#define S5P6440_PA_UART(x) (0xEC000000 + ((x) * S3C_UART_OFFSET)) -#define S5P6450_PA_UART(x) ((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000)) +#define S5P64X0_PA_SROMC 0xE7000000 -#define S5P_PA_UART0 S5P6450_PA_UART(0) -#define S5P_PA_UART1 S5P6450_PA_UART(1) -#define S5P_PA_UART2 S5P6450_PA_UART(2) -#define S5P_PA_UART3 S5P6450_PA_UART(3) -#define S5P_PA_UART4 S5P6450_PA_UART(4) -#define S5P_PA_UART5 S5P6450_PA_UART(5) +#define S5P64X0_PA_PDMA 0xE9000000 -#define S5P_SZ_UART SZ_256 +#define S5P64X0_PA_TIMER 0xEA000000 +#define S5P64X0_PA_RTC 0xEA100000 +#define S5P64X0_PA_WDT 0xEA200000 -#define S5P6440_PA_IIC0 (0xEC104000) -#define S5P6440_PA_IIC1 (0xEC20F000) -#define S5P6450_PA_IIC0 (0xEC100000) -#define S5P6450_PA_IIC1 (0xEC200000) +#define S5P6440_PA_IIC0 0xEC104000 +#define S5P6440_PA_IIC1 0xEC20F000 +#define S5P6450_PA_IIC0 0xEC100000 +#define S5P6450_PA_IIC1 0xEC200000 -#define S5P64X0_PA_SPI0 (0xEC400000) -#define S5P64X0_PA_SPI1 (0xEC500000) +#define S5P64X0_PA_SPI0 0xEC400000 +#define S5P64X0_PA_SPI1 0xEC500000 -#define S5P64X0_PA_HSOTG (0xED100000) +#define S5P64X0_PA_HSOTG 0xED100000 #define S5P64X0_PA_HSMMC(x) (0xED800000 + ((x) * 0x100000)) -#define S5P64X0_PA_I2S (0xF2000000) +#define S5P64X0_PA_I2S 0xF2000000 #define S5P6450_PA_I2S1 0xF2800000 #define S5P6450_PA_I2S2 0xF2900000 -#define S5P64X0_PA_PCM (0xF2100000) +#define S5P64X0_PA_PCM 0xF2100000 -#define S5P64X0_PA_ADC (0xF3000000) +#define S5P64X0_PA_ADC 0xF3000000 -/* compatibiltiy defines. */ +/* Compatibiltiy Defines */ #define S3C_PA_HSMMC0 S5P64X0_PA_HSMMC(0) #define S3C_PA_HSMMC1 S5P64X0_PA_HSMMC(1) @@ -83,6 +65,25 @@ #define S3C_PA_RTC S5P64X0_PA_RTC #define S3C_PA_WDT S5P64X0_PA_WDT +#define S5P_PA_CHIPID S5P64X0_PA_CHIPID +#define S5P_PA_SROMC S5P64X0_PA_SROMC +#define S5P_PA_SYSCON S5P64X0_PA_SYSCON +#define S5P_PA_TIMER S5P64X0_PA_TIMER + #define SAMSUNG_PA_ADC S5P64X0_PA_ADC +/* UART */ + +#define S5P6440_PA_UART(x) (0xEC000000 + ((x) * S3C_UART_OFFSET)) +#define S5P6450_PA_UART(x) ((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000)) + +#define S5P_PA_UART0 S5P6450_PA_UART(0) +#define S5P_PA_UART1 S5P6450_PA_UART(1) +#define S5P_PA_UART2 S5P6450_PA_UART(2) +#define S5P_PA_UART3 S5P6450_PA_UART(3) +#define S5P_PA_UART4 S5P6450_PA_UART(4) +#define S5P_PA_UART5 S5P6450_PA_UART(5) + +#define S5P_SZ_UART SZ_256 + #endif /* __ASM_ARCH_MAP_H */ diff --git a/trunk/arch/arm/mach-s5pc100/include/mach/map.h b/trunk/arch/arm/mach-s5pc100/include/mach/map.h index 328467b346aa..ccbe6b767f7d 100644 --- a/trunk/arch/arm/mach-s5pc100/include/mach/map.h +++ b/trunk/arch/arm/mach-s5pc100/include/mach/map.h @@ -1,4 +1,7 @@ /* linux/arch/arm/mach-s5pc100/include/mach/map.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ * * Copyright 2009 Samsung Electronics Co. * Byungho Min @@ -16,145 +19,115 @@ #include #include -/* - * map-base.h has already defined virtual memory address - * S3C_VA_IRQ S3C_ADDR(0x00000000) irq controller(s) - * S3C_VA_SYS S3C_ADDR(0x00100000) system control - * S3C_VA_MEM S3C_ADDR(0x00200000) system control (not used) - * S3C_VA_TIMER S3C_ADDR(0x00300000) timer block - * S3C_VA_WATCHDOG S3C_ADDR(0x00400000) watchdog - * S3C_VA_UART S3C_ADDR(0x01000000) UART - * - * S5PC100 specific virtual memory address can be defined here - * S5PC1XX_VA_GPIO S3C_ADDR(0x00500000) GPIO - * - */ +#define S5PC100_PA_SDRAM 0x20000000 + +#define S5PC100_PA_ONENAND 0xE7100000 +#define S5PC100_PA_ONENAND_BUF 0xB0000000 + +#define S5PC100_PA_CHIPID 0xE0000000 -#define S5PC100_PA_ONENAND_BUF (0xB0000000) -#define S5PC100_SZ_ONENAND_BUF (SZ_256M - SZ_32M) +#define S5PC100_PA_SYSCON 0xE0100000 -/* Chip ID */ +#define S5PC100_PA_OTHERS 0xE0200000 -#define S5PC100_PA_CHIPID (0xE0000000) -#define S5P_PA_CHIPID S5PC100_PA_CHIPID +#define S5PC100_PA_GPIO 0xE0300000 -#define S5PC100_PA_SYSCON (0xE0100000) -#define S5P_PA_SYSCON S5PC100_PA_SYSCON +#define S5PC100_PA_VIC0 0xE4000000 +#define S5PC100_PA_VIC1 0xE4100000 +#define S5PC100_PA_VIC2 0xE4200000 -#define S5PC100_PA_OTHERS (0xE0200000) -#define S5PC100_VA_OTHERS (S3C_VA_SYS + 0x10000) +#define S5PC100_PA_SROMC 0xE7000000 -#define S5PC100_PA_GPIO (0xE0300000) -#define S5PC1XX_VA_GPIO S3C_ADDR(0x00500000) +#define S5PC100_PA_CFCON 0xE7800000 -/* Interrupt */ -#define S5PC100_PA_VIC0 (0xE4000000) -#define S5PC100_PA_VIC1 (0xE4100000) -#define S5PC100_PA_VIC2 (0xE4200000) -#define S5PC100_VA_VIC S3C_VA_IRQ -#define S5PC100_VA_VIC_OFFSET 0x10000 -#define S5PC1XX_VA_VIC(x) (S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET)) +#define S5PC100_PA_MDMA 0xE8100000 +#define S5PC100_PA_PDMA0 0xE9000000 +#define S5PC100_PA_PDMA1 0xE9200000 -#define S5PC100_PA_SROMC (0xE7000000) -#define S5P_PA_SROMC S5PC100_PA_SROMC +#define S5PC100_PA_TIMER 0xEA000000 +#define S5PC100_PA_SYSTIMER 0xEA100000 +#define S5PC100_PA_WATCHDOG 0xEA200000 +#define S5PC100_PA_RTC 0xEA300000 -#define S5PC100_PA_ONENAND (0xE7100000) +#define S5PC100_PA_UART 0xEC000000 -#define S5PC100_PA_CFCON (0xE7800000) +#define S5PC100_PA_IIC0 0xEC100000 +#define S5PC100_PA_IIC1 0xEC200000 -/* DMA */ -#define S5PC100_PA_MDMA (0xE8100000) -#define S5PC100_PA_PDMA0 (0xE9000000) -#define S5PC100_PA_PDMA1 (0xE9200000) +#define S5PC100_PA_SPI0 0xEC300000 +#define S5PC100_PA_SPI1 0xEC400000 +#define S5PC100_PA_SPI2 0xEC500000 -/* Timer */ -#define S5PC100_PA_TIMER (0xEA000000) -#define S5P_PA_TIMER S5PC100_PA_TIMER +#define S5PC100_PA_USB_HSOTG 0xED200000 +#define S5PC100_PA_USB_HSPHY 0xED300000 -#define S5PC100_PA_SYSTIMER (0xEA100000) +#define S5PC100_PA_HSMMC(x) (0xED800000 + ((x) * 0x100000)) -#define S5PC100_PA_WATCHDOG (0xEA200000) -#define S5PC100_PA_RTC (0xEA300000) +#define S5PC100_PA_FB 0xEE000000 -#define S5PC100_PA_UART (0xEC000000) +#define S5PC100_PA_FIMC0 0xEE200000 +#define S5PC100_PA_FIMC1 0xEE300000 +#define S5PC100_PA_FIMC2 0xEE400000 -#define S5P_PA_UART0 (S5PC100_PA_UART + 0x0) -#define S5P_PA_UART1 (S5PC100_PA_UART + 0x400) -#define S5P_PA_UART2 (S5PC100_PA_UART + 0x800) -#define S5P_PA_UART3 (S5PC100_PA_UART + 0xC00) -#define S5P_SZ_UART SZ_256 +#define S5PC100_PA_I2S0 0xF2000000 +#define S5PC100_PA_I2S1 0xF2100000 +#define S5PC100_PA_I2S2 0xF2200000 -#define S5PC100_PA_IIC0 (0xEC100000) -#define S5PC100_PA_IIC1 (0xEC200000) +#define S5PC100_PA_AC97 0xF2300000 -/* SPI */ -#define S5PC100_PA_SPI0 0xEC300000 -#define S5PC100_PA_SPI1 0xEC400000 -#define S5PC100_PA_SPI2 0xEC500000 +#define S5PC100_PA_PCM0 0xF2400000 +#define S5PC100_PA_PCM1 0xF2500000 -/* USB HS OTG */ -#define S5PC100_PA_USB_HSOTG (0xED200000) -#define S5PC100_PA_USB_HSPHY (0xED300000) +#define S5PC100_PA_SPDIF 0xF2600000 -#define S5PC100_PA_FB (0xEE000000) +#define S5PC100_PA_TSADC 0xF3000000 -#define S5PC100_PA_FIMC0 (0xEE200000) -#define S5PC100_PA_FIMC1 (0xEE300000) -#define S5PC100_PA_FIMC2 (0xEE400000) +#define S5PC100_PA_KEYPAD 0xF3100000 -#define S5PC100_PA_I2S0 (0xF2000000) -#define S5PC100_PA_I2S1 (0xF2100000) -#define S5PC100_PA_I2S2 (0xF2200000) +/* Compatibiltiy Defines */ -#define S5PC100_PA_AC97 0xF2300000 +#define S3C_PA_FB S5PC100_PA_FB +#define S3C_PA_HSMMC0 S5PC100_PA_HSMMC(0) +#define S3C_PA_HSMMC1 S5PC100_PA_HSMMC(1) +#define S3C_PA_HSMMC2 S5PC100_PA_HSMMC(2) +#define S3C_PA_IIC S5PC100_PA_IIC0 +#define S3C_PA_IIC1 S5PC100_PA_IIC1 +#define S3C_PA_KEYPAD S5PC100_PA_KEYPAD +#define S3C_PA_ONENAND S5PC100_PA_ONENAND +#define S3C_PA_ONENAND_BUF S5PC100_PA_ONENAND_BUF +#define S3C_PA_RTC S5PC100_PA_RTC +#define S3C_PA_TSADC S5PC100_PA_TSADC +#define S3C_PA_USB_HSOTG S5PC100_PA_USB_HSOTG +#define S3C_PA_USB_HSPHY S5PC100_PA_USB_HSPHY +#define S3C_PA_WDT S5PC100_PA_WATCHDOG -/* PCM */ -#define S5PC100_PA_PCM0 0xF2400000 -#define S5PC100_PA_PCM1 0xF2500000 +#define S5P_PA_CHIPID S5PC100_PA_CHIPID +#define S5P_PA_FIMC0 S5PC100_PA_FIMC0 +#define S5P_PA_FIMC1 S5PC100_PA_FIMC1 +#define S5P_PA_FIMC2 S5PC100_PA_FIMC2 +#define S5P_PA_SDRAM S5PC100_PA_SDRAM +#define S5P_PA_SROMC S5PC100_PA_SROMC +#define S5P_PA_SYSCON S5PC100_PA_SYSCON +#define S5P_PA_TIMER S5PC100_PA_TIMER -#define S5PC100_PA_SPDIF 0xF2600000 +#define SAMSUNG_PA_ADC S5PC100_PA_TSADC +#define SAMSUNG_PA_CFCON S5PC100_PA_CFCON +#define SAMSUNG_PA_KEYPAD S5PC100_PA_KEYPAD -#define S5PC100_PA_TSADC (0xF3000000) +#define S5PC100_VA_OTHERS (S3C_VA_SYS + 0x10000) -/* KEYPAD */ -#define S5PC100_PA_KEYPAD (0xF3100000) +#define S3C_SZ_ONENAND_BUF (SZ_256M - SZ_32M) -#define S5PC100_PA_HSMMC(x) (0xED800000 + ((x) * 0x100000)) +/* UART */ -#define S5PC100_PA_SDRAM (0x20000000) -#define S5P_PA_SDRAM S5PC100_PA_SDRAM +#define S3C_PA_UART S5PC100_PA_UART -/* compatibiltiy defines. */ -#define S3C_PA_UART S5PC100_PA_UART -#define S3C_PA_IIC S5PC100_PA_IIC0 -#define S3C_PA_IIC1 S5PC100_PA_IIC1 -#define S3C_PA_FB S5PC100_PA_FB -#define S3C_PA_G2D S5PC100_PA_G2D -#define S3C_PA_G3D S5PC100_PA_G3D -#define S3C_PA_JPEG S5PC100_PA_JPEG -#define S3C_PA_ROTATOR S5PC100_PA_ROTATOR -#define S5P_VA_VIC0 S5PC1XX_VA_VIC(0) -#define S5P_VA_VIC1 S5PC1XX_VA_VIC(1) -#define S5P_VA_VIC2 S5PC1XX_VA_VIC(2) -#define S3C_PA_USB_HSOTG S5PC100_PA_USB_HSOTG -#define S3C_PA_USB_HSPHY S5PC100_PA_USB_HSPHY -#define S3C_PA_HSMMC0 S5PC100_PA_HSMMC(0) -#define S3C_PA_HSMMC1 S5PC100_PA_HSMMC(1) -#define S3C_PA_HSMMC2 S5PC100_PA_HSMMC(2) -#define S3C_PA_KEYPAD S5PC100_PA_KEYPAD -#define S3C_PA_WDT S5PC100_PA_WATCHDOG -#define S3C_PA_TSADC S5PC100_PA_TSADC -#define S3C_PA_ONENAND S5PC100_PA_ONENAND -#define S3C_PA_ONENAND_BUF S5PC100_PA_ONENAND_BUF -#define S3C_SZ_ONENAND_BUF S5PC100_SZ_ONENAND_BUF -#define S3C_PA_RTC S5PC100_PA_RTC - -#define SAMSUNG_PA_ADC S5PC100_PA_TSADC -#define SAMSUNG_PA_CFCON S5PC100_PA_CFCON -#define SAMSUNG_PA_KEYPAD S5PC100_PA_KEYPAD +#define S5P_PA_UART(x) (S3C_PA_UART + ((x) * S3C_UART_OFFSET)) +#define S5P_PA_UART0 S5P_PA_UART(0) +#define S5P_PA_UART1 S5P_PA_UART(1) +#define S5P_PA_UART2 S5P_PA_UART(2) +#define S5P_PA_UART3 S5P_PA_UART(3) -#define S5P_PA_FIMC0 S5PC100_PA_FIMC0 -#define S5P_PA_FIMC1 S5PC100_PA_FIMC1 -#define S5P_PA_FIMC2 S5PC100_PA_FIMC2 +#define S5P_SZ_UART SZ_256 -#endif /* __ASM_ARCH_C100_MAP_H */ +#endif /* __ASM_ARCH_MAP_H */ diff --git a/trunk/arch/arm/mach-s5pv210/include/mach/map.h b/trunk/arch/arm/mach-s5pv210/include/mach/map.h index 3611492ad681..1dd58836fd4f 100644 --- a/trunk/arch/arm/mach-s5pv210/include/mach/map.h +++ b/trunk/arch/arm/mach-s5pv210/include/mach/map.h @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s5pv210/include/mach/map.h * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * S5PV210 - Memory map definitions @@ -16,122 +16,120 @@ #include #include -#define S5PV210_PA_SROM_BANK5 (0xA8000000) +#define S5PV210_PA_SDRAM 0x20000000 -#define S5PC110_PA_ONENAND (0xB0000000) -#define S5P_PA_ONENAND S5PC110_PA_ONENAND +#define S5PV210_PA_SROM_BANK5 0xA8000000 -#define S5PC110_PA_ONENAND_DMA (0xB0600000) -#define S5P_PA_ONENAND_DMA S5PC110_PA_ONENAND_DMA +#define S5PC110_PA_ONENAND 0xB0000000 +#define S5PC110_PA_ONENAND_DMA 0xB0600000 -#define S5PV210_PA_CHIPID (0xE0000000) -#define S5P_PA_CHIPID S5PV210_PA_CHIPID +#define S5PV210_PA_CHIPID 0xE0000000 -#define S5PV210_PA_SYSCON (0xE0100000) -#define S5P_PA_SYSCON S5PV210_PA_SYSCON +#define S5PV210_PA_SYSCON 0xE0100000 -#define S5PV210_PA_GPIO (0xE0200000) +#define S5PV210_PA_GPIO 0xE0200000 -/* SPI */ -#define S5PV210_PA_SPI0 0xE1300000 -#define S5PV210_PA_SPI1 0xE1400000 +#define S5PV210_PA_SPDIF 0xE1100000 -#define S5PV210_PA_KEYPAD (0xE1600000) +#define S5PV210_PA_SPI0 0xE1300000 +#define S5PV210_PA_SPI1 0xE1400000 -#define S5PV210_PA_IIC0 (0xE1800000) -#define S5PV210_PA_IIC1 (0xFAB00000) -#define S5PV210_PA_IIC2 (0xE1A00000) +#define S5PV210_PA_KEYPAD 0xE1600000 -#define S5PV210_PA_TIMER (0xE2500000) -#define S5P_PA_TIMER S5PV210_PA_TIMER +#define S5PV210_PA_ADC 0xE1700000 -#define S5PV210_PA_SYSTIMER (0xE2600000) +#define S5PV210_PA_IIC0 0xE1800000 +#define S5PV210_PA_IIC1 0xFAB00000 +#define S5PV210_PA_IIC2 0xE1A00000 -#define S5PV210_PA_WATCHDOG (0xE2700000) +#define S5PV210_PA_AC97 0xE2200000 -#define S5PV210_PA_RTC (0xE2800000) -#define S5PV210_PA_UART (0xE2900000) +#define S5PV210_PA_PCM0 0xE2300000 +#define S5PV210_PA_PCM1 0xE1200000 +#define S5PV210_PA_PCM2 0xE2B00000 -#define S5P_PA_UART0 (S5PV210_PA_UART + 0x0) -#define S5P_PA_UART1 (S5PV210_PA_UART + 0x400) -#define S5P_PA_UART2 (S5PV210_PA_UART + 0x800) -#define S5P_PA_UART3 (S5PV210_PA_UART + 0xC00) +#define S5PV210_PA_TIMER 0xE2500000 +#define S5PV210_PA_SYSTIMER 0xE2600000 +#define S5PV210_PA_WATCHDOG 0xE2700000 +#define S5PV210_PA_RTC 0xE2800000 -#define S5P_SZ_UART SZ_256 +#define S5PV210_PA_UART 0xE2900000 -#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) +#define S5PV210_PA_SROMC 0xE8000000 -#define S5PV210_PA_SROMC (0xE8000000) -#define S5P_PA_SROMC S5PV210_PA_SROMC +#define S5PV210_PA_CFCON 0xE8200000 -#define S5PV210_PA_CFCON (0xE8200000) +#define S5PV210_PA_HSMMC(x) (0xEB000000 + ((x) * 0x100000)) -#define S5PV210_PA_MDMA 0xFA200000 -#define S5PV210_PA_PDMA0 0xE0900000 -#define S5PV210_PA_PDMA1 0xE0A00000 +#define S5PV210_PA_HSOTG 0xEC000000 +#define S5PV210_PA_HSPHY 0xEC100000 -#define S5PV210_PA_FB (0xF8000000) +#define S5PV210_PA_IIS0 0xEEE30000 +#define S5PV210_PA_IIS1 0xE2100000 +#define S5PV210_PA_IIS2 0xE2A00000 -#define S5PV210_PA_FIMC0 (0xFB200000) -#define S5PV210_PA_FIMC1 (0xFB300000) -#define S5PV210_PA_FIMC2 (0xFB400000) +#define S5PV210_PA_DMC0 0xF0000000 +#define S5PV210_PA_DMC1 0xF1400000 -#define S5PV210_PA_HSMMC(x) (0xEB000000 + ((x) * 0x100000)) +#define S5PV210_PA_VIC0 0xF2000000 +#define S5PV210_PA_VIC1 0xF2100000 +#define S5PV210_PA_VIC2 0xF2200000 +#define S5PV210_PA_VIC3 0xF2300000 -#define S5PV210_PA_HSOTG (0xEC000000) -#define S5PV210_PA_HSPHY (0xEC100000) +#define S5PV210_PA_FB 0xF8000000 -#define S5PV210_PA_VIC0 (0xF2000000) -#define S5PV210_PA_VIC1 (0xF2100000) -#define S5PV210_PA_VIC2 (0xF2200000) -#define S5PV210_PA_VIC3 (0xF2300000) +#define S5PV210_PA_MDMA 0xFA200000 +#define S5PV210_PA_PDMA0 0xE0900000 +#define S5PV210_PA_PDMA1 0xE0A00000 -#define S5PV210_PA_SDRAM (0x20000000) -#define S5P_PA_SDRAM S5PV210_PA_SDRAM +#define S5PV210_PA_MIPI_CSIS 0xFA600000 -/* S/PDIF */ -#define S5PV210_PA_SPDIF 0xE1100000 +#define S5PV210_PA_FIMC0 0xFB200000 +#define S5PV210_PA_FIMC1 0xFB300000 +#define S5PV210_PA_FIMC2 0xFB400000 -/* I2S */ -#define S5PV210_PA_IIS0 0xEEE30000 -#define S5PV210_PA_IIS1 0xE2100000 -#define S5PV210_PA_IIS2 0xE2A00000 +/* Compatibiltiy Defines */ -/* PCM */ -#define S5PV210_PA_PCM0 0xE2300000 -#define S5PV210_PA_PCM1 0xE1200000 -#define S5PV210_PA_PCM2 0xE2B00000 +#define S3C_PA_FB S5PV210_PA_FB +#define S3C_PA_HSMMC0 S5PV210_PA_HSMMC(0) +#define S3C_PA_HSMMC1 S5PV210_PA_HSMMC(1) +#define S3C_PA_HSMMC2 S5PV210_PA_HSMMC(2) +#define S3C_PA_HSMMC3 S5PV210_PA_HSMMC(3) +#define S3C_PA_IIC S5PV210_PA_IIC0 +#define S3C_PA_IIC1 S5PV210_PA_IIC1 +#define S3C_PA_IIC2 S5PV210_PA_IIC2 +#define S3C_PA_RTC S5PV210_PA_RTC +#define S3C_PA_USB_HSOTG S5PV210_PA_HSOTG +#define S3C_PA_WDT S5PV210_PA_WATCHDOG -/* AC97 */ -#define S5PV210_PA_AC97 0xE2200000 +#define S5P_PA_CHIPID S5PV210_PA_CHIPID +#define S5P_PA_FIMC0 S5PV210_PA_FIMC0 +#define S5P_PA_FIMC1 S5PV210_PA_FIMC1 +#define S5P_PA_FIMC2 S5PV210_PA_FIMC2 +#define S5P_PA_MIPI_CSIS0 S5PV210_PA_MIPI_CSIS +#define S5P_PA_ONENAND S5PC110_PA_ONENAND +#define S5P_PA_ONENAND_DMA S5PC110_PA_ONENAND_DMA +#define S5P_PA_SDRAM S5PV210_PA_SDRAM +#define S5P_PA_SROMC S5PV210_PA_SROMC +#define S5P_PA_SYSCON S5PV210_PA_SYSCON +#define S5P_PA_TIMER S5PV210_PA_TIMER -#define S5PV210_PA_ADC (0xE1700000) +#define SAMSUNG_PA_ADC S5PV210_PA_ADC +#define SAMSUNG_PA_CFCON S5PV210_PA_CFCON +#define SAMSUNG_PA_KEYPAD S5PV210_PA_KEYPAD -#define S5PV210_PA_DMC0 (0xF0000000) -#define S5PV210_PA_DMC1 (0xF1400000) +/* UART */ -#define S5PV210_PA_MIPI_CSIS 0xFA600000 +#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET)) -/* compatibiltiy defines. */ -#define S3C_PA_UART S5PV210_PA_UART -#define S3C_PA_HSMMC0 S5PV210_PA_HSMMC(0) -#define S3C_PA_HSMMC1 S5PV210_PA_HSMMC(1) -#define S3C_PA_HSMMC2 S5PV210_PA_HSMMC(2) -#define S3C_PA_HSMMC3 S5PV210_PA_HSMMC(3) -#define S3C_PA_IIC S5PV210_PA_IIC0 -#define S3C_PA_IIC1 S5PV210_PA_IIC1 -#define S3C_PA_IIC2 S5PV210_PA_IIC2 -#define S3C_PA_FB S5PV210_PA_FB -#define S3C_PA_RTC S5PV210_PA_RTC -#define S3C_PA_WDT S5PV210_PA_WATCHDOG -#define S3C_PA_USB_HSOTG S5PV210_PA_HSOTG -#define S5P_PA_FIMC0 S5PV210_PA_FIMC0 -#define S5P_PA_FIMC1 S5PV210_PA_FIMC1 -#define S5P_PA_FIMC2 S5PV210_PA_FIMC2 -#define S5P_PA_MIPI_CSIS0 S5PV210_PA_MIPI_CSIS +#define S3C_PA_UART S5PV210_PA_UART -#define SAMSUNG_PA_ADC S5PV210_PA_ADC -#define SAMSUNG_PA_CFCON S5PV210_PA_CFCON -#define SAMSUNG_PA_KEYPAD S5PV210_PA_KEYPAD +#define S5P_PA_UART(x) (S3C_PA_UART + ((x) * S3C_UART_OFFSET)) +#define S5P_PA_UART0 S5P_PA_UART(0) +#define S5P_PA_UART1 S5P_PA_UART(1) +#define S5P_PA_UART2 S5P_PA_UART(2) +#define S5P_PA_UART3 S5P_PA_UART(3) + +#define S5P_SZ_UART SZ_256 #endif /* __ASM_ARCH_MAP_H */ diff --git a/trunk/arch/arm/mach-s5pv210/mach-aquila.c b/trunk/arch/arm/mach-s5pv210/mach-aquila.c index 461aa035afc0..557add4fc56c 100644 --- a/trunk/arch/arm/mach-s5pv210/mach-aquila.c +++ b/trunk/arch/arm/mach-s5pv210/mach-aquila.c @@ -149,7 +149,7 @@ static struct regulator_init_data aquila_ldo2_data = { static struct regulator_init_data aquila_ldo3_data = { .constraints = { - .name = "VUSB/MIPI_1.1V", + .name = "VUSB+MIPI_1.1V", .min_uV = 1100000, .max_uV = 1100000, .apply_uV = 1, @@ -197,7 +197,7 @@ static struct regulator_init_data aquila_ldo7_data = { static struct regulator_init_data aquila_ldo8_data = { .constraints = { - .name = "VUSB/VADC_3.3V", + .name = "VUSB+VADC_3.3V", .min_uV = 3300000, .max_uV = 3300000, .apply_uV = 1, @@ -207,7 +207,7 @@ static struct regulator_init_data aquila_ldo8_data = { static struct regulator_init_data aquila_ldo9_data = { .constraints = { - .name = "VCC/VCAM_2.8V", + .name = "VCC+VCAM_2.8V", .min_uV = 2800000, .max_uV = 2800000, .apply_uV = 1, @@ -381,9 +381,12 @@ static struct max8998_platform_data aquila_max8998_pdata = { .buck1_set1 = S5PV210_GPH0(3), .buck1_set2 = S5PV210_GPH0(4), .buck2_set3 = S5PV210_GPH0(5), - .buck1_max_voltage1 = 1200000, - .buck1_max_voltage2 = 1200000, - .buck2_max_voltage = 1200000, + .buck1_voltage1 = 1200000, + .buck1_voltage2 = 1200000, + .buck1_voltage3 = 1200000, + .buck1_voltage4 = 1200000, + .buck2_voltage1 = 1200000, + .buck2_voltage2 = 1200000, }; #endif diff --git a/trunk/arch/arm/mach-s5pv210/mach-goni.c b/trunk/arch/arm/mach-s5pv210/mach-goni.c index e22d5112fd44..056f5c769b0a 100644 --- a/trunk/arch/arm/mach-s5pv210/mach-goni.c +++ b/trunk/arch/arm/mach-s5pv210/mach-goni.c @@ -288,7 +288,7 @@ static struct regulator_init_data goni_ldo2_data = { static struct regulator_init_data goni_ldo3_data = { .constraints = { - .name = "VUSB/MIPI_1.1V", + .name = "VUSB+MIPI_1.1V", .min_uV = 1100000, .max_uV = 1100000, .apply_uV = 1, @@ -337,7 +337,7 @@ static struct regulator_init_data goni_ldo7_data = { static struct regulator_init_data goni_ldo8_data = { .constraints = { - .name = "VUSB/VADC_3.3V", + .name = "VUSB+VADC_3.3V", .min_uV = 3300000, .max_uV = 3300000, .apply_uV = 1, @@ -347,7 +347,7 @@ static struct regulator_init_data goni_ldo8_data = { static struct regulator_init_data goni_ldo9_data = { .constraints = { - .name = "VCC/VCAM_2.8V", + .name = "VCC+VCAM_2.8V", .min_uV = 2800000, .max_uV = 2800000, .apply_uV = 1, @@ -521,9 +521,12 @@ static struct max8998_platform_data goni_max8998_pdata = { .buck1_set1 = S5PV210_GPH0(3), .buck1_set2 = S5PV210_GPH0(4), .buck2_set3 = S5PV210_GPH0(5), - .buck1_max_voltage1 = 1200000, - .buck1_max_voltage2 = 1200000, - .buck2_max_voltage = 1200000, + .buck1_voltage1 = 1200000, + .buck1_voltage2 = 1200000, + .buck1_voltage3 = 1200000, + .buck1_voltage4 = 1200000, + .buck2_voltage1 = 1200000, + .buck2_voltage2 = 1200000, }; #endif diff --git a/trunk/arch/arm/mach-s5pv310/include/mach/map.h b/trunk/arch/arm/mach-s5pv310/include/mach/map.h index 3060f78e12ab..901657fa7a12 100644 --- a/trunk/arch/arm/mach-s5pv310/include/mach/map.h +++ b/trunk/arch/arm/mach-s5pv310/include/mach/map.h @@ -1,6 +1,6 @@ /* linux/arch/arm/mach-s5pv310/include/mach/map.h * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ * * S5PV310 - Memory map definitions @@ -23,90 +23,43 @@ #include -#define S5PV310_PA_SYSRAM (0x02025000) +#define S5PV310_PA_SYSRAM 0x02025000 -#define S5PV310_PA_SROM_BANK(x) (0x04000000 + ((x) * 0x01000000)) - -#define S5PC210_PA_ONENAND (0x0C000000) -#define S5P_PA_ONENAND S5PC210_PA_ONENAND - -#define S5PC210_PA_ONENAND_DMA (0x0C600000) -#define S5P_PA_ONENAND_DMA S5PC210_PA_ONENAND_DMA - -#define S5PV310_PA_CHIPID (0x10000000) -#define S5P_PA_CHIPID S5PV310_PA_CHIPID - -#define S5PV310_PA_SYSCON (0x10010000) -#define S5P_PA_SYSCON S5PV310_PA_SYSCON +#define S5PV310_PA_I2S0 0x03830000 +#define S5PV310_PA_I2S1 0xE3100000 +#define S5PV310_PA_I2S2 0xE2A00000 -#define S5PV310_PA_PMU (0x10020000) +#define S5PV310_PA_PCM0 0x03840000 +#define S5PV310_PA_PCM1 0x13980000 +#define S5PV310_PA_PCM2 0x13990000 -#define S5PV310_PA_CMU (0x10030000) - -#define S5PV310_PA_WATCHDOG (0x10060000) -#define S5PV310_PA_RTC (0x10070000) - -#define S5PV310_PA_DMC0 (0x10400000) - -#define S5PV310_PA_COMBINER (0x10448000) - -#define S5PV310_PA_COREPERI (0x10500000) -#define S5PV310_PA_GIC_CPU (0x10500100) -#define S5PV310_PA_TWD (0x10500600) -#define S5PV310_PA_GIC_DIST (0x10501000) -#define S5PV310_PA_L2CC (0x10502000) - -/* DMA */ -#define S5PV310_PA_MDMA 0x10810000 -#define S5PV310_PA_PDMA0 0x12680000 -#define S5PV310_PA_PDMA1 0x12690000 - -#define S5PV310_PA_GPIO1 (0x11400000) -#define S5PV310_PA_GPIO2 (0x11000000) -#define S5PV310_PA_GPIO3 (0x03860000) - -#define S5PV310_PA_MIPI_CSIS0 0x11880000 -#define S5PV310_PA_MIPI_CSIS1 0x11890000 +#define S5PV310_PA_SROM_BANK(x) (0x04000000 + ((x) * 0x01000000)) -#define S5PV310_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000)) +#define S5PC210_PA_ONENAND 0x0C000000 +#define S5PC210_PA_ONENAND_DMA 0x0C600000 -#define S5PV310_PA_SROMC (0x12570000) -#define S5P_PA_SROMC S5PV310_PA_SROMC +#define S5PV310_PA_CHIPID 0x10000000 -/* S/PDIF */ -#define S5PV310_PA_SPDIF 0xE1100000 +#define S5PV310_PA_SYSCON 0x10010000 +#define S5PV310_PA_PMU 0x10020000 +#define S5PV310_PA_CMU 0x10030000 -/* I2S */ -#define S5PV310_PA_I2S0 0x03830000 -#define S5PV310_PA_I2S1 0xE3100000 -#define S5PV310_PA_I2S2 0xE2A00000 +#define S5PV310_PA_WATCHDOG 0x10060000 +#define S5PV310_PA_RTC 0x10070000 -/* PCM */ -#define S5PV310_PA_PCM0 0x03840000 -#define S5PV310_PA_PCM1 0x13980000 -#define S5PV310_PA_PCM2 0x13990000 +#define S5PV310_PA_DMC0 0x10400000 -/* AC97 */ -#define S5PV310_PA_AC97 0x139A0000 +#define S5PV310_PA_COMBINER 0x10448000 -#define S5PV310_PA_UART (0x13800000) +#define S5PV310_PA_COREPERI 0x10500000 +#define S5PV310_PA_GIC_CPU 0x10500100 +#define S5PV310_PA_TWD 0x10500600 +#define S5PV310_PA_GIC_DIST 0x10501000 +#define S5PV310_PA_L2CC 0x10502000 -#define S5P_PA_UART(x) (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET)) -#define S5P_PA_UART0 S5P_PA_UART(0) -#define S5P_PA_UART1 S5P_PA_UART(1) -#define S5P_PA_UART2 S5P_PA_UART(2) -#define S5P_PA_UART3 S5P_PA_UART(3) -#define S5P_PA_UART4 S5P_PA_UART(4) - -#define S5P_SZ_UART SZ_256 - -#define S5PV310_PA_IIC(x) (0x13860000 + ((x) * 0x10000)) - -#define S5PV310_PA_TIMER (0x139D0000) -#define S5P_PA_TIMER S5PV310_PA_TIMER - -#define S5PV310_PA_SDRAM (0x40000000) -#define S5P_PA_SDRAM S5PV310_PA_SDRAM +#define S5PV310_PA_MDMA 0x10810000 +#define S5PV310_PA_PDMA0 0x12680000 +#define S5PV310_PA_PDMA1 0x12690000 #define S5PV310_PA_SYSMMU_MDMA 0x10A40000 #define S5PV310_PA_SYSMMU_SSS 0x10A50000 @@ -125,8 +78,31 @@ #define S5PV310_PA_SYSMMU_MFC_L 0x13620000 #define S5PV310_PA_SYSMMU_MFC_R 0x13630000 -/* compatibiltiy defines. */ -#define S3C_PA_UART S5PV310_PA_UART +#define S5PV310_PA_GPIO1 0x11400000 +#define S5PV310_PA_GPIO2 0x11000000 +#define S5PV310_PA_GPIO3 0x03860000 + +#define S5PV310_PA_MIPI_CSIS0 0x11880000 +#define S5PV310_PA_MIPI_CSIS1 0x11890000 + +#define S5PV310_PA_HSMMC(x) (0x12510000 + ((x) * 0x10000)) + +#define S5PV310_PA_SROMC 0x12570000 + +#define S5PV310_PA_UART 0x13800000 + +#define S5PV310_PA_IIC(x) (0x13860000 + ((x) * 0x10000)) + +#define S5PV310_PA_AC97 0x139A0000 + +#define S5PV310_PA_TIMER 0x139D0000 + +#define S5PV310_PA_SDRAM 0x40000000 + +#define S5PV310_PA_SPDIF 0xE1100000 + +/* Compatibiltiy Defines */ + #define S3C_PA_HSMMC0 S5PV310_PA_HSMMC(0) #define S3C_PA_HSMMC1 S5PV310_PA_HSMMC(1) #define S3C_PA_HSMMC2 S5PV310_PA_HSMMC(2) @@ -141,7 +117,28 @@ #define S3C_PA_IIC7 S5PV310_PA_IIC(7) #define S3C_PA_RTC S5PV310_PA_RTC #define S3C_PA_WDT S5PV310_PA_WATCHDOG + +#define S5P_PA_CHIPID S5PV310_PA_CHIPID #define S5P_PA_MIPI_CSIS0 S5PV310_PA_MIPI_CSIS0 #define S5P_PA_MIPI_CSIS1 S5PV310_PA_MIPI_CSIS1 +#define S5P_PA_ONENAND S5PC210_PA_ONENAND +#define S5P_PA_ONENAND_DMA S5PC210_PA_ONENAND_DMA +#define S5P_PA_SDRAM S5PV310_PA_SDRAM +#define S5P_PA_SROMC S5PV310_PA_SROMC +#define S5P_PA_SYSCON S5PV310_PA_SYSCON +#define S5P_PA_TIMER S5PV310_PA_TIMER + +/* UART */ + +#define S3C_PA_UART S5PV310_PA_UART + +#define S5P_PA_UART(x) (S3C_PA_UART + ((x) * S3C_UART_OFFSET)) +#define S5P_PA_UART0 S5P_PA_UART(0) +#define S5P_PA_UART1 S5P_PA_UART(1) +#define S5P_PA_UART2 S5P_PA_UART(2) +#define S5P_PA_UART3 S5P_PA_UART(3) +#define S5P_PA_UART4 S5P_PA_UART(4) + +#define S5P_SZ_UART SZ_256 #endif /* __ASM_ARCH_MAP_H */ diff --git a/trunk/arch/arm/mach-spear3xx/include/mach/spear320.h b/trunk/arch/arm/mach-spear3xx/include/mach/spear320.h index cacf17a958cd..53677e464d4b 100644 --- a/trunk/arch/arm/mach-spear3xx/include/mach/spear320.h +++ b/trunk/arch/arm/mach-spear3xx/include/mach/spear320.h @@ -62,7 +62,7 @@ #define SPEAR320_SMII1_BASE 0xAB000000 #define SPEAR320_SMII1_SIZE 0x01000000 -#define SPEAR320_SOC_CONFIG_BASE 0xB4000000 +#define SPEAR320_SOC_CONFIG_BASE 0xB3000000 #define SPEAR320_SOC_CONFIG_SIZE 0x00000070 /* Interrupt registers offsets and masks */ #define INT_STS_MASK_REG 0x04 diff --git a/trunk/arch/arm/mm/cache-l2x0.c b/trunk/arch/arm/mm/cache-l2x0.c index 170c9bb95866..f2ce38e085d2 100644 --- a/trunk/arch/arm/mm/cache-l2x0.c +++ b/trunk/arch/arm/mm/cache-l2x0.c @@ -49,7 +49,13 @@ static inline void cache_wait(void __iomem *reg, unsigned long mask) static inline void cache_sync(void) { void __iomem *base = l2x0_base; + +#ifdef CONFIG_ARM_ERRATA_753970 + /* write to an unmmapped register */ + writel_relaxed(0, base + L2X0_DUMMY_REG); +#else writel_relaxed(0, base + L2X0_CACHE_SYNC); +#endif cache_wait(base + L2X0_CACHE_SYNC, 1); } diff --git a/trunk/arch/arm/mm/proc-v7.S b/trunk/arch/arm/mm/proc-v7.S index 0c1172b56b4e..8e3356239136 100644 --- a/trunk/arch/arm/mm/proc-v7.S +++ b/trunk/arch/arm/mm/proc-v7.S @@ -264,6 +264,12 @@ __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 + 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 +#endif 3: mov r10, #0 #ifdef HARVARD_CACHE diff --git a/trunk/arch/arm/plat-s5p/dev-uart.c b/trunk/arch/arm/plat-s5p/dev-uart.c index 6a7342886171..afaf87fdb93e 100644 --- a/trunk/arch/arm/plat-s5p/dev-uart.c +++ b/trunk/arch/arm/plat-s5p/dev-uart.c @@ -28,7 +28,7 @@ static struct resource s5p_uart0_resource[] = { [0] = { .start = S5P_PA_UART0, - .end = S5P_PA_UART0 + S5P_SZ_UART, + .end = S5P_PA_UART0 + S5P_SZ_UART - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -51,7 +51,7 @@ static struct resource s5p_uart0_resource[] = { static struct resource s5p_uart1_resource[] = { [0] = { .start = S5P_PA_UART1, - .end = S5P_PA_UART1 + S5P_SZ_UART, + .end = S5P_PA_UART1 + S5P_SZ_UART - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -74,7 +74,7 @@ static struct resource s5p_uart1_resource[] = { static struct resource s5p_uart2_resource[] = { [0] = { .start = S5P_PA_UART2, - .end = S5P_PA_UART2 + S5P_SZ_UART, + .end = S5P_PA_UART2 + S5P_SZ_UART - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -98,7 +98,7 @@ static struct resource s5p_uart3_resource[] = { #if CONFIG_SERIAL_SAMSUNG_UARTS > 3 [0] = { .start = S5P_PA_UART3, - .end = S5P_PA_UART3 + S5P_SZ_UART, + .end = S5P_PA_UART3 + S5P_SZ_UART - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -123,7 +123,7 @@ static struct resource s5p_uart4_resource[] = { #if CONFIG_SERIAL_SAMSUNG_UARTS > 4 [0] = { .start = S5P_PA_UART4, - .end = S5P_PA_UART4 + S5P_SZ_UART, + .end = S5P_PA_UART4 + S5P_SZ_UART - 1, .flags = IORESOURCE_MEM, }, [1] = { @@ -148,7 +148,7 @@ static struct resource s5p_uart5_resource[] = { #if CONFIG_SERIAL_SAMSUNG_UARTS > 5 [0] = { .start = S5P_PA_UART5, - .end = S5P_PA_UART5 + S5P_SZ_UART, + .end = S5P_PA_UART5 + S5P_SZ_UART - 1, .flags = IORESOURCE_MEM, }, [1] = { diff --git a/trunk/arch/arm/plat-samsung/dev-ts.c b/trunk/arch/arm/plat-samsung/dev-ts.c index 236ef8427d7d..3e4bd8147bf4 100644 --- a/trunk/arch/arm/plat-samsung/dev-ts.c +++ b/trunk/arch/arm/plat-samsung/dev-ts.c @@ -58,4 +58,3 @@ void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd) s3c_device_ts.dev.platform_data = npd; } -EXPORT_SYMBOL(s3c24xx_ts_set_platdata); diff --git a/trunk/arch/arm/plat-spear/include/plat/uncompress.h b/trunk/arch/arm/plat-spear/include/plat/uncompress.h index 99ba6789cc97..6dd455bafdfd 100644 --- a/trunk/arch/arm/plat-spear/include/plat/uncompress.h +++ b/trunk/arch/arm/plat-spear/include/plat/uncompress.h @@ -24,10 +24,10 @@ static inline void putc(int c) { void __iomem *base = (void __iomem *)SPEAR_DBG_UART_BASE; - while (readl(base + UART01x_FR) & UART01x_FR_TXFF) + while (readl_relaxed(base + UART01x_FR) & UART01x_FR_TXFF) barrier(); - writel(c, base + UART01x_DR); + writel_relaxed(c, base + UART01x_DR); } static inline void flush(void) diff --git a/trunk/arch/arm/plat-spear/include/plat/vmalloc.h b/trunk/arch/arm/plat-spear/include/plat/vmalloc.h index 09e9372aea21..8c8b24d07046 100644 --- a/trunk/arch/arm/plat-spear/include/plat/vmalloc.h +++ b/trunk/arch/arm/plat-spear/include/plat/vmalloc.h @@ -14,6 +14,6 @@ #ifndef __PLAT_VMALLOC_H #define __PLAT_VMALLOC_H -#define VMALLOC_END 0xF0000000 +#define VMALLOC_END 0xF0000000UL #endif /* __PLAT_VMALLOC_H */ diff --git a/trunk/arch/s390/boot/compressed/misc.c b/trunk/arch/s390/boot/compressed/misc.c index 0851eb1e919e..2751b3a8a66f 100644 --- a/trunk/arch/s390/boot/compressed/misc.c +++ b/trunk/arch/s390/boot/compressed/misc.c @@ -133,11 +133,12 @@ unsigned long decompress_kernel(void) unsigned long output_addr; unsigned char *output; - check_ipl_parmblock((void *) 0, (unsigned long) output + SZ__bss_start); + output_addr = ((unsigned long) &_end + HEAP_SIZE + 4095UL) & -4096UL; + check_ipl_parmblock((void *) 0, output_addr + SZ__bss_start); memset(&_bss, 0, &_ebss - &_bss); free_mem_ptr = (unsigned long)&_end; free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; - output = (unsigned char *) ((free_mem_end_ptr + 4095UL) & -4096UL); + output = (unsigned char *) output_addr; #ifdef CONFIG_BLK_DEV_INITRD /* diff --git a/trunk/arch/s390/crypto/sha_common.c b/trunk/arch/s390/crypto/sha_common.c index f42dbabc0d30..48884f89ab92 100644 --- a/trunk/arch/s390/crypto/sha_common.c +++ b/trunk/arch/s390/crypto/sha_common.c @@ -38,6 +38,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) BUG_ON(ret != bsize); data += bsize - index; len -= bsize - index; + index = 0; } /* process as many blocks as possible */ diff --git a/trunk/arch/s390/include/asm/atomic.h b/trunk/arch/s390/include/asm/atomic.h index 76daea117181..5c5ba10384c2 100644 --- a/trunk/arch/s390/include/asm/atomic.h +++ b/trunk/arch/s390/include/asm/atomic.h @@ -36,14 +36,19 @@ static inline int atomic_read(const atomic_t *v) { - barrier(); - return v->counter; + int c; + + asm volatile( + " l %0,%1\n" + : "=d" (c) : "Q" (v->counter)); + return c; } static inline void atomic_set(atomic_t *v, int i) { - v->counter = i; - barrier(); + asm volatile( + " st %1,%0\n" + : "=Q" (v->counter) : "d" (i)); } static inline int atomic_add_return(int i, atomic_t *v) @@ -128,14 +133,19 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) static inline long long atomic64_read(const atomic64_t *v) { - barrier(); - return v->counter; + long long c; + + asm volatile( + " lg %0,%1\n" + : "=d" (c) : "Q" (v->counter)); + return c; } static inline void atomic64_set(atomic64_t *v, long long i) { - v->counter = i; - barrier(); + asm volatile( + " stg %1,%0\n" + : "=Q" (v->counter) : "d" (i)); } static inline long long atomic64_add_return(long long i, atomic64_t *v) diff --git a/trunk/arch/s390/include/asm/cache.h b/trunk/arch/s390/include/asm/cache.h index 24aafa68b643..2a30d5ac0667 100644 --- a/trunk/arch/s390/include/asm/cache.h +++ b/trunk/arch/s390/include/asm/cache.h @@ -13,6 +13,7 @@ #define L1_CACHE_BYTES 256 #define L1_CACHE_SHIFT 8 +#define NET_SKB_PAD 32 #define __read_mostly __attribute__((__section__(".data..read_mostly"))) diff --git a/trunk/arch/sparc/include/asm/pcr.h b/trunk/arch/sparc/include/asm/pcr.h index a2f5c61f924e..843e4faf6a50 100644 --- a/trunk/arch/sparc/include/asm/pcr.h +++ b/trunk/arch/sparc/include/asm/pcr.h @@ -43,4 +43,6 @@ static inline u64 picl_value(unsigned int nmi_hz) extern u64 pcr_enable; +extern int pcr_arch_init(void); + #endif /* __PCR_H */ diff --git a/trunk/arch/sparc/kernel/iommu.c b/trunk/arch/sparc/kernel/iommu.c index 47977a77f6c6..72509d0e34be 100644 --- a/trunk/arch/sparc/kernel/iommu.c +++ b/trunk/arch/sparc/kernel/iommu.c @@ -255,10 +255,9 @@ static inline iopte_t *alloc_npages(struct device *dev, struct iommu *iommu, static int iommu_alloc_ctx(struct iommu *iommu) { int lowest = iommu->ctx_lowest_free; - int sz = IOMMU_NUM_CTXS - lowest; - int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest); + int n = find_next_zero_bit(iommu->ctx_bitmap, IOMMU_NUM_CTXS, lowest); - if (unlikely(n == sz)) { + if (unlikely(n == IOMMU_NUM_CTXS)) { n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1); if (unlikely(n == lowest)) { printk(KERN_WARNING "IOMMU: Ran out of contexts.\n"); diff --git a/trunk/arch/sparc/kernel/pcr.c b/trunk/arch/sparc/kernel/pcr.c index ae96cf52a955..7c2ced612b8f 100644 --- a/trunk/arch/sparc/kernel/pcr.c +++ b/trunk/arch/sparc/kernel/pcr.c @@ -167,5 +167,3 @@ int __init pcr_arch_init(void) unregister_perf_hsvc(); return err; } - -early_initcall(pcr_arch_init); diff --git a/trunk/arch/sparc/kernel/smp_64.c b/trunk/arch/sparc/kernel/smp_64.c index b6a2b8f47040..555a76d1f4a1 100644 --- a/trunk/arch/sparc/kernel/smp_64.c +++ b/trunk/arch/sparc/kernel/smp_64.c @@ -49,6 +49,7 @@ #include #include #include +#include #include "cpumap.h" @@ -1358,6 +1359,7 @@ void __cpu_die(unsigned int cpu) void __init smp_cpus_done(unsigned int max_cpus) { + pcr_arch_init(); } void smp_send_reschedule(int cpu) diff --git a/trunk/arch/sparc/kernel/una_asm_32.S b/trunk/arch/sparc/kernel/una_asm_32.S index 8cc03458eb7e..8f096e84a937 100644 --- a/trunk/arch/sparc/kernel/una_asm_32.S +++ b/trunk/arch/sparc/kernel/una_asm_32.S @@ -24,9 +24,9 @@ retl_efault: .globl __do_int_store __do_int_store: ld [%o2], %g1 - cmp %1, 2 + cmp %o1, 2 be 2f - cmp %1, 4 + cmp %o1, 4 be 1f srl %g1, 24, %g2 srl %g1, 16, %g7 diff --git a/trunk/arch/sparc/lib/bitext.c b/trunk/arch/sparc/lib/bitext.c index 764b3eb7b604..48d00e72ce15 100644 --- a/trunk/arch/sparc/lib/bitext.c +++ b/trunk/arch/sparc/lib/bitext.c @@ -10,7 +10,7 @@ */ #include -#include +#include #include @@ -80,8 +80,7 @@ int bit_map_string_get(struct bit_map *t, int len, int align) while (test_bit(offset + i, t->map) == 0) { i++; if (i == len) { - for (i = 0; i < len; i++) - __set_bit(offset + i, t->map); + bitmap_set(t->map, offset, len); if (offset == t->first_free) t->first_free = find_next_zero_bit (t->map, t->size, diff --git a/trunk/arch/x86/include/asm/cpufeature.h b/trunk/arch/x86/include/asm/cpufeature.h index 91f3e087cf21..220e2ea08e80 100644 --- a/trunk/arch/x86/include/asm/cpufeature.h +++ b/trunk/arch/x86/include/asm/cpufeature.h @@ -160,7 +160,6 @@ #define X86_FEATURE_NODEID_MSR (6*32+19) /* NodeId MSR */ #define X86_FEATURE_TBM (6*32+21) /* trailing bit manipulations */ #define X86_FEATURE_TOPOEXT (6*32+22) /* topology extensions CPUID leafs */ -#define X86_FEATURE_PERFCTR_CORE (6*32+23) /* core performance counter extensions */ /* * Auxiliary flags: Linux defined - For features scattered in various @@ -280,7 +279,6 @@ extern const char * const x86_power_flags[32]; #define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE) #define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR) #define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ) -#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE) #if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64) # define cpu_has_invlpg 1 diff --git a/trunk/arch/x86/include/asm/kdebug.h b/trunk/arch/x86/include/asm/kdebug.h index 518bbbb9ee59..ca242d35e873 100644 --- a/trunk/arch/x86/include/asm/kdebug.h +++ b/trunk/arch/x86/include/asm/kdebug.h @@ -13,6 +13,7 @@ enum die_val { DIE_PANIC, DIE_NMI, DIE_DIE, + DIE_NMIWATCHDOG, DIE_KERNELDEBUG, DIE_TRAP, DIE_GPF, diff --git a/trunk/arch/x86/include/asm/nmi.h b/trunk/arch/x86/include/asm/nmi.h index 07f46016d3ff..c76f5b92b840 100644 --- a/trunk/arch/x86/include/asm/nmi.h +++ b/trunk/arch/x86/include/asm/nmi.h @@ -7,6 +7,7 @@ #ifdef CONFIG_X86_LOCAL_APIC +extern void die_nmi(char *str, struct pt_regs *regs, int do_panic); extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); extern int reserve_perfctr_nmi(unsigned int); extern void release_perfctr_nmi(unsigned int); diff --git a/trunk/arch/x86/kernel/cpu/perf_event.c b/trunk/arch/x86/kernel/cpu/perf_event.c index 10bfe2472d16..390fa6d8c140 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event.c +++ b/trunk/arch/x86/kernel/cpu/perf_event.c @@ -166,8 +166,10 @@ struct cpu_hw_events { /* * Constraint on the Event code + UMask */ -#define PEBS_EVENT_CONSTRAINT(c, n) \ +#define INTEL_UEVENT_CONSTRAINT(c, n) \ EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK) +#define PEBS_EVENT_CONSTRAINT(c, n) \ + INTEL_UEVENT_CONSTRAINT(c, n) #define EVENT_CONSTRAINT_END \ EVENT_CONSTRAINT(0, 0, 0) @@ -298,7 +300,7 @@ x86_perf_event_update(struct perf_event *event) */ again: prev_raw_count = local64_read(&hwc->prev_count); - rdmsrl(hwc->event_base, new_raw_count); + rdmsrl(hwc->event_base + idx, new_raw_count); if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, new_raw_count) != prev_raw_count) @@ -321,24 +323,6 @@ x86_perf_event_update(struct perf_event *event) return new_raw_count; } -/* using X86_FEATURE_PERFCTR_CORE to later implement ALTERNATIVE() here */ -static inline int x86_pmu_addr_offset(int index) -{ - if (boot_cpu_has(X86_FEATURE_PERFCTR_CORE)) - return index << 1; - return index; -} - -static inline unsigned int x86_pmu_config_addr(int index) -{ - return x86_pmu.eventsel + x86_pmu_addr_offset(index); -} - -static inline unsigned int x86_pmu_event_addr(int index) -{ - return x86_pmu.perfctr + x86_pmu_addr_offset(index); -} - static atomic_t active_events; static DEFINE_MUTEX(pmc_reserve_mutex); @@ -349,12 +333,12 @@ static bool reserve_pmc_hardware(void) int i; for (i = 0; i < x86_pmu.num_counters; i++) { - if (!reserve_perfctr_nmi(x86_pmu_event_addr(i))) + if (!reserve_perfctr_nmi(x86_pmu.perfctr + i)) goto perfctr_fail; } for (i = 0; i < x86_pmu.num_counters; i++) { - if (!reserve_evntsel_nmi(x86_pmu_config_addr(i))) + if (!reserve_evntsel_nmi(x86_pmu.eventsel + i)) goto eventsel_fail; } @@ -362,13 +346,13 @@ static bool reserve_pmc_hardware(void) eventsel_fail: for (i--; i >= 0; i--) - release_evntsel_nmi(x86_pmu_config_addr(i)); + release_evntsel_nmi(x86_pmu.eventsel + i); i = x86_pmu.num_counters; perfctr_fail: for (i--; i >= 0; i--) - release_perfctr_nmi(x86_pmu_event_addr(i)); + release_perfctr_nmi(x86_pmu.perfctr + i); return false; } @@ -378,8 +362,8 @@ static void release_pmc_hardware(void) int i; for (i = 0; i < x86_pmu.num_counters; i++) { - release_perfctr_nmi(x86_pmu_event_addr(i)); - release_evntsel_nmi(x86_pmu_config_addr(i)); + release_perfctr_nmi(x86_pmu.perfctr + i); + release_evntsel_nmi(x86_pmu.eventsel + i); } } @@ -400,7 +384,7 @@ static bool check_hw_exists(void) * complain and bail. */ for (i = 0; i < x86_pmu.num_counters; i++) { - reg = x86_pmu_config_addr(i); + reg = x86_pmu.eventsel + i; ret = rdmsrl_safe(reg, &val); if (ret) goto msr_fail; @@ -425,8 +409,8 @@ static bool check_hw_exists(void) * that don't trap on the MSR access and always return 0s. */ val = 0xabcdUL; - ret = checking_wrmsrl(x86_pmu_event_addr(0), val); - ret |= rdmsrl_safe(x86_pmu_event_addr(0), &val_new); + ret = checking_wrmsrl(x86_pmu.perfctr, val); + ret |= rdmsrl_safe(x86_pmu.perfctr, &val_new); if (ret || val != val_new) goto msr_fail; @@ -635,11 +619,11 @@ static void x86_pmu_disable_all(void) if (!test_bit(idx, cpuc->active_mask)) continue; - rdmsrl(x86_pmu_config_addr(idx), val); + rdmsrl(x86_pmu.eventsel + idx, val); if (!(val & ARCH_PERFMON_EVENTSEL_ENABLE)) continue; val &= ~ARCH_PERFMON_EVENTSEL_ENABLE; - wrmsrl(x86_pmu_config_addr(idx), val); + wrmsrl(x86_pmu.eventsel + idx, val); } } @@ -660,24 +644,21 @@ static void x86_pmu_disable(struct pmu *pmu) x86_pmu.disable_all(); } -static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, - u64 enable_mask) -{ - wrmsrl(hwc->config_base, hwc->config | enable_mask); -} - static void x86_pmu_enable_all(int added) { struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); int idx; for (idx = 0; idx < x86_pmu.num_counters; idx++) { - struct hw_perf_event *hwc = &cpuc->events[idx]->hw; + struct perf_event *event = cpuc->events[idx]; + u64 val; if (!test_bit(idx, cpuc->active_mask)) continue; - __x86_pmu_enable_event(hwc, ARCH_PERFMON_EVENTSEL_ENABLE); + val = event->hw.config; + val |= ARCH_PERFMON_EVENTSEL_ENABLE; + wrmsrl(x86_pmu.eventsel + idx, val); } } @@ -842,10 +823,15 @@ static inline void x86_assign_hw_event(struct perf_event *event, hwc->event_base = 0; } else if (hwc->idx >= X86_PMC_IDX_FIXED) { hwc->config_base = MSR_ARCH_PERFMON_FIXED_CTR_CTRL; - hwc->event_base = MSR_ARCH_PERFMON_FIXED_CTR0; + /* + * We set it so that event_base + idx in wrmsr/rdmsr maps to + * MSR_ARCH_PERFMON_FIXED_CTR0 ... CTR2: + */ + hwc->event_base = + MSR_ARCH_PERFMON_FIXED_CTR0 - X86_PMC_IDX_FIXED; } else { - hwc->config_base = x86_pmu_config_addr(hwc->idx); - hwc->event_base = x86_pmu_event_addr(hwc->idx); + hwc->config_base = x86_pmu.eventsel; + hwc->event_base = x86_pmu.perfctr; } } @@ -931,11 +917,17 @@ static void x86_pmu_enable(struct pmu *pmu) x86_pmu.enable_all(added); } +static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc, + u64 enable_mask) +{ + wrmsrl(hwc->config_base + hwc->idx, hwc->config | enable_mask); +} + static inline void x86_pmu_disable_event(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - wrmsrl(hwc->config_base, hwc->config); + wrmsrl(hwc->config_base + hwc->idx, hwc->config); } static DEFINE_PER_CPU(u64 [X86_PMC_IDX_MAX], pmc_prev_left); @@ -988,7 +980,7 @@ x86_perf_event_set_period(struct perf_event *event) */ local64_set(&hwc->prev_count, (u64)-left); - wrmsrl(hwc->event_base, (u64)(-left) & x86_pmu.cntval_mask); + wrmsrl(hwc->event_base + idx, (u64)(-left) & x86_pmu.cntval_mask); /* * Due to erratum on certan cpu we need @@ -996,7 +988,7 @@ x86_perf_event_set_period(struct perf_event *event) * is updated properly */ if (x86_pmu.perfctr_second_write) { - wrmsrl(hwc->event_base, + wrmsrl(hwc->event_base + idx, (u64)(-left) & x86_pmu.cntval_mask); } @@ -1123,8 +1115,8 @@ void perf_event_print_debug(void) pr_info("CPU#%d: active: %016llx\n", cpu, *(u64 *)cpuc->active_mask); for (idx = 0; idx < x86_pmu.num_counters; idx++) { - rdmsrl(x86_pmu_config_addr(idx), pmc_ctrl); - rdmsrl(x86_pmu_event_addr(idx), pmc_count); + rdmsrl(x86_pmu.eventsel + idx, pmc_ctrl); + rdmsrl(x86_pmu.perfctr + idx, pmc_count); prev_left = per_cpu(pmc_prev_left[idx], cpu); @@ -1399,7 +1391,7 @@ static void __init pmu_check_apic(void) pr_info("no hardware sampling interrupt available.\n"); } -static int __init init_hw_perf_events(void) +int __init init_hw_perf_events(void) { struct event_constraint *c; int err; @@ -1618,7 +1610,7 @@ static int validate_group(struct perf_event *event) return ret; } -static int x86_pmu_event_init(struct perf_event *event) +int x86_pmu_event_init(struct perf_event *event) { struct pmu *tmp; int err; diff --git a/trunk/arch/x86/kernel/cpu/perf_event_amd.c b/trunk/arch/x86/kernel/cpu/perf_event_amd.c index 461f62bbd774..67e2202a6039 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_amd.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_amd.c @@ -127,11 +127,6 @@ static int amd_pmu_hw_config(struct perf_event *event) /* * AMD64 events are detected based on their event codes. */ -static inline unsigned int amd_get_event_code(struct hw_perf_event *hwc) -{ - return ((hwc->config >> 24) & 0x0f00) | (hwc->config & 0x00ff); -} - static inline int amd_is_nb_event(struct hw_perf_event *hwc) { return (hwc->config & 0xe0) == 0xe0; @@ -390,181 +385,13 @@ static __initconst const struct x86_pmu amd_pmu = { .cpu_dead = amd_pmu_cpu_dead, }; -/* AMD Family 15h */ - -#define AMD_EVENT_TYPE_MASK 0x000000F0ULL - -#define AMD_EVENT_FP 0x00000000ULL ... 0x00000010ULL -#define AMD_EVENT_LS 0x00000020ULL ... 0x00000030ULL -#define AMD_EVENT_DC 0x00000040ULL ... 0x00000050ULL -#define AMD_EVENT_CU 0x00000060ULL ... 0x00000070ULL -#define AMD_EVENT_IC_DE 0x00000080ULL ... 0x00000090ULL -#define AMD_EVENT_EX_LS 0x000000C0ULL -#define AMD_EVENT_DE 0x000000D0ULL -#define AMD_EVENT_NB 0x000000E0ULL ... 0x000000F0ULL - -/* - * AMD family 15h event code/PMC mappings: - * - * type = event_code & 0x0F0: - * - * 0x000 FP PERF_CTL[5:3] - * 0x010 FP PERF_CTL[5:3] - * 0x020 LS PERF_CTL[5:0] - * 0x030 LS PERF_CTL[5:0] - * 0x040 DC PERF_CTL[5:0] - * 0x050 DC PERF_CTL[5:0] - * 0x060 CU PERF_CTL[2:0] - * 0x070 CU PERF_CTL[2:0] - * 0x080 IC/DE PERF_CTL[2:0] - * 0x090 IC/DE PERF_CTL[2:0] - * 0x0A0 --- - * 0x0B0 --- - * 0x0C0 EX/LS PERF_CTL[5:0] - * 0x0D0 DE PERF_CTL[2:0] - * 0x0E0 NB NB_PERF_CTL[3:0] - * 0x0F0 NB NB_PERF_CTL[3:0] - * - * Exceptions: - * - * 0x003 FP PERF_CTL[3] - * 0x00B FP PERF_CTL[3] - * 0x00D FP PERF_CTL[3] - * 0x023 DE PERF_CTL[2:0] - * 0x02D LS PERF_CTL[3] - * 0x02E LS PERF_CTL[3,0] - * 0x043 CU PERF_CTL[2:0] - * 0x045 CU PERF_CTL[2:0] - * 0x046 CU PERF_CTL[2:0] - * 0x054 CU PERF_CTL[2:0] - * 0x055 CU PERF_CTL[2:0] - * 0x08F IC PERF_CTL[0] - * 0x187 DE PERF_CTL[0] - * 0x188 DE PERF_CTL[0] - * 0x0DB EX PERF_CTL[5:0] - * 0x0DC LS PERF_CTL[5:0] - * 0x0DD LS PERF_CTL[5:0] - * 0x0DE LS PERF_CTL[5:0] - * 0x0DF LS PERF_CTL[5:0] - * 0x1D6 EX PERF_CTL[5:0] - * 0x1D8 EX PERF_CTL[5:0] - */ - -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(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); - -static struct event_constraint * -amd_get_event_constraints_f15h(struct cpu_hw_events *cpuc, struct perf_event *event) -{ - unsigned int event_code = amd_get_event_code(&event->hw); - - switch (event_code & AMD_EVENT_TYPE_MASK) { - case AMD_EVENT_FP: - switch (event_code) { - case 0x003: - case 0x00B: - case 0x00D: - return &amd_f15_PMC3; - default: - return &amd_f15_PMC53; - } - case AMD_EVENT_LS: - case AMD_EVENT_DC: - case AMD_EVENT_EX_LS: - switch (event_code) { - case 0x023: - case 0x043: - case 0x045: - case 0x046: - case 0x054: - case 0x055: - return &amd_f15_PMC20; - case 0x02D: - return &amd_f15_PMC3; - case 0x02E: - return &amd_f15_PMC30; - default: - return &amd_f15_PMC50; - } - case AMD_EVENT_CU: - case AMD_EVENT_IC_DE: - case AMD_EVENT_DE: - switch (event_code) { - case 0x08F: - case 0x187: - case 0x188: - return &amd_f15_PMC0; - case 0x0DB ... 0x0DF: - case 0x1D6: - case 0x1D8: - return &amd_f15_PMC50; - default: - return &amd_f15_PMC20; - } - case AMD_EVENT_NB: - /* not yet implemented */ - return &emptyconstraint; - default: - return &emptyconstraint; - } -} - -static __initconst const struct x86_pmu amd_pmu_f15h = { - .name = "AMD Family 15h", - .handle_irq = x86_pmu_handle_irq, - .disable_all = x86_pmu_disable_all, - .enable_all = x86_pmu_enable_all, - .enable = x86_pmu_enable_event, - .disable = x86_pmu_disable_event, - .hw_config = amd_pmu_hw_config, - .schedule_events = x86_schedule_events, - .eventsel = MSR_F15H_PERF_CTL, - .perfctr = MSR_F15H_PERF_CTR, - .event_map = amd_pmu_event_map, - .max_events = ARRAY_SIZE(amd_perfmon_event_map), - .num_counters = 6, - .cntval_bits = 48, - .cntval_mask = (1ULL << 48) - 1, - .apic = 1, - /* use highest bit to detect overflow */ - .max_period = (1ULL << 47) - 1, - .get_event_constraints = amd_get_event_constraints_f15h, - /* nortbridge counters not yet implemented: */ -#if 0 - .put_event_constraints = amd_put_event_constraints, - - .cpu_prepare = amd_pmu_cpu_prepare, - .cpu_starting = amd_pmu_cpu_starting, - .cpu_dead = amd_pmu_cpu_dead, -#endif -}; - static __init int amd_pmu_init(void) { /* Performance-monitoring supported from K7 and later: */ if (boot_cpu_data.x86 < 6) return -ENODEV; - /* - * If core performance counter extensions exists, it must be - * family 15h, otherwise fail. See x86_pmu_addr_offset(). - */ - switch (boot_cpu_data.x86) { - case 0x15: - if (!cpu_has_perfctr_core) - return -ENODEV; - x86_pmu = amd_pmu_f15h; - break; - default: - if (cpu_has_perfctr_core) - return -ENODEV; - x86_pmu = amd_pmu; - break; - } + x86_pmu = amd_pmu; /* Events are common for all AMDs */ memcpy(hw_cache_event_ids, amd_hw_cache_event_ids, diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel.c b/trunk/arch/x86/kernel/cpu/perf_event_intel.c index 084b38362db7..d00f386b0b30 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel.c @@ -76,6 +76,19 @@ static struct event_constraint intel_westmere_event_constraints[] = EVENT_CONSTRAINT_END }; +static struct event_constraint intel_snb_event_constraints[] = +{ + FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ + FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */ + /* FIXED_EVENT_CONSTRAINT(0x013c, 2), CPU_CLK_UNHALTED.REF */ + INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.PENDING */ + INTEL_EVENT_CONSTRAINT(0xb7, 0x1), /* OFF_CORE_RESPONSE_0 */ + INTEL_EVENT_CONSTRAINT(0xbb, 0x8), /* OFF_CORE_RESPONSE_1 */ + INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */ + INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ + EVENT_CONSTRAINT_END +}; + static struct event_constraint intel_gen_event_constraints[] = { FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */ @@ -89,6 +102,106 @@ static u64 intel_pmu_event_map(int hw_event) return intel_perfmon_event_map[hw_event]; } +static __initconst const u64 snb_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX] = +{ + [ C(L1D) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0xf1d0, /* MEM_UOP_RETIRED.LOADS */ + [ C(RESULT_MISS) ] = 0x0151, /* L1D.REPLACEMENT */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0xf2d0, /* MEM_UOP_RETIRED.STORES */ + [ C(RESULT_MISS) ] = 0x0851, /* L1D.ALL_M_REPLACEMENT */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x024e, /* HW_PRE_REQ.DL1_MISS */ + }, + }, + [ C(L1I ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0280, /* ICACHE.MISSES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(LL ) ] = { + /* + * TBD: Need Off-core Response Performance Monitoring support + */ + [ C(OP_READ) ] = { + /* OFFCORE_RESPONSE_0.ANY_DATA.LOCAL_CACHE */ + [ C(RESULT_ACCESS) ] = 0x01b7, + /* OFFCORE_RESPONSE_1.ANY_DATA.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01bb, + }, + [ C(OP_WRITE) ] = { + /* OFFCORE_RESPONSE_0.ANY_RFO.LOCAL_CACHE */ + [ C(RESULT_ACCESS) ] = 0x01b7, + /* OFFCORE_RESPONSE_1.ANY_RFO.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01bb, + }, + [ C(OP_PREFETCH) ] = { + /* OFFCORE_RESPONSE_0.PREFETCH.LOCAL_CACHE */ + [ C(RESULT_ACCESS) ] = 0x01b7, + /* OFFCORE_RESPONSE_1.PREFETCH.ANY_LLC_MISS */ + [ C(RESULT_MISS) ] = 0x01bb, + }, + }, + [ C(DTLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x81d0, /* MEM_UOP_RETIRED.ALL_LOADS */ + [ C(RESULT_MISS) ] = 0x0108, /* DTLB_LOAD_MISSES.CAUSES_A_WALK */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = 0x82d0, /* MEM_UOP_RETIRED.ALL_STORES */ + [ C(RESULT_MISS) ] = 0x0149, /* DTLB_STORE_MISSES.MISS_CAUSES_A_WALK */ + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = 0x0, + [ C(RESULT_MISS) ] = 0x0, + }, + }, + [ C(ITLB) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x1085, /* ITLB_MISSES.STLB_HIT */ + [ C(RESULT_MISS) ] = 0x0185, /* ITLB_MISSES.CAUSES_A_WALK */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, + [ C(BPU ) ] = { + [ C(OP_READ) ] = { + [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */ + [ C(RESULT_MISS) ] = 0x00c5, /* BR_MISP_RETIRED.ALL_BRANCHES */ + }, + [ C(OP_WRITE) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + [ C(OP_PREFETCH) ] = { + [ C(RESULT_ACCESS) ] = -1, + [ C(RESULT_MISS) ] = -1, + }, + }, +}; + static __initconst const u64 westmere_hw_cache_event_ids [PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] @@ -691,8 +804,8 @@ static void intel_pmu_reset(void) printk("clearing PMU state on CPU#%d\n", smp_processor_id()); for (idx = 0; idx < x86_pmu.num_counters; idx++) { - checking_wrmsrl(x86_pmu_config_addr(idx), 0ull); - checking_wrmsrl(x86_pmu_event_addr(idx), 0ull); + checking_wrmsrl(x86_pmu.eventsel + idx, 0ull); + checking_wrmsrl(x86_pmu.perfctr + idx, 0ull); } for (idx = 0; idx < x86_pmu.num_counters_fixed; idx++) checking_wrmsrl(MSR_ARCH_PERFMON_FIXED_CTR0 + idx, 0ull); @@ -1062,6 +1175,17 @@ static __init int intel_pmu_init(void) pr_cont("Westmere events, "); break; + case 42: /* SandyBridge */ + memcpy(hw_cache_event_ids, snb_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + + intel_pmu_lbr_init_nhm(); + + x86_pmu.event_constraints = intel_snb_event_constraints; + x86_pmu.pebs_constraints = intel_snb_pebs_events; + pr_cont("SandyBridge events, "); + break; + default: /* * default constraints for v2 and up diff --git a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c index b7dcd9f2b8a0..825199834885 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -388,6 +388,44 @@ static struct event_constraint intel_nehalem_pebs_events[] = { EVENT_CONSTRAINT_END }; +static struct event_constraint intel_snb_pebs_events[] = { + PEBS_EVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */ + PEBS_EVENT_CONSTRAINT(0x01c2, 0xf), /* UOPS_RETIRED.ALL */ + PEBS_EVENT_CONSTRAINT(0x02c2, 0xf), /* UOPS_RETIRED.RETIRE_SLOTS */ + PEBS_EVENT_CONSTRAINT(0x01c4, 0xf), /* BR_INST_RETIRED.CONDITIONAL */ + PEBS_EVENT_CONSTRAINT(0x02c4, 0xf), /* BR_INST_RETIRED.NEAR_CALL */ + PEBS_EVENT_CONSTRAINT(0x04c4, 0xf), /* BR_INST_RETIRED.ALL_BRANCHES */ + PEBS_EVENT_CONSTRAINT(0x08c4, 0xf), /* BR_INST_RETIRED.NEAR_RETURN */ + PEBS_EVENT_CONSTRAINT(0x10c4, 0xf), /* BR_INST_RETIRED.NOT_TAKEN */ + PEBS_EVENT_CONSTRAINT(0x20c4, 0xf), /* BR_INST_RETIRED.NEAR_TAKEN */ + PEBS_EVENT_CONSTRAINT(0x40c4, 0xf), /* BR_INST_RETIRED.FAR_BRANCH */ + PEBS_EVENT_CONSTRAINT(0x01c5, 0xf), /* BR_MISP_RETIRED.CONDITIONAL */ + PEBS_EVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */ + PEBS_EVENT_CONSTRAINT(0x04c5, 0xf), /* BR_MISP_RETIRED.ALL_BRANCHES */ + PEBS_EVENT_CONSTRAINT(0x10c5, 0xf), /* BR_MISP_RETIRED.NOT_TAKEN */ + PEBS_EVENT_CONSTRAINT(0x20c5, 0xf), /* BR_MISP_RETIRED.TAKEN */ + PEBS_EVENT_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ + PEBS_EVENT_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORE */ + PEBS_EVENT_CONSTRAINT(0x11d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_LOADS */ + PEBS_EVENT_CONSTRAINT(0x12d0, 0xf), /* MEM_UOP_RETIRED.STLB_MISS_STORES */ + PEBS_EVENT_CONSTRAINT(0x21d0, 0xf), /* MEM_UOP_RETIRED.LOCK_LOADS */ + PEBS_EVENT_CONSTRAINT(0x22d0, 0xf), /* MEM_UOP_RETIRED.LOCK_STORES */ + PEBS_EVENT_CONSTRAINT(0x41d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_LOADS */ + PEBS_EVENT_CONSTRAINT(0x42d0, 0xf), /* MEM_UOP_RETIRED.SPLIT_STORES */ + PEBS_EVENT_CONSTRAINT(0x81d0, 0xf), /* MEM_UOP_RETIRED.ANY_LOADS */ + PEBS_EVENT_CONSTRAINT(0x82d0, 0xf), /* MEM_UOP_RETIRED.ANY_STORES */ + PEBS_EVENT_CONSTRAINT(0x01d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L1_HIT */ + PEBS_EVENT_CONSTRAINT(0x02d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.L2_HIT */ + PEBS_EVENT_CONSTRAINT(0x04d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.LLC_HIT */ + PEBS_EVENT_CONSTRAINT(0x40d1, 0xf), /* MEM_LOAD_UOPS_RETIRED.HIT_LFB */ + PEBS_EVENT_CONSTRAINT(0x01d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS */ + PEBS_EVENT_CONSTRAINT(0x02d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT */ + PEBS_EVENT_CONSTRAINT(0x04d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM */ + PEBS_EVENT_CONSTRAINT(0x08d2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_NONE */ + PEBS_EVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */ + EVENT_CONSTRAINT_END +}; + static struct event_constraint * intel_pebs_constraints(struct perf_event *event) { diff --git a/trunk/arch/x86/kernel/cpu/perf_event_p4.c b/trunk/arch/x86/kernel/cpu/perf_event_p4.c index 3769ac822f96..ff751a9f182b 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_p4.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_p4.c @@ -764,9 +764,9 @@ static inline int p4_pmu_clear_cccr_ovf(struct hw_perf_event *hwc) u64 v; /* an official way for overflow indication */ - rdmsrl(hwc->config_base, v); + rdmsrl(hwc->config_base + hwc->idx, v); if (v & P4_CCCR_OVF) { - wrmsrl(hwc->config_base, v & ~P4_CCCR_OVF); + wrmsrl(hwc->config_base + hwc->idx, v & ~P4_CCCR_OVF); return 1; } @@ -815,7 +815,7 @@ static inline void p4_pmu_disable_event(struct perf_event *event) * state we need to clear P4_CCCR_OVF, otherwise interrupt get * asserted again and again */ - (void)checking_wrmsrl(hwc->config_base, + (void)checking_wrmsrl(hwc->config_base + hwc->idx, (u64)(p4_config_unpack_cccr(hwc->config)) & ~P4_CCCR_ENABLE & ~P4_CCCR_OVF & ~P4_CCCR_RESERVED); } @@ -885,7 +885,7 @@ static void p4_pmu_enable_event(struct perf_event *event) p4_pmu_enable_pebs(hwc->config); (void)checking_wrmsrl(escr_addr, escr_conf); - (void)checking_wrmsrl(hwc->config_base, + (void)checking_wrmsrl(hwc->config_base + hwc->idx, (cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE); } diff --git a/trunk/arch/x86/kernel/cpu/perf_event_p6.c b/trunk/arch/x86/kernel/cpu/perf_event_p6.c index 20c097e33860..34ba07be2cda 100644 --- a/trunk/arch/x86/kernel/cpu/perf_event_p6.c +++ b/trunk/arch/x86/kernel/cpu/perf_event_p6.c @@ -68,7 +68,7 @@ p6_pmu_disable_event(struct perf_event *event) if (cpuc->enabled) val |= ARCH_PERFMON_EVENTSEL_ENABLE; - (void)checking_wrmsrl(hwc->config_base, val); + (void)checking_wrmsrl(hwc->config_base + hwc->idx, val); } static void p6_pmu_enable_event(struct perf_event *event) @@ -81,7 +81,7 @@ static void p6_pmu_enable_event(struct perf_event *event) if (cpuc->enabled) val |= ARCH_PERFMON_EVENTSEL_ENABLE; - (void)checking_wrmsrl(hwc->config_base, val); + (void)checking_wrmsrl(hwc->config_base + hwc->idx, val); } static __initconst const struct x86_pmu p6_pmu = { diff --git a/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c b/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c index 966512b2cacf..d5a236615501 100644 --- a/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c +++ b/trunk/arch/x86/kernel/cpu/perfctr-watchdog.c @@ -46,8 +46,6 @@ static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr) /* returns the bit offset of the performance counter register */ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (msr >= MSR_F15H_PERF_CTR) - return (msr - MSR_F15H_PERF_CTR) >> 1; return msr - MSR_K7_PERFCTR0; case X86_VENDOR_INTEL: if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) @@ -72,8 +70,6 @@ static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) /* returns the bit offset of the event selection register */ switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: - if (msr >= MSR_F15H_PERF_CTL) - return (msr - MSR_F15H_PERF_CTL) >> 1; return msr - MSR_K7_EVNTSEL0; case X86_VENDOR_INTEL: if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) diff --git a/trunk/arch/x86/kernel/dumpstack.c b/trunk/arch/x86/kernel/dumpstack.c index 220a1c11cfde..df20723a6a1b 100644 --- a/trunk/arch/x86/kernel/dumpstack.c +++ b/trunk/arch/x86/kernel/dumpstack.c @@ -320,6 +320,31 @@ void die(const char *str, struct pt_regs *regs, long err) oops_end(flags, regs, sig); } +void notrace __kprobes +die_nmi(char *str, struct pt_regs *regs, int do_panic) +{ + unsigned long flags; + + if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) + return; + + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + flags = oops_begin(); + printk(KERN_EMERG "%s", str); + printk(" on CPU%d, ip %08lx, registers:\n", + smp_processor_id(), regs->ip); + show_registers(regs); + oops_end(flags, regs, 0); + if (do_panic || panic_on_oops) + panic("Non maskable interrupt"); + nmi_exit(); + local_irq_enable(); + do_exit(SIGBUS); +} + static int __init oops_setup(char *s) { if (!s) diff --git a/trunk/arch/x86/kernel/kgdb.c b/trunk/arch/x86/kernel/kgdb.c index 7c64c420a9f6..a4130005028a 100644 --- a/trunk/arch/x86/kernel/kgdb.c +++ b/trunk/arch/x86/kernel/kgdb.c @@ -533,6 +533,15 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) } return NOTIFY_DONE; + case DIE_NMIWATCHDOG: + if (atomic_read(&kgdb_active) != -1) { + /* KGDB CPU roundup: */ + kgdb_nmicallback(raw_smp_processor_id(), regs); + return NOTIFY_STOP; + } + /* Enter debugger: */ + break; + case DIE_DEBUG: if (atomic_read(&kgdb_cpu_doing_single_step) != -1) { if (user_mode(regs)) diff --git a/trunk/drivers/atm/solos-pci.c b/trunk/drivers/atm/solos-pci.c index 73fb1c4f4cd4..25ef1a4556e6 100644 --- a/trunk/drivers/atm/solos-pci.c +++ b/trunk/drivers/atm/solos-pci.c @@ -866,8 +866,9 @@ static int popen(struct atm_vcc *vcc) } skb = alloc_skb(sizeof(*header), GFP_ATOMIC); - if (!skb && net_ratelimit()) { - dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); + if (!skb) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); return -ENOMEM; } header = (void *)skb_put(skb, sizeof(*header)); diff --git a/trunk/drivers/bluetooth/ath3k.c b/trunk/drivers/bluetooth/ath3k.c index a126e614601f..333c21289d97 100644 --- a/trunk/drivers/bluetooth/ath3k.c +++ b/trunk/drivers/bluetooth/ath3k.c @@ -39,6 +39,8 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3002) }, + /* Atheros AR9285 Malbec with sflash firmware */ + { USB_DEVICE(0x03F0, 0x311D) }, { } /* Terminating entry */ }; diff --git a/trunk/drivers/bluetooth/btusb.c b/trunk/drivers/bluetooth/btusb.c index 1da773f899a2..4cefa91e6c34 100644 --- a/trunk/drivers/bluetooth/btusb.c +++ b/trunk/drivers/bluetooth/btusb.c @@ -102,6 +102,9 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, + /* Atheros AR9285 Malbec with sflash firmware */ + { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, + /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, diff --git a/trunk/drivers/char/pcmcia/cm4000_cs.c b/trunk/drivers/char/pcmcia/cm4000_cs.c index 777181a2e603..bcbbc71febb7 100644 --- a/trunk/drivers/char/pcmcia/cm4000_cs.c +++ b/trunk/drivers/char/pcmcia/cm4000_cs.c @@ -830,8 +830,7 @@ static void monitor_card(unsigned long p) test_bit(IS_ANY_T1, &dev->flags))) { DEBUGP(4, dev, "Perform AUTOPPS\n"); set_bit(IS_AUTOPPS_ACT, &dev->flags); - ptsreq.protocol = ptsreq.protocol = - (0x01 << dev->proto); + ptsreq.protocol = (0x01 << dev->proto); ptsreq.flags = 0x01; ptsreq.pts1 = 0x00; ptsreq.pts2 = 0x00; diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.c b/trunk/drivers/char/pcmcia/ipwireless/main.c index 94b8eb4d691d..444155a305ae 100644 --- a/trunk/drivers/char/pcmcia/ipwireless/main.c +++ b/trunk/drivers/char/pcmcia/ipwireless/main.c @@ -78,7 +78,6 @@ static void signalled_reboot_callback(void *callback_data) static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data) { struct ipw_dev *ipw = priv_data; - struct resource *io_resource; int ret; p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; @@ -92,9 +91,12 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data) if (ret) return ret; - io_resource = request_region(p_dev->resource[0]->start, - resource_size(p_dev->resource[0]), - IPWIRELESS_PCCARD_NAME); + if (!request_region(p_dev->resource[0]->start, + resource_size(p_dev->resource[0]), + IPWIRELESS_PCCARD_NAME)) { + ret = -EBUSY; + goto exit; + } p_dev->resource[2]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE; @@ -105,22 +107,25 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data) ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr); if (ret != 0) - goto exit2; + goto exit1; ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100; - ipw->attr_memory = ioremap(p_dev->resource[2]->start, + ipw->common_memory = ioremap(p_dev->resource[2]->start, resource_size(p_dev->resource[2])); - request_mem_region(p_dev->resource[2]->start, - resource_size(p_dev->resource[2]), - IPWIRELESS_PCCARD_NAME); + if (!request_mem_region(p_dev->resource[2]->start, + resource_size(p_dev->resource[2]), + IPWIRELESS_PCCARD_NAME)) { + ret = -EBUSY; + goto exit2; + } p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE; p_dev->resource[3]->end = 0; /* this used to be 0x1000 */ ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0); if (ret != 0) - goto exit2; + goto exit3; ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0); if (ret != 0) @@ -128,23 +133,28 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data) ipw->attr_memory = ioremap(p_dev->resource[3]->start, resource_size(p_dev->resource[3])); - request_mem_region(p_dev->resource[3]->start, - resource_size(p_dev->resource[3]), - IPWIRELESS_PCCARD_NAME); + if (!request_mem_region(p_dev->resource[3]->start, + resource_size(p_dev->resource[3]), + IPWIRELESS_PCCARD_NAME)) { + ret = -EBUSY; + goto exit4; + } return 0; +exit4: + iounmap(ipw->attr_memory); exit3: + release_mem_region(p_dev->resource[2]->start, + resource_size(p_dev->resource[2])); exit2: - if (ipw->common_memory) { - release_mem_region(p_dev->resource[2]->start, - resource_size(p_dev->resource[2])); - iounmap(ipw->common_memory); - } + iounmap(ipw->common_memory); exit1: - release_resource(io_resource); + release_region(p_dev->resource[0]->start, + resource_size(p_dev->resource[0])); +exit: pcmcia_disable_device(p_dev); - return -1; + return ret; } static int config_ipwireless(struct ipw_dev *ipw) @@ -219,6 +229,8 @@ static int config_ipwireless(struct ipw_dev *ipw) static void release_ipwireless(struct ipw_dev *ipw) { + release_region(ipw->link->resource[0]->start, + resource_size(ipw->link->resource[0])); if (ipw->common_memory) { release_mem_region(ipw->link->resource[2]->start, resource_size(ipw->link->resource[2])); diff --git a/trunk/drivers/char/tpm/tpm.c b/trunk/drivers/char/tpm/tpm.c index faf5a2c65926..36e0fa161c2b 100644 --- a/trunk/drivers/char/tpm/tpm.c +++ b/trunk/drivers/char/tpm/tpm.c @@ -577,11 +577,9 @@ void tpm_get_timeouts(struct tpm_chip *chip) if (rc) return; - if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || - be32_to_cpu(tpm_cmd.header.out.length) - != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) + if (be32_to_cpu(tpm_cmd.header.out.return_code) + != 3 * sizeof(u32)) return; - duration_cap = &tpm_cmd.params.getcap_out.cap.duration; chip->vendor.duration[TPM_SHORT] = usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); @@ -941,18 +939,6 @@ ssize_t tpm_show_caps_1_2(struct device * dev, } EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); -ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct tpm_chip *chip = dev_get_drvdata(dev); - - return sprintf(buf, "%d %d %d\n", - jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), - jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), - jiffies_to_usecs(chip->vendor.duration[TPM_LONG])); -} -EXPORT_SYMBOL_GPL(tpm_show_timeouts); - ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { diff --git a/trunk/drivers/char/tpm/tpm.h b/trunk/drivers/char/tpm/tpm.h index d84ff772c26f..72ddb031b69a 100644 --- a/trunk/drivers/char/tpm/tpm.h +++ b/trunk/drivers/char/tpm/tpm.h @@ -56,8 +56,6 @@ extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, char *); extern ssize_t tpm_show_temp_deactivated(struct device *, struct device_attribute *attr, char *); -extern ssize_t tpm_show_timeouts(struct device *, - struct device_attribute *attr, char *); struct tpm_chip; diff --git a/trunk/drivers/char/tpm/tpm_tis.c b/trunk/drivers/char/tpm/tpm_tis.c index 0d1d38e5f266..dd21df55689d 100644 --- a/trunk/drivers/char/tpm/tpm_tis.c +++ b/trunk/drivers/char/tpm/tpm_tis.c @@ -376,7 +376,6 @@ static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); -static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); static struct attribute *tis_attrs[] = { &dev_attr_pubek.attr, @@ -386,8 +385,7 @@ static struct attribute *tis_attrs[] = { &dev_attr_owned.attr, &dev_attr_temp_deactivated.attr, &dev_attr_caps.attr, - &dev_attr_cancel.attr, - &dev_attr_timeouts.attr, NULL, + &dev_attr_cancel.attr, NULL, }; static struct attribute_group tis_attr_grp = { diff --git a/trunk/drivers/gpu/drm/i915/i915_reg.h b/trunk/drivers/gpu/drm/i915/i915_reg.h index 15d94c63918c..729d4233b763 100644 --- a/trunk/drivers/gpu/drm/i915/i915_reg.h +++ b/trunk/drivers/gpu/drm/i915/i915_reg.h @@ -1553,17 +1553,7 @@ /* Backlight control */ #define BLC_PWM_CTL 0x61254 -#define BACKLIGHT_MODULATION_FREQ_SHIFT (17) #define BLC_PWM_CTL2 0x61250 /* 965+ only */ -#define BLM_COMBINATION_MODE (1 << 30) -/* - * This is the most significant 15 bits of the number of backlight cycles in a - * complete cycle of the modulated backlight control. - * - * The actual value is this field multiplied by two. - */ -#define BACKLIGHT_MODULATION_FREQ_MASK (0x7fff << 17) -#define BLM_LEGACY_MODE (1 << 16) /* * This is the number of cycles out of the backlight modulation cycle for which * the backlight is on. diff --git a/trunk/drivers/gpu/drm/i915/intel_panel.c b/trunk/drivers/gpu/drm/i915/intel_panel.c index c65992df458d..d860abeda70f 100644 --- a/trunk/drivers/gpu/drm/i915/intel_panel.c +++ b/trunk/drivers/gpu/drm/i915/intel_panel.c @@ -30,8 +30,6 @@ #include "intel_drv.h" -#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */ - void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) @@ -112,19 +110,6 @@ intel_pch_panel_fitting(struct drm_device *dev, dev_priv->pch_pf_size = (width << 16) | height; } -static int is_backlight_combination_mode(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (INTEL_INFO(dev)->gen >= 4) - return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE; - - if (IS_GEN2(dev)) - return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE; - - return 0; -} - static u32 i915_read_blc_pwm_ctl(struct drm_i915_private *dev_priv) { u32 val; @@ -181,9 +166,6 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) if (INTEL_INFO(dev)->gen < 4) max &= ~1; } - - if (is_backlight_combination_mode(dev)) - max *= 0xff; } DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max); @@ -201,15 +183,6 @@ u32 intel_panel_get_backlight(struct drm_device *dev) val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; if (IS_PINEVIEW(dev)) val >>= 1; - - if (is_backlight_combination_mode(dev)){ - u8 lbpc; - - val &= ~1; - pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); - val *= lbpc; - val >>= 1; - } } DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val); @@ -232,16 +205,6 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level) if (HAS_PCH_SPLIT(dev)) return intel_pch_panel_set_backlight(dev, level); - - if (is_backlight_combination_mode(dev)){ - u32 max = intel_panel_get_max_backlight(dev); - u8 lpbc; - - lpbc = level * 0xfe / max + 1; - level /= lpbc; - pci_write_config_byte(dev->pdev, PCI_LBPC, lpbc); - } - tmp = I915_READ(BLC_PWM_CTL); if (IS_PINEVIEW(dev)) { tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c b/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c index 49e5e99917e2..6bdab891c64e 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -6228,7 +6228,7 @@ parse_dcb15_entry(struct drm_device *dev, struct dcb_table *dcb, entry->tvconf.has_component_output = false; break; case OUTPUT_LVDS: - if ((conn & 0x00003f00) != 0x10) + if ((conn & 0x00003f00) >> 8 != 0x10) entry->lvdsconf.use_straps_for_mode = true; entry->lvdsconf.use_power_scripts = true; break; diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_bo.c b/trunk/drivers/gpu/drm/nouveau/nouveau_bo.c index a7fae26f4654..d38a4d9f9b0b 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -128,6 +128,7 @@ nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, } } + nvbo->bo.mem.num_pages = size >> PAGE_SHIFT; nouveau_bo_placement_set(nvbo, flags, 0); nvbo->channel = chan; @@ -166,17 +167,17 @@ static void set_placement_range(struct nouveau_bo *nvbo, uint32_t type) { struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); + int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; if (dev_priv->card_type == NV_10 && - nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) { + nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && + nvbo->bo.mem.num_pages < vram_pages / 2) { /* * Make sure that the color and depth buffers are handled * by independent memory controller units. Up to a 9x * speed up when alpha-blending and depth-test are enabled * at the same time. */ - int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; - if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { nvbo->placement.fpfn = vram_pages / 2; nvbo->placement.lpfn = ~0; @@ -785,7 +786,7 @@ nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) goto out; - ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); + ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem); out: ttm_bo_mem_put(bo, &tmp_mem); return ret; @@ -811,11 +812,11 @@ nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr, if (ret) return ret; - ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, &tmp_mem); + ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, &tmp_mem); if (ret) goto out; - ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); + ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_reserve, no_wait_gpu, new_mem); if (ret) goto out; diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c index a21e00076839..390d82c3c4b0 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -507,6 +507,7 @@ nouveau_connector_native_mode(struct drm_connector *connector) int high_w = 0, high_h = 0, high_v = 0; list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { + mode->vrefresh = drm_mode_vrefresh(mode); if (helper->mode_valid(connector, mode) != MODE_OK || (mode->flags & DRM_MODE_FLAG_INTERLACE)) continue; diff --git a/trunk/drivers/gpu/drm/nouveau/nouveau_pm.c b/trunk/drivers/gpu/drm/nouveau/nouveau_pm.c index f05c0cddfeca..4399e2f34db4 100644 --- a/trunk/drivers/gpu/drm/nouveau/nouveau_pm.c +++ b/trunk/drivers/gpu/drm/nouveau/nouveau_pm.c @@ -543,7 +543,7 @@ nouveau_pm_resume(struct drm_device *dev) struct nouveau_pm_engine *pm = &dev_priv->engine.pm; struct nouveau_pm_level *perflvl; - if (pm->cur == &pm->boot) + if (!pm->cur || pm->cur == &pm->boot) return; perflvl = pm->cur; diff --git a/trunk/drivers/gpu/drm/nouveau/nv04_dfp.c b/trunk/drivers/gpu/drm/nouveau/nv04_dfp.c index ef23550407b5..c82db37d9f41 100644 --- a/trunk/drivers/gpu/drm/nouveau/nv04_dfp.c +++ b/trunk/drivers/gpu/drm/nouveau/nv04_dfp.c @@ -342,8 +342,8 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, if (nv_encoder->dcb->type == OUTPUT_LVDS) { bool duallink, dummy; - nouveau_bios_parse_lvds_table(dev, nv_connector->native_mode-> - clock, &duallink, &dummy); + nouveau_bios_parse_lvds_table(dev, output_mode->clock, + &duallink, &dummy); if (duallink) regp->fp_control |= (8 << 28); } else @@ -518,8 +518,6 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) return; if (nv_encoder->dcb->lvdsconf.use_power_scripts) { - struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder); - /* when removing an output, crtc may not be set, but PANEL_OFF * must still be run */ @@ -527,12 +525,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode) nv04_dfp_get_bound_head(dev, nv_encoder->dcb); if (mode == DRM_MODE_DPMS_ON) { - if (!nv_connector->native_mode) { - NV_ERROR(dev, "Not turning on LVDS without native mode\n"); - return; - } call_lvds_script(dev, nv_encoder->dcb, head, - LVDS_PANEL_ON, nv_connector->native_mode->clock); + LVDS_PANEL_ON, nv_encoder->mode.clock); } else /* pxclk of 0 is fine for PANEL_OFF, and for a * disconnected LVDS encoder there is no native_mode diff --git a/trunk/drivers/gpu/drm/nouveau/nv40_graph.c b/trunk/drivers/gpu/drm/nouveau/nv40_graph.c index 8870d72388c8..18d30c2c1aa6 100644 --- a/trunk/drivers/gpu/drm/nouveau/nv40_graph.c +++ b/trunk/drivers/gpu/drm/nouveau/nv40_graph.c @@ -211,18 +211,32 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i) struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; switch (dev_priv->chipset) { + case 0x40: + case 0x41: /* guess */ + case 0x42: + case 0x43: + case 0x45: /* guess */ + case 0x4e: + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); + break; case 0x44: case 0x4a: - case 0x4e: nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); break; - case 0x46: case 0x47: case 0x49: case 0x4b: + case 0x4c: + case 0x67: + default: nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr); @@ -230,15 +244,6 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i) nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); break; - - default: - nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); - break; } } @@ -396,17 +401,20 @@ nv40_graph_init(struct drm_device *dev) break; default: switch (dev_priv->chipset) { - case 0x46: - case 0x47: - case 0x49: - case 0x4b: - nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); - nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); - break; - default: + case 0x41: + case 0x42: + case 0x43: + case 0x45: + case 0x4e: + case 0x44: + case 0x4a: nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1)); break; + default: + nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); + nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); + break; } nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0)); nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1)); diff --git a/trunk/drivers/gpu/drm/radeon/atombios_crtc.c b/trunk/drivers/gpu/drm/radeon/atombios_crtc.c index 095bc507fb16..a4e5e53e0a62 100644 --- a/trunk/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/trunk/drivers/gpu/drm/radeon/atombios_crtc.c @@ -557,9 +557,9 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, /* use recommended ref_div for ss */ if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; if (ss_enabled) { if (ss->refdiv) { + pll->flags |= RADEON_PLL_PREFER_MINM_OVER_MAXP; pll->flags |= RADEON_PLL_USE_REF_DIV; pll->reference_div = ss->refdiv; if (ASIC_IS_AVIVO(rdev)) @@ -662,10 +662,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, index, (uint32_t *)&args); adjusted_clock = le32_to_cpu(args.v3.sOutput.ulDispPllFreq) * 10; if (args.v3.sOutput.ucRefDiv) { + pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; pll->flags |= RADEON_PLL_USE_REF_DIV; pll->reference_div = args.v3.sOutput.ucRefDiv; } if (args.v3.sOutput.ucPostDiv) { + pll->flags |= RADEON_PLL_USE_FRAC_FB_DIV; pll->flags |= RADEON_PLL_USE_POST_DIV; pll->post_div = args.v3.sOutput.ucPostDiv; } diff --git a/trunk/drivers/gpu/drm/radeon/r300.c b/trunk/drivers/gpu/drm/radeon/r300.c index 768c60ee4ab6..069efa8c8ecf 100644 --- a/trunk/drivers/gpu/drm/radeon/r300.c +++ b/trunk/drivers/gpu/drm/radeon/r300.c @@ -910,6 +910,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_X16: + case R300_TX_FORMAT_FL_I16: case R300_TX_FORMAT_Y8X8: case R300_TX_FORMAT_Z5Y6X5: case R300_TX_FORMAT_Z6Y5X5: @@ -922,6 +923,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, track->textures[i].compress_format = R100_TRACK_COMP_NONE; break; case R300_TX_FORMAT_Y16X16: + case R300_TX_FORMAT_FL_I16A16: case R300_TX_FORMAT_Z11Y11X10: case R300_TX_FORMAT_Z10Y11X11: case R300_TX_FORMAT_W8Z8Y8X8: diff --git a/trunk/drivers/hwmon/Kconfig b/trunk/drivers/hwmon/Kconfig index 773e484f1646..297bc9a7d6e6 100644 --- a/trunk/drivers/hwmon/Kconfig +++ b/trunk/drivers/hwmon/Kconfig @@ -238,13 +238,13 @@ config SENSORS_K8TEMP will be called k8temp. config SENSORS_K10TEMP - tristate "AMD Phenom/Sempron/Turion/Opteron temperature sensor" + tristate "AMD Family 10h/11h/12h/14h temperature sensor" depends on X86 && PCI help If you say yes here you get support for the temperature sensor(s) inside your CPU. Supported are later revisions of - the AMD Family 10h and all revisions of the AMD Family 11h - microarchitectures. + the AMD Family 10h and all revisions of the AMD Family 11h, + 12h (Llano), and 14h (Brazos) microarchitectures. This driver can also be built as a module. If so, the module will be called k10temp. @@ -455,13 +455,14 @@ config SENSORS_JZ4740 called jz4740-hwmon. config SENSORS_JC42 - tristate "JEDEC JC42.4 compliant temperature sensors" + tristate "JEDEC JC42.4 compliant memory module temperature sensors" depends on I2C help - If you say yes here you get support for Jedec JC42.4 compliant - temperature sensors. Support will include, but not be limited to, - ADT7408, CAT34TS02,, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243, - MCP9843, SE97, SE98, STTS424, TSE2002B3, and TS3000B3. + If you say yes here, you get support for JEDEC JC42.4 compliant + temperature sensors, which are used on many DDR3 memory modules for + mobile devices and servers. Support will include, but not be limited + to, ADT7408, CAT34TS02, CAT6095, MAX6604, MCP9805, MCP98242, MCP98243, + MCP9843, SE97, SE98, STTS424(E), TSE2002B3, and TS3000B3. This driver can also be built as a module. If so, the module will be called jc42. @@ -574,7 +575,7 @@ config SENSORS_LM85 help If you say yes here you get support for National Semiconductor LM85 sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100, - EMC6D101 and EMC6D102. + EMC6D101, EMC6D102, and EMC6D103. This driver can also be built as a module. If so, the module will be called lm85. diff --git a/trunk/drivers/hwmon/jc42.c b/trunk/drivers/hwmon/jc42.c index 340fc78c8dde..934991237061 100644 --- a/trunk/drivers/hwmon/jc42.c +++ b/trunk/drivers/hwmon/jc42.c @@ -53,6 +53,8 @@ static const unsigned short normal_i2c[] = { /* Configuration register defines */ #define JC42_CFG_CRIT_ONLY (1 << 2) +#define JC42_CFG_TCRIT_LOCK (1 << 6) +#define JC42_CFG_EVENT_LOCK (1 << 7) #define JC42_CFG_SHUTDOWN (1 << 8) #define JC42_CFG_HYST_SHIFT 9 #define JC42_CFG_HYST_MASK 0x03 @@ -332,7 +334,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev, { struct i2c_client *client = to_i2c_client(dev); struct jc42_data *data = i2c_get_clientdata(client); - long val; + unsigned long val; int diff, hyst; int err; int ret = count; @@ -380,14 +382,14 @@ static ssize_t show_alarm(struct device *dev, static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL); -static DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, +static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, set_temp_crit); -static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, +static DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min, set_temp_min); -static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, +static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, set_temp_max); -static DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, +static DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, set_temp_crit_hyst); static DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_max_hyst, NULL); @@ -412,8 +414,31 @@ static struct attribute *jc42_attributes[] = { NULL }; +static mode_t jc42_attribute_mode(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct i2c_client *client = to_i2c_client(dev); + struct jc42_data *data = i2c_get_clientdata(client); + unsigned int config = data->config; + bool readonly; + + if (attr == &dev_attr_temp1_crit.attr) + readonly = config & JC42_CFG_TCRIT_LOCK; + else if (attr == &dev_attr_temp1_min.attr || + attr == &dev_attr_temp1_max.attr) + readonly = config & JC42_CFG_EVENT_LOCK; + else if (attr == &dev_attr_temp1_crit_hyst.attr) + readonly = config & (JC42_CFG_EVENT_LOCK | JC42_CFG_TCRIT_LOCK); + else + readonly = true; + + return S_IRUGO | (readonly ? 0 : S_IWUSR); +} + static const struct attribute_group jc42_group = { .attrs = jc42_attributes, + .is_visible = jc42_attribute_mode, }; /* Return 0 if detection is successful, -ENODEV otherwise */ diff --git a/trunk/drivers/hwmon/k10temp.c b/trunk/drivers/hwmon/k10temp.c index da5a2404cd3e..82bf65aa2968 100644 --- a/trunk/drivers/hwmon/k10temp.c +++ b/trunk/drivers/hwmon/k10temp.c @@ -1,5 +1,5 @@ /* - * k10temp.c - AMD Family 10h/11h processor hardware monitoring + * k10temp.c - AMD Family 10h/11h/12h/14h processor hardware monitoring * * Copyright (c) 2009 Clemens Ladisch * @@ -25,7 +25,7 @@ #include #include -MODULE_DESCRIPTION("AMD Family 10h/11h CPU core temperature monitor"); +MODULE_DESCRIPTION("AMD Family 10h/11h/12h/14h CPU core temperature monitor"); MODULE_AUTHOR("Clemens Ladisch "); MODULE_LICENSE("GPL"); @@ -208,6 +208,7 @@ static void __devexit k10temp_remove(struct pci_dev *pdev) static const struct pci_device_id k10temp_id_table[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) }, { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) }, + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) }, {} }; MODULE_DEVICE_TABLE(pci, k10temp_id_table); diff --git a/trunk/drivers/hwmon/lm85.c b/trunk/drivers/hwmon/lm85.c index 1e229847f37a..d2cc28660816 100644 --- a/trunk/drivers/hwmon/lm85.c +++ b/trunk/drivers/hwmon/lm85.c @@ -41,7 +41,7 @@ static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END }; enum chips { any_chip, lm85b, lm85c, adm1027, adt7463, adt7468, - emc6d100, emc6d102 + emc6d100, emc6d102, emc6d103 }; /* The LM85 registers */ @@ -90,6 +90,9 @@ enum chips { #define LM85_VERSTEP_EMC6D100_A0 0x60 #define LM85_VERSTEP_EMC6D100_A1 0x61 #define LM85_VERSTEP_EMC6D102 0x65 +#define LM85_VERSTEP_EMC6D103_A0 0x68 +#define LM85_VERSTEP_EMC6D103_A1 0x69 +#define LM85_VERSTEP_EMC6D103S 0x6A /* Also known as EMC6D103:A2 */ #define LM85_REG_CONFIG 0x40 @@ -348,6 +351,7 @@ static const struct i2c_device_id lm85_id[] = { { "emc6d100", emc6d100 }, { "emc6d101", emc6d100 }, { "emc6d102", emc6d102 }, + { "emc6d103", emc6d103 }, { } }; MODULE_DEVICE_TABLE(i2c, lm85_id); @@ -1250,6 +1254,20 @@ static int lm85_detect(struct i2c_client *client, struct i2c_board_info *info) case LM85_VERSTEP_EMC6D102: type_name = "emc6d102"; break; + case LM85_VERSTEP_EMC6D103_A0: + case LM85_VERSTEP_EMC6D103_A1: + type_name = "emc6d103"; + break; + /* + * Registers apparently missing in EMC6D103S/EMC6D103:A2 + * compared to EMC6D103:A0, EMC6D103:A1, and EMC6D102 + * (according to the data sheets), but used unconditionally + * in the driver: 62[5:7], 6D[0:7], and 6E[0:7]. + * So skip EMC6D103S for now. + case LM85_VERSTEP_EMC6D103S: + type_name = "emc6d103s"; + break; + */ } } else { dev_dbg(&adapter->dev, @@ -1283,6 +1301,7 @@ static int lm85_probe(struct i2c_client *client, case adt7468: case emc6d100: case emc6d102: + case emc6d103: data->freq_map = adm1027_freq_map; break; default: @@ -1468,7 +1487,7 @@ static struct lm85_data *lm85_update_device(struct device *dev) /* More alarm bits */ data->alarms |= lm85_read_value(client, EMC6D100_REG_ALARM3) << 16; - } else if (data->type == emc6d102) { + } else if (data->type == emc6d102 || data->type == emc6d103) { /* Have to read LSB bits after the MSB ones because the reading of the MSB bits has frozen the LSBs (backward from the ADM1027). diff --git a/trunk/drivers/i2c/busses/i2c-omap.c b/trunk/drivers/i2c/busses/i2c-omap.c index b605ff3a1fa0..829a2a1029f7 100644 --- a/trunk/drivers/i2c/busses/i2c-omap.c +++ b/trunk/drivers/i2c/busses/i2c-omap.c @@ -847,11 +847,15 @@ omap_i2c_isr(int this_irq, void *dev_id) dev_err(dev->dev, "Arbitration lost\n"); err |= OMAP_I2C_STAT_AL; } + /* + * ProDB0017052: Clear ARDY bit twice + */ if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | - OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); + OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | + OMAP_I2C_STAT_ARDY)); omap_i2c_complete_cmd(dev, err); return IRQ_HANDLED; } @@ -1137,12 +1141,41 @@ omap_i2c_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_SUSPEND +static int omap_i2c_suspend(struct device *dev) +{ + if (!pm_runtime_suspended(dev)) + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) + dev->bus->pm->runtime_suspend(dev); + + return 0; +} + +static int omap_i2c_resume(struct device *dev) +{ + if (!pm_runtime_suspended(dev)) + if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) + dev->bus->pm->runtime_resume(dev); + + return 0; +} + +static struct dev_pm_ops omap_i2c_pm_ops = { + .suspend = omap_i2c_suspend, + .resume = omap_i2c_resume, +}; +#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) +#else +#define OMAP_I2C_PM_OPS NULL +#endif + static struct platform_driver omap_i2c_driver = { .probe = omap_i2c_probe, .remove = omap_i2c_remove, .driver = { .name = "omap_i2c", .owner = THIS_MODULE, + .pm = OMAP_I2C_PM_OPS, }, }; diff --git a/trunk/drivers/i2c/busses/i2c-stu300.c b/trunk/drivers/i2c/busses/i2c-stu300.c index 495be451d326..266135ddf7fa 100644 --- a/trunk/drivers/i2c/busses/i2c-stu300.c +++ b/trunk/drivers/i2c/busses/i2c-stu300.c @@ -942,7 +942,7 @@ stu300_probe(struct platform_device *pdev) adap->owner = THIS_MODULE; /* DDC class but actually often used for more generic I2C */ adap->class = I2C_CLASS_DDC; - strncpy(adap->name, "ST Microelectronics DDC I2C adapter", + strlcpy(adap->name, "ST Microelectronics DDC I2C adapter", sizeof(adap->name)); adap->nr = bus_nr; adap->algo = &stu300_algo; diff --git a/trunk/drivers/infiniband/hw/nes/nes_hw.c b/trunk/drivers/infiniband/hw/nes/nes_hw.c index 8b606fd64022..08c194861af5 100644 --- a/trunk/drivers/infiniband/hw/nes/nes_hw.c +++ b/trunk/drivers/infiniband/hw/nes/nes_hw.c @@ -2610,9 +2610,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_carrier_on(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 0) { - nesdev->iw_status = 1; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 0) { + nesdev->iw_status = 1; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } @@ -2642,9 +2644,11 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) netif_carrier_off(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 1) { - nesdev->iw_status = 0; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 1) { + nesdev->iw_status = 0; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } @@ -2703,9 +2707,11 @@ void nes_recheck_link_status(struct work_struct *work) netif_carrier_on(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 0) { - nesdev->iw_status = 1; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 0) { + nesdev->iw_status = 1; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } @@ -2723,9 +2729,11 @@ void nes_recheck_link_status(struct work_struct *work) netif_carrier_off(nesvnic->netdev); spin_lock(&nesvnic->port_ibevent_lock); - if (nesdev->iw_status == 1) { - nesdev->iw_status = 0; - nes_port_ibevent(nesvnic); + if (nesvnic->of_device_registered) { + if (nesdev->iw_status == 1) { + nesdev->iw_status = 0; + nes_port_ibevent(nesvnic); + } } spin_unlock(&nesvnic->port_ibevent_lock); } diff --git a/trunk/drivers/infiniband/hw/qib/qib_rc.c b/trunk/drivers/infiniband/hw/qib/qib_rc.c index 8245237b67ce..eca0c41f1226 100644 --- a/trunk/drivers/infiniband/hw/qib/qib_rc.c +++ b/trunk/drivers/infiniband/hw/qib/qib_rc.c @@ -1005,7 +1005,8 @@ void qib_rc_send_complete(struct qib_qp *qp, struct qib_ib_header *hdr) * there are still requests that haven't been acked. */ if ((psn & IB_BTH_REQ_ACK) && qp->s_acked != qp->s_tail && - !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN))) + !(qp->s_flags & (QIB_S_TIMER | QIB_S_WAIT_RNR | QIB_S_WAIT_PSN)) && + (ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) start_timer(qp); while (qp->s_last != qp->s_acked) { @@ -1439,6 +1440,8 @@ static void qib_rc_rcv_resp(struct qib_ibport *ibp, } spin_lock_irqsave(&qp->s_lock, flags); + if (!(ib_qib_state_ops[qp->state] & QIB_PROCESS_RECV_OK)) + goto ack_done; /* Ignore invalid responses. */ if (qib_cmp24(psn, qp->s_next_psn) >= 0) diff --git a/trunk/drivers/isdn/hisax/isdnl2.c b/trunk/drivers/isdn/hisax/isdnl2.c index 0858791978d8..cfff0c41d298 100644 --- a/trunk/drivers/isdn/hisax/isdnl2.c +++ b/trunk/drivers/isdn/hisax/isdnl2.c @@ -1247,10 +1247,10 @@ static void l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) { struct PStack *st = fi->userdata; - struct sk_buff *skb, *oskb; + struct sk_buff *skb; struct Layer2 *l2 = &st->l2; u_char header[MAX_HEADER_LEN]; - int i; + int i, hdr_space_needed; int unsigned p1; u_long flags; @@ -1261,6 +1261,16 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) if (!skb) return; + hdr_space_needed = l2headersize(l2, 0); + if (hdr_space_needed > skb_headroom(skb)) { + struct sk_buff *orig_skb = skb; + + skb = skb_realloc_headroom(skb, hdr_space_needed); + if (!skb) { + dev_kfree_skb(orig_skb); + return; + } + } spin_lock_irqsave(&l2->lock, flags); if(test_bit(FLG_MOD128, &l2->flag)) p1 = (l2->vs - l2->va) % 128; @@ -1285,19 +1295,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) l2->vs = (l2->vs + 1) % 8; } spin_unlock_irqrestore(&l2->lock, flags); - p1 = skb->data - skb->head; - if (p1 >= i) - memcpy(skb_push(skb, i), header, i); - else { - printk(KERN_WARNING - "isdl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); - oskb = skb; - skb = alloc_skb(oskb->len + i, GFP_ATOMIC); - memcpy(skb_put(skb, i), header, i); - skb_copy_from_linear_data(oskb, - skb_put(skb, oskb->len), oskb->len); - dev_kfree_skb(oskb); - } + memcpy(skb_push(skb, i), header, i); st->l2.l2l1(st, PH_PULL | INDICATION, skb); test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { diff --git a/trunk/drivers/memstick/core/memstick.c b/trunk/drivers/memstick/core/memstick.c index e9a3eab7b0cf..8c1d85e27be4 100644 --- a/trunk/drivers/memstick/core/memstick.c +++ b/trunk/drivers/memstick/core/memstick.c @@ -621,7 +621,7 @@ static int __init memstick_init(void) { int rc; - workqueue = create_freezeable_workqueue("kmemstick"); + workqueue = create_freezable_workqueue("kmemstick"); if (!workqueue) return -ENOMEM; diff --git a/trunk/drivers/message/fusion/mptbase.h b/trunk/drivers/message/fusion/mptbase.h index f71f22948477..1735c84ff757 100644 --- a/trunk/drivers/message/fusion/mptbase.h +++ b/trunk/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2008 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.04.17" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.17" +#define MPT_LINUX_VERSION_COMMON "3.04.18" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.18" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ diff --git a/trunk/drivers/message/fusion/mptctl.c b/trunk/drivers/message/fusion/mptctl.c index a3856ed90aef..e8deb8ed0499 100644 --- a/trunk/drivers/message/fusion/mptctl.c +++ b/trunk/drivers/message/fusion/mptctl.c @@ -596,6 +596,13 @@ mptctl_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) return 1; } +static int +mptctl_release(struct inode *inode, struct file *filep) +{ + fasync_helper(-1, filep, 0, &async_queue); + return 0; +} + static int mptctl_fasync(int fd, struct file *filep, int mode) { @@ -2815,6 +2822,7 @@ static const struct file_operations mptctl_fops = { .llseek = no_llseek, .fasync = mptctl_fasync, .unlocked_ioctl = mptctl_ioctl, + .release = mptctl_release, #ifdef CONFIG_COMPAT .compat_ioctl = compat_mpctl_ioctl, #endif diff --git a/trunk/drivers/message/fusion/mptscsih.c b/trunk/drivers/message/fusion/mptscsih.c index 59b8f53d1ece..0d9b82a44540 100644 --- a/trunk/drivers/message/fusion/mptscsih.c +++ b/trunk/drivers/message/fusion/mptscsih.c @@ -1873,8 +1873,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) } out: - printk(MYIOC_s_INFO_FMT "task abort: %s (sc=%p)\n", - ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), SCpnt); + printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p) (sn=%ld)\n", + ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval, + SCpnt, SCpnt->serial_number); return retval; } @@ -1911,7 +1912,7 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) vdevice = SCpnt->device->hostdata; if (!vdevice || !vdevice->vtarget) { - retval = SUCCESS; + retval = 0; goto out; } diff --git a/trunk/drivers/misc/tifm_core.c b/trunk/drivers/misc/tifm_core.c index 5f6852dff40b..44d4475a09dd 100644 --- a/trunk/drivers/misc/tifm_core.c +++ b/trunk/drivers/misc/tifm_core.c @@ -329,7 +329,7 @@ static int __init tifm_init(void) { int rc; - workqueue = create_freezeable_workqueue("tifm"); + workqueue = create_freezable_workqueue("tifm"); if (!workqueue) return -ENOMEM; diff --git a/trunk/drivers/misc/vmw_balloon.c b/trunk/drivers/misc/vmw_balloon.c index 4d2ea8e80140..6df5a55da110 100644 --- a/trunk/drivers/misc/vmw_balloon.c +++ b/trunk/drivers/misc/vmw_balloon.c @@ -785,7 +785,7 @@ static int __init vmballoon_init(void) if (x86_hyper != &x86_hyper_vmware) return -ENODEV; - vmballoon_wq = create_freezeable_workqueue("vmmemctl"); + vmballoon_wq = create_freezable_workqueue("vmmemctl"); if (!vmballoon_wq) { pr_err("failed to create workqueue\n"); return -ENOMEM; diff --git a/trunk/drivers/mtd/nand/r852.c b/trunk/drivers/mtd/nand/r852.c index d9d7efbc77cc..6322d1fb5d62 100644 --- a/trunk/drivers/mtd/nand/r852.c +++ b/trunk/drivers/mtd/nand/r852.c @@ -930,7 +930,7 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) init_completion(&dev->dma_done); - dev->card_workqueue = create_freezeable_workqueue(DRV_NAME); + dev->card_workqueue = create_freezable_workqueue(DRV_NAME); if (!dev->card_workqueue) goto error9; diff --git a/trunk/drivers/mtd/sm_ftl.c b/trunk/drivers/mtd/sm_ftl.c index 67822cf6c025..ac0d6a8613b5 100644 --- a/trunk/drivers/mtd/sm_ftl.c +++ b/trunk/drivers/mtd/sm_ftl.c @@ -1258,7 +1258,7 @@ static struct mtd_blktrans_ops sm_ftl_ops = { static __init int sm_module_init(void) { int error = 0; - cache_flush_workqueue = create_freezeable_workqueue("smflush"); + cache_flush_workqueue = create_freezable_workqueue("smflush"); if (IS_ERR(cache_flush_workqueue)) return PTR_ERR(cache_flush_workqueue); diff --git a/trunk/drivers/net/can/mcp251x.c b/trunk/drivers/net/can/mcp251x.c index 7ab534aee452..7513c4523ac4 100644 --- a/trunk/drivers/net/can/mcp251x.c +++ b/trunk/drivers/net/can/mcp251x.c @@ -940,7 +940,7 @@ static int mcp251x_open(struct net_device *net) goto open_unlock; } - priv->wq = create_freezeable_workqueue("mcp251x_wq"); + priv->wq = create_freezable_workqueue("mcp251x_wq"); INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler); INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler); diff --git a/trunk/drivers/net/can/softing/Kconfig b/trunk/drivers/net/can/softing/Kconfig index 8ba81b3ddd90..5de46a9a77bb 100644 --- a/trunk/drivers/net/can/softing/Kconfig +++ b/trunk/drivers/net/can/softing/Kconfig @@ -18,7 +18,7 @@ config CAN_SOFTING config CAN_SOFTING_CS tristate "Softing Gmbh CAN pcmcia cards" depends on PCMCIA - select CAN_SOFTING + depends on CAN_SOFTING ---help--- Support for PCMCIA cards from Softing Gmbh & some cards from Vector Gmbh. diff --git a/trunk/drivers/net/cxgb4vf/cxgb4vf_main.c b/trunk/drivers/net/cxgb4vf/cxgb4vf_main.c index 56166ae2059f..6aad64df4dcb 100644 --- a/trunk/drivers/net/cxgb4vf/cxgb4vf_main.c +++ b/trunk/drivers/net/cxgb4vf/cxgb4vf_main.c @@ -2040,7 +2040,7 @@ static int __devinit setup_debugfs(struct adapter *adapter) { int i; - BUG_ON(adapter->debugfs_root == NULL); + BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); /* * Debugfs support is best effort. @@ -2061,7 +2061,7 @@ static int __devinit setup_debugfs(struct adapter *adapter) */ static void cleanup_debugfs(struct adapter *adapter) { - BUG_ON(adapter->debugfs_root == NULL); + BUG_ON(IS_ERR_OR_NULL(adapter->debugfs_root)); /* * Unlike our sister routine cleanup_proc(), we don't need to remove @@ -2488,17 +2488,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, struct port_info *pi; struct net_device *netdev; - /* - * Vet our module parameters. - */ - if (msi != MSI_MSIX && msi != MSI_MSI) { - dev_err(&pdev->dev, "bad module parameter msi=%d; must be %d" - " (MSI-X or MSI) or %d (MSI)\n", msi, MSI_MSIX, - MSI_MSI); - err = -EINVAL; - goto err_out; - } - /* * Print our driver banner the first time we're called to initialize a * device. @@ -2711,11 +2700,11 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, /* * Set up our debugfs entries. */ - if (cxgb4vf_debugfs_root) { + if (!IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) { adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), cxgb4vf_debugfs_root); - if (adapter->debugfs_root == NULL) + if (IS_ERR_OR_NULL(adapter->debugfs_root)) dev_warn(&pdev->dev, "could not create debugfs" " directory"); else @@ -2770,7 +2759,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, */ err_free_debugfs: - if (adapter->debugfs_root) { + if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { cleanup_debugfs(adapter); debugfs_remove_recursive(adapter->debugfs_root); } @@ -2802,7 +2791,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev, err_disable_device: pci_disable_device(pdev); -err_out: return err; } @@ -2840,7 +2828,7 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev) /* * Tear down our debugfs entries. */ - if (adapter->debugfs_root) { + if (!IS_ERR_OR_NULL(adapter->debugfs_root)) { cleanup_debugfs(adapter); debugfs_remove_recursive(adapter->debugfs_root); } @@ -2873,6 +2861,46 @@ static void __devexit cxgb4vf_pci_remove(struct pci_dev *pdev) pci_release_regions(pdev); } +/* + * "Shutdown" quiesce the device, stopping Ingress Packet and Interrupt + * delivery. + */ +static void __devexit cxgb4vf_pci_shutdown(struct pci_dev *pdev) +{ + struct adapter *adapter; + int pidx; + + adapter = pci_get_drvdata(pdev); + if (!adapter) + return; + + /* + * Disable all Virtual Interfaces. This will shut down the + * delivery of all ingress packets into the chip for these + * Virtual Interfaces. + */ + for_each_port(adapter, pidx) { + struct net_device *netdev; + struct port_info *pi; + + if (!test_bit(pidx, &adapter->registered_device_map)) + continue; + + netdev = adapter->port[pidx]; + if (!netdev) + continue; + + pi = netdev_priv(netdev); + t4vf_enable_vi(adapter, pi->viid, false, false); + } + + /* + * Free up all Queues which will prevent further DMA and + * Interrupts allowing various internal pathways to drain. + */ + t4vf_free_sge_resources(adapter); +} + /* * PCI Device registration data structures. */ @@ -2906,6 +2934,7 @@ static struct pci_driver cxgb4vf_driver = { .id_table = cxgb4vf_pci_tbl, .probe = cxgb4vf_pci_probe, .remove = __devexit_p(cxgb4vf_pci_remove), + .shutdown = __devexit_p(cxgb4vf_pci_shutdown), }; /* @@ -2915,14 +2944,25 @@ static int __init cxgb4vf_module_init(void) { int ret; + /* + * Vet our module parameters. + */ + if (msi != MSI_MSIX && msi != MSI_MSI) { + printk(KERN_WARNING KBUILD_MODNAME + ": bad module parameter msi=%d; must be %d" + " (MSI-X or MSI) or %d (MSI)\n", + msi, MSI_MSIX, MSI_MSI); + return -EINVAL; + } + /* Debugfs support is optional, just warn if this fails */ cxgb4vf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (!cxgb4vf_debugfs_root) + if (IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) printk(KERN_WARNING KBUILD_MODNAME ": could not create" " debugfs entry, continuing\n"); ret = pci_register_driver(&cxgb4vf_driver); - if (ret < 0) + if (ret < 0 && !IS_ERR_OR_NULL(cxgb4vf_debugfs_root)) debugfs_remove(cxgb4vf_debugfs_root); return ret; } diff --git a/trunk/drivers/net/cxgb4vf/t4vf_hw.c b/trunk/drivers/net/cxgb4vf/t4vf_hw.c index 0f51c80475ce..192db226ec7f 100644 --- a/trunk/drivers/net/cxgb4vf/t4vf_hw.c +++ b/trunk/drivers/net/cxgb4vf/t4vf_hw.c @@ -171,7 +171,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size, delay_idx = 0; ms = delay[0]; - for (i = 0; i < 500; i += ms) { + for (i = 0; i < FW_CMD_MAX_TIMEOUT; i += ms) { if (sleep_ok) { ms = delay[delay_idx]; if (delay_idx < ARRAY_SIZE(delay) - 1) diff --git a/trunk/drivers/net/e1000e/netdev.c b/trunk/drivers/net/e1000e/netdev.c index 3065870cf2a7..3fa110ddb041 100644 --- a/trunk/drivers/net/e1000e/netdev.c +++ b/trunk/drivers/net/e1000e/netdev.c @@ -937,6 +937,9 @@ static void e1000_print_hw_hang(struct work_struct *work) u16 phy_status, phy_1000t_status, phy_ext_status; u16 pci_status; + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + e1e_rphy(hw, PHY_STATUS, &phy_status); e1e_rphy(hw, PHY_1000T_STATUS, &phy_1000t_status); e1e_rphy(hw, PHY_EXT_STATUS, &phy_ext_status); @@ -1506,6 +1509,9 @@ static void e1000e_downshift_workaround(struct work_struct *work) struct e1000_adapter *adapter = container_of(work, struct e1000_adapter, downshift_task); + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + e1000e_gig_downshift_workaround_ich8lan(&adapter->hw); } @@ -3338,6 +3344,21 @@ int e1000e_up(struct e1000_adapter *adapter) return 0; } +static void e1000e_flush_descriptors(struct e1000_adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + + if (!(adapter->flags2 & FLAG2_DMA_BURST)) + return; + + /* flush pending descriptor writebacks to memory */ + ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); + ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD); + + /* execute the writes immediately */ + e1e_flush(); +} + void e1000e_down(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -3377,6 +3398,9 @@ void e1000e_down(struct e1000_adapter *adapter) if (!pci_channel_offline(adapter->pdev)) e1000e_reset(adapter); + + e1000e_flush_descriptors(adapter); + e1000_clean_tx_ring(adapter); e1000_clean_rx_ring(adapter); @@ -3765,6 +3789,10 @@ static void e1000e_update_phy_task(struct work_struct *work) { struct e1000_adapter *adapter = container_of(work, struct e1000_adapter, update_phy_task); + + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + e1000_get_phy_info(&adapter->hw); } @@ -3775,6 +3803,10 @@ static void e1000e_update_phy_task(struct work_struct *work) static void e1000_update_phy_info(unsigned long data) { struct e1000_adapter *adapter = (struct e1000_adapter *) data; + + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + schedule_work(&adapter->update_phy_task); } @@ -4149,6 +4181,9 @@ static void e1000_watchdog_task(struct work_struct *work) u32 link, tctl; int tx_pending = 0; + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + link = e1000e_has_link(adapter); if ((netif_carrier_ok(netdev)) && link) { /* Cancel scheduled suspend requests. */ @@ -4337,19 +4372,12 @@ static void e1000_watchdog_task(struct work_struct *work) else ew32(ICS, E1000_ICS_RXDMT0); + /* flush pending descriptors to memory before detecting Tx hang */ + e1000e_flush_descriptors(adapter); + /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = 1; - /* flush partial descriptors to memory before detecting Tx hang */ - if (adapter->flags2 & FLAG2_DMA_BURST) { - ew32(TIDV, adapter->tx_int_delay | E1000_TIDV_FPD); - ew32(RDTR, adapter->rx_int_delay | E1000_RDTR_FPD); - /* - * no need to flush the writes because the timeout code does - * an er32 first thing - */ - } - /* * With 82571 controllers, LAA may be overwritten due to controller * reset from the other port. Set the appropriate LAA in RAR[0] @@ -4887,6 +4915,10 @@ static void e1000_reset_task(struct work_struct *work) struct e1000_adapter *adapter; adapter = container_of(work, struct e1000_adapter, reset_task); + /* don't run the task if already down */ + if (test_bit(__E1000_DOWN, &adapter->state)) + return; + if (!((adapter->flags & FLAG_RX_NEEDS_RESTART) && (adapter->flags & FLAG_RX_RESTART_NOW))) { e1000e_dump(adapter); diff --git a/trunk/drivers/net/forcedeth.c b/trunk/drivers/net/forcedeth.c index af09296ef0dd..9c0b1bac6af6 100644 --- a/trunk/drivers/net/forcedeth.c +++ b/trunk/drivers/net/forcedeth.c @@ -5645,6 +5645,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i goto out_error; } + netif_carrier_off(dev); + dev_info(&pci_dev->dev, "ifname %s, PHY OUI 0x%x @ %d, addr %pM\n", dev->name, np->phy_oui, np->phyaddr, dev->dev_addr); diff --git a/trunk/drivers/net/ixgbe/ixgbe_fcoe.c b/trunk/drivers/net/ixgbe/ixgbe_fcoe.c index 8753980668c7..c54a88274d51 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/trunk/drivers/net/ixgbe/ixgbe_fcoe.c @@ -159,7 +159,7 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, struct scatterlist *sg; unsigned int i, j, dmacount; unsigned int len; - static const unsigned int bufflen = 4096; + static const unsigned int bufflen = IXGBE_FCBUFF_MIN; unsigned int firstoff = 0; unsigned int lastsize; unsigned int thisoff = 0; @@ -254,6 +254,24 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, /* only the last buffer may have non-full bufflen */ lastsize = thisoff + thislen; + /* + * lastsize can not be buffer len. + * If it is then adding another buffer with lastsize = 1. + */ + if (lastsize == bufflen) { + if (j >= IXGBE_BUFFCNT_MAX) { + e_err(drv, "xid=%x:%d,%d,%d:addr=%llx " + "not enough user buffers. We need an extra " + "buffer because lastsize is bufflen.\n", + xid, i, j, dmacount, (u64)addr); + goto out_noddp_free; + } + + ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma); + j++; + lastsize = 1; + } + fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT); fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); @@ -532,6 +550,24 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) e_err(drv, "failed to allocated FCoE DDP pool\n"); spin_lock_init(&fcoe->lock); + + /* Extra buffer to be shared by all DDPs for HW work around */ + fcoe->extra_ddp_buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_ATOMIC); + if (fcoe->extra_ddp_buffer == NULL) { + e_err(drv, "failed to allocated extra DDP buffer\n"); + goto out_extra_ddp_buffer_alloc; + } + + fcoe->extra_ddp_buffer_dma = + dma_map_single(&adapter->pdev->dev, + fcoe->extra_ddp_buffer, + IXGBE_FCBUFF_MIN, + DMA_FROM_DEVICE); + if (dma_mapping_error(&adapter->pdev->dev, + fcoe->extra_ddp_buffer_dma)) { + e_err(drv, "failed to map extra DDP buffer\n"); + goto out_extra_ddp_buffer_dma; + } } /* Enable L2 eth type filter for FCoE */ @@ -581,6 +617,14 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) } } #endif + + return; + +out_extra_ddp_buffer_dma: + kfree(fcoe->extra_ddp_buffer); +out_extra_ddp_buffer_alloc: + pci_pool_destroy(fcoe->pool); + fcoe->pool = NULL; } /** @@ -600,6 +644,11 @@ void ixgbe_cleanup_fcoe(struct ixgbe_adapter *adapter) if (fcoe->pool) { for (i = 0; i < IXGBE_FCOE_DDP_MAX; i++) ixgbe_fcoe_ddp_put(adapter->netdev, i); + dma_unmap_single(&adapter->pdev->dev, + fcoe->extra_ddp_buffer_dma, + IXGBE_FCBUFF_MIN, + DMA_FROM_DEVICE); + kfree(fcoe->extra_ddp_buffer); pci_pool_destroy(fcoe->pool); fcoe->pool = NULL; } diff --git a/trunk/drivers/net/ixgbe/ixgbe_fcoe.h b/trunk/drivers/net/ixgbe/ixgbe_fcoe.h index 4bc2c551c8db..65cc8fb14fe7 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_fcoe.h +++ b/trunk/drivers/net/ixgbe/ixgbe_fcoe.h @@ -70,6 +70,8 @@ struct ixgbe_fcoe { spinlock_t lock; struct pci_pool *pool; struct ixgbe_fcoe_ddp ddp[IXGBE_FCOE_DDP_MAX]; + unsigned char *extra_ddp_buffer; + dma_addr_t extra_ddp_buffer_dma; }; #endif /* _IXGBE_FCOE_H */ diff --git a/trunk/drivers/net/ixgbe/ixgbe_main.c b/trunk/drivers/net/ixgbe/ixgbe_main.c index fbae703b46d7..30f9ccfb4f87 100644 --- a/trunk/drivers/net/ixgbe/ixgbe_main.c +++ b/trunk/drivers/net/ixgbe/ixgbe_main.c @@ -3728,7 +3728,8 @@ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) * We need to try and force an autonegotiation * session, then bring up link. */ - hw->mac.ops.setup_sfp(hw); + if (hw->mac.ops.setup_sfp) + hw->mac.ops.setup_sfp(hw); if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) schedule_work(&adapter->multispeed_fiber_task); } else { @@ -5968,7 +5969,8 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work) unregister_netdev(adapter->netdev); return; } - hw->mac.ops.setup_sfp(hw); + if (hw->mac.ops.setup_sfp) + hw->mac.ops.setup_sfp(hw); if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) /* This will also work for DA Twinax connections */ diff --git a/trunk/drivers/net/pch_gbe/pch_gbe.h b/trunk/drivers/net/pch_gbe/pch_gbe.h index a0c26a99520f..e1e33c80fb25 100644 --- a/trunk/drivers/net/pch_gbe/pch_gbe.h +++ b/trunk/drivers/net/pch_gbe/pch_gbe.h @@ -73,7 +73,7 @@ struct pch_gbe_regs { struct pch_gbe_regs_mac_adr mac_adr[16]; u32 ADDR_MASK; u32 MIIM; - u32 reserve2; + u32 MAC_ADDR_LOAD; u32 RGMII_ST; u32 RGMII_CTRL; u32 reserve3[3]; diff --git a/trunk/drivers/net/pch_gbe/pch_gbe_main.c b/trunk/drivers/net/pch_gbe/pch_gbe_main.c index 4c9a7d4f3fca..b99e90aca37d 100644 --- a/trunk/drivers/net/pch_gbe/pch_gbe_main.c +++ b/trunk/drivers/net/pch_gbe/pch_gbe_main.c @@ -29,6 +29,7 @@ const char pch_driver_version[] = DRV_VERSION; #define PCH_GBE_SHORT_PKT 64 #define DSC_INIT16 0xC000 #define PCH_GBE_DMA_ALIGN 0 +#define PCH_GBE_DMA_PADDING 2 #define PCH_GBE_WATCHDOG_PERIOD (1 * HZ) /* watchdog time */ #define PCH_GBE_COPYBREAK_DEFAULT 256 #define PCH_GBE_PCI_BAR 1 @@ -88,6 +89,12 @@ static unsigned int copybreak __read_mostly = PCH_GBE_COPYBREAK_DEFAULT; static int pch_gbe_mdio_read(struct net_device *netdev, int addr, int reg); static void pch_gbe_mdio_write(struct net_device *netdev, int addr, int reg, int data); + +inline void pch_gbe_mac_load_mac_addr(struct pch_gbe_hw *hw) +{ + iowrite32(0x01, &hw->reg->MAC_ADDR_LOAD); +} + /** * pch_gbe_mac_read_mac_addr - Read MAC address * @hw: Pointer to the HW structure @@ -1365,16 +1372,13 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, struct pch_gbe_buffer *buffer_info; struct pch_gbe_rx_desc *rx_desc; u32 length; - unsigned char tmp_packet[ETH_HLEN]; unsigned int i; unsigned int cleaned_count = 0; bool cleaned = false; - struct sk_buff *skb; + struct sk_buff *skb, *new_skb; u8 dma_status; u16 gbec_status; u32 tcp_ip_status; - u8 skb_copy_flag = 0; - u8 skb_padding_flag = 0; i = rx_ring->next_to_clean; @@ -1418,55 +1422,70 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter, pr_err("Receive CRC Error\n"); } else { /* get receive length */ - /* length convert[-3], padding[-2] */ - length = (rx_desc->rx_words_eob) - 3 - 2; + /* length convert[-3] */ + length = (rx_desc->rx_words_eob) - 3; /* Decide the data conversion method */ if (!adapter->rx_csum) { /* [Header:14][payload] */ - skb_padding_flag = 0; - skb_copy_flag = 1; + if (NET_IP_ALIGN) { + /* Because alignment differs, + * the new_skb is newly allocated, + * and data is copied to new_skb.*/ + new_skb = netdev_alloc_skb(netdev, + length + NET_IP_ALIGN); + if (!new_skb) { + /* dorrop error */ + pr_err("New skb allocation " + "Error\n"); + goto dorrop; + } + skb_reserve(new_skb, NET_IP_ALIGN); + memcpy(new_skb->data, skb->data, + length); + skb = new_skb; + } else { + /* DMA buffer is used as SKB as it is.*/ + buffer_info->skb = NULL; + } } else { /* [Header:14][padding:2][payload] */ - skb_padding_flag = 1; - if (length < copybreak) - skb_copy_flag = 1; - else - skb_copy_flag = 0; - } - - /* Data conversion */ - if (skb_copy_flag) { /* recycle skb */ - struct sk_buff *new_skb; - new_skb = - netdev_alloc_skb(netdev, - length + NET_IP_ALIGN); - if (new_skb) { - if (!skb_padding_flag) { - skb_reserve(new_skb, - NET_IP_ALIGN); + /* The length includes padding length */ + length = length - PCH_GBE_DMA_PADDING; + if ((length < copybreak) || + (NET_IP_ALIGN != PCH_GBE_DMA_PADDING)) { + /* Because alignment differs, + * the new_skb is newly allocated, + * and data is copied to new_skb. + * Padding data is deleted + * at the time of a copy.*/ + new_skb = netdev_alloc_skb(netdev, + length + NET_IP_ALIGN); + if (!new_skb) { + /* dorrop error */ + pr_err("New skb allocation " + "Error\n"); + goto dorrop; } + skb_reserve(new_skb, NET_IP_ALIGN); memcpy(new_skb->data, skb->data, - length); - /* save the skb - * in buffer_info as good */ + ETH_HLEN); + memcpy(&new_skb->data[ETH_HLEN], + &skb->data[ETH_HLEN + + PCH_GBE_DMA_PADDING], + length - ETH_HLEN); skb = new_skb; - } else if (!skb_padding_flag) { - /* dorrop error */ - pr_err("New skb allocation Error\n"); - goto dorrop; + } else { + /* Padding data is deleted + * by moving header data.*/ + memmove(&skb->data[PCH_GBE_DMA_PADDING], + &skb->data[0], ETH_HLEN); + skb_reserve(skb, NET_IP_ALIGN); + buffer_info->skb = NULL; } - } else { - buffer_info->skb = NULL; } - if (skb_padding_flag) { - memcpy(&tmp_packet[0], &skb->data[0], ETH_HLEN); - memcpy(&skb->data[NET_IP_ALIGN], &tmp_packet[0], - ETH_HLEN); - skb_reserve(skb, NET_IP_ALIGN); - - } - + /* The length includes FCS length */ + length = length - ETH_FCS_LEN; /* update status of driver */ adapter->stats.rx_bytes += length; adapter->stats.rx_packets++; @@ -2318,6 +2337,7 @@ static int pch_gbe_probe(struct pci_dev *pdev, netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO; pch_gbe_set_ethtool_ops(netdev); + pch_gbe_mac_load_mac_addr(&adapter->hw); pch_gbe_mac_reset_hw(&adapter->hw); /* setup the private structure */ diff --git a/trunk/drivers/net/r8169.c b/trunk/drivers/net/r8169.c index 59ccf0c5c610..469ab0b7ce31 100644 --- a/trunk/drivers/net/r8169.c +++ b/trunk/drivers/net/r8169.c @@ -3190,6 +3190,8 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_dev_run_wake(pdev)) pm_runtime_put_noidle(&pdev->dev); + netif_carrier_off(dev); + out: return rc; diff --git a/trunk/drivers/net/stmmac/stmmac_main.c b/trunk/drivers/net/stmmac/stmmac_main.c index 34a0af3837f9..0e5f03135b50 100644 --- a/trunk/drivers/net/stmmac/stmmac_main.c +++ b/trunk/drivers/net/stmmac/stmmac_main.c @@ -1560,8 +1560,10 @@ static int stmmac_mac_device_setup(struct net_device *dev) priv->hw = device; - if (device_can_wakeup(priv->device)) + if (device_can_wakeup(priv->device)) { priv->wolopts = WAKE_MAGIC; /* Magic Frame as default */ + enable_irq_wake(dev->irq); + } return 0; } diff --git a/trunk/drivers/net/tg3.c b/trunk/drivers/net/tg3.c index 93b32d366611..06c0e5033656 100644 --- a/trunk/drivers/net/tg3.c +++ b/trunk/drivers/net/tg3.c @@ -11158,7 +11158,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) + if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || + ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !netif_running(dev))) return -EAGAIN; spin_lock_bh(&tp->lock); @@ -11174,7 +11176,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) break; /* We have no PHY */ - if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) + if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) || + ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && + !netif_running(dev))) return -EAGAIN; spin_lock_bh(&tp->lock); diff --git a/trunk/drivers/net/usb/hso.c b/trunk/drivers/net/usb/hso.c index bed8fcedff49..6d83812603b6 100644 --- a/trunk/drivers/net/usb/hso.c +++ b/trunk/drivers/net/usb/hso.c @@ -2628,15 +2628,15 @@ static struct hso_device *hso_create_net_device(struct usb_interface *interface, static void hso_free_tiomget(struct hso_serial *serial) { - struct hso_tiocmget *tiocmget = serial->tiocmget; + struct hso_tiocmget *tiocmget; + if (!serial) + return; + tiocmget = serial->tiocmget; if (tiocmget) { - if (tiocmget->urb) { - usb_free_urb(tiocmget->urb); - tiocmget->urb = NULL; - } + usb_free_urb(tiocmget->urb); + tiocmget->urb = NULL; serial->tiocmget = NULL; kfree(tiocmget); - } } diff --git a/trunk/drivers/net/usb/usbnet.c b/trunk/drivers/net/usb/usbnet.c index ed9a41643ff4..95c41d56631c 100644 --- a/trunk/drivers/net/usb/usbnet.c +++ b/trunk/drivers/net/usb/usbnet.c @@ -931,8 +931,10 @@ kevent (struct work_struct *work) if (urb != NULL) { clear_bit (EVENT_RX_MEMORY, &dev->flags); status = usb_autopm_get_interface(dev->intf); - if (status < 0) + if (status < 0) { + usb_free_urb(urb); goto fail_lowmem; + } if (rx_submit (dev, urb, GFP_KERNEL) == -ENOLINK) resched = 0; usb_autopm_put_interface(dev->intf); diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c b/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c index a9b852be4509..39b6f16c87fa 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -402,72 +402,6 @@ static void iwl3945_accumulative_statistics(struct iwl_priv *priv, } #endif -/** - * iwl3945_good_plcp_health - checks for plcp error. - * - * When the plcp error is exceeding the thresholds, reset the radio - * to improve the throughput. - */ -static bool iwl3945_good_plcp_health(struct iwl_priv *priv, - struct iwl_rx_packet *pkt) -{ - bool rc = true; - struct iwl3945_notif_statistics current_stat; - int combined_plcp_delta; - unsigned int plcp_msec; - unsigned long plcp_received_jiffies; - - if (priv->cfg->base_params->plcp_delta_threshold == - IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) { - IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n"); - return rc; - } - memcpy(¤t_stat, pkt->u.raw, sizeof(struct - iwl3945_notif_statistics)); - /* - * check for plcp_err and trigger radio reset if it exceeds - * the plcp error threshold plcp_delta. - */ - plcp_received_jiffies = jiffies; - plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies - - (long) priv->plcp_jiffies); - priv->plcp_jiffies = plcp_received_jiffies; - /* - * check to make sure plcp_msec is not 0 to prevent division - * by zero. - */ - if (plcp_msec) { - combined_plcp_delta = - (le32_to_cpu(current_stat.rx.ofdm.plcp_err) - - le32_to_cpu(priv->_3945.statistics.rx.ofdm.plcp_err)); - - if ((combined_plcp_delta > 0) && - ((combined_plcp_delta * 100) / plcp_msec) > - priv->cfg->base_params->plcp_delta_threshold) { - /* - * if plcp_err exceed the threshold, the following - * data is printed in csv format: - * Text: plcp_err exceeded %d, - * Received ofdm.plcp_err, - * Current ofdm.plcp_err, - * combined_plcp_delta, - * plcp_msec - */ - IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, " - "%u, %d, %u mSecs\n", - priv->cfg->base_params->plcp_delta_threshold, - le32_to_cpu(current_stat.rx.ofdm.plcp_err), - combined_plcp_delta, plcp_msec); - /* - * Reset the RF radio due to the high plcp - * error rate - */ - rc = false; - } - } - return rc; -} - void iwl3945_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { @@ -2734,7 +2668,6 @@ static struct iwl_lib_ops iwl3945_lib = { .isr_ops = { .isr = iwl_isr_legacy, }, - .check_plcp_health = iwl3945_good_plcp_health, .debugfs_ops = { .rx_stats_read = iwl3945_ucode_rx_stats_read, diff --git a/trunk/drivers/pcmcia/pcmcia_resource.c b/trunk/drivers/pcmcia/pcmcia_resource.c index 0bdda5b3ed55..42fbf1a75576 100644 --- a/trunk/drivers/pcmcia/pcmcia_resource.c +++ b/trunk/drivers/pcmcia/pcmcia_resource.c @@ -518,6 +518,8 @@ int pcmcia_enable_device(struct pcmcia_device *p_dev) flags |= CONF_ENABLE_IOCARD; if (flags & CONF_ENABLE_IOCARD) s->socket.flags |= SS_IOCARD; + if (flags & CONF_ENABLE_ZVCARD) + s->socket.flags |= SS_ZVCARD | SS_IOCARD; if (flags & CONF_ENABLE_SPKR) { s->socket.flags |= SS_SPKR_ENA; status = CCSR_AUDIO_ENA; diff --git a/trunk/drivers/pcmcia/pxa2xx_base.c b/trunk/drivers/pcmcia/pxa2xx_base.c index 3755e7c8c715..2c540542b5af 100644 --- a/trunk/drivers/pcmcia/pxa2xx_base.c +++ b/trunk/drivers/pcmcia/pxa2xx_base.c @@ -215,7 +215,7 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, } #endif -static void pxa2xx_configure_sockets(struct device *dev) +void pxa2xx_configure_sockets(struct device *dev) { struct pcmcia_low_level *ops = dev->platform_data; /* diff --git a/trunk/drivers/pcmcia/pxa2xx_base.h b/trunk/drivers/pcmcia/pxa2xx_base.h index bb62ea87b8f9..b609b45469ed 100644 --- a/trunk/drivers/pcmcia/pxa2xx_base.h +++ b/trunk/drivers/pcmcia/pxa2xx_base.h @@ -1,3 +1,4 @@ int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt); void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops); +void pxa2xx_configure_sockets(struct device *dev); diff --git a/trunk/drivers/pcmcia/pxa2xx_lubbock.c b/trunk/drivers/pcmcia/pxa2xx_lubbock.c index b9f8c8fb42bd..25afe637c657 100644 --- a/trunk/drivers/pcmcia/pxa2xx_lubbock.c +++ b/trunk/drivers/pcmcia/pxa2xx_lubbock.c @@ -226,6 +226,7 @@ int pcmcia_lubbock_init(struct sa1111_dev *sadev) lubbock_set_misc_wr((1 << 15) | (1 << 14), 0); pxa2xx_drv_pcmcia_ops(&lubbock_pcmcia_ops); + pxa2xx_configure_sockets(&sadev->dev); ret = sa1111_pcmcia_add(sadev, &lubbock_pcmcia_ops, pxa2xx_drv_pcmcia_add_one); } diff --git a/trunk/drivers/platform/x86/Kconfig b/trunk/drivers/platform/x86/Kconfig index d163bc2e2b9e..a59af5b24f0a 100644 --- a/trunk/drivers/platform/x86/Kconfig +++ b/trunk/drivers/platform/x86/Kconfig @@ -227,7 +227,7 @@ config SONYPI_COMPAT config IDEAPAD_LAPTOP tristate "Lenovo IdeaPad Laptop Extras" depends on ACPI - depends on RFKILL + depends on RFKILL && INPUT select INPUT_SPARSEKMAP help This is a driver for the rfkill switches on Lenovo IdeaPad netbooks. diff --git a/trunk/drivers/platform/x86/acer-wmi.c b/trunk/drivers/platform/x86/acer-wmi.c index c5c4b8c32eb8..38b34a73866a 100644 --- a/trunk/drivers/platform/x86/acer-wmi.c +++ b/trunk/drivers/platform/x86/acer-wmi.c @@ -84,7 +84,7 @@ MODULE_LICENSE("GPL"); */ #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" -#define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" +#define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" @@ -1280,7 +1280,7 @@ static ssize_t set_bool_threeg(struct device *dev, return -EINVAL; return count; } -static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg, +static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg, set_bool_threeg); static ssize_t show_interface(struct device *dev, struct device_attribute *attr, diff --git a/trunk/drivers/platform/x86/asus_acpi.c b/trunk/drivers/platform/x86/asus_acpi.c index 4633fd8532cc..fe495939c307 100644 --- a/trunk/drivers/platform/x86/asus_acpi.c +++ b/trunk/drivers/platform/x86/asus_acpi.c @@ -1081,14 +1081,8 @@ static int asus_hotk_add_fs(struct acpi_device *device) struct proc_dir_entry *proc; mode_t mode; - /* - * If parameter uid or gid is not changed, keep the default setting for - * our proc entries (-rw-rw-rw-) else, it means we care about security, - * and then set to -rw-rw---- - */ - if ((asus_uid == 0) && (asus_gid == 0)) { - mode = S_IFREG | S_IRUGO | S_IWUGO; + mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP; } else { mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP; printk(KERN_WARNING " asus_uid and asus_gid parameters are " diff --git a/trunk/drivers/platform/x86/dell-laptop.c b/trunk/drivers/platform/x86/dell-laptop.c index 34657f96b5a5..ad24ef36f9f7 100644 --- a/trunk/drivers/platform/x86/dell-laptop.c +++ b/trunk/drivers/platform/x86/dell-laptop.c @@ -290,9 +290,12 @@ static int dell_rfkill_set(void *data, bool blocked) dell_send_request(buffer, 17, 11); /* If the hardware switch controls this radio, and the hardware - switch is disabled, don't allow changing the software state */ + switch is disabled, don't allow changing the software state. + If the hardware switch is reported as not supported, always + fire the SMI to toggle the killswitch. */ if ((hwswitch_state & BIT(hwswitch_bit)) && - !(buffer->output[1] & BIT(16))) { + !(buffer->output[1] & BIT(16)) && + (buffer->output[1] & BIT(0))) { ret = -EINVAL; goto out; } @@ -398,6 +401,23 @@ static const struct file_operations dell_debugfs_fops = { static void dell_update_rfkill(struct work_struct *ignored) { + int status; + + get_buffer(); + dell_send_request(buffer, 17, 11); + status = buffer->output[1]; + release_buffer(); + + /* if hardware rfkill is not supported, set it explicitly */ + if (!(status & BIT(0))) { + if (wifi_rfkill) + dell_rfkill_set((void *)1, !((status & BIT(17)) >> 17)); + if (bluetooth_rfkill) + dell_rfkill_set((void *)2, !((status & BIT(18)) >> 18)); + if (wwan_rfkill) + dell_rfkill_set((void *)3, !((status & BIT(19)) >> 19)); + } + if (wifi_rfkill) dell_rfkill_query(wifi_rfkill, (void *)1); if (bluetooth_rfkill) diff --git a/trunk/drivers/platform/x86/intel_pmic_gpio.c b/trunk/drivers/platform/x86/intel_pmic_gpio.c index 930e62762365..61433d492862 100644 --- a/trunk/drivers/platform/x86/intel_pmic_gpio.c +++ b/trunk/drivers/platform/x86/intel_pmic_gpio.c @@ -60,69 +60,20 @@ enum pmic_gpio_register { #define GPOSW_DOU 0x08 #define GPOSW_RDRV 0x30 +#define GPIO_UPDATE_TYPE 0x80000000 #define NUM_GPIO 24 -struct pmic_gpio_irq { - spinlock_t lock; - u32 trigger[NUM_GPIO]; - u32 dirty; - struct work_struct work; -}; - - struct pmic_gpio { + struct mutex buslock; struct gpio_chip chip; - struct pmic_gpio_irq irqtypes; void *gpiointr; int irq; unsigned irq_base; + unsigned int update_type; + u32 trigger_type; }; -static void pmic_program_irqtype(int gpio, int type) -{ - if (type & IRQ_TYPE_EDGE_RISING) - intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20); - else - intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20); - - if (type & IRQ_TYPE_EDGE_FALLING) - intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10); - else - intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); -}; - -static void pmic_irqtype_work(struct work_struct *work) -{ - struct pmic_gpio_irq *t = - container_of(work, struct pmic_gpio_irq, work); - unsigned long flags; - int i; - u16 type; - - spin_lock_irqsave(&t->lock, flags); - /* As we drop the lock, we may need multiple scans if we race the - pmic_irq_type function */ - while (t->dirty) { - /* - * For each pin that has the dirty bit set send an IPC - * message to configure the hardware via the PMIC - */ - for (i = 0; i < NUM_GPIO; i++) { - if (!(t->dirty & (1 << i))) - continue; - t->dirty &= ~(1 << i); - /* We can't trust the array entry or dirty - once the lock is dropped */ - type = t->trigger[i]; - spin_unlock_irqrestore(&t->lock, flags); - pmic_program_irqtype(i, type); - spin_lock_irqsave(&t->lock, flags); - } - } - spin_unlock_irqrestore(&t->lock, flags); -} - static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { if (offset > 8) { @@ -190,25 +141,24 @@ static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1 << (offset - 16)); } -static int pmic_irq_type(unsigned irq, unsigned type) +/* + * This is called from genirq with pg->buslock locked and + * irq_desc->lock held. We can not access the scu bus here, so we + * store the change and update in the bus_sync_unlock() function below + */ +static int pmic_irq_type(struct irq_data *data, unsigned type) { - struct pmic_gpio *pg = get_irq_chip_data(irq); - u32 gpio = irq - pg->irq_base; - unsigned long flags; + struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); + u32 gpio = data->irq - pg->irq_base; if (gpio >= pg->chip.ngpio) return -EINVAL; - spin_lock_irqsave(&pg->irqtypes.lock, flags); - pg->irqtypes.trigger[gpio] = type; - pg->irqtypes.dirty |= (1 << gpio); - spin_unlock_irqrestore(&pg->irqtypes.lock, flags); - schedule_work(&pg->irqtypes.work); + pg->trigger_type = type; + pg->update_type = gpio | GPIO_UPDATE_TYPE; return 0; } - - static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip); @@ -217,38 +167,32 @@ static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) } /* the gpiointr register is read-clear, so just do nothing. */ -static void pmic_irq_unmask(unsigned irq) -{ -}; +static void pmic_irq_unmask(struct irq_data *data) { } -static void pmic_irq_mask(unsigned irq) -{ -}; +static void pmic_irq_mask(struct irq_data *data) { } static struct irq_chip pmic_irqchip = { .name = "PMIC-GPIO", - .mask = pmic_irq_mask, - .unmask = pmic_irq_unmask, - .set_type = pmic_irq_type, + .irq_mask = pmic_irq_mask, + .irq_unmask = pmic_irq_unmask, + .irq_set_type = pmic_irq_type, }; -static void pmic_irq_handler(unsigned irq, struct irq_desc *desc) +static irqreturn_t pmic_irq_handler(int irq, void *data) { - struct pmic_gpio *pg = (struct pmic_gpio *)get_irq_data(irq); + struct pmic_gpio *pg = data; u8 intsts = *((u8 *)pg->gpiointr + 4); int gpio; + irqreturn_t ret = IRQ_NONE; for (gpio = 0; gpio < 8; gpio++) { if (intsts & (1 << gpio)) { pr_debug("pmic pin %d triggered\n", gpio); generic_handle_irq(pg->irq_base + gpio); + ret = IRQ_HANDLED; } } - - if (desc->chip->irq_eoi) - desc->chip->irq_eoi(irq_get_irq_data(irq)); - else - dev_warn(pg->chip.dev, "missing EOI handler for irq %d\n", irq); + return ret; } static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) @@ -297,8 +241,7 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) pg->chip.can_sleep = 1; pg->chip.dev = dev; - INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work); - spin_lock_init(&pg->irqtypes.lock); + mutex_init(&pg->buslock); pg->chip.dev = dev; retval = gpiochip_add(&pg->chip); @@ -306,8 +249,13 @@ static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) printk(KERN_ERR "%s: Can not add pmic gpio chip.\n", __func__); goto err; } - set_irq_data(pg->irq, pg); - set_irq_chained_handler(pg->irq, pmic_irq_handler); + + retval = request_irq(pg->irq, pmic_irq_handler, 0, "pmic", pg); + if (retval) { + printk(KERN_WARNING "pmic: Interrupt request failed\n"); + goto err; + } + for (i = 0; i < 8; i++) { set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip, handle_simple_irq, "demux"); diff --git a/trunk/drivers/platform/x86/tc1100-wmi.c b/trunk/drivers/platform/x86/tc1100-wmi.c index 1fe0f1feff71..865ef78d6f1a 100644 --- a/trunk/drivers/platform/x86/tc1100-wmi.c +++ b/trunk/drivers/platform/x86/tc1100-wmi.c @@ -162,7 +162,7 @@ set_bool_##value(struct device *dev, struct device_attribute *attr, \ return -EINVAL; \ return count; \ } \ -static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \ +static DEVICE_ATTR(value, S_IRUGO | S_IWUSR, \ show_bool_##value, set_bool_##value); show_set_bool(wireless, TC1100_INSTANCE_WIRELESS); diff --git a/trunk/drivers/platform/x86/thinkpad_acpi.c b/trunk/drivers/platform/x86/thinkpad_acpi.c index dd599585c6a9..eb9922385ef8 100644 --- a/trunk/drivers/platform/x86/thinkpad_acpi.c +++ b/trunk/drivers/platform/x86/thinkpad_acpi.c @@ -2275,16 +2275,12 @@ static void tpacpi_input_send_key(const unsigned int scancode) if (keycode != KEY_RESERVED) { mutex_lock(&tpacpi_inputdev_send_mutex); + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); input_report_key(tpacpi_inputdev, keycode, 1); - if (keycode == KEY_UNKNOWN) - input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, - scancode); input_sync(tpacpi_inputdev); + input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); input_report_key(tpacpi_inputdev, keycode, 0); - if (keycode == KEY_UNKNOWN) - input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, - scancode); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); diff --git a/trunk/drivers/rtc/Kconfig b/trunk/drivers/rtc/Kconfig index cdd97192dc69..4941cade319f 100644 --- a/trunk/drivers/rtc/Kconfig +++ b/trunk/drivers/rtc/Kconfig @@ -97,6 +97,18 @@ config RTC_INTF_DEV If unsure, say Y. +config RTC_INTF_DEV_UIE_EMUL + bool "RTC UIE emulation on dev interface" + depends on RTC_INTF_DEV + help + Provides an emulation for RTC_UIE if the underlying rtc chip + driver does not expose RTC_UIE ioctls. Those requests generate + once-per-second update interrupts, used for synchronization. + + The emulation code will read the time from the hardware + clock several times per second, please enable this option + only if you know that you really need it. + config RTC_DRV_TEST tristate "Test driver/device" help diff --git a/trunk/drivers/rtc/interface.c b/trunk/drivers/rtc/interface.c index a0c01967244d..cb2f0728fd70 100644 --- a/trunk/drivers/rtc/interface.c +++ b/trunk/drivers/rtc/interface.c @@ -209,9 +209,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) } if (err) - return err; - - if (!rtc->ops) + /* nothing */; + else if (!rtc->ops) err = -ENODEV; else if (!rtc->ops->alarm_irq_enable) err = -EINVAL; @@ -229,6 +228,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) if (err) return err; +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + if (enabled == 0 && rtc->uie_irq_active) { + mutex_unlock(&rtc->ops_lock); + return rtc_dev_update_irq_enable_emul(rtc, 0); + } +#endif /* make sure we're changing state */ if (rtc->uie_rtctimer.enabled == enabled) goto out; @@ -248,6 +253,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) out: mutex_unlock(&rtc->ops_lock); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + /* + * Enable emulation if the driver did not provide + * the update_irq_enable function pointer or if returned + * -EINVAL to signal that it has been configured without + * interrupts or that are not available at the moment. + */ + if (err == -EINVAL) + err = rtc_dev_update_irq_enable_emul(rtc, enabled); +#endif return err; } @@ -263,7 +278,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable); * * Triggers the registered irq_task function callback. */ -static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) +void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) { unsigned long flags; diff --git a/trunk/drivers/rtc/rtc-dev.c b/trunk/drivers/rtc/rtc-dev.c index 37c3cc1b3dd5..d0e06edb14c5 100644 --- a/trunk/drivers/rtc/rtc-dev.c +++ b/trunk/drivers/rtc/rtc-dev.c @@ -46,6 +46,105 @@ static int rtc_dev_open(struct inode *inode, struct file *file) return err; } +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL +/* + * Routine to poll RTC seconds field for change as often as possible, + * after first RTC_UIE use timer to reduce polling + */ +static void rtc_uie_task(struct work_struct *work) +{ + struct rtc_device *rtc = + container_of(work, struct rtc_device, uie_task); + struct rtc_time tm; + int num = 0; + int err; + + err = rtc_read_time(rtc, &tm); + + spin_lock_irq(&rtc->irq_lock); + if (rtc->stop_uie_polling || err) { + rtc->uie_task_active = 0; + } else if (rtc->oldsecs != tm.tm_sec) { + num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; + rtc->oldsecs = tm.tm_sec; + rtc->uie_timer.expires = jiffies + HZ - (HZ/10); + rtc->uie_timer_active = 1; + rtc->uie_task_active = 0; + add_timer(&rtc->uie_timer); + } else if (schedule_work(&rtc->uie_task) == 0) { + rtc->uie_task_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + if (num) + rtc_handle_legacy_irq(rtc, num, RTC_UF); +} +static void rtc_uie_timer(unsigned long data) +{ + struct rtc_device *rtc = (struct rtc_device *)data; + unsigned long flags; + + spin_lock_irqsave(&rtc->irq_lock, flags); + rtc->uie_timer_active = 0; + rtc->uie_task_active = 1; + if ((schedule_work(&rtc->uie_task) == 0)) + rtc->uie_task_active = 0; + spin_unlock_irqrestore(&rtc->irq_lock, flags); +} + +static int clear_uie(struct rtc_device *rtc) +{ + spin_lock_irq(&rtc->irq_lock); + if (rtc->uie_irq_active) { + rtc->stop_uie_polling = 1; + if (rtc->uie_timer_active) { + spin_unlock_irq(&rtc->irq_lock); + del_timer_sync(&rtc->uie_timer); + spin_lock_irq(&rtc->irq_lock); + rtc->uie_timer_active = 0; + } + if (rtc->uie_task_active) { + spin_unlock_irq(&rtc->irq_lock); + flush_scheduled_work(); + spin_lock_irq(&rtc->irq_lock); + } + rtc->uie_irq_active = 0; + } + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +static int set_uie(struct rtc_device *rtc) +{ + struct rtc_time tm; + int err; + + err = rtc_read_time(rtc, &tm); + if (err) + return err; + spin_lock_irq(&rtc->irq_lock); + if (!rtc->uie_irq_active) { + rtc->uie_irq_active = 1; + rtc->stop_uie_polling = 0; + rtc->oldsecs = tm.tm_sec; + rtc->uie_task_active = 1; + if (schedule_work(&rtc->uie_task) == 0) + rtc->uie_task_active = 0; + } + rtc->irq_data = 0; + spin_unlock_irq(&rtc->irq_lock); + return 0; +} + +int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) +{ + if (enabled) + return set_uie(rtc); + else + return clear_uie(rtc); +} +EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); + +#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ static ssize_t rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -387,6 +486,11 @@ void rtc_dev_prepare(struct rtc_device *rtc) rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + INIT_WORK(&rtc->uie_task, rtc_uie_task); + setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); +#endif + cdev_init(&rtc->char_dev, &rtc_dev_fops); rtc->char_dev.owner = rtc->owner; } diff --git a/trunk/drivers/s390/block/dasd_eckd.c b/trunk/drivers/s390/block/dasd_eckd.c index 318672d05563..a9fe23d5bd0f 100644 --- a/trunk/drivers/s390/block/dasd_eckd.c +++ b/trunk/drivers/s390/block/dasd_eckd.c @@ -72,7 +72,7 @@ static struct dasd_discipline dasd_eckd_discipline; static struct ccw_device_id dasd_eckd_ids[] = { { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1}, { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2}, - { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3}, + { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3380, 0), .driver_info = 0x3}, { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4}, { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5}, { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6}, diff --git a/trunk/drivers/scsi/qla2xxx/qla_attr.c b/trunk/drivers/scsi/qla2xxx/qla_attr.c index 44578b56ad0a..d3e58d763b43 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_attr.c +++ b/trunk/drivers/scsi/qla2xxx/qla_attr.c @@ -1561,6 +1561,7 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) { struct Scsi_Host *host = rport_to_shost(rport); fc_port_t *fcport = *(fc_port_t **)rport->dd_data; + unsigned long flags; if (!fcport) return; @@ -1573,10 +1574,10 @@ qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) * Transport has effectively 'deleted' the rport, clear * all local references. */ - spin_lock_irq(host->host_lock); + spin_lock_irqsave(host->host_lock, flags); fcport->rport = fcport->drport = NULL; *((fc_port_t **)rport->dd_data) = NULL; - spin_unlock_irq(host->host_lock); + spin_unlock_irqrestore(host->host_lock, flags); if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) return; diff --git a/trunk/drivers/scsi/qla2xxx/qla_init.c b/trunk/drivers/scsi/qla2xxx/qla_init.c index f948e1a73aec..d9479c3fe5f8 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_init.c +++ b/trunk/drivers/scsi/qla2xxx/qla_init.c @@ -2505,11 +2505,12 @@ qla2x00_rport_del(void *data) { fc_port_t *fcport = data; struct fc_rport *rport; + unsigned long flags; - spin_lock_irq(fcport->vha->host->host_lock); + spin_lock_irqsave(fcport->vha->host->host_lock, flags); rport = fcport->drport ? fcport->drport: fcport->rport; fcport->drport = NULL; - spin_unlock_irq(fcport->vha->host->host_lock); + spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); if (rport) fc_remote_port_delete(rport); } @@ -2879,6 +2880,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) struct fc_rport_identifiers rport_ids; struct fc_rport *rport; struct qla_hw_data *ha = vha->hw; + unsigned long flags; qla2x00_rport_del(fcport); @@ -2893,9 +2895,9 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) "Unable to allocate fc remote port!\n"); return; } - spin_lock_irq(fcport->vha->host->host_lock); + spin_lock_irqsave(fcport->vha->host->host_lock, flags); *((fc_port_t **)rport->dd_data) = fcport; - spin_unlock_irq(fcport->vha->host->host_lock); + spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); rport->supported_classes = fcport->supported_classes; diff --git a/trunk/drivers/scsi/qla2xxx/qla_os.c b/trunk/drivers/scsi/qla2xxx/qla_os.c index c194c23ca1fb..f27724d76cf6 100644 --- a/trunk/drivers/scsi/qla2xxx/qla_os.c +++ b/trunk/drivers/scsi/qla2xxx/qla_os.c @@ -562,7 +562,6 @@ qla2xxx_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *) } if (atomic_read(&fcport->state) != FCS_ONLINE) { if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || - atomic_read(&fcport->state) == FCS_DEVICE_LOST || atomic_read(&base_vha->loop_state) == LOOP_DEAD) { cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; @@ -2513,6 +2512,7 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, { struct fc_rport *rport; scsi_qla_host_t *base_vha; + unsigned long flags; if (!fcport->rport) return; @@ -2520,9 +2520,9 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, rport = fcport->rport; if (defer) { base_vha = pci_get_drvdata(vha->hw->pdev); - spin_lock_irq(vha->host->host_lock); + spin_lock_irqsave(vha->host->host_lock, flags); fcport->drport = rport; - spin_unlock_irq(vha->host->host_lock); + spin_unlock_irqrestore(vha->host->host_lock, flags); set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); qla2xxx_wake_dpc(base_vha); } else @@ -3282,10 +3282,10 @@ qla2x00_do_dpc(void *data) set_user_nice(current, -20); + set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { DEBUG3(printk("qla2x00: DPC handler sleeping\n")); - set_current_state(TASK_INTERRUPTIBLE); schedule(); __set_current_state(TASK_RUNNING); @@ -3454,7 +3454,9 @@ qla2x00_do_dpc(void *data) qla2x00_do_dpc_all_vps(base_vha); ha->dpc_active = 0; + set_current_state(TASK_INTERRUPTIBLE); } /* End of while(1) */ + __set_current_state(TASK_RUNNING); DEBUG(printk("scsi(%ld): DPC handler exiting\n", base_vha->host_no)); diff --git a/trunk/drivers/scsi/scsi_debug.c b/trunk/drivers/scsi/scsi_debug.c index 7b310934efed..a6b2d72022fc 100644 --- a/trunk/drivers/scsi/scsi_debug.c +++ b/trunk/drivers/scsi/scsi_debug.c @@ -1671,7 +1671,7 @@ static int do_device_access(struct scsi_cmnd *scmd, unsigned long long lba, unsigned int num, int write) { int ret; - unsigned int block, rest = 0; + unsigned long long block, rest = 0; int (*func)(struct scsi_cmnd *, unsigned char *, int); func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; diff --git a/trunk/drivers/spi/pxa2xx_spi_pci.c b/trunk/drivers/spi/pxa2xx_spi_pci.c index 351d8a375b57..19752b09e155 100644 --- a/trunk/drivers/spi/pxa2xx_spi_pci.c +++ b/trunk/drivers/spi/pxa2xx_spi_pci.c @@ -7,10 +7,9 @@ #include #include -struct awesome_struct { +struct ce4100_info { struct ssp_device ssp; - struct platform_device spi_pdev; - struct pxa2xx_spi_master spi_pdata; + struct platform_device *spi_pdev; }; static DEFINE_MUTEX(ssp_lock); @@ -51,23 +50,15 @@ void pxa_ssp_free(struct ssp_device *ssp) } EXPORT_SYMBOL_GPL(pxa_ssp_free); -static void plat_dev_release(struct device *dev) -{ - struct awesome_struct *as = container_of(dev, - struct awesome_struct, spi_pdev.dev); - - of_device_node_put(&as->spi_pdev.dev); -} - static int __devinit ce4100_spi_probe(struct pci_dev *dev, const struct pci_device_id *ent) { int ret; resource_size_t phys_beg; resource_size_t phys_len; - struct awesome_struct *spi_info; + struct ce4100_info *spi_info; struct platform_device *pdev; - struct pxa2xx_spi_master *spi_pdata; + struct pxa2xx_spi_master spi_pdata; struct ssp_device *ssp; ret = pci_enable_device(dev); @@ -84,33 +75,30 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev, return ret; } + pdev = platform_device_alloc("pxa2xx-spi", dev->devfn); spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL); - if (!spi_info) { + if (!pdev || !spi_info ) { ret = -ENOMEM; - goto err_kz; + goto err_nomem; } - ssp = &spi_info->ssp; - pdev = &spi_info->spi_pdev; - spi_pdata = &spi_info->spi_pdata; + memset(&spi_pdata, 0, sizeof(spi_pdata)); + spi_pdata.num_chipselect = dev->devfn; - pdev->name = "pxa2xx-spi"; - pdev->id = dev->devfn; - pdev->dev.parent = &dev->dev; - pdev->dev.platform_data = &spi_info->spi_pdata; + ret = platform_device_add_data(pdev, &spi_pdata, sizeof(spi_pdata)); + if (ret) + goto err_nomem; + pdev->dev.parent = &dev->dev; #ifdef CONFIG_OF pdev->dev.of_node = dev->dev.of_node; #endif - pdev->dev.release = plat_dev_release; - - spi_pdata->num_chipselect = dev->devfn; - + ssp = &spi_info->ssp; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = ioremap(phys_beg, phys_len); if (!ssp->mmio_base) { dev_err(&pdev->dev, "failed to ioremap() registers\n"); ret = -EIO; - goto err_remap; + goto err_nomem; } ssp->irq = dev->irq; ssp->port_id = pdev->id; @@ -122,7 +110,7 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev, pci_set_drvdata(dev, spi_info); - ret = platform_device_register(pdev); + ret = platform_device_add(pdev); if (ret) goto err_dev_add; @@ -135,27 +123,21 @@ static int __devinit ce4100_spi_probe(struct pci_dev *dev, mutex_unlock(&ssp_lock); iounmap(ssp->mmio_base); -err_remap: - kfree(spi_info); - -err_kz: +err_nomem: release_mem_region(phys_beg, phys_len); - + platform_device_put(pdev); + kfree(spi_info); return ret; } static void __devexit ce4100_spi_remove(struct pci_dev *dev) { - struct awesome_struct *spi_info; - struct platform_device *pdev; + struct ce4100_info *spi_info; struct ssp_device *ssp; spi_info = pci_get_drvdata(dev); - ssp = &spi_info->ssp; - pdev = &spi_info->spi_pdev; - - platform_device_unregister(pdev); + platform_device_unregister(spi_info->spi_pdev); iounmap(ssp->mmio_base); release_mem_region(pci_resource_start(dev, 0), @@ -171,7 +153,6 @@ static void __devexit ce4100_spi_remove(struct pci_dev *dev) } static struct pci_device_id ce4100_spi_devices[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) }, { }, }; diff --git a/trunk/drivers/target/Makefile b/trunk/drivers/target/Makefile index 5cfd70819f08..973bb190ef57 100644 --- a/trunk/drivers/target/Makefile +++ b/trunk/drivers/target/Makefile @@ -13,8 +13,7 @@ target_core_mod-y := target_core_configfs.o \ target_core_transport.o \ target_core_cdb.o \ target_core_ua.o \ - target_core_rd.o \ - target_core_mib.o + target_core_rd.o obj-$(CONFIG_TARGET_CORE) += target_core_mod.o diff --git a/trunk/drivers/target/target_core_configfs.c b/trunk/drivers/target/target_core_configfs.c index 2764510798b0..caf8dc18ee0a 100644 --- a/trunk/drivers/target/target_core_configfs.c +++ b/trunk/drivers/target/target_core_configfs.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -1971,13 +1970,35 @@ static void target_core_dev_release(struct config_item *item) { struct se_subsystem_dev *se_dev = container_of(to_config_group(item), struct se_subsystem_dev, se_dev_group); - struct config_group *dev_cg; - - if (!(se_dev)) - return; + struct se_hba *hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); + struct se_subsystem_api *t = hba->transport; + struct config_group *dev_cg = &se_dev->se_dev_group; - dev_cg = &se_dev->se_dev_group; kfree(dev_cg->default_groups); + /* + * This pointer will set when the storage is enabled with: + *`echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` + */ + if (se_dev->se_dev_ptr) { + printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_" + "virtual_device() for se_dev_ptr: %p\n", + se_dev->se_dev_ptr); + + se_free_virtual_device(se_dev->se_dev_ptr, hba); + } else { + /* + * Release struct se_subsystem_dev->se_dev_su_ptr.. + */ + printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_" + "device() for se_dev_su_ptr: %p\n", + se_dev->se_dev_su_ptr); + + t->free_device(se_dev->se_dev_su_ptr); + } + + printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem" + "_dev_t: %p\n", se_dev); + kfree(se_dev); } static ssize_t target_core_dev_show(struct config_item *item, @@ -2140,7 +2161,16 @@ static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = { NULL, }; +static void target_core_alua_lu_gp_release(struct config_item *item) +{ + struct t10_alua_lu_gp *lu_gp = container_of(to_config_group(item), + struct t10_alua_lu_gp, lu_gp_group); + + core_alua_free_lu_gp(lu_gp); +} + static struct configfs_item_operations target_core_alua_lu_gp_ops = { + .release = target_core_alua_lu_gp_release, .show_attribute = target_core_alua_lu_gp_attr_show, .store_attribute = target_core_alua_lu_gp_attr_store, }; @@ -2191,9 +2221,11 @@ static void target_core_alua_drop_lu_gp( printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Logical Unit" " Group: core/alua/lu_gps/%s, ID: %hu\n", config_item_name(item), lu_gp->lu_gp_id); - + /* + * core_alua_free_lu_gp() is called from target_core_alua_lu_gp_ops->release() + * -> target_core_alua_lu_gp_release() + */ config_item_put(item); - core_alua_free_lu_gp(lu_gp); } static struct configfs_group_operations target_core_alua_lu_gps_group_ops = { @@ -2549,7 +2581,16 @@ static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = { NULL, }; +static void target_core_alua_tg_pt_gp_release(struct config_item *item) +{ + struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(to_config_group(item), + struct t10_alua_tg_pt_gp, tg_pt_gp_group); + + core_alua_free_tg_pt_gp(tg_pt_gp); +} + static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = { + .release = target_core_alua_tg_pt_gp_release, .show_attribute = target_core_alua_tg_pt_gp_attr_show, .store_attribute = target_core_alua_tg_pt_gp_attr_store, }; @@ -2602,9 +2643,11 @@ static void target_core_alua_drop_tg_pt_gp( printk(KERN_INFO "Target_Core_ConfigFS: Releasing ALUA Target Port" " Group: alua/tg_pt_gps/%s, ID: %hu\n", config_item_name(item), tg_pt_gp->tg_pt_gp_id); - + /* + * core_alua_free_tg_pt_gp() is called from target_core_alua_tg_pt_gp_ops->release() + * -> target_core_alua_tg_pt_gp_release(). + */ config_item_put(item); - core_alua_free_tg_pt_gp(tg_pt_gp); } static struct configfs_group_operations target_core_alua_tg_pt_gps_group_ops = { @@ -2771,13 +2814,11 @@ static void target_core_drop_subdev( struct se_subsystem_api *t; struct config_item *df_item; struct config_group *dev_cg, *tg_pt_gp_cg; - int i, ret; + int i; hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); - if (mutex_lock_interruptible(&hba->hba_access_mutex)) - goto out; - + mutex_lock(&hba->hba_access_mutex); t = hba->transport; spin_lock(&se_global->g_device_lock); @@ -2791,7 +2832,10 @@ static void target_core_drop_subdev( config_item_put(df_item); } kfree(tg_pt_gp_cg->default_groups); - core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); + /* + * core_alua_free_tg_pt_gp() is called from ->default_tg_pt_gp + * directly from target_core_alua_tg_pt_gp_release(). + */ T10_ALUA(se_dev)->default_tg_pt_gp = NULL; dev_cg = &se_dev->se_dev_group; @@ -2800,38 +2844,12 @@ static void target_core_drop_subdev( dev_cg->default_groups[i] = NULL; config_item_put(df_item); } - - config_item_put(item); /* - * This pointer will set when the storage is enabled with: - * `echo 1 > $CONFIGFS/core/$HBA/$DEV/dev_enable` + * The releasing of se_dev and associated se_dev->se_dev_ptr is done + * from target_core_dev_item_ops->release() ->target_core_dev_release(). */ - if (se_dev->se_dev_ptr) { - printk(KERN_INFO "Target_Core_ConfigFS: Calling se_free_" - "virtual_device() for se_dev_ptr: %p\n", - se_dev->se_dev_ptr); - - ret = se_free_virtual_device(se_dev->se_dev_ptr, hba); - if (ret < 0) - goto hba_out; - } else { - /* - * Release struct se_subsystem_dev->se_dev_su_ptr.. - */ - printk(KERN_INFO "Target_Core_ConfigFS: Calling t->free_" - "device() for se_dev_su_ptr: %p\n", - se_dev->se_dev_su_ptr); - - t->free_device(se_dev->se_dev_su_ptr); - } - - printk(KERN_INFO "Target_Core_ConfigFS: Deallocating se_subsystem" - "_dev_t: %p\n", se_dev); - -hba_out: + config_item_put(item); mutex_unlock(&hba->hba_access_mutex); -out: - kfree(se_dev); } static struct configfs_group_operations target_core_hba_group_ops = { @@ -2914,6 +2932,13 @@ SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR); CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group); +static void target_core_hba_release(struct config_item *item) +{ + struct se_hba *hba = container_of(to_config_group(item), + struct se_hba, hba_group); + core_delete_hba(hba); +} + static struct configfs_attribute *target_core_hba_attrs[] = { &target_core_hba_hba_info.attr, &target_core_hba_hba_mode.attr, @@ -2921,6 +2946,7 @@ static struct configfs_attribute *target_core_hba_attrs[] = { }; static struct configfs_item_operations target_core_hba_item_ops = { + .release = target_core_hba_release, .show_attribute = target_core_hba_attr_show, .store_attribute = target_core_hba_attr_store, }; @@ -2997,10 +3023,11 @@ static void target_core_call_delhbafromtarget( struct config_group *group, struct config_item *item) { - struct se_hba *hba = item_to_hba(item); - + /* + * core_delete_hba() is called from target_core_hba_item_ops->release() + * -> target_core_hba_release() + */ config_item_put(item); - core_delete_hba(hba); } static struct configfs_group_operations target_core_group_ops = { @@ -3022,7 +3049,6 @@ static int target_core_init_configfs(void) struct config_group *target_cg, *hba_cg = NULL, *alua_cg = NULL; struct config_group *lu_gp_cg = NULL; struct configfs_subsystem *subsys; - struct proc_dir_entry *scsi_target_proc = NULL; struct t10_alua_lu_gp *lu_gp; int ret; @@ -3128,21 +3154,10 @@ static int target_core_init_configfs(void) if (core_dev_setup_virtual_lun0() < 0) goto out; - scsi_target_proc = proc_mkdir("scsi_target", 0); - if (!(scsi_target_proc)) { - printk(KERN_ERR "proc_mkdir(scsi_target, 0) failed\n"); - goto out; - } - ret = init_scsi_target_mib(); - if (ret < 0) - goto out; - return 0; out: configfs_unregister_subsystem(subsys); - if (scsi_target_proc) - remove_proc_entry("scsi_target", 0); core_dev_release_virtual_lun0(); rd_module_exit(); out_global: @@ -3178,8 +3193,7 @@ static void target_core_exit_configfs(void) config_item_put(item); } kfree(lu_gp_cg->default_groups); - core_alua_free_lu_gp(se_global->default_lu_gp); - se_global->default_lu_gp = NULL; + lu_gp_cg->default_groups = NULL; alua_cg = &se_global->alua_group; for (i = 0; alua_cg->default_groups[i]; i++) { @@ -3188,6 +3202,7 @@ static void target_core_exit_configfs(void) config_item_put(item); } kfree(alua_cg->default_groups); + alua_cg->default_groups = NULL; hba_cg = &se_global->target_core_hbagroup; for (i = 0; hba_cg->default_groups[i]; i++) { @@ -3196,20 +3211,20 @@ static void target_core_exit_configfs(void) config_item_put(item); } kfree(hba_cg->default_groups); - - for (i = 0; subsys->su_group.default_groups[i]; i++) { - item = &subsys->su_group.default_groups[i]->cg_item; - subsys->su_group.default_groups[i] = NULL; - config_item_put(item); - } + hba_cg->default_groups = NULL; + /* + * We expect subsys->su_group.default_groups to be released + * by configfs subsystem provider logic.. + */ + configfs_unregister_subsystem(subsys); kfree(subsys->su_group.default_groups); - configfs_unregister_subsystem(subsys); + core_alua_free_lu_gp(se_global->default_lu_gp); + se_global->default_lu_gp = NULL; + printk(KERN_INFO "TARGET_CORE[0]: Released ConfigFS Fabric" " Infrastructure\n"); - remove_scsi_target_mib(); - remove_proc_entry("scsi_target", 0); core_dev_release_virtual_lun0(); rd_module_exit(); release_se_global(); diff --git a/trunk/drivers/target/target_core_device.c b/trunk/drivers/target/target_core_device.c index 317ce58d426d..5da051a07fa3 100644 --- a/trunk/drivers/target/target_core_device.c +++ b/trunk/drivers/target/target_core_device.c @@ -373,11 +373,11 @@ int core_update_device_list_for_node( /* * deve->se_lun_acl will be NULL for demo-mode created LUNs * that have not been explictly concerted to MappedLUNs -> - * struct se_lun_acl. + * struct se_lun_acl, but we remove deve->alua_port_list from + * port->sep_alua_list. This also means that active UAs and + * NodeACL context specific PR metadata for demo-mode + * MappedLUN *deve will be released below.. */ - if (!(deve->se_lun_acl)) - return 0; - spin_lock_bh(&port->sep_alua_lock); list_del(&deve->alua_port_list); spin_unlock_bh(&port->sep_alua_lock); @@ -395,12 +395,14 @@ int core_update_device_list_for_node( printk(KERN_ERR "struct se_dev_entry->se_lun_acl" " already set for demo mode -> explict" " LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); return -1; } if (deve->se_lun != lun) { printk(KERN_ERR "struct se_dev_entry->se_lun does" " match passed struct se_lun for demo mode" " -> explict LUN ACL transition\n"); + spin_unlock_irq(&nacl->device_list_lock); return -1; } deve->se_lun_acl = lun_acl; @@ -865,9 +867,6 @@ static void se_dev_stop(struct se_device *dev) } } spin_unlock(&hba->device_lock); - - while (atomic_read(&hba->dev_mib_access_count)) - cpu_relax(); } int se_dev_check_online(struct se_device *dev) diff --git a/trunk/drivers/target/target_core_fabric_configfs.c b/trunk/drivers/target/target_core_fabric_configfs.c index 32b148d7e261..b65d1c8e7740 100644 --- a/trunk/drivers/target/target_core_fabric_configfs.c +++ b/trunk/drivers/target/target_core_fabric_configfs.c @@ -214,12 +214,22 @@ TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR); CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group); +static void target_fabric_mappedlun_release(struct config_item *item) +{ + struct se_lun_acl *lacl = container_of(to_config_group(item), + struct se_lun_acl, se_lun_group); + struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg; + + core_dev_free_initiator_node_lun_acl(se_tpg, lacl); +} + static struct configfs_attribute *target_fabric_mappedlun_attrs[] = { &target_fabric_mappedlun_write_protect.attr, NULL, }; static struct configfs_item_operations target_fabric_mappedlun_item_ops = { + .release = target_fabric_mappedlun_release, .show_attribute = target_fabric_mappedlun_attr_show, .store_attribute = target_fabric_mappedlun_attr_store, .allow_link = target_fabric_mappedlun_link, @@ -337,15 +347,21 @@ static void target_fabric_drop_mappedlun( struct config_group *group, struct config_item *item) { - struct se_lun_acl *lacl = container_of(to_config_group(item), - struct se_lun_acl, se_lun_group); - struct se_portal_group *se_tpg = lacl->se_lun_nacl->se_tpg; - config_item_put(item); - core_dev_free_initiator_node_lun_acl(se_tpg, lacl); +} + +static void target_fabric_nacl_base_release(struct config_item *item) +{ + struct se_node_acl *se_nacl = container_of(to_config_group(item), + struct se_node_acl, acl_group); + struct se_portal_group *se_tpg = se_nacl->se_tpg; + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + + tf->tf_ops.fabric_drop_nodeacl(se_nacl); } static struct configfs_item_operations target_fabric_nacl_base_item_ops = { + .release = target_fabric_nacl_base_release, .show_attribute = target_fabric_nacl_base_attr_show, .store_attribute = target_fabric_nacl_base_attr_store, }; @@ -404,9 +420,6 @@ static void target_fabric_drop_nodeacl( struct config_group *group, struct config_item *item) { - struct se_portal_group *se_tpg = container_of(group, - struct se_portal_group, tpg_acl_group); - struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_node_acl *se_nacl = container_of(to_config_group(item), struct se_node_acl, acl_group); struct config_item *df_item; @@ -419,9 +432,10 @@ static void target_fabric_drop_nodeacl( nacl_cg->default_groups[i] = NULL; config_item_put(df_item); } - + /* + * struct se_node_acl free is done in target_fabric_nacl_base_release() + */ config_item_put(item); - tf->tf_ops.fabric_drop_nodeacl(se_nacl); } static struct configfs_group_operations target_fabric_nacl_group_ops = { @@ -437,7 +451,18 @@ TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL); CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group); +static void target_fabric_np_base_release(struct config_item *item) +{ + struct se_tpg_np *se_tpg_np = container_of(to_config_group(item), + struct se_tpg_np, tpg_np_group); + struct se_portal_group *se_tpg = se_tpg_np->tpg_np_parent; + struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + + tf->tf_ops.fabric_drop_np(se_tpg_np); +} + static struct configfs_item_operations target_fabric_np_base_item_ops = { + .release = target_fabric_np_base_release, .show_attribute = target_fabric_np_base_attr_show, .store_attribute = target_fabric_np_base_attr_store, }; @@ -466,6 +491,7 @@ static struct config_group *target_fabric_make_np( if (!(se_tpg_np) || IS_ERR(se_tpg_np)) return ERR_PTR(-EINVAL); + se_tpg_np->tpg_np_parent = se_tpg; config_group_init_type_name(&se_tpg_np->tpg_np_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_np_base_cit); @@ -476,14 +502,10 @@ static void target_fabric_drop_np( struct config_group *group, struct config_item *item) { - struct se_portal_group *se_tpg = container_of(group, - struct se_portal_group, tpg_np_group); - struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; - struct se_tpg_np *se_tpg_np = container_of(to_config_group(item), - struct se_tpg_np, tpg_np_group); - + /* + * struct se_tpg_np is released via target_fabric_np_base_release() + */ config_item_put(item); - tf->tf_ops.fabric_drop_np(se_tpg_np); } static struct configfs_group_operations target_fabric_np_group_ops = { @@ -814,7 +836,18 @@ TF_CIT_SETUP(tpg_param, &target_fabric_tpg_param_item_ops, NULL, NULL); */ CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group); +static void target_fabric_tpg_release(struct config_item *item) +{ + struct se_portal_group *se_tpg = container_of(to_config_group(item), + struct se_portal_group, tpg_group); + struct se_wwn *wwn = se_tpg->se_tpg_wwn; + struct target_fabric_configfs *tf = wwn->wwn_tf; + + tf->tf_ops.fabric_drop_tpg(se_tpg); +} + static struct configfs_item_operations target_fabric_tpg_base_item_ops = { + .release = target_fabric_tpg_release, .show_attribute = target_fabric_tpg_attr_show, .store_attribute = target_fabric_tpg_attr_store, }; @@ -872,8 +905,6 @@ static void target_fabric_drop_tpg( struct config_group *group, struct config_item *item) { - struct se_wwn *wwn = container_of(group, struct se_wwn, wwn_group); - struct target_fabric_configfs *tf = wwn->wwn_tf; struct se_portal_group *se_tpg = container_of(to_config_group(item), struct se_portal_group, tpg_group); struct config_group *tpg_cg = &se_tpg->tpg_group; @@ -890,15 +921,28 @@ static void target_fabric_drop_tpg( } config_item_put(item); - tf->tf_ops.fabric_drop_tpg(se_tpg); } +static void target_fabric_release_wwn(struct config_item *item) +{ + struct se_wwn *wwn = container_of(to_config_group(item), + struct se_wwn, wwn_group); + struct target_fabric_configfs *tf = wwn->wwn_tf; + + tf->tf_ops.fabric_drop_wwn(wwn); +} + +static struct configfs_item_operations target_fabric_tpg_item_ops = { + .release = target_fabric_release_wwn, +}; + static struct configfs_group_operations target_fabric_tpg_group_ops = { .make_group = target_fabric_make_tpg, .drop_item = target_fabric_drop_tpg, }; -TF_CIT_SETUP(tpg, NULL, &target_fabric_tpg_group_ops, NULL); +TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops, + NULL); /* End of tfc_tpg_cit */ @@ -932,13 +976,7 @@ static void target_fabric_drop_wwn( struct config_group *group, struct config_item *item) { - struct target_fabric_configfs *tf = container_of(group, - struct target_fabric_configfs, tf_group); - struct se_wwn *wwn = container_of(to_config_group(item), - struct se_wwn, wwn_group); - config_item_put(item); - tf->tf_ops.fabric_drop_wwn(wwn); } static struct configfs_group_operations target_fabric_wwn_group_ops = { diff --git a/trunk/drivers/target/target_core_iblock.c b/trunk/drivers/target/target_core_iblock.c index c6e0d757e76e..67f0c09983c8 100644 --- a/trunk/drivers/target/target_core_iblock.c +++ b/trunk/drivers/target/target_core_iblock.c @@ -154,7 +154,7 @@ static struct se_device *iblock_create_virtdevice( bd = blkdev_get_by_path(ib_dev->ibd_udev_path, FMODE_WRITE|FMODE_READ|FMODE_EXCL, ib_dev); - if (!(bd)) + if (IS_ERR(bd)) goto failed; /* * Setup the local scope queue_limits from struct request_queue->limits @@ -220,8 +220,10 @@ static void iblock_free_device(void *p) { struct iblock_dev *ib_dev = p; - blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); - bioset_free(ib_dev->ibd_bio_set); + if (ib_dev->ibd_bd != NULL) + blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL); + if (ib_dev->ibd_bio_set != NULL) + bioset_free(ib_dev->ibd_bio_set); kfree(ib_dev); } diff --git a/trunk/drivers/target/target_core_mib.c b/trunk/drivers/target/target_core_mib.c deleted file mode 100644 index d5a48aa0d2d1..000000000000 --- a/trunk/drivers/target/target_core_mib.c +++ /dev/null @@ -1,1078 +0,0 @@ -/******************************************************************************* - * Filename: target_core_mib.c - * - * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. - * Copyright (c) 2007-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org - * - * Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - ******************************************************************************/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "target_core_hba.h" -#include "target_core_mib.h" - -/* SCSI mib table index */ -static struct scsi_index_table scsi_index_table; - -#ifndef INITIAL_JIFFIES -#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) -#endif - -/* SCSI Instance Table */ -#define SCSI_INST_SW_INDEX 1 -#define SCSI_TRANSPORT_INDEX 1 - -#define NONE "None" -#define ISPRINT(a) ((a >= ' ') && (a <= '~')) - -static inline int list_is_first(const struct list_head *list, - const struct list_head *head) -{ - return list->prev == head; -} - -static void *locate_hba_start( - struct seq_file *seq, - loff_t *pos) -{ - spin_lock(&se_global->g_device_lock); - return seq_list_start(&se_global->g_se_dev_list, *pos); -} - -static void *locate_hba_next( - struct seq_file *seq, - void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_se_dev_list, pos); -} - -static void locate_hba_stop(struct seq_file *seq, void *v) -{ - spin_unlock(&se_global->g_device_lock); -} - -/**************************************************************************** - * SCSI MIB Tables - ****************************************************************************/ - -/* - * SCSI Instance Table - */ -static void *scsi_inst_seq_start( - struct seq_file *seq, - loff_t *pos) -{ - spin_lock(&se_global->hba_lock); - return seq_list_start(&se_global->g_hba_list, *pos); -} - -static void *scsi_inst_seq_next( - struct seq_file *seq, - void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_hba_list, pos); -} - -static void scsi_inst_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock(&se_global->hba_lock); -} - -static int scsi_inst_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba = list_entry(v, struct se_hba, hba_list); - - if (list_is_first(&hba->hba_list, &se_global->g_hba_list)) - seq_puts(seq, "inst sw_indx\n"); - - seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX); - seq_printf(seq, "plugin: %s version: %s\n", - hba->transport->name, TARGET_CORE_VERSION); - - return 0; -} - -static const struct seq_operations scsi_inst_seq_ops = { - .start = scsi_inst_seq_start, - .next = scsi_inst_seq_next, - .stop = scsi_inst_seq_stop, - .show = scsi_inst_seq_show -}; - -static int scsi_inst_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_inst_seq_ops); -} - -static const struct file_operations scsi_inst_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_inst_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Device Table - */ -static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_dev_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_dev_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - char str[28]; - int k; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst indx role ports\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - seq_printf(seq, "%u %u %s %u\n", hba->hba_index, - dev->dev_index, "Target", dev->dev_port_count); - - memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); - - /* vendor */ - for (k = 0; k < 8; k++) - str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ? - DEV_T10_WWN(dev)->vendor[k] : 0x20; - str[k] = 0x20; - - /* model */ - for (k = 0; k < 16; k++) - str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ? - DEV_T10_WWN(dev)->model[k] : 0x20; - str[k + 9] = 0; - - seq_printf(seq, "dev_alias: %s\n", str); - - return 0; -} - -static const struct seq_operations scsi_dev_seq_ops = { - .start = scsi_dev_seq_start, - .next = scsi_dev_seq_next, - .stop = scsi_dev_seq_stop, - .show = scsi_dev_seq_show -}; - -static int scsi_dev_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_dev_seq_ops); -} - -static const struct file_operations scsi_dev_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_dev_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Port Table - */ -static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_port_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_port_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - struct se_port *sep, *sep_tmp; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst device indx role busy_count\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - /* FIXME: scsiPortBusyStatuses count */ - spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { - seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index, - dev->dev_index, sep->sep_index, "Device", - dev->dev_index, 0); - } - spin_unlock(&dev->se_port_lock); - - return 0; -} - -static const struct seq_operations scsi_port_seq_ops = { - .start = scsi_port_seq_start, - .next = scsi_port_seq_next, - .stop = scsi_port_seq_stop, - .show = scsi_port_seq_show -}; - -static int scsi_port_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_port_seq_ops); -} - -static const struct file_operations scsi_port_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_port_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Transport Table - */ -static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_transport_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_transport_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - struct se_port *se, *se_tmp; - struct se_portal_group *tpg; - struct t10_wwn *wwn; - char buf[64]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst device indx dev_name\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - wwn = DEV_T10_WWN(dev); - - spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) { - tpg = se->sep_tpg; - sprintf(buf, "scsiTransport%s", - TPG_TFO(tpg)->get_fabric_name()); - - seq_printf(seq, "%u %s %u %s+%s\n", - hba->hba_index, /* scsiTransportIndex */ - buf, /* scsiTransportType */ - (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ? - TPG_TFO(tpg)->tpg_get_inst_index(tpg) : - 0, - TPG_TFO(tpg)->tpg_get_wwn(tpg), - (strlen(wwn->unit_serial)) ? - /* scsiTransportDevName */ - wwn->unit_serial : wwn->vendor); - } - spin_unlock(&dev->se_port_lock); - - return 0; -} - -static const struct seq_operations scsi_transport_seq_ops = { - .start = scsi_transport_seq_start, - .next = scsi_transport_seq_next, - .stop = scsi_transport_seq_stop, - .show = scsi_transport_seq_show -}; - -static int scsi_transport_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_transport_seq_ops); -} - -static const struct file_operations scsi_transport_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_transport_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Target Device Table - */ -static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - - -#define LU_COUNT 1 /* for now */ -static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - int non_accessible_lus = 0; - char status[16]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst indx num_LUs status non_access_LUs" - " resets\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - switch (dev->dev_status) { - case TRANSPORT_DEVICE_ACTIVATED: - strcpy(status, "activated"); - break; - case TRANSPORT_DEVICE_DEACTIVATED: - strcpy(status, "deactivated"); - non_accessible_lus = 1; - break; - case TRANSPORT_DEVICE_SHUTDOWN: - strcpy(status, "shutdown"); - non_accessible_lus = 1; - break; - case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: - case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: - strcpy(status, "offline"); - non_accessible_lus = 1; - break; - default: - sprintf(status, "unknown(%d)", dev->dev_status); - non_accessible_lus = 1; - } - - seq_printf(seq, "%u %u %u %s %u %u\n", - hba->hba_index, dev->dev_index, LU_COUNT, - status, non_accessible_lus, dev->num_resets); - - return 0; -} - -static const struct seq_operations scsi_tgt_dev_seq_ops = { - .start = scsi_tgt_dev_seq_start, - .next = scsi_tgt_dev_seq_next, - .stop = scsi_tgt_dev_seq_stop, - .show = scsi_tgt_dev_seq_show -}; - -static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_tgt_dev_seq_ops); -} - -static const struct file_operations scsi_tgt_dev_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_tgt_dev_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Target Port Table - */ -static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - struct se_port *sep, *sep_tmp; - struct se_portal_group *tpg; - u32 rx_mbytes, tx_mbytes; - unsigned long long num_cmds; - char buf[64]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst device indx name port_index in_cmds" - " write_mbytes read_mbytes hs_in_cmds\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - spin_lock(&dev->se_port_lock); - list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { - tpg = sep->sep_tpg; - sprintf(buf, "%sPort#", - TPG_TFO(tpg)->get_fabric_name()); - - seq_printf(seq, "%u %u %u %s%d %s%s%d ", - hba->hba_index, - dev->dev_index, - sep->sep_index, - buf, sep->sep_index, - TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", - TPG_TFO(tpg)->tpg_get_tag(tpg)); - - spin_lock(&sep->sep_lun->lun_sep_lock); - num_cmds = sep->sep_stats.cmd_pdus; - rx_mbytes = (sep->sep_stats.rx_data_octets >> 20); - tx_mbytes = (sep->sep_stats.tx_data_octets >> 20); - spin_unlock(&sep->sep_lun->lun_sep_lock); - - seq_printf(seq, "%llu %u %u %u\n", num_cmds, - rx_mbytes, tx_mbytes, 0); - } - spin_unlock(&dev->se_port_lock); - - return 0; -} - -static const struct seq_operations scsi_tgt_port_seq_ops = { - .start = scsi_tgt_port_seq_start, - .next = scsi_tgt_port_seq_next, - .stop = scsi_tgt_port_seq_stop, - .show = scsi_tgt_port_seq_show -}; - -static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_tgt_port_seq_ops); -} - -static const struct file_operations scsi_tgt_port_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_tgt_port_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Authorized Initiator Table: - * It contains the SCSI Initiators authorized to be attached to one of the - * local Target ports. - * Iterates through all active TPGs and extracts the info from the ACLs - */ -static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos) -{ - spin_lock_bh(&se_global->se_tpg_lock); - return seq_list_start(&se_global->g_se_tpg_list, *pos); -} - -static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_se_tpg_list, pos); -} - -static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_bh(&se_global->se_tpg_lock); -} - -static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v) -{ - struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, - se_tpg_list); - struct se_dev_entry *deve; - struct se_lun *lun; - struct se_node_acl *se_nacl; - int j; - - if (list_is_first(&se_tpg->se_tpg_list, - &se_global->g_se_tpg_list)) - seq_puts(seq, "inst dev port indx dev_or_port intr_name " - "map_indx att_count num_cmds read_mbytes " - "write_mbytes hs_num_cmds creation_time row_status\n"); - - if (!(se_tpg)) - return 0; - - spin_lock(&se_tpg->acl_node_lock); - list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) { - - atomic_inc(&se_nacl->mib_ref_count); - smp_mb__after_atomic_inc(); - spin_unlock(&se_tpg->acl_node_lock); - - spin_lock_irq(&se_nacl->device_list_lock); - for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { - deve = &se_nacl->device_list[j]; - if (!(deve->lun_flags & - TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || - (!deve->se_lun)) - continue; - lun = deve->se_lun; - if (!lun->lun_se_dev) - continue; - - seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u" - " %u %s\n", - /* scsiInstIndex */ - (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? - TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : - 0, - /* scsiDeviceIndex */ - lun->lun_se_dev->dev_index, - /* scsiAuthIntrTgtPortIndex */ - TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), - /* scsiAuthIntrIndex */ - se_nacl->acl_index, - /* scsiAuthIntrDevOrPort */ - 1, - /* scsiAuthIntrName */ - se_nacl->initiatorname[0] ? - se_nacl->initiatorname : NONE, - /* FIXME: scsiAuthIntrLunMapIndex */ - 0, - /* scsiAuthIntrAttachedTimes */ - deve->attach_count, - /* scsiAuthIntrOutCommands */ - deve->total_cmds, - /* scsiAuthIntrReadMegaBytes */ - (u32)(deve->read_bytes >> 20), - /* scsiAuthIntrWrittenMegaBytes */ - (u32)(deve->write_bytes >> 20), - /* FIXME: scsiAuthIntrHSOutCommands */ - 0, - /* scsiAuthIntrLastCreation */ - (u32)(((u32)deve->creation_time - - INITIAL_JIFFIES) * 100 / HZ), - /* FIXME: scsiAuthIntrRowStatus */ - "Ready"); - } - spin_unlock_irq(&se_nacl->device_list_lock); - - spin_lock(&se_tpg->acl_node_lock); - atomic_dec(&se_nacl->mib_ref_count); - smp_mb__after_atomic_dec(); - } - spin_unlock(&se_tpg->acl_node_lock); - - return 0; -} - -static const struct seq_operations scsi_auth_intr_seq_ops = { - .start = scsi_auth_intr_seq_start, - .next = scsi_auth_intr_seq_next, - .stop = scsi_auth_intr_seq_stop, - .show = scsi_auth_intr_seq_show -}; - -static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_auth_intr_seq_ops); -} - -static const struct file_operations scsi_auth_intr_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_auth_intr_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Attached Initiator Port Table: - * It lists the SCSI Initiators attached to one of the local Target ports. - * Iterates through all active TPGs and use active sessions from each TPG - * to list the info fo this table. - */ -static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos) -{ - spin_lock_bh(&se_global->se_tpg_lock); - return seq_list_start(&se_global->g_se_tpg_list, *pos); -} - -static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v, - loff_t *pos) -{ - return seq_list_next(v, &se_global->g_se_tpg_list, pos); -} - -static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v) -{ - spin_unlock_bh(&se_global->se_tpg_lock); -} - -static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v) -{ - struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, - se_tpg_list); - struct se_dev_entry *deve; - struct se_lun *lun; - struct se_node_acl *se_nacl; - struct se_session *se_sess; - unsigned char buf[64]; - int j; - - if (list_is_first(&se_tpg->se_tpg_list, - &se_global->g_se_tpg_list)) - seq_puts(seq, "inst dev port indx port_auth_indx port_name" - " port_ident\n"); - - if (!(se_tpg)) - return 0; - - spin_lock(&se_tpg->session_lock); - list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) { - if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) || - (!se_sess->se_node_acl) || - (!se_sess->se_node_acl->device_list)) - continue; - - atomic_inc(&se_sess->mib_ref_count); - smp_mb__after_atomic_inc(); - se_nacl = se_sess->se_node_acl; - atomic_inc(&se_nacl->mib_ref_count); - smp_mb__after_atomic_inc(); - spin_unlock(&se_tpg->session_lock); - - spin_lock_irq(&se_nacl->device_list_lock); - for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { - deve = &se_nacl->device_list[j]; - if (!(deve->lun_flags & - TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || - (!deve->se_lun)) - continue; - - lun = deve->se_lun; - if (!lun->lun_se_dev) - continue; - - memset(buf, 0, 64); - if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) - TPG_TFO(se_tpg)->sess_get_initiator_sid( - se_sess, (unsigned char *)&buf[0], 64); - - seq_printf(seq, "%u %u %u %u %u %s+i+%s\n", - /* scsiInstIndex */ - (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? - TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : - 0, - /* scsiDeviceIndex */ - lun->lun_se_dev->dev_index, - /* scsiPortIndex */ - TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), - /* scsiAttIntrPortIndex */ - (TPG_TFO(se_tpg)->sess_get_index != NULL) ? - TPG_TFO(se_tpg)->sess_get_index(se_sess) : - 0, - /* scsiAttIntrPortAuthIntrIdx */ - se_nacl->acl_index, - /* scsiAttIntrPortName */ - se_nacl->initiatorname[0] ? - se_nacl->initiatorname : NONE, - /* scsiAttIntrPortIdentifier */ - buf); - } - spin_unlock_irq(&se_nacl->device_list_lock); - - spin_lock(&se_tpg->session_lock); - atomic_dec(&se_nacl->mib_ref_count); - smp_mb__after_atomic_dec(); - atomic_dec(&se_sess->mib_ref_count); - smp_mb__after_atomic_dec(); - } - spin_unlock(&se_tpg->session_lock); - - return 0; -} - -static const struct seq_operations scsi_att_intr_port_seq_ops = { - .start = scsi_att_intr_port_seq_start, - .next = scsi_att_intr_port_seq_next, - .stop = scsi_att_intr_port_seq_stop, - .show = scsi_att_intr_port_seq_show -}; - -static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_att_intr_port_seq_ops); -} - -static const struct file_operations scsi_att_intr_port_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_att_intr_port_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * SCSI Logical Unit Table - */ -static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos) -{ - return locate_hba_start(seq, pos); -} - -static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return locate_hba_next(seq, v, pos); -} - -static void scsi_lu_seq_stop(struct seq_file *seq, void *v) -{ - locate_hba_stop(seq, v); -} - -#define SCSI_LU_INDEX 1 -static int scsi_lu_seq_show(struct seq_file *seq, void *v) -{ - struct se_hba *hba; - struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, - g_se_dev_list); - struct se_device *dev = se_dev->se_dev_ptr; - int j; - char str[28]; - - if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) - seq_puts(seq, "inst dev indx LUN lu_name vend prod rev" - " dev_type status state-bit num_cmds read_mbytes" - " write_mbytes resets full_stat hs_num_cmds creation_time\n"); - - if (!(dev)) - return 0; - - hba = dev->se_hba; - if (!(hba)) { - /* Log error ? */ - return 0; - } - - /* Fix LU state, if we can read it from the device */ - seq_printf(seq, "%u %u %u %llu %s", hba->hba_index, - dev->dev_index, SCSI_LU_INDEX, - (unsigned long long)0, /* FIXME: scsiLuDefaultLun */ - (strlen(DEV_T10_WWN(dev)->unit_serial)) ? - /* scsiLuWwnName */ - (char *)&DEV_T10_WWN(dev)->unit_serial[0] : - "None"); - - memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); - /* scsiLuVendorId */ - for (j = 0; j < 8; j++) - str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ? - DEV_T10_WWN(dev)->vendor[j] : 0x20; - str[8] = 0; - seq_printf(seq, " %s", str); - - /* scsiLuProductId */ - for (j = 0; j < 16; j++) - str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ? - DEV_T10_WWN(dev)->model[j] : 0x20; - str[16] = 0; - seq_printf(seq, " %s", str); - - /* scsiLuRevisionId */ - for (j = 0; j < 4; j++) - str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ? - DEV_T10_WWN(dev)->revision[j] : 0x20; - str[4] = 0; - seq_printf(seq, " %s", str); - - seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n", - /* scsiLuPeripheralType */ - TRANSPORT(dev)->get_device_type(dev), - (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? - "available" : "notavailable", /* scsiLuStatus */ - "exposed", /* scsiLuState */ - (unsigned long long)dev->num_cmds, - /* scsiLuReadMegaBytes */ - (u32)(dev->read_bytes >> 20), - /* scsiLuWrittenMegaBytes */ - (u32)(dev->write_bytes >> 20), - dev->num_resets, /* scsiLuInResets */ - 0, /* scsiLuOutTaskSetFullStatus */ - 0, /* scsiLuHSInCommands */ - (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) * - 100 / HZ)); - - return 0; -} - -static const struct seq_operations scsi_lu_seq_ops = { - .start = scsi_lu_seq_start, - .next = scsi_lu_seq_next, - .stop = scsi_lu_seq_stop, - .show = scsi_lu_seq_show -}; - -static int scsi_lu_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_lu_seq_ops); -} - -static const struct file_operations scsi_lu_seq_fops = { - .owner = THIS_MODULE, - .open = scsi_lu_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/****************************************************************************/ - -/* - * Remove proc fs entries - */ -void remove_scsi_target_mib(void) -{ - remove_proc_entry("scsi_target/mib/scsi_inst", NULL); - remove_proc_entry("scsi_target/mib/scsi_dev", NULL); - remove_proc_entry("scsi_target/mib/scsi_port", NULL); - remove_proc_entry("scsi_target/mib/scsi_transport", NULL); - remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL); - remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL); - remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL); - remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL); - remove_proc_entry("scsi_target/mib/scsi_lu", NULL); - remove_proc_entry("scsi_target/mib", NULL); -} - -/* - * Create proc fs entries for the mib tables - */ -int init_scsi_target_mib(void) -{ - struct proc_dir_entry *dir_entry; - struct proc_dir_entry *scsi_inst_entry; - struct proc_dir_entry *scsi_dev_entry; - struct proc_dir_entry *scsi_port_entry; - struct proc_dir_entry *scsi_transport_entry; - struct proc_dir_entry *scsi_tgt_dev_entry; - struct proc_dir_entry *scsi_tgt_port_entry; - struct proc_dir_entry *scsi_auth_intr_entry; - struct proc_dir_entry *scsi_att_intr_port_entry; - struct proc_dir_entry *scsi_lu_entry; - - dir_entry = proc_mkdir("scsi_target/mib", NULL); - if (!(dir_entry)) { - printk(KERN_ERR "proc_mkdir() failed.\n"); - return -1; - } - - scsi_inst_entry = - create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL); - if (scsi_inst_entry) - scsi_inst_entry->proc_fops = &scsi_inst_seq_fops; - else - goto error; - - scsi_dev_entry = - create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL); - if (scsi_dev_entry) - scsi_dev_entry->proc_fops = &scsi_dev_seq_fops; - else - goto error; - - scsi_port_entry = - create_proc_entry("scsi_target/mib/scsi_port", 0, NULL); - if (scsi_port_entry) - scsi_port_entry->proc_fops = &scsi_port_seq_fops; - else - goto error; - - scsi_transport_entry = - create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL); - if (scsi_transport_entry) - scsi_transport_entry->proc_fops = &scsi_transport_seq_fops; - else - goto error; - - scsi_tgt_dev_entry = - create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL); - if (scsi_tgt_dev_entry) - scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops; - else - goto error; - - scsi_tgt_port_entry = - create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL); - if (scsi_tgt_port_entry) - scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops; - else - goto error; - - scsi_auth_intr_entry = - create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL); - if (scsi_auth_intr_entry) - scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops; - else - goto error; - - scsi_att_intr_port_entry = - create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL); - if (scsi_att_intr_port_entry) - scsi_att_intr_port_entry->proc_fops = - &scsi_att_intr_port_seq_fops; - else - goto error; - - scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL); - if (scsi_lu_entry) - scsi_lu_entry->proc_fops = &scsi_lu_seq_fops; - else - goto error; - - return 0; - -error: - printk(KERN_ERR "create_proc_entry() failed.\n"); - remove_scsi_target_mib(); - return -1; -} - -/* - * Initialize the index table for allocating unique row indexes to various mib - * tables - */ -void init_scsi_index_table(void) -{ - memset(&scsi_index_table, 0, sizeof(struct scsi_index_table)); - spin_lock_init(&scsi_index_table.lock); -} - -/* - * Allocate a new row index for the entry type specified - */ -u32 scsi_get_new_index(scsi_index_t type) -{ - u32 new_index; - - if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) { - printk(KERN_ERR "Invalid index type %d\n", type); - return -1; - } - - spin_lock(&scsi_index_table.lock); - new_index = ++scsi_index_table.scsi_mib_index[type]; - if (new_index == 0) - new_index = ++scsi_index_table.scsi_mib_index[type]; - spin_unlock(&scsi_index_table.lock); - - return new_index; -} -EXPORT_SYMBOL(scsi_get_new_index); diff --git a/trunk/drivers/target/target_core_mib.h b/trunk/drivers/target/target_core_mib.h deleted file mode 100644 index 277204633850..000000000000 --- a/trunk/drivers/target/target_core_mib.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef TARGET_CORE_MIB_H -#define TARGET_CORE_MIB_H - -typedef enum { - SCSI_INST_INDEX, - SCSI_DEVICE_INDEX, - SCSI_AUTH_INTR_INDEX, - SCSI_INDEX_TYPE_MAX -} scsi_index_t; - -struct scsi_index_table { - spinlock_t lock; - u32 scsi_mib_index[SCSI_INDEX_TYPE_MAX]; -} ____cacheline_aligned; - -/* SCSI Port stats */ -struct scsi_port_stats { - u64 cmd_pdus; - u64 tx_data_octets; - u64 rx_data_octets; -} ____cacheline_aligned; - -extern int init_scsi_target_mib(void); -extern void remove_scsi_target_mib(void); -extern void init_scsi_index_table(void); -extern u32 scsi_get_new_index(scsi_index_t); - -#endif /*** TARGET_CORE_MIB_H ***/ diff --git a/trunk/drivers/target/target_core_pscsi.c b/trunk/drivers/target/target_core_pscsi.c index 742d24609a9b..f2a08477a68c 100644 --- a/trunk/drivers/target/target_core_pscsi.c +++ b/trunk/drivers/target/target_core_pscsi.c @@ -462,8 +462,8 @@ static struct se_device *pscsi_create_type_disk( */ bd = blkdev_get_by_path(se_dev->se_dev_udev_path, FMODE_WRITE|FMODE_READ|FMODE_EXCL, pdv); - if (!(bd)) { - printk("pSCSI: blkdev_get_by_path() failed\n"); + if (IS_ERR(bd)) { + printk(KERN_ERR "pSCSI: blkdev_get_by_path() failed\n"); scsi_device_put(sd); return NULL; } diff --git a/trunk/drivers/target/target_core_tpg.c b/trunk/drivers/target/target_core_tpg.c index abfa81a57115..c26f67467623 100644 --- a/trunk/drivers/target/target_core_tpg.c +++ b/trunk/drivers/target/target_core_tpg.c @@ -275,7 +275,6 @@ struct se_node_acl *core_tpg_check_initiator_node_acl( spin_lock_init(&acl->device_list_lock); spin_lock_init(&acl->nacl_sess_lock); atomic_set(&acl->acl_pr_ref_count, 0); - atomic_set(&acl->mib_ref_count, 0); acl->queue_depth = TPG_TFO(tpg)->tpg_get_default_depth(tpg); snprintf(acl->initiatorname, TRANSPORT_IQN_LEN, "%s", initiatorname); acl->se_tpg = tpg; @@ -318,12 +317,6 @@ void core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *nacl) cpu_relax(); } -void core_tpg_wait_for_mib_ref(struct se_node_acl *nacl) -{ - while (atomic_read(&nacl->mib_ref_count) != 0) - cpu_relax(); -} - void core_tpg_clear_object_luns(struct se_portal_group *tpg) { int i, ret; @@ -480,7 +473,6 @@ int core_tpg_del_initiator_node_acl( spin_unlock_bh(&tpg->session_lock); core_tpg_wait_for_nacl_pr_ref(acl); - core_tpg_wait_for_mib_ref(acl); core_clear_initiator_node_from_tpg(acl, tpg); core_free_device_list_for_node(acl, tpg); @@ -701,6 +693,8 @@ EXPORT_SYMBOL(core_tpg_register); int core_tpg_deregister(struct se_portal_group *se_tpg) { + struct se_node_acl *nacl, *nacl_tmp; + printk(KERN_INFO "TARGET_CORE[%s]: Deallocating %s struct se_portal_group" " for endpoint: %s Portal Tag %u\n", (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) ? @@ -714,6 +708,25 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) cpu_relax(); + /* + * Release any remaining demo-mode generated se_node_acl that have + * not been released because of TFO->tpg_check_demo_mode_cache() == 1 + * in transport_deregister_session(). + */ + spin_lock_bh(&se_tpg->acl_node_lock); + list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list, + acl_list) { + list_del(&nacl->acl_list); + se_tpg->num_node_acls--; + spin_unlock_bh(&se_tpg->acl_node_lock); + + core_tpg_wait_for_nacl_pr_ref(nacl); + core_free_device_list_for_node(nacl, se_tpg); + TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg, nacl); + + spin_lock_bh(&se_tpg->acl_node_lock); + } + spin_unlock_bh(&se_tpg->acl_node_lock); if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL) core_tpg_release_virtual_lun0(se_tpg); diff --git a/trunk/drivers/target/target_core_transport.c b/trunk/drivers/target/target_core_transport.c index 28b6292ff298..236e22d8cfae 100644 --- a/trunk/drivers/target/target_core_transport.c +++ b/trunk/drivers/target/target_core_transport.c @@ -379,6 +379,40 @@ void release_se_global(void) se_global = NULL; } +/* SCSI statistics table index */ +static struct scsi_index_table scsi_index_table; + +/* + * Initialize the index table for allocating unique row indexes to various mib + * tables. + */ +void init_scsi_index_table(void) +{ + memset(&scsi_index_table, 0, sizeof(struct scsi_index_table)); + spin_lock_init(&scsi_index_table.lock); +} + +/* + * Allocate a new row index for the entry type specified + */ +u32 scsi_get_new_index(scsi_index_t type) +{ + u32 new_index; + + if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) { + printk(KERN_ERR "Invalid index type %d\n", type); + return -EINVAL; + } + + spin_lock(&scsi_index_table.lock); + new_index = ++scsi_index_table.scsi_mib_index[type]; + if (new_index == 0) + new_index = ++scsi_index_table.scsi_mib_index[type]; + spin_unlock(&scsi_index_table.lock); + + return new_index; +} + void transport_init_queue_obj(struct se_queue_obj *qobj) { atomic_set(&qobj->queue_cnt, 0); @@ -437,7 +471,6 @@ struct se_session *transport_init_session(void) } INIT_LIST_HEAD(&se_sess->sess_list); INIT_LIST_HEAD(&se_sess->sess_acl_list); - atomic_set(&se_sess->mib_ref_count, 0); return se_sess; } @@ -546,12 +579,6 @@ void transport_deregister_session(struct se_session *se_sess) transport_free_session(se_sess); return; } - /* - * Wait for possible reference in drivers/target/target_core_mib.c: - * scsi_att_intr_port_seq_show() - */ - while (atomic_read(&se_sess->mib_ref_count) != 0) - cpu_relax(); spin_lock_bh(&se_tpg->session_lock); list_del(&se_sess->sess_list); @@ -574,7 +601,6 @@ void transport_deregister_session(struct se_session *se_sess) spin_unlock_bh(&se_tpg->acl_node_lock); core_tpg_wait_for_nacl_pr_ref(se_nacl); - core_tpg_wait_for_mib_ref(se_nacl); core_free_device_list_for_node(se_nacl, se_tpg); TPG_TFO(se_tpg)->tpg_release_fabric_acl(se_tpg, se_nacl); @@ -4827,6 +4853,8 @@ static int transport_do_se_mem_map( return ret; } + + BUG_ON(list_empty(se_mem_list)); /* * This is the normal path for all normal non BIDI and BIDI-COMMAND * WRITE payloads.. If we need to do BIDI READ passthrough for @@ -5008,7 +5036,9 @@ transport_map_control_cmd_to_task(struct se_cmd *cmd) struct se_mem *se_mem = NULL, *se_mem_lout = NULL; u32 se_mem_cnt = 0, task_offset = 0; - BUG_ON(list_empty(cmd->t_task->t_mem_list)); + if (!list_empty(T_TASK(cmd)->t_mem_list)) + se_mem = list_entry(T_TASK(cmd)->t_mem_list->next, + struct se_mem, se_list); ret = transport_do_se_mem_map(dev, task, cmd->t_task->t_mem_list, NULL, se_mem, diff --git a/trunk/drivers/tty/serial/max3100.c b/trunk/drivers/tty/serial/max3100.c index beb1afa27d8d..7b951adac54b 100644 --- a/trunk/drivers/tty/serial/max3100.c +++ b/trunk/drivers/tty/serial/max3100.c @@ -601,7 +601,7 @@ static int max3100_startup(struct uart_port *port) s->rts = 0; sprintf(b, "max3100-%d", s->minor); - s->workqueue = create_freezeable_workqueue(b); + s->workqueue = create_freezable_workqueue(b); if (!s->workqueue) { dev_warn(&s->spi->dev, "cannot create workqueue\n"); return -EBUSY; diff --git a/trunk/drivers/tty/serial/max3107.c b/trunk/drivers/tty/serial/max3107.c index 910870edf708..750b4f627315 100644 --- a/trunk/drivers/tty/serial/max3107.c +++ b/trunk/drivers/tty/serial/max3107.c @@ -833,7 +833,7 @@ static int max3107_startup(struct uart_port *port) struct max3107_port *s = container_of(port, struct max3107_port, port); /* Initialize work queue */ - s->workqueue = create_freezeable_workqueue("max3107"); + s->workqueue = create_freezable_workqueue("max3107"); if (!s->workqueue) { dev_err(&s->spi->dev, "Workqueue creation failed\n"); return -EBUSY; diff --git a/trunk/drivers/usb/core/quirks.c b/trunk/drivers/usb/core/quirks.c index 44c595432d6f..81ce6a8e1d94 100644 --- a/trunk/drivers/usb/core/quirks.c +++ b/trunk/drivers/usb/core/quirks.c @@ -48,6 +48,10 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04b4, 0x0526), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Samsung Android phone modem - ID conflict with SPH-I500 */ + { USB_DEVICE(0x04e8, 0x6601), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Roland SC-8820 */ { USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -68,6 +72,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Keytouch QWERTY Panel keyboard */ + { USB_DEVICE(0x0926, 0x3333), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* X-Rite/Gretag-Macbeth Eye-One Pro display colorimeter */ { USB_DEVICE(0x0971, 0x2000), .driver_info = USB_QUIRK_NO_SET_INTF }, diff --git a/trunk/drivers/usb/musb/musb_core.h b/trunk/drivers/usb/musb/musb_core.h index d74a8113ae74..e6400be8a0f8 100644 --- a/trunk/drivers/usb/musb/musb_core.h +++ b/trunk/drivers/usb/musb/musb_core.h @@ -488,6 +488,15 @@ struct musb { unsigned set_address:1; unsigned test_mode:1; unsigned softconnect:1; + + u8 address; + u8 test_mode_nr; + u16 ackpend; /* ep0 */ + enum musb_g_ep0_state ep0_state; + struct usb_gadget g; /* the gadget */ + struct usb_gadget_driver *gadget_driver; /* its driver */ +#endif + /* * FIXME: Remove this flag. * @@ -501,14 +510,6 @@ struct musb { */ unsigned double_buffer_not_ok:1 __deprecated; - u8 address; - u8 test_mode_nr; - u16 ackpend; /* ep0 */ - enum musb_g_ep0_state ep0_state; - struct usb_gadget g; /* the gadget */ - struct usb_gadget_driver *gadget_driver; /* its driver */ -#endif - struct musb_hdrc_config *config; #ifdef MUSB_CONFIG_PROC_FS diff --git a/trunk/drivers/usb/musb/omap2430.c b/trunk/drivers/usb/musb/omap2430.c index a3f12333fc41..bc8badd16897 100644 --- a/trunk/drivers/usb/musb/omap2430.c +++ b/trunk/drivers/usb/musb/omap2430.c @@ -362,6 +362,7 @@ static int omap2430_musb_init(struct musb *musb) static int omap2430_musb_exit(struct musb *musb) { + del_timer_sync(&musb_idle_timer); omap2430_low_level_exit(musb); otg_put_transceiver(musb->xceiv); diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index 7481ff8a49e4..0457813eebee 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -301,6 +301,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, + { USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */ + .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist + }, { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */ { } diff --git a/trunk/drivers/usb/serial/usb_wwan.c b/trunk/drivers/usb/serial/usb_wwan.c index b004b2a485c3..9c014e2ecd68 100644 --- a/trunk/drivers/usb/serial/usb_wwan.c +++ b/trunk/drivers/usb/serial/usb_wwan.c @@ -295,12 +295,15 @@ static void usb_wwan_indat_callback(struct urb *urb) __func__, status, endpoint); } else { tty = tty_port_tty_get(&port->port); - if (urb->actual_length) { - tty_insert_flip_string(tty, data, urb->actual_length); - tty_flip_buffer_push(tty); - } else - dbg("%s: empty read urb received", __func__); - tty_kref_put(tty); + if (tty) { + if (urb->actual_length) { + tty_insert_flip_string(tty, data, + urb->actual_length); + tty_flip_buffer_push(tty); + } else + dbg("%s: empty read urb received", __func__); + tty_kref_put(tty); + } /* Resubmit urb so we continue receiving */ if (status != -ESHUTDOWN) { diff --git a/trunk/drivers/usb/serial/visor.c b/trunk/drivers/usb/serial/visor.c index 15a5d89b7f39..1c11959a7d58 100644 --- a/trunk/drivers/usb/serial/visor.c +++ b/trunk/drivers/usb/serial/visor.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "visor.h" /* @@ -479,6 +480,17 @@ static int visor_probe(struct usb_serial *serial, dbg("%s", __func__); + /* + * some Samsung Android phones in modem mode have the same ID + * as SPH-I500, but they are ACM devices, so dont bind to them + */ + if (id->idVendor == SAMSUNG_VENDOR_ID && + id->idProduct == SAMSUNG_SPH_I500_ID && + serial->dev->descriptor.bDeviceClass == USB_CLASS_COMM && + serial->dev->descriptor.bDeviceSubClass == + USB_CDC_SUBCLASS_ACM) + return -ENODEV; + if (serial->dev->actconfig->desc.bConfigurationValue != 1) { dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", serial->dev->actconfig->desc.bConfigurationValue); diff --git a/trunk/drivers/xen/manage.c b/trunk/drivers/xen/manage.c index db8c4c4ac880..24177272bcb8 100644 --- a/trunk/drivers/xen/manage.c +++ b/trunk/drivers/xen/manage.c @@ -37,11 +37,19 @@ static enum shutdown_state shutting_down = SHUTDOWN_INVALID; #ifdef CONFIG_PM_SLEEP static int xen_hvm_suspend(void *data) { + int err; struct sched_shutdown r = { .reason = SHUTDOWN_suspend }; int *cancelled = data; BUG_ON(!irqs_disabled()); + err = sysdev_suspend(PMSG_SUSPEND); + if (err) { + printk(KERN_ERR "xen_hvm_suspend: sysdev_suspend failed: %d\n", + err); + return err; + } + *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r); xen_hvm_post_suspend(*cancelled); @@ -53,6 +61,8 @@ static int xen_hvm_suspend(void *data) xen_timer_resume(); } + sysdev_resume(); + return 0; } diff --git a/trunk/fs/block_dev.c b/trunk/fs/block_dev.c index 333a7bb4cb9c..4fb8a3431531 100644 --- a/trunk/fs/block_dev.c +++ b/trunk/fs/block_dev.c @@ -1215,12 +1215,6 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) res = __blkdev_get(bdev, mode, 0); - /* __blkdev_get() may alter read only status, check it afterwards */ - if (!res && (mode & FMODE_WRITE) && bdev_read_only(bdev)) { - __blkdev_put(bdev, mode, 0); - res = -EACCES; - } - if (whole) { /* finish claiming */ mutex_lock(&bdev->bd_mutex); @@ -1298,6 +1292,11 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, if (err) return ERR_PTR(err); + if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) { + blkdev_put(bdev, mode); + return ERR_PTR(-EACCES); + } + return bdev; } EXPORT_SYMBOL(blkdev_get_by_path); diff --git a/trunk/fs/ceph/dir.c b/trunk/fs/ceph/dir.c index 0bc68de8edd7..f0aef787a102 100644 --- a/trunk/fs/ceph/dir.c +++ b/trunk/fs/ceph/dir.c @@ -60,6 +60,7 @@ int ceph_init_dentry(struct dentry *dentry) } di->dentry = dentry; di->lease_session = NULL; + di->parent_inode = igrab(dentry->d_parent->d_inode); dentry->d_fsdata = di; dentry->d_time = jiffies; ceph_dentry_lru_add(dentry); @@ -1033,7 +1034,7 @@ static void ceph_dentry_release(struct dentry *dentry) u64 snapid = CEPH_NOSNAP; if (!IS_ROOT(dentry)) { - parent_inode = dentry->d_parent->d_inode; + parent_inode = di->parent_inode; if (parent_inode) snapid = ceph_snap(parent_inode); } @@ -1058,6 +1059,8 @@ static void ceph_dentry_release(struct dentry *dentry) kmem_cache_free(ceph_dentry_cachep, di); dentry->d_fsdata = NULL; } + if (parent_inode) + iput(parent_inode); } static int ceph_snapdir_d_revalidate(struct dentry *dentry, diff --git a/trunk/fs/ceph/snap.c b/trunk/fs/ceph/snap.c index 39c243acd062..f40b9139e437 100644 --- a/trunk/fs/ceph/snap.c +++ b/trunk/fs/ceph/snap.c @@ -584,10 +584,14 @@ static void queue_realm_cap_snaps(struct ceph_snap_realm *realm) if (lastinode) iput(lastinode); - dout("queue_realm_cap_snaps %p %llx children\n", realm, realm->ino); - list_for_each_entry(child, &realm->children, child_item) - queue_realm_cap_snaps(child); + list_for_each_entry(child, &realm->children, child_item) { + dout("queue_realm_cap_snaps %p %llx queue child %p %llx\n", + realm, realm->ino, child, child->ino); + list_del_init(&child->dirty_item); + list_add(&child->dirty_item, &realm->dirty_item); + } + list_del_init(&realm->dirty_item); dout("queue_realm_cap_snaps %p %llx done\n", realm, realm->ino); } @@ -683,7 +687,9 @@ int ceph_update_snap_trace(struct ceph_mds_client *mdsc, * queue cap snaps _after_ we've built the new snap contexts, * so that i_head_snapc can be set appropriately. */ - list_for_each_entry(realm, &dirty_realms, dirty_item) { + while (!list_empty(&dirty_realms)) { + realm = list_first_entry(&dirty_realms, struct ceph_snap_realm, + dirty_item); queue_realm_cap_snaps(realm); } diff --git a/trunk/fs/ceph/super.h b/trunk/fs/ceph/super.h index 20b907d76ae2..88fcaa21b801 100644 --- a/trunk/fs/ceph/super.h +++ b/trunk/fs/ceph/super.h @@ -207,6 +207,7 @@ struct ceph_dentry_info { struct dentry *dentry; u64 time; u64 offset; + struct inode *parent_inode; }; struct ceph_inode_xattrs_info { diff --git a/trunk/fs/cifs/cifsfs.h b/trunk/fs/cifs/cifsfs.h index 4a3330235d55..a9371b6578c0 100644 --- a/trunk/fs/cifs/cifsfs.h +++ b/trunk/fs/cifs/cifsfs.h @@ -127,5 +127,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); extern const struct export_operations cifs_export_ops; #endif /* EXPERIMENTAL */ -#define CIFS_VERSION "1.70" +#define CIFS_VERSION "1.71" #endif /* _CIFSFS_H */ diff --git a/trunk/fs/cifs/netmisc.c b/trunk/fs/cifs/netmisc.c index 8d9189f64477..79f641eeda30 100644 --- a/trunk/fs/cifs/netmisc.c +++ b/trunk/fs/cifs/netmisc.c @@ -170,7 +170,7 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len) { int rc, alen, slen; const char *pct; - char *endp, scope_id[13]; + char scope_id[13]; struct sockaddr_in *s4 = (struct sockaddr_in *) dst; struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; @@ -197,9 +197,9 @@ cifs_convert_address(struct sockaddr *dst, const char *src, int len) memcpy(scope_id, pct + 1, slen); scope_id[slen] = '\0'; - s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); - if (endp != scope_id + slen) - return 0; + rc = strict_strtoul(scope_id, 0, + (unsigned long *)&s6->sin6_scope_id); + rc = (rc == 0) ? 1 : 0; } return rc; diff --git a/trunk/fs/cifs/sess.c b/trunk/fs/cifs/sess.c index 1adc9625a344..16765703131b 100644 --- a/trunk/fs/cifs/sess.c +++ b/trunk/fs/cifs/sess.c @@ -656,13 +656,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, if (type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH - char lnm_session_key[CIFS_SESS_KEY_SIZE]; + char lnm_session_key[CIFS_AUTH_RESP_SIZE]; pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); + pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); /* Calculate hash with password and copy into bcc_ptr. * Encryption Key (stored as in cryptkey) gets used if the @@ -675,8 +675,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, true : false, lnm_session_key); ses->flags |= CIFS_SES_LANMAN; - memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); - bcc_ptr += CIFS_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE); + bcc_ptr += CIFS_AUTH_RESP_SIZE; /* can not sign if LANMAN negotiated so no need to calculate signing key? but what if server diff --git a/trunk/fs/ecryptfs/dentry.c b/trunk/fs/ecryptfs/dentry.c index 6fc4f319b550..534c1d46e69e 100644 --- a/trunk/fs/ecryptfs/dentry.c +++ b/trunk/fs/ecryptfs/dentry.c @@ -46,24 +46,28 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) { struct dentry *lower_dentry; struct vfsmount *lower_mnt; - struct dentry *dentry_save; - struct vfsmount *vfsmount_save; + struct dentry *dentry_save = NULL; + struct vfsmount *vfsmount_save = NULL; int rc = 1; - if (nd->flags & LOOKUP_RCU) + if (nd && nd->flags & LOOKUP_RCU) return -ECHILD; lower_dentry = ecryptfs_dentry_to_lower(dentry); lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) goto out; - dentry_save = nd->path.dentry; - vfsmount_save = nd->path.mnt; - nd->path.dentry = lower_dentry; - nd->path.mnt = lower_mnt; + if (nd) { + dentry_save = nd->path.dentry; + vfsmount_save = nd->path.mnt; + nd->path.dentry = lower_dentry; + nd->path.mnt = lower_mnt; + } rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd); - nd->path.dentry = dentry_save; - nd->path.mnt = vfsmount_save; + if (nd) { + nd->path.dentry = dentry_save; + nd->path.mnt = vfsmount_save; + } if (dentry->d_inode) { struct inode *lower_inode = ecryptfs_inode_to_lower(dentry->d_inode); diff --git a/trunk/fs/ecryptfs/ecryptfs_kernel.h b/trunk/fs/ecryptfs/ecryptfs_kernel.h index dbc84ed96336..e00753496e3e 100644 --- a/trunk/fs/ecryptfs/ecryptfs_kernel.h +++ b/trunk/fs/ecryptfs/ecryptfs_kernel.h @@ -632,8 +632,7 @@ int ecryptfs_interpose(struct dentry *hidden_dentry, u32 flags); int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, - struct inode *ecryptfs_dir_inode, - struct nameidata *ecryptfs_nd); + struct inode *ecryptfs_dir_inode); int ecryptfs_decode_and_decrypt_filename(char **decrypted_name, size_t *decrypted_name_size, struct dentry *ecryptfs_dentry, diff --git a/trunk/fs/ecryptfs/file.c b/trunk/fs/ecryptfs/file.c index 81e10e6a9443..7d1050e254f9 100644 --- a/trunk/fs/ecryptfs/file.c +++ b/trunk/fs/ecryptfs/file.c @@ -317,6 +317,7 @@ ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) const struct file_operations ecryptfs_dir_fops = { .readdir = ecryptfs_readdir, + .read = generic_read_dir, .unlocked_ioctl = ecryptfs_unlocked_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, diff --git a/trunk/fs/ecryptfs/inode.c b/trunk/fs/ecryptfs/inode.c index bd33f87a1907..b592938a84bc 100644 --- a/trunk/fs/ecryptfs/inode.c +++ b/trunk/fs/ecryptfs/inode.c @@ -74,16 +74,20 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, unsigned int flags_save; int rc; - dentry_save = nd->path.dentry; - vfsmount_save = nd->path.mnt; - flags_save = nd->flags; - nd->path.dentry = lower_dentry; - nd->path.mnt = lower_mnt; - nd->flags &= ~LOOKUP_OPEN; + if (nd) { + dentry_save = nd->path.dentry; + vfsmount_save = nd->path.mnt; + flags_save = nd->flags; + nd->path.dentry = lower_dentry; + nd->path.mnt = lower_mnt; + nd->flags &= ~LOOKUP_OPEN; + } rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd); - nd->path.dentry = dentry_save; - nd->path.mnt = vfsmount_save; - nd->flags = flags_save; + if (nd) { + nd->path.dentry = dentry_save; + nd->path.mnt = vfsmount_save; + nd->flags = flags_save; + } return rc; } @@ -241,8 +245,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry, */ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, struct dentry *lower_dentry, - struct inode *ecryptfs_dir_inode, - struct nameidata *ecryptfs_nd) + struct inode *ecryptfs_dir_inode) { struct dentry *lower_dir_dentry; struct vfsmount *lower_mnt; @@ -290,8 +293,6 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, goto out; if (special_file(lower_inode->i_mode)) goto out; - if (!ecryptfs_nd) - goto out; /* Released in this function */ page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER); if (!page_virt) { @@ -348,75 +349,6 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, return rc; } -/** - * ecryptfs_new_lower_dentry - * @name: The name of the new dentry. - * @lower_dir_dentry: Parent directory of the new dentry. - * @nd: nameidata from last lookup. - * - * Create a new dentry or get it from lower parent dir. - */ -static struct dentry * -ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry, - struct nameidata *nd) -{ - struct dentry *new_dentry; - struct dentry *tmp; - struct inode *lower_dir_inode; - - lower_dir_inode = lower_dir_dentry->d_inode; - - tmp = d_alloc(lower_dir_dentry, name); - if (!tmp) - return ERR_PTR(-ENOMEM); - - mutex_lock(&lower_dir_inode->i_mutex); - new_dentry = lower_dir_inode->i_op->lookup(lower_dir_inode, tmp, nd); - mutex_unlock(&lower_dir_inode->i_mutex); - - if (!new_dentry) - new_dentry = tmp; - else - dput(tmp); - - return new_dentry; -} - - -/** - * ecryptfs_lookup_one_lower - * @ecryptfs_dentry: The eCryptfs dentry that we are looking up - * @lower_dir_dentry: lower parent directory - * @name: lower file name - * - * Get the lower dentry from vfs. If lower dentry does not exist yet, - * create it. - */ -static struct dentry * -ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry, - struct dentry *lower_dir_dentry, struct qstr *name) -{ - struct nameidata nd; - struct vfsmount *lower_mnt; - int err; - - lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( - ecryptfs_dentry->d_parent)); - err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd); - mntput(lower_mnt); - - if (!err) { - /* we dont need the mount */ - mntput(nd.path.mnt); - return nd.path.dentry; - } - if (err != -ENOENT) - return ERR_PTR(err); - - /* create a new lower dentry */ - return ecryptfs_new_lower_dentry(name, lower_dir_dentry, &nd); -} - /** * ecryptfs_lookup * @ecryptfs_dir_inode: The eCryptfs directory inode @@ -434,7 +366,6 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, size_t encrypted_and_encoded_name_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL; struct dentry *lower_dir_dentry, *lower_dentry; - struct qstr lower_name; int rc = 0; if ((ecryptfs_dentry->d_name.len == 1 @@ -444,20 +375,14 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, goto out_d_drop; } lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); - lower_name.name = ecryptfs_dentry->d_name.name; - lower_name.len = ecryptfs_dentry->d_name.len; - lower_name.hash = ecryptfs_dentry->d_name.hash; - if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { - rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, - lower_dir_dentry->d_inode, &lower_name); - if (rc < 0) - goto out_d_drop; - } - lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, - lower_dir_dentry, &lower_name); + mutex_lock(&lower_dir_dentry->d_inode->i_mutex); + lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, + lower_dir_dentry, + ecryptfs_dentry->d_name.len); + mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); - ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " + ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, encrypted_and_encoded_name); goto out_d_drop; @@ -479,28 +404,21 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, "filename; rc = [%d]\n", __func__, rc); goto out_d_drop; } - lower_name.name = encrypted_and_encoded_name; - lower_name.len = encrypted_and_encoded_name_size; - lower_name.hash = full_name_hash(lower_name.name, lower_name.len); - if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { - rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, - lower_dir_dentry->d_inode, &lower_name); - if (rc < 0) - goto out_d_drop; - } - lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, - lower_dir_dentry, &lower_name); + mutex_lock(&lower_dir_dentry->d_inode->i_mutex); + lower_dentry = lookup_one_len(encrypted_and_encoded_name, + lower_dir_dentry, + encrypted_and_encoded_name_size); + mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); if (IS_ERR(lower_dentry)) { rc = PTR_ERR(lower_dentry); - ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " + ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " "[%d] on lower_dentry = [%s]\n", __func__, rc, encrypted_and_encoded_name); goto out_d_drop; } lookup_and_interpose: rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry, - ecryptfs_dir_inode, - ecryptfs_nd); + ecryptfs_dir_inode); goto out; out_d_drop: d_drop(ecryptfs_dentry); @@ -1092,6 +1010,8 @@ int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, rc = vfs_getattr(ecryptfs_dentry_to_lower_mnt(dentry), ecryptfs_dentry_to_lower(dentry), &lower_stat); if (!rc) { + fsstack_copy_attr_all(dentry->d_inode, + ecryptfs_inode_to_lower(dentry->d_inode)); generic_fillattr(dentry->d_inode, stat); stat->blocks = lower_stat.blocks; } diff --git a/trunk/fs/eventfd.c b/trunk/fs/eventfd.c index e0194b3e14d6..d9a591773919 100644 --- a/trunk/fs/eventfd.c +++ b/trunk/fs/eventfd.c @@ -99,7 +99,7 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_get); * @ctx: [in] Pointer to eventfd context. * * The eventfd context reference must have been previously acquired either - * with eventfd_ctx_get() or eventfd_ctx_fdget()). + * with eventfd_ctx_get() or eventfd_ctx_fdget(). */ void eventfd_ctx_put(struct eventfd_ctx *ctx) { @@ -146,9 +146,9 @@ static void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt) * eventfd_ctx_remove_wait_queue - Read the current counter and removes wait queue. * @ctx: [in] Pointer to eventfd context. * @wait: [in] Wait queue to be removed. - * @cnt: [out] Pointer to the 64bit conter value. + * @cnt: [out] Pointer to the 64-bit counter value. * - * Returns zero if successful, or the following error codes: + * Returns %0 if successful, or the following error codes: * * -EAGAIN : The operation would have blocked. * @@ -175,11 +175,11 @@ EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue); * eventfd_ctx_read - Reads the eventfd counter or wait if it is zero. * @ctx: [in] Pointer to eventfd context. * @no_wait: [in] Different from zero if the operation should not block. - * @cnt: [out] Pointer to the 64bit conter value. + * @cnt: [out] Pointer to the 64-bit counter value. * - * Returns zero if successful, or the following error codes: + * Returns %0 if successful, or the following error codes: * - * -EAGAIN : The operation would have blocked but @no_wait was nonzero. + * -EAGAIN : The operation would have blocked but @no_wait was non-zero. * -ERESTARTSYS : A signal interrupted the wait operation. * * If @no_wait is zero, the function might sleep until the eventfd internal diff --git a/trunk/fs/gfs2/glock.c b/trunk/fs/gfs2/glock.c index 08a8beb152e6..7cd9a5a68d59 100644 --- a/trunk/fs/gfs2/glock.c +++ b/trunk/fs/gfs2/glock.c @@ -1779,11 +1779,11 @@ int __init gfs2_glock_init(void) #endif glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM | - WQ_HIGHPRI | WQ_FREEZEABLE, 0); + WQ_HIGHPRI | WQ_FREEZABLE, 0); if (IS_ERR(glock_workqueue)) return PTR_ERR(glock_workqueue); gfs2_delete_workqueue = alloc_workqueue("delete_workqueue", - WQ_MEM_RECLAIM | WQ_FREEZEABLE, + WQ_MEM_RECLAIM | WQ_FREEZABLE, 0); if (IS_ERR(gfs2_delete_workqueue)) { destroy_workqueue(glock_workqueue); diff --git a/trunk/fs/gfs2/main.c b/trunk/fs/gfs2/main.c index ebef7ab6e17e..85ba027d1c4d 100644 --- a/trunk/fs/gfs2/main.c +++ b/trunk/fs/gfs2/main.c @@ -144,7 +144,7 @@ static int __init init_gfs2_fs(void) error = -ENOMEM; gfs_recovery_wq = alloc_workqueue("gfs_recovery", - WQ_MEM_RECLAIM | WQ_FREEZEABLE, 0); + WQ_MEM_RECLAIM | WQ_FREEZABLE, 0); if (!gfs_recovery_wq) goto fail_wq; diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index 9e701e28a329..0087cf9c2c6b 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -795,7 +795,7 @@ __do_follow_link(const struct path *link, struct nameidata *nd, void **p) * Without that kind of total limit, nasty chains of consecutive * symlinks can cause almost arbitrarily long lookups. */ -static inline int do_follow_link(struct path *path, struct nameidata *nd) +static inline int do_follow_link(struct inode *inode, struct path *path, struct nameidata *nd) { void *cookie; int err = -ELOOP; @@ -803,6 +803,7 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) /* We drop rcu-walk here */ if (nameidata_dentry_drop_rcu_maybe(nd, path->dentry)) return -ECHILD; + BUG_ON(inode != path->dentry->d_inode); if (current->link_count >= MAX_NESTED_LINKS) goto loop; @@ -1413,8 +1414,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) goto out_dput; if (inode->i_op->follow_link) { - BUG_ON(inode != next.dentry->d_inode); - err = do_follow_link(&next, nd); + err = do_follow_link(inode, &next, nd); if (err) goto return_err; nd->inode = nd->path.dentry->d_inode; @@ -1458,8 +1458,7 @@ static int link_path_walk(const char *name, struct nameidata *nd) break; if (inode && unlikely(inode->i_op->follow_link) && (lookup_flags & LOOKUP_FOLLOW)) { - BUG_ON(inode != next.dentry->d_inode); - err = do_follow_link(&next, nd); + err = do_follow_link(inode, &next, nd); if (err) goto return_err; nd->inode = nd->path.dentry->d_inode; diff --git a/trunk/fs/nfsd/nfs4xdr.c b/trunk/fs/nfsd/nfs4xdr.c index 956629b9cdc9..1275b8655070 100644 --- a/trunk/fs/nfsd/nfs4xdr.c +++ b/trunk/fs/nfsd/nfs4xdr.c @@ -317,8 +317,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, READ_BUF(dummy32); len += (XDR_QUADLEN(dummy32) << 2); READMEM(buf, dummy32); - if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) - goto out_nfserr; + if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) + return status; iattr->ia_valid |= ATTR_UID; } if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { @@ -328,8 +328,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, READ_BUF(dummy32); len += (XDR_QUADLEN(dummy32) << 2); READMEM(buf, dummy32); - if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) - goto out_nfserr; + if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) + return status; iattr->ia_valid |= ATTR_GID; } if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { diff --git a/trunk/fs/partitions/mac.c b/trunk/fs/partitions/mac.c index 68d6a216ee79..11f688bd76c5 100644 --- a/trunk/fs/partitions/mac.c +++ b/trunk/fs/partitions/mac.c @@ -29,10 +29,9 @@ static inline void mac_fix_string(char *stg, int len) int mac_partition(struct parsed_partitions *state) { - int slot = 1; Sector sect; unsigned char *data; - int blk, blocks_in_map; + int slot, blocks_in_map; unsigned secsize; #ifdef CONFIG_PPC_PMAC int found_root = 0; @@ -59,10 +58,14 @@ int mac_partition(struct parsed_partitions *state) put_dev_sector(sect); return 0; /* not a MacOS disk */ } - strlcat(state->pp_buf, " [mac]", PAGE_SIZE); blocks_in_map = be32_to_cpu(part->map_count); - for (blk = 1; blk <= blocks_in_map; ++blk) { - int pos = blk * secsize; + if (blocks_in_map < 0 || blocks_in_map >= DISK_MAX_PARTS) { + put_dev_sector(sect); + return 0; + } + strlcat(state->pp_buf, " [mac]", PAGE_SIZE); + for (slot = 1; slot <= blocks_in_map; ++slot) { + int pos = slot * secsize; put_dev_sector(sect); data = read_part_sector(state, pos/512, §); if (!data) @@ -113,13 +116,11 @@ int mac_partition(struct parsed_partitions *state) } if (goodness > found_root_goodness) { - found_root = blk; + found_root = slot; found_root_goodness = goodness; } } #endif /* CONFIG_PPC_PMAC */ - - ++slot; } #ifdef CONFIG_PPC_PMAC if (found_root_goodness) diff --git a/trunk/include/linux/cgroup.h b/trunk/include/linux/cgroup.h index e654fa239916..ce104e33cd22 100644 --- a/trunk/include/linux/cgroup.h +++ b/trunk/include/linux/cgroup.h @@ -474,8 +474,7 @@ struct cgroup_subsys { struct cgroup *old_cgrp, struct task_struct *tsk, bool threadgroup); void (*fork)(struct cgroup_subsys *ss, struct task_struct *task); - void (*exit)(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task); + void (*exit)(struct cgroup_subsys *ss, struct task_struct *task); int (*populate)(struct cgroup_subsys *ss, struct cgroup *cgrp); void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cgrp); @@ -627,7 +626,6 @@ bool css_is_ancestor(struct cgroup_subsys_state *cg, /* Get id and depth of css */ unsigned short css_id(struct cgroup_subsys_state *css); unsigned short css_depth(struct cgroup_subsys_state *css); -struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id); #else /* !CONFIG_CGROUPS */ diff --git a/trunk/include/linux/cgroup_subsys.h b/trunk/include/linux/cgroup_subsys.h index cdbfcb8780ec..ccefff02b6cb 100644 --- a/trunk/include/linux/cgroup_subsys.h +++ b/trunk/include/linux/cgroup_subsys.h @@ -65,8 +65,4 @@ SUBSYS(net_cls) SUBSYS(blkio) #endif -#ifdef CONFIG_CGROUP_PERF -SUBSYS(perf) -#endif - /* */ diff --git a/trunk/include/linux/freezer.h b/trunk/include/linux/freezer.h index da7e52b099f3..1effc8b56b4e 100644 --- a/trunk/include/linux/freezer.h +++ b/trunk/include/linux/freezer.h @@ -109,7 +109,7 @@ static inline void freezer_count(void) } /* - * Check if the task should be counted as freezeable by the freezer + * Check if the task should be counted as freezable by the freezer */ static inline int freezer_should_skip(struct task_struct *p) { diff --git a/trunk/include/linux/ftrace.h b/trunk/include/linux/ftrace.h index ca29e03c1fac..dcd6a7c3a435 100644 --- a/trunk/include/linux/ftrace.h +++ b/trunk/include/linux/ftrace.h @@ -428,7 +428,6 @@ extern void unregister_ftrace_graph(void); extern void ftrace_graph_init_task(struct task_struct *t); extern void ftrace_graph_exit_task(struct task_struct *t); -extern void ftrace_graph_init_idle_task(struct task_struct *t, int cpu); static inline int task_curr_ret_stack(struct task_struct *t) { @@ -452,7 +451,6 @@ static inline void unpause_graph_tracing(void) static inline void ftrace_graph_init_task(struct task_struct *t) { } static inline void ftrace_graph_exit_task(struct task_struct *t) { } -static inline void ftrace_graph_init_idle_task(struct task_struct *t, int cpu) { } static inline int register_ftrace_graph(trace_func_graph_ret_t retfunc, trace_func_graph_ent_t entryfunc) diff --git a/trunk/include/linux/ftrace_event.h b/trunk/include/linux/ftrace_event.h index 1a99e7939c2b..47e3997f7b5c 100644 --- a/trunk/include/linux/ftrace_event.h +++ b/trunk/include/linux/ftrace_event.h @@ -208,6 +208,7 @@ struct ftrace_event_call { #define PERF_MAX_TRACE_SIZE 2048 +#define MAX_FILTER_PRED 32 #define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ extern void destroy_preds(struct ftrace_event_call *call); diff --git a/trunk/include/linux/list.h b/trunk/include/linux/list.h index 9a5f8a71810c..3a54266a1e85 100644 --- a/trunk/include/linux/list.h +++ b/trunk/include/linux/list.h @@ -96,6 +96,11 @@ static inline void __list_del(struct list_head * prev, struct list_head * next) * in an undefined state. */ #ifndef CONFIG_DEBUG_LIST +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + static inline void list_del(struct list_head *entry) { __list_del(entry->prev, entry->next); @@ -103,6 +108,7 @@ static inline void list_del(struct list_head *entry) entry->prev = LIST_POISON2; } #else +extern void __list_del_entry(struct list_head *entry); extern void list_del(struct list_head *entry); #endif @@ -135,7 +141,7 @@ static inline void list_replace_init(struct list_head *old, */ static inline void list_del_init(struct list_head *entry) { - __list_del(entry->prev, entry->next); + __list_del_entry(entry); INIT_LIST_HEAD(entry); } @@ -146,7 +152,7 @@ static inline void list_del_init(struct list_head *entry) */ static inline void list_move(struct list_head *list, struct list_head *head) { - __list_del(list->prev, list->next); + __list_del_entry(list); list_add(list, head); } @@ -158,7 +164,7 @@ static inline void list_move(struct list_head *list, struct list_head *head) static inline void list_move_tail(struct list_head *list, struct list_head *head) { - __list_del(list->prev, list->next); + __list_del_entry(list); list_add_tail(list, head); } diff --git a/trunk/include/linux/module.h b/trunk/include/linux/module.h index 9bdf27c7615b..5de42043dff0 100644 --- a/trunk/include/linux/module.h +++ b/trunk/include/linux/module.h @@ -62,7 +62,7 @@ struct module_version_attribute { struct module_attribute mattr; const char *module_name; const char *version; -}; +} __attribute__ ((__aligned__(sizeof(void *)))); struct module_kobject { diff --git a/trunk/include/linux/perf_event.h b/trunk/include/linux/perf_event.h index 8ceb5a6fd9c9..dda5b0a3ff60 100644 --- a/trunk/include/linux/perf_event.h +++ b/trunk/include/linux/perf_event.h @@ -464,7 +464,6 @@ enum perf_callchain_context { #define PERF_FLAG_FD_NO_GROUP (1U << 0) #define PERF_FLAG_FD_OUTPUT (1U << 1) -#define PERF_FLAG_PID_CGROUP (1U << 2) /* pid=cgroup id, per-cpu mode only */ #ifdef __KERNEL__ /* @@ -472,7 +471,6 @@ enum perf_callchain_context { */ #ifdef CONFIG_PERF_EVENTS -# include # include # include #endif @@ -718,22 +716,6 @@ struct swevent_hlist { #define PERF_ATTACH_GROUP 0x02 #define PERF_ATTACH_TASK 0x04 -#ifdef CONFIG_CGROUP_PERF -/* - * perf_cgroup_info keeps track of time_enabled for a cgroup. - * This is a per-cpu dynamically allocated data structure. - */ -struct perf_cgroup_info { - u64 time; - u64 timestamp; -}; - -struct perf_cgroup { - struct cgroup_subsys_state css; - struct perf_cgroup_info *info; /* timing info, one per cpu */ -}; -#endif - /** * struct perf_event - performance event kernel representation: */ @@ -850,11 +832,6 @@ struct perf_event { struct event_filter *filter; #endif -#ifdef CONFIG_CGROUP_PERF - struct perf_cgroup *cgrp; /* cgroup event is attach to */ - int cgrp_defer_enabled; -#endif - #endif /* CONFIG_PERF_EVENTS */ }; @@ -909,7 +886,6 @@ struct perf_event_context { u64 generation; int pin_count; struct rcu_head rcu_head; - int nr_cgroups; /* cgroup events present */ }; /* @@ -929,9 +905,6 @@ struct perf_cpu_context { struct list_head rotation_list; int jiffies_interval; struct pmu *active_pmu; -#ifdef CONFIG_CGROUP_PERF - struct perf_cgroup *cgrp; -#endif }; struct perf_output_handle { @@ -1067,11 +1040,11 @@ perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr) __perf_sw_event(event_id, nr, nmi, regs, addr); } -extern atomic_t perf_sched_events; +extern atomic_t perf_task_events; static inline void perf_event_task_sched_in(struct task_struct *task) { - COND_STMT(&perf_sched_events, __perf_event_task_sched_in(task)); + COND_STMT(&perf_task_events, __perf_event_task_sched_in(task)); } static inline @@ -1079,7 +1052,7 @@ void perf_event_task_sched_out(struct task_struct *task, struct task_struct *nex { perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); - COND_STMT(&perf_sched_events, __perf_event_task_sched_out(task, next)); + COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next)); } extern void perf_event_mmap(struct vm_area_struct *vma); @@ -1110,10 +1083,6 @@ extern int sysctl_perf_event_paranoid; extern int sysctl_perf_event_mlock; extern int sysctl_perf_event_sample_rate; -extern int perf_proc_update_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); - static inline bool perf_paranoid_tracepoint_raw(void) { return sysctl_perf_event_paranoid > -1; diff --git a/trunk/include/linux/rtc.h b/trunk/include/linux/rtc.h index a0b639f8e805..89c3e5182991 100644 --- a/trunk/include/linux/rtc.h +++ b/trunk/include/linux/rtc.h @@ -203,6 +203,18 @@ struct rtc_device struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */ int pie_enabled; struct work_struct irqwork; + + +#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL + struct work_struct uie_task; + struct timer_list uie_timer; + /* Those fields are protected by rtc->irq_lock */ + unsigned int oldsecs; + unsigned int uie_irq_active:1; + unsigned int stop_uie_polling:1; + unsigned int uie_task_active:1; + unsigned int uie_timer_active:1; +#endif }; #define to_rtc_device(d) container_of(d, struct rtc_device, dev) @@ -235,7 +247,10 @@ extern int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq); extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled); extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled); +extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, + unsigned int enabled); +void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode); void rtc_aie_update_irq(void *private); void rtc_uie_update_irq(void *private); enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer); diff --git a/trunk/include/linux/sched.h b/trunk/include/linux/sched.h index 0b40ee3f6d7a..777d8a5ed06b 100644 --- a/trunk/include/linux/sched.h +++ b/trunk/include/linux/sched.h @@ -1744,7 +1744,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t * #define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ #define PF_MEMPOLICY 0x10000000 /* Non-default NUMA mempolicy */ #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ -#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezeable */ +#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ #define PF_FREEZER_NOSIG 0x80000000 /* Freezer won't send signals to it */ /* @@ -2578,6 +2578,13 @@ static inline void inc_syscw(struct task_struct *tsk) #define TASK_SIZE_OF(tsk) TASK_SIZE #endif +/* + * Call the function if the target task is executing on a CPU right now: + */ +extern void task_oncpu_function_call(struct task_struct *p, + void (*func) (void *info), void *info); + + #ifdef CONFIG_MM_OWNER extern void mm_update_next_owner(struct mm_struct *mm); extern void mm_init_owner(struct mm_struct *mm, struct task_struct *p); diff --git a/trunk/include/linux/syscalls.h b/trunk/include/linux/syscalls.h index a17fcea2ca58..98664db1be47 100644 --- a/trunk/include/linux/syscalls.h +++ b/trunk/include/linux/syscalls.h @@ -132,11 +132,11 @@ extern struct trace_event_functions exit_syscall_print_funcs; .class = &event_class_syscall_enter, \ .event.funcs = &enter_syscall_print_funcs, \ .data = (void *)&__syscall_meta_##sname,\ - .flags = TRACE_EVENT_FL_CAP_ANY, \ }; \ static struct ftrace_event_call __used \ __attribute__((section("_ftrace_events"))) \ - *__event_enter_##sname = &event_enter_##sname; + *__event_enter_##sname = &event_enter_##sname; \ + __TRACE_EVENT_FLAGS(enter_##sname, TRACE_EVENT_FL_CAP_ANY) #define SYSCALL_TRACE_EXIT_EVENT(sname) \ static struct syscall_metadata __syscall_meta_##sname; \ @@ -146,11 +146,11 @@ extern struct trace_event_functions exit_syscall_print_funcs; .class = &event_class_syscall_exit, \ .event.funcs = &exit_syscall_print_funcs, \ .data = (void *)&__syscall_meta_##sname,\ - .flags = TRACE_EVENT_FL_CAP_ANY, \ }; \ static struct ftrace_event_call __used \ __attribute__((section("_ftrace_events"))) \ - *__event_exit_##sname = &event_exit_##sname; + *__event_exit_##sname = &event_exit_##sname; \ + __TRACE_EVENT_FLAGS(exit_##sname, TRACE_EVENT_FL_CAP_ANY) #define SYSCALL_METADATA(sname, nb) \ SYSCALL_TRACE_ENTER_EVENT(sname); \ @@ -158,7 +158,6 @@ extern struct trace_event_functions exit_syscall_print_funcs; static struct syscall_metadata __used \ __syscall_meta_##sname = { \ .name = "sys"#sname, \ - .syscall_nr = -1, /* Filled in at boot */ \ .nb_args = nb, \ .types = types_##sname, \ .args = args_##sname, \ @@ -176,7 +175,6 @@ extern struct trace_event_functions exit_syscall_print_funcs; static struct syscall_metadata __used \ __syscall_meta__##sname = { \ .name = "sys_"#sname, \ - .syscall_nr = -1, /* Filled in at boot */ \ .nb_args = 0, \ .enter_event = &event_enter__##sname, \ .exit_event = &event_exit__##sname, \ diff --git a/trunk/include/linux/workqueue.h b/trunk/include/linux/workqueue.h index 1ac11586a2f5..f7998a3bf020 100644 --- a/trunk/include/linux/workqueue.h +++ b/trunk/include/linux/workqueue.h @@ -250,7 +250,7 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; } enum { WQ_NON_REENTRANT = 1 << 0, /* guarantee non-reentrance */ WQ_UNBOUND = 1 << 1, /* not bound to any cpu */ - WQ_FREEZEABLE = 1 << 2, /* freeze during suspend */ + WQ_FREEZABLE = 1 << 2, /* freeze during suspend */ WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */ WQ_HIGHPRI = 1 << 4, /* high priority */ WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */ @@ -318,7 +318,7 @@ __alloc_workqueue_key(const char *name, unsigned int flags, int max_active, /** * alloc_ordered_workqueue - allocate an ordered workqueue * @name: name of the workqueue - * @flags: WQ_* flags (only WQ_FREEZEABLE and WQ_MEM_RECLAIM are meaningful) + * @flags: WQ_* flags (only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful) * * Allocate an ordered workqueue. An ordered workqueue executes at * most one work item at any given time in the queued order. They are @@ -335,8 +335,8 @@ alloc_ordered_workqueue(const char *name, unsigned int flags) #define create_workqueue(name) \ alloc_workqueue((name), WQ_MEM_RECLAIM, 1) -#define create_freezeable_workqueue(name) \ - alloc_workqueue((name), WQ_FREEZEABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1) +#define create_freezable_workqueue(name) \ + alloc_workqueue((name), WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM, 1) #define create_singlethread_workqueue(name) \ alloc_workqueue((name), WQ_UNBOUND | WQ_MEM_RECLAIM, 1) diff --git a/trunk/include/pcmcia/ds.h b/trunk/include/pcmcia/ds.h index 8479b66c067b..3fd5064dd43a 100644 --- a/trunk/include/pcmcia/ds.h +++ b/trunk/include/pcmcia/ds.h @@ -261,6 +261,7 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev); #define CONF_ENABLE_ESR 0x0008 #define CONF_ENABLE_IOCARD 0x0010 /* auto-enabled if IO resources or IRQ * (CONF_ENABLE_IRQ) in use */ +#define CONF_ENABLE_ZVCARD 0x0020 /* flags used by pcmcia_loop_config() autoconfiguration */ #define CONF_AUTO_CHECK_VCC 0x0100 /* check for matching Vcc? */ diff --git a/trunk/include/sound/wm8903.h b/trunk/include/sound/wm8903.h index b4a0db2307ef..1eeebd534f7e 100644 --- a/trunk/include/sound/wm8903.h +++ b/trunk/include/sound/wm8903.h @@ -17,13 +17,9 @@ /* * R6 (0x06) - Mic Bias Control 0 */ -#define WM8903_MICDET_HYST_ENA 0x0080 /* MICDET_HYST_ENA */ -#define WM8903_MICDET_HYST_ENA_MASK 0x0080 /* MICDET_HYST_ENA */ -#define WM8903_MICDET_HYST_ENA_SHIFT 7 /* MICDET_HYST_ENA */ -#define WM8903_MICDET_HYST_ENA_WIDTH 1 /* MICDET_HYST_ENA */ -#define WM8903_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */ -#define WM8903_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */ -#define WM8903_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */ +#define WM8903_MICDET_THR_MASK 0x0030 /* MICDET_THR - [5:4] */ +#define WM8903_MICDET_THR_SHIFT 4 /* MICDET_THR - [5:4] */ +#define WM8903_MICDET_THR_WIDTH 2 /* MICDET_THR - [5:4] */ #define WM8903_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */ #define WM8903_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */ #define WM8903_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */ diff --git a/trunk/include/target/target_core_base.h b/trunk/include/target/target_core_base.h index 07fdfb6b9a9a..0828b6c8610a 100644 --- a/trunk/include/target/target_core_base.h +++ b/trunk/include/target/target_core_base.h @@ -8,7 +8,6 @@ #include #include #include -#include "target_core_mib.h" #define TARGET_CORE_MOD_VERSION "v4.0.0-rc6" #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT)) @@ -195,6 +194,21 @@ typedef enum { SAM_TASK_ATTR_EMULATED } t10_task_attr_index_t; +/* + * Used for target SCSI statistics + */ +typedef enum { + SCSI_INST_INDEX, + SCSI_DEVICE_INDEX, + SCSI_AUTH_INTR_INDEX, + SCSI_INDEX_TYPE_MAX +} scsi_index_t; + +struct scsi_index_table { + spinlock_t lock; + u32 scsi_mib_index[SCSI_INDEX_TYPE_MAX]; +} ____cacheline_aligned; + struct se_cmd; struct t10_alua { @@ -578,8 +592,6 @@ struct se_node_acl { spinlock_t stats_lock; /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ atomic_t acl_pr_ref_count; - /* Used for MIB access */ - atomic_t mib_ref_count; struct se_dev_entry *device_list; struct se_session *nacl_sess; struct se_portal_group *se_tpg; @@ -595,8 +607,6 @@ struct se_node_acl { } ____cacheline_aligned; struct se_session { - /* Used for MIB access */ - atomic_t mib_ref_count; u64 sess_bin_isid; struct se_node_acl *se_node_acl; struct se_portal_group *se_tpg; @@ -806,7 +816,6 @@ struct se_hba { /* Virtual iSCSI devices attached. */ u32 dev_count; u32 hba_index; - atomic_t dev_mib_access_count; atomic_t load_balance_queue; atomic_t left_queue_depth; /* Maximum queue depth the HBA can handle. */ @@ -845,6 +854,12 @@ struct se_lun { #define SE_LUN(c) ((struct se_lun *)(c)->se_lun) +struct scsi_port_stats { + u64 cmd_pdus; + u64 tx_data_octets; + u64 rx_data_octets; +} ____cacheline_aligned; + struct se_port { /* RELATIVE TARGET PORT IDENTIFER */ u16 sep_rtpi; @@ -867,6 +882,7 @@ struct se_port { } ____cacheline_aligned; struct se_tpg_np { + struct se_portal_group *tpg_np_parent; struct config_group tpg_np_group; } ____cacheline_aligned; diff --git a/trunk/include/target/target_core_transport.h b/trunk/include/target/target_core_transport.h index 66f44e56eb80..246940511579 100644 --- a/trunk/include/target/target_core_transport.h +++ b/trunk/include/target/target_core_transport.h @@ -111,6 +111,8 @@ struct se_subsystem_api; extern int init_se_global(void); extern void release_se_global(void); +extern void init_scsi_index_table(void); +extern u32 scsi_get_new_index(scsi_index_t); extern void transport_init_queue_obj(struct se_queue_obj *); extern int transport_subsystem_check_init(void); extern int transport_subsystem_register(struct se_subsystem_api *); diff --git a/trunk/init/Kconfig b/trunk/init/Kconfig index 20d6bd919b8d..be788c0957d4 100644 --- a/trunk/init/Kconfig +++ b/trunk/init/Kconfig @@ -683,16 +683,6 @@ config CGROUP_MEM_RES_CTLR_SWAP_ENABLED select this option (if, for some reason, they need to disable it then noswapaccount does the trick). -config CGROUP_PERF - bool "Enable perf_event per-cpu per-container group (cgroup) monitoring" - depends on PERF_EVENTS && CGROUPS - help - This option extends the per-cpu mode to restrict monitoring to - threads which belong to the cgroup specificied and run on the - designated cpu. - - Say N if unsure. - menuconfig CGROUP_SCHED bool "Group CPU scheduler" depends on EXPERIMENTAL diff --git a/trunk/kernel/cgroup.c b/trunk/kernel/cgroup.c index 95362d15128c..b24d7027b83c 100644 --- a/trunk/kernel/cgroup.c +++ b/trunk/kernel/cgroup.c @@ -4230,8 +4230,20 @@ void cgroup_post_fork(struct task_struct *child) */ void cgroup_exit(struct task_struct *tsk, int run_callbacks) { - struct css_set *cg; int i; + struct css_set *cg; + + if (run_callbacks && need_forkexit_callback) { + /* + * modular subsystems can't use callbacks, so no need to lock + * the subsys array + */ + for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) { + struct cgroup_subsys *ss = subsys[i]; + if (ss->exit) + ss->exit(ss, tsk); + } + } /* * Unlink from the css_set task list if necessary. @@ -4249,24 +4261,7 @@ void cgroup_exit(struct task_struct *tsk, int run_callbacks) task_lock(tsk); cg = tsk->cgroups; tsk->cgroups = &init_css_set; - - if (run_callbacks && need_forkexit_callback) { - /* - * modular subsystems can't use callbacks, so no need to lock - * the subsys array - */ - for (i = 0; i < CGROUP_BUILTIN_SUBSYS_COUNT; i++) { - struct cgroup_subsys *ss = subsys[i]; - if (ss->exit) { - struct cgroup *old_cgrp = - rcu_dereference_raw(cg->subsys[i])->cgroup; - struct cgroup *cgrp = task_cgroup(tsk, i); - ss->exit(ss, cgrp, old_cgrp, tsk); - } - } - } task_unlock(tsk); - if (cg) put_css_set_taskexit(cg); } @@ -4818,29 +4813,6 @@ css_get_next(struct cgroup_subsys *ss, int id, return ret; } -/* - * get corresponding css from file open on cgroupfs directory - */ -struct cgroup_subsys_state *cgroup_css_from_dir(struct file *f, int id) -{ - struct cgroup *cgrp; - struct inode *inode; - struct cgroup_subsys_state *css; - - inode = f->f_dentry->d_inode; - /* check in cgroup filesystem dir */ - if (inode->i_op != &cgroup_dir_inode_operations) - return ERR_PTR(-EBADF); - - if (id < 0 || id >= CGROUP_SUBSYS_COUNT) - return ERR_PTR(-EINVAL); - - /* get cgroup */ - cgrp = __d_cgrp(f->f_dentry); - css = cgrp->subsys[id]; - return css ? css : ERR_PTR(-ENOENT); -} - #ifdef CONFIG_CGROUP_DEBUG static struct cgroup_subsys_state *debug_create(struct cgroup_subsys *ss, struct cgroup *cont) diff --git a/trunk/kernel/irq/internals.h b/trunk/kernel/irq/internals.h index 4571ae7e085a..99c3bc8a6fb4 100644 --- a/trunk/kernel/irq/internals.h +++ b/trunk/kernel/irq/internals.h @@ -3,6 +3,12 @@ */ #include +#ifdef CONFIG_SPARSE_IRQ +# define IRQ_BITMAP_BITS (NR_IRQS + 8196) +#else +# define IRQ_BITMAP_BITS NR_IRQS +#endif + extern int noirqdebug; #define irq_data_to_desc(data) container_of(data, struct irq_desc, irq_data) diff --git a/trunk/kernel/irq/irqdesc.c b/trunk/kernel/irq/irqdesc.c index 282f20230e67..2039bea31bdf 100644 --- a/trunk/kernel/irq/irqdesc.c +++ b/trunk/kernel/irq/irqdesc.c @@ -94,7 +94,7 @@ int nr_irqs = NR_IRQS; EXPORT_SYMBOL_GPL(nr_irqs); static DEFINE_MUTEX(sparse_irq_lock); -static DECLARE_BITMAP(allocated_irqs, NR_IRQS); +static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS); #ifdef CONFIG_SPARSE_IRQ @@ -217,6 +217,15 @@ int __init early_irq_init(void) initcnt = arch_probe_nr_irqs(); printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt); + if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS)) + nr_irqs = IRQ_BITMAP_BITS; + + if (WARN_ON(initcnt > IRQ_BITMAP_BITS)) + initcnt = IRQ_BITMAP_BITS; + + if (initcnt > nr_irqs) + nr_irqs = initcnt; + for (i = 0; i < initcnt; i++) { desc = alloc_desc(i, node); set_bit(i, allocated_irqs); diff --git a/trunk/kernel/irq/manage.c b/trunk/kernel/irq/manage.c index 0caa59f747dd..9033c1c70828 100644 --- a/trunk/kernel/irq/manage.c +++ b/trunk/kernel/irq/manage.c @@ -1100,7 +1100,7 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler, if (retval) kfree(action); -#ifdef CONFIG_DEBUG_SHIRQ +#ifdef CONFIG_DEBUG_SHIRQ_FIXME if (!retval && (irqflags & IRQF_SHARED)) { /* * It's a shared IRQ -- the driver ought to be prepared for it diff --git a/trunk/kernel/irq/resend.c b/trunk/kernel/irq/resend.c index 891115a929aa..dc49358b73fa 100644 --- a/trunk/kernel/irq/resend.c +++ b/trunk/kernel/irq/resend.c @@ -23,7 +23,7 @@ #ifdef CONFIG_HARDIRQS_SW_RESEND /* Bitmap to handle software resend of interrupts: */ -static DECLARE_BITMAP(irqs_resend, NR_IRQS); +static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS); /* * Run software resends of IRQ's diff --git a/trunk/kernel/perf_event.c b/trunk/kernel/perf_event.c index 64a018e94fca..656222fcf767 100644 --- a/trunk/kernel/perf_event.c +++ b/trunk/kernel/perf_event.c @@ -38,96 +38,13 @@ #include -struct remote_function_call { - struct task_struct *p; - int (*func)(void *info); - void *info; - int ret; -}; - -static void remote_function(void *data) -{ - struct remote_function_call *tfc = data; - struct task_struct *p = tfc->p; - - if (p) { - tfc->ret = -EAGAIN; - if (task_cpu(p) != smp_processor_id() || !task_curr(p)) - return; - } - - tfc->ret = tfc->func(tfc->info); -} - -/** - * task_function_call - call a function on the cpu on which a task runs - * @p: the task to evaluate - * @func: the function to be called - * @info: the function call argument - * - * Calls the function @func when the task is currently running. This might - * be on the current CPU, which just calls the function directly - * - * returns: @func return value, or - * -ESRCH - when the process isn't running - * -EAGAIN - when the process moved away - */ -static int -task_function_call(struct task_struct *p, int (*func) (void *info), void *info) -{ - struct remote_function_call data = { - .p = p, - .func = func, - .info = info, - .ret = -ESRCH, /* No such (running) process */ - }; - - if (task_curr(p)) - smp_call_function_single(task_cpu(p), remote_function, &data, 1); - - return data.ret; -} - -/** - * cpu_function_call - call a function on the cpu - * @func: the function to be called - * @info: the function call argument - * - * Calls the function @func on the remote cpu. - * - * returns: @func return value or -ENXIO when the cpu is offline - */ -static int cpu_function_call(int cpu, int (*func) (void *info), void *info) -{ - struct remote_function_call data = { - .p = NULL, - .func = func, - .info = info, - .ret = -ENXIO, /* No such CPU */ - }; - - smp_call_function_single(cpu, remote_function, &data, 1); - - return data.ret; -} - -#define PERF_FLAG_ALL (PERF_FLAG_FD_NO_GROUP |\ - PERF_FLAG_FD_OUTPUT |\ - PERF_FLAG_PID_CGROUP) - enum event_type_t { EVENT_FLEXIBLE = 0x1, EVENT_PINNED = 0x2, EVENT_ALL = EVENT_FLEXIBLE | EVENT_PINNED, }; -/* - * perf_sched_events : >0 events exist - * perf_cgroup_events: >0 per-cpu cgroup events exist on this cpu - */ -atomic_t perf_sched_events __read_mostly; -static DEFINE_PER_CPU(atomic_t, perf_cgroup_events); - +atomic_t perf_task_events __read_mostly; static atomic_t nr_mmap_events __read_mostly; static atomic_t nr_comm_events __read_mostly; static atomic_t nr_task_events __read_mostly; @@ -150,24 +67,7 @@ int sysctl_perf_event_mlock __read_mostly = 512; /* 'free' kb per user */ /* * max perf event sample rate */ -#define DEFAULT_MAX_SAMPLE_RATE 100000 -int sysctl_perf_event_sample_rate __read_mostly = DEFAULT_MAX_SAMPLE_RATE; -static int max_samples_per_tick __read_mostly = - DIV_ROUND_UP(DEFAULT_MAX_SAMPLE_RATE, HZ); - -int perf_proc_update_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret = proc_dointvec(table, write, buffer, lenp, ppos); - - if (ret || !write) - return ret; - - max_samples_per_tick = DIV_ROUND_UP(sysctl_perf_event_sample_rate, HZ); - - return 0; -} +int sysctl_perf_event_sample_rate __read_mostly = 100000; static atomic64_t perf_event_id; @@ -175,11 +75,7 @@ static void cpu_ctx_sched_out(struct perf_cpu_context *cpuctx, enum event_type_t event_type); static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, - enum event_type_t event_type, - struct task_struct *task); - -static void update_context_time(struct perf_event_context *ctx); -static u64 perf_event_time(struct perf_event *event); + enum event_type_t event_type); void __weak perf_event_print_debug(void) { } @@ -193,357 +89,6 @@ static inline u64 perf_clock(void) return local_clock(); } -static inline struct perf_cpu_context * -__get_cpu_context(struct perf_event_context *ctx) -{ - return this_cpu_ptr(ctx->pmu->pmu_cpu_context); -} - -#ifdef CONFIG_CGROUP_PERF - -/* - * Must ensure cgroup is pinned (css_get) before calling - * this function. In other words, we cannot call this function - * if there is no cgroup event for the current CPU context. - */ -static inline struct perf_cgroup * -perf_cgroup_from_task(struct task_struct *task) -{ - return container_of(task_subsys_state(task, perf_subsys_id), - struct perf_cgroup, css); -} - -static inline bool -perf_cgroup_match(struct perf_event *event) -{ - struct perf_event_context *ctx = event->ctx; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - - return !event->cgrp || event->cgrp == cpuctx->cgrp; -} - -static inline void perf_get_cgroup(struct perf_event *event) -{ - css_get(&event->cgrp->css); -} - -static inline void perf_put_cgroup(struct perf_event *event) -{ - css_put(&event->cgrp->css); -} - -static inline void perf_detach_cgroup(struct perf_event *event) -{ - perf_put_cgroup(event); - event->cgrp = NULL; -} - -static inline int is_cgroup_event(struct perf_event *event) -{ - return event->cgrp != NULL; -} - -static inline u64 perf_cgroup_event_time(struct perf_event *event) -{ - struct perf_cgroup_info *t; - - t = per_cpu_ptr(event->cgrp->info, event->cpu); - return t->time; -} - -static inline void __update_cgrp_time(struct perf_cgroup *cgrp) -{ - struct perf_cgroup_info *info; - u64 now; - - now = perf_clock(); - - info = this_cpu_ptr(cgrp->info); - - info->time += now - info->timestamp; - info->timestamp = now; -} - -static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) -{ - struct perf_cgroup *cgrp_out = cpuctx->cgrp; - if (cgrp_out) - __update_cgrp_time(cgrp_out); -} - -static inline void update_cgrp_time_from_event(struct perf_event *event) -{ - struct perf_cgroup *cgrp; - - /* - * ensure we access cgroup data only when needed and - * when we know the cgroup is pinned (css_get) - */ - if (!is_cgroup_event(event)) - return; - - cgrp = perf_cgroup_from_task(current); - /* - * Do not update time when cgroup is not active - */ - if (cgrp == event->cgrp) - __update_cgrp_time(event->cgrp); -} - -static inline void -perf_cgroup_set_timestamp(struct task_struct *task, - struct perf_event_context *ctx) -{ - struct perf_cgroup *cgrp; - struct perf_cgroup_info *info; - - /* - * ctx->lock held by caller - * ensure we do not access cgroup data - * unless we have the cgroup pinned (css_get) - */ - if (!task || !ctx->nr_cgroups) - return; - - cgrp = perf_cgroup_from_task(task); - info = this_cpu_ptr(cgrp->info); - info->timestamp = ctx->timestamp; -} - -#define PERF_CGROUP_SWOUT 0x1 /* cgroup switch out every event */ -#define PERF_CGROUP_SWIN 0x2 /* cgroup switch in events based on task */ - -/* - * reschedule events based on the cgroup constraint of task. - * - * mode SWOUT : schedule out everything - * mode SWIN : schedule in based on cgroup for next - */ -void perf_cgroup_switch(struct task_struct *task, int mode) -{ - struct perf_cpu_context *cpuctx; - struct pmu *pmu; - unsigned long flags; - - /* - * disable interrupts to avoid geting nr_cgroup - * changes via __perf_event_disable(). Also - * avoids preemption. - */ - local_irq_save(flags); - - /* - * we reschedule only in the presence of cgroup - * constrained events. - */ - rcu_read_lock(); - - list_for_each_entry_rcu(pmu, &pmus, entry) { - - cpuctx = this_cpu_ptr(pmu->pmu_cpu_context); - - perf_pmu_disable(cpuctx->ctx.pmu); - - /* - * perf_cgroup_events says at least one - * context on this CPU has cgroup events. - * - * ctx->nr_cgroups reports the number of cgroup - * events for a context. - */ - if (cpuctx->ctx.nr_cgroups > 0) { - - if (mode & PERF_CGROUP_SWOUT) { - cpu_ctx_sched_out(cpuctx, EVENT_ALL); - /* - * must not be done before ctxswout due - * to event_filter_match() in event_sched_out() - */ - cpuctx->cgrp = NULL; - } - - if (mode & PERF_CGROUP_SWIN) { - /* set cgrp before ctxsw in to - * allow event_filter_match() to not - * have to pass task around - */ - cpuctx->cgrp = perf_cgroup_from_task(task); - cpu_ctx_sched_in(cpuctx, EVENT_ALL, task); - } - } - - perf_pmu_enable(cpuctx->ctx.pmu); - } - - rcu_read_unlock(); - - local_irq_restore(flags); -} - -static inline void perf_cgroup_sched_out(struct task_struct *task) -{ - perf_cgroup_switch(task, PERF_CGROUP_SWOUT); -} - -static inline void perf_cgroup_sched_in(struct task_struct *task) -{ - perf_cgroup_switch(task, PERF_CGROUP_SWIN); -} - -static inline int perf_cgroup_connect(int fd, struct perf_event *event, - struct perf_event_attr *attr, - struct perf_event *group_leader) -{ - struct perf_cgroup *cgrp; - struct cgroup_subsys_state *css; - struct file *file; - int ret = 0, fput_needed; - - file = fget_light(fd, &fput_needed); - if (!file) - return -EBADF; - - css = cgroup_css_from_dir(file, perf_subsys_id); - if (IS_ERR(css)) - return PTR_ERR(css); - - cgrp = container_of(css, struct perf_cgroup, css); - event->cgrp = cgrp; - - /* - * all events in a group must monitor - * the same cgroup because a task belongs - * to only one perf cgroup at a time - */ - if (group_leader && group_leader->cgrp != cgrp) { - perf_detach_cgroup(event); - ret = -EINVAL; - } else { - /* must be done before we fput() the file */ - perf_get_cgroup(event); - } - fput_light(file, fput_needed); - return ret; -} - -static inline void -perf_cgroup_set_shadow_time(struct perf_event *event, u64 now) -{ - struct perf_cgroup_info *t; - t = per_cpu_ptr(event->cgrp->info, event->cpu); - event->shadow_ctx_time = now - t->timestamp; -} - -static inline void -perf_cgroup_defer_enabled(struct perf_event *event) -{ - /* - * when the current task's perf cgroup does not match - * the event's, we need to remember to call the - * perf_mark_enable() function the first time a task with - * a matching perf cgroup is scheduled in. - */ - if (is_cgroup_event(event) && !perf_cgroup_match(event)) - event->cgrp_defer_enabled = 1; -} - -static inline void -perf_cgroup_mark_enabled(struct perf_event *event, - struct perf_event_context *ctx) -{ - struct perf_event *sub; - u64 tstamp = perf_event_time(event); - - if (!event->cgrp_defer_enabled) - return; - - event->cgrp_defer_enabled = 0; - - event->tstamp_enabled = tstamp - event->total_time_enabled; - list_for_each_entry(sub, &event->sibling_list, group_entry) { - if (sub->state >= PERF_EVENT_STATE_INACTIVE) { - sub->tstamp_enabled = tstamp - sub->total_time_enabled; - sub->cgrp_defer_enabled = 0; - } - } -} -#else /* !CONFIG_CGROUP_PERF */ - -static inline bool -perf_cgroup_match(struct perf_event *event) -{ - return true; -} - -static inline void perf_detach_cgroup(struct perf_event *event) -{} - -static inline int is_cgroup_event(struct perf_event *event) -{ - return 0; -} - -static inline u64 perf_cgroup_event_cgrp_time(struct perf_event *event) -{ - return 0; -} - -static inline void update_cgrp_time_from_event(struct perf_event *event) -{ -} - -static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx) -{ -} - -static inline void perf_cgroup_sched_out(struct task_struct *task) -{ -} - -static inline void perf_cgroup_sched_in(struct task_struct *task) -{ -} - -static inline int perf_cgroup_connect(pid_t pid, struct perf_event *event, - struct perf_event_attr *attr, - struct perf_event *group_leader) -{ - return -EINVAL; -} - -static inline void -perf_cgroup_set_timestamp(struct task_struct *task, - struct perf_event_context *ctx) -{ -} - -void -perf_cgroup_switch(struct task_struct *task, struct task_struct *next) -{ -} - -static inline void -perf_cgroup_set_shadow_time(struct perf_event *event, u64 now) -{ -} - -static inline u64 perf_cgroup_event_time(struct perf_event *event) -{ - return 0; -} - -static inline void -perf_cgroup_defer_enabled(struct perf_event *event) -{ -} - -static inline void -perf_cgroup_mark_enabled(struct perf_event *event, - struct perf_event_context *ctx) -{ -} -#endif - void perf_pmu_disable(struct pmu *pmu) { int *count = this_cpu_ptr(pmu->pmu_disable_count); @@ -709,6 +254,7 @@ static void perf_unpin_context(struct perf_event_context *ctx) raw_spin_lock_irqsave(&ctx->lock, flags); --ctx->pin_count; raw_spin_unlock_irqrestore(&ctx->lock, flags); + put_ctx(ctx); } /* @@ -725,10 +271,6 @@ static void update_context_time(struct perf_event_context *ctx) static u64 perf_event_time(struct perf_event *event) { struct perf_event_context *ctx = event->ctx; - - if (is_cgroup_event(event)) - return perf_cgroup_event_time(event); - return ctx ? ctx->time : 0; } @@ -743,20 +285,9 @@ static void update_event_times(struct perf_event *event) if (event->state < PERF_EVENT_STATE_INACTIVE || event->group_leader->state < PERF_EVENT_STATE_INACTIVE) return; - /* - * in cgroup mode, time_enabled represents - * the time the event was enabled AND active - * tasks were in the monitored cgroup. This is - * independent of the activity of the context as - * there may be a mix of cgroup and non-cgroup events. - * - * That is why we treat cgroup events differently - * here. - */ - if (is_cgroup_event(event)) + + if (ctx->is_active) run_end = perf_event_time(event); - else if (ctx->is_active) - run_end = ctx->time; else run_end = event->tstamp_stopped; @@ -768,7 +299,6 @@ static void update_event_times(struct perf_event *event) run_end = perf_event_time(event); event->total_time_running = run_end - event->tstamp_running; - } /* @@ -817,17 +347,6 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx) list_add_tail(&event->group_entry, list); } - if (is_cgroup_event(event)) { - ctx->nr_cgroups++; - /* - * one more event: - * - that has cgroup constraint on event->cpu - * - that may need work on context switch - */ - atomic_inc(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_inc(&perf_sched_events); - } - list_add_rcu(&event->event_entry, &ctx->event_list); if (!ctx->nr_events) perf_pmu_rotate_start(ctx->pmu); @@ -954,12 +473,6 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx) event->attach_state &= ~PERF_ATTACH_CONTEXT; - if (is_cgroup_event(event)) { - ctx->nr_cgroups--; - atomic_dec(&per_cpu(perf_cgroup_events, event->cpu)); - jump_label_dec(&perf_sched_events); - } - ctx->nr_events--; if (event->attr.inherit_stat) ctx->nr_stat--; @@ -1031,8 +544,7 @@ static void perf_group_detach(struct perf_event *event) static inline int event_filter_match(struct perf_event *event) { - return (event->cpu == -1 || event->cpu == smp_processor_id()) - && perf_cgroup_match(event); + return event->cpu == -1 || event->cpu == smp_processor_id(); } static void @@ -1050,7 +562,7 @@ event_sched_out(struct perf_event *event, */ if (event->state == PERF_EVENT_STATE_INACTIVE && !event_filter_match(event)) { - delta = tstamp - event->tstamp_stopped; + delta = ctx->time - event->tstamp_stopped; event->tstamp_running += delta; event->tstamp_stopped = tstamp; } @@ -1094,30 +606,47 @@ group_sched_out(struct perf_event *group_event, cpuctx->exclusive = 0; } +static inline struct perf_cpu_context * +__get_cpu_context(struct perf_event_context *ctx) +{ + return this_cpu_ptr(ctx->pmu->pmu_cpu_context); +} + /* * Cross CPU call to remove a performance event * * We disable the event on the hardware level first. After that we * remove it from the context list. */ -static int __perf_remove_from_context(void *info) +static void __perf_event_remove_from_context(void *info) { struct perf_event *event = info; struct perf_event_context *ctx = event->ctx; struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); + /* + * If this is a task context, we need to check whether it is + * the current task context of this cpu. If not it has been + * scheduled out before the smp call arrived. + */ + if (ctx->task && cpuctx->task_ctx != ctx) + return; + raw_spin_lock(&ctx->lock); + event_sched_out(event, cpuctx, ctx); + list_del_event(event, ctx); - raw_spin_unlock(&ctx->lock); - return 0; + raw_spin_unlock(&ctx->lock); } /* * Remove the event from a task's (or a CPU's) list of events. * + * Must be called with ctx->mutex held. + * * CPU events are removed with a smp call. For task events we only * call when the task is on a CPU. * @@ -1128,48 +657,49 @@ static int __perf_remove_from_context(void *info) * When called from perf_event_exit_task, it's OK because the * context has been detached from its task. */ -static void perf_remove_from_context(struct perf_event *event) +static void perf_event_remove_from_context(struct perf_event *event) { struct perf_event_context *ctx = event->ctx; struct task_struct *task = ctx->task; - lockdep_assert_held(&ctx->mutex); - if (!task) { /* * Per cpu events are removed via an smp call and * the removal is always successful. */ - cpu_function_call(event->cpu, __perf_remove_from_context, event); + smp_call_function_single(event->cpu, + __perf_event_remove_from_context, + event, 1); return; } retry: - if (!task_function_call(task, __perf_remove_from_context, event)) - return; + task_oncpu_function_call(task, __perf_event_remove_from_context, + event); raw_spin_lock_irq(&ctx->lock); /* - * If we failed to find a running task, but find the context active now - * that we've acquired the ctx->lock, retry. + * If the context is active we need to retry the smp call. */ - if (ctx->is_active) { + if (ctx->nr_active && !list_empty(&event->group_entry)) { raw_spin_unlock_irq(&ctx->lock); goto retry; } /* - * Since the task isn't running, its safe to remove the event, us - * holding the ctx->lock ensures the task won't get scheduled in. + * The lock prevents that this context is scheduled in so we + * can remove the event safely, if the call above did not + * succeed. */ - list_del_event(event, ctx); + if (!list_empty(&event->group_entry)) + list_del_event(event, ctx); raw_spin_unlock_irq(&ctx->lock); } /* * Cross CPU call to disable a performance event */ -static int __perf_event_disable(void *info) +static void __perf_event_disable(void *info) { struct perf_event *event = info; struct perf_event_context *ctx = event->ctx; @@ -1178,12 +708,9 @@ static int __perf_event_disable(void *info) /* * If this is a per-task event, need to check whether this * event's task is the current task on this cpu. - * - * Can trigger due to concurrent perf_event_context_sched_out() - * flipping contexts around. */ if (ctx->task && cpuctx->task_ctx != ctx) - return -EINVAL; + return; raw_spin_lock(&ctx->lock); @@ -1193,7 +720,6 @@ static int __perf_event_disable(void *info) */ if (event->state >= PERF_EVENT_STATE_INACTIVE) { update_context_time(ctx); - update_cgrp_time_from_event(event); update_group_times(event); if (event == event->group_leader) group_sched_out(event, cpuctx, ctx); @@ -1203,8 +729,6 @@ static int __perf_event_disable(void *info) } raw_spin_unlock(&ctx->lock); - - return 0; } /* @@ -1229,13 +753,13 @@ void perf_event_disable(struct perf_event *event) /* * Disable the event on the cpu that it's on */ - cpu_function_call(event->cpu, __perf_event_disable, event); + smp_call_function_single(event->cpu, __perf_event_disable, + event, 1); return; } retry: - if (!task_function_call(task, __perf_event_disable, event)) - return; + task_oncpu_function_call(task, __perf_event_disable, event); raw_spin_lock_irq(&ctx->lock); /* @@ -1243,11 +767,6 @@ void perf_event_disable(struct perf_event *event) */ if (event->state == PERF_EVENT_STATE_ACTIVE) { raw_spin_unlock_irq(&ctx->lock); - /* - * Reload the task pointer, it might have been changed by - * a concurrent perf_event_context_sched_out(). - */ - task = ctx->task; goto retry; } @@ -1259,42 +778,8 @@ void perf_event_disable(struct perf_event *event) update_group_times(event); event->state = PERF_EVENT_STATE_OFF; } - raw_spin_unlock_irq(&ctx->lock); -} -static void perf_set_shadow_time(struct perf_event *event, - struct perf_event_context *ctx, - u64 tstamp) -{ - /* - * use the correct time source for the time snapshot - * - * We could get by without this by leveraging the - * fact that to get to this function, the caller - * has most likely already called update_context_time() - * and update_cgrp_time_xx() and thus both timestamp - * are identical (or very close). Given that tstamp is, - * already adjusted for cgroup, we could say that: - * tstamp - ctx->timestamp - * is equivalent to - * tstamp - cgrp->timestamp. - * - * Then, in perf_output_read(), the calculation would - * work with no changes because: - * - event is guaranteed scheduled in - * - no scheduled out in between - * - thus the timestamp would be the same - * - * But this is a bit hairy. - * - * So instead, we have an explicit cgroup call to remain - * within the time time source all along. We believe it - * is cleaner and simpler to understand. - */ - if (is_cgroup_event(event)) - perf_cgroup_set_shadow_time(event, tstamp); - else - event->shadow_ctx_time = tstamp - ctx->timestamp; + raw_spin_unlock_irq(&ctx->lock); } #define MAX_INTERRUPTS (~0ULL) @@ -1337,7 +822,7 @@ event_sched_in(struct perf_event *event, event->tstamp_running += tstamp - event->tstamp_stopped; - perf_set_shadow_time(event, ctx, tstamp); + event->shadow_ctx_time = tstamp - ctx->timestamp; if (!is_software_event(event)) cpuctx->active_oncpu++; @@ -1458,15 +943,12 @@ static void add_event_to_ctx(struct perf_event *event, event->tstamp_stopped = tstamp; } -static void perf_event_context_sched_in(struct perf_event_context *ctx, - struct task_struct *tsk); - /* * Cross CPU call to install and enable a performance event * * Must be called with ctx->mutex held */ -static int __perf_install_in_context(void *info) +static void __perf_install_in_context(void *info) { struct perf_event *event = info; struct perf_event_context *ctx = event->ctx; @@ -1475,22 +957,21 @@ static int __perf_install_in_context(void *info) int err; /* - * In case we're installing a new context to an already running task, - * could also happen before perf_event_task_sched_in() on architectures - * which do context switches with IRQs enabled. + * If this is a task context, we need to check whether it is + * the current task context of this cpu. If not it has been + * scheduled out before the smp call arrived. + * Or possibly this is the right context but it isn't + * on this cpu because it had no events. */ - if (ctx->task && !cpuctx->task_ctx) - perf_event_context_sched_in(ctx, ctx->task); + if (ctx->task && cpuctx->task_ctx != ctx) { + if (cpuctx->task_ctx || ctx->task != current) + return; + cpuctx->task_ctx = ctx; + } raw_spin_lock(&ctx->lock); ctx->is_active = 1; update_context_time(ctx); - /* - * update cgrp time only if current cgrp - * matches event->cgrp. Must be done before - * calling add_event_to_ctx() - */ - update_cgrp_time_from_event(event); add_event_to_ctx(event, ctx); @@ -1531,8 +1012,6 @@ static int __perf_install_in_context(void *info) unlock: raw_spin_unlock(&ctx->lock); - - return 0; } /* @@ -1544,6 +1023,8 @@ static int __perf_install_in_context(void *info) * If the event is attached to a task which is on a CPU we use a smp * call to enable it in the task context. The task might have been * scheduled away, but we check this in the smp call again. + * + * Must be called with ctx->mutex held. */ static void perf_install_in_context(struct perf_event_context *ctx, @@ -1552,8 +1033,6 @@ perf_install_in_context(struct perf_event_context *ctx, { struct task_struct *task = ctx->task; - lockdep_assert_held(&ctx->mutex); - event->ctx = ctx; if (!task) { @@ -1561,29 +1040,31 @@ perf_install_in_context(struct perf_event_context *ctx, * Per cpu events are installed via an smp call and * the install is always successful. */ - cpu_function_call(cpu, __perf_install_in_context, event); + smp_call_function_single(cpu, __perf_install_in_context, + event, 1); return; } retry: - if (!task_function_call(task, __perf_install_in_context, event)) - return; + task_oncpu_function_call(task, __perf_install_in_context, + event); raw_spin_lock_irq(&ctx->lock); /* - * If we failed to find a running task, but find the context active now - * that we've acquired the ctx->lock, retry. + * we need to retry the smp call. */ - if (ctx->is_active) { + if (ctx->is_active && list_empty(&event->group_entry)) { raw_spin_unlock_irq(&ctx->lock); goto retry; } /* - * Since the task isn't running, its safe to add the event, us holding - * the ctx->lock ensures the task won't get scheduled in. + * The lock prevents that this context is scheduled in so we + * can add the event safely, if it the call above did not + * succeed. */ - add_event_to_ctx(event, ctx); + if (list_empty(&event->group_entry)) + add_event_to_ctx(event, ctx); raw_spin_unlock_irq(&ctx->lock); } @@ -1612,7 +1093,7 @@ static void __perf_event_mark_enabled(struct perf_event *event, /* * Cross CPU call to enable a performance event */ -static int __perf_event_enable(void *info) +static void __perf_event_enable(void *info) { struct perf_event *event = info; struct perf_event_context *ctx = event->ctx; @@ -1620,27 +1101,26 @@ static int __perf_event_enable(void *info) struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); int err; - if (WARN_ON_ONCE(!ctx->is_active)) - return -EINVAL; + /* + * If this is a per-task event, need to check whether this + * event's task is the current task on this cpu. + */ + if (ctx->task && cpuctx->task_ctx != ctx) { + if (cpuctx->task_ctx || ctx->task != current) + return; + cpuctx->task_ctx = ctx; + } raw_spin_lock(&ctx->lock); + ctx->is_active = 1; update_context_time(ctx); if (event->state >= PERF_EVENT_STATE_INACTIVE) goto unlock; - - /* - * set current task's cgroup time reference point - */ - perf_cgroup_set_timestamp(current, ctx); - __perf_event_mark_enabled(event, ctx); - if (!event_filter_match(event)) { - if (is_cgroup_event(event)) - perf_cgroup_defer_enabled(event); + if (!event_filter_match(event)) goto unlock; - } /* * If the event is in a group and isn't the group leader, @@ -1673,8 +1153,6 @@ static int __perf_event_enable(void *info) unlock: raw_spin_unlock(&ctx->lock); - - return 0; } /* @@ -1695,7 +1173,8 @@ void perf_event_enable(struct perf_event *event) /* * Enable the event on the cpu that it's on */ - cpu_function_call(event->cpu, __perf_event_enable, event); + smp_call_function_single(event->cpu, __perf_event_enable, + event, 1); return; } @@ -1714,15 +1193,8 @@ void perf_event_enable(struct perf_event *event) event->state = PERF_EVENT_STATE_OFF; retry: - if (!ctx->is_active) { - __perf_event_mark_enabled(event, ctx); - goto out; - } - raw_spin_unlock_irq(&ctx->lock); - - if (!task_function_call(task, __perf_event_enable, event)) - return; + task_oncpu_function_call(task, __perf_event_enable, event); raw_spin_lock_irq(&ctx->lock); @@ -1730,14 +1202,15 @@ void perf_event_enable(struct perf_event *event) * If the context is active and the event is still off, * we need to retry the cross-call. */ - if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF) { - /* - * task could have been flipped by a concurrent - * perf_event_context_sched_out() - */ - task = ctx->task; + if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF) goto retry; - } + + /* + * Since we have the lock this context can't be scheduled + * in, so we can change the state safely. + */ + if (event->state == PERF_EVENT_STATE_OFF) + __perf_event_mark_enabled(event, ctx); out: raw_spin_unlock_irq(&ctx->lock); @@ -1769,7 +1242,6 @@ static void ctx_sched_out(struct perf_event_context *ctx, if (likely(!ctx->nr_events)) goto out; update_context_time(ctx); - update_cgrp_time_from_cpuctx(cpuctx); if (!ctx->nr_active) goto out; @@ -1882,8 +1354,8 @@ static void perf_event_sync_stat(struct perf_event_context *ctx, } } -static void perf_event_context_sched_out(struct task_struct *task, int ctxn, - struct task_struct *next) +void perf_event_context_sched_out(struct task_struct *task, int ctxn, + struct task_struct *next) { struct perf_event_context *ctx = task->perf_event_ctxp[ctxn]; struct perf_event_context *next_ctx; @@ -1959,14 +1431,6 @@ void __perf_event_task_sched_out(struct task_struct *task, for_each_task_context_nr(ctxn) perf_event_context_sched_out(task, ctxn, next); - - /* - * if cgroup events exist on this CPU, then we need - * to check if we have to switch out PMU state. - * cgroup event are system-wide mode only - */ - if (atomic_read(&__get_cpu_var(perf_cgroup_events))) - perf_cgroup_sched_out(task); } static void task_ctx_sched_out(struct perf_event_context *ctx, @@ -2005,10 +1469,6 @@ ctx_pinned_sched_in(struct perf_event_context *ctx, if (!event_filter_match(event)) continue; - /* may need to reset tstamp_enabled */ - if (is_cgroup_event(event)) - perf_cgroup_mark_enabled(event, ctx); - if (group_can_go_on(event, cpuctx, 1)) group_sched_in(event, cpuctx, ctx); @@ -2041,10 +1501,6 @@ ctx_flexible_sched_in(struct perf_event_context *ctx, if (!event_filter_match(event)) continue; - /* may need to reset tstamp_enabled */ - if (is_cgroup_event(event)) - perf_cgroup_mark_enabled(event, ctx); - if (group_can_go_on(event, cpuctx, can_add_hw)) { if (group_sched_in(event, cpuctx, ctx)) can_add_hw = 0; @@ -2055,19 +1511,15 @@ ctx_flexible_sched_in(struct perf_event_context *ctx, static void ctx_sched_in(struct perf_event_context *ctx, struct perf_cpu_context *cpuctx, - enum event_type_t event_type, - struct task_struct *task) + enum event_type_t event_type) { - u64 now; - raw_spin_lock(&ctx->lock); ctx->is_active = 1; if (likely(!ctx->nr_events)) goto out; - now = perf_clock(); - ctx->timestamp = now; - perf_cgroup_set_timestamp(task, ctx); + ctx->timestamp = perf_clock(); + /* * First go through the list and put on any pinned groups * in order to give them the best chance of going on. @@ -2084,12 +1536,11 @@ ctx_sched_in(struct perf_event_context *ctx, } static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx, - enum event_type_t event_type, - struct task_struct *task) + enum event_type_t event_type) { struct perf_event_context *ctx = &cpuctx->ctx; - ctx_sched_in(ctx, cpuctx, event_type, task); + ctx_sched_in(ctx, cpuctx, event_type); } static void task_ctx_sched_in(struct perf_event_context *ctx, @@ -2097,16 +1548,15 @@ static void task_ctx_sched_in(struct perf_event_context *ctx, { struct perf_cpu_context *cpuctx; - cpuctx = __get_cpu_context(ctx); + cpuctx = __get_cpu_context(ctx); if (cpuctx->task_ctx == ctx) return; - ctx_sched_in(ctx, cpuctx, event_type, NULL); + ctx_sched_in(ctx, cpuctx, event_type); cpuctx->task_ctx = ctx; } -static void perf_event_context_sched_in(struct perf_event_context *ctx, - struct task_struct *task) +void perf_event_context_sched_in(struct perf_event_context *ctx) { struct perf_cpu_context *cpuctx; @@ -2122,9 +1572,9 @@ static void perf_event_context_sched_in(struct perf_event_context *ctx, */ cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE); - ctx_sched_in(ctx, cpuctx, EVENT_PINNED, task); - cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, task); - ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task); + ctx_sched_in(ctx, cpuctx, EVENT_PINNED); + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE); + ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE); cpuctx->task_ctx = ctx; @@ -2157,15 +1607,8 @@ void __perf_event_task_sched_in(struct task_struct *task) if (likely(!ctx)) continue; - perf_event_context_sched_in(ctx, task); + perf_event_context_sched_in(ctx); } - /* - * if cgroup events exist on this CPU, then we need - * to check if we have to switch in PMU state. - * cgroup event are system-wide mode only - */ - if (atomic_read(&__get_cpu_var(perf_cgroup_events))) - perf_cgroup_sched_in(task); } static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) @@ -2195,7 +1638,7 @@ static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count) * Reduce accuracy by one bit such that @a and @b converge * to a similar magnitude. */ -#define REDUCE_FLS(a, b) \ +#define REDUCE_FLS(a, b) \ do { \ if (a##_fls > b##_fls) { \ a >>= 1; \ @@ -2365,7 +1808,7 @@ static void perf_rotate_context(struct perf_cpu_context *cpuctx) if (ctx) rotate_ctx(ctx); - cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE, current); + cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE); if (ctx) task_ctx_sched_in(ctx, EVENT_FLEXIBLE); @@ -2444,7 +1887,7 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx) raw_spin_unlock(&ctx->lock); - perf_event_context_sched_in(ctx, ctx->task); + perf_event_context_sched_in(ctx); out: local_irq_restore(flags); } @@ -2469,10 +1912,8 @@ static void __perf_event_read(void *info) return; raw_spin_lock(&ctx->lock); - if (ctx->is_active) { + if (ctx->is_active) update_context_time(ctx); - update_cgrp_time_from_event(event); - } update_event_times(event); if (event->state == PERF_EVENT_STATE_ACTIVE) event->pmu->read(event); @@ -2503,10 +1944,8 @@ static u64 perf_event_read(struct perf_event *event) * (e.g., thread is blocked), in that case * we cannot update context time */ - if (ctx->is_active) { + if (ctx->is_active) update_context_time(ctx); - update_cgrp_time_from_event(event); - } update_event_times(event); raw_spin_unlock_irqrestore(&ctx->lock, flags); } @@ -2785,9 +2224,6 @@ find_lively_task_by_vpid(pid_t vpid) } -/* - * Returns a matching context with refcount and pincount. - */ static struct perf_event_context * find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) { @@ -2812,7 +2248,6 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); ctx = &cpuctx->ctx; get_ctx(ctx); - ++ctx->pin_count; return ctx; } @@ -2826,7 +2261,6 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) ctx = perf_lock_task_context(task, ctxn, &flags); if (ctx) { unclone_ctx(ctx); - ++ctx->pin_count; raw_spin_unlock_irqrestore(&ctx->lock, flags); } @@ -2848,10 +2282,8 @@ find_get_context(struct pmu *pmu, struct task_struct *task, int cpu) err = -ESRCH; else if (task->perf_event_ctxp[ctxn]) err = -EAGAIN; - else { - ++ctx->pin_count; + else rcu_assign_pointer(task->perf_event_ctxp[ctxn], ctx); - } mutex_unlock(&task->perf_event_mutex); if (unlikely(err)) { @@ -2891,7 +2323,7 @@ static void free_event(struct perf_event *event) if (!event->parent) { if (event->attach_state & PERF_ATTACH_TASK) - jump_label_dec(&perf_sched_events); + jump_label_dec(&perf_task_events); if (event->attr.mmap || event->attr.mmap_data) atomic_dec(&nr_mmap_events); if (event->attr.comm) @@ -2907,9 +2339,6 @@ static void free_event(struct perf_event *event) event->buffer = NULL; } - if (is_cgroup_event(event)) - perf_detach_cgroup(event); - if (event->destroy) event->destroy(event); @@ -4977,14 +4406,26 @@ static int __perf_event_overflow(struct perf_event *event, int nmi, if (unlikely(!is_sampling_event(event))) return 0; - if (unlikely(hwc->interrupts >= max_samples_per_tick)) { - if (throttle) { - hwc->interrupts = MAX_INTERRUPTS; - perf_log_throttle(event, 0); + if (!throttle) { + hwc->interrupts++; + } else { + if (hwc->interrupts != MAX_INTERRUPTS) { + hwc->interrupts++; + if (HZ * hwc->interrupts > + (u64)sysctl_perf_event_sample_rate) { + hwc->interrupts = MAX_INTERRUPTS; + perf_log_throttle(event, 0); + ret = 1; + } + } else { + /* + * Keep re-disabling events even though on the previous + * pass we disabled it - just in case we raced with a + * sched-in and the event got enabled again: + */ ret = 1; } - } else - hwc->interrupts++; + } if (event->attr.freq) { u64 now = perf_clock(); @@ -5621,10 +5062,6 @@ static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer) u64 period; event = container_of(hrtimer, struct perf_event, hw.hrtimer); - - if (event->state != PERF_EVENT_STATE_ACTIVE) - return HRTIMER_NORESTART; - event->pmu->read(event); perf_sample_data_init(&data, 0); @@ -5651,6 +5088,9 @@ static void perf_swevent_start_hrtimer(struct perf_event *event) if (!is_sampling_event(event)) return; + hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + hwc->hrtimer.function = perf_swevent_hrtimer; + period = local64_read(&hwc->period_left); if (period) { if (period < 0) @@ -5677,30 +5117,6 @@ static void perf_swevent_cancel_hrtimer(struct perf_event *event) } } -static void perf_swevent_init_hrtimer(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - - if (!is_sampling_event(event)) - return; - - hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hwc->hrtimer.function = perf_swevent_hrtimer; - - /* - * Since hrtimers have a fixed rate, we can do a static freq->period - * mapping and avoid the whole period adjust feedback stuff. - */ - if (event->attr.freq) { - long freq = event->attr.sample_freq; - - event->attr.sample_period = NSEC_PER_SEC / freq; - hwc->sample_period = event->attr.sample_period; - local64_set(&hwc->period_left, hwc->sample_period); - event->attr.freq = 0; - } -} - /* * Software event: cpu wall time clock */ @@ -5753,8 +5169,6 @@ static int cpu_clock_event_init(struct perf_event *event) if (event->attr.config != PERF_COUNT_SW_CPU_CLOCK) return -ENOENT; - perf_swevent_init_hrtimer(event); - return 0; } @@ -5810,9 +5224,16 @@ static void task_clock_event_del(struct perf_event *event, int flags) static void task_clock_event_read(struct perf_event *event) { - u64 now = perf_clock(); - u64 delta = now - event->ctx->timestamp; - u64 time = event->ctx->time + delta; + u64 time; + + if (!in_nmi()) { + update_context_time(event->ctx); + time = event->ctx->time; + } else { + u64 now = perf_clock(); + u64 delta = now - event->ctx->timestamp; + time = event->ctx->time + delta; + } task_clock_event_update(event, time); } @@ -5825,8 +5246,6 @@ static int task_clock_event_init(struct perf_event *event) if (event->attr.config != PERF_COUNT_SW_TASK_CLOCK) return -ENOENT; - perf_swevent_init_hrtimer(event); - return 0; } @@ -6234,7 +5653,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); + jump_label_inc(&perf_task_events); if (event->attr.mmap || event->attr.mmap_data) atomic_inc(&nr_mmap_events); if (event->attr.comm) @@ -6409,7 +5828,7 @@ SYSCALL_DEFINE5(perf_event_open, int err; /* for future expandability... */ - if (flags & ~PERF_FLAG_ALL) + if (flags & ~(PERF_FLAG_FD_NO_GROUP | PERF_FLAG_FD_OUTPUT)) return -EINVAL; err = perf_copy_attr(attr_uptr, &attr); @@ -6426,15 +5845,6 @@ SYSCALL_DEFINE5(perf_event_open, return -EINVAL; } - /* - * In cgroup mode, the pid argument is used to pass the fd - * opened to the cgroup directory in cgroupfs. The cpu argument - * designates the cpu on which to monitor threads from that - * cgroup. - */ - if ((flags & PERF_FLAG_PID_CGROUP) && (pid == -1 || cpu == -1)) - return -EINVAL; - event_fd = get_unused_fd_flags(O_RDWR); if (event_fd < 0) return event_fd; @@ -6452,7 +5862,7 @@ SYSCALL_DEFINE5(perf_event_open, group_leader = NULL; } - if (pid != -1 && !(flags & PERF_FLAG_PID_CGROUP)) { + if (pid != -1) { task = find_lively_task_by_vpid(pid); if (IS_ERR(task)) { err = PTR_ERR(task); @@ -6466,12 +5876,6 @@ SYSCALL_DEFINE5(perf_event_open, goto err_task; } - if (flags & PERF_FLAG_PID_CGROUP) { - err = perf_cgroup_connect(pid, event, &attr, group_leader); - if (err) - goto err_alloc; - } - /* * Special case software events and allow them to be part of * any hardware group. @@ -6557,10 +5961,10 @@ SYSCALL_DEFINE5(perf_event_open, struct perf_event_context *gctx = group_leader->ctx; mutex_lock(&gctx->mutex); - perf_remove_from_context(group_leader); + perf_event_remove_from_context(group_leader); list_for_each_entry(sibling, &group_leader->sibling_list, group_entry) { - perf_remove_from_context(sibling); + perf_event_remove_from_context(sibling); put_ctx(gctx); } mutex_unlock(&gctx->mutex); @@ -6583,7 +5987,6 @@ SYSCALL_DEFINE5(perf_event_open, perf_install_in_context(ctx, event, cpu); ++ctx->generation; - perf_unpin_context(ctx); mutex_unlock(&ctx->mutex); event->owner = current; @@ -6609,7 +6012,6 @@ SYSCALL_DEFINE5(perf_event_open, return event_fd; err_context: - perf_unpin_context(ctx); put_ctx(ctx); err_alloc: free_event(event); @@ -6660,7 +6062,6 @@ perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu, mutex_lock(&ctx->mutex); perf_install_in_context(ctx, event, cpu); ++ctx->generation; - perf_unpin_context(ctx); mutex_unlock(&ctx->mutex); return event; @@ -6714,7 +6115,7 @@ __perf_event_exit_task(struct perf_event *child_event, { struct perf_event *parent_event; - perf_remove_from_context(child_event); + perf_event_remove_from_context(child_event); parent_event = child_event->parent; /* @@ -7021,7 +6422,7 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent, return 0; } - child_ctx = child->perf_event_ctxp[ctxn]; + child_ctx = child->perf_event_ctxp[ctxn]; if (!child_ctx) { /* * This is executed from the parent task context, so @@ -7136,7 +6537,6 @@ int perf_event_init_context(struct task_struct *child, int ctxn) mutex_unlock(&parent_ctx->mutex); perf_unpin_context(parent_ctx); - put_ctx(parent_ctx); return ret; } @@ -7206,9 +6606,9 @@ static void __perf_event_exit_context(void *__info) perf_pmu_rotate_stop(ctx->pmu); list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry) - __perf_remove_from_context(event); + __perf_event_remove_from_context(event); list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry) - __perf_remove_from_context(event); + __perf_event_remove_from_context(event); } static void perf_event_exit_cpu_context(int cpu) @@ -7332,92 +6732,3 @@ static int __init perf_event_sysfs_init(void) return ret; } device_initcall(perf_event_sysfs_init); - -#ifdef CONFIG_CGROUP_PERF -static struct cgroup_subsys_state *perf_cgroup_create( - struct cgroup_subsys *ss, struct cgroup *cont) -{ - struct perf_cgroup *jc; - struct perf_cgroup_info *t; - int c; - - jc = kmalloc(sizeof(*jc), GFP_KERNEL); - if (!jc) - return ERR_PTR(-ENOMEM); - - memset(jc, 0, sizeof(*jc)); - - jc->info = alloc_percpu(struct perf_cgroup_info); - if (!jc->info) { - kfree(jc); - return ERR_PTR(-ENOMEM); - } - - for_each_possible_cpu(c) { - t = per_cpu_ptr(jc->info, c); - t->time = 0; - t->timestamp = 0; - } - return &jc->css; -} - -static void perf_cgroup_destroy(struct cgroup_subsys *ss, - struct cgroup *cont) -{ - struct perf_cgroup *jc; - jc = container_of(cgroup_subsys_state(cont, perf_subsys_id), - struct perf_cgroup, css); - free_percpu(jc->info); - kfree(jc); -} - -static int __perf_cgroup_move(void *info) -{ - struct task_struct *task = info; - perf_cgroup_switch(task, PERF_CGROUP_SWOUT | PERF_CGROUP_SWIN); - return 0; -} - -static void perf_cgroup_move(struct task_struct *task) -{ - task_function_call(task, __perf_cgroup_move, task); -} - -static void perf_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task, - bool threadgroup) -{ - perf_cgroup_move(task); - if (threadgroup) { - struct task_struct *c; - rcu_read_lock(); - list_for_each_entry_rcu(c, &task->thread_group, thread_group) { - perf_cgroup_move(c); - } - rcu_read_unlock(); - } -} - -static void perf_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task) -{ - /* - * cgroup_exit() is called in the copy_process() failure path. - * Ignore this case since the task hasn't ran yet, this avoids - * trying to poke a half freed task state from generic code. - */ - if (!(task->flags & PF_EXITING)) - return; - - perf_cgroup_move(task); -} - -struct cgroup_subsys perf_subsys = { - .name = "perf_event", - .subsys_id = perf_subsys_id, - .create = perf_cgroup_create, - .destroy = perf_cgroup_destroy, - .exit = perf_cgroup_exit, - .attach = perf_cgroup_attach, -}; -#endif /* CONFIG_CGROUP_PERF */ diff --git a/trunk/kernel/power/main.c b/trunk/kernel/power/main.c index 7b5db6a8561e..701853042c28 100644 --- a/trunk/kernel/power/main.c +++ b/trunk/kernel/power/main.c @@ -326,7 +326,7 @@ EXPORT_SYMBOL_GPL(pm_wq); static int __init pm_start_workqueue(void) { - pm_wq = alloc_workqueue("pm", WQ_FREEZEABLE, 0); + pm_wq = alloc_workqueue("pm", WQ_FREEZABLE, 0); return pm_wq ? 0 : -ENOMEM; } diff --git a/trunk/kernel/power/process.c b/trunk/kernel/power/process.c index d6d2a10320e0..0cf3a27a6c9d 100644 --- a/trunk/kernel/power/process.c +++ b/trunk/kernel/power/process.c @@ -22,7 +22,7 @@ */ #define TIMEOUT (20 * HZ) -static inline int freezeable(struct task_struct * p) +static inline int freezable(struct task_struct * p) { if ((p == current) || (p->flags & PF_NOFREEZE) || @@ -53,7 +53,7 @@ static int try_to_freeze_tasks(bool sig_only) todo = 0; read_lock(&tasklist_lock); do_each_thread(g, p) { - if (frozen(p) || !freezeable(p)) + if (frozen(p) || !freezable(p)) continue; if (!freeze_task(p, sig_only)) @@ -167,7 +167,7 @@ static void thaw_tasks(bool nosig_only) read_lock(&tasklist_lock); do_each_thread(g, p) { - if (!freezeable(p)) + if (!freezable(p)) continue; if (nosig_only && should_send_signal(p)) diff --git a/trunk/kernel/power/snapshot.c b/trunk/kernel/power/snapshot.c index 0dac75ea4456..64db648ff911 100644 --- a/trunk/kernel/power/snapshot.c +++ b/trunk/kernel/power/snapshot.c @@ -1519,11 +1519,8 @@ static int swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm, unsigned int nr_pages, unsigned int nr_highmem) { - int error = 0; - if (nr_highmem > 0) { - error = get_highmem_buffer(PG_ANY); - if (error) + if (get_highmem_buffer(PG_ANY)) goto err_out; if (nr_highmem > alloc_highmem) { nr_highmem -= alloc_highmem; @@ -1546,7 +1543,7 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm, err_out: swsusp_free(); - return error; + return -ENOMEM; } asmlinkage int swsusp_save(void) diff --git a/trunk/kernel/sched.c b/trunk/kernel/sched.c index 79e611cd83dd..18d38e4ec7ba 100644 --- a/trunk/kernel/sched.c +++ b/trunk/kernel/sched.c @@ -606,6 +606,9 @@ static inline struct task_group *task_group(struct task_struct *p) struct task_group *tg; struct cgroup_subsys_state *css; + if (p->flags & PF_EXITING) + return &root_task_group; + css = task_subsys_state_check(p, cpu_cgroup_subsys_id, lockdep_is_held(&task_rq(p)->lock)); tg = container_of(css, struct task_group, css); @@ -2262,6 +2265,27 @@ void kick_process(struct task_struct *p) EXPORT_SYMBOL_GPL(kick_process); #endif /* CONFIG_SMP */ +/** + * task_oncpu_function_call - call a function on the cpu on which a task runs + * @p: the task to evaluate + * @func: the function to be called + * @info: the function call argument + * + * Calls the function @func when the task is currently running. This might + * be on the current CPU, which just calls the function directly + */ +void task_oncpu_function_call(struct task_struct *p, + void (*func) (void *info), void *info) +{ + int cpu; + + preempt_disable(); + cpu = task_cpu(p); + if (task_curr(p)) + smp_call_function_single(cpu, func, info, 1); + preempt_enable(); +} + #ifdef CONFIG_SMP /* * ->cpus_allowed is protected by either TASK_WAKING or rq->lock held. @@ -2752,12 +2776,9 @@ static inline void prepare_task_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) { - sched_info_switch(prev, next); - perf_event_task_sched_out(prev, next); fire_sched_out_preempt_notifiers(prev, next); prepare_lock_switch(rq, next); prepare_arch_switch(next); - trace_sched_switch(prev, next); } /** @@ -2890,7 +2911,7 @@ context_switch(struct rq *rq, struct task_struct *prev, struct mm_struct *mm, *oldmm; prepare_task_switch(rq, prev, next); - + trace_sched_switch(prev, next); mm = next->mm; oldmm = prev->active_mm; /* @@ -3968,6 +3989,9 @@ asmlinkage void __sched schedule(void) rq->skip_clock_update = 0; if (likely(prev != next)) { + sched_info_switch(prev, next); + perf_event_task_sched_out(prev, next); + rq->nr_switches++; rq->curr = next; ++*switch_count; @@ -5547,7 +5571,7 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu) * The idle tasks have their own, simple scheduling class: */ idle->sched_class = &idle_sched_class; - ftrace_graph_init_idle_task(idle, cpu); + ftrace_graph_init_task(idle); } /* @@ -8860,8 +8884,7 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, } static void -cpu_cgroup_exit(struct cgroup_subsys *ss, struct cgroup *cgrp, - struct cgroup *old_cgrp, struct task_struct *task) +cpu_cgroup_exit(struct cgroup_subsys *ss, struct task_struct *task) { /* * cgroup_exit() is called in the copy_process() failure path. diff --git a/trunk/kernel/sysctl.c b/trunk/kernel/sysctl.c index daef911cbadb..0f1bd83db985 100644 --- a/trunk/kernel/sysctl.c +++ b/trunk/kernel/sysctl.c @@ -948,7 +948,7 @@ static struct ctl_table kern_table[] = { .data = &sysctl_perf_event_sample_rate, .maxlen = sizeof(sysctl_perf_event_sample_rate), .mode = 0644, - .proc_handler = perf_proc_update_handler, + .proc_handler = proc_dointvec, }, #endif #ifdef CONFIG_KMEMCHECK diff --git a/trunk/kernel/trace/ftrace.c b/trunk/kernel/trace/ftrace.c index 888b611897d3..f3dadae83883 100644 --- a/trunk/kernel/trace/ftrace.c +++ b/trunk/kernel/trace/ftrace.c @@ -3328,7 +3328,7 @@ static int start_graph_tracing(void) /* The cpu_boot init_task->ret_stack will never be freed */ for_each_online_cpu(cpu) { if (!idle_task(cpu)->ret_stack) - ftrace_graph_init_idle_task(idle_task(cpu), cpu); + ftrace_graph_init_task(idle_task(cpu)); } do { @@ -3418,49 +3418,6 @@ void unregister_ftrace_graph(void) mutex_unlock(&ftrace_lock); } -static DEFINE_PER_CPU(struct ftrace_ret_stack *, idle_ret_stack); - -static void -graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack) -{ - atomic_set(&t->tracing_graph_pause, 0); - atomic_set(&t->trace_overrun, 0); - t->ftrace_timestamp = 0; - /* make curr_ret_stack visable before we add the ret_stack */ - smp_wmb(); - t->ret_stack = ret_stack; -} - -/* - * Allocate a return stack for the idle task. May be the first - * time through, or it may be done by CPU hotplug online. - */ -void ftrace_graph_init_idle_task(struct task_struct *t, int cpu) -{ - t->curr_ret_stack = -1; - /* - * The idle task has no parent, it either has its own - * stack or no stack at all. - */ - if (t->ret_stack) - WARN_ON(t->ret_stack != per_cpu(idle_ret_stack, cpu)); - - if (ftrace_graph_active) { - struct ftrace_ret_stack *ret_stack; - - ret_stack = per_cpu(idle_ret_stack, cpu); - if (!ret_stack) { - ret_stack = kmalloc(FTRACE_RETFUNC_DEPTH - * sizeof(struct ftrace_ret_stack), - GFP_KERNEL); - if (!ret_stack) - return; - per_cpu(idle_ret_stack, cpu) = ret_stack; - } - graph_init_task(t, ret_stack); - } -} - /* Allocate a return stack for newly created task */ void ftrace_graph_init_task(struct task_struct *t) { @@ -3476,7 +3433,12 @@ void ftrace_graph_init_task(struct task_struct *t) GFP_KERNEL); if (!ret_stack) return; - graph_init_task(t, ret_stack); + atomic_set(&t->tracing_graph_pause, 0); + atomic_set(&t->trace_overrun, 0); + t->ftrace_timestamp = 0; + /* make curr_ret_stack visable before we add the ret_stack */ + smp_wmb(); + t->ret_stack = ret_stack; } } diff --git a/trunk/kernel/trace/trace.c b/trunk/kernel/trace/trace.c index 8dc8da6733f9..dc53ecb80589 100644 --- a/trunk/kernel/trace/trace.c +++ b/trunk/kernel/trace/trace.c @@ -2710,10 +2710,6 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf, mutex_lock(&trace_types_lock); if (tracer_enabled ^ val) { - - /* Only need to warn if this is used to change the state */ - WARN_ONCE(1, "tracing_enabled is deprecated. Use tracing_on"); - if (val) { tracer_enabled = 1; if (current_trace->start) diff --git a/trunk/kernel/trace/trace.h b/trunk/kernel/trace/trace.h index 856e73cc1d3f..9021f8c0c0c3 100644 --- a/trunk/kernel/trace/trace.h +++ b/trunk/kernel/trace/trace.h @@ -661,10 +661,8 @@ struct ftrace_event_field { }; struct event_filter { - int n_preds; /* Number assigned */ - int a_preds; /* allocated */ - struct filter_pred *preds; - struct filter_pred *root; + int n_preds; + struct filter_pred **preds; char *filter_string; }; @@ -676,23 +674,11 @@ struct event_subsystem { int nr_events; }; -#define FILTER_PRED_INVALID ((unsigned short)-1) -#define FILTER_PRED_IS_RIGHT (1 << 15) -#define FILTER_PRED_FOLD (1 << 15) - -/* - * The max preds is the size of unsigned short with - * two flags at the MSBs. One bit is used for both the IS_RIGHT - * and FOLD flags. The other is reserved. - * - * 2^14 preds is way more than enough. - */ -#define MAX_FILTER_PRED 16384 - struct filter_pred; struct regex; -typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event); +typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, + int val1, int val2); typedef int (*regex_match_func)(char *str, struct regex *r, int len); @@ -714,23 +700,11 @@ struct filter_pred { filter_pred_fn_t fn; u64 val; struct regex regex; - /* - * Leaf nodes use field_name, ops is used by AND and OR - * nodes. The field_name is always freed when freeing a pred. - * We can overload field_name for ops and have it freed - * as well. - */ - union { - char *field_name; - unsigned short *ops; - }; + char *field_name; int offset; int not; int op; - unsigned short index; - unsigned short parent; - unsigned short left; - unsigned short right; + int pop_n; }; extern struct list_head ftrace_common_fields; diff --git a/trunk/kernel/trace/trace_events_filter.c b/trunk/kernel/trace/trace_events_filter.c index 3249b4f77ef0..36d40104b17f 100644 --- a/trunk/kernel/trace/trace_events_filter.c +++ b/trunk/kernel/trace/trace_events_filter.c @@ -123,13 +123,9 @@ struct filter_parse_state { } operand; }; -struct pred_stack { - struct filter_pred **preds; - int index; -}; - #define DEFINE_COMPARISON_PRED(type) \ -static int filter_pred_##type(struct filter_pred *pred, void *event) \ +static int filter_pred_##type(struct filter_pred *pred, void *event, \ + int val1, int val2) \ { \ type *addr = (type *)(event + pred->offset); \ type val = (type)pred->val; \ @@ -156,7 +152,8 @@ static int filter_pred_##type(struct filter_pred *pred, void *event) \ } #define DEFINE_EQUALITY_PRED(size) \ -static int filter_pred_##size(struct filter_pred *pred, void *event) \ +static int filter_pred_##size(struct filter_pred *pred, void *event, \ + int val1, int val2) \ { \ u##size *addr = (u##size *)(event + pred->offset); \ u##size val = (u##size)pred->val; \ @@ -181,8 +178,23 @@ DEFINE_EQUALITY_PRED(32); DEFINE_EQUALITY_PRED(16); DEFINE_EQUALITY_PRED(8); +static int filter_pred_and(struct filter_pred *pred __attribute((unused)), + void *event __attribute((unused)), + int val1, int val2) +{ + return val1 && val2; +} + +static int filter_pred_or(struct filter_pred *pred __attribute((unused)), + void *event __attribute((unused)), + int val1, int val2) +{ + return val1 || val2; +} + /* Filter predicate for fixed sized arrays of characters */ -static int filter_pred_string(struct filter_pred *pred, void *event) +static int filter_pred_string(struct filter_pred *pred, void *event, + int val1, int val2) { char *addr = (char *)(event + pred->offset); int cmp, match; @@ -195,7 +207,8 @@ static int filter_pred_string(struct filter_pred *pred, void *event) } /* Filter predicate for char * pointers */ -static int filter_pred_pchar(struct filter_pred *pred, void *event) +static int filter_pred_pchar(struct filter_pred *pred, void *event, + int val1, int val2) { char **addr = (char **)(event + pred->offset); int cmp, match; @@ -218,7 +231,8 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event) * and add it to the address of the entry, and at last we have * the address of the string. */ -static int filter_pred_strloc(struct filter_pred *pred, void *event) +static int filter_pred_strloc(struct filter_pred *pred, void *event, + int val1, int val2) { u32 str_item = *(u32 *)(event + pred->offset); int str_loc = str_item & 0xffff; @@ -233,7 +247,8 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event) return match; } -static int filter_pred_none(struct filter_pred *pred, void *event) +static int filter_pred_none(struct filter_pred *pred, void *event, + int val1, int val2) { return 0; } @@ -362,147 +377,32 @@ static void filter_build_regex(struct filter_pred *pred) pred->not ^= not; } -enum move_type { - MOVE_DOWN, - MOVE_UP_FROM_LEFT, - MOVE_UP_FROM_RIGHT -}; - -static struct filter_pred * -get_pred_parent(struct filter_pred *pred, struct filter_pred *preds, - int index, enum move_type *move) -{ - if (pred->parent & FILTER_PRED_IS_RIGHT) - *move = MOVE_UP_FROM_RIGHT; - else - *move = MOVE_UP_FROM_LEFT; - pred = &preds[pred->parent & ~FILTER_PRED_IS_RIGHT]; - - return pred; -} - -/* - * A series of AND or ORs where found together. Instead of - * climbing up and down the tree branches, an array of the - * ops were made in order of checks. We can just move across - * the array and short circuit if needed. - */ -static int process_ops(struct filter_pred *preds, - struct filter_pred *op, void *rec) -{ - struct filter_pred *pred; - int type; - int match; - int i; - - /* - * Micro-optimization: We set type to true if op - * is an OR and false otherwise (AND). Then we - * just need to test if the match is equal to - * the type, and if it is, we can short circuit the - * rest of the checks: - * - * if ((match && op->op == OP_OR) || - * (!match && op->op == OP_AND)) - * return match; - */ - type = op->op == OP_OR; - - for (i = 0; i < op->val; i++) { - pred = &preds[op->ops[i]]; - match = pred->fn(pred, rec); - if (!!match == type) - return match; - } - return match; -} - /* return 1 if event matches, 0 otherwise (discard) */ int filter_match_preds(struct event_filter *filter, void *rec) { - int match = -1; - enum move_type move = MOVE_DOWN; - struct filter_pred *preds; + int match, top = 0, val1 = 0, val2 = 0; + int stack[MAX_FILTER_PRED]; struct filter_pred *pred; - struct filter_pred *root; - int n_preds; - int done = 0; - - /* no filter is considered a match */ - if (!filter) - return 1; - - n_preds = filter->n_preds; - - if (!n_preds) - return 1; - - /* - * n_preds, root and filter->preds are protect with preemption disabled. - */ - preds = rcu_dereference_sched(filter->preds); - root = rcu_dereference_sched(filter->root); - if (!root) - return 1; - - pred = root; - - /* match is currently meaningless */ - match = -1; + int i; - do { - switch (move) { - case MOVE_DOWN: - /* only AND and OR have children */ - if (pred->left != FILTER_PRED_INVALID) { - /* If ops is set, then it was folded. */ - if (!pred->ops) { - /* keep going to down the left side */ - pred = &preds[pred->left]; - continue; - } - /* We can treat folded ops as a leaf node */ - match = process_ops(preds, pred, rec); - } else - match = pred->fn(pred, rec); - /* If this pred is the only pred */ - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - case MOVE_UP_FROM_LEFT: - /* - * Check for short circuits. - * - * Optimization: !!match == (pred->op == OP_OR) - * is the same as: - * if ((match && pred->op == OP_OR) || - * (!match && pred->op == OP_AND)) - */ - if (!!match == (pred->op == OP_OR)) { - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - } - /* now go down the right side of the tree. */ - pred = &preds[pred->right]; - move = MOVE_DOWN; - continue; - case MOVE_UP_FROM_RIGHT: - /* We finished this equation. */ - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); + for (i = 0; i < filter->n_preds; i++) { + pred = filter->preds[i]; + if (!pred->pop_n) { + match = pred->fn(pred, rec, val1, val2); + stack[top++] = match; continue; } - done = 1; - } while (!done); + if (pred->pop_n > top) { + WARN_ON_ONCE(1); + return 0; + } + val1 = stack[--top]; + val2 = stack[--top]; + match = pred->fn(pred, rec, val1, val2); + stack[top++] = match; + } - return match; + return stack[--top]; } EXPORT_SYMBOL_GPL(filter_match_preds); @@ -514,9 +414,6 @@ static void parse_error(struct filter_parse_state *ps, int err, int pos) static void remove_filter_string(struct event_filter *filter) { - if (!filter) - return; - kfree(filter->filter_string); filter->filter_string = NULL; } @@ -576,10 +473,9 @@ static void append_filter_err(struct filter_parse_state *ps, void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) { - struct event_filter *filter; + struct event_filter *filter = call->filter; mutex_lock(&event_mutex); - filter = call->filter; if (filter && filter->filter_string) trace_seq_printf(s, "%s\n", filter->filter_string); else @@ -590,10 +486,9 @@ void print_event_filter(struct ftrace_event_call *call, struct trace_seq *s) void print_subsystem_event_filter(struct event_subsystem *system, struct trace_seq *s) { - struct event_filter *filter; + struct event_filter *filter = system->filter; mutex_lock(&event_mutex); - filter = system->filter; if (filter && filter->filter_string) trace_seq_printf(s, "%s\n", filter->filter_string); else @@ -644,58 +539,10 @@ static void filter_clear_pred(struct filter_pred *pred) pred->regex.len = 0; } -static int __alloc_pred_stack(struct pred_stack *stack, int n_preds) -{ - stack->preds = kzalloc(sizeof(*stack->preds)*(n_preds + 1), GFP_KERNEL); - if (!stack->preds) - return -ENOMEM; - stack->index = n_preds; - return 0; -} - -static void __free_pred_stack(struct pred_stack *stack) -{ - kfree(stack->preds); - stack->index = 0; -} - -static int __push_pred_stack(struct pred_stack *stack, - struct filter_pred *pred) -{ - int index = stack->index; - - if (WARN_ON(index == 0)) - return -ENOSPC; - - stack->preds[--index] = pred; - stack->index = index; - return 0; -} - -static struct filter_pred * -__pop_pred_stack(struct pred_stack *stack) -{ - struct filter_pred *pred; - int index = stack->index; - - pred = stack->preds[index++]; - if (!pred) - return NULL; - - stack->index = index; - return pred; -} - -static int filter_set_pred(struct event_filter *filter, - int idx, - struct pred_stack *stack, +static int filter_set_pred(struct filter_pred *dest, struct filter_pred *src, filter_pred_fn_t fn) { - struct filter_pred *dest = &filter->preds[idx]; - struct filter_pred *left; - struct filter_pred *right; - *dest = *src; if (src->field_name) { dest->field_name = kstrdup(src->field_name, GFP_KERNEL); @@ -703,140 +550,116 @@ static int filter_set_pred(struct event_filter *filter, return -ENOMEM; } dest->fn = fn; - dest->index = idx; - - if (dest->op == OP_OR || dest->op == OP_AND) { - right = __pop_pred_stack(stack); - left = __pop_pred_stack(stack); - if (!left || !right) - return -EINVAL; - /* - * If both children can be folded - * and they are the same op as this op or a leaf, - * then this op can be folded. - */ - if (left->index & FILTER_PRED_FOLD && - (left->op == dest->op || - left->left == FILTER_PRED_INVALID) && - right->index & FILTER_PRED_FOLD && - (right->op == dest->op || - right->left == FILTER_PRED_INVALID)) - dest->index |= FILTER_PRED_FOLD; - - dest->left = left->index & ~FILTER_PRED_FOLD; - dest->right = right->index & ~FILTER_PRED_FOLD; - left->parent = dest->index & ~FILTER_PRED_FOLD; - right->parent = dest->index | FILTER_PRED_IS_RIGHT; - } else { - /* - * Make dest->left invalid to be used as a quick - * way to know this is a leaf node. - */ - dest->left = FILTER_PRED_INVALID; - - /* All leafs allow folding the parent ops. */ - dest->index |= FILTER_PRED_FOLD; - } - return __push_pred_stack(stack, dest); + return 0; } -static void __free_preds(struct event_filter *filter) +static void filter_disable_preds(struct ftrace_event_call *call) { + struct event_filter *filter = call->filter; int i; - if (filter->preds) { - for (i = 0; i < filter->a_preds; i++) - kfree(filter->preds[i].field_name); - kfree(filter->preds); - filter->preds = NULL; - } - filter->a_preds = 0; + call->flags &= ~TRACE_EVENT_FL_FILTERED; filter->n_preds = 0; -} -static void filter_disable(struct ftrace_event_call *call) -{ - call->flags &= ~TRACE_EVENT_FL_FILTERED; + for (i = 0; i < MAX_FILTER_PRED; i++) + filter->preds[i]->fn = filter_pred_none; } -static void __free_filter(struct event_filter *filter) +static void __free_preds(struct event_filter *filter) { + int i; + if (!filter) return; - __free_preds(filter); + for (i = 0; i < MAX_FILTER_PRED; i++) { + if (filter->preds[i]) + filter_free_pred(filter->preds[i]); + } + kfree(filter->preds); kfree(filter->filter_string); kfree(filter); } -/* - * Called when destroying the ftrace_event_call. - * The call is being freed, so we do not need to worry about - * the call being currently used. This is for module code removing - * the tracepoints from within it. - */ void destroy_preds(struct ftrace_event_call *call) { - __free_filter(call->filter); + __free_preds(call->filter); call->filter = NULL; + call->flags &= ~TRACE_EVENT_FL_FILTERED; } -static struct event_filter *__alloc_filter(void) +static struct event_filter *__alloc_preds(void) { struct event_filter *filter; - - filter = kzalloc(sizeof(*filter), GFP_KERNEL); - return filter; -} - -static int __alloc_preds(struct event_filter *filter, int n_preds) -{ struct filter_pred *pred; int i; - if (filter->preds) - __free_preds(filter); + filter = kzalloc(sizeof(*filter), GFP_KERNEL); + if (!filter) + return ERR_PTR(-ENOMEM); - filter->preds = - kzalloc(sizeof(*filter->preds) * n_preds, GFP_KERNEL); + filter->n_preds = 0; + filter->preds = kzalloc(MAX_FILTER_PRED * sizeof(pred), GFP_KERNEL); if (!filter->preds) - return -ENOMEM; + goto oom; - filter->a_preds = n_preds; - filter->n_preds = 0; - - for (i = 0; i < n_preds; i++) { - pred = &filter->preds[i]; + for (i = 0; i < MAX_FILTER_PRED; i++) { + pred = kzalloc(sizeof(*pred), GFP_KERNEL); + if (!pred) + goto oom; pred->fn = filter_pred_none; + filter->preds[i] = pred; } + return filter; + +oom: + __free_preds(filter); + return ERR_PTR(-ENOMEM); +} + +static int init_preds(struct ftrace_event_call *call) +{ + if (call->filter) + return 0; + + call->flags &= ~TRACE_EVENT_FL_FILTERED; + call->filter = __alloc_preds(); + if (IS_ERR(call->filter)) + return PTR_ERR(call->filter); + return 0; } -static void filter_free_subsystem_preds(struct event_subsystem *system) +static int init_subsystem_preds(struct event_subsystem *system) { struct ftrace_event_call *call; + int err; list_for_each_entry(call, &ftrace_events, list) { if (strcmp(call->class->system, system->name) != 0) continue; - filter_disable(call); - remove_filter_string(call->filter); + err = init_preds(call); + if (err) + return err; } + + return 0; } -static void filter_free_subsystem_filters(struct event_subsystem *system) +static void filter_free_subsystem_preds(struct event_subsystem *system) { struct ftrace_event_call *call; list_for_each_entry(call, &ftrace_events, list) { if (strcmp(call->class->system, system->name) != 0) continue; - __free_filter(call->filter); - call->filter = NULL; + + filter_disable_preds(call); + remove_filter_string(call->filter); } } @@ -844,19 +667,18 @@ static int filter_add_pred_fn(struct filter_parse_state *ps, struct ftrace_event_call *call, struct event_filter *filter, struct filter_pred *pred, - struct pred_stack *stack, filter_pred_fn_t fn) { int idx, err; - if (WARN_ON(filter->n_preds == filter->a_preds)) { + if (filter->n_preds == MAX_FILTER_PRED) { parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); return -ENOSPC; } idx = filter->n_preds; - filter_clear_pred(&filter->preds[idx]); - err = filter_set_pred(filter, idx, stack, pred, fn); + filter_clear_pred(filter->preds[idx]); + err = filter_set_pred(filter->preds[idx], pred, fn); if (err) return err; @@ -941,7 +763,6 @@ static int filter_add_pred(struct filter_parse_state *ps, struct ftrace_event_call *call, struct event_filter *filter, struct filter_pred *pred, - struct pred_stack *stack, bool dry_run) { struct ftrace_event_field *field; @@ -949,12 +770,17 @@ static int filter_add_pred(struct filter_parse_state *ps, unsigned long long val; int ret; - fn = pred->fn = filter_pred_none; + pred->fn = filter_pred_none; - if (pred->op == OP_AND) + if (pred->op == OP_AND) { + pred->pop_n = 2; + fn = filter_pred_and; goto add_pred_fn; - else if (pred->op == OP_OR) + } else if (pred->op == OP_OR) { + pred->pop_n = 2; + fn = filter_pred_or; goto add_pred_fn; + } field = find_event_field(call, pred->field_name); if (!field) { @@ -1003,7 +829,7 @@ static int filter_add_pred(struct filter_parse_state *ps, add_pred_fn: if (!dry_run) - return filter_add_pred_fn(ps, call, filter, pred, stack, fn); + return filter_add_pred_fn(ps, call, filter, pred, fn); return 0; } @@ -1361,234 +1187,6 @@ static int check_preds(struct filter_parse_state *ps) return 0; } -static int count_preds(struct filter_parse_state *ps) -{ - struct postfix_elt *elt; - int n_preds = 0; - - list_for_each_entry(elt, &ps->postfix, list) { - if (elt->op == OP_NONE) - continue; - n_preds++; - } - - return n_preds; -} - -/* - * The tree is walked at filtering of an event. If the tree is not correctly - * built, it may cause an infinite loop. Check here that the tree does - * indeed terminate. - */ -static int check_pred_tree(struct event_filter *filter, - struct filter_pred *root) -{ - struct filter_pred *preds; - struct filter_pred *pred; - enum move_type move = MOVE_DOWN; - int count = 0; - int done = 0; - int max; - - /* - * The max that we can hit a node is three times. - * Once going down, once coming up from left, and - * once coming up from right. This is more than enough - * since leafs are only hit a single time. - */ - max = 3 * filter->n_preds; - - preds = filter->preds; - if (!preds) - return -EINVAL; - pred = root; - - do { - if (WARN_ON(count++ > max)) - return -EINVAL; - - switch (move) { - case MOVE_DOWN: - if (pred->left != FILTER_PRED_INVALID) { - pred = &preds[pred->left]; - continue; - } - /* A leaf at the root is just a leaf in the tree */ - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - case MOVE_UP_FROM_LEFT: - pred = &preds[pred->right]; - move = MOVE_DOWN; - continue; - case MOVE_UP_FROM_RIGHT: - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - } - done = 1; - } while (!done); - - /* We are fine. */ - return 0; -} - -static int count_leafs(struct filter_pred *preds, struct filter_pred *root) -{ - struct filter_pred *pred; - enum move_type move = MOVE_DOWN; - int count = 0; - int done = 0; - - pred = root; - - do { - switch (move) { - case MOVE_DOWN: - if (pred->left != FILTER_PRED_INVALID) { - pred = &preds[pred->left]; - continue; - } - /* A leaf at the root is just a leaf in the tree */ - if (pred == root) - return 1; - count++; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - case MOVE_UP_FROM_LEFT: - pred = &preds[pred->right]; - move = MOVE_DOWN; - continue; - case MOVE_UP_FROM_RIGHT: - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - } - done = 1; - } while (!done); - - return count; -} - -static int fold_pred(struct filter_pred *preds, struct filter_pred *root) -{ - struct filter_pred *pred; - enum move_type move = MOVE_DOWN; - int count = 0; - int children; - int done = 0; - - /* No need to keep the fold flag */ - root->index &= ~FILTER_PRED_FOLD; - - /* If the root is a leaf then do nothing */ - if (root->left == FILTER_PRED_INVALID) - return 0; - - /* count the children */ - children = count_leafs(preds, &preds[root->left]); - children += count_leafs(preds, &preds[root->right]); - - root->ops = kzalloc(sizeof(*root->ops) * children, GFP_KERNEL); - if (!root->ops) - return -ENOMEM; - - root->val = children; - - pred = root; - do { - switch (move) { - case MOVE_DOWN: - if (pred->left != FILTER_PRED_INVALID) { - pred = &preds[pred->left]; - continue; - } - if (WARN_ON(count == children)) - return -EINVAL; - pred->index &= ~FILTER_PRED_FOLD; - root->ops[count++] = pred->index; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - case MOVE_UP_FROM_LEFT: - pred = &preds[pred->right]; - move = MOVE_DOWN; - continue; - case MOVE_UP_FROM_RIGHT: - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - } - done = 1; - } while (!done); - - return 0; -} - -/* - * To optimize the processing of the ops, if we have several "ors" or - * "ands" together, we can put them in an array and process them all - * together speeding up the filter logic. - */ -static int fold_pred_tree(struct event_filter *filter, - struct filter_pred *root) -{ - struct filter_pred *preds; - struct filter_pred *pred; - enum move_type move = MOVE_DOWN; - int done = 0; - int err; - - preds = filter->preds; - if (!preds) - return -EINVAL; - pred = root; - - do { - switch (move) { - case MOVE_DOWN: - if (pred->index & FILTER_PRED_FOLD) { - err = fold_pred(preds, pred); - if (err) - return err; - /* Folded nodes are like leafs */ - } else if (pred->left != FILTER_PRED_INVALID) { - pred = &preds[pred->left]; - continue; - } - - /* A leaf at the root is just a leaf in the tree */ - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - case MOVE_UP_FROM_LEFT: - pred = &preds[pred->right]; - move = MOVE_DOWN; - continue; - case MOVE_UP_FROM_RIGHT: - if (pred == root) - break; - pred = get_pred_parent(pred, preds, - pred->parent, &move); - continue; - } - done = 1; - } while (!done); - - return 0; -} - static int replace_preds(struct ftrace_event_call *call, struct event_filter *filter, struct filter_parse_state *ps, @@ -1597,32 +1195,14 @@ static int replace_preds(struct ftrace_event_call *call, { char *operand1 = NULL, *operand2 = NULL; struct filter_pred *pred; - struct filter_pred *root; struct postfix_elt *elt; - struct pred_stack stack = { }; /* init to NULL */ int err; int n_preds = 0; - n_preds = count_preds(ps); - if (n_preds >= MAX_FILTER_PRED) { - parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); - return -ENOSPC; - } - err = check_preds(ps); if (err) return err; - if (!dry_run) { - err = __alloc_pred_stack(&stack, n_preds); - if (err) - return err; - err = __alloc_preds(filter, n_preds); - if (err) - goto fail; - } - - n_preds = 0; list_for_each_entry(elt, &ps->postfix, list) { if (elt->op == OP_NONE) { if (!operand1) @@ -1631,16 +1211,14 @@ static int replace_preds(struct ftrace_event_call *call, operand2 = elt->operand; else { parse_error(ps, FILT_ERR_TOO_MANY_OPERANDS, 0); - err = -EINVAL; - goto fail; + return -EINVAL; } continue; } - if (WARN_ON(n_preds++ == MAX_FILTER_PRED)) { + if (n_preds++ == MAX_FILTER_PRED) { parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0); - err = -ENOSPC; - goto fail; + return -ENOSPC; } if (elt->op == OP_AND || elt->op == OP_OR) { @@ -1650,181 +1228,76 @@ static int replace_preds(struct ftrace_event_call *call, if (!operand1 || !operand2) { parse_error(ps, FILT_ERR_MISSING_FIELD, 0); - err = -EINVAL; - goto fail; + return -EINVAL; } pred = create_pred(elt->op, operand1, operand2); add_pred: - if (!pred) { - err = -ENOMEM; - goto fail; - } - err = filter_add_pred(ps, call, filter, pred, &stack, dry_run); + if (!pred) + return -ENOMEM; + err = filter_add_pred(ps, call, filter, pred, dry_run); filter_free_pred(pred); if (err) - goto fail; + return err; operand1 = operand2 = NULL; } - if (!dry_run) { - /* We should have one item left on the stack */ - pred = __pop_pred_stack(&stack); - if (!pred) - return -EINVAL; - /* This item is where we start from in matching */ - root = pred; - /* Make sure the stack is empty */ - pred = __pop_pred_stack(&stack); - if (WARN_ON(pred)) { - err = -EINVAL; - filter->root = NULL; - goto fail; - } - err = check_pred_tree(filter, root); - if (err) - goto fail; - - /* Optimize the tree */ - err = fold_pred_tree(filter, root); - if (err) - goto fail; - - /* We don't set root until we know it works */ - barrier(); - filter->root = root; - } - - err = 0; -fail: - __free_pred_stack(&stack); - return err; + return 0; } -struct filter_list { - struct list_head list; - struct event_filter *filter; -}; - static int replace_system_preds(struct event_subsystem *system, struct filter_parse_state *ps, char *filter_string) { struct ftrace_event_call *call; - struct filter_list *filter_item; - struct filter_list *tmp; - LIST_HEAD(filter_list); bool fail = true; int err; list_for_each_entry(call, &ftrace_events, list) { + struct event_filter *filter = call->filter; if (strcmp(call->class->system, system->name) != 0) continue; - /* - * Try to see if the filter can be applied - * (filter arg is ignored on dry_run) - */ - err = replace_preds(call, NULL, ps, filter_string, true); + /* try to see if the filter can be applied */ + err = replace_preds(call, filter, ps, filter_string, true); if (err) - goto fail; - } - - list_for_each_entry(call, &ftrace_events, list) { - struct event_filter *filter; - - if (strcmp(call->class->system, system->name) != 0) continue; - filter_item = kzalloc(sizeof(*filter_item), GFP_KERNEL); - if (!filter_item) - goto fail_mem; - - list_add_tail(&filter_item->list, &filter_list); - - filter_item->filter = __alloc_filter(); - if (!filter_item->filter) - goto fail_mem; - filter = filter_item->filter; - - /* Can only fail on no memory */ - err = replace_filter_string(filter, filter_string); - if (err) - goto fail_mem; - + /* really apply the filter */ + filter_disable_preds(call); err = replace_preds(call, filter, ps, filter_string, false); - if (err) { - filter_disable(call); - parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); - append_filter_err(ps, filter); - } else + if (err) + filter_disable_preds(call); + else { call->flags |= TRACE_EVENT_FL_FILTERED; - /* - * Regardless of if this returned an error, we still - * replace the filter for the call. - */ - filter = call->filter; - call->filter = filter_item->filter; - filter_item->filter = filter; - + replace_filter_string(filter, filter_string); + } fail = false; } - if (fail) - goto fail; - - /* - * The calls can still be using the old filters. - * Do a synchronize_sched() to ensure all calls are - * done with them before we free them. - */ - synchronize_sched(); - list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { - __free_filter(filter_item->filter); - list_del(&filter_item->list); - kfree(filter_item); + if (fail) { + parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); + return -EINVAL; } return 0; - fail: - /* No call succeeded */ - list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { - list_del(&filter_item->list); - kfree(filter_item); - } - parse_error(ps, FILT_ERR_BAD_SUBSYS_FILTER, 0); - return -EINVAL; - fail_mem: - /* If any call succeeded, we still need to sync */ - if (!fail) - synchronize_sched(); - list_for_each_entry_safe(filter_item, tmp, &filter_list, list) { - __free_filter(filter_item->filter); - list_del(&filter_item->list); - kfree(filter_item); - } - return -ENOMEM; } int apply_event_filter(struct ftrace_event_call *call, char *filter_string) { + int err; struct filter_parse_state *ps; - struct event_filter *filter; - struct event_filter *tmp; - int err = 0; mutex_lock(&event_mutex); + err = init_preds(call); + if (err) + goto out_unlock; + if (!strcmp(strstrip(filter_string), "0")) { - filter_disable(call); - filter = call->filter; - if (!filter) - goto out_unlock; - call->filter = NULL; - /* Make sure the filter is not being used */ - synchronize_sched(); - __free_filter(filter); + filter_disable_preds(call); + remove_filter_string(call->filter); goto out_unlock; } @@ -1833,41 +1306,22 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) if (!ps) goto out_unlock; - filter = __alloc_filter(); - if (!filter) { - kfree(ps); - goto out_unlock; - } - - replace_filter_string(filter, filter_string); + filter_disable_preds(call); + replace_filter_string(call->filter, filter_string); parse_init(ps, filter_ops, filter_string); err = filter_parse(ps); if (err) { - append_filter_err(ps, filter); + append_filter_err(ps, call->filter); goto out; } - err = replace_preds(call, filter, ps, filter_string, false); - if (err) { - filter_disable(call); - append_filter_err(ps, filter); - } else + err = replace_preds(call, call->filter, ps, filter_string, false); + if (err) + append_filter_err(ps, call->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 - */ - tmp = call->filter; - 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); @@ -1880,21 +1334,18 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) int apply_subsystem_event_filter(struct event_subsystem *system, char *filter_string) { + int err; struct filter_parse_state *ps; - struct event_filter *filter; - int err = 0; mutex_lock(&event_mutex); + err = init_subsystem_preds(system); + if (err) + goto out_unlock; + if (!strcmp(strstrip(filter_string), "0")) { filter_free_subsystem_preds(system); remove_filter_string(system->filter); - filter = system->filter; - system->filter = NULL; - /* Ensure all filters are no longer used */ - synchronize_sched(); - filter_free_subsystem_filters(system); - __free_filter(filter); goto out_unlock; } @@ -1903,17 +1354,7 @@ int apply_subsystem_event_filter(struct event_subsystem *system, 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; + replace_filter_string(system->filter, filter_string); parse_init(ps, filter_ops, filter_string); err = filter_parse(ps); @@ -1943,7 +1384,7 @@ void ftrace_profile_free_filter(struct perf_event *event) struct event_filter *filter = event->filter; event->filter = NULL; - __free_filter(filter); + __free_preds(filter); } int ftrace_profile_set_filter(struct perf_event *event, int event_id, @@ -1969,8 +1410,8 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, if (event->filter) goto out_unlock; - filter = __alloc_filter(); - if (!filter) { + filter = __alloc_preds(); + if (IS_ERR(filter)) { err = PTR_ERR(filter); goto out_unlock; } @@ -1978,7 +1419,7 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, err = -ENOMEM; ps = kzalloc(sizeof(*ps), GFP_KERNEL); if (!ps) - goto free_filter; + goto free_preds; parse_init(ps, filter_ops, filter_str); err = filter_parse(ps); @@ -1994,9 +1435,9 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id, postfix_clear(ps); kfree(ps); -free_filter: +free_preds: if (err) - __free_filter(filter); + __free_preds(filter); out_unlock: mutex_unlock(&event_mutex); diff --git a/trunk/kernel/trace/trace_kprobe.c b/trunk/kernel/trace/trace_kprobe.c index 8435b43b1782..2dec9bcde8b4 100644 --- a/trunk/kernel/trace/trace_kprobe.c +++ b/trunk/kernel/trace/trace_kprobe.c @@ -353,43 +353,6 @@ static __kprobes void free_deref_fetch_param(struct deref_fetch_param *data) kfree(data); } -/* Bitfield fetch function */ -struct bitfield_fetch_param { - struct fetch_param orig; - unsigned char hi_shift; - unsigned char low_shift; -}; - -#define DEFINE_FETCH_bitfield(type) \ -static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\ - void *data, void *dest) \ -{ \ - struct bitfield_fetch_param *bprm = data; \ - type buf = 0; \ - call_fetch(&bprm->orig, regs, &buf); \ - if (buf) { \ - buf <<= bprm->hi_shift; \ - buf >>= bprm->low_shift; \ - } \ - *(type *)dest = buf; \ -} -DEFINE_BASIC_FETCH_FUNCS(bitfield) -#define fetch_bitfield_string NULL -#define fetch_bitfield_string_size NULL - -static __kprobes void -free_bitfield_fetch_param(struct bitfield_fetch_param *data) -{ - /* - * Don't check the bitfield itself, because this must be the - * last fetch function. - */ - if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) - free_deref_fetch_param(data->orig.data); - else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) - free_symbol_cache(data->orig.data); - kfree(data); -} /* Default (unsigned long) fetch type */ #define __DEFAULT_FETCH_TYPE(t) u##t #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) @@ -404,7 +367,6 @@ enum { FETCH_MTD_memory, FETCH_MTD_symbol, FETCH_MTD_deref, - FETCH_MTD_bitfield, FETCH_MTD_END, }; @@ -425,7 +387,6 @@ ASSIGN_FETCH_FUNC(retval, ftype), \ ASSIGN_FETCH_FUNC(memory, ftype), \ ASSIGN_FETCH_FUNC(symbol, ftype), \ ASSIGN_FETCH_FUNC(deref, ftype), \ -ASSIGN_FETCH_FUNC(bitfield, ftype), \ } \ } @@ -469,33 +430,9 @@ static const struct fetch_type *find_fetch_type(const char *type) if (!type) type = DEFAULT_FETCH_TYPE_STR; - /* Special case: bitfield */ - if (*type == 'b') { - unsigned long bs; - type = strchr(type, '/'); - if (!type) - goto fail; - type++; - if (strict_strtoul(type, 0, &bs)) - goto fail; - switch (bs) { - case 8: - return find_fetch_type("u8"); - case 16: - return find_fetch_type("u16"); - case 32: - return find_fetch_type("u32"); - case 64: - return find_fetch_type("u64"); - default: - goto fail; - } - } - for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++) if (strcmp(type, fetch_type_table[i].name) == 0) return &fetch_type_table[i]; -fail: return NULL; } @@ -649,9 +586,7 @@ static struct trace_probe *alloc_trace_probe(const char *group, static void free_probe_arg(struct probe_arg *arg) { - if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) - free_bitfield_fetch_param(arg->fetch.data); - else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) + if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) free_deref_fetch_param(arg->fetch.data); else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) free_symbol_cache(arg->fetch.data); @@ -832,15 +767,16 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t, } break; case '+': /* deref memory */ - arg++; /* Skip '+', because strict_strtol() rejects it. */ case '-': tmp = strchr(arg, '('); if (!tmp) break; *tmp = '\0'; - ret = strict_strtol(arg, 0, &offset); + ret = strict_strtol(arg + 1, 0, &offset); if (ret) break; + if (arg[0] == '-') + offset = -offset; arg = tmp + 1; tmp = strrchr(arg, ')'); if (tmp) { @@ -871,41 +807,6 @@ static int __parse_probe_arg(char *arg, const struct fetch_type *t, return ret; } -#define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) - -/* Bitfield type needs to be parsed into a fetch function */ -static int __parse_bitfield_probe_arg(const char *bf, - const struct fetch_type *t, - struct fetch_param *f) -{ - struct bitfield_fetch_param *bprm; - unsigned long bw, bo; - char *tail; - - if (*bf != 'b') - return 0; - - bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); - if (!bprm) - return -ENOMEM; - bprm->orig = *f; - f->fn = t->fetch[FETCH_MTD_bitfield]; - f->data = (void *)bprm; - - bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ - if (bw == 0 || *tail != '@') - return -EINVAL; - - bf = tail + 1; - bo = simple_strtoul(bf, &tail, 0); - if (tail == bf || *tail != '/') - return -EINVAL; - - bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); - bprm->low_shift = bprm->hi_shift + bo; - return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; -} - /* String length checking wrapper */ static int parse_probe_arg(char *arg, struct trace_probe *tp, struct probe_arg *parg, int is_return) @@ -935,8 +836,6 @@ static int parse_probe_arg(char *arg, struct trace_probe *tp, parg->offset = tp->size; tp->size += parg->type->size; ret = __parse_probe_arg(arg, parg->type, &parg->fetch, is_return); - if (ret >= 0 && t != NULL) - ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); if (ret >= 0) { parg->fetch_size.fn = get_fetch_size_function(parg->type, parg->fetch.fn); @@ -1231,7 +1130,7 @@ static int command_trace_probe(const char *buf) return ret; } -#define WRITE_BUFSIZE 4096 +#define WRITE_BUFSIZE 128 static ssize_t probes_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) diff --git a/trunk/kernel/trace/trace_sched_switch.c b/trunk/kernel/trace/trace_sched_switch.c index 7e62c0a18456..8f758d070c43 100644 --- a/trunk/kernel/trace/trace_sched_switch.c +++ b/trunk/kernel/trace/trace_sched_switch.c @@ -247,3 +247,51 @@ void tracing_sched_switch_assign_trace(struct trace_array *tr) ctx_trace = tr; } +static void stop_sched_trace(struct trace_array *tr) +{ + tracing_stop_sched_switch_record(); +} + +static int sched_switch_trace_init(struct trace_array *tr) +{ + ctx_trace = tr; + tracing_reset_online_cpus(tr); + tracing_start_sched_switch_record(); + return 0; +} + +static void sched_switch_trace_reset(struct trace_array *tr) +{ + if (sched_ref) + stop_sched_trace(tr); +} + +static void sched_switch_trace_start(struct trace_array *tr) +{ + sched_stopped = 0; +} + +static void sched_switch_trace_stop(struct trace_array *tr) +{ + sched_stopped = 1; +} + +static struct tracer sched_switch_trace __read_mostly = +{ + .name = "sched_switch", + .init = sched_switch_trace_init, + .reset = sched_switch_trace_reset, + .start = sched_switch_trace_start, + .stop = sched_switch_trace_stop, + .wait_pipe = poll_wait_pipe, +#ifdef CONFIG_FTRACE_SELFTEST + .selftest = trace_selftest_startup_sched_switch, +#endif +}; + +__init static int init_sched_switch_trace(void) +{ + return register_tracer(&sched_switch_trace); +} +device_initcall(init_sched_switch_trace); + diff --git a/trunk/kernel/trace/trace_syscalls.c b/trunk/kernel/trace/trace_syscalls.c index ee7b5a0bb9f8..5c9fe08d2093 100644 --- a/trunk/kernel/trace/trace_syscalls.c +++ b/trunk/kernel/trace/trace_syscalls.c @@ -60,19 +60,6 @@ extern struct syscall_metadata *__stop_syscalls_metadata[]; static struct syscall_metadata **syscalls_metadata; -#ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME -static inline bool arch_syscall_match_sym_name(const char *sym, const char *name) -{ - /* - * Only compare after the "sys" prefix. Archs that use - * syscall wrappers may have syscalls symbols aliases prefixed - * with "SyS" instead of "sys", leading to an unwanted - * mismatch. - */ - return !strcmp(sym + 3, name + 3); -} -#endif - static __init struct syscall_metadata * find_syscall_meta(unsigned long syscall) { @@ -85,11 +72,14 @@ find_syscall_meta(unsigned long syscall) stop = __stop_syscalls_metadata; kallsyms_lookup(syscall, NULL, NULL, NULL, str); - if (arch_syscall_match_sym_name(str, "sys_ni_syscall")) - return NULL; - for ( ; start < stop; start++) { - if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name)) + /* + * Only compare after the "sys" prefix. Archs that use + * syscall wrappers may have syscalls symbols aliases prefixed + * with "SyS" instead of "sys", leading to an unwanted + * mismatch. + */ + if ((*start)->name && !strcmp((*start)->name + 3, str + 3)) return *start; } return NULL; @@ -369,7 +359,7 @@ int reg_event_syscall_enter(struct ftrace_event_call *call) int num; num = ((struct syscall_metadata *)call->data)->syscall_nr; - if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) + if (num < 0 || num >= NR_syscalls) return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_enter) @@ -387,7 +377,7 @@ void unreg_event_syscall_enter(struct ftrace_event_call *call) int num; num = ((struct syscall_metadata *)call->data)->syscall_nr; - if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) + if (num < 0 || num >= NR_syscalls) return; mutex_lock(&syscall_trace_lock); sys_refcount_enter--; @@ -403,7 +393,7 @@ int reg_event_syscall_exit(struct ftrace_event_call *call) int num; num = ((struct syscall_metadata *)call->data)->syscall_nr; - if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) + if (num < 0 || num >= NR_syscalls) return -ENOSYS; mutex_lock(&syscall_trace_lock); if (!sys_refcount_exit) @@ -421,7 +411,7 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call) int num; num = ((struct syscall_metadata *)call->data)->syscall_nr; - if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls)) + if (num < 0 || num >= NR_syscalls) return; mutex_lock(&syscall_trace_lock); sys_refcount_exit--; @@ -434,14 +424,6 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call) int init_syscall_trace(struct ftrace_event_call *call) { int id; - int num; - - num = ((struct syscall_metadata *)call->data)->syscall_nr; - if (num < 0 || num >= NR_syscalls) { - pr_debug("syscall %s metadata not mapped, disabling ftrace event\n", - ((struct syscall_metadata *)call->data)->name); - return -ENOSYS; - } if (set_syscall_print_fmt(call) < 0) return -ENOMEM; @@ -456,7 +438,7 @@ int init_syscall_trace(struct ftrace_event_call *call) return id; } -unsigned long __init __weak arch_syscall_addr(int nr) +unsigned long __init arch_syscall_addr(int nr) { return (unsigned long)sys_call_table[nr]; } diff --git a/trunk/kernel/workqueue.c b/trunk/kernel/workqueue.c index 11869faa6819..ee6578b578ad 100644 --- a/trunk/kernel/workqueue.c +++ b/trunk/kernel/workqueue.c @@ -79,7 +79,9 @@ enum { MAX_IDLE_WORKERS_RATIO = 4, /* 1/4 of busy can be idle */ IDLE_WORKER_TIMEOUT = 300 * HZ, /* keep idle ones for 5 mins */ - MAYDAY_INITIAL_TIMEOUT = HZ / 100, /* call for help after 10ms */ + MAYDAY_INITIAL_TIMEOUT = HZ / 100 >= 2 ? HZ / 100 : 2, + /* call for help after 10ms + (min two ticks) */ MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */ CREATE_COOLDOWN = HZ, /* time to breath after fail */ TRUSTEE_COOLDOWN = HZ / 10, /* for trustee draining */ @@ -2047,6 +2049,15 @@ static int rescuer_thread(void *__wq) move_linked_works(work, scheduled, &n); process_scheduled_works(rescuer); + + /* + * Leave this gcwq. If keep_working() is %true, notify a + * regular worker; otherwise, we end up with 0 concurrency + * and stalling the execution. + */ + if (keep_working(gcwq)) + wake_up_worker(gcwq); + spin_unlock_irq(&gcwq->lock); } @@ -2956,7 +2967,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name, */ spin_lock(&workqueue_lock); - if (workqueue_freezing && wq->flags & WQ_FREEZEABLE) + if (workqueue_freezing && wq->flags & WQ_FREEZABLE) for_each_cwq_cpu(cpu, wq) get_cwq(cpu, wq)->max_active = 0; @@ -3068,7 +3079,7 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) spin_lock_irq(&gcwq->lock); - if (!(wq->flags & WQ_FREEZEABLE) || + if (!(wq->flags & WQ_FREEZABLE) || !(gcwq->flags & GCWQ_FREEZING)) get_cwq(gcwq->cpu, wq)->max_active = max_active; @@ -3318,7 +3329,7 @@ static int __cpuinit trustee_thread(void *__gcwq) * want to get it over with ASAP - spam rescuers, wake up as * many idlers as necessary and create new ones till the * worklist is empty. Note that if the gcwq is frozen, there - * may be frozen works in freezeable cwqs. Don't declare + * may be frozen works in freezable cwqs. Don't declare * completion while frozen. */ while (gcwq->nr_workers != gcwq->nr_idle || @@ -3576,9 +3587,9 @@ EXPORT_SYMBOL_GPL(work_on_cpu); /** * freeze_workqueues_begin - begin freezing workqueues * - * Start freezing workqueues. After this function returns, all - * freezeable workqueues will queue new works to their frozen_works - * list instead of gcwq->worklist. + * Start freezing workqueues. After this function returns, all freezable + * workqueues will queue new works to their frozen_works list instead of + * gcwq->worklist. * * CONTEXT: * Grabs and releases workqueue_lock and gcwq->lock's. @@ -3604,7 +3615,7 @@ void freeze_workqueues_begin(void) list_for_each_entry(wq, &workqueues, list) { struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); - if (cwq && wq->flags & WQ_FREEZEABLE) + if (cwq && wq->flags & WQ_FREEZABLE) cwq->max_active = 0; } @@ -3615,7 +3626,7 @@ void freeze_workqueues_begin(void) } /** - * freeze_workqueues_busy - are freezeable workqueues still busy? + * freeze_workqueues_busy - are freezable workqueues still busy? * * Check whether freezing is complete. This function must be called * between freeze_workqueues_begin() and thaw_workqueues(). @@ -3624,8 +3635,8 @@ void freeze_workqueues_begin(void) * Grabs and releases workqueue_lock. * * RETURNS: - * %true if some freezeable workqueues are still busy. %false if - * freezing is complete. + * %true if some freezable workqueues are still busy. %false if freezing + * is complete. */ bool freeze_workqueues_busy(void) { @@ -3645,7 +3656,7 @@ bool freeze_workqueues_busy(void) list_for_each_entry(wq, &workqueues, list) { struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); - if (!cwq || !(wq->flags & WQ_FREEZEABLE)) + if (!cwq || !(wq->flags & WQ_FREEZABLE)) continue; BUG_ON(cwq->nr_active < 0); @@ -3690,7 +3701,7 @@ void thaw_workqueues(void) list_for_each_entry(wq, &workqueues, list) { struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); - if (!cwq || !(wq->flags & WQ_FREEZEABLE)) + if (!cwq || !(wq->flags & WQ_FREEZABLE)) continue; /* restore max_active and repopulate worklist */ diff --git a/trunk/lib/list_debug.c b/trunk/lib/list_debug.c index 344c710d16ca..b8029a5583ff 100644 --- a/trunk/lib/list_debug.c +++ b/trunk/lib/list_debug.c @@ -35,6 +35,31 @@ void __list_add(struct list_head *new, } EXPORT_SYMBOL(__list_add); +void __list_del_entry(struct list_head *entry) +{ + struct list_head *prev, *next; + + prev = entry->prev; + next = entry->next; + + if (WARN(next == LIST_POISON1, + "list_del corruption, %p->next is LIST_POISON1 (%p)\n", + entry, LIST_POISON1) || + WARN(prev == LIST_POISON2, + "list_del corruption, %p->prev is LIST_POISON2 (%p)\n", + entry, LIST_POISON2) || + WARN(prev->next != entry, + "list_del corruption. prev->next should be %p, " + "but was %p\n", entry, prev->next) || + WARN(next->prev != entry, + "list_del corruption. next->prev should be %p, " + "but was %p\n", entry, next->prev)) + return; + + __list_del(prev, next); +} +EXPORT_SYMBOL(__list_del_entry); + /** * list_del - deletes entry from list. * @entry: the element to delete from the list. @@ -43,19 +68,7 @@ EXPORT_SYMBOL(__list_add); */ void list_del(struct list_head *entry) { - WARN(entry->next == LIST_POISON1, - "list_del corruption, next is LIST_POISON1 (%p)\n", - LIST_POISON1); - WARN(entry->next != LIST_POISON1 && entry->prev == LIST_POISON2, - "list_del corruption, prev is LIST_POISON2 (%p)\n", - LIST_POISON2); - WARN(entry->prev->next != entry, - "list_del corruption. prev->next should be %p, " - "but was %p\n", entry, entry->prev->next); - WARN(entry->next->prev != entry, - "list_del corruption. next->prev should be %p, " - "but was %p\n", entry, entry->next->prev); - __list_del(entry->prev, entry->next); + __list_del_entry(entry); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } diff --git a/trunk/net/bluetooth/l2cap.c b/trunk/net/bluetooth/l2cap.c index 7550abb0c96a..675614e38e14 100644 --- a/trunk/net/bluetooth/l2cap.c +++ b/trunk/net/bluetooth/l2cap.c @@ -859,6 +859,7 @@ static void __l2cap_sock_close(struct sock *sk, int reason) result = L2CAP_CR_SEC_BLOCK; else result = L2CAP_CR_BAD_PSM; + sk->sk_state = BT_DISCONN; rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); diff --git a/trunk/net/bridge/br_input.c b/trunk/net/bridge/br_input.c index 6f6d8e1b776f..88e4aa9cb1f9 100644 --- a/trunk/net/bridge/br_input.c +++ b/trunk/net/bridge/br_input.c @@ -80,7 +80,7 @@ int br_handle_frame_finish(struct sk_buff *skb) if (is_multicast_ether_addr(dest)) { mdst = br_mdb_get(br, skb); if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) { - if ((mdst && !hlist_unhashed(&mdst->mglist)) || + if ((mdst && mdst->mglist) || br_multicast_is_router(br)) skb2 = skb; br_multicast_forward(mdst, skb, skb2); diff --git a/trunk/net/bridge/br_multicast.c b/trunk/net/bridge/br_multicast.c index f701a21acb34..09d5c0987925 100644 --- a/trunk/net/bridge/br_multicast.c +++ b/trunk/net/bridge/br_multicast.c @@ -232,8 +232,7 @@ static void br_multicast_group_expired(unsigned long data) if (!netif_running(br->dev) || timer_pending(&mp->timer)) goto out; - if (!hlist_unhashed(&mp->mglist)) - hlist_del_init(&mp->mglist); + mp->mglist = false; if (mp->ports) goto out; @@ -276,7 +275,7 @@ static void br_multicast_del_pg(struct net_bridge *br, del_timer(&p->query_timer); call_rcu_bh(&p->rcu, br_multicast_free_pg); - if (!mp->ports && hlist_unhashed(&mp->mglist) && + if (!mp->ports && !mp->mglist && netif_running(br->dev)) mod_timer(&mp->timer, jiffies); @@ -528,7 +527,7 @@ static void br_multicast_group_query_expired(unsigned long data) struct net_bridge *br = mp->br; spin_lock(&br->multicast_lock); - if (!netif_running(br->dev) || hlist_unhashed(&mp->mglist) || + if (!netif_running(br->dev) || !mp->mglist || mp->queries_sent >= br->multicast_last_member_count) goto out; @@ -719,7 +718,7 @@ static int br_multicast_add_group(struct net_bridge *br, goto err; if (!port) { - hlist_add_head(&mp->mglist, &br->mglist); + mp->mglist = true; mod_timer(&mp->timer, now + br->multicast_membership_interval); goto out; } @@ -1165,7 +1164,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, max_delay *= br->multicast_last_member_count; - if (!hlist_unhashed(&mp->mglist) && + if (mp->mglist && (timer_pending(&mp->timer) ? time_after(mp->timer.expires, now + max_delay) : try_to_del_timer_sync(&mp->timer) >= 0)) @@ -1177,7 +1176,7 @@ static int br_ip4_multicast_query(struct net_bridge *br, if (timer_pending(&p->timer) ? time_after(p->timer.expires, now + max_delay) : try_to_del_timer_sync(&p->timer) >= 0) - mod_timer(&mp->timer, now + max_delay); + mod_timer(&p->timer, now + max_delay); } out: @@ -1236,7 +1235,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, goto out; max_delay *= br->multicast_last_member_count; - if (!hlist_unhashed(&mp->mglist) && + if (mp->mglist && (timer_pending(&mp->timer) ? time_after(mp->timer.expires, now + max_delay) : try_to_del_timer_sync(&mp->timer) >= 0)) @@ -1248,7 +1247,7 @@ static int br_ip6_multicast_query(struct net_bridge *br, if (timer_pending(&p->timer) ? time_after(p->timer.expires, now + max_delay) : try_to_del_timer_sync(&p->timer) >= 0) - mod_timer(&mp->timer, now + max_delay); + mod_timer(&p->timer, now + max_delay); } out: @@ -1283,7 +1282,7 @@ static void br_multicast_leave_group(struct net_bridge *br, br->multicast_last_member_interval; if (!port) { - if (!hlist_unhashed(&mp->mglist) && + if (mp->mglist && (timer_pending(&mp->timer) ? time_after(mp->timer.expires, time) : try_to_del_timer_sync(&mp->timer) >= 0)) { diff --git a/trunk/net/bridge/br_private.h b/trunk/net/bridge/br_private.h index 84aac7734bfc..4e1b620b6be6 100644 --- a/trunk/net/bridge/br_private.h +++ b/trunk/net/bridge/br_private.h @@ -84,13 +84,13 @@ struct net_bridge_port_group { struct net_bridge_mdb_entry { struct hlist_node hlist[2]; - struct hlist_node mglist; struct net_bridge *br; struct net_bridge_port_group __rcu *ports; struct rcu_head rcu; struct timer_list timer; struct timer_list query_timer; struct br_ip addr; + bool mglist; u32 queries_sent; }; @@ -238,7 +238,6 @@ struct net_bridge spinlock_t multicast_lock; struct net_bridge_mdb_htable __rcu *mdb; struct hlist_head router_list; - struct hlist_head mglist; struct timer_list multicast_router_timer; struct timer_list multicast_querier_timer; diff --git a/trunk/net/ceph/messenger.c b/trunk/net/ceph/messenger.c index dff633d62e5b..35b36b86d762 100644 --- a/trunk/net/ceph/messenger.c +++ b/trunk/net/ceph/messenger.c @@ -252,8 +252,12 @@ static int ceph_tcp_recvmsg(struct socket *sock, void *buf, size_t len) { struct kvec iov = {buf, len}; struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; + int r; - return kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags); + r = kernel_recvmsg(sock, &msg, &iov, 1, len, msg.msg_flags); + if (r == -EAGAIN) + r = 0; + return r; } /* @@ -264,13 +268,17 @@ static int ceph_tcp_sendmsg(struct socket *sock, struct kvec *iov, size_t kvlen, size_t len, int more) { struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL }; + int r; if (more) msg.msg_flags |= MSG_MORE; else msg.msg_flags |= MSG_EOR; /* superfluous, but what the hell */ - return kernel_sendmsg(sock, &msg, iov, kvlen, len); + r = kernel_sendmsg(sock, &msg, iov, kvlen, len); + if (r == -EAGAIN) + r = 0; + return r; } @@ -847,6 +855,8 @@ static int write_partial_msg_pages(struct ceph_connection *con) (msg->pages || msg->pagelist || msg->bio || in_trail)) kunmap(page); + if (ret == -EAGAIN) + ret = 0; if (ret <= 0) goto out; @@ -1737,16 +1747,12 @@ static int try_write(struct ceph_connection *con) if (con->out_skip) { ret = write_partial_skip(con); if (ret <= 0) - goto done; - if (ret < 0) { - dout("try_write write_partial_skip err %d\n", ret); - goto done; - } + goto out; } if (con->out_kvec_left) { ret = write_partial_kvec(con); if (ret <= 0) - goto done; + goto out; } /* msg pages? */ @@ -1761,11 +1767,11 @@ static int try_write(struct ceph_connection *con) if (ret == 1) goto more_kvec; /* we need to send the footer, too! */ if (ret == 0) - goto done; + goto out; if (ret < 0) { dout("try_write write_partial_msg_pages err %d\n", ret); - goto done; + goto out; } } @@ -1789,10 +1795,9 @@ static int try_write(struct ceph_connection *con) /* Nothing to do! */ clear_bit(WRITE_PENDING, &con->state); dout("try_write nothing else to write.\n"); -done: ret = 0; out: - dout("try_write done on %p\n", con); + dout("try_write done on %p ret %d\n", con, ret); return ret; } @@ -1821,19 +1826,17 @@ static int try_read(struct ceph_connection *con) dout("try_read connecting\n"); ret = read_partial_banner(con); if (ret <= 0) - goto done; - if (process_banner(con) < 0) { - ret = -1; goto out; - } + ret = process_banner(con); + if (ret < 0) + goto out; } ret = read_partial_connect(con); if (ret <= 0) - goto done; - if (process_connect(con) < 0) { - ret = -1; goto out; - } + ret = process_connect(con); + if (ret < 0) + goto out; goto more; } @@ -1848,7 +1851,7 @@ static int try_read(struct ceph_connection *con) dout("skipping %d / %d bytes\n", skip, -con->in_base_pos); ret = ceph_tcp_recvmsg(con->sock, buf, skip); if (ret <= 0) - goto done; + goto out; con->in_base_pos += ret; if (con->in_base_pos) goto more; @@ -1859,7 +1862,7 @@ static int try_read(struct ceph_connection *con) */ ret = ceph_tcp_recvmsg(con->sock, &con->in_tag, 1); if (ret <= 0) - goto done; + goto out; dout("try_read got tag %d\n", (int)con->in_tag); switch (con->in_tag) { case CEPH_MSGR_TAG_MSG: @@ -1870,7 +1873,7 @@ static int try_read(struct ceph_connection *con) break; case CEPH_MSGR_TAG_CLOSE: set_bit(CLOSED, &con->state); /* fixme */ - goto done; + goto out; default: goto bad_tag; } @@ -1882,13 +1885,12 @@ static int try_read(struct ceph_connection *con) case -EBADMSG: con->error_msg = "bad crc"; ret = -EIO; - goto out; + break; case -EIO: con->error_msg = "io error"; - goto out; - default: - goto done; + break; } + goto out; } if (con->in_tag == CEPH_MSGR_TAG_READY) goto more; @@ -1898,15 +1900,13 @@ static int try_read(struct ceph_connection *con) if (con->in_tag == CEPH_MSGR_TAG_ACK) { ret = read_partial_ack(con); if (ret <= 0) - goto done; + goto out; process_ack(con); goto more; } -done: - ret = 0; out: - dout("try_read done on %p\n", con); + dout("try_read done on %p ret %d\n", con, ret); return ret; bad_tag: diff --git a/trunk/net/core/dev.c b/trunk/net/core/dev.c index 8e726cb47ed7..8ae6631abcc2 100644 --- a/trunk/net/core/dev.c +++ b/trunk/net/core/dev.c @@ -1280,10 +1280,13 @@ static int __dev_close_many(struct list_head *head) static int __dev_close(struct net_device *dev) { + int retval; LIST_HEAD(single); list_add(&dev->unreg_list, &single); - return __dev_close_many(&single); + retval = __dev_close_many(&single); + list_del(&single); + return retval; } int dev_close_many(struct list_head *head) @@ -1325,7 +1328,7 @@ int dev_close(struct net_device *dev) list_add(&dev->unreg_list, &single); dev_close_many(&single); - + list_del(&single); return 0; } EXPORT_SYMBOL(dev_close); @@ -5063,6 +5066,7 @@ static void rollback_registered(struct net_device *dev) list_add(&dev->unreg_list, &single); rollback_registered_many(&single); + list_del(&single); } unsigned long netdev_fix_features(unsigned long features, const char *name) @@ -6216,6 +6220,7 @@ static void __net_exit default_device_exit_batch(struct list_head *net_list) } } unregister_netdevice_many(&dev_kill_list); + list_del(&dev_kill_list); rtnl_unlock(); } diff --git a/trunk/net/dcb/dcbnl.c b/trunk/net/dcb/dcbnl.c index 6b03f561caec..d5074a567289 100644 --- a/trunk/net/dcb/dcbnl.c +++ b/trunk/net/dcb/dcbnl.c @@ -626,6 +626,9 @@ static int dcbnl_getapp(struct net_device *netdev, struct nlattr **tb, dcb->cmd = DCB_CMD_GAPP; app_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_APP); + if (!app_nest) + goto out_cancel; + ret = nla_put_u8(dcbnl_skb, DCB_APP_ATTR_IDTYPE, idtype); if (ret) goto out_cancel; @@ -1613,6 +1616,10 @@ EXPORT_SYMBOL(dcb_getapp); u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) { struct dcb_app_type *itr; + struct dcb_app_type event; + + memcpy(&event.name, dev->name, sizeof(event.name)); + memcpy(&event.app, new, sizeof(event.app)); spin_lock(&dcb_lock); /* Search for existing match and replace */ @@ -1644,7 +1651,7 @@ u8 dcb_setapp(struct net_device *dev, struct dcb_app *new) } out: spin_unlock(&dcb_lock); - call_dcbevent_notifiers(DCB_APP_EVENT, new); + call_dcbevent_notifiers(DCB_APP_EVENT, &event); return 0; } EXPORT_SYMBOL(dcb_setapp); diff --git a/trunk/net/ipv4/devinet.c b/trunk/net/ipv4/devinet.c index 748cb5b337bd..df4616fce929 100644 --- a/trunk/net/ipv4/devinet.c +++ b/trunk/net/ipv4/devinet.c @@ -1030,6 +1030,21 @@ static inline bool inetdev_valid_mtu(unsigned mtu) return mtu >= 68; } +static void inetdev_send_gratuitous_arp(struct net_device *dev, + struct in_device *in_dev) + +{ + struct in_ifaddr *ifa = in_dev->ifa_list; + + if (!ifa) + return; + + arp_send(ARPOP_REQUEST, ETH_P_ARP, + ifa->ifa_address, dev, + ifa->ifa_address, NULL, + dev->dev_addr, NULL); +} + /* Called only under RTNL semaphore */ static int inetdev_event(struct notifier_block *this, unsigned long event, @@ -1082,18 +1097,13 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, } ip_mc_up(in_dev); /* fall through */ - case NETDEV_NOTIFY_PEERS: case NETDEV_CHANGEADDR: + if (!IN_DEV_ARP_NOTIFY(in_dev)) + break; + /* fall through */ + case NETDEV_NOTIFY_PEERS: /* Send gratuitous ARP to notify of link change */ - if (IN_DEV_ARP_NOTIFY(in_dev)) { - struct in_ifaddr *ifa = in_dev->ifa_list; - - if (ifa) - arp_send(ARPOP_REQUEST, ETH_P_ARP, - ifa->ifa_address, dev, - ifa->ifa_address, NULL, - dev->dev_addr, NULL); - } + inetdev_send_gratuitous_arp(dev, in_dev); break; case NETDEV_DOWN: ip_mc_down(in_dev); diff --git a/trunk/net/ipv4/ip_gre.c b/trunk/net/ipv4/ip_gre.c index eb68a0e34e49..6613edfac28c 100644 --- a/trunk/net/ipv4/ip_gre.c +++ b/trunk/net/ipv4/ip_gre.c @@ -775,6 +775,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev .fl4_dst = dst, .fl4_src = tiph->saddr, .fl4_tos = RT_TOS(tos), + .proto = IPPROTO_GRE, .fl_gre_key = tunnel->parms.o_key }; if (ip_route_output_key(dev_net(dev), &rt, &fl)) { diff --git a/trunk/net/ipv4/route.c b/trunk/net/ipv4/route.c index 788a3e74834e..6ed6603c2f6d 100644 --- a/trunk/net/ipv4/route.c +++ b/trunk/net/ipv4/route.c @@ -2722,6 +2722,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { .destroy = ipv4_dst_destroy, .check = ipv4_blackhole_dst_check, .default_mtu = ipv4_blackhole_default_mtu, + .default_advmss = ipv4_default_advmss, .update_pmtu = ipv4_rt_blackhole_update_pmtu, }; diff --git a/trunk/net/ipv6/route.c b/trunk/net/ipv6/route.c index 1c29f95695de..a998db6e7895 100644 --- a/trunk/net/ipv6/route.c +++ b/trunk/net/ipv6/route.c @@ -128,6 +128,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { .destroy = ip6_dst_destroy, .check = ip6_dst_check, .default_mtu = ip6_blackhole_default_mtu, + .default_advmss = ip6_default_advmss, .update_pmtu = ip6_rt_blackhole_update_pmtu, }; diff --git a/trunk/net/mac80211/util.c b/trunk/net/mac80211/util.c index cf68700abffa..d036597aabbe 100644 --- a/trunk/net/mac80211/util.c +++ b/trunk/net/mac80211/util.c @@ -1210,7 +1210,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) switch (sdata->vif.type) { case NL80211_IFTYPE_STATION: changed |= BSS_CHANGED_ASSOC; + mutex_lock(&sdata->u.mgd.mtx); ieee80211_bss_info_change_notify(sdata, changed); + mutex_unlock(&sdata->u.mgd.mtx); break; case NL80211_IFTYPE_ADHOC: changed |= BSS_CHANGED_IBSS; diff --git a/trunk/net/netfilter/core.c b/trunk/net/netfilter/core.c index 32fcbe290c04..4aa614b8a96a 100644 --- a/trunk/net/netfilter/core.c +++ b/trunk/net/netfilter/core.c @@ -133,6 +133,7 @@ unsigned int nf_iterate(struct list_head *head, /* Optimization: we don't need to hold module reference here, since function can't sleep. --RR */ +repeat: verdict = elem->hook(hook, skb, indev, outdev, okfn); if (verdict != NF_ACCEPT) { #ifdef CONFIG_NETFILTER_DEBUG @@ -145,7 +146,7 @@ unsigned int nf_iterate(struct list_head *head, #endif if (verdict != NF_REPEAT) return verdict; - *i = (*i)->prev; + goto repeat; } } return NF_ACCEPT; diff --git a/trunk/net/xfrm/xfrm_policy.c b/trunk/net/xfrm/xfrm_policy.c index 8b3ef404c794..6459588befc3 100644 --- a/trunk/net/xfrm/xfrm_policy.c +++ b/trunk/net/xfrm/xfrm_policy.c @@ -1340,10 +1340,13 @@ static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) default: BUG(); } - xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS); + xdst = dst_alloc(dst_ops); xfrm_policy_put_afinfo(afinfo); - xdst->flo.ops = &xfrm_bundle_fc_ops; + if (likely(xdst)) + xdst->flo.ops = &xfrm_bundle_fc_ops; + else + xdst = ERR_PTR(-ENOBUFS); return xdst; } diff --git a/trunk/scripts/basic/fixdep.c b/trunk/scripts/basic/fixdep.c index c9a16abacab4..6c94c6ce2925 100644 --- a/trunk/scripts/basic/fixdep.c +++ b/trunk/scripts/basic/fixdep.c @@ -315,6 +315,7 @@ static void parse_dep_file(void *map, size_t len) char *end = m + len; char *p; char s[PATH_MAX]; + int first; p = strchr(m, ':'); if (!p) { @@ -327,6 +328,7 @@ static void parse_dep_file(void *map, size_t len) clear_config(); + first = 1; while (m < end) { while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) m++; @@ -340,9 +342,17 @@ static void parse_dep_file(void *map, size_t len) if (strrcmp(s, "include/generated/autoconf.h") && strrcmp(s, "arch/um/include/uml-config.h") && strrcmp(s, ".ver")) { - printf(" %s \\\n", s); + /* + * Do not output the first dependency (the + * source file), so that kbuild is not confused + * if a .c file is rewritten into .S or vice + * versa. + */ + if (!first) + printf(" %s \\\n", s); do_config_file(s); } + first = 0; m = p + 1; } printf("\n%s: $(deps_%s)\n\n", target, target); diff --git a/trunk/scripts/kconfig/streamline_config.pl b/trunk/scripts/kconfig/streamline_config.pl index a4fe923c0131..fd81fc33d633 100644 --- a/trunk/scripts/kconfig/streamline_config.pl +++ b/trunk/scripts/kconfig/streamline_config.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -w # -# Copyright 2005-2009 - Steven Rostedt +# Copywrite 2005-2009 - Steven Rostedt # Licensed under the terms of the GNU GPL License version 2 # # It's simple enough to figure out how this works. diff --git a/trunk/sound/pci/au88x0/au88x0_core.c b/trunk/sound/pci/au88x0/au88x0_core.c index 23f49f356e0f..16c0bdfbb164 100644 --- a/trunk/sound/pci/au88x0/au88x0_core.c +++ b/trunk/sound/pci/au88x0/au88x0_core.c @@ -1252,11 +1252,19 @@ static void vortex_adbdma_resetup(vortex_t *vortex, int adbdma) { static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma) { stream_t *dma = &vortex->dma_adb[adbdma]; - int temp; + int temp, page, delta; temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)); - temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1)); - return temp; + page = (temp & ADB_SUBBUF_MASK) >> ADB_SUBBUF_SHIFT; + if (dma->nr_periods >= 4) + delta = (page - dma->period_real) & 3; + else { + delta = (page - dma->period_real); + if (delta < 0) + delta += dma->nr_periods; + } + return (dma->period_virt + delta) * dma->period_bytes + + (temp & (dma->period_bytes - 1)); } static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma) diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index 0baffcdee8f9..fcedad9a5fef 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -2308,6 +2308,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1043, 0x8410, "ASUS", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index fbe97d32140d..dd7c5c12225d 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -3410,7 +3410,7 @@ static void cx_auto_parse_output(struct hda_codec *codec) } } spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.max_channels = nums * 2; + spec->multiout.max_channels = spec->multiout.num_dacs * 2; if (cfg->hp_outs > 0) spec->auto_mute = 1; @@ -3729,9 +3729,9 @@ static int cx_auto_init(struct hda_codec *codec) return 0; } -static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, +static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, const char *dir, int cidx, - hda_nid_t nid, int hda_dir) + hda_nid_t nid, int hda_dir, int amp_idx) { static char name[32]; static struct snd_kcontrol_new knew[] = { @@ -3743,7 +3743,8 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, for (i = 0; i < 2; i++) { struct snd_kcontrol *kctl; - knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir); + knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx, + hda_dir); knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; knew[i].index = cidx; snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); @@ -3759,6 +3760,9 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, return 0; } +#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ + cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0) + #define cx_auto_add_pb_volume(codec, nid, str, idx) \ cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) @@ -3808,29 +3812,60 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; static const char *prev_label; - int i, err, cidx; + int i, err, cidx, conn_len; + hda_nid_t conn[HDA_MAX_CONNECTIONS]; + + int multi_adc_volume = 0; /* If the ADC nid has several input volumes */ + int adc_nid = spec->adc_nids[0]; + + conn_len = snd_hda_get_connections(codec, adc_nid, conn, + HDA_MAX_CONNECTIONS); + if (conn_len < 0) + return conn_len; + + multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1; + if (!multi_adc_volume) { + err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid, + HDA_INPUT); + if (err < 0) + return err; + } - err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0], - HDA_INPUT); - if (err < 0) - return err; prev_label = NULL; cidx = 0; for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; const char *label; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) + int j; + int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; + if (!pin_amp && !multi_adc_volume) continue; + label = hda_get_autocfg_input_label(codec, cfg, i); if (label == prev_label) cidx++; else cidx = 0; prev_label = label; - err = cx_auto_add_volume(codec, label, " Capture", cidx, - nid, HDA_INPUT); - if (err < 0) - return err; + + if (pin_amp) { + err = cx_auto_add_volume(codec, label, " Boost", cidx, + nid, HDA_INPUT); + if (err < 0) + return err; + } + + if (!multi_adc_volume) + continue; + for (j = 0; j < conn_len; j++) { + if (conn[j] == nid) { + err = cx_auto_add_volume_idx(codec, label, + " Capture", cidx, adc_nid, HDA_INPUT, j); + if (err < 0) + return err; + break; + } + } } return 0; } diff --git a/trunk/sound/soc/codecs/cx20442.c b/trunk/sound/soc/codecs/cx20442.c index bb4bf65b9e7e..0bb424af956f 100644 --- a/trunk/sound/soc/codecs/cx20442.c +++ b/trunk/sound/soc/codecs/cx20442.c @@ -367,7 +367,7 @@ static int cx20442_codec_remove(struct snd_soc_codec *codec) return 0; } -static const u8 cx20442_reg = CX20442_TELOUT | CX20442_MIC; +static const u8 cx20442_reg; static struct snd_soc_codec_driver cx20442_codec_dev = { .probe = cx20442_codec_probe, diff --git a/trunk/sound/soc/codecs/wm8903.c b/trunk/sound/soc/codecs/wm8903.c index 987476a5895f..017d99ceb42e 100644 --- a/trunk/sound/soc/codecs/wm8903.c +++ b/trunk/sound/soc/codecs/wm8903.c @@ -1482,7 +1482,7 @@ int wm8903_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, WM8903_MICDET_EINT | WM8903_MICSHRT_EINT, irq_mask); - if (det && shrt) { + if (det || shrt) { /* Enable mic detection, this may not have been set through * platform data (eg, if the defaults are OK). */ snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0, diff --git a/trunk/sound/soc/codecs/wm8994.c b/trunk/sound/soc/codecs/wm8994.c index 37b8aa8a680f..a60b5dbf0154 100644 --- a/trunk/sound/soc/codecs/wm8994.c +++ b/trunk/sound/soc/codecs/wm8994.c @@ -107,6 +107,9 @@ struct wm8994_priv { int revision; struct wm8994_pdata *pdata; + + unsigned int aif1clk_enable:1; + unsigned int aif2clk_enable:1; }; static int wm8994_readable(unsigned int reg) @@ -1004,6 +1007,93 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec) } } +static int late_enable_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (wm8994->aif1clk_enable) + snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, + WM8994_AIF1CLK_ENA_MASK, + WM8994_AIF1CLK_ENA); + if (wm8994->aif2clk_enable) + snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, + WM8994_AIF2CLK_ENA_MASK, + WM8994_AIF2CLK_ENA); + break; + } + + return 0; +} + +static int late_disable_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMD: + if (wm8994->aif1clk_enable) { + snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1, + WM8994_AIF1CLK_ENA_MASK, 0); + wm8994->aif1clk_enable = 0; + } + if (wm8994->aif2clk_enable) { + snd_soc_update_bits(codec, WM8994_AIF2_CLOCKING_1, + WM8994_AIF2CLK_ENA_MASK, 0); + wm8994->aif2clk_enable = 0; + } + break; + } + + return 0; +} + +static int aif1clk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wm8994->aif1clk_enable = 1; + break; + } + + return 0; +} + +static int aif2clk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wm8994->aif2clk_enable = 1; + break; + } + + return 0; +} + +static int dac_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + unsigned int mask = 1 << w->shift; + + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, + mask, mask); + return 0; +} + static const char *hp_mux_text[] = { "Mixer", "DAC", @@ -1272,6 +1362,47 @@ static const struct soc_enum aif2dacr_src_enum = static const struct snd_kcontrol_new aif2dacr_src_mux = SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum); +static const struct snd_soc_dapm_widget wm8994_lateclk_revd_widgets[] = { +SND_SOC_DAPM_SUPPLY("AIF1CLK", SND_SOC_NOPM, 0, 0, aif1clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), +SND_SOC_DAPM_SUPPLY("AIF2CLK", SND_SOC_NOPM, 0, 0, aif2clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + +SND_SOC_DAPM_PGA_E("Late DAC1L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + late_enable_ev, SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_PGA_E("Late DAC1R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + late_enable_ev, SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + late_enable_ev, SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, + late_enable_ev, SND_SOC_DAPM_PRE_PMU), + +SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) +}; + +static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { +SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) +}; + +static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { +SND_SOC_DAPM_DAC_E("DAC2L", NULL, SND_SOC_NOPM, 3, 0, + dac_ev, SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_DAC_E("DAC2R", NULL, SND_SOC_NOPM, 2, 0, + dac_ev, SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_DAC_E("DAC1L", NULL, SND_SOC_NOPM, 1, 0, + dac_ev, SND_SOC_DAPM_PRE_PMU), +SND_SOC_DAPM_DAC_E("DAC1R", NULL, SND_SOC_NOPM, 0, 0, + dac_ev, SND_SOC_DAPM_PRE_PMU), +}; + +static const struct snd_soc_dapm_widget wm8994_dac_widgets[] = { +SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0), +SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0), +SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0), +SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), +}; + static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { SND_SOC_DAPM_INPUT("DMIC1DAT"), SND_SOC_DAPM_INPUT("DMIC2DAT"), @@ -1284,9 +1415,6 @@ SND_SOC_DAPM_SUPPLY("DSP1CLK", WM8994_CLOCKING_1, 3, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DSP2CLK", WM8994_CLOCKING_1, 2, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DSPINTCLK", WM8994_CLOCKING_1, 1, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), -SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0), - SND_SOC_DAPM_AIF_OUT("AIF1ADC1L", NULL, 0, WM8994_POWER_MANAGEMENT_4, 9, 0), SND_SOC_DAPM_AIF_OUT("AIF1ADC1R", NULL, @@ -1372,11 +1500,6 @@ SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("ADCL Mux", WM8994_POWER_MANAGEMENT_4, 1, 0, &adcl_mux), SND_SOC_DAPM_MUX("ADCR Mux", WM8994_POWER_MANAGEMENT_4, 0, 0, &adcr_mux), -SND_SOC_DAPM_DAC("DAC2L", NULL, WM8994_POWER_MANAGEMENT_5, 3, 0), -SND_SOC_DAPM_DAC("DAC2R", NULL, WM8994_POWER_MANAGEMENT_5, 2, 0), -SND_SOC_DAPM_DAC("DAC1L", NULL, WM8994_POWER_MANAGEMENT_5, 1, 0), -SND_SOC_DAPM_DAC("DAC1R", NULL, WM8994_POWER_MANAGEMENT_5, 0, 0), - SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), @@ -1516,14 +1639,12 @@ static const struct snd_soc_dapm_route intercon[] = { { "AIF2ADC Mux", "AIF3DACDAT", "AIF3ADCDAT" }, /* DAC1 inputs */ - { "DAC1L", NULL, "DAC1L Mixer" }, { "DAC1L Mixer", "AIF2 Switch", "AIF2DACL" }, { "DAC1L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, { "DAC1L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, { "DAC1L Mixer", "Left Sidetone Switch", "Left Sidetone" }, { "DAC1L Mixer", "Right Sidetone Switch", "Right Sidetone" }, - { "DAC1R", NULL, "DAC1R Mixer" }, { "DAC1R Mixer", "AIF2 Switch", "AIF2DACR" }, { "DAC1R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, { "DAC1R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, @@ -1532,7 +1653,6 @@ static const struct snd_soc_dapm_route intercon[] = { /* DAC2/AIF2 outputs */ { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" }, - { "DAC2L", NULL, "AIF2DAC2L Mixer" }, { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" }, { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, @@ -1540,7 +1660,6 @@ static const struct snd_soc_dapm_route intercon[] = { { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" }, { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" }, - { "DAC2R", NULL, "AIF2DAC2R Mixer" }, { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" }, { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, @@ -1584,6 +1703,24 @@ static const struct snd_soc_dapm_route intercon[] = { { "Right Headphone Mux", "DAC", "DAC1R" }, }; +static const struct snd_soc_dapm_route wm8994_lateclk_revd_intercon[] = { + { "DAC1L", NULL, "Late DAC1L Enable PGA" }, + { "Late DAC1L Enable PGA", NULL, "DAC1L Mixer" }, + { "DAC1R", NULL, "Late DAC1R Enable PGA" }, + { "Late DAC1R Enable PGA", NULL, "DAC1R Mixer" }, + { "DAC2L", NULL, "Late DAC2L Enable PGA" }, + { "Late DAC2L Enable PGA", NULL, "AIF2DAC2L Mixer" }, + { "DAC2R", NULL, "Late DAC2R Enable PGA" }, + { "Late DAC2R Enable PGA", NULL, "AIF2DAC2R Mixer" } +}; + +static const struct snd_soc_dapm_route wm8994_lateclk_intercon[] = { + { "DAC1L", NULL, "DAC1L Mixer" }, + { "DAC1R", NULL, "DAC1R Mixer" }, + { "DAC2L", NULL, "AIF2DAC2L Mixer" }, + { "DAC2R", NULL, "AIF2DAC2R Mixer" }, +}; + static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { { "AIF1DACDAT", NULL, "AIF2DACDAT" }, { "AIF2DACDAT", NULL, "AIF1DACDAT" }, @@ -2514,6 +2651,22 @@ static int wm8994_resume(struct snd_soc_codec *codec) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); int i, ret; + unsigned int val, mask; + + if (wm8994->revision < 4) { + /* force a HW read */ + val = wm8994_reg_read(codec->control_data, + WM8994_POWER_MANAGEMENT_5); + + /* modify the cache only */ + codec->cache_only = 1; + mask = WM8994_DAC1R_ENA | WM8994_DAC1L_ENA | + WM8994_DAC2R_ENA | WM8994_DAC2L_ENA; + val &= mask; + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, + mask, val); + codec->cache_only = 0; + } /* Restore the registers */ ret = snd_soc_cache_sync(codec); @@ -3125,6 +3278,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) case WM8994: snd_soc_dapm_new_controls(dapm, wm8994_specific_dapm_widgets, ARRAY_SIZE(wm8994_specific_dapm_widgets)); + if (wm8994->revision < 4) { + snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, + ARRAY_SIZE(wm8994_lateclk_revd_widgets)); + snd_soc_dapm_new_controls(dapm, wm8994_dac_revd_widgets, + ARRAY_SIZE(wm8994_dac_revd_widgets)); + } else { + snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets, + ARRAY_SIZE(wm8994_lateclk_widgets)); + snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets, + ARRAY_SIZE(wm8994_dac_widgets)); + } break; case WM8958: snd_soc_add_controls(codec, wm8958_snd_controls, @@ -3143,10 +3307,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) snd_soc_dapm_add_routes(dapm, wm8994_intercon, ARRAY_SIZE(wm8994_intercon)); - if (wm8994->revision < 4) + if (wm8994->revision < 4) { snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon, ARRAY_SIZE(wm8994_revd_intercon)); - + snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon, + ARRAY_SIZE(wm8994_lateclk_revd_intercon)); + } else { + snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon, + ARRAY_SIZE(wm8994_lateclk_intercon)); + } break; case WM8958: snd_soc_dapm_add_routes(dapm, wm8958_intercon, diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index 8194f150bab7..25e54230cc6a 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -712,7 +712,15 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) !path->connected(path->source, path->sink)) continue; - if (path->sink && path->sink->power_check && + if (!path->sink) + continue; + + if (path->sink->force) { + power = 1; + break; + } + + if (path->sink->power_check && path->sink->power_check(path->sink)) { power = 1; break; @@ -1627,6 +1635,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) { struct snd_soc_dapm_widget *w; + unsigned int val; list_for_each_entry(w, &dapm->card->widgets, list) { @@ -1675,6 +1684,18 @@ int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm) case snd_soc_dapm_post: break; } + + /* Read the initial power state from the device */ + if (w->reg >= 0) { + val = snd_soc_read(w->codec, w->reg); + val &= 1 << w->shift; + if (w->invert) + val = !val; + + if (val) + w->power = 1; + } + w->new = 1; } diff --git a/trunk/sound/usb/caiaq/audio.c b/trunk/sound/usb/caiaq/audio.c index 68b97477577b..66eabafb1c24 100644 --- a/trunk/sound/usb/caiaq/audio.c +++ b/trunk/sound/usb/caiaq/audio.c @@ -785,7 +785,7 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *dev) } dev->pcm->private_data = dev; - strcpy(dev->pcm->name, dev->product_name); + strlcpy(dev->pcm->name, dev->product_name, sizeof(dev->pcm->name)); memset(dev->sub_playback, 0, sizeof(dev->sub_playback)); memset(dev->sub_capture, 0, sizeof(dev->sub_capture)); diff --git a/trunk/sound/usb/caiaq/midi.c b/trunk/sound/usb/caiaq/midi.c index 2f218c77fff2..a1a47088fd0c 100644 --- a/trunk/sound/usb/caiaq/midi.c +++ b/trunk/sound/usb/caiaq/midi.c @@ -136,7 +136,7 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device) if (ret < 0) return ret; - strcpy(rmidi->name, device->product_name); + strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name)); rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = device; diff --git a/trunk/tools/perf/.gitignore b/trunk/tools/perf/.gitignore index 416684be0ad3..cb43289e447f 100644 --- a/trunk/tools/perf/.gitignore +++ b/trunk/tools/perf/.gitignore @@ -1,3 +1,4 @@ +PERF-BUILD-OPTIONS PERF-CFLAGS PERF-GUI-VARS PERF-VERSION-FILE diff --git a/trunk/tools/perf/Documentation/Makefile b/trunk/tools/perf/Documentation/Makefile index 4626a398836a..bd498d496952 100644 --- a/trunk/tools/perf/Documentation/Makefile +++ b/trunk/tools/perf/Documentation/Makefile @@ -178,8 +178,8 @@ install-pdf: pdf $(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir) $(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir) -#install-html: html -# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) +install-html: html + '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir) ../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE $(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE @@ -288,16 +288,15 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \ mv $@+ $@ -# UNIMPLEMENTED -#install-webdoc : html -# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST) +install-webdoc : html + '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST) -# quick-install: quick-install-man +quick-install: quick-install-man -# quick-install-man: -# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) +quick-install-man: + '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir) -#quick-install-html: -# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) +quick-install-html: + '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir) .PHONY: .FORCE-PERF-VERSION-FILE diff --git a/trunk/tools/perf/Documentation/perf-list.txt b/trunk/tools/perf/Documentation/perf-list.txt index 7a527f7e9da9..399751befeed 100644 --- a/trunk/tools/perf/Documentation/perf-list.txt +++ b/trunk/tools/perf/Documentation/perf-list.txt @@ -8,7 +8,7 @@ perf-list - List all symbolic event types SYNOPSIS -------- [verse] -'perf list' [hw|sw|cache|tracepoint|event_glob] +'perf list' DESCRIPTION ----------- @@ -63,26 +63,7 @@ details. Some of them are referenced in the SEE ALSO section below. OPTIONS ------- - -Without options all known events will be listed. - -To limit the list use: - -. 'hw' or 'hardware' to list hardware events such as cache-misses, etc. - -. 'sw' or 'software' to list software events such as context switches, etc. - -. 'cache' or 'hwcache' to list hardware cache events such as L1-dcache-loads, etc. - -. 'tracepoint' to list all tracepoint events, alternatively use - 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, - block, etc. - -. If none of the above is matched, it will apply the supplied glob to all - events, printing the ones that match. - -One or more types can be used at the same time, listing the events for the -types specified. +None SEE ALSO -------- diff --git a/trunk/tools/perf/Documentation/perf-lock.txt b/trunk/tools/perf/Documentation/perf-lock.txt index 4a26a2f3a6a3..921de259ea10 100644 --- a/trunk/tools/perf/Documentation/perf-lock.txt +++ b/trunk/tools/perf/Documentation/perf-lock.txt @@ -24,8 +24,8 @@ and statistics with this 'perf lock' command. 'perf lock report' reports statistical data. -COMMON OPTIONS --------------- +OPTIONS +------- -i:: --input=:: @@ -39,14 +39,6 @@ COMMON OPTIONS --dump-raw-trace:: Dump raw trace in ASCII. -REPORT OPTIONS --------------- - --k:: ---key=:: - Sorting key. Possible values: acquired (default), contended, - wait_total, wait_max, wait_min. - SEE ALSO -------- linkperf:perf[1] diff --git a/trunk/tools/perf/Documentation/perf-probe.txt b/trunk/tools/perf/Documentation/perf-probe.txt index 02bafce4b341..86b797a35aa6 100644 --- a/trunk/tools/perf/Documentation/perf-probe.txt +++ b/trunk/tools/perf/Documentation/perf-probe.txt @@ -16,7 +16,7 @@ or or 'perf probe' --list or -'perf probe' [options] --line='LINE' +'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' or 'perf probe' [options] --vars='PROBEPOINT' @@ -73,17 +73,6 @@ OPTIONS (Only for --vars) Show external defined variables in addition to local variables. --F:: ---funcs:: - Show available functions in given module or kernel. - ---filter=FILTER:: - (Only for --vars and --funcs) Set filter. FILTER is a combination of glob - pattern, see FILTER PATTERN for detail. - Default FILTER is "!__k???tab_* & !__crc_*" for --vars, and "!_*" - for --funcs. - If several filters are specified, only the last filter is used. - -f:: --force:: Forcibly add events with existing name. @@ -128,14 +117,13 @@ LINE SYNTAX ----------- Line range is described by following syntax. - "FUNC[@SRC][:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]" + "FUNC[:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]" FUNC specifies the function name of showing lines. 'RLN' is the start line number from function entry line, and 'RLN2' is the end line number. As same as probe syntax, 'SRC' means the source file path, 'ALN' is start line number, and 'ALN2' is end line number in the file. It is also possible to specify how -many lines to show by using 'NUM'. Moreover, 'FUNC@SRC' combination is good -for searching a specific function when several functions share same name. +many lines to show by using 'NUM'. So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. LAZY MATCHING @@ -147,14 +135,6 @@ e.g. This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.) -FILTER PATTERN --------------- - The filter pattern is a glob matching pattern(s) to filter variables. - In addition, you can use "!" for specifying filter-out rule. You also can give several rules combined with "&" or "|", and fold those rules as one rule by using "(" ")". - -e.g. - With --filter "foo* | bar*", perf probe -V shows variables which start with "foo" or "bar". - With --filter "!foo* & *bar", perf probe -V shows variables which don't start with "foo" and end with "bar", like "fizzbar". But "foobar" is filtered out. EXAMPLES -------- diff --git a/trunk/tools/perf/Documentation/perf-record.txt b/trunk/tools/perf/Documentation/perf-record.txt index 5a520f825295..e032716c839b 100644 --- a/trunk/tools/perf/Documentation/perf-record.txt +++ b/trunk/tools/perf/Documentation/perf-record.txt @@ -137,17 +137,6 @@ Do not update the builid cache. This saves some overhead in situations where the information in the perf.data file (which includes buildids) is sufficient. --G name,...:: ---cgroup name,...:: -monitor only in the container (cgroup) called "name". This option is available only -in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to -container "name" are monitored when they run on the monitored CPUs. Multiple cgroups -can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup -to first event, second cgroup to second event and so on. It is possible to provide -an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have -corresponding events, i.e., they always refer to events defined earlier on the command -line. - SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/trunk/tools/perf/Documentation/perf-stat.txt b/trunk/tools/perf/Documentation/perf-stat.txt index 918cc38ee6d1..b6da7affbbee 100644 --- a/trunk/tools/perf/Documentation/perf-stat.txt +++ b/trunk/tools/perf/Documentation/perf-stat.txt @@ -83,17 +83,6 @@ This option is only valid in system-wide mode. print counts using a CSV-style output to make it easy to import directly into spreadsheets. Columns are separated by the string specified in SEP. --G name:: ---cgroup name:: -monitor only in the container (cgroup) called "name". This option is available only -in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to -container "name" are monitored when they run on the monitored CPUs. Multiple cgroups -can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup -to first event, second cgroup to second event and so on. It is possible to provide -an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have -corresponding events, i.e., they always refer to events defined earlier on the command -line. - EXAMPLES -------- diff --git a/trunk/tools/perf/Makefile b/trunk/tools/perf/Makefile index 9b8421805c5c..7141c42e1469 100644 --- a/trunk/tools/perf/Makefile +++ b/trunk/tools/perf/Makefile @@ -3,7 +3,7 @@ ifeq ("$(origin O)", "command line") endif # The default target of this Makefile is... -all: +all:: ifneq ($(OUTPUT),) # check that the output directory actually exists @@ -11,12 +11,152 @@ OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) endif -# Define V to have a more verbose compile. +# Define V=1 to have a more verbose compile. +# Define V=2 to have an even more verbose compile. +# +# Define SNPRINTF_RETURNS_BOGUS if your are on a system which snprintf() +# or vsnprintf() return -1 instead of number of characters which would +# have been written to the final string if enough space had been available. +# +# Define FREAD_READS_DIRECTORIES if your are on a system which succeeds +# when attempting to read from an fopen'ed directory. +# +# Define NO_OPENSSL environment variable if you do not have OpenSSL. +# This also implies MOZILLA_SHA1. +# +# Define CURLDIR=/foo/bar if your curl header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +# +# Define EXPATDIR=/foo/bar if your expat header and library files are in +# /foo/bar/include and /foo/bar/lib directories. +# +# Define NO_D_INO_IN_DIRENT if you don't have d_ino in your struct dirent. +# +# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks +# d_type in struct dirent (latest Cygwin -- will be fixed soonish). +# +# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) +# do not support the 'size specifiers' introduced by C99, namely ll, hh, +# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). +# some C compilers supported these specifiers prior to C99 as an extension. +# +# Define NO_STRCASESTR if you don't have strcasestr. +# +# Define NO_MEMMEM if you don't have memmem. +# +# Define NO_STRTOUMAX if you don't have strtoumax in the C library. +# If your compiler also does not support long long or does not have +# strtoull, define NO_STRTOULL. +# +# Define NO_SETENV if you don't have setenv in the C library. +# +# Define NO_UNSETENV if you don't have unsetenv in the C library. +# +# Define NO_MKDTEMP if you don't have mkdtemp in the C library. +# +# Define NO_SYS_SELECT_H if you don't have sys/select.h. +# +# Define NO_SYMLINK_HEAD if you never want .perf/HEAD to be a symbolic link. +# Enable it on Windows. By default, symrefs are still used. +# +# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability +# tests. These tests take up a significant amount of the total test time +# but are not needed unless you plan to talk to SVN repos. +# +# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink +# installed in /sw, but don't want PERF to link against any libraries +# installed there. If defined you may specify your own (or Fink's) +# include directories and library directories by defining CFLAGS +# and LDFLAGS appropriately. +# +# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X, +# have DarwinPorts installed in /opt/local, but don't want PERF to +# link against any libraries installed there. If defined you may +# specify your own (or DarwinPort's) include directories and +# library directories by defining CFLAGS and LDFLAGS appropriately. +# +# Define PPC_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for PowerPC. +# +# Define ARM_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine optimized for ARM. +# +# Define MOZILLA_SHA1 environment variable when running make to make use of +# a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast +# on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default +# choice) has very fast version optimized for i586. +# +# Define NEEDS_SSL_WITH_CRYPTO if you need -lcrypto with -lssl (Darwin). +# +# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin). +# +# Define NEEDS_SOCKET if linking with libc is not enough (SunOS, +# Patrick Mauritz). +# +# Define NO_MMAP if you want to avoid mmap. +# +# Define NO_PTHREADS if you do not have or do not want to use Pthreads. +# +# Define NO_PREAD if you have a problem with pread() system call (e.g. +# cygwin.dll before v1.5.22). +# +# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is +# generally faster on your platform than accessing the working directory. +# +# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support +# the executable mode bit, but doesn't really do so. +# +# Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). +# +# Define NO_SOCKADDR_STORAGE if your platform does not have struct +# sockaddr_storage. +# +# Define NO_ICONV if your libc does not properly support iconv. +# +# Define OLD_ICONV if your library has an old iconv(), where the second +# (input buffer pointer) parameter is declared with type (const char **). +# +# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound. +# +# Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib" +# that tells runtime paths to dynamic libraries; +# "-Wl,-rpath=/path/lib" is used instead. +# +# Define USE_NSEC below if you want perf to care about sub-second file mtimes +# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and +# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely +# randomly break unless your underlying filesystem supports those sub-second +# times (my ext3 doesn't). +# +# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of +# "st_ctim" +# +# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" +# available. This automatically turns USE_NSEC off. +# +# Define USE_STDEV below if you want perf to care about the underlying device +# change being considered an inode change from the update-index perspective. +# +# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks +# field that counts the on-disk footprint in 512-byte blocks. # # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8 # # Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72. # +# Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's +# MakeMaker (e.g. using ActiveState under Cygwin). +# +# Define NO_PERL if you do not want Perl scripts or libraries at all. +# +# Define INTERNAL_QSORT to use Git's implementation of qsort(), which +# is a simplified version of the merge sort used in glibc. This is +# recommended if Git triggers O(n^2) behavior in your platform's qsort(). +# +# Define NO_EXTERNAL_GREP if you don't want "perf grep" to ever call +# your external grep (e.g., if your system lacks grep, if its grep is +# broken, or spawning external process is slower than built-in grep perf has). +# # Define LDFLAGS=-static to build a static binary. # # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. @@ -27,7 +167,12 @@ $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) -include $(OUTPUT)PERF-VERSION-FILE -uname_M := $(shell uname -m 2>/dev/null || echo not) +uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') +uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not') +uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not') +uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not') +uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not') +uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not') ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ @@ -46,6 +191,8 @@ ifeq ($(ARCH),x86_64) ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S endif +# CFLAGS and LDFLAGS are for the users to override from the command line. + # # Include saner warnings here, which can catch bugs: # @@ -123,13 +270,22 @@ CC = $(CROSS_COMPILE)gcc AR = $(CROSS_COMPILE)ar RM = rm -f MKDIR = mkdir +TAR = tar FIND = find INSTALL = install +RPMBUILD = rpmbuild +PTHREAD_LIBS = -lpthread # sparse is architecture-neutral, which means that we need to tell it # explicitly what architecture to check for. Fix this up for yours.. SPARSE_FLAGS = -D__BIG_ENDIAN__ -D__powerpc__ +ifeq ($(V), 2) + QUIET_STDERR = ">/dev/null" +else + QUIET_STDERR = ">/dev/null 2>&1" +endif + -include feature-tests.mak ifeq ($(call try-cc,$(SOURCE_HELLO),-Werror -fstack-protector-all),y) @@ -154,37 +310,49 @@ BASIC_LDFLAGS = # Guard against environment variables BUILTIN_OBJS = +BUILT_INS = +COMPAT_CFLAGS = +COMPAT_OBJS = LIB_H = LIB_OBJS = -PYRF_OBJS = +SCRIPT_PERL = SCRIPT_SH = +TEST_PROGRAMS = SCRIPT_SH += perf-archive.sh grep-libs = $(filter -l%,$(1)) strip-libs = $(filter-out -l%,$(1)) -$(OUTPUT)python/perf.so: $(PYRF_OBJS) - $(QUIET_GEN)python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \ - --build-temp='$(OUTPUT)python/temp' # # No Perl scripts right now: # -SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) +# SCRIPT_PERL += perf-add--interactive.perl + +SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ + $(patsubst %.perl,%,$(SCRIPT_PERL)) + +# Empty... +EXTRA_PROGRAMS = + +# ... and all the rest that could be moved out of bindir to perfexecdir +PROGRAMS += $(EXTRA_PROGRAMS) # # Single 'perf' binary right now: # PROGRAMS += $(OUTPUT)perf -LANG_BINDINGS = +# List built-in command $C whose implementation cmd_$C() is not in +# builtin-$C.o but is linked in as part of some other command. +# # what 'all' will build and 'install' will install, in perfexecdir ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS) # what 'all' will build but not install in perfexecdir -OTHER_PROGRAMS = $(OUTPUT)perf +OTHER_PROGRAMS = $(OUTPUT)perf$X # Set paths to tools early so that they can be used for version tests. ifndef SHELL_PATH @@ -227,7 +395,6 @@ LIB_H += util/include/dwarf-regs.h LIB_H += util/include/asm/dwarf2.h LIB_H += util/include/asm/cpufeature.h LIB_H += perf.h -LIB_H += util/annotate.h LIB_H += util/cache.h LIB_H += util/callchain.h LIB_H += util/build-id.h @@ -235,7 +402,6 @@ LIB_H += util/debug.h LIB_H += util/debugfs.h LIB_H += util/event.h LIB_H += util/evsel.h -LIB_H += util/evlist.h LIB_H += util/exec_cmd.h LIB_H += util/types.h LIB_H += util/levenshtein.h @@ -250,7 +416,6 @@ LIB_H += util/help.h LIB_H += util/session.h LIB_H += util/strbuf.h LIB_H += util/strlist.h -LIB_H += util/strfilter.h LIB_H += util/svghelper.h LIB_H += util/run-command.h LIB_H += util/sigchain.h @@ -260,26 +425,21 @@ LIB_H += util/values.h LIB_H += util/sort.h LIB_H += util/hist.h LIB_H += util/thread.h -LIB_H += util/thread_map.h LIB_H += util/trace-event.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h LIB_H += util/pstack.h LIB_H += util/cpumap.h -LIB_H += util/top.h LIB_H += $(ARCH_INCLUDE) -LIB_H += util/cgroup.h LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/alias.o -LIB_OBJS += $(OUTPUT)util/annotate.o LIB_OBJS += $(OUTPUT)util/build-id.o LIB_OBJS += $(OUTPUT)util/config.o LIB_OBJS += $(OUTPUT)util/ctype.o LIB_OBJS += $(OUTPUT)util/debugfs.o LIB_OBJS += $(OUTPUT)util/environment.o LIB_OBJS += $(OUTPUT)util/event.o -LIB_OBJS += $(OUTPUT)util/evlist.o LIB_OBJS += $(OUTPUT)util/evsel.o LIB_OBJS += $(OUTPUT)util/exec_cmd.o LIB_OBJS += $(OUTPUT)util/help.o @@ -295,8 +455,6 @@ LIB_OBJS += $(OUTPUT)util/quote.o LIB_OBJS += $(OUTPUT)util/strbuf.o LIB_OBJS += $(OUTPUT)util/string.o LIB_OBJS += $(OUTPUT)util/strlist.o -LIB_OBJS += $(OUTPUT)util/strfilter.o -LIB_OBJS += $(OUTPUT)util/top.o LIB_OBJS += $(OUTPUT)util/usage.o LIB_OBJS += $(OUTPUT)util/wrapper.o LIB_OBJS += $(OUTPUT)util/sigchain.o @@ -311,7 +469,6 @@ LIB_OBJS += $(OUTPUT)util/map.o LIB_OBJS += $(OUTPUT)util/pstack.o LIB_OBJS += $(OUTPUT)util/session.o LIB_OBJS += $(OUTPUT)util/thread.o -LIB_OBJS += $(OUTPUT)util/thread_map.o LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-read.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o @@ -323,7 +480,6 @@ LIB_OBJS += $(OUTPUT)util/probe-event.o LIB_OBJS += $(OUTPUT)util/util.o LIB_OBJS += $(OUTPUT)util/xyarray.o LIB_OBJS += $(OUTPUT)util/cpumap.o -LIB_OBJS += $(OUTPUT)util/cgroup.o BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o @@ -358,20 +514,6 @@ BUILTIN_OBJS += $(OUTPUT)builtin-inject.o PERFLIBS = $(LIB_FILE) -# Files needed for the python binding, perf.so -# pyrf is just an internal name needed for all those wrappers. -# This has to be in sync with what is in the 'sources' variable in -# tools/perf/util/setup.py - -PYRF_OBJS += $(OUTPUT)util/cpumap.o -PYRF_OBJS += $(OUTPUT)util/ctype.o -PYRF_OBJS += $(OUTPUT)util/evlist.o -PYRF_OBJS += $(OUTPUT)util/evsel.o -PYRF_OBJS += $(OUTPUT)util/python.o -PYRF_OBJS += $(OUTPUT)util/thread_map.o -PYRF_OBJS += $(OUTPUT)util/util.o -PYRF_OBJS += $(OUTPUT)util/xyarray.o - # # Platform specific tweaks # @@ -393,6 +535,22 @@ endif # NO_DWARF -include arch/$(ARCH)/Makefile +ifeq ($(uname_S),Darwin) + ifndef NO_FINK + ifeq ($(shell test -d /sw/lib && echo y),y) + BASIC_CFLAGS += -I/sw/include + BASIC_LDFLAGS += -L/sw/lib + endif + endif + ifndef NO_DARWIN_PORTS + ifeq ($(shell test -d /opt/local/lib && echo y),y) + BASIC_CFLAGS += -I/opt/local/include + BASIC_LDFLAGS += -L/opt/local/lib + endif + endif + PTHREAD_LIBS = +endif + ifneq ($(OUTPUT),) BASIC_CFLAGS += -I$(OUTPUT) endif @@ -437,7 +595,6 @@ else LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o - LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o LIB_OBJS += $(OUTPUT)util/ui/helpline.o LIB_OBJS += $(OUTPUT)util/ui/progress.o LIB_OBJS += $(OUTPUT)util/ui/util.o @@ -447,7 +604,6 @@ else LIB_H += util/ui/libslang.h LIB_H += util/ui/progress.h LIB_H += util/ui/util.h - LIB_H += util/ui/ui.h endif endif @@ -479,14 +635,12 @@ else PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null` FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS) ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y) - msg := $(warning No Python.h found, install python-dev[el] to have python support in 'perf script' and to build the python bindings) BASIC_CFLAGS += -DNO_LIBPYTHON else ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS) EXTLIBS += $(PYTHON_EMBED_LIBADD) LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o - LANG_BINDINGS += $(OUTPUT)python/perf.so endif endif @@ -536,13 +690,201 @@ else endif endif +ifndef CC_LD_DYNPATH + ifdef NO_R_TO_GCC_LINKER + # Some gcc does not accept and pass -R to the linker to specify + # the runtime dynamic library path. + CC_LD_DYNPATH = -Wl,-rpath, + else + CC_LD_DYNPATH = -R + endif +endif + +ifdef NEEDS_SOCKET + EXTLIBS += -lsocket +endif +ifdef NEEDS_NSL + EXTLIBS += -lnsl +endif +ifdef NO_D_TYPE_IN_DIRENT + BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT +endif +ifdef NO_D_INO_IN_DIRENT + BASIC_CFLAGS += -DNO_D_INO_IN_DIRENT +endif +ifdef NO_ST_BLOCKS_IN_STRUCT_STAT + BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT +endif +ifdef USE_NSEC + BASIC_CFLAGS += -DUSE_NSEC +endif +ifdef USE_ST_TIMESPEC + BASIC_CFLAGS += -DUSE_ST_TIMESPEC +endif +ifdef NO_NSEC + BASIC_CFLAGS += -DNO_NSEC +endif +ifdef NO_C99_FORMAT + BASIC_CFLAGS += -DNO_C99_FORMAT +endif +ifdef SNPRINTF_RETURNS_BOGUS + COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS + COMPAT_OBJS += $(OUTPUT)compat/snprintf.o +endif +ifdef FREAD_READS_DIRECTORIES + COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES + COMPAT_OBJS += $(OUTPUT)compat/fopen.o +endif +ifdef NO_SYMLINK_HEAD + BASIC_CFLAGS += -DNO_SYMLINK_HEAD +endif +ifdef NO_STRCASESTR + COMPAT_CFLAGS += -DNO_STRCASESTR + COMPAT_OBJS += $(OUTPUT)compat/strcasestr.o +endif +ifdef NO_STRTOUMAX + COMPAT_CFLAGS += -DNO_STRTOUMAX + COMPAT_OBJS += $(OUTPUT)compat/strtoumax.o +endif +ifdef NO_STRTOULL + COMPAT_CFLAGS += -DNO_STRTOULL +endif +ifdef NO_SETENV + COMPAT_CFLAGS += -DNO_SETENV + COMPAT_OBJS += $(OUTPUT)compat/setenv.o +endif +ifdef NO_MKDTEMP + COMPAT_CFLAGS += -DNO_MKDTEMP + COMPAT_OBJS += $(OUTPUT)compat/mkdtemp.o +endif +ifdef NO_UNSETENV + COMPAT_CFLAGS += -DNO_UNSETENV + COMPAT_OBJS += $(OUTPUT)compat/unsetenv.o +endif +ifdef NO_SYS_SELECT_H + BASIC_CFLAGS += -DNO_SYS_SELECT_H +endif +ifdef NO_MMAP + COMPAT_CFLAGS += -DNO_MMAP + COMPAT_OBJS += $(OUTPUT)compat/mmap.o +else + ifdef USE_WIN32_MMAP + COMPAT_CFLAGS += -DUSE_WIN32_MMAP + COMPAT_OBJS += $(OUTPUT)compat/win32mmap.o + endif +endif +ifdef NO_PREAD + COMPAT_CFLAGS += -DNO_PREAD + COMPAT_OBJS += $(OUTPUT)compat/pread.o +endif +ifdef NO_FAST_WORKING_DIRECTORY + BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY +endif +ifdef NO_TRUSTABLE_FILEMODE + BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE +endif +ifdef NO_IPV6 + BASIC_CFLAGS += -DNO_IPV6 +endif +ifdef NO_UINTMAX_T + BASIC_CFLAGS += -Duintmax_t=uint32_t +endif +ifdef NO_SOCKADDR_STORAGE +ifdef NO_IPV6 + BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in +else + BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6 +endif +endif +ifdef NO_INET_NTOP + LIB_OBJS += $(OUTPUT)compat/inet_ntop.o +endif +ifdef NO_INET_PTON + LIB_OBJS += $(OUTPUT)compat/inet_pton.o +endif + +ifdef NO_ICONV + BASIC_CFLAGS += -DNO_ICONV +endif + +ifdef OLD_ICONV + BASIC_CFLAGS += -DOLD_ICONV +endif + +ifdef NO_DEFLATE_BOUND + BASIC_CFLAGS += -DNO_DEFLATE_BOUND +endif + +ifdef PPC_SHA1 + SHA1_HEADER = "ppc/sha1.h" + LIB_OBJS += $(OUTPUT)ppc/sha1.o ppc/sha1ppc.o +else +ifdef ARM_SHA1 + SHA1_HEADER = "arm/sha1.h" + LIB_OBJS += $(OUTPUT)arm/sha1.o $(OUTPUT)arm/sha1_arm.o +else +ifdef MOZILLA_SHA1 + SHA1_HEADER = "mozilla-sha1/sha1.h" + LIB_OBJS += $(OUTPUT)mozilla-sha1/sha1.o +else + SHA1_HEADER = + EXTLIBS += $(LIB_4_CRYPTO) +endif +endif +endif +ifdef NO_PERL_MAKEMAKER + export NO_PERL_MAKEMAKER +endif +ifdef NO_HSTRERROR + COMPAT_CFLAGS += -DNO_HSTRERROR + COMPAT_OBJS += $(OUTPUT)compat/hstrerror.o +endif +ifdef NO_MEMMEM + COMPAT_CFLAGS += -DNO_MEMMEM + COMPAT_OBJS += $(OUTPUT)compat/memmem.o +endif +ifdef INTERNAL_QSORT + COMPAT_CFLAGS += -DINTERNAL_QSORT + COMPAT_OBJS += $(OUTPUT)compat/qsort.o +endif +ifdef RUNTIME_PREFIX + COMPAT_CFLAGS += -DRUNTIME_PREFIX +endif + +ifdef DIR_HAS_BSD_GROUP_SEMANTICS + COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS +endif +ifdef NO_EXTERNAL_GREP + BASIC_CFLAGS += -DNO_EXTERNAL_GREP +endif + +ifeq ($(PERL_PATH),) +NO_PERL=NoThanks +endif + +QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir +QUIET_SUBDIR1 = + +ifneq ($(findstring $(MAKEFLAGS),w),w) +PRINT_DIR = --no-print-directory +else # "make -w" +NO_SUBDIR = : +endif + ifneq ($(findstring $(MAKEFLAGS),s),s) ifndef V QUIET_CC = @echo ' ' CC $@; QUIET_AR = @echo ' ' AR $@; QUIET_LINK = @echo ' ' LINK $@; QUIET_MKDIR = @echo ' ' MKDIR $@; + QUIET_BUILT_IN = @echo ' ' BUILTIN $@; QUIET_GEN = @echo ' ' GEN $@; + QUIET_SUBDIR0 = +@subdir= + QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ + $(MAKE) $(PRINT_DIR) -C $$subdir + export V + export QUIET_GEN + export QUIET_BUILT_IN endif endif @@ -552,6 +894,7 @@ endif # Shell quote (do not use $(call) to accommodate ancient setups); +SHA1_HEADER_SQ = $(subst ','\'',$(SHA1_HEADER)) ETC_PERFCONFIG_SQ = $(subst ','\'',$(ETC_PERFCONFIG)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) @@ -565,36 +908,46 @@ htmldir_SQ = $(subst ','\'',$(htmldir)) prefix_SQ = $(subst ','\'',$(prefix)) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) +PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) LIBS = -Wl,--whole-archive $(PERFLIBS) -Wl,--no-whole-archive $(EXTLIBS) +BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \ + $(COMPAT_CFLAGS) +LIB_OBJS += $(COMPAT_OBJS) + ALL_CFLAGS += $(BASIC_CFLAGS) ALL_CFLAGS += $(ARCH_CFLAGS) ALL_LDFLAGS += $(BASIC_LDFLAGS) -export INSTALL SHELL_PATH +export TAR INSTALL DESTDIR SHELL_PATH ### Build rules SHELL = $(SHELL_PATH) -all: shell_compatibility_test $(ALL_PROGRAMS) $(LANG_BINDINGS) $(OTHER_PROGRAMS) +all:: shell_compatibility_test $(ALL_PROGRAMS) $(BUILT_INS) $(OTHER_PROGRAMS) $(OUTPUT)PERF-BUILD-OPTIONS +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) perf$X)), test '$p' -ef '$p$X' || $(RM) '$p';) +endif + +all:: please_set_SHELL_PATH_to_a_more_modern_shell: @$$(:) shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell -strip: $(PROGRAMS) $(OUTPUT)perf - $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf +strip: $(PROGRAMS) $(OUTPUT)perf$X + $(STRIP) $(STRIP_OPTS) $(PROGRAMS) $(OUTPUT)perf$X $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS $(QUIET_CC)$(CC) -DPERF_VERSION='"$(PERF_VERSION)"' \ '-DPERF_HTML_PATH="$(htmldir_SQ)"' \ $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@ -$(OUTPUT)perf: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) +$(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \ $(BUILTIN_OBJS) $(LIBS) -o $@ @@ -610,17 +963,39 @@ $(OUTPUT)builtin-timechart.o: builtin-timechart.c $(OUTPUT)common-cmds.h $(OUTPU '-DPERF_MAN_PATH="$(mandir_SQ)"' \ '-DPERF_INFO_PATH="$(infodir_SQ)"' $< +$(BUILT_INS): $(OUTPUT)perf$X + $(QUIET_BUILT_IN)$(RM) $@ && \ + ln perf$X $@ 2>/dev/null || \ + ln -s perf$X $@ 2>/dev/null || \ + cp perf$X $@ + $(OUTPUT)common-cmds.h: util/generate-cmdlist.sh command-list.txt $(OUTPUT)common-cmds.h: $(wildcard Documentation/perf-*.txt) $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@ -$(SCRIPTS) : % : %.sh - $(QUIET_GEN)$(INSTALL) '$@.sh' '$(OUTPUT)$@' +$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh + $(QUIET_GEN)$(RM) $(OUTPUT)$@ $(OUTPUT)$@+ && \ + sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ + -e 's|@SHELL_PATH@|$(SHELL_PATH_SQ)|' \ + -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ + -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ + -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ + $@.sh > $(OUTPUT)$@+ && \ + chmod +x $(OUTPUT)$@+ && \ + mv $(OUTPUT)$@+ $(OUTPUT)$@ + +configure: configure.ac + $(QUIET_GEN)$(RM) $@ $<+ && \ + sed -e 's/@@PERF_VERSION@@/$(PERF_VERSION)/g' \ + $< > $<+ && \ + autoconf -o $@ $<+ && \ + $(RM) $<+ # These can record PERF_VERSION $(OUTPUT)perf.o perf.spec \ - $(SCRIPTS) \ + $(patsubst %.sh,%,$(SCRIPT_SH)) \ + $(patsubst %.perl,%,$(SCRIPT_PERL)) \ : $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS @@ -637,6 +1012,9 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS '-DPREFIX="$(prefix_SQ)"' \ $< +$(OUTPUT)builtin-init-db.o: builtin-init-db.c $(OUTPUT)PERF-CFLAGS + $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DDEFAULT_PERF_TEMPLATE_DIR='"$(template_dir_SQ)"' $< + $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< @@ -646,9 +1024,6 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS $(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< -$(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS - $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< - $(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< @@ -670,11 +1045,12 @@ $(OUTPUT)util/scripting-engines/trace-event-python.o: util/scripting-engines/tra $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Util/Context.c $(OUTPUT)PERF-CFLAGS $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PYTHON_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-nested-externs $< -$(OUTPUT)perf-%: %.o $(PERFLIBS) +$(OUTPUT)perf-%$X: %.o $(PERFLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) -$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) +$(patsubst perf-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) +builtin-revert.o wt-status.o: wt-status.h # we compile into subdirectories. if the target directory is not the source directory, they might not exists. So # we depend the various files onto their directories. @@ -687,36 +1063,6 @@ $(sort $(dir $(DIRECTORY_DEPS))): $(LIB_FILE): $(LIB_OBJS) $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS) -help: - @echo 'Perf make targets:' - @echo ' doc - make *all* documentation (see below)' - @echo ' man - make manpage documentation (access with man )' - @echo ' html - make html documentation' - @echo ' info - make GNU info documentation (access with info )' - @echo ' pdf - make pdf documentation' - @echo ' TAGS - use etags to make tag information for source browsing' - @echo ' tags - use ctags to make tag information for source browsing' - @echo ' cscope - use cscope to make interactive browsing database' - @echo '' - @echo 'Perf install targets:' - @echo ' NOTE: documentation build requires asciidoc, xmlto packages to be installed' - @echo ' HINT: use "make prefix= " to install to a particular' - @echo ' path like make prefix=/usr/local install install-doc' - @echo ' install - install compiled binaries' - @echo ' install-doc - install *all* documentation' - @echo ' install-man - install manpage documentation' - @echo ' install-html - install html documentation' - @echo ' install-info - install GNU info documentation' - @echo ' install-pdf - install pdf documentation' - @echo '' - @echo ' quick-install-doc - alias for quick-install-man' - @echo ' quick-install-man - install the documentation quickly' - @echo ' quick-install-html - install the html documentation quickly' - @echo '' - @echo 'Perf maintainer targets:' - @echo ' distclean - alias to clean' - @echo ' clean - clean all binary objects and build output' - doc: $(MAKE) -C Documentation all @@ -755,12 +1101,30 @@ $(OUTPUT)PERF-CFLAGS: .FORCE-PERF-CFLAGS echo "$$FLAGS" >$(OUTPUT)PERF-CFLAGS; \ fi +# We need to apply sq twice, once to protect from the shell +# that runs $(OUTPUT)PERF-BUILD-OPTIONS, and then again to protect it +# and the first level quoting from the shell that runs "echo". +$(OUTPUT)PERF-BUILD-OPTIONS: .FORCE-PERF-BUILD-OPTIONS + @echo SHELL_PATH=\''$(subst ','\'',$(SHELL_PATH_SQ))'\' >$@ + @echo TAR=\''$(subst ','\'',$(subst ','\'',$(TAR)))'\' >>$@ + @echo NO_CURL=\''$(subst ','\'',$(subst ','\'',$(NO_CURL)))'\' >>$@ + @echo NO_PERL=\''$(subst ','\'',$(subst ','\'',$(NO_PERL)))'\' >>$@ + ### Testing rules +# +# None right now: +# +# TEST_PROGRAMS += test-something$X + +all:: $(TEST_PROGRAMS) + # GNU make supports exporting all variables by "export" without parameters. # However, the environment gets quite big, and some programs have problems # with that. +export NO_SVN_TESTS + check: $(OUTPUT)common-cmds.h if sparse; \ then \ @@ -769,21 +1133,33 @@ check: $(OUTPUT)common-cmds.h sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; \ done; \ else \ + echo 2>&1 "Did you mean 'make test'?"; \ exit 1; \ fi +remove-dashes: + ./fixup-builtins $(BUILT_INS) $(PROGRAMS) $(SCRIPTS) + ### Installation rules +ifneq ($(filter /%,$(firstword $(template_dir))),) +template_instdir = $(template_dir) +else +template_instdir = $(prefix)/$(template_dir) +endif +export template_instdir + ifneq ($(filter /%,$(firstword $(perfexecdir))),) perfexec_instdir = $(perfexecdir) else perfexec_instdir = $(prefix)/$(perfexecdir) endif perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir)) +export perfexec_instdir install: all $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)' - $(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)' + $(INSTALL) $(OUTPUT)perf$X '$(DESTDIR_SQ)$(bindir_SQ)' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/Perf-Trace-Util/lib/Perf/Trace' $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/perl/bin' $(INSTALL) $(OUTPUT)perf-archive -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' @@ -796,6 +1172,14 @@ install: all $(INSTALL) scripts/python/*.py -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python' $(INSTALL) scripts/python/bin/* -t '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/scripts/python/bin' +ifdef BUILT_INS + $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' + $(INSTALL) $(BUILT_INS) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)' +ifneq (,$X) + $(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_PROGRAMS) $(BUILT_INS) $(OUTPUT)perf$X)), $(RM) '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/$p';) +endif +endif + install-doc: $(MAKE) -C Documentation install @@ -820,17 +1204,104 @@ quick-install-man: quick-install-html: $(MAKE) -C Documentation quick-install-html + +### Maintainer's dist rules +# +# None right now +# +# +# perf.spec: perf.spec.in +# sed -e 's/@@VERSION@@/$(PERF_VERSION)/g' < $< > $@+ +# mv $@+ $@ +# +# PERF_TARNAME=perf-$(PERF_VERSION) +# dist: perf.spec perf-archive$(X) configure +# ./perf-archive --format=tar \ +# --prefix=$(PERF_TARNAME)/ HEAD^{tree} > $(PERF_TARNAME).tar +# @mkdir -p $(PERF_TARNAME) +# @cp perf.spec configure $(PERF_TARNAME) +# @echo $(PERF_VERSION) > $(PERF_TARNAME)/version +# $(TAR) rf $(PERF_TARNAME).tar \ +# $(PERF_TARNAME)/perf.spec \ +# $(PERF_TARNAME)/configure \ +# $(PERF_TARNAME)/version +# @$(RM) -r $(PERF_TARNAME) +# gzip -f -9 $(PERF_TARNAME).tar +# +# htmldocs = perf-htmldocs-$(PERF_VERSION) +# manpages = perf-manpages-$(PERF_VERSION) +# dist-doc: +# $(RM) -r .doc-tmp-dir +# mkdir .doc-tmp-dir +# $(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc +# cd .doc-tmp-dir && $(TAR) cf ../$(htmldocs).tar . +# gzip -n -9 -f $(htmldocs).tar +# : +# $(RM) -r .doc-tmp-dir +# mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7 +# $(MAKE) -C Documentation DESTDIR=./ \ +# man1dir=../.doc-tmp-dir/man1 \ +# man5dir=../.doc-tmp-dir/man5 \ +# man7dir=../.doc-tmp-dir/man7 \ +# install +# cd .doc-tmp-dir && $(TAR) cf ../$(manpages).tar . +# gzip -n -9 -f $(manpages).tar +# $(RM) -r .doc-tmp-dir +# +# rpm: dist +# $(RPMBUILD) -ta $(PERF_TARNAME).tar.gz + ### Cleaning rules +distclean: clean +# $(RM) configure + clean: - $(RM) $(OUTPUT){*.o,*/*.o,*/*/*.o,*/*/*/*.o,$(LIB_FILE),perf-archive} - $(RM) $(ALL_PROGRAMS) perf + $(RM) *.o */*.o */*/*.o */*/*/*.o $(LIB_FILE) + $(RM) $(ALL_PROGRAMS) $(BUILT_INS) perf$X + $(RM) $(TEST_PROGRAMS) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* + $(RM) -r autom4te.cache + $(RM) config.log config.mak.autogen config.mak.append config.status config.cache + $(RM) -r $(PERF_TARNAME) .doc-tmp-dir + $(RM) $(PERF_TARNAME).tar.gz perf-core_$(PERF_VERSION)-*.tar.gz + $(RM) $(htmldocs).tar.gz $(manpages).tar.gz $(MAKE) -C Documentation/ clean - $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS - @python util/setup.py clean --build-lib='$(OUTPUT)python' \ - --build-temp='$(OUTPUT)python/temp' + $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-BUILD-OPTIONS .PHONY: all install clean strip .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell .PHONY: .FORCE-PERF-VERSION-FILE TAGS tags cscope .FORCE-PERF-CFLAGS +.PHONY: .FORCE-PERF-BUILD-OPTIONS + +### Make sure built-ins do not have dups and listed in perf.c +# +check-builtins:: + ./check-builtins.sh + +### Test suite coverage testing +# +# None right now +# +# .PHONY: coverage coverage-clean coverage-build coverage-report +# +# coverage: +# $(MAKE) coverage-build +# $(MAKE) coverage-report +# +# coverage-clean: +# rm -f *.gcda *.gcno +# +# COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs +# COVERAGE_LDFLAGS = $(CFLAGS) -O0 -lgcov +# +# coverage-build: coverage-clean +# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all +# $(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \ +# -j1 test +# +# coverage-report: +# gcov -b *.c */*.c +# grep '^function.*called 0 ' *.c.gcov */*.c.gcov \ +# | sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \ +# | tee coverage-untested-functions diff --git a/trunk/tools/perf/bench/sched-pipe.c b/trunk/tools/perf/bench/sched-pipe.c index 0c7454f8b8a9..d9ab3ce446ac 100644 --- a/trunk/tools/perf/bench/sched-pipe.c +++ b/trunk/tools/perf/bench/sched-pipe.c @@ -55,7 +55,7 @@ int bench_sched_pipe(int argc, const char **argv, * discarding returned value of read(), write() * causes error in building environment for perf */ - int __used ret, wait_stat; + int ret, wait_stat; pid_t pid, retpid; argc = parse_options(argc, argv, options, diff --git a/trunk/tools/perf/builtin-annotate.c b/trunk/tools/perf/builtin-annotate.c index 427182953fd7..8879463807e4 100644 --- a/trunk/tools/perf/builtin-annotate.c +++ b/trunk/tools/perf/builtin-annotate.c @@ -9,7 +9,6 @@ #include "util/util.h" -#include "util/util.h" #include "util/color.h" #include #include "util/cache.h" @@ -19,7 +18,6 @@ #include "perf.h" #include "util/debug.h" -#include "util/annotate.h" #include "util/event.h" #include "util/parse-options.h" #include "util/parse-events.h" @@ -57,29 +55,15 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) if (he == NULL) return -ENOMEM; - if (he->ms.sym != NULL) { - /* - * All aggregated on the first sym_hist. - */ - struct annotation *notes = symbol__annotation(he->ms.sym); - if (notes->src == NULL && - symbol__alloc_hist(he->ms.sym, 1) < 0) - return -ENOMEM; - - return hist_entry__inc_addr_samples(he, 0, al->addr); - } - - return 0; + return hist_entry__inc_addr_samples(he, al->addr); } -static int process_sample_event(union perf_event *event, - struct perf_sample *sample, +static int process_sample_event(event_t *event, struct sample_data *sample, struct perf_session *session) { struct addr_location al; - if (perf_event__preprocess_sample(event, session, &al, sample, - symbol__annotate_init) < 0) { + if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); return -1; @@ -94,10 +78,245 @@ static int process_sample_event(union perf_event *event, return 0; } -static int hist_entry__tty_annotate(struct hist_entry *he, int evidx) +static int objdump_line__print(struct objdump_line *self, + struct list_head *head, + struct hist_entry *he, u64 len) +{ + struct symbol *sym = he->ms.sym; + static const char *prev_line; + static const char *prev_color; + + if (self->offset != -1) { + const char *path = NULL; + unsigned int hits = 0; + double percent = 0.0; + const char *color; + struct sym_priv *priv = symbol__priv(sym); + struct sym_ext *sym_ext = priv->ext; + struct sym_hist *h = priv->hist; + s64 offset = self->offset; + struct objdump_line *next = objdump__get_next_ip_line(head, self); + + while (offset < (s64)len && + (next == NULL || offset < next->offset)) { + if (sym_ext) { + if (path == NULL) + path = sym_ext[offset].path; + percent += sym_ext[offset].percent; + } else + hits += h->ip[offset]; + + ++offset; + } + + if (sym_ext == NULL && h->sum) + percent = 100.0 * hits / h->sum; + + color = get_percent_color(percent); + + /* + * Also color the filename and line if needed, with + * the same color than the percentage. Don't print it + * twice for close colored ip with the same filename:line + */ + if (path) { + if (!prev_line || strcmp(prev_line, path) + || color != prev_color) { + color_fprintf(stdout, color, " %s", path); + prev_line = path; + prev_color = color; + } + } + + color_fprintf(stdout, color, " %7.2f", percent); + printf(" : "); + color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line); + } else { + if (!*self->line) + printf(" :\n"); + else + printf(" : %s\n", self->line); + } + + return 0; +} + +static struct rb_root root_sym_ext; + +static void insert_source_line(struct sym_ext *sym_ext) +{ + struct sym_ext *iter; + struct rb_node **p = &root_sym_ext.rb_node; + struct rb_node *parent = NULL; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct sym_ext, node); + + if (sym_ext->percent > iter->percent) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&sym_ext->node, parent, p); + rb_insert_color(&sym_ext->node, &root_sym_ext); +} + +static void free_source_line(struct hist_entry *he, int len) +{ + struct sym_priv *priv = symbol__priv(he->ms.sym); + struct sym_ext *sym_ext = priv->ext; + int i; + + if (!sym_ext) + return; + + for (i = 0; i < len; i++) + free(sym_ext[i].path); + free(sym_ext); + + priv->ext = NULL; + root_sym_ext = RB_ROOT; +} + +/* Get the filename:line for the colored entries */ +static void +get_source_line(struct hist_entry *he, int len, const char *filename) +{ + struct symbol *sym = he->ms.sym; + u64 start; + int i; + char cmd[PATH_MAX * 2]; + struct sym_ext *sym_ext; + struct sym_priv *priv = symbol__priv(sym); + struct sym_hist *h = priv->hist; + + if (!h->sum) + return; + + sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext)); + if (!priv->ext) + return; + + start = he->ms.map->unmap_ip(he->ms.map, sym->start); + + for (i = 0; i < len; i++) { + char *path = NULL; + size_t line_len; + u64 offset; + FILE *fp; + + sym_ext[i].percent = 100.0 * h->ip[i] / h->sum; + if (sym_ext[i].percent <= 0.5) + continue; + + offset = start + i; + sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); + fp = popen(cmd, "r"); + if (!fp) + continue; + + if (getline(&path, &line_len, fp) < 0 || !line_len) + goto next; + + sym_ext[i].path = malloc(sizeof(char) * line_len + 1); + if (!sym_ext[i].path) + goto next; + + strcpy(sym_ext[i].path, path); + insert_source_line(&sym_ext[i]); + + next: + pclose(fp); + } +} + +static void print_summary(const char *filename) { - return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx, - print_line, full_paths, 0, 0); + struct sym_ext *sym_ext; + struct rb_node *node; + + printf("\nSorted summary for file %s\n", filename); + printf("----------------------------------------------\n\n"); + + if (RB_EMPTY_ROOT(&root_sym_ext)) { + printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); + return; + } + + node = rb_first(&root_sym_ext); + while (node) { + double percent; + const char *color; + char *path; + + sym_ext = rb_entry(node, struct sym_ext, node); + percent = sym_ext->percent; + color = get_percent_color(percent); + path = sym_ext->path; + + color_fprintf(stdout, color, " %7.2f %s", percent, path); + node = rb_next(node); + } +} + +static void hist_entry__print_hits(struct hist_entry *self) +{ + struct symbol *sym = self->ms.sym; + struct sym_priv *priv = symbol__priv(sym); + struct sym_hist *h = priv->hist; + u64 len = sym->end - sym->start, offset; + + for (offset = 0; offset < len; ++offset) + if (h->ip[offset] != 0) + printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, + sym->start + offset, h->ip[offset]); + printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); +} + +static int hist_entry__tty_annotate(struct hist_entry *he) +{ + struct map *map = he->ms.map; + struct dso *dso = map->dso; + struct symbol *sym = he->ms.sym; + const char *filename = dso->long_name, *d_filename; + u64 len; + LIST_HEAD(head); + struct objdump_line *pos, *n; + + if (hist_entry__annotate(he, &head, 0) < 0) + return -1; + + if (full_paths) + d_filename = filename; + else + d_filename = basename(filename); + + len = sym->end - sym->start; + + if (print_line) { + get_source_line(he, len, filename); + print_summary(filename); + } + + printf("\n\n------------------------------------------------\n"); + printf(" Percent | Source code & Disassembly of %s\n", d_filename); + printf("------------------------------------------------\n"); + + if (verbose) + hist_entry__print_hits(he); + + list_for_each_entry_safe(pos, n, &head, node) { + objdump_line__print(pos, &head, he, len); + list_del(&pos->node); + objdump_line__free(pos); + } + + if (print_line) + free_source_line(he, len); + + return 0; } static void hists__find_annotations(struct hists *self) @@ -107,13 +326,13 @@ static void hists__find_annotations(struct hists *self) while (nd) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); - struct annotation *notes; + struct sym_priv *priv; if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned) goto find_next; - notes = symbol__annotation(he->ms.sym); - if (notes->src == NULL) { + priv = symbol__priv(he->ms.sym); + if (priv->hist == NULL) { find_next: if (key == KEY_LEFT) nd = rb_prev(nd); @@ -123,8 +342,7 @@ static void hists__find_annotations(struct hists *self) } if (use_browser > 0) { - /* For now all is aggregated on the first */ - key = hist_entry__tui_annotate(he, 0); + key = hist_entry__tui_annotate(he); switch (key) { case KEY_RIGHT: next = rb_next(nd); @@ -139,25 +357,24 @@ static void hists__find_annotations(struct hists *self) if (next != NULL) nd = next; } else { - /* For now all is aggregated on the first */ - hist_entry__tty_annotate(he, 0); + hist_entry__tty_annotate(he); nd = rb_next(nd); /* * Since we have a hist_entry per IP for the same - * symbol, free he->ms.sym->src to signal we already + * symbol, free he->ms.sym->hist to signal we already * processed this symbol. */ - free(notes->src); - notes->src = NULL; + free(priv->hist); + priv->hist = NULL; } } } 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, + .mmap = event__process_mmap, + .comm = event__process_comm, + .fork = event__process_task, .ordered_samples = true, .ordering_requires_timestamps = true, }; @@ -234,9 +451,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used) else if (use_tui) use_browser = 1; - setup_browser(true); + setup_browser(); - symbol_conf.priv_size = sizeof(struct annotation); + symbol_conf.priv_size = sizeof(struct sym_priv); symbol_conf.try_vmlinux_path = true; if (symbol__init() < 0) diff --git a/trunk/tools/perf/builtin-diff.c b/trunk/tools/perf/builtin-diff.c index 6b7d91160ecb..3153e492dbcc 100644 --- a/trunk/tools/perf/builtin-diff.c +++ b/trunk/tools/perf/builtin-diff.c @@ -30,13 +30,13 @@ static int hists__add_entry(struct hists *self, return -ENOMEM; } -static int diff__process_sample_event(union perf_event *event, - struct perf_sample *sample, +static int diff__process_sample_event(event_t *event, + struct sample_data *sample, struct perf_session *session) { struct addr_location al; - if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { + if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { pr_warning("problem processing %d event, skipping it.\n", event->header.type); return -1; @@ -56,11 +56,11 @@ static int diff__process_sample_event(union perf_event *event, static struct perf_event_ops event_ops = { .sample = diff__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, + .mmap = event__process_mmap, + .comm = event__process_comm, + .exit = event__process_task, + .fork = event__process_task, + .lost = event__process_lost, .ordered_samples = true, .ordering_requires_timestamps = true, }; diff --git a/trunk/tools/perf/builtin-inject.c b/trunk/tools/perf/builtin-inject.c index e29f04ed3396..0c78ffa7bf67 100644 --- a/trunk/tools/perf/builtin-inject.c +++ b/trunk/tools/perf/builtin-inject.c @@ -16,8 +16,8 @@ static char const *input_name = "-"; static bool inject_build_ids; -static int perf_event__repipe_synth(union perf_event *event, - struct perf_session *session __used) +static int event__repipe_synth(event_t *event, + struct perf_session *session __used) { uint32_t size; void *buf = event; @@ -36,44 +36,41 @@ static int perf_event__repipe_synth(union perf_event *event, return 0; } -static int perf_event__repipe(union perf_event *event, - struct perf_sample *sample __used, - struct perf_session *session) +static int event__repipe(event_t *event, struct sample_data *sample __used, + struct perf_session *session) { - return perf_event__repipe_synth(event, session); + return event__repipe_synth(event, session); } -static int perf_event__repipe_mmap(union perf_event *event, - struct perf_sample *sample, - struct perf_session *session) +static int event__repipe_mmap(event_t *self, struct sample_data *sample, + struct perf_session *session) { int err; - err = perf_event__process_mmap(event, sample, session); - perf_event__repipe(event, sample, session); + err = event__process_mmap(self, sample, session); + event__repipe(self, sample, session); return err; } -static int perf_event__repipe_task(union perf_event *event, - struct perf_sample *sample, - struct perf_session *session) +static int event__repipe_task(event_t *self, struct sample_data *sample, + struct perf_session *session) { int err; - err = perf_event__process_task(event, sample, session); - perf_event__repipe(event, sample, session); + err = event__process_task(self, sample, session); + event__repipe(self, sample, session); return err; } -static int perf_event__repipe_tracing_data(union perf_event *event, - struct perf_session *session) +static int event__repipe_tracing_data(event_t *self, + struct perf_session *session) { int err; - perf_event__repipe_synth(event, session); - err = perf_event__process_tracing_data(event, session); + event__repipe_synth(self, session); + err = event__process_tracing_data(self, session); return err; } @@ -112,8 +109,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) if (self->kernel) misc = PERF_RECORD_MISC_KERNEL; - err = perf_event__synthesize_build_id(self, misc, perf_event__repipe, - machine, session); + err = event__synthesize_build_id(self, misc, event__repipe, + machine, session); if (err) { pr_err("Can't synthesize build_id event for %s\n", self->long_name); return -1; @@ -122,9 +119,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) return 0; } -static int perf_event__inject_buildid(union perf_event *event, - struct perf_sample *sample, - struct perf_session *session) +static int event__inject_buildid(event_t *event, struct sample_data *sample, + struct perf_session *session) { struct addr_location al; struct thread *thread; @@ -159,24 +155,24 @@ static int perf_event__inject_buildid(union perf_event *event, } repipe: - perf_event__repipe(event, sample, session); + event__repipe(event, sample, session); return 0; } struct perf_event_ops inject_ops = { - .sample = perf_event__repipe, - .mmap = perf_event__repipe, - .comm = perf_event__repipe, - .fork = perf_event__repipe, - .exit = perf_event__repipe, - .lost = perf_event__repipe, - .read = perf_event__repipe, - .throttle = perf_event__repipe, - .unthrottle = perf_event__repipe, - .attr = perf_event__repipe_synth, - .event_type = perf_event__repipe_synth, - .tracing_data = perf_event__repipe_synth, - .build_id = perf_event__repipe_synth, + .sample = event__repipe, + .mmap = event__repipe, + .comm = event__repipe, + .fork = event__repipe, + .exit = event__repipe, + .lost = event__repipe, + .read = event__repipe, + .throttle = event__repipe, + .unthrottle = event__repipe, + .attr = event__repipe_synth, + .event_type = event__repipe_synth, + .tracing_data = event__repipe_synth, + .build_id = event__repipe_synth, }; extern volatile int session_done; @@ -194,10 +190,10 @@ static int __cmd_inject(void) signal(SIGINT, sig_handler); if (inject_build_ids) { - 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; + inject_ops.sample = event__inject_buildid; + inject_ops.mmap = event__repipe_mmap; + inject_ops.fork = event__repipe_task; + inject_ops.tracing_data = event__repipe_tracing_data; } session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops); diff --git a/trunk/tools/perf/builtin-kmem.c b/trunk/tools/perf/builtin-kmem.c index 7f618f4e7b79..d97256d65980 100644 --- a/trunk/tools/perf/builtin-kmem.c +++ b/trunk/tools/perf/builtin-kmem.c @@ -275,8 +275,9 @@ static void process_free_event(void *data, s_alloc->alloc_cpu = -1; } -static void process_raw_event(union perf_event *raw_event __used, void *data, - int cpu, u64 timestamp, struct thread *thread) +static void +process_raw_event(event_t *raw_event __used, void *data, + int cpu, u64 timestamp, struct thread *thread) { struct event *event; int type; @@ -303,8 +304,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, } } -static int process_sample_event(union perf_event *event, - struct perf_sample *sample, +static int process_sample_event(event_t *event, struct sample_data *sample, struct perf_session *session) { struct thread *thread = perf_session__findnew(session, event->ip.pid); @@ -325,7 +325,7 @@ static int process_sample_event(union perf_event *event, static struct perf_event_ops event_ops = { .sample = process_sample_event, - .comm = perf_event__process_comm, + .comm = event__process_comm, .ordered_samples = true, }; diff --git a/trunk/tools/perf/builtin-list.c b/trunk/tools/perf/builtin-list.c index 6313b6eb3ebb..d88c6961274c 100644 --- a/trunk/tools/perf/builtin-list.c +++ b/trunk/tools/perf/builtin-list.c @@ -5,7 +5,6 @@ * * Copyright (C) 2009, Thomas Gleixner * Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar - * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo */ #include "builtin.h" @@ -14,47 +13,9 @@ #include "util/parse-events.h" #include "util/cache.h" -int cmd_list(int argc, const char **argv, const char *prefix __used) +int cmd_list(int argc __used, const char **argv __used, const char *prefix __used) { setup_pager(); - - if (argc == 1) - print_events(NULL); - else { - int i; - - for (i = 1; i < argc; ++i) { - if (i > 1) - putchar('\n'); - if (strncmp(argv[i], "tracepoint", 10) == 0) - print_tracepoint_events(NULL, NULL); - else if (strcmp(argv[i], "hw") == 0 || - strcmp(argv[i], "hardware") == 0) - print_events_type(PERF_TYPE_HARDWARE); - else if (strcmp(argv[i], "sw") == 0 || - strcmp(argv[i], "software") == 0) - print_events_type(PERF_TYPE_SOFTWARE); - else if (strcmp(argv[i], "cache") == 0 || - strcmp(argv[i], "hwcache") == 0) - print_hwcache_events(NULL); - else { - char *sep = strchr(argv[i], ':'), *s; - int sep_idx; - - if (sep == NULL) { - print_events(argv[i]); - continue; - } - sep_idx = sep - argv[i]; - s = strdup(argv[i]); - if (s == NULL) - return -1; - - s[sep_idx] = '\0'; - print_tracepoint_events(s, s + sep_idx + 1); - free(s); - } - } - } + print_events(); return 0; } diff --git a/trunk/tools/perf/builtin-lock.c b/trunk/tools/perf/builtin-lock.c index 2e93f99b1480..2b36defc5d73 100644 --- a/trunk/tools/perf/builtin-lock.c +++ b/trunk/tools/perf/builtin-lock.c @@ -834,14 +834,14 @@ static void dump_info(void) die("Unknown type of information\n"); } -static int process_sample_event(union perf_event *event, struct perf_sample *sample, +static int process_sample_event(event_t *self, struct sample_data *sample, struct perf_session *s) { struct thread *thread = perf_session__findnew(s, sample->tid); if (thread == NULL) { pr_debug("problem processing %d event, skipping it.\n", - event->header.type); + self->header.type); return -1; } @@ -852,7 +852,7 @@ static int process_sample_event(union perf_event *event, struct perf_sample *sam static struct perf_event_ops eops = { .sample = process_sample_event, - .comm = perf_event__process_comm, + .comm = event__process_comm, .ordered_samples = true, }; @@ -893,7 +893,7 @@ static const char * const report_usage[] = { static const struct option report_options[] = { OPT_STRING('k', "key", &sort_key, "acquired", - "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"), + "key for sorting"), /* TODO: type */ OPT_END() }; diff --git a/trunk/tools/perf/builtin-probe.c b/trunk/tools/perf/builtin-probe.c index 2c0e64d0b4aa..add163c9f0e7 100644 --- a/trunk/tools/perf/builtin-probe.c +++ b/trunk/tools/perf/builtin-probe.c @@ -36,7 +36,6 @@ #include "builtin.h" #include "util/util.h" #include "util/strlist.h" -#include "util/strfilter.h" #include "util/symbol.h" #include "util/debug.h" #include "util/debugfs.h" @@ -44,8 +43,6 @@ #include "util/probe-finder.h" #include "util/probe-event.h" -#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" -#define DEFAULT_FUNC_FILTER "!_*" #define MAX_PATH_LEN 256 /* Session management structure */ @@ -55,7 +52,6 @@ static struct { bool show_lines; bool show_vars; bool show_ext_vars; - bool show_funcs; bool mod_events; int nevents; struct perf_probe_event events[MAX_PROBES]; @@ -63,7 +59,6 @@ static struct { struct line_range line_range; const char *target_module; int max_probe_points; - struct strfilter *filter; } params; /* Parse an event definition. Note that any error must die. */ @@ -162,27 +157,6 @@ static int opt_show_vars(const struct option *opt __used, } #endif -static int opt_set_filter(const struct option *opt __used, - const char *str, int unset __used) -{ - const char *err; - - if (str) { - pr_debug2("Set filter: %s\n", str); - if (params.filter) - strfilter__delete(params.filter); - params.filter = strfilter__new(str, &err); - if (!params.filter) { - pr_err("Filter parse error at %td.\n", err - str + 1); - pr_err("Source: \"%s\"\n", str); - pr_err(" %*c\n", (int)(err - str + 1), '^'); - return -EINVAL; - } - } - - return 0; -} - static const char * const probe_usage[] = { "perf probe [] 'PROBEDEF' ['PROBEDEF' ...]", "perf probe [] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", @@ -247,13 +221,6 @@ static const struct option options[] = { OPT__DRY_RUN(&probe_event_dry_run), OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, "Set how many probe points can be found for a probe."), - OPT_BOOLEAN('F', "funcs", ¶ms.show_funcs, - "Show potential probe-able functions."), - OPT_CALLBACK('\0', "filter", NULL, - "[!]FILTER", "Set a filter (with --vars/funcs only)\n" - "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" - "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", - opt_set_filter), OPT_END() }; @@ -279,7 +246,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) params.max_probe_points = MAX_PROBES; if ((!params.nevents && !params.dellist && !params.list_events && - !params.show_lines && !params.show_funcs)) + !params.show_lines)) usage_with_options(probe_usage, options); /* @@ -300,41 +267,12 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) pr_err(" Error: Don't use --list with --vars.\n"); usage_with_options(probe_usage, options); } - if (params.show_funcs) { - pr_err(" Error: Don't use --list with --funcs.\n"); - usage_with_options(probe_usage, options); - } ret = show_perf_probe_events(); if (ret < 0) pr_err(" Error: Failed to show event list. (%d)\n", ret); return ret; } - if (params.show_funcs) { - if (params.nevents != 0 || params.dellist) { - pr_err(" Error: Don't use --funcs with" - " --add/--del.\n"); - usage_with_options(probe_usage, options); - } - if (params.show_lines) { - pr_err(" Error: Don't use --funcs with --line.\n"); - usage_with_options(probe_usage, options); - } - if (params.show_vars) { - pr_err(" Error: Don't use --funcs with --vars.\n"); - usage_with_options(probe_usage, options); - } - if (!params.filter) - params.filter = strfilter__new(DEFAULT_FUNC_FILTER, - NULL); - ret = show_available_funcs(params.target_module, - params.filter); - strfilter__delete(params.filter); - if (ret < 0) - pr_err(" Error: Failed to show functions." - " (%d)\n", ret); - return ret; - } #ifdef DWARF_SUPPORT if (params.show_lines) { @@ -359,16 +297,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) " --add/--del.\n"); usage_with_options(probe_usage, options); } - if (!params.filter) - params.filter = strfilter__new(DEFAULT_VAR_FILTER, - NULL); - ret = show_available_vars(params.events, params.nevents, params.max_probe_points, params.target_module, - params.filter, params.show_ext_vars); - strfilter__delete(params.filter); if (ret < 0) pr_err(" Error: Failed to show vars. (%d)\n", ret); return ret; diff --git a/trunk/tools/perf/builtin-record.c b/trunk/tools/perf/builtin-record.c index d40a81e8cc56..60cac6f92e8b 100644 --- a/trunk/tools/perf/builtin-record.c +++ b/trunk/tools/perf/builtin-record.c @@ -18,20 +18,17 @@ #include "util/header.h" #include "util/event.h" -#include "util/evlist.h" #include "util/evsel.h" #include "util/debug.h" #include "util/session.h" #include "util/symbol.h" #include "util/cpumap.h" -#include "util/thread_map.h" #include #include #include #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) -#define SID(e, x, y) xyarray__entry(e->id, x, y) enum write_mode_t { WRITE_FORCE, @@ -42,13 +39,14 @@ static u64 user_interval = ULLONG_MAX; static u64 default_interval = 0; static u64 sample_type; +static struct cpu_map *cpus; static unsigned int page_size; static unsigned int mmap_pages = 128; 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 const char *output_name = "perf.data"; static int group = 0; static int realtime_prio = 0; static bool nodelay = false; @@ -57,6 +55,7 @@ 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 struct thread_map *threads; static pid_t child_pid = -1; static bool no_inherit = false; static enum write_mode_t write_mode = WRITE_FORCE; @@ -67,17 +66,51 @@ 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 struct pollfd *event_array; + +static int nr_poll = 0; +static int nr_cpu = 0; + static int file_new = 1; static off_t post_processing_offset; static struct perf_session *session; static const char *cpu_list; +struct mmap_data { + void *base; + unsigned int mask; + unsigned int prev; +}; + +static struct mmap_data mmap_array[MAX_NR_CPUS]; + +static unsigned long mmap_read_head(struct mmap_data *md) +{ + struct perf_event_mmap_page *pc = md->base; + long head; + + head = pc->data_head; + rmb(); + + return head; +} + +static void mmap_write_tail(struct mmap_data *md, unsigned long tail) +{ + struct perf_event_mmap_page *pc = md->base; + + /* + * ensure all reads are done before we write the tail out. + */ + /* mb(); */ + pc->data_tail = tail; +} + static void advance_output(size_t size) { bytes_written += size; @@ -98,26 +131,42 @@ static void write_output(void *buf, size_t size) } } -static int process_synthesized_event(union perf_event *event, - struct perf_sample *sample __used, +static int process_synthesized_event(event_t *event, + struct sample_data *sample __used, struct perf_session *self __used) { write_output(event, event->header.size); return 0; } -static void mmap_read(struct perf_mmap *md) +static void mmap_read(struct mmap_data *md) { - unsigned int head = perf_mmap__read_head(md); + unsigned int head = mmap_read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; unsigned long size; void *buf; + int diff; - if (old == head) - return; + /* + * If we're further behind than half the buffer, there's a chance + * the writer will bite our tail and mess up the samples under us. + * + * If we somehow ended up ahead of the head, we got messed up. + * + * In either case, truncate and restart at head. + */ + diff = head - old; + if (diff < 0) { + fprintf(stderr, "WARNING: failed to keep up with mmap data\n"); + /* + * head points to a known good entry, start there. + */ + old = head; + } - samples++; + if (old != head) + samples++; size = head - old; @@ -136,7 +185,7 @@ static void mmap_read(struct perf_mmap *md) write_output(buf, size); md->prev = old; - perf_mmap__write_tail(md, old); + mmap_write_tail(md, old); } static volatile int done = 0; @@ -160,6 +209,8 @@ static void sig_atexit(void) kill(getpid(), signr); } +static int group_fd; + static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) { struct perf_header_attr *h_attr; @@ -180,38 +231,31 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n static void create_counter(struct perf_evsel *evsel, int cpu) { + char *filter = evsel->filter; struct perf_event_attr *attr = &evsel->attr; struct perf_header_attr *h_attr; - struct perf_sample_id *sid; - int thread_index; - - for (thread_index = 0; thread_index < evsel_list->threads->nr; thread_index++) { - h_attr = get_header_attr(attr, evsel->idx); - if (h_attr == NULL) - die("nomem\n"); - - if (!file_new) { - if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { - fprintf(stderr, "incompatible append\n"); - exit(-1); - } - } - - sid = SID(evsel, cpu, thread_index); - if (perf_header_attr__add_id(h_attr, sid->id) < 0) { - pr_warning("Not enough memory to add id\n"); - exit(-1); - } - } - - if (!sample_type) - sample_type = attr->sample_type; -} - -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 */ + int thread_index; + int ret; + struct { + u64 count; + u64 time_enabled; + u64 time_running; + u64 id; + } read_data; + /* + * Check if parse_single_tracepoint_event has already asked for + * PERF_SAMPLE_TIME. + * + * XXX this is kludgy but short term fix for problems introduced by + * eac23d1c that broke 'perf script' by having different sample_types + * when using multiple tracepoint events when we use a perf binary + * that tries to use sample_id_all on an older kernel. + * + * We need to move counter creation to perf_session, support + * different sample_types, etc. + */ + bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | @@ -219,7 +263,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; - if (evlist->nr_entries > 1) + if (nr_counters > 1) attr->sample_type |= PERF_SAMPLE_ID; /* @@ -271,40 +315,19 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) attr->mmap = track; attr->comm = track; - + attr->inherit = !no_inherit; if (target_pid == -1 && target_tid == -1 && !system_wide) { attr->disabled = 1; attr->enable_on_exec = 1; } -} - -static void open_counters(struct perf_evlist *evlist) -{ - struct perf_evsel *pos; - int cpu; - - list_for_each_entry(pos, &evlist->entries, node) { - struct perf_event_attr *attr = &pos->attr; - /* - * Check if parse_single_tracepoint_event has already asked for - * PERF_SAMPLE_TIME. - * - * XXX this is kludgy but short term fix for problems introduced by - * eac23d1c that broke 'perf script' by having different sample_types - * when using multiple tracepoint events when we use a perf binary - * that tries to use sample_id_all on an older kernel. - * - * We need to move counter creation to perf_session, support - * different sample_types, etc. - */ - bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; - - config_attr(pos, evlist); retry_sample_id: - attr->sample_id_all = sample_id_all_avail ? 1 : 0; + attr->sample_id_all = sample_id_all_avail ? 1 : 0; + + for (thread_index = 0; thread_index < threads->nr; thread_index++) { try_again: - if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, - !no_inherit) < 0) { + FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); + + if (FD(evsel, nr_cpu, thread_index) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -341,7 +364,7 @@ static void open_counters(struct perf_evlist *evlist) } printf("\n"); error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", - err, strerror(err)); + FD(evsel, nr_cpu, thread_index), strerror(err)); #if defined(__i386__) || defined(__x86_64__) if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) @@ -352,22 +375,90 @@ static void open_counters(struct perf_evlist *evlist) #endif die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); + exit(-1); } - } - if (perf_evlist__set_filters(evlist)) { - error("failed to set filter with %d (%s)\n", errno, - strerror(errno)); - exit(-1); - } + h_attr = get_header_attr(attr, evsel->idx); + if (h_attr == NULL) + die("nomem\n"); + + if (!file_new) { + if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { + fprintf(stderr, "incompatible append\n"); + exit(-1); + } + } + + if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { + perror("Unable to read perf file descriptor"); + exit(-1); + } + + if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { + pr_warning("Not enough memory to add id\n"); + exit(-1); + } + + assert(FD(evsel, nr_cpu, thread_index) >= 0); + fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK); + + /* + * First counter acts as the group leader: + */ + if (group && group_fd == -1) + group_fd = FD(evsel, nr_cpu, thread_index); + + if (evsel->idx || thread_index) { + struct perf_evsel *first; + first = list_entry(evsel_list.next, struct perf_evsel, node); + ret = ioctl(FD(evsel, nr_cpu, thread_index), + PERF_EVENT_IOC_SET_OUTPUT, + FD(first, nr_cpu, 0)); + if (ret) { + error("failed to set output: %d (%s)\n", errno, + strerror(errno)); + exit(-1); + } + } else { + mmap_array[nr_cpu].prev = 0; + mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; + mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0); + if (mmap_array[nr_cpu].base == MAP_FAILED) { + error("failed to mmap with %d (%s)\n", errno, strerror(errno)); + exit(-1); + } - if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) - die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index); + event_array[nr_poll].events = POLLIN; + nr_poll++; + } - for (cpu = 0; cpu < evsel_list->cpus->nr; ++cpu) { - list_for_each_entry(pos, &evlist->entries, node) - create_counter(pos, cpu); + if (filter != NULL) { + ret = ioctl(FD(evsel, nr_cpu, thread_index), + PERF_EVENT_IOC_SET_FILTER, filter); + if (ret) { + error("failed to set filter with %d (%s)\n", errno, + strerror(errno)); + exit(-1); + } + } } + + if (!sample_type) + sample_type = attr->sample_type; +} + +static void open_counters(int cpu) +{ + struct perf_evsel *pos; + + group_fd = -1; + + list_for_each_entry(pos, &evsel_list, node) + create_counter(pos, cpu); + + nr_cpu++; } static int process_buildids(void) @@ -390,14 +481,14 @@ static void atexit_header(void) if (!no_buildid) process_buildids(); - perf_header__write(&session->header, evsel_list, output, true); + perf_header__write(&session->header, output, true); perf_session__delete(session); - perf_evlist__delete(evsel_list); + perf_evsel_list__delete(); symbol__exit(); } } -static void perf_event__synthesize_guest_os(struct machine *machine, void *data) +static void event__synthesize_guest_os(struct machine *machine, void *data) { int err; struct perf_session *psession = data; @@ -413,8 +504,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(process_synthesized_event, - psession, machine); + err = 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); @@ -423,12 +514,11 @@ 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(process_synthesized_event, - psession, machine, "_text"); + err = event__synthesize_kernel_mmap(process_synthesized_event, + psession, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, - psession, machine, - "_stext"); + err = 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); @@ -443,9 +533,9 @@ static void mmap_read_all(void) { int i; - for (i = 0; i < evsel_list->cpus->nr; i++) { - if (evsel_list->mmap[i].base) - mmap_read(&evsel_list->mmap[i]); + for (i = 0; i < nr_cpu; i++) { + if (mmap_array[i].base) + mmap_read(&mmap_array[i]); } if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) @@ -476,26 +566,18 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } - if (!output_name) { - if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) - pipe_output = 1; - else - output_name = "perf.data"; - } - if (output_name) { - if (!strcmp(output_name, "-")) - pipe_output = 1; - else if (!stat(output_name, &st) && st.st_size) { - 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 (write_mode == WRITE_APPEND) { - write_mode = WRITE_FORCE; + if (!strcmp(output_name, "-")) + pipe_output = 1; + else if (!stat(output_name, &st) && st.st_size) { + 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 (write_mode == WRITE_APPEND) { + write_mode = WRITE_FORCE; } flags = O_CREAT|O_RDWR; @@ -529,9 +611,14 @@ static int __cmd_record(int argc, const char **argv) goto out_delete_session; } - if (have_tracepoints(&evsel_list->entries)) + if (have_tracepoints(&evsel_list)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); + /* + * perf_session__delete(session) will be called at atexit_header() + */ + atexit(atexit_header); + if (forks) { child_pid = fork(); if (child_pid < 0) { @@ -572,7 +659,7 @@ static int __cmd_record(int argc, const char **argv) } if (!system_wide && target_tid == -1 && target_pid == -1) - evsel_list->threads->map[0] = child_pid; + threads->map[0] = child_pid; close(child_ready_pipe[1]); close(go_pipe[0]); @@ -586,22 +673,21 @@ static int __cmd_record(int argc, const char **argv) close(child_ready_pipe[0]); } - open_counters(evsel_list); + if (!system_wide && no_inherit && !cpu_list) { + open_counters(-1); + } else { + for (i = 0; i < cpus->nr; i++) + open_counters(cpus->map[i]); + } perf_session__set_sample_type(session, sample_type); - /* - * perf_session__delete(session) will be called at atexit_header() - */ - atexit(atexit_header); - if (pipe_output) { err = perf_header__write_pipe(output); if (err < 0) return err; } else if (file_new) { - err = perf_header__write(&session->header, evsel_list, - output, false); + err = perf_header__write(&session->header, output, false); if (err < 0) return err; } @@ -611,22 +697,22 @@ static int __cmd_record(int argc, const char **argv) perf_session__set_sample_id_all(session, sample_id_all_avail); if (pipe_output) { - err = perf_event__synthesize_attrs(&session->header, - process_synthesized_event, - session); + err = event__synthesize_attrs(&session->header, + process_synthesized_event, + session); if (err < 0) { pr_err("Couldn't synthesize attrs.\n"); return err; } - err = perf_event__synthesize_event_types(process_synthesized_event, - session); + err = event__synthesize_event_types(process_synthesized_event, + session); if (err < 0) { pr_err("Couldn't synthesize event_types.\n"); return err; } - if (have_tracepoints(&evsel_list->entries)) { + if (have_tracepoints(&evsel_list)) { /* * FIXME err <= 0 here actually means that * there were no tracepoints so its not really @@ -635,9 +721,9 @@ static int __cmd_record(int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ - err = perf_event__synthesize_tracing_data(output, evsel_list, - process_synthesized_event, - session); + err = event__synthesize_tracing_data(output, &evsel_list, + process_synthesized_event, + session); if (err <= 0) { pr_err("Couldn't record tracing data.\n"); return err; @@ -652,34 +738,31 @@ static int __cmd_record(int argc, const char **argv) return -1; } - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, - session, machine, "_text"); + err = event__synthesize_kernel_mmap(process_synthesized_event, + session, machine, "_text"); if (err < 0) - err = perf_event__synthesize_kernel_mmap(process_synthesized_event, - session, machine, "_stext"); + err = 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(process_synthesized_event, - session, machine); + err = 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, - perf_event__synthesize_guest_os); + perf_session__process_machines(session, event__synthesize_guest_os); if (!system_wide) - perf_event__synthesize_thread_map(evsel_list->threads, - process_synthesized_event, - session); + event__synthesize_thread_map(threads, process_synthesized_event, + session); else - perf_event__synthesize_threads(process_synthesized_event, - session); + event__synthesize_threads(process_synthesized_event, session); if (realtime_prio) { struct sched_param param; @@ -706,17 +789,17 @@ static int __cmd_record(int argc, const char **argv) if (hits == samples) { if (done) break; - err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); + err = poll(event_array, nr_poll, -1); waking++; } if (done) { - for (i = 0; i < evsel_list->cpus->nr; i++) { + for (i = 0; i < nr_cpu; i++) { struct perf_evsel *pos; - list_for_each_entry(pos, &evsel_list->entries, node) { + list_for_each_entry(pos, &evsel_list, node) { for (thread = 0; - thread < evsel_list->threads->nr; + thread < threads->nr; thread++) ioctl(FD(pos, i, thread), PERF_EVENT_IOC_DISABLE); @@ -755,10 +838,10 @@ static const char * const record_usage[] = { static bool force, append_file; const struct option record_options[] = { - OPT_CALLBACK('e', "event", &evsel_list, "event", + OPT_CALLBACK('e', "event", NULL, "event", "event selector. use 'perf list' to list available events", parse_events), - OPT_CALLBACK(0, "filter", &evsel_list, "filter", + OPT_CALLBACK(0, "filter", NULL, "filter", "event filter", parse_filter), OPT_INTEGER('p', "pid", &target_pid, "record events on existing process id"), @@ -801,9 +884,6 @@ const struct option record_options[] = { "do not update the buildid cache"), OPT_BOOLEAN('B', "no-buildid", &no_buildid, "do not collect buildids in perf.data"), - OPT_CALLBACK('G', "cgroup", &evsel_list, "name", - "monitor event in cgroup name only", - parse_cgroups), OPT_END() }; @@ -812,10 +892,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) int err = -ENOMEM; struct perf_evsel *pos; - evsel_list = perf_evlist__new(NULL, NULL); - if (evsel_list == NULL) - return -ENOMEM; - argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target_pid == -1 && target_tid == -1 && @@ -832,19 +908,12 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) write_mode = WRITE_FORCE; } - if (nr_cgroups && !system_wide) { - fprintf(stderr, "cgroup monitoring only available in" - " system-wide mode\n"); - usage_with_options(record_usage, record_options); - } - symbol__init(); if (no_buildid_cache || no_buildid) disable_buildid_cache(); - if (evsel_list->nr_entries == 0 && - perf_evlist__add_default(evsel_list) < 0) { + if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { pr_err("Not enough memory for event selector list\n"); goto out_symbol_exit; } @@ -852,19 +921,27 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (target_pid != -1) target_tid = target_pid; - if (perf_evlist__create_maps(evsel_list, target_pid, - target_tid, cpu_list) < 0) + threads = thread_map__new(target_pid, target_tid); + if (threads == NULL) { + pr_err("Problems finding threads of monitor\n"); usage_with_options(record_usage, record_options); + } + + cpus = cpu_map__new(cpu_list); + if (cpus == NULL) { + perror("failed to parse CPUs map"); + return -1; + } - list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, - evsel_list->threads->nr) < 0) + list_for_each_entry(pos, &evsel_list, node) { + if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; if (perf_header__push_event(pos->attr.config, event_name(pos))) goto out_free_fd; } - - if (perf_evlist__alloc_pollfd(evsel_list) < 0) + event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * + MAX_COUNTERS * threads->nr)); + if (!event_array) goto out_free_fd; if (user_interval != ULLONG_MAX) @@ -882,12 +959,16 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) } else { fprintf(stderr, "frequency and count are zero, aborting\n"); err = -EINVAL; - goto out_free_fd; + goto out_free_event_array; } err = __cmd_record(argc, argv); + +out_free_event_array: + free(event_array); out_free_fd: - perf_evlist__delete_maps(evsel_list); + thread_map__delete(threads); + threads = NULL; out_symbol_exit: symbol__exit(); return err; diff --git a/trunk/tools/perf/builtin-report.c b/trunk/tools/perf/builtin-report.c index dddcc7ea2bec..c27e31f289e6 100644 --- a/trunk/tools/perf/builtin-report.c +++ b/trunk/tools/perf/builtin-report.c @@ -9,7 +9,6 @@ #include "util/util.h" -#include "util/annotate.h" #include "util/color.h" #include #include "util/cache.h" @@ -44,7 +43,6 @@ 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"; -static symbol_filter_t annotate_init; static struct hists *perf_session__hists_findnew(struct perf_session *self, u64 event_stream, u32 type, @@ -79,96 +77,86 @@ static struct hists *perf_session__hists_findnew(struct perf_session *self, return new; } -static int perf_session__add_hist_entry(struct perf_session *session, +static int perf_session__add_hist_entry(struct perf_session *self, struct addr_location *al, - struct perf_sample *sample) + struct sample_data *data) { + struct map_symbol *syms = NULL; struct symbol *parent = NULL; - int err = 0; + int err = -ENOMEM; struct hist_entry *he; struct hists *hists; struct perf_event_attr *attr; - if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { - err = perf_session__resolve_callchain(session, al->thread, - sample->callchain, &parent); - if (err) - return err; + if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { + syms = perf_session__resolve_callchain(self, al->thread, + data->callchain, &parent); + if (syms == NULL) + return -ENOMEM; } - attr = perf_header__find_attr(sample->id, &session->header); + attr = perf_header__find_attr(data->id, &self->header); if (attr) - hists = perf_session__hists_findnew(session, sample->id, attr->type, attr->config); + hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config); else - hists = perf_session__hists_findnew(session, sample->id, 0, 0); + hists = perf_session__hists_findnew(self, data->id, 0, 0); if (hists == NULL) - return -ENOMEM; - - he = __hists__add_entry(hists, al, parent, sample->period); + goto out_free_syms; + he = __hists__add_entry(hists, al, parent, data->period); if (he == NULL) - return -ENOMEM; - + goto out_free_syms; + err = 0; if (symbol_conf.use_callchain) { - err = callchain_append(he->callchain, &session->callchain_cursor, - sample->period); + err = callchain_append(he->callchain, data->callchain, syms, + data->period); if (err) - return err; + goto out_free_syms; } /* * Only in the newt browser we are doing integrated annotation, * so we don't allocated the extra space needed because the stdio * code will not use it. */ - if (al->sym != NULL && use_browser > 0) { - /* - * All aggregated on the first sym_hist. - */ - struct annotation *notes = symbol__annotation(he->ms.sym); - if (notes->src == NULL && - symbol__alloc_hist(he->ms.sym, 1) < 0) - err = -ENOMEM; - else - err = hist_entry__inc_addr_samples(he, 0, al->addr); - } - + if (use_browser > 0) + err = hist_entry__inc_addr_samples(he, al->addr); +out_free_syms: + free(syms); return err; } static int add_event_total(struct perf_session *session, - struct perf_sample *sample, + struct sample_data *data, struct perf_event_attr *attr) { struct hists *hists; if (attr) - hists = perf_session__hists_findnew(session, sample->id, + hists = perf_session__hists_findnew(session, data->id, attr->type, attr->config); else - hists = perf_session__hists_findnew(session, sample->id, 0, 0); + hists = perf_session__hists_findnew(session, data->id, 0, 0); if (!hists) return -ENOMEM; - hists->stats.total_period += sample->period; + hists->stats.total_period += data->period; /* * FIXME: add_event_total should be moved from here to * perf_session__process_event so that the proper hist is passed to * the event_op methods. */ hists__inc_nr_events(hists, PERF_RECORD_SAMPLE); - session->hists.stats.total_period += sample->period; + session->hists.stats.total_period += data->period; return 0; } -static int process_sample_event(union perf_event *event, - struct perf_sample *sample, +static int process_sample_event(event_t *event, struct sample_data *sample, struct perf_session *session) { struct addr_location al; struct perf_event_attr *attr; - if (perf_event__preprocess_sample(event, session, &al, sample, - annotate_init) < 0) { + if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) { fprintf(stderr, "problem processing %d event, skipping it.\n", event->header.type); return -1; @@ -192,8 +180,7 @@ static int process_sample_event(union perf_event *event, return 0; } -static int process_read_event(union perf_event *event, - struct perf_sample *sample __used, +static int process_read_event(event_t *event, struct sample_data *sample __used, struct perf_session *session __used) { struct perf_event_attr *attr; @@ -235,7 +222,7 @@ static int perf_session__setup_sample_type(struct perf_session *self) } 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) { + if (register_callchain_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain" " params\n"); return -EINVAL; @@ -246,17 +233,17 @@ static int perf_session__setup_sample_type(struct perf_session *self) } 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, + .sample = process_sample_event, + .mmap = event__process_mmap, + .comm = event__process_comm, + .exit = event__process_task, + .fork = event__process_task, + .lost = event__process_lost, + .read = process_read_event, + .attr = event__process_attr, + .event_type = event__process_event_type, + .tracing_data = event__process_tracing_data, + .build_id = event__process_build_id, .ordered_samples = true, .ordering_requires_timestamps = true, }; @@ -350,12 +337,6 @@ static int __cmd_report(void) perf_session__fprintf_dsos(session, stdout); next = rb_first(&session->hists_tree); - - if (next == NULL) { - ui__warning("The %s file has no samples!\n", input_name); - goto out_delete; - } - while (next) { struct hists *hists; @@ -366,7 +347,7 @@ static int __cmd_report(void) } if (use_browser > 0) - hists__tui_browse_tree(&session->hists_tree, help, 0); + hists__tui_browse_tree(&session->hists_tree, help); else hists__tty_browse_tree(&session->hists_tree, help); @@ -443,7 +424,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, if (tok2) callchain_param.print_limit = strtod(tok2, &endptr); setup: - if (callchain_register_param(&callchain_param) < 0) { + if (register_callchain_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain params\n"); return -1; } @@ -517,7 +498,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) use_browser = 1; if (strcmp(input_name, "-") != 0) - setup_browser(true); + setup_browser(); else use_browser = 0; /* @@ -526,8 +507,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) * implementation. */ if (use_browser > 0) { - symbol_conf.priv_size = sizeof(struct annotation); - annotate_init = symbol__annotate_init; + symbol_conf.priv_size = sizeof(struct sym_priv); /* * For searching by name on the "Browse map details". * providing it only in verbose mode not to bloat too diff --git a/trunk/tools/perf/builtin-sched.c b/trunk/tools/perf/builtin-sched.c index a32f411faeac..29acb894e035 100644 --- a/trunk/tools/perf/builtin-sched.c +++ b/trunk/tools/perf/builtin-sched.c @@ -369,6 +369,11 @@ static void process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom) { int ret = 0; + u64 now; + long long delta; + + now = get_nsecs(); + delta = start_time + atom->timestamp - now; switch (atom->type) { case SCHED_EVENT_RUN: @@ -557,7 +562,7 @@ static void wait_for_tasks(void) static void run_one_test(void) { - u64 T0, T1, delta, avg_delta, fluct; + u64 T0, T1, delta, avg_delta, fluct, std_dev; T0 = get_nsecs(); wait_for_tasks(); @@ -573,6 +578,7 @@ static void run_one_test(void) else fluct = delta - avg_delta; sum_fluct += fluct; + std_dev = sum_fluct / nr_runs / sqrt(nr_runs); if (!run_avg) run_avg = delta; run_avg = (run_avg*9 + delta)/10; @@ -793,7 +799,7 @@ replay_switch_event(struct trace_switch_event *switch_event, u64 timestamp, struct thread *thread __used) { - struct task_desc *prev, __used *next; + struct task_desc *prev, *next; u64 timestamp0; s64 delta; @@ -1398,7 +1404,7 @@ map_switch_event(struct trace_switch_event *switch_event, u64 timestamp, struct thread *thread __used) { - struct thread *sched_out __used, *sched_in; + struct thread *sched_out, *sched_in; int new_shortname; u64 timestamp0; s64 delta; @@ -1574,9 +1580,9 @@ process_sched_migrate_task_event(void *data, struct perf_session *session, event, cpu, timestamp, 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) +static void +process_raw_event(event_t *raw_event __used, struct perf_session *session, + void *data, int cpu, u64 timestamp, struct thread *thread) { struct event *event; int type; @@ -1601,8 +1607,7 @@ static void process_raw_event(union perf_event *raw_event __used, process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread); } -static int process_sample_event(union perf_event *event, - struct perf_sample *sample, +static int process_sample_event(event_t *event, struct sample_data *sample, struct perf_session *session) { struct thread *thread; @@ -1630,9 +1635,9 @@ static int process_sample_event(union perf_event *event, 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, + .comm = event__process_comm, + .lost = event__process_lost, + .fork = event__process_task, .ordered_samples = true, }; diff --git a/trunk/tools/perf/builtin-script.c b/trunk/tools/perf/builtin-script.c index 5f40df635dcb..b766c2a9ac97 100644 --- a/trunk/tools/perf/builtin-script.c +++ b/trunk/tools/perf/builtin-script.c @@ -63,8 +63,7 @@ static int cleanup_scripting(void) static char const *input_name = "perf.data"; -static int process_sample_event(union perf_event *event, - struct perf_sample *sample, +static int process_sample_event(event_t *event, struct sample_data *sample, struct perf_session *session) { struct thread *thread = perf_session__findnew(session, event->ip.pid); @@ -101,14 +100,14 @@ static int process_sample_event(union perf_event *event, } static struct perf_event_ops event_ops = { - .sample = process_sample_event, - .comm = perf_event__process_comm, - .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, + .sample = process_sample_event, + .comm = event__process_comm, + .attr = event__process_attr, + .event_type = event__process_event_type, + .tracing_data = event__process_tracing_data, + .build_id = event__process_build_id, .ordering_requires_timestamps = true, + .ordered_samples = true, }; extern volatile int session_done; diff --git a/trunk/tools/perf/builtin-stat.c b/trunk/tools/perf/builtin-stat.c index 21c025222496..a482a191a0ca 100644 --- a/trunk/tools/perf/builtin-stat.c +++ b/trunk/tools/perf/builtin-stat.c @@ -43,13 +43,11 @@ #include "util/parse-options.h" #include "util/parse-events.h" #include "util/event.h" -#include "util/evlist.h" #include "util/evsel.h" #include "util/debug.h" #include "util/header.h" #include "util/cpumap.h" #include "util/thread.h" -#include "util/thread_map.h" #include #include @@ -73,9 +71,8 @@ static struct perf_event_attr default_attrs[] = { }; -struct perf_evlist *evsel_list; - static bool system_wide = false; +static struct cpu_map *cpus; static int run_idx = 0; static int run_count = 1; @@ -84,6 +81,7 @@ static bool scale = true; static bool no_aggr = false; static pid_t target_pid = -1; static pid_t target_tid = -1; +static struct thread_map *threads; static pid_t child_pid = -1; static bool null_run = false; static bool big_num = true; @@ -168,7 +166,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) PERF_FORMAT_TOTAL_TIME_RUNNING; if (system_wide) - return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false); + return perf_evsel__open_per_cpu(evsel, cpus); attr->inherit = !no_inherit; if (target_pid == -1 && target_tid == -1) { @@ -176,7 +174,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) attr->enable_on_exec = 1; } - return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false); + return perf_evsel__open_per_thread(evsel, threads); } /* @@ -201,8 +199,7 @@ static int read_counter_aggr(struct perf_evsel *counter) u64 *count = counter->counts->aggr.values; int i; - if (__perf_evsel__read(counter, evsel_list->cpus->nr, - evsel_list->threads->nr, scale) < 0) + if (__perf_evsel__read(counter, cpus->nr, threads->nr, scale) < 0) return -1; for (i = 0; i < 3; i++) @@ -235,7 +232,7 @@ static int read_counter(struct perf_evsel *counter) u64 *count; int cpu; - for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) { + for (cpu = 0; cpu < cpus->nr; cpu++) { if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) return -1; @@ -300,7 +297,7 @@ static int run_perf_stat(int argc __used, const char **argv) } if (target_tid == -1 && target_pid == -1 && !system_wide) - evsel_list->threads->map[0] = child_pid; + threads->map[0] = child_pid; /* * Wait for the child to be ready to exec. @@ -312,7 +309,7 @@ static int run_perf_stat(int argc __used, const char **argv) close(child_ready_pipe[0]); } - list_for_each_entry(counter, &evsel_list->entries, node) { + list_for_each_entry(counter, &evsel_list, node) { if (create_perf_stat_counter(counter) < 0) { if (errno == -EPERM || errno == -EACCES) { error("You may not have permission to collect %sstats.\n" @@ -350,15 +347,14 @@ static int run_perf_stat(int argc __used, const char **argv) update_stats(&walltime_nsecs_stats, t1 - t0); if (no_aggr) { - list_for_each_entry(counter, &evsel_list->entries, node) { + list_for_each_entry(counter, &evsel_list, node) { read_counter(counter); - perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1); + perf_evsel__close_fd(counter, cpus->nr, 1); } } else { - list_for_each_entry(counter, &evsel_list->entries, node) { + list_for_each_entry(counter, &evsel_list, node) { read_counter_aggr(counter); - perf_evsel__close_fd(counter, evsel_list->cpus->nr, - evsel_list->threads->nr); + perf_evsel__close_fd(counter, cpus->nr, threads->nr); } } @@ -386,13 +382,10 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) if (no_aggr) sprintf(cpustr, "CPU%*d%s", csv_output ? 0 : -4, - evsel_list->cpus->map[cpu], csv_sep); + cpus->map[cpu], csv_sep); fprintf(stderr, fmt, cpustr, msecs, csv_sep, event_name(evsel)); - if (evsel->cgrp) - fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); - if (csv_output) return; @@ -417,15 +410,12 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) if (no_aggr) sprintf(cpustr, "CPU%*d%s", csv_output ? 0 : -4, - evsel_list->cpus->map[cpu], csv_sep); + cpus->map[cpu], csv_sep); else cpu = 0; fprintf(stderr, fmt, cpustr, avg, csv_sep, event_name(evsel)); - if (evsel->cgrp) - fprintf(stderr, "%s%s", csv_sep, evsel->cgrp->name); - if (csv_output) return; @@ -466,17 +456,9 @@ static void print_counter_aggr(struct perf_evsel *counter) int scaled = counter->counts->scaled; if (scaled == -1) { - fprintf(stderr, "%*s%s%*s", + fprintf(stderr, "%*s%s%-24s\n", csv_output ? 0 : 18, - "", - csv_sep, - csv_output ? 0 : -24, - event_name(counter)); - - if (counter->cgrp) - fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); - - fputc('\n', stderr); + "", csv_sep, event_name(counter)); return; } @@ -501,6 +483,7 @@ static void print_counter_aggr(struct perf_evsel *counter) fprintf(stderr, " (scaled from %.2f%%)", 100 * avg_running / avg_enabled); } + fprintf(stderr, "\n"); } @@ -513,23 +496,19 @@ static void print_counter(struct perf_evsel *counter) u64 ena, run, val; int cpu; - for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) { + for (cpu = 0; cpu < cpus->nr; cpu++) { val = counter->counts->cpu[cpu].val; ena = counter->counts->cpu[cpu].ena; run = counter->counts->cpu[cpu].run; if (run == 0 || ena == 0) { - fprintf(stderr, "CPU%*d%s%*s%s%*s", + fprintf(stderr, "CPU%*d%s%*s%s%-24s", csv_output ? 0 : -4, - evsel_list->cpus->map[cpu], csv_sep, + cpus->map[cpu], csv_sep, csv_output ? 0 : 18, "", csv_sep, - csv_output ? 0 : -24, event_name(counter)); - if (counter->cgrp) - fprintf(stderr, "%s%s", csv_sep, counter->cgrp->name); - - fputc('\n', stderr); + fprintf(stderr, "\n"); continue; } @@ -546,7 +525,7 @@ static void print_counter(struct perf_evsel *counter) 100.0 * run / ena); } } - fputc('\n', stderr); + fprintf(stderr, "\n"); } } @@ -576,10 +555,10 @@ static void print_stat(int argc, const char **argv) } if (no_aggr) { - list_for_each_entry(counter, &evsel_list->entries, node) + list_for_each_entry(counter, &evsel_list, node) print_counter(counter); } else { - list_for_each_entry(counter, &evsel_list->entries, node) + list_for_each_entry(counter, &evsel_list, node) print_counter_aggr(counter); } @@ -631,7 +610,7 @@ static int stat__set_big_num(const struct option *opt __used, } static const struct option options[] = { - OPT_CALLBACK('e', "event", &evsel_list, "event", + OPT_CALLBACK('e', "event", NULL, "event", "event selector. use 'perf list' to list available events", parse_events), OPT_BOOLEAN('i', "no-inherit", &no_inherit, @@ -659,9 +638,6 @@ static const struct option options[] = { "disable CPU count aggregation"), OPT_STRING('x', "field-separator", &csv_sep, "separator", "print counts with custom separator"), - OPT_CALLBACK('G', "cgroup", &evsel_list, "name", - "monitor event in cgroup name only", - parse_cgroups), OPT_END() }; @@ -672,10 +648,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) setlocale(LC_ALL, ""); - evsel_list = perf_evlist__new(NULL, NULL); - if (evsel_list == NULL) - return -ENOMEM; - argc = parse_options(argc, argv, options, stat_usage, PARSE_OPT_STOP_AT_NON_OPTION); @@ -702,50 +674,49 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) if (run_count <= 0) usage_with_options(stat_usage, options); - /* no_aggr, cgroup are for system-wide only */ - if ((no_aggr || nr_cgroups) && !system_wide) { - fprintf(stderr, "both cgroup and no-aggregation " - "modes only available in system-wide mode\n"); - + /* no_aggr is for system-wide only */ + if (no_aggr && !system_wide) usage_with_options(stat_usage, options); - } /* Set attrs and nr_counters if no event is selected and !null_run */ - if (!null_run && !evsel_list->nr_entries) { + if (!null_run && !nr_counters) { size_t c; + nr_counters = ARRAY_SIZE(default_attrs); + for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { - pos = perf_evsel__new(&default_attrs[c], c); + pos = perf_evsel__new(&default_attrs[c], + nr_counters); if (pos == NULL) goto out; - perf_evlist__add(evsel_list, pos); + list_add(&pos->node, &evsel_list); } } if (target_pid != -1) target_tid = target_pid; - evsel_list->threads = thread_map__new(target_pid, target_tid); - if (evsel_list->threads == NULL) { + threads = thread_map__new(target_pid, target_tid); + if (threads == NULL) { pr_err("Problems finding threads of monitor\n"); usage_with_options(stat_usage, options); } if (system_wide) - evsel_list->cpus = cpu_map__new(cpu_list); + cpus = cpu_map__new(cpu_list); else - evsel_list->cpus = cpu_map__dummy_new(); + cpus = cpu_map__dummy_new(); - if (evsel_list->cpus == NULL) { + if (cpus == NULL) { perror("failed to parse CPUs map"); usage_with_options(stat_usage, options); return -1; } - list_for_each_entry(pos, &evsel_list->entries, node) { + list_for_each_entry(pos, &evsel_list, node) { if (perf_evsel__alloc_stat_priv(pos) < 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) + perf_evsel__alloc_counts(pos, cpus->nr) < 0 || + perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; } @@ -770,10 +741,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) if (status != -1) print_stat(argc, argv); out_free_fd: - list_for_each_entry(pos, &evsel_list->entries, node) + list_for_each_entry(pos, &evsel_list, node) perf_evsel__free_stat_priv(pos); - perf_evlist__delete_maps(evsel_list); + perf_evsel_list__delete(); out: - perf_evlist__delete(evsel_list); + thread_map__delete(threads); + threads = NULL; return status; } diff --git a/trunk/tools/perf/builtin-test.c b/trunk/tools/perf/builtin-test.c index 1b2106c58f66..5dcdba653d70 100644 --- a/trunk/tools/perf/builtin-test.c +++ b/trunk/tools/perf/builtin-test.c @@ -7,11 +7,10 @@ #include "util/cache.h" #include "util/debug.h" -#include "util/evlist.h" #include "util/parse-options.h" -#include "util/parse-events.h" +#include "util/session.h" #include "util/symbol.h" -#include "util/thread_map.h" +#include "util/thread.h" static long page_size; @@ -239,14 +238,14 @@ static int test__vmlinux_matches_kallsyms(void) #include "util/evsel.h" #include -static int trace_event__id(const char *evname) +static int trace_event__id(const char *event_name) { char *filename; int err = -1, fd; if (asprintf(&filename, "/sys/kernel/debug/tracing/events/syscalls/%s/id", - evname) < 0) + event_name) < 0) return -1; fd = open(filename, O_RDONLY); @@ -290,7 +289,7 @@ static int test__open_syscall_event(void) goto out_thread_map_delete; } - if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) { + if (perf_evsel__open_per_thread(evsel, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); @@ -348,9 +347,9 @@ static int test__open_syscall_event_on_all_cpus(void) } cpus = cpu_map__new(NULL); - if (cpus == NULL) { - pr_debug("cpu_map__new\n"); - goto out_thread_map_delete; + if (threads == NULL) { + pr_debug("thread_map__new\n"); + return -1; } @@ -365,7 +364,7 @@ static int test__open_syscall_event_on_all_cpus(void) goto out_thread_map_delete; } - if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) { + if (perf_evsel__open(evsel, cpus, threads) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); @@ -409,8 +408,6 @@ static int test__open_syscall_event_on_all_cpus(void) goto out_close_fd; } - err = 0; - for (cpu = 0; cpu < cpus->nr; ++cpu) { unsigned int expected; @@ -419,18 +416,18 @@ static int test__open_syscall_event_on_all_cpus(void) if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { pr_debug("perf_evsel__open_read_on_cpu\n"); - err = -1; - break; + goto out_close_fd; } expected = nr_open_calls + cpu; if (evsel->counts->cpu[cpu].val != expected) { pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); - err = -1; + goto out_close_fd; } } + err = 0; out_close_fd: perf_evsel__close_fd(evsel, 1, threads->nr); out_evsel_delete: @@ -440,159 +437,6 @@ static int test__open_syscall_event_on_all_cpus(void) return err; } -/* - * This test will generate random numbers of calls to some getpid syscalls, - * then establish an mmap for a group of events that are created to monitor - * the syscalls. - * - * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated - * sample.id field to map back to its respective perf_evsel instance. - * - * Then it checks if the number of syscalls reported as perf events by - * the kernel corresponds to the number of syscalls made. - */ -static int test__basic_mmap(void) -{ - int err = -1; - union perf_event *event; - struct thread_map *threads; - struct cpu_map *cpus; - struct perf_evlist *evlist; - struct perf_event_attr attr = { - .type = PERF_TYPE_TRACEPOINT, - .read_format = PERF_FORMAT_ID, - .sample_type = PERF_SAMPLE_ID, - .watermark = 0, - }; - cpu_set_t cpu_set; - const char *syscall_names[] = { "getsid", "getppid", "getpgrp", - "getpgid", }; - pid_t (*syscalls[])(void) = { (void *)getsid, getppid, getpgrp, - (void*)getpgid }; -#define nsyscalls ARRAY_SIZE(syscall_names) - int ids[nsyscalls]; - unsigned int nr_events[nsyscalls], - expected_nr_events[nsyscalls], i, j; - struct perf_evsel *evsels[nsyscalls], *evsel; - - for (i = 0; i < nsyscalls; ++i) { - char name[64]; - - snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); - ids[i] = trace_event__id(name); - if (ids[i] < 0) { - pr_debug("Is debugfs mounted on /sys/kernel/debug?\n"); - return -1; - } - nr_events[i] = 0; - expected_nr_events[i] = random() % 257; - } - - threads = thread_map__new(-1, getpid()); - if (threads == NULL) { - pr_debug("thread_map__new\n"); - return -1; - } - - cpus = cpu_map__new(NULL); - if (cpus == NULL) { - pr_debug("cpu_map__new\n"); - goto out_free_threads; - } - - CPU_ZERO(&cpu_set); - CPU_SET(cpus->map[0], &cpu_set); - sched_setaffinity(0, sizeof(cpu_set), &cpu_set); - if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { - pr_debug("sched_setaffinity() failed on CPU %d: %s ", - cpus->map[0], strerror(errno)); - goto out_free_cpus; - } - - evlist = perf_evlist__new(cpus, threads); - if (evlist == NULL) { - pr_debug("perf_evlist__new\n"); - goto out_free_cpus; - } - - /* anonymous union fields, can't be initialized above */ - attr.wakeup_events = 1; - attr.sample_period = 1; - - for (i = 0; i < nsyscalls; ++i) { - attr.config = ids[i]; - evsels[i] = perf_evsel__new(&attr, i); - if (evsels[i] == NULL) { - pr_debug("perf_evsel__new\n"); - goto out_free_evlist; - } - - perf_evlist__add(evlist, evsels[i]); - - if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) { - pr_debug("failed to open counter: %s, " - "tweak /proc/sys/kernel/perf_event_paranoid?\n", - strerror(errno)); - goto out_close_fd; - } - } - - if (perf_evlist__mmap(evlist, 128, true) < 0) { - pr_debug("failed to mmap events: %d (%s)\n", errno, - strerror(errno)); - goto out_close_fd; - } - - for (i = 0; i < nsyscalls; ++i) - for (j = 0; j < expected_nr_events[i]; ++j) { - int foo = syscalls[i](); - ++foo; - } - - while ((event = perf_evlist__read_on_cpu(evlist, 0)) != NULL) { - struct perf_sample sample; - - if (event->header.type != PERF_RECORD_SAMPLE) { - pr_debug("unexpected %s event\n", - perf_event__name(event->header.type)); - goto out_munmap; - } - - perf_event__parse_sample(event, attr.sample_type, false, &sample); - evsel = perf_evlist__id2evsel(evlist, sample.id); - if (evsel == NULL) { - pr_debug("event with id %" PRIu64 - " doesn't map to an evsel\n", sample.id); - goto out_munmap; - } - nr_events[evsel->idx]++; - } - - list_for_each_entry(evsel, &evlist->entries, node) { - if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { - pr_debug("expected %d %s events, got %d\n", - expected_nr_events[evsel->idx], - event_name(evsel), nr_events[evsel->idx]); - goto out_munmap; - } - } - - err = 0; -out_munmap: - perf_evlist__munmap(evlist); -out_close_fd: - for (i = 0; i < nsyscalls; ++i) - perf_evsel__close_fd(evsels[i], 1, threads->nr); -out_free_evlist: - perf_evlist__delete(evlist); -out_free_cpus: - cpu_map__delete(cpus); -out_free_threads: - thread_map__delete(threads); - return err; -#undef nsyscalls -} - static struct test { const char *desc; int (*func)(void); @@ -609,10 +453,6 @@ static struct test { .desc = "detect open syscall event on all cpus", .func = test__open_syscall_event_on_all_cpus, }, - { - .desc = "read samples using the mmap interface", - .func = test__basic_mmap, - }, { .func = NULL, }, diff --git a/trunk/tools/perf/builtin-timechart.c b/trunk/tools/perf/builtin-timechart.c index 0801275c500e..0ace786e83e0 100644 --- a/trunk/tools/perf/builtin-timechart.c +++ b/trunk/tools/perf/builtin-timechart.c @@ -264,9 +264,6 @@ pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end) c->start_time = start; if (p->start_time == 0 || p->start_time > start) p->start_time = start; - - if (cpu > numcpus) - numcpus = cpu; } #define MAX_CPUS 4096 @@ -276,24 +273,21 @@ 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(union perf_event *event, - struct perf_sample *sample __used, +static int process_comm_event(event_t *event, struct sample_data *sample __used, struct perf_session *session __used) { pid_set_comm(event->comm.tid, event->comm.comm); return 0; } -static int process_fork_event(union perf_event *event, - struct perf_sample *sample __used, +static int process_fork_event(event_t *event, struct sample_data *sample __used, struct perf_session *session __used) { pid_fork(event->fork.pid, event->fork.ppid, event->fork.time); return 0; } -static int process_exit_event(union perf_event *event, - struct perf_sample *sample __used, +static int process_exit_event(event_t *event, struct sample_data *sample __used, struct perf_session *session __used) { pid_exit(event->fork.pid, event->fork.time); @@ -489,8 +483,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) } -static int process_sample_event(union perf_event *event __used, - struct perf_sample *sample, +static int process_sample_event(event_t *event __used, + struct sample_data *sample, struct perf_session *session) { struct trace_entry *te; @@ -514,6 +508,9 @@ static int process_sample_event(union perf_event *event __used, if (!event_str) return 0; + if (sample->cpu > numcpus) + numcpus = sample->cpu; + if (strcmp(event_str, "power:cpu_idle") == 0) { struct power_processor_entry *ppe = (void *)te; if (ppe->state == (u32)PWR_EVENT_EXIT) diff --git a/trunk/tools/perf/builtin-top.c b/trunk/tools/perf/builtin-top.c index 417f757e3cbe..5a29d9cd9486 100644 --- a/trunk/tools/perf/builtin-top.c +++ b/trunk/tools/perf/builtin-top.c @@ -20,16 +20,11 @@ #include "perf.h" -#include "util/annotate.h" -#include "util/cache.h" #include "util/color.h" -#include "util/evlist.h" #include "util/evsel.h" #include "util/session.h" #include "util/symbol.h" #include "util/thread.h" -#include "util/thread_map.h" -#include "util/top.h" #include "util/util.h" #include #include "util/parse-options.h" @@ -50,6 +45,7 @@ #include #include #include +#include #include #include @@ -64,42 +60,85 @@ #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) -static struct perf_top top = { - .count_filter = 5, - .delay_secs = 2, - .display_weighted = -1, - .target_pid = -1, - .target_tid = -1, - .active_symbols = LIST_HEAD_INIT(top.active_symbols), - .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER, - .active_symbols_cond = PTHREAD_COND_INITIALIZER, - .freq = 1000, /* 1 KHz */ -}; - static bool system_wide = false; -static bool use_tui, use_stdio; - static int default_interval = 0; +static int count_filter = 5; +static int print_entries; + +static int target_pid = -1; +static int target_tid = -1; +static struct thread_map *threads; static bool inherit = false; +static struct cpu_map *cpus; static int realtime_prio = 0; static bool group = false; static unsigned int page_size; -static unsigned int mmap_pages = 128; +static unsigned int mmap_pages = 16; +static int freq = 1000; /* 1 KHz */ +static int delay_secs = 2; +static bool zero = false; static bool dump_symtab = false; +static bool hide_kernel_symbols = false; +static bool hide_user_symbols = false; static struct winsize winsize; +/* + * Source + */ + +struct source_line { + u64 eip; + unsigned long count[MAX_COUNTERS]; + char *line; + struct source_line *next; +}; + static const char *sym_filter = NULL; +struct sym_entry *sym_filter_entry = NULL; struct sym_entry *sym_filter_entry_sched = NULL; static int sym_pcnt_filter = 5; +static int sym_counter = 0; +static struct perf_evsel *sym_evsel = NULL; +static int display_weighted = -1; +static const char *cpu_list; + +/* + * Symbols + */ + +struct sym_entry_source { + struct source_line *source; + struct source_line *lines; + struct source_line **lines_tail; + pthread_mutex_t lock; +}; + +struct sym_entry { + struct rb_node rb_node; + struct list_head node; + unsigned long snap_count; + double weight; + int skip; + u16 name_len; + u8 origin; + struct map *map; + struct sym_entry_source *src; + unsigned long count[0]; +}; /* * Source functions */ +static inline struct symbol *sym_entry__symbol(struct sym_entry *self) +{ + return ((void *)self) + symbol_conf.priv_size; +} + void get_term_dimensions(struct winsize *ws) { char *s = getenv("LINES"); @@ -124,10 +163,10 @@ void get_term_dimensions(struct winsize *ws) static void update_print_entries(struct winsize *ws) { - top.print_entries = ws->ws_row; + print_entries = ws->ws_row; - if (top.print_entries > 9) - top.print_entries -= 9; + if (print_entries > 9) + print_entries -= 9; } static void sig_winch_handler(int sig __used) @@ -139,9 +178,12 @@ static void sig_winch_handler(int sig __used) static int parse_source(struct sym_entry *syme) { struct symbol *sym; - struct annotation *notes; + struct sym_entry_source *source; struct map *map; - int err = -1; + FILE *file; + char command[PATH_MAX*2]; + const char *path; + u64 len; if (!syme) return -1; @@ -152,137 +194,411 @@ static int parse_source(struct sym_entry *syme) /* * We can't annotate with just /proc/kallsyms */ - if (map->dso->origin == DSO__ORIG_KERNEL) { - pr_err("Can't annotate %s: No vmlinux file was found in the " - "path\n", sym->name); - sleep(1); + if (map->dso->origin == DSO__ORIG_KERNEL) return -1; + + if (syme->src == NULL) { + syme->src = zalloc(sizeof(*source)); + if (syme->src == NULL) + return -1; + pthread_mutex_init(&syme->src->lock, NULL); } - notes = symbol__annotation(sym); - if (notes->src != NULL) { - pthread_mutex_lock(¬es->lock); + source = syme->src; + + if (source->lines) { + pthread_mutex_lock(&source->lock); goto out_assign; } + path = map->dso->long_name; - pthread_mutex_lock(¬es->lock); + len = sym->end - sym->start; - 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); - sleep(1); - return err; - } + sprintf(command, + "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s", + BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start), + BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path); - err = symbol__annotate(sym, syme->map, 0); - if (err == 0) { -out_assign: - top.sym_filter_entry = syme; - } + file = popen(command, "r"); + if (!file) + return -1; - pthread_mutex_unlock(¬es->lock); - return err; + pthread_mutex_lock(&source->lock); + source->lines_tail = &source->lines; + while (!feof(file)) { + struct source_line *src; + size_t dummy = 0; + char *c, *sep; + + src = malloc(sizeof(struct source_line)); + assert(src != NULL); + memset(src, 0, sizeof(struct source_line)); + + if (getline(&src->line, &dummy, file) < 0) + break; + if (!src->line) + break; + + c = strchr(src->line, '\n'); + if (c) + *c = 0; + + src->next = NULL; + *source->lines_tail = src; + source->lines_tail = &src->next; + + src->eip = strtoull(src->line, &sep, 16); + if (*sep == ':') + src->eip = map__objdump_2ip(map, src->eip); + else /* this line has no ip info (e.g. source line) */ + src->eip = 0; + } + pclose(file); +out_assign: + sym_filter_entry = syme; + pthread_mutex_unlock(&source->lock); + return 0; } static void __zero_source_counters(struct sym_entry *syme) { - struct symbol *sym = sym_entry__symbol(syme); - symbol__annotate_zero_histograms(sym); + int i; + struct source_line *line; + + line = syme->src->lines; + while (line) { + for (i = 0; i < nr_counters; i++) + line->count[i] = 0; + line = line->next; + } } static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) { - struct annotation *notes; - struct symbol *sym; + struct source_line *line; - if (syme != top.sym_filter_entry) + if (syme != sym_filter_entry) return; - sym = sym_entry__symbol(syme); - notes = symbol__annotation(sym); - - if (pthread_mutex_trylock(¬es->lock)) + if (pthread_mutex_trylock(&syme->src->lock)) return; - ip = syme->map->map_ip(syme->map, ip); - symbol__inc_addr_samples(sym, syme->map, counter, ip); + if (syme->src == NULL || syme->src->source == NULL) + goto out_unlock; - pthread_mutex_unlock(¬es->lock); + for (line = syme->src->lines; line; line = line->next) { + /* skip lines without IP info */ + if (line->eip == 0) + continue; + if (line->eip == ip) { + line->count[counter]++; + break; + } + if (line->eip > ip) + break; + } +out_unlock: + pthread_mutex_unlock(&syme->src->lock); } +#define PATTERN_LEN (BITS_PER_LONG / 4 + 2) + +static void lookup_sym_source(struct sym_entry *syme) +{ + struct symbol *symbol = sym_entry__symbol(syme); + struct source_line *line; + char pattern[PATTERN_LEN + 1]; + + sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4, + map__rip_2objdump(syme->map, symbol->start)); + + pthread_mutex_lock(&syme->src->lock); + for (line = syme->src->lines; line; line = line->next) { + if (memcmp(line->line, pattern, PATTERN_LEN) == 0) { + syme->src->source = line; + break; + } + } + pthread_mutex_unlock(&syme->src->lock); +} + +static void show_lines(struct source_line *queue, int count, int total) +{ + int i; + struct source_line *line; + + line = queue; + for (i = 0; i < count; i++) { + float pcnt = 100.0*(float)line->count[sym_counter]/(float)total; + + printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); + line = line->next; + } +} + +#define TRACE_COUNT 3 + static void show_details(struct sym_entry *syme) { - struct annotation *notes; struct symbol *symbol; - int more; + struct source_line *line; + struct source_line *line_queue = NULL; + int displayed = 0; + int line_queue_count = 0, total = 0, more = 0; if (!syme) return; - symbol = sym_entry__symbol(syme); - notes = symbol__annotation(symbol); - - pthread_mutex_lock(¬es->lock); + if (!syme->src->source) + lookup_sym_source(syme); - if (notes->src == NULL) - goto out_unlock; + if (!syme->src->source) + return; - printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); + symbol = sym_entry__symbol(syme); + printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); - more = symbol__annotate_printf(symbol, syme->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); - if (more != 0) + pthread_mutex_lock(&syme->src->lock); + line = syme->src->source; + while (line) { + total += line->count[sym_counter]; + line = line->next; + } + + line = syme->src->source; + while (line) { + float pcnt = 0.0; + + if (!line_queue_count) + line_queue = line; + line_queue_count++; + + if (line->count[sym_counter]) + pcnt = 100.0 * line->count[sym_counter] / (float)total; + if (pcnt >= (float)sym_pcnt_filter) { + if (displayed <= print_entries) + show_lines(line_queue, line_queue_count, total); + else more++; + displayed += line_queue_count; + line_queue_count = 0; + line_queue = NULL; + } else if (line_queue_count > TRACE_COUNT) { + line_queue = line_queue->next; + line_queue_count--; + } + + line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; + line = line->next; + } + pthread_mutex_unlock(&syme->src->lock); + if (more) printf("%d lines not displayed, maybe increase display entries [e]\n", more); -out_unlock: - pthread_mutex_unlock(¬es->lock); } +/* + * Symbols will be added here in event__process_sample and will get out + * after decayed. + */ +static LIST_HEAD(active_symbols); +static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; + +/* + * Ordering weight: count-1 * count-2 * ... / count-n + */ +static double sym_weight(const struct sym_entry *sym) +{ + double weight = sym->snap_count; + int counter; + + if (!display_weighted) + return weight; + + for (counter = 1; counter < nr_counters-1; counter++) + weight *= sym->count[counter]; + + weight /= (sym->count[counter] + 1); + + return weight; +} + +static long samples; +static long kernel_samples, us_samples; +static long exact_samples; +static long guest_us_samples, guest_kernel_samples; static const char CONSOLE_CLEAR[] = ""; static void __list_insert_active_sym(struct sym_entry *syme) { - list_add(&syme->node, &top.active_symbols); + list_add(&syme->node, &active_symbols); } -static void print_sym_table(struct perf_session *session) +static void list_remove_active_sym(struct sym_entry *syme) { - char bf[160]; - int printed = 0; - struct rb_node *nd; - struct sym_entry *syme; + pthread_mutex_lock(&active_symbols_lock); + list_del_init(&syme->node); + pthread_mutex_unlock(&active_symbols_lock); +} + +static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) +{ + struct rb_node **p = &tree->rb_node; + struct rb_node *parent = NULL; + struct sym_entry *iter; + + while (*p != NULL) { + parent = *p; + iter = rb_entry(parent, struct sym_entry, rb_node); + + if (se->weight > iter->weight) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&se->rb_node, parent, p); + rb_insert_color(&se->rb_node, tree); +} + +static void print_sym_table(void) +{ + int printed = 0, j; + struct perf_evsel *counter; + int snap = !display_weighted ? sym_counter : 0; + float samples_per_sec = samples/delay_secs; + float ksamples_per_sec = kernel_samples/delay_secs; + float us_samples_per_sec = (us_samples)/delay_secs; + float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs; + float guest_us_samples_per_sec = (guest_us_samples)/delay_secs; + float esamples_percent = (100.0*exact_samples)/samples; + float sum_ksamples = 0.0; + struct sym_entry *syme, *n; struct rb_root tmp = RB_ROOT; + struct rb_node *nd; + int sym_width = 0, dso_width = 0, dso_short_width = 0; const int win_width = winsize.ws_col - 1; - int sym_width, dso_width, dso_short_width; - float sum_ksamples = perf_top__decay_samples(&top, &tmp); - puts(CONSOLE_CLEAR); + samples = us_samples = kernel_samples = exact_samples = 0; + guest_kernel_samples = guest_us_samples = 0; - perf_top__header_snprintf(&top, bf, sizeof(bf)); - printf("%s\n", bf); + /* Sort the active symbols */ + pthread_mutex_lock(&active_symbols_lock); + syme = list_entry(active_symbols.next, struct sym_entry, node); + pthread_mutex_unlock(&active_symbols_lock); - perf_top__reset_sample_counters(&top); + list_for_each_entry_safe_from(syme, n, &active_symbols, node) { + syme->snap_count = syme->count[snap]; + if (syme->snap_count != 0) { + + if ((hide_user_symbols && + syme->origin == PERF_RECORD_MISC_USER) || + (hide_kernel_symbols && + syme->origin == PERF_RECORD_MISC_KERNEL)) { + list_remove_active_sym(syme); + continue; + } + syme->weight = sym_weight(syme); + rb_insert_active_sym(&tmp, syme); + sum_ksamples += syme->snap_count; + + for (j = 0; j < nr_counters; j++) + syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; + } else + list_remove_active_sym(syme); + } + + puts(CONSOLE_CLEAR); printf("%-*.*s\n", win_width, win_width, graph_dotted_line); + if (!perf_guest) { + printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%" + " exact: %4.1f%% [", + samples_per_sec, + 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / + samples_per_sec)), + esamples_percent); + } else { + printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" + " guest kernel:%4.1f%% guest us:%4.1f%%" + " exact: %4.1f%% [", + samples_per_sec, + 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) / + samples_per_sec)), + 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) / + samples_per_sec)), + 100.0 - (100.0 * ((samples_per_sec - + guest_kernel_samples_per_sec) / + samples_per_sec)), + 100.0 - (100.0 * ((samples_per_sec - + guest_us_samples_per_sec) / + samples_per_sec)), + esamples_percent); + } + + if (nr_counters == 1 || !display_weighted) { + struct perf_evsel *first; + first = list_entry(evsel_list.next, struct perf_evsel, node); + printf("%" PRIu64, (uint64_t)first->attr.sample_period); + if (freq) + printf("Hz "); + else + printf(" "); + } + + if (!display_weighted) + printf("%s", event_name(sym_evsel)); + else list_for_each_entry(counter, &evsel_list, node) { + if (counter->idx) + printf("/"); - if (session->hists.stats.total_lost != 0) { - color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); - printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", - session->hists.stats.total_lost); + printf("%s", event_name(counter)); } - if (top.sym_filter_entry) { - show_details(top.sym_filter_entry); + printf( "], "); + + if (target_pid != -1) + printf(" (target_pid: %d", target_pid); + else if (target_tid != -1) + printf(" (target_tid: %d", target_tid); + else + printf(" (all"); + + if (cpu_list) + printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list); + else { + if (target_tid != -1) + printf(")\n"); + else + printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : ""); + } + + printf("%-*.*s\n", win_width, win_width, graph_dotted_line); + + if (sym_filter_entry) { + show_details(sym_filter_entry); return; } - perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, - &sym_width); + /* + * Find the longest symbol name that will be displayed + */ + for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { + syme = rb_entry(nd, struct sym_entry, rb_node); + if (++printed > print_entries || + (int)syme->snap_count < count_filter) + continue; + + if (syme->map->dso->long_name_len > dso_width) + dso_width = syme->map->dso->long_name_len; + + if (syme->map->dso->short_name_len > dso_short_width) + dso_short_width = syme->map->dso->short_name_len; + + if (syme->name_len > sym_width) + sym_width = syme->name_len; + } + + printed = 0; if (sym_width + dso_width > winsize.ws_col - 29) { dso_width = dso_short_width; @@ -290,7 +606,7 @@ static void print_sym_table(struct perf_session *session) sym_width = winsize.ws_col - dso_width - 29; } putchar('\n'); - if (top.evlist->nr_entries == 1) + if (nr_counters == 1) printf(" samples pcnt"); else printf(" weight samples pcnt"); @@ -299,7 +615,7 @@ static void print_sym_table(struct perf_session *session) printf(" RIP "); printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); printf(" %s _______ _____", - top.evlist->nr_entries == 1 ? " " : "______"); + nr_counters == 1 ? " " : "______"); if (verbose) printf(" ________________"); printf(" %-*.*s", sym_width, sym_width, graph_line); @@ -312,14 +628,13 @@ static void print_sym_table(struct perf_session *session) syme = rb_entry(nd, struct sym_entry, rb_node); sym = sym_entry__symbol(syme); - if (++printed > top.print_entries || - (int)syme->snap_count < top.count_filter) + if (++printed > print_entries || (int)syme->snap_count < count_filter) continue; pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / sum_ksamples)); - if (top.evlist->nr_entries == 1 || !top.display_weighted) + if (nr_counters == 1 || !display_weighted) printf("%20.2f ", syme->weight); else printf("%9.1f %10ld ", syme->weight, syme->snap_count); @@ -378,8 +693,10 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) /* zero counters of active symbol */ if (syme) { + pthread_mutex_lock(&syme->src->lock); __zero_source_counters(syme); *target = NULL; + pthread_mutex_unlock(&syme->src->lock); } fprintf(stdout, "\n%s: ", msg); @@ -390,11 +707,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) if (p) *p = 0; - pthread_mutex_lock(&top.active_symbols_lock); - syme = list_entry(top.active_symbols.next, struct sym_entry, node); - pthread_mutex_unlock(&top.active_symbols_lock); + pthread_mutex_lock(&active_symbols_lock); + syme = list_entry(active_symbols.next, struct sym_entry, node); + pthread_mutex_unlock(&active_symbols_lock); - list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { + list_for_each_entry_safe_from(syme, n, &active_symbols, node) { struct symbol *sym = sym_entry__symbol(syme); if (!strcmp(buf, sym->name)) { @@ -418,34 +735,34 @@ static void print_mapped_keys(void) { char *name = NULL; - if (top.sym_filter_entry) { - struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); + if (sym_filter_entry) { + struct symbol *sym = sym_entry__symbol(sym_filter_entry); 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", delay_secs); + fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); - if (top.evlist->nr_entries > 1) - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel)); + if (nr_counters > 1) + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(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", count_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"); - if (top.evlist->nr_entries > 1) - fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0); + if (nr_counters > 1) + fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); fprintf(stdout, "\t[K] hide kernel_symbols symbols. \t(%s)\n", - top.hide_kernel_symbols ? "yes" : "no"); + 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); + hide_user_symbols ? "yes" : "no"); + fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); fprintf(stdout, "\t[qQ] quit.\n"); } @@ -466,7 +783,7 @@ static int key_mapped(int c) return 1; case 'E': case 'w': - return top.evlist->nr_entries > 1 ? 1 : 0; + return nr_counters > 1 ? 1 : 0; default: break; } @@ -501,47 +818,47 @@ static void handle_keypress(struct perf_session *session, int c) switch (c) { case 'd': - prompt_integer(&top.delay_secs, "Enter display delay"); - if (top.delay_secs < 1) - top.delay_secs = 1; + prompt_integer(&delay_secs, "Enter display delay"); + if (delay_secs < 1) + delay_secs = 1; break; case 'e': - prompt_integer(&top.print_entries, "Enter display entries (lines)"); - if (top.print_entries == 0) { + prompt_integer(&print_entries, "Enter display entries (lines)"); + if (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 (nr_counters > 1) { 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(sym_evsel, &evsel_list, node) + fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); - prompt_integer(&top.sym_counter, "Enter details event counter"); + prompt_integer(&sym_counter, "Enter details event counter"); - if (top.sym_counter >= top.evlist->nr_entries) { - top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); - top.sym_counter = 0; - fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); + if (sym_counter >= nr_counters) { + sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); + sym_counter = 0; + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); sleep(1); break; } - list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) - if (top.sym_evsel->idx == top.sym_counter) + list_for_each_entry(sym_evsel, &evsel_list, node) + if (sym_evsel->idx == sym_counter) break; - } else top.sym_counter = 0; + } else sym_counter = 0; break; case 'f': - prompt_integer(&top.count_filter, "Enter display event count filter"); + prompt_integer(&count_filter, "Enter display event count filter"); break; case 'F': prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); break; case 'K': - top.hide_kernel_symbols = !top.hide_kernel_symbols; + hide_kernel_symbols = !hide_kernel_symbols; break; case 'q': case 'Q': @@ -550,50 +867,34 @@ static void handle_keypress(struct perf_session *session, int c) perf_session__fprintf_dsos(session, stderr); exit(0); case 's': - prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); + prompt_symbol(&sym_filter_entry, "Enter details symbol"); break; case 'S': - if (!top.sym_filter_entry) + if (!sym_filter_entry) break; else { - struct sym_entry *syme = top.sym_filter_entry; + struct sym_entry *syme = sym_filter_entry; - top.sym_filter_entry = NULL; + pthread_mutex_lock(&syme->src->lock); + sym_filter_entry = NULL; __zero_source_counters(syme); + pthread_mutex_unlock(&syme->src->lock); } break; case 'U': - top.hide_user_symbols = !top.hide_user_symbols; + hide_user_symbols = !hide_user_symbols; break; case 'w': - top.display_weighted = ~top.display_weighted; + display_weighted = ~display_weighted; break; case 'z': - top.zero = !top.zero; + zero = !zero; break; default: break; } } -static void *display_thread_tui(void *arg __used) -{ - int err = 0; - pthread_mutex_lock(&top.active_symbols_lock); - while (list_empty(&top.active_symbols)) { - err = pthread_cond_wait(&top.active_symbols_cond, - &top.active_symbols_lock); - if (err) - break; - } - pthread_mutex_unlock(&top.active_symbols_lock); - if (!err) - perf_top__tui_browser(&top); - exit_browser(0); - exit(0); - return NULL; -} - static void *display_thread(void *arg __used) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; @@ -608,13 +909,13 @@ static void *display_thread(void *arg __used) tc.c_cc[VTIME] = 0; repeat: - delay_msecs = top.delay_secs * 1000; + delay_msecs = delay_secs * 1000; tcsetattr(0, TCSANOW, &tc); /* trash return*/ getc(stdin); do { - print_sym_table(session); + print_sym_table(); } while (!poll(&stdin_poll, 1, delay_msecs) == 1); c = getc(stdin); @@ -629,7 +930,6 @@ static void *display_thread(void *arg __used) /* Tag samples to be skipped. */ static const char *skip_symbols[] = { "default_idle", - "native_safe_halt", "cpu_idle", "enter_idle", "exit_idle", @@ -665,9 +965,9 @@ static int symbol_filter(struct map *map, struct symbol *sym) syme = symbol__priv(sym); syme->map = map; - symbol__annotate_init(map, sym); + syme->src = NULL; - if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { + if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { /* schedule initial sym_filter_entry setup */ sym_filter_entry_sched = syme; sym_filter = NULL; @@ -680,40 +980,44 @@ static int symbol_filter(struct map *map, struct symbol *sym) } } + if (!syme->skip) + syme->name_len = strlen(sym->name); + return 0; } -static void perf_event__process_sample(const union perf_event *event, - struct perf_sample *sample, - struct perf_session *session) +static void event__process_sample(const event_t *self, + struct sample_data *sample, + struct perf_session *session, + struct perf_evsel *evsel) { - u64 ip = event->ip.ip; + u64 ip = self->ip.ip; struct sym_entry *syme; struct addr_location al; struct machine *machine; - u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - ++top.samples; + ++samples; switch (origin) { case PERF_RECORD_MISC_USER: - ++top.us_samples; - if (top.hide_user_symbols) + ++us_samples; + if (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) + ++kernel_samples; + if (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); + ++guest_kernel_samples; + machine = perf_session__find_machine(session, self->ip.pid); break; case PERF_RECORD_MISC_GUEST_USER: - ++top.guest_us_samples; + ++guest_us_samples; /* * TODO: we don't process guest user from host side * except simple counting. @@ -725,15 +1029,15 @@ static void perf_event__process_sample(const union perf_event *event, if (!machine && perf_guest) { pr_err("Can't find guest [%d]'s kernel information\n", - event->ip.pid); + self->ip.pid); return; } - if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) - top.exact_samples++; + if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) + exact_samples++; - if (perf_event__preprocess_sample(event, session, &al, sample, - symbol_filter) < 0 || + if (event__preprocess_sample(self, session, &al, sample, + symbol_filter) < 0 || al.filtered) return; @@ -751,9 +1055,8 @@ static void perf_event__process_sample(const union perf_event *event, */ if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { - ui__warning("The %s file can't be used\n", - symbol_conf.vmlinux_name); - exit_browser(0); + pr_err("The %s file can't be used\n", + symbol_conf.vmlinux_name); exit(1); } @@ -762,13 +1065,13 @@ static void perf_event__process_sample(const union perf_event *event, /* let's see, whether we need to install initial sym_filter_entry */ if (sym_filter_entry_sched) { - top.sym_filter_entry = sym_filter_entry_sched; + sym_filter_entry = sym_filter_entry_sched; sym_filter_entry_sched = NULL; - if (parse_source(top.sym_filter_entry) < 0) { - struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); + if (parse_source(sym_filter_entry) < 0) { + struct symbol *sym = sym_entry__symbol(sym_filter_entry); pr_err("Can't annotate %s", sym->name); - if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { + if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { pr_err(": No vmlinux file was found in the path:\n"); machine__fprintf_vmlinux_path(machine, stderr); } else @@ -779,73 +1082,166 @@ static void perf_event__process_sample(const union perf_event *event, syme = symbol__priv(al.sym); if (!syme->skip) { - struct perf_evsel *evsel; - - syme->origin = origin; - evsel = perf_evlist__id2evsel(top.evlist, sample->id); - assert(evsel != NULL); syme->count[evsel->idx]++; + syme->origin = origin; record_precise_ip(syme, evsel->idx, ip); - pthread_mutex_lock(&top.active_symbols_lock); - if (list_empty(&syme->node) || !syme->node.next) { - static bool first = true; + pthread_mutex_lock(&active_symbols_lock); + if (list_empty(&syme->node) || !syme->node.next) __list_insert_active_sym(syme); - if (first) { - pthread_cond_broadcast(&top.active_symbols_cond); - first = false; - } - } - pthread_mutex_unlock(&top.active_symbols_lock); + pthread_mutex_unlock(&active_symbols_lock); } } -static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) +struct mmap_data { + void *base; + int mask; + unsigned int prev; +}; + +static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel, + int ncpus, int nthreads) +{ + evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data)); + return evsel->priv != NULL ? 0 : -ENOMEM; +} + +static void perf_evsel__free_mmap(struct perf_evsel *evsel) +{ + xyarray__delete(evsel->priv); + evsel->priv = NULL; +} + +static unsigned int mmap_read_head(struct mmap_data *md) +{ + struct perf_event_mmap_page *pc = md->base; + int head; + + head = pc->data_head; + rmb(); + + return head; +} + +static void perf_session__mmap_read_counter(struct perf_session *self, + struct perf_evsel *evsel, + int cpu, int thread_idx) { - struct perf_sample sample; - union perf_event *event; + struct xyarray *mmap_array = evsel->priv; + struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); + unsigned int head = mmap_read_head(md); + unsigned int old = md->prev; + unsigned char *data = md->base + page_size; + struct sample_data sample; + int diff; + + /* + * If we're further behind than half the buffer, there's a chance + * the writer will bite our tail and mess up the samples under us. + * + * If we somehow ended up ahead of the head, we got messed up. + * + * In either case, truncate and restart at head. + */ + diff = head - old; + if (diff > md->mask / 2 || diff < 0) { + fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); + + /* + * head points to a known good entry, start there. + */ + old = head; + } + + for (; old != head;) { + event_t *event = (event_t *)&data[old & md->mask]; + + event_t event_copy; - while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) { - perf_session__parse_sample(self, event, &sample); + size_t size = event->header.size; + /* + * Event straddles the mmap boundary -- header should always + * be inside due to u64 alignment of output. + */ + if ((old & md->mask) + size != ((old + size) & md->mask)) { + unsigned int offset = old; + unsigned int len = min(sizeof(*event), size), cpy; + void *dst = &event_copy; + + do { + cpy = min(md->mask + 1 - (offset & md->mask), len); + memcpy(dst, &data[offset & md->mask], cpy); + offset += cpy; + dst += cpy; + len -= cpy; + } while (len); + + event = &event_copy; + } + + event__parse_sample(event, self, &sample); if (event->header.type == PERF_RECORD_SAMPLE) - perf_event__process_sample(event, &sample, self); + event__process_sample(event, &sample, self, evsel); else - perf_event__process(event, &sample, self); + event__process(event, &sample, self); + old += size; } + + md->prev = old; } +static struct pollfd *event_array; + static void perf_session__mmap_read(struct perf_session *self) { - int i; - - for (i = 0; i < top.evlist->cpus->nr; i++) - perf_session__mmap_read_cpu(self, i); + struct perf_evsel *counter; + int i, thread_index; + + for (i = 0; i < cpus->nr; i++) { + list_for_each_entry(counter, &evsel_list, node) { + for (thread_index = 0; + thread_index < threads->nr; + thread_index++) { + perf_session__mmap_read_counter(self, + counter, i, thread_index); + } + } + } } -static void start_counters(struct perf_evlist *evlist) +int nr_poll; +int group_fd; + +static void start_counter(int i, struct perf_evsel *evsel) { - struct perf_evsel *counter; + struct xyarray *mmap_array = evsel->priv; + struct mmap_data *mm; + struct perf_event_attr *attr; + int cpu = -1; + int thread_index; - list_for_each_entry(counter, &evlist->entries, node) { - struct perf_event_attr *attr = &counter->attr; + if (target_tid == -1) + cpu = cpus->map[i]; - attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + attr = &evsel->attr; - if (top.freq) { - attr->sample_type |= PERF_SAMPLE_PERIOD; - attr->freq = 1; - attr->sample_freq = top.freq; - } + attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; - if (evlist->nr_entries > 1) { - attr->sample_type |= PERF_SAMPLE_ID; - attr->read_format |= PERF_FORMAT_ID; - } + if (freq) { + attr->sample_type |= PERF_SAMPLE_PERIOD; + attr->freq = 1; + attr->sample_freq = freq; + } - attr->mmap = 1; + attr->inherit = (cpu < 0) && inherit; + attr->mmap = 1; + + for (thread_index = 0; thread_index < threads->nr; thread_index++) { try_again: - if (perf_evsel__open(counter, top.evlist->cpus, - top.evlist->threads, group, inherit) < 0) { + FD(evsel, i, thread_index) = sys_perf_event_open(attr, + threads->map[thread_index], cpu, group_fd, 0); + + if (FD(evsel, i, thread_index) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -857,8 +1253,8 @@ static void start_counters(struct perf_evlist *evlist) * based cpu-clock-tick sw counter, which * is always available even if no PMU support: */ - if (attr->type == PERF_TYPE_HARDWARE && - attr->config == PERF_COUNT_HW_CPU_CYCLES) { + if (attr->type == PERF_TYPE_HARDWARE + && attr->config == PERF_COUNT_HW_CPU_CYCLES) { if (verbose) warning(" ... trying to fall back to cpu-clock-ticks\n"); @@ -868,23 +1264,39 @@ static void start_counters(struct perf_evlist *evlist) goto try_again; } printf("\n"); - error("sys_perf_event_open() syscall returned with %d " - "(%s). /bin/dmesg may provide additional information.\n", - err, strerror(err)); + error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", + FD(evsel, i, thread_index), strerror(err)); die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); } - } + assert(FD(evsel, i, thread_index) >= 0); + fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); - if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) - die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + /* + * First counter acts as the group leader: + */ + if (group && group_fd == -1) + group_fd = FD(evsel, i, thread_index); + + event_array[nr_poll].fd = FD(evsel, i, thread_index); + event_array[nr_poll].events = POLLIN; + nr_poll++; + + mm = xyarray__entry(mmap_array, i, thread_index); + mm->prev = 0; + mm->mask = mmap_pages*page_size - 1; + mm->base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); + if (mm->base == MAP_FAILED) + die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + } } static int __cmd_top(void) { pthread_t thread; - struct perf_evsel *first; - int ret __used; + struct perf_evsel *counter; + int i, ret; /* * 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. @@ -893,23 +1305,23 @@ static int __cmd_top(void) if (session == NULL) return -ENOMEM; - if (top.target_tid != -1) - perf_event__synthesize_thread_map(top.evlist->threads, - perf_event__process, session); + if (target_tid != -1) + event__synthesize_thread_map(threads, event__process, session); else - perf_event__synthesize_threads(perf_event__process, session); + event__synthesize_threads(event__process, session); - start_counters(top.evlist); - first = list_entry(top.evlist->entries.next, struct perf_evsel, node); - perf_session__set_sample_type(session, first->attr.sample_type); + for (i = 0; i < cpus->nr; i++) { + group_fd = -1; + list_for_each_entry(counter, &evsel_list, node) + start_counter(i, counter); + } /* Wait for a minimal set of events before starting the snapshot */ - poll(top.evlist->pollfd, top.evlist->nr_fds, 100); + poll(&event_array[0], nr_poll, 100); perf_session__mmap_read(session); - if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : - display_thread), session)) { + if (pthread_create(&thread, NULL, display_thread, session)) { printf("Could not create display thread.\n"); exit(-1); } @@ -925,12 +1337,12 @@ static int __cmd_top(void) } while (1) { - u64 hits = top.samples; + int hits = samples; perf_session__mmap_read(session); - if (hits == top.samples) - ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); + if (hits == samples) + ret = poll(event_array, nr_poll, 100); } return 0; @@ -942,31 +1354,31 @@ static const char * const top_usage[] = { }; static const struct option options[] = { - OPT_CALLBACK('e', "event", &top.evlist, "event", + OPT_CALLBACK('e', "event", NULL, "event", "event selector. use 'perf list' to list available events", parse_events), OPT_INTEGER('c', "count", &default_interval, "event period to sample"), - OPT_INTEGER('p', "pid", &top.target_pid, + OPT_INTEGER('p', "pid", &target_pid, "profile events on existing process id"), - OPT_INTEGER('t', "tid", &top.target_tid, + OPT_INTEGER('t', "tid", &target_tid, "profile events on existing thread id"), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), - OPT_STRING('C', "cpu", &top.cpu_list, "cpu", + OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to monitor"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), - OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, + OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, "hide kernel symbols"), 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, + OPT_INTEGER('d', "delay", &delay_secs, "number of seconds to delay between refreshes"), OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, "dump the symbol table used for profiling"), - OPT_INTEGER('f', "count-filter", &top.count_filter, + OPT_INTEGER('f', "count-filter", &count_filter, "only display functions with more events than this"), OPT_BOOLEAN('g', "group", &group, "put the counters into a counter group"), @@ -974,16 +1386,14 @@ static const struct option options[] = { "child tasks inherit counters"), OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", "symbol to annotate"), - OPT_BOOLEAN('z', "zero", &top.zero, + OPT_BOOLEAN('z', "zero", &zero, "zero history across updates"), - OPT_INTEGER('F', "freq", &top.freq, + OPT_INTEGER('F', "freq", &freq, "profile at this frequency"), - OPT_INTEGER('E', "entries", &top.print_entries, + OPT_INTEGER('E', "entries", &print_entries, "display this many functions"), - OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, + OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, "hide user symbols"), - 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_END() @@ -994,68 +1404,64 @@ 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) - return -ENOMEM; - page_size = sysconf(_SC_PAGE_SIZE); argc = parse_options(argc, argv, options, top_usage, 0); if (argc) usage_with_options(top_usage, options); - /* - * XXX For now start disabled, only using TUI if explicitely asked for. - * Change that when handle_keys equivalent gets written, live annotation - * done, etc. - */ - use_browser = 0; + if (target_pid != -1) + target_tid = target_pid; - if (use_stdio) - use_browser = 0; - else if (use_tui) - use_browser = 1; + threads = thread_map__new(target_pid, target_tid); + if (threads == NULL) { + pr_err("Problems finding threads of monitor\n"); + usage_with_options(top_usage, options); + } - setup_browser(false); + event_array = malloc((sizeof(struct pollfd) * + MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); + if (!event_array) + return -ENOMEM; /* CPU and PID are mutually exclusive */ - if (top.target_tid > 0 && top.cpu_list) { + if (target_tid > 0 && cpu_list) { printf("WARNING: PID switch overriding CPU\n"); sleep(1); - top.cpu_list = NULL; + cpu_list = NULL; } - if (top.target_pid != -1) - top.target_tid = top.target_pid; - - if (perf_evlist__create_maps(top.evlist, top.target_pid, - top.target_tid, top.cpu_list) < 0) - usage_with_options(top_usage, options); - - if (!top.evlist->nr_entries && - perf_evlist__add_default(top.evlist) < 0) { + if (!nr_counters && perf_evsel_list__create_default() < 0) { pr_err("Not enough memory for event selector list\n"); return -ENOMEM; } - if (top.delay_secs < 1) - top.delay_secs = 1; + if (delay_secs < 1) + delay_secs = 1; /* * User specified count overrides default frequency. */ if (default_interval) - top.freq = 0; - else if (top.freq) { - default_interval = top.freq; + freq = 0; + else if (freq) { + default_interval = 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) + if (target_tid != -1) + cpus = cpu_map__dummy_new(); + else + cpus = cpu_map__new(cpu_list); + + if (cpus == NULL) + usage_with_options(top_usage, options); + + list_for_each_entry(pos, &evsel_list, node) { + if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || + perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: @@ -1066,28 +1472,26 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) 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); + sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); - symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + - (top.evlist->nr_entries + 1) * sizeof(unsigned long)); + symbol_conf.priv_size = (sizeof(struct sym_entry) + + (nr_counters + 1) * sizeof(unsigned long)); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init() < 0) return -1; get_term_dimensions(&winsize); - if (top.print_entries == 0) { + if (print_entries == 0) { update_print_entries(&winsize); signal(SIGWINCH, sig_winch_handler); } status = __cmd_top(); out_free_fd: - perf_evlist__delete(top.evlist); + list_for_each_entry(pos, &evsel_list, node) + perf_evsel__free_mmap(pos); + perf_evsel_list__delete(); return status; } diff --git a/trunk/tools/perf/perf.h b/trunk/tools/perf/perf.h index a5fc660c1f12..95aaf565c704 100644 --- a/trunk/tools/perf/perf.h +++ b/trunk/tools/perf/perf.h @@ -94,32 +94,6 @@ void get_term_dimensions(struct winsize *ws); #include "util/types.h" #include -struct perf_mmap { - void *base; - int mask; - unsigned int prev; -}; - -static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm) -{ - struct perf_event_mmap_page *pc = mm->base; - int head = pc->data_head; - rmb(); - return head; -} - -static inline void perf_mmap__write_tail(struct perf_mmap *md, - unsigned long tail) -{ - struct perf_event_mmap_page *pc = md->base; - - /* - * ensure all reads are done before we write the tail out. - */ - /* mb(); */ - pc->data_tail = tail; -} - /* * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all * counters in the current task. diff --git a/trunk/tools/perf/python/twatch.py b/trunk/tools/perf/python/twatch.py deleted file mode 100755 index df638c438a9f..000000000000 --- a/trunk/tools/perf/python/twatch.py +++ /dev/null @@ -1,41 +0,0 @@ -#! /usr/bin/python -# -*- python -*- -# -*- coding: utf-8 -*- -# twatch - Experimental use of the perf python interface -# Copyright (C) 2011 Arnaldo Carvalho de Melo -# -# This application 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; version 2. -# -# This application 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. - -import perf - -def main(): - cpus = perf.cpu_map() - threads = perf.thread_map() - evsel = perf.evsel(task = 1, comm = 1, mmap = 0, - wakeup_events = 1, sample_period = 1, - sample_id_all = 1, - sample_type = perf.SAMPLE_PERIOD | perf.SAMPLE_TID | perf.SAMPLE_CPU | perf.SAMPLE_TID) - evsel.open(cpus = cpus, threads = threads); - evlist = perf.evlist(cpus, threads) - evlist.add(evsel) - evlist.mmap() - while True: - evlist.poll(timeout = -1) - for cpu in cpus: - event = evlist.read_on_cpu(cpu) - if not event: - continue - print "cpu: %2d, pid: %4d, tid: %4d" % (event.sample_cpu, - event.sample_pid, - event.sample_tid), - print event - -if __name__ == '__main__': - main() diff --git a/trunk/tools/perf/util/annotate.c b/trunk/tools/perf/util/annotate.c deleted file mode 100644 index 0d0830c98cd7..000000000000 --- a/trunk/tools/perf/util/annotate.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo - * - * Parts came from builtin-annotate.c, see those files for further - * copyright notes. - * - * Released under the GPL v2. (and only v2, not any later version) - */ - -#include "util.h" -#include "build-id.h" -#include "color.h" -#include "cache.h" -#include "symbol.h" -#include "debug.h" -#include "annotate.h" -#include - -int symbol__annotate_init(struct map *map __used, struct symbol *sym) -{ - struct annotation *notes = symbol__annotation(sym); - pthread_mutex_init(¬es->lock, NULL); - return 0; -} - -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) + nevents * sizeof_sym_hist); - if (notes->src == NULL) - return -1; - notes->src->sizeof_sym_hist = sizeof_sym_hist; - notes->src->nr_histograms = nevents; - INIT_LIST_HEAD(¬es->src->source); - return 0; -} - -void symbol__annotate_zero_histograms(struct symbol *sym) -{ - struct annotation *notes = symbol__annotation(sym); - - pthread_mutex_lock(¬es->lock); - if (notes->src != NULL) - memset(notes->src->histograms, 0, - notes->src->nr_histograms * notes->src->sizeof_sym_hist); - pthread_mutex_unlock(¬es->lock); -} - -int symbol__inc_addr_samples(struct symbol *sym, struct map *map, - int evidx, u64 addr) -{ - unsigned offset; - struct annotation *notes; - struct sym_hist *h; - - notes = symbol__annotation(sym); - if (notes->src == NULL) - return -ENOMEM; - - pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - - if (addr >= sym->end) - return 0; - - offset = addr - sym->start; - h = annotation__histogram(notes, evidx); - h->sum++; - h->addr[offset]++; - - pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 - ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, - addr, addr - sym->start, evidx, h->addr[offset]); - return 0; -} - -static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) -{ - struct objdump_line *self = malloc(sizeof(*self) + privsize); - - if (self != NULL) { - self->offset = offset; - self->line = line; - } - - return self; -} - -void objdump_line__free(struct objdump_line *self) -{ - free(self->line); - free(self); -} - -static void objdump__add_line(struct list_head *head, struct objdump_line *line) -{ - list_add_tail(&line->node, head); -} - -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, - struct objdump_line *pos) -{ - list_for_each_entry_continue(pos, head, node) - if (pos->offset >= 0) - return pos; - - return NULL; -} - -static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, - int evidx, u64 len, int min_pcnt, - int printed, int max_lines, - struct objdump_line *queue) -{ - static const char *prev_line; - static const char *prev_color; - - if (oline->offset != -1) { - const char *path = NULL; - unsigned int hits = 0; - double percent = 0.0; - const char *color; - struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src->lines; - struct sym_hist *h = annotation__histogram(notes, evidx); - s64 offset = oline->offset; - struct objdump_line *next; - - next = objdump__get_next_ip_line(¬es->src->source, oline); - - while (offset < (s64)len && - (next == NULL || offset < next->offset)) { - if (src_line) { - if (path == NULL) - path = src_line[offset].path; - percent += src_line[offset].percent; - } else - hits += h->addr[offset]; - - ++offset; - } - - if (src_line == NULL && h->sum) - percent = 100.0 * hits / h->sum; - - if (percent < min_pcnt) - return -1; - - if (max_lines && printed >= max_lines) - return 1; - - if (queue != NULL) { - list_for_each_entry_from(queue, ¬es->src->source, node) { - if (queue == oline) - break; - objdump_line__print(queue, sym, evidx, len, - 0, 0, 1, NULL); - } - } - - color = get_percent_color(percent); - - /* - * Also color the filename and line if needed, with - * the same color than the percentage. Don't print it - * twice for close colored addr with the same filename:line - */ - if (path) { - if (!prev_line || strcmp(prev_line, path) - || color != prev_color) { - color_fprintf(stdout, color, " %s", path); - prev_line = path; - prev_color = color; - } - } - - color_fprintf(stdout, color, " %7.2f", percent); - printf(" : "); - color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); - } else if (max_lines && printed >= max_lines) - return 1; - else { - if (queue) - return -1; - - if (!*oline->line) - printf(" :\n"); - else - printf(" : %s\n", oline->line); - } - - return 0; -} - -static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, - FILE *file, size_t privsize) -{ - struct annotation *notes = symbol__annotation(sym); - struct objdump_line *objdump_line; - char *line = NULL, *tmp, *tmp2, *c; - size_t line_len; - s64 line_ip, offset = -1; - - if (getline(&line, &line_len, file) < 0) - return -1; - - if (!line) - return -1; - - while (line_len != 0 && isspace(line[line_len - 1])) - line[--line_len] = '\0'; - - c = strchr(line, '\n'); - if (c) - *c = 0; - - line_ip = -1; - - /* - * Strip leading spaces: - */ - tmp = line; - while (*tmp) { - if (*tmp != ' ') - break; - tmp++; - } - - if (*tmp) { - /* - * Parse hexa addresses followed by ':' - */ - line_ip = strtoull(tmp, &tmp2, 16); - if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0') - line_ip = -1; - } - - if (line_ip != -1) { - u64 start = map__rip_2objdump(map, sym->start), - end = map__rip_2objdump(map, sym->end); - - offset = line_ip - start; - if (offset < 0 || (u64)line_ip > end) - offset = -1; - } - - objdump_line = objdump_line__new(offset, line, privsize); - if (objdump_line == NULL) { - free(line); - return -1; - } - objdump__add_line(¬es->src->source, objdump_line); - - return 0; -} - -int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) -{ - struct dso *dso = map->dso; - char *filename = dso__build_id_filename(dso, NULL, 0); - bool free_filename = true; - char command[PATH_MAX * 2]; - FILE *file; - int err = 0; - char symfs_filename[PATH_MAX]; - - if (filename) { - snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", - symbol_conf.symfs, filename); - } - - if (filename == NULL) { - if (dso->has_build_id) { - pr_err("Can't annotate %s: not enough memory\n", - sym->name); - return -ENOMEM; - } - goto fallback; - } else if (readlink(symfs_filename, command, sizeof(command)) < 0 || - strstr(command, "[kernel.kallsyms]") || - access(symfs_filename, R_OK)) { - free(filename); -fallback: - /* - * If we don't have build-ids or the build-id file isn't in the - * cache, or is just a kallsyms file, well, lets hope that this - * DSO is the same as when 'perf record' ran. - */ - filename = dso->long_name; - snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", - symbol_conf.symfs, filename); - free_filename = false; - } - - if (dso->origin == DSO__ORIG_KERNEL) { - char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; - char *build_id_msg = NULL; - - if (dso->annotate_warned) - goto out_free_filename; - - if (dso->has_build_id) { - build_id__sprintf(dso->build_id, - sizeof(dso->build_id), bf + 15); - build_id_msg = bf; - } - err = -ENOENT; - dso->annotate_warned = 1; - pr_err("Can't annotate %s: No vmlinux file%s was found in the " - "path.\nPlease use 'perf buildid-cache -av vmlinux' or " - "--vmlinux vmlinux.\n", - sym->name, build_id_msg ?: ""); - goto out_free_filename; - } - - pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, - filename, sym->name, map->unmap_ip(map, sym->start), - map->unmap_ip(map, sym->end)); - - pr_debug("annotating [%p] %30s : [%p] %30s\n", - dso, dso->long_name, sym, sym->name); - - snprintf(command, sizeof(command), - "objdump --start-address=0x%016" PRIx64 - " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", - map__rip_2objdump(map, sym->start), - map__rip_2objdump(map, sym->end), - symfs_filename, filename); - - pr_debug("Executing: %s\n", command); - - file = popen(command, "r"); - if (!file) - goto out_free_filename; - - while (!feof(file)) - if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) - break; - - pclose(file); -out_free_filename: - if (free_filename) - free(filename); - return err; -} - -static void insert_source_line(struct rb_root *root, struct source_line *src_line) -{ - struct source_line *iter; - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - - while (*p != NULL) { - parent = *p; - iter = rb_entry(parent, struct source_line, node); - - if (src_line->percent > iter->percent) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - rb_link_node(&src_line->node, parent, p); - rb_insert_color(&src_line->node, root); -} - -static void symbol__free_source_line(struct symbol *sym, int len) -{ - struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src->lines; - int i; - - for (i = 0; i < len; i++) - free(src_line[i].path); - - free(src_line); - notes->src->lines = NULL; -} - -/* Get the filename:line for the colored entries */ -static int symbol__get_source_line(struct symbol *sym, struct map *map, - int evidx, struct rb_root *root, int len, - const char *filename) -{ - u64 start; - int i; - char cmd[PATH_MAX * 2]; - struct source_line *src_line; - struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evidx); - - if (!h->sum) - return 0; - - src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); - if (!notes->src->lines) - return -1; - - start = map->unmap_ip(map, sym->start); - - for (i = 0; i < len; i++) { - char *path = NULL; - size_t line_len; - u64 offset; - FILE *fp; - - src_line[i].percent = 100.0 * h->addr[i] / h->sum; - if (src_line[i].percent <= 0.5) - continue; - - offset = start + i; - sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); - fp = popen(cmd, "r"); - if (!fp) - continue; - - if (getline(&path, &line_len, fp) < 0 || !line_len) - goto next; - - src_line[i].path = malloc(sizeof(char) * line_len + 1); - if (!src_line[i].path) - goto next; - - strcpy(src_line[i].path, path); - insert_source_line(root, &src_line[i]); - - next: - pclose(fp); - } - - return 0; -} - -static void print_summary(struct rb_root *root, const char *filename) -{ - struct source_line *src_line; - struct rb_node *node; - - printf("\nSorted summary for file %s\n", filename); - printf("----------------------------------------------\n\n"); - - if (RB_EMPTY_ROOT(root)) { - printf(" Nothing higher than %1.1f%%\n", MIN_GREEN); - return; - } - - node = rb_first(root); - while (node) { - double percent; - const char *color; - char *path; - - src_line = rb_entry(node, struct source_line, node); - percent = src_line->percent; - color = get_percent_color(percent); - path = src_line->path; - - color_fprintf(stdout, color, " %7.2f %s", percent, path); - node = rb_next(node); - } -} - -static void symbol__annotate_hits(struct symbol *sym, int evidx) -{ - struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evidx); - u64 len = sym->end - sym->start, offset; - - for (offset = 0; offset < len; ++offset) - if (h->addr[offset] != 0) - printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2, - sym->start + offset, h->addr[offset]); - printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); -} - -int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, - bool full_paths, int min_pcnt, int max_lines, - int context) -{ - struct dso *dso = map->dso; - const char *filename = dso->long_name, *d_filename; - struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos, *queue = NULL; - int printed = 2, queue_len = 0; - int more = 0; - u64 len; - - if (full_paths) - d_filename = filename; - else - d_filename = basename(filename); - - len = sym->end - sym->start; - - printf(" Percent | Source code & Disassembly of %s\n", d_filename); - printf("------------------------------------------------\n"); - - if (verbose) - symbol__annotate_hits(sym, evidx); - - list_for_each_entry(pos, ¬es->src->source, node) { - if (context && queue == NULL) { - queue = pos; - queue_len = 0; - } - - switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, - printed, max_lines, queue)) { - case 0: - ++printed; - if (context) { - printed += queue_len; - queue = NULL; - queue_len = 0; - } - break; - case 1: - /* filtered by max_lines */ - ++more; - break; - case -1: - default: - /* - * Filtered by min_pcnt or non IP lines when - * context != 0 - */ - if (!context) - break; - if (queue_len == context) - queue = list_entry(queue->node.next, typeof(*queue), node); - else - ++queue_len; - break; - } - } - - return more; -} - -void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) -{ - struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evidx); - - memset(h, 0, notes->src->sizeof_sym_hist); -} - -void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) -{ - struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evidx); - struct objdump_line *pos; - int len = sym->end - sym->start; - - h->sum = 0; - - list_for_each_entry(pos, ¬es->src->source, node) { - if (pos->offset != -1 && pos->offset < len) { - h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; - h->sum += h->addr[pos->offset]; - } - } -} - -void objdump_line_list__purge(struct list_head *head) -{ - struct objdump_line *pos, *n; - - list_for_each_entry_safe(pos, n, head, node) { - list_del(&pos->node); - objdump_line__free(pos); - } -} - -int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, - bool print_lines, bool full_paths, int min_pcnt, - int max_lines) -{ - struct dso *dso = map->dso; - const char *filename = dso->long_name; - struct rb_root source_line = RB_ROOT; - u64 len; - - if (symbol__annotate(sym, map, 0) < 0) - return -1; - - len = sym->end - sym->start; - - if (print_lines) { - symbol__get_source_line(sym, map, evidx, &source_line, - len, filename); - print_summary(&source_line, filename); - } - - symbol__annotate_printf(sym, map, evidx, full_paths, - min_pcnt, max_lines, 0); - if (print_lines) - symbol__free_source_line(sym, len); - - objdump_line_list__purge(&symbol__annotation(sym)->src->source); - - return 0; -} diff --git a/trunk/tools/perf/util/annotate.h b/trunk/tools/perf/util/annotate.h deleted file mode 100644 index c2c286896801..000000000000 --- a/trunk/tools/perf/util/annotate.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef __PERF_ANNOTATE_H -#define __PERF_ANNOTATE_H - -#include -#include "types.h" -#include "symbol.h" -#include -#include - -struct objdump_line { - struct list_head node; - s64 offset; - char *line; -}; - -void objdump_line__free(struct objdump_line *self); -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, - struct objdump_line *pos); - -struct sym_hist { - u64 sum; - u64 addr[0]; -}; - -struct source_line { - struct rb_node node; - double percent; - char *path; -}; - -/** struct annotated_source - symbols with hits have this attached as in sannotation - * - * @histogram: Array of addr hit histograms per event being monitored - * @lines: If 'print_lines' is specified, per source code line percentages - * @source: source parsed from objdump -dS - * - * lines is allocated, percentages calculated and all sorted by percentage - * when the annotation is about to be presented, so the percentages are for - * one of the entries in the histogram array, i.e. for the event/counter being - * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate - * returns. - */ -struct annotated_source { - struct list_head source; - struct source_line *lines; - int nr_histograms; - int sizeof_sym_hist; - struct sym_hist histograms[0]; -}; - -struct annotation { - pthread_mutex_t lock; - struct annotated_source *src; -}; - -struct sannotation { - struct annotation annotation; - struct symbol symbol; -}; - -static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) -{ - return (((void *)¬es->src->histograms) + - (notes->src->sizeof_sym_hist * idx)); -} - -static inline struct annotation *symbol__annotation(struct symbol *sym) -{ - struct sannotation *a = container_of(sym, struct sannotation, symbol); - return &a->annotation; -} - -int symbol__inc_addr_samples(struct symbol *sym, struct map *map, - int evidx, u64 addr); -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); -int symbol__annotate_init(struct map *map __used, struct symbol *sym); -int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, - bool full_paths, int min_pcnt, int max_lines, - int context); -void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); -void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); -void objdump_line_list__purge(struct list_head *head); - -int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, - bool print_lines, bool full_paths, int min_pcnt, - int max_lines); - -#ifdef NO_NEWT_SUPPORT -static inline int symbol__tui_annotate(struct symbol *sym __used, - struct map *map __used, - int evidx __used, int refresh __used) -{ - return 0; -} -#else -int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - int refresh); -#endif - -#endif /* __PERF_ANNOTATE_H */ diff --git a/trunk/tools/perf/util/build-id.c b/trunk/tools/perf/util/build-id.c index 31f934af9861..deffb8c96071 100644 --- a/trunk/tools/perf/util/build-id.c +++ b/trunk/tools/perf/util/build-id.c @@ -14,8 +14,8 @@ #include #include "debug.h" -static int build_id__mark_dso_hit(union perf_event *event, - struct perf_sample *sample __used, +static int build_id__mark_dso_hit(event_t *event, + struct sample_data *sample __used, struct perf_session *session) { struct addr_location al; @@ -37,14 +37,13 @@ static int build_id__mark_dso_hit(union perf_event *event, return 0; } -static int perf_event__exit_del_thread(union perf_event *event, - struct perf_sample *sample __used, - struct perf_session *session) +static int event__exit_del_thread(event_t *self, struct sample_data *sample __used, + struct perf_session *session) { - struct thread *thread = perf_session__findnew(session, event->fork.tid); + struct thread *thread = perf_session__findnew(session, self->fork.tid); - dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, - event->fork.ppid, event->fork.ptid); + dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, + self->fork.ppid, self->fork.ptid); if (thread) { rb_erase(&thread->rb_node, &session->threads); @@ -57,9 +56,9 @@ static int perf_event__exit_del_thread(union perf_event *event, 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, - .exit = perf_event__exit_del_thread, + .mmap = event__process_mmap, + .fork = event__process_task, + .exit = event__exit_del_thread, }; char *dso__build_id_filename(struct dso *self, char *bf, size_t size) diff --git a/trunk/tools/perf/util/cache.h b/trunk/tools/perf/util/cache.h index fc5e5a09d5b9..a7729797fd96 100644 --- a/trunk/tools/perf/util/cache.h +++ b/trunk/tools/perf/util/cache.h @@ -34,14 +34,13 @@ extern int pager_use_color; extern int use_browser; #ifdef NO_NEWT_SUPPORT -static inline void setup_browser(bool fallback_to_pager) +static inline void setup_browser(void) { - if (fallback_to_pager) - setup_pager(); + setup_pager(); } static inline void exit_browser(bool wait_for_ok __used) {} #else -void setup_browser(bool fallback_to_pager); +void setup_browser(void); void exit_browser(bool wait_for_ok); #endif diff --git a/trunk/tools/perf/util/callchain.c b/trunk/tools/perf/util/callchain.c index 9f7106a8d9a4..e12d539417b2 100644 --- a/trunk/tools/perf/util/callchain.c +++ b/trunk/tools/perf/util/callchain.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011, Frederic Weisbecker + * Copyright (C) 2009-2010, Frederic Weisbecker * * Handle the callchains from the stream in an ad-hoc radix tree and then * sort them in an rbtree. @@ -18,8 +18,7 @@ #include "util.h" #include "callchain.h" -bool ip_callchain__valid(struct ip_callchain *chain, - const union perf_event *event) +bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event) { unsigned int chain_size = event->header.size; chain_size -= (unsigned long)&event->ip.__more_data - (unsigned long)event; @@ -27,10 +26,10 @@ bool ip_callchain__valid(struct ip_callchain *chain, } #define chain_for_each_child(child, parent) \ - list_for_each_entry(child, &parent->children, siblings) + list_for_each_entry(child, &parent->children, brothers) #define chain_for_each_child_safe(child, next, parent) \ - list_for_each_entry_safe(child, next, &parent->children, siblings) + list_for_each_entry_safe(child, next, &parent->children, brothers) static void rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, @@ -39,14 +38,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain, struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; struct callchain_node *rnode; - u64 chain_cumul = callchain_cumul_hits(chain); + u64 chain_cumul = cumul_hits(chain); while (*p) { u64 rnode_cumul; parent = *p; rnode = rb_entry(parent, struct callchain_node, rb_node); - rnode_cumul = callchain_cumul_hits(rnode); + rnode_cumul = cumul_hits(rnode); switch (mode) { case CHAIN_FLAT: @@ -105,7 +104,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node, chain_for_each_child(child, node) { __sort_chain_graph_abs(child, min_hit); - if (callchain_cumul_hits(child) >= min_hit) + if (cumul_hits(child) >= min_hit) rb_insert_callchain(&node->rb_root, child, CHAIN_GRAPH_ABS); } @@ -130,7 +129,7 @@ static void __sort_chain_graph_rel(struct callchain_node *node, chain_for_each_child(child, node) { __sort_chain_graph_rel(child, min_percent); - if (callchain_cumul_hits(child) >= min_hit) + if (cumul_hits(child) >= min_hit) rb_insert_callchain(&node->rb_root, child, CHAIN_GRAPH_REL); } @@ -144,7 +143,7 @@ sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root, rb_root->rb_node = chain_root->node.rb_root.rb_node; } -int callchain_register_param(struct callchain_param *param) +int register_callchain_param(struct callchain_param *param) { switch (param->mode) { case CHAIN_GRAPH_ABS: @@ -190,27 +189,32 @@ create_child(struct callchain_node *parent, bool inherit_children) chain_for_each_child(next, new) next->parent = new; } - list_add_tail(&new->siblings, &parent->children); + list_add_tail(&new->brothers, &parent->children); return new; } +struct resolved_ip { + u64 ip; + struct map_symbol ms; +}; + +struct resolved_chain { + u64 nr; + struct resolved_ip ips[0]; +}; + + /* * Fill the node with callchain values */ static void -fill_node(struct callchain_node *node, struct callchain_cursor *cursor) +fill_node(struct callchain_node *node, struct resolved_chain *chain, int start) { - struct callchain_cursor_node *cursor_node; - - node->val_nr = cursor->nr - cursor->pos; - if (!node->val_nr) - pr_warning("Warning: empty node in callchain tree\n"); + unsigned int i; - cursor_node = callchain_cursor_current(cursor); - - while (cursor_node) { + for (i = start; i < chain->nr; i++) { struct callchain_list *call; call = zalloc(sizeof(*call)); @@ -218,25 +222,23 @@ fill_node(struct callchain_node *node, struct callchain_cursor *cursor) perror("not enough memory for the code path tree"); return; } - call->ip = cursor_node->ip; - call->ms.sym = cursor_node->sym; - call->ms.map = cursor_node->map; + call->ip = chain->ips[i].ip; + call->ms = chain->ips[i].ms; list_add_tail(&call->list, &node->val); - - callchain_cursor_advance(cursor); - cursor_node = callchain_cursor_current(cursor); } + node->val_nr = chain->nr - start; + if (!node->val_nr) + pr_warning("Warning: empty node in callchain tree\n"); } static void -add_child(struct callchain_node *parent, - struct callchain_cursor *cursor, - u64 period) +add_child(struct callchain_node *parent, struct resolved_chain *chain, + int start, u64 period) { struct callchain_node *new; new = create_child(parent, false); - fill_node(new, cursor); + fill_node(new, chain, start); new->children_hit = 0; new->hit = period; @@ -248,10 +250,9 @@ add_child(struct callchain_node *parent, * Then create another child to host the given callchain of new branch */ static void -split_add_child(struct callchain_node *parent, - struct callchain_cursor *cursor, - struct callchain_list *to_split, - u64 idx_parents, u64 idx_local, u64 period) +split_add_child(struct callchain_node *parent, struct resolved_chain *chain, + struct callchain_list *to_split, int idx_parents, int idx_local, + u64 period) { struct callchain_node *new; struct list_head *old_tail; @@ -271,14 +272,14 @@ split_add_child(struct callchain_node *parent, /* split the hits */ new->hit = parent->hit; new->children_hit = parent->children_hit; - parent->children_hit = callchain_cumul_hits(new); + parent->children_hit = cumul_hits(new); new->val_nr = parent->val_nr - idx_local; parent->val_nr = idx_local; /* create a new child for the new branch if any */ - if (idx_total < cursor->nr) { + if (idx_total < chain->nr) { parent->hit = 0; - add_child(parent, cursor, period); + add_child(parent, chain, idx_total, period); parent->children_hit += period; } else { parent->hit = period; @@ -286,41 +287,36 @@ split_add_child(struct callchain_node *parent, } static int -append_chain(struct callchain_node *root, - struct callchain_cursor *cursor, - u64 period); +append_chain(struct callchain_node *root, struct resolved_chain *chain, + unsigned int start, u64 period); static void -append_chain_children(struct callchain_node *root, - struct callchain_cursor *cursor, - u64 period) +append_chain_children(struct callchain_node *root, struct resolved_chain *chain, + unsigned int start, u64 period) { struct callchain_node *rnode; /* lookup in childrens */ chain_for_each_child(rnode, root) { - unsigned int ret = append_chain(rnode, cursor, period); + unsigned int ret = append_chain(rnode, chain, start, period); if (!ret) goto inc_children_hit; } /* nothing in children, add to the current node */ - add_child(root, cursor, period); + add_child(root, chain, start, period); inc_children_hit: root->children_hit += period; } static int -append_chain(struct callchain_node *root, - struct callchain_cursor *cursor, - u64 period) +append_chain(struct callchain_node *root, struct resolved_chain *chain, + unsigned int start, u64 period) { - struct callchain_cursor_node *curr_snap = cursor->curr; struct callchain_list *cnode; - u64 start = cursor->pos; + unsigned int i = start; bool found = false; - u64 matches; /* * Lookup in the current node @@ -328,134 +324,141 @@ append_chain(struct callchain_node *root, * anywhere inside a function. */ list_for_each_entry(cnode, &root->val, list) { - struct callchain_cursor_node *node; struct symbol *sym; - node = callchain_cursor_current(cursor); - if (!node) + if (i == chain->nr) break; - sym = node->sym; + sym = chain->ips[i].ms.sym; if (cnode->ms.sym && sym) { if (cnode->ms.sym->start != sym->start) break; - } else if (cnode->ip != node->ip) + } else if (cnode->ip != chain->ips[i].ip) break; if (!found) found = true; - - callchain_cursor_advance(cursor); + i++; } /* matches not, relay on the parent */ - if (!found) { - cursor->curr = curr_snap; - cursor->pos = start; + if (!found) return -1; - } - - matches = cursor->pos - start; /* we match only a part of the node. Split it and add the new chain */ - if (matches < root->val_nr) { - split_add_child(root, cursor, cnode, start, matches, period); + if (i - start < root->val_nr) { + split_add_child(root, chain, cnode, start, i - start, period); return 0; } /* we match 100% of the path, increment the hit */ - if (matches == root->val_nr && cursor->pos == cursor->nr) { + if (i - start == root->val_nr && i == chain->nr) { root->hit += period; return 0; } /* We match the node and still have a part remaining */ - append_chain_children(root, cursor, period); + append_chain_children(root, chain, i, period); return 0; } -int callchain_append(struct callchain_root *root, - struct callchain_cursor *cursor, - u64 period) +static void filter_context(struct ip_callchain *old, struct resolved_chain *new, + struct map_symbol *syms) +{ + int i, j = 0; + + for (i = 0; i < (int)old->nr; i++) { + if (old->ips[i] >= PERF_CONTEXT_MAX) + continue; + + new->ips[j].ip = old->ips[i]; + new->ips[j].ms = syms[i]; + j++; + } + + new->nr = j; +} + + +int callchain_append(struct callchain_root *root, struct ip_callchain *chain, + struct map_symbol *syms, u64 period) { - if (!cursor->nr) + struct resolved_chain *filtered; + + if (!chain->nr) return 0; - callchain_cursor_commit(cursor); + filtered = zalloc(sizeof(*filtered) + + chain->nr * sizeof(struct resolved_ip)); + if (!filtered) + return -ENOMEM; + + filter_context(chain, filtered, syms); + + if (!filtered->nr) + goto end; - append_chain_children(&root->node, cursor, period); + append_chain_children(&root->node, filtered, 0, period); - if (cursor->nr > root->max_depth) - root->max_depth = cursor->nr; + if (filtered->nr > root->max_depth) + root->max_depth = filtered->nr; +end: + free(filtered); return 0; } static int -merge_chain_branch(struct callchain_cursor *cursor, - struct callchain_node *dst, struct callchain_node *src) +merge_chain_branch(struct callchain_node *dst, struct callchain_node *src, + struct resolved_chain *chain) { - struct callchain_cursor_node **old_last = cursor->last; struct callchain_node *child, *next_child; struct callchain_list *list, *next_list; - int old_pos = cursor->nr; + int old_pos = chain->nr; int err = 0; list_for_each_entry_safe(list, next_list, &src->val, list) { - callchain_cursor_append(cursor, list->ip, - list->ms.map, list->ms.sym); + chain->ips[chain->nr].ip = list->ip; + chain->ips[chain->nr].ms = list->ms; + chain->nr++; list_del(&list->list); free(list); } - if (src->hit) { - callchain_cursor_commit(cursor); - append_chain_children(dst, cursor, src->hit); - } + if (src->hit) + append_chain_children(dst, chain, 0, src->hit); chain_for_each_child_safe(child, next_child, src) { - err = merge_chain_branch(cursor, dst, child); + err = merge_chain_branch(dst, child, chain); if (err) break; - list_del(&child->siblings); + list_del(&child->brothers); free(child); } - cursor->nr = old_pos; - cursor->last = old_last; + chain->nr = old_pos; return err; } -int callchain_merge(struct callchain_cursor *cursor, - struct callchain_root *dst, struct callchain_root *src) -{ - return merge_chain_branch(cursor, &dst->node, &src->node); -} - -int callchain_cursor_append(struct callchain_cursor *cursor, - u64 ip, struct map *map, struct symbol *sym) +int callchain_merge(struct callchain_root *dst, struct callchain_root *src) { - struct callchain_cursor_node *node = *cursor->last; + struct resolved_chain *chain; + int err; - if (!node) { - node = calloc(sizeof(*node), 1); - if (!node) - return -ENOMEM; + chain = malloc(sizeof(*chain) + + src->max_depth * sizeof(struct resolved_ip)); + if (!chain) + return -ENOMEM; - *cursor->last = node; - } - - node->ip = ip; - node->map = map; - node->sym = sym; + chain->nr = 0; - cursor->nr++; + err = merge_chain_branch(&dst->node, &src->node, chain); - cursor->last = &node->next; + free(chain); - return 0; + return err; } diff --git a/trunk/tools/perf/util/callchain.h b/trunk/tools/perf/util/callchain.h index 1a79df9f739f..c15fb8c24ad2 100644 --- a/trunk/tools/perf/util/callchain.h +++ b/trunk/tools/perf/util/callchain.h @@ -16,7 +16,7 @@ enum chain_mode { struct callchain_node { struct callchain_node *parent; - struct list_head siblings; + struct list_head brothers; struct list_head children; struct list_head val; struct rb_node rb_node; /* to sort nodes in an rbtree */ @@ -49,30 +49,9 @@ struct callchain_list { struct list_head list; }; -/* - * A callchain cursor is a single linked list that - * let one feed a callchain progressively. - * It keeps persitent allocated entries to minimize - * allocations. - */ -struct callchain_cursor_node { - u64 ip; - struct map *map; - struct symbol *sym; - struct callchain_cursor_node *next; -}; - -struct callchain_cursor { - u64 nr; - struct callchain_cursor_node *first; - struct callchain_cursor_node **last; - u64 pos; - struct callchain_cursor_node *curr; -}; - static inline void callchain_init(struct callchain_root *root) { - INIT_LIST_HEAD(&root->node.siblings); + INIT_LIST_HEAD(&root->node.brothers); INIT_LIST_HEAD(&root->node.children); INIT_LIST_HEAD(&root->node.val); @@ -82,54 +61,15 @@ static inline void callchain_init(struct callchain_root *root) root->max_depth = 0; } -static inline u64 callchain_cumul_hits(struct callchain_node *node) +static inline u64 cumul_hits(struct callchain_node *node) { return node->hit + node->children_hit; } -int callchain_register_param(struct callchain_param *param); -int callchain_append(struct callchain_root *root, - struct callchain_cursor *cursor, - u64 period); - -int callchain_merge(struct callchain_cursor *cursor, - struct callchain_root *dst, struct callchain_root *src); - -bool ip_callchain__valid(struct ip_callchain *chain, - const union perf_event *event); -/* - * Initialize a cursor before adding entries inside, but keep - * the previously allocated entries as a cache. - */ -static inline void callchain_cursor_reset(struct callchain_cursor *cursor) -{ - cursor->nr = 0; - cursor->last = &cursor->first; -} - -int callchain_cursor_append(struct callchain_cursor *cursor, u64 ip, - struct map *map, struct symbol *sym); +int register_callchain_param(struct callchain_param *param); +int callchain_append(struct callchain_root *root, struct ip_callchain *chain, + struct map_symbol *syms, u64 period); +int callchain_merge(struct callchain_root *dst, struct callchain_root *src); -/* Close a cursor writing session. Initialize for the reader */ -static inline void callchain_cursor_commit(struct callchain_cursor *cursor) -{ - cursor->curr = cursor->first; - cursor->pos = 0; -} - -/* Cursor reading iteration helpers */ -static inline struct callchain_cursor_node * -callchain_cursor_current(struct callchain_cursor *cursor) -{ - if (cursor->pos == cursor->nr) - return NULL; - - return cursor->curr; -} - -static inline void callchain_cursor_advance(struct callchain_cursor *cursor) -{ - cursor->curr = cursor->curr->next; - cursor->pos++; -} +bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event); #endif /* __PERF_CALLCHAIN_H */ diff --git a/trunk/tools/perf/util/cgroup.c b/trunk/tools/perf/util/cgroup.c deleted file mode 100644 index 9fea75535221..000000000000 --- a/trunk/tools/perf/util/cgroup.c +++ /dev/null @@ -1,178 +0,0 @@ -#include "util.h" -#include "../perf.h" -#include "parse-options.h" -#include "evsel.h" -#include "cgroup.h" -#include "debugfs.h" /* MAX_PATH, STR() */ -#include "evlist.h" - -int nr_cgroups; - -static int -cgroupfs_find_mountpoint(char *buf, size_t maxlen) -{ - FILE *fp; - char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; - char *token, *saved_ptr; - int found = 0; - - fp = fopen("/proc/mounts", "r"); - if (!fp) - return -1; - - /* - * in order to handle split hierarchy, we need to scan /proc/mounts - * and inspect every cgroupfs mount point to find one that has - * perf_event subsystem - */ - 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")) { - - token = strtok_r(tokens, ",", &saved_ptr); - - while (token != NULL) { - if (!strcmp(token, "perf_event")) { - found = 1; - break; - } - token = strtok_r(NULL, ",", &saved_ptr); - } - } - if (found) - break; - } - fclose(fp); - if (!found) - return -1; - - if (strlen(mountpoint) < maxlen) { - strcpy(buf, mountpoint); - return 0; - } - return -1; -} - -static int open_cgroup(char *name) -{ - char path[MAX_PATH+1]; - char mnt[MAX_PATH+1]; - int fd; - - - if (cgroupfs_find_mountpoint(mnt, MAX_PATH+1)) - return -1; - - snprintf(path, MAX_PATH, "%s/%s", mnt, name); - - fd = open(path, O_RDONLY); - if (fd == -1) - fprintf(stderr, "no access to cgroup %s\n", path); - - return fd; -} - -static int add_cgroup(struct perf_evlist *evlist, char *str) -{ - struct perf_evsel *counter; - struct cgroup_sel *cgrp = NULL; - int n; - /* - * check if cgrp is already defined, if so we reuse it - */ - list_for_each_entry(counter, &evlist->entries, node) { - cgrp = counter->cgrp; - if (!cgrp) - continue; - if (!strcmp(cgrp->name, str)) - break; - - cgrp = NULL; - } - - if (!cgrp) { - cgrp = zalloc(sizeof(*cgrp)); - if (!cgrp) - return -1; - - cgrp->name = str; - - cgrp->fd = open_cgroup(str); - if (cgrp->fd == -1) { - free(cgrp); - return -1; - } - } - - /* - * find corresponding event - * if add cgroup N, then need to find event N - */ - n = 0; - list_for_each_entry(counter, &evlist->entries, node) { - if (n == nr_cgroups) - goto found; - n++; - } - if (cgrp->refcnt == 0) - free(cgrp); - - return -1; -found: - cgrp->refcnt++; - counter->cgrp = cgrp; - return 0; -} - -void close_cgroup(struct cgroup_sel *cgrp) -{ - if (!cgrp) - return; - - /* XXX: not reentrant */ - if (--cgrp->refcnt == 0) { - close(cgrp->fd); - free(cgrp->name); - free(cgrp); - } -} - -int parse_cgroups(const struct option *opt __used, const char *str, - int unset __used) -{ - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; - const char *p, *e, *eos = str + strlen(str); - char *s; - int ret; - - if (list_empty(&evlist->entries)) { - fprintf(stderr, "must define events before cgroups\n"); - return -1; - } - - for (;;) { - p = strchr(str, ','); - e = p ? p : eos; - - /* allow empty cgroups, i.e., skip */ - if (e - str) { - /* termination added */ - s = strndup(str, e - str); - if (!s) - return -1; - ret = add_cgroup(evlist, s); - if (ret) { - free(s); - return -1; - } - } - /* nr_cgroups is increased een for empty cgroups */ - nr_cgroups++; - if (!p) - break; - str = p+1; - } - return 0; -} diff --git a/trunk/tools/perf/util/cgroup.h b/trunk/tools/perf/util/cgroup.h deleted file mode 100644 index 89acd6debdc5..000000000000 --- a/trunk/tools/perf/util/cgroup.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __CGROUP_H__ -#define __CGROUP_H__ - -struct option; - -struct cgroup_sel { - char *name; - int fd; - int refcnt; -}; - - -extern int nr_cgroups; /* number of explicit cgroups defined */ -extern void close_cgroup(struct cgroup_sel *cgrp); -extern int parse_cgroups(const struct option *opt, const char *str, int unset); - -#endif /* __CGROUP_H__ */ diff --git a/trunk/tools/perf/util/cpumap.c b/trunk/tools/perf/util/cpumap.c index 6893eec693ab..3ccaa1043383 100644 --- a/trunk/tools/perf/util/cpumap.c +++ b/trunk/tools/perf/util/cpumap.c @@ -177,8 +177,3 @@ struct cpu_map *cpu_map__dummy_new(void) return cpus; } - -void cpu_map__delete(struct cpu_map *map) -{ - free(map); -} diff --git a/trunk/tools/perf/util/cpumap.h b/trunk/tools/perf/util/cpumap.h index 072c0a374794..f7a4f42f6307 100644 --- a/trunk/tools/perf/util/cpumap.h +++ b/trunk/tools/perf/util/cpumap.h @@ -8,6 +8,6 @@ struct cpu_map { struct cpu_map *cpu_map__new(const char *cpu_list); struct cpu_map *cpu_map__dummy_new(void); -void cpu_map__delete(struct cpu_map *map); +void *cpu_map__delete(struct cpu_map *map); #endif /* __PERF_CPUMAP_H */ diff --git a/trunk/tools/perf/util/debug.c b/trunk/tools/perf/util/debug.c index d4536a9e0d8c..01bbe8ecec3f 100644 --- a/trunk/tools/perf/util/debug.c +++ b/trunk/tools/perf/util/debug.c @@ -57,7 +57,7 @@ void ui__warning(const char *format, ...) } #endif -void trace_event(union perf_event *event) +void trace_event(event_t *event) { unsigned char *raw_event = (void *)event; const char *color = PERF_COLOR_BLUE; diff --git a/trunk/tools/perf/util/debug.h b/trunk/tools/perf/util/debug.h index 93516cf4682c..ca35fd66b5df 100644 --- a/trunk/tools/perf/util/debug.h +++ b/trunk/tools/perf/util/debug.h @@ -9,7 +9,7 @@ extern int verbose; extern bool quiet, dump_trace; int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); -void trace_event(union perf_event *event); +void trace_event(event_t *event); struct ui_progress; diff --git a/trunk/tools/perf/util/event.c b/trunk/tools/perf/util/event.c index fbf5754c8866..50d0a931497a 100644 --- a/trunk/tools/perf/util/event.c +++ b/trunk/tools/perf/util/event.c @@ -6,9 +6,8 @@ #include "string.h" #include "strlist.h" #include "thread.h" -#include "thread_map.h" -static const char *perf_event__names[] = { +static const char *event__name[] = { [0] = "TOTAL", [PERF_RECORD_MMAP] = "MMAP", [PERF_RECORD_LOST] = "LOST", @@ -26,16 +25,16 @@ static const char *perf_event__names[] = { [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", }; -const char *perf_event__name(unsigned int id) +const char *event__get_event_name(unsigned int id) { - if (id >= ARRAY_SIZE(perf_event__names)) + if (id >= ARRAY_SIZE(event__name)) return "INVALID"; - if (!perf_event__names[id]) + if (!event__name[id]) return "UNKNOWN"; - return perf_event__names[id]; + return event__name[id]; } -static struct perf_sample synth_sample = { +static struct sample_data synth_sample = { .pid = -1, .tid = -1, .time = -1, @@ -44,9 +43,9 @@ static struct perf_sample synth_sample = { .period = 1, }; -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) +static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full, + event__handler_t process, + struct perf_session *session) { char filename[PATH_MAX]; char bf[BUFSIZ]; @@ -127,10 +126,9 @@ static pid_t perf_event__synthesize_comm(union perf_event *event, pid_t pid, return tgid; } -static int perf_event__synthesize_mmap_events(union perf_event *event, - pid_t pid, pid_t tgid, - perf_event__handler_t process, - struct perf_session *session) +static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid, + event__handler_t process, + struct perf_session *session) { char filename[PATH_MAX]; FILE *fp; @@ -201,14 +199,14 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, return 0; } -int perf_event__synthesize_modules(perf_event__handler_t process, - struct perf_session *session, - struct machine *machine) +int event__synthesize_modules(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) + - session->id_hdr_size)); + event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); + if (event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); @@ -253,24 +251,23 @@ int perf_event__synthesize_modules(perf_event__handler_t process, return 0; } -static int __event__synthesize_thread(union perf_event *comm_event, - union perf_event *mmap_event, - pid_t pid, perf_event__handler_t process, +static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event, + pid_t pid, event__handler_t process, struct perf_session *session) { - pid_t tgid = perf_event__synthesize_comm(comm_event, pid, 1, process, + pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process, session); if (tgid == -1) return -1; - return perf_event__synthesize_mmap_events(mmap_event, pid, tgid, + return event__synthesize_mmap_events(mmap_event, pid, tgid, process, session); } -int perf_event__synthesize_thread_map(struct thread_map *threads, - perf_event__handler_t process, - struct perf_session *session) +int event__synthesize_thread_map(struct thread_map *threads, + event__handler_t process, + struct perf_session *session) { - union perf_event *comm_event, *mmap_event; + event_t *comm_event, *mmap_event; int err = -1, thread; comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); @@ -297,12 +294,12 @@ int perf_event__synthesize_thread_map(struct thread_map *threads, return err; } -int perf_event__synthesize_threads(perf_event__handler_t process, - struct perf_session *session) +int event__synthesize_threads(event__handler_t process, + struct perf_session *session) { DIR *proc; struct dirent dirent, *next; - union perf_event *comm_event, *mmap_event; + event_t *comm_event, *mmap_event; int err = -1; comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size); @@ -360,10 +357,10 @@ static int find_symbol_cb(void *arg, const char *name, char type, return 1; } -int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, - struct perf_session *session, - struct machine *machine, - const char *symbol_name) +int event__synthesize_kernel_mmap(event__handler_t process, + struct perf_session *session, + struct machine *machine, + const char *symbol_name) { size_t size; const char *filename, *mmap_name; @@ -377,8 +374,8 @@ int perf_event__synthesize_kernel_mmap(perf_event__handler_t process, * kernels. */ struct process_symbol_args args = { .name = symbol_name, }; - union perf_event *event = zalloc((sizeof(event->mmap) + - session->id_hdr_size)); + event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size); + if (event == NULL) { pr_debug("Not enough memory synthesizing mmap event " "for kernel modules\n"); @@ -451,15 +448,14 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm, return 0; } -int perf_event__process_comm(union perf_event *event, - struct perf_sample *sample __used, - struct perf_session *session) +int event__process_comm(event_t *self, struct sample_data *sample __used, + struct perf_session *session) { - struct thread *thread = perf_session__findnew(session, event->comm.tid); + struct thread *thread = perf_session__findnew(session, self->comm.tid); - dump_printf(": %s:%d\n", event->comm.comm, event->comm.tid); + dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid); - if (thread == NULL || thread__set_comm_adjust(thread, event->comm.comm, + if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm, &session->hists)) { dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); return -1; @@ -468,21 +464,19 @@ int perf_event__process_comm(union perf_event *event, return 0; } -int perf_event__process_lost(union perf_event *event, - struct perf_sample *sample __used, - struct perf_session *session) +int event__process_lost(event_t *self, struct sample_data *sample __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; + self->lost.id, self->lost.lost); + session->hists.stats.total_lost += self->lost.lost; return 0; } -static void perf_event__set_kernel_mmap_len(union perf_event *event, - struct map **maps) +static void event_set_kernel_mmap_len(struct map **maps, event_t *self) { - maps[MAP__FUNCTION]->start = event->mmap.start; - maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len; + maps[MAP__FUNCTION]->start = self->mmap.start; + maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len; /* * Be a bit paranoid here, some perf.data file came with * a zero sized synthesized MMAP event for the kernel. @@ -491,8 +485,8 @@ static void perf_event__set_kernel_mmap_len(union perf_event *event, maps[MAP__FUNCTION]->end = ~0ULL; } -static int perf_event__process_kernel_mmap(union perf_event *event, - struct perf_session *session) +static int event__process_kernel_mmap(event_t *self, + struct perf_session *session) { struct map *map; char kmmap_prefix[PATH_MAX]; @@ -500,9 +494,9 @@ static int perf_event__process_kernel_mmap(union perf_event *event, enum dso_kernel_type kernel_type; bool is_kernel_mmap; - machine = perf_session__findnew_machine(session, event->mmap.pid); + machine = perf_session__findnew_machine(session, self->mmap.pid); if (!machine) { - pr_err("Can't find id %d's machine\n", event->mmap.pid); + pr_err("Can't find id %d's machine\n", self->mmap.pid); goto out_problem; } @@ -512,17 +506,17 @@ static int perf_event__process_kernel_mmap(union perf_event *event, else kernel_type = DSO_TYPE_GUEST_KERNEL; - is_kernel_mmap = memcmp(event->mmap.filename, + is_kernel_mmap = memcmp(self->mmap.filename, kmmap_prefix, strlen(kmmap_prefix)) == 0; - if (event->mmap.filename[0] == '/' || - (!is_kernel_mmap && event->mmap.filename[0] == '[')) { + if (self->mmap.filename[0] == '/' || + (!is_kernel_mmap && self->mmap.filename[0] == '[')) { char short_module_name[1024]; char *name, *dot; - if (event->mmap.filename[0] == '/') { - name = strrchr(event->mmap.filename, '/'); + if (self->mmap.filename[0] == '/') { + name = strrchr(self->mmap.filename, '/'); if (name == NULL) goto out_problem; @@ -534,10 +528,10 @@ static int perf_event__process_kernel_mmap(union perf_event *event, "[%.*s]", (int)(dot - name), name); strxfrchar(short_module_name, '-', '_'); } else - strcpy(short_module_name, event->mmap.filename); + strcpy(short_module_name, self->mmap.filename); - map = machine__new_module(machine, event->mmap.start, - event->mmap.filename); + map = machine__new_module(machine, self->mmap.start, + self->mmap.filename); if (map == NULL) goto out_problem; @@ -547,9 +541,9 @@ static int perf_event__process_kernel_mmap(union perf_event *event, map->dso->short_name = name; map->dso->sname_alloc = 1; - map->end = map->start + event->mmap.len; + map->end = map->start + self->mmap.len; } else if (is_kernel_mmap) { - const char *symbol_name = (event->mmap.filename + + const char *symbol_name = (self->mmap.filename + strlen(kmmap_prefix)); /* * Should be there already, from the build-id table in @@ -564,10 +558,10 @@ static int perf_event__process_kernel_mmap(union perf_event *event, if (__machine__create_kernel_maps(machine, kernel) < 0) goto out_problem; - perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps); + event_set_kernel_mmap_len(machine->vmlinux_maps, self); perf_session__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, symbol_name, - event->mmap.pgoff); + self->mmap.pgoff); if (machine__is_default_guest(machine)) { /* * preload dso of guest kernel and modules @@ -581,23 +575,22 @@ static int perf_event__process_kernel_mmap(union perf_event *event, return -1; } -int perf_event__process_mmap(union perf_event *event, - struct perf_sample *sample __used, - struct perf_session *session) +int event__process_mmap(event_t *self, struct sample_data *sample __used, + struct perf_session *session) { struct machine *machine; struct thread *thread; struct map *map; - u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; int ret = 0; 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); + self->mmap.pid, self->mmap.tid, self->mmap.start, + self->mmap.len, self->mmap.pgoff, self->mmap.filename); if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL || cpumode == PERF_RECORD_MISC_KERNEL) { - ret = perf_event__process_kernel_mmap(event, session); + ret = event__process_kernel_mmap(self, session); if (ret < 0) goto out_problem; return 0; @@ -606,12 +599,12 @@ int perf_event__process_mmap(union perf_event *event, machine = perf_session__find_host_machine(session); if (machine == NULL) goto out_problem; - thread = perf_session__findnew(session, event->mmap.pid); + thread = perf_session__findnew(session, self->mmap.pid); if (thread == NULL) goto out_problem; - map = map__new(&machine->user_dsos, event->mmap.start, - event->mmap.len, event->mmap.pgoff, - event->mmap.pid, event->mmap.filename, + map = map__new(&machine->user_dsos, self->mmap.start, + self->mmap.len, self->mmap.pgoff, + self->mmap.pid, self->mmap.filename, MAP__FUNCTION); if (map == NULL) goto out_problem; @@ -624,17 +617,16 @@ int perf_event__process_mmap(union perf_event *event, return 0; } -int perf_event__process_task(union perf_event *event, - struct perf_sample *sample __used, - struct perf_session *session) +int event__process_task(event_t *self, struct sample_data *sample __used, + struct perf_session *session) { - struct thread *thread = perf_session__findnew(session, event->fork.tid); - struct thread *parent = perf_session__findnew(session, event->fork.ptid); + struct thread *thread = perf_session__findnew(session, self->fork.tid); + struct thread *parent = perf_session__findnew(session, self->fork.ptid); - dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid, - event->fork.ppid, event->fork.ptid); + dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid, + self->fork.ppid, self->fork.ptid); - if (event->header.type == PERF_RECORD_EXIT) { + if (self->header.type == PERF_RECORD_EXIT) { perf_session__remove_thread(session, thread); return 0; } @@ -648,22 +640,20 @@ int perf_event__process_task(union perf_event *event, return 0; } -int perf_event__process(union perf_event *event, struct perf_sample *sample, - struct perf_session *session) +int event__process(event_t *event, struct sample_data *sample, + struct perf_session *session) { switch (event->header.type) { case PERF_RECORD_COMM: - perf_event__process_comm(event, sample, session); + event__process_comm(event, sample, session); break; case PERF_RECORD_MMAP: - perf_event__process_mmap(event, sample, session); + event__process_mmap(event, sample, session); break; case PERF_RECORD_FORK: case PERF_RECORD_EXIT: - perf_event__process_task(event, sample, session); + event__process_task(event, sample, session); break; - case PERF_RECORD_LOST: - perf_event__process_lost(event, sample, session); default: break; } @@ -772,14 +762,12 @@ static void dso__calc_col_width(struct dso *self, struct hists *hists) self->slen_calculated = 1; } -int perf_event__preprocess_sample(const union perf_event *event, - struct perf_session *session, - struct addr_location *al, - struct perf_sample *sample, - symbol_filter_t filter) +int event__preprocess_sample(const event_t *self, struct perf_session *session, + struct addr_location *al, struct sample_data *data, + symbol_filter_t filter) { - u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - struct thread *thread = perf_session__findnew(session, event->ip.pid); + u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + struct thread *thread = perf_session__findnew(session, self->ip.pid); if (thread == NULL) return -1; @@ -801,12 +789,12 @@ int perf_event__preprocess_sample(const union perf_event *event, machine__create_kernel_maps(&session->host_machine); thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, - event->ip.pid, event->ip.ip, al); + self->ip.pid, self->ip.ip, al); dump_printf(" ...... dso: %s\n", al->map ? al->map->dso->long_name : al->level == 'H' ? "[hypervisor]" : ""); al->sym = NULL; - al->cpu = sample->cpu; + al->cpu = data->cpu; if (al->map) { if (symbol_conf.dso_list && @@ -846,3 +834,128 @@ int perf_event__preprocess_sample(const union perf_event *event, al->filtered = true; return 0; } + +static int event__parse_id_sample(const event_t *event, + struct perf_session *session, + struct sample_data *sample) +{ + const u64 *array; + u64 type; + + sample->cpu = sample->pid = sample->tid = -1; + sample->stream_id = sample->id = sample->time = -1ULL; + + if (!session->sample_id_all) + return 0; + + array = event->sample.array; + array += ((event->header.size - + sizeof(event->header)) / sizeof(u64)) - 1; + type = session->sample_type; + + if (type & PERF_SAMPLE_CPU) { + u32 *p = (u32 *)array; + sample->cpu = *p; + array--; + } + + if (type & PERF_SAMPLE_STREAM_ID) { + sample->stream_id = *array; + array--; + } + + if (type & PERF_SAMPLE_ID) { + sample->id = *array; + array--; + } + + if (type & PERF_SAMPLE_TIME) { + sample->time = *array; + array--; + } + + if (type & PERF_SAMPLE_TID) { + u32 *p = (u32 *)array; + sample->pid = p[0]; + sample->tid = p[1]; + } + + return 0; +} + +int event__parse_sample(const event_t *event, struct perf_session *session, + struct sample_data *data) +{ + const u64 *array; + u64 type; + + if (event->header.type != PERF_RECORD_SAMPLE) + return event__parse_id_sample(event, session, data); + + array = event->sample.array; + type = session->sample_type; + + if (type & PERF_SAMPLE_IP) { + data->ip = event->ip.ip; + array++; + } + + if (type & PERF_SAMPLE_TID) { + u32 *p = (u32 *)array; + data->pid = p[0]; + data->tid = p[1]; + array++; + } + + if (type & PERF_SAMPLE_TIME) { + data->time = *array; + array++; + } + + if (type & PERF_SAMPLE_ADDR) { + data->addr = *array; + array++; + } + + data->id = -1ULL; + if (type & PERF_SAMPLE_ID) { + data->id = *array; + array++; + } + + if (type & PERF_SAMPLE_STREAM_ID) { + data->stream_id = *array; + array++; + } + + if (type & PERF_SAMPLE_CPU) { + u32 *p = (u32 *)array; + data->cpu = *p; + array++; + } else + data->cpu = -1; + + if (type & PERF_SAMPLE_PERIOD) { + data->period = *array; + array++; + } + + if (type & PERF_SAMPLE_READ) { + pr_debug("PERF_SAMPLE_READ is unsuported for now\n"); + return -1; + } + + if (type & PERF_SAMPLE_CALLCHAIN) { + data->callchain = (struct ip_callchain *)array; + array += 1 + data->callchain->nr; + } + + if (type & PERF_SAMPLE_RAW) { + u32 *p = (u32 *)array; + data->raw_size = *p; + p++; + data->raw_data = p; + } + + return 0; +} diff --git a/trunk/tools/perf/util/event.h b/trunk/tools/perf/util/event.h index 9c35170fb379..cc7b52f9b492 100644 --- a/trunk/tools/perf/util/event.h +++ b/trunk/tools/perf/util/event.h @@ -61,7 +61,7 @@ struct sample_event { u64 array[]; }; -struct perf_sample { +struct sample_data { u64 ip; u32 pid, tid; u64 time; @@ -117,7 +117,7 @@ struct tracing_data_event { u32 size; }; -union perf_event { +typedef union event_union { struct perf_event_header header; struct ip_event ip; struct mmap_event mmap; @@ -130,54 +130,50 @@ union perf_event { struct event_type_event event_type; struct tracing_data_event tracing_data; struct build_id_event build_id; -}; +} event_t; -void perf_event__print_totals(void); +void event__print_totals(void); struct perf_session; struct thread_map; -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 perf_session *session); - -int perf_event__synthesize_thread_map(struct thread_map *threads, - perf_event__handler_t process, +typedef int (*event__handler_synth_t)(event_t *event, 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(perf_event__handler_t process, - struct perf_session *session, - 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, +typedef int (*event__handler_t)(event_t *event, struct sample_data *sample, + struct perf_session *session); + +int event__synthesize_thread_map(struct thread_map *threads, + event__handler_t process, + struct perf_session *session); +int event__synthesize_threads(event__handler_t process, + struct perf_session *session); +int event__synthesize_kernel_mmap(event__handler_t process, + struct perf_session *session, + struct machine *machine, + const char *symbol_name); + +int event__synthesize_modules(event__handler_t process, + struct perf_session *session, + struct machine *machine); + +int event__process_comm(event_t *self, struct sample_data *sample, + struct perf_session *session); +int event__process_lost(event_t *self, struct sample_data *sample, struct perf_session *session); +int event__process_mmap(event_t *self, struct sample_data *sample, + struct perf_session *session); +int event__process_task(event_t *self, struct sample_data *sample, + struct perf_session *session); +int event__process(event_t *event, struct sample_data *sample, + struct perf_session *session); struct addr_location; -int perf_event__preprocess_sample(const union perf_event *self, - struct perf_session *session, - struct addr_location *al, - struct perf_sample *sample, - symbol_filter_t filter); - -const char *perf_event__name(unsigned int id); +int event__preprocess_sample(const event_t *self, struct perf_session *session, + struct addr_location *al, struct sample_data *data, + symbol_filter_t filter); +int event__parse_sample(const event_t *event, struct perf_session *session, + struct sample_data *sample); -int perf_event__parse_sample(const union perf_event *event, u64 type, - bool sample_id_all, struct perf_sample *sample); +const char *event__get_event_name(unsigned int id); #endif /* __PERF_RECORD_H */ diff --git a/trunk/tools/perf/util/evlist.c b/trunk/tools/perf/util/evlist.c deleted file mode 100644 index 030ae7f05e03..000000000000 --- a/trunk/tools/perf/util/evlist.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo - * - * Parts came from builtin-{top,stat,record}.c, see those files for further - * copyright notes. - * - * Released under the GPL v2. (and only v2, not any later version) - */ -#include -#include "cpumap.h" -#include "thread_map.h" -#include "evlist.h" -#include "evsel.h" -#include "util.h" - -#include - -#include -#include - -#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) -#define SID(e, x, y) xyarray__entry(e->id, x, y) - -void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads) -{ - int i; - - for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) - INIT_HLIST_HEAD(&evlist->heads[i]); - INIT_LIST_HEAD(&evlist->entries); - perf_evlist__set_maps(evlist, cpus, threads); -} - -struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, - struct thread_map *threads) -{ - struct perf_evlist *evlist = zalloc(sizeof(*evlist)); - - if (evlist != NULL) - perf_evlist__init(evlist, cpus, threads); - - return evlist; -} - -static void perf_evlist__purge(struct perf_evlist *evlist) -{ - struct perf_evsel *pos, *n; - - list_for_each_entry_safe(pos, n, &evlist->entries, node) { - list_del_init(&pos->node); - perf_evsel__delete(pos); - } - - evlist->nr_entries = 0; -} - -void perf_evlist__exit(struct perf_evlist *evlist) -{ - free(evlist->mmap); - free(evlist->pollfd); - evlist->mmap = NULL; - evlist->pollfd = NULL; -} - -void perf_evlist__delete(struct perf_evlist *evlist) -{ - perf_evlist__purge(evlist); - perf_evlist__exit(evlist); - free(evlist); -} - -void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) -{ - list_add_tail(&entry->node, &evlist->entries); - ++evlist->nr_entries; -} - -int perf_evlist__add_default(struct perf_evlist *evlist) -{ - struct perf_event_attr attr = { - .type = PERF_TYPE_HARDWARE, - .config = PERF_COUNT_HW_CPU_CYCLES, - }; - struct perf_evsel *evsel = perf_evsel__new(&attr, 0); - - if (evsel == NULL) - return -ENOMEM; - - perf_evlist__add(evlist, evsel); - return 0; -} - -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); - return evlist->pollfd != NULL ? 0 : -ENOMEM; -} - -void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) -{ - fcntl(fd, F_SETFL, O_NONBLOCK); - evlist->pollfd[evlist->nr_fds].fd = fd; - evlist->pollfd[evlist->nr_fds].events = POLLIN; - evlist->nr_fds++; -} - -static int perf_evlist__id_hash(struct perf_evlist *evlist, struct perf_evsel *evsel, - int cpu, int thread, int fd) -{ - struct perf_sample_id *sid; - u64 read_data[4] = { 0, }; - int hash, id_idx = 1; /* The first entry is the counter value */ - - if (!(evsel->attr.read_format & PERF_FORMAT_ID) || - read(fd, &read_data, sizeof(read_data)) == -1) - return -1; - - if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - ++id_idx; - if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - ++id_idx; - - sid = SID(evsel, cpu, thread); - sid->id = read_data[id_idx]; - sid->evsel = evsel; - hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); - hlist_add_head(&sid->node, &evlist->heads[hash]); - return 0; -} - -struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) -{ - struct hlist_head *head; - struct hlist_node *pos; - struct perf_sample_id *sid; - int hash; - - if (evlist->nr_entries == 1) - return list_entry(evlist->entries.next, struct perf_evsel, node); - - hash = hash_64(id, PERF_EVLIST__HLIST_BITS); - head = &evlist->heads[hash]; - - hlist_for_each_entry(sid, pos, head, node) - if (sid->id == id) - return sid->evsel; - return NULL; -} - -union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu) -{ - /* XXX Move this to perf.c, making it generally available */ - unsigned int page_size = sysconf(_SC_PAGE_SIZE); - struct perf_mmap *md = &evlist->mmap[cpu]; - unsigned int head = perf_mmap__read_head(md); - unsigned int old = md->prev; - unsigned char *data = md->base + page_size; - union perf_event *event = NULL; - - if (evlist->overwrite) { - /* - * If we're further behind than half the buffer, there's a chance - * the writer will bite our tail and mess up the samples under us. - * - * If we somehow ended up ahead of the head, we got messed up. - * - * In either case, truncate and restart at head. - */ - int diff = head - old; - if (diff > md->mask / 2 || diff < 0) { - fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); - - /* - * head points to a known good entry, start there. - */ - old = head; - } - } - - if (old != head) { - size_t size; - - event = (union perf_event *)&data[old & md->mask]; - size = event->header.size; - - /* - * Event straddles the mmap boundary -- header should always - * be inside due to u64 alignment of output. - */ - if ((old & md->mask) + size != ((old + size) & md->mask)) { - unsigned int offset = old; - unsigned int len = min(sizeof(*event), size), cpy; - void *dst = &evlist->event_copy; - - do { - cpy = min(md->mask + 1 - (offset & md->mask), len); - memcpy(dst, &data[offset & md->mask], cpy); - offset += cpy; - dst += cpy; - len -= cpy; - } while (len); - - event = &evlist->event_copy; - } - - old += size; - } - - md->prev = old; - - if (!evlist->overwrite) - perf_mmap__write_tail(md, old); - - return event; -} - -void perf_evlist__munmap(struct perf_evlist *evlist) -{ - int cpu; - - for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { - if (evlist->mmap[cpu].base != NULL) { - munmap(evlist->mmap[cpu].base, evlist->mmap_len); - evlist->mmap[cpu].base = NULL; - } - } -} - -int perf_evlist__alloc_mmap(struct perf_evlist *evlist) -{ - evlist->mmap = zalloc(evlist->cpus->nr * sizeof(struct perf_mmap)); - return evlist->mmap != NULL ? 0 : -ENOMEM; -} - -static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot, - int mask, int fd) -{ - evlist->mmap[cpu].prev = 0; - evlist->mmap[cpu].mask = mask; - evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot, - MAP_SHARED, fd, 0); - if (evlist->mmap[cpu].base == MAP_FAILED) - return -1; - - perf_evlist__add_pollfd(evlist, fd); - return 0; -} - -/** perf_evlist__mmap - Create per cpu maps to receive events - * - * @evlist - list of events - * @pages - map length in pages - * @overwrite - overwrite older events? - * - * If overwrite is false the user needs to signal event consuption using: - * - * struct perf_mmap *m = &evlist->mmap[cpu]; - * unsigned int head = perf_mmap__read_head(m); - * - * perf_mmap__write_tail(m, head) - * - * Using perf_evlist__read_on_cpu does this automatically. - */ -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, cpu; - struct perf_evsel *first_evsel, *evsel; - const struct cpu_map *cpus = evlist->cpus; - const struct thread_map *threads = evlist->threads; - int thread, prot = PROT_READ | (overwrite ? 0 : PROT_WRITE); - - if (evlist->mmap == NULL && perf_evlist__alloc_mmap(evlist) < 0) - return -ENOMEM; - - if (evlist->pollfd == NULL && perf_evlist__alloc_pollfd(evlist) < 0) - return -ENOMEM; - - evlist->overwrite = overwrite; - evlist->mmap_len = (pages + 1) * page_size; - first_evsel = list_entry(evlist->entries.next, struct perf_evsel, node); - - list_for_each_entry(evsel, &evlist->entries, node) { - if ((evsel->attr.read_format & PERF_FORMAT_ID) && - evsel->id == NULL && - perf_evsel__alloc_id(evsel, cpus->nr, threads->nr) < 0) - return -ENOMEM; - - for (cpu = 0; cpu < cpus->nr; cpu++) { - for (thread = 0; thread < threads->nr; thread++) { - int fd = FD(evsel, cpu, thread); - - if (evsel->idx || thread) { - if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, - FD(first_evsel, cpu, 0)) != 0) - goto out_unmap; - } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0) - goto out_unmap; - - if ((evsel->attr.read_format & PERF_FORMAT_ID) && - perf_evlist__id_hash(evlist, evsel, cpu, thread, fd) < 0) - goto out_unmap; - } - } - } - - return 0; - -out_unmap: - for (cpu = 0; cpu < cpus->nr; cpu++) { - if (evlist->mmap[cpu].base != NULL) { - munmap(evlist->mmap[cpu].base, evlist->mmap_len); - evlist->mmap[cpu].base = NULL; - } - } - return -1; -} - -int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, - pid_t target_tid, const char *cpu_list) -{ - evlist->threads = thread_map__new(target_pid, target_tid); - - if (evlist->threads == NULL) - return -1; - - if (target_tid != -1) - evlist->cpus = cpu_map__dummy_new(); - else - evlist->cpus = cpu_map__new(cpu_list); - - if (evlist->cpus == NULL) - goto out_delete_threads; - - return 0; - -out_delete_threads: - thread_map__delete(evlist->threads); - return -1; -} - -void perf_evlist__delete_maps(struct perf_evlist *evlist) -{ - cpu_map__delete(evlist->cpus); - thread_map__delete(evlist->threads); - evlist->cpus = NULL; - evlist->threads = NULL; -} - -int perf_evlist__set_filters(struct perf_evlist *evlist) -{ - const struct thread_map *threads = evlist->threads; - const struct cpu_map *cpus = evlist->cpus; - struct perf_evsel *evsel; - char *filter; - int thread; - int cpu; - int err; - int fd; - - list_for_each_entry(evsel, &evlist->entries, node) { - filter = evsel->filter; - if (!filter) - continue; - for (cpu = 0; cpu < cpus->nr; cpu++) { - for (thread = 0; thread < threads->nr; thread++) { - fd = FD(evsel, cpu, thread); - err = ioctl(fd, PERF_EVENT_IOC_SET_FILTER, filter); - if (err) - return err; - } - } - } - - return 0; -} diff --git a/trunk/tools/perf/util/evlist.h b/trunk/tools/perf/util/evlist.h deleted file mode 100644 index b75805aeb7e4..000000000000 --- a/trunk/tools/perf/util/evlist.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef __PERF_EVLIST_H -#define __PERF_EVLIST_H 1 - -#include -#include "../perf.h" -#include "event.h" - -struct pollfd; -struct thread_map; -struct cpu_map; - -#define PERF_EVLIST__HLIST_BITS 8 -#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) - -struct perf_evlist { - struct list_head entries; - struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; - int nr_entries; - int nr_fds; - int mmap_len; - bool overwrite; - union perf_event event_copy; - struct perf_mmap *mmap; - struct pollfd *pollfd; - struct thread_map *threads; - struct cpu_map *cpus; -}; - -struct perf_evsel; - -struct perf_evlist *perf_evlist__new(struct cpu_map *cpus, - struct thread_map *threads); -void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads); -void perf_evlist__exit(struct perf_evlist *evlist); -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__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); - -union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *self, int cpu); - -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); - -static inline void perf_evlist__set_maps(struct perf_evlist *evlist, - struct cpu_map *cpus, - struct thread_map *threads) -{ - evlist->cpus = cpus; - evlist->threads = threads; -} - -int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, - pid_t target_tid, const char *cpu_list); -void perf_evlist__delete_maps(struct perf_evlist *evlist); -int perf_evlist__set_filters(struct perf_evlist *evlist); - -#endif /* __PERF_EVLIST_H */ diff --git a/trunk/tools/perf/util/evsel.c b/trunk/tools/perf/util/evsel.c index 8083d5126fca..d8575d31ee6c 100644 --- a/trunk/tools/perf/util/evsel.c +++ b/trunk/tools/perf/util/evsel.c @@ -1,34 +1,20 @@ -/* - * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo - * - * Parts came from builtin-{top,stat,record}.c, see those files for further - * copyright notes. - * - * Released under the GPL v2. (and only v2, not any later version) - */ - #include "evsel.h" -#include "evlist.h" +#include "../perf.h" #include "util.h" #include "cpumap.h" -#include "thread_map.h" +#include "thread.h" #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) -void perf_evsel__init(struct perf_evsel *evsel, - struct perf_event_attr *attr, int idx) -{ - evsel->idx = idx; - evsel->attr = *attr; - INIT_LIST_HEAD(&evsel->node); -} - struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) { struct perf_evsel *evsel = zalloc(sizeof(*evsel)); - if (evsel != NULL) - perf_evsel__init(evsel, attr, idx); + if (evsel != NULL) { + evsel->idx = idx; + evsel->attr = *attr; + INIT_LIST_HEAD(&evsel->node); + } return evsel; } @@ -39,12 +25,6 @@ int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) return evsel->fd != NULL ? 0 : -ENOMEM; } -int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) -{ - evsel->id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); - return evsel->id != NULL ? 0 : -ENOMEM; -} - int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) { evsel->counts = zalloc((sizeof(*evsel->counts) + @@ -58,12 +38,6 @@ void perf_evsel__free_fd(struct perf_evsel *evsel) evsel->fd = NULL; } -void perf_evsel__free_id(struct perf_evsel *evsel) -{ - xyarray__delete(evsel->id); - evsel->id = NULL; -} - void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) { int cpu, thread; @@ -75,18 +49,10 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) } } -void perf_evsel__exit(struct perf_evsel *evsel) +void perf_evsel__delete(struct perf_evsel *evsel) { assert(list_empty(&evsel->node)); xyarray__delete(evsel->fd); - xyarray__delete(evsel->id); -} - -void perf_evsel__delete(struct perf_evsel *evsel) -{ - perf_evsel__exit(evsel); - close_cgroup(evsel->cgrp); - free(evsel->name); free(evsel); } @@ -162,51 +128,21 @@ int __perf_evsel__read(struct perf_evsel *evsel, } static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit) + struct thread_map *threads) { int cpu, thread; - unsigned long flags = 0; - int pid = -1; if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) return -1; - if (evsel->cgrp) { - flags = PERF_FLAG_PID_CGROUP; - pid = evsel->cgrp->fd; - } - for (cpu = 0; cpu < cpus->nr; cpu++) { - int group_fd = -1; - /* - * Don't allow mmap() of inherited per-task counters. This - * would create a performance issue due to all children writing - * to the same buffer. - * - * FIXME: - * Proper fix is not to pass 'inherit' to perf_evsel__open*, - * but a 'flags' parameter, with 'group' folded there as well, - * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if - * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is - * set. Lets go for the minimal fix first tho. - */ - evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit; - for (thread = 0; thread < threads->nr; thread++) { - - if (!evsel->cgrp) - pid = threads->map[thread]; - FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, - pid, - cpus->map[cpu], - group_fd, flags); + threads->map[thread], + cpus->map[cpu], -1, 0); if (FD(evsel, cpu, thread) < 0) goto out_close; - - if (group && group_fd == -1) - group_fd = FD(evsel, cpu, thread); } } @@ -239,9 +175,10 @@ static struct { .threads = { -1, }, }; -int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit) +int perf_evsel__open(struct perf_evsel *evsel, + struct cpu_map *cpus, struct thread_map *threads) { + if (cpus == NULL) { /* Work around old compiler warnings about strict aliasing */ cpus = &empty_cpu_map.map; @@ -250,135 +187,15 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, if (threads == NULL) threads = &empty_thread_map.map; - return __perf_evsel__open(evsel, cpus, threads, group, inherit); -} - -int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus, bool group, bool inherit) -{ - return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit); -} - -int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads, bool group, bool inherit) -{ - return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); + return __perf_evsel__open(evsel, cpus, threads); } -static int perf_event__parse_id_sample(const union perf_event *event, u64 type, - struct perf_sample *sample) +int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) { - const u64 *array = event->sample.array; - - array += ((event->header.size - - sizeof(event->header)) / sizeof(u64)) - 1; - - if (type & PERF_SAMPLE_CPU) { - u32 *p = (u32 *)array; - sample->cpu = *p; - array--; - } - - if (type & PERF_SAMPLE_STREAM_ID) { - sample->stream_id = *array; - array--; - } - - if (type & PERF_SAMPLE_ID) { - sample->id = *array; - array--; - } - - if (type & PERF_SAMPLE_TIME) { - sample->time = *array; - array--; - } - - if (type & PERF_SAMPLE_TID) { - u32 *p = (u32 *)array; - sample->pid = p[0]; - sample->tid = p[1]; - } - - return 0; + return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); } -int perf_event__parse_sample(const union perf_event *event, u64 type, - bool sample_id_all, struct perf_sample *data) +int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) { - const u64 *array; - - data->cpu = data->pid = data->tid = -1; - data->stream_id = data->id = data->time = -1ULL; - - if (event->header.type != PERF_RECORD_SAMPLE) { - if (!sample_id_all) - return 0; - return perf_event__parse_id_sample(event, type, data); - } - - array = event->sample.array; - - if (type & PERF_SAMPLE_IP) { - data->ip = event->ip.ip; - array++; - } - - if (type & PERF_SAMPLE_TID) { - u32 *p = (u32 *)array; - data->pid = p[0]; - data->tid = p[1]; - array++; - } - - if (type & PERF_SAMPLE_TIME) { - data->time = *array; - array++; - } - - if (type & PERF_SAMPLE_ADDR) { - data->addr = *array; - array++; - } - - data->id = -1ULL; - if (type & PERF_SAMPLE_ID) { - data->id = *array; - array++; - } - - if (type & PERF_SAMPLE_STREAM_ID) { - data->stream_id = *array; - array++; - } - - if (type & PERF_SAMPLE_CPU) { - u32 *p = (u32 *)array; - data->cpu = *p; - array++; - } - - if (type & PERF_SAMPLE_PERIOD) { - data->period = *array; - array++; - } - - if (type & PERF_SAMPLE_READ) { - fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n"); - return -1; - } - - if (type & PERF_SAMPLE_CALLCHAIN) { - data->callchain = (struct ip_callchain *)array; - array += 1 + data->callchain->nr; - } - - if (type & PERF_SAMPLE_RAW) { - u32 *p = (u32 *)array; - data->raw_size = *p; - p++; - data->raw_data = p; - } - - return 0; + return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); } diff --git a/trunk/tools/perf/util/evsel.h b/trunk/tools/perf/util/evsel.h index f6fc8f651a25..b2d755fe88a5 100644 --- a/trunk/tools/perf/util/evsel.h +++ b/trunk/tools/perf/util/evsel.h @@ -6,7 +6,6 @@ #include "../../../include/linux/perf_event.h" #include "types.h" #include "xyarray.h" -#include "cgroup.h" struct perf_counts_values { union { @@ -25,60 +24,31 @@ struct perf_counts { struct perf_counts_values cpu[]; }; -struct perf_evsel; - -/* - * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are - * more than one entry in the evlist. - */ -struct perf_sample_id { - struct hlist_node node; - u64 id; - struct perf_evsel *evsel; -}; - -/** struct perf_evsel - event selector - * - * @name - Can be set to retain the original event name passed by the user, - * so that when showing results in tools such as 'perf stat', we - * show the name used, not some alias. - */ struct perf_evsel { struct list_head node; struct perf_event_attr attr; char *filter; struct xyarray *fd; - struct xyarray *id; struct perf_counts *counts; int idx; - char *name; void *priv; - struct cgroup_sel *cgrp; }; struct cpu_map; struct thread_map; -struct perf_evlist; struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); -void perf_evsel__init(struct perf_evsel *evsel, - struct perf_event_attr *attr, int idx); -void perf_evsel__exit(struct perf_evsel *evsel); void perf_evsel__delete(struct perf_evsel *evsel); 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); void perf_evsel__free_fd(struct perf_evsel *evsel); -void perf_evsel__free_id(struct perf_evsel *evsel); void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); -int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus, bool group, bool inherit); -int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads, bool group, bool inherit); -int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit); +int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus); +int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads); +int perf_evsel__open(struct perf_evsel *evsel, + struct cpu_map *cpus, struct thread_map *threads); #define perf_evsel__match(evsel, t, c) \ (evsel->attr.type == PERF_TYPE_##t && \ diff --git a/trunk/tools/perf/util/exec_cmd.c b/trunk/tools/perf/util/exec_cmd.c index 7adf4ad15d8f..67eeff571568 100644 --- a/trunk/tools/perf/util/exec_cmd.c +++ b/trunk/tools/perf/util/exec_cmd.c @@ -11,12 +11,31 @@ static const char *argv0_path; const char *system_path(const char *path) { +#ifdef RUNTIME_PREFIX + static const char *prefix; +#else static const char *prefix = PREFIX; +#endif struct strbuf d = STRBUF_INIT; if (is_absolute_path(path)) return path; +#ifdef RUNTIME_PREFIX + assert(argv0_path); + assert(is_absolute_path(argv0_path)); + + if (!prefix && + !(prefix = strip_path_suffix(argv0_path, PERF_EXEC_PATH)) && + !(prefix = strip_path_suffix(argv0_path, BINDIR)) && + !(prefix = strip_path_suffix(argv0_path, "perf"))) { + prefix = PREFIX; + fprintf(stderr, "RUNTIME_PREFIX requested, " + "but prefix computation failed. " + "Using static fallback '%s'.\n", prefix); + } +#endif + strbuf_addf(&d, "%s/%s", prefix, path); path = strbuf_detach(&d, NULL); return path; diff --git a/trunk/tools/perf/util/header.c b/trunk/tools/perf/util/header.c index 72c124dc5781..f6a929e74981 100644 --- a/trunk/tools/perf/util/header.c +++ b/trunk/tools/perf/util/header.c @@ -8,7 +8,6 @@ #include #include -#include "evlist.h" #include "util.h" #include "header.h" #include "../perf.h" @@ -429,8 +428,7 @@ static bool perf_session__read_build_ids(struct perf_session *self, bool with_hi return ret; } -static int perf_header__adds_write(struct perf_header *self, - struct perf_evlist *evlist, int fd) +static int perf_header__adds_write(struct perf_header *self, int fd) { int nr_sections; struct perf_session *session; @@ -465,7 +463,7 @@ static int perf_header__adds_write(struct perf_header *self, /* Write trace info */ trace_sec->offset = lseek(fd, 0, SEEK_CUR); - read_tracing_data(fd, &evlist->entries); + read_tracing_data(fd, &evsel_list); trace_sec->size = lseek(fd, 0, SEEK_CUR) - trace_sec->offset; } @@ -515,8 +513,7 @@ int perf_header__write_pipe(int fd) return 0; } -int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, - int fd, bool at_exit) +int perf_header__write(struct perf_header *self, int fd, bool at_exit) { struct perf_file_header f_header; struct perf_file_attr f_attr; @@ -569,7 +566,7 @@ int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, self->data_offset = lseek(fd, 0, SEEK_CUR); if (at_exit) { - err = perf_header__adds_write(self, evlist, fd); + err = perf_header__adds_write(self, fd); if (err < 0) return err; } @@ -1000,11 +997,11 @@ perf_header__find_attr(u64 id, struct perf_header *header) return NULL; } -int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, - perf_event__handler_t process, - struct perf_session *session) +int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, + event__handler_t process, + struct perf_session *session) { - union perf_event *ev; + event_t *ev; size_t size; int err; @@ -1031,9 +1028,8 @@ int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, return err; } -int perf_event__synthesize_attrs(struct perf_header *self, - perf_event__handler_t process, - struct perf_session *session) +int event__synthesize_attrs(struct perf_header *self, event__handler_t process, + struct perf_session *session) { struct perf_header_attr *attr; int i, err = 0; @@ -1041,8 +1037,8 @@ int perf_event__synthesize_attrs(struct perf_header *self, for (i = 0; i < self->attrs; i++) { attr = self->attr[i]; - err = perf_event__synthesize_attr(&attr->attr, attr->ids, - attr->id, process, session); + err = event__synthesize_attr(&attr->attr, attr->ids, attr->id, + process, session); if (err) { pr_debug("failed to create perf header attribute\n"); return err; @@ -1052,22 +1048,21 @@ int perf_event__synthesize_attrs(struct perf_header *self, return err; } -int perf_event__process_attr(union perf_event *event, - struct perf_session *session) +int event__process_attr(event_t *self, struct perf_session *session) { struct perf_header_attr *attr; unsigned int i, ids, n_ids; - attr = perf_header_attr__new(&event->attr.attr); + attr = perf_header_attr__new(&self->attr.attr); if (attr == NULL) return -ENOMEM; - ids = event->header.size; - ids -= (void *)&event->attr.id - (void *)event; + ids = self->header.size; + ids -= (void *)&self->attr.id - (void *)self; n_ids = ids / sizeof(u64); for (i = 0; i < n_ids; i++) { - if (perf_header_attr__add_id(attr, event->attr.id[i]) < 0) { + if (perf_header_attr__add_id(attr, self->attr.id[i]) < 0) { perf_header_attr__delete(attr); return -ENOMEM; } @@ -1083,11 +1078,11 @@ int perf_event__process_attr(union perf_event *event, return 0; } -int perf_event__synthesize_event_type(u64 event_id, char *name, - perf_event__handler_t process, - struct perf_session *session) +int event__synthesize_event_type(u64 event_id, char *name, + event__handler_t process, + struct perf_session *session) { - union perf_event ev; + event_t ev; size_t size = 0; int err = 0; @@ -1108,8 +1103,8 @@ int perf_event__synthesize_event_type(u64 event_id, char *name, return err; } -int perf_event__synthesize_event_types(perf_event__handler_t process, - struct perf_session *session) +int event__synthesize_event_types(event__handler_t process, + struct perf_session *session) { struct perf_trace_event_type *type; int i, err = 0; @@ -1117,9 +1112,8 @@ int perf_event__synthesize_event_types(perf_event__handler_t process, for (i = 0; i < event_count; i++) { type = &events[i]; - err = perf_event__synthesize_event_type(type->event_id, - type->name, process, - session); + err = event__synthesize_event_type(type->event_id, type->name, + process, session); if (err) { pr_debug("failed to create perf header event type\n"); return err; @@ -1129,28 +1123,28 @@ int perf_event__synthesize_event_types(perf_event__handler_t process, return err; } -int perf_event__process_event_type(union perf_event *event, - struct perf_session *session __unused) +int event__process_event_type(event_t *self, + struct perf_session *session __unused) { - if (perf_header__push_event(event->event_type.event_type.event_id, - event->event_type.event_type.name) < 0) + if (perf_header__push_event(self->event_type.event_type.event_id, + self->event_type.event_type.name) < 0) return -ENOMEM; return 0; } -int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, - perf_event__handler_t process, +int event__synthesize_tracing_data(int fd, struct list_head *pattrs, + event__handler_t process, struct perf_session *session __unused) { - union perf_event ev; + event_t ev; ssize_t size = 0, aligned_size = 0, padding; - int err __used = 0; + int err = 0; memset(&ev, 0, sizeof(ev)); ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; - size = read_tracing_data_size(fd, &evlist->entries); + size = read_tracing_data_size(fd, pattrs); if (size <= 0) return size; aligned_size = ALIGN(size, sizeof(u64)); @@ -1160,16 +1154,16 @@ int perf_event__synthesize_tracing_data(int fd, struct perf_evlist *evlist, process(&ev, NULL, session); - err = read_tracing_data(fd, &evlist->entries); + err = read_tracing_data(fd, pattrs); write_padded(fd, NULL, 0, padding); return aligned_size; } -int perf_event__process_tracing_data(union perf_event *event, - struct perf_session *session) +int event__process_tracing_data(event_t *self, + struct perf_session *session) { - ssize_t size_read, padding, size = event->tracing_data.size; + ssize_t size_read, padding, size = self->tracing_data.size; off_t offset = lseek(session->fd, 0, SEEK_CUR); char buf[BUFSIZ]; @@ -1195,12 +1189,12 @@ int perf_event__process_tracing_data(union perf_event *event, return size_read + padding; } -int perf_event__synthesize_build_id(struct dso *pos, u16 misc, - perf_event__handler_t process, - struct machine *machine, - struct perf_session *session) +int event__synthesize_build_id(struct dso *pos, u16 misc, + event__handler_t process, + struct machine *machine, + struct perf_session *session) { - union perf_event ev; + event_t ev; size_t len; int err = 0; @@ -1223,11 +1217,11 @@ int perf_event__synthesize_build_id(struct dso *pos, u16 misc, return err; } -int perf_event__process_build_id(union perf_event *event, - struct perf_session *session) +int event__process_build_id(event_t *self, + struct perf_session *session) { - __event_process_build_id(&event->build_id, - event->build_id.filename, + __event_process_build_id(&self->build_id, + self->build_id.filename, session); return 0; } diff --git a/trunk/tools/perf/util/header.h b/trunk/tools/perf/util/header.h index f042cebcec1e..33f16be7b72f 100644 --- a/trunk/tools/perf/util/header.h +++ b/trunk/tools/perf/util/header.h @@ -65,11 +65,8 @@ struct perf_header { int perf_header__init(struct perf_header *self); void perf_header__exit(struct perf_header *self); -struct perf_evlist; - int perf_header__read(struct perf_session *session, int fd); -int perf_header__write(struct perf_header *self, struct perf_evlist *evlist, - int fd, bool at_exit); +int perf_header__write(struct perf_header *self, int fd, bool at_exit); int perf_header__write_pipe(int fd); int perf_header__add_attr(struct perf_header *self, @@ -100,32 +97,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_event_attr *attr, u16 ids, u64 *id, - perf_event__handler_t process, - struct perf_session *session); -int perf_event__synthesize_attrs(struct perf_header *self, - perf_event__handler_t process, +int event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, + event__handler_t process, + struct perf_session *session); +int event__synthesize_attrs(struct perf_header *self, + event__handler_t process, + struct perf_session *session); +int event__process_attr(event_t *self, struct perf_session *session); + +int event__synthesize_event_type(u64 event_id, char *name, + event__handler_t process, struct perf_session *session); -int perf_event__process_attr(union perf_event *event, struct perf_session *session); - -int perf_event__synthesize_event_type(u64 event_id, char *name, - 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, +int event__synthesize_event_types(event__handler_t process, + struct perf_session *session); +int event__process_event_type(event_t *self, + struct perf_session *session); + +int event__synthesize_tracing_data(int fd, struct list_head *pattrs, + event__handler_t process, struct perf_session *session); +int event__process_tracing_data(event_t *self, + struct perf_session *session); + +int event__synthesize_build_id(struct dso *pos, u16 misc, + event__handler_t process, + struct machine *machine, + struct perf_session *session); +int event__process_build_id(event_t *self, 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 dso *pos, u16 misc, - perf_event__handler_t process, - struct machine *machine, - struct perf_session *session); -int perf_event__process_build_id(union perf_event *event, - struct perf_session *session); #endif /* __PERF_HEADER_H */ diff --git a/trunk/tools/perf/util/hist.c b/trunk/tools/perf/util/hist.c index da2899e8c6f8..df51560f16f7 100644 --- a/trunk/tools/perf/util/hist.c +++ b/trunk/tools/perf/util/hist.c @@ -1,4 +1,3 @@ -#include "annotate.h" #include "util.h" #include "build-id.h" #include "hist.h" @@ -212,9 +211,7 @@ void hist_entry__free(struct hist_entry *he) * collapse the histogram */ -static bool hists__collapse_insert_entry(struct hists *self, - struct rb_root *root, - struct hist_entry *he) +static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he) { struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; @@ -229,11 +226,8 @@ static bool hists__collapse_insert_entry(struct hists *self, if (!cmp) { iter->period += he->period; - if (symbol_conf.use_callchain) { - callchain_cursor_reset(&self->callchain_cursor); - callchain_merge(&self->callchain_cursor, iter->callchain, - he->callchain); - } + if (symbol_conf.use_callchain) + callchain_merge(iter->callchain, he->callchain); hist_entry__free(he); return false; } @@ -268,7 +262,7 @@ void hists__collapse_resort(struct hists *self) next = rb_next(&n->rb_node); rb_erase(&n->rb_node, &self->entries); - if (hists__collapse_insert_entry(self, &tmp, n)) + if (collapse__insert_entry(&tmp, n)) hists__inc_nr_entries(self, n); } @@ -431,7 +425,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct callchain_node *self, u64 cumul; child = rb_entry(node, struct callchain_node, rb_node); - cumul = callchain_cumul_hits(child); + cumul = cumul_hits(child); remaining -= cumul; /* @@ -953,14 +947,225 @@ void hists__filter_by_thread(struct hists *self, const struct thread *thread) } } -int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) +static int symbol__alloc_hist(struct symbol *self) +{ + struct sym_priv *priv = symbol__priv(self); + const int size = (sizeof(*priv->hist) + + (self->end - self->start) * sizeof(u64)); + + priv->hist = zalloc(size); + return priv->hist == NULL ? -1 : 0; +} + +int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip) +{ + unsigned int sym_size, offset; + struct symbol *sym = self->ms.sym; + struct sym_priv *priv; + struct sym_hist *h; + + if (!sym || !self->ms.map) + return 0; + + priv = symbol__priv(sym); + if (priv->hist == NULL && symbol__alloc_hist(sym) < 0) + return -ENOMEM; + + sym_size = sym->end - sym->start; + offset = ip - sym->start; + + pr_debug3("%s: ip=%#" PRIx64 "\n", __func__, self->ms.map->unmap_ip(self->ms.map, ip)); + + if (offset >= sym_size) + return 0; + + h = priv->hist; + h->sum++; + h->ip[offset]++; + + pr_debug3("%#" PRIx64 " %s: period++ [ip: %#" PRIx64 ", %#" PRIx64 + "] => %" PRIu64 "\n", self->ms.sym->start, self->ms.sym->name, + ip, ip - self->ms.sym->start, h->ip[offset]); + return 0; +} + +static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) +{ + struct objdump_line *self = malloc(sizeof(*self) + privsize); + + if (self != NULL) { + self->offset = offset; + self->line = line; + } + + return self; +} + +void objdump_line__free(struct objdump_line *self) +{ + free(self->line); + free(self); +} + +static void objdump__add_line(struct list_head *head, struct objdump_line *line) +{ + list_add_tail(&line->node, head); +} + +struct objdump_line *objdump__get_next_ip_line(struct list_head *head, + struct objdump_line *pos) +{ + list_for_each_entry_continue(pos, head, node) + if (pos->offset >= 0) + return pos; + + return NULL; +} + +static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file, + struct list_head *head, size_t privsize) { - return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); + struct symbol *sym = self->ms.sym; + struct objdump_line *objdump_line; + char *line = NULL, *tmp, *tmp2, *c; + size_t line_len; + s64 line_ip, offset = -1; + + if (getline(&line, &line_len, file) < 0) + return -1; + + if (!line) + return -1; + + while (line_len != 0 && isspace(line[line_len - 1])) + line[--line_len] = '\0'; + + c = strchr(line, '\n'); + if (c) + *c = 0; + + line_ip = -1; + + /* + * Strip leading spaces: + */ + tmp = line; + while (*tmp) { + if (*tmp != ' ') + break; + tmp++; + } + + if (*tmp) { + /* + * Parse hexa addresses followed by ':' + */ + line_ip = strtoull(tmp, &tmp2, 16); + if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0') + line_ip = -1; + } + + if (line_ip != -1) { + u64 start = map__rip_2objdump(self->ms.map, sym->start), + end = map__rip_2objdump(self->ms.map, sym->end); + + offset = line_ip - start; + if (offset < 0 || (u64)line_ip > end) + offset = -1; + } + + objdump_line = objdump_line__new(offset, line, privsize); + if (objdump_line == NULL) { + free(line); + return -1; + } + objdump__add_line(head, objdump_line); + + return 0; } -int hist_entry__annotate(struct hist_entry *he, size_t privsize) +int hist_entry__annotate(struct hist_entry *self, struct list_head *head, + size_t privsize) { - return symbol__annotate(he->ms.sym, he->ms.map, privsize); + struct symbol *sym = self->ms.sym; + struct map *map = self->ms.map; + struct dso *dso = map->dso; + char *filename = dso__build_id_filename(dso, NULL, 0); + bool free_filename = true; + char command[PATH_MAX * 2]; + FILE *file; + int err = 0; + u64 len; + char symfs_filename[PATH_MAX]; + + if (filename) { + snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", + symbol_conf.symfs, filename); + } + + if (filename == NULL) { + if (dso->has_build_id) { + pr_err("Can't annotate %s: not enough memory\n", + sym->name); + return -ENOMEM; + } + goto fallback; + } else if (readlink(symfs_filename, command, sizeof(command)) < 0 || + strstr(command, "[kernel.kallsyms]") || + access(symfs_filename, R_OK)) { + free(filename); +fallback: + /* + * If we don't have build-ids or the build-id file isn't in the + * cache, or is just a kallsyms file, well, lets hope that this + * DSO is the same as when 'perf record' ran. + */ + filename = dso->long_name; + snprintf(symfs_filename, sizeof(symfs_filename), "%s%s", + symbol_conf.symfs, filename); + free_filename = false; + } + + if (dso->origin == DSO__ORIG_KERNEL) { + if (dso->annotate_warned) + goto out_free_filename; + err = -ENOENT; + dso->annotate_warned = 1; + pr_err("Can't annotate %s: No vmlinux file was found in the " + "path\n", sym->name); + goto out_free_filename; + } + + pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, + filename, sym->name, map->unmap_ip(map, sym->start), + map->unmap_ip(map, sym->end)); + + len = sym->end - sym->start; + + pr_debug("annotating [%p] %30s : [%p] %30s\n", + dso, dso->long_name, sym, sym->name); + + snprintf(command, sizeof(command), + "objdump --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand", + map__rip_2objdump(map, sym->start), + map__rip_2objdump(map, sym->end), + symfs_filename, filename); + + pr_debug("Executing: %s\n", command); + + file = popen(command, "r"); + if (!file) + goto out_free_filename; + + while (!feof(file)) + if (hist_entry__parse_objdump_line(self, file, head, privsize) < 0) + break; + + pclose(file); +out_free_filename: + if (free_filename) + free(filename); + return err; } void hists__inc_nr_events(struct hists *self, u32 type) @@ -975,7 +1180,7 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp) size_t ret = 0; for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { - const char *name = perf_event__name(i); + const char *name = event__get_event_name(i); if (!strcmp(name, "UNKNOWN")) continue; diff --git a/trunk/tools/perf/util/hist.h b/trunk/tools/perf/util/hist.h index 37c79089de09..ee789856a8c9 100644 --- a/trunk/tools/perf/util/hist.h +++ b/trunk/tools/perf/util/hist.h @@ -9,6 +9,33 @@ extern struct callchain_param callchain_param; struct hist_entry; struct addr_location; struct symbol; +struct rb_root; + +struct objdump_line { + struct list_head node; + s64 offset; + char *line; +}; + +void objdump_line__free(struct objdump_line *self); +struct objdump_line *objdump__get_next_ip_line(struct list_head *head, + struct objdump_line *pos); + +struct sym_hist { + u64 sum; + u64 ip[0]; +}; + +struct sym_ext { + struct rb_node node; + double percent; + char *path; +}; + +struct sym_priv { + struct sym_hist *hist; + struct sym_ext *ext; +}; /* * The kernel collects the number of events it couldn't send in a stretch and @@ -50,8 +77,6 @@ struct hists { u64 event_stream; u32 type; u16 col_len[HISTC_NR_COLS]; - /* Best would be to reuse the session callchain cursor */ - struct callchain_cursor callchain_cursor; }; struct hist_entry *__hists__add_entry(struct hists *self, @@ -77,8 +102,9 @@ size_t hists__fprintf_nr_events(struct hists *self, FILE *fp); size_t hists__fprintf(struct hists *self, struct hists *pair, bool show_displacement, FILE *fp); -int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); -int hist_entry__annotate(struct hist_entry *self, size_t privsize); +int hist_entry__inc_addr_samples(struct hist_entry *self, u64 ip); +int hist_entry__annotate(struct hist_entry *self, struct list_head *head, + size_t privsize); void hists__filter_by_dso(struct hists *self, const struct dso *dso); void hists__filter_by_thread(struct hists *self, const struct thread *thread); @@ -90,20 +116,18 @@ bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len); #ifdef NO_NEWT_SUPPORT static inline int hists__browse(struct hists *self __used, const char *helpline __used, - const char *ev_name __used, int evidx __used) + const char *ev_name __used) { return 0; } static inline int hists__tui_browse_tree(struct rb_root *self __used, - const char *help __used, - int evidx __used) + const char *help __used) { return 0; } -static inline int hist_entry__tui_annotate(struct hist_entry *self __used, - int evidx __used) +static inline int hist_entry__tui_annotate(struct hist_entry *self __used) { return 0; } @@ -112,13 +136,13 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used, #else #include int hists__browse(struct hists *self, const char *helpline, - const char *ev_name, int evidx); -int hist_entry__tui_annotate(struct hist_entry *self, int evidx); + const char *ev_name); +int hist_entry__tui_annotate(struct hist_entry *self); #define KEY_LEFT NEWT_KEY_LEFT #define KEY_RIGHT NEWT_KEY_RIGHT -int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx); +int hists__tui_browse_tree(struct rb_root *self, const char *help); #endif unsigned int hists__sort_list_width(struct hists *self); diff --git a/trunk/tools/perf/util/include/linux/list.h b/trunk/tools/perf/util/include/linux/list.h index 356c7e467b83..f5ca26e53fbb 100644 --- a/trunk/tools/perf/util/include/linux/list.h +++ b/trunk/tools/perf/util/include/linux/list.h @@ -1,4 +1,3 @@ -#include #include "../../../../include/linux/list.h" #ifndef PERF_LIST_H diff --git a/trunk/tools/perf/util/parse-events.c b/trunk/tools/perf/util/parse-events.c index 54a7e2634d58..135f69baf966 100644 --- a/trunk/tools/perf/util/parse-events.c +++ b/trunk/tools/perf/util/parse-events.c @@ -1,7 +1,6 @@ #include "../../../include/linux/hw_breakpoint.h" #include "util.h" #include "../perf.h" -#include "evlist.h" #include "evsel.h" #include "parse-options.h" #include "parse-events.h" @@ -12,6 +11,10 @@ #include "header.h" #include "debugfs.h" +int nr_counters; + +LIST_HEAD(evsel_list); + struct event_symbol { u8 type; u64 config; @@ -268,9 +271,6 @@ const char *event_name(struct perf_evsel *evsel) u64 config = evsel->attr.config; int type = evsel->attr.type; - if (evsel->name) - return evsel->name; - return __event_name(type, config); } @@ -449,8 +449,8 @@ parse_single_tracepoint_event(char *sys_name, /* sys + ':' + event + ':' + flags*/ #define MAX_EVOPT_LEN (MAX_EVENT_LENGTH * 2 + 2 + 128) static enum event_result -parse_multiple_tracepoint_event(const struct option *opt, char *sys_name, - const char *evt_exp, char *flags) +parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, + char *flags) { char evt_path[MAXPATHLEN]; struct dirent *evt_ent; @@ -483,16 +483,15 @@ parse_multiple_tracepoint_event(const struct option *opt, char *sys_name, if (len < 0) return EVT_FAILED; - if (parse_events(opt, event_opt, 0)) + if (parse_events(NULL, event_opt, 0)) return EVT_FAILED; } return EVT_HANDLED_ALL; } -static enum event_result -parse_tracepoint_event(const struct option *opt, const char **strp, - struct perf_event_attr *attr) +static enum event_result parse_tracepoint_event(const char **strp, + struct perf_event_attr *attr) { const char *evt_name; char *flags = NULL, *comma_loc; @@ -531,7 +530,7 @@ parse_tracepoint_event(const struct option *opt, const char **strp, return EVT_FAILED; if (strpbrk(evt_name, "*?")) { *strp += strlen(sys_name) + evt_length + 1; /* 1 == the ':' */ - return parse_multiple_tracepoint_event(opt, sys_name, evt_name, + return parse_multiple_tracepoint_event(sys_name, evt_name, flags); } else { return parse_single_tracepoint_event(sys_name, evt_name, @@ -741,12 +740,11 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr) * Symbolic names are (almost) exactly matched. */ static enum event_result -parse_event_symbols(const struct option *opt, const char **str, - struct perf_event_attr *attr) +parse_event_symbols(const char **str, struct perf_event_attr *attr) { enum event_result ret; - ret = parse_tracepoint_event(opt, str, attr); + ret = parse_tracepoint_event(str, attr); if (ret != EVT_FAILED) goto modifier; @@ -780,17 +778,14 @@ parse_event_symbols(const struct option *opt, const char **str, return ret; } -int parse_events(const struct option *opt, const char *str, int unset __used) +int parse_events(const struct option *opt __used, const char *str, int unset __used) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; struct perf_event_attr attr; enum event_result ret; - const char *ostr; for (;;) { - ostr = str; memset(&attr, 0, sizeof(attr)); - ret = parse_event_symbols(opt, &str, &attr); + ret = parse_event_symbols(&str, &attr); if (ret == EVT_FAILED) return -1; @@ -799,15 +794,12 @@ int parse_events(const struct option *opt, const char *str, int unset __used) if (ret != EVT_HANDLED_ALL) { struct perf_evsel *evsel; - evsel = perf_evsel__new(&attr, evlist->nr_entries); + evsel = perf_evsel__new(&attr, + nr_counters); if (evsel == NULL) return -1; - perf_evlist__add(evlist, evsel); - - evsel->name = calloc(str - ostr + 1, 1); - if (!evsel->name) - return -1; - strncpy(evsel->name, ostr, str - ostr); + list_add_tail(&evsel->node, &evsel_list); + ++nr_counters; } if (*str == 0) @@ -821,14 +813,13 @@ int parse_events(const struct option *opt, const char *str, int unset __used) return 0; } -int parse_filter(const struct option *opt, const char *str, +int parse_filter(const struct option *opt __used, const char *str, int unset __used) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; struct perf_evsel *last = NULL; - if (evlist->nr_entries > 0) - last = list_entry(evlist->entries.prev, struct perf_evsel, node); + if (!list_empty(&evsel_list)) + last = list_entry(evsel_list.prev, struct perf_evsel, node); if (last == NULL || last->attr.type != PERF_TYPE_TRACEPOINT) { fprintf(stderr, @@ -858,7 +849,7 @@ static const char * const event_type_descriptors[] = { * Print the events from /tracing/events */ -void print_tracepoint_events(const char *subsys_glob, const char *event_glob) +static void print_tracepoint_events(void) { DIR *sys_dir, *evt_dir; struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; @@ -873,9 +864,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) return; for_each_subsystem(sys_dir, sys_dirent, sys_next) { - if (subsys_glob != NULL && - !strglobmatch(sys_dirent.d_name, subsys_glob)) - continue; snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path, sys_dirent.d_name); @@ -884,10 +872,6 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob) continue; for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { - if (event_glob != NULL && - !strglobmatch(evt_dirent.d_name, event_glob)) - continue; - snprintf(evt_path, MAXPATHLEN, "%s:%s", sys_dirent.d_name, evt_dirent.d_name); printf(" %-42s [%s]\n", evt_path, @@ -939,61 +923,13 @@ int is_valid_tracepoint(const char *event_string) return 0; } -void print_events_type(u8 type) -{ - struct event_symbol *syms = event_symbols; - unsigned int i; - char name[64]; - - for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { - if (type != syms->type) - continue; - - if (strlen(syms->alias)) - snprintf(name, sizeof(name), "%s OR %s", - syms->symbol, syms->alias); - else - snprintf(name, sizeof(name), "%s", syms->symbol); - - printf(" %-42s [%s]\n", name, - event_type_descriptors[type]); - } -} - -int print_hwcache_events(const char *event_glob) -{ - unsigned int type, op, i, printed = 0; - - for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { - for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { - /* skip invalid cache type */ - if (!is_cache_op_valid(type, op)) - continue; - - for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { - char *name = event_cache_name(type, op, i); - - if (event_glob != NULL && - !strglobmatch(name, event_glob)) - continue; - - printf(" %-42s [%s]\n", name, - event_type_descriptors[PERF_TYPE_HW_CACHE]); - ++printed; - } - } - } - - return printed; -} - /* * Print the help text for the event symbols: */ -void print_events(const char *event_glob) +void print_events(void) { struct event_symbol *syms = event_symbols; - unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0; + unsigned int i, type, op, prev_type = -1; char name[40]; printf("\n"); @@ -1002,16 +938,8 @@ void print_events(const char *event_glob) for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) { type = syms->type; - if (type != prev_type && printed) { + if (type != prev_type) printf("\n"); - printed = 0; - ntypes_printed++; - } - - if (event_glob != NULL && - !(strglobmatch(syms->symbol, event_glob) || - (syms->alias && strglobmatch(syms->alias, event_glob)))) - continue; if (strlen(syms->alias)) sprintf(name, "%s OR %s", syms->symbol, syms->alias); @@ -1021,17 +949,22 @@ void print_events(const char *event_glob) event_type_descriptors[type]); prev_type = type; - ++printed; } - if (ntypes_printed) { - printed = 0; - printf("\n"); - } - print_hwcache_events(event_glob); + printf("\n"); + for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) { + for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) { + /* skip invalid cache type */ + if (!is_cache_op_valid(type, op)) + continue; - if (event_glob != NULL) - return; + for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) { + printf(" %-42s [%s]\n", + event_cache_name(type, op, i), + event_type_descriptors[PERF_TYPE_HW_CACHE]); + } + } + } printf("\n"); printf(" %-42s [%s]\n", @@ -1044,7 +977,37 @@ void print_events(const char *event_glob) event_type_descriptors[PERF_TYPE_BREAKPOINT]); printf("\n"); - print_tracepoint_events(NULL, NULL); + print_tracepoint_events(); exit(129); } + +int perf_evsel_list__create_default(void) +{ + struct perf_evsel *evsel; + struct perf_event_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.type = PERF_TYPE_HARDWARE; + attr.config = PERF_COUNT_HW_CPU_CYCLES; + + evsel = perf_evsel__new(&attr, 0); + + if (evsel == NULL) + return -ENOMEM; + + list_add(&evsel->node, &evsel_list); + ++nr_counters; + return 0; +} + +void perf_evsel_list__delete(void) +{ + struct perf_evsel *pos, *n; + + list_for_each_entry_safe(pos, n, &evsel_list, node) { + list_del_init(&pos->node); + perf_evsel__delete(pos); + } + nr_counters = 0; +} diff --git a/trunk/tools/perf/util/parse-events.h b/trunk/tools/perf/util/parse-events.h index 212f88e07a9c..458e3ecf17af 100644 --- a/trunk/tools/perf/util/parse-events.h +++ b/trunk/tools/perf/util/parse-events.h @@ -9,6 +9,11 @@ struct list_head; struct perf_evsel; +extern struct list_head evsel_list; + +int perf_evsel_list__create_default(void); +void perf_evsel_list__delete(void); + struct option; struct tracepoint_path { @@ -20,6 +25,8 @@ struct tracepoint_path { extern struct tracepoint_path *tracepoint_id_to_path(u64 config); extern bool have_tracepoints(struct list_head *evlist); +extern int nr_counters; + const char *event_name(struct perf_evsel *event); extern const char *__event_name(int type, u64 config); @@ -28,10 +35,7 @@ extern int parse_filter(const struct option *opt, const char *str, int unset); #define EVENTS_HELP_MAX (128*1024) -void print_events(const char *event_glob); -void print_events_type(u8 type); -void print_tracepoint_events(const char *subsys_glob, const char *event_glob); -int print_hwcache_events(const char *event_glob); +extern void print_events(void); extern int is_valid_tracepoint(const char *event_string); extern char debugfs_path[]; diff --git a/trunk/tools/perf/util/probe-event.c b/trunk/tools/perf/util/probe-event.c index 5ddee66020a7..6e29d9c9dccc 100644 --- a/trunk/tools/perf/util/probe-event.c +++ b/trunk/tools/perf/util/probe-event.c @@ -31,7 +31,6 @@ #include #include #include -#include #undef _GNU_SOURCE #include "util.h" @@ -112,25 +111,7 @@ static struct symbol *__find_kernel_function_by_name(const char *name, NULL); } -static struct map *kernel_get_module_map(const char *module) -{ - struct rb_node *nd; - struct map_groups *grp = &machine.kmaps; - - if (!module) - module = "kernel"; - - for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { - struct map *pos = rb_entry(nd, struct map, rb_node); - if (strncmp(pos->dso->short_name + 1, module, - pos->dso->short_name_len - 2) == 0) { - return pos; - } - } - return NULL; -} - -static struct dso *kernel_get_module_dso(const char *module) +const char *kernel_get_module_path(const char *module) { struct dso *dso; struct map *map; @@ -160,13 +141,7 @@ static struct dso *kernel_get_module_dso(const char *module) } } found: - return dso; -} - -const char *kernel_get_module_path(const char *module) -{ - struct dso *dso = kernel_get_module_dso(module); - return (dso) ? dso->long_name : NULL; + return dso->long_name; } #ifdef DWARF_SUPPORT @@ -409,7 +384,7 @@ int show_line_range(struct line_range *lr, const char *module) setup_pager(); if (lr->function) - fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, + fprintf(stdout, "<%s:%d>\n", lr->function, lr->start - lr->offset); else fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); @@ -451,14 +426,12 @@ int show_line_range(struct line_range *lr, const char *module) } static int show_available_vars_at(int fd, struct perf_probe_event *pev, - int max_vls, struct strfilter *_filter, - bool externs) + int max_vls, bool externs) { char *buf; - int ret, i, nvars; + int ret, i; struct str_node *node; struct variable_list *vls = NULL, *vl; - const char *var; buf = synthesize_perf_probe_point(&pev->point); if (!buf) @@ -466,45 +439,36 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev, pr_debug("Searching variables at %s\n", buf); ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); - if (ret <= 0) { - pr_err("Failed to find variables at %s (%d)\n", buf, ret); - goto end; - } - /* Some variables are found */ - fprintf(stdout, "Available variables at %s\n", buf); - for (i = 0; i < ret; i++) { - vl = &vls[i]; - /* - * A probe point might be converted to - * several trace points. - */ - fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, - vl->point.offset); - free(vl->point.symbol); - nvars = 0; - if (vl->vars) { - strlist__for_each(node, vl->vars) { - var = strchr(node->s, '\t') + 1; - if (strfilter__compare(_filter, var)) { + if (ret > 0) { + /* Some variables were found */ + fprintf(stdout, "Available variables at %s\n", buf); + for (i = 0; i < ret; i++) { + vl = &vls[i]; + /* + * A probe point might be converted to + * several trace points. + */ + fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, + vl->point.offset); + free(vl->point.symbol); + if (vl->vars) { + strlist__for_each(node, vl->vars) fprintf(stdout, "\t\t%s\n", node->s); - nvars++; - } - } - strlist__delete(vl->vars); + strlist__delete(vl->vars); + } else + fprintf(stdout, "(No variables)\n"); } - if (nvars == 0) - fprintf(stdout, "\t\t(No matched variables)\n"); - } - free(vls); -end: + free(vls); + } else + pr_err("Failed to find variables at %s (%d)\n", buf, ret); + free(buf); return ret; } /* Show available variables on given probe point */ int show_available_vars(struct perf_probe_event *pevs, int npevs, - int max_vls, const char *module, - struct strfilter *_filter, bool externs) + int max_vls, const char *module, bool externs) { int i, fd, ret = 0; @@ -521,8 +485,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, setup_pager(); for (i = 0; i < npevs && ret >= 0; i++) - ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, - externs); + ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); close(fd); return ret; @@ -568,9 +531,7 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused) int show_available_vars(struct perf_probe_event *pevs __unused, int npevs __unused, int max_vls __unused, - const char *module __unused, - struct strfilter *filter __unused, - bool externs __unused) + const char *module __unused, bool externs __unused) { pr_warning("Debuginfo-analysis is not supported.\n"); return -ENOSYS; @@ -595,11 +556,11 @@ static int parse_line_num(char **ptr, int *val, const char *what) * The line range syntax is described by: * * SRC[:SLN[+NUM|-ELN]] - * FNC[@SRC][:SLN[+NUM|-ELN]] + * FNC[:SLN[+NUM|-ELN]] */ int parse_line_range_desc(const char *arg, struct line_range *lr) { - char *range, *file, *name = strdup(arg); + char *range, *name = strdup(arg); int err; if (!name) @@ -649,16 +610,7 @@ int parse_line_range_desc(const char *arg, struct line_range *lr) } } - file = strchr(name, '@'); - if (file) { - *file = '\0'; - lr->file = strdup(++file); - if (lr->file == NULL) { - err = -ENOMEM; - goto err; - } - lr->function = name; - } else if (strchr(name, '.')) + if (strchr(name, '.')) lr->file = name; else lr->function = name; @@ -1832,12 +1784,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, } /* Loop 2: add all events */ - for (i = 0; i < npevs; i++) { + for (i = 0; i < npevs && ret >= 0; i++) ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, pkgs[i].ntevs, force_add); - if (ret < 0) - break; - } end: /* Loop 3: cleanup and free trace events */ for (i = 0; i < npevs; i++) { @@ -1963,46 +1912,4 @@ int del_perf_probe_events(struct strlist *dellist) return ret; } -/* TODO: don't use a global variable for filter ... */ -static struct strfilter *available_func_filter; - -/* - * If a symbol corresponds to a function with global binding and - * matches filter return 0. For all others return 1. - */ -static int filter_available_functions(struct map *map __unused, - struct symbol *sym) -{ - if (sym->binding == STB_GLOBAL && - strfilter__compare(available_func_filter, sym->name)) - return 0; - return 1; -} - -int show_available_funcs(const char *module, struct strfilter *_filter) -{ - struct map *map; - int ret; - - setup_pager(); - - ret = init_vmlinux(); - if (ret < 0) - return ret; - map = kernel_get_module_map(module); - if (!map) { - pr_err("Failed to find %s map.\n", (module) ? : "kernel"); - return -EINVAL; - } - available_func_filter = _filter; - if (map__load(map, filter_available_functions)) { - pr_err("Failed to load map.\n"); - return -EINVAL; - } - if (!dso__sorted_by_name(map->dso, map->type)) - dso__sort_by_name(map->dso, map->type); - - dso__fprintf_symbols_by_name(map->dso, map->type, stdout); - return 0; -} diff --git a/trunk/tools/perf/util/probe-event.h b/trunk/tools/perf/util/probe-event.h index 3434fc9d79d5..5accbedfea37 100644 --- a/trunk/tools/perf/util/probe-event.h +++ b/trunk/tools/perf/util/probe-event.h @@ -3,7 +3,6 @@ #include #include "strlist.h" -#include "strfilter.h" extern bool probe_event_dry_run; @@ -127,8 +126,7 @@ extern int show_perf_probe_events(void); extern int show_line_range(struct line_range *lr, const char *module); extern int show_available_vars(struct perf_probe_event *pevs, int npevs, int max_probe_points, const char *module, - struct strfilter *filter, bool externs); -extern int show_available_funcs(const char *module, struct strfilter *filter); + bool externs); /* Maximum index number of event-name postfix */ diff --git a/trunk/tools/perf/util/probe-finder.c b/trunk/tools/perf/util/probe-finder.c index 17f9c4a66ddd..ab83b6ac5d65 100644 --- a/trunk/tools/perf/util/probe-finder.c +++ b/trunk/tools/perf/util/probe-finder.c @@ -33,7 +33,6 @@ #include #include -#include #include "event.h" #include "debug.h" #include "util.h" @@ -281,19 +280,6 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) return name ? (strcmp(tname, name) == 0) : false; } -/* Get callsite line number of inline-function instance */ -static int die_get_call_lineno(Dwarf_Die *in_die) -{ - Dwarf_Attribute attr; - Dwarf_Word ret; - - if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) - return -ENOENT; - - dwarf_formudata(&attr, &ret); - return (int)ret; -} - /* Get type die */ static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) { @@ -334,23 +320,13 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) return vr_die; } -static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, - Dwarf_Word *result) -{ - Dwarf_Attribute attr; - - if (dwarf_attr(tp_die, attr_name, &attr) == NULL || - dwarf_formudata(&attr, result) != 0) - return -ENOENT; - - return 0; -} - static bool die_is_signed_type(Dwarf_Die *tp_die) { + Dwarf_Attribute attr; Dwarf_Word ret; - if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret)) + if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || + dwarf_formudata(&attr, &ret) != 0) return false; return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || @@ -359,29 +335,11 @@ static bool die_is_signed_type(Dwarf_Die *tp_die) static int die_get_byte_size(Dwarf_Die *tp_die) { + Dwarf_Attribute attr; Dwarf_Word ret; - if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret)) - return 0; - - return (int)ret; -} - -static int die_get_bit_size(Dwarf_Die *tp_die) -{ - Dwarf_Word ret; - - if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret)) - return 0; - - return (int)ret; -} - -static int die_get_bit_offset(Dwarf_Die *tp_die) -{ - Dwarf_Word ret; - - if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret)) + if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || + dwarf_formudata(&attr, &ret) != 0) return 0; return (int)ret; @@ -500,151 +458,6 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); } -/* Walker on lines (Note: line number will not be sorted) */ -typedef int (* line_walk_handler_t) (const char *fname, int lineno, - Dwarf_Addr addr, void *data); - -struct __line_walk_param { - const char *fname; - line_walk_handler_t handler; - void *data; - int retval; -}; - -static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) -{ - struct __line_walk_param *lw = data; - Dwarf_Addr addr; - int lineno; - - if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { - lineno = die_get_call_lineno(in_die); - if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { - lw->retval = lw->handler(lw->fname, lineno, addr, - lw->data); - if (lw->retval != 0) - return DIE_FIND_CB_FOUND; - } - } - return DIE_FIND_CB_SIBLING; -} - -/* Walk on lines of blocks included in given DIE */ -static int __die_walk_funclines(Dwarf_Die *sp_die, - line_walk_handler_t handler, void *data) -{ - struct __line_walk_param lw = { - .handler = handler, - .data = data, - .retval = 0, - }; - Dwarf_Die die_mem; - Dwarf_Addr addr; - int lineno; - - /* Handle function declaration line */ - lw.fname = dwarf_decl_file(sp_die); - if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && - dwarf_entrypc(sp_die, &addr) == 0) { - lw.retval = handler(lw.fname, lineno, addr, data); - if (lw.retval != 0) - goto done; - } - die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); -done: - return lw.retval; -} - -static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) -{ - struct __line_walk_param *lw = data; - - lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data); - if (lw->retval != 0) - return DWARF_CB_ABORT; - - return DWARF_CB_OK; -} - -/* - * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on - * the lines inside the subprogram, otherwise PDIE must be a CU DIE. - */ -static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler, - void *data) -{ - Dwarf_Lines *lines; - Dwarf_Line *line; - Dwarf_Addr addr; - const char *fname; - int lineno, ret = 0; - Dwarf_Die die_mem, *cu_die; - size_t nlines, i; - - /* Get the CU die */ - if (dwarf_tag(pdie) == DW_TAG_subprogram) - cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL); - else - cu_die = pdie; - if (!cu_die) { - pr_debug2("Failed to get CU from subprogram\n"); - return -EINVAL; - } - - /* Get lines list in the CU */ - if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { - pr_debug2("Failed to get source lines on this CU.\n"); - return -ENOENT; - } - pr_debug2("Get %zd lines from this CU\n", nlines); - - /* Walk on the lines on lines list */ - for (i = 0; i < nlines; i++) { - line = dwarf_onesrcline(lines, i); - if (line == NULL || - dwarf_lineno(line, &lineno) != 0 || - dwarf_lineaddr(line, &addr) != 0) { - pr_debug2("Failed to get line info. " - "Possible error in debuginfo.\n"); - continue; - } - /* Filter lines based on address */ - if (pdie != cu_die) - /* - * Address filtering - * The line is included in given function, and - * no inline block includes it. - */ - if (!dwarf_haspc(pdie, addr) || - die_find_inlinefunc(pdie, addr, &die_mem)) - continue; - /* Get source line */ - fname = dwarf_linesrc(line, NULL, NULL); - - ret = handler(fname, lineno, addr, data); - if (ret != 0) - return ret; - } - - /* - * Dwarf lines doesn't include function declarations and inlined - * subroutines. We have to check functions list or given function. - */ - if (pdie != cu_die) - ret = __die_walk_funclines(pdie, handler, data); - else { - struct __line_walk_param param = { - .handler = handler, - .data = data, - .retval = 0, - }; - dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); - ret = param.retval; - } - - return ret; -} - struct __find_variable_param { const char *name; Dwarf_Addr addr; @@ -856,8 +669,6 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, return 0; } -#define BYTES_TO_BITS(nb) ((nb) * BITS_PER_LONG / sizeof(long)) - static int convert_variable_type(Dwarf_Die *vr_die, struct probe_trace_arg *tvar, const char *cast) @@ -874,14 +685,6 @@ static int convert_variable_type(Dwarf_Die *vr_die, return (tvar->type == NULL) ? -ENOMEM : 0; } - if (die_get_bit_size(vr_die) != 0) { - /* This is a bitfield */ - ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die), - die_get_bit_offset(vr_die), - BYTES_TO_BITS(die_get_byte_size(vr_die))); - goto formatted; - } - if (die_get_real_type(vr_die, &type) == NULL) { pr_warning("Failed to get a type information of %s.\n", dwarf_diename(vr_die)); @@ -926,31 +729,29 @@ static int convert_variable_type(Dwarf_Die *vr_die, return (tvar->type == NULL) ? -ENOMEM : 0; } - ret = BYTES_TO_BITS(die_get_byte_size(&type)); - if (!ret) - /* No size ... try to use default type */ - return 0; + ret = die_get_byte_size(&type) * 8; + if (ret) { + /* Check the bitwidth */ + if (ret > MAX_BASIC_TYPE_BITS) { + pr_info("%s exceeds max-bitwidth." + " Cut down to %d bits.\n", + dwarf_diename(&type), MAX_BASIC_TYPE_BITS); + ret = MAX_BASIC_TYPE_BITS; + } - /* Check the bitwidth */ - if (ret > MAX_BASIC_TYPE_BITS) { - pr_info("%s exceeds max-bitwidth. Cut down to %d bits.\n", - dwarf_diename(&type), MAX_BASIC_TYPE_BITS); - ret = MAX_BASIC_TYPE_BITS; - } - ret = snprintf(buf, 16, "%c%d", - die_is_signed_type(&type) ? 's' : 'u', ret); - -formatted: - if (ret < 0 || ret >= 16) { - if (ret >= 16) - ret = -E2BIG; - pr_warning("Failed to convert variable type: %s\n", - strerror(-ret)); - return ret; + ret = snprintf(buf, 16, "%c%d", + die_is_signed_type(&type) ? 's' : 'u', ret); + if (ret < 0 || ret >= 16) { + if (ret >= 16) + ret = -E2BIG; + pr_warning("Failed to convert variable type: %s\n", + strerror(-ret)); + return ret; + } + tvar->type = strdup(buf); + if (tvar->type == NULL) + return -ENOMEM; } - tvar->type = strdup(buf); - if (tvar->type == NULL) - return -ENOMEM; return 0; } @@ -1249,102 +1050,157 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) return ret; } -static int probe_point_line_walker(const char *fname, int lineno, - Dwarf_Addr addr, void *data) +/* Find probe point from its line number */ +static int find_probe_point_by_line(struct probe_finder *pf) { - struct probe_finder *pf = data; - int ret; + Dwarf_Lines *lines; + Dwarf_Line *line; + size_t nlines, i; + Dwarf_Addr addr; + int lineno; + int ret = 0; - if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) - return 0; + if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { + pr_warning("No source lines found.\n"); + return -ENOENT; + } - pf->addr = addr; - ret = call_probe_finder(NULL, pf); + for (i = 0; i < nlines && ret == 0; i++) { + line = dwarf_onesrcline(lines, i); + if (dwarf_lineno(line, &lineno) != 0 || + lineno != pf->lno) + continue; - /* Continue if no error, because the line will be in inline function */ - return ret < 0 ? ret : 0; -} + /* TODO: Get fileno from line, but how? */ + if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) + continue; -/* Find probe point from its line number */ -static int find_probe_point_by_line(struct probe_finder *pf) -{ - return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf); + if (dwarf_lineaddr(line, &addr) != 0) { + pr_warning("Failed to get the address of the line.\n"); + return -ENOENT; + } + pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", + (int)i, lineno, (uintmax_t)addr); + pf->addr = addr; + + ret = call_probe_finder(NULL, pf); + /* Continuing, because target line might be inlined. */ + } + return ret; } /* Find lines which match lazy pattern */ static int find_lazy_match_lines(struct list_head *head, const char *fname, const char *pat) { - FILE *fp; - char *line = NULL; - size_t line_len; - ssize_t len; - int count = 0, linenum = 1; - - fp = fopen(fname, "r"); - if (!fp) { - pr_warning("Failed to open %s: %s\n", fname, strerror(errno)); + char *fbuf, *p1, *p2; + int fd, line, nlines = -1; + struct stat st; + + fd = open(fname, O_RDONLY); + if (fd < 0) { + pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); return -errno; } - while ((len = getline(&line, &line_len, fp)) > 0) { - - if (line[len - 1] == '\n') - line[len - 1] = '\0'; - - if (strlazymatch(line, pat)) { - line_list__add_line(head, linenum); - count++; + if (fstat(fd, &st) < 0) { + pr_warning("Failed to get the size of %s: %s\n", + fname, strerror(errno)); + nlines = -errno; + goto out_close; + } + + nlines = -ENOMEM; + fbuf = malloc(st.st_size + 2); + if (fbuf == NULL) + goto out_close; + if (read(fd, fbuf, st.st_size) < 0) { + pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); + nlines = -errno; + goto out_free_fbuf; + } + fbuf[st.st_size] = '\n'; /* Dummy line */ + fbuf[st.st_size + 1] = '\0'; + p1 = fbuf; + line = 1; + nlines = 0; + while ((p2 = strchr(p1, '\n')) != NULL) { + *p2 = '\0'; + if (strlazymatch(p1, pat)) { + line_list__add_line(head, line); + nlines++; } - linenum++; + line++; + p1 = p2 + 1; } - - if (ferror(fp)) - count = -errno; - free(line); - fclose(fp); - - if (count == 0) - pr_debug("No matched lines found in %s.\n", fname); - return count; -} - -static int probe_point_lazy_walker(const char *fname, int lineno, - Dwarf_Addr addr, void *data) -{ - struct probe_finder *pf = data; - int ret; - - if (!line_list__has_line(&pf->lcache, lineno) || - strtailcmp(fname, pf->fname) != 0) - return 0; - - pr_debug("Probe line found: line:%d addr:0x%llx\n", - lineno, (unsigned long long)addr); - pf->addr = addr; - ret = call_probe_finder(NULL, pf); - - /* - * Continue if no error, because the lazy pattern will match - * to other lines - */ - return ret < 0 ?: 0; +out_free_fbuf: + free(fbuf); +out_close: + close(fd); + return nlines; } /* Find probe points from lazy pattern */ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) { + Dwarf_Lines *lines; + Dwarf_Line *line; + size_t nlines, i; + Dwarf_Addr addr; + Dwarf_Die die_mem; + int lineno; int ret = 0; if (list_empty(&pf->lcache)) { /* Matching lazy line pattern */ ret = find_lazy_match_lines(&pf->lcache, pf->fname, pf->pev->point.lazy_line); - if (ret <= 0) + if (ret == 0) { + pr_debug("No matched lines found in %s.\n", pf->fname); + return 0; + } else if (ret < 0) return ret; } - return die_walk_lines(sp_die, probe_point_lazy_walker, pf); + if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { + pr_warning("No source lines found.\n"); + return -ENOENT; + } + + for (i = 0; i < nlines && ret >= 0; i++) { + line = dwarf_onesrcline(lines, i); + + if (dwarf_lineno(line, &lineno) != 0 || + !line_list__has_line(&pf->lcache, lineno)) + continue; + + /* TODO: Get fileno from line, but how? */ + if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) + continue; + + if (dwarf_lineaddr(line, &addr) != 0) { + pr_debug("Failed to get the address of line %d.\n", + lineno); + continue; + } + if (sp_die) { + /* Address filtering 1: does sp_die include addr? */ + if (!dwarf_haspc(sp_die, addr)) + continue; + /* Address filtering 2: No child include addr? */ + if (die_find_inlinefunc(sp_die, addr, &die_mem)) + continue; + } + + pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n", + (int)i, lineno, (unsigned long long)addr); + pf->addr = addr; + + ret = call_probe_finder(sp_die, pf); + /* Continuing, because target line might be inlined. */ + } + /* TODO: deallocate lines, but how? */ + return ret; } /* Callback parameter with return value */ @@ -1462,7 +1318,8 @@ static int find_probes(int fd, struct probe_finder *pf) off = 0; line_list__init(&pf->lcache); /* Loop on CUs (Compilation Unit) */ - while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { + while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && + ret >= 0) { /* Get the DIE(Debugging Information Entry) of this CU */ diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); if (!diep) @@ -1483,8 +1340,6 @@ static int find_probes(int fd, struct probe_finder *pf) pf->lno = pp->line; ret = find_probe_point_by_line(pf); } - if (ret < 0) - break; } off = noff; } @@ -1789,28 +1644,91 @@ static int line_range_add_line(const char *src, unsigned int lineno, return line_list__add_line(&lr->line_list, lineno); } -static int line_range_walk_cb(const char *fname, int lineno, - Dwarf_Addr addr __used, - void *data) +/* Search function declaration lines */ +static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) { - struct line_finder *lf = data; + struct dwarf_callback_param *param = data; + struct line_finder *lf = param->data; + const char *src; + int lineno; - if ((strtailcmp(fname, lf->fname) != 0) || + src = dwarf_decl_file(sp_die); + if (src && strtailcmp(src, lf->fname) != 0) + return DWARF_CB_OK; + + if (dwarf_decl_line(sp_die, &lineno) != 0 || (lf->lno_s > lineno || lf->lno_e < lineno)) - return 0; + return DWARF_CB_OK; - if (line_range_add_line(fname, lineno, lf->lr) < 0) - return -EINVAL; + param->retval = line_range_add_line(src, lineno, lf->lr); + if (param->retval < 0) + return DWARF_CB_ABORT; + return DWARF_CB_OK; +} - return 0; +static int find_line_range_func_decl_lines(struct line_finder *lf) +{ + struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; + dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0); + return param.retval; } /* Find line range from its line number */ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) { - int ret; + Dwarf_Lines *lines; + Dwarf_Line *line; + size_t nlines, i; + Dwarf_Addr addr; + int lineno, ret = 0; + const char *src; + Dwarf_Die die_mem; + + line_list__init(&lf->lr->line_list); + if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { + pr_warning("No source lines found.\n"); + return -ENOENT; + } - ret = die_walk_lines(sp_die ?: &lf->cu_die, line_range_walk_cb, lf); + /* Search probable lines on lines list */ + for (i = 0; i < nlines; i++) { + line = dwarf_onesrcline(lines, i); + if (dwarf_lineno(line, &lineno) != 0 || + (lf->lno_s > lineno || lf->lno_e < lineno)) + continue; + + if (sp_die) { + /* Address filtering 1: does sp_die include addr? */ + if (dwarf_lineaddr(line, &addr) != 0 || + !dwarf_haspc(sp_die, addr)) + continue; + + /* Address filtering 2: No child include addr? */ + if (die_find_inlinefunc(sp_die, addr, &die_mem)) + continue; + } + + /* TODO: Get fileno from line, but how? */ + src = dwarf_linesrc(line, NULL, NULL); + if (strtailcmp(src, lf->fname) != 0) + continue; + + ret = line_range_add_line(src, lineno, lf->lr); + if (ret < 0) + return ret; + } + + /* + * Dwarf lines doesn't include function declarations. We have to + * check functions list or given function. + */ + if (sp_die) { + src = dwarf_decl_file(sp_die); + if (src && dwarf_decl_line(sp_die, &lineno) == 0 && + (lf->lno_s <= lineno && lf->lno_e >= lineno)) + ret = line_range_add_line(src, lineno, lf->lr); + } else + ret = find_line_range_func_decl_lines(lf); /* Update status */ if (ret >= 0) @@ -1840,6 +1758,9 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) struct line_finder *lf = param->data; struct line_range *lr = lf->lr; + pr_debug("find (%llx) %s\n", + (unsigned long long)dwarf_dieoffset(sp_die), + dwarf_diename(sp_die)); if (dwarf_tag(sp_die) == DW_TAG_subprogram && die_compare_name(sp_die, lr->function)) { lf->fname = dwarf_decl_file(sp_die); diff --git a/trunk/tools/perf/util/python.c b/trunk/tools/perf/util/python.c deleted file mode 100644 index a9f2d7e1204d..000000000000 --- a/trunk/tools/perf/util/python.c +++ /dev/null @@ -1,896 +0,0 @@ -#include -#include -#include -#include -#include "evlist.h" -#include "evsel.h" -#include "event.h" -#include "cpumap.h" -#include "thread_map.h" - -/* Define PyVarObject_HEAD_INIT for python 2.5 */ -#ifndef PyVarObject_HEAD_INIT -# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size, -#endif - -struct throttle_event { - struct perf_event_header header; - u64 time; - u64 id; - u64 stream_id; -}; - -PyMODINIT_FUNC initperf(void); - -#define member_def(type, member, ptype, help) \ - { #member, ptype, \ - offsetof(struct pyrf_event, event) + offsetof(struct type, member), \ - 0, help } - -#define sample_member_def(name, member, ptype, help) \ - { #name, ptype, \ - offsetof(struct pyrf_event, sample) + offsetof(struct perf_sample, member), \ - 0, help } - -struct pyrf_event { - PyObject_HEAD - struct perf_sample sample; - union perf_event event; -}; - -#define sample_members \ - sample_member_def(sample_ip, ip, T_ULONGLONG, "event type"), \ - sample_member_def(sample_pid, pid, T_INT, "event pid"), \ - sample_member_def(sample_tid, tid, T_INT, "event tid"), \ - sample_member_def(sample_time, time, T_ULONGLONG, "event timestamp"), \ - sample_member_def(sample_addr, addr, T_ULONGLONG, "event addr"), \ - sample_member_def(sample_id, id, T_ULONGLONG, "event id"), \ - sample_member_def(sample_stream_id, stream_id, T_ULONGLONG, "event stream id"), \ - sample_member_def(sample_period, period, T_ULONGLONG, "event period"), \ - sample_member_def(sample_cpu, cpu, T_UINT, "event cpu"), - -static char pyrf_mmap_event__doc[] = PyDoc_STR("perf mmap event object."); - -static PyMemberDef pyrf_mmap_event__members[] = { - sample_members - member_def(perf_event_header, type, T_UINT, "event type"), - member_def(mmap_event, pid, T_UINT, "event pid"), - member_def(mmap_event, tid, T_UINT, "event tid"), - member_def(mmap_event, start, T_ULONGLONG, "start of the map"), - member_def(mmap_event, len, T_ULONGLONG, "map length"), - member_def(mmap_event, pgoff, T_ULONGLONG, "page offset"), - member_def(mmap_event, filename, T_STRING_INPLACE, "backing store"), - { .name = NULL, }, -}; - -static PyObject *pyrf_mmap_event__repr(struct pyrf_event *pevent) -{ - PyObject *ret; - char *s; - - if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRIx64 ", " - "length: %#" PRIx64 ", offset: %#" PRIx64 ", " - "filename: %s }", - pevent->event.mmap.pid, pevent->event.mmap.tid, - pevent->event.mmap.start, pevent->event.mmap.len, - pevent->event.mmap.pgoff, pevent->event.mmap.filename) < 0) { - ret = PyErr_NoMemory(); - } else { - ret = PyString_FromString(s); - free(s); - } - return ret; -} - -static PyTypeObject pyrf_mmap_event__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.mmap_event", - .tp_basicsize = sizeof(struct pyrf_event), - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_doc = pyrf_mmap_event__doc, - .tp_members = pyrf_mmap_event__members, - .tp_repr = (reprfunc)pyrf_mmap_event__repr, -}; - -static char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event object."); - -static PyMemberDef pyrf_task_event__members[] = { - sample_members - member_def(perf_event_header, type, T_UINT, "event type"), - member_def(fork_event, pid, T_UINT, "event pid"), - member_def(fork_event, ppid, T_UINT, "event ppid"), - member_def(fork_event, tid, T_UINT, "event tid"), - member_def(fork_event, ptid, T_UINT, "event ptid"), - member_def(fork_event, time, T_ULONGLONG, "timestamp"), - { .name = NULL, }, -}; - -static PyObject *pyrf_task_event__repr(struct pyrf_event *pevent) -{ - return PyString_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, " - "ptid: %u, time: %" PRIu64 "}", - pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit", - pevent->event.fork.pid, - pevent->event.fork.ppid, - pevent->event.fork.tid, - pevent->event.fork.ptid, - pevent->event.fork.time); -} - -static PyTypeObject pyrf_task_event__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.task_event", - .tp_basicsize = sizeof(struct pyrf_event), - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_doc = pyrf_task_event__doc, - .tp_members = pyrf_task_event__members, - .tp_repr = (reprfunc)pyrf_task_event__repr, -}; - -static char pyrf_comm_event__doc[] = PyDoc_STR("perf comm event object."); - -static PyMemberDef pyrf_comm_event__members[] = { - sample_members - member_def(perf_event_header, type, T_UINT, "event type"), - member_def(comm_event, pid, T_UINT, "event pid"), - member_def(comm_event, tid, T_UINT, "event tid"), - member_def(comm_event, comm, T_STRING_INPLACE, "process name"), - { .name = NULL, }, -}; - -static PyObject *pyrf_comm_event__repr(struct pyrf_event *pevent) -{ - return PyString_FromFormat("{ type: comm, pid: %u, tid: %u, comm: %s }", - pevent->event.comm.pid, - pevent->event.comm.tid, - pevent->event.comm.comm); -} - -static PyTypeObject pyrf_comm_event__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.comm_event", - .tp_basicsize = sizeof(struct pyrf_event), - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_doc = pyrf_comm_event__doc, - .tp_members = pyrf_comm_event__members, - .tp_repr = (reprfunc)pyrf_comm_event__repr, -}; - -static char pyrf_throttle_event__doc[] = PyDoc_STR("perf throttle event object."); - -static PyMemberDef pyrf_throttle_event__members[] = { - sample_members - member_def(perf_event_header, type, T_UINT, "event type"), - member_def(throttle_event, time, T_ULONGLONG, "timestamp"), - member_def(throttle_event, id, T_ULONGLONG, "event id"), - member_def(throttle_event, stream_id, T_ULONGLONG, "event stream id"), - { .name = NULL, }, -}; - -static PyObject *pyrf_throttle_event__repr(struct pyrf_event *pevent) -{ - struct throttle_event *te = (struct throttle_event *)(&pevent->event.header + 1); - - return PyString_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64 - ", stream_id: %" PRIu64 " }", - pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un", - te->time, te->id, te->stream_id); -} - -static PyTypeObject pyrf_throttle_event__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.throttle_event", - .tp_basicsize = sizeof(struct pyrf_event), - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_doc = pyrf_throttle_event__doc, - .tp_members = pyrf_throttle_event__members, - .tp_repr = (reprfunc)pyrf_throttle_event__repr, -}; - -static int pyrf_event__setup_types(void) -{ - int err; - pyrf_mmap_event__type.tp_new = - pyrf_task_event__type.tp_new = - pyrf_comm_event__type.tp_new = - pyrf_throttle_event__type.tp_new = PyType_GenericNew; - err = PyType_Ready(&pyrf_mmap_event__type); - if (err < 0) - goto out; - err = PyType_Ready(&pyrf_task_event__type); - if (err < 0) - goto out; - err = PyType_Ready(&pyrf_comm_event__type); - if (err < 0) - goto out; - err = PyType_Ready(&pyrf_throttle_event__type); - if (err < 0) - goto out; -out: - return err; -} - -static PyTypeObject *pyrf_event__type[] = { - [PERF_RECORD_MMAP] = &pyrf_mmap_event__type, - [PERF_RECORD_LOST] = &pyrf_mmap_event__type, - [PERF_RECORD_COMM] = &pyrf_comm_event__type, - [PERF_RECORD_EXIT] = &pyrf_task_event__type, - [PERF_RECORD_THROTTLE] = &pyrf_throttle_event__type, - [PERF_RECORD_UNTHROTTLE] = &pyrf_throttle_event__type, - [PERF_RECORD_FORK] = &pyrf_task_event__type, - [PERF_RECORD_READ] = &pyrf_mmap_event__type, - [PERF_RECORD_SAMPLE] = &pyrf_mmap_event__type, -}; - -static PyObject *pyrf_event__new(union perf_event *event) -{ - struct pyrf_event *pevent; - PyTypeObject *ptype; - - if (event->header.type < PERF_RECORD_MMAP || - event->header.type > PERF_RECORD_SAMPLE) - return NULL; - - ptype = pyrf_event__type[event->header.type]; - pevent = PyObject_New(struct pyrf_event, ptype); - if (pevent != NULL) - memcpy(&pevent->event, event, event->header.size); - return (PyObject *)pevent; -} - -struct pyrf_cpu_map { - PyObject_HEAD - - struct cpu_map *cpus; -}; - -static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, - PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "cpustr", NULL, NULL, }; - char *cpustr = NULL; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", - kwlist, &cpustr)) - return -1; - - pcpus->cpus = cpu_map__new(cpustr); - if (pcpus->cpus == NULL) - return -1; - return 0; -} - -static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus) -{ - cpu_map__delete(pcpus->cpus); - pcpus->ob_type->tp_free((PyObject*)pcpus); -} - -static Py_ssize_t pyrf_cpu_map__length(PyObject *obj) -{ - struct pyrf_cpu_map *pcpus = (void *)obj; - - return pcpus->cpus->nr; -} - -static PyObject *pyrf_cpu_map__item(PyObject *obj, Py_ssize_t i) -{ - struct pyrf_cpu_map *pcpus = (void *)obj; - - if (i >= pcpus->cpus->nr) - return NULL; - - return Py_BuildValue("i", pcpus->cpus->map[i]); -} - -static PySequenceMethods pyrf_cpu_map__sequence_methods = { - .sq_length = pyrf_cpu_map__length, - .sq_item = pyrf_cpu_map__item, -}; - -static char pyrf_cpu_map__doc[] = PyDoc_STR("cpu map object."); - -static PyTypeObject pyrf_cpu_map__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.cpu_map", - .tp_basicsize = sizeof(struct pyrf_cpu_map), - .tp_dealloc = (destructor)pyrf_cpu_map__delete, - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_doc = pyrf_cpu_map__doc, - .tp_as_sequence = &pyrf_cpu_map__sequence_methods, - .tp_init = (initproc)pyrf_cpu_map__init, -}; - -static int pyrf_cpu_map__setup_types(void) -{ - pyrf_cpu_map__type.tp_new = PyType_GenericNew; - return PyType_Ready(&pyrf_cpu_map__type); -} - -struct pyrf_thread_map { - PyObject_HEAD - - struct thread_map *threads; -}; - -static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, - PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "pid", "tid", NULL, NULL, }; - int pid = -1, tid = -1; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", - kwlist, &pid, &tid)) - return -1; - - pthreads->threads = thread_map__new(pid, tid); - if (pthreads->threads == NULL) - return -1; - return 0; -} - -static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads) -{ - thread_map__delete(pthreads->threads); - pthreads->ob_type->tp_free((PyObject*)pthreads); -} - -static Py_ssize_t pyrf_thread_map__length(PyObject *obj) -{ - struct pyrf_thread_map *pthreads = (void *)obj; - - return pthreads->threads->nr; -} - -static PyObject *pyrf_thread_map__item(PyObject *obj, Py_ssize_t i) -{ - struct pyrf_thread_map *pthreads = (void *)obj; - - if (i >= pthreads->threads->nr) - return NULL; - - return Py_BuildValue("i", pthreads->threads->map[i]); -} - -static PySequenceMethods pyrf_thread_map__sequence_methods = { - .sq_length = pyrf_thread_map__length, - .sq_item = pyrf_thread_map__item, -}; - -static char pyrf_thread_map__doc[] = PyDoc_STR("thread map object."); - -static PyTypeObject pyrf_thread_map__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.thread_map", - .tp_basicsize = sizeof(struct pyrf_thread_map), - .tp_dealloc = (destructor)pyrf_thread_map__delete, - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_doc = pyrf_thread_map__doc, - .tp_as_sequence = &pyrf_thread_map__sequence_methods, - .tp_init = (initproc)pyrf_thread_map__init, -}; - -static int pyrf_thread_map__setup_types(void) -{ - pyrf_thread_map__type.tp_new = PyType_GenericNew; - return PyType_Ready(&pyrf_thread_map__type); -} - -struct pyrf_evsel { - PyObject_HEAD - - struct perf_evsel evsel; -}; - -static int pyrf_evsel__init(struct pyrf_evsel *pevsel, - PyObject *args, PyObject *kwargs) -{ - struct perf_event_attr attr = { - .type = PERF_TYPE_HARDWARE, - .config = PERF_COUNT_HW_CPU_CYCLES, - .sample_type = PERF_SAMPLE_PERIOD | PERF_SAMPLE_TID, - }; - static char *kwlist[] = { - "type", - "config", - "sample_freq", - "sample_period", - "sample_type", - "read_format", - "disabled", - "inherit", - "pinned", - "exclusive", - "exclude_user", - "exclude_kernel", - "exclude_hv", - "exclude_idle", - "mmap", - "comm", - "freq", - "inherit_stat", - "enable_on_exec", - "task", - "watermark", - "precise_ip", - "mmap_data", - "sample_id_all", - "wakeup_events", - "bp_type", - "bp_addr", - "bp_len", NULL, NULL, }; - u64 sample_period = 0; - u32 disabled = 0, - inherit = 0, - pinned = 0, - exclusive = 0, - exclude_user = 0, - exclude_kernel = 0, - exclude_hv = 0, - exclude_idle = 0, - mmap = 0, - comm = 0, - freq = 1, - inherit_stat = 0, - enable_on_exec = 0, - task = 0, - watermark = 0, - precise_ip = 0, - mmap_data = 0, - sample_id_all = 1; - int idx = 0; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "|iKiKKiiiiiiiiiiiiiiiiiiiiiKK", kwlist, - &attr.type, &attr.config, &attr.sample_freq, - &sample_period, &attr.sample_type, - &attr.read_format, &disabled, &inherit, - &pinned, &exclusive, &exclude_user, - &exclude_kernel, &exclude_hv, &exclude_idle, - &mmap, &comm, &freq, &inherit_stat, - &enable_on_exec, &task, &watermark, - &precise_ip, &mmap_data, &sample_id_all, - &attr.wakeup_events, &attr.bp_type, - &attr.bp_addr, &attr.bp_len, &idx)) - return -1; - - /* union... */ - if (sample_period != 0) { - if (attr.sample_freq != 0) - return -1; /* FIXME: throw right exception */ - attr.sample_period = sample_period; - } - - /* Bitfields */ - attr.disabled = disabled; - attr.inherit = inherit; - attr.pinned = pinned; - attr.exclusive = exclusive; - attr.exclude_user = exclude_user; - attr.exclude_kernel = exclude_kernel; - attr.exclude_hv = exclude_hv; - attr.exclude_idle = exclude_idle; - attr.mmap = mmap; - attr.comm = comm; - attr.freq = freq; - attr.inherit_stat = inherit_stat; - attr.enable_on_exec = enable_on_exec; - attr.task = task; - attr.watermark = watermark; - attr.precise_ip = precise_ip; - attr.mmap_data = mmap_data; - attr.sample_id_all = sample_id_all; - - perf_evsel__init(&pevsel->evsel, &attr, idx); - return 0; -} - -static void pyrf_evsel__delete(struct pyrf_evsel *pevsel) -{ - perf_evsel__exit(&pevsel->evsel); - pevsel->ob_type->tp_free((PyObject*)pevsel); -} - -static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, - PyObject *args, PyObject *kwargs) -{ - struct perf_evsel *evsel = &pevsel->evsel; - struct cpu_map *cpus = NULL; - struct thread_map *threads = NULL; - PyObject *pcpus = NULL, *pthreads = NULL; - int group = 0, overwrite = 0; - static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, - &pcpus, &pthreads, &group, &overwrite)) - return NULL; - - if (pthreads != NULL) - threads = ((struct pyrf_thread_map *)pthreads)->threads; - - if (pcpus != NULL) - cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - - if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef pyrf_evsel__methods[] = { - { - .ml_name = "open", - .ml_meth = (PyCFunction)pyrf_evsel__open, - .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = PyDoc_STR("open the event selector file descriptor table.") - }, - { .ml_name = NULL, } -}; - -static char pyrf_evsel__doc[] = PyDoc_STR("perf event selector list object."); - -static PyTypeObject pyrf_evsel__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.evsel", - .tp_basicsize = sizeof(struct pyrf_evsel), - .tp_dealloc = (destructor)pyrf_evsel__delete, - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_doc = pyrf_evsel__doc, - .tp_methods = pyrf_evsel__methods, - .tp_init = (initproc)pyrf_evsel__init, -}; - -static int pyrf_evsel__setup_types(void) -{ - pyrf_evsel__type.tp_new = PyType_GenericNew; - return PyType_Ready(&pyrf_evsel__type); -} - -struct pyrf_evlist { - PyObject_HEAD - - struct perf_evlist evlist; -}; - -static int pyrf_evlist__init(struct pyrf_evlist *pevlist, - PyObject *args, PyObject *kwargs __used) -{ - PyObject *pcpus = NULL, *pthreads = NULL; - struct cpu_map *cpus; - struct thread_map *threads; - - if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads)) - return -1; - - threads = ((struct pyrf_thread_map *)pthreads)->threads; - cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - perf_evlist__init(&pevlist->evlist, cpus, threads); - return 0; -} - -static void pyrf_evlist__delete(struct pyrf_evlist *pevlist) -{ - perf_evlist__exit(&pevlist->evlist); - pevlist->ob_type->tp_free((PyObject*)pevlist); -} - -static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, - PyObject *args, PyObject *kwargs) -{ - struct perf_evlist *evlist = &pevlist->evlist; - static char *kwlist[] = {"pages", "overwrite", - NULL, NULL}; - int pages = 128, overwrite = false; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", kwlist, - &pages, &overwrite)) - return NULL; - - if (perf_evlist__mmap(evlist, pages, overwrite) < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist, - PyObject *args, PyObject *kwargs) -{ - struct perf_evlist *evlist = &pevlist->evlist; - static char *kwlist[] = {"timeout", NULL, NULL}; - int timeout = -1, n; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &timeout)) - return NULL; - - n = poll(evlist->pollfd, evlist->nr_fds, timeout); - if (n < 0) { - PyErr_SetFromErrno(PyExc_OSError); - return NULL; - } - - return Py_BuildValue("i", n); -} - -static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, - PyObject *args __used, PyObject *kwargs __used) -{ - struct perf_evlist *evlist = &pevlist->evlist; - PyObject *list = PyList_New(0); - int i; - - for (i = 0; i < evlist->nr_fds; ++i) { - PyObject *file; - FILE *fp = fdopen(evlist->pollfd[i].fd, "r"); - - if (fp == NULL) - goto free_list; - - file = PyFile_FromFile(fp, "perf", "r", NULL); - if (file == NULL) - goto free_list; - - if (PyList_Append(list, file) != 0) { - Py_DECREF(file); - goto free_list; - } - - Py_DECREF(file); - } - - return list; -free_list: - return PyErr_NoMemory(); -} - - -static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, - PyObject *args, PyObject *kwargs __used) -{ - struct perf_evlist *evlist = &pevlist->evlist; - PyObject *pevsel; - struct perf_evsel *evsel; - - if (!PyArg_ParseTuple(args, "O", &pevsel)) - return NULL; - - Py_INCREF(pevsel); - evsel = &((struct pyrf_evsel *)pevsel)->evsel; - evsel->idx = evlist->nr_entries; - perf_evlist__add(evlist, evsel); - - return Py_BuildValue("i", evlist->nr_entries); -} - -static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, - PyObject *args, PyObject *kwargs) -{ - struct perf_evlist *evlist = &pevlist->evlist; - union perf_event *event; - int sample_id_all = 1, cpu; - static char *kwlist[] = {"sample_id_all", NULL, NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, - &cpu, &sample_id_all)) - return NULL; - - event = perf_evlist__read_on_cpu(evlist, cpu); - if (event != NULL) { - struct perf_evsel *first; - PyObject *pyevent = pyrf_event__new(event); - struct pyrf_event *pevent = (struct pyrf_event *)pyevent; - - if (pyevent == NULL) - return PyErr_NoMemory(); - - first = list_entry(evlist->entries.next, struct perf_evsel, node); - perf_event__parse_sample(event, first->attr.sample_type, sample_id_all, - &pevent->sample); - return pyevent; - } - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef pyrf_evlist__methods[] = { - { - .ml_name = "mmap", - .ml_meth = (PyCFunction)pyrf_evlist__mmap, - .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = PyDoc_STR("mmap the file descriptor table.") - }, - { - .ml_name = "poll", - .ml_meth = (PyCFunction)pyrf_evlist__poll, - .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = PyDoc_STR("poll the file descriptor table.") - }, - { - .ml_name = "get_pollfd", - .ml_meth = (PyCFunction)pyrf_evlist__get_pollfd, - .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = PyDoc_STR("get the poll file descriptor table.") - }, - { - .ml_name = "add", - .ml_meth = (PyCFunction)pyrf_evlist__add, - .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = PyDoc_STR("adds an event selector to the list.") - }, - { - .ml_name = "read_on_cpu", - .ml_meth = (PyCFunction)pyrf_evlist__read_on_cpu, - .ml_flags = METH_VARARGS | METH_KEYWORDS, - .ml_doc = PyDoc_STR("reads an event.") - }, - { .ml_name = NULL, } -}; - -static Py_ssize_t pyrf_evlist__length(PyObject *obj) -{ - struct pyrf_evlist *pevlist = (void *)obj; - - return pevlist->evlist.nr_entries; -} - -static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) -{ - struct pyrf_evlist *pevlist = (void *)obj; - struct perf_evsel *pos; - - if (i >= pevlist->evlist.nr_entries) - return NULL; - - list_for_each_entry(pos, &pevlist->evlist.entries, node) - if (i-- == 0) - break; - - return Py_BuildValue("O", container_of(pos, struct pyrf_evsel, evsel)); -} - -static PySequenceMethods pyrf_evlist__sequence_methods = { - .sq_length = pyrf_evlist__length, - .sq_item = pyrf_evlist__item, -}; - -static char pyrf_evlist__doc[] = PyDoc_STR("perf event selector list object."); - -static PyTypeObject pyrf_evlist__type = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "perf.evlist", - .tp_basicsize = sizeof(struct pyrf_evlist), - .tp_dealloc = (destructor)pyrf_evlist__delete, - .tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, - .tp_as_sequence = &pyrf_evlist__sequence_methods, - .tp_doc = pyrf_evlist__doc, - .tp_methods = pyrf_evlist__methods, - .tp_init = (initproc)pyrf_evlist__init, -}; - -static int pyrf_evlist__setup_types(void) -{ - pyrf_evlist__type.tp_new = PyType_GenericNew; - return PyType_Ready(&pyrf_evlist__type); -} - -static struct { - const char *name; - int value; -} perf__constants[] = { - { "TYPE_HARDWARE", PERF_TYPE_HARDWARE }, - { "TYPE_SOFTWARE", PERF_TYPE_SOFTWARE }, - { "TYPE_TRACEPOINT", PERF_TYPE_TRACEPOINT }, - { "TYPE_HW_CACHE", PERF_TYPE_HW_CACHE }, - { "TYPE_RAW", PERF_TYPE_RAW }, - { "TYPE_BREAKPOINT", PERF_TYPE_BREAKPOINT }, - - { "COUNT_HW_CPU_CYCLES", PERF_COUNT_HW_CPU_CYCLES }, - { "COUNT_HW_INSTRUCTIONS", PERF_COUNT_HW_INSTRUCTIONS }, - { "COUNT_HW_CACHE_REFERENCES", PERF_COUNT_HW_CACHE_REFERENCES }, - { "COUNT_HW_CACHE_MISSES", PERF_COUNT_HW_CACHE_MISSES }, - { "COUNT_HW_BRANCH_INSTRUCTIONS", PERF_COUNT_HW_BRANCH_INSTRUCTIONS }, - { "COUNT_HW_BRANCH_MISSES", PERF_COUNT_HW_BRANCH_MISSES }, - { "COUNT_HW_BUS_CYCLES", PERF_COUNT_HW_BUS_CYCLES }, - { "COUNT_HW_CACHE_L1D", PERF_COUNT_HW_CACHE_L1D }, - { "COUNT_HW_CACHE_L1I", PERF_COUNT_HW_CACHE_L1I }, - { "COUNT_HW_CACHE_LL", PERF_COUNT_HW_CACHE_LL }, - { "COUNT_HW_CACHE_DTLB", PERF_COUNT_HW_CACHE_DTLB }, - { "COUNT_HW_CACHE_ITLB", PERF_COUNT_HW_CACHE_ITLB }, - { "COUNT_HW_CACHE_BPU", PERF_COUNT_HW_CACHE_BPU }, - { "COUNT_HW_CACHE_OP_READ", PERF_COUNT_HW_CACHE_OP_READ }, - { "COUNT_HW_CACHE_OP_WRITE", PERF_COUNT_HW_CACHE_OP_WRITE }, - { "COUNT_HW_CACHE_OP_PREFETCH", PERF_COUNT_HW_CACHE_OP_PREFETCH }, - { "COUNT_HW_CACHE_RESULT_ACCESS", PERF_COUNT_HW_CACHE_RESULT_ACCESS }, - { "COUNT_HW_CACHE_RESULT_MISS", PERF_COUNT_HW_CACHE_RESULT_MISS }, - - { "COUNT_SW_CPU_CLOCK", PERF_COUNT_SW_CPU_CLOCK }, - { "COUNT_SW_TASK_CLOCK", PERF_COUNT_SW_TASK_CLOCK }, - { "COUNT_SW_PAGE_FAULTS", PERF_COUNT_SW_PAGE_FAULTS }, - { "COUNT_SW_CONTEXT_SWITCHES", PERF_COUNT_SW_CONTEXT_SWITCHES }, - { "COUNT_SW_CPU_MIGRATIONS", PERF_COUNT_SW_CPU_MIGRATIONS }, - { "COUNT_SW_PAGE_FAULTS_MIN", PERF_COUNT_SW_PAGE_FAULTS_MIN }, - { "COUNT_SW_PAGE_FAULTS_MAJ", PERF_COUNT_SW_PAGE_FAULTS_MAJ }, - { "COUNT_SW_ALIGNMENT_FAULTS", PERF_COUNT_SW_ALIGNMENT_FAULTS }, - { "COUNT_SW_EMULATION_FAULTS", PERF_COUNT_SW_EMULATION_FAULTS }, - - { "SAMPLE_IP", PERF_SAMPLE_IP }, - { "SAMPLE_TID", PERF_SAMPLE_TID }, - { "SAMPLE_TIME", PERF_SAMPLE_TIME }, - { "SAMPLE_ADDR", PERF_SAMPLE_ADDR }, - { "SAMPLE_READ", PERF_SAMPLE_READ }, - { "SAMPLE_CALLCHAIN", PERF_SAMPLE_CALLCHAIN }, - { "SAMPLE_ID", PERF_SAMPLE_ID }, - { "SAMPLE_CPU", PERF_SAMPLE_CPU }, - { "SAMPLE_PERIOD", PERF_SAMPLE_PERIOD }, - { "SAMPLE_STREAM_ID", PERF_SAMPLE_STREAM_ID }, - { "SAMPLE_RAW", PERF_SAMPLE_RAW }, - - { "FORMAT_TOTAL_TIME_ENABLED", PERF_FORMAT_TOTAL_TIME_ENABLED }, - { "FORMAT_TOTAL_TIME_RUNNING", PERF_FORMAT_TOTAL_TIME_RUNNING }, - { "FORMAT_ID", PERF_FORMAT_ID }, - { "FORMAT_GROUP", PERF_FORMAT_GROUP }, - - { "RECORD_MMAP", PERF_RECORD_MMAP }, - { "RECORD_LOST", PERF_RECORD_LOST }, - { "RECORD_COMM", PERF_RECORD_COMM }, - { "RECORD_EXIT", PERF_RECORD_EXIT }, - { "RECORD_THROTTLE", PERF_RECORD_THROTTLE }, - { "RECORD_UNTHROTTLE", PERF_RECORD_UNTHROTTLE }, - { "RECORD_FORK", PERF_RECORD_FORK }, - { "RECORD_READ", PERF_RECORD_READ }, - { "RECORD_SAMPLE", PERF_RECORD_SAMPLE }, - { .name = NULL, }, -}; - -static PyMethodDef perf__methods[] = { - { .ml_name = NULL, } -}; - -PyMODINIT_FUNC initperf(void) -{ - PyObject *obj; - int i; - PyObject *dict, *module = Py_InitModule("perf", perf__methods); - - if (module == NULL || - pyrf_event__setup_types() < 0 || - pyrf_evlist__setup_types() < 0 || - pyrf_evsel__setup_types() < 0 || - pyrf_thread_map__setup_types() < 0 || - pyrf_cpu_map__setup_types() < 0) - return; - - Py_INCREF(&pyrf_evlist__type); - PyModule_AddObject(module, "evlist", (PyObject*)&pyrf_evlist__type); - - Py_INCREF(&pyrf_evsel__type); - PyModule_AddObject(module, "evsel", (PyObject*)&pyrf_evsel__type); - - Py_INCREF(&pyrf_thread_map__type); - PyModule_AddObject(module, "thread_map", (PyObject*)&pyrf_thread_map__type); - - Py_INCREF(&pyrf_cpu_map__type); - PyModule_AddObject(module, "cpu_map", (PyObject*)&pyrf_cpu_map__type); - - dict = PyModule_GetDict(module); - if (dict == NULL) - goto error; - - for (i = 0; perf__constants[i].name != NULL; i++) { - obj = PyInt_FromLong(perf__constants[i].value); - if (obj == NULL) - goto error; - PyDict_SetItemString(dict, perf__constants[i].name, obj); - Py_DECREF(obj); - } - -error: - if (PyErr_Occurred()) - PyErr_SetString(PyExc_ImportError, "perf: Init failed!"); -} 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 2040b8538527..c6d99334bdfa 100644 --- a/trunk/tools/perf/util/scripting-engines/trace-event-python.c +++ b/trunk/tools/perf/util/scripting-engines/trace-event-python.c @@ -248,7 +248,8 @@ static void python_process_event(int cpu, void *data, context = PyCObject_FromVoidPtr(scripting_context, NULL); PyTuple_SetItem(t, n++, PyString_FromString(handler_name)); - PyTuple_SetItem(t, n++, context); + PyTuple_SetItem(t, n++, + PyCObject_FromVoidPtr(scripting_context, NULL)); if (handler) { PyTuple_SetItem(t, n++, PyInt_FromLong(cpu)); diff --git a/trunk/tools/perf/util/session.c b/trunk/tools/perf/util/session.c index a3a871f7bda3..105f00bfd555 100644 --- a/trunk/tools/perf/util/session.c +++ b/trunk/tools/perf/util/session.c @@ -67,7 +67,7 @@ static int perf_session__open(struct perf_session *self, bool force) static void perf_session__id_header_size(struct perf_session *session) { - struct perf_sample *data; + struct sample_data *data; u64 sample_type = session->sample_type; u16 size = 0; @@ -165,7 +165,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, } else if (mode == O_WRONLY) { /* * In O_RDONLY mode this will be performed when reading the - * kernel MMAP event, in perf_event__process_mmap(). + * kernel MMAP event, in event__process_mmap(). */ if (perf_session__create_kernel_maps(self) < 0) goto out_delete; @@ -242,16 +242,17 @@ static bool symbol__match_parent_regex(struct symbol *sym) return 0; } -int perf_session__resolve_callchain(struct perf_session *self, - struct thread *thread, - struct ip_callchain *chain, - struct symbol **parent) +struct map_symbol *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; + struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); - callchain_cursor_reset(&self->callchain_cursor); + if (!syms) + return NULL; for (i = 0; i < chain->nr; i++) { u64 ip = chain->ips[i]; @@ -280,33 +281,30 @@ int perf_session__resolve_callchain(struct perf_session *self, *parent = al.sym; if (!symbol_conf.use_callchain) break; + syms[i].map = al.map; + syms[i].sym = al.sym; } - - err = callchain_cursor_append(&self->callchain_cursor, - ip, al.map, al.sym); - if (err) - return err; } - return 0; + return syms; } -static int process_event_synth_stub(union perf_event *event __used, +static int process_event_synth_stub(event_t *event __used, struct perf_session *session __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_event_stub(union perf_event *event __used, - struct perf_sample *sample __used, +static int process_event_stub(event_t *event __used, + struct sample_data *sample __used, struct perf_session *session __used) { dump_printf(": unhandled!\n"); return 0; } -static int process_finished_round_stub(union perf_event *event __used, +static int process_finished_round_stub(event_t *event __used, struct perf_session *session __used, struct perf_event_ops *ops __used) { @@ -314,7 +312,7 @@ static int process_finished_round_stub(union perf_event *event __used, return 0; } -static int process_finished_round(union perf_event *event, +static int process_finished_round(event_t *event, struct perf_session *session, struct perf_event_ops *ops); @@ -331,7 +329,7 @@ static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) if (handler->exit == NULL) handler->exit = process_event_stub; if (handler->lost == NULL) - handler->lost = perf_event__process_lost; + handler->lost = event__process_lost; if (handler->read == NULL) handler->read = process_event_stub; if (handler->throttle == NULL) @@ -365,98 +363,98 @@ void mem_bswap_64(void *src, int byte_size) } } -static void perf_event__all64_swap(union perf_event *event) +static void event__all64_swap(event_t *self) { - struct perf_event_header *hdr = &event->header; - mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); + struct perf_event_header *hdr = &self->header; + mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); } -static void perf_event__comm_swap(union perf_event *event) +static void event__comm_swap(event_t *self) { - event->comm.pid = bswap_32(event->comm.pid); - event->comm.tid = bswap_32(event->comm.tid); + self->comm.pid = bswap_32(self->comm.pid); + self->comm.tid = bswap_32(self->comm.tid); } -static void perf_event__mmap_swap(union perf_event *event) +static void event__mmap_swap(event_t *self) { - event->mmap.pid = bswap_32(event->mmap.pid); - event->mmap.tid = bswap_32(event->mmap.tid); - event->mmap.start = bswap_64(event->mmap.start); - event->mmap.len = bswap_64(event->mmap.len); - event->mmap.pgoff = bswap_64(event->mmap.pgoff); + self->mmap.pid = bswap_32(self->mmap.pid); + self->mmap.tid = bswap_32(self->mmap.tid); + self->mmap.start = bswap_64(self->mmap.start); + self->mmap.len = bswap_64(self->mmap.len); + self->mmap.pgoff = bswap_64(self->mmap.pgoff); } -static void perf_event__task_swap(union perf_event *event) +static void event__task_swap(event_t *self) { - event->fork.pid = bswap_32(event->fork.pid); - event->fork.tid = bswap_32(event->fork.tid); - event->fork.ppid = bswap_32(event->fork.ppid); - event->fork.ptid = bswap_32(event->fork.ptid); - event->fork.time = bswap_64(event->fork.time); + self->fork.pid = bswap_32(self->fork.pid); + self->fork.tid = bswap_32(self->fork.tid); + self->fork.ppid = bswap_32(self->fork.ppid); + self->fork.ptid = bswap_32(self->fork.ptid); + self->fork.time = bswap_64(self->fork.time); } -static void perf_event__read_swap(union perf_event *event) +static void event__read_swap(event_t *self) { - event->read.pid = bswap_32(event->read.pid); - event->read.tid = bswap_32(event->read.tid); - event->read.value = bswap_64(event->read.value); - event->read.time_enabled = bswap_64(event->read.time_enabled); - event->read.time_running = bswap_64(event->read.time_running); - event->read.id = bswap_64(event->read.id); + self->read.pid = bswap_32(self->read.pid); + self->read.tid = bswap_32(self->read.tid); + self->read.value = bswap_64(self->read.value); + self->read.time_enabled = bswap_64(self->read.time_enabled); + self->read.time_running = bswap_64(self->read.time_running); + self->read.id = bswap_64(self->read.id); } -static void perf_event__attr_swap(union perf_event *event) +static void event__attr_swap(event_t *self) { size_t size; - event->attr.attr.type = bswap_32(event->attr.attr.type); - event->attr.attr.size = bswap_32(event->attr.attr.size); - event->attr.attr.config = bswap_64(event->attr.attr.config); - event->attr.attr.sample_period = bswap_64(event->attr.attr.sample_period); - event->attr.attr.sample_type = bswap_64(event->attr.attr.sample_type); - event->attr.attr.read_format = bswap_64(event->attr.attr.read_format); - event->attr.attr.wakeup_events = bswap_32(event->attr.attr.wakeup_events); - event->attr.attr.bp_type = bswap_32(event->attr.attr.bp_type); - event->attr.attr.bp_addr = bswap_64(event->attr.attr.bp_addr); - event->attr.attr.bp_len = bswap_64(event->attr.attr.bp_len); - - size = event->header.size; - size -= (void *)&event->attr.id - (void *)event; - mem_bswap_64(event->attr.id, size); + self->attr.attr.type = bswap_32(self->attr.attr.type); + self->attr.attr.size = bswap_32(self->attr.attr.size); + self->attr.attr.config = bswap_64(self->attr.attr.config); + self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); + self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type); + self->attr.attr.read_format = bswap_64(self->attr.attr.read_format); + self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events); + self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type); + self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr); + self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len); + + size = self->header.size; + size -= (void *)&self->attr.id - (void *)self; + mem_bswap_64(self->attr.id, size); } -static void perf_event__event_type_swap(union perf_event *event) +static void event__event_type_swap(event_t *self) { - event->event_type.event_type.event_id = - bswap_64(event->event_type.event_type.event_id); + self->event_type.event_type.event_id = + bswap_64(self->event_type.event_type.event_id); } -static void perf_event__tracing_data_swap(union perf_event *event) +static void event__tracing_data_swap(event_t *self) { - event->tracing_data.size = bswap_32(event->tracing_data.size); + self->tracing_data.size = bswap_32(self->tracing_data.size); } -typedef void (*perf_event__swap_op)(union perf_event *event); - -static perf_event__swap_op perf_event__swap_ops[] = { - [PERF_RECORD_MMAP] = perf_event__mmap_swap, - [PERF_RECORD_COMM] = perf_event__comm_swap, - [PERF_RECORD_FORK] = perf_event__task_swap, - [PERF_RECORD_EXIT] = perf_event__task_swap, - [PERF_RECORD_LOST] = perf_event__all64_swap, - [PERF_RECORD_READ] = perf_event__read_swap, - [PERF_RECORD_SAMPLE] = perf_event__all64_swap, - [PERF_RECORD_HEADER_ATTR] = perf_event__attr_swap, - [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, - [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, - [PERF_RECORD_HEADER_BUILD_ID] = NULL, - [PERF_RECORD_HEADER_MAX] = NULL, +typedef void (*event__swap_op)(event_t *self); + +static event__swap_op event__swap_ops[] = { + [PERF_RECORD_MMAP] = event__mmap_swap, + [PERF_RECORD_COMM] = event__comm_swap, + [PERF_RECORD_FORK] = event__task_swap, + [PERF_RECORD_EXIT] = event__task_swap, + [PERF_RECORD_LOST] = event__all64_swap, + [PERF_RECORD_READ] = event__read_swap, + [PERF_RECORD_SAMPLE] = event__all64_swap, + [PERF_RECORD_HEADER_ATTR] = event__attr_swap, + [PERF_RECORD_HEADER_EVENT_TYPE] = event__event_type_swap, + [PERF_RECORD_HEADER_TRACING_DATA] = event__tracing_data_swap, + [PERF_RECORD_HEADER_BUILD_ID] = NULL, + [PERF_RECORD_HEADER_MAX] = NULL, }; struct sample_queue { u64 timestamp; u64 file_offset; - union perf_event *event; + event_t *event; struct list_head list; }; @@ -474,8 +472,8 @@ 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, + event_t *event, + struct sample_data *sample, struct perf_event_ops *ops, u64 file_offset); @@ -485,7 +483,7 @@ static void flush_sample_queue(struct perf_session *s, struct ordered_samples *os = &s->ordered_samples; struct list_head *head = &os->samples; struct sample_queue *tmp, *iter; - struct perf_sample sample; + struct sample_data sample; u64 limit = os->next_flush; u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; @@ -496,7 +494,7 @@ static void flush_sample_queue(struct perf_session *s, if (iter->timestamp > limit) break; - perf_session__parse_sample(s, iter->event, &sample); + event__parse_sample(iter->event, s, &sample); perf_session_deliver_event(s, iter->event, &sample, ops, iter->file_offset); @@ -552,7 +550,7 @@ static void flush_sample_queue(struct perf_session *s, * Flush every events below timestamp 7 * etc... */ -static int process_finished_round(union perf_event *event __used, +static int process_finished_round(event_t *event __used, struct perf_session *session, struct perf_event_ops *ops) { @@ -609,12 +607,12 @@ static void __queue_event(struct sample_queue *new, struct perf_session *s) #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct sample_queue)) -static int perf_session_queue_event(struct perf_session *s, union perf_event *event, - struct perf_sample *sample, u64 file_offset) +static int perf_session_queue_event(struct perf_session *s, event_t *event, + struct sample_data *data, u64 file_offset) { struct ordered_samples *os = &s->ordered_samples; struct list_head *sc = &os->sample_cache; - u64 timestamp = sample->time; + u64 timestamp = data->time; struct sample_queue *new; if (!timestamp || timestamp == ~0ULL) @@ -650,7 +648,7 @@ static int perf_session_queue_event(struct perf_session *s, union perf_event *ev return 0; } -static void callchain__printf(struct perf_sample *sample) +static void callchain__printf(struct sample_data *sample) { unsigned int i; @@ -662,8 +660,8 @@ static void callchain__printf(struct perf_sample *sample) } static void perf_session__print_tstamp(struct perf_session *session, - union perf_event *event, - struct perf_sample *sample) + event_t *event, + struct sample_data *sample) { if (event->header.type != PERF_RECORD_SAMPLE && !session->sample_id_all) { @@ -678,8 +676,8 @@ static void perf_session__print_tstamp(struct perf_session *session, printf("%" PRIu64 " ", sample->time); } -static void dump_event(struct perf_session *session, union perf_event *event, - u64 file_offset, struct perf_sample *sample) +static void dump_event(struct perf_session *session, event_t *event, + u64 file_offset, struct sample_data *sample) { if (!dump_trace) return; @@ -693,11 +691,11 @@ static void dump_event(struct perf_session *session, union perf_event *event, perf_session__print_tstamp(session, event, sample); printf("%#" PRIx64 " [%#x]: PERF_RECORD_%s", file_offset, - event->header.size, perf_event__name(event->header.type)); + event->header.size, event__get_event_name(event->header.type)); } -static void dump_sample(struct perf_session *session, union perf_event *event, - struct perf_sample *sample) +static void dump_sample(struct perf_session *session, event_t *event, + struct sample_data *sample) { if (!dump_trace) return; @@ -711,8 +709,8 @@ static void dump_sample(struct perf_session *session, union perf_event *event, } static int perf_session_deliver_event(struct perf_session *session, - union perf_event *event, - struct perf_sample *sample, + event_t *event, + struct sample_data *sample, struct perf_event_ops *ops, u64 file_offset) { @@ -745,7 +743,7 @@ static int perf_session_deliver_event(struct perf_session *session, } static int perf_session__preprocess_sample(struct perf_session *session, - union perf_event *event, struct perf_sample *sample) + event_t *event, struct sample_data *sample) { if (event->header.type != PERF_RECORD_SAMPLE || !(session->sample_type & PERF_SAMPLE_CALLCHAIN)) @@ -760,7 +758,7 @@ static int perf_session__preprocess_sample(struct perf_session *session, return 0; } -static int perf_session__process_user_event(struct perf_session *session, union perf_event *event, +static int perf_session__process_user_event(struct perf_session *session, event_t *event, struct perf_event_ops *ops, u64 file_offset) { dump_event(session, event, file_offset, NULL); @@ -785,16 +783,15 @@ 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, + event_t *event, struct perf_event_ops *ops, u64 file_offset) { - struct perf_sample sample; + struct sample_data sample; int ret; - if (session->header.needs_swap && - perf_event__swap_ops[event->header.type]) - perf_event__swap_ops[event->header.type](event); + if (session->header.needs_swap && event__swap_ops[event->header.type]) + event__swap_ops[event->header.type](event); if (event->header.type >= PERF_RECORD_HEADER_MAX) return -EINVAL; @@ -807,7 +804,7 @@ static int perf_session__process_event(struct perf_session *session, /* * For all kernel events we get the sample data */ - perf_session__parse_sample(session, event, &sample); + event__parse_sample(event, session, &sample); /* Preprocess sample records - precheck callchains */ if (perf_session__preprocess_sample(session, event, &sample)) @@ -846,7 +843,7 @@ 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_event_ops *ops) { - if (ops->lost == perf_event__process_lost && + if (ops->lost == event__process_lost && session->hists.stats.total_lost != 0) { ui__warning("Processed %" PRIu64 " events and LOST %" PRIu64 "!\n\nCheck IO/CPU overload!\n\n", @@ -878,7 +875,7 @@ volatile int session_done; static int __perf_session__process_pipe_events(struct perf_session *self, struct perf_event_ops *ops) { - union perf_event event; + event_t event; uint32_t size; int skip = 0; u64 head; @@ -959,7 +956,7 @@ int __perf_session__process_events(struct perf_session *session, struct ui_progress *progress; size_t page_size, mmap_size; char *buf, *mmaps[8]; - union perf_event *event; + event_t *event; uint32_t size; perf_event_ops__fill_defaults(ops); @@ -1004,7 +1001,7 @@ int __perf_session__process_events(struct perf_session *session, file_pos = file_offset + head; more: - event = (union perf_event *)(buf + head); + event = (event_t *)(buf + head); if (session->header.needs_swap) perf_event_header__bswap(&event->header); diff --git a/trunk/tools/perf/util/session.h b/trunk/tools/perf/util/session.h index 977b3a1b14aa..decd83f274fd 100644 --- a/trunk/tools/perf/util/session.h +++ b/trunk/tools/perf/util/session.h @@ -51,17 +51,15 @@ struct perf_session { int cwdlen; char *cwd; struct ordered_samples ordered_samples; - struct callchain_cursor callchain_cursor; - char filename[0]; + char filename[0]; }; struct perf_event_ops; -typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, +typedef int (*event_op)(event_t *self, struct sample_data *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, +typedef int (*event_synth_op)(event_t *self, struct perf_session *session); +typedef int (*event_op2)(event_t *self, struct perf_session *session, struct perf_event_ops *ops); struct perf_event_ops { @@ -96,10 +94,10 @@ int __perf_session__process_events(struct perf_session *self, int perf_session__process_events(struct perf_session *self, struct perf_event_ops *event_ops); -int perf_session__resolve_callchain(struct perf_session *self, - struct thread *thread, - struct ip_callchain *chain, - struct symbol **parent); +struct map_symbol *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); @@ -156,13 +154,4 @@ size_t perf_session__fprintf_nr_events(struct perf_session *self, FILE *fp) { return hists__fprintf_nr_events(&self->hists, fp); } - -static inline int perf_session__parse_sample(struct perf_session *session, - const union perf_event *event, - struct perf_sample *sample) -{ - return perf_event__parse_sample(event, session->sample_type, - session->sample_id_all, sample); -} - #endif /* __PERF_SESSION_H */ diff --git a/trunk/tools/perf/util/setup.py b/trunk/tools/perf/util/setup.py deleted file mode 100644 index e24ffadb20b2..000000000000 --- a/trunk/tools/perf/util/setup.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/python2 - -from distutils.core import setup, Extension - -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'], - include_dirs = ['util/include'], - extra_compile_args = ['-fno-strict-aliasing', '-Wno-write-strings']) - -setup(name='perf', - version='0.1', - description='Interface with the Linux profiling infrastructure', - author='Arnaldo Carvalho de Melo', - author_email='acme@redhat.com', - license='GPLv2', - url='http://perf.wiki.kernel.org', - ext_modules=[perf]) diff --git a/trunk/tools/perf/util/strfilter.c b/trunk/tools/perf/util/strfilter.c deleted file mode 100644 index 834c8ebfe38e..000000000000 --- a/trunk/tools/perf/util/strfilter.c +++ /dev/null @@ -1,199 +0,0 @@ -#include "util.h" -#include "string.h" -#include "strfilter.h" - -/* Operators */ -static const char *OP_and = "&"; /* Logical AND */ -static const char *OP_or = "|"; /* Logical OR */ -static const char *OP_not = "!"; /* Logical NOT */ - -#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!') -#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')') - -static void strfilter_node__delete(struct strfilter_node *self) -{ - if (self) { - if (self->p && !is_operator(*self->p)) - free((char *)self->p); - strfilter_node__delete(self->l); - strfilter_node__delete(self->r); - free(self); - } -} - -void strfilter__delete(struct strfilter *self) -{ - if (self) { - strfilter_node__delete(self->root); - free(self); - } -} - -static const char *get_token(const char *s, const char **e) -{ - const char *p; - - while (isspace(*s)) /* Skip spaces */ - s++; - - if (*s == '\0') { - p = s; - goto end; - } - - p = s + 1; - if (!is_separator(*s)) { - /* End search */ -retry: - while (*p && !is_separator(*p) && !isspace(*p)) - p++; - /* Escape and special case: '!' is also used in glob pattern */ - if (*(p - 1) == '\\' || (*p == '!' && *(p - 1) == '[')) { - p++; - goto retry; - } - } -end: - *e = p; - return s; -} - -static struct strfilter_node *strfilter_node__alloc(const char *op, - struct strfilter_node *l, - struct strfilter_node *r) -{ - struct strfilter_node *ret = zalloc(sizeof(struct strfilter_node)); - - if (ret) { - ret->p = op; - ret->l = l; - ret->r = r; - } - - return ret; -} - -static struct strfilter_node *strfilter_node__new(const char *s, - const char **ep) -{ - struct strfilter_node root, *cur, *last_op; - const char *e; - - if (!s) - return NULL; - - memset(&root, 0, sizeof(root)); - last_op = cur = &root; - - s = get_token(s, &e); - while (*s != '\0' && *s != ')') { - switch (*s) { - case '&': /* Exchg last OP->r with AND */ - if (!cur->r || !last_op->r) - goto error; - cur = strfilter_node__alloc(OP_and, last_op->r, NULL); - if (!cur) - goto nomem; - last_op->r = cur; - last_op = cur; - break; - case '|': /* Exchg the root with OR */ - if (!cur->r || !root.r) - goto error; - cur = strfilter_node__alloc(OP_or, root.r, NULL); - if (!cur) - goto nomem; - root.r = cur; - last_op = cur; - break; - case '!': /* Add NOT as a leaf node */ - if (cur->r) - goto error; - cur->r = strfilter_node__alloc(OP_not, NULL, NULL); - if (!cur->r) - goto nomem; - cur = cur->r; - break; - case '(': /* Recursively parses inside the parenthesis */ - if (cur->r) - goto error; - cur->r = strfilter_node__new(s + 1, &s); - if (!s) - goto nomem; - if (!cur->r || *s != ')') - goto error; - e = s + 1; - break; - default: - if (cur->r) - goto error; - cur->r = strfilter_node__alloc(NULL, NULL, NULL); - if (!cur->r) - goto nomem; - cur->r->p = strndup(s, e - s); - if (!cur->r->p) - goto nomem; - } - s = get_token(e, &e); - } - if (!cur->r) - goto error; - *ep = s; - return root.r; -nomem: - s = NULL; -error: - *ep = s; - strfilter_node__delete(root.r); - return NULL; -} - -/* - * Parse filter rule and return new strfilter. - * Return NULL if fail, and *ep == NULL if memory allocation failed. - */ -struct strfilter *strfilter__new(const char *rules, const char **err) -{ - struct strfilter *ret = zalloc(sizeof(struct strfilter)); - const char *ep = NULL; - - if (ret) - ret->root = strfilter_node__new(rules, &ep); - - if (!ret || !ret->root || *ep != '\0') { - if (err) - *err = ep; - strfilter__delete(ret); - ret = NULL; - } - - return ret; -} - -static bool strfilter_node__compare(struct strfilter_node *self, - const char *str) -{ - if (!self || !self->p) - return false; - - switch (*self->p) { - case '|': /* OR */ - return strfilter_node__compare(self->l, str) || - strfilter_node__compare(self->r, str); - case '&': /* AND */ - return strfilter_node__compare(self->l, str) && - strfilter_node__compare(self->r, str); - case '!': /* NOT */ - return !strfilter_node__compare(self->r, str); - default: - return strglobmatch(str, self->p); - } -} - -/* Return true if STR matches the filter rules */ -bool strfilter__compare(struct strfilter *self, const char *str) -{ - if (!self) - return false; - return strfilter_node__compare(self->root, str); -} diff --git a/trunk/tools/perf/util/strfilter.h b/trunk/tools/perf/util/strfilter.h deleted file mode 100644 index 00f58a7506de..000000000000 --- a/trunk/tools/perf/util/strfilter.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __PERF_STRFILTER_H -#define __PERF_STRFILTER_H -/* General purpose glob matching filter */ - -#include -#include - -/* A node of string filter */ -struct strfilter_node { - struct strfilter_node *l; /* Tree left branche (for &,|) */ - struct strfilter_node *r; /* Tree right branche (for !,&,|) */ - const char *p; /* Operator or rule */ -}; - -/* String filter */ -struct strfilter { - struct strfilter_node *root; -}; - -/** - * strfilter__new - Create a new string filter - * @rules: Filter rule, which is a combination of glob expressions. - * @err: Pointer which points an error detected on @rules - * - * Parse @rules and return new strfilter. Return NULL if an error detected. - * In that case, *@err will indicate where it is detected, and *@err is NULL - * if a memory allocation is failed. - */ -struct strfilter *strfilter__new(const char *rules, const char **err); - -/** - * strfilter__compare - compare given string and a string filter - * @self: String filter - * @str: target string - * - * Compare @str and @self. Return true if the str match the rule - */ -bool strfilter__compare(struct strfilter *self, const char *str); - -/** - * strfilter__delete - delete a string filter - * @self: String filter to delete - * - * Delete @self. - */ -void strfilter__delete(struct strfilter *self); - -#endif diff --git a/trunk/tools/perf/util/svghelper.c b/trunk/tools/perf/util/svghelper.c index fb737fe9be91..96c866045d60 100644 --- a/trunk/tools/perf/util/svghelper.c +++ b/trunk/tools/perf/util/svghelper.c @@ -456,9 +456,9 @@ void svg_legenda(void) return; svg_legenda_box(0, "Running", "sample"); - svg_legenda_box(100, "Idle","rect.c1"); - svg_legenda_box(200, "Deeper Idle", "rect.c3"); - svg_legenda_box(350, "Deepest Idle", "rect.c6"); + svg_legenda_box(100, "Idle","c1"); + svg_legenda_box(200, "Deeper Idle", "c3"); + svg_legenda_box(350, "Deepest Idle", "c6"); svg_legenda_box(550, "Sleeping", "process2"); svg_legenda_box(650, "Waiting for cpu", "waiting"); svg_legenda_box(800, "Blocked on IO", "blocked"); diff --git a/trunk/tools/perf/util/symbol.c b/trunk/tools/perf/util/symbol.c index 3e193f8e3061..b1bf490aff88 100644 --- a/trunk/tools/perf/util/symbol.c +++ b/trunk/tools/perf/util/symbol.c @@ -1525,8 +1525,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) symbol_conf.symfs, self->long_name); break; case DSO__ORIG_GUEST_KMODULE: - if (map->groups && machine) - root_dir = machine->root_dir; + if (map->groups && map->groups->machine) + root_dir = map->groups->machine->root_dir; else root_dir = ""; snprintf(name, size, "%s%s%s", symbol_conf.symfs, @@ -1836,7 +1836,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map, int err = -1, fd; char symfs_vmlinux[PATH_MAX]; - snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s/%s", + snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", symbol_conf.symfs, vmlinux); fd = open(symfs_vmlinux, O_RDONLY); if (fd < 0) diff --git a/trunk/tools/perf/util/thread.c b/trunk/tools/perf/util/thread.c index d5d3b22250f3..00f4eade2e3e 100644 --- a/trunk/tools/perf/util/thread.c +++ b/trunk/tools/perf/util/thread.c @@ -7,6 +7,61 @@ #include "util.h" #include "debug.h" +/* Skip "." and ".." directories */ +static int filter(const struct dirent *dir) +{ + if (dir->d_name[0] == '.') + return 0; + else + return 1; +} + +struct thread_map *thread_map__new_by_pid(pid_t pid) +{ + struct thread_map *threads; + char name[256]; + int items; + struct dirent **namelist = NULL; + int i; + + sprintf(name, "/proc/%d/task", pid); + items = scandir(name, &namelist, filter, NULL); + if (items <= 0) + return NULL; + + threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); + if (threads != NULL) { + for (i = 0; i < items; i++) + threads->map[i] = atoi(namelist[i]->d_name); + threads->nr = items; + } + + for (i=0; imap[0] = tid; + threads->nr = 1; + } + + return threads; +} + +struct thread_map *thread_map__new(pid_t pid, pid_t tid) +{ + if (pid != -1) + return thread_map__new_by_pid(pid); + return thread_map__new_by_tid(tid); +} + static struct thread *thread__new(pid_t pid) { struct thread *self = zalloc(sizeof(*self)); diff --git a/trunk/tools/perf/util/thread.h b/trunk/tools/perf/util/thread.h index e5f2401c1b5e..d7574101054a 100644 --- a/trunk/tools/perf/util/thread.h +++ b/trunk/tools/perf/util/thread.h @@ -18,10 +18,24 @@ struct thread { int comm_len; }; +struct thread_map { + int nr; + int map[]; +}; + struct perf_session; void thread__delete(struct thread *self); +struct thread_map *thread_map__new_by_pid(pid_t pid); +struct thread_map *thread_map__new_by_tid(pid_t tid); +struct thread_map *thread_map__new(pid_t pid, pid_t tid); + +static inline void thread_map__delete(struct thread_map *threads) +{ + free(threads); +} + 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); diff --git a/trunk/tools/perf/util/thread_map.c b/trunk/tools/perf/util/thread_map.c deleted file mode 100644 index a5df131b77c3..000000000000 --- a/trunk/tools/perf/util/thread_map.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include "thread_map.h" - -/* Skip "." and ".." directories */ -static int filter(const struct dirent *dir) -{ - if (dir->d_name[0] == '.') - return 0; - else - return 1; -} - -struct thread_map *thread_map__new_by_pid(pid_t pid) -{ - struct thread_map *threads; - char name[256]; - int items; - struct dirent **namelist = NULL; - int i; - - sprintf(name, "/proc/%d/task", pid); - items = scandir(name, &namelist, filter, NULL); - if (items <= 0) - return NULL; - - threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); - if (threads != NULL) { - for (i = 0; i < items; i++) - threads->map[i] = atoi(namelist[i]->d_name); - threads->nr = items; - } - - for (i=0; imap[0] = tid; - threads->nr = 1; - } - - return threads; -} - -struct thread_map *thread_map__new(pid_t pid, pid_t tid) -{ - if (pid != -1) - return thread_map__new_by_pid(pid); - return thread_map__new_by_tid(tid); -} - -void thread_map__delete(struct thread_map *threads) -{ - free(threads); -} diff --git a/trunk/tools/perf/util/thread_map.h b/trunk/tools/perf/util/thread_map.h deleted file mode 100644 index 3cb907311409..000000000000 --- a/trunk/tools/perf/util/thread_map.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __PERF_THREAD_MAP_H -#define __PERF_THREAD_MAP_H - -#include - -struct thread_map { - int nr; - int map[]; -}; - -struct thread_map *thread_map__new_by_pid(pid_t pid); -struct thread_map *thread_map__new_by_tid(pid_t tid); -struct thread_map *thread_map__new(pid_t pid, pid_t tid); -void thread_map__delete(struct thread_map *threads); -#endif /* __PERF_THREAD_MAP_H */ diff --git a/trunk/tools/perf/util/top.c b/trunk/tools/perf/util/top.c deleted file mode 100644 index 70a9c13f4ad5..000000000000 --- a/trunk/tools/perf/util/top.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo - * - * Refactored from builtin-top.c, see that files for further copyright notes. - * - * Released under the GPL v2. (and only v2, not any later version) - */ - -#include "cpumap.h" -#include "event.h" -#include "evlist.h" -#include "evsel.h" -#include "parse-events.h" -#include "symbol.h" -#include "top.h" -#include - -/* - * Ordering weight: count-1 * count-2 * ... / count-n - */ -static double sym_weight(const struct sym_entry *sym, struct perf_top *top) -{ - double weight = sym->snap_count; - int counter; - - if (!top->display_weighted) - return weight; - - for (counter = 1; counter < top->evlist->nr_entries - 1; counter++) - weight *= sym->count[counter]; - - weight /= (sym->count[counter] + 1); - - return weight; -} - -static void perf_top__remove_active_sym(struct perf_top *top, struct sym_entry *syme) -{ - pthread_mutex_lock(&top->active_symbols_lock); - list_del_init(&syme->node); - pthread_mutex_unlock(&top->active_symbols_lock); -} - -static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) -{ - struct rb_node **p = &tree->rb_node; - struct rb_node *parent = NULL; - struct sym_entry *iter; - - while (*p != NULL) { - parent = *p; - iter = rb_entry(parent, struct sym_entry, rb_node); - - if (se->weight > iter->weight) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - rb_link_node(&se->rb_node, parent, p); - rb_insert_color(&se->rb_node, tree); -} - -size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) -{ - struct perf_evsel *counter; - float samples_per_sec = top->samples / top->delay_secs; - float ksamples_per_sec = top->kernel_samples / top->delay_secs; - float esamples_percent = (100.0 * top->exact_samples) / top->samples; - size_t ret = 0; - - if (!perf_guest) { - ret = snprintf(bf, size, - " PerfTop:%8.0f irqs/sec kernel:%4.1f%%" - " exact: %4.1f%% [", samples_per_sec, - 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / - samples_per_sec)), - esamples_percent); - } else { - float us_samples_per_sec = top->us_samples / top->delay_secs; - float guest_kernel_samples_per_sec = top->guest_kernel_samples / top->delay_secs; - float guest_us_samples_per_sec = top->guest_us_samples / top->delay_secs; - - ret = snprintf(bf, size, - " PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" - " guest kernel:%4.1f%% guest us:%4.1f%%" - " exact: %4.1f%% [", samples_per_sec, - 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / - samples_per_sec)), - 100.0 - (100.0 * ((samples_per_sec - us_samples_per_sec) / - samples_per_sec)), - 100.0 - (100.0 * ((samples_per_sec - - guest_kernel_samples_per_sec) / - samples_per_sec)), - 100.0 - (100.0 * ((samples_per_sec - - guest_us_samples_per_sec) / - samples_per_sec)), - esamples_percent); - } - - if (top->evlist->nr_entries == 1 || !top->display_weighted) { - struct perf_evsel *first; - first = list_entry(top->evlist->entries.next, struct perf_evsel, node); - ret += snprintf(bf + ret, size - ret, "%" PRIu64 "%s ", - (uint64_t)first->attr.sample_period, - top->freq ? "Hz" : ""); - } - - if (!top->display_weighted) { - ret += snprintf(bf + ret, size - ret, "%s", - event_name(top->sym_evsel)); - } else list_for_each_entry(counter, &top->evlist->entries, node) { - ret += snprintf(bf + ret, size - ret, "%s%s", - counter->idx ? "/" : "", event_name(counter)); - } - - ret += snprintf(bf + ret, size - ret, "], "); - - if (top->target_pid != -1) - ret += snprintf(bf + ret, size - ret, " (target_pid: %d", - top->target_pid); - else if (top->target_tid != -1) - ret += snprintf(bf + ret, size - ret, " (target_tid: %d", - top->target_tid); - else - ret += snprintf(bf + ret, size - ret, " (all"); - - if (top->cpu_list) - ret += snprintf(bf + ret, size - ret, ", CPU%s: %s)", - top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); - else { - if (top->target_tid != -1) - ret += snprintf(bf + ret, size - ret, ")"); - else - ret += snprintf(bf + ret, size - ret, ", %d CPU%s)", - top->evlist->cpus->nr, - top->evlist->cpus->nr > 1 ? "s" : ""); - } - - return ret; -} - -void perf_top__reset_sample_counters(struct perf_top *top) -{ - top->samples = top->us_samples = top->kernel_samples = - top->exact_samples = top->guest_kernel_samples = - top->guest_us_samples = 0; -} - -float perf_top__decay_samples(struct perf_top *top, struct rb_root *root) -{ - struct sym_entry *syme, *n; - float sum_ksamples = 0.0; - int snap = !top->display_weighted ? top->sym_counter : 0, j; - - /* Sort the active symbols */ - pthread_mutex_lock(&top->active_symbols_lock); - syme = list_entry(top->active_symbols.next, struct sym_entry, node); - pthread_mutex_unlock(&top->active_symbols_lock); - - top->rb_entries = 0; - list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) { - syme->snap_count = syme->count[snap]; - if (syme->snap_count != 0) { - - if ((top->hide_user_symbols && - syme->origin == PERF_RECORD_MISC_USER) || - (top->hide_kernel_symbols && - syme->origin == PERF_RECORD_MISC_KERNEL)) { - perf_top__remove_active_sym(top, syme); - continue; - } - syme->weight = sym_weight(syme, top); - - if ((int)syme->snap_count >= top->count_filter) { - rb_insert_active_sym(root, syme); - ++top->rb_entries; - } - sum_ksamples += syme->snap_count; - - for (j = 0; j < top->evlist->nr_entries; j++) - syme->count[j] = top->zero ? 0 : syme->count[j] * 7 / 8; - } else - perf_top__remove_active_sym(top, syme); - } - - return sum_ksamples; -} - -/* - * Find the longest symbol name that will be displayed - */ -void perf_top__find_widths(struct perf_top *top, struct rb_root *root, - int *dso_width, int *dso_short_width, int *sym_width) -{ - struct rb_node *nd; - int printed = 0; - - *sym_width = *dso_width = *dso_short_width = 0; - - for (nd = rb_first(root); nd; nd = rb_next(nd)) { - struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); - struct symbol *sym = sym_entry__symbol(syme); - - if (++printed > top->print_entries || - (int)syme->snap_count < top->count_filter) - continue; - - if (syme->map->dso->long_name_len > *dso_width) - *dso_width = syme->map->dso->long_name_len; - - if (syme->map->dso->short_name_len > *dso_short_width) - *dso_short_width = syme->map->dso->short_name_len; - - if (sym->namelen > *sym_width) - *sym_width = sym->namelen; - } -} diff --git a/trunk/tools/perf/util/top.h b/trunk/tools/perf/util/top.h deleted file mode 100644 index 96d1cb78af01..000000000000 --- a/trunk/tools/perf/util/top.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __PERF_TOP_H -#define __PERF_TOP_H 1 - -#include "types.h" -#include "../perf.h" -#include -#include -#include -#include - -struct perf_evlist; -struct perf_evsel; - -struct sym_entry { - struct rb_node rb_node; - struct list_head node; - unsigned long snap_count; - double weight; - int skip; - u8 origin; - struct map *map; - unsigned long count[0]; -}; - -static inline struct symbol *sym_entry__symbol(struct sym_entry *self) -{ - return ((void *)self) + symbol_conf.priv_size; -} - -struct perf_top { - struct perf_evlist *evlist; - /* - * Symbols will be added here in perf_event__process_sample and will - * get out after decayed. - */ - struct list_head active_symbols; - pthread_mutex_t active_symbols_lock; - pthread_cond_t active_symbols_cond; - u64 samples; - u64 kernel_samples, us_samples; - u64 exact_samples; - u64 guest_us_samples, guest_kernel_samples; - int print_entries, count_filter, delay_secs; - int display_weighted, freq, rb_entries, sym_counter; - pid_t target_pid, target_tid; - bool hide_kernel_symbols, hide_user_symbols, zero; - const char *cpu_list; - struct sym_entry *sym_filter_entry; - struct perf_evsel *sym_evsel; -}; - -size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); -void perf_top__reset_sample_counters(struct perf_top *top); -float perf_top__decay_samples(struct perf_top *top, struct rb_root *root); -void perf_top__find_widths(struct perf_top *top, struct rb_root *root, - int *dso_width, int *dso_short_width, int *sym_width); - -#ifdef NO_NEWT_SUPPORT -static inline int perf_top__tui_browser(struct perf_top *top __used) -{ - return 0; -} -#else -int perf_top__tui_browser(struct perf_top *top); -#endif -#endif /* __PERF_TOP_H */ diff --git a/trunk/tools/perf/util/trace-event-parse.c b/trunk/tools/perf/util/trace-event-parse.c index d8e622dd738a..73a02223c629 100644 --- a/trunk/tools/perf/util/trace-event-parse.c +++ b/trunk/tools/perf/util/trace-event-parse.c @@ -153,7 +153,7 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused) char *next = NULL; char *addr_str; char ch; - int ret __used; + int ret; int i; line = strtok_r(file, "\n", &next); diff --git a/trunk/tools/perf/util/ui/browser.c b/trunk/tools/perf/util/ui/browser.c index 611219f80680..8bc010edca25 100644 --- a/trunk/tools/perf/util/ui/browser.c +++ b/trunk/tools/perf/util/ui/browser.c @@ -1,5 +1,4 @@ #include "libslang.h" -#include "ui.h" #include #include #include @@ -157,20 +156,6 @@ void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]) } } -void __ui_browser__show_title(struct ui_browser *browser, const char *title) -{ - SLsmg_gotorc(0, 0); - ui_browser__set_color(browser, NEWT_COLORSET_ROOT); - slsmg_write_nstring(title, browser->width); -} - -void ui_browser__show_title(struct ui_browser *browser, const char *title) -{ - pthread_mutex_lock(&ui__lock); - __ui_browser__show_title(browser, title); - pthread_mutex_unlock(&ui__lock); -} - int ui_browser__show(struct ui_browser *self, const char *title, const char *helpline, ...) { @@ -193,8 +178,9 @@ int ui_browser__show(struct ui_browser *self, const char *title, if (self->sb == NULL) return -1; - pthread_mutex_lock(&ui__lock); - __ui_browser__show_title(self, title); + SLsmg_gotorc(0, 0); + ui_browser__set_color(self, NEWT_COLORSET_ROOT); + slsmg_write_nstring(title, self->width); ui_browser__add_exit_keys(self, keys); newtFormAddComponent(self->form, self->sb); @@ -202,30 +188,25 @@ int ui_browser__show(struct ui_browser *self, const char *title, va_start(ap, helpline); ui_helpline__vpush(helpline, ap); va_end(ap); - pthread_mutex_unlock(&ui__lock); return 0; } void ui_browser__hide(struct ui_browser *self) { - pthread_mutex_lock(&ui__lock); newtFormDestroy(self->form); self->form = NULL; ui_helpline__pop(); - pthread_mutex_unlock(&ui__lock); } int ui_browser__refresh(struct ui_browser *self) { int row; - pthread_mutex_lock(&ui__lock); newtScrollbarSet(self->sb, self->index, self->nr_entries - 1); row = self->refresh(self); ui_browser__set_color(self, HE_COLORSET_NORMAL); SLsmg_fill_region(self->y + row, self->x, self->height - row, self->width, ' '); - pthread_mutex_unlock(&ui__lock); return 0; } diff --git a/trunk/tools/perf/util/ui/browser.h b/trunk/tools/perf/util/ui/browser.h index fc63dda10910..0dc7e4da36f5 100644 --- a/trunk/tools/perf/util/ui/browser.h +++ b/trunk/tools/perf/util/ui/browser.h @@ -24,6 +24,7 @@ struct ui_browser { u32 nr_entries; }; + void ui_browser__set_color(struct ui_browser *self, int color); void ui_browser__set_percent_color(struct ui_browser *self, double percent, bool current); @@ -34,8 +35,6 @@ void ui_browser__reset_index(struct ui_browser *self); void ui_browser__gotorc(struct ui_browser *self, int y, int x); void ui_browser__add_exit_key(struct ui_browser *self, int key); void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]); -void __ui_browser__show_title(struct ui_browser *browser, const char *title); -void ui_browser__show_title(struct ui_browser *browser, const char *title); int ui_browser__show(struct ui_browser *self, const char *title, const char *helpline, ...); void ui_browser__hide(struct ui_browser *self); diff --git a/trunk/tools/perf/util/ui/browsers/annotate.c b/trunk/tools/perf/util/ui/browsers/annotate.c index 8c17a8730e4a..82b78f99251b 100644 --- a/trunk/tools/perf/util/ui/browsers/annotate.c +++ b/trunk/tools/perf/util/ui/browsers/annotate.c @@ -1,12 +1,9 @@ #include "../browser.h" #include "../helpline.h" #include "../libslang.h" -#include "../../annotate.h" #include "../../hist.h" #include "../../sort.h" #include "../../symbol.h" -#include "../../annotate.h" -#include static void ui__error_window(const char *fmt, ...) { @@ -45,6 +42,8 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro struct objdump_line_rb_node *olrb = objdump_line__rb(ol); ui_browser__set_percent_color(self, olrb->percent, current_entry); slsmg_printf(" %7.2f ", olrb->percent); + if (!current_entry) + ui_browser__set_color(self, HE_COLORSET_CODE); } else { ui_browser__set_percent_color(self, 0, current_entry); slsmg_write_nstring(" ", 9); @@ -56,40 +55,35 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro slsmg_write_nstring(" ", width - 18); else slsmg_write_nstring(ol->line, width - 18); - - if (!current_entry) - ui_browser__set_color(self, HE_COLORSET_CODE); } static double objdump_line__calc_percent(struct objdump_line *self, - struct symbol *sym, int evidx) + struct list_head *head, + struct symbol *sym) { double percent = 0.0; if (self->offset != -1) { int len = sym->end - sym->start; unsigned int hits = 0; - struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src->lines; - struct sym_hist *h = annotation__histogram(notes, evidx); + struct sym_priv *priv = symbol__priv(sym); + struct sym_ext *sym_ext = priv->ext; + struct sym_hist *h = priv->hist; s64 offset = self->offset; - struct objdump_line *next; + struct objdump_line *next = objdump__get_next_ip_line(head, self); + - next = objdump__get_next_ip_line(¬es->src->source, self); while (offset < (s64)len && (next == NULL || offset < next->offset)) { - if (src_line) { - percent += src_line[offset].percent; + if (sym_ext) { + percent += sym_ext[offset].percent; } else - hits += h->addr[offset]; + hits += h->ip[offset]; ++offset; } - /* - * If the percentage wasn't already calculated in - * symbol__get_source_line, do it now: - */ - if (src_line == NULL && h->sum) + + if (sym_ext == NULL && h->sum) percent = 100.0 * hits / h->sum; } @@ -139,161 +133,103 @@ static void annotate_browser__set_top(struct annotate_browser *self, self->curr_hot = nd; } -static void annotate_browser__calc_percent(struct annotate_browser *browser, - int evidx) +static int annotate_browser__run(struct annotate_browser *self) { - struct symbol *sym = browser->b.priv; - struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos; - - browser->entries = RB_ROOT; - - pthread_mutex_lock(¬es->lock); - - list_for_each_entry(pos, ¬es->src->source, node) { - struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); - rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); - if (rbpos->percent < 0.01) { - RB_CLEAR_NODE(&rbpos->rb_node); - continue; - } - objdump__insert_line(&browser->entries, rbpos); - } - pthread_mutex_unlock(¬es->lock); - - browser->curr_hot = rb_last(&browser->entries); -} + struct rb_node *nd; + struct hist_entry *he = self->b.priv; + int key; -static int annotate_browser__run(struct annotate_browser *self, int evidx, - int refresh) -{ - struct rb_node *nd = NULL; - struct symbol *sym = self->b.priv; + if (ui_browser__show(&self->b, he->ms.sym->name, + "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0) + return -1; /* - * RIGHT To allow builtin-annotate to cycle thru multiple symbols by + * To allow builtin-annotate to cycle thru multiple symbols by * examining the exit key for this function. */ - int exit_keys[] = { 'H', NEWT_KEY_TAB, NEWT_KEY_UNTAB, - NEWT_KEY_RIGHT, 0 }; - int key; - - if (ui_browser__show(&self->b, sym->name, - "<-, -> or ESC: exit, TAB/shift+TAB: " - "cycle hottest lines, H: Hottest") < 0) - return -1; - - ui_browser__add_exit_keys(&self->b, exit_keys); - annotate_browser__calc_percent(self, evidx); - - if (self->curr_hot) - annotate_browser__set_top(self, self->curr_hot); + ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT); nd = self->curr_hot; - - if (refresh != 0) - newtFormSetTimer(self->b.form, refresh); + if (nd) { + int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 }; + ui_browser__add_exit_keys(&self->b, tabs); + } while (1) { key = ui_browser__run(&self->b); - if (refresh != 0) { - annotate_browser__calc_percent(self, evidx); - /* - * Current line focus got out of the list of most active - * lines, NULL it so that if TAB|UNTAB is pressed, we - * move to curr_hot (current hottest line). - */ - if (nd != NULL && RB_EMPTY_NODE(nd)) - nd = NULL; - } - switch (key) { - case -1: - /* - * FIXME we need to check if it was - * es.reason == NEWT_EXIT_TIMER - */ - if (refresh != 0) - symbol__annotate_decay_histogram(sym, evidx); - continue; case NEWT_KEY_TAB: - if (nd != NULL) { - nd = rb_prev(nd); - if (nd == NULL) - nd = rb_last(&self->entries); - } else - nd = self->curr_hot; + nd = rb_prev(nd); + if (nd == NULL) + nd = rb_last(&self->entries); + annotate_browser__set_top(self, nd); break; case NEWT_KEY_UNTAB: - if (nd != NULL) - nd = rb_next(nd); - if (nd == NULL) - nd = rb_first(&self->entries); - else - nd = self->curr_hot; - break; - case 'H': - nd = self->curr_hot; + nd = rb_next(nd); + if (nd == NULL) + nd = rb_first(&self->entries); + annotate_browser__set_top(self, nd); break; default: goto out; } - - if (nd != NULL) - annotate_browser__set_top(self, nd); } out: ui_browser__hide(&self->b); return key; } -int hist_entry__tui_annotate(struct hist_entry *he, int evidx) -{ - return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx, 0); -} - -int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, - int refresh) +int hist_entry__tui_annotate(struct hist_entry *self) { struct objdump_line *pos, *n; - struct annotation *notes = symbol__annotation(sym); + struct objdump_line_rb_node *rbpos; + LIST_HEAD(head); struct annotate_browser browser = { .b = { - .entries = ¬es->src->source, + .entries = &head, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, - .priv = sym, + .priv = self, }, }; int ret; - if (sym == NULL) + if (self->ms.sym == NULL) return -1; - if (map->dso->annotate_warned) + if (self->ms.map->dso->annotate_warned) return -1; - if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { + if (hist_entry__annotate(self, &head, sizeof(*rbpos)) < 0) { ui__error_window(ui_helpline__last_msg); return -1; } ui_helpline__push("Press <- or ESC to exit"); - list_for_each_entry(pos, ¬es->src->source, node) { - struct objdump_line_rb_node *rbpos; + list_for_each_entry(pos, &head, node) { size_t line_len = strlen(pos->line); - if (browser.b.width < line_len) browser.b.width = line_len; rbpos = objdump_line__rb(pos); rbpos->idx = browser.b.nr_entries++; + rbpos->percent = objdump_line__calc_percent(pos, &head, self->ms.sym); + if (rbpos->percent < 0.01) + continue; + objdump__insert_line(&browser.entries, rbpos); } + /* + * Position the browser at the hottest line. + */ + browser.curr_hot = rb_last(&browser.entries); + if (browser.curr_hot) + annotate_browser__set_top(&browser, browser.curr_hot); + browser.b.width += 18; /* Percentage */ - ret = annotate_browser__run(&browser, evidx, refresh); - list_for_each_entry_safe(pos, n, ¬es->src->source, node) { + ret = annotate_browser__run(&browser); + list_for_each_entry_safe(pos, n, &head, 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 497b3c4076a3..60c463c16028 100644 --- a/trunk/tools/perf/util/ui/browsers/hists.c +++ b/trunk/tools/perf/util/ui/browsers/hists.c @@ -377,7 +377,7 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self, while (node) { struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); struct rb_node *next = rb_next(node); - u64 cumul = callchain_cumul_hits(child); + u64 cumul = cumul_hits(child); struct callchain_list *chain; char folded_sign = ' '; int first = true; @@ -797,8 +797,7 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size, return printed; } -int hists__browse(struct hists *self, const char *helpline, - const char *ev_name, int evidx) +int hists__browse(struct hists *self, const char *helpline, const char *ev_name) { struct hist_browser *browser = hist_browser__new(self); struct pstack *fstack; @@ -924,11 +923,19 @@ int hists__browse(struct hists *self, const char *helpline, if (choice == annotate) { struct hist_entry *he; do_annotate: + if (browser->selection->map->dso->origin == DSO__ORIG_KERNEL) { + browser->selection->map->dso->annotate_warned = 1; + ui_helpline__puts("No vmlinux file found, can't " + "annotate with just a " + "kallsyms file"); + continue; + } + he = hist_browser__selected_entry(browser); if (he == NULL) continue; - hist_entry__tui_annotate(he, evidx); + hist_entry__tui_annotate(he); } else if (choice == browse_map) map__browse(browser->selection->map); else if (choice == zoom_dso) { @@ -977,7 +984,7 @@ int hists__browse(struct hists *self, const char *helpline, return key; } -int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx) +int hists__tui_browse_tree(struct rb_root *self, const char *help) { struct rb_node *first = rb_first(self), *nd = first, *next; int key = 0; @@ -986,7 +993,7 @@ int hists__tui_browse_tree(struct rb_root *self, const char *help, int evidx) struct hists *hists = rb_entry(nd, struct hists, rb_node); const char *ev_name = __event_name(hists->type, hists->config); - key = hists__browse(hists, help, ev_name, evidx); + key = hists__browse(hists, help, ev_name); switch (key) { case NEWT_KEY_TAB: next = rb_next(nd); diff --git a/trunk/tools/perf/util/ui/browsers/map.c b/trunk/tools/perf/util/ui/browsers/map.c index 8462bffe20bc..e5158369106e 100644 --- a/trunk/tools/perf/util/ui/browsers/map.c +++ b/trunk/tools/perf/util/ui/browsers/map.c @@ -41,7 +41,7 @@ static int ui_entry__read(const char *title, char *bf, size_t size, int width) out_free_form: newtPopWindow(); newtFormDestroy(form); - return err; + return 0; } struct map_browser { diff --git a/trunk/tools/perf/util/ui/browsers/top.c b/trunk/tools/perf/util/ui/browsers/top.c deleted file mode 100644 index 5a06538532af..000000000000 --- a/trunk/tools/perf/util/ui/browsers/top.c +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo - * - * Parts came from builtin-{top,stat,record}.c, see those files for further - * copyright notes. - * - * Released under the GPL v2. (and only v2, not any later version) - */ -#include "../browser.h" -#include "../../annotate.h" -#include "../helpline.h" -#include "../libslang.h" -#include "../util.h" -#include "../../evlist.h" -#include "../../hist.h" -#include "../../sort.h" -#include "../../symbol.h" -#include "../../top.h" - -struct perf_top_browser { - struct ui_browser b; - struct rb_root root; - struct sym_entry *selection; - float sum_ksamples; - int dso_width; - int dso_short_width; - int sym_width; -}; - -static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row) -{ - struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b); - struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node); - bool current_entry = ui_browser__is_current_entry(browser, row); - struct symbol *symbol = sym_entry__symbol(syme); - struct perf_top *top = browser->priv; - int width = browser->width; - double pcnt; - - pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) / - top_browser->sum_ksamples)); - ui_browser__set_percent_color(browser, pcnt, current_entry); - - if (top->evlist->nr_entries == 1 || !top->display_weighted) { - slsmg_printf("%20.2f ", syme->weight); - width -= 24; - } else { - slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count); - width -= 23; - } - - slsmg_printf("%4.1f%%", pcnt); - width -= 7; - - if (verbose) { - slsmg_printf(" %016" PRIx64, symbol->start); - width -= 17; - } - - slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width, - symbol->name); - width -= top_browser->sym_width; - slsmg_write_nstring(width >= syme->map->dso->long_name_len ? - syme->map->dso->long_name : - syme->map->dso->short_name, width); - - if (current_entry) - top_browser->selection = syme; -} - -static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) -{ - struct perf_top *top = browser->b.priv; - u64 top_idx = browser->b.top_idx; - - browser->root = RB_ROOT; - browser->b.top = NULL; - browser->sum_ksamples = perf_top__decay_samples(top, &browser->root); - /* - * No active symbols - */ - if (top->rb_entries == 0) - return; - - perf_top__find_widths(top, &browser->root, &browser->dso_width, - &browser->dso_short_width, - &browser->sym_width); - if (browser->sym_width + browser->dso_width > browser->b.width - 29) { - browser->dso_width = browser->dso_short_width; - if (browser->sym_width + browser->dso_width > browser->b.width - 29) - browser->sym_width = browser->b.width - browser->dso_width - 29; - } - - /* - * Adjust the ui_browser indexes since the entries in the browser->root - * rb_tree may have changed, then seek it from start, so that we get a - * possible new top of the screen. - */ - browser->b.nr_entries = top->rb_entries; - - if (top_idx >= browser->b.nr_entries) { - if (browser->b.height >= browser->b.nr_entries) - top_idx = browser->b.nr_entries - browser->b.height; - else - top_idx = 0; - } - - if (browser->b.index >= top_idx + browser->b.height) - browser->b.index = top_idx + browser->b.index - browser->b.top_idx; - - if (browser->b.index >= browser->b.nr_entries) - browser->b.index = browser->b.nr_entries - 1; - - browser->b.top_idx = top_idx; - browser->b.seek(&browser->b, top_idx, SEEK_SET); -} - -static void perf_top_browser__annotate(struct perf_top_browser *browser) -{ - struct sym_entry *syme = browser->selection; - struct symbol *sym = sym_entry__symbol(syme); - struct annotation *notes = symbol__annotation(sym); - struct perf_top *top = browser->b.priv; - - if (notes->src != NULL) - goto do_annotation; - - pthread_mutex_lock(¬es->lock); - - top->sym_filter_entry = NULL; - - if (symbol__alloc_hist(sym, top->evlist->nr_entries) < 0) { - pr_err("Not enough memory for annotating '%s' symbol!\n", - sym->name); - pthread_mutex_unlock(¬es->lock); - return; - } - - top->sym_filter_entry = syme; - - pthread_mutex_unlock(¬es->lock); -do_annotation: - symbol__tui_annotate(sym, syme->map, 0, top->delay_secs * 1000); -} - -static int perf_top_browser__run(struct perf_top_browser *browser) -{ - int key; - char title[160]; - struct perf_top *top = browser->b.priv; - int delay_msecs = top->delay_secs * 1000; - int exit_keys[] = { 'a', NEWT_KEY_ENTER, NEWT_KEY_RIGHT, 0, }; - - perf_top_browser__update_rb_tree(browser); - perf_top__header_snprintf(top, title, sizeof(title)); - perf_top__reset_sample_counters(top); - - if (ui_browser__show(&browser->b, title, - "ESC: exit, ENTER|->|a: Live Annotate") < 0) - return -1; - - newtFormSetTimer(browser->b.form, delay_msecs); - ui_browser__add_exit_keys(&browser->b, exit_keys); - - while (1) { - key = ui_browser__run(&browser->b); - - switch (key) { - case -1: - /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ - perf_top_browser__update_rb_tree(browser); - perf_top__header_snprintf(top, title, sizeof(title)); - perf_top__reset_sample_counters(top); - ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT); - SLsmg_gotorc(0, 0); - slsmg_write_nstring(title, browser->b.width); - break; - case 'a': - case NEWT_KEY_RIGHT: - case NEWT_KEY_ENTER: - if (browser->selection) - perf_top_browser__annotate(browser); - break; - case NEWT_KEY_LEFT: - continue; - case NEWT_KEY_ESCAPE: - if (!ui__dialog_yesno("Do you really want to exit?")) - continue; - /* Fall thru */ - default: - goto out; - } - } -out: - ui_browser__hide(&browser->b); - return key; -} - -int perf_top__tui_browser(struct perf_top *top) -{ - struct perf_top_browser browser = { - .b = { - .entries = &browser.root, - .refresh = ui_browser__rb_tree_refresh, - .seek = ui_browser__rb_tree_seek, - .write = perf_top_browser__write, - .priv = top, - }, - }; - - ui_helpline__push("Press <- or ESC to exit"); - return perf_top_browser__run(&browser); -} diff --git a/trunk/tools/perf/util/ui/helpline.c b/trunk/tools/perf/util/ui/helpline.c index f36d2ff509ed..8d79daa4458a 100644 --- a/trunk/tools/perf/util/ui/helpline.c +++ b/trunk/tools/perf/util/ui/helpline.c @@ -5,7 +5,6 @@ #include "../debug.h" #include "helpline.h" -#include "ui.h" void ui_helpline__pop(void) { @@ -56,8 +55,7 @@ int ui_helpline__show_help(const char *format, va_list ap) int ret; static int backlog; - pthread_mutex_lock(&ui__lock); - ret = vsnprintf(ui_helpline__last_msg + backlog, + ret = vsnprintf(ui_helpline__last_msg + backlog, sizeof(ui_helpline__last_msg) - backlog, format, ap); backlog += ret; @@ -66,7 +64,6 @@ int ui_helpline__show_help(const char *format, va_list ap) newtRefresh(); backlog = 0; } - pthread_mutex_unlock(&ui__lock); return ret; } diff --git a/trunk/tools/perf/util/ui/libslang.h b/trunk/tools/perf/util/ui/libslang.h index 2b63e1c9b181..5623da8e8080 100644 --- a/trunk/tools/perf/util/ui/libslang.h +++ b/trunk/tools/perf/util/ui/libslang.h @@ -13,11 +13,11 @@ #if SLANG_VERSION < 20104 #define slsmg_printf(msg, args...) \ - SLsmg_printf((char *)(msg), ##args) + SLsmg_printf((char *)msg, ##args) #define slsmg_write_nstring(msg, len) \ - SLsmg_write_nstring((char *)(msg), len) + SLsmg_write_nstring((char *)msg, len) #define sltt_set_color(obj, name, fg, bg) \ - SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg)) + SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg) #else #define slsmg_printf SLsmg_printf #define slsmg_write_nstring SLsmg_write_nstring diff --git a/trunk/tools/perf/util/ui/setup.c b/trunk/tools/perf/util/ui/setup.c index ee46d671db59..662085032eb7 100644 --- a/trunk/tools/perf/util/ui/setup.c +++ b/trunk/tools/perf/util/ui/setup.c @@ -6,9 +6,6 @@ #include "../debug.h" #include "browser.h" #include "helpline.h" -#include "ui.h" - -pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; static void newt_suspend(void *d __used) { @@ -17,12 +14,11 @@ static void newt_suspend(void *d __used) newtResume(); } -void setup_browser(bool fallback_to_pager) +void setup_browser(void) { if (!isatty(1) || !use_browser || dump_trace) { use_browser = 0; - if (fallback_to_pager) - setup_pager(); + setup_pager(); return; } diff --git a/trunk/tools/perf/util/ui/ui.h b/trunk/tools/perf/util/ui/ui.h deleted file mode 100644 index d264e059c829..000000000000 --- a/trunk/tools/perf/util/ui/ui.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _PERF_UI_H_ -#define _PERF_UI_H_ 1 - -#include - -extern pthread_mutex_t ui__lock; - -#endif /* _PERF_UI_H_ */ diff --git a/trunk/tools/perf/util/ui/util.c b/trunk/tools/perf/util/ui/util.c index fdf1fc8f08bc..7b5a8926624e 100644 --- a/trunk/tools/perf/util/ui/util.c +++ b/trunk/tools/perf/util/ui/util.c @@ -9,7 +9,6 @@ #include "../debug.h" #include "browser.h" #include "helpline.h" -#include "ui.h" #include "util.h" static void newt_form__set_exit_keys(newtComponent self) @@ -119,12 +118,10 @@ void ui__warning(const char *format, ...) va_list args; va_start(args, format); - if (use_browser > 0) { - pthread_mutex_lock(&ui__lock); + if (use_browser > 0) newtWinMessagev((char *)warning_str, (char *)ok, (char *)format, args); - pthread_mutex_unlock(&ui__lock); - } else + else vfprintf(stderr, format, args); va_end(args); } diff --git a/trunk/tools/perf/util/util.h b/trunk/tools/perf/util/util.h index fc784284ac8b..e833f26f3bfc 100644 --- a/trunk/tools/perf/util/util.h +++ b/trunk/tools/perf/util/util.h @@ -70,7 +70,9 @@ #include #include #include +#ifndef NO_SYS_SELECT_H #include +#endif #include #include #include @@ -81,6 +83,10 @@ #include "types.h" #include +#ifndef NO_ICONV +#include +#endif + extern const char *graph_line; extern const char *graph_dotted_line; extern char buildid_dir[]; @@ -230,6 +236,26 @@ static inline int sane_case(int x, int high) return x; } +#ifndef DIR_HAS_BSD_GROUP_SEMANTICS +# define FORCE_DIR_SET_GID S_ISGID +#else +# define FORCE_DIR_SET_GID 0 +#endif + +#ifdef NO_NSEC +#undef USE_NSEC +#define ST_CTIME_NSEC(st) 0 +#define ST_MTIME_NSEC(st) 0 +#else +#ifdef USE_ST_TIMESPEC +#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctimespec.tv_nsec)) +#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtimespec.tv_nsec)) +#else +#define ST_CTIME_NSEC(st) ((unsigned int)((st).st_ctim.tv_nsec)) +#define ST_MTIME_NSEC(st) ((unsigned int)((st).st_mtim.tv_nsec)) +#endif +#endif + int mkdir_p(char *path, mode_t mode); int copyfile(const char *from, const char *to); diff --git a/trunk/tools/testing/ktest/ktest.pl b/trunk/tools/testing/ktest/ktest.pl index ba7c63af6f3b..e1c62eeb88f5 100755 --- a/trunk/tools/testing/ktest/ktest.pl +++ b/trunk/tools/testing/ktest/ktest.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -w # -# Copyright 2010 - Steven Rostedt , Red Hat Inc. +# Copywrite 2010 - Steven Rostedt , Red Hat Inc. # Licensed under the terms of the GNU GPL License version 2 #