aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/scripts/python
Commit message (Collapse)AuthorAge
* perf script: Add drop monitor scriptNeil Horman2011-09-29
| | | | | | | | | | | | | | | | | | | A while back I created the dropmonitor protocol, which allowed users to get reports of dropped frames communicated to them via a netlink socket. While useful, several people have now asked that I integrate the ability to do drop monitoring with perf, so they don't have to run additional tools. This patch adds a drop monitor script to the perf suite, and provides the same output that the netlink socket does. Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1309801217-22450-1-git-send-email-nhorman@tuxdriver.com Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf script: Finish the rename from trace to scriptArnaldo Carvalho de Melo2010-12-25
| | | | | | | | | | | | | | | | | | The scripts have calls to 'perf trace' that need to be converted to 'perf script', do it. This problem was introduced in 133dc4c. Reported-by: Torok Edwin <edwintorok@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Torok Edwin <edwintorok@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf: Rename 'perf trace' to 'perf script'Ingo Molnar2010-11-16
| | | | | | | | Free the perf trace name space and rename the trace to 'script' which is a better match for the scripting engine. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
* perf trace scripting: remove system-wide param from shell scriptsTom Zanussi2010-11-10
| | | | | | | | | Including -a unconditionally when recording doesn't allow for the option of running scripts without it. Future patches will add add it back if needed at run-time. Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Acked-by: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
* perf python scripting: Add futex-contention scriptArnaldo Carvalho de Melo2010-10-26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The equivalent to this SystemTAP script: http://sourceware.org/systemtap/wiki/WSFutexContention [root@doppio ~]# perf trace futex-contention Press control+C to stop and show the summary ^Cnpviewer.bin[15242] lock 7f0a8be19104 contended 29 times, 72806 avg ns npviewer.bin[15242] lock 7f0a8be19130 contended 2 times, 1355 avg ns synergyc[17245] lock f127f4 contended 1 times, 1830569 avg ns firefox[15116] lock 7f2b7238af0c contended 168 times, 1230390 avg ns synergyc[17245] lock f2fc20 contended 1 times, 33149 avg ns npviewer.bin[15255] lock 7f0a8be19074 contended 155 times, 73047 avg ns npviewer.bin[15255] lock 7f0a8be190a0 contended 127 times, 7088 avg ns synergyc[17247] lock f12854 contended 1 times, 46741 avg ns synergyc[17245] lock f12610 contended 1 times, 7358 avg ns [root@doppio ~]# Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf python scripting: Fixup cut'n'paste error in sctop scriptArnaldo Carvalho de Melo2010-10-26
| | | | | | | | | | | | Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf python scripting: Support fedora 11 (audit 1.7.17)Arnaldo Carvalho de Melo2010-10-25
| | | | | | | | | | | | | | | Where we don't have the audit.MACH_ARMEB constant. Cc: David S. Miller <davem@davemloft.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf python scripting: Improve the syscalls-by-pid scriptArnaldo Carvalho de Melo2010-10-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | . Print message at script start telling how to get te summary . Print the syscall names . Accept both pid (if numeric) or COMM name Now it looks like this: [root@emilia tmp]# perf trace syscall-counts-by-pid Press control+C to stop and show the summary ^C syscall events by comm/pid: comm [pid]/syscalls count ---------------------------------------- ---------- automount [1670] futex 2 sshd [2322] rt_sigprocmask 4 select 2 write 1 read 1 perf [15178] read 2506 open 794 close 769 write 240 getdents 112 lseek 16 stat 9 perf_counter_open 5 fcntl 5 mmap 5 statfs 2 perf [15179] read 56701 open 499 stat 176 fstat 149 close 109 mmap 98 brk 75 rt_sigaction 66 munmap 42 mprotect 24 lstat 7 lseek 5 getdents 4 ioctl 3 readlink 2 futex 1 statfs 1 getegid 1 geteuid 1 getgid 1 getuid 1 getrlimit 1 fcntl 1 uname 1 write 1 [root@emilia tmp]# fg -bash: fg: current: no such job [root@emilia tmp]# perf trace syscall-counts-by-pid 2322 Press control+C to stop and show the summary ^C syscall events by comm/pid: comm [pid]/syscalls count ---------------------------------------- ---------- sshd [2322] rt_sigprocmask 4 select 2 write 1 read 1 [root@emilia tmp]# perf trace syscall-counts-by-pid sshd Press control+C to stop and show the summary ^C syscall events for sshd: comm [pid]/syscalls count ---------------------------------------- ---------- sshd [2322] rt_sigprocmask 4 select 2 write 1 read 1 [root@emilia tmp]# Cc: David S. Miller <davem@davemloft.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf python scripting: print the syscall name on sctopArnaldo Carvalho de Melo2010-10-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | [root@emilia tmp]# perf trace sctop 1 syscall events: event count ---------------------------------------- ---------- read 215400 futex 4029 write 376 brk 33 rt_sigprocmask 24 select 17 lseek 2 fsync 1 ^C[root@emilia tmp]# Cc: David S. Miller <davem@davemloft.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf python scripting: Improve the syscalls-counts scriptArnaldo Carvalho de Melo2010-10-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | . Print message at script start telling how to get te summary . Print the syscall name Now it looks like this: [root@emilia ~]# perf trace syscall-counts Press control+C to stop and show the summary ^C syscall events: event count ---------------------------------------- ----------- read 102752 open 1293 close 878 write 319 stat 185 fstat 149 getdents 116 mmap 98 brk 80 rt_sigaction 66 munmap 42 mprotect 24 lseek 21 lstat 7 rt_sigprocmask 4 futex 3 statfs 3 ioctl 3 readlink 2 select 2 getegid 1 geteuid 1 getgid 1 getuid 1 getrlimit 1 fcntl 1 uname 1 [root@emilia ~]# Cc: David S. Miller <davem@davemloft.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf python scripting: Improve the failed-syscalls-by-pid scriptArnaldo Carvalho de Melo2010-10-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | . Print message at script start telling how to get te summary . Print the syscall name using the audit-lib-python package, if installed . Print the errno string . Accept both pid (if numeric) or COMM name Now it looks like this: [root@emilia ~]# perf trace failed-syscalls-by-pid Press control+C to stop and show the summary ^C syscall errors: comm [pid] count ------------------------------ ---------- automount [1670] syscall: futex err = ETIMEDOUT 39 irqbalance [1462] syscall: openat err = ENOENT 4 perf [7888] syscall: lseek err = ESPIPE 1 syscall: open err = ENOENT 24 perf [7889] syscall: ioctl err = EINVAL 1 syscall: readlink err = EINVAL 2 syscall: open err = ENOENT 389 syscall: stat err = ENOENT 141 syscall: lseek err = ESPIPE 3 [root@emilia ~]# [root@emilia ~]# perf trace failed-syscalls-by-pid 1670 Press control+C to stop and show the summary ^C syscall errors: comm [pid] count ------------------------------ ---------- automount [1670] syscall: futex err = ETIMEDOUT 2 [root@emilia ~]# [root@emilia ~]# [root@emilia ~]# [root@emilia ~]# perf trace failed-syscalls-by-pid automount Press control+C to stop and show the summary ^C syscall errors for automount: comm [pid] count ------------------------------ ---------- automount [1669] syscall: futex err = ETIMEDOUT 1 automount [1670] syscall: futex err = ETIMEDOUT 5 [root@emilia ~]# Cc: David S. Miller <davem@davemloft.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf trace: Use $PERF_EXEC_PATH in canned report scriptsBen Hutchings2010-10-23
| | | | | | | | | | | | Set $PERF_EXEC_PATH before starting the record and report scripts, and make them use it where necessary. Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <1286723403.2955.205.camel@localhost> Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf: Add a script to show packets processingKoki Sanagi2010-09-07
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add a perf script which shows packets processing and processed time. It helps us to investigate networking or network devices. If you want to use it, install perf and record perf.data like following. If you set script, perf gathers records until it ends. If not, you must Ctrl-C to stop recording. And if you want a report from record, If you use some options, you can limit the output. Option is below. tx: show only tx packets processing rx: show only rx packets processing dev=: show processing on this device debug: work with debug mode. It shows buffer status. For example, if you want to show received packets processing associated with eth4, 106133.171439sec cpu=0 irq_entry(+0.000msec irq=24:eth4) | softirq_entry(+0.006msec) | |---netif_receive_skb(+0.010msec skb=f2d15900 len=100) | | | skb_copy_datagram_iovec(+0.039msec 10291::10291) | napi_poll_exit(+0.022msec eth4) This perf script helps us to analyze the processing time of a transmit/receive sequence. Signed-off-by: Koki Sanagi <sanagi.koki@jp.fujitsu.com> Acked-by: David S. Miller <davem@davemloft.net> Cc: Neil Horman <nhorman@tuxdriver.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Kaneshige Kenji <kaneshige.kenji@jp.fujitsu.com> Cc: Izumo Taku <izumi.taku@jp.fujitsu.com> Cc: Kosaki Motohiro <kosaki.motohiro@jp.fujitsu.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Scott Mcmillan <scott.a.mcmillan@intel.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Eric Dumazet <eric.dumazet@gmail.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <4C72439D.3040001@jp.fujitsu.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
* perf, sched migration: Librarize task states and event headers helpersFrederic Weisbecker2010-08-01
| | | | | | | | | | | | | Librarize the task state and event headers helpers as they can be generally useful. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Nikhil Rao <ncrao@google.com> Cc: Tom Zanussi <tzanussi@gmail.com>
* perf, sched migration: Librarize the GUI classFrederic Weisbecker2010-08-01
| | | | | | | | | | | | | Export the GUI facility in the common library path. It is going to be useful for other scheduler views. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Nikhil Rao <ncrao@google.com> Cc: Tom Zanussi <tzanussi@gmail.com>
* perf, sched migration: Make the GUI class client agnosticFrederic Weisbecker2010-08-01
| | | | | | | | | | | | | | Make the perf migration GUI generic so that it can be reused for other kinds of trace painting. No more notion of CPUs or runqueue from the GUI class, it's now used as a library by the trace parser. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Nikhil Rao <ncrao@google.com> Cc: Tom Zanussi <tzanussi@gmail.com>
* perf, sched migration: Make it vertically scrollableFrederic Weisbecker2010-08-01
| | | | | | | | | | | | | | | | | | | With scheduler traces covering more than two cpus, rectangles of the CPUs 3 and more are not visibles. This makes the vertical navigation scrollable so that all of the CPUs rectangles are available. We also want to be able to zoom vertically, so that we can fit at best the screen with CPU rectangles, but that's for later. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Nikhil Rao <ncrao@google.com> Cc: Tom Zanussi <tzanussi@gmail.com>
* perf, sched migration: Parameterize cpu height and spacingNikhil Rao2010-08-01
| | | | | | | | | | | | | | | | | Without vertical zoom, it is not possible to see all CPUs in a trace taken on a larger machine. This patch parameterizes the height and spacing of CPUs so that you can fit more cpus into the screen. Ideally we should dynamically size/space the CPU rectangles with some minimum threshold. Until then, this patch is a stop-gap. Signed-off-by: Nikhil Rao <ncrao@google.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
* perf, sched migration: Fix key bindingsNikhil Rao2010-08-01
| | | | | | | | | | | | | | EVT_KEY_DOWN and EVT_LEFT_DOWN events are not bound to the RootFrame event handler. As a result, zoom/scroll via keyboard events do not work. This patch adds the missing bindings. Signed-off-by: Nikhil Rao <ncrao@google.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
* perf, sched migration: Ignore unhandled task statesFrederic Weisbecker2010-08-01
| | | | | | | | | | | | | | Stop printing an error message when we don't have the letter for a given task state. All we need to know is if the task is in the TASK_RUNNING state. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Nikhil Rao <ncrao@google.com> Cc: Tom Zanussi <tzanussi@gmail.com>
* perf, sched migration: Handle ignored migrate out eventsFrederic Weisbecker2010-08-01
| | | | | | | | | | | | | | | | | | | Migrate out events may happen on tasks that are not in the runqueue, for example this is the case for tasks that are sleeping. In this case, we don't want to log the migrate out event in the source runqueue because the task is not eventually in the runqueue and we have already logged its sleep event. This fixes timeslices that spuriously propagate a sleep event from the previous timeslice. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Nikhil Rao <ncrao@google.com> Cc: Tom Zanussi <tzanussi@gmail.com>
* perf: New migration tool overviewFrederic Weisbecker2010-08-01
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This brings a GUI tool that displays an overview of the load of tasks proportion in each CPUs. The CPUs forward progress is cut in timeslices. A new timeslice is created for every runqueue event: a task gets pushed out or pulled in the runqueue. For each timeslice, every CPUs rectangle is colored with a red power that describes the local load against the total load. This more red is the rectangle, the higher is the given CPU load. This load is the number of tasks running on the CPU, without any distinction against the scheduler policy of the tasks, for now. Also for each timeslice, the event origin is depicted on the CPUs that triggered it using a thin colored line on top of the rectangle timeslice. These events are: * sleep: a task went to sleep and has then been pulled out the runqueue. The origin color in the thin line is dark blue. * wake up: a task woke up and has then been pushed in the runqueue. The origin color is yellow. * wake up new: a new task woke up and has then been pushed in the runqueue. The origin color is green. * migrate in: a task migrated in the runqueue due to a load balancing operation. The origin color is violet. * migrate out: reverse of the previous one. Migrate in events usually have paired migrate out events in another runqueue. The origin color is light blue. Clicking on a timeslice provides the runqueue event details and the runqueue state. The CPU rectangles can be navigated using the usual arrow controls. Horizontal zooming in/out is possible with the "+" and "-" buttons. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Venkatesh Pallipadi <venki@google.com> Cc: Pierre Tardy <tardyp@gmail.com> Cc: Nikhil Rao <ncrao@google.com> Cc: Li Zefan <lizf@cn.fujitsu.com>
* perf scripts python: Give field dict to unhandled callbackPierre Tardy2010-06-01
| | | | | | | | | | | | | | | | | | | trace_unhandled() callback does not allow to access event fields, this patch resolves the problem. It can also been used as a more pythonic and flexible way for script writters to demux event types This will for example greatly simplify pytimechart event demux. Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Tom Zanussi <tzanussi@gmail.com> Cc: Ingo Molnar <mingo@elte.hu>, Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <1275340329-2397-1-git-send-email-tardyp@gmail.com> Signed-off-by: Pierre Tardy <tardyp@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf/trace/scripting: syscall-counts script cleanupTom Zanussi2010-05-10
| | | | | | | | | | | | A small fix for the syscall counts script: - silence the match output in the shell script Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> LKML-Reference: <1273466820-9330-10-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf/trace/scripting: syscall-counts-by-pid script cleanupTom Zanussi2010-05-10
| | | | | | | | | | | | A small fix for the syscall counts by pid script: - silence the match output in the shell script Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> LKML-Reference: <1273466820-9330-9-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf/trace/scripting: failed-syscalls-by-pid script cleanupTom Zanussi2010-05-10
| | | | | | | | | | | | A small fixe for the failed syscalls by pid script: - silence the match output in the shell script Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> LKML-Reference: <1273466820-9330-8-git-send-email-tzanussi@gmail.com> Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
* perf: Remove leftover useless options to record trace events from scriptsFrederic Weisbecker2010-04-30
| | | | | | | | | | | | | | -f, -c 1, -R are now useless for trace events recording, moreover -M is useless and event hurts. Remove them from the documentation examples and from record scripts. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Tom Zanussi <tzanussi@gmail.com>
* perf trace/scripting: Enable scripting shell scripts for live modeTom Zanussi2010-04-14
| | | | | | | | | | | | | | | | | | It should be possible to run any perf trace script in 'live mode'. This requires being able to pass in e.g. '-i -' or other args, which the current shell scripts aren't equipped to handle. In a few cases, there are required or optional args that also need special handling. This patch makes changes the current set of shell scripts as necessary. Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Cc: fweisbec@gmail.com Cc: rostedt@goodmis.org Cc: k-keiichi@bx.jp.nec.com Cc: acme@ghostprotocols.net LKML-Reference: <1270184365-8281-11-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
* perf trace/scripting: Add rwtop and sctop scriptsTom Zanussi2010-04-14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | A couple of scripts, one in Python and the other in Perl, that demonstrate 'live mode' tracing. For each, the output of the perf event stream is fed continuously to the script, which continuously aggregates the data and reports the current results every 3 seconds, or at the optionally specified interval. After the current results are displayed, the aggregations are cleared and the cycle begins anew. To run the scripts, simply pipe the output of the 'perf trace record' step as input to the corresponding 'perf trace report' step, using '-' as the filename to -o and -i: $ perf trace record sctop -o - | perf trace report sctop -i - Also adds clear_term() utility functions to the Util.pm and Util.py utility modules, for use by any script to clear the screen. Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Cc: fweisbec@gmail.com Cc: rostedt@goodmis.org Cc: k-keiichi@bx.jp.nec.com Cc: acme@ghostprotocols.net LKML-Reference: <1270184365-8281-10-git-send-email-tzanussi@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
* perf/scripts: Add syscall tracing scriptsTom Zanussi2010-02-24
| | | | | | | | | | | | | | | | | | Adds a set of scripts that aggregate system call totals and system call errors. Most are Python scripts that also test basic functionality of the new Python engine, but there's also one Perl script added for comparison and for reference in some new Documentation contained in a later patch. Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Keiichi KII <k-keiichi@bx.jp.nec.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <1264580883-15324-8-git-send-email-tzanussi@gmail.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
* perf/scripts: Add Python scripting engineTom Zanussi2010-02-24
Add base support for Python scripting to perf trace. Signed-off-by: Tom Zanussi <tzanussi@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Keiichi KII <k-keiichi@bx.jp.nec.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> LKML-Reference: <1264580883-15324-6-git-send-email-tzanussi@gmail.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
tten from FADT don't have a "path" attribute */ if(dev->handle) { result = device_create_file(&dev->dev, &dev_attr_path); if(result) goto end; } if(dev->flags.hardware_id) { result = device_create_file(&dev->dev, &dev_attr_hid); if(result) goto end; } if (dev->flags.hardware_id || dev->flags.compatible_ids){ result = device_create_file(&dev->dev, &dev_attr_modalias); if(result) goto end; } /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. */ status = acpi_get_handle(dev->handle, "_EJ0", &temp); if (ACPI_SUCCESS(status)) result = device_create_file(&dev->dev, &dev_attr_eject); end: return result; } static void acpi_device_remove_files(struct acpi_device *dev) { acpi_status status; acpi_handle temp; /* * If device has _EJ0, 'eject' file is created that is used to trigger * hot-removal function from userland. */ status = acpi_get_handle(dev->handle, "_EJ0", &temp); if (ACPI_SUCCESS(status)) device_remove_file(&dev->dev, &dev_attr_eject); if (dev->flags.hardware_id || dev->flags.compatible_ids) device_remove_file(&dev->dev, &dev_attr_modalias); if(dev->flags.hardware_id) device_remove_file(&dev->dev, &dev_attr_hid); if(dev->handle) device_remove_file(&dev->dev, &dev_attr_path); } /* -------------------------------------------------------------------------- ACPI Bus operations -------------------------------------------------------------------------- */ int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { const struct acpi_device_id *id; if (device->flags.hardware_id) { for (id = ids; id->id[0]; id++) { if (!strcmp((char*)id->id, device->pnp.hardware_id)) return 0; } } if (device->flags.compatible_ids) { struct acpi_compatible_id_list *cid_list = device->pnp.cid_list; int i; for (id = ids; id->id[0]; id++) { /* compare multiple _CID entries against driver ids */ for (i = 0; i < cid_list->count; i++) { if (!strcmp((char*)id->id, cid_list->id[i].value)) return 0; } } } return -ENOENT; } EXPORT_SYMBOL(acpi_match_device_ids); static void acpi_device_release(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); kfree(acpi_dev->pnp.cid_list); kfree(acpi_dev); } static int acpi_device_suspend(struct device *dev, pm_message_t state) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = acpi_dev->driver; if (acpi_drv && acpi_drv->ops.suspend) return acpi_drv->ops.suspend(acpi_dev, state); return 0; } static int acpi_device_resume(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = acpi_dev->driver; if (acpi_drv && acpi_drv->ops.resume) return acpi_drv->ops.resume(acpi_dev); return 0; } static int acpi_bus_match(struct device *dev, struct device_driver *drv) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = to_acpi_driver(drv); return !acpi_match_device_ids(acpi_dev, acpi_drv->ids); } static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct acpi_device *acpi_dev = to_acpi_device(dev); int len; if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], sizeof(env->buf) - env->buflen); if (len >= (sizeof(env->buf) - env->buflen)) return -ENOMEM; env->buflen += len; return 0; } static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *); static int acpi_start_single_object(struct acpi_device *); static int acpi_device_probe(struct device * dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); int ret; ret = acpi_bus_driver_init(acpi_dev, acpi_drv); if (!ret) { if (acpi_dev->bus_ops.acpi_op_start) acpi_start_single_object(acpi_dev); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", acpi_drv->name, acpi_dev->pnp.bus_id)); get_device(dev); } return ret; } static int acpi_device_remove(struct device * dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = acpi_dev->driver; if (acpi_drv) { if (acpi_drv->ops.stop) acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type); if (acpi_drv->ops.remove) acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); } acpi_dev->driver = NULL; acpi_driver_data(dev) = NULL; put_device(dev); return 0; } static void acpi_device_shutdown(struct device *dev) { struct acpi_device *acpi_dev = to_acpi_device(dev); struct acpi_driver *acpi_drv = acpi_dev->driver; if (acpi_drv && acpi_drv->ops.shutdown) acpi_drv->ops.shutdown(acpi_dev); return ; } struct bus_type acpi_bus_type = { .name = "acpi", .suspend = acpi_device_suspend, .resume = acpi_device_resume, .shutdown = acpi_device_shutdown, .match = acpi_bus_match, .probe = acpi_device_probe, .remove = acpi_device_remove, .uevent = acpi_device_uevent, }; static int acpi_device_register(struct acpi_device *device, struct acpi_device *parent) { int result; struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; int found = 0; /* * Linkage * ------- * Link this device to its parent and siblings. */ INIT_LIST_HEAD(&device->children); INIT_LIST_HEAD(&device->node); INIT_LIST_HEAD(&device->g_list); INIT_LIST_HEAD(&device->wakeup_list); new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); if (!new_bus_id) { printk(KERN_ERR PREFIX "Memory allocation error\n"); return -ENOMEM; } spin_lock(&acpi_device_lock); /* * Find suitable bus_id and instance number in acpi_bus_id_list * If failed, create one and link it into acpi_bus_id_list */ list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) { if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) { acpi_device_bus_id->instance_no ++; found = 1; kfree(new_bus_id); break; } } if(!found) { acpi_device_bus_id = new_bus_id; strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device"); acpi_device_bus_id->instance_no = 0; list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list); } sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no); if (device->parent) { list_add_tail(&device->node, &device->parent->children); list_add_tail(&device->g_list, &device->parent->g_list); } else list_add_tail(&device->g_list, &acpi_device_list); if (device->wakeup.flags.valid) list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list); spin_unlock(&acpi_device_lock); if (device->parent) device->dev.parent = &parent->dev; device->dev.bus = &acpi_bus_type; device_initialize(&device->dev); device->dev.release = &acpi_device_release; result = device_add(&device->dev); if(result) { printk("Error adding device %s", device->dev.bus_id); goto end; } result = acpi_device_setup_files(device); if(result) ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id)); device->removal_type = ACPI_BUS_REMOVAL_NORMAL; return 0; end: spin_lock(&acpi_device_lock); if (device->parent) { list_del(&device->node); list_del(&device->g_list); } else list_del(&device->g_list); list_del(&device->wakeup_list); spin_unlock(&acpi_device_lock); return result; } static void acpi_device_unregister(struct acpi_device *device, int type) { spin_lock(&acpi_device_lock); if (device->parent) { list_del(&device->node); list_del(&device->g_list); } else list_del(&device->g_list); list_del(&device->wakeup_list); spin_unlock(&acpi_device_lock); acpi_detach_data(device->handle, acpi_bus_data_handler); acpi_device_remove_files(device); device_unregister(&device->dev); } /* -------------------------------------------------------------------------- Driver Management -------------------------------------------------------------------------- */ /** * acpi_bus_driver_init - add a device to a driver * @device: the device to add and initialize * @driver: driver for the device * * Used to initialize a device via its device driver. Called whenever a * driver is bound to a device. Invokes the driver's add() ops. */ static int acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver) { int result = 0; if (!device || !driver) return -EINVAL; if (!driver->ops.add) return -ENOSYS; result = driver->ops.add(device); if (result) { device->driver = NULL; acpi_driver_data(device) = NULL; return result; } device->driver = driver; /* * TBD - Configuration Management: Assign resources to device based * upon possible configuration and currently allocated resources. */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); return 0; } static int acpi_start_single_object(struct acpi_device *device) { int result = 0; struct acpi_driver *driver; if (!(driver = device->driver)) return 0; if (driver->ops.start) { result = driver->ops.start(device); if (result && driver->ops.remove) driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); } return result; } /** * acpi_bus_register_driver - register a driver with the ACPI bus * @driver: driver being registered * * Registers a driver with the ACPI bus. Searches the namespace for all * devices that match the driver's criteria and binds. Returns zero for * success or a negative error status for failure. */ int acpi_bus_register_driver(struct acpi_driver *driver) { int ret; if (acpi_disabled) return -ENODEV; driver->drv.name = driver->name; driver->drv.bus = &acpi_bus_type; driver->drv.owner = driver->owner; ret = driver_register(&driver->drv); return ret; } EXPORT_SYMBOL(acpi_bus_register_driver); /** * acpi_bus_unregister_driver - unregisters a driver with the APIC bus * @driver: driver to unregister * * Unregisters a driver with the ACPI bus. Searches the namespace for all * devices that match the driver's criteria and unbinds. */ void acpi_bus_unregister_driver(struct acpi_driver *driver) { driver_unregister(&driver->drv); } EXPORT_SYMBOL(acpi_bus_unregister_driver); /* -------------------------------------------------------------------------- Device Enumeration -------------------------------------------------------------------------- */ acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd) { acpi_status status; acpi_handle tmp; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; union acpi_object *obj; status = acpi_get_handle(handle, "_EJD", &tmp); if (ACPI_FAILURE(status)) return status; status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer); if (ACPI_SUCCESS(status)) { obj = buffer.pointer; status = acpi_get_handle(NULL, obj->string.pointer, ejd); kfree(buffer.pointer); } return status; } EXPORT_SYMBOL_GPL(acpi_bus_get_ejd); void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context) { /* TBD */ return; } static int acpi_bus_get_perf_flags(struct acpi_device *device) { device->performance.state = ACPI_STATE_UNKNOWN; return 0; } static acpi_status acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, union acpi_object *package) { int i = 0; union acpi_object *element = NULL; if (!device || !package || (package->package.count < 2)) return AE_BAD_PARAMETER; element = &(package->package.elements[0]); if (!element) return AE_BAD_PARAMETER; if (element->type == ACPI_TYPE_PACKAGE) { if ((element->package.count < 2) || (element->package.elements[0].type != ACPI_TYPE_LOCAL_REFERENCE) || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) return AE_BAD_DATA; device->wakeup.gpe_device = element->package.elements[0].reference.handle; device->wakeup.gpe_number = (u32) element->package.elements[1].integer.value; } else if (element->type == ACPI_TYPE_INTEGER) { device->wakeup.gpe_number = element->integer.value; } else return AE_BAD_DATA; element = &(package->package.elements[1]); if (element->type != ACPI_TYPE_INTEGER) { return AE_BAD_DATA; } device->wakeup.sleep_state = element->integer.value; if ((package->package.count - 2) > ACPI_MAX_HANDLES) { return AE_NO_MEMORY; } device->wakeup.resources.count = package->package.count - 2; for (i = 0; i < device->wakeup.resources.count; i++) { element = &(package->package.elements[i + 2]); if (element->type != ACPI_TYPE_ANY) { return AE_BAD_DATA; } device->wakeup.resources.handles[i] = element->reference.handle; } return AE_OK; } static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) { acpi_status status = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *package = NULL; struct acpi_device_id button_device_ids[] = { {"PNP0C0D", 0}, {"PNP0C0C", 0}, {"PNP0C0E", 0}, {"", 0}, }; /* _PRW */ status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); goto end; } package = (union acpi_object *)buffer.pointer; status = acpi_bus_extract_wakeup_device_power_package(device, package); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); goto end; } kfree(buffer.pointer); device->wakeup.flags.valid = 1; /* Power button, Lid switch always enable wakeup */ if (!acpi_match_device_ids(device, button_device_ids)) device->wakeup.flags.run_wake = 1; end: if (ACPI_FAILURE(status)) device->flags.wake_capable = 0; return 0; } static int acpi_bus_get_power_flags(struct acpi_device *device) { acpi_status status = 0; acpi_handle handle = NULL; u32 i = 0; /* * Power Management Flags */ status = acpi_get_handle(device->handle, "_PSC", &handle); if (ACPI_SUCCESS(status)) device->power.flags.explicit_get = 1; status = acpi_get_handle(device->handle, "_IRC", &handle); if (ACPI_SUCCESS(status)) device->power.flags.inrush_current = 1; /* * Enumerate supported power management states */ for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) { struct acpi_device_power_state *ps = &device->power.states[i]; char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; /* Evaluate "_PRx" to se if power resources are referenced */ acpi_evaluate_reference(device->handle, object_name, NULL, &ps->resources); if (ps->resources.count) { device->power.flags.power_resources = 1; ps->flags.valid = 1; } /* Evaluate "_PSx" to see if we can do explicit sets */ object_name[2] = 'S'; status = acpi_get_handle(device->handle, object_name, &handle); if (ACPI_SUCCESS(status)) { ps->flags.explicit_set = 1; ps->flags.valid = 1; } /* State is valid if we have some power control */ if (ps->resources.count || ps->flags.explicit_set) ps->flags.valid = 1; ps->power = -1; /* Unknown - driver assigned */ ps->latency = -1; /* Unknown - driver assigned */ } /* Set defaults for D0 and D3 states (always valid) */ device->power.states[ACPI_STATE_D0].flags.valid = 1; device->power.states[ACPI_STATE_D0].power = 100; device->power.states[ACPI_STATE_D3].flags.valid = 1; device->power.states[ACPI_STATE_D3].power = 0; /* TBD: System wake support and resource requirements. */ device->power.state = ACPI_STATE_UNKNOWN; return 0; } static int acpi_bus_get_flags(struct acpi_device *device) { acpi_status status = AE_OK; acpi_handle temp = NULL; /* Presence of _STA indicates 'dynamic_status' */ status = acpi_get_handle(device->handle, "_STA", &temp); if (ACPI_SUCCESS(status)) device->flags.dynamic_status = 1; /* Presence of _CID indicates 'compatible_ids' */ status = acpi_get_handle(device->handle, "_CID", &temp); if (ACPI_SUCCESS(status)) device->flags.compatible_ids = 1; /* Presence of _RMV indicates 'removable' */ status = acpi_get_handle(device->handle, "_RMV", &temp); if (ACPI_SUCCESS(status)) device->flags.removable = 1; /* Presence of _EJD|_EJ0 indicates 'ejectable' */ status = acpi_get_handle(device->handle, "_EJD", &temp); if (ACPI_SUCCESS(status)) device->flags.ejectable = 1; else { status = acpi_get_handle(device->handle, "_EJ0", &temp); if (ACPI_SUCCESS(status)) device->flags.ejectable = 1; } /* Presence of _LCK indicates 'lockable' */ status = acpi_get_handle(device->handle, "_LCK", &temp); if (ACPI_SUCCESS(status)) device->flags.lockable = 1; /* Presence of _PS0|_PR0 indicates 'power manageable' */ status = acpi_get_handle(device->handle, "_PS0", &temp); if (ACPI_FAILURE(status)) status = acpi_get_handle(device->handle, "_PR0", &temp); if (ACPI_SUCCESS(status)) device->flags.power_manageable = 1; /* Presence of _PRW indicates wake capable */ status = acpi_get_handle(device->handle, "_PRW", &temp); if (ACPI_SUCCESS(status)) device->flags.wake_capable = 1; /* TBD: Peformance management */ return 0; } static void acpi_device_get_busid(struct acpi_device *device, acpi_handle handle, int type) { char bus_id[5] = { '?', 0 }; struct acpi_buffer buffer = { sizeof(bus_id), bus_id }; int i = 0; /* * Bus ID * ------ * The device's Bus ID is simply the object name. * TBD: Shouldn't this value be unique (within the ACPI namespace)? */ switch (type) { case ACPI_BUS_TYPE_SYSTEM: strcpy(device->pnp.bus_id, "ACPI"); break; case ACPI_BUS_TYPE_POWER_BUTTON: strcpy(device->pnp.bus_id, "PWRF"); break; case ACPI_BUS_TYPE_SLEEP_BUTTON: strcpy(device->pnp.bus_id, "SLPF"); break; default: acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); /* Clean up trailing underscores (if any) */ for (i = 3; i > 1; i--) { if (bus_id[i] == '_') bus_id[i] = '\0'; else break; } strcpy(device->pnp.bus_id, bus_id); break; } } static int acpi_video_bus_match(struct acpi_device *device) { acpi_handle h_dummy1; acpi_handle h_dummy2; acpi_handle h_dummy3; if (!device) return -EINVAL; /* Since there is no HID, CID for ACPI Video drivers, we have * to check well known required nodes for each feature we support. */ /* Does this device able to support video switching ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) && ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2))) return 0; /* Does this device able to retrieve a video ROM ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1))) return 0; /* Does this device able to configure which video head to be POSTed ? */ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) && ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) && ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3))) return 0; return -ENODEV; } /* * acpi_bay_match - see if a device is an ejectable driver bay * * If an acpi object is ejectable and has one of the ACPI ATA methods defined, * then we can safely call it an ejectable drive bay */ static int acpi_bay_match(struct acpi_device *device){ acpi_status status; acpi_handle handle; acpi_handle tmp; acpi_handle phandle; handle = device->handle; status = acpi_get_handle(handle, "_EJ0", &tmp); if (ACPI_FAILURE(status)) return -ENODEV; if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) || (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) || (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) || (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp)))) return 0; if (acpi_get_parent(handle, &phandle)) return -ENODEV; if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) || (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) || (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) || (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp)))) return 0; return -ENODEV; } static void acpi_device_set_id(struct acpi_device *device, struct acpi_device *parent, acpi_handle handle, int type) { struct acpi_device_info *info; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; char *hid = NULL; char *uid = NULL; struct acpi_compatible_id_list *cid_list = NULL; acpi_status status; switch (type) { case ACPI_BUS_TYPE_DEVICE: status = acpi_get_object_info(handle, &buffer); if (ACPI_FAILURE(status)) { printk("%s: Error reading device info\n", __FUNCTION__); return; } info = buffer.pointer; if (info->valid & ACPI_VALID_HID) hid = info->hardware_id.value; if (info->valid & ACPI_VALID_UID) uid = info->unique_id.value; if (info->valid & ACPI_VALID_CID) cid_list = &info->compatibility_id; if (info->valid & ACPI_VALID_ADR) { device->pnp.bus_address = info->address; device->flags.bus_address = 1; } if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){ status = acpi_video_bus_match(device); if(ACPI_SUCCESS(status)) hid = ACPI_VIDEO_HID; status = acpi_bay_match(device); if (ACPI_SUCCESS(status)) hid = ACPI_BAY_HID; } break; case ACPI_BUS_TYPE_POWER: hid = ACPI_POWER_HID; break; case ACPI_BUS_TYPE_PROCESSOR: hid = ACPI_PROCESSOR_HID; break; case ACPI_BUS_TYPE_SYSTEM: hid = ACPI_SYSTEM_HID; break; case ACPI_BUS_TYPE_THERMAL: hid = ACPI_THERMAL_HID; break; case ACPI_BUS_TYPE_POWER_BUTTON: hid = ACPI_BUTTON_HID_POWERF; break; case ACPI_BUS_TYPE_SLEEP_BUTTON: hid = ACPI_BUTTON_HID_SLEEPF; break; } /* * \_SB * ---- * Fix for the system root bus device -- the only root-level device. */ if (((acpi_handle)parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) { hid = ACPI_BUS_HID; strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); strcpy(device->pnp.device_class, ACPI_BUS_CLASS); } if (hid) { strcpy(device->pnp.hardware_id, hid); device->flags.hardware_id = 1; } if (uid) { strcpy(device->pnp.unique_id, uid); device->flags.unique_id = 1; } if (cid_list) { device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL); if (device->pnp.cid_list) memcpy(device->pnp.cid_list, cid_list, cid_list->size); else printk(KERN_ERR "Memory allocation error\n"); } kfree(buffer.pointer); } static int acpi_device_set_context(struct acpi_device *device, int type) { acpi_status status = AE_OK; int result = 0; /* * Context * ------- * Attach this 'struct acpi_device' to the ACPI object. This makes * resolutions from handle->device very efficient. Note that we need * to be careful with fixed-feature devices as they all attach to the * root object. */ if (type != ACPI_BUS_TYPE_POWER_BUTTON && type != ACPI_BUS_TYPE_SLEEP_BUTTON) { status = acpi_attach_data(device->handle, acpi_bus_data_handler, device); if (ACPI_FAILURE(status)) { printk("Error attaching device data\n"); result = -ENODEV; } } return result; } static int acpi_bus_remove(struct acpi_device *dev, int rmdevice) { if (!dev) return -EINVAL; dev->removal_type = ACPI_BUS_REMOVAL_EJECT; device_release_driver(&dev->dev); if (!rmdevice) return 0; /* * unbind _ADR-Based Devices when hot removal */ if (dev->flags.bus_address) { if ((dev->parent) && (dev->parent->ops.unbind)) dev->parent->ops.unbind(dev); } acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT); return 0; } static int acpi_add_single_object(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type, struct acpi_bus_ops *ops) { int result = 0; struct acpi_device *device = NULL; if (!child) return -EINVAL; device = kzalloc(sizeof(struct acpi_device), GFP_KERNEL); if (!device) { printk(KERN_ERR PREFIX "Memory allocation error\n"); return -ENOMEM; } device->handle = handle; device->parent = parent; device->bus_ops = *ops; /* workround for not call .start */ acpi_device_get_busid(device, handle, type); /* * Flags * ----- * Get prior to calling acpi_bus_get_status() so we know whether * or not _STA is present. Note that we only look for object * handles -- cannot evaluate objects until we know the device is * present and properly initialized. */ result = acpi_bus_get_flags(device); if (result) goto end; /* * Status * ------ * See if the device is present. We always assume that non-Device * and non-Processor objects (e.g. thermal zones, power resources, * etc.) are present, functioning, etc. (at least when parent object * is present). Note that _STA has a different meaning for some * objects (e.g. power resources) so we need to be careful how we use * it. */ switch (type) { case ACPI_BUS_TYPE_PROCESSOR: case ACPI_BUS_TYPE_DEVICE: result = acpi_bus_get_status(device); if (ACPI_FAILURE(result) || !device->status.present) { result = -ENOENT; goto end; } break; default: STRUCT_TO_INT(device->status) = ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING; break; } /* * Initialize Device * ----------------- * TBD: Synch with Core's enumeration/initialization process. */ /* * Hardware ID, Unique ID, & Bus Address * ------------------------------------- */ acpi_device_set_id(device, parent, handle, type); /* * Power Management * ---------------- */ if (device->flags.power_manageable) { result = acpi_bus_get_power_flags(device); if (result) goto end; } /* * Wakeup device management *----------------------- */ if (device->flags.wake_capable) { result = acpi_bus_get_wakeup_device_flags(device); if (result) goto end; } /* * Performance Management * ---------------------- */ if (device->flags.performance_manageable) { result = acpi_bus_get_perf_flags(device); if (result) goto end; } if ((result = acpi_device_set_context(device, type))) goto end; result = acpi_device_register(device, parent); /* * Bind _ADR-Based Devices when hot add */ if (device->flags.bus_address) { if (device->parent && device->parent->ops.bind) device->parent->ops.bind(device); } end: if (!result) *child = device; else { kfree(device->pnp.cid_list); kfree(device); } return result; } static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops) { acpi_status status = AE_OK; struct acpi_device *parent = NULL; struct acpi_device *child = NULL; acpi_handle phandle = NULL; acpi_handle chandle = NULL; acpi_object_type type = 0; u32 level = 1; if (!start) return -EINVAL; parent = start; phandle = start->handle; /* * Parse through the ACPI namespace, identify all 'devices', and * create a new 'struct acpi_device' for each. */ while ((level > 0) && parent) { status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, chandle, &chandle); /* * If this scope is exhausted then move our way back up. */ if (ACPI_FAILURE(status)) { level--; chandle = phandle; acpi_get_parent(phandle, &phandle); if (parent->parent) parent = parent->parent; continue; } status = acpi_get_type(chandle, &type); if (ACPI_FAILURE(status)) continue; /* * If this is a scope object then parse it (depth-first). */ if (type == ACPI_TYPE_LOCAL_SCOPE) { level++; phandle = chandle; chandle = NULL; continue; } /* * We're only interested in objects that we consider 'devices'. */ switch (type) { case ACPI_TYPE_DEVICE: type = ACPI_BUS_TYPE_DEVICE; break; case ACPI_TYPE_PROCESSOR: type = ACPI_BUS_TYPE_PROCESSOR; break; case ACPI_TYPE_THERMAL: type = ACPI_BUS_TYPE_THERMAL; break; case ACPI_TYPE_POWER: type = ACPI_BUS_TYPE_POWER; break; default: continue; } if (ops->acpi_op_add) status = acpi_add_single_object(&child, parent, chandle, type, ops); else status = acpi_bus_get_device(chandle, &child); if (ACPI_FAILURE(status)) continue; if (ops->acpi_op_start && !(ops->acpi_op_add)) { status = acpi_start_single_object(child); if (ACPI_FAILURE(status)) continue; } /* * If the device is present, enabled, and functioning then * parse its scope (depth-first). Note that we need to * represent absent devices to facilitate PnP notifications * -- but only the subtree head (not all of its children, * which will be enumerated when the parent is inserted). * * TBD: Need notifications and other detection mechanisms * in place before we can fully implement this. */ if (child->status.present) { status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, NULL, NULL); if (ACPI_SUCCESS(status)) { level++; phandle = chandle; chandle = NULL; parent = child; } } } return 0; } int acpi_bus_add(struct acpi_device **child, struct acpi_device *parent, acpi_handle handle, int type) { int result; struct acpi_bus_ops ops; memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; result = acpi_add_single_object(child, parent, handle, type, &ops); if (!result) result = acpi_bus_scan(*child, &ops); return result; } EXPORT_SYMBOL(acpi_bus_add); int acpi_bus_start(struct acpi_device *device) { int result; struct acpi_bus_ops ops; if (!device) return -EINVAL; result = acpi_start_single_object(device); if (!result) { memset(&ops, 0, sizeof(ops)); ops.acpi_op_start = 1; result = acpi_bus_scan(device, &ops); } return result; } EXPORT_SYMBOL(acpi_bus_start); int acpi_bus_trim(struct acpi_device *start, int rmdevice) { acpi_status status; struct acpi_device *parent, *child; acpi_handle phandle, chandle; acpi_object_type type; u32 level = 1; int err = 0; parent = start; phandle = start->handle; child = chandle = NULL; while ((level > 0) && parent && (!err)) { status = acpi_get_next_object(ACPI_TYPE_ANY, phandle, chandle, &chandle); /* * If this scope is exhausted then move our way back up. */ if (ACPI_FAILURE(status)) { level--; chandle = phandle; acpi_get_parent(phandle, &phandle); child = parent; parent = parent->parent; if (level == 0) err = acpi_bus_remove(child, rmdevice); else err = acpi_bus_remove(child, 1); continue; } status = acpi_get_type(chandle, &type); if (ACPI_FAILURE(status)) { continue; } /* * If there is a device corresponding to chandle then * parse it (depth-first). */ if (acpi_bus_get_device(chandle, &child) == 0) { level++; phandle = chandle; chandle = NULL; parent = child; } continue; } return err; } EXPORT_SYMBOL_GPL(acpi_bus_trim); static int acpi_bus_scan_fixed(struct acpi_device *root) { int result = 0; struct acpi_device *device = NULL; struct acpi_bus_ops ops; if (!root) return -ENODEV; memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; ops.acpi_op_start = 1; /* * Enumerate all fixed-feature devices. */ if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_POWER_BUTTON, &ops); } if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { result = acpi_add_single_object(&device, acpi_root, NULL, ACPI_BUS_TYPE_SLEEP_BUTTON, &ops); } return result; } static int __init acpi_scan_init(void) { int result; struct acpi_bus_ops ops; if (acpi_disabled) return 0; memset(&ops, 0, sizeof(ops)); ops.acpi_op_add = 1; ops.acpi_op_start = 1; result = bus_register(&acpi_bus_type); if (result) { /* We don't want to quit even if we failed to add suspend/resume */ printk(KERN_ERR PREFIX "Could not register bus type\n"); } /* * Create the root device in the bus's device tree */ result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SYSTEM, &ops); if (result) goto Done; /* * Enumerate devices in the ACPI namespace. */ result = acpi_bus_scan_fixed(acpi_root); if (!result) result = acpi_bus_scan(acpi_root, &ops); if (result) acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); Done: return result; } subsys_initcall(acpi_scan_init);